From 04940534bc439ae2dd0f6f87016a2d28b6d58b78 Mon Sep 17 00:00:00 2001 From: Esmorall Date: Sun, 8 Dec 2019 18:36:44 -0300 Subject: [PATCH] Added new experimental option (disable tick for untracked entities) --- EntityTrackerFixer/config.yml | 5 +- EntityTrackerFixer/plugin.yml | 2 +- .../entitytrackerfixer/CheckTask.java | 4 + .../EntityTrackerFixer.java | 11 +++ .../entitytrackerfixer/UntrackerTask.java | 4 + .../entitytrackerfixer/config/ConfigMain.java | 6 ++ .../entitytick/EntityTickManager.java | 88 +++++++++++++++++++ .../entitytick/EntityTickWorldCache.java | 31 +++++++ 8 files changed, 149 insertions(+), 2 deletions(-) create mode 100644 EntityTrackerFixer/src/net/minemora/entitytrackerfixer/entitytick/EntityTickManager.java create mode 100644 EntityTrackerFixer/src/net/minemora/entitytrackerfixer/entitytick/EntityTickWorldCache.java diff --git a/EntityTrackerFixer/config.yml b/EntityTrackerFixer/config.yml index 4854373..e17d20a 100644 --- a/EntityTrackerFixer/config.yml +++ b/EntityTrackerFixer/config.yml @@ -8,9 +8,12 @@ #Log when the plugin untrack entities log-to-console: true +#disable tick for untracked entities +disable-tick-for-untracked-entities: true + #How many ticks between untrack process #The untrack process will check for untracked entities by players but still by the server, and untrack them. -untrack-ticks: 600 +untrack-ticks: 400 #if tps are not below this value, the task will not perform the untrack and it will wait for the next run tps-limit: 18.5 diff --git a/EntityTrackerFixer/plugin.yml b/EntityTrackerFixer/plugin.yml index 602aaca..0d888a6 100644 --- a/EntityTrackerFixer/plugin.yml +++ b/EntityTrackerFixer/plugin.yml @@ -1,6 +1,6 @@ name: EntityTrackerFixer main: net.minemora.entitytrackerfixer.EntityTrackerFixer -version: 1.1 +version: 1.2.0 api-version: 1.14 author: Esmorall commands: diff --git a/EntityTrackerFixer/src/net/minemora/entitytrackerfixer/CheckTask.java b/EntityTrackerFixer/src/net/minemora/entitytrackerfixer/CheckTask.java index e822ebc..d833332 100644 --- a/EntityTrackerFixer/src/net/minemora/entitytrackerfixer/CheckTask.java +++ b/EntityTrackerFixer/src/net/minemora/entitytrackerfixer/CheckTask.java @@ -13,6 +13,7 @@ import org.bukkit.scheduler.BukkitRunnable; import net.minecraft.server.v1_14_R1.ChunkProviderServer; import net.minecraft.server.v1_14_R1.WorldServer; import net.minemora.entitytrackerfixer.config.ConfigMain; +import net.minemora.entitytrackerfixer.entitytick.EntityTickManager; public class CheckTask extends BukkitRunnable { @@ -40,6 +41,9 @@ public class CheckTask extends BukkitRunnable { for(Entity ent : player.getNearbyEntities(d, d, d)) { if(!cps.playerChunkMap.trackedEntities.containsKey(ent.getEntityId())) { trackAgain.add(((CraftEntity)ent).getHandle()); + if(ConfigMain.isDisableTickUntracked()) { + EntityTickManager.getInstance().enableTicking(((CraftEntity)ent).getHandle(), worldName); + } } } } diff --git a/EntityTrackerFixer/src/net/minemora/entitytrackerfixer/EntityTrackerFixer.java b/EntityTrackerFixer/src/net/minemora/entitytrackerfixer/EntityTrackerFixer.java index 0e4f303..17827ca 100644 --- a/EntityTrackerFixer/src/net/minemora/entitytrackerfixer/EntityTrackerFixer.java +++ b/EntityTrackerFixer/src/net/minemora/entitytrackerfixer/EntityTrackerFixer.java @@ -1,8 +1,11 @@ package net.minemora.entitytrackerfixer; +import org.bukkit.Bukkit; import org.bukkit.plugin.java.JavaPlugin; import net.minemora.entitytrackerfixer.config.ConfigMain; +import net.minemora.entitytrackerfixer.entitytick.EntityTickManager; +import net.minemora.entitytrackerfixer.entitytick.EntityTickWorldCache; public class EntityTrackerFixer extends JavaPlugin { @@ -12,6 +15,14 @@ public class EntityTrackerFixer extends JavaPlugin { public void onEnable() { plugin = this; ConfigMain.getInstance().setup(this); + if(ConfigMain.isDisableTickUntracked()) { + for(String worldName : ConfigMain.getWorlds()) { + if(Bukkit.getWorld(worldName) == null) { + continue; + } + EntityTickManager.getInstance().getCache().put(worldName, new EntityTickWorldCache(worldName)); + } + } new UntrackerTask().runTaskTimer(this, ConfigMain.getUntrackTicks(), ConfigMain.getUntrackTicks()); new CheckTask().runTaskTimer(this, ConfigMain.getUntrackTicks() + 1, ConfigMain.getCheckFrequency()); } diff --git a/EntityTrackerFixer/src/net/minemora/entitytrackerfixer/UntrackerTask.java b/EntityTrackerFixer/src/net/minemora/entitytrackerfixer/UntrackerTask.java index acdadd2..b624d6b 100644 --- a/EntityTrackerFixer/src/net/minemora/entitytrackerfixer/UntrackerTask.java +++ b/EntityTrackerFixer/src/net/minemora/entitytrackerfixer/UntrackerTask.java @@ -14,6 +14,7 @@ import net.minecraft.server.v1_14_R1.MinecraftServer; import net.minecraft.server.v1_14_R1.WorldServer; import net.minecraft.server.v1_14_R1.PlayerChunkMap.EntityTracker; import net.minemora.entitytrackerfixer.config.ConfigMain; +import net.minemora.entitytrackerfixer.entitytick.EntityTickManager; import net.minemora.entitytrackerfixer.util.ReflectionUtils; public class UntrackerTask extends BukkitRunnable { @@ -90,6 +91,9 @@ public class UntrackerTask extends BukkitRunnable { for(int id : toRemove) { cps.playerChunkMap.trackedEntities.remove(id); + if(ConfigMain.isDisableTickUntracked()) { + EntityTickManager.getInstance().disableTicking(id, worldName); + } } /* diff --git a/EntityTrackerFixer/src/net/minemora/entitytrackerfixer/config/ConfigMain.java b/EntityTrackerFixer/src/net/minemora/entitytrackerfixer/config/ConfigMain.java index 3de5b41..78a3aa7 100644 --- a/EntityTrackerFixer/src/net/minemora/entitytrackerfixer/config/ConfigMain.java +++ b/EntityTrackerFixer/src/net/minemora/entitytrackerfixer/config/ConfigMain.java @@ -14,6 +14,7 @@ public final class ConfigMain extends Config { private static int trackingRange; private static double minTps; private static boolean logToConsole = true; + private static boolean disableTickUntracked = true; private static List worlds = new ArrayList<>(); private ConfigMain() { @@ -28,6 +29,7 @@ public final class ConfigMain extends Config { minTps = getConfig().getDouble("tps-limit", 18.5); worlds = getConfig().getStringList("worlds"); logToConsole = getConfig().getBoolean("log-to-console", true); + disableTickUntracked = getConfig().getBoolean("disable-tick-for-untracked-entities", true); } public static FileConfiguration get() { @@ -69,4 +71,8 @@ public final class ConfigMain extends Config { public static boolean isLogToConsole() { return logToConsole; } + + public static boolean isDisableTickUntracked() { + return disableTickUntracked; + } } \ No newline at end of file diff --git a/EntityTrackerFixer/src/net/minemora/entitytrackerfixer/entitytick/EntityTickManager.java b/EntityTrackerFixer/src/net/minemora/entitytrackerfixer/entitytick/EntityTickManager.java new file mode 100644 index 0000000..4b2d18e --- /dev/null +++ b/EntityTrackerFixer/src/net/minemora/entitytrackerfixer/entitytick/EntityTickManager.java @@ -0,0 +1,88 @@ +package net.minemora.entitytrackerfixer.entitytick; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; + +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_14_R1.CraftWorld; + +import net.minecraft.server.v1_14_R1.WorldServer; +import net.minemora.entitytrackerfixer.UntrackerTask; +import net.minemora.entitytrackerfixer.util.ReflectionUtils; + +public class EntityTickManager extends TimerTask { + + private static Field tickingField; + + static { + try { + tickingField = ReflectionUtils.getClassPrivateField(WorldServer.class, "ticking"); + } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { + e.printStackTrace(); + } + } + + private static EntityTickManager instance; + + private Map cache = new HashMap<>(); + + private Timer timer; + + private EntityTickManager() { + this.timer = new Timer(); + timer.schedule(this, 2069, 2069); + } + + public void disableTicking(int id, String worldName) { + cache.get(worldName).getToTick().remove(id); + cache.get(worldName).getToUntick().add(id); + } + + public void enableTicking(net.minecraft.server.v1_14_R1.Entity entity, String worldName) { + cache.get(worldName).getToUntick().remove(entity.getId()); + cache.get(worldName).getToTick().put(entity.getId(), entity); + } + + @Override + public void run() { + if(UntrackerTask.isRunning()) { + return; + } + for(String worldName : cache.keySet()) { + WorldServer ws = ((CraftWorld)Bukkit.getWorld(worldName)).getHandle(); + try { + boolean ticking = tickingField.getBoolean(ws); + if(ticking) { + continue; + } + EntityTickWorldCache ewc = cache.get(worldName); + //System.out.println("unticking: " + ewc.getToUntick().size() + " entities, ticking again: " + ewc.getToTick().size() + " entities"); + for(int i : ewc.getToUntick()) { + ws.entitiesById.remove(i); + } + ewc.getToUntick().clear(); + for(int i : ewc.getToTick().keySet()) { + ws.entitiesById.put(i, ewc.getToTick().get(i)); + } + ewc.getToTick().clear(); + } catch (IllegalArgumentException | IllegalAccessException e) { + e.printStackTrace(); + } + } + } + + public static EntityTickManager getInstance() { + if(instance == null) { + instance = new EntityTickManager(); + } + return instance; + } + + public Map getCache() { + return cache; + } + +} diff --git a/EntityTrackerFixer/src/net/minemora/entitytrackerfixer/entitytick/EntityTickWorldCache.java b/EntityTrackerFixer/src/net/minemora/entitytrackerfixer/entitytick/EntityTickWorldCache.java new file mode 100644 index 0000000..3e745bb --- /dev/null +++ b/EntityTrackerFixer/src/net/minemora/entitytrackerfixer/entitytick/EntityTickWorldCache.java @@ -0,0 +1,31 @@ +package net.minemora.entitytrackerfixer.entitytick; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class EntityTickWorldCache { + + private String worldName; + + private Set toUntick = new HashSet<>(); + private Map toTick = new HashMap<>(); + + public EntityTickWorldCache(String worldName) { + this.worldName = worldName; + } + + public Set getToUntick() { + return toUntick; + } + + public Map getToTick() { + return toTick; + } + + public String getWorldName() { + return worldName; + } + +}