All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.nukkit.scoreboard.manager.ScoreboardManager Maven / Gradle / Ivy

There is a newer version: 1.20.40-r1
Show newest version
package cn.nukkit.scoreboard.manager;


import cn.nukkit.Player;
import cn.nukkit.Server;
import cn.nukkit.api.PowerNukkitXOnly;
import cn.nukkit.api.Since;
import cn.nukkit.entity.EntityLiving;
import cn.nukkit.event.scoreboard.ScoreboardObjectiveChangeEvent;
import cn.nukkit.scoreboard.data.DisplaySlot;
import cn.nukkit.scoreboard.displayer.IScoreboardViewer;
import cn.nukkit.scoreboard.scoreboard.IScoreboard;
import cn.nukkit.scoreboard.scorer.EntityScorer;
import cn.nukkit.scoreboard.scorer.PlayerScorer;
import cn.nukkit.scoreboard.storage.IScoreboardStorage;
import lombok.Getter;
import org.jetbrains.annotations.Nullable;

import java.util.*;

@PowerNukkitXOnly
@Since("1.19.30-r1")
@Getter
public class ScoreboardManager implements IScoreboardManager{

    protected Map scoreboards = new HashMap<>();
    protected Map display = new HashMap<>();
    protected Set viewers = new HashSet<>();
    protected IScoreboardStorage storage;

    public ScoreboardManager(IScoreboardStorage storage) {
        this.storage = storage;
        read();
    }

    @Override
    public boolean addScoreboard(IScoreboard scoreboard) {
        var event = new ScoreboardObjectiveChangeEvent(scoreboard, ScoreboardObjectiveChangeEvent.ActionType.ADD);
        Server.getInstance().getPluginManager().callEvent(event);
        if (event.isCancelled()) {
            return false;
        }
        scoreboards.put(scoreboard.getObjectiveName(), scoreboard);
        return true;
    }

    @Override
    public boolean removeScoreboard(IScoreboard scoreboard) {
        return removeScoreboard(scoreboard.getObjectiveName());
    }

    @Override
    public boolean removeScoreboard(String objectiveName) {
        var removed = scoreboards.get(objectiveName);
        if (removed == null) return false;
        var event = new ScoreboardObjectiveChangeEvent(removed, ScoreboardObjectiveChangeEvent.ActionType.REMOVE);
        Server.getInstance().getPluginManager().callEvent(event);
        if (event.isCancelled()) {
            return false;
        }
       scoreboards.remove(objectiveName);
       viewers.forEach(viewer -> viewer.removeScoreboard(removed));
       display.forEach((slot, scoreboard) -> {
           if (scoreboard != null && scoreboard.getObjectiveName().equals(objectiveName)) {
                display.put(slot, null);
           }
       });
       return true;
    }

    @Override
    public IScoreboard getScoreboard(String objectiveName) {
        return scoreboards.get(objectiveName);
    }

    @Override
    public boolean containScoreboard(IScoreboard scoreboard) {
        return scoreboards.containsKey(scoreboard.getObjectiveName());
    }

    @Override
    public boolean containScoreboard(String name) {
        return scoreboards.containsKey(name);
    }

    @Override
    public IScoreboard getDisplaySlot(DisplaySlot slot) {
        return display.get(slot);
    }

    @Override
    public void setDisplay(DisplaySlot slot, @Nullable IScoreboard scoreboard) {
        var old = display.put(slot, scoreboard);
        if (old != null) this.viewers.forEach(viewer -> old.removeViewer(viewer, slot));
        if (scoreboard != null) this.viewers.forEach(viewer -> scoreboard.addViewer(viewer, slot));
    }

    @Override
    public boolean addViewer(IScoreboardViewer viewer) {
        var added =  this.viewers.add(viewer);
        if (added) this.display.forEach((slot, scoreboard) -> {
            if (scoreboard != null) scoreboard.addViewer(viewer, slot);
        });
        return added;
    }

    @Override
    public boolean removeViewer(IScoreboardViewer viewer) {
        var removed = viewers.remove(viewer);
        if (removed) this.display.forEach((slot, scoreboard) -> {
            if (scoreboard != null) scoreboard.removeViewer(viewer, slot);
        });
        return removed;
    }

    /**
     * 你可能会对这里的代码感到疑惑
     * 这里其实是为了规避玩家下线导致的“玩家离线”计分项
     * 我们在玩家下线时,删除其他在线玩家显示槽位中的“玩家离线”
     * 并在其重新连接上服务器时加回去
     */

    @Override
    public void onPlayerJoin(Player player) {
        addViewer(player);
        var scorer = new PlayerScorer(player);
        this.scoreboards.values().forEach(scoreboard -> {
            if (scoreboard.containLine(scorer)) {
                this.viewers.forEach(viewer -> viewer.updateScore(scoreboard.getLine(scorer)));
            }
        });
    }

    @Override
    public void beforePlayerQuit(Player player) {
        var scorer = new PlayerScorer(player);
        this.scoreboards.values().forEach(scoreboard -> {
            if (scoreboard.containLine(scorer)) {
                this.viewers.forEach(viewer -> viewer.removeLine(scoreboard.getLine(scorer)));
            }
        });
        removeViewer(player);
    }

    @Override
    public void onEntityDead(EntityLiving entity) {
        var scorer = new EntityScorer(entity);
        this.scoreboards.forEach((s, scoreboard) -> {
            if (scoreboard.getLines().isEmpty()) return;
            scoreboard.removeLine(scorer);
        });
    }

    @Override
    public void save() {
        storage.removeAllScoreboard();
        storage.saveScoreboard(scoreboards.values());
        storage.saveDisplay(display);
    }

    @Override
    public void read() {
        //新建一个列表避免迭代冲突
        new ArrayList<>(this.scoreboards.values()).forEach(this::removeScoreboard);
        this.display.forEach((slot, scoreboard) -> setDisplay(slot, null));

        scoreboards = storage.readScoreboard();
        storage.readDisplay().forEach((slot, objectiveName) -> {
            var scoreboard = getScoreboard(objectiveName);
            if (scoreboard != null) {
                this.setDisplay(slot, scoreboard);
            }
        });
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy