/* This file is a part of the SteamWar software. Copyright (C) 2020 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.commands; import de.steamwar.bausystem.BauSystem; import de.steamwar.bausystem.CraftbukkitWrapper; import de.steamwar.bausystem.Permission; import de.steamwar.bausystem.world.TPSUtils; import de.steamwar.bausystem.world.Welt; import de.steamwar.command.SWCommand; import de.steamwar.command.SWCommandUtils; import de.steamwar.command.TypeMapper; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitTask; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class CommandTPSLimiter extends SWCommand { private static CommandTPSLimiter instance = null; { instance = this; } private static final World WORLD = Bukkit.getWorlds().get(0); private static double currentTPSLimit = 20; private long lastTime = System.nanoTime(); private long currentTime = System.nanoTime(); private double delay = 0; private int loops = 0; private long sleepDelay = 0; private BukkitTask tpsLimiter = null; private List tabCompletions = new ArrayList<>(Arrays.asList("0,5", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20")); public CommandTPSLimiter() { super("tpslimit"); if (TPSUtils.isWarpAllowed()) { for (int i = 20; i <= 60; i += 5) { tabCompletions.add(i + ""); } } } @Register(help = true) public void genericHelp(Player p, String... args) { p.sendMessage(BauSystem.PREFIX + "Jetziges TPS limit: " + currentTPSLimit); p.sendMessage("§8/§etpslimit §8[§7TPS§8|§edefault§8] §8- §7Setzte die TPS auf dem Bau"); } @Register({"default"}) public void defaultCommand(Player p) { if (!permissionCheck(p)) return; currentTPSLimit = 20; sendNewTPSLimitMessage(); tpsLimiter(); } @Register public void valueCommand(Player p, double tpsLimitDouble) { if (!permissionCheck(p)) return; if (tpsLimitDouble < 0.5 || tpsLimitDouble > (TPSUtils.isWarpAllowed() ? 60 : 20)) { sendInvalidArgumentMessage(p); return; } currentTPSLimit = tpsLimitDouble; sendNewTPSLimitMessage(); tpsLimiter(); } @ClassMapper(value = double.class, local = true) public TypeMapper doubleTypeMapper() { return SWCommandUtils.createMapper(s -> { try { return Double.parseDouble(s.replace(',', '.')); } catch (NumberFormatException e) { return 0D; } }, s -> tabCompletions); } private boolean permissionCheck(Player player) { if (Welt.noPermission(player, Permission.WORLD)) { player.sendMessage(BauSystem.PREFIX + "§cDu darfst hier nicht den TPS-Limiter nutzen"); return false; } return true; } private void sendNewTPSLimitMessage() { Bukkit.getOnlinePlayers().forEach(p -> p.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText("§eTPS limit auf " + currentTPSLimit + " gesetzt."))); } private void sendInvalidArgumentMessage(Player player) { player.sendMessage(BauSystem.PREFIX + "§cNur Zahlen zwischen 0,5 und " + (TPSUtils.isWarpAllowed() ? 60 : 20) + ", und 'default' erlaubt."); } private void tpsLimiter() { delay = 20 / currentTPSLimit; loops = (int) Math.ceil(delay); sleepDelay = (long) (50 * delay) / loops; TPSUtils.setTPS(currentTPSLimit); if (currentTPSLimit >= 20) { if (tpsLimiter == null) return; tpsLimiter.cancel(); tpsLimiter = null; } else { if (tpsLimiter != null) return; tpsLimiter = Bukkit.getScheduler().runTaskTimer(BauSystem.getPlugin(), () -> { CraftbukkitWrapper.impl.createTickCache(WORLD); for (int i = 0; i < loops; i++) { sleepUntilNextTick(sleepDelay); CraftbukkitWrapper.impl.sendTickPackets(); } }, 0, 1); } } private void sleepUntilNextTick(long neededDelta) { lastTime = currentTime; currentTime = System.nanoTime(); long timeDelta = (currentTime - lastTime) / 1000000; if (neededDelta - timeDelta < 0) return; try { Thread.sleep(neededDelta - timeDelta); currentTime = System.nanoTime(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } public static double getCurrentTPSLimit() { return (double) Math.round(currentTPSLimit * 10.0D) / 10.0D; } public static void setTPS(double d) { if (d < 0.5) d = 0.5; if (d > (TPSUtils.isWarpAllowed() ? 60 : 20)) d = (TPSUtils.isWarpAllowed() ? 60 : 20); if (instance != null) { currentTPSLimit = d; instance.tpsLimiter(); } } }