From 54be965100933a191ccaace398a69794f4fce1fe Mon Sep 17 00:00:00 2001 From: Christian Koop Date: Mon, 26 Dec 2022 20:15:43 +0100 Subject: [PATCH 01/10] Updates dependency WildStacker to use the API module and added repo url --- pom.xml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index dff2ba4..bfe3ca7 100644 --- a/pom.xml +++ b/pom.xml @@ -99,6 +99,11 @@ CodeMC https://repo.codemc.org/repository/maven-public/ + + + bg-repo + https://repo.bg-software.com/repository/api/ + @@ -118,8 +123,8 @@ com.bgsoftware - wildstacker - 3.5.1 + WildStackerAPI + 3.8.1 provided From 0afd8ad41cc789e02e0c0d4321835f8481638f0d Mon Sep 17 00:00:00 2001 From: Christian Koop Date: Mon, 26 Dec 2022 20:16:10 +0100 Subject: [PATCH 02/10] Updates dependency MythicMobs to v4.13.0 and adds the maven repo --- pom.xml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index bfe3ca7..2e11833 100644 --- a/pom.xml +++ b/pom.xml @@ -104,6 +104,11 @@ bg-repo https://repo.bg-software.com/repository/api/ + + + lumine-repo + https://mvn.lumine.io/repository/maven-public/ + @@ -144,8 +149,8 @@ io.lumine - MythicMobs - 4.10.1 + Mythic-Dist + 4.13.0 provided From 75d93421abb9ce73983c5b5f7ef787bf2beab716 Mon Sep 17 00:00:00 2001 From: ceze88 Date: Tue, 27 Dec 2022 12:25:43 +0100 Subject: [PATCH 03/10] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b742454..dc1f426 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ * [Suggestions](#suggestions) ## Introduction -Ultimatestacker is a simple yet powerful stacking plugin for Minecraft that allows you to stack mobs, items, spawners and blocks on your server all in a single. This allows for the reduction of lag from large amounts of mobs walking around and in mob grinders, items floating on the ground, large aounts of placed spawners in grinders, and also allows you to remove randomly placed block towers in your builds and turn them in to a single block. The plugin stores all the mobs, items, spawners and blocks, and displays a single entity along with a hologram above the entity that allows you to see how many entities are in that particular stack. This functionality is sure to keep your players coming back because of the high entity caps with reduced lag. +Ultimatestacker is a simple yet powerful stacking plugin for Minecraft that allows you to stack mobs, items, spawners and blocks on your server all in a single. This allows for the reduction of lag from large amounts of mobs walking around and in mob grinders, items floating on the ground, large amounts of placed spawners in grinders, and also allows you to remove randomly placed block towers in your builds and turn them in to a single block. The plugin stores all the mobs, items, spawners and blocks, and displays a single entity along with a hologram above the entity that allows you to see how many entities are in that particular stack. This functionality is sure to keep your players coming back because of the high entity caps with reduced lag. ## Marketplace You can visit [our marketplace](https://songoda.com/marketplace/product/ultimatestacker-the-simple-to-use-stacker.16) to download ultimatestacker as well as take a look at many other fantastic plugins which are sure to catch your eye. From a69c8ad0c3fce169918d92fdf3c1cb233765c5fc Mon Sep 17 00:00:00 2001 From: ceze88 Date: Mon, 2 Jan 2023 13:38:58 +0100 Subject: [PATCH 04/10] Performance fixes, fix Mythicmobs compatibility, MySQL/SQLite fixes --- pom.xml | 6 +- .../ultimatestacker/UltimateStacker.java | 8 +- .../ultimatestacker/database/DataManager.java | 12 ++- .../database/migrations/_2_EntityStacks.java | 2 +- .../_5_StackedEntitiesTableUpdate.java | 21 +++++ .../events/EntityStackKillEvent.java | 72 ++++++++++++++++ .../listeners/DeathListeners.java | 13 +-- .../listeners/item/ItemListeners.java | 7 +- .../lootables/LootablesManager.java | 72 +++++++++++++++- .../stackable/entity/ColdEntityStack.java | 12 ++- .../stackable/entity/EntityStack.java | 83 +++++++++++-------- .../entities/MythicMobsCustomEntity.java | 25 +++--- .../ultimatestacker/tasks/StackingTask.java | 1 + .../songoda/ultimatestacker/utils/Async.java | 17 ++++ 14 files changed, 280 insertions(+), 71 deletions(-) create mode 100644 src/main/java/com/songoda/ultimatestacker/database/migrations/_5_StackedEntitiesTableUpdate.java create mode 100644 src/main/java/com/songoda/ultimatestacker/events/EntityStackKillEvent.java create mode 100644 src/main/java/com/songoda/ultimatestacker/utils/Async.java diff --git a/pom.xml b/pom.xml index 2e11833..c931968 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ com.songoda UltimateStacker 4.0.0 - 2.3.1 + 2.3.2 clean install UltimateStacker-${project.version} @@ -122,7 +122,7 @@ com.songoda SongodaCore - 2.6.17-SNAPSHOT + 2.6.17 compile @@ -150,7 +150,7 @@ io.lumine Mythic-Dist - 4.13.0 + 5.2.0 provided diff --git a/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java b/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java index e23b20d..f11873a 100644 --- a/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java +++ b/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java @@ -27,6 +27,7 @@ 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.hook.StackerHook; import com.songoda.ultimatestacker.hook.hooks.JobsHook; import com.songoda.ultimatestacker.listeners.*; @@ -46,6 +47,7 @@ import com.songoda.ultimatestacker.stackable.entity.custom.CustomEntityManager; import com.songoda.ultimatestacker.stackable.spawner.SpawnerStack; 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 org.apache.commons.lang.WordUtils; import org.bukkit.Bukkit; @@ -104,6 +106,7 @@ public class UltimateStacker extends SongodaPlugin { public void onPluginDisable() { this.dataManager.bulkUpdateSpawners(this.spawnerStackManager.getStacks()); HologramManager.removeAllHolograms(); + Async.shutdown(); } @Override @@ -227,7 +230,8 @@ public class UltimateStacker extends SongodaPlugin { new _1_InitialMigration(), new _2_EntityStacks(), new _3_BlockStacks(), - new _4_DataPurge()); + new _4_DataPurge(), + new _5_StackedEntitiesTableUpdate()); this.dataMigrationManager.runMigrations(); } @@ -392,7 +396,7 @@ public class UltimateStacker extends SongodaPlugin { */ public static void spawnStackedItem(ItemStack item, int amount, Location location) { location.getWorld().dropItem(location, item, dropped -> { - updateItemAmount(dropped, amount); + updateItemMeta(dropped, item, amount); }); } diff --git a/src/main/java/com/songoda/ultimatestacker/database/DataManager.java b/src/main/java/com/songoda/ultimatestacker/database/DataManager.java index 00e8c48..d75731f 100644 --- a/src/main/java/com/songoda/ultimatestacker/database/DataManager.java +++ b/src/main/java/com/songoda/ultimatestacker/database/DataManager.java @@ -3,6 +3,7 @@ package com.songoda.ultimatestacker.database; import com.songoda.core.compatibility.CompatibleMaterial; import com.songoda.core.database.DataManagerAbstract; 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; @@ -68,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 " + this.getTablePrefix() + "spawners (amount, world, x, y, z) VALUES (?, ?, ?, ?, ?)"; + String createSpawner = "INSERT INTO " + getSyntax("OR REPLACE ", DatabaseType.SQLITE) + this.getTablePrefix() + "spawners (amount, world, x, y, z) VALUES (?, ?, ?, ?, ?)"; PreparedStatement statement = connection.prepareStatement(createSpawner); statement.setInt(1, spawnerStack.getAmount()); @@ -103,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 " + this.getTablePrefix() + "blocks (amount, material, world, x, y, z) VALUES (?, ?, ?, ?, ?, ?)"; + String createSpawner = "INSERT INTO " + getSyntax("OR REPLACE ", 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()); @@ -124,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 " + this.getTablePrefix() + "host_entities (uuid, create_duplicates) VALUES (?, ?)"; + String createSerializedEntity = "INSERT INTO " + getSyntax("OR REPLACE ", 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()); @@ -141,12 +142,15 @@ public class DataManager extends DataManagerAbstract { public void createStackedEntity(EntityStack hostStack, StackedEntity stackedEntity) { this.runAsync(() -> { try (Connection connection = this.databaseConnector.getConnection()){ - String createSerializedEntity = "INSERT INTO " + this.getTablePrefix() + "stacked_entities (uuid, host, serialized_entity) VALUES (?, ?, ?)"; + String createSerializedEntity = "INSERT INTO " + getSyntax("OR REPLACE ", 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(); 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 1fbcebe..17c660f 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 @@ -32,7 +32,7 @@ public class _2_EntityStacks extends DataMigration { statement.execute("CREATE TABLE " + tablePrefix + "stacked_entities (" + "uuid VARCHAR(36) PRIMARY KEY NOT NULL," + "host INTEGER NOT NULL," + - "serialized_entity VARBINARY(999) 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 new file mode 100644 index 0000000..77362b9 --- /dev/null +++ b/src/main/java/com/songoda/ultimatestacker/database/migrations/_5_StackedEntitiesTableUpdate.java @@ -0,0 +1,21 @@ +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)"); + } + } +} diff --git a/src/main/java/com/songoda/ultimatestacker/events/EntityStackKillEvent.java b/src/main/java/com/songoda/ultimatestacker/events/EntityStackKillEvent.java new file mode 100644 index 0000000..c1297b2 --- /dev/null +++ b/src/main/java/com/songoda/ultimatestacker/events/EntityStackKillEvent.java @@ -0,0 +1,72 @@ +package com.songoda.ultimatestacker.events; + +import com.songoda.ultimatestacker.stackable.entity.EntityStack; +import org.bukkit.entity.LivingEntity; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +/** + * Called when an entity is killed by a player which is stacked + */ +public class EntityStackKillEvent extends Event { + + private static final HandlerList handlers = new HandlerList(); + private final EntityStack entityStack; + private final boolean instantKill; + + public EntityStackKillEvent(EntityStack entityStack) { + this.entityStack = entityStack; + this.instantKill = false; + } + + public EntityStackKillEvent(EntityStack entityStack, boolean instantKill) { + this.entityStack = entityStack; + this.instantKill = instantKill; + } + + /** + * Get the host entity of the stack + * + * @return Entity + */ + public LivingEntity getEntity() { + return entityStack.getHostEntity(); + } + + /** + * Returns true if the entity was killed instantly + * + * @return true if the entity was killed instantly false otherwise + */ + public boolean isInstantKill() { + return instantKill; + } + + /** + * Get the current size of the entity stack + * + * @return stack size + */ + public int getStackSize() { + return entityStack.getAmount(); + } + + /** + * Get the new size of the entity stack + * + * @return new stack size or 0 if instant killed + */ + public int getNewStackSize() { + return instantKill ? 0 : entityStack.getAmount() - 1; + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } + +} diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/DeathListeners.java b/src/main/java/com/songoda/ultimatestacker/listeners/DeathListeners.java index 620d073..e21fd5c 100644 --- a/src/main/java/com/songoda/ultimatestacker/listeners/DeathListeners.java +++ b/src/main/java/com/songoda/ultimatestacker/listeners/DeathListeners.java @@ -78,11 +78,14 @@ public class DeathListeners implements Listener { && !entity.getWorld().getGameRuleValue(GameRule.DO_MOB_LOOT)) drops.clear(); - if (plugin.getEntityStackManager().isStackedAndLoaded(event.getEntity())) - plugin.getEntityStackManager().getStack(event.getEntity()) - .onDeath(entity, drops, custom, event.getDroppedExp(), event); - else - DropUtils.processStackedDrop(event.getEntity(), drops, event); + if (plugin.getCustomEntityManager().getCustomEntity(entity) == null) { + if (plugin.getEntityStackManager().isStackedAndLoaded(event.getEntity())) { + plugin.getEntityStackManager().getStack(event.getEntity()).onDeath(entity, drops, custom, event.getDroppedExp(), event); + } else { + DropUtils.processStackedDrop(event.getEntity(), drops, event); + } + } + finalItems.remove(entity.getUniqueId()); } diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/item/ItemListeners.java b/src/main/java/com/songoda/ultimatestacker/listeners/item/ItemListeners.java index e36b74f..f060c17 100644 --- a/src/main/java/com/songoda/ultimatestacker/listeners/item/ItemListeners.java +++ b/src/main/java/com/songoda/ultimatestacker/listeners/item/ItemListeners.java @@ -83,6 +83,11 @@ public class ItemListeners implements Listener { return; //Compatibility with Shop instance: https://www.spigotmc.org/resources/shop-a-simple-intuitive-shop-instance.9628/ } - UltimateStacker.updateItemAmount(event.getEntity(), itemStack, itemStack.getAmount()); + if (UltimateStacker.hasCustomAmount(event.getEntity())) { + UltimateStacker.updateItemAmount(event.getEntity(), itemStack, UltimateStacker.getActualItemAmount(event.getEntity()) + itemStack.getAmount()); + } else { + UltimateStacker.updateItemAmount(event.getEntity(), itemStack, itemStack.getAmount()); + } + } } diff --git a/src/main/java/com/songoda/ultimatestacker/lootables/LootablesManager.java b/src/main/java/com/songoda/ultimatestacker/lootables/LootablesManager.java index 0a6fab6..8ee9547 100644 --- a/src/main/java/com/songoda/ultimatestacker/lootables/LootablesManager.java +++ b/src/main/java/com/songoda/ultimatestacker/lootables/LootablesManager.java @@ -19,11 +19,13 @@ import org.bukkit.entity.EntityType; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Projectile; import org.bukkit.entity.Sheep; +import org.bukkit.entity.Zombie; import org.bukkit.event.entity.EntityDamageByEntityEvent; import java.io.File; import java.util.ArrayList; import java.util.List; +import java.util.Random; public class LootablesManager { @@ -41,7 +43,7 @@ public class LootablesManager { public List getDrops(LivingEntity entity) { List toDrop = new ArrayList<>(); - if (entity instanceof Ageable && !((Ageable) entity).isAdult() + if (entity instanceof Ageable && !((Ageable) entity).isAdult() && !(entity instanceof Zombie) || !lootManager.getRegisteredLootables().containsKey(entity.getType().name())) return toDrop; Lootable lootable = lootManager.getRegisteredLootables().get(entity.getType().name()); @@ -63,7 +65,7 @@ public class LootablesManager { if (entity instanceof Sheep) { modify = (Loot loot2) -> { CompatibleMaterial material = loot2.getMaterial(); - if (material.name().contains("WOOL") && ((Sheep) entity).getColor() != null) { + if (material != null && material.name().contains("WOOL") && ((Sheep) entity).getColor() != null) { if (((Sheep) entity).isSheared()) return null; if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)) loot2.setMaterial(CompatibleMaterial.valueOf(((Sheep) entity).getColor() + "_WOOL")); @@ -95,6 +97,72 @@ public class LootablesManager { looting); } + public List getDrops(LivingEntity entity, int times) { + List toDrop = new ArrayList<>(); + if (entity instanceof Ageable && !((Ageable) entity).isAdult() && !(entity instanceof Zombie) + || !lootManager.getRegisteredLootables().containsKey(entity.getType().name())) return toDrop; + + Lootable lootable = lootManager.getRegisteredLootables().get(entity.getType().name()); + int looting = entity.getKiller() != null + && entity.getKiller().getItemInHand().containsEnchantment(Enchantment.LOOT_BONUS_MOBS) + ? entity.getKiller().getItemInHand().getEnchantmentLevel(Enchantment.LOOT_BONUS_MOBS) + : 0; + + int rerollChance = Settings.REROLL.getBoolean() ? looting / (looting + 1) : 0; + + Random random = new Random(); + for (Loot loot : lootable.getRegisteredLoot()) { + List drops = runLoot(entity, loot, rerollChance, looting); + drops.forEach(drop -> { + int max = 2 * (int)(times * 0.55); //this generates more than the original, we need to reduce it + int amount = random.nextInt((max - times) + 1) + times; + if (loot.getChance() > 0) { + amount = (int)(amount * loot.getChance()/100); + } + drop.getItemStack().setAmount(amount); + toDrop.add(drop); + }); + } + if (toDrop.isEmpty()) { + return getDrops(entity, times); + } + return toDrop; + } + + public List getDrops(LivingEntity entity, int times, int attempts) { + attempts--; + List toDrop = new ArrayList<>(); + if (entity instanceof Ageable && !((Ageable) entity).isAdult() && !(entity instanceof Zombie) + || !lootManager.getRegisteredLootables().containsKey(entity.getType().name())) return toDrop; + + Lootable lootable = lootManager.getRegisteredLootables().get(entity.getType().name()); + int looting = entity.getKiller() != null + && entity.getKiller().getItemInHand().containsEnchantment(Enchantment.LOOT_BONUS_MOBS) + ? entity.getKiller().getItemInHand().getEnchantmentLevel(Enchantment.LOOT_BONUS_MOBS) + : 0; + + int rerollChance = Settings.REROLL.getBoolean() ? looting / (looting + 1) : 0; + + Random random = new Random(); + for (Loot loot : lootable.getRegisteredLoot()) { + List drops = runLoot(entity, loot, rerollChance, looting); + drops.forEach(drop -> { + int max = 2 * (int)(times * 0.55); //this generates more than the original, we need to reduce it + int amount = random.nextInt((max - times) + 1) + times; + if (loot.getChance() > 0) { + amount = (int)(amount * loot.getChance()/100); + } + drop.getItemStack().setAmount(amount); + toDrop.add(drop); + }); + } + if (toDrop.isEmpty() && attempts > 0) { + return getDrops(entity, times, 2); + } + return toDrop; + } + + public void createDefaultLootables() { if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_17)) { // Add Glow Squid. diff --git a/src/main/java/com/songoda/ultimatestacker/stackable/entity/ColdEntityStack.java b/src/main/java/com/songoda/ultimatestacker/stackable/entity/ColdEntityStack.java index ba8e51f..62d3dd4 100644 --- a/src/main/java/com/songoda/ultimatestacker/stackable/entity/ColdEntityStack.java +++ b/src/main/java/com/songoda/ultimatestacker/stackable/entity/ColdEntityStack.java @@ -58,7 +58,7 @@ public class ColdEntityStack implements Stackable { this.stackedEntities.addAll(stackedEntities); } - public StackedEntity addEntityToStackSilently(StackedEntity stackedEntity) { + public synchronized StackedEntity addEntityToStackSilently(StackedEntity stackedEntity) { if (stackedEntity == null) return null; stackedEntities.push(stackedEntity); return stackedEntity; @@ -140,17 +140,15 @@ public class ColdEntityStack implements Stackable { return getStackedEntity(entity, false); } - protected StackedEntity getStackedEntity(Entity entity, boolean newUUID) { + protected synchronized StackedEntity getStackedEntity(Entity entity, boolean newUUID) { + if (entity == null) return null; UUID uuid = entity.getUniqueId(); NBTEntity nbtEntity = NmsManager.getNbt().of(entity); - if (newUUID) { - uuid = UUID.randomUUID(); - nbtEntity.set("UUID", uuid); - } + CustomEntity customEntity = plugin.getCustomEntityManager().getCustomEntity(entity); if (customEntity != null) nbtEntity.set(customEntity.getPluginName() + "_UltimateStacker", customEntity.getNBTIdentifier(entity)); - return new StackedEntity(uuid, nbtEntity.serialize("Attributes")); + return new StackedEntity(uuid, nbtEntity.serialize()); } public int getId() { 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 d377ba4..dffad7b 100644 --- a/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java +++ b/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java @@ -1,11 +1,12 @@ package com.songoda.ultimatestacker.stackable.entity; -import com.google.common.base.Throwables; import com.songoda.core.compatibility.ServerVersion; import com.songoda.core.lootables.loot.Drop; import com.songoda.core.lootables.loot.DropUtils; import com.songoda.ultimatestacker.UltimateStacker; +import com.songoda.ultimatestacker.events.EntityStackKillEvent; import com.songoda.ultimatestacker.settings.Settings; +import com.songoda.ultimatestacker.utils.Async; import com.songoda.ultimatestacker.utils.Methods; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -58,23 +59,27 @@ public class EntityStack extends ColdEntityStack { } public void updateStack() { - if (createDuplicates != 0) { - List stackedEntities = new ArrayList<>(); - for (int i = 0; i < createDuplicates; i++) - stackedEntities.add(addEntityToStackSilently(getStackedEntity(hostEntity, true))); - plugin.getDataManager().createStackedEntities(this, stackedEntities); + Async.run(() -> { + if (createDuplicates != 0) { + List stackedEntities = new ArrayList<>(); + long start = System.currentTimeMillis(); + 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; - } - if (!Settings.ENTITY_NAMETAGS.getBoolean()) return; - - Bukkit.getScheduler().scheduleSyncDelayedTask(UltimateStacker.getInstance(), () -> { - if (hostEntity == null) return; - - hostEntity.setCustomNameVisible(!Settings.HOLOGRAMS_ON_LOOK_ENTITY.getBoolean()); - hostEntity.setCustomName(Methods.compileEntityName(hostEntity, getAmount())); - }, hostEntity == null ? 1L : 0L); + createDuplicates = 0; + } + if (!Settings.ENTITY_NAMETAGS.getBoolean()) return; + Bukkit.getScheduler().scheduleSyncDelayedTask(UltimateStacker.getInstance(), () -> { + if (hostEntity == null) return; + hostEntity.setCustomNameVisible(!Settings.HOLOGRAMS_ON_LOOK_ENTITY.getBoolean()); + hostEntity.setCustomName(Methods.compileEntityName(hostEntity, getAmount())); + }, hostEntity == null ? 1L : 0L); + }); } public LivingEntity getHostEntity() { @@ -97,20 +102,6 @@ public class EntityStack extends ColdEntityStack { private void handleWholeStackDeath(LivingEntity killed, List drops, boolean custom, int droppedExp, EntityDeathEvent event) { plugin.getDataManager().deleteHost(this); - List preStackedDrops = new ArrayList<>(); - for (int i = 1; i < getAmount(); i++) { - if (i == 1) { - drops.removeIf(it -> it.getItemStack() != null - && it.getItemStack().isSimilar(killed.getEquipment().getItemInHand())); - for (ItemStack item : killed.getEquipment().getArmorContents()) { - drops.removeIf(it -> it.getItemStack() != null && it.getItemStack().isSimilar(item)); - } - } - if (custom) - drops = plugin.getLootablesManager().getDrops(killed); - preStackedDrops.addAll(drops); - } - // 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(); @@ -120,8 +111,19 @@ public class EntityStack extends ColdEntityStack { event.setDroppedExp(droppedExp * getAmount()); } - DropUtils.processStackedDrop(killed, preStackedDrops, event); + if (plugin.getCustomEntityManager().getCustomEntity(killed) == null) { + Async.run(() -> { + drops.removeIf(it -> it.getItemStack() != null + && it.getItemStack().isSimilar(killed.getEquipment().getItemInHand())); + for (ItemStack item : killed.getEquipment().getArmorContents()) { + drops.removeIf(it -> it.getItemStack() != null && it.getItemStack().isSimilar(item)); + } + DropUtils.processStackedDrop(killed, plugin.getLootablesManager().getDrops(killed, getAmount()), event); + }); + } + + event.getDrops().clear(); if (killed.getKiller() == null) return; plugin.addExp(killed.getKiller(), this); plugin.getEntityStackManager().removeStack(event.getEntity()); @@ -130,9 +132,14 @@ public class EntityStack extends ColdEntityStack { 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(); killed.remove(); LivingEntity newEntity = takeOneAndSpawnEntity(killed.getLocation()); + if (newEntity == null) { + return; + } // In versions 1.14 and below experience is not dropping. Because of this we are doing this ourselves. if (ServerVersion.isServerVersionAtOrBelow(ServerVersion.V1_14)) { @@ -140,16 +147,18 @@ public class EntityStack extends ColdEntityStack { if (droppedExp > 0) killedLocation.getWorld().spawn(killedLocation, ExperienceOrb.class).setExperience(droppedExp); } - - DropUtils.processStackedDrop(killed, drops, event); + if (plugin.getCustomEntityManager().getCustomEntity(killed) == null) { + DropUtils.processStackedDrop(killed, drops, event); + } newEntity.setVelocity(velocity); stackManager.updateStack(killed, newEntity); updateStack(); - if (stackedEntities.isEmpty()) + if (stackedEntities.isEmpty()) { destroy(); + } } public void onDeath(LivingEntity killed, List drops, boolean custom, int droppedExp, EntityDeathEvent event) { @@ -200,8 +209,10 @@ public class EntityStack extends ColdEntityStack { if (full) plugin.getEntityStackManager().removeStack(this.hostUniqueId); if (hostEntity != null) { - hostEntity.setCustomNameVisible(false); - hostEntity.setCustomName(null); + try { + hostEntity.setCustomNameVisible(false); + hostEntity.setCustomName(null); + } catch (NullPointerException ignored) {} } hostEntity = null; hostUniqueId = null; 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 8783347..c1db85e 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 @@ -1,10 +1,10 @@ package com.songoda.ultimatestacker.stackable.entity.custom.entities; import com.songoda.ultimatestacker.stackable.entity.custom.CustomEntity; -import io.lumine.xikage.mythicmobs.MythicMobs; -import io.lumine.xikage.mythicmobs.mobs.ActiveMob; -import io.lumine.xikage.mythicmobs.mobs.MobManager; -import io.lumine.xikage.mythicmobs.mobs.MythicMob; +import io.lumine.mythic.api.mobs.MobManager; +import io.lumine.mythic.bukkit.BukkitAdapter; +import io.lumine.mythic.bukkit.MythicBukkit; +import io.lumine.mythic.core.mobs.ActiveMob; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Entity; @@ -23,12 +23,16 @@ public class MythicMobsCustomEntity extends CustomEntity { @Override public boolean isMatchingType(Entity entity) { - return getMobManager().isActiveMob(entity.getUniqueId()); + return getMobManager().getActiveMobs().stream().anyMatch(activeMob -> activeMob.getEntity().getBukkitEntity().getType().equals(entity.getType())); } @Override public String getDisplayName(Entity entity) { - return getMobManager().getMythicMobInstance(entity).getType().getDisplayName().toString(); + return getMobManager().getActiveMobs().stream() + .filter(activeMob -> activeMob.getEntity().getBukkitEntity().getUniqueId().equals(entity.getUniqueId())) + .findFirst() + .map(ActiveMob::getMobType) + .orElse(null); } @Override @@ -44,16 +48,17 @@ public class MythicMobsCustomEntity extends CustomEntity { @Override public LivingEntity spawnFromIdentifier(String string, Location location) { - if (getMobManager().getMobTypes().stream().map(MythicMob::getInternalName).noneMatch(t -> t.equals(string))) + if (!getMobManager().getMythicMob(string).isPresent()) { return null; - return (LivingEntity)getMobManager().spawnMob(string, location).getEntity().getBukkitEntity(); + } + return (LivingEntity)getMobManager().getMythicMob(string).get().spawn(BukkitAdapter.adapt(location), 1).getEntity().getBukkitEntity(); } private ActiveMob getMob(Entity entity) { - return getMobManager().getMythicMobInstance(entity); + return MythicBukkit.inst().getMobManager().getMythicMobInstance(entity); } private MobManager getMobManager() { - return ((MythicMobs) plugin).getMobManager(); + return ((MythicBukkit) plugin).getMobManager(); } } diff --git a/src/main/java/com/songoda/ultimatestacker/tasks/StackingTask.java b/src/main/java/com/songoda/ultimatestacker/tasks/StackingTask.java index a0950a1..6bbca63 100644 --- a/src/main/java/com/songoda/ultimatestacker/tasks/StackingTask.java +++ b/src/main/java/com/songoda/ultimatestacker/tasks/StackingTask.java @@ -11,6 +11,7 @@ import com.songoda.ultimatestacker.stackable.entity.EntityStack; import com.songoda.ultimatestacker.stackable.entity.EntityStackManager; import com.songoda.ultimatestacker.stackable.entity.StackedEntity; 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.Location; diff --git a/src/main/java/com/songoda/ultimatestacker/utils/Async.java b/src/main/java/com/songoda/ultimatestacker/utils/Async.java new file mode 100644 index 0000000..2028cfe --- /dev/null +++ b/src/main/java/com/songoda/ultimatestacker/utils/Async.java @@ -0,0 +1,17 @@ +package com.songoda.ultimatestacker.utils; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class Async { + + private static ExecutorService executor = Executors.newFixedThreadPool(10); + + public static void run(Runnable runnable) { + executor.execute(runnable); + } + + public static void shutdown() { + executor.shutdown(); + } +} From 1db481d1aafa44608361f74c888673d32bcb8934 Mon Sep 17 00:00:00 2001 From: ceze88 Date: Mon, 16 Jan 2023 21:32:17 +0100 Subject: [PATCH 05/10] New looting system --- pom.xml | 2 +- .../ultimatestacker/UltimateStacker.java | 7 +- .../listeners/DeathListeners.java | 3 + .../lootables/LootablesManager.java | 93 ++++++++++--------- .../stackable/entity/EntityStack.java | 22 +++-- .../stackable/entity/custom/CustomEntity.java | 2 + .../entity/custom/CustomEntityManager.java | 6 +- .../entities/MythicMobsCustomEntity.java | 10 +- .../ultimatestacker/utils/Methods.java | 3 +- 9 files changed, 92 insertions(+), 56 deletions(-) diff --git a/pom.xml b/pom.xml index c931968..6918987 100644 --- a/pom.xml +++ b/pom.xml @@ -122,7 +122,7 @@ com.songoda SongodaCore - 2.6.17 + 2.6.18-Dev compile diff --git a/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java b/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java index f11873a..a66e984 100644 --- a/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java +++ b/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java @@ -64,6 +64,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; +import java.util.Objects; import java.util.Set; public class UltimateStacker extends SongodaPlugin { @@ -104,6 +105,8 @@ public class UltimateStacker extends SongodaPlugin { @Override public void onPluginDisable() { + this.stackingTask.cancel(); + this.stackingTask = null; this.dataManager.bulkUpdateSpawners(this.spawnerStackManager.getStacks()); HologramManager.removeAllHolograms(); Async.shutdown(); @@ -395,7 +398,9 @@ public class UltimateStacker extends SongodaPlugin { * @param location The location to spawn the item */ public static void spawnStackedItem(ItemStack item, int amount, Location location) { - location.getWorld().dropItem(location, item, dropped -> { + if (item.getType() == Material.AIR) return; + Objects.requireNonNull(location.getWorld()).dropItem(location, item, dropped -> { + if (dropped.getItemStack().getType() == Material.AIR) return; updateItemMeta(dropped, item, amount); }); } diff --git a/src/main/java/com/songoda/ultimatestacker/listeners/DeathListeners.java b/src/main/java/com/songoda/ultimatestacker/listeners/DeathListeners.java index e21fd5c..714184a 100644 --- a/src/main/java/com/songoda/ultimatestacker/listeners/DeathListeners.java +++ b/src/main/java/com/songoda/ultimatestacker/listeners/DeathListeners.java @@ -63,6 +63,9 @@ public class DeathListeners implements Listener { if (event.getEntityType() == EntityType.PLAYER || event.getEntityType() == EntityType.ARMOR_STAND) return; + //Respect MythicMobs + if (plugin.getCustomEntityManager().isCustomEntity(entity)) return; + boolean custom = Settings.CUSTOM_DROPS.getBoolean(); List drops = custom ? plugin.getLootablesManager().getDrops(event.getEntity()) : event.getDrops().stream().map(Drop::new).collect(Collectors.toList()); diff --git a/src/main/java/com/songoda/ultimatestacker/lootables/LootablesManager.java b/src/main/java/com/songoda/ultimatestacker/lootables/LootablesManager.java index 8ee9547..ea65de0 100644 --- a/src/main/java/com/songoda/ultimatestacker/lootables/LootablesManager.java +++ b/src/main/java/com/songoda/ultimatestacker/lootables/LootablesManager.java @@ -11,6 +11,8 @@ import com.songoda.core.lootables.loot.LootManager; import com.songoda.core.lootables.loot.Lootable; import com.songoda.ultimatestacker.UltimateStacker; import com.songoda.ultimatestacker.settings.Settings; +import com.songoda.ultimatestacker.stackable.entity.custom.CustomEntity; +import com.songoda.ultimatestacker.stackable.entity.custom.CustomEntityManager; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Ageable; import org.bukkit.entity.Creeper; @@ -21,11 +23,13 @@ import org.bukkit.entity.Projectile; import org.bukkit.entity.Sheep; import org.bukkit.entity.Zombie; import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.inventory.ItemStack; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Random; +import java.util.stream.Collectors; public class LootablesManager { @@ -98,35 +102,7 @@ public class LootablesManager { } public List getDrops(LivingEntity entity, int times) { - List toDrop = new ArrayList<>(); - if (entity instanceof Ageable && !((Ageable) entity).isAdult() && !(entity instanceof Zombie) - || !lootManager.getRegisteredLootables().containsKey(entity.getType().name())) return toDrop; - - Lootable lootable = lootManager.getRegisteredLootables().get(entity.getType().name()); - int looting = entity.getKiller() != null - && entity.getKiller().getItemInHand().containsEnchantment(Enchantment.LOOT_BONUS_MOBS) - ? entity.getKiller().getItemInHand().getEnchantmentLevel(Enchantment.LOOT_BONUS_MOBS) - : 0; - - int rerollChance = Settings.REROLL.getBoolean() ? looting / (looting + 1) : 0; - - Random random = new Random(); - for (Loot loot : lootable.getRegisteredLoot()) { - List drops = runLoot(entity, loot, rerollChance, looting); - drops.forEach(drop -> { - int max = 2 * (int)(times * 0.55); //this generates more than the original, we need to reduce it - int amount = random.nextInt((max - times) + 1) + times; - if (loot.getChance() > 0) { - amount = (int)(amount * loot.getChance()/100); - } - drop.getItemStack().setAmount(amount); - toDrop.add(drop); - }); - } - if (toDrop.isEmpty()) { - return getDrops(entity, times); - } - return toDrop; + return getDrops(entity, times, 3); } public List getDrops(LivingEntity entity, int times, int attempts) { @@ -141,23 +117,56 @@ public class LootablesManager { ? entity.getKiller().getItemInHand().getEnchantmentLevel(Enchantment.LOOT_BONUS_MOBS) : 0; - int rerollChance = Settings.REROLL.getBoolean() ? looting / (looting + 1) : 0; + double extraChance = looting / (looting + 1.0); Random random = new Random(); - for (Loot loot : lootable.getRegisteredLoot()) { - List drops = runLoot(entity, loot, rerollChance, looting); - drops.forEach(drop -> { - int max = 2 * (int)(times * 0.55); //this generates more than the original, we need to reduce it - int amount = random.nextInt((max - times) + 1) + times; - if (loot.getChance() > 0) { - amount = (int)(amount * loot.getChance()/100); - } - drop.getItemStack().setAmount(amount); - toDrop.add(drop); - }); + boolean isCharged = entity instanceof Creeper && ((Creeper) entity).isPowered(); + + //Run main loot + for (Loot loot : lootable.getRegisteredLoot().stream().filter(loot -> loot.getMaterial() != null).collect(Collectors.toList())) { + if (loot.isRequireCharged() && !isCharged) continue; + if (loot.getOnlyDropFor().size() != 0 && loot.getOnlyDropFor().stream().noneMatch(type -> entity.getKiller() != null && type == entity.getKiller().getType())) continue; + int finalLooting = loot.isAllowLootingEnchant() ? looting : 0; + + int max = (int) (((loot.getMax() + finalLooting) * times) * (loot.getChance()/100)); + int min = (int) ((loot.getMin()) * times * (loot.getChance()/100)); + + int amount = random.nextInt((max - min) + 1) + min; + + if (amount > 0) { + ItemStack item = entity.getFireTicks() > 0 + ? loot.getBurnedMaterial() != null ? loot.getBurnedMaterial().getItem() : loot.getMaterial().getItem() + : loot.getMaterial().getItem().clone(); + item.setAmount(amount); + toDrop.add(new Drop(item)); + } } + //Run child loot + for (Loot loot : lootable.getRegisteredLoot().stream().filter(loot -> loot.getMaterial() == null).collect(Collectors.toList())) { + for (Loot child : loot.getChildLoot()) { + if (child.isRequireCharged() && !isCharged) continue; + if (loot.getOnlyDropFor().size() != 0 && loot.getOnlyDropFor().stream().noneMatch(type -> entity.getKiller() != null && type == entity.getKiller().getType())) continue; + + int finalLooting = child.isAllowLootingEnchant() ? looting : 0; + + int max = (int) (((loot.getMax() + finalLooting) * times * (loot.getChance()/100))); + int min = (int) ((loot.getMin()) * times * (loot.getChance()/100)); + min = (int) (min - min*0.90); + + int amount = random.nextInt((max - min) + 1) + min; + + if (amount > 0) { + ItemStack item = entity.getFireTicks() > 0 + ? child.getBurnedMaterial() != null ? child.getBurnedMaterial().getItem() : child.getMaterial().getItem() + : child.getMaterial().getItem().clone(); + item.setAmount(amount); + toDrop.add(new Drop(item)); + } + } + } + if (toDrop.isEmpty() && attempts > 0) { - return getDrops(entity, times, 2); + return getDrops(entity, times, attempts); } return toDrop; } 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 dffad7b..cdd9d7b 100644 --- a/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java +++ b/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java @@ -11,6 +11,7 @@ import com.songoda.ultimatestacker.utils.Methods; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; import org.bukkit.entity.ExperienceOrb; import org.bukkit.entity.LivingEntity; import org.bukkit.event.entity.EntityDamageEvent; @@ -62,7 +63,7 @@ public class EntityStack extends ColdEntityStack { Async.run(() -> { if (createDuplicates != 0) { List stackedEntities = new ArrayList<>(); - long start = System.currentTimeMillis(); + for (int i = 0; i < createDuplicates; i++) { StackedEntity entity = addEntityToStackSilently(getStackedEntity(hostEntity, true)); if (entity != null) @@ -71,15 +72,20 @@ public class EntityStack extends ColdEntityStack { plugin.getDataManager().createStackedEntities(this, stackedEntities); createDuplicates = 0; + updateNametag(); } - if (!Settings.ENTITY_NAMETAGS.getBoolean()) return; - Bukkit.getScheduler().scheduleSyncDelayedTask(UltimateStacker.getInstance(), () -> { - if (hostEntity == null) return; - - hostEntity.setCustomNameVisible(!Settings.HOLOGRAMS_ON_LOOK_ENTITY.getBoolean()); - hostEntity.setCustomName(Methods.compileEntityName(hostEntity, getAmount())); - }, hostEntity == null ? 1L : 0L); }); + 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 LivingEntity getHostEntity() { diff --git a/src/main/java/com/songoda/ultimatestacker/stackable/entity/custom/CustomEntity.java b/src/main/java/com/songoda/ultimatestacker/stackable/entity/custom/CustomEntity.java index 0c0956a..65bb26e 100644 --- a/src/main/java/com/songoda/ultimatestacker/stackable/entity/custom/CustomEntity.java +++ b/src/main/java/com/songoda/ultimatestacker/stackable/entity/custom/CustomEntity.java @@ -24,4 +24,6 @@ public abstract class CustomEntity { public abstract String getNBTIdentifier(Entity entity); public abstract LivingEntity spawnFromIdentifier(String string, Location location); + + public abstract boolean isCustomEntity(Entity entity); } 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 ca08a97..e055715 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 @@ -29,7 +29,7 @@ public class CustomEntityManager { public CustomEntity getCustomEntity(Entity entity) { for (CustomEntity customEntity : registeredCustomEntities) { - if (customEntity.isMatchingType(entity)) { + if (customEntity.isMatchingType(entity) && customEntity.isCustomEntity(entity)) { if (Settings.BLACKLISTED_CUSTOM_ENTITIES.getStringList() .contains((customEntity.getPluginName() + "_" + customEntity.getNBTIdentifier(entity)).toLowerCase())) continue; @@ -42,4 +42,8 @@ public class CustomEntityManager { public List getRegisteredCustomEntities() { return Collections.unmodifiableList(registeredCustomEntities); } + + public boolean isCustomEntity(Entity entity) { + return getCustomEntity(entity) != null && getCustomEntity(entity).isCustomEntity(entity); + } } 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 c1db85e..5613eb4 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 @@ -8,6 +8,7 @@ import io.lumine.mythic.core.mobs.ActiveMob; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; import org.bukkit.entity.LivingEntity; public class MythicMobsCustomEntity extends CustomEntity { @@ -37,7 +38,7 @@ public class MythicMobsCustomEntity extends CustomEntity { @Override public boolean isSimilar(LivingEntity original, LivingEntity entity) { - if (!isMatchingType(original) || !isMatchingType(entity)) return false; + if (!isMatchingType(original) || !isMatchingType(entity) || getMob(entity) == null) return false; return getMob(original).getType().equals(getMob(entity).getType()); } @@ -48,12 +49,17 @@ public class MythicMobsCustomEntity extends CustomEntity { @Override public LivingEntity spawnFromIdentifier(String string, Location location) { - if (!getMobManager().getMythicMob(string).isPresent()) { + if (getMobManager().getMythicMob(string).isPresent()) { return null; } return (LivingEntity)getMobManager().getMythicMob(string).get().spawn(BukkitAdapter.adapt(location), 1).getEntity().getBukkitEntity(); } + @Override + public boolean isCustomEntity(Entity entity) { + return getMob(entity) != null; + } + private ActiveMob getMob(Entity entity) { return MythicBukkit.inst().getMobManager().getMythicMobInstance(entity); } diff --git a/src/main/java/com/songoda/ultimatestacker/utils/Methods.java b/src/main/java/com/songoda/ultimatestacker/utils/Methods.java index 5c25f37..8b2d52f 100644 --- a/src/main/java/com/songoda/ultimatestacker/utils/Methods.java +++ b/src/main/java/com/songoda/ultimatestacker/utils/Methods.java @@ -118,8 +118,9 @@ public class Methods { String displayName = TextUtils.formatText(UltimateStacker.getInstance().getMobFile().getString("Mobs." + entity.getType().name() + ".Display Name")); CustomEntity customEntity = UltimateStacker.getInstance().getCustomEntityManager().getCustomEntity(entity); - if (customEntity != null) + if (customEntity != null) { displayName = customEntity.getDisplayName(entity); + } nameFormat = nameFormat.replace("{TYPE}", displayName); nameFormat = nameFormat.replace("{AMT}", Integer.toString(amount)); From 44f26784ff2c2955491e633aff91b21b8533e2b0 Mon Sep 17 00:00:00 2001 From: ceze88 Date: Mon, 16 Jan 2023 21:32:34 +0100 Subject: [PATCH 06/10] Release 2.3.3-Dev --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6918987..1ad2759 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ com.songoda UltimateStacker 4.0.0 - 2.3.2 + 2.3.3-Dev clean install UltimateStacker-${project.version} From f4a7eaac7a63551490eee1accf60acd5c41f14c7 Mon Sep 17 00:00:00 2001 From: ceze88 Date: Sat, 21 Jan 2023 16:15:24 +0100 Subject: [PATCH 07/10] Fix ClassNotFoundException in older versions when dropping items --- .../songoda/ultimatestacker/UltimateStacker.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java b/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java index a66e984..f4817cc 100644 --- a/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java +++ b/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java @@ -53,6 +53,7 @@ import org.apache.commons.lang.WordUtils; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.entity.EntityType; import org.bukkit.entity.Item; import org.bukkit.entity.Player; @@ -399,10 +400,18 @@ public class UltimateStacker extends SongodaPlugin { */ public static void spawnStackedItem(ItemStack item, int amount, Location location) { if (item.getType() == Material.AIR) return; - Objects.requireNonNull(location.getWorld()).dropItem(location, item, dropped -> { + World world = location.getWorld(); + if (world == null) return; + if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_17)) { + world.dropItem(location, item, dropped -> { + if (dropped.getItemStack().getType() == Material.AIR) return; + updateItemMeta(dropped, item, amount); + }); + } else { + Item dropped = world.dropItem(location, item); if (dropped.getItemStack().getType() == Material.AIR) return; updateItemMeta(dropped, item, amount); - }); + } } /** From efde51034d81a5cf6a0facf8a5fad120530fba3d Mon Sep 17 00:00:00 2001 From: ceze88 Date: Wed, 25 Jan 2023 15:50:41 +0100 Subject: [PATCH 08/10] Fix memory leak --- .../java/com/songoda/ultimatestacker/UltimateStacker.java | 1 + .../ultimatestacker/stackable/entity/EntityStack.java | 2 +- src/main/java/com/songoda/ultimatestacker/utils/Async.java | 6 +++++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java b/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java index f4817cc..cecfa93 100644 --- a/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java +++ b/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java @@ -116,6 +116,7 @@ public class UltimateStacker extends SongodaPlugin { @Override public void onPluginEnable() { // Run Songoda Updater + Async.start(); SongodaCore.registerPlugin(this, 16, CompatibleMaterial.IRON_INGOT); // Setup Config Settings.setupConfig(); 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 cdd9d7b..7142de3 100644 --- a/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java +++ b/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java @@ -130,9 +130,9 @@ public class EntityStack extends ColdEntityStack { } event.getDrops().clear(); + plugin.getEntityStackManager().removeStack(event.getEntity()); if (killed.getKiller() == null) return; plugin.addExp(killed.getKiller(), this); - plugin.getEntityStackManager().removeStack(event.getEntity()); } private void handleSingleStackDeath(LivingEntity killed, List drops, int droppedExp, EntityDeathEvent event) { diff --git a/src/main/java/com/songoda/ultimatestacker/utils/Async.java b/src/main/java/com/songoda/ultimatestacker/utils/Async.java index 2028cfe..4cbaa2c 100644 --- a/src/main/java/com/songoda/ultimatestacker/utils/Async.java +++ b/src/main/java/com/songoda/ultimatestacker/utils/Async.java @@ -5,7 +5,11 @@ import java.util.concurrent.Executors; public class Async { - private static ExecutorService executor = Executors.newFixedThreadPool(10); + private static ExecutorService executor; + + public static void start() { + executor = Executors.newFixedThreadPool(5); + } public static void run(Runnable runnable) { executor.execute(runnable); From affd81914683a00589071f8a703ea8b94fe800bf Mon Sep 17 00:00:00 2001 From: ceze88 Date: Wed, 25 Jan 2023 15:53:48 +0100 Subject: [PATCH 09/10] Ignore rare errors for now --- .../stackable/entity/EntityStack.java | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) 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 7142de3..e2de50a 100644 --- a/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java +++ b/src/main/java/com/songoda/ultimatestacker/stackable/entity/EntityStack.java @@ -63,16 +63,19 @@ public class EntityStack extends ColdEntityStack { 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); - for (int i = 0; i < createDuplicates; i++) { - StackedEntity entity = addEntityToStackSilently(getStackedEntity(hostEntity, true)); - if (entity != null) - stackedEntities.add(entity); + createDuplicates = 0; + updateNametag(); + } catch (Exception ignored) { + //Ignored for now } - plugin.getDataManager().createStackedEntities(this, stackedEntities); - - createDuplicates = 0; - updateNametag(); } }); updateNametag(); From 86a14a5407d63bac5dce1f508484e300b6f8612b Mon Sep 17 00:00:00 2001 From: ceze88 Date: Wed, 25 Jan 2023 17:13:15 +0100 Subject: [PATCH 10/10] Release v2.3.3 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 1ad2759..88adc75 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ com.songoda UltimateStacker 4.0.0 - 2.3.3-Dev + 2.3.3 clean install UltimateStacker-${project.version} @@ -122,7 +122,7 @@ com.songoda SongodaCore - 2.6.18-Dev + 2.6.18 compile