diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 22d20355b..1d7dfe882 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -297,7 +297,7 @@ public class GeyserSession implements Player { startGamePacket.setCurrentTick(0); startGamePacket.setEnchantmentSeed(0); startGamePacket.setMultiplayerCorrelationId(""); - startGamePacket.setCachedPalette(Toolbox.CACHED_PALLETE.copy()); + startGamePacket.setCachedPalette(Toolbox.CACHED_PALLETE.retainedDuplicate()); startGamePacket.setItemEntries(Toolbox.ITEMS); upstream.sendPacket(startGamePacket); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaChatTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaChatTranslator.java index cc5838c90..e604e20a3 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaChatTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaChatTranslator.java @@ -43,12 +43,16 @@ public class JavaChatTranslator extends PacketTranslator { switch (packet.getType()) { case CHAT: textPacket.setType(TextPacket.Type.CHAT); + break; case SYSTEM: textPacket.setType(TextPacket.Type.SYSTEM); + break; case NOTIFICATION: textPacket.setType(TextPacket.Type.TIP); + break; default: textPacket.setType(TextPacket.Type.RAW); + break; } if (packet.getMessage() instanceof TranslationMessage) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaPlayerListEntryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaPlayerListEntryTranslator.java index cddcc098e..d0653ee06 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaPlayerListEntryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaPlayerListEntryTranslator.java @@ -22,7 +22,7 @@ public class JavaPlayerListEntryTranslator extends PacketTranslator { @Override public void translate(ServerScoreboardObjectivePacket packet, GeyserSession session) { - try { - ScoreboardCache cache = session.getScoreboardCache(); - Scoreboard scoreboard = cache.getScoreboard(); + ScoreboardCache cache = session.getScoreboardCache(); + Scoreboard scoreboard = cache.getScoreboard(); - if (scoreboard.getObjective(packet.getName()) == null) { - // whoops sent objective to early, ignore it - return; - } + Objective objective = scoreboard.getObjective(packet.getName()); - switch (packet.getAction()) { - case ADD: - Objective objective = scoreboard.getObjective(packet.getName()); - objective.setDisplayName(MessageUtils.getBedrockMessage(packet.getDisplayName())); - objective.setType(packet.getType().ordinal()); - break; - case UPDATE: - Objective updateObj = scoreboard.getObjective(packet.getName()); - updateObj.setDisplayName(MessageUtils.getBedrockMessage(packet.getDisplayName())); - break; - case REMOVE: - scoreboard.unregisterObjective(packet.getName()); - break; - } - - scoreboard.onUpdate(); - } catch (Exception ex) { - ex.printStackTrace(); + if (objective == null && packet.getAction() != ObjectiveAction.REMOVE) { + objective = scoreboard.registerNewObjective(packet.getName(), true); } + + switch (packet.getAction()) { + case ADD: + case UPDATE: + objective.setDisplayName(MessageUtils.getBedrockMessage(packet.getDisplayName())); + objective.setType(packet.getType().ordinal()); + break; + case REMOVE: + scoreboard.unregisterObjective(packet.getName()); + break; + } + + if (objective != null && !objective.isTemp()) scoreboard.onUpdate(); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaUpdateScoreTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaUpdateScoreTranslator.java index dae080a3b..7d21deaf0 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaUpdateScoreTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaUpdateScoreTranslator.java @@ -25,12 +25,13 @@ package org.geysermc.connector.network.translators.java.scoreboard; +import com.github.steveice10.mc.protocol.data.game.scoreboard.ScoreboardAction; import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerUpdateScorePacket; import org.geysermc.api.Geyser; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; -import org.geysermc.connector.scoreboard.Scoreboard; import org.geysermc.connector.scoreboard.Objective; +import org.geysermc.connector.scoreboard.Scoreboard; public class JavaUpdateScoreTranslator extends PacketTranslator { @@ -40,18 +41,24 @@ public class JavaUpdateScoreTranslator extends PacketTranslator scores = new HashMap<>(); + private Objective(Scoreboard scoreboard) { + this.id = scoreboard.getNextId().getAndIncrement(); + this.scoreboard = scoreboard; + } + + /** + * /!\ This method is made for temporary objectives until the real objective is received + */ + public Objective(Scoreboard scoreboard, String objectiveName) { + this(scoreboard); + this.objectiveName = objectiveName; + this.temp = true; + } + public Objective(Scoreboard scoreboard, String objectiveName, ScoreboardPosition displaySlot, String displayName, int type) { this(scoreboard, objectiveName, displaySlot.name().toLowerCase(), displayName, type); } public Objective(Scoreboard scoreboard, String objectiveName, String displaySlot, String displayName, int type) { - this.scoreboard = scoreboard; - this.id = scoreboard.getNextId().getAndIncrement(); + this(scoreboard); this.objectiveName = objectiveName; this.displaySlot = displaySlot; this.displayName = displayName; @@ -61,9 +75,9 @@ public class Objective { public void registerScore(String id, int score) { if (!scores.containsKey(id)) { - Score score1 = new Score(this, id).setScore(score); - Team team = scoreboard.getTeamFor(id); - if (team != null) score1.setTeam(team); + Score score1 = new Score(this, id) + .setScore(score) + .setTeam(scoreboard.getTeamFor(id)); scores.put(id, score1); } } @@ -80,9 +94,9 @@ public class Objective { if (!scores.containsKey(oldText) || oldText.equals(newText)) return; Score oldScore = scores.get(oldText); - Score newScore = new Score(this, newText).setScore(oldScore.getScore()); - Team team = scoreboard.getTeamFor(newText); - if (team != null) newScore.setTeam(team); + Score newScore = new Score(this, newText) + .setScore(oldScore.getScore()) + .setTeam(scoreboard.getTeamFor(newText)); scores.put(newText, newScore); oldScore.setUpdateType(UpdateType.REMOVE); @@ -123,4 +137,11 @@ public class Objective { if (updateType == UpdateType.NOTHING) updateType = UpdateType.UPDATE; return this; } + + public void removeTemp(ScoreboardPosition displaySlot) { + if (temp) { + temp = false; + this.displaySlot = displaySlot.name().toLowerCase(); + } + } } diff --git a/connector/src/main/java/org/geysermc/connector/scoreboard/Score.java b/connector/src/main/java/org/geysermc/connector/scoreboard/Score.java index 9e4966582..f4778d953 100644 --- a/connector/src/main/java/org/geysermc/connector/scoreboard/Score.java +++ b/connector/src/main/java/org/geysermc/connector/scoreboard/Score.java @@ -39,7 +39,7 @@ public class Score { private String name; private Team team; private int score; - + private int oldScore = Integer.MIN_VALUE; public Score(Objective objective, String name) { this.id = objective.getScoreboard().getNextId().getAndIncrement(); @@ -48,9 +48,17 @@ public class Score { } public String getDisplayName() { - if (team != null) { + if (team != null && team.getUpdateType() != UpdateType.REMOVE) { return team.getPrefix() + name + team.getSuffix(); } return name; } + + public Score setScore(int score) { + if (oldScore == Integer.MIN_VALUE) { + this.oldScore = score; + } + this.score = score; + return this; + } } diff --git a/connector/src/main/java/org/geysermc/connector/scoreboard/Scoreboard.java b/connector/src/main/java/org/geysermc/connector/scoreboard/Scoreboard.java index 22b080cb6..948da13ae 100644 --- a/connector/src/main/java/org/geysermc/connector/scoreboard/Scoreboard.java +++ b/connector/src/main/java/org/geysermc/connector/scoreboard/Scoreboard.java @@ -32,7 +32,6 @@ import com.nukkitx.protocol.bedrock.packet.SetDisplayObjectivePacket; import com.nukkitx.protocol.bedrock.packet.SetScorePacket; import lombok.Getter; import org.geysermc.api.Geyser; -import org.geysermc.connector.console.GeyserLogger; import org.geysermc.connector.network.session.GeyserSession; import java.util.*; @@ -52,13 +51,30 @@ public class Scoreboard { this.session = session; } - public Objective registerNewObjective(String objectiveId, ScoreboardPosition displaySlot) { - Objective objective = new Objective(this, objectiveId, displaySlot, "unknown", 0); - if (objectives.containsKey(objectiveId)) despawnObjective(objectives.get(objectiveId)); + public Objective registerNewObjective(String objectiveId, boolean temp) { + if (!temp || objectives.containsKey(objectiveId)) return objectives.get(objectiveId); + Objective objective = new Objective(this, objectiveId); objectives.put(objectiveId, objective); return objective; } + public Objective registerNewObjective(String objectiveId, ScoreboardPosition displaySlot) { + Objective objective = null; + if (objectives.containsKey(objectiveId)) { + objective = objectives.get(objectiveId); + if (objective.isTemp()) objective.removeTemp(displaySlot); + else { + despawnObjective(objective); + objective = null; + } + } + if (objective == null) { + objective = new Objective(this, objectiveId, displaySlot, "unknown", 0); + objectives.put(objectiveId, objective); + } + return objective; + } + public Team registerNewTeam(String teamName, Set players) { if (teams.containsKey(teamName)) { Geyser.getLogger().info("Ignoring team " + teamName + ". It overrides without removing old team."); @@ -71,7 +87,7 @@ public class Scoreboard { for (Objective objective : objectives.values()) { for (Score score : objective.getScores().values()) { if (players.contains(score.getName())) { - score.setTeam(team).setUpdateType(ADD); + score.setTeam(team); } } } @@ -92,15 +108,8 @@ public class Scoreboard { } public void removeTeam(String teamName) { - if (teams.remove(teamName) != null) { - for (Objective objective : objectives.values()) { - for (Score score : objective.getScores().values()) { - if (score.getName().equals(teamName)) { - score.setTeam(null).setUpdateType(ADD); - } - } - } - } + Team remove = teams.remove(teamName); + if (remove != null) remove.setUpdateType(REMOVE); } public void onUpdate() { @@ -110,23 +119,64 @@ public class Scoreboard { for (String objectiveId : new ArrayList<>(objectives.keySet())) { Objective objective = objectives.get(objectiveId); + if (objective.isTemp()) { + Geyser.getLogger().debug("Ignoring temp Scoreboard Objective '"+ objectiveId +'\''); + continue; + } + if (objective.getUpdateType() != NOTHING) changedObjectives.add(objective); + boolean globalUpdate = objective.getUpdateType() == UPDATE; + boolean globalAdd = objective.getUpdateType() == ADD || globalUpdate; + boolean globalRemove = objective.getUpdateType() == REMOVE || globalUpdate; + + boolean hasUpdate = globalUpdate; + + List handledScores = new ArrayList<>(); for (String identifier : new HashSet<>(objective.getScores().keySet())) { Score score = objective.getScores().get(identifier); + Team team = score.getTeam(); - boolean add = (objective.getUpdateType() != NOTHING && objective.getUpdateType() != REMOVE) && score.getUpdateType() != REMOVE || score.getUpdateType() == ADD; - boolean remove = (add && score.getUpdateType() != ADD && objective.getUpdateType() != ADD) || objective.getUpdateType() == REMOVE || score.getUpdateType() == REMOVE; + boolean inTeam = team != null && team.getEntities().contains(score.getName()); - ScoreInfo info = new ScoreInfo(score.getId(), score.getObjective().getObjectiveName(), score.getScore(), score.getDisplayName()); - if (add || (score.getTeam() != null && (score.getTeam().getUpdateType() == ADD || score.getTeam().getUpdateType() == UPDATE))) addScores.add(info); - if (remove || (score.getTeam() != null && score.getTeam().getUpdateType() != NOTHING)) removeScores.add(info); + boolean teamAdd = team != null && (team.getUpdateType() == ADD || team.getUpdateType() == UPDATE); + boolean teamRemove = team != null && (team.getUpdateType() == REMOVE || team.getUpdateType() == UPDATE); + + if (team != null && (team.getUpdateType() == REMOVE || inTeam)) score.setTeam(null); + + boolean add = (hasUpdate || globalAdd || teamAdd || teamRemove || score.getUpdateType() == ADD || score.getUpdateType() == UPDATE) && (score.getUpdateType() != REMOVE); + boolean remove = hasUpdate || globalRemove || teamAdd || teamRemove || score.getUpdateType() == REMOVE || score.getUpdateType() == UPDATE; + + boolean updated = false; + if (!hasUpdate) { + updated = hasUpdate = add; + } + + if (updated) { + for (Score score1 : handledScores) { + ScoreInfo scoreInfo = new ScoreInfo(score1.getId(), score1.getObjective().getObjectiveName(), score1.getScore(), score1.getDisplayName()); + addScores.add(scoreInfo); + removeScores.add(scoreInfo); + } + } + + if (add) { + addScores.add(new ScoreInfo(score.getId(), score.getObjective().getObjectiveName(), score.getScore(), score.getDisplayName())); + } + if (remove) { + removeScores.add(new ScoreInfo(score.getId(), score.getObjective().getObjectiveName(), score.getOldScore(), score.getDisplayName())); + } + score.setOldScore(score.getScore()); if (score.getUpdateType() == REMOVE) { objective.removeScore(score.getName()); } - if (addScores.contains(info) || removeScores.contains(info)) changedObjectives.add(objective); + if (add || remove) { + changedObjectives.add(objective); + } else { // stays the same like before + handledScores.add(score); + } score.setUpdateType(NOTHING); } } diff --git a/connector/src/main/java/org/geysermc/connector/scoreboard/Team.java b/connector/src/main/java/org/geysermc/connector/scoreboard/Team.java index 2106787ea..7dcb5f3f5 100644 --- a/connector/src/main/java/org/geysermc/connector/scoreboard/Team.java +++ b/connector/src/main/java/org/geysermc/connector/scoreboard/Team.java @@ -36,29 +36,20 @@ public class Team { added.add(name); } } + setUpdateType(UpdateType.UPDATE); for (Objective objective : scoreboard.getObjectives().values()) { for (Score score : objective.getScores().values()) { if (added.contains(score.getName())) { - score.setTeam(this).setUpdateType(UpdateType.ADD); + score.setTeam(this); } } } } public void removeEntities(String... names) { - List removed = new ArrayList<>(); for (String name : names) { - if (entities.contains(name)) { - entities.remove(name); - removed.add(name); - } - } - for (Objective objective : scoreboard.getObjectives().values()) { - for (Score score : objective.getScores().values()) { - if (removed.contains(score.getName())) { - score.setTeam(null).setUpdateType(UpdateType.ADD); - } - } + entities.remove(name); } + setUpdateType(UpdateType.UPDATE); } }