From a69c8ad0c3fce169918d92fdf3c1cb233765c5fc Mon Sep 17 00:00:00 2001 From: ceze88 Date: Mon, 2 Jan 2023 13:38:58 +0100 Subject: [PATCH] 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(); + } +}