diff --git a/pom.xml b/pom.xml
index f3fbd8d..9188505 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,7 +2,7 @@
com.songoda
UltimateStacker
4.0.0
- 2.0.10
+ 2.1
clean install
UltimateStacker-${project.version}
@@ -160,5 +160,10 @@
sqlite-jdbc
3.23.1
+
+ io.lumine
+ MythicMobs
+ 4.10.1
+
diff --git a/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java b/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java
index 85c9263..f94a782 100644
--- a/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java
+++ b/src/main/java/com/songoda/ultimatestacker/UltimateStacker.java
@@ -40,6 +40,7 @@ import com.songoda.ultimatestacker.stackable.block.BlockStack;
import com.songoda.ultimatestacker.stackable.block.BlockStackManager;
import com.songoda.ultimatestacker.stackable.entity.EntityStack;
import com.songoda.ultimatestacker.stackable.entity.EntityStackManager;
+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;
@@ -77,6 +78,7 @@ public class UltimateStacker extends SongodaPlugin {
private BlockStackManager blockStackManager;
private LootablesManager lootablesManager;
private CommandManager commandManager;
+ private CustomEntityManager customEntityManager;
private StackingTask stackingTask;
private DatabaseConnector databaseConnector;
@@ -161,6 +163,7 @@ public class UltimateStacker extends SongodaPlugin {
this.spawnerStackManager = new SpawnerStackManager();
this.entityStackManager = new EntityStackManager(this);
this.blockStackManager = new BlockStackManager();
+ this.customEntityManager = new CustomEntityManager();
guiManager.init();
PluginManager pluginManager = Bukkit.getPluginManager();
@@ -343,6 +346,9 @@ public class UltimateStacker extends SongodaPlugin {
return blockStackManager;
}
+ public CustomEntityManager getCustomEntityManager() {
+ return customEntityManager;
+ }
public void updateHologram(Hologramable stack) {
// Is this stack invalid?
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 0d9ea95..1fbcebe 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(255) NOT NULL" +
+ "serialized_entity VARBINARY(999) NOT NULL" +
")");
}
}
diff --git a/src/main/java/com/songoda/ultimatestacker/settings/Settings.java b/src/main/java/com/songoda/ultimatestacker/settings/Settings.java
index 6b1744f..f6e8bee 100644
--- a/src/main/java/com/songoda/ultimatestacker/settings/Settings.java
+++ b/src/main/java/com/songoda/ultimatestacker/settings/Settings.java
@@ -152,6 +152,15 @@ public class Settings {
public static final ConfigSetting SHEAR_IN_ONE_CLICK = new ConfigSetting(config, "Entities.Shear In One Click", false,
"Should entities be sheared in a single click?");
+ public static final ConfigSetting ENABLED_CUSTOM_ENTITY_PLUGINS = new ConfigSetting(config, "Entities.Enabled Custom Entity Plugins", Collections.singletonList("MythicMobs"),
+ "Which custom entity plugins should be used?",
+ "Remove a plugin from this list to disable the stacking of their entities.");
+
+ public static final ConfigSetting BLACKLISTED_CUSTOM_ENTITIES = new ConfigSetting(config, "Entities.Blacklisted Custom Entities", Collections.singletonList("mythicmobs_test"),
+ "Which custom entities should not be stacked?",
+ "List the entities using their plugin name as a prefix in all lowercase.",
+ "Example: mythicmobs_test");
+
public static final ConfigSetting STACK_ITEMS = new ConfigSetting(config, "Items.Enabled", true,
"Should items be stacked?");
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 ea35108..b3614c5 100644
--- a/src/main/java/com/songoda/ultimatestacker/stackable/entity/ColdEntityStack.java
+++ b/src/main/java/com/songoda/ultimatestacker/stackable/entity/ColdEntityStack.java
@@ -3,6 +3,7 @@ package com.songoda.ultimatestacker.stackable.entity;
import com.songoda.core.nms.NmsManager;
import com.songoda.core.nms.nbt.NBTEntity;
import com.songoda.ultimatestacker.UltimateStacker;
+import com.songoda.ultimatestacker.stackable.entity.custom.CustomEntity;
import com.songoda.ultimatestacker.utils.Stackable;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
@@ -71,7 +72,7 @@ public class ColdEntityStack implements Stackable {
public List takeEntities(int amount) {
List entities = new LinkedList<>();
- for (int i = 0; i < amount; i ++) {
+ for (int i = 0; i < amount; i++) {
StackedEntity entity = stackedEntities.pollFirst();
if (entity != null)
entities.add(entity);
@@ -90,7 +91,18 @@ public class ColdEntityStack implements Stackable {
if (stackedEntities.isEmpty()) return null;
NBTEntity nbtEntity = NmsManager.getNbt().newEntity();
nbtEntity.deSerialize(stackedEntities.getFirst().getSerializedEntity());
- LivingEntity newEntity = (LivingEntity)nbtEntity.spawn(location);
+
+ for (CustomEntity customEntity : plugin.getCustomEntityManager().getRegisteredCustomEntities()) {
+ String identifier = customEntity.getPluginName() + "_UltimateStacker";
+ if (!nbtEntity.has(identifier)) continue;
+ LivingEntity entity = customEntity.spawnFromIdentifier(nbtEntity.getString(identifier), location);
+ if (entity == null) continue;
+ stackedEntities.removeFirst();
+ plugin.getDataManager().deleteStackedEntity(entity.getUniqueId());
+ return entity;
+ }
+
+ LivingEntity newEntity = (LivingEntity) nbtEntity.spawn(location);
stackedEntities.removeFirst();
plugin.getDataManager().deleteStackedEntity(newEntity.getUniqueId());
@@ -126,6 +138,9 @@ public class ColdEntityStack implements Stackable {
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"));
}
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
new file mode 100644
index 0000000..0c0956a
--- /dev/null
+++ b/src/main/java/com/songoda/ultimatestacker/stackable/entity/custom/CustomEntity.java
@@ -0,0 +1,27 @@
+package com.songoda.ultimatestacker.stackable.entity.custom;
+
+import org.bukkit.Location;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.LivingEntity;
+import org.bukkit.plugin.Plugin;
+
+public abstract class CustomEntity {
+
+ protected final Plugin plugin;
+
+ protected CustomEntity(Plugin plugin) {
+ this.plugin = plugin;
+ }
+
+ public abstract String getPluginName();
+
+ public abstract boolean isMatchingType(Entity entity);
+
+ public abstract String getDisplayName(Entity entity);
+
+ public abstract boolean isSimilar(LivingEntity original, LivingEntity entity);
+
+ public abstract String getNBTIdentifier(Entity entity);
+
+ public abstract LivingEntity spawnFromIdentifier(String string, Location location);
+}
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
new file mode 100644
index 0000000..ca08a97
--- /dev/null
+++ b/src/main/java/com/songoda/ultimatestacker/stackable/entity/custom/CustomEntityManager.java
@@ -0,0 +1,45 @@
+package com.songoda.ultimatestacker.stackable.entity.custom;
+
+import com.songoda.ultimatestacker.settings.Settings;
+import com.songoda.ultimatestacker.stackable.entity.custom.entities.MythicMobsCustomEntity;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Entity;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class CustomEntityManager {
+
+ public CustomEntityManager() {
+ load();
+ }
+
+ private final List registeredCustomEntities = new ArrayList<>();
+
+ public void load() {
+ if (isEnabled("MythicMobs"))
+ registeredCustomEntities.add(new MythicMobsCustomEntity());
+ }
+
+ public boolean isEnabled(String plugin) {
+ return Bukkit.getPluginManager().isPluginEnabled(plugin)
+ && Settings.ENABLED_CUSTOM_ENTITY_PLUGINS.getStringList().contains(plugin);
+ }
+
+ public CustomEntity getCustomEntity(Entity entity) {
+ for (CustomEntity customEntity : registeredCustomEntities) {
+ if (customEntity.isMatchingType(entity)) {
+ if (Settings.BLACKLISTED_CUSTOM_ENTITIES.getStringList()
+ .contains((customEntity.getPluginName() + "_" + customEntity.getNBTIdentifier(entity)).toLowerCase()))
+ continue;
+ return customEntity;
+ }
+ }
+ return null;
+ }
+
+ public List getRegisteredCustomEntities() {
+ return Collections.unmodifiableList(registeredCustomEntities);
+ }
+}
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
new file mode 100644
index 0000000..8783347
--- /dev/null
+++ b/src/main/java/com/songoda/ultimatestacker/stackable/entity/custom/entities/MythicMobsCustomEntity.java
@@ -0,0 +1,59 @@
+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 org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.LivingEntity;
+
+public class MythicMobsCustomEntity extends CustomEntity {
+
+ public MythicMobsCustomEntity() {
+ super(Bukkit.getPluginManager().getPlugin("MythicMobs"));
+ }
+
+ @Override
+ public String getPluginName() {
+ return "MythicMobs";
+ }
+
+ @Override
+ public boolean isMatchingType(Entity entity) {
+ return getMobManager().isActiveMob(entity.getUniqueId());
+ }
+
+ @Override
+ public String getDisplayName(Entity entity) {
+ return getMobManager().getMythicMobInstance(entity).getType().getDisplayName().toString();
+ }
+
+ @Override
+ public boolean isSimilar(LivingEntity original, LivingEntity entity) {
+ if (!isMatchingType(original) || !isMatchingType(entity)) return false;
+ return getMob(original).getType().equals(getMob(entity).getType());
+ }
+
+ @Override
+ public String getNBTIdentifier(Entity entity) {
+ return getMob(entity).getType().getInternalName();
+ }
+
+ @Override
+ public LivingEntity spawnFromIdentifier(String string, Location location) {
+ if (getMobManager().getMobTypes().stream().map(MythicMob::getInternalName).noneMatch(t -> t.equals(string)))
+ return null;
+ return (LivingEntity)getMobManager().spawnMob(string, location).getEntity().getBukkitEntity();
+ }
+
+ private ActiveMob getMob(Entity entity) {
+ return getMobManager().getMythicMobInstance(entity);
+ }
+
+ private MobManager getMobManager() {
+ return ((MythicMobs) 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 dfcd3c5..60e1878 100644
--- a/src/main/java/com/songoda/ultimatestacker/tasks/StackingTask.java
+++ b/src/main/java/com/songoda/ultimatestacker/tasks/StackingTask.java
@@ -9,6 +9,7 @@ import com.songoda.ultimatestacker.stackable.entity.Check;
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.CachedChunk;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@@ -167,8 +168,9 @@ public class StackingTask extends BukkitRunnable {
// Attempt to split our stack. If the split is successful then skip this entity.
if (isStack && attemptSplit(stack, livingEntity)) return;
- // If this entity is named or disabled then skip it.
- if (!isStack && livingEntity.getCustomName() != null
+ // If this entity is named, a custom entity or disabled then skip it.
+ if (!isStack && (livingEntity.getCustomName() != null
+ && plugin.getCustomEntityManager().getCustomEntity(livingEntity) == null)
|| !configurationSection.getBoolean("Mobs." + livingEntity.getType().name() + ".Enabled"))
return;
@@ -286,7 +288,8 @@ public class StackingTask extends BukkitRunnable {
&& !this.processed.contains(entity.getUniqueId())).limit(maxEntityStackSize).forEach(entity -> {
// Make sure we're not naming some poor kids pet.
- if (entity.getCustomName() != null) {
+ if (entity.getCustomName() != null
+ && plugin.getCustomEntityManager().getCustomEntity(entity) == null) {
processed.add(livingEntity.getUniqueId());
newStack.destroy();
return;
@@ -405,6 +408,10 @@ public class StackingTask extends BukkitRunnable {
entityList.add(entity);
}
+ CustomEntity customEntity = plugin.getCustomEntityManager().getCustomEntity(initialEntity);
+ if (customEntity != null)
+ entityList.removeIf(entity -> !customEntity.isSimilar(initialEntity, entity));
+
if (stackFlyingDown && canFly(initialEntity))
entityList.removeIf(entity -> entity.getLocation().getY() > initialEntity.getLocation().getY());
diff --git a/src/main/java/com/songoda/ultimatestacker/utils/Methods.java b/src/main/java/com/songoda/ultimatestacker/utils/Methods.java
index 8956f34..cbba1d8 100644
--- a/src/main/java/com/songoda/ultimatestacker/utils/Methods.java
+++ b/src/main/java/com/songoda/ultimatestacker/utils/Methods.java
@@ -6,6 +6,8 @@ import com.songoda.core.nms.nbt.NBTItem;
import com.songoda.core.utils.TextUtils;
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.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
@@ -125,6 +127,10 @@ public class Methods {
String nameFormat = Settings.NAME_FORMAT_ENTITY.getString();
String displayName = Methods.formatText(UltimateStacker.getInstance().getMobFile().getString("Mobs." + entity.getType().name() + ".Display Name"));
+ CustomEntity customEntity = UltimateStacker.getInstance().getCustomEntityManager().getCustomEntity(entity);
+ if (customEntity != null)
+ displayName = customEntity.getDisplayName(entity);
+
nameFormat = nameFormat.replace("{TYPE}", displayName);
nameFormat = nameFormat.replace("{AMT}", Integer.toString(amount));
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
index a44770a..d1119b1 100644
--- a/src/main/resources/plugin.yml
+++ b/src/main/resources/plugin.yml
@@ -1,7 +1,7 @@
name: UltimateStacker
description: UltimateStacker
version: maven-version-number
-softdepend: [HolographicDisplays, Holograms, CMI, WorldGuard, EpicSpawners, mcMMO, WildStacker, StackMob]
+softdepend: [MythicMobs, HolographicDisplays, Holograms, CMI, WorldGuard, EpicSpawners, mcMMO, WildStacker, StackMob]
loadbefore: [WorldGuard]
main: com.songoda.ultimatestacker.UltimateStacker
author: songoda