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 ed72d1801..884134948 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 @@ -51,6 +51,7 @@ import org.geysermc.api.session.AuthData; import org.geysermc.api.window.FormWindow; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.network.session.cache.InventoryCache; +import org.geysermc.connector.network.session.cache.ScoreboardCache; import org.geysermc.connector.network.session.cache.WindowCache; import org.geysermc.connector.network.translators.Registry; import org.geysermc.connector.utils.Toolbox; @@ -77,6 +78,9 @@ public class GeyserSession implements PlayerSession, Player { @Getter private WindowCache windowCache; + @Getter + private ScoreboardCache scoreboardCache; + @Getter private boolean loggedIn; @@ -89,6 +93,8 @@ public class GeyserSession implements PlayerSession, Player { this.inventoryCache = new InventoryCache(this); this.windowCache = new WindowCache(this); + this.scoreboardCache = new ScoreboardCache(this); + this.loggedIn = false; } diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/ScoreboardCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/ScoreboardCache.java new file mode 100644 index 000000000..01efa9693 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/session/cache/ScoreboardCache.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2019 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.connector.network.session.cache; + +import com.nukkitx.protocol.bedrock.packet.RemoveObjectivePacket; +import lombok.Getter; +import lombok.Setter; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.scoreboard.Scoreboard; + +public class ScoreboardCache { + + private GeyserSession session; + + public ScoreboardCache(GeyserSession session) { + this.session = session; + } + + @Getter + @Setter + private Scoreboard scoreboard; + + public void removeScoreboard() { + RemoveObjectivePacket removeObjectivePacket = new RemoveObjectivePacket(); + removeObjectivePacket.setObjectiveId(scoreboard.getObjective().getObjectiveName()); + session.getUpstream().sendPacket(removeObjectivePacket); + } +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaScoreboardDisplayTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaScoreboardDisplayTranslator.java new file mode 100644 index 000000000..db4eef2f2 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaScoreboardDisplayTranslator.java @@ -0,0 +1,19 @@ +package org.geysermc.connector.network.translators.java.scoreboard; + +import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerDisplayScoreboardPacket; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.session.cache.ScoreboardCache; +import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.network.translators.scoreboard.Scoreboard; + +public class JavaScoreboardDisplayTranslator extends PacketTranslator { + @Override + public void translate(ServerDisplayScoreboardPacket packet, GeyserSession session) { + try { + ScoreboardCache cache = session.getScoreboardCache(); + Scoreboard scoreboard = new Scoreboard(session); + } catch (Exception ex) { + ex.printStackTrace(); + } + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaScoreboardObjectiveTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaScoreboardObjectiveTranslator.java new file mode 100644 index 000000000..7076d1c66 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaScoreboardObjectiveTranslator.java @@ -0,0 +1,41 @@ +package org.geysermc.connector.network.translators.java.scoreboard; + +import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerScoreboardObjectivePacket; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.session.cache.ScoreboardCache; +import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.network.translators.scoreboard.Scoreboard; +import org.geysermc.connector.network.translators.scoreboard.ScoreboardObjective; +import org.geysermc.connector.utils.MessageUtils; + +public class JavaScoreboardObjectiveTranslator extends PacketTranslator { + @Override + public void translate(ServerScoreboardObjectivePacket packet, GeyserSession session) { + try { + ScoreboardCache cache = session.getScoreboardCache(); + Scoreboard scoreboard = new Scoreboard(session); + if (cache.getScoreboard() != null) + scoreboard = cache.getScoreboard(); + + switch (packet.getAction()) { + case ADD: + ScoreboardObjective objective = scoreboard.registerNewObjective(packet.getName()); + objective.setDisplaySlot(ScoreboardObjective.DisplaySlot.SIDEBAR); + objective.setDisplayName(MessageUtils.getBedrockMessage(packet.getDisplayName())); + break; + case UPDATE: + ScoreboardObjective updateObj = scoreboard.getObjective(packet.getName()); + updateObj.setDisplayName(MessageUtils.getBedrockMessage(packet.getDisplayName())); + break; + case REMOVE: + scoreboard.unregisterObjective(packet.getName()); + break; + } + + scoreboard.onUpdate(); + cache.setScoreboard(scoreboard); + } catch (Exception ex) { + ex.printStackTrace(); + } + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaScoreboardTeamTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaScoreboardTeamTranslator.java new file mode 100644 index 000000000..85845a4ff --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaScoreboardTeamTranslator.java @@ -0,0 +1,17 @@ +package org.geysermc.connector.network.translators.java.scoreboard; + +import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerTeamPacket; +import com.nukkitx.protocol.bedrock.packet.SetScorePacket; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.session.cache.ScoreboardCache; +import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.network.translators.scoreboard.Scoreboard; +import org.geysermc.connector.network.translators.scoreboard.ScoreboardObjective; +import org.geysermc.connector.utils.MessageUtils; + +public class JavaScoreboardTeamTranslator extends PacketTranslator { + @Override + public void translate(ServerTeamPacket packet, GeyserSession session) { + + } +} 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 new file mode 100644 index 000000000..3f67ed192 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaUpdateScoreTranslator.java @@ -0,0 +1,39 @@ +package org.geysermc.connector.network.translators.java.scoreboard; + +import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerUpdateScorePacket; +import com.nukkitx.protocol.bedrock.packet.SetScorePacket; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.session.cache.ScoreboardCache; +import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.network.translators.scoreboard.Scoreboard; +import org.geysermc.connector.network.translators.scoreboard.ScoreboardObjective; + +public class JavaUpdateScoreTranslator extends PacketTranslator { + @Override + public void translate(ServerUpdateScorePacket packet, GeyserSession session) { + try { + ScoreboardCache cache = session.getScoreboardCache(); + Scoreboard scoreboard = new Scoreboard(session); + if (cache.getScoreboard() != null) + scoreboard = cache.getScoreboard(); + + ScoreboardObjective objective = scoreboard.getObjective(packet.getObjective()); + if (objective == null) { + objective = scoreboard.registerNewObjective(packet.getObjective()); + } + + switch (packet.getAction()) { + case REMOVE: + objective.registerScore(packet.getEntry(), packet.getEntry(), packet.getValue(), SetScorePacket.Action.REMOVE); + break; + case ADD_OR_UPDATE: + objective.registerScore(packet.getEntry(), packet.getEntry(), packet.getValue(), SetScorePacket.Action.SET); + break; + } + cache.setScoreboard(scoreboard); + scoreboard.onUpdate(); + } catch (Exception ex) { + ex.printStackTrace(); + } + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/scoreboard/Score.java b/connector/src/main/java/org/geysermc/connector/network/translators/scoreboard/Score.java new file mode 100644 index 000000000..764d9bc7c --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/scoreboard/Score.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2019 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.connector.network.translators.scoreboard; + +import com.nukkitx.protocol.bedrock.packet.SetScorePacket; +import lombok.Getter; +import lombok.Setter; + +import java.util.Random; + +/** + * Adapted from: https://github.com/Ragnok123/GTScoreboard + */ +public class Score { + + @Getter + @Setter + private int score; + + @Getter + private long scoreboardId; + + private ScoreboardObjective objective; + + @Getter + @Setter + private String fakePlayer; + + @Getter + @Setter + private SetScorePacket.Action action = SetScorePacket.Action.SET; + + private boolean modified = false; + + @Getter + @Setter + private String fakeId; + + public Score(ScoreboardObjective objective, String fakePlayer) { + this.scoreboardId = -new Random().nextLong(); + this.objective = objective; + this.fakePlayer = fakePlayer; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/scoreboard/Scoreboard.java b/connector/src/main/java/org/geysermc/connector/network/translators/scoreboard/Scoreboard.java new file mode 100644 index 000000000..6388b6267 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/scoreboard/Scoreboard.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2019 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.connector.network.translators.scoreboard; + +import com.nukkitx.protocol.bedrock.data.ScoreInfo; +import com.nukkitx.protocol.bedrock.packet.RemoveObjectivePacket; +import com.nukkitx.protocol.bedrock.packet.SetDisplayObjectivePacket; +import com.nukkitx.protocol.bedrock.packet.SetScorePacket; +import lombok.Getter; +import lombok.Setter; +import org.geysermc.connector.network.session.GeyserSession; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; + +/** + * Adapted from: https://github.com/Ragnok123/GTScoreboard + */ +public class Scoreboard { + + @Getter + private ScoreboardObjective objective; + + private GeyserSession session; + + @Getter + @Setter + private long id; + + private Map objectiveMap = new HashMap(); + + public Scoreboard(GeyserSession session) { + this.session = session; + + id = new Random().nextLong(); + } + + public ScoreboardObjective registerNewObjective(String objectiveName) { + ScoreboardObjective objective = new ScoreboardObjective(); + objective.setObjectiveName(objectiveName); + this.objective = objective; + if (!objectiveMap.containsKey(objectiveName)) { + objectiveMap.put(objectiveName, objective); + } + + return objective; + } + + public ScoreboardObjective getObjective(String objectiveName) { + ScoreboardObjective objective = null; + if (objectiveMap.containsKey(objectiveName) && this.objective.getObjectiveName().contains(objectiveName)) { + objective = this.objective; + } + + return objective; + } + + public void setObjective(String objectiveName) { + if (objectiveMap.containsKey(objectiveName)) + objective = objectiveMap.get(objectiveName); + } + + public void unregisterObjective(String objectiveName) { + if (!objectiveMap.containsKey(objectiveName)) + return; + + if (objective.getObjectiveName().equals(objectiveName)) { + objective = null; + } + + objectiveMap.remove(objectiveName); + } + + public void onUpdate() { + RemoveObjectivePacket removeObjectivePacket = new RemoveObjectivePacket(); + removeObjectivePacket.setObjectiveId(objective.getObjectiveName()); + session.getUpstream().sendPacket(removeObjectivePacket); + + SetDisplayObjectivePacket displayObjectivePacket = new SetDisplayObjectivePacket(); + displayObjectivePacket.setObjectiveId(objective.getObjectiveName()); + displayObjectivePacket.setDisplayName(objective.getDisplayName()); + displayObjectivePacket.setCriteria("dummy"); + displayObjectivePacket.setDisplaySlot("sidebar"); + displayObjectivePacket.setSortOrder(2); + session.getUpstream().sendPacket(displayObjectivePacket); + + Map fakeMap = new HashMap(); + for (Map.Entry entry : objective.getScores().entrySet()) { + fakeMap.put(entry.getKey(), entry.getValue()); + } + + for (String string : fakeMap.keySet()) { + Score score = fakeMap.get(string); + ScoreInfo scoreInfo = new ScoreInfo(score.getScoreboardId(), objective.getObjectiveName(), score.getScore(), score.getFakePlayer()); + + SetScorePacket setScorePacket = new SetScorePacket(); + setScorePacket.setAction(score.getAction()); + setScorePacket.setInfos(Arrays.asList(scoreInfo)); + session.getUpstream().sendPacket(setScorePacket); + + if (score.getAction() == SetScorePacket.Action.REMOVE) { + String id = score.getFakeId(); + objective.getScores().remove(id); + } + } + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/scoreboard/ScoreboardObjective.java b/connector/src/main/java/org/geysermc/connector/network/translators/scoreboard/ScoreboardObjective.java new file mode 100644 index 000000000..a140ff677 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/scoreboard/ScoreboardObjective.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2019 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.connector.network.translators.scoreboard; + +import com.nukkitx.protocol.bedrock.packet.SetScorePacket; +import lombok.Getter; +import lombok.Setter; +import org.geysermc.connector.console.GeyserLogger; + +import java.util.HashMap; +import java.util.Map; + +/** + * Adapted from: https://github.com/Ragnok123/GTScoreboard + */ +public class ScoreboardObjective { + + @Getter + @Setter + private int scoreboardTick = 0; + + @Getter + @Setter + private String objectiveName; + + @Getter + @Setter + private DisplaySlot displaySlot; + + @Getter + @Setter + private String displayName; + + @Getter + private Map scores = new HashMap(); + + public void registerScore(String id, String fake, int value) { + registerScore(id, fake, value, SetScorePacket.Action.SET); + } + + public void registerScore(String id, String fake, int value, SetScorePacket.Action action) { + Score score = new Score(this, fake); + score.setScore(value); + score.setFakeId(id); + score.setAction(action); + if (!scores.containsKey(id)) { + scores.put(id, score); + } else { + setScore(id, value); + } + } + + public void setScore(String id, int value) { + if (scores.containsKey(id)) { + Score modifiedScore = scores.get(id); + modifiedScore.setScore(value); + scores.remove(id); + scores.put(id, modifiedScore); + } + } + + public void setScoreText(String id, String text) { + if (scores.containsKey(id)) { + Score newScore = new Score(this, text); + newScore.setScore(scores.get(id).getScore()); + newScore.setFakeId(id); + scores.remove(id); + scores.put(id, newScore); + } + } + + public int getScore(String id) { + int i = 0; + if (scores.containsKey(id)) { + Score score = scores.get(id); + i = score.getScore(); + } + + return i; + } + + public Score getScore(int line) { + Score score = null; + for (Map.Entry entry : scores.entrySet()) { + if (entry.getValue().getScore() == line) + return entry.getValue(); + } + + return null; + } + + public void resetScore(String id) { + if (scores.containsKey(id)) { + Score modifiedScore = scores.get(id); + modifiedScore.setAction(SetScorePacket.Action.REMOVE); + scores.remove(id); + scores.put(id, modifiedScore); + } + } + + public enum DisplaySlot { + + SIDEBAR, + LIST, + BELOWNAME; + + } +}