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.auth.data.GameProfile;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
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.mc.protocol.data.message.TextMessage;
|
||||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
@ -235,18 +234,12 @@ public class PlayerEntity extends LivingEntity {
|
||||||
}
|
}
|
||||||
Team team = session.getWorldCache().getScoreboard().getTeamFor(username);
|
Team team = session.getWorldCache().getScoreboard().getTeamFor(username);
|
||||||
if (team != null) {
|
if (team != null) {
|
||||||
// Cover different visibility settings
|
String displayName = "";
|
||||||
if (team.getNameTagVisibility() == NameTagVisibility.NEVER) {
|
if (team.isVisibleFor(session.getPlayerEntity().getUsername())) {
|
||||||
metadata.put(EntityData.NAMETAG, "");
|
displayName = MessageUtils.toChatColor(team.getColor()) + username;
|
||||||
} else if (team.getNameTagVisibility() == NameTagVisibility.HIDE_FOR_OTHER_TEAMS &&
|
displayName = team.getCurrentData().getDisplayName(displayName);
|
||||||
!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());
|
|
||||||
}
|
}
|
||||||
|
metadata.put(EntityData.NAMETAG, displayName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,7 @@ public class JavaDisplayScoreboardTranslator extends PacketTranslator<ServerDisp
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(ServerDisplayScoreboardPacket packet, GeyserSession session) {
|
public void translate(ServerDisplayScoreboardPacket packet, GeyserSession session) {
|
||||||
session.getWorldCache().getScoreboard().registerNewObjective(
|
session.getWorldCache().getScoreboard()
|
||||||
packet.getName(), packet.getPosition()
|
.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.network.translators.Translator;
|
||||||
import org.geysermc.connector.scoreboard.Objective;
|
import org.geysermc.connector.scoreboard.Objective;
|
||||||
import org.geysermc.connector.scoreboard.Scoreboard;
|
import org.geysermc.connector.scoreboard.Scoreboard;
|
||||||
|
import org.geysermc.connector.scoreboard.ScoreboardUpdater;
|
||||||
import org.geysermc.connector.utils.MessageUtils;
|
import org.geysermc.connector.utils.MessageUtils;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.data.game.scoreboard.ObjectiveAction;
|
import com.github.steveice10.mc.protocol.data.game.scoreboard.ObjectiveAction;
|
||||||
|
@ -41,8 +42,10 @@ public class JavaScoreboardObjectiveTranslator extends PacketTranslator<ServerSc
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(ServerScoreboardObjectivePacket packet, GeyserSession session) {
|
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());
|
Objective objective = scoreboard.getObjective(packet.getName());
|
||||||
|
int pps = worldCache.increaseAndGetScoreboardPacketsPerSecond();
|
||||||
|
|
||||||
if (objective == null && packet.getAction() != ObjectiveAction.REMOVE) {
|
if (objective == null && packet.getAction() != ObjectiveAction.REMOVE) {
|
||||||
objective = scoreboard.registerNewObjective(packet.getName(), false);
|
objective = scoreboard.registerNewObjective(packet.getName(), false);
|
||||||
|
@ -51,15 +54,21 @@ public class JavaScoreboardObjectiveTranslator extends PacketTranslator<ServerSc
|
||||||
switch (packet.getAction()) {
|
switch (packet.getAction()) {
|
||||||
case ADD:
|
case ADD:
|
||||||
case UPDATE:
|
case UPDATE:
|
||||||
objective.setDisplayName(MessageUtils.getBedrockMessage(packet.getDisplayName()));
|
objective.setDisplayName(MessageUtils.getBedrockMessage(packet.getDisplayName()))
|
||||||
objective.setType(packet.getType().ordinal());
|
.setType(packet.getType().ordinal());
|
||||||
break;
|
break;
|
||||||
case REMOVE:
|
case REMOVE:
|
||||||
scoreboard.unregisterObjective(packet.getName());
|
scoreboard.unregisterObjective(packet.getName());
|
||||||
break;
|
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();
|
scoreboard.onUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,14 +33,16 @@ import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public class Objective {
|
public final class Objective {
|
||||||
private final Scoreboard scoreboard;
|
private final Scoreboard scoreboard;
|
||||||
private final long id;
|
private final long id;
|
||||||
private boolean active = true;
|
private boolean active = true;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
private UpdateType updateType = UpdateType.ADD;
|
private UpdateType updateType = UpdateType.ADD;
|
||||||
|
|
||||||
private String objectiveName;
|
private String objectiveName;
|
||||||
|
private ScoreboardPosition displaySlot;
|
||||||
private String displaySlotName;
|
private String displaySlotName;
|
||||||
private String displayName = "unknown";
|
private String displayName = "unknown";
|
||||||
private int type = 0; // 0 = integer, 1 = heart
|
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) {
|
public Objective(Scoreboard scoreboard, String objectiveName, ScoreboardPosition displaySlot, String displayName, int type) {
|
||||||
this(scoreboard);
|
this(scoreboard);
|
||||||
this.objectiveName = objectiveName;
|
this.objectiveName = objectiveName;
|
||||||
|
this.displaySlot = correctDisplaySlot(displaySlot);
|
||||||
this.displaySlotName = translateDisplaySlot(displaySlot);
|
this.displaySlotName = translateDisplaySlot(displaySlot);
|
||||||
this.displayName = displayName;
|
this.displayName = displayName;
|
||||||
this.type = type;
|
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) {
|
public void registerScore(String id, int score) {
|
||||||
if (!scores.containsKey(id)) {
|
if (!scores.containsKey(id)) {
|
||||||
Score score1 = new Score(this, id)
|
long scoreId = scoreboard.getNextId().getAndIncrement();
|
||||||
|
Score scoreObject = new Score(scoreId, id)
|
||||||
.setScore(score)
|
.setScore(score)
|
||||||
.setTeam(scoreboard.getTeamFor(id))
|
.setTeam(scoreboard.getTeamFor(id))
|
||||||
.setUpdateType(UpdateType.ADD);
|
.setUpdateType(UpdateType.ADD);
|
||||||
scores.put(id, score1);
|
scores.put(id, scoreObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setScore(String id, int score) {
|
public void setScore(String id, int score) {
|
||||||
if (scores.containsKey(id)) {
|
Score stored = scores.get(id);
|
||||||
scores.get(id).setScore(score);
|
if (stored != null) {
|
||||||
|
stored.setScore(score)
|
||||||
|
.setUpdateType(UpdateType.UPDATE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
registerScore(id, score);
|
registerScore(id, score);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getScore(String id) {
|
|
||||||
if (scores.containsKey(id)) {
|
|
||||||
return scores.get(id).getScore();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeScore(String id) {
|
public void removeScore(String id) {
|
||||||
if (scores.containsKey(id)) {
|
Score stored = scores.get(id);
|
||||||
scores.get(id).setUpdateType(UpdateType.REMOVE);
|
if (stored != null) {
|
||||||
|
stored.setUpdateType(UpdateType.REMOVE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,6 +151,7 @@ public class Objective {
|
||||||
public void setActive(ScoreboardPosition displaySlot) {
|
public void setActive(ScoreboardPosition displaySlot) {
|
||||||
if (!active) {
|
if (!active) {
|
||||||
active = true;
|
active = true;
|
||||||
|
this.displaySlot = correctDisplaySlot(displaySlot);
|
||||||
displaySlotName = translateDisplaySlot(displaySlot);
|
displaySlotName = translateDisplaySlot(displaySlot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,15 +159,4 @@ public class Objective {
|
||||||
public void removed() {
|
public void removed() {
|
||||||
scores = null;
|
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 com.nukkitx.protocol.bedrock.data.ScoreInfo;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
public class Score {
|
public final class Score {
|
||||||
private final Objective objective;
|
|
||||||
private ScoreInfo cachedInfo;
|
|
||||||
private final long id;
|
private final long id;
|
||||||
|
|
||||||
@Setter
|
|
||||||
private UpdateType updateType = UpdateType.ADD;
|
|
||||||
private final String name;
|
private final String name;
|
||||||
private Team team;
|
private ScoreInfo cachedInfo;
|
||||||
private int score;
|
|
||||||
@Setter
|
|
||||||
private int oldScore = Integer.MIN_VALUE;
|
|
||||||
|
|
||||||
public Score(Objective objective, String name) {
|
private ScoreData currentData;
|
||||||
this.id = objective.getScoreboard().getNextId().getAndIncrement();
|
private ScoreData cachedData;
|
||||||
this.objective = objective;
|
|
||||||
|
public Score(long id, String name) {
|
||||||
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
this.currentData = new ScoreData();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDisplayName() {
|
public String getDisplayName() {
|
||||||
|
Team team = cachedData.team;
|
||||||
if (team != null) {
|
if (team != null) {
|
||||||
return team.getPrefix() + name + team.getSuffix();
|
return team.getDisplayName(name);
|
||||||
}
|
}
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Score setScore(int score) {
|
public Score setScore(int score) {
|
||||||
this.score = score;
|
currentData.score = score;
|
||||||
updateType = UpdateType.UPDATE;
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Team getTeam() {
|
||||||
|
return currentData.team;
|
||||||
|
}
|
||||||
|
|
||||||
public Score setTeam(Team team) {
|
public Score setTeam(Team team) {
|
||||||
if (this.team != null && team != null) {
|
if (currentData.team != null && team != null) {
|
||||||
if (!this.team.equals(team)) {
|
if (!currentData.team.equals(team)) {
|
||||||
this.team = team;
|
currentData.team = team;
|
||||||
updateType = UpdateType.UPDATE;
|
currentData.updateType = UpdateType.UPDATE;
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
// simplified from (this.team != null && team == null) || (this.team == null && team != null)
|
// simplified from (this.team != null && team == null) || (this.team == null && team != null)
|
||||||
if (this.team != null || team != null) {
|
if (currentData.team != null || team != null) {
|
||||||
this.team = team;
|
currentData.team = team;
|
||||||
updateType = UpdateType.UPDATE;
|
currentData.updateType = UpdateType.UPDATE;
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update() {
|
public UpdateType getUpdateType() {
|
||||||
cachedInfo = new ScoreInfo(id, objective.getObjectiveName(), score, getDisplayName());
|
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.*;
|
import static org.geysermc.connector.scoreboard.UpdateType.*;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public class Scoreboard {
|
public final class Scoreboard {
|
||||||
private final GeyserSession session;
|
private final GeyserSession session;
|
||||||
private final GeyserLogger logger;
|
private final GeyserLogger logger;
|
||||||
private final AtomicLong nextId = new AtomicLong(0);
|
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, Objective> objectives = new ConcurrentHashMap<>();
|
||||||
private final Map<String, Team> teams = new HashMap<>();
|
private final Map<String, Team> teams = new HashMap<>();
|
||||||
|
|
||||||
private int lastScoreCount = 0;
|
private int lastAddScoreCount = 0;
|
||||||
|
private int lastRemoveScoreCount = 0;
|
||||||
|
|
||||||
public Scoreboard(GeyserSession session) {
|
public Scoreboard(GeyserSession session) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
|
@ -59,19 +60,21 @@ public class Scoreboard {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Objective registerNewObjective(String objectiveId, boolean active) {
|
public Objective registerNewObjective(String objectiveId, boolean active) {
|
||||||
if (active || objectives.containsKey(objectiveId)) {
|
Objective objective = objectives.get(objectiveId);
|
||||||
return objectives.get(objectiveId);
|
if (active || objective != null) {
|
||||||
|
return objective;
|
||||||
}
|
}
|
||||||
Objective objective = new Objective(this, objectiveId);
|
objective = new Objective(this, objectiveId);
|
||||||
objectives.put(objectiveId, objective);
|
objectives.put(objectiveId, objective);
|
||||||
return objective;
|
return objective;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Objective registerNewObjective(String objectiveId, ScoreboardPosition displaySlot) {
|
public Objective displayObjective(String objectiveId, ScoreboardPosition displaySlot) {
|
||||||
Objective objective = objectives.get(objectiveId);
|
Objective objective = objectives.get(objectiveId);
|
||||||
if (objective != null) {
|
if (objective != null) {
|
||||||
if (!objective.isActive()) {
|
if (!objective.isActive()) {
|
||||||
objective.setActive(displaySlot);
|
objective.setActive(displaySlot);
|
||||||
|
removeOldObjectives(objective);
|
||||||
return objective;
|
return objective;
|
||||||
}
|
}
|
||||||
despawnObjective(objective);
|
despawnObjective(objective);
|
||||||
|
@ -79,9 +82,21 @@ public class Scoreboard {
|
||||||
|
|
||||||
objective = new Objective(this, objectiveId, displaySlot, "unknown", 0);
|
objective = new Objective(this, objectiveId, displaySlot, "unknown", 0);
|
||||||
objectives.put(objectiveId, objective);
|
objectives.put(objectiveId, objective);
|
||||||
|
removeOldObjectives(objective);
|
||||||
return 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) {
|
public Team registerNewTeam(String teamName, Set<String> players) {
|
||||||
Team team = teams.get(teamName);
|
Team team = teams.get(teamName);
|
||||||
if (team != null) {
|
if (team != null) {
|
||||||
|
@ -89,7 +104,7 @@ public class Scoreboard {
|
||||||
return team;
|
return team;
|
||||||
}
|
}
|
||||||
|
|
||||||
team = new Team(this, teamName).setEntities(players);
|
team = new Team(this, teamName).addEntities(players);
|
||||||
teams.put(teamName, team);
|
teams.put(teamName, team);
|
||||||
return team;
|
return team;
|
||||||
}
|
}
|
||||||
|
@ -117,8 +132,9 @@ public class Scoreboard {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onUpdate() {
|
public void onUpdate() {
|
||||||
List<ScoreInfo> addScores = new ArrayList<>(getLastScoreCount());
|
List<ScoreInfo> addScores = new ArrayList<>(getLastAddScoreCount());
|
||||||
List<ScoreInfo> removeScores = new ArrayList<>(getLastScoreCount());
|
List<ScoreInfo> removeScores = new ArrayList<>(getLastRemoveScoreCount());
|
||||||
|
List<Objective> removedObjectives = new ArrayList<>();
|
||||||
|
|
||||||
for (Objective objective : objectives.values()) {
|
for (Objective objective : objectives.values()) {
|
||||||
if (!objective.isActive()) {
|
if (!objective.isActive()) {
|
||||||
|
@ -129,65 +145,58 @@ public class Scoreboard {
|
||||||
// hearts can't hold teams, so we treat them differently
|
// hearts can't hold teams, so we treat them differently
|
||||||
if (objective.getType() == 1) {
|
if (objective.getType() == 1) {
|
||||||
for (Score score : objective.getScores().values()) {
|
for (Score score : objective.getScores().values()) {
|
||||||
if (score.getUpdateType() == NOTHING) {
|
boolean update = score.shouldUpdate();
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean update = score.getUpdateType() == UPDATE;
|
|
||||||
if (update) {
|
if (update) {
|
||||||
score.update();
|
score.update(objective.getObjectiveName());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (score.getUpdateType() == ADD || update) {
|
if (score.getUpdateType() != REMOVE && update) {
|
||||||
addScores.add(score.getCachedInfo());
|
addScores.add(score.getCachedInfo());
|
||||||
}
|
}
|
||||||
if (score.getUpdateType() == REMOVE || update) {
|
if (score.getUpdateType() != ADD && update) {
|
||||||
removeScores.add(score.getCachedInfo());
|
removeScores.add(score.getCachedInfo());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean globalUpdate = objective.getUpdateType() == UPDATE;
|
boolean objectiveUpdate = objective.getUpdateType() == UPDATE;
|
||||||
boolean globalAdd = objective.getUpdateType() == ADD;
|
boolean objectiveAdd = objective.getUpdateType() == ADD;
|
||||||
boolean globalRemove = objective.getUpdateType() == REMOVE;
|
boolean objectiveRemove = objective.getUpdateType() == REMOVE;
|
||||||
|
|
||||||
for (Score score : objective.getScores().values()) {
|
for (Score score : objective.getScores().values()) {
|
||||||
Team team = score.getTeam();
|
Team team = score.getTeam();
|
||||||
|
|
||||||
boolean add = globalAdd || globalUpdate;
|
boolean add = objectiveAdd || objectiveUpdate;
|
||||||
boolean remove = globalRemove;
|
boolean remove = false;
|
||||||
boolean teamChanged = false;
|
|
||||||
if (team != null) {
|
if (team != null) {
|
||||||
if (team.getUpdateType() == REMOVE || !team.hasEntity(score.getName())) {
|
if (team.getUpdateType() == REMOVE || !team.hasEntity(score.getName())) {
|
||||||
score.setTeam(null);
|
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;
|
add |= score.shouldUpdate();
|
||||||
remove |= score.getUpdateType() == REMOVE || score.getUpdateType() == UPDATE;
|
remove |= score.shouldUpdate();
|
||||||
|
|
||||||
if (score.getUpdateType() == REMOVE || globalRemove) {
|
if (score.getUpdateType() == REMOVE || objectiveRemove) {
|
||||||
add = false;
|
add = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (score.getUpdateType() == ADD) {
|
if (score.getUpdateType() == ADD || objectiveRemove) {
|
||||||
remove = false;
|
remove = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (score.getUpdateType() == ADD || score.getUpdateType() == UPDATE || teamChanged) {
|
if (score.shouldUpdate()) {
|
||||||
score.update();
|
score.update(objective.getObjectiveName());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (add) {
|
if (add) {
|
||||||
addScores.add(score.getCachedInfo());
|
addScores.add(score.getCachedInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remove) {
|
if (remove) {
|
||||||
removeScores.add(score.getCachedInfo());
|
removeScores.add(score.getCachedInfo());
|
||||||
}
|
}
|
||||||
|
@ -200,17 +209,17 @@ public class Scoreboard {
|
||||||
score.setUpdateType(NOTHING);
|
score.setUpdateType(NOTHING);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (globalRemove || globalUpdate) {
|
if (objectiveRemove) {
|
||||||
|
removedObjectives.add(objective);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (objectiveUpdate) {
|
||||||
RemoveObjectivePacket removeObjectivePacket = new RemoveObjectivePacket();
|
RemoveObjectivePacket removeObjectivePacket = new RemoveObjectivePacket();
|
||||||
removeObjectivePacket.setObjectiveId(objective.getObjectiveName());
|
removeObjectivePacket.setObjectiveId(objective.getObjectiveName());
|
||||||
session.sendUpstreamPacket(removeObjectivePacket);
|
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();
|
SetDisplayObjectivePacket displayObjectivePacket = new SetDisplayObjectivePacket();
|
||||||
displayObjectivePacket.setObjectiveId(objective.getObjectiveName());
|
displayObjectivePacket.setObjectiveId(objective.getObjectiveName());
|
||||||
displayObjectivePacket.setDisplayName(objective.getDisplayName());
|
displayObjectivePacket.setDisplayName(objective.getDisplayName());
|
||||||
|
@ -223,6 +232,20 @@ public class Scoreboard {
|
||||||
objective.setUpdateType(NOTHING);
|
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()) {
|
if (!removeScores.isEmpty()) {
|
||||||
SetScorePacket setScorePacket = new SetScorePacket();
|
SetScorePacket setScorePacket = new SetScorePacket();
|
||||||
setScorePacket.setAction(SetScorePacket.Action.REMOVE);
|
setScorePacket.setAction(SetScorePacket.Action.REMOVE);
|
||||||
|
@ -237,37 +260,27 @@ public class Scoreboard {
|
||||||
session.sendUpstreamPacket(setScorePacket);
|
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) {
|
public void despawnObjective(Objective objective) {
|
||||||
|
objectives.remove(objective.getObjectiveName());
|
||||||
|
objective.removed();
|
||||||
|
|
||||||
RemoveObjectivePacket removeObjectivePacket = new RemoveObjectivePacket();
|
RemoveObjectivePacket removeObjectivePacket = new RemoveObjectivePacket();
|
||||||
removeObjectivePacket.setObjectiveId(objective.getObjectiveName());
|
removeObjectivePacket.setObjectiveId(objective.getObjectiveName());
|
||||||
session.sendUpstreamPacket(removeObjectivePacket);
|
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) {
|
public Team getTeamFor(String entity) {
|
||||||
for (Team team : teams.values()) {
|
for (Team team : teams.values()) {
|
||||||
if (team.getEntities().contains(entity)) {
|
if (team.hasEntity(entity)) {
|
||||||
return team;
|
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.NameTagVisibility;
|
||||||
import com.github.steveice10.mc.protocol.data.game.scoreboard.TeamColor;
|
import com.github.steveice10.mc.protocol.data.game.scoreboard.TeamColor;
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||||
|
import lombok.AccessLevel;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
@ -36,62 +37,90 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@Getter @Setter
|
@Getter
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
public class Team {
|
public final class Team {
|
||||||
private final Scoreboard scoreboard;
|
private final Scoreboard scoreboard;
|
||||||
private final String id;
|
private final String id;
|
||||||
|
|
||||||
private UpdateType updateType = UpdateType.ADD;
|
@Getter(AccessLevel.NONE)
|
||||||
private String name;
|
private final Set<String> entities;
|
||||||
|
@Setter private NameTagVisibility nameTagVisibility;
|
||||||
|
@Setter private TeamColor color;
|
||||||
|
|
||||||
private NameTagVisibility nameTagVisibility;
|
private TeamData currentData;
|
||||||
private String prefix;
|
private TeamData cachedData;
|
||||||
private TeamColor color;
|
|
||||||
private String suffix;
|
private boolean updating;
|
||||||
private Set<String> entities = new ObjectOpenHashSet<>();
|
|
||||||
|
|
||||||
public Team(Scoreboard scoreboard, String id) {
|
public Team(Scoreboard scoreboard, String id) {
|
||||||
this.scoreboard = scoreboard;
|
this.scoreboard = scoreboard;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
currentData = new TeamData();
|
||||||
|
entities = new ObjectOpenHashSet<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addEntities(String... names) {
|
private void checkAddedEntities(List<String> added) {
|
||||||
List<String> added = new ArrayList<>();
|
if (added.size() == 0) {
|
||||||
for (String name : names) {
|
return;
|
||||||
if (entities.add(name)) {
|
|
||||||
added.add(name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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 (Objective objective : scoreboard.getObjectives().values()) {
|
||||||
for (Score score : objective.getScores().values()) {
|
for (String addedEntity : added) {
|
||||||
if (added.contains(score.getName())) {
|
Score score = objective.getScores().get(addedEntity);
|
||||||
|
if (score != null) {
|
||||||
score.setTeam(this);
|
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) {
|
public void removeEntities(String... names) {
|
||||||
for (String name : names) {
|
for (String name : names) {
|
||||||
entities.remove(name);
|
entities.remove(name);
|
||||||
}
|
}
|
||||||
setUpdateType(UpdateType.UPDATE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasEntity(String name) {
|
public boolean hasEntity(String name) {
|
||||||
return entities.contains(name);
|
return entities.contains(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Team setName(String name) {
|
||||||
|
currentData.name = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public Team setPrefix(String prefix) {
|
public Team setPrefix(String prefix) {
|
||||||
// replace "null" to an empty string,
|
// replace "null" to an empty string,
|
||||||
// we do this here to improve the performance of Score#getDisplayName
|
// we do this here to improve the performance of Score#getDisplayName
|
||||||
if (prefix.length() == 4 && "null".equals(prefix)) {
|
if (prefix.length() == 4 && "null".equals(prefix)) {
|
||||||
this.prefix = "";
|
currentData.prefix = "";
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
this.prefix = prefix;
|
currentData.prefix = prefix;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,15 +128,92 @@ public class Team {
|
||||||
// replace "null" to an empty string,
|
// replace "null" to an empty string,
|
||||||
// we do this here to improve the performance of Score#getDisplayName
|
// we do this here to improve the performance of Score#getDisplayName
|
||||||
if (suffix.length() == 4 && "null".equals(suffix)) {
|
if (suffix.length() == 4 && "null".equals(suffix)) {
|
||||||
this.suffix = "";
|
currentData.suffix = "";
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
this.suffix = suffix;
|
currentData.suffix = suffix;
|
||||||
return this;
|
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
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return id.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