diff --git a/SpigotCore/SpigotCore_21/build.gradle.kts b/SpigotCore/SpigotCore_21/build.gradle.kts
new file mode 100644
index 00000000..b702534b
--- /dev/null
+++ b/SpigotCore/SpigotCore_21/build.gradle.kts
@@ -0,0 +1,33 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2024 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+plugins {
+ steamwar.java
+}
+
+dependencies {
+ compileOnly(project(":SpigotCore:SpigotCore_Main", "default"))
+
+ compileOnly(libs.paperapi21) {
+ attributes {
+ // Very Hacky, but it works
+ attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 21)
+ }
+ }
+}
diff --git a/SpigotCore/SpigotCore_21/src/de/steamwar/scoreboard/SWScoreboard21.java b/SpigotCore/SpigotCore_21/src/de/steamwar/scoreboard/SWScoreboard21.java
new file mode 100644
index 00000000..0834e166
--- /dev/null
+++ b/SpigotCore/SpigotCore_21/src/de/steamwar/scoreboard/SWScoreboard21.java
@@ -0,0 +1,74 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2024 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.scoreboard;
+
+import de.steamwar.core.Core;
+import net.kyori.adventure.text.Component;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import org.bukkit.scoreboard.DisplaySlot;
+import org.bukkit.scoreboard.Objective;
+import org.bukkit.scoreboard.Scoreboard;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class SWScoreboard21 implements SWScoreboard.ISWScoreboard {
+
+ private static final HashMap playerBoards = new HashMap<>();
+ private static final String SIDEBAR = "sw-sidebar";
+
+ static {
+ Bukkit.getScheduler().runTaskTimer(Core.getInstance(), () -> {
+ for(Map.Entry scoreboard : playerBoards.entrySet()) {
+ render(scoreboard.getKey(), scoreboard.getValue());
+ }
+ }, 5, 10);
+ }
+
+ private static void render(Player player, ScoreboardCallback callback) {
+ if (player.getScoreboard().getObjective(SIDEBAR) != null) {
+ player.getScoreboard().getObjective(SIDEBAR).unregister();
+ }
+
+ Objective objective = player.getScoreboard().registerNewObjective(SIDEBAR, "dummy", Component.text(callback.getTitle()));
+ objective.setAutoUpdateDisplay(true);
+ objective.setDisplaySlot(DisplaySlot.SIDEBAR);
+
+ callback.getData().forEach((text, score) -> objective.getScore(text).setScore(score));
+ }
+
+ @Override
+ public boolean createScoreboard(Player player, ScoreboardCallback callback) {
+ Scoreboard scoreboard = Bukkit.getScoreboardManager().getNewScoreboard();
+ player.setScoreboard(scoreboard);
+
+ render(player, callback);
+
+ playerBoards.put(player, callback);
+ return true;
+ }
+
+ @Override
+ public void removeScoreboard(Player player) {
+ player.getScoreboard().getObjective(SIDEBAR).unregister();
+ playerBoards.remove(player);
+ }
+}
diff --git a/SpigotCore/SpigotCore_8/src/de/steamwar/scoreboard/SWScoreboard8.java b/SpigotCore/SpigotCore_8/src/de/steamwar/scoreboard/SWScoreboard8.java
new file mode 100644
index 00000000..3af0fc93
--- /dev/null
+++ b/SpigotCore/SpigotCore_8/src/de/steamwar/scoreboard/SWScoreboard8.java
@@ -0,0 +1,115 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2024 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.scoreboard;
+
+import com.comphenix.tinyprotocol.Reflection;
+import com.comphenix.tinyprotocol.TinyProtocol;
+import de.steamwar.core.Core;
+import de.steamwar.core.FlatteningWrapper;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class SWScoreboard8 implements SWScoreboard.ISWScoreboard {
+ private static final Reflection.FieldAccessor scoreboardName = Reflection.getField(FlatteningWrapper.scoreboardObjective, String.class, 0);
+ private static final Reflection.FieldAccessor scoreboardAction = Reflection.getField(FlatteningWrapper.scoreboardObjective, int.class, Core.getVersion() > 15 ? 3 : 0);
+ private static final Class> scoreboardDisplayEnum = Reflection.getClass("{nms.world.scores.criteria}.IScoreboardCriteria$EnumScoreboardHealthDisplay");
+ private static final Reflection.FieldAccessor> scoreboardDisplayType = Reflection.getField(FlatteningWrapper.scoreboardObjective, scoreboardDisplayEnum, 0);
+ private static final Object displayTypeIntegers = scoreboardDisplayEnum.getEnumConstants()[0];
+
+ private static final Reflection.FieldAccessor scoreName = Reflection.getField(FlatteningWrapper.scoreboardScore, String.class, 0);
+ private static final Reflection.FieldAccessor scoreScoreboardName = Reflection.getField(FlatteningWrapper.scoreboardScore, String.class, 1);
+ private static final Reflection.FieldAccessor scoreValue = Reflection.getField(FlatteningWrapper.scoreboardScore, int.class, 0);
+
+ private static final HashMap playerBoards = new HashMap<>(); //Object -> Scoreboard | Alle Versionen in der Map!
+ private static int toggle = 0; // Scoreboard 0 updates while scoreboard 1 is presenting. toggle marks the current active scoreboard
+
+ private static final String SIDEBAR = "Sidebar";
+ private static final Object[] DELETE_SCOREBOARD = new Object[2];
+ private static final Object[] DISPLAY_SIDEBAR = new Object[2];
+
+ static {
+ Class> scoreboardDisplayObjective = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutScoreboardDisplayObjective");
+ Reflection.FieldAccessor scoreboardDisplayName = Reflection.getField(scoreboardDisplayObjective, String.class, 0);
+ Reflection.FieldAccessor scoreboardDisplaySlot = Reflection.getField(scoreboardDisplayObjective, int.class, 0);
+ for(int id = 0; id < 2; id++) {
+ DELETE_SCOREBOARD[id] = Reflection.newInstance(FlatteningWrapper.scoreboardObjective);
+ scoreboardName.set(DELETE_SCOREBOARD[id], SIDEBAR + id);
+ scoreboardAction.set(DELETE_SCOREBOARD[id], 1); //1 to remove
+
+ DISPLAY_SIDEBAR[id] = Reflection.newInstance(scoreboardDisplayObjective);
+ scoreboardDisplayName.set(DISPLAY_SIDEBAR[id], SIDEBAR + id);
+ scoreboardDisplaySlot.set(DISPLAY_SIDEBAR[id], 1); // 1 = Sidebar
+ }
+
+ Bukkit.getScheduler().runTaskTimer(Core.getInstance(), () -> {
+ toggle ^= 1; // Toggle between 0 and 1
+
+ for(Map.Entry scoreboard : playerBoards.entrySet()) {
+ Player player = scoreboard.getKey();
+ ScoreboardCallback callback = scoreboard.getValue();
+
+ TinyProtocol.instance.sendPacket(player, DELETE_SCOREBOARD[toggle]);
+ TinyProtocol.instance.sendPacket(player, createSidebarPacket(callback.getTitle()));
+ for(Map.Entry score : callback.getData().entrySet()){
+ TinyProtocol.instance.sendPacket(player, createScorePacket(score.getKey(), score.getValue()));
+ }
+
+ Bukkit.getScheduler().runTaskLater(Core.getInstance(), () -> {
+ if(!player.isOnline())
+ return;
+ TinyProtocol.instance.sendPacket(player, DISPLAY_SIDEBAR[toggle]);
+ }, 2);
+ }
+ }, 10, 5);
+ }
+
+ public boolean createScoreboard(Player player, ScoreboardCallback callback) {
+ playerBoards.put(player, callback);
+ return true;
+ }
+
+ public void removeScoreboard(Player player) {
+ if(playerBoards.remove(player) == null || !player.isOnline())
+ return;
+
+ TinyProtocol.instance.sendPacket(player, DELETE_SCOREBOARD[toggle]);
+ }
+
+ private static Object createSidebarPacket(String name){
+ Object packet = Reflection.newInstance(FlatteningWrapper.scoreboardObjective);
+ scoreboardName.set(packet, SIDEBAR + toggle);
+ scoreboardAction.set(packet, 0); //0 to create
+ FlatteningWrapper.impl.setScoreboardTitle(packet, name);
+ scoreboardDisplayType.set(packet, displayTypeIntegers);
+ return packet;
+ }
+
+ private static Object createScorePacket(String name, int value){
+ Object packet = Reflection.newInstance(FlatteningWrapper.scoreboardScore);
+ scoreName.set(packet, name);
+ scoreScoreboardName.set(packet, SIDEBAR + toggle);
+ scoreValue.set(packet, value);
+ FlatteningWrapper.impl.setScoreAction(packet);
+ return packet;
+ }
+}
diff --git a/SpigotCore/SpigotCore_Main/src/de/steamwar/scoreboard/SWScoreboard.java b/SpigotCore/SpigotCore_Main/src/de/steamwar/scoreboard/SWScoreboard.java
index 440e29a0..5fd8808e 100644
--- a/SpigotCore/SpigotCore_Main/src/de/steamwar/scoreboard/SWScoreboard.java
+++ b/SpigotCore/SpigotCore_Main/src/de/steamwar/scoreboard/SWScoreboard.java
@@ -19,99 +19,25 @@
package de.steamwar.scoreboard;
-import com.comphenix.tinyprotocol.Reflection;
-import com.comphenix.tinyprotocol.TinyProtocol;
import de.steamwar.core.Core;
-import de.steamwar.core.FlatteningWrapper;
-import org.bukkit.Bukkit;
+import de.steamwar.core.VersionDependent;
import org.bukkit.entity.Player;
-import java.util.HashMap;
-import java.util.Map;
-
public class SWScoreboard {
private SWScoreboard() {}
- private static final Reflection.FieldAccessor scoreboardName = Reflection.getField(FlatteningWrapper.scoreboardObjective, String.class, 0);
- private static final Reflection.FieldAccessor scoreboardAction = Reflection.getField(FlatteningWrapper.scoreboardObjective, int.class, Core.getVersion() > 15 ? 3 : 0);
- private static final Class> scoreboardDisplayEnum = Reflection.getClass("{nms.world.scores.criteria}.IScoreboardCriteria$EnumScoreboardHealthDisplay");
- private static final Reflection.FieldAccessor> scoreboardDisplayType = Reflection.getField(FlatteningWrapper.scoreboardObjective, scoreboardDisplayEnum, 0);
- private static final Object displayTypeIntegers = scoreboardDisplayEnum.getEnumConstants()[0];
-
- private static final Reflection.FieldAccessor scoreName = Reflection.getField(FlatteningWrapper.scoreboardScore, String.class, 0);
- private static final Reflection.FieldAccessor scoreScoreboardName = Reflection.getField(FlatteningWrapper.scoreboardScore, String.class, 1);
- private static final Reflection.FieldAccessor scoreValue = Reflection.getField(FlatteningWrapper.scoreboardScore, int.class, 0);
-
- private static final HashMap playerBoards = new HashMap<>(); //Object -> Scoreboard | Alle Versionen in der Map!
- private static int toggle = 0; // Scoreboard 0 updates while scoreboard 1 is presenting. toggle marks the current active scoreboard
-
- private static final String SIDEBAR = "Sidebar";
- private static final Object[] DELETE_SCOREBOARD = new Object[2];
- private static final Object[] DISPLAY_SIDEBAR = new Object[2];
-
- static {
- Class> scoreboardDisplayObjective = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutScoreboardDisplayObjective");
- Reflection.FieldAccessor scoreboardDisplayName = Reflection.getField(scoreboardDisplayObjective, String.class, 0);
- Reflection.FieldAccessor scoreboardDisplaySlot = Reflection.getField(scoreboardDisplayObjective, int.class, 0);
- for(int id = 0; id < 2; id++) {
- DELETE_SCOREBOARD[id] = Reflection.newInstance(FlatteningWrapper.scoreboardObjective);
- scoreboardName.set(DELETE_SCOREBOARD[id], SIDEBAR + id);
- scoreboardAction.set(DELETE_SCOREBOARD[id], 1); //1 to remove
-
- DISPLAY_SIDEBAR[id] = Reflection.newInstance(scoreboardDisplayObjective);
- scoreboardDisplayName.set(DISPLAY_SIDEBAR[id], SIDEBAR + id);
- scoreboardDisplaySlot.set(DISPLAY_SIDEBAR[id], 1); // 1 = Sidebar
- }
-
- Bukkit.getScheduler().runTaskTimer(Core.getInstance(), () -> {
- toggle ^= 1; // Toggle between 0 and 1
-
- for(Map.Entry scoreboard : playerBoards.entrySet()) {
- Player player = scoreboard.getKey();
- ScoreboardCallback callback = scoreboard.getValue();
-
- TinyProtocol.instance.sendPacket(player, DELETE_SCOREBOARD[toggle]);
- TinyProtocol.instance.sendPacket(player, createSidebarPacket(callback.getTitle()));
- for(Map.Entry score : callback.getData().entrySet()){
- TinyProtocol.instance.sendPacket(player, createScorePacket(score.getKey(), score.getValue()));
- }
-
- Bukkit.getScheduler().runTaskLater(Core.getInstance(), () -> {
- if(!player.isOnline())
- return;
- TinyProtocol.instance.sendPacket(player, DISPLAY_SIDEBAR[toggle]);
- }, 2);
- }
- }, 10, 5);
- }
+ private static final ISWScoreboard impl = VersionDependent.getVersionImpl(Core.getInstance());
public static boolean createScoreboard(Player player, ScoreboardCallback callback) {
- playerBoards.put(player, callback);
- return true;
+ return impl.createScoreboard(player, callback);
}
public static void removeScoreboard(Player player) {
- if(playerBoards.remove(player) == null || !player.isOnline())
- return;
-
- TinyProtocol.instance.sendPacket(player, DELETE_SCOREBOARD[toggle]);
+ impl.removeScoreboard(player);
}
- private static Object createSidebarPacket(String name){
- Object packet = Reflection.newInstance(FlatteningWrapper.scoreboardObjective);
- scoreboardName.set(packet, SIDEBAR + toggle);
- scoreboardAction.set(packet, 0); //0 to create
- FlatteningWrapper.impl.setScoreboardTitle(packet, name);
- scoreboardDisplayType.set(packet, displayTypeIntegers);
- return packet;
- }
-
- private static Object createScorePacket(String name, int value){
- Object packet = Reflection.newInstance(FlatteningWrapper.scoreboardScore);
- scoreName.set(packet, name);
- scoreScoreboardName.set(packet, SIDEBAR + toggle);
- scoreValue.set(packet, value);
- FlatteningWrapper.impl.setScoreAction(packet);
- return packet;
+ public interface ISWScoreboard {
+ boolean createScoreboard(Player player, ScoreboardCallback callback);
+ void removeScoreboard(Player player);
}
}
diff --git a/SpigotCore/build.gradle.kts b/SpigotCore/build.gradle.kts
index 3838522b..b7ff647e 100644
--- a/SpigotCore/build.gradle.kts
+++ b/SpigotCore/build.gradle.kts
@@ -40,4 +40,5 @@ dependencies {
implementation(project(":SpigotCore:SpigotCore_18"))
implementation(project(":SpigotCore:SpigotCore_19"))
implementation(project(":SpigotCore:SpigotCore_20"))
+ implementation(project(":SpigotCore:SpigotCore_21"))
}
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 2379d8bd..4b92c2ba 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -203,6 +203,7 @@ include(
"SpigotCore:SpigotCore_18",
"SpigotCore:SpigotCore_19",
"SpigotCore:SpigotCore_20",
+ "SpigotCore:SpigotCore_21",
"SpigotCore:SpigotCore_Main"
)