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));