From 2d4d9e42b5b3fc15a2c49ef9a72cab88edab6dc5 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn Date: Mon, 30 Jul 2018 18:21:25 -0400 Subject: [PATCH] Properly handle scoreboard removal while switching between servers --- .../backend/BackendPlaySessionHandler.java | 7 +- .../client/ClientPlaySessionHandler.java | 86 +++++++++++++++++++ .../proxy/data/scoreboard/Objective.java | 8 ++ .../proxy/data/scoreboard/Scoreboard.java | 30 ++++--- 4 files changed, 115 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java b/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java index 70dcae4fa..fc603c26b 100644 --- a/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java +++ b/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java @@ -60,8 +60,11 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler { } } else { // Just forward the packet on. We don't have anything to handle at this time. - if (packet.getClass().getName().contains("Scoreboard")) { - System.out.println(packet); + if (packet instanceof ScoreboardTeam || + packet instanceof ScoreboardObjective || + packet instanceof ScoreboardSetScore || + packet instanceof ScoreboardDisplay) { + playerHandler.handleServerScoreboardPacket(packet); } connection.getProxyPlayer().getConnection().write(packet); } diff --git a/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index 4a1c9db37..ed25417ae 100644 --- a/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -3,7 +3,10 @@ package com.velocitypowered.proxy.connection.client; import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.connection.backend.ServerConnection; import com.velocitypowered.proxy.data.ServerInfo; +import com.velocitypowered.proxy.data.scoreboard.Objective; +import com.velocitypowered.proxy.data.scoreboard.Score; import com.velocitypowered.proxy.data.scoreboard.Scoreboard; +import com.velocitypowered.proxy.data.scoreboard.Team; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.packets.*; import com.velocitypowered.proxy.connection.MinecraftSessionHandler; @@ -149,6 +152,9 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { } serverBossBars.clear(); + // Remove scoreboard junk. + clearServerScoreboard(); + // Tell the server about this client's plugin messages. Velocity will forward them on to the client. if (!clientPluginMsgChannels.isEmpty()) { player.getConnectedServer().getChannel().delayedWrite( @@ -218,6 +224,86 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { } } + public void handleServerScoreboardPacket(MinecraftPacket packet) { + logger.info("Server scoreboard packet: {}", packet); + + if (packet instanceof ScoreboardDisplay) { + ScoreboardDisplay sd = (ScoreboardDisplay) packet; + serverScoreboard.setPosition(sd.getPosition()); + serverScoreboard.setDisplayName(sd.getDisplayName()); + } + + if (packet instanceof ScoreboardObjective) { + ScoreboardObjective so = (ScoreboardObjective) packet; + if (so.getMode() == 0) { + Objective o = new Objective(so.getId()); + o.setDisplayName(so.getDisplayName()); + o.setType(so.getType()); + serverScoreboard.getObjectives().put(so.getId(), o); + } else { + serverScoreboard.getObjectives().remove(so.getId()); + } + } + + if (packet instanceof ScoreboardSetScore) { + ScoreboardSetScore sss = (ScoreboardSetScore) packet; + Objective objective = serverScoreboard.getObjectives().get(sss.getObjective()); + if (objective == null) { + return; + } + switch (sss.getAction()) { + case 0: + Score score = new Score(sss.getEntity(), sss.getValue()); + objective.getScores().put(sss.getEntity(), score); + break; + case 1: + objective.getScores().remove(sss.getEntity()); + break; + } + } + + if (packet instanceof ScoreboardTeam) { + ScoreboardTeam st = (ScoreboardTeam) packet; + switch (st.getMode()) { + case 0: + // TODO: Preserve other team information? We might not need to... + Team team = new Team(st.getId()); + serverScoreboard.getTeams().put(st.getId(), team); + break; + case 1: + serverScoreboard.getTeams().remove(st.getId()); + break; + } + } + } + + private void clearServerScoreboard() { + logger.info("Scoreboard prior to cleaning: {}", serverScoreboard); + for (Objective objective : serverScoreboard.getObjectives().values()) { + for (Score score : objective.getScores().values()) { + ScoreboardSetScore sss = new ScoreboardSetScore(); + sss.setObjective(objective.getId()); + sss.setAction((byte) 1); + sss.setEntity(score.getTarget()); + player.getConnection().delayedWrite(sss); + } + + ScoreboardObjective so = new ScoreboardObjective(); + so.setId(objective.getId()); + so.setMode((byte) 1); + player.getConnection().delayedWrite(so); + } + + for (Team team : serverScoreboard.getTeams().values()) { + ScoreboardTeam st = new ScoreboardTeam(); + st.setId(team.getId()); + st.setMode((byte) 1); + player.getConnection().delayedWrite(st); + } + + serverScoreboard = new Scoreboard(); + } + public Set getClientPluginMsgChannels() { return clientPluginMsgChannels; } diff --git a/src/main/java/com/velocitypowered/proxy/data/scoreboard/Objective.java b/src/main/java/com/velocitypowered/proxy/data/scoreboard/Objective.java index eea29dbd8..6f677c7d3 100644 --- a/src/main/java/com/velocitypowered/proxy/data/scoreboard/Objective.java +++ b/src/main/java/com/velocitypowered/proxy/data/scoreboard/Objective.java @@ -36,6 +36,14 @@ public class Objective { return scores; } + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + public void setType(String type) { + this.type = type; + } + @Override public String toString() { return "Objective{" + diff --git a/src/main/java/com/velocitypowered/proxy/data/scoreboard/Scoreboard.java b/src/main/java/com/velocitypowered/proxy/data/scoreboard/Scoreboard.java index fa3c95260..b4d9d8535 100644 --- a/src/main/java/com/velocitypowered/proxy/data/scoreboard/Scoreboard.java +++ b/src/main/java/com/velocitypowered/proxy/data/scoreboard/Scoreboard.java @@ -1,23 +1,20 @@ package com.velocitypowered.proxy.data.scoreboard; -import java.util.ArrayList; -import java.util.List; +import java.util.HashMap; +import java.util.Map; public class Scoreboard { - private String name; + private String displayName; private byte position; - private final List objectives = new ArrayList<>(); - - public Scoreboard() { + private final Map objectives = new HashMap<>(); + private final Map teams = new HashMap<>(); + public String getDisplayName() { + return displayName; } - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; + public void setDisplayName(String displayName) { + this.displayName = displayName; } public byte getPosition() { @@ -28,16 +25,21 @@ public class Scoreboard { this.position = position; } - public List getObjectives() { + public Map getObjectives() { return objectives; } + public Map getTeams() { + return teams; + } + @Override public String toString() { return "Scoreboard{" + - "name='" + name + '\'' + + "displayName='" + displayName + '\'' + ", position=" + position + ", objectives=" + objectives + + ", teams=" + teams + '}'; } }