diff --git a/BauSystem/BauSystem_21/src/de/steamwar/bausystem/utils/NativeTickManager21.java b/BauSystem/BauSystem_21/src/de/steamwar/bausystem/utils/NativeTickManager21.java
new file mode 100644
index 00000000..80d9ce17
--- /dev/null
+++ b/BauSystem/BauSystem_21/src/de/steamwar/bausystem/utils/NativeTickManager21.java
@@ -0,0 +1,96 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2025 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.bausystem.utils;
+
+import com.comphenix.tinyprotocol.TinyProtocol;
+import net.minecraft.network.protocol.game.ClientboundTickingStatePacket;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.ServerTickRateManager;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+public class NativeTickManager21 implements NativeTickManager {
+ private static final ServerTickRateManager manager = MinecraftServer.getServer().tickRateManager();
+
+ private boolean blockTpsPacket = true;
+
+ public NativeTickManager21() {
+ TinyProtocol.instance.addFilter(ClientboundTickingStatePacket.class, this::blockPacket);
+ }
+
+ private Object blockPacket(Player player, Object packet) {
+ if (blockTpsPacket) {
+ return new ClientboundTickingStatePacket(20, manager.isFrozen());
+ } else {
+ return packet;
+ }
+ }
+
+ @Override
+ public void blockTpsPacket(boolean block) {
+ blockTpsPacket = block;
+ if (blockTpsPacket) {
+ ClientboundTickingStatePacket packet = new ClientboundTickingStatePacket(20, manager.isFrozen());
+ Bukkit.getOnlinePlayers().forEach(player -> TinyProtocol.instance.sendPacket(player, packet));
+ } else {
+ ClientboundTickingStatePacket packet = new ClientboundTickingStatePacket(manager.tickrate(), manager.isFrozen());
+ Bukkit.getOnlinePlayers().forEach(player -> TinyProtocol.instance.sendPacket(player, packet));
+ }
+ }
+
+ @Override
+ public void setTickRate(float tickRate) {
+ if (getFreezeState()) {
+ setFreeze(false);
+ }
+ manager.setTickRate(tickRate);
+ }
+
+ @Override
+ public boolean getFreezeState() {
+ return manager.isFrozen();
+ }
+
+ @Override
+ public void setFreeze(boolean freeze) {
+ manager.setFrozen(freeze);
+ manager.tick();
+ }
+
+ @Override
+ public void stepTick(int ticks) {
+ manager.stepGameIfPaused(ticks);
+ }
+
+ @Override
+ public void sprintTicks(int ticks) {
+ manager.requestGameToSprint(ticks, true);
+ }
+
+ @Override
+ public boolean isSprinting() {
+ return manager.isSprinting();
+ }
+
+ @Override
+ public float tickrate() {
+ return manager.tickrate();
+ }
+}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/TPSSystem.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/TPSSystem.java
index ac393e57..46dc7257 100644
--- a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/TPSSystem.java
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/TPSSystem.java
@@ -25,6 +25,7 @@ import de.steamwar.bausystem.SWUtils;
import de.steamwar.bausystem.linkage.specific.BauGuiItem;
import de.steamwar.bausystem.region.GlobalRegion;
import de.steamwar.bausystem.region.Region;
+import de.steamwar.bausystem.utils.NativeTickManager;
import de.steamwar.bausystem.utils.ScoreboardElement;
import de.steamwar.bausystem.utils.TickEndEvent;
import de.steamwar.bausystem.utils.bossbar.BauSystemBossbar;
@@ -40,6 +41,7 @@ import de.steamwar.linkage.Linked;
import de.steamwar.linkage.LinkedInstance;
import de.steamwar.linkage.MaxVersion;
import lombok.Getter;
+import lombok.Setter;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.boss.BarColor;
@@ -52,10 +54,9 @@ import org.bukkit.inventory.ItemStack;
import java.util.Arrays;
@Linked
-@MaxVersion(20) // Hotfix for 1.21 tps limit! -> Backport coming later
+@MaxVersion(20)
public class TPSSystem implements Listener {
- @Getter
private static double currentTPSLimit = 20;
public TPSSystem() {
@@ -66,7 +67,7 @@ public class TPSSystem implements Listener {
}
new TPSLimitCommand();
new TickLimitCommand();
- if (Core.getVersion() >= 15 && Core.getVersion() <= 20) { // If 1.21 support is not directly present
+ if (Core.getVersion() >= 15 && Core.getVersion() <= 20) {
new TPSWarpCommand();
new TickWarpCommand();
if (TPSFreezeUtils.isCanFreeze()) {
@@ -320,7 +321,14 @@ public class TPSSystem implements Listener {
@Override
public String get(Region region, Player p) {
- if (tpsSystem != null && tpsSystem.currentlyStepping) {
+ boolean isWarping = tpsSystem.currentlyStepping;
+ boolean isFrozen = TPSFreezeUtils.frozen();
+ if (Core.getVersion() >= 21) {
+ isWarping = NativeTickManager.impl.isSprinting();
+ isFrozen = NativeTickManager.impl.getFreezeState();
+ }
+
+ if (tpsSystem != null && isWarping) {
long time = System.currentTimeMillis() % 1000;
if (time < 250) {
return "§e" + BauSystem.MESSAGE.parse("SCOREBOARD_TPS", p) + "§8: §7•••";
@@ -331,7 +339,7 @@ public class TPSSystem implements Listener {
} else {
return "§e" + BauSystem.MESSAGE.parse("SCOREBOARD_TPS", p) + "§8: §7••§e•";
}
- } else if (TPSFreezeUtils.frozen()) {
+ } else if (isFrozen) {
return "§e" + BauSystem.MESSAGE.parse("SCOREBOARD_TPS", p) + "§8: " + BauSystem.MESSAGE.parse("SCOREBOARD_TPS_FROZEN", p);
} else {
return "§e" + BauSystem.MESSAGE.parse("SCOREBOARD_TPS", p) + "§8: " + tpsColor() + TPSWatcher.getTPSUnlimited(TPSWatcher.TPSType.ONE_SECOND) + tpsLimit();
@@ -357,6 +365,14 @@ public class TPSSystem implements Listener {
}
}
+ public static double getCurrentTPSLimit() {
+ if (Core.getVersion() >= 21) {
+ return NativeTickManager.impl.tickrate();
+ } else {
+ return currentTPSLimit;
+ }
+ }
+
@Linked
public static class TPSSystemBauGuiItem extends BauGuiItem {
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/modern/ModernTPSLimitCommand.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/modern/ModernTPSLimitCommand.java
new file mode 100644
index 00000000..4d2295c0
--- /dev/null
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/modern/ModernTPSLimitCommand.java
@@ -0,0 +1,68 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2025 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.bausystem.features.tpslimit.modern;
+
+import de.steamwar.bausystem.BauSystem;
+import de.steamwar.bausystem.utils.NativeTickManager;
+import de.steamwar.command.SWCommand;
+import de.steamwar.linkage.Linked;
+import de.steamwar.linkage.MinVersion;
+import org.bukkit.entity.Player;
+
+import static de.steamwar.bausystem.features.tpslimit.modern.ModernTickCommand.sendTickRateChange;
+
+@Linked
+@MinVersion(21)
+public class ModernTPSLimitCommand extends SWCommand {
+ public ModernTPSLimitCommand() {
+ super("tpslimit");
+ setMessage(BauSystem.MESSAGE);
+ addDefaultHelpMessage("TPSLIMIT_HELP");
+ }
+
+ @Register(value = "0", description = "TPSLIMIT_FREEZE_HELP")
+ public void freeze(@Validator Player player) {
+ NativeTickManager.impl.setFreeze(true);
+ sendTickRateChange();
+ }
+
+ @Register(description = "TPSLIMIT_LIMIT_HELP")
+ public void limit(@Validator Player player, @Min(doubleValue = 0.5) @Max(doubleValue = 20.0) float tpsLimit) {
+ NativeTickManager.impl.setTickRate(tpsLimit);
+ sendTickRateChange();
+ }
+
+ @Register(description = "TPSLIMIT_WARP_HELP")
+ public void warp(@Validator Player player, @Min(doubleValue = 20.0, inclusive = false) float tpsLimit) {
+ NativeTickManager.impl.setTickRate(tpsLimit);
+ sendTickRateChange();
+ }
+
+ @Register(description = "TPSLIMIT_HELP")
+ public void currentLimit(Player player) {
+ BauSystem.MESSAGE.send("TPSLIMIT_CURRENT", player, NativeTickManager.impl.tickrate());
+ }
+
+ @Register(value = "default", description = "TPSLIMIT_DEFAULT_HELP")
+ public void reset(@Validator Player player) {
+ NativeTickManager.impl.setTickRate(20);
+ sendTickRateChange();
+ }
+}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/modern/ModernTickCommand.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/modern/ModernTickCommand.java
new file mode 100644
index 00000000..057658b5
--- /dev/null
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/features/tpslimit/modern/ModernTickCommand.java
@@ -0,0 +1,99 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2025 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.bausystem.features.tpslimit.modern;
+
+import de.steamwar.bausystem.BauSystem;
+import de.steamwar.bausystem.SWUtils;
+import de.steamwar.bausystem.utils.NativeTickManager;
+import de.steamwar.command.SWCommand;
+import de.steamwar.linkage.Linked;
+import de.steamwar.linkage.MinVersion;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Listener;
+
+@Linked
+@MinVersion(21)
+public class ModernTickCommand extends SWCommand implements Listener {
+ public ModernTickCommand() {
+ super("tick");
+ setMessage(BauSystem.MESSAGE);
+ }
+
+ public static void sendTickRateChange() {
+ Bukkit.getOnlinePlayers().forEach(player -> {
+ if (NativeTickManager.impl.getFreezeState()) {
+ SWUtils.sendToActionbar(player, BauSystem.MESSAGE.parse("TPSLIMIT_FROZEN", player));
+ } else {
+ SWUtils.sendToActionbar(player, BauSystem.MESSAGE.parse("TPSLIMIT_SET", player, NativeTickManager.impl.tickrate()));
+ }
+ });
+ }
+
+ @Register(value = {"rate", "0"}, description = "TICK_FREEZE_HELP")
+ @Register(value = "freeze", description = "TICK_FREEZE_HELP_2")
+ public void freeze(@Validator Player player) {
+ NativeTickManager.impl.setFreeze(true);
+ sendTickRateChange();
+ }
+
+ @Register(value = "unfreeze", description = "TICK_UNFREEZE_HELP")
+ public void unfreeze(@Validator Player player) {
+ NativeTickManager.impl.setFreeze(false);
+ sendTickRateChange();
+ }
+
+ @Register(value = "step", description = "TICK_STEPPING_HELP")
+ public void step(@Validator Player player, @Min(intValue = 1) @OptionalValue("1") int steps) {
+ NativeTickManager.impl.stepTick(steps);
+ }
+
+ @Register(value = "warp", description = "TICK_WARP_HELP")
+ public void warp(@Validator Player player, @Min(intValue = 1) @OptionalValue("1") int steps) {
+ NativeTickManager.impl.sprintTicks(steps);
+ }
+
+ @Register(value = "rate", description = "TICK_LIMIT_HELP")
+ public void limit(@Validator Player player, @Min(doubleValue = 0.5, inclusive = false) float tpsLimit) {
+ NativeTickManager.impl.setTickRate(tpsLimit);
+ sendTickRateChange();
+ }
+
+ @Register(value = "rate", description = "TICK_HELP")
+ public void currentLimit(Player player) {
+ BauSystem.MESSAGE.send("TPSLIMIT_CURRENT", player, NativeTickManager.impl.tickrate());
+ }
+
+ @Register(value = {"rate", "default"}, description = "TICK_DEFAULT_HELP")
+ public void reset(@Validator Player player) {
+ NativeTickManager.impl.setTickRate(20);
+ sendTickRateChange();
+ }
+
+ @Register(value = "normalclient")
+ public void smooth(@Validator Player player) {
+ NativeTickManager.impl.blockTpsPacket(true);
+ }
+
+ @Register(value = "slowclient")
+ public void unsmooth(@Validator Player player) {
+ NativeTickManager.impl.blockTpsPacket(false);
+ }
+}
diff --git a/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/NativeTickManager.java b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/NativeTickManager.java
new file mode 100644
index 00000000..7dadf98f
--- /dev/null
+++ b/BauSystem/BauSystem_Main/src/de/steamwar/bausystem/utils/NativeTickManager.java
@@ -0,0 +1,36 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2025 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.bausystem.utils;
+
+import de.steamwar.bausystem.BauSystem;
+import de.steamwar.core.VersionDependent;
+
+public interface NativeTickManager {
+ NativeTickManager impl = VersionDependent.getVersionImpl(BauSystem.getInstance());
+
+ void setTickRate(float tickRate);
+ boolean getFreezeState();
+ void setFreeze(boolean freeze);
+ void stepTick(int ticks);
+ void sprintTicks(int ticks);
+ boolean isSprinting();
+ float tickrate();
+ void blockTpsPacket(boolean block);
+}