From 21b7507801c8828219be62af8eaec150e6d18f64 Mon Sep 17 00:00:00 2001 From: ceze88 Date: Wed, 25 Jan 2023 23:20:44 +0100 Subject: [PATCH 01/31] Hotfix for SQLite and readd old MythicMobs compatibility --- .../ultimatestacker/database/DataManager.java | 8 +- .../migrations/_1_InitialMigration.java | 2 +- .../database/migrations/_2_EntityStacks.java | 4 +- .../database/migrations/_3_BlockStacks.java | 2 +- .../database/migrations/_4_DataPurge.java | 2 + .../_5_StackedEntitiesTableUpdate.java | 3 + .../entity/custom/CustomEntityManager.java | 12 +- .../entities/MythicMobsCustomEntity.java | 4 +- .../MythicMobsCustomEntityLegacy.java | 128 ++++++++++++++++++ .../custom/entities/MythicMobsProvider.java | 11 ++ 10 files changed, 164 insertions(+), 12 deletions(-) create mode 100644 src/main/java/com/songoda/ultimatestacker/stackable/entity/custom/entities/MythicMobsCustomEntityLegacy.java create mode 100644 src/main/java/com/songoda/ultimatestacker/stackable/entity/custom/entities/MythicMobsProvider.java diff --git a/src/main/java/com/songoda/ultimatestacker/database/DataManager.java b/src/main/java/com/songoda/ultimatestacker/database/DataManager.java index d75731f..c3fe296 100644 --- a/src/main/java/com/songoda/ultimatestacker/database/DataManager.java +++ b/src/main/java/com/songoda/ultimatestacker/database/DataManager.java @@ -69,7 +69,7 @@ public class DataManager extends DataManagerAbstract { public void createSpawner(SpawnerStack spawnerStack) { this.runAsync(() -> { try (Connection connection = this.databaseConnector.getConnection()) { - String createSpawner = "INSERT INTO " + getSyntax("OR REPLACE ", DatabaseType.SQLITE) + this.getTablePrefix() + "spawners (amount, world, x, y, z) VALUES (?, ?, ?, ?, ?)"; + String createSpawner = "INSERT " + getSyntax("INTO ", DatabaseType.MYSQL) + getSyntax("OR REPLACE INTO ", DatabaseType.SQLITE) + this.getTablePrefix() + "spawners (amount, world, x, y, z) VALUES (?, ?, ?, ?, ?)"; PreparedStatement statement = connection.prepareStatement(createSpawner); statement.setInt(1, spawnerStack.getAmount()); @@ -104,7 +104,7 @@ public class DataManager extends DataManagerAbstract { public void createBlock(BlockStack blockStack) { this.runAsync(() -> { try (Connection connection = this.databaseConnector.getConnection()) { - String createSpawner = "INSERT INTO " + getSyntax("OR REPLACE ", DatabaseType.SQLITE) + this.getTablePrefix() + "blocks (amount, material, world, x, y, z) VALUES (?, ?, ?, ?, ?, ?)"; + String createSpawner = "INSERT " + getSyntax("INTO ", DatabaseType.MYSQL) + getSyntax("OR REPLACE INTO ", DatabaseType.SQLITE) + this.getTablePrefix() + "blocks (amount, material, world, x, y, z) VALUES (?, ?, ?, ?, ?, ?)"; PreparedStatement statement = connection.prepareStatement(createSpawner); statement.setInt(1, blockStack.getAmount()); statement.setString(2, blockStack.getMaterial().name()); @@ -125,7 +125,7 @@ public class DataManager extends DataManagerAbstract { public void createHostEntity(ColdEntityStack stack) { this.runAsync(() -> { try (Connection connection = this.databaseConnector.getConnection()) { - String createSerializedEntity = "INSERT INTO " + getSyntax("OR REPLACE ", DatabaseType.SQLITE) + this.getTablePrefix() + "host_entities (uuid, create_duplicates) VALUES (?, ?)"; + String createSerializedEntity = "INSERT " + getSyntax("INTO ", DatabaseType.MYSQL) + getSyntax("OR REPLACE INTO ", DatabaseType.SQLITE) + this.getTablePrefix() + "host_entities (uuid, create_duplicates) VALUES (?, ?)"; PreparedStatement statement = connection.prepareStatement(createSerializedEntity); if (stack == null || stack.getHostUniqueId() == null) return; statement.setString(1, stack.getHostUniqueId().toString()); @@ -142,7 +142,7 @@ public class DataManager extends DataManagerAbstract { public void createStackedEntity(EntityStack hostStack, StackedEntity stackedEntity) { this.runAsync(() -> { try (Connection connection = this.databaseConnector.getConnection()){ - String createSerializedEntity = "INSERT INTO " + getSyntax("OR REPLACE ", DatabaseType.SQLITE) + this.getTablePrefix() + "stacked_entities (uuid, host, serialized_entity) VALUES (?, ?, ?) " + String createSerializedEntity = "INSERT " + getSyntax("INTO ", DatabaseType.MYSQL) + getSyntax("OR REPLACE INTO ", DatabaseType.SQLITE) + this.getTablePrefix() + "stacked_entities (uuid, host, serialized_entity) VALUES (?, ?, ?) " + (Settings.MYSQL_ENABLED.getBoolean() ? "ON DUPLICATE KEY UPDATE host = ?, serialized_entity = ?" : "ON CONFLICT(uuid) DO UPDATE SET host = ?, serialized_entity = ?"); PreparedStatement statement = connection.prepareStatement(createSerializedEntity); if (hostStack.getHostUniqueId() == null) return; diff --git a/src/main/java/com/songoda/ultimatestacker/database/migrations/_1_InitialMigration.java b/src/main/java/com/songoda/ultimatestacker/database/migrations/_1_InitialMigration.java index a19420a..4eba4ad 100644 --- a/src/main/java/com/songoda/ultimatestacker/database/migrations/_1_InitialMigration.java +++ b/src/main/java/com/songoda/ultimatestacker/database/migrations/_1_InitialMigration.java @@ -20,7 +20,7 @@ public class _1_InitialMigration extends DataMigration { // Create spawners table try (Statement statement = connection.createStatement()) { - statement.execute("CREATE TABLE " + tablePrefix + "spawners (" + + statement.execute("CREATE TABLE IF NOT EXISTS " + tablePrefix + "spawners (" + "id INTEGER PRIMARY KEY" + autoIncrement + ", " + "amount INTEGER NOT NULL," + "world TEXT NOT NULL, " + diff --git a/src/main/java/com/songoda/ultimatestacker/database/migrations/_2_EntityStacks.java b/src/main/java/com/songoda/ultimatestacker/database/migrations/_2_EntityStacks.java index 17c660f..1427518 100644 --- a/src/main/java/com/songoda/ultimatestacker/database/migrations/_2_EntityStacks.java +++ b/src/main/java/com/songoda/ultimatestacker/database/migrations/_2_EntityStacks.java @@ -20,7 +20,7 @@ public class _2_EntityStacks extends DataMigration { // Create host entities table try (Statement statement = connection.createStatement()) { - statement.execute("CREATE TABLE " + tablePrefix + "host_entities (" + + statement.execute("CREATE TABLE IF NOT EXISTS " + tablePrefix + "host_entities (" + "id INTEGER PRIMARY KEY" + autoIncrement + ", " + "uuid VARCHAR(36) NOT NULL," + "create_duplicates INTEGER NOT NULL DEFAULT 0" + @@ -29,7 +29,7 @@ public class _2_EntityStacks extends DataMigration { // Create stacked entities table try (Statement statement = connection.createStatement()) { - statement.execute("CREATE TABLE " + tablePrefix + "stacked_entities (" + + statement.execute("CREATE TABLE IF NOT EXISTS " + tablePrefix + "stacked_entities (" + "uuid VARCHAR(36) PRIMARY KEY NOT NULL," + "host INTEGER NOT NULL," + "serialized_entity VARBINARY(9999) NOT NULL" + diff --git a/src/main/java/com/songoda/ultimatestacker/database/migrations/_3_BlockStacks.java b/src/main/java/com/songoda/ultimatestacker/database/migrations/_3_BlockStacks.java index 66e12ab..1a15bcb 100644 --- a/src/main/java/com/songoda/ultimatestacker/database/migrations/_3_BlockStacks.java +++ b/src/main/java/com/songoda/ultimatestacker/database/migrations/_3_BlockStacks.java @@ -20,7 +20,7 @@ public class _3_BlockStacks extends DataMigration { // Create blocks table try (Statement statement = connection.createStatement()) { - statement.execute("CREATE TABLE " + tablePrefix + "blocks (" + + statement.execute("CREATE TABLE IF NOT EXISTS " + tablePrefix + "blocks (" + "id INTEGER PRIMARY KEY" + autoIncrement + ", " + "amount INTEGER NOT NULL," + "material TEXT NOT NULL," + diff --git a/src/main/java/com/songoda/ultimatestacker/database/migrations/_4_DataPurge.java b/src/main/java/com/songoda/ultimatestacker/database/migrations/_4_DataPurge.java index 2ce6297..68c2331 100644 --- a/src/main/java/com/songoda/ultimatestacker/database/migrations/_4_DataPurge.java +++ b/src/main/java/com/songoda/ultimatestacker/database/migrations/_4_DataPurge.java @@ -18,6 +18,8 @@ public class _4_DataPurge extends DataMigration { public void migrate(Connection connection, String tablePrefix) throws SQLException { try (Statement statement = connection.createStatement()) { statement.execute("ALTER TABLE " + tablePrefix + "host_entities ADD COLUMN updated_at datetime DEFAULT NULL"); + } catch (SQLException e) { + // Ignore } } } diff --git a/src/main/java/com/songoda/ultimatestacker/database/migrations/_5_StackedEntitiesTableUpdate.java b/src/main/java/com/songoda/ultimatestacker/database/migrations/_5_StackedEntitiesTableUpdate.java index 77362b9..a485421 100644 --- a/src/main/java/com/songoda/ultimatestacker/database/migrations/_5_StackedEntitiesTableUpdate.java +++ b/src/main/java/com/songoda/ultimatestacker/database/migrations/_5_StackedEntitiesTableUpdate.java @@ -16,6 +16,9 @@ public class _5_StackedEntitiesTableUpdate extends DataMigration { public void migrate(Connection connection, String tablePrefix) throws SQLException { try (Statement statement = connection.createStatement()) { statement.execute("ALTER TABLE " + tablePrefix + "stacked_entities MODIFY serialized_entity VARBINARY(9999)"); + } catch (SQLException e) { + // Ignore + //TODO fix it for sqlite } } } diff --git a/src/main/java/com/songoda/ultimatestacker/stackable/entity/custom/CustomEntityManager.java b/src/main/java/com/songoda/ultimatestacker/stackable/entity/custom/CustomEntityManager.java index e055715..07c01f3 100644 --- a/src/main/java/com/songoda/ultimatestacker/stackable/entity/custom/CustomEntityManager.java +++ b/src/main/java/com/songoda/ultimatestacker/stackable/entity/custom/CustomEntityManager.java @@ -2,8 +2,10 @@ package com.songoda.ultimatestacker.stackable.entity.custom; import com.songoda.ultimatestacker.settings.Settings; import com.songoda.ultimatestacker.stackable.entity.custom.entities.MythicMobsCustomEntity; +import com.songoda.ultimatestacker.stackable.entity.custom.entities.MythicMobsCustomEntityLegacy; import org.bukkit.Bukkit; import org.bukkit.entity.Entity; +import org.bukkit.plugin.Plugin; import java.util.ArrayList; import java.util.Collections; @@ -18,8 +20,14 @@ public class CustomEntityManager { private final List registeredCustomEntities = new ArrayList<>(); public void load() { - if (isEnabled("MythicMobs")) - registeredCustomEntities.add(new MythicMobsCustomEntity()); + if (isEnabled("MythicMobs")) { + Plugin plugin = Bukkit.getPluginManager().getPlugin("MythicMobs"); + if (plugin.getDescription().getVersion().startsWith("4.")) { + registeredCustomEntities.add(new MythicMobsCustomEntityLegacy()); + } else { + registeredCustomEntities.add(new MythicMobsCustomEntity()); + } + } } public boolean isEnabled(String plugin) { diff --git a/src/main/java/com/songoda/ultimatestacker/stackable/entity/custom/entities/MythicMobsCustomEntity.java b/src/main/java/com/songoda/ultimatestacker/stackable/entity/custom/entities/MythicMobsCustomEntity.java index 5613eb4..3b1233d 100644 --- a/src/main/java/com/songoda/ultimatestacker/stackable/entity/custom/entities/MythicMobsCustomEntity.java +++ b/src/main/java/com/songoda/ultimatestacker/stackable/entity/custom/entities/MythicMobsCustomEntity.java @@ -11,7 +11,7 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.LivingEntity; -public class MythicMobsCustomEntity extends CustomEntity { +public class MythicMobsCustomEntity extends MythicMobsProvider { public MythicMobsCustomEntity() { super(Bukkit.getPluginManager().getPlugin("MythicMobs")); @@ -38,7 +38,7 @@ public class MythicMobsCustomEntity extends CustomEntity { @Override public boolean isSimilar(LivingEntity original, LivingEntity entity) { - if (!isMatchingType(original) || !isMatchingType(entity) || getMob(entity) == null) return false; + if (!isMatchingType(original) || getMob(entity) == null) return false; return getMob(original).getType().equals(getMob(entity).getType()); } diff --git a/src/main/java/com/songoda/ultimatestacker/stackable/entity/custom/entities/MythicMobsCustomEntityLegacy.java b/src/main/java/com/songoda/ultimatestacker/stackable/entity/custom/entities/MythicMobsCustomEntityLegacy.java new file mode 100644 index 0000000..fdd0c0f --- /dev/null +++ b/src/main/java/com/songoda/ultimatestacker/stackable/entity/custom/entities/MythicMobsCustomEntityLegacy.java @@ -0,0 +1,128 @@ +package com.songoda.ultimatestacker.stackable.entity.custom.entities; + +import com.songoda.ultimatestacker.stackable.entity.custom.CustomEntity; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.plugin.Plugin; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Objects; +import java.util.UUID; + +public class MythicMobsCustomEntityLegacy extends MythicMobsProvider { + + + public MythicMobsCustomEntityLegacy() { + super(Bukkit.getPluginManager().getPlugin("MythicMobs")); + } + + @Override + public String getPluginName() { + return "MythicMobs"; + } + + @Override + public boolean isMatchingType(Entity entity) { + try { + return (boolean) getMobManager().getClass().getMethod("isActiveMob", UUID.class).invoke(getMobManager(), entity.getUniqueId()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public String getDisplayName(Entity entity) { + try { + Object mob = getMob(entity); + if (mob == null) return null; + Object type = mob.getClass().getMethod("getType").invoke(mob); + return type.getClass().getMethod("getDisplayName").invoke(type).toString(); + } catch (Exception e) { + return null; + } + } + + @Override + public boolean isSimilar(LivingEntity original, LivingEntity entity) { + if (!isMatchingType(original) || getMob(entity) == null) return false; + try { + Object originalMob = getMob(original); + Object mob = getMob(entity); + return originalMob.getClass().getMethod("getType").invoke(originalMob).equals(mob.getClass().getMethod("getType").invoke(mob)); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public String getNBTIdentifier(Entity entity) { + try { + Object mob = getMob(entity); + Object type = mob.getClass().getMethod("getType").invoke(mob); + return getInternalName(type); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public LivingEntity spawnFromIdentifier(String string, Location location) { + return getMobTypes().stream().map(type -> { + try { + if (getInternalName(type).equals(string)) { + return (LivingEntity) getMobManager().getClass().getMethod("spawnMob", String.class, Location.class).invoke(getMobManager(), getInternalName(type), location); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + return null; + }).filter(Objects::nonNull).findFirst().orElse(null); + } + + @Override + public boolean isCustomEntity(Entity entity) { + return getMob(entity) != null; + } + + private Object getMob(Entity entity) { + try { + return getMobManager().getClass().getMethod("getMythicMobInstance", Entity.class).invoke(getMobManager(), entity); + } catch (Exception e) { + return null; + } + } + + private String getInternalName(Object type) { + try { + return type.getClass().getMethod("getInternalName").invoke(type).toString(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private Collection getMobTypes() { + try { + Method getMobTypes = getMobManager().getClass().getMethod("getMobTypes"); + return (Collection) getMobTypes.invoke(getMobManager()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private Object getMobManager() { + try { + Field mobManager = plugin.getClass().getDeclaredField("mobManager"); + mobManager.setAccessible(true); + return mobManager.get(plugin); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/src/main/java/com/songoda/ultimatestacker/stackable/entity/custom/entities/MythicMobsProvider.java b/src/main/java/com/songoda/ultimatestacker/stackable/entity/custom/entities/MythicMobsProvider.java new file mode 100644 index 0000000..75fee23 --- /dev/null +++ b/src/main/java/com/songoda/ultimatestacker/stackable/entity/custom/entities/MythicMobsProvider.java @@ -0,0 +1,11 @@ +package com.songoda.ultimatestacker.stackable.entity.custom.entities; + +import com.songoda.ultimatestacker.stackable.entity.custom.CustomEntity; +import org.bukkit.plugin.Plugin; + +public abstract class MythicMobsProvider extends CustomEntity { + + protected MythicMobsProvider(Plugin plugin) { + super(plugin); + } +} From 4e4fda611c744bc203e7223e1bdb2c3017ac02da Mon Sep 17 00:00:00 2001 From: ceze88 Date: Wed, 25 Jan 2023 23:21:11 +0100 Subject: [PATCH 02/31] Release v2.3.4 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 88adc75..812594b 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ com.songoda UltimateStacker 4.0.0 - 2.3.3 + 2.3.4 clean install UltimateStacker-${project.version} From 71baf3a7e822664bc360c3ef04f9ce7b4986ce9c Mon Sep 17 00:00:00 2001 From: ceze88 Date: Sat, 4 Feb 2023 14:48:13 +0100 Subject: [PATCH 03/31] Rewrite mob stacking, performance improvements --- .../ultimatestacker/UltimateStacker.java | 19 +- .../commands/CommandRemoveAll.java | 5 +- .../commands/CommandSpawn.java | 4 +- .../convert/StackMobConvert.java | 8 - .../convert/WildStackerConvert.java | 17 -- .../ultimatestacker/database/DataManager.java | 195 --------------- .../database/migrations/_2_EntityStacks.java | 9 - .../_5_StackedEntitiesTableUpdate.java | 24 -- ....java => _6_RemoveStackedEntityTable.java} | 14 +- .../ultimatestacker/gui/GUIConvertWhat.java | 2 +- .../listeners/ChunkListeners.java | 41 ---- .../listeners/ClearLagListeners.java | 4 +- .../listeners/DeathListeners.java | 4 +- .../listeners/InteractListeners.java | 2 +- .../listeners/ShearListeners.java | 2 +- .../listeners/SheepDyeListeners.java | 2 +- .../listeners/SpawnerListeners.java | 6 +- .../listeners/TameListeners.java | 2 +- .../entity/EntityCurrentListener.java | 6 +- .../listeners/entity/EntityListeners.java | 4 +- .../stackable/entity/ColdEntityStack.java | 169 ------------- .../stackable/entity/EntityStack.java | 124 +++------- .../stackable/entity/EntityStackManager.java | 172 +++++-------- .../stackable/entity/StackedEntity.java | 74 +++++- .../ultimatestacker/tasks/StackingTask.java | 226 ++++++------------ 25 files changed, 258 insertions(+), 877 deletions(-) delete mode 100644 src/main/java/com/songoda/ultimatestacker/database/migrations/_5_StackedEntitiesTableUpdate.java rename src/main/java/com/songoda/ultimatestacker/database/migrations/{_4_DataPurge.java => _6_RemoveStackedEntityTable.java} (52%) delete mode 100644 src/main/java/com/songoda/ultimatestacker/listeners/ChunkListeners.java delete mode 100644 src/main/java/com/songoda/ultimatestacker/stackable/entity/ColdEntityStack.java diff --git a/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java b/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java index cecfa93..5c81465 100644 --- a/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java +++ b/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java @@ -26,8 +26,7 @@ import com.songoda.ultimatestacker.database.DataManager; import com.songoda.ultimatestacker.database.migrations._1_InitialMigration; import com.songoda.ultimatestacker.database.migrations._2_EntityStacks; import com.songoda.ultimatestacker.database.migrations._3_BlockStacks; -import com.songoda.ultimatestacker.database.migrations._4_DataPurge; -import com.songoda.ultimatestacker.database.migrations._5_StackedEntitiesTableUpdate; +import com.songoda.ultimatestacker.database.migrations._6_RemoveStackedEntityTable; import com.songoda.ultimatestacker.hook.StackerHook; import com.songoda.ultimatestacker.hook.hooks.JobsHook; import com.songoda.ultimatestacker.listeners.*; @@ -49,6 +48,7 @@ import com.songoda.ultimatestacker.stackable.spawner.SpawnerStackManager; import com.songoda.ultimatestacker.tasks.StackingTask; import com.songoda.ultimatestacker.utils.Async; import com.songoda.ultimatestacker.utils.Methods; +import io.lumine.mythic.bukkit.listeners.ChunkListeners; import org.apache.commons.lang.WordUtils; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -106,7 +106,7 @@ public class UltimateStacker extends SongodaPlugin { @Override public void onPluginDisable() { - this.stackingTask.cancel(); + this.stackingTask.stop(); this.stackingTask = null; this.dataManager.bulkUpdateSpawners(this.spawnerStackManager.getStacks()); HologramManager.removeAllHolograms(); @@ -235,8 +235,7 @@ public class UltimateStacker extends SongodaPlugin { new _1_InitialMigration(), new _2_EntityStacks(), new _3_BlockStacks(), - new _4_DataPurge(), - new _5_StackedEntitiesTableUpdate()); + new _6_RemoveStackedEntityTable()); this.dataMigrationManager.runMigrations(); } @@ -260,12 +259,8 @@ public class UltimateStacker extends SongodaPlugin { } } }); - this.dataManager.getEntities((entities) -> { - entityStackManager.addStacks(entities.values()); - entityStackManager.tryAndLoadColdEntities(); - this.stackingTask = new StackingTask(this); - getServer().getPluginManager().registerEvents(new ChunkListeners(entityStackManager), this); - }); + + this.stackingTask = new StackingTask(this); final boolean useBlockHolo = Settings.BLOCK_HOLOGRAMS.getBoolean(); this.dataManager.getBlocks((blocks) -> { this.blockStackManager.addBlocks(blocks); @@ -302,7 +297,7 @@ public class UltimateStacker extends SongodaPlugin { this.setLocale(getConfig().getString("System.Language Mode"), true); this.locale.reloadMessages(); - this.stackingTask.cancel(); + this.stackingTask.stop(); this.stackingTask = new StackingTask(this); this.mobFile.load(); diff --git a/src/main/java/com/songoda/ultimatestacker/commands/CommandRemoveAll.java b/src/main/java/com/songoda/ultimatestacker/commands/CommandRemoveAll.java index 01d36c8..840a8eb 100644 --- a/src/main/java/com/songoda/ultimatestacker/commands/CommandRemoveAll.java +++ b/src/main/java/com/songoda/ultimatestacker/commands/CommandRemoveAll.java @@ -46,10 +46,9 @@ public class CommandRemoveAll extends AbstractCommand { for (Entity entityO : world.getEntities()) { if (entityO instanceof Player) continue; - if (entityO instanceof LivingEntity && (stackManager.isStackedAndLoaded((LivingEntity)entityO) || all) + if (entityO instanceof LivingEntity && (stackManager.isStackedEntity(entityO) || all) && type.equalsIgnoreCase("entities")) { - entityO.remove(); - plugin.getEntityStackManager().removeStack(entityO); + plugin.getEntityStackManager().getStack((LivingEntity) entityO).destroy(); amountRemoved++; } else if (entityO.getType() == EntityType.DROPPED_ITEM && type.equalsIgnoreCase("items")) { if (!UltimateStacker.hasCustomAmount((Item)entityO) && !all) diff --git a/src/main/java/com/songoda/ultimatestacker/commands/CommandSpawn.java b/src/main/java/com/songoda/ultimatestacker/commands/CommandSpawn.java index 085f499..c5b0e8f 100644 --- a/src/main/java/com/songoda/ultimatestacker/commands/CommandSpawn.java +++ b/src/main/java/com/songoda/ultimatestacker/commands/CommandSpawn.java @@ -56,9 +56,7 @@ public class CommandSpawn extends AbstractCommand { sender.sendMessage(TextUtils.formatText("&6" + list)); } else { LivingEntity entity = (LivingEntity)player.getWorld().spawnEntity(player.getLocation(), type); - EntityStack stack = plugin.getEntityStackManager().addStack(entity); - stack.createDuplicates(((Methods.isInt(args[1])) ? Integer.parseInt(args[1]) : 1) - 1); - stack.updateStack(); + EntityStack stack = plugin.getEntityStackManager().createStack(entity, Integer.parseInt(args[1])); plugin.getStackingTask().attemptSplit(stack, entity); } diff --git a/src/main/java/com/songoda/ultimatestacker/convert/StackMobConvert.java b/src/main/java/com/songoda/ultimatestacker/convert/StackMobConvert.java index 72be5db..96eb27a 100644 --- a/src/main/java/com/songoda/ultimatestacker/convert/StackMobConvert.java +++ b/src/main/java/com/songoda/ultimatestacker/convert/StackMobConvert.java @@ -36,14 +36,6 @@ public class StackMobConvert implements Convert { @Override public void convertEntities() { - EntityStackManager entityStackManager = plugin.getEntityStackManager(); - for (Map.Entry entry : stackMob.getStorageManager().getAmountCache().entrySet()) { - if (!entityStackManager.isStackedAndLoaded(entry.getKey())) { - entityStackManager.addLegacyColdStack(entry.getKey(), entry.getValue()); - continue; - } - } - } @Override diff --git a/src/main/java/com/songoda/ultimatestacker/convert/WildStackerConvert.java b/src/main/java/com/songoda/ultimatestacker/convert/WildStackerConvert.java index f943450..be50053 100644 --- a/src/main/java/com/songoda/ultimatestacker/convert/WildStackerConvert.java +++ b/src/main/java/com/songoda/ultimatestacker/convert/WildStackerConvert.java @@ -43,23 +43,6 @@ public class WildStackerConvert implements Convert { @Override public void convertEntities() { - EntityStackManager entityStackManager = plugin.getEntityStackManager(); - - DatabaseConnector connector = new SQLiteConnector(this.wildStacker); - connector.connect(connection -> { - - try (Statement statement = connection.createStatement()) { - ResultSet result = statement.executeQuery("SELECT uuid, stackAmount FROM entities"); - while (result.next()) { - UUID uuid = UUID.fromString(result.getString("uuid")); - int amount = result.getInt("stackAmount"); - if (!entityStackManager.isEntityInColdStorage(uuid)) - entityStackManager.addLegacyColdStack(uuid, amount); - } - } - }); - - } @Override diff --git a/src/main/java/com/songoda/ultimatestacker/database/DataManager.java b/src/main/java/com/songoda/ultimatestacker/database/DataManager.java index c3fe296..9ad0357 100644 --- a/src/main/java/com/songoda/ultimatestacker/database/DataManager.java +++ b/src/main/java/com/songoda/ultimatestacker/database/DataManager.java @@ -6,7 +6,6 @@ import com.songoda.core.database.DatabaseConnector; import com.songoda.core.database.DatabaseType; import com.songoda.ultimatestacker.settings.Settings; import com.songoda.ultimatestacker.stackable.block.BlockStack; -import com.songoda.ultimatestacker.stackable.entity.ColdEntityStack; import com.songoda.ultimatestacker.stackable.entity.EntityStack; import com.songoda.ultimatestacker.stackable.entity.StackedEntity; import com.songoda.ultimatestacker.stackable.spawner.SpawnerStack; @@ -122,130 +121,6 @@ public class DataManager extends DataManagerAbstract { }); } - public void createHostEntity(ColdEntityStack stack) { - this.runAsync(() -> { - try (Connection connection = this.databaseConnector.getConnection()) { - String createSerializedEntity = "INSERT " + getSyntax("INTO ", DatabaseType.MYSQL) + getSyntax("OR REPLACE INTO ", DatabaseType.SQLITE) + this.getTablePrefix() + "host_entities (uuid, create_duplicates) VALUES (?, ?)"; - PreparedStatement statement = connection.prepareStatement(createSerializedEntity); - if (stack == null || stack.getHostUniqueId() == null) return; - statement.setString(1, stack.getHostUniqueId().toString()); - statement.setInt(2, stack.getCreateDuplicates()); - statement.executeUpdate(); - int stackId = this.lastInsertedId(connection, "host_entities"); - this.sync(() -> stack.setId(stackId)); - } catch (Exception ex) { - ex.printStackTrace(); - } - }); - } - - public void createStackedEntity(EntityStack hostStack, StackedEntity stackedEntity) { - this.runAsync(() -> { - try (Connection connection = this.databaseConnector.getConnection()){ - String createSerializedEntity = "INSERT " + getSyntax("INTO ", DatabaseType.MYSQL) + getSyntax("OR REPLACE INTO ", DatabaseType.SQLITE) + this.getTablePrefix() + "stacked_entities (uuid, host, serialized_entity) VALUES (?, ?, ?) " - + (Settings.MYSQL_ENABLED.getBoolean() ? "ON DUPLICATE KEY UPDATE host = ?, serialized_entity = ?" : "ON CONFLICT(uuid) DO UPDATE SET host = ?, serialized_entity = ?"); - PreparedStatement statement = connection.prepareStatement(createSerializedEntity); - if (hostStack.getHostUniqueId() == null) return; - statement.setString(1, stackedEntity.getUniqueId().toString()); - statement.setInt(2, hostStack.getId()); - statement.setBytes(3, stackedEntity.getSerializedEntity()); - statement.setInt(4, hostStack.getId()); - statement.setBytes(5, stackedEntity.getSerializedEntity()); - statement.executeUpdate(); - } catch (Exception ex) { - ex.printStackTrace(); - } - }); - } - - public void createStackedEntities(ColdEntityStack hostStack, List stackedEntities) { - this.runAsync(() -> { - try (Connection connection = this.databaseConnector.getConnection()) { - String createSerializedEntity = "REPLACE INTO " + this.getTablePrefix() + "stacked_entities (uuid, host, serialized_entity) VALUES (?, ?, ?)"; - PreparedStatement statement = connection.prepareStatement(createSerializedEntity); - if (hostStack.getHostUniqueId() == null) return; - for (StackedEntity entity : stackedEntities) { - statement.setString(1, entity.getUniqueId().toString()); - statement.setInt(2, hostStack.getId()); - statement.setBytes(3, entity.getSerializedEntity()); - statement.addBatch(); - } - statement.executeBatch(); - } catch (Exception ex) { - ex.printStackTrace(); - } - }); - } - - public void updateHost(ColdEntityStack hostStack) { - this.runAsync(() -> { - try (Connection connection = this.databaseConnector.getConnection()) { - String updateHost = "UPDATE " + this.getTablePrefix() + "host_entities SET uuid = ?, create_duplicates = ?, updated_at = current_timestamp WHERE id = ?"; - PreparedStatement statement = connection.prepareStatement(updateHost); - if (hostStack.getHostUniqueId() == null) return; - statement.setString(1, hostStack.getHostUniqueId().toString()); - statement.setInt(2, hostStack.getCreateDuplicates()); - statement.setInt(3, hostStack.getId()); - statement.executeUpdate(); - } catch (Exception ex) { - ex.printStackTrace(); - } - }); - } - - public void deleteHost(ColdEntityStack stack) { - this.runAsync(() -> { - try (Connection connection = this.databaseConnector.getConnection()) { - String deleteHost = "DELETE FROM " + this.getTablePrefix() + "host_entities WHERE id = ?"; - try (PreparedStatement statement = connection.prepareStatement(deleteHost)) { - statement.setInt(1, stack.getId()); - statement.executeUpdate(); - } - - String deleteStackedEntities = "DELETE FROM " + this.getTablePrefix() + "stacked_entities WHERE host = ?"; - try (PreparedStatement statement = connection.prepareStatement(deleteStackedEntities)) { - statement.setInt(1, stack.getId()); - statement.executeUpdate(); - } - } catch (Exception ex) { - ex.printStackTrace(); - } - }); - } - - public void deleteStackedEntity(UUID uuid) { - if (uuid == null) - return; - - this.runAsync(() -> { - try (Connection connection = this.databaseConnector.getConnection()) { - String deleteStackedEntity = "DELETE FROM " + this.getTablePrefix() + "stacked_entities WHERE uuid = ?"; - PreparedStatement statement = connection.prepareStatement(deleteStackedEntity); - statement.setString(1, uuid.toString()); - statement.executeUpdate(); - } catch (Exception ex) { - ex.printStackTrace(); - } - }); - } - - public void deleteStackedEntities(List entities) { - this.runAsync(() -> { - try (Connection connection = this.databaseConnector.getConnection()) { - String deleteStackedEntities = "DELETE FROM " + this.getTablePrefix() + "stacked_entities WHERE uuid = ?"; - PreparedStatement statement = connection.prepareStatement(deleteStackedEntities); - for (StackedEntity entity : entities) { - if (entity == null) continue; - statement.setString(1, entity.getUniqueId().toString()); - statement.addBatch(); - } - statement.executeBatch(); - } catch (Exception ex) { - ex.printStackTrace(); - } - }); - } - public void deleteSpawner(SpawnerStack spawnerStack) { this.runAsync(() -> { try (Connection connection = this.databaseConnector.getConnection()) { @@ -272,76 +147,6 @@ public class DataManager extends DataManagerAbstract { }); } - public void getEntities(Consumer> callback) { - this.runAsync(() -> { - try (Connection connection = this.databaseConnector.getConnection()) { - - Map entities = new HashMap<>(); - - boolean mysql = Settings.MYSQL_ENABLED.getBoolean(); - int databasePurge = Settings.DATABASE_PURGE.getInt(); - String whereStatement = mysql ? "WHERE updated_at < NOW() - INTERVAL " + databasePurge + " DAY" : "WHERE updated_at <= date('now','-" + databasePurge + " day')"; - String selectOldEntities = "SELECT * FROM " + this.getTablePrefix() + "host_entities " + whereStatement; - - try (Statement statement = connection.createStatement()) { - List toDelete = new ArrayList<>(); - - ResultSet result = statement.executeQuery(selectOldEntities); - while (result.next()) { - int hostId = result.getInt("id"); - toDelete.add(String.valueOf(hostId)); - } - - if (!toDelete.isEmpty()) { - statement.execute("DELETE FROM " + this.getTablePrefix() + "host_entities " + whereStatement); - statement.execute("DELETE FROM " + this.getTablePrefix() + "stacked_entities WHERE host IN (" + String.join(", ", toDelete) + ")"); - } - } catch (Exception e) { - e.printStackTrace(); - } - - - String selectEntities = "SELECT * FROM " + this.getTablePrefix() + "host_entities"; - try (Statement statement = connection.createStatement()) { - ResultSet result = statement.executeQuery(selectEntities); - while (result.next()) { - int hostId = result.getInt("id"); - - UUID host = UUID.fromString(result.getString("uuid")); - - int createDuplicates = result.getInt("create_duplicates"); - - ColdEntityStack stack = new ColdEntityStack(host, hostId); - stack.createDuplicates(createDuplicates); - entities.put(hostId, stack); - } - } catch (Exception e) { - e.printStackTrace(); - } - - String selectStackedEntities = "SELECT * FROM " + this.getTablePrefix() + "stacked_entities"; - try (Statement statement = connection.createStatement()) { - ResultSet result = statement.executeQuery(selectStackedEntities); - while (result.next()) { - UUID uuid = UUID.fromString(result.getString("uuid")); - int hostId = result.getInt("host"); - byte[] serializedEntity = result.getBytes("serialized_entity"); - - ColdEntityStack stack = entities.get(hostId); - if (stack == null) continue; - stack.addEntityToStackSilently(new StackedEntity(uuid, serializedEntity)); - } - } catch (Exception e) { - e.printStackTrace(); - } - - this.sync(() -> callback.accept(entities)); - } catch (Exception ex) { - ex.printStackTrace(); - } - }); - } - public void getSpawners(Consumer> callback) { this.runAsync(() -> { try (Connection connection = this.databaseConnector.getConnection()){ diff --git a/src/main/java/com/songoda/ultimatestacker/database/migrations/_2_EntityStacks.java b/src/main/java/com/songoda/ultimatestacker/database/migrations/_2_EntityStacks.java index 1427518..4ab17b0 100644 --- a/src/main/java/com/songoda/ultimatestacker/database/migrations/_2_EntityStacks.java +++ b/src/main/java/com/songoda/ultimatestacker/database/migrations/_2_EntityStacks.java @@ -26,14 +26,5 @@ public class _2_EntityStacks extends DataMigration { "create_duplicates INTEGER NOT NULL DEFAULT 0" + ")"); } - - // Create stacked entities table - try (Statement statement = connection.createStatement()) { - statement.execute("CREATE TABLE IF NOT EXISTS " + tablePrefix + "stacked_entities (" + - "uuid VARCHAR(36) PRIMARY KEY NOT NULL," + - "host INTEGER NOT NULL," + - "serialized_entity VARBINARY(9999) NOT NULL" + - ")"); - } } } diff --git a/src/main/java/com/songoda/ultimatestacker/database/migrations/_5_StackedEntitiesTableUpdate.java b/src/main/java/com/songoda/ultimatestacker/database/migrations/_5_StackedEntitiesTableUpdate.java deleted file mode 100644 index a485421..0000000 --- a/src/main/java/com/songoda/ultimatestacker/database/migrations/_5_StackedEntitiesTableUpdate.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.songoda.ultimatestacker.database.migrations; - -import com.songoda.core.database.DataMigration; - -import java.sql.Connection; -import java.sql.SQLException; -import java.sql.Statement; - -public class _5_StackedEntitiesTableUpdate extends DataMigration { - - public _5_StackedEntitiesTableUpdate() { - super(5); - } - - @Override - public void migrate(Connection connection, String tablePrefix) throws SQLException { - try (Statement statement = connection.createStatement()) { - statement.execute("ALTER TABLE " + tablePrefix + "stacked_entities MODIFY serialized_entity VARBINARY(9999)"); - } catch (SQLException e) { - // Ignore - //TODO fix it for sqlite - } - } -} diff --git a/src/main/java/com/songoda/ultimatestacker/database/migrations/_4_DataPurge.java b/src/main/java/com/songoda/ultimatestacker/database/migrations/_6_RemoveStackedEntityTable.java similarity index 52% rename from src/main/java/com/songoda/ultimatestacker/database/migrations/_4_DataPurge.java rename to src/main/java/com/songoda/ultimatestacker/database/migrations/_6_RemoveStackedEntityTable.java index 68c2331..ecf5bcc 100644 --- a/src/main/java/com/songoda/ultimatestacker/database/migrations/_4_DataPurge.java +++ b/src/main/java/com/songoda/ultimatestacker/database/migrations/_6_RemoveStackedEntityTable.java @@ -1,25 +1,23 @@ package com.songoda.ultimatestacker.database.migrations; import com.songoda.core.database.DataMigration; -import com.songoda.core.database.MySQLConnector; -import com.songoda.ultimatestacker.UltimateStacker; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; -public class _4_DataPurge extends DataMigration { +public class _6_RemoveStackedEntityTable extends DataMigration { - public _4_DataPurge() { - super(4); + public _6_RemoveStackedEntityTable() { + super(6); } @Override - public void migrate(Connection connection, String tablePrefix) throws SQLException { + public void migrate(Connection connection, String tablePrefix) { try (Statement statement = connection.createStatement()) { - statement.execute("ALTER TABLE " + tablePrefix + "host_entities ADD COLUMN updated_at datetime DEFAULT NULL"); + statement.execute("DROP TABLE " + tablePrefix + "stacked_entities"); } catch (SQLException e) { - // Ignore + e.printStackTrace(); } } } diff --git a/src/main/java/com/songoda/ultimatestacker/gui/GUIConvertWhat.java b/src/main/java/com/songoda/ultimatestacker/gui/GUIConvertWhat.java index 51d62b8..bcb0269 100644 --- a/src/main/java/com/songoda/ultimatestacker/gui/GUIConvertWhat.java +++ b/src/main/java/com/songoda/ultimatestacker/gui/GUIConvertWhat.java @@ -55,7 +55,7 @@ public class GUIConvertWhat extends Gui { private void run(Player player) { if (entities) { convertFrom.convertEntities(); - UltimateStacker.getInstance().getEntityStackManager().tryAndLoadColdEntities(); + //UltimateStacker.getInstance().getEntityStackManager().tryAndLoadColdEntities(); } if (spawners) { convertFrom.convertSpawners(); diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/ChunkListeners.java b/src/main/java/com/songoda/ultimatestacker/listeners/ChunkListeners.java deleted file mode 100644 index 95b58d0..0000000 --- a/src/main/java/com/songoda/ultimatestacker/listeners/ChunkListeners.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.songoda.ultimatestacker.listeners; - -import com.songoda.ultimatestacker.stackable.entity.EntityStackManager; -import org.bukkit.Chunk; -import org.bukkit.entity.Entity; -import org.bukkit.entity.LivingEntity; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.world.ChunkLoadEvent; -import org.bukkit.event.world.ChunkUnloadEvent; - -public class ChunkListeners implements Listener { - - private final EntityStackManager entityStackManager; - - public ChunkListeners(EntityStackManager entityStackManager) { - this.entityStackManager = entityStackManager; - } - - @EventHandler - public void onChunkLoad(ChunkLoadEvent event) { - Chunk chunk = event.getChunk(); - for (Entity entity : chunk.getEntities()) { - if (!(entity instanceof LivingEntity)) continue; - if (entityStackManager.isEntityInColdStorage((LivingEntity) entity)) { - entityStackManager.loadStack((LivingEntity) entity); - } - } - } - - @EventHandler - public void onChunkUnload(ChunkUnloadEvent event) { - Chunk chunk = event.getChunk(); - for (Entity entity : chunk.getEntities()) { - if (!(entity instanceof LivingEntity)) continue; - if (entityStackManager.isStackedAndLoaded((LivingEntity) entity)) { - entityStackManager.unloadStack((LivingEntity) entity); - } - } - } -} diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/ClearLagListeners.java b/src/main/java/com/songoda/ultimatestacker/listeners/ClearLagListeners.java index d87a293..360c43c 100644 --- a/src/main/java/com/songoda/ultimatestacker/listeners/ClearLagListeners.java +++ b/src/main/java/com/songoda/ultimatestacker/listeners/ClearLagListeners.java @@ -18,8 +18,8 @@ public class ClearLagListeners implements Listener { @EventHandler public void onClearLaggTask(EntityRemoveEvent event) { for (Entity entity : event.getWorld().getEntities()) { - if (entity instanceof LivingEntity && plugin.getEntityStackManager().isStackedAndLoaded((LivingEntity)entity)) { - plugin.getEntityStackManager().removeStack(entity); + if (entity instanceof LivingEntity && plugin.getEntityStackManager().isStackedEntity(entity)) { + plugin.getEntityStackManager().getStack((LivingEntity) entity).destroy(); event.addEntity(entity); } } diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/DeathListeners.java b/src/main/java/com/songoda/ultimatestacker/listeners/DeathListeners.java index 714184a..48744ad 100644 --- a/src/main/java/com/songoda/ultimatestacker/listeners/DeathListeners.java +++ b/src/main/java/com/songoda/ultimatestacker/listeners/DeathListeners.java @@ -82,7 +82,7 @@ public class DeathListeners implements Listener { drops.clear(); if (plugin.getCustomEntityManager().getCustomEntity(entity) == null) { - if (plugin.getEntityStackManager().isStackedAndLoaded(event.getEntity())) { + if (plugin.getEntityStackManager().isStackedEntity(event.getEntity())) { plugin.getEntityStackManager().getStack(event.getEntity()).onDeath(entity, drops, custom, event.getDroppedExp(), event); } else { DropUtils.processStackedDrop(event.getEntity(), drops, event); @@ -157,7 +157,7 @@ public class DeathListeners implements Listener { if (!(event.getEntity() instanceof LivingEntity)) return; LivingEntity entity = (LivingEntity) event.getEntity(); - if (!plugin.getEntityStackManager().isStackedAndLoaded(entity)) return; + if (!plugin.getEntityStackManager().isStackedEntity(entity)) return; EntityStack stack = plugin.getEntityStackManager().getStack(entity); Player player = (Player) event.getDamager(); diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/InteractListeners.java b/src/main/java/com/songoda/ultimatestacker/listeners/InteractListeners.java index 8f44abd..0d1b2ee 100644 --- a/src/main/java/com/songoda/ultimatestacker/listeners/InteractListeners.java +++ b/src/main/java/com/songoda/ultimatestacker/listeners/InteractListeners.java @@ -38,7 +38,7 @@ public class InteractListeners implements Listener { ItemStack item = player.getInventory().getItemInHand(); - if (!plugin.getEntityStackManager().isStackedAndLoaded(entity)) return; + if (!plugin.getEntityStackManager().isStackedEntity(entity)) return; if (item.getType() != Material.NAME_TAG && !correctFood(item, entity)) return; diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/ShearListeners.java b/src/main/java/com/songoda/ultimatestacker/listeners/ShearListeners.java index 6af0d97..70ee389 100644 --- a/src/main/java/com/songoda/ultimatestacker/listeners/ShearListeners.java +++ b/src/main/java/com/songoda/ultimatestacker/listeners/ShearListeners.java @@ -38,7 +38,7 @@ public class ShearListeners implements Listener { && entity.getType() != EntityType.MUSHROOM_COW && entity.getType() != EntityType.SNOWMAN) return; EntityStackManager stackManager = plugin.getEntityStackManager(); - if (!stackManager.isStackedAndLoaded(entity)) return; + if (!stackManager.isStackedEntity(entity)) return; if (event.getEntity().getType() == EntityType.SHEEP && Settings.SPLIT_CHECKS.getStringList().stream().noneMatch(line -> Split.valueOf(line) == Split.SHEEP_SHEAR) diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/SheepDyeListeners.java b/src/main/java/com/songoda/ultimatestacker/listeners/SheepDyeListeners.java index 5c7b396..1fe55dd 100644 --- a/src/main/java/com/songoda/ultimatestacker/listeners/SheepDyeListeners.java +++ b/src/main/java/com/songoda/ultimatestacker/listeners/SheepDyeListeners.java @@ -24,7 +24,7 @@ public class SheepDyeListeners implements Listener { LivingEntity entity = event.getEntity(); EntityStackManager stackManager = plugin.getEntityStackManager(); - if (!stackManager.isStackedAndLoaded(entity)) return; + if (!stackManager.isStackedEntity(entity)) return; if (Settings.SPLIT_CHECKS.getStringList().stream().noneMatch(line -> Split.valueOf(line) == Split.SHEEP_DYE)) return; diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/SpawnerListeners.java b/src/main/java/com/songoda/ultimatestacker/listeners/SpawnerListeners.java index 4ccb69d..c1449c8 100644 --- a/src/main/java/com/songoda/ultimatestacker/listeners/SpawnerListeners.java +++ b/src/main/java/com/songoda/ultimatestacker/listeners/SpawnerListeners.java @@ -67,12 +67,16 @@ public class SpawnerListeners implements Listener { SpawnerStack spawnerStack = spawnerStackManager.getSpawner(location); - spawnerStack.spawn(spawnerStack.calculateSpawnCount(), "EXPLOSION_NORMAL", null, (e) -> { + int amountToSpawn = spawnerStack.calculateSpawnCount(); + + spawnerStack.spawn(amountToSpawn, "EXPLOSION_NORMAL", null, (e) -> { if (Settings.NO_AI.getBoolean()) EntityUtils.setUnaware(e); if (mcmmo) entity.setMetadata("mcMMO: Spawned Entity", new FixedMetadataValue(plugin, true)); + + UltimateStacker.getInstance().getEntityStackManager().setStack(e, amountToSpawn); return true; }, event.getEntityType()); } diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/TameListeners.java b/src/main/java/com/songoda/ultimatestacker/listeners/TameListeners.java index d993b4e..ec93ed4 100644 --- a/src/main/java/com/songoda/ultimatestacker/listeners/TameListeners.java +++ b/src/main/java/com/songoda/ultimatestacker/listeners/TameListeners.java @@ -22,7 +22,7 @@ public class TameListeners implements Listener { LivingEntity entity = event.getEntity(); EntityStackManager stackManager = plugin.getEntityStackManager(); - if (!stackManager.isStackedAndLoaded(entity)) return; + if (!stackManager.isStackedEntity(entity)) return; EntityStack stack = plugin.getEntityStackManager().getStack(entity); diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/entity/EntityCurrentListener.java b/src/main/java/com/songoda/ultimatestacker/listeners/entity/EntityCurrentListener.java index 66b61f2..05a1f04 100644 --- a/src/main/java/com/songoda/ultimatestacker/listeners/entity/EntityCurrentListener.java +++ b/src/main/java/com/songoda/ultimatestacker/listeners/entity/EntityCurrentListener.java @@ -20,13 +20,11 @@ public class EntityCurrentListener implements Listener { @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public void onSpawn(EntityTransformEvent event) { EntityStackManager stackManager = plugin.getEntityStackManager(); - if (stackManager.isStackedAndLoaded(event.getEntity().getUniqueId()) + if (stackManager.isStackedEntity(event.getEntity()) && event.getEntity() instanceof LivingEntity && event.getTransformedEntity() instanceof LivingEntity) { - EntityStack stack = stackManager.updateStack((LivingEntity) event.getEntity(), - (LivingEntity) event.getTransformedEntity()); + EntityStack stack = stackManager.updateStack((LivingEntity) event.getEntity(), (LivingEntity) event.getTransformedEntity()); stack.releaseHost(); - stack.updateStack(); } } } diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/entity/EntityListeners.java b/src/main/java/com/songoda/ultimatestacker/listeners/entity/EntityListeners.java index bfc0f1f..fe3b937 100644 --- a/src/main/java/com/songoda/ultimatestacker/listeners/entity/EntityListeners.java +++ b/src/main/java/com/songoda/ultimatestacker/listeners/entity/EntityListeners.java @@ -59,7 +59,7 @@ public class EntityListeners implements Listener { EntityStackManager stackManager = plugin.getEntityStackManager(); - if (!stackManager.isStackedAndLoaded(entity)) return; + if (!stackManager.isStackedEntity(entity)) return; EntityStack stack = stackManager.getStack(entity); @@ -78,7 +78,7 @@ public class EntityListeners implements Listener { Entity entity = event.getEntity(); - if (entity instanceof LivingEntity && plugin.getEntityStackManager().isStackedAndLoaded((LivingEntity) entity) + if (entity instanceof LivingEntity && plugin.getEntityStackManager().isStackedEntity(entity) && Settings.DISABLE_KNOCKBACK.getBoolean() && ((Player) event.getDamager()).getItemInHand().getEnchantmentLevel(Enchantment.KNOCKBACK) == 0) { Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, () -> { diff --git a/src/main/java/com/songoda/ultimatestacker/stackable/entity/ColdEntityStack.java b/src/main/java/com/songoda/ultimatestacker/stackable/entity/ColdEntityStack.java deleted file mode 100644 index 62d3dd4..0000000 --- a/src/main/java/com/songoda/ultimatestacker/stackable/entity/ColdEntityStack.java +++ /dev/null @@ -1,169 +0,0 @@ -package com.songoda.ultimatestacker.stackable.entity; - -import com.songoda.core.nms.NmsManager; -import com.songoda.core.nms.nbt.NBTEntity; -import com.songoda.ultimatestacker.UltimateStacker; -import com.songoda.ultimatestacker.stackable.entity.custom.CustomEntity; -import com.songoda.ultimatestacker.utils.Stackable; -import org.bukkit.Location; -import org.bukkit.entity.Entity; -import org.bukkit.entity.LivingEntity; - -import java.util.Deque; -import java.util.LinkedList; -import java.util.List; -import java.util.Objects; -import java.util.UUID; -import java.util.concurrent.ConcurrentLinkedDeque; -import java.util.stream.Collectors; - -public class ColdEntityStack implements Stackable { - - protected static final UltimateStacker plugin = UltimateStacker.getInstance(); - - // The id to identify this stack in the database. - private int id; - - // The unique id of the stacks host. - protected UUID hostUniqueId; - - // These are the entities below the host. - protected final Deque stackedEntities = new ConcurrentLinkedDeque<>(); - - // The amount of duplicates of the host to create when loaded. - protected int createDuplicates = 0; - - public ColdEntityStack(UUID hostUniqueId, int id) { - this.hostUniqueId = hostUniqueId; - this.id = id; - } - - public ColdEntityStack(UUID hostUniqueId) { - this.hostUniqueId = hostUniqueId; - } - - public StackedEntity addEntityToStackSilently(Entity entity) { - return addEntityToStackSilently(getStackedEntity(entity)); - } - - public List addRawEntitiesToStackSilently(List unstackedEntities) { - List stackedEntities = unstackedEntities.stream() - .map(this::getStackedEntity).collect(Collectors.toList()); - addEntitiesToStackSilently(stackedEntities); - return stackedEntities; - } - - public void addEntitiesToStackSilently(List stackedEntities) { - stackedEntities.removeIf(Objects::isNull); - this.stackedEntities.addAll(stackedEntities); - } - - public synchronized StackedEntity addEntityToStackSilently(StackedEntity stackedEntity) { - if (stackedEntity == null) return null; - stackedEntities.push(stackedEntity); - return stackedEntity; - } - - public void moveEntitiesFromStack(EntityStack stack, int amount) { - List stackedEntities = stack.takeEntities(amount); - this.stackedEntities.addAll(stackedEntities); - plugin.getDataManager().createStackedEntities(this, stackedEntities); - } - - public List takeEntities(int amount) { - List entities = new LinkedList<>(); - for (int i = 0; i < amount; i++) { - StackedEntity entity = stackedEntities.pollFirst(); - if (entity != null) - entities.add(entity); - } - plugin.getDataManager().deleteStackedEntities(entities); - return entities; - } - - public List takeAllEntities() { - List entities = new LinkedList<>(stackedEntities); - stackedEntities.clear(); - return entities; - } - - public LivingEntity takeOneAndSpawnEntity(Location location) { - if (stackedEntities.isEmpty()) return null; - NBTEntity nbtEntity = NmsManager.getNbt().newEntity(); - nbtEntity.deSerialize(stackedEntities.getFirst().getSerializedEntity()); - - for (CustomEntity customEntity : plugin.getCustomEntityManager().getRegisteredCustomEntities()) { - String identifier = customEntity.getPluginName() + "_UltimateStacker"; - if (!nbtEntity.has(identifier)) continue; - LivingEntity entity = customEntity.spawnFromIdentifier(nbtEntity.getString(identifier), location); - if (entity == null) continue; - stackedEntities.removeFirst(); - plugin.getDataManager().deleteStackedEntity(entity.getUniqueId()); - return entity; - } - - LivingEntity newEntity = null; - for (int i = 0; i < 5; i++) { - newEntity = (LivingEntity) nbtEntity.spawn(location); - - if (newEntity != null) { - stackedEntities.removeFirst(); - plugin.getDataManager().deleteStackedEntity(newEntity.getUniqueId()); - break; - } - } - if (newEntity == null) - plugin.getDataManager().deleteStackedEntity(hostUniqueId); - - return newEntity; - } - - @Override - public int getAmount() { - return stackedEntities.size() + 1; - } - - @Override - public boolean isValid() { - return true; - } - - public void createDuplicates(int duplicates) { - this.createDuplicates = duplicates; - } - - public int getCreateDuplicates() { - return createDuplicates; - } - - protected StackedEntity getStackedEntity(Entity entity) { - return getStackedEntity(entity, false); - } - - protected synchronized StackedEntity getStackedEntity(Entity entity, boolean newUUID) { - if (entity == null) return null; - UUID uuid = entity.getUniqueId(); - NBTEntity nbtEntity = NmsManager.getNbt().of(entity); - - CustomEntity customEntity = plugin.getCustomEntityManager().getCustomEntity(entity); - if (customEntity != null) - nbtEntity.set(customEntity.getPluginName() + "_UltimateStacker", customEntity.getNBTIdentifier(entity)); - return new StackedEntity(uuid, nbtEntity.serialize()); - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public UUID getHostUniqueId() { - return hostUniqueId; - } - - public void setHostUniqueId(UUID hostUniqueId) { - this.hostUniqueId = hostUniqueId; - } -} diff --git a/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java b/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java index e2de50a..d1f2ffd 100644 --- a/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java +++ b/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java @@ -3,9 +3,12 @@ package com.songoda.ultimatestacker.stackable.entity; import com.songoda.core.compatibility.ServerVersion; import com.songoda.core.lootables.loot.Drop; import com.songoda.core.lootables.loot.DropUtils; +import com.songoda.core.nms.NmsManager; +import com.songoda.core.nms.nbt.NBTEntity; import com.songoda.ultimatestacker.UltimateStacker; import com.songoda.ultimatestacker.events.EntityStackKillEvent; import com.songoda.ultimatestacker.settings.Settings; +import com.songoda.ultimatestacker.stackable.entity.custom.CustomEntity; import com.songoda.ultimatestacker.utils.Async; import com.songoda.ultimatestacker.utils.Methods; import org.bukkit.Bukkit; @@ -21,96 +24,42 @@ import org.bukkit.util.Vector; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.concurrent.ThreadLocalRandom; -public class EntityStack extends ColdEntityStack { +public class EntityStack extends StackedEntity { - // This is the host entity which is not stored in serialized nbt. - private LivingEntity hostEntity; + private static final UltimateStacker plugin = UltimateStacker.getInstance(); public EntityStack(LivingEntity hostEntity) { - super(hostEntity.getUniqueId()); - this.hostEntity = hostEntity; + super(hostEntity); } - public EntityStack(LivingEntity hostEntity, ColdEntityStack coldEntityStack) { - this(hostEntity); - this.setId(coldEntityStack.getId()); - this.stackedEntities.addAll(coldEntityStack.stackedEntities); + public EntityStack(LivingEntity hostEntity, int amount) { + super(hostEntity, amount); } - public StackedEntity addEntityToStack(Entity entity) { - StackedEntity stackedEntity = addEntityToStackSilently(entity); - updateStack(); - return stackedEntity; + public synchronized EntityStack addEntityToStack(int amount) { + setAmount(getAmount() + amount); + return this; } - @Override - public List takeEntities(int amount) { - List entities = super.takeEntities(amount); - if (this.stackedEntities.isEmpty()) - destroy(true); - return entities; - } - - @Override - public List takeAllEntities() { - destroy(true); - return super.takeAllEntities(); - } - - public void updateStack() { - Async.run(() -> { - if (createDuplicates != 0) { - List stackedEntities = new ArrayList<>(); - try { - for (int i = 0; i < createDuplicates; i++) { - StackedEntity entity = addEntityToStackSilently(getStackedEntity(hostEntity, true)); - if (entity != null) - stackedEntities.add(entity); - } - plugin.getDataManager().createStackedEntities(this, stackedEntities); - - createDuplicates = 0; - updateNametag(); - } catch (Exception ignored) { - //Ignored for now - } - } - }); - updateNametag(); - } - - public void updateNametag() { - if (hostEntity == null) { - //Delay with 1 tick to make sure the entity is loaded. - Bukkit.getScheduler().scheduleSyncDelayedTask(UltimateStacker.getInstance(), this::updateNametag, 1L); - return; - } - hostEntity.setCustomNameVisible(!Settings.HOLOGRAMS_ON_LOOK_ENTITY.getBoolean()); - hostEntity.setCustomName(Methods.compileEntityName(hostEntity, getAmount())); + public synchronized EntityStack removeEntityFromStack(int amount) { + setAmount(getAmount() - amount); + return this; } public LivingEntity getHostEntity() { - if (hostEntity == null) { - plugin.getEntityStackManager().removeStack(this.hostUniqueId); - return null; - } return hostEntity; } - public StackedEntity getHostAsStackedEntity() { - return getStackedEntity(hostEntity); - } - protected void setHostEntity(LivingEntity hostEntity) { this.hostEntity = hostEntity; - this.hostUniqueId = hostEntity.getUniqueId(); } private void handleWholeStackDeath(LivingEntity killed, List drops, boolean custom, int droppedExp, EntityDeathEvent event) { - plugin.getDataManager().deleteHost(this); + EntityStack stack = plugin.getEntityStackManager().getStack(killed); // In versions 1.14 and below experience is not dropping. Because of this we are doing this ourselves. if (ServerVersion.isServerVersionAtOrBelow(ServerVersion.V1_14)) { Location killedLocation = killed.getLocation(); @@ -133,7 +82,7 @@ public class EntityStack extends ColdEntityStack { } event.getDrops().clear(); - plugin.getEntityStackManager().removeStack(event.getEntity()); + stack.destroy(); if (killed.getKiller() == null) return; plugin.addExp(killed.getKiller(), this); } @@ -162,12 +111,6 @@ public class EntityStack extends ColdEntityStack { newEntity.setVelocity(velocity); stackManager.updateStack(killed, newEntity); - - updateStack(); - - if (stackedEntities.isEmpty()) { - destroy(); - } } public void onDeath(LivingEntity killed, List drops, boolean custom, int droppedExp, EntityDeathEvent event) { @@ -195,42 +138,37 @@ public class EntityStack extends ColdEntityStack { } } + public LivingEntity takeOneAndSpawnEntity(Location location) { + if (amount <= 0) return null; + amount--; + LivingEntity entity = Objects.requireNonNull(location.getWorld()).spawn(location, hostEntity.getClass()); + this.hostEntity = entity; + updateNameTag(); + return entity; + } + public void releaseHost() { LivingEntity oldHost = hostEntity; LivingEntity entity = takeOneAndSpawnEntity(hostEntity.getLocation()); - if (!stackedEntities.isEmpty()) { - destroy(false); + if (getAmount() >= 0) { plugin.getEntityStackManager().updateStack(oldHost, entity); - entity.setVelocity(new Vector(ThreadLocalRandom.current().nextDouble(-1, 1.01), - 0, ThreadLocalRandom.current().nextDouble(-1, 1.01)).normalize().multiply(0.5)); + updateNameTag(); } else { destroy(); } - updateStack(); - } public void destroy() { - destroy(true); - } - - public void destroy(boolean full) { - if (full) - plugin.getEntityStackManager().removeStack(this.hostUniqueId); - if (hostEntity != null) { - try { - hostEntity.setCustomNameVisible(false); - hostEntity.setCustomName(null); - } catch (NullPointerException ignored) {} - } + if (hostEntity == null) return; + Bukkit.getScheduler().runTask(plugin, hostEntity::remove); hostEntity = null; - hostUniqueId = null; } @Override public String toString() { return "EntityStack{" + "hostEntity=" + hostEntity + + ", amount=" + amount + '}'; } } diff --git a/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStackManager.java b/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStackManager.java index 29d8a77..8c32af6 100644 --- a/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStackManager.java +++ b/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStackManager.java @@ -7,6 +7,7 @@ import org.bukkit.ChatColor; import org.bukkit.Chunk; import org.bukkit.World; import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; import org.bukkit.entity.LivingEntity; import java.util.Collection; @@ -17,157 +18,92 @@ import java.util.UUID; public class EntityStackManager { - // These are all stacked mobs loaded into memory. - private static final Map stacks = new HashMap<>(); - - // This will only be used for stacks that have not yet been loaded into the game. - private static final Map coldStacks = new HashMap<>(); - private final UltimateStacker plugin; public EntityStackManager(UltimateStacker plugin) { this.plugin = plugin; } - public EntityStack addStack(EntityStack stack) { - stacks.put(stack.getHostEntity().getUniqueId(), stack); - return stack; + public EntityStack createStack(LivingEntity entity, int amount) { + return new EntityStack(entity, amount); + } + + public boolean isStackedEntity(Entity entity) { + return entity.hasMetadata("US_AMOUNT"); + } + + public int getAmount(Entity entity) { + if (!isStackedEntity(entity)) return 1; + if (entity.getMetadata("US_AMOUNT").isEmpty()) return 1; + return entity.getMetadata("US_AMOUNT").get(0).asInt(); } public EntityStack addStack(LivingEntity entity) { - if (entity == null) return null; - EntityStack stack = new EntityStack(entity); - plugin.getDataManager().createHostEntity(stack); - stacks.put(entity.getUniqueId(), stack); - return stack; + return addStack(entity, getAmount(entity) == 1 ? 1 : getAmount(entity)); } public EntityStack addStack(LivingEntity entity, int amount) { if (entity == null) return null; - EntityStack stack = new EntityStack(entity); - plugin.getDataManager().createHostEntity(stack); - stacks.put(entity.getUniqueId(), stack); - stack.createDuplicates(amount - 1); - plugin.getDataManager().updateHost(stack); - stack.updateStack(); - return stack; - } - - @Deprecated - public EntityStack addSerializedStack(LivingEntity entity, String customName) { - if (customName != null && customName.contains(String.valueOf(ChatColor.COLOR_CHAR))) { - String name = customName.replace(String.valueOf(ChatColor.COLOR_CHAR), "") - .replace(";", ""); - if (!name.contains(":")) return null; - String split = name.split(":")[0]; - int amount = Methods.isInt(split) ? Integer.parseInt(split) : 0; - return addStack(entity, amount); + if (isStackedEntity(entity)) { + EntityStack stack = getStack(entity); + stack.addEntityToStack(amount); + return stack; } return null; } - @Deprecated - public EntityStack addSerializedStack(LivingEntity entity) { - return addSerializedStack(entity, entity.getCustomName()); + public EntityStack getStack(UUID uuid) { + Entity entity = Bukkit.getEntity(uuid); + if (entity == null) return null; + if (isStackedEntity(entity)) { + if (entity instanceof LivingEntity) { + return new EntityStack((LivingEntity) entity); + } + } + return null; } public EntityStack getStack(LivingEntity entity) { - EntityStack stack = getStack(entity.getUniqueId()); - if (stack == null) stack = addSerializedStack(entity); + if (!isStackedEntity(entity)) return null; + return new EntityStack(entity); + } + + public EntityStack decreaseStack(Entity entity) { + EntityStack stack = getStack((LivingEntity) entity); + if (stack == null) return null; + stack.removeEntityFromStack(1); return stack; } - public EntityStack getStack(UUID uuid) { - return stacks.get(uuid); - } - - public EntityStack removeStack(Entity entity) { - return removeStack(entity.getUniqueId()); - } - - public EntityStack removeStack(UUID uuid) { - EntityStack stack = stacks.remove(uuid); - if (stack != null) { - plugin.getDataManager().deleteHost(stack); - stack.destroy(); - } - + public EntityStack decreaseStack(Entity entity, int amount) { + EntityStack stack = getStack((LivingEntity) entity); + if (stack == null) return null; + stack.removeEntityFromStack(amount); return stack; } - public Map getStacks() { - return Collections.unmodifiableMap(stacks); + public EntityStack updateStack(LivingEntity entity) { + EntityStack stack = getStack(entity); + if (stack == null) return null; + stack.updateNameTag(); + return stack; } public EntityStack updateStack(LivingEntity oldEntity, LivingEntity newEntity) { - EntityStack stack = stacks.remove(oldEntity.getUniqueId()); + EntityStack stack = getStack(oldEntity); if (stack == null) return null; - stack.setHostEntity(newEntity); - stacks.put(newEntity.getUniqueId(), stack); - plugin.getDataManager().updateHost(stack); - return stack; - } - - @Deprecated - public boolean isStacked(UUID entity) { - return isStackedAndLoaded(entity); - } - - public boolean isStackedAndLoaded(LivingEntity entity) { - return stacks.containsKey(entity.getUniqueId()); - } - - public boolean isStackedAndLoaded(UUID entity) { - return stacks.containsKey(entity); - } - - public boolean isEntityInColdStorage(UUID entity) { - return coldStacks.containsKey(entity); - } - - public boolean isEntityInColdStorage(LivingEntity entity) { - return isEntityInColdStorage(entity.getUniqueId()); - } - - public void loadStack(LivingEntity entity) { - ColdEntityStack coldStack = coldStacks.get(entity.getUniqueId()); - if (coldStack == null) return; - EntityStack stack = new EntityStack(entity, coldStack); - stack.updateStack(); - stacks.put(entity.getUniqueId(), stack); - plugin.getDataManager().updateHost(coldStack); - } - - public void unloadStack(LivingEntity entity) { - EntityStack stack = stacks.get(entity.getUniqueId()); - if (stack == null) return; - ColdEntityStack coldStack = new EntityStack(entity, stack); + int amount = stack.getAmount(); stack.destroy(); - coldStacks.put(entity.getUniqueId(), coldStack); + return createStack(newEntity, amount); } - public void addStacks(Collection entities) { - for (ColdEntityStack stack : entities) - coldStacks.put(stack.hostUniqueId, stack); - } - - public ColdEntityStack addLegacyColdStack(UUID entity, int amount) { - ColdEntityStack stack = new ColdEntityStack(entity); - plugin.getDataManager().createHostEntity(stack); - stack.createDuplicates(amount - 1); - plugin.getDataManager().updateHost(stack); - coldStacks.put(entity, stack); - return stack; - } - - public void tryAndLoadColdEntities() { - for (World world : Bukkit.getWorlds()) { - for (Chunk chunk : world.getLoadedChunks()) { - for (Entity entity : chunk.getEntities()) { - if (entity instanceof LivingEntity) - loadStack((LivingEntity)entity); - } - } + public void setStack(LivingEntity newEntity, int amount) { + if (isStackedEntity(newEntity)) { + EntityStack stack = getStack(newEntity); + stack.setAmount(amount); + System.err.println("Stacked entity already exists, updating stack amount to " + amount); + } else { + createStack(newEntity, amount); } } } diff --git a/src/main/java/com/songoda/ultimatestacker/stackable/entity/StackedEntity.java b/src/main/java/com/songoda/ultimatestacker/stackable/entity/StackedEntity.java index 189ee53..0558b97 100644 --- a/src/main/java/com/songoda/ultimatestacker/stackable/entity/StackedEntity.java +++ b/src/main/java/com/songoda/ultimatestacker/stackable/entity/StackedEntity.java @@ -1,22 +1,78 @@ package com.songoda.ultimatestacker.stackable.entity; +import com.songoda.ultimatestacker.UltimateStacker; +import com.songoda.ultimatestacker.settings.Settings; +import com.songoda.ultimatestacker.utils.Methods; +import org.bukkit.Bukkit; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.LivingEntity; +import org.bukkit.metadata.FixedMetadataValue; + import java.util.UUID; public class StackedEntity { - private final UUID uniqueId; - private final byte[] serializedEntity; + protected int amount; + protected LivingEntity hostEntity; - public StackedEntity(UUID uniqueId, byte[] serializedEntity) { - this.uniqueId = uniqueId; - this.serializedEntity = serializedEntity; + /** + * Gets an existing stack from an entity or creates a new one if it doesn't exist. + * @param entity The entity to get the stack from. + */ + public StackedEntity(LivingEntity entity) { + if (entity == null) return; + if (!UltimateStacker.getInstance().getEntityStackManager().isStackedEntity(entity)) { + entity.setMetadata("US_AMOUNT", new FixedMetadataValue(UltimateStacker.getInstance(), 1)); + this.amount = 1; + updateNameTag(); + } else { + //get the amount from the entity + this.amount = UltimateStacker.getInstance().getEntityStackManager().getAmount(entity); + } + this.hostEntity = entity; } - public UUID getUniqueId() { - return uniqueId; + /** + * Creates a new stack or overrides an existing stack. + * @param entity The entity to create the stack for. + * @param amount The amount of entities in the stack. + */ + public StackedEntity(LivingEntity entity, int amount) { + if (entity == null) return; + this.hostEntity = entity; + this.amount = amount; + entity.setMetadata("US_AMOUNT", new FixedMetadataValue(UltimateStacker.getInstance(), amount)); + updateNameTag(); } - public byte[] getSerializedEntity() { - return serializedEntity; + + public EntityType getType() { + return hostEntity.getType(); + } + + public int getAmount() { + return amount; + } + + public void setAmount(int amount) { + this.amount = amount; + this.hostEntity.setMetadata("US_AMOUNT", new FixedMetadataValue(UltimateStacker.getInstance(), amount)); + updateNameTag(); + } + + public UUID getUuid() { + return hostEntity.getUniqueId(); + } + + public LivingEntity getHostEntity() { + return hostEntity; + } + + protected void updateNameTag() { + if (hostEntity == null) { + return; + } + hostEntity.setCustomNameVisible(!Settings.HOLOGRAMS_ON_LOOK_ENTITY.getBoolean()); + hostEntity.setCustomName(Methods.compileEntityName(hostEntity, getAmount())); } } diff --git a/src/main/java/com/songoda/ultimatestacker/tasks/StackingTask.java b/src/main/java/com/songoda/ultimatestacker/tasks/StackingTask.java index 6bbca63..c409712 100644 --- a/src/main/java/com/songoda/ultimatestacker/tasks/StackingTask.java +++ b/src/main/java/com/songoda/ultimatestacker/tasks/StackingTask.java @@ -58,11 +58,14 @@ import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; -public class StackingTask extends BukkitRunnable { +public class StackingTask implements Runnable { private final UltimateStacker plugin; + private final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(4); private final EntityStackManager stackManager; @@ -96,7 +99,12 @@ public class StackingTask extends BukkitRunnable { loadedWorlds.add(new SWorld(world)); // Start the stacking task. - runTaskTimerAsynchronously(plugin, 0, Settings.STACK_SEARCH_TICK_SPEED.getInt()); + //runTaskTimerAsynchronously(plugin, 0, Settings.STACK_SEARCH_TICK_SPEED.getInt()); + executorService.scheduleAtFixedRate(this, 0, Settings.STACK_SEARCH_TICK_SPEED.getInt()*20L, java.util.concurrent.TimeUnit.MILLISECONDS); + } + + public void stop() { + executorService.shutdown(); } @Override @@ -197,32 +205,46 @@ public class StackingTask extends BukkitRunnable { } - private void processEntity(LivingEntity livingEntity, SWorld sWorld, Location location) { + private void processEntity(LivingEntity baseEntity, SWorld sWorld, Location location) { + + // Check our WorldGuard flag. + Boolean flag = WorldGuardHook.isEnabled() ? WorldGuardHook.getBooleanFlag(baseEntity.getLocation(), "mob-stacking") : null; + if (flag != null && !flag) { + return; + } + // Get the stack from the entity. It should be noted that this value will // be null if our entity is not a stack. - EntityStack stack = plugin.getEntityStackManager().getStack(livingEntity); - - // Is this entity stacked? - boolean isStack = stack != null; - - // The amount that is stackable. - int amountToStack = isStack ? stack.getAmount() : 1; - - // Attempt to split our stack. If the split is successful then skip this entity. - if (isStack && attemptSplit(stack, livingEntity)) return; - - // If this entity is named, a custom entity or disabled then skip it. - if (!isStack && (livingEntity.getCustomName() != null - && plugin.getCustomEntityManager().getCustomEntity(livingEntity) == null) - || !configurationSection.getBoolean("Mobs." + livingEntity.getType().name() + ".Enabled")) - return; + EntityStack baseStack = plugin.getEntityStackManager().getStack(baseEntity); // Get the maximum stack size for this entity. - int maxEntityStackSize = getEntityStackSize(livingEntity); + int maxEntityStackSize = getEntityStackSize(baseEntity); + + // Is this entity stacked? + boolean isStack = baseStack != null; + + if (isStack && baseStack.getAmount() == maxEntityStackSize) { + // If the stack is already at the max size then we can skip it. + return; + } + + // The amount that is stackable. + int amountToStack = isStack ? baseStack.getAmount() : 1; + + // Attempt to split our stack. If the split is successful then skip this entity. + if (isStack && attemptSplit(baseStack, baseEntity)) return; + + // If this entity is named, a custom entity or disabled then skip it. + if (!isStack && (baseEntity.getCustomName() != null + && plugin.getCustomEntityManager().getCustomEntity(baseEntity) == null) + || !configurationSection.getBoolean("Mobs." + baseEntity.getType().name() + ".Enabled")) + return; + + // Get similar entities around our entity and make sure those entities are both compatible and stackable. List stackableFriends = new LinkedList<>(); - for (LivingEntity entity : getSimilarEntitiesAroundEntity(livingEntity, sWorld, location)) { + for (LivingEntity entity : getSimilarEntitiesAroundEntity(baseEntity, sWorld, location)) { // Check to see if entity is not stackable. if (!isEntityStackable(entity)) continue; @@ -231,156 +253,56 @@ public class StackingTask extends BukkitRunnable { } // Loop through our similar stackable entities. - for (LivingEntity entity : stackableFriends) { - // Make sure the entity has not already been processed. - if (this.processed.contains(entity.getUniqueId())) continue; - - // Check our WorldGuard flag. - Boolean flag = WorldGuardHook.isEnabled() ? WorldGuardHook.getBooleanFlag(livingEntity.getLocation(), "mob-stacking") : null; - if (flag != null && !flag) - continue; + for (LivingEntity friendlyEntity : stackableFriends) { + // Make sure the friendlyEntity has not already been processed. + if (this.processed.contains(friendlyEntity.getUniqueId())) continue; // Get this entities friendStack. - EntityStack friendStack = stackManager.getStack(entity); + EntityStack friendStack = stackManager.getStack(friendlyEntity); - // Check to see if this entity is stacked and friendStack plus + if (friendStack == null) continue; + + // Check to see if this friendlyEntity is stacked and friendStack plus // our amount to stack is not above our max friendStack size - // for this entity. - if (friendStack != null && (friendStack.getAmount() + amountToStack) <= maxEntityStackSize) { + // for this friendlyEntity. - // If we are a stack lets merge our stack with the just found friend stack. - if (isStack) { - // Get the host entity. - StackedEntity host = stack.getHostAsStackedEntity(); - // Get all the stacked entities in our stack and add them to a list. - List entities = stack.takeAllEntities(); - // Add the host to this list. - entities.add(host); - // Add the collected entities to the new stack. - friendStack.addEntitiesToStackSilently(entities); - // Update friend stack to display changes. - friendStack.updateStack(); - // Push changes to the database. - plugin.getDataManager().createStackedEntities(friendStack, entities); - } else { - // If we are not stacked add ourselves to the found friendStack. - plugin.getDataManager().createStackedEntity(friendStack, friendStack.addEntityToStack(livingEntity)); + boolean overstack = (friendStack.getAmount() + amountToStack) > maxEntityStackSize; + + if (!overstack) { + friendStack.setAmount(friendStack.getAmount() + amountToStack); + if (baseEntity.isLeashed()) + Bukkit.getScheduler().runTask(plugin, () -> baseEntity.getWorld() + .dropItemNaturally(baseEntity.getLocation(), CompatibleMaterial.LEAD.getItem())); + if (baseStack != null) { + baseStack.destroy(); } - - // Drop lead if applicable then remove our entity and mark it as processed. - if (livingEntity.isLeashed()) - Bukkit.getScheduler().runTask(plugin, () -> livingEntity.getWorld() - .dropItemNaturally(livingEntity.getLocation(), CompatibleMaterial.LEAD.getItem())); - Bukkit.getScheduler().runTask(plugin, livingEntity::remove); - processed.add(livingEntity.getUniqueId()); - - return; - } else if (friendStack == null - && isStack - && (stack.getAmount() + 1) <= maxEntityStackSize - && canFly(entity) - && Settings.ONLY_STACK_FLYING_DOWN.getBoolean() - && location.getY() > entity.getLocation().getY()) { - - // Make the friend the new stack host. - EntityStack newStack = stackManager.updateStack(livingEntity, entity); - - if (newStack == null) { - continue; - } - - // Add our entity to that stack - plugin.getDataManager().createStackedEntity(newStack, newStack.addEntityToStack(livingEntity)); - - // Remove our entity and mark it as processed. - Bukkit.getScheduler().runTask(plugin, livingEntity::remove); - processed.add(livingEntity.getUniqueId()); + processed.add(baseEntity.getUniqueId()); return; } } - - // If our entity is stacked then skip this entity. - if (isStack) return; - - // Check our WorldGuard flag. - Boolean flag = WorldGuardHook.isEnabled() ? WorldGuardHook.getBooleanFlag(livingEntity.getLocation(), "mob-stacking") : null; - if (flag != null && !flag) - return; - - // Remove all stacked entities from our stackable friends. - stackableFriends.removeIf(stackManager::isStackedAndLoaded); - - // If the stack cap is met then delete this entity. - if (maxPerTypeStacksPerChunk != -1 - && (getSimilarStacksInChunk(sWorld, livingEntity) + 1) > maxPerTypeStacksPerChunk) { - Bukkit.getScheduler().runTask(plugin, livingEntity::remove); - this.processed.add(livingEntity.getUniqueId()); - return; - } - - // If there are none or not enough stackable friends left to create a new entity, - // the stack sizes overlap then skip this entity. - if (stackableFriends.isEmpty() - || stackableFriends.size() < minEntityStackSize - 1 - || minEntityStackSize > maxEntityStackSize) return; - - // If a stack was never found create a new one. - EntityStack newStack = stackManager.addStack(livingEntity); - - List livingEntities = new LinkedList<>(); - - // Loop through the unstacked and unprocessed stackable friends while not creating - // a stack larger than the maximum. - stackableFriends.stream().filter(entity -> !stackManager.isStackedAndLoaded(entity) - && !this.processed.contains(entity.getUniqueId())).limit(maxEntityStackSize).forEach(entity -> { - - // Make sure we're not naming some poor kids pet. - if (entity.getCustomName() != null - && plugin.getCustomEntityManager().getCustomEntity(entity) == null) { - processed.add(livingEntity.getUniqueId()); - newStack.destroy(); - return; - } - - // Drop lead if applicable then remove our entity and mark it as processed. - if (entity.isLeashed()) { - Bukkit.getScheduler().runTask(plugin, () -> entity.getWorld().dropItemNaturally(entity.getLocation(), CompatibleMaterial.LEAD.getItem())); - } - livingEntities.add(entity); - Bukkit.getScheduler().runTask(plugin, entity::remove); - processed.add(entity.getUniqueId()); - - }); - - // Add our new approved entities to the new stack and commit them to the database. - plugin.getDataManager().createStackedEntities(newStack, - newStack.addRawEntitiesToStackSilently(livingEntities)); - - // Update our stack. - newStack.updateStack(); } - public boolean attemptSplit(EntityStack stack, LivingEntity livingEntity) { - int stackSize = stack.getAmount(); + public boolean attemptSplit(EntityStack baseStack, LivingEntity livingEntity) { + int stackSize = baseStack.getAmount(); int maxEntityStackAmount = getEntityStackSize(livingEntity); if (stackSize <= maxEntityStackAmount) return false; - // Destroy the stack. - stack.destroy(); + baseStack.setAmount(maxEntityStackAmount); Bukkit.getScheduler().runTask(plugin, () -> { - for (int i = stackSize; i > 0; i -= maxEntityStackAmount) { - LivingEntity entity = stack.takeOneAndSpawnEntity(livingEntity.getLocation()); - if (entity == null) continue; - EntityStack newStack = plugin.getEntityStackManager().addStack(entity); - newStack.moveEntitiesFromStack(stack, Math.min(i, maxEntityStackAmount) - 1); - newStack.updateStack(); - } + int finalStackSize = stackSize - maxEntityStackAmount; + do { + // Create a new stack, summon entity and add to stack. + LivingEntity newEntity = (LivingEntity) livingEntity.getWorld().spawnEntity(livingEntity.getLocation(), livingEntity.getType()); + int toAdd = Math.min(finalStackSize, maxEntityStackAmount); + EntityStack newStack = stackManager.createStack(newEntity, toAdd); + processed.add(newEntity.getUniqueId()); + finalStackSize -= maxEntityStackAmount; + } while (finalStackSize >= 0); }); // Remove our entity and mark it as processed. - Bukkit.getScheduler().runTask(plugin, livingEntity::remove); processed.add(livingEntity.getUniqueId()); return true; } @@ -443,7 +365,7 @@ public class StackingTask extends BukkitRunnable { public int getSimilarStacksInChunk(SWorld sWorld, LivingEntity entity) { int count = 0; for (LivingEntity e : getNearbyEntities(sWorld, entity.getLocation(), -1, true)) { - if (entity.getType() == e.getType() && plugin.getEntityStackManager().isStackedAndLoaded(e)) + if (entity.getType() == e.getType() && plugin.getEntityStackManager().isStackedEntity(e)) count++; } return count; From 65b817b8ddac7267b7e20a4da81a31a7c8b7e38e Mon Sep 17 00:00:00 2001 From: ceze88 Date: Sat, 4 Feb 2023 14:48:23 +0100 Subject: [PATCH 04/31] Release v2.4.0-DEV --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 812594b..a95c71d 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ com.songoda UltimateStacker 4.0.0 - 2.3.4 + 2.4.0-DEV clean install UltimateStacker-${project.version} From d610f41d008a121795a22cda11f055babeff49cb Mon Sep 17 00:00:00 2001 From: ceze88 Date: Sun, 5 Feb 2023 13:14:44 +0100 Subject: [PATCH 05/31] Fix slime/magma cube replication --- .../entity/EntityCurrentListener.java | 12 ++++++++++++ .../stackable/entity/EntityStack.java | 11 +++++------ .../stackable/entity/EntityStackManager.java | 18 ++++++++++++++++-- .../ultimatestacker/tasks/StackingTask.java | 3 +-- 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/entity/EntityCurrentListener.java b/src/main/java/com/songoda/ultimatestacker/listeners/entity/EntityCurrentListener.java index 05a1f04..71bba69 100644 --- a/src/main/java/com/songoda/ultimatestacker/listeners/entity/EntityCurrentListener.java +++ b/src/main/java/com/songoda/ultimatestacker/listeners/entity/EntityCurrentListener.java @@ -3,11 +3,18 @@ package com.songoda.ultimatestacker.listeners.entity; import com.songoda.ultimatestacker.UltimateStacker; import com.songoda.ultimatestacker.stackable.entity.EntityStack; import com.songoda.ultimatestacker.stackable.entity.EntityStackManager; +import org.bukkit.Bukkit; +import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Slime; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityTransformEvent; +import org.bukkit.event.world.EntitiesLoadEvent; + +import java.util.Arrays; +import java.util.List; public class EntityCurrentListener implements Listener { @@ -23,6 +30,11 @@ public class EntityCurrentListener implements Listener { if (stackManager.isStackedEntity(event.getEntity()) && event.getEntity() instanceof LivingEntity && event.getTransformedEntity() instanceof LivingEntity) { + if (event.getTransformReason().equals(EntityTransformEvent.TransformReason.SPLIT)) { + stackManager.getStack((LivingEntity) event.getEntity()).removeEntityFromStack(1); + event.setCancelled(true); + return; + } EntityStack stack = stackManager.updateStack((LivingEntity) event.getEntity(), (LivingEntity) event.getTransformedEntity()); stack.releaseHost(); } diff --git a/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java b/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java index d1f2ffd..fd72ef5 100644 --- a/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java +++ b/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java @@ -53,7 +53,7 @@ public class EntityStack extends StackedEntity { return hostEntity; } - protected void setHostEntity(LivingEntity hostEntity) { + protected synchronized void setHostEntity(LivingEntity hostEntity) { this.hostEntity = hostEntity; } @@ -89,7 +89,6 @@ public class EntityStack extends StackedEntity { private void handleSingleStackDeath(LivingEntity killed, List drops, int droppedExp, EntityDeathEvent event) { EntityStackManager stackManager = plugin.getEntityStackManager(); - Bukkit.getPluginManager().callEvent(new EntityStackKillEvent(this, false)); Vector velocity = killed.getVelocity().clone(); @@ -138,16 +137,16 @@ public class EntityStack extends StackedEntity { } } - public LivingEntity takeOneAndSpawnEntity(Location location) { + public synchronized LivingEntity takeOneAndSpawnEntity(Location location) { if (amount <= 0) return null; - amount--; LivingEntity entity = Objects.requireNonNull(location.getWorld()).spawn(location, hostEntity.getClass()); this.hostEntity = entity; + setAmount(amount--); updateNameTag(); return entity; } - public void releaseHost() { + public synchronized void releaseHost() { LivingEntity oldHost = hostEntity; LivingEntity entity = takeOneAndSpawnEntity(hostEntity.getLocation()); if (getAmount() >= 0) { @@ -158,7 +157,7 @@ public class EntityStack extends StackedEntity { } } - public void destroy() { + public synchronized void destroy() { if (hostEntity == null) return; Bukkit.getScheduler().runTask(plugin, hostEntity::remove); hostEntity = null; diff --git a/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStackManager.java b/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStackManager.java index 8c32af6..7777dcb 100644 --- a/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStackManager.java +++ b/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStackManager.java @@ -89,10 +89,25 @@ public class EntityStackManager { return stack; } + /** + * Transfers the stack from one entity to another. + * (e.g. slimes split) + * @param oldEntity The old entity to transfer the stack from. + * @param newEntity The new entity to transfer the stack to. + * @return The new stack. + */ + public EntityStack transferStack(LivingEntity oldEntity, LivingEntity newEntity) { + EntityStack stack = getStack(oldEntity); + if (stack == null) return null; + EntityStack newStack = new EntityStack(newEntity, stack.getAmount()); + stack.destroy(); + return newStack; + } + public EntityStack updateStack(LivingEntity oldEntity, LivingEntity newEntity) { EntityStack stack = getStack(oldEntity); if (stack == null) return null; - int amount = stack.getAmount(); + int amount = stack.getAmount()-1; stack.destroy(); return createStack(newEntity, amount); } @@ -101,7 +116,6 @@ public class EntityStackManager { if (isStackedEntity(newEntity)) { EntityStack stack = getStack(newEntity); stack.setAmount(amount); - System.err.println("Stacked entity already exists, updating stack amount to " + amount); } else { createStack(newEntity, amount); } diff --git a/src/main/java/com/songoda/ultimatestacker/tasks/StackingTask.java b/src/main/java/com/songoda/ultimatestacker/tasks/StackingTask.java index c409712..e80e63b 100644 --- a/src/main/java/com/songoda/ultimatestacker/tasks/StackingTask.java +++ b/src/main/java/com/songoda/ultimatestacker/tasks/StackingTask.java @@ -65,7 +65,7 @@ import java.util.concurrent.ScheduledExecutorService; public class StackingTask implements Runnable { private final UltimateStacker plugin; - private final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(4); + private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); private final EntityStackManager stackManager; @@ -93,7 +93,6 @@ public class StackingTask implements Runnable { public StackingTask(UltimateStacker plugin) { this.plugin = plugin; this.stackManager = plugin.getEntityStackManager(); - // Add loaded worlds. for (World world : Bukkit.getWorlds()) loadedWorlds.add(new SWorld(world)); From 9f77b489741e5d4da4aa72657767575755228673 Mon Sep 17 00:00:00 2001 From: ceze88 Date: Fri, 17 Feb 2023 16:33:28 +0100 Subject: [PATCH 06/31] Minor fix for loots --- .../songoda/ultimatestacker/stackable/entity/EntityStack.java | 2 +- .../ultimatestacker/stackable/entity/EntityStackManager.java | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java b/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java index fd72ef5..731c574 100644 --- a/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java +++ b/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java @@ -133,8 +133,8 @@ public class EntityStack extends StackedEntity { return; } } - handleSingleStackDeath(killed, drops, droppedExp, event); } + handleSingleStackDeath(killed, drops, droppedExp, event); } public synchronized LivingEntity takeOneAndSpawnEntity(Location location) { diff --git a/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStackManager.java b/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStackManager.java index 7777dcb..3b1b508 100644 --- a/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStackManager.java +++ b/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStackManager.java @@ -109,6 +109,10 @@ public class EntityStackManager { if (stack == null) return null; int amount = stack.getAmount()-1; stack.destroy(); + if (amount == 0 && newEntity != null) { + newEntity.remove(); + return null; + } return createStack(newEntity, amount); } From 1142fb0e6a3cb913617bedb1e6bbbf728d96cdee Mon Sep 17 00:00:00 2001 From: ceze88 Date: Wed, 22 Feb 2023 09:59:28 +0100 Subject: [PATCH 07/31] Fix Stacking Task, fix loot tables for non stacked mobs. Add last player damage to mobs. Performance improvements. --- .../listeners/entity/EntityListeners.java | 7 +- .../stackable/entity/EntityStack.java | 16 +- .../stackable/entity/EntityStackManager.java | 15 ++ .../ultimatestacker/tasks/StackingTask.java | 170 +++++++++--------- 4 files changed, 116 insertions(+), 92 deletions(-) diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/entity/EntityListeners.java b/src/main/java/com/songoda/ultimatestacker/listeners/entity/EntityListeners.java index fe3b937..a222fc8 100644 --- a/src/main/java/com/songoda/ultimatestacker/listeners/entity/EntityListeners.java +++ b/src/main/java/com/songoda/ultimatestacker/listeners/entity/EntityListeners.java @@ -78,7 +78,12 @@ public class EntityListeners implements Listener { Entity entity = event.getEntity(); - if (entity instanceof LivingEntity && plugin.getEntityStackManager().isStackedEntity(entity) + if (!(entity instanceof LivingEntity)) return; + if (event.getDamager() instanceof Player) { + plugin.getEntityStackManager().setLastPlayerDamage(entity, (Player) event.getDamager()); + } + + if (plugin.getEntityStackManager().isStackedEntity(entity) && Settings.DISABLE_KNOCKBACK.getBoolean() && ((Player) event.getDamager()).getItemInHand().getEnchantmentLevel(Enchantment.KNOCKBACK) == 0) { Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, () -> { diff --git a/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java b/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java index 731c574..c34198e 100644 --- a/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java +++ b/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java @@ -116,12 +116,23 @@ public class EntityStack extends StackedEntity { killed.setCustomName(null); killed.setCustomNameVisible(false); + //replace %player% in drop commands with the last player to damage the entity + String lastDamage = plugin.getEntityStackManager().getLastPlayerDamage(killed); + if (lastDamage != null) { + drops.forEach(drop -> { + if (drop.getCommand() != null) { + drop.setCommand(drop.getCommand().replace("%player%", lastDamage)); + } + }); + } + boolean killWholeStack = Settings.KILL_WHOLE_STACK_ON_DEATH.getBoolean() || plugin.getMobFile().getBoolean("Mobs." + killed.getType().name() + ".Kill Whole Stack"); - if (killWholeStack && getAmount() != 1) { + if (killWholeStack && getAmount() > 1) { handleWholeStackDeath(killed, drops, custom, droppedExp, event); - } else if (getAmount() != 1) { + return; + } else if (getAmount() > 1) { List reasons = Settings.INSTANT_KILL.getStringList(); EntityDamageEvent lastDamageCause = killed.getLastDamageCause(); @@ -134,6 +145,7 @@ public class EntityStack extends StackedEntity { } } } + System.err.println("Single death"); handleSingleStackDeath(killed, drops, droppedExp, event); } diff --git a/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStackManager.java b/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStackManager.java index 3b1b508..eec6b6b 100644 --- a/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStackManager.java +++ b/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStackManager.java @@ -9,6 +9,8 @@ import org.bukkit.World; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.metadata.FixedMetadataValue; import java.util.Collection; import java.util.Collections; @@ -38,6 +40,19 @@ public class EntityStackManager { return entity.getMetadata("US_AMOUNT").get(0).asInt(); } + public String getLastPlayerDamage(Entity entity) { + if (!entity.hasMetadata("US_LAST_PLAYER_DAMAGE")) return null; + if (entity.getMetadata("US_LAST_PLAYER_DAMAGE").isEmpty()) return null; + return entity.getMetadata("US_LAST_PLAYER_DAMAGE").get(0).asString(); + } + + public void setLastPlayerDamage(Entity entity, Player player) { + if (player == null) return; + if (entity == null) return; + if (entity instanceof Player) return; + entity.setMetadata("US_LAST_PLAYER_DAMAGE", new FixedMetadataValue(plugin, player.getName())); + } + public EntityStack addStack(LivingEntity entity) { return addStack(entity, getAmount(entity) == 1 ? 1 : getAmount(entity)); } diff --git a/src/main/java/com/songoda/ultimatestacker/tasks/StackingTask.java b/src/main/java/com/songoda/ultimatestacker/tasks/StackingTask.java index e80e63b..e665ce7 100644 --- a/src/main/java/com/songoda/ultimatestacker/tasks/StackingTask.java +++ b/src/main/java/com/songoda/ultimatestacker/tasks/StackingTask.java @@ -44,25 +44,31 @@ import org.bukkit.entity.TropicalFish; import org.bukkit.entity.Villager; import org.bukkit.entity.Wolf; import org.bukkit.entity.Zombie; +import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.inventory.EntityEquipment; import org.bukkit.scheduler.BukkitRunnable; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TimerTask; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; -public class StackingTask implements Runnable { +public class StackingTask extends TimerTask { private final UltimateStacker plugin; private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); @@ -99,7 +105,7 @@ public class StackingTask implements Runnable { // Start the stacking task. //runTaskTimerAsynchronously(plugin, 0, Settings.STACK_SEARCH_TICK_SPEED.getInt()); - executorService.scheduleAtFixedRate(this, 0, Settings.STACK_SEARCH_TICK_SPEED.getInt()*20L, java.util.concurrent.TimeUnit.MILLISECONDS); + executorService.scheduleAtFixedRate(this, 0, (Settings.STACK_SEARCH_TICK_SPEED.getInt()*50L), TimeUnit.MILLISECONDS); } public void stop() { @@ -108,44 +114,48 @@ public class StackingTask implements Runnable { @Override public void run() { - // Should entities be stacked? - if (!Settings.STACK_ENTITIES.getBoolean()) return; + //make sure if the task running if any error occurs + try { + // Should entities be stacked? + if (!Settings.STACK_ENTITIES.getBoolean()) return; - // Loop through each world. - for (SWorld sWorld : loadedWorlds) { - // If world is disabled then continue to the next world. - if (isWorldDisabled(sWorld.getWorld())) continue; + // Loop through each world. + for (SWorld sWorld : loadedWorlds) { + // If world is disabled then continue to the next world. + if (isWorldDisabled(sWorld.getWorld())) continue; - // Get the loaded entities from the current world and reverse them. - List entities; - try { - entities = getLivingEntitiesSync(sWorld).get(); - } catch (ExecutionException | InterruptedException ex) { - ex.printStackTrace(); - continue; - } - Collections.reverse(entities); - - // Loop through the entities. - for (LivingEntity entity : entities) { - // Get entity location to pass around as its faster this way. - Location location = entity.getLocation(); - - // Check to see if entity is not stackable. - if (!isEntityStackable(entity)) + // Get the loaded entities from the current world and reverse them. + List entities; + try { + entities = getLivingEntitiesSync(sWorld).get(); + } catch (ExecutionException | InterruptedException ex) { + ex.printStackTrace(); continue; + } + Collections.reverse(entities); - // Make sure our entity has not already been processed. - // Skip it if it has been. - if (this.processed.contains(entity.getUniqueId())) continue; + // Loop through the entities. + for (LivingEntity entity : entities) { + // Make sure our entity has not already been processed. + // Skip it if it has been. + if (this.processed.contains(entity.getUniqueId())) continue; - // Process the entity. - this.processEntity(entity, sWorld, location); + // Check to see if entity is not stackable. + if (!isEntityStackable(entity)) { + continue; + } + + // Get entity location to pass around as its faster this way. + Location location = entity.getLocation(); + + // Process the entity. + this.processEntity(entity, sWorld, location); + } } - } - // Clear caches in preparation for the next run. - this.processed.clear(); - this.cachedChunks.clear(); + // Clear caches in preparation for the next run. + this.processed.clear(); + this.cachedChunks.clear(); + } catch (Exception ignored) {} } private Future> getLivingEntitiesSync(SWorld sWorld) { @@ -186,9 +196,10 @@ public class StackingTask implements Runnable { // If only stack from spawners is enabled, make sure the entity spawned from a spawner. if (!"SPAWNER".equals(spawnReason)) return false; - } else if (!(stackReasons = this.stackReasons).isEmpty() && !stackReasons.contains(spawnReason)) + } else if (!(stackReasons = this.stackReasons).isEmpty() && !stackReasons.contains(spawnReason)) { // Only stack if on the list of events to stack return false; + } // Cast our entity to living entity. LivingEntity livingEntity = (LivingEntity) entity; @@ -224,6 +235,7 @@ public class StackingTask implements Runnable { if (isStack && baseStack.getAmount() == maxEntityStackSize) { // If the stack is already at the max size then we can skip it. + processed.add(baseEntity.getUniqueId()); return; } @@ -236,10 +248,10 @@ public class StackingTask implements Runnable { // If this entity is named, a custom entity or disabled then skip it. if (!isStack && (baseEntity.getCustomName() != null && plugin.getCustomEntityManager().getCustomEntity(baseEntity) == null) - || !configurationSection.getBoolean("Mobs." + baseEntity.getType().name() + ".Enabled")) + || !configurationSection.getBoolean("Mobs." + baseEntity.getType().name() + ".Enabled")) { + processed.add(baseEntity.getUniqueId()); return; - - + } // Get similar entities around our entity and make sure those entities are both compatible and stackable. List stackableFriends = new LinkedList<>(); @@ -258,24 +270,24 @@ public class StackingTask implements Runnable { // Get this entities friendStack. EntityStack friendStack = stackManager.getStack(friendlyEntity); - - if (friendStack == null) continue; + int amount = friendStack != null ? friendStack.getAmount() : 1; // Check to see if this friendlyEntity is stacked and friendStack plus // our amount to stack is not above our max friendStack size // for this friendlyEntity. - boolean overstack = (friendStack.getAmount() + amountToStack) > maxEntityStackSize; + boolean overstack = (amount + amountToStack) > maxEntityStackSize; if (!overstack) { - friendStack.setAmount(friendStack.getAmount() + amountToStack); - if (baseEntity.isLeashed()) - Bukkit.getScheduler().runTask(plugin, () -> baseEntity.getWorld() - .dropItemNaturally(baseEntity.getLocation(), CompatibleMaterial.LEAD.getItem())); - if (baseStack != null) { - baseStack.destroy(); - } + stackManager.createStack(friendlyEntity, amount + amountToStack); processed.add(baseEntity.getUniqueId()); + + Bukkit.getScheduler().runTask(plugin, () -> { + if (baseEntity.isLeashed()) { + baseEntity.getWorld().dropItemNaturally(baseEntity.getLocation(), CompatibleMaterial.LEAD.getItem()); + } + baseEntity.remove(); + }); return; } } @@ -301,12 +313,16 @@ public class StackingTask implements Runnable { } while (finalStackSize >= 0); }); - // Remove our entity and mark it as processed. + //Mark it as processed. processed.add(livingEntity.getUniqueId()); return true; } private Set getNearbyChunks(SWorld sWorld, Location location, double radius, boolean singleChunk) { + //get current chunk + if (radius == -1) { + return new HashSet<>(Collections.singletonList(new CachedChunk(sWorld, location.getChunk().getX(), location.getChunk().getZ()))); + } World world = location.getWorld(); Set chunks = new HashSet<>(); if (world == null) return chunks; @@ -330,55 +346,31 @@ public class StackingTask implements Runnable { return chunks; } - private List getNearbyEntities(SWorld sWorld, Location location, double radius, boolean singleChunk) { + /** + * Get all entities around an entity within a radius which are similar to the entity. + * @param entity The entity to get similar entities around. + * @param radius The radius to get entities around. + * @param singleChunk Whether to only get entities in the same chunk as the entity. + * @return A list of similar entities around the entity. + */ + private List getFriendlyStacksNearby(LivingEntity entity, double radius, boolean singleChunk) { List entities = new ArrayList<>(); - for (CachedChunk chunk : getNearbyChunks(sWorld, location, radius, singleChunk)) { - if (chunk == null) continue; - Entity[] entityArray; - if (cachedChunks.containsKey(chunk)) { - entityArray = cachedChunks.get(chunk); - } else { - try { - entityArray = getEntitiesInChunkSync(chunk).get(); - cachedChunks.put(chunk, entityArray); - } catch (ExecutionException | InterruptedException ex) { - ex.printStackTrace(); - continue; + Set chunks = getNearbyChunks(new SWorld(entity.getWorld()), entity.getLocation(), radius, singleChunk); + for (CachedChunk chunk : chunks) { + Entity[] entityList = chunk.getEntities(); + for (Entity e : entityList) { + if (!processed.contains(e.getUniqueId()) && e.getType() == entity.getType() && e instanceof LivingEntity && e.isValid() && e.getLocation().distance(entity.getLocation()) <= radius) { + entities.add((LivingEntity) e); } } - - if (entityArray == null) continue; - - for (Entity e : entityArray) { - if (e == null) continue; - if (e.getWorld() != location.getWorld() - || !(e instanceof LivingEntity) - || (!singleChunk && location.distanceSquared(e.getLocation()) >= radius * radius)) continue; - entities.add((LivingEntity) e); - } } - + entities.removeIf(entity1 -> entity1.equals(entity)); return entities; } - public int getSimilarStacksInChunk(SWorld sWorld, LivingEntity entity) { - int count = 0; - for (LivingEntity e : getNearbyEntities(sWorld, entity.getLocation(), -1, true)) { - if (entity.getType() == e.getType() && plugin.getEntityStackManager().isStackedEntity(e)) - count++; - } - return count; - } - public List getSimilarEntitiesAroundEntity(LivingEntity initialEntity, SWorld sWorld, Location location) { // Create a list of all entities around the initial entity of the same type. - List entityList = new LinkedList<>(); - - for (LivingEntity entity : getNearbyEntities(sWorld, location, searchRadius, stackWholeChunk)) { - if (entity.getType() != initialEntity.getType() || entity == initialEntity) - continue; - entityList.add(entity); - } + List entityList = new LinkedList<>(getFriendlyStacksNearby(initialEntity, searchRadius, stackWholeChunk)); CustomEntity customEntity = plugin.getCustomEntityManager().getCustomEntity(initialEntity); if (customEntity != null) From f4811ae1df5260e6f52b11ccf72ad4c3ff351e76 Mon Sep 17 00:00:00 2001 From: ceze88 Date: Wed, 22 Feb 2023 10:30:59 +0100 Subject: [PATCH 08/31] Wups --- .../songoda/ultimatestacker/stackable/entity/EntityStack.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java b/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java index c34198e..998f568 100644 --- a/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java +++ b/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java @@ -145,7 +145,6 @@ public class EntityStack extends StackedEntity { } } } - System.err.println("Single death"); handleSingleStackDeath(killed, drops, droppedExp, event); } From 640db6e34450aad032d8cabfc7f52c837bef272b Mon Sep 17 00:00:00 2001 From: ceze88 Date: Wed, 29 Mar 2023 21:21:00 +0200 Subject: [PATCH 09/31] Fix entity stacking, looting --- .../commands/CommandRemoveAll.java | 5 +++- .../listeners/BlockListeners.java | 10 +++++--- .../listeners/DeathListeners.java | 24 +++++++++++++++++++ .../entity/EntityCurrentListener.java | 5 ++-- .../lootables/LootablesManager.java | 4 ++++ .../stackable/entity/EntityStack.java | 14 ++--------- .../stackable/entity/EntityStackManager.java | 4 ++-- .../entity/custom/CustomEntityManager.java | 7 ++++++ .../ultimatestacker/tasks/StackingTask.java | 18 ++++++++------ 9 files changed, 64 insertions(+), 27 deletions(-) diff --git a/src/main/java/com/songoda/ultimatestacker/commands/CommandRemoveAll.java b/src/main/java/com/songoda/ultimatestacker/commands/CommandRemoveAll.java index 840a8eb..ea8cca8 100644 --- a/src/main/java/com/songoda/ultimatestacker/commands/CommandRemoveAll.java +++ b/src/main/java/com/songoda/ultimatestacker/commands/CommandRemoveAll.java @@ -3,6 +3,7 @@ package com.songoda.ultimatestacker.commands; import com.songoda.core.commands.AbstractCommand; import com.songoda.core.utils.TextUtils; import com.songoda.ultimatestacker.UltimateStacker; +import com.songoda.ultimatestacker.stackable.entity.EntityStack; import com.songoda.ultimatestacker.stackable.entity.EntityStackManager; import com.songoda.ultimatestacker.utils.Methods; import org.bukkit.Bukkit; @@ -48,7 +49,9 @@ public class CommandRemoveAll extends AbstractCommand { if (entityO instanceof LivingEntity && (stackManager.isStackedEntity(entityO) || all) && type.equalsIgnoreCase("entities")) { - plugin.getEntityStackManager().getStack((LivingEntity) entityO).destroy(); + EntityStack stack = plugin.getEntityStackManager().getStack((LivingEntity) entityO); + if (stack == null) continue; + stack.destroy(); amountRemoved++; } else if (entityO.getType() == EntityType.DROPPED_ITEM && type.equalsIgnoreCase("items")) { if (!UltimateStacker.hasCustomAmount((Item)entityO) && !all) diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java b/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java index 85513c9..f88544b 100644 --- a/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java +++ b/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java @@ -19,6 +19,7 @@ import org.bukkit.block.CreatureSpawner; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; +import org.bukkit.event.Event; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -40,8 +41,9 @@ public class BlockListeners implements Listener { this.plugin = plugin; } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST) public void onBlockInteract(PlayerInteractEvent event) { + if (event.useInteractedBlock() == Event.Result.DENY) return; Block block = event.getClickedBlock(); Player player = event.getPlayer(); CompatibleHand hand = CompatibleHand.getHand(event); @@ -166,8 +168,9 @@ public class BlockListeners implements Listener { } } - @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST) public void onBlockPlace(BlockPlaceEvent event) { + if (event.isCancelled()) return; Block block = event.getBlock(); Player player = event.getPlayer(); @@ -196,8 +199,9 @@ public class BlockListeners implements Listener { plugin.updateHologram(stack); } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST) public void onBlockBreak(BlockBreakEvent event) { + if (event.isCancelled()) return; Block block = event.getBlock(); if (block.getType() != CompatibleMaterial.SPAWNER.getMaterial()) return; diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/DeathListeners.java b/src/main/java/com/songoda/ultimatestacker/listeners/DeathListeners.java index 48744ad..4082770 100644 --- a/src/main/java/com/songoda/ultimatestacker/listeners/DeathListeners.java +++ b/src/main/java/com/songoda/ultimatestacker/listeners/DeathListeners.java @@ -7,6 +7,7 @@ import com.songoda.core.lootables.loot.DropUtils; import com.songoda.ultimatestacker.UltimateStacker; import com.songoda.ultimatestacker.settings.Settings; import com.songoda.ultimatestacker.stackable.entity.EntityStack; +import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.GameRule; import org.bukkit.Material; @@ -82,6 +83,10 @@ public class DeathListeners implements Listener { drops.clear(); if (plugin.getCustomEntityManager().getCustomEntity(entity) == null) { + //replace %player% in drop commands with the last player to damage the entity + //Run commands here, or it will be buggy + runCommands(entity, drops); + if (plugin.getEntityStackManager().isStackedEntity(event.getEntity())) { plugin.getEntityStackManager().getStack(event.getEntity()).onDeath(entity, drops, custom, event.getDroppedExp(), event); } else { @@ -92,6 +97,25 @@ public class DeathListeners implements Listener { finalItems.remove(entity.getUniqueId()); } + private void runCommands(LivingEntity entity, List drops) { + String lastDamage = plugin.getEntityStackManager().getLastPlayerDamage(entity); + if (lastDamage != null) { + List commands = new ArrayList<>(); + drops.forEach(drop -> { + if (drop.getCommand() != null) { + String command = drop.getCommand().replace("%player%", lastDamage); + drop.setCommand(null); + commands.add(command); + } + }); + Bukkit.getScheduler().runTask(plugin, () -> { + for (String command : commands) { + Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command); + } + }); + } + } + private boolean shouldDrop(LivingEntity entity, Material material) { if (entity.getEquipment() != null && entity.getEquipment().getArmorContents().length != 0) { if (Settings.DONT_DROP_ARMOR.getBoolean()) diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/entity/EntityCurrentListener.java b/src/main/java/com/songoda/ultimatestacker/listeners/entity/EntityCurrentListener.java index 71bba69..a32b96c 100644 --- a/src/main/java/com/songoda/ultimatestacker/listeners/entity/EntityCurrentListener.java +++ b/src/main/java/com/songoda/ultimatestacker/listeners/entity/EntityCurrentListener.java @@ -1,15 +1,16 @@ package com.songoda.ultimatestacker.listeners.entity; import com.songoda.ultimatestacker.UltimateStacker; +import com.songoda.ultimatestacker.settings.Settings; import com.songoda.ultimatestacker.stackable.entity.EntityStack; import com.songoda.ultimatestacker.stackable.entity.EntityStackManager; import org.bukkit.Bukkit; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Slime; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDeathEvent; import org.bukkit.event.entity.EntityTransformEvent; import org.bukkit.event.world.EntitiesLoadEvent; @@ -31,11 +32,11 @@ public class EntityCurrentListener implements Listener { && event.getEntity() instanceof LivingEntity && event.getTransformedEntity() instanceof LivingEntity) { if (event.getTransformReason().equals(EntityTransformEvent.TransformReason.SPLIT)) { - stackManager.getStack((LivingEntity) event.getEntity()).removeEntityFromStack(1); event.setCancelled(true); return; } EntityStack stack = stackManager.updateStack((LivingEntity) event.getEntity(), (LivingEntity) event.getTransformedEntity()); + if (stack == null) return; stack.releaseHost(); } } diff --git a/src/main/java/com/songoda/ultimatestacker/lootables/LootablesManager.java b/src/main/java/com/songoda/ultimatestacker/lootables/LootablesManager.java index ea65de0..156b114 100644 --- a/src/main/java/com/songoda/ultimatestacker/lootables/LootablesManager.java +++ b/src/main/java/com/songoda/ultimatestacker/lootables/LootablesManager.java @@ -101,6 +101,10 @@ public class LootablesManager { looting); } + public List getItemStackDrops(LivingEntity entity, int times) { + return getDrops(entity, times).stream().map(Drop::getItemStack).collect(Collectors.toList()); + } + public List getDrops(LivingEntity entity, int times) { return getDrops(entity, times, 3); } diff --git a/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java b/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java index 998f568..4b6b27f 100644 --- a/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java +++ b/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java @@ -23,6 +23,7 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.util.Vector; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.concurrent.ThreadLocalRandom; @@ -116,22 +117,11 @@ public class EntityStack extends StackedEntity { killed.setCustomName(null); killed.setCustomNameVisible(false); - //replace %player% in drop commands with the last player to damage the entity - String lastDamage = plugin.getEntityStackManager().getLastPlayerDamage(killed); - if (lastDamage != null) { - drops.forEach(drop -> { - if (drop.getCommand() != null) { - drop.setCommand(drop.getCommand().replace("%player%", lastDamage)); - } - }); - } - boolean killWholeStack = Settings.KILL_WHOLE_STACK_ON_DEATH.getBoolean() || plugin.getMobFile().getBoolean("Mobs." + killed.getType().name() + ".Kill Whole Stack"); if (killWholeStack && getAmount() > 1) { handleWholeStackDeath(killed, drops, custom, droppedExp, event); - return; } else if (getAmount() > 1) { List reasons = Settings.INSTANT_KILL.getStringList(); EntityDamageEvent lastDamageCause = killed.getLastDamageCause(); @@ -144,8 +134,8 @@ public class EntityStack extends StackedEntity { return; } } + handleSingleStackDeath(killed, drops, droppedExp, event); } - handleSingleStackDeath(killed, drops, droppedExp, event); } public synchronized LivingEntity takeOneAndSpawnEntity(Location location) { diff --git a/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStackManager.java b/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStackManager.java index eec6b6b..19192bb 100644 --- a/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStackManager.java +++ b/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStackManager.java @@ -111,10 +111,10 @@ public class EntityStackManager { * @param newEntity The new entity to transfer the stack to. * @return The new stack. */ - public EntityStack transferStack(LivingEntity oldEntity, LivingEntity newEntity) { + public EntityStack transferStack(LivingEntity oldEntity, LivingEntity newEntity, boolean takeOne) { EntityStack stack = getStack(oldEntity); if (stack == null) return null; - EntityStack newStack = new EntityStack(newEntity, stack.getAmount()); + EntityStack newStack = new EntityStack(newEntity, takeOne ? stack.getAmount()-1 : stack.getAmount()); stack.destroy(); return newStack; } diff --git a/src/main/java/com/songoda/ultimatestacker/stackable/entity/custom/CustomEntityManager.java b/src/main/java/com/songoda/ultimatestacker/stackable/entity/custom/CustomEntityManager.java index 07c01f3..73fc0bd 100644 --- a/src/main/java/com/songoda/ultimatestacker/stackable/entity/custom/CustomEntityManager.java +++ b/src/main/java/com/songoda/ultimatestacker/stackable/entity/custom/CustomEntityManager.java @@ -54,4 +54,11 @@ public class CustomEntityManager { public boolean isCustomEntity(Entity entity) { return getCustomEntity(entity) != null && getCustomEntity(entity).isCustomEntity(entity); } + + public boolean isStackable(Entity entity) { + CustomEntity customEntity = getCustomEntity(entity); + if (customEntity == null) return true; + String key = customEntity.getPluginName().toLowerCase() + "_" + customEntity.getNBTIdentifier(entity).toLowerCase(); + return !Settings.BLACKLISTED_CUSTOM_ENTITIES.getStringList().contains(key); + } } diff --git a/src/main/java/com/songoda/ultimatestacker/tasks/StackingTask.java b/src/main/java/com/songoda/ultimatestacker/tasks/StackingTask.java index e665ce7..e400d4a 100644 --- a/src/main/java/com/songoda/ultimatestacker/tasks/StackingTask.java +++ b/src/main/java/com/songoda/ultimatestacker/tasks/StackingTask.java @@ -355,16 +355,20 @@ public class StackingTask extends TimerTask { */ private List getFriendlyStacksNearby(LivingEntity entity, double radius, boolean singleChunk) { List entities = new ArrayList<>(); - Set chunks = getNearbyChunks(new SWorld(entity.getWorld()), entity.getLocation(), radius, singleChunk); - for (CachedChunk chunk : chunks) { - Entity[] entityList = chunk.getEntities(); - for (Entity e : entityList) { - if (!processed.contains(e.getUniqueId()) && e.getType() == entity.getType() && e instanceof LivingEntity && e.isValid() && e.getLocation().distance(entity.getLocation()) <= radius) { - entities.add((LivingEntity) e); + try { + Set chunks = getNearbyChunks(new SWorld(entity.getWorld()), entity.getLocation(), radius, singleChunk); + for (CachedChunk chunk : chunks) { + Entity[] entityList = getEntitiesInChunkSync(chunk).get(); + for (Entity e : entityList) { + if (!processed.contains(e.getUniqueId()) && e.getType() == entity.getType() && e instanceof LivingEntity && e.isValid() && e.getLocation().distance(entity.getLocation()) <= radius) { + entities.add((LivingEntity) e); + } } } + entities.removeIf(entity1 -> entity1.equals(entity) || !UltimateStacker.getInstance().getCustomEntityManager().isStackable(entity1)); + } catch (Exception ex) { + ex.printStackTrace(); } - entities.removeIf(entity1 -> entity1.equals(entity)); return entities; } From 6bbfa61ec69d65afa5015c98e657ecfda6852c40 Mon Sep 17 00:00:00 2001 From: Christian Koop Date: Wed, 29 Mar 2023 21:25:22 +0200 Subject: [PATCH 10/31] Switch LICENSE to CC BY-NC-ND 4.0 Co-authored-by: Eli Rickard <38917063+EliRickard@users.noreply.github.com> --- LICENSE | 328 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 323 insertions(+), 5 deletions(-) diff --git a/LICENSE b/LICENSE index 2ddfa07..6328600 100644 --- a/LICENSE +++ b/LICENSE @@ -1,9 +1,327 @@ -Copyright (c) 2018 Brianna O’Keefe +Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 +International Public License -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software with minimal restriction, including the rights to use, copy, modify or merge while excluding the rights to publish, (re)distribute, sub-license, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution-NonCommercial-NoDerivatives 4.0 International Public +License ("Public License"). To the extent this Public License may be +interpreted as a contract, You are granted the Licensed Rights in +consideration of Your acceptance of these terms and conditions, and the +Licensor grants You such rights in consideration of benefits the +Licensor receives from making the Licensed Material available under +these terms and conditions. -The same distribution rights and limitations above shall similarly apply to any and all source code, and other means that can be used to emulate this work. -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +Section 1 -- Definitions. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + c. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + d. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + e. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + f. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + g. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + h. NonCommercial means not primarily intended for or directed towards + commercial advantage or monetary compensation. For purposes of + this Public License, the exchange of the Licensed Material for + other material subject to Copyright and Similar Rights by digital + file-sharing or similar means is NonCommercial provided there is + no payment of monetary compensation in connection with the + exchange. + + i. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + j. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + k. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part, for NonCommercial purposes only; and + + b. produce and reproduce, but not Share, Adapted Material + for NonCommercial purposes only. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties, including when + the Licensed Material is used other than for NonCommercial + purposes. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material, You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + For the avoidance of doubt, You do not have permission under + this Public License to Share Adapted Material. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database for NonCommercial purposes + only and provided You do not Share Adapted Material; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material; and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + +======================================================================= From fec0d9fd6419104529e2bf94145f6e716411745e Mon Sep 17 00:00:00 2001 From: ceze88 Date: Wed, 29 Mar 2023 21:37:33 +0200 Subject: [PATCH 11/31] Release 2.4.0-BETA --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index a95c71d..2d84743 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ com.songoda UltimateStacker 4.0.0 - 2.4.0-DEV + 2.4.0-BETA clean install UltimateStacker-${project.version} @@ -122,7 +122,7 @@ com.songoda SongodaCore - 2.6.18 + 2.6.19-DEV compile From 818ecf3d9ab64ed38c994165ea77699c4ae40c93 Mon Sep 17 00:00:00 2001 From: ceze88 Date: Sat, 1 Apr 2023 15:55:37 +0200 Subject: [PATCH 12/31] Add BentoBox compatibility --- .../com/songoda/ultimatestacker/UltimateStacker.java | 5 +++++ .../ultimatestacker/listeners/BlockListeners.java | 12 +++++++++++- src/main/resources/plugin.yml | 2 +- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java b/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java index 5c81465..11d210a 100644 --- a/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java +++ b/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java @@ -13,6 +13,7 @@ import com.songoda.core.database.SQLiteConnector; import com.songoda.core.gui.GuiManager; import com.songoda.core.hooks.EntityStackerManager; import com.songoda.core.hooks.HologramManager; +import com.songoda.core.hooks.ProtectionManager; import com.songoda.core.hooks.WorldGuardHook; import com.songoda.core.utils.TextUtils; import com.songoda.ultimatestacker.commands.CommandConvert; @@ -170,6 +171,10 @@ public class UltimateStacker extends SongodaPlugin { spawnerFile.load(); spawnerFile.saveChanges(); + if (Bukkit.getPluginManager().isPluginEnabled("BentoBox")) { + ProtectionManager.load(Bukkit.getPluginManager().getPlugin("BentoBox")); + } + this.spawnerStackManager = new SpawnerStackManager(); this.entityStackManager = new EntityStackManager(this); this.blockStackManager = new BlockStackManager(); diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java b/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java index f88544b..6446adc 100644 --- a/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java +++ b/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java @@ -2,6 +2,8 @@ package com.songoda.ultimatestacker.listeners; import com.songoda.core.compatibility.CompatibleHand; import com.songoda.core.compatibility.CompatibleMaterial; +import com.songoda.core.hooks.ProtectionManager; +import com.songoda.core.hooks.protection.BentoBoxProtection; import com.songoda.core.third_party.de.tr7zw.nbtapi.NBTItem; import com.songoda.ultimatestacker.UltimateStacker; import com.songoda.ultimatestacker.events.SpawnerBreakEvent; @@ -46,10 +48,18 @@ public class BlockListeners implements Listener { if (event.useInteractedBlock() == Event.Result.DENY) return; Block block = event.getClickedBlock(); Player player = event.getPlayer(); + + if (block == null) return; + + if (!ProtectionManager.canInteract(player, block.getLocation()) || !ProtectionManager.canBreak(player, block.getLocation())) { + if (!player.isOp()) { + return; + } + } + CompatibleHand hand = CompatibleHand.getHand(event); ItemStack inHand = hand.getItem(player); - if (block == null) return; if (Settings.STACK_BLOCKS.getBoolean()) { BlockStackManager blockStackManager = plugin.getBlockStackManager(); diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index d1119b1..7ec5605 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,7 +1,7 @@ name: UltimateStacker description: UltimateStacker version: maven-version-number -softdepend: [MythicMobs, HolographicDisplays, Holograms, CMI, WorldGuard, EpicSpawners, mcMMO, WildStacker, StackMob] +softdepend: [MythicMobs, HolographicDisplays, Holograms, CMI, WorldGuard, EpicSpawners, mcMMO, WildStacker, StackMob, BentoBox] loadbefore: [WorldGuard] main: com.songoda.ultimatestacker.UltimateStacker author: songoda From 999bb4c8873c3123b53135189dd4e24167954317 Mon Sep 17 00:00:00 2001 From: ceze88 Date: Sat, 1 Apr 2023 15:56:32 +0200 Subject: [PATCH 13/31] Release 2.4.0-BETA-2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2d84743..c2046d0 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ com.songoda UltimateStacker 4.0.0 - 2.4.0-BETA + 2.4.0-BETA-2 clean install UltimateStacker-${project.version} From 673ae8fdc4670d7b16e58eb607f53393d77f0c44 Mon Sep 17 00:00:00 2001 From: ceze88 Date: Sat, 1 Apr 2023 15:59:24 +0200 Subject: [PATCH 14/31] Add WOLF to loot tables --- .../songoda/ultimatestacker/lootables/LootablesManager.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/songoda/ultimatestacker/lootables/LootablesManager.java b/src/main/java/com/songoda/ultimatestacker/lootables/LootablesManager.java index 156b114..e8963ba 100644 --- a/src/main/java/com/songoda/ultimatestacker/lootables/LootablesManager.java +++ b/src/main/java/com/songoda/ultimatestacker/lootables/LootablesManager.java @@ -852,6 +852,9 @@ public class LootablesManager { lootManager.addLootable(new Lootable("SILVERFISH", new LootBuilder().build())); + lootManager.addLootable(new Lootable("WOLF", + new LootBuilder().build())); + lootManager.saveLootables(true); } From 93aa9a7532da4942856cf07b6794bb379b7edfc0 Mon Sep 17 00:00:00 2001 From: ceze88 Date: Sat, 1 Apr 2023 15:59:56 +0200 Subject: [PATCH 15/31] Release 2.4.0-BETA-3 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c2046d0..bfc5fee 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ com.songoda UltimateStacker 4.0.0 - 2.4.0-BETA-2 + 2.4.0-BETA-3 clean install UltimateStacker-${project.version} From a43230f3b12926482a55d7689d0014f3c228dca6 Mon Sep 17 00:00:00 2001 From: ceze88 Date: Wed, 5 Apr 2023 11:57:17 +0200 Subject: [PATCH 16/31] Fix Block stacks giving one less block when destroyed --- .../com/songoda/ultimatestacker/UltimateStacker.java | 1 + .../ultimatestacker/listeners/BlockListeners.java | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java b/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java index 11d210a..c5e5bf3 100644 --- a/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java +++ b/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java @@ -55,6 +55,7 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; +import org.bukkit.block.Block; import org.bukkit.entity.EntityType; import org.bukkit.entity.Item; import org.bukkit.entity.Player; diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java b/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java index 6446adc..f5d83da 100644 --- a/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java +++ b/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java @@ -109,9 +109,15 @@ public class BlockListeners implements Listener { } } stack.add(amountToRemove); - if (stack.getAmount() < 2) + if (stack.getAmount() < 2) { stack.destroy(); - else { + ItemStack item = stack.getMaterial().getItem(); + if (Settings.ADD_TO_INVENTORY.getBoolean()) { + player.getInventory().addItem(item); + } else { + block.getWorld().dropItemNaturally(block.getLocation().clone().add(.5, 1, .5), item); + } + } else { plugin.updateHologram(stack); plugin.getDataManager().updateBlock(stack); } From f51cc19c448d612a734946e69cee40b0c578bb2c Mon Sep 17 00:00:00 2001 From: ceze88 Date: Wed, 5 Apr 2023 22:05:14 +0200 Subject: [PATCH 17/31] Fix block stack dupe/item liss --- .../java/com/songoda/ultimatestacker/database/DataManager.java | 1 + .../com/songoda/ultimatestacker/listeners/BlockListeners.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/songoda/ultimatestacker/database/DataManager.java b/src/main/java/com/songoda/ultimatestacker/database/DataManager.java index 9ad0357..10f2a7f 100644 --- a/src/main/java/com/songoda/ultimatestacker/database/DataManager.java +++ b/src/main/java/com/songoda/ultimatestacker/database/DataManager.java @@ -86,6 +86,7 @@ public class DataManager extends DataManagerAbstract { } public void updateBlock(BlockStack blockStack) { + if (blockStack.getAmount() == 0) return; this.runAsync(() -> { try (Connection connection = this.databaseConnector.getConnection()) { String updateBlock = "UPDATE " + this.getTablePrefix() + "blocks SET amount = ? WHERE id = ?"; diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java b/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java index f5d83da..b23a18b 100644 --- a/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java +++ b/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java @@ -74,7 +74,7 @@ public class BlockListeners implements Listener { if (event.getAction() == Action.RIGHT_CLICK_BLOCK) { if (!isStacked) plugin.getDataManager().createBlock(stack); if (stack.getMaterial() == CompatibleMaterial.getMaterial(inHand)) { - int amountToAdd = player.isSneaking() || Settings.ALWAYS_ADD_ALL.getBoolean() ? inHand.getAmount() : 1; + int amountToAdd = player.isSneaking() || Settings.ALWAYS_ADD_ALL.getBoolean() ? inHand.getAmount()-1 : 1; if (!isStacked) amountToAdd++; stack.add(amountToAdd); event.setCancelled(true); From 42451e708b495f264e51d8e75748181713bc8f6f Mon Sep 17 00:00:00 2001 From: ceze88 Date: Fri, 7 Apr 2023 18:58:21 +0200 Subject: [PATCH 18/31] Rewrite block stacking --- .../ultimatestacker/UltimateStacker.java | 1 + .../ultimatestacker/database/DataManager.java | 20 +++ .../listeners/BlockListeners.java | 129 +++++++++++------- .../stackable/block/BlockStack.java | 2 +- .../stackable/block/BlockStackManager.java | 10 +- 5 files changed, 105 insertions(+), 57 deletions(-) diff --git a/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java b/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java index c5e5bf3..a92b12e 100644 --- a/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java +++ b/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java @@ -111,6 +111,7 @@ public class UltimateStacker extends SongodaPlugin { this.stackingTask.stop(); this.stackingTask = null; this.dataManager.bulkUpdateSpawners(this.spawnerStackManager.getStacks()); + this.dataManager.bulkUpdateBlocks(this.blockStackManager.getStacks()); HologramManager.removeAllHolograms(); Async.shutdown(); } diff --git a/src/main/java/com/songoda/ultimatestacker/database/DataManager.java b/src/main/java/com/songoda/ultimatestacker/database/DataManager.java index 10f2a7f..c258595 100644 --- a/src/main/java/com/songoda/ultimatestacker/database/DataManager.java +++ b/src/main/java/com/songoda/ultimatestacker/database/DataManager.java @@ -216,6 +216,11 @@ public class DataManager extends DataManagerAbstract { BlockStack blockStack = new BlockStack(material, location, amount); blockStack.setId(blockId); + if (amount == 0) { + //remove from database + this.deleteBlock(blockStack); + continue; + } blocks.put(location, blockStack); this.sync(() -> callback.accept(blocks)); @@ -225,4 +230,19 @@ public class DataManager extends DataManagerAbstract { } }); } + + public void bulkUpdateBlocks(Collection stacks) { + try (Connection connection = this.databaseConnector.getConnection()) { + String updateSpawner = "UPDATE " + this.getTablePrefix() + "blocks SET amount = ? WHERE id = ?"; + PreparedStatement statement = connection.prepareStatement(updateSpawner); + for (BlockStack spawnerStack : stacks) { + statement.setInt(1, spawnerStack.getAmount()); + statement.setInt(2, spawnerStack.getId()); + statement.addBatch(); + } + statement.executeBatch(); + } catch (Exception ex) { + ex.printStackTrace(); + } + } } diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java b/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java index b23a18b..5489978 100644 --- a/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java +++ b/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java @@ -13,9 +13,11 @@ import com.songoda.ultimatestacker.stackable.block.BlockStack; import com.songoda.ultimatestacker.stackable.block.BlockStackManager; import com.songoda.ultimatestacker.stackable.spawner.SpawnerStack; import com.songoda.ultimatestacker.utils.Methods; +import io.lumine.mythic.bukkit.utils.menu.ClickAction; import org.apache.commons.lang.math.NumberUtils; import org.bukkit.Bukkit; import org.bukkit.GameMode; +import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.CreatureSpawner; import org.bukkit.enchantments.Enchantment; @@ -59,72 +61,93 @@ public class BlockListeners implements Listener { CompatibleHand hand = CompatibleHand.getHand(event); ItemStack inHand = hand.getItem(player); + boolean isSneaking = player.isSneaking(); + Action clickAction = event.getAction(); + int inHandAmount = inHand.getAmount(); - - if (Settings.STACK_BLOCKS.getBoolean()) { - BlockStackManager blockStackManager = plugin.getBlockStackManager(); - - boolean isStacked = blockStackManager.isBlock(block.getLocation()); + //Stacking blocks + if (Settings.STACK_BLOCKS.getBoolean() + && Settings.STACKABLE_BLOCKS.getStringList().contains(block.getType().name()) //Is block stackable + && !block.getType().equals(CompatibleMaterial.SPAWNER.getMaterial()) //Don't stack spawners here + ) { CompatibleMaterial blockType = CompatibleMaterial.getMaterial(block); if (blockType == null) return; - if (isStacked || Settings.STACKABLE_BLOCKS.getStringList().contains(blockType.name())) { - BlockStack stack = blockStackManager.getBlock(block, blockType); - if (event.getAction() == Action.RIGHT_CLICK_BLOCK) { - if (!isStacked) plugin.getDataManager().createBlock(stack); - if (stack.getMaterial() == CompatibleMaterial.getMaterial(inHand)) { - int amountToAdd = player.isSneaking() || Settings.ALWAYS_ADD_ALL.getBoolean() ? inHand.getAmount()-1 : 1; - if (!isStacked) amountToAdd++; - stack.add(amountToAdd); - event.setCancelled(true); - if (player.getGameMode() != GameMode.CREATIVE) - hand.takeItem(player, amountToAdd); - plugin.updateHologram(stack); - } - plugin.getDataManager().updateBlock(stack); - } else if (event.getAction() == Action.LEFT_CLICK_BLOCK && stack.getAmount() != 0) { - event.setCancelled(true); - int amountToRemove = player.isSneaking() - ? Math.min(Settings.MAX_REMOVEABLE.getInt(), stack.getAmount()) - 1 : 1; + BlockStackManager blockStackManager = plugin.getBlockStackManager(); + boolean isStacked = blockStackManager.isBlock(block.getLocation()); + BlockStack stack = blockStackManager.getBlock(block.getLocation()); - ItemStack removed = stack.getMaterial().getItem(); - removed.setAmount(amountToRemove); - stack.take(amountToRemove); - int maxStack = removed.getMaxStackSize(); - - while (amountToRemove > 0) { - int subtract = Math.min(amountToRemove, maxStack); - amountToRemove -= subtract; - ItemStack newItem = removed.clone(); - newItem.setAmount(subtract); - if (Settings.ADD_TO_INVENTORY.getBoolean()) { - Map result = player.getInventory().addItem(newItem); - if (result.get(0) != null) { - amountToRemove += result.get(0).getAmount(); - break; - } - } else { - block.getWorld().dropItemNaturally(block.getLocation().clone().add(.5, 1, .5), newItem); - } - } - stack.add(amountToRemove); - if (stack.getAmount() < 2) { - stack.destroy(); - ItemStack item = stack.getMaterial().getItem(); - if (Settings.ADD_TO_INVENTORY.getBoolean()) { - player.getInventory().addItem(item); - } else { - block.getWorld().dropItemNaturally(block.getLocation().clone().add(.5, 1, .5), item); + //Modify stack + if (isStacked) { + event.setCancelled(true); + //Add to stack + if (clickAction == Action.RIGHT_CLICK_BLOCK) { + if (inHand.getType().equals(Material.AIR)) return; + if(!blockType.equals(CompatibleMaterial.getMaterial(inHand))) return; + //Add all held items to stack + if (Settings.ALWAYS_ADD_ALL.getBoolean() || isSneaking) { + stack.add(inHandAmount); + if (player.getGameMode() != GameMode.CREATIVE) { + hand.takeItem(player, inHandAmount); } } else { - plugin.updateHologram(stack); - plugin.getDataManager().updateBlock(stack); + //Add one held item to stack + stack.add(1); + if (player.getGameMode() != GameMode.CREATIVE) { + hand.takeItem(player, 1); + } } } + + //Remove from stack + if (clickAction == Action.LEFT_CLICK_BLOCK) { + if (isSneaking) { + //Remove all items from stack + int amountToRemove = Math.min(Settings.MAX_REMOVEABLE.getInt(), stack.getAmount()); + ItemStack removed = stack.getMaterial().getItem(); + removed.setAmount(amountToRemove); + stack.take(amountToRemove); + if (Settings.ADD_TO_INVENTORY.getBoolean()) { + player.getInventory().addItem(removed); + } else { + player.getWorld().dropItemNaturally(block.getLocation(), removed); + } + } else { + //Remove one item from stack + stack.take(1); + if (Settings.ADD_TO_INVENTORY.getBoolean()) { + player.getInventory().addItem(stack.getMaterial().getItem()); + } else { + player.getWorld().dropItemNaturally(block.getLocation(), stack.getMaterial().getItem()); + } + } + if (stack.getAmount() == 0) { + //Remove stack + stack.destroy(); + return; + } + } + //update hologram + plugin.updateHologram(stack); + return; + } else { + if (isSneaking) return; + //Check if player clicked the same type as the clicked block + if (inHand.getType().equals(Material.AIR)) return; + if(!blockType.equals(CompatibleMaterial.getMaterial(inHand))) return; + if (clickAction != Action.RIGHT_CLICK_BLOCK) return; + //Create new stack + event.setCancelled(true); + hand.takeItem(player, 1); + BlockStack newStack = blockStackManager.createBlock(block); + plugin.getDataManager().createBlock(newStack); + plugin.updateHologram(newStack); } + return; } + //Stacking spawners if (block.getType() != CompatibleMaterial.SPAWNER.getMaterial() || inHand.getType() != CompatibleMaterial.SPAWNER.getMaterial() || event.getAction() == Action.LEFT_CLICK_BLOCK) return; diff --git a/src/main/java/com/songoda/ultimatestacker/stackable/block/BlockStack.java b/src/main/java/com/songoda/ultimatestacker/stackable/block/BlockStack.java index 94b4d44..cc59b69 100644 --- a/src/main/java/com/songoda/ultimatestacker/stackable/block/BlockStack.java +++ b/src/main/java/com/songoda/ultimatestacker/stackable/block/BlockStack.java @@ -22,7 +22,7 @@ public class BlockStack implements Stackable, Hologramable { // The id that identifies this stack in the database. private int id; - private int amount = 0; + private int amount = 1; private final CompatibleMaterial material; private final Location location; diff --git a/src/main/java/com/songoda/ultimatestacker/stackable/block/BlockStackManager.java b/src/main/java/com/songoda/ultimatestacker/stackable/block/BlockStackManager.java index b53dfe7..136bb63 100644 --- a/src/main/java/com/songoda/ultimatestacker/stackable/block/BlockStackManager.java +++ b/src/main/java/com/songoda/ultimatestacker/stackable/block/BlockStackManager.java @@ -26,12 +26,16 @@ public class BlockStackManager { return registeredBlocks.remove(roundLocation(location)); } - public BlockStack getBlock(Location location, CompatibleMaterial material) { + public BlockStack getBlock(Location location) { + return this.registeredBlocks.get(location); + } + + public BlockStack createBlock(Location location, CompatibleMaterial material) { return this.registeredBlocks.computeIfAbsent(location, b -> new BlockStack(material, location)); } - public BlockStack getBlock(Block block, CompatibleMaterial material) { - return this.getBlock(block.getLocation(), material); + public BlockStack createBlock(Block block) { + return this.createBlock(block.getLocation(), CompatibleMaterial.getMaterial(block)); } public boolean isBlock(Location location) { From 88a5df4fec51fd4791b00c6a24cf9a9bada6b1ce Mon Sep 17 00:00:00 2001 From: ceze88 Date: Fri, 7 Apr 2023 21:43:17 +0200 Subject: [PATCH 19/31] Add softdepends to plugin.yml --- src/main/resources/plugin.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 7ec5605..f61a302 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,7 +1,7 @@ name: UltimateStacker description: UltimateStacker version: maven-version-number -softdepend: [MythicMobs, HolographicDisplays, Holograms, CMI, WorldGuard, EpicSpawners, mcMMO, WildStacker, StackMob, BentoBox] +softdepend: [MythicMobs, HolographicDisplays, Holograms, DecentHolograms, CMI, WorldGuard, EpicSpawners, mcMMO, WildStacker, StackMob, BentoBox, ViaVersion] loadbefore: [WorldGuard] main: com.songoda.ultimatestacker.UltimateStacker author: songoda From 732062fb610efa4a64b3aa4ecc1d72e6beb3a5af Mon Sep 17 00:00:00 2001 From: ceze88 Date: Fri, 7 Apr 2023 21:43:39 +0200 Subject: [PATCH 20/31] Fix NPE on plugin reload --- .../com/songoda/ultimatestacker/listeners/SpawnerListeners.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/SpawnerListeners.java b/src/main/java/com/songoda/ultimatestacker/listeners/SpawnerListeners.java index c1449c8..130cd2d 100644 --- a/src/main/java/com/songoda/ultimatestacker/listeners/SpawnerListeners.java +++ b/src/main/java/com/songoda/ultimatestacker/listeners/SpawnerListeners.java @@ -39,6 +39,7 @@ public class SpawnerListeners implements Listener { @EventHandler public void onSpawn(SpawnerSpawnEvent event) { + if (plugin.getStackingTask() == null) return; //Don't spam error when reloading the plugin if (!Settings.STACK_ENTITIES.getBoolean() || !plugin.spawnersEnabled() || plugin.getStackingTask().isWorldDisabled(event.getLocation().getWorld())) return; From bc25500bce1d2072620349a983d9df35d66eb5ea Mon Sep 17 00:00:00 2001 From: ceze88 Date: Fri, 7 Apr 2023 21:44:08 +0200 Subject: [PATCH 21/31] Improve stacking task speed --- .../ultimatestacker/tasks/StackingTask.java | 524 +++++++++--------- .../ultimatestacker/utils/CachedChunk.java | 2 +- 2 files changed, 265 insertions(+), 261 deletions(-) diff --git a/src/main/java/com/songoda/ultimatestacker/tasks/StackingTask.java b/src/main/java/com/songoda/ultimatestacker/tasks/StackingTask.java index e400d4a..b9661ef 100644 --- a/src/main/java/com/songoda/ultimatestacker/tasks/StackingTask.java +++ b/src/main/java/com/songoda/ultimatestacker/tasks/StackingTask.java @@ -14,6 +14,7 @@ import com.songoda.ultimatestacker.stackable.entity.custom.CustomEntity; import com.songoda.ultimatestacker.utils.Async; import com.songoda.ultimatestacker.utils.CachedChunk; import org.bukkit.Bukkit; +import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; @@ -78,8 +79,6 @@ public class StackingTask extends TimerTask { private final ConfigurationSection configurationSection = UltimateStacker.getInstance().getMobFile(); private final List processed = new ArrayList<>(); - private final Map cachedChunks = new HashMap<>(); - private final Map entityStackSizes = new HashMap<>(); private final int maxEntityStackSize = Settings.MAX_STACK_ENTITIES.getInt(), minEntityStackSize = Settings.MIN_STACK_ENTITIES.getInt(), @@ -134,27 +133,28 @@ public class StackingTask extends TimerTask { } Collections.reverse(entities); - // Loop through the entities. - for (LivingEntity entity : entities) { - // Make sure our entity has not already been processed. - // Skip it if it has been. - if (this.processed.contains(entity.getUniqueId())) continue; + Bukkit.getScheduler().runTask(plugin, () -> { + // Loop through the entities. + for (LivingEntity entity : entities) { + // Make sure our entity has not already been processed. + // Skip it if it has been. + if (this.processed.contains(entity.getUniqueId())) continue; - // Check to see if entity is not stackable. - if (!isEntityStackable(entity)) { - continue; + // Check to see if entity is not stackable. + if (!isEntityStackable(entity)) { + continue; + } + + // Get entity location to pass around as its faster this way. + Location location = entity.getLocation(); + + // Process the entity. + this.processEntity(entity, sWorld, location); } - - // Get entity location to pass around as its faster this way. - Location location = entity.getLocation(); - - // Process the entity. - this.processEntity(entity, sWorld, location); - } + }); } // Clear caches in preparation for the next run. this.processed.clear(); - this.cachedChunks.clear(); } catch (Exception ignored) {} } @@ -167,8 +167,7 @@ public class StackingTask extends TimerTask { private Future getEntitiesInChunkSync(CachedChunk cachedChunk) { CompletableFuture future = new CompletableFuture<>(); - Bukkit.getScheduler().scheduleSyncDelayedTask(this.plugin, () -> future.complete(cachedChunk.getEntities())); - + Bukkit.getScheduler().runTask(this.plugin, () -> future.complete(cachedChunk.getEntities())); return future; } @@ -255,7 +254,8 @@ public class StackingTask extends TimerTask { // Get similar entities around our entity and make sure those entities are both compatible and stackable. List stackableFriends = new LinkedList<>(); - for (LivingEntity entity : getSimilarEntitiesAroundEntity(baseEntity, sWorld, location)) { + List list = getSimilarEntitiesAroundEntity(baseEntity, sWorld, location); + for (LivingEntity entity : list) { // Check to see if entity is not stackable. if (!isEntityStackable(entity)) continue; @@ -358,7 +358,7 @@ public class StackingTask extends TimerTask { try { Set chunks = getNearbyChunks(new SWorld(entity.getWorld()), entity.getLocation(), radius, singleChunk); for (CachedChunk chunk : chunks) { - Entity[] entityList = getEntitiesInChunkSync(chunk).get(); + Entity[] entityList = chunk.getEntities(); for (Entity e : entityList) { if (!processed.contains(e.getUniqueId()) && e.getType() == entity.getType() && e instanceof LivingEntity && e.isValid() && e.getLocation().distance(entity.getLocation()) <= radius) { entities.add((LivingEntity) e); @@ -373,258 +373,262 @@ public class StackingTask extends TimerTask { } public List getSimilarEntitiesAroundEntity(LivingEntity initialEntity, SWorld sWorld, Location location) { - // Create a list of all entities around the initial entity of the same type. - List entityList = new LinkedList<>(getFriendlyStacksNearby(initialEntity, searchRadius, stackWholeChunk)); + try { + // Create a list of all entities around the initial entity of the same type. + List entityList = new LinkedList<>(getFriendlyStacksNearby(initialEntity, searchRadius, stackWholeChunk)); - CustomEntity customEntity = plugin.getCustomEntityManager().getCustomEntity(initialEntity); - if (customEntity != null) - entityList.removeIf(entity -> !customEntity.isSimilar(initialEntity, entity)); + CustomEntity customEntity = plugin.getCustomEntityManager().getCustomEntity(initialEntity); + if (customEntity != null) + entityList.removeIf(entity -> !customEntity.isSimilar(initialEntity, entity)); - if (stackFlyingDown && canFly(initialEntity)) - entityList.removeIf(entity -> entity.getLocation().getY() > initialEntity.getLocation().getY()); + if (stackFlyingDown && canFly(initialEntity)) + entityList.removeIf(entity -> entity.getLocation().getY() > initialEntity.getLocation().getY()); - for (Check check : checks) { - if (check == null) continue; - switch (check) { - case SPAWN_REASON: { - if (initialEntity.hasMetadata("US_REASON")) - entityList.removeIf(entity -> entity.hasMetadata("US_REASON") && !entity.getMetadata("US_REASON").get(0).asString().equals("US_REASON")); - } - case AGE: { - if (!(initialEntity instanceof Ageable)) break; - - if (((Ageable) initialEntity).isAdult()) { - entityList.removeIf(entity -> !((Ageable) entity).isAdult()); - } else { - entityList.removeIf(entity -> ((Ageable) entity).isAdult()); + for (Check check : checks) { + if (check == null) continue; + switch (check) { + case SPAWN_REASON: { + if (initialEntity.hasMetadata("US_REASON")) + entityList.removeIf(entity -> entity.hasMetadata("US_REASON") && !entity.getMetadata("US_REASON").get(0).asString().equals("US_REASON")); } - break; - } - case NERFED: { - if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_9)) break; - entityList.removeIf(entity -> entity.hasAI() != initialEntity.hasAI()); - } - case IS_TAMED: { - if (!(initialEntity instanceof Tameable)) break; - if (((Tameable) initialEntity).isTamed()) { - entityList.removeIf(entity -> !((Tameable) entity).isTamed()); - } else { - entityList.removeIf(entity -> ((Tameable) entity).isTamed()); - } - } - case ANIMAL_OWNER: { - if (!(initialEntity instanceof Tameable)) break; + case AGE: { + if (!(initialEntity instanceof Ageable)) break; - Tameable tameable = ((Tameable) initialEntity); - entityList.removeIf(entity -> ((Tameable) entity).getOwner() != tameable.getOwner()); - } - case PIG_SADDLE: { - if (!(initialEntity instanceof Pig)) break; - entityList.removeIf(entity -> ((Pig) entity).hasSaddle()); - break; - } - case SKELETON_TYPE: { - if (!(initialEntity instanceof Skeleton)) break; - - Skeleton skeleton = (Skeleton) initialEntity; - entityList.removeIf(entity -> ((Skeleton) entity).getSkeletonType() != skeleton.getSkeletonType()); - break; - } - case SHEEP_COLOR: { - if (!(initialEntity instanceof Sheep)) break; - - Sheep sheep = ((Sheep) initialEntity); - entityList.removeIf(entity -> ((Sheep) entity).getColor() != sheep.getColor()); - break; - } - case SHEEP_SHEARED: { - if (!(initialEntity instanceof Sheep)) break; - - Sheep sheep = ((Sheep) initialEntity); - if (sheep.isSheared()) { - entityList.removeIf(entity -> !((Sheep) entity).isSheared()); - } else { - entityList.removeIf(entity -> ((Sheep) entity).isSheared()); - } - break; - } - case SNOWMAN_DERPED: { - if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_9) - || !(initialEntity instanceof Snowman)) break; - - Snowman snowman = ((Snowman) initialEntity); - if (snowman.isDerp()) { - entityList.removeIf(entity -> !((Snowman) entity).isDerp()); - } else { - entityList.removeIf(entity -> ((Snowman) entity).isDerp()); - } - break; - } - case LLAMA_COLOR: { - if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_11) - || !(initialEntity instanceof Llama)) break; - Llama llama = ((Llama) initialEntity); - entityList.removeIf(entity -> ((Llama) entity).getColor() != llama.getColor()); - break; - } - case LLAMA_STRENGTH: { - if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_11) - || !(initialEntity instanceof Llama)) break; - Llama llama = ((Llama) initialEntity); - entityList.removeIf(entity -> ((Llama) entity).getStrength() != llama.getStrength()); - break; - } - case VILLAGER_PROFESSION: { - if (!(initialEntity instanceof Villager)) break; - Villager villager = ((Villager) initialEntity); - entityList.removeIf(entity -> ((Villager) entity).getProfession() != villager.getProfession()); - break; - } - case SLIME_SIZE: { - if (!(initialEntity instanceof Slime)) break; - Slime slime = ((Slime) initialEntity); - entityList.removeIf(entity -> ((Slime) entity).getSize() != slime.getSize()); - break; - } - case HORSE_CARRYING_CHEST: { - if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_11)) { - if (!(initialEntity instanceof ChestedHorse)) break; - entityList.removeIf(entity -> ((ChestedHorse) entity).isCarryingChest()); - } else { - if (!(initialEntity instanceof Horse)) break; - entityList.removeIf(entity -> ((Horse) entity).isCarryingChest()); - } - break; - } - case HORSE_HAS_ARMOR: { - if (!(initialEntity instanceof Horse)) break; - entityList.removeIf(entity -> ((Horse) entity).getInventory().getArmor() != null); - break; - } - case HORSE_HAS_SADDLE: { - if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13) - && initialEntity instanceof AbstractHorse) { - entityList.removeIf(entity -> ((AbstractHorse) entity).getInventory().getSaddle() != null); + if (((Ageable) initialEntity).isAdult()) { + entityList.removeIf(entity -> !((Ageable) entity).isAdult()); + } else { + entityList.removeIf(entity -> ((Ageable) entity).isAdult()); + } break; } - if (!(initialEntity instanceof Horse)) break; - entityList.removeIf(entity -> ((Horse) entity).getInventory().getSaddle() != null); - break; - } - case HORSE_JUMP: { - if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_11)) { - if (!(initialEntity instanceof AbstractHorse)) break; - AbstractHorse horse = ((AbstractHorse) initialEntity); - entityList.removeIf(entity -> ((AbstractHorse) entity).getJumpStrength() != horse.getJumpStrength()); - } else { + case NERFED: { + if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_9)) break; + entityList.removeIf(entity -> entity.hasAI() != initialEntity.hasAI()); + } + case IS_TAMED: { + if (!(initialEntity instanceof Tameable)) break; + if (((Tameable) initialEntity).isTamed()) { + entityList.removeIf(entity -> !((Tameable) entity).isTamed()); + } else { + entityList.removeIf(entity -> ((Tameable) entity).isTamed()); + } + } + case ANIMAL_OWNER: { + if (!(initialEntity instanceof Tameable)) break; + + Tameable tameable = ((Tameable) initialEntity); + entityList.removeIf(entity -> ((Tameable) entity).getOwner() != tameable.getOwner()); + } + case PIG_SADDLE: { + if (!(initialEntity instanceof Pig)) break; + entityList.removeIf(entity -> ((Pig) entity).hasSaddle()); + break; + } + case SKELETON_TYPE: { + if (!(initialEntity instanceof Skeleton)) break; + + Skeleton skeleton = (Skeleton) initialEntity; + entityList.removeIf(entity -> ((Skeleton) entity).getSkeletonType() != skeleton.getSkeletonType()); + break; + } + case SHEEP_COLOR: { + if (!(initialEntity instanceof Sheep)) break; + + Sheep sheep = ((Sheep) initialEntity); + entityList.removeIf(entity -> ((Sheep) entity).getColor() != sheep.getColor()); + break; + } + case SHEEP_SHEARED: { + if (!(initialEntity instanceof Sheep)) break; + + Sheep sheep = ((Sheep) initialEntity); + if (sheep.isSheared()) { + entityList.removeIf(entity -> !((Sheep) entity).isSheared()); + } else { + entityList.removeIf(entity -> ((Sheep) entity).isSheared()); + } + break; + } + case SNOWMAN_DERPED: { + if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_9) + || !(initialEntity instanceof Snowman)) break; + + Snowman snowman = ((Snowman) initialEntity); + if (snowman.isDerp()) { + entityList.removeIf(entity -> !((Snowman) entity).isDerp()); + } else { + entityList.removeIf(entity -> ((Snowman) entity).isDerp()); + } + break; + } + case LLAMA_COLOR: { + if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_11) + || !(initialEntity instanceof Llama)) break; + Llama llama = ((Llama) initialEntity); + entityList.removeIf(entity -> ((Llama) entity).getColor() != llama.getColor()); + break; + } + case LLAMA_STRENGTH: { + if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_11) + || !(initialEntity instanceof Llama)) break; + Llama llama = ((Llama) initialEntity); + entityList.removeIf(entity -> ((Llama) entity).getStrength() != llama.getStrength()); + break; + } + case VILLAGER_PROFESSION: { + if (!(initialEntity instanceof Villager)) break; + Villager villager = ((Villager) initialEntity); + entityList.removeIf(entity -> ((Villager) entity).getProfession() != villager.getProfession()); + break; + } + case SLIME_SIZE: { + if (!(initialEntity instanceof Slime)) break; + Slime slime = ((Slime) initialEntity); + entityList.removeIf(entity -> ((Slime) entity).getSize() != slime.getSize()); + break; + } + case HORSE_CARRYING_CHEST: { + if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_11)) { + if (!(initialEntity instanceof ChestedHorse)) break; + entityList.removeIf(entity -> ((ChestedHorse) entity).isCarryingChest()); + } else { + if (!(initialEntity instanceof Horse)) break; + entityList.removeIf(entity -> ((Horse) entity).isCarryingChest()); + } + break; + } + case HORSE_HAS_ARMOR: { + if (!(initialEntity instanceof Horse)) break; + entityList.removeIf(entity -> ((Horse) entity).getInventory().getArmor() != null); + break; + } + case HORSE_HAS_SADDLE: { + if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13) + && initialEntity instanceof AbstractHorse) { + entityList.removeIf(entity -> ((AbstractHorse) entity).getInventory().getSaddle() != null); + break; + } + if (!(initialEntity instanceof Horse)) break; + entityList.removeIf(entity -> ((Horse) entity).getInventory().getSaddle() != null); + break; + } + case HORSE_JUMP: { + if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_11)) { + if (!(initialEntity instanceof AbstractHorse)) break; + AbstractHorse horse = ((AbstractHorse) initialEntity); + entityList.removeIf(entity -> ((AbstractHorse) entity).getJumpStrength() != horse.getJumpStrength()); + } else { + if (!(initialEntity instanceof Horse)) break; + Horse horse = ((Horse) initialEntity); + entityList.removeIf(entity -> ((Horse) entity).getJumpStrength() != horse.getJumpStrength()); + + } + break; + } + case HORSE_COLOR: { if (!(initialEntity instanceof Horse)) break; Horse horse = ((Horse) initialEntity); - entityList.removeIf(entity -> ((Horse) entity).getJumpStrength() != horse.getJumpStrength()); - + entityList.removeIf(entity -> ((Horse) entity).getColor() != horse.getColor()); + break; + } + case HORSE_STYLE: { + if (!(initialEntity instanceof Horse)) break; + Horse horse = ((Horse) initialEntity); + entityList.removeIf(entity -> ((Horse) entity).getStyle() != horse.getStyle()); + break; + } + case ZOMBIE_BABY: { + if (!(initialEntity instanceof Zombie)) break; + Zombie zombie = (Zombie) initialEntity; + entityList.removeIf(entity -> ((Zombie) entity).isBaby() != zombie.isBaby()); + break; + } + case WOLF_COLLAR_COLOR: { + if (!(initialEntity instanceof Wolf)) break; + Wolf wolf = (Wolf) initialEntity; + entityList.removeIf(entity -> ((Wolf) entity).getCollarColor() != wolf.getCollarColor()); + break; + } + case OCELOT_TYPE: { + if (!(initialEntity instanceof Ocelot)) break; + Ocelot ocelot = (Ocelot) initialEntity; + entityList.removeIf(entity -> ((Ocelot) entity).getCatType() != ocelot.getCatType()); + } + case CAT_TYPE: { + if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_14) + || !(initialEntity instanceof Cat)) break; + Cat cat = (Cat) initialEntity; + entityList.removeIf(entity -> ((Cat) entity).getCatType() != cat.getCatType()); + break; + } + case HAS_EQUIPMENT: { + if (initialEntity.getEquipment() == null) break; + boolean imEquipped = isEquipped(initialEntity); + if (imEquipped) + entityList = new ArrayList<>(); + else + entityList.removeIf(this::isEquipped); + break; + } + case RABBIT_TYPE: { + if (!(initialEntity instanceof Rabbit)) break; + Rabbit rabbit = (Rabbit) initialEntity; + entityList.removeIf(entity -> ((Rabbit) entity).getRabbitType() != rabbit.getRabbitType()); + break; + } + case PARROT_TYPE: { + if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_12) + || !(initialEntity instanceof Parrot)) break; + Parrot parrot = (Parrot) initialEntity; + entityList.removeIf(entity -> ((Parrot) entity).getVariant() != parrot.getVariant()); + break; + } + case PUFFERFISH_STATE: { + if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13) + || !(initialEntity instanceof PufferFish)) break; + PufferFish pufferFish = (PufferFish) initialEntity; + entityList.removeIf(entity -> ((PufferFish) entity).getPuffState() != pufferFish.getPuffState()); + break; + } + case TROPICALFISH_PATTERN: { + if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13) + || !(initialEntity instanceof TropicalFish)) break; + TropicalFish tropicalFish = (TropicalFish) initialEntity; + entityList.removeIf(entity -> ((TropicalFish) entity).getPattern() != tropicalFish.getPattern()); + break; + } + case TROPICALFISH_PATTERN_COLOR: { + if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13) + || !(initialEntity instanceof TropicalFish)) break; + TropicalFish tropicalFish = (TropicalFish) initialEntity; + entityList.removeIf(entity -> ((TropicalFish) entity).getPatternColor() != tropicalFish.getPatternColor()); + break; + } + case TROPICALFISH_BODY_COLOR: { + if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13) + || !(initialEntity instanceof TropicalFish)) break; + TropicalFish tropicalFish = (TropicalFish) initialEntity; + entityList.removeIf(entity -> ((TropicalFish) entity).getBodyColor() != tropicalFish.getBodyColor()); + break; + } + case PHANTOM_SIZE: { + if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13) + || !(initialEntity instanceof Phantom)) break; + Phantom phantom = (Phantom) initialEntity; + entityList.removeIf(entity -> ((Phantom) entity).getSize() != phantom.getSize()); + break; } - break; - } - case HORSE_COLOR: { - if (!(initialEntity instanceof Horse)) break; - Horse horse = ((Horse) initialEntity); - entityList.removeIf(entity -> ((Horse) entity).getColor() != horse.getColor()); - break; - } - case HORSE_STYLE: { - if (!(initialEntity instanceof Horse)) break; - Horse horse = ((Horse) initialEntity); - entityList.removeIf(entity -> ((Horse) entity).getStyle() != horse.getStyle()); - break; - } - case ZOMBIE_BABY: { - if (!(initialEntity instanceof Zombie)) break; - Zombie zombie = (Zombie) initialEntity; - entityList.removeIf(entity -> ((Zombie) entity).isBaby() != zombie.isBaby()); - break; - } - case WOLF_COLLAR_COLOR: { - if (!(initialEntity instanceof Wolf)) break; - Wolf wolf = (Wolf) initialEntity; - entityList.removeIf(entity -> ((Wolf) entity).getCollarColor() != wolf.getCollarColor()); - break; - } - case OCELOT_TYPE: { - if (!(initialEntity instanceof Ocelot)) break; - Ocelot ocelot = (Ocelot) initialEntity; - entityList.removeIf(entity -> ((Ocelot) entity).getCatType() != ocelot.getCatType()); - } - case CAT_TYPE: { - if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_14) - || !(initialEntity instanceof Cat)) break; - Cat cat = (Cat) initialEntity; - entityList.removeIf(entity -> ((Cat) entity).getCatType() != cat.getCatType()); - break; - } - case HAS_EQUIPMENT: { - if (initialEntity.getEquipment() == null) break; - boolean imEquipped = isEquipped(initialEntity); - if (imEquipped) - entityList = new ArrayList<>(); - else - entityList.removeIf(this::isEquipped); - break; - } - case RABBIT_TYPE: { - if (!(initialEntity instanceof Rabbit)) break; - Rabbit rabbit = (Rabbit) initialEntity; - entityList.removeIf(entity -> ((Rabbit) entity).getRabbitType() != rabbit.getRabbitType()); - break; - } - case PARROT_TYPE: { - if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_12) - || !(initialEntity instanceof Parrot)) break; - Parrot parrot = (Parrot) initialEntity; - entityList.removeIf(entity -> ((Parrot) entity).getVariant() != parrot.getVariant()); - break; - } - case PUFFERFISH_STATE: { - if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13) - || !(initialEntity instanceof PufferFish)) break; - PufferFish pufferFish = (PufferFish) initialEntity; - entityList.removeIf(entity -> ((PufferFish) entity).getPuffState() != pufferFish.getPuffState()); - break; - } - case TROPICALFISH_PATTERN: { - if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13) - || !(initialEntity instanceof TropicalFish)) break; - TropicalFish tropicalFish = (TropicalFish) initialEntity; - entityList.removeIf(entity -> ((TropicalFish) entity).getPattern() != tropicalFish.getPattern()); - break; - } - case TROPICALFISH_PATTERN_COLOR: { - if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13) - || !(initialEntity instanceof TropicalFish)) break; - TropicalFish tropicalFish = (TropicalFish) initialEntity; - entityList.removeIf(entity -> ((TropicalFish) entity).getPatternColor() != tropicalFish.getPatternColor()); - break; - } - case TROPICALFISH_BODY_COLOR: { - if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13) - || !(initialEntity instanceof TropicalFish)) break; - TropicalFish tropicalFish = (TropicalFish) initialEntity; - entityList.removeIf(entity -> ((TropicalFish) entity).getBodyColor() != tropicalFish.getBodyColor()); - break; - } - case PHANTOM_SIZE: { - if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13) - || !(initialEntity instanceof Phantom)) break; - Phantom phantom = (Phantom) initialEntity; - entityList.removeIf(entity -> ((Phantom) entity).getSize() != phantom.getSize()); - break; } } - } - if (initialEntity.hasMetadata("breedCooldown")) { - entityList.removeIf(entity -> !entity.hasMetadata("breedCooldown")); + if (initialEntity.hasMetadata("breedCooldown")) { + entityList.removeIf(entity -> !entity.hasMetadata("breedCooldown")); + } + return entityList; + } catch (Exception ex) { + ex.printStackTrace(); } - - return entityList; + return new ArrayList<>(); } public boolean isEquipped(LivingEntity initialEntity) { diff --git a/src/main/java/com/songoda/ultimatestacker/utils/CachedChunk.java b/src/main/java/com/songoda/ultimatestacker/utils/CachedChunk.java index ad3ec47..732bffb 100644 --- a/src/main/java/com/songoda/ultimatestacker/utils/CachedChunk.java +++ b/src/main/java/com/songoda/ultimatestacker/utils/CachedChunk.java @@ -49,7 +49,7 @@ public class CachedChunk { return new Entity[0]; } Chunk chunk = getChunk(); - return chunk == null ? new Entity[0] : sWorld.getEntitiesFromChunk(x, z); + return chunk == null ? new Entity[0] : chunk.getEntities(); } @Override From bdb548fbd60a8b012dfb70d6121c7cfa3e407eb2 Mon Sep 17 00:00:00 2001 From: ceze88 Date: Fri, 7 Apr 2023 21:44:44 +0200 Subject: [PATCH 22/31] Release 2.4.0-BETA-4 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bfc5fee..1fe3db2 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ com.songoda UltimateStacker 4.0.0 - 2.4.0-BETA-3 + 2.4.0-BETA-4 clean install UltimateStacker-${project.version} From 4bf2d9b479d828210f6fd5522b04969400d729ae Mon Sep 17 00:00:00 2001 From: ceze88 Date: Fri, 7 Apr 2023 22:03:04 +0200 Subject: [PATCH 23/31] Update holograms on chunk load to prevent missing holograms --- .../ultimatestacker/listeners/BlockListeners.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java b/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java index 5489978..3c6722a 100644 --- a/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java +++ b/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java @@ -16,6 +16,7 @@ import com.songoda.ultimatestacker.utils.Methods; import io.lumine.mythic.bukkit.utils.menu.ClickAction; import org.apache.commons.lang.math.NumberUtils; import org.bukkit.Bukkit; +import org.bukkit.Chunk; import org.bukkit.GameMode; import org.bukkit.Material; import org.bukkit.block.Block; @@ -31,6 +32,7 @@ import org.bukkit.event.block.Action; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.BlockStateMeta; @@ -45,6 +47,14 @@ public class BlockListeners implements Listener { this.plugin = plugin; } + @EventHandler + public void onChunkLoad(ChunkLoadEvent event) { + if (!Settings.STACK_BLOCKS.getBoolean()) return; + Chunk chunk = event.getChunk(); + BlockStackManager blockStackManager = plugin.getBlockStackManager(); + blockStackManager.getStacks().stream().filter(stack -> stack.getLocation().getChunk().equals(chunk)).forEach(plugin::updateHologram); + } + @EventHandler(priority = EventPriority.HIGHEST) public void onBlockInteract(PlayerInteractEvent event) { if (event.useInteractedBlock() == Event.Result.DENY) return; From f234cdd73e6fea9b612be7d498637e0ad37e3888 Mon Sep 17 00:00:00 2001 From: ceze88 Date: Fri, 7 Apr 2023 22:43:31 +0200 Subject: [PATCH 24/31] Move ChunkLoadEvent to separate ChunkListener class --- .../ultimatestacker/UltimateStacker.java | 1 + .../listeners/BlockListeners.java | 8 ------ .../listeners/ChunkListener.java | 28 +++++++++++++++++++ .../stackable/block/BlockStackManager.java | 3 +- 4 files changed, 31 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/songoda/ultimatestacker/listeners/ChunkListener.java diff --git a/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java b/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java index a92b12e..6cfa4e7 100644 --- a/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java +++ b/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java @@ -281,6 +281,7 @@ public class UltimateStacker extends SongodaPlugin { } } }); + getServer().getPluginManager().registerEvents(new ChunkListener(this), this); } public void addExp(Player player, EntityStack stack) { diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java b/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java index 3c6722a..cbf8f51 100644 --- a/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java +++ b/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java @@ -47,14 +47,6 @@ public class BlockListeners implements Listener { this.plugin = plugin; } - @EventHandler - public void onChunkLoad(ChunkLoadEvent event) { - if (!Settings.STACK_BLOCKS.getBoolean()) return; - Chunk chunk = event.getChunk(); - BlockStackManager blockStackManager = plugin.getBlockStackManager(); - blockStackManager.getStacks().stream().filter(stack -> stack.getLocation().getChunk().equals(chunk)).forEach(plugin::updateHologram); - } - @EventHandler(priority = EventPriority.HIGHEST) public void onBlockInteract(PlayerInteractEvent event) { if (event.useInteractedBlock() == Event.Result.DENY) return; diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/ChunkListener.java b/src/main/java/com/songoda/ultimatestacker/listeners/ChunkListener.java new file mode 100644 index 0000000..8866462 --- /dev/null +++ b/src/main/java/com/songoda/ultimatestacker/listeners/ChunkListener.java @@ -0,0 +1,28 @@ +package com.songoda.ultimatestacker.listeners; + +import com.songoda.ultimatestacker.UltimateStacker; +import com.songoda.ultimatestacker.settings.Settings; +import com.songoda.ultimatestacker.stackable.block.BlockStackManager; +import org.bukkit.Chunk; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.world.ChunkLoadEvent; + +public class ChunkListener implements Listener { + + private final BlockStackManager blockStackManager; + private final UltimateStacker plugin; + + public ChunkListener(UltimateStacker plugin) { + this.blockStackManager = plugin.getBlockStackManager(); + this.plugin = plugin; + } + + @EventHandler + public void onChunkLoad(ChunkLoadEvent event) { + if (!Settings.STACK_BLOCKS.getBoolean()) return; + Chunk chunk = event.getChunk(); + BlockStackManager blockStackManager = plugin.getBlockStackManager(); + blockStackManager.getStacks().stream().filter(stack -> stack.getLocation().getChunk().equals(chunk)).forEach(plugin::updateHologram); + } +} diff --git a/src/main/java/com/songoda/ultimatestacker/stackable/block/BlockStackManager.java b/src/main/java/com/songoda/ultimatestacker/stackable/block/BlockStackManager.java index 136bb63..30474f4 100644 --- a/src/main/java/com/songoda/ultimatestacker/stackable/block/BlockStackManager.java +++ b/src/main/java/com/songoda/ultimatestacker/stackable/block/BlockStackManager.java @@ -8,10 +8,11 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; public class BlockStackManager { - private final Map registeredBlocks = new HashMap<>(); + private final Map registeredBlocks = new ConcurrentHashMap<>(); public void addBlocks(Map blocks) { this.registeredBlocks.putAll(blocks); From e073cab3223ebf996dc6c92e66c434645ef68ca5 Mon Sep 17 00:00:00 2001 From: ceze88 Date: Mon, 10 Apr 2023 17:14:34 +0200 Subject: [PATCH 25/31] Revert "Update holograms on chunk load to prevent missing holograms" This reverts commit 4bf2d9b479d828210f6fd5522b04969400d729ae. --- .../com/songoda/ultimatestacker/listeners/BlockListeners.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java b/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java index cbf8f51..5489978 100644 --- a/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java +++ b/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java @@ -16,7 +16,6 @@ import com.songoda.ultimatestacker.utils.Methods; import io.lumine.mythic.bukkit.utils.menu.ClickAction; import org.apache.commons.lang.math.NumberUtils; import org.bukkit.Bukkit; -import org.bukkit.Chunk; import org.bukkit.GameMode; import org.bukkit.Material; import org.bukkit.block.Block; @@ -32,7 +31,6 @@ import org.bukkit.event.block.Action; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.BlockStateMeta; From f2b9cbce3e5dda1fd2bfb5f634276095fa516a03 Mon Sep 17 00:00:00 2001 From: ceze88 Date: Mon, 10 Apr 2023 17:14:37 +0200 Subject: [PATCH 26/31] Revert "Move ChunkLoadEvent to separate ChunkListener class" This reverts commit f234cdd73e6fea9b612be7d498637e0ad37e3888. --- .../ultimatestacker/UltimateStacker.java | 1 - .../listeners/BlockListeners.java | 8 ++++++ .../listeners/ChunkListener.java | 28 ------------------- .../stackable/block/BlockStackManager.java | 3 +- 4 files changed, 9 insertions(+), 31 deletions(-) delete mode 100644 src/main/java/com/songoda/ultimatestacker/listeners/ChunkListener.java diff --git a/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java b/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java index 6cfa4e7..a92b12e 100644 --- a/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java +++ b/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java @@ -281,7 +281,6 @@ public class UltimateStacker extends SongodaPlugin { } } }); - getServer().getPluginManager().registerEvents(new ChunkListener(this), this); } public void addExp(Player player, EntityStack stack) { diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java b/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java index 5489978..e6d6c1b 100644 --- a/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java +++ b/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java @@ -45,6 +45,14 @@ public class BlockListeners implements Listener { this.plugin = plugin; } + @EventHandler + public void onChunkLoad(ChunkLoadEvent event) { + if (!Settings.STACK_BLOCKS.getBoolean()) return; + Chunk chunk = event.getChunk(); + BlockStackManager blockStackManager = plugin.getBlockStackManager(); + blockStackManager.getStacks().stream().filter(stack -> stack.getLocation().getChunk().equals(chunk)).forEach(plugin::updateHologram); + } + @EventHandler(priority = EventPriority.HIGHEST) public void onBlockInteract(PlayerInteractEvent event) { if (event.useInteractedBlock() == Event.Result.DENY) return; diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/ChunkListener.java b/src/main/java/com/songoda/ultimatestacker/listeners/ChunkListener.java deleted file mode 100644 index 8866462..0000000 --- a/src/main/java/com/songoda/ultimatestacker/listeners/ChunkListener.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.songoda.ultimatestacker.listeners; - -import com.songoda.ultimatestacker.UltimateStacker; -import com.songoda.ultimatestacker.settings.Settings; -import com.songoda.ultimatestacker.stackable.block.BlockStackManager; -import org.bukkit.Chunk; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.world.ChunkLoadEvent; - -public class ChunkListener implements Listener { - - private final BlockStackManager blockStackManager; - private final UltimateStacker plugin; - - public ChunkListener(UltimateStacker plugin) { - this.blockStackManager = plugin.getBlockStackManager(); - this.plugin = plugin; - } - - @EventHandler - public void onChunkLoad(ChunkLoadEvent event) { - if (!Settings.STACK_BLOCKS.getBoolean()) return; - Chunk chunk = event.getChunk(); - BlockStackManager blockStackManager = plugin.getBlockStackManager(); - blockStackManager.getStacks().stream().filter(stack -> stack.getLocation().getChunk().equals(chunk)).forEach(plugin::updateHologram); - } -} diff --git a/src/main/java/com/songoda/ultimatestacker/stackable/block/BlockStackManager.java b/src/main/java/com/songoda/ultimatestacker/stackable/block/BlockStackManager.java index 30474f4..136bb63 100644 --- a/src/main/java/com/songoda/ultimatestacker/stackable/block/BlockStackManager.java +++ b/src/main/java/com/songoda/ultimatestacker/stackable/block/BlockStackManager.java @@ -8,11 +8,10 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; public class BlockStackManager { - private final Map registeredBlocks = new ConcurrentHashMap<>(); + private final Map registeredBlocks = new HashMap<>(); public void addBlocks(Map blocks) { this.registeredBlocks.putAll(blocks); From a00b6fb7fef0be072d476e2224ce3c4c71551afc Mon Sep 17 00:00:00 2001 From: ceze88 Date: Mon, 10 Apr 2023 17:17:00 +0200 Subject: [PATCH 27/31] Readd method for compatibility reasons --- .../ultimatestacker/stackable/block/BlockStackManager.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/songoda/ultimatestacker/stackable/block/BlockStackManager.java b/src/main/java/com/songoda/ultimatestacker/stackable/block/BlockStackManager.java index 136bb63..8445acd 100644 --- a/src/main/java/com/songoda/ultimatestacker/stackable/block/BlockStackManager.java +++ b/src/main/java/com/songoda/ultimatestacker/stackable/block/BlockStackManager.java @@ -30,6 +30,10 @@ public class BlockStackManager { return this.registeredBlocks.get(location); } + public BlockStack getBlock(Block block, CompatibleMaterial material) { + return this.getBlock(block.getLocation()); + } + public BlockStack createBlock(Location location, CompatibleMaterial material) { return this.registeredBlocks.computeIfAbsent(location, b -> new BlockStack(material, location)); } From 3eeef59c5fa354d38a9cb09761f242f7d4637e6b Mon Sep 17 00:00:00 2001 From: ceze88 Date: Mon, 10 Apr 2023 17:17:44 +0200 Subject: [PATCH 28/31] Fix block stacking in creative, save stack after update --- .../songoda/ultimatestacker/listeners/BlockListeners.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java b/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java index e6d6c1b..e1c9548 100644 --- a/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java +++ b/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java @@ -138,6 +138,7 @@ public class BlockListeners implements Listener { } //update hologram plugin.updateHologram(stack); + plugin.getDataManager().updateBlock(stack); return; } else { if (isSneaking) return; @@ -147,7 +148,9 @@ public class BlockListeners implements Listener { if (clickAction != Action.RIGHT_CLICK_BLOCK) return; //Create new stack event.setCancelled(true); - hand.takeItem(player, 1); + if (player.getGameMode() != GameMode.CREATIVE) { + hand.takeItem(player, 1); + } BlockStack newStack = blockStackManager.createBlock(block); plugin.getDataManager().createBlock(newStack); plugin.updateHologram(newStack); From 2d55f3851c2fe602d3bb1c7c1820a684de81b36a Mon Sep 17 00:00:00 2001 From: ceze88 Date: Thu, 13 Apr 2023 17:07:57 +0200 Subject: [PATCH 29/31] Revert chunk listener stuff --- .../songoda/ultimatestacker/listeners/BlockListeners.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java b/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java index e1c9548..02b32a5 100644 --- a/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java +++ b/src/main/java/com/songoda/ultimatestacker/listeners/BlockListeners.java @@ -45,14 +45,6 @@ public class BlockListeners implements Listener { this.plugin = plugin; } - @EventHandler - public void onChunkLoad(ChunkLoadEvent event) { - if (!Settings.STACK_BLOCKS.getBoolean()) return; - Chunk chunk = event.getChunk(); - BlockStackManager blockStackManager = plugin.getBlockStackManager(); - blockStackManager.getStacks().stream().filter(stack -> stack.getLocation().getChunk().equals(chunk)).forEach(plugin::updateHologram); - } - @EventHandler(priority = EventPriority.HIGHEST) public void onBlockInteract(PlayerInteractEvent event) { if (event.useInteractedBlock() == Event.Result.DENY) return; From 6dad22622af2c888be89ee108fa8a860f99a8d5b Mon Sep 17 00:00:00 2001 From: ceze88 Date: Thu, 13 Apr 2023 17:09:03 +0200 Subject: [PATCH 30/31] Updates SongodaCore to v2.6.19 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1fe3db2..d5f43a1 100644 --- a/pom.xml +++ b/pom.xml @@ -122,7 +122,7 @@ com.songoda SongodaCore - 2.6.19-DEV + 2.6.19 compile From aaf45767bd98356e7663229b3872ab9f5f06b0b9 Mon Sep 17 00:00:00 2001 From: ceze88 Date: Thu, 13 Apr 2023 17:09:50 +0200 Subject: [PATCH 31/31] Release 2.4.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d5f43a1..7e0806b 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ com.songoda UltimateStacker 4.0.0 - 2.4.0-BETA-4 + 2.4.0 clean install UltimateStacker-${project.version}