From e7e1c8a8329ee3f0d38a955cfc75ffb306681735 Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Sat, 23 Dec 2023 11:53:07 -0800 Subject: [PATCH] Fix and add new scoreboard API (#10037) --- .../api/0450-Add-more-scoreboard-API.patch | 90 +++++++++++++++++++ .../0725-Improve-scoreboard-entries.patch | 11 +-- .../server/1052-Fix-scoreboard-entries.patch | 36 ++++++++ .../server/1053-add-more-scoreboard-API.patch | 79 ++++++++++++++++ 4 files changed, 211 insertions(+), 5 deletions(-) create mode 100644 patches/api/0450-Add-more-scoreboard-API.patch create mode 100644 patches/server/1052-Fix-scoreboard-entries.patch create mode 100644 patches/server/1053-add-more-scoreboard-API.patch diff --git a/patches/api/0450-Add-more-scoreboard-API.patch b/patches/api/0450-Add-more-scoreboard-API.patch new file mode 100644 index 0000000000..201af36b0c --- /dev/null +++ b/patches/api/0450-Add-more-scoreboard-API.patch @@ -0,0 +1,90 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 16 Dec 2023 14:45:46 -0800 +Subject: [PATCH] Add more scoreboard API + + +diff --git a/src/main/java/org/bukkit/scoreboard/Objective.java b/src/main/java/org/bukkit/scoreboard/Objective.java +index a193ffabb05160b462dee1ba8f687fdbc84405b6..bd4d84cbf220ab02f09ece97873bbf0bdf7a45ba 100644 +--- a/src/main/java/org/bukkit/scoreboard/Objective.java ++++ b/src/main/java/org/bukkit/scoreboard/Objective.java +@@ -175,4 +175,24 @@ public interface Objective { + */ + @NotNull Score getScoreFor(@NotNull org.bukkit.entity.Entity entity) throws IllegalArgumentException, IllegalStateException; + // Paper end - improve scoreboard entries ++ ++ // Paper start - add more score API ++ /** ++ * Gets if this objective will auto update score ++ * displays on changes. ++ * ++ * @return true if auto updating ++ * @throws IllegalStateException if this objective has been unregistered ++ */ ++ boolean willAutoUpdateDisplay(); ++ ++ /** ++ * Sets if this objective will auto update ++ * score displays on changes. ++ * ++ * @param autoUpdateDisplay true to auto update ++ * @throws IllegalStateException if this objective has been unregistered ++ */ ++ void setAutoUpdateDisplay(boolean autoUpdateDisplay); ++ // Paper end - add more score API + } +diff --git a/src/main/java/org/bukkit/scoreboard/Score.java b/src/main/java/org/bukkit/scoreboard/Score.java +index 1eaa9a93f8eff5f18a6cce2d74f21eb19db273c8..5b6f243492d55d2db0d6944dc6daca9b181551d6 100644 +--- a/src/main/java/org/bukkit/scoreboard/Score.java ++++ b/src/main/java/org/bukkit/scoreboard/Score.java +@@ -83,4 +83,50 @@ public interface Score { + */ + void resetScore() throws IllegalStateException; + // Paper end ++ ++ // Paper start - add more score API ++ /** ++ * Gets if this score is triggerable and cannot ++ * be used by the {@code /trigger} command executed ++ * by the owner of this score. ++ * ++ * @return true if triggerable, false if not triggerable, score isn't set, or the objective isn't {@link Criteria#TRIGGER} ++ * @throws IllegalStateException if the associated objective has been unregistered ++ */ ++ boolean isTriggerable(); ++ ++ /** ++ * Sets if this score is triggerable and can ++ * be used by the {@code /trigger} command ++ * executed by the owner of this score. Can ++ * only be set on {@link Criteria#TRIGGER} objectives. ++ *

++ * If the score doesn't exist (aka {@link #isScoreSet()} returns false), ++ * this will create the score with a 0 value. ++ * ++ * @param triggerable true to enable trigger, false to disable ++ * @throws IllegalArgumentException if this objective isn't {@link Criteria#TRIGGER} ++ * @throws IllegalStateException if the associated objective has been unregistered ++ */ ++ void setTriggerable(boolean triggerable); ++ ++ /** ++ * Get the custom name for this entry. ++ * ++ * @return the custom name or null if not set (or score isn't set) ++ * @throws IllegalStateException if the associated objective has been unregistered ++ */ ++ @Nullable net.kyori.adventure.text.Component customName(); ++ ++ /** ++ * Sets the custom name for this entry. ++ *

++ * If the score doesn't exist (aka {@link #isScoreSet()} returns false), ++ * this will create the score with a 0 value. ++ * ++ * @param customName the custom name or null to reset ++ * @throws IllegalStateException if the associated objective has been unregistered ++ */ ++ void customName(net.kyori.adventure.text.@Nullable Component customName); ++ // Paper end - add more score API + } diff --git a/patches/server/0725-Improve-scoreboard-entries.patch b/patches/server/0725-Improve-scoreboard-entries.patch index aad5a9dba5..517f4b20ec 100644 --- a/patches/server/0725-Improve-scoreboard-entries.patch +++ b/patches/server/0725-Improve-scoreboard-entries.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Improve scoreboard entries diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java -index da1e4496d78a2c1b258ff8bb316414cb8a662ba2..3157f3d2f9ce7af4a763203672817a7f5c7bd4fb 100644 +index da1e4496d78a2c1b258ff8bb316414cb8a662ba2..b36e5574c10e6d70a399e2ac0704fd4f43dbb444 100644 --- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java +++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java -@@ -144,6 +144,14 @@ final class CraftObjective extends CraftScoreboardComponent implements Objective +@@ -144,6 +144,15 @@ final class CraftObjective extends CraftScoreboardComponent implements Objective return new CraftScore(this, CraftScoreboard.getScoreHolder(entry)); } @@ -16,7 +16,8 @@ index da1e4496d78a2c1b258ff8bb316414cb8a662ba2..3157f3d2f9ce7af4a763203672817a7f + @Override + public Score getScoreFor(org.bukkit.entity.Entity entity) throws IllegalArgumentException, IllegalStateException { + Preconditions.checkArgument(entity != null, "Entity cannot be null"); -+ return getScore(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName()); ++ this.checkState(); ++ return new CraftScore(this, ((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle()); + } + // Paper end + @@ -35,13 +36,13 @@ index fdb30a7e728798c59742b812ef28c5094d6093fc..bd8a5bb2b84daf013750aec9887dcb4b + @Override + public ImmutableSet getScoresFor(org.bukkit.entity.Entity entity) throws IllegalArgumentException { + Preconditions.checkArgument(entity != null, "Entity cannot be null"); -+ return this.getScores(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName()); ++ return this.getScores(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle()); + } + + @Override + public void resetScoresFor(org.bukkit.entity.Entity entity) throws IllegalArgumentException { + Preconditions.checkArgument(entity != null, "Entity cannot be null"); -+ this.resetScores(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle().getScoreboardName()); ++ this.resetScores(((org.bukkit.craftbukkit.entity.CraftEntity) entity).getHandle()); + } + + @Override diff --git a/patches/server/1052-Fix-scoreboard-entries.patch b/patches/server/1052-Fix-scoreboard-entries.patch new file mode 100644 index 0000000000..9af3a73f36 --- /dev/null +++ b/patches/server/1052-Fix-scoreboard-entries.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 16 Dec 2023 13:06:20 -0800 +Subject: [PATCH] Fix scoreboard entries + +1.20.3/4 introduced ScoreHolder which broke a lot of existing +logic that just assumed score entries were strings. + +diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java +index be020d6b686c1ad5bd8b7cee0b6050304d434022..d3d0d71b6fbacc30917682fcc1aace1902a64248 100644 +--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java ++++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java +@@ -42,12 +42,12 @@ final class CraftScore implements Score { + public int getScore() { + Scoreboard board = this.objective.checkState().board; + +- if (board.getTrackedPlayers().contains(this.entry)) { // Lazy ++ // if (board.getTrackedPlayers().contains(this.entry)) { // Lazy // Paper - just use the null check + ReadOnlyScoreInfo score = board.getPlayerScoreInfo(this.entry, this.objective.getHandle()); + if (score != null) { // Lazy + return score.value(); + } +- } ++ // } // Paper - just use the null check above + + return 0; // Lazy + } +@@ -61,7 +61,7 @@ final class CraftScore implements Score { + public boolean isScoreSet() { + Scoreboard board = this.objective.checkState().board; + +- return board.getTrackedPlayers().contains(this.entry) && board.getPlayerScoreInfo(this.entry, this.objective.getHandle()) != null; ++ return /*board.getTrackedPlayers().contains(this.entry) && */board.getPlayerScoreInfo(this.entry, this.objective.getHandle()) != null; // Paper - just check if the player score info exists + } + + @Override diff --git a/patches/server/1053-add-more-scoreboard-API.patch b/patches/server/1053-add-more-scoreboard-API.patch new file mode 100644 index 0000000000..bb2c0c4a40 --- /dev/null +++ b/patches/server/1053-add-more-scoreboard-API.patch @@ -0,0 +1,79 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Sat, 16 Dec 2023 14:46:01 -0800 +Subject: [PATCH] add more scoreboard API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java +index b36e5574c10e6d70a399e2ac0704fd4f43dbb444..2d3abf2a1da487ead74d698cc5ea4eb729c35c8d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java ++++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftObjective.java +@@ -185,6 +185,19 @@ final class CraftObjective extends CraftScoreboardComponent implements Objective + final CraftObjective other = (CraftObjective) obj; + return !(this.objective != other.objective && (this.objective == null || !this.objective.equals(other.objective))); + } ++ // Paper start - add more score API ++ @Override ++ public boolean willAutoUpdateDisplay() { ++ this.checkState(); ++ return this.objective.displayAutoUpdate(); ++ } ++ ++ @Override ++ public void setAutoUpdateDisplay(final boolean autoUpdateDisplay) { ++ this.checkState(); ++ this.objective.setDisplayAutoUpdate(autoUpdateDisplay); ++ } ++ // Paper end - add more score API + + + } +diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java +index d3d0d71b6fbacc30917682fcc1aace1902a64248..ae57f91a4f604fdc6946c9a032e59a3ea3254fe7 100644 +--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java ++++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftScore.java +@@ -76,4 +76,44 @@ final class CraftScore implements Score { + board.resetSinglePlayerScore(entry, this.objective.getHandle()); + } + // Paper end ++ ++ // Paper start - add more score API ++ @Override ++ public boolean isTriggerable() { ++ if (this.objective.getTrackedCriteria() != org.bukkit.scoreboard.Criteria.TRIGGER) { ++ return false; ++ } ++ final Scoreboard board = this.objective.checkState().board; ++ final ReadOnlyScoreInfo scoreInfo = board.getPlayerScoreInfo(this.entry, this.objective.getHandle()); ++ return scoreInfo != null && !scoreInfo.isLocked(); ++ } ++ ++ @Override ++ public void setTriggerable(final boolean triggerable) { ++ com.google.common.base.Preconditions.checkArgument(this.objective.getTrackedCriteria() == org.bukkit.scoreboard.Criteria.TRIGGER, "the criteria isn't 'trigger'"); ++ final Scoreboard board = this.objective.checkState().board; ++ if (triggerable) { ++ board.getOrCreatePlayerScore(this.entry, this.objective.getHandle()).unlock(); ++ } else { ++ board.getOrCreatePlayerScore(this.entry, this.objective.getHandle()).lock(); ++ } ++ } ++ ++ @Override ++ public net.kyori.adventure.text.Component customName() { ++ final Scoreboard board = this.objective.checkState().board; ++ final ReadOnlyScoreInfo scoreInfo = board.getPlayerScoreInfo(this.entry, this.objective.getHandle()); ++ if (scoreInfo == null) { ++ return null; // If score doesn't exist, don't create one ++ } ++ final net.minecraft.network.chat.Component display = board.getOrCreatePlayerScore(this.entry, this.objective.getHandle()).display(); ++ return display == null ? null : io.papermc.paper.adventure.PaperAdventure.asAdventure(display); ++ } ++ ++ @Override ++ public void customName(final net.kyori.adventure.text.Component customName) { ++ final Scoreboard board = this.objective.checkState().board; ++ board.getOrCreatePlayerScore(this.entry, this.objective.getHandle()).display(io.papermc.paper.adventure.PaperAdventure.asVanilla(customName)); ++ } ++ // Paper end - add more score API + }