From 541e9aa456cb3cf00acb55d6827db5eeedfa86b3 Mon Sep 17 00:00:00 2001 From: Stefatorus Date: Tue, 21 Sep 2021 17:15:33 +0300 Subject: [PATCH] Added min-stack, spawn reasons to stacker. --- plugin.yml | 2 +- server.yml | 16 +++- src/cx/sfy/LagAssist/Main.java | 4 +- src/cx/sfy/LagAssist/client/ClientMain.java | 4 +- src/cx/sfy/LagAssist/client/ClientPacket.java | 34 ++++--- .../LagAssist/microfeatures/AdvertRunner.java | 1 - src/cx/sfy/LagAssist/stacker/StackChunk.java | 95 +++++++++++++------ .../sfy/LagAssist/stacker/StackManager.java | 37 +++++++- 8 files changed, 141 insertions(+), 52 deletions(-) diff --git a/plugin.yml b/plugin.yml index e08d2eb..27c8563 100644 --- a/plugin.yml +++ b/plugin.yml @@ -1,6 +1,6 @@ name: LagAssist author: Stefatorus -version: 2.24.2 +version: 2.25.0 api-version: 1.13 description: LagAssist is an advanced anti-lag solution that allows server owners find and remove lag using multiple advanced and efficient methods. main: cx.sfy.LagAssist.Main diff --git a/server.yml b/server.yml index c9879d3..f5724b9 100644 --- a/server.yml +++ b/server.yml @@ -78,6 +78,11 @@ smart-stacker: tag-visibility: true # Size is required if you want stacking to work. tag-format: "&f{type} &cx{size}" + # What spawn reasons should be allowed for mob stacking. + # Use ALL to allow all mobs to stack, or alternatively use any value from here: + # VALUES: https://hub.spigotmc.org/javadocs/spigot/org/bukkit/event/entity/CreatureSpawnEvent.SpawnReason.html + spawn-reasons: + - "ALL" # What entity types you want to be stackable. stackable: # - "SKELETON" @@ -105,6 +110,15 @@ smart-stacker: # What's the highest amount a stack can get to? Since there's a limit of 1 stack per # split, it's useful to keep this higher. max-stack: 500 + # The min-stack feature allows you how many mobs should be in a split before attempting to stack them. + # This can help retain some vanilla behaviour, but will have a negative effect on performance. Due to + # popular demand, it was added as the overall stacker should STILL be better performance wise than the + # alternatives, but don't set a min stack size if performance is your key concern. + # + # (!) To still have a good performance impact, LagAssist uses caching, which may result in the actually + # mob counts that are checked to stack to slightly differ. This should not be very noticeable. + # + min-stack: 0 # This section deals with custom handling for damage for stacked mobs. damage: # What damage causes should be multiplied by the stack count. @@ -764,4 +778,4 @@ hooks: # What message should show up to players that get paid. %amount% for paid amount. message: "&c&lLag&f&lAssist &e» &fYou were paid %amount% in the paywave." # This allows the system to update the config if the plugin is updated. -version: 30 \ No newline at end of file +version: 31 \ No newline at end of file diff --git a/src/cx/sfy/LagAssist/Main.java b/src/cx/sfy/LagAssist/Main.java index f80d509..254853e 100644 --- a/src/cx/sfy/LagAssist/Main.java +++ b/src/cx/sfy/LagAssist/Main.java @@ -56,7 +56,7 @@ public class Main extends JavaPlugin implements Listener { p = this; file = new File(getDataFolder(), "server.yml"); - config = Others.getConfig(file, 29); + config = Others.getConfig(file, 31); paper = VersionMgr.isPaper(); @@ -106,7 +106,7 @@ public class Main extends JavaPlugin implements Listener { } public static void ReloadPlugin(CommandSender s) { - config = Others.getConfig(file, 29); + config = Others.getConfig(file, 31); Bukkit.getLogger().info(Main.PREFIX + "Reloading Systems:"); EnableClasses(true); diff --git a/src/cx/sfy/LagAssist/client/ClientMain.java b/src/cx/sfy/LagAssist/client/ClientMain.java index a7d96e5..b195565 100644 --- a/src/cx/sfy/LagAssist/client/ClientMain.java +++ b/src/cx/sfy/LagAssist/client/ClientMain.java @@ -15,6 +15,7 @@ import cx.sfy.LagAssist.cmd.ClientCmdListener; import cx.sfy.LagAssist.gui.DataGUI; import cx.sfy.LagAssist.packets.Reflection; import cx.sfy.LagAssist.utils.Others; +import cx.sfy.LagAssist.utils.VersionMgr; import net.md_5.bungee.api.ChatColor; public class ClientMain implements Listener { @@ -79,7 +80,8 @@ public class ClientMain implements Listener { Reflection.getCommandMap().register(Main.p.getDescription().getName(), cmd); Main.p.getCommand(ClientMain.command).setExecutor(new ClientCmdListener()); - Bukkit.getLogger().info(" §e[§a✔§e] §fClient Optimizer."); + Bukkit.getLogger().info(" §e[§a✔§e] §fClient Optimizer. " + (VersionMgr.isV_17Plus() ? " EXPERIMENTAL SUPPORT 1.17+" : "")); + } diff --git a/src/cx/sfy/LagAssist/client/ClientPacket.java b/src/cx/sfy/LagAssist/client/ClientPacket.java index 9c95551..2aee8c5 100644 --- a/src/cx/sfy/LagAssist/client/ClientPacket.java +++ b/src/cx/sfy/LagAssist/client/ClientPacket.java @@ -1,8 +1,8 @@ package cx.sfy.LagAssist.client; +import java.util.ArrayList; import java.util.UUID; -import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; @@ -26,39 +26,42 @@ public class ClientPacket { } try { String name = msg.getClass().getSimpleName().toLowerCase(); + String entitytype = null; if (name.equals("packetplayoutspawnentity") && (ClientGUI.isOn(ToggleState.TNT, p) || ClientGUI.isOn(ToggleState.SAND, p))) { - Entity ent; if (VersionMgr.isV1_8()) { int x = ((int) Reflection.getFieldValue(msg, "b")) / 32; int y = ((int) Reflection.getFieldValue(msg, "c")) / 32; int z = ((int) Reflection.getFieldValue(msg, "d")) / 32; Location loc = new Location(p.getWorld(), x, y, z); - ent = Reflection.getEntity(loc); + entitytype = Reflection.getEntity(loc).getType().toString(); } else if (VersionMgr.isV1_17()) { - UUID u = (UUID) Reflection.getFieldValue(msg, "d"); - ent = Bukkit.getEntity(u); - } if (VersionMgr.isNewMaterials()) { + Object entitytypes = Reflection.getFieldValue(msg, "m"); + entitytypes = Reflection.getFieldValue(entitytypes, "bv"); + + entitytype = entitytypes == null ? "unknown" : entitytypes.toString(); + } else if (VersionMgr.isNewMaterials()) { + // TODO: SYNC METHOD FIX MAY CAUSE MAJOR LAG! UUID u = (UUID) Reflection.getFieldValue(msg, "b"); - ent = Bukkit.getEntity(u); + entitytype = getEntityAsync(p, u).getType().toString().toUpperCase(); } else { double x = ((double) Reflection.getFieldValue(msg, "c")); double y = ((double) Reflection.getFieldValue(msg, "d")); double z = ((double) Reflection.getFieldValue(msg, "e")); Location loc = new Location(p.getWorld(), x, y, z); - ent = Reflection.getEntity(loc); + entitytype = Reflection.getEntity(loc).getType().toString(); } - if (ent == null) { + if (entitytype == null) { return false; } + - String type = ent.getType().toString(); - if (type == "PRIMED_TNT") { + if (entitytype.contains("tnt")) { return ClientGUI.isOn(ToggleState.TNT, p); - } else if (type == "FALLING_BLOCK") { + } else if (entitytype.contains("falling_block")) { return ClientGUI.isOn(ToggleState.SAND, p); } } else if (name.equals("packetplayoutworldparticles")) { @@ -84,5 +87,12 @@ public class ClientPacket { return false; } + + private static Entity getEntityAsync(Player p, UUID u) { + for (Entity ent : new ArrayList<>(p.getWorld().getEntities())) { + if (ent.getUniqueId() == u) return ent; + } + return null; + } } diff --git a/src/cx/sfy/LagAssist/microfeatures/AdvertRunner.java b/src/cx/sfy/LagAssist/microfeatures/AdvertRunner.java index df54674..8105518 100644 --- a/src/cx/sfy/LagAssist/microfeatures/AdvertRunner.java +++ b/src/cx/sfy/LagAssist/microfeatures/AdvertRunner.java @@ -10,7 +10,6 @@ import org.bukkit.plugin.messaging.PluginMessageListener; import cx.sfy.LagAssist.Data; import cx.sfy.LagAssist.Main; import cx.sfy.LagAssist.utils.Chat; -import net.minecraft.server.v1_12_R1.AdvancementProgress.a; public class AdvertRunner implements Listener, PluginMessageListener { diff --git a/src/cx/sfy/LagAssist/stacker/StackChunk.java b/src/cx/sfy/LagAssist/stacker/StackChunk.java index 2b45222..794ac75 100644 --- a/src/cx/sfy/LagAssist/stacker/StackChunk.java +++ b/src/cx/sfy/LagAssist/stacker/StackChunk.java @@ -2,8 +2,10 @@ package cx.sfy.LagAssist.stacker; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -17,6 +19,7 @@ import org.bukkit.entity.EntityType; import org.bukkit.entity.LivingEntity; import org.bukkit.event.entity.EntityDeathEvent; import org.bukkit.inventory.ItemStack; +import org.bukkit.metadata.FixedMetadataValue; import cx.sfy.LagAssist.Main; import cx.sfy.LagAssist.utils.MathUtils; @@ -31,22 +34,22 @@ public class StackChunk { public static String regexpat = ""; private static int splits = 8; - private Map>[] ents; - + private Map>[] ents; + public static void Enabler() { splits = Main.config.getInt("smart-stacker.technical.splits"); nameformat = ChatColor.translateAlternateColorCodes('&', Main.config.getString("smart-stacker.gameplay.tag-format")); regexpat = nameformat.replace("{size}", "(.*.)"); } - + @SuppressWarnings("unchecked") public StackChunk(Chunk chk) { - ents = (Map>[]) new HashMap[256 / splits]; + ents = (Map>[]) new HashMap[256 / splits]; for (int i = 0; i < 256 / splits; i++) { - ents[i] = new HashMap>(); + ents[i] = new HashMap>(); } } @@ -54,7 +57,7 @@ public class StackChunk { // kept alive. public static boolean tryStacking(Location loc, EntityType type, Entity optional) { Chunk chk = loc.getChunk(); - + StackChunk stchk; if (chunks.containsKey(chk)) { @@ -82,7 +85,7 @@ public class StackChunk { Entity free = getMatch(stchk.ents[split], loc, type, optional); size += getStack(free); - + Main.sendDebug("FINAL SIZE: " + size, 2); consumed = (free.equals(optional)) ? false : true; @@ -116,47 +119,55 @@ public class StackChunk { return consumed; } - private static Entity getMatch(Map> ents, Location loc, EntityType type, + private static Entity getMatch(Map> ents, Location loc, EntityType type, Entity optional) { if (!ents.containsKey(type)) { - ents.put(type, new ArrayList()); + ents.put(type, new HashSet()); } - List list = ents.get(type); + Set list = ents.get(type); Entity ideal = null; if (optional == null) { - if (list.isEmpty()) { + if (list.isEmpty() || isUnderMinimum(list)) { ideal = loc.getWorld().spawnEntity(loc, type); list.add(ideal); return ideal; } else { - return list.get(0); + return list.iterator().next(); } + } else if (isUnderMinimum(list)) { + list.add(optional); + return optional; } - + for (Entity ent : list) { boolean similar = StackComparer.isSimilar(ent, optional); if (similar) { return ent; } } - + list.add(optional); return optional; + } public static int getStack(Entity ent) { if (!StackManager.smartstacker) { return 0; } - + if (ent == null) { return 0; } - + + if (ent.hasMetadata("lagassist.stacksize")) { + return ent.getMetadata("lagassist.stacksize").get(0).asInt(); + } + String name = ent.getCustomName(); if (name == null) { @@ -165,7 +176,7 @@ public class StackChunk { Pattern pat = Pattern.compile(regexpat.replace("{type}", Others.firstHighcase(ent.getType().toString())), Pattern.MULTILINE); - + Matcher match = pat.matcher(name); if (!match.find()) { @@ -185,6 +196,7 @@ public class StackChunk { String formatted = nameformat.replace("{type}", Others.firstHighcase(ent.getType().toString())) .replace("{size}", "" + Math.min(size, Main.config.getInt("smart-stacker.technical.max-stack"))); + ent.setMetadata("lagassist.stacksize", new FixedMetadataValue(Main.p, size)); ent.setCustomName(formatted); ent.setCustomNameVisible(Main.config.getBoolean("smart-stacker.gameplay.tag-visibility")); } @@ -201,7 +213,7 @@ public class StackChunk { if (stack < 2) { return; } - + List drops = new ArrayList(); for (ItemStack itm : e.getDrops()) { @@ -216,7 +228,7 @@ public class StackChunk { e.getDrops().clear(); e.getDrops().addAll(drops); - e.setDroppedExp(e.getDroppedExp()*stack); + e.setDroppedExp(e.getDroppedExp() * stack); } public static void runShutdown() { @@ -225,7 +237,7 @@ public class StackChunk { } for (StackChunk chk : chunks.values()) { for (int i = 0; i < splits; i++) { - for (List elist : chk.ents[i].values()) { + for (Set elist : chk.ents[i].values()) { for (Entity ent : elist) { ent.remove(); } @@ -262,25 +274,50 @@ public class StackChunk { } } } - + public static void unloadChunk(Chunk chk) { StackChunk stack = chunks.get(chk); - + if (stack == null) { return; } - - for (Map> m : stack.ents) { - for (ArrayList types : m.values()) { + + for (Map> m : stack.ents) { + for (HashSet types : m.values()) { for (Entity ent : types) { ent.remove(); } } } - + chunks.remove(chk); - - + + } + + /* + * Implement min stack feature in beta. + * + * TODO: TEST FUNCTIONALITY + */ + protected static boolean isUnderMinimum(Set ents) { + int minstack = Main.config.getInt("smart-stacker.technical.min-stack"); + + if (minstack <= 1) { + return false; + } + + int stacktotal = getStackTotal(ents); + + return minstack > 0 && stacktotal < minstack; + } + + private static int getStackTotal(Set ents) { + int total = 0; + for (Entity ent : ents) { + total += getStack(ent); + } + + return total; } // Setting clean to true makes it force it; @@ -291,7 +328,7 @@ public class StackChunk { StackChunk stchk = chunks.get(chk); - if (!stchk.ents[split].containsKey(ent)) { + if (!stchk.ents[split].containsKey(ent) || isUnderMinimum(stchk.ents[split].get(ent))) { return; } diff --git a/src/cx/sfy/LagAssist/stacker/StackManager.java b/src/cx/sfy/LagAssist/stacker/StackManager.java index 63f4005..1887c7c 100644 --- a/src/cx/sfy/LagAssist/stacker/StackManager.java +++ b/src/cx/sfy/LagAssist/stacker/StackManager.java @@ -13,6 +13,7 @@ import org.bukkit.event.Cancellable; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; +import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.EntityDeathEvent; import org.bukkit.event.entity.EntitySpawnEvent; import org.bukkit.event.inventory.PrepareAnvilEvent; @@ -20,6 +21,7 @@ import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.event.world.ChunkUnloadEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.metadata.FixedMetadataValue; import cx.sfy.LagAssist.Main; import cx.sfy.LagAssist.stacker.StackMonitor.SplitChangeEvent; @@ -61,6 +63,23 @@ public class StackManager implements Listener { StackChunk.runShutdown(); } + @EventHandler(priority = EventPriority.LOW) + public void onCreatureSpawn(CreatureSpawnEvent e) { + if (e.isCancelled()) { + return; + } + + if (!smartstacker) { + return; + } + + if (WorldMgr.isBlacklisted(e.getLocation().getWorld())) { + return; + } + + e.getEntity().setMetadata("lagassist.spawnreason", new FixedMetadataValue(Main.p, e.getSpawnReason())); + } + @EventHandler(priority = EventPriority.HIGH) public void onSpawn(EntitySpawnEvent e) { @@ -81,12 +100,12 @@ public class StackManager implements Listener { return; } + Entity ent = e.getEntity(); + if (!Main.config.getBoolean("smart-stacker.checks.spawn-check")) { return; } - Entity ent = e.getEntity(); - // if (!(ent instanceof LivingEntity)) { // return; // } @@ -242,7 +261,7 @@ public class StackManager implements Listener { StackChunk.unloadChunk(chk); } - + public static boolean isStackable(Entity ent) { if (ent == null) { return false; @@ -256,11 +275,19 @@ public class StackManager implements Listener { return false; } - if (StackChunk.getStack(ent) < 0) { + if (!Main.config.getStringList("smart-stacker.gameplay.stackable").contains(ent.getType().toString().toUpperCase())) { return false; } - if (!Main.config.getStringList("smart-stacker.gameplay.stackable").contains(ent.getType().toString().toUpperCase())) { + String spawnreason = ent.hasMetadata("lagassist.spawnreason") ? ent.getMetadata("lagassist.spawnreason").get(0).value().toString().toUpperCase() : "UNKNOWN"; + + if(!(Main.config.getStringList("smart-stacker.gameplay.spawn-reasons").contains("ALL") || Main.config.getStringList("smart-stacker.gameplay.spawn-reasons").contains(spawnreason))) { + return false; + } + + int stacksize = StackChunk.getStack(ent); + + if (stacksize < 0) { return false; }