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