/* * 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 de.steamwar.Reflection; import de.steamwar.bausystem.BauSystem; import net.minecraft.network.protocol.game.ClientboundTickingStatePacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.ServerTickRateManager; import net.minecraft.world.TickRateManager; import org.bukkit.Bukkit; import org.bukkit.entity.Player; public class TickManager21 implements TickManager { private static final ServerTickRateManager manager = MinecraftServer.getServer().tickRateManager(); private static final Reflection.Field frozenTicksToRun = Reflection.getField(TickRateManager.class, int.class, 0); private static final Reflection.Field remainingSprintTicks = Reflection.getField(ServerTickRateManager.class, long.class, 0); private boolean blockTpsPacket = true; private int totalSteps; public TickManager21() { 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 boolean canFreeze() { return true; } @Override public void setBlockTpsPacket(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 (isFrozen()) { setFreeze(false); } manager.setTickRate(tickRate); } @Override public boolean isFrozen() { return manager.isFrozen(); } @Override public void setFreeze(boolean freeze) { manager.setFrozen(freeze); } @Override public void stepTicks(int ticks) { if (manager.isSprinting()) { manager.stopSprinting(); } else if (manager.isSteppingForward()) { manager.stopStepping(); } this.totalSteps = ticks; manager.setFrozen(true); manager.stepGameIfPaused(ticks); manager.setFrozen(false); Bukkit.getScheduler().runTaskTimer(BauSystem.getInstance(), (bukkitTask) -> { if (manager.isSteppingForward()) return; manager.setFrozen(true); bukkitTask.cancel(); }, 1, 1); } @Override public void sprintTicks(int ticks) { if (manager.isSteppingForward()) { manager.stopStepping(); } else if (manager.isSprinting()) { manager.stopSprinting(); } this.totalSteps = ticks; manager.requestGameToSprint(ticks, true); } @Override public boolean isSprinting() { return manager.isSprinting(); } @Override public boolean isStepping() { return manager.isSteppingForward(); } @Override public float getTickRate() { return manager.tickrate(); } @Override public long getRemainingTicks() { if (isSprinting()) { return remainingSprintTicks.get(manager); } else { return frozenTicksToRun.get(manager); } } @Override public long getDoneTicks() { return totalSteps - getRemainingTicks(); } @Override public long getTotalTicks() { return totalSteps; } }