forked from GeyserMC/Geyser
Fixed some issues related to Scoreboards (#1446)
* Fixes some issues related to Scoreboard Teams * The cached Score info should update no matter what kind of update the Team got. * Team entities specified at the create Team packet should also be checked if they exist as Score in the registered Objectives * Rewrote some Scoreboard code and fixed various issues * Minor formatting changes
This commit is contained in:
parent
2d95302b10
commit
e00715ceab
7 changed files with 333 additions and 154 deletions
|
@ -27,7 +27,6 @@ package org.geysermc.connector.entity;
|
|||
|
||||
import com.github.steveice10.mc.auth.data.GameProfile;
|
||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||
import com.github.steveice10.mc.protocol.data.game.scoreboard.NameTagVisibility;
|
||||
import com.github.steveice10.mc.protocol.data.message.TextMessage;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.nukkitx.math.vector.Vector3f;
|
||||
|
@ -235,18 +234,12 @@ public class PlayerEntity extends LivingEntity {
|
|||
}
|
||||
Team team = session.getWorldCache().getScoreboard().getTeamFor(username);
|
||||
if (team != null) {
|
||||
// Cover different visibility settings
|
||||
if (team.getNameTagVisibility() == NameTagVisibility.NEVER) {
|
||||
metadata.put(EntityData.NAMETAG, "");
|
||||
} else if (team.getNameTagVisibility() == NameTagVisibility.HIDE_FOR_OTHER_TEAMS &&
|
||||
!team.getEntities().contains(session.getPlayerEntity().getUsername())) {
|
||||
metadata.put(EntityData.NAMETAG, "");
|
||||
} else if (team.getNameTagVisibility() == NameTagVisibility.HIDE_FOR_OWN_TEAM &&
|
||||
team.getEntities().contains(session.getPlayerEntity().getUsername())) {
|
||||
metadata.put(EntityData.NAMETAG, "");
|
||||
} else {
|
||||
metadata.put(EntityData.NAMETAG, team.getPrefix() + MessageUtils.toChatColor(team.getColor()) + username + team.getSuffix());
|
||||
String displayName = "";
|
||||
if (team.isVisibleFor(session.getPlayerEntity().getUsername())) {
|
||||
displayName = MessageUtils.toChatColor(team.getColor()) + username;
|
||||
displayName = team.getCurrentData().getDisplayName(displayName);
|
||||
}
|
||||
metadata.put(EntityData.NAMETAG, displayName);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,8 +36,7 @@ public class JavaDisplayScoreboardTranslator extends PacketTranslator<ServerDisp
|
|||
|
||||
@Override
|
||||
public void translate(ServerDisplayScoreboardPacket packet, GeyserSession session) {
|
||||
session.getWorldCache().getScoreboard().registerNewObjective(
|
||||
packet.getName(), packet.getPosition()
|
||||
);
|
||||
session.getWorldCache().getScoreboard()
|
||||
.displayObjective(packet.getName(), packet.getPosition());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.geysermc.connector.network.translators.PacketTranslator;
|
|||
import org.geysermc.connector.network.translators.Translator;
|
||||
import org.geysermc.connector.scoreboard.Objective;
|
||||
import org.geysermc.connector.scoreboard.Scoreboard;
|
||||
import org.geysermc.connector.scoreboard.ScoreboardUpdater;
|
||||
import org.geysermc.connector.utils.MessageUtils;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.scoreboard.ObjectiveAction;
|
||||
|
@ -41,8 +42,10 @@ public class JavaScoreboardObjectiveTranslator extends PacketTranslator<ServerSc
|
|||
|
||||
@Override
|
||||
public void translate(ServerScoreboardObjectivePacket packet, GeyserSession session) {
|
||||
Scoreboard scoreboard = session.getWorldCache().getScoreboard();
|
||||
WorldCache worldCache = session.getWorldCache();
|
||||
Scoreboard scoreboard = worldCache.getScoreboard();
|
||||
Objective objective = scoreboard.getObjective(packet.getName());
|
||||
int pps = worldCache.increaseAndGetScoreboardPacketsPerSecond();
|
||||
|
||||
if (objective == null && packet.getAction() != ObjectiveAction.REMOVE) {
|
||||
objective = scoreboard.registerNewObjective(packet.getName(), false);
|
||||
|
@ -51,15 +54,21 @@ public class JavaScoreboardObjectiveTranslator extends PacketTranslator<ServerSc
|
|||
switch (packet.getAction()) {
|
||||
case ADD:
|
||||
case UPDATE:
|
||||
objective.setDisplayName(MessageUtils.getBedrockMessage(packet.getDisplayName()));
|
||||
objective.setType(packet.getType().ordinal());
|
||||
objective.setDisplayName(MessageUtils.getBedrockMessage(packet.getDisplayName()))
|
||||
.setType(packet.getType().ordinal());
|
||||
break;
|
||||
case REMOVE:
|
||||
scoreboard.unregisterObjective(packet.getName());
|
||||
break;
|
||||
}
|
||||
|
||||
if (objective != null && objective.isActive()) {
|
||||
if (objective == null || !objective.isActive()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// ScoreboardUpdater will handle it for us if the packets per second
|
||||
// (for score and team packets) is higher then the first threshold
|
||||
if (pps < ScoreboardUpdater.FIRST_SCORE_PACKETS_PER_SECOND_THRESHOLD) {
|
||||
scoreboard.onUpdate();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,14 +33,16 @@ import java.util.Map;
|
|||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@Getter
|
||||
public class Objective {
|
||||
public final class Objective {
|
||||
private final Scoreboard scoreboard;
|
||||
private final long id;
|
||||
private boolean active = true;
|
||||
|
||||
@Setter
|
||||
private UpdateType updateType = UpdateType.ADD;
|
||||
|
||||
private String objectiveName;
|
||||
private ScoreboardPosition displaySlot;
|
||||
private String displaySlotName;
|
||||
private String displayName = "unknown";
|
||||
private int type = 0; // 0 = integer, 1 = heart
|
||||
|
@ -67,39 +69,59 @@ public class Objective {
|
|||
public Objective(Scoreboard scoreboard, String objectiveName, ScoreboardPosition displaySlot, String displayName, int type) {
|
||||
this(scoreboard);
|
||||
this.objectiveName = objectiveName;
|
||||
this.displaySlot = correctDisplaySlot(displaySlot);
|
||||
this.displaySlotName = translateDisplaySlot(displaySlot);
|
||||
this.displayName = displayName;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
private static String translateDisplaySlot(ScoreboardPosition displaySlot) {
|
||||
switch (displaySlot) {
|
||||
case BELOW_NAME:
|
||||
return "belowname";
|
||||
case PLAYER_LIST:
|
||||
return "list";
|
||||
default:
|
||||
return "sidebar";
|
||||
}
|
||||
}
|
||||
|
||||
private static ScoreboardPosition correctDisplaySlot(ScoreboardPosition displaySlot) {
|
||||
switch (displaySlot) {
|
||||
case BELOW_NAME:
|
||||
return ScoreboardPosition.BELOW_NAME;
|
||||
case PLAYER_LIST:
|
||||
return ScoreboardPosition.PLAYER_LIST;
|
||||
default:
|
||||
return ScoreboardPosition.SIDEBAR;
|
||||
}
|
||||
}
|
||||
|
||||
public void registerScore(String id, int score) {
|
||||
if (!scores.containsKey(id)) {
|
||||
Score score1 = new Score(this, id)
|
||||
long scoreId = scoreboard.getNextId().getAndIncrement();
|
||||
Score scoreObject = new Score(scoreId, id)
|
||||
.setScore(score)
|
||||
.setTeam(scoreboard.getTeamFor(id))
|
||||
.setUpdateType(UpdateType.ADD);
|
||||
scores.put(id, score1);
|
||||
scores.put(id, scoreObject);
|
||||
}
|
||||
}
|
||||
|
||||
public void setScore(String id, int score) {
|
||||
if (scores.containsKey(id)) {
|
||||
scores.get(id).setScore(score);
|
||||
Score stored = scores.get(id);
|
||||
if (stored != null) {
|
||||
stored.setScore(score)
|
||||
.setUpdateType(UpdateType.UPDATE);
|
||||
return;
|
||||
}
|
||||
registerScore(id, score);
|
||||
}
|
||||
|
||||
public int getScore(String id) {
|
||||
if (scores.containsKey(id)) {
|
||||
return scores.get(id).getScore();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void removeScore(String id) {
|
||||
if (scores.containsKey(id)) {
|
||||
scores.get(id).setUpdateType(UpdateType.REMOVE);
|
||||
Score stored = scores.get(id);
|
||||
if (stored != null) {
|
||||
stored.setUpdateType(UpdateType.REMOVE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,6 +151,7 @@ public class Objective {
|
|||
public void setActive(ScoreboardPosition displaySlot) {
|
||||
if (!active) {
|
||||
active = true;
|
||||
this.displaySlot = correctDisplaySlot(displaySlot);
|
||||
displaySlotName = translateDisplaySlot(displaySlot);
|
||||
}
|
||||
}
|
||||
|
@ -136,15 +159,4 @@ public class Objective {
|
|||
public void removed() {
|
||||
scores = null;
|
||||
}
|
||||
|
||||
private static String translateDisplaySlot(ScoreboardPosition displaySlot) {
|
||||
switch (displaySlot) {
|
||||
case BELOW_NAME:
|
||||
return "belowname";
|
||||
case PLAYER_LIST:
|
||||
return "list";
|
||||
default:
|
||||
return "sidebar";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,60 +27,107 @@ package org.geysermc.connector.scoreboard;
|
|||
|
||||
import com.nukkitx.protocol.bedrock.data.ScoreInfo;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Getter
|
||||
@Accessors(chain = true)
|
||||
public class Score {
|
||||
private final Objective objective;
|
||||
private ScoreInfo cachedInfo;
|
||||
public final class Score {
|
||||
private final long id;
|
||||
|
||||
@Setter
|
||||
private UpdateType updateType = UpdateType.ADD;
|
||||
private final String name;
|
||||
private Team team;
|
||||
private int score;
|
||||
@Setter
|
||||
private int oldScore = Integer.MIN_VALUE;
|
||||
private ScoreInfo cachedInfo;
|
||||
|
||||
public Score(Objective objective, String name) {
|
||||
this.id = objective.getScoreboard().getNextId().getAndIncrement();
|
||||
this.objective = objective;
|
||||
private ScoreData currentData;
|
||||
private ScoreData cachedData;
|
||||
|
||||
public Score(long id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.currentData = new ScoreData();
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
Team team = cachedData.team;
|
||||
if (team != null) {
|
||||
return team.getPrefix() + name + team.getSuffix();
|
||||
return team.getDisplayName(name);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
public Score setScore(int score) {
|
||||
this.score = score;
|
||||
updateType = UpdateType.UPDATE;
|
||||
currentData.score = score;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Team getTeam() {
|
||||
return currentData.team;
|
||||
}
|
||||
|
||||
public Score setTeam(Team team) {
|
||||
if (this.team != null && team != null) {
|
||||
if (!this.team.equals(team)) {
|
||||
this.team = team;
|
||||
updateType = UpdateType.UPDATE;
|
||||
if (currentData.team != null && team != null) {
|
||||
if (!currentData.team.equals(team)) {
|
||||
currentData.team = team;
|
||||
currentData.updateType = UpdateType.UPDATE;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
// simplified from (this.team != null && team == null) || (this.team == null && team != null)
|
||||
if (this.team != null || team != null) {
|
||||
this.team = team;
|
||||
updateType = UpdateType.UPDATE;
|
||||
if (currentData.team != null || team != null) {
|
||||
currentData.team = team;
|
||||
currentData.updateType = UpdateType.UPDATE;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public void update() {
|
||||
cachedInfo = new ScoreInfo(id, objective.getObjectiveName(), score, getDisplayName());
|
||||
public UpdateType getUpdateType() {
|
||||
return cachedData != null ? cachedData.updateType : currentData.updateType;
|
||||
}
|
||||
|
||||
public Score setUpdateType(UpdateType updateType) {
|
||||
if (updateType != UpdateType.NOTHING) {
|
||||
currentData.updateTime = System.currentTimeMillis();
|
||||
}
|
||||
currentData.updateType = updateType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean shouldUpdate() {
|
||||
return cachedData == null || currentData.updateTime > cachedData.updateTime ||
|
||||
(currentData.team != null && currentData.team.shouldUpdate());
|
||||
}
|
||||
|
||||
public void update(String objectiveName) {
|
||||
if (cachedData == null) {
|
||||
cachedData = new ScoreData();
|
||||
cachedData.updateType = UpdateType.ADD;
|
||||
if (currentData.updateType == UpdateType.REMOVE) {
|
||||
cachedData.updateType = UpdateType.REMOVE;
|
||||
}
|
||||
} else {
|
||||
cachedData.updateType = currentData.updateType;
|
||||
}
|
||||
|
||||
cachedData.updateTime = currentData.updateTime;
|
||||
cachedData.team = currentData.team;
|
||||
cachedData.score = currentData.score;
|
||||
|
||||
String name = this.name;
|
||||
if (cachedData.team != null) {
|
||||
cachedData.team.prepareUpdate();
|
||||
name = cachedData.team.getDisplayName(name);
|
||||
}
|
||||
cachedInfo = new ScoreInfo(id, objectiveName, cachedData.score, name);
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static final class ScoreData {
|
||||
protected UpdateType updateType;
|
||||
protected long updateTime;
|
||||
|
||||
private Team team;
|
||||
private int score;
|
||||
|
||||
protected ScoreData() {
|
||||
updateType = UpdateType.ADD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ import java.util.concurrent.atomic.AtomicLong;
|
|||
import static org.geysermc.connector.scoreboard.UpdateType.*;
|
||||
|
||||
@Getter
|
||||
public class Scoreboard {
|
||||
public final class Scoreboard {
|
||||
private final GeyserSession session;
|
||||
private final GeyserLogger logger;
|
||||
private final AtomicLong nextId = new AtomicLong(0);
|
||||
|
@ -51,7 +51,8 @@ public class Scoreboard {
|
|||
private final Map<String, Objective> objectives = new ConcurrentHashMap<>();
|
||||
private final Map<String, Team> teams = new HashMap<>();
|
||||
|
||||
private int lastScoreCount = 0;
|
||||
private int lastAddScoreCount = 0;
|
||||
private int lastRemoveScoreCount = 0;
|
||||
|
||||
public Scoreboard(GeyserSession session) {
|
||||
this.session = session;
|
||||
|
@ -59,19 +60,21 @@ public class Scoreboard {
|
|||
}
|
||||
|
||||
public Objective registerNewObjective(String objectiveId, boolean active) {
|
||||
if (active || objectives.containsKey(objectiveId)) {
|
||||
return objectives.get(objectiveId);
|
||||
Objective objective = objectives.get(objectiveId);
|
||||
if (active || objective != null) {
|
||||
return objective;
|
||||
}
|
||||
Objective objective = new Objective(this, objectiveId);
|
||||
objective = new Objective(this, objectiveId);
|
||||
objectives.put(objectiveId, objective);
|
||||
return objective;
|
||||
}
|
||||
|
||||
public Objective registerNewObjective(String objectiveId, ScoreboardPosition displaySlot) {
|
||||
public Objective displayObjective(String objectiveId, ScoreboardPosition displaySlot) {
|
||||
Objective objective = objectives.get(objectiveId);
|
||||
if (objective != null) {
|
||||
if (!objective.isActive()) {
|
||||
objective.setActive(displaySlot);
|
||||
removeOldObjectives(objective);
|
||||
return objective;
|
||||
}
|
||||
despawnObjective(objective);
|
||||
|
@ -79,9 +82,21 @@ public class Scoreboard {
|
|||
|
||||
objective = new Objective(this, objectiveId, displaySlot, "unknown", 0);
|
||||
objectives.put(objectiveId, objective);
|
||||
removeOldObjectives(objective);
|
||||
return objective;
|
||||
}
|
||||
|
||||
private void removeOldObjectives(Objective newObjective) {
|
||||
for (Objective next : objectives.values()) {
|
||||
if (next.getId() == newObjective.getId()) {
|
||||
continue;
|
||||
}
|
||||
if (next.getDisplaySlot() == newObjective.getDisplaySlot()) {
|
||||
next.setUpdateType(REMOVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Team registerNewTeam(String teamName, Set<String> players) {
|
||||
Team team = teams.get(teamName);
|
||||
if (team != null) {
|
||||
|
@ -89,7 +104,7 @@ public class Scoreboard {
|
|||
return team;
|
||||
}
|
||||
|
||||
team = new Team(this, teamName).setEntities(players);
|
||||
team = new Team(this, teamName).addEntities(players);
|
||||
teams.put(teamName, team);
|
||||
return team;
|
||||
}
|
||||
|
@ -117,8 +132,9 @@ public class Scoreboard {
|
|||
}
|
||||
|
||||
public void onUpdate() {
|
||||
List<ScoreInfo> addScores = new ArrayList<>(getLastScoreCount());
|
||||
List<ScoreInfo> removeScores = new ArrayList<>(getLastScoreCount());
|
||||
List<ScoreInfo> addScores = new ArrayList<>(getLastAddScoreCount());
|
||||
List<ScoreInfo> removeScores = new ArrayList<>(getLastRemoveScoreCount());
|
||||
List<Objective> removedObjectives = new ArrayList<>();
|
||||
|
||||
for (Objective objective : objectives.values()) {
|
||||
if (!objective.isActive()) {
|
||||
|
@ -129,65 +145,58 @@ public class Scoreboard {
|
|||
// hearts can't hold teams, so we treat them differently
|
||||
if (objective.getType() == 1) {
|
||||
for (Score score : objective.getScores().values()) {
|
||||
if (score.getUpdateType() == NOTHING) {
|
||||
continue;
|
||||
}
|
||||
boolean update = score.shouldUpdate();
|
||||
|
||||
boolean update = score.getUpdateType() == UPDATE;
|
||||
if (update) {
|
||||
score.update();
|
||||
score.update(objective.getObjectiveName());
|
||||
}
|
||||
|
||||
if (score.getUpdateType() == ADD || update) {
|
||||
if (score.getUpdateType() != REMOVE && update) {
|
||||
addScores.add(score.getCachedInfo());
|
||||
}
|
||||
if (score.getUpdateType() == REMOVE || update) {
|
||||
if (score.getUpdateType() != ADD && update) {
|
||||
removeScores.add(score.getCachedInfo());
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean globalUpdate = objective.getUpdateType() == UPDATE;
|
||||
boolean globalAdd = objective.getUpdateType() == ADD;
|
||||
boolean globalRemove = objective.getUpdateType() == REMOVE;
|
||||
boolean objectiveUpdate = objective.getUpdateType() == UPDATE;
|
||||
boolean objectiveAdd = objective.getUpdateType() == ADD;
|
||||
boolean objectiveRemove = objective.getUpdateType() == REMOVE;
|
||||
|
||||
for (Score score : objective.getScores().values()) {
|
||||
Team team = score.getTeam();
|
||||
|
||||
boolean add = globalAdd || globalUpdate;
|
||||
boolean remove = globalRemove;
|
||||
boolean teamChanged = false;
|
||||
boolean add = objectiveAdd || objectiveUpdate;
|
||||
boolean remove = false;
|
||||
if (team != null) {
|
||||
if (team.getUpdateType() == REMOVE || !team.hasEntity(score.getName())) {
|
||||
score.setTeam(null);
|
||||
teamChanged = true;
|
||||
add = true;
|
||||
remove = true;
|
||||
}
|
||||
|
||||
teamChanged |= team.getUpdateType() == UPDATE;
|
||||
|
||||
add |= team.getUpdateType() == ADD || team.getUpdateType() == UPDATE;
|
||||
remove |= team.getUpdateType() != NOTHING;
|
||||
}
|
||||
|
||||
add |= score.getUpdateType() == ADD || score.getUpdateType() == UPDATE;
|
||||
remove |= score.getUpdateType() == REMOVE || score.getUpdateType() == UPDATE;
|
||||
add |= score.shouldUpdate();
|
||||
remove |= score.shouldUpdate();
|
||||
|
||||
if (score.getUpdateType() == REMOVE || globalRemove) {
|
||||
if (score.getUpdateType() == REMOVE || objectiveRemove) {
|
||||
add = false;
|
||||
}
|
||||
|
||||
if (score.getUpdateType() == ADD) {
|
||||
if (score.getUpdateType() == ADD || objectiveRemove) {
|
||||
remove = false;
|
||||
}
|
||||
|
||||
if (score.getUpdateType() == ADD || score.getUpdateType() == UPDATE || teamChanged) {
|
||||
score.update();
|
||||
if (score.shouldUpdate()) {
|
||||
score.update(objective.getObjectiveName());
|
||||
}
|
||||
|
||||
if (add) {
|
||||
addScores.add(score.getCachedInfo());
|
||||
}
|
||||
|
||||
if (remove) {
|
||||
removeScores.add(score.getCachedInfo());
|
||||
}
|
||||
|
@ -200,17 +209,17 @@ public class Scoreboard {
|
|||
score.setUpdateType(NOTHING);
|
||||
}
|
||||
|
||||
if (globalRemove || globalUpdate) {
|
||||
if (objectiveRemove) {
|
||||
removedObjectives.add(objective);
|
||||
}
|
||||
|
||||
if (objectiveUpdate) {
|
||||
RemoveObjectivePacket removeObjectivePacket = new RemoveObjectivePacket();
|
||||
removeObjectivePacket.setObjectiveId(objective.getObjectiveName());
|
||||
session.sendUpstreamPacket(removeObjectivePacket);
|
||||
if (globalRemove) {
|
||||
objectives.remove(objective.getObjectiveName()); // now we can deregister
|
||||
objective.removed();
|
||||
}
|
||||
}
|
||||
|
||||
if ((globalAdd || globalUpdate) && !globalRemove) {
|
||||
if ((objectiveAdd || objectiveUpdate) && !objectiveRemove) {
|
||||
SetDisplayObjectivePacket displayObjectivePacket = new SetDisplayObjectivePacket();
|
||||
displayObjectivePacket.setObjectiveId(objective.getObjectiveName());
|
||||
displayObjectivePacket.setDisplayName(objective.getDisplayName());
|
||||
|
@ -223,6 +232,20 @@ public class Scoreboard {
|
|||
objective.setUpdateType(NOTHING);
|
||||
}
|
||||
|
||||
Iterator<Team> teamIterator = teams.values().iterator();
|
||||
while (teamIterator.hasNext()) {
|
||||
Team current = teamIterator.next();
|
||||
|
||||
switch (current.getUpdateType()) {
|
||||
case ADD:
|
||||
case UPDATE:
|
||||
current.markUpdated();
|
||||
break;
|
||||
case REMOVE:
|
||||
teamIterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
if (!removeScores.isEmpty()) {
|
||||
SetScorePacket setScorePacket = new SetScorePacket();
|
||||
setScorePacket.setAction(SetScorePacket.Action.REMOVE);
|
||||
|
@ -237,37 +260,27 @@ public class Scoreboard {
|
|||
session.sendUpstreamPacket(setScorePacket);
|
||||
}
|
||||
|
||||
lastScoreCount = addScores.size();
|
||||
// prevents crashes in some cases
|
||||
for (Objective objective : removedObjectives) {
|
||||
despawnObjective(objective);
|
||||
}
|
||||
|
||||
lastAddScoreCount = addScores.size();
|
||||
lastRemoveScoreCount = removeScores.size();
|
||||
}
|
||||
|
||||
public void despawnObjective(Objective objective) {
|
||||
objectives.remove(objective.getObjectiveName());
|
||||
objective.removed();
|
||||
|
||||
RemoveObjectivePacket removeObjectivePacket = new RemoveObjectivePacket();
|
||||
removeObjectivePacket.setObjectiveId(objective.getObjectiveName());
|
||||
session.sendUpstreamPacket(removeObjectivePacket);
|
||||
objectives.remove(objective.getDisplayName());
|
||||
|
||||
List<ScoreInfo> toRemove = new ArrayList<>();
|
||||
for (String identifier : objective.getScores().keySet()) {
|
||||
Score score = objective.getScores().get(identifier);
|
||||
toRemove.add(new ScoreInfo(
|
||||
score.getId(), score.getObjective().getObjectiveName(),
|
||||
0, ""
|
||||
));
|
||||
}
|
||||
|
||||
objective.removed();
|
||||
|
||||
if (!toRemove.isEmpty()) {
|
||||
SetScorePacket setScorePacket = new SetScorePacket();
|
||||
setScorePacket.setAction(SetScorePacket.Action.REMOVE);
|
||||
setScorePacket.setInfos(toRemove);
|
||||
session.sendUpstreamPacket(setScorePacket);
|
||||
}
|
||||
}
|
||||
|
||||
public Team getTeamFor(String entity) {
|
||||
for (Team team : teams.values()) {
|
||||
if (team.getEntities().contains(entity)) {
|
||||
if (team.hasEntity(entity)) {
|
||||
return team;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ package org.geysermc.connector.scoreboard;
|
|||
import com.github.steveice10.mc.protocol.data.game.scoreboard.NameTagVisibility;
|
||||
import com.github.steveice10.mc.protocol.data.game.scoreboard.TeamColor;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
@ -36,62 +37,90 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Getter @Setter
|
||||
@Getter
|
||||
@Accessors(chain = true)
|
||||
public class Team {
|
||||
public final class Team {
|
||||
private final Scoreboard scoreboard;
|
||||
private final String id;
|
||||
|
||||
private UpdateType updateType = UpdateType.ADD;
|
||||
private String name;
|
||||
@Getter(AccessLevel.NONE)
|
||||
private final Set<String> entities;
|
||||
@Setter private NameTagVisibility nameTagVisibility;
|
||||
@Setter private TeamColor color;
|
||||
|
||||
private NameTagVisibility nameTagVisibility;
|
||||
private String prefix;
|
||||
private TeamColor color;
|
||||
private String suffix;
|
||||
private Set<String> entities = new ObjectOpenHashSet<>();
|
||||
private TeamData currentData;
|
||||
private TeamData cachedData;
|
||||
|
||||
private boolean updating;
|
||||
|
||||
public Team(Scoreboard scoreboard, String id) {
|
||||
this.scoreboard = scoreboard;
|
||||
this.id = id;
|
||||
currentData = new TeamData();
|
||||
entities = new ObjectOpenHashSet<>();
|
||||
}
|
||||
|
||||
public void addEntities(String... names) {
|
||||
List<String> added = new ArrayList<>();
|
||||
for (String name : names) {
|
||||
if (entities.add(name)) {
|
||||
added.add(name);
|
||||
}
|
||||
private void checkAddedEntities(List<String> added) {
|
||||
if (added.size() == 0) {
|
||||
return;
|
||||
}
|
||||
setUpdateType(UpdateType.UPDATE);
|
||||
// we don't have to change the updateType,
|
||||
// because the scores itself need updating, not the team
|
||||
for (Objective objective : scoreboard.getObjectives().values()) {
|
||||
for (Score score : objective.getScores().values()) {
|
||||
if (added.contains(score.getName())) {
|
||||
for (String addedEntity : added) {
|
||||
Score score = objective.getScores().get(addedEntity);
|
||||
if (score != null) {
|
||||
score.setTeam(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Team addEntities(String... names) {
|
||||
List<String> added = new ArrayList<>();
|
||||
for (String name : names) {
|
||||
if (entities.add(name)) {
|
||||
added.add(name);
|
||||
}
|
||||
}
|
||||
checkAddedEntities(added);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Team addEntities(Set<String> names) {
|
||||
List<String> added = new ArrayList<>();
|
||||
for (String name : names) {
|
||||
if (entities.add(name)) {
|
||||
added.add(name);
|
||||
}
|
||||
}
|
||||
checkAddedEntities(added);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void removeEntities(String... names) {
|
||||
for (String name : names) {
|
||||
entities.remove(name);
|
||||
}
|
||||
setUpdateType(UpdateType.UPDATE);
|
||||
}
|
||||
|
||||
public boolean hasEntity(String name) {
|
||||
return entities.contains(name);
|
||||
}
|
||||
|
||||
public Team setName(String name) {
|
||||
currentData.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Team setPrefix(String prefix) {
|
||||
// replace "null" to an empty string,
|
||||
// we do this here to improve the performance of Score#getDisplayName
|
||||
if (prefix.length() == 4 && "null".equals(prefix)) {
|
||||
this.prefix = "";
|
||||
currentData.prefix = "";
|
||||
return this;
|
||||
}
|
||||
this.prefix = prefix;
|
||||
currentData.prefix = prefix;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -99,15 +128,92 @@ public class Team {
|
|||
// replace "null" to an empty string,
|
||||
// we do this here to improve the performance of Score#getDisplayName
|
||||
if (suffix.length() == 4 && "null".equals(suffix)) {
|
||||
this.suffix = "";
|
||||
currentData.suffix = "";
|
||||
return this;
|
||||
}
|
||||
this.suffix = suffix;
|
||||
currentData.suffix = suffix;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getDisplayName(String score) {
|
||||
return cachedData != null ?
|
||||
cachedData.getDisplayName(score) :
|
||||
currentData.getDisplayName(score);
|
||||
}
|
||||
|
||||
public void markUpdated() {
|
||||
updating = false;
|
||||
}
|
||||
|
||||
public boolean shouldUpdate() {
|
||||
return updating || cachedData == null || currentData.updateTime > cachedData.updateTime;
|
||||
}
|
||||
|
||||
public void prepareUpdate() {
|
||||
if (updating) {
|
||||
return;
|
||||
}
|
||||
updating = true;
|
||||
|
||||
if (cachedData == null) {
|
||||
cachedData = new TeamData();
|
||||
cachedData.updateType = currentData.updateType != UpdateType.REMOVE ? UpdateType.ADD : UpdateType.REMOVE;
|
||||
} else {
|
||||
cachedData.updateType = currentData.updateType;
|
||||
}
|
||||
|
||||
cachedData.updateTime = currentData.updateTime;
|
||||
cachedData.name = currentData.name;
|
||||
cachedData.prefix = currentData.prefix;
|
||||
cachedData.suffix = currentData.suffix;
|
||||
}
|
||||
|
||||
public UpdateType getUpdateType() {
|
||||
return cachedData != null ? cachedData.updateType : currentData.updateType;
|
||||
}
|
||||
|
||||
public Team setUpdateType(UpdateType updateType) {
|
||||
if (updateType != UpdateType.NOTHING) {
|
||||
currentData.updateTime = System.currentTimeMillis();
|
||||
}
|
||||
currentData.updateType = updateType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isVisibleFor(String entity) {
|
||||
switch (nameTagVisibility) {
|
||||
case HIDE_FOR_OTHER_TEAMS:
|
||||
return hasEntity(entity);
|
||||
case HIDE_FOR_OWN_TEAM:
|
||||
return !hasEntity(entity);
|
||||
case ALWAYS:
|
||||
return true;
|
||||
case NEVER:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id.hashCode();
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static final class TeamData {
|
||||
protected UpdateType updateType;
|
||||
protected long updateTime;
|
||||
|
||||
protected String name;
|
||||
protected String prefix;
|
||||
protected String suffix;
|
||||
|
||||
protected TeamData() {
|
||||
updateType = UpdateType.ADD;
|
||||
}
|
||||
|
||||
public String getDisplayName(String score) {
|
||||
return prefix + score + suffix;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue