mirror of
https://github.com/songoda/UltimateStacker.git
synced 2024-11-27 04:25:21 +01:00
Rewrite mob stacking, performance improvements
This commit is contained in:
parent
4e4fda611c
commit
71baf3a7e8
@ -26,8 +26,7 @@ import com.songoda.ultimatestacker.database.DataManager;
|
||||
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.database.migrations._6_RemoveStackedEntityTable;
|
||||
import com.songoda.ultimatestacker.hook.StackerHook;
|
||||
import com.songoda.ultimatestacker.hook.hooks.JobsHook;
|
||||
import com.songoda.ultimatestacker.listeners.*;
|
||||
@ -49,6 +48,7 @@ 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 io.lumine.mythic.bukkit.listeners.ChunkListeners;
|
||||
import org.apache.commons.lang.WordUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
@ -106,7 +106,7 @@ public class UltimateStacker extends SongodaPlugin {
|
||||
|
||||
@Override
|
||||
public void onPluginDisable() {
|
||||
this.stackingTask.cancel();
|
||||
this.stackingTask.stop();
|
||||
this.stackingTask = null;
|
||||
this.dataManager.bulkUpdateSpawners(this.spawnerStackManager.getStacks());
|
||||
HologramManager.removeAllHolograms();
|
||||
@ -235,8 +235,7 @@ public class UltimateStacker extends SongodaPlugin {
|
||||
new _1_InitialMigration(),
|
||||
new _2_EntityStacks(),
|
||||
new _3_BlockStacks(),
|
||||
new _4_DataPurge(),
|
||||
new _5_StackedEntitiesTableUpdate());
|
||||
new _6_RemoveStackedEntityTable());
|
||||
this.dataMigrationManager.runMigrations();
|
||||
}
|
||||
|
||||
@ -260,12 +259,8 @@ public class UltimateStacker extends SongodaPlugin {
|
||||
}
|
||||
}
|
||||
});
|
||||
this.dataManager.getEntities((entities) -> {
|
||||
entityStackManager.addStacks(entities.values());
|
||||
entityStackManager.tryAndLoadColdEntities();
|
||||
this.stackingTask = new StackingTask(this);
|
||||
getServer().getPluginManager().registerEvents(new ChunkListeners(entityStackManager), this);
|
||||
});
|
||||
|
||||
this.stackingTask = new StackingTask(this);
|
||||
final boolean useBlockHolo = Settings.BLOCK_HOLOGRAMS.getBoolean();
|
||||
this.dataManager.getBlocks((blocks) -> {
|
||||
this.blockStackManager.addBlocks(blocks);
|
||||
@ -302,7 +297,7 @@ public class UltimateStacker extends SongodaPlugin {
|
||||
this.setLocale(getConfig().getString("System.Language Mode"), true);
|
||||
this.locale.reloadMessages();
|
||||
|
||||
this.stackingTask.cancel();
|
||||
this.stackingTask.stop();
|
||||
this.stackingTask = new StackingTask(this);
|
||||
|
||||
this.mobFile.load();
|
||||
|
@ -46,10 +46,9 @@ public class CommandRemoveAll extends AbstractCommand {
|
||||
for (Entity entityO : world.getEntities()) {
|
||||
if (entityO instanceof Player) continue;
|
||||
|
||||
if (entityO instanceof LivingEntity && (stackManager.isStackedAndLoaded((LivingEntity)entityO) || all)
|
||||
if (entityO instanceof LivingEntity && (stackManager.isStackedEntity(entityO) || all)
|
||||
&& type.equalsIgnoreCase("entities")) {
|
||||
entityO.remove();
|
||||
plugin.getEntityStackManager().removeStack(entityO);
|
||||
plugin.getEntityStackManager().getStack((LivingEntity) entityO).destroy();
|
||||
amountRemoved++;
|
||||
} else if (entityO.getType() == EntityType.DROPPED_ITEM && type.equalsIgnoreCase("items")) {
|
||||
if (!UltimateStacker.hasCustomAmount((Item)entityO) && !all)
|
||||
|
@ -56,9 +56,7 @@ public class CommandSpawn extends AbstractCommand {
|
||||
sender.sendMessage(TextUtils.formatText("&6" + list));
|
||||
} else {
|
||||
LivingEntity entity = (LivingEntity)player.getWorld().spawnEntity(player.getLocation(), type);
|
||||
EntityStack stack = plugin.getEntityStackManager().addStack(entity);
|
||||
stack.createDuplicates(((Methods.isInt(args[1])) ? Integer.parseInt(args[1]) : 1) - 1);
|
||||
stack.updateStack();
|
||||
EntityStack stack = plugin.getEntityStackManager().createStack(entity, Integer.parseInt(args[1]));
|
||||
plugin.getStackingTask().attemptSplit(stack, entity);
|
||||
}
|
||||
|
||||
|
@ -36,14 +36,6 @@ public class StackMobConvert implements Convert {
|
||||
|
||||
@Override
|
||||
public void convertEntities() {
|
||||
EntityStackManager entityStackManager = plugin.getEntityStackManager();
|
||||
for (Map.Entry<UUID, Integer> entry : stackMob.getStorageManager().getAmountCache().entrySet()) {
|
||||
if (!entityStackManager.isStackedAndLoaded(entry.getKey())) {
|
||||
entityStackManager.addLegacyColdStack(entry.getKey(), entry.getValue());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -43,23 +43,6 @@ public class WildStackerConvert implements Convert {
|
||||
|
||||
@Override
|
||||
public void convertEntities() {
|
||||
EntityStackManager entityStackManager = plugin.getEntityStackManager();
|
||||
|
||||
DatabaseConnector connector = new SQLiteConnector(this.wildStacker);
|
||||
connector.connect(connection -> {
|
||||
|
||||
try (Statement statement = connection.createStatement()) {
|
||||
ResultSet result = statement.executeQuery("SELECT uuid, stackAmount FROM entities");
|
||||
while (result.next()) {
|
||||
UUID uuid = UUID.fromString(result.getString("uuid"));
|
||||
int amount = result.getInt("stackAmount");
|
||||
if (!entityStackManager.isEntityInColdStorage(uuid))
|
||||
entityStackManager.addLegacyColdStack(uuid, amount);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -6,7 +6,6 @@ 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;
|
||||
import com.songoda.ultimatestacker.stackable.entity.EntityStack;
|
||||
import com.songoda.ultimatestacker.stackable.entity.StackedEntity;
|
||||
import com.songoda.ultimatestacker.stackable.spawner.SpawnerStack;
|
||||
@ -122,130 +121,6 @@ public class DataManager extends DataManagerAbstract {
|
||||
});
|
||||
}
|
||||
|
||||
public void createHostEntity(ColdEntityStack stack) {
|
||||
this.runAsync(() -> {
|
||||
try (Connection connection = this.databaseConnector.getConnection()) {
|
||||
String createSerializedEntity = "INSERT " + getSyntax("INTO ", DatabaseType.MYSQL) + getSyntax("OR REPLACE INTO ", 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());
|
||||
statement.setInt(2, stack.getCreateDuplicates());
|
||||
statement.executeUpdate();
|
||||
int stackId = this.lastInsertedId(connection, "host_entities");
|
||||
this.sync(() -> stack.setId(stackId));
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void createStackedEntity(EntityStack hostStack, StackedEntity stackedEntity) {
|
||||
this.runAsync(() -> {
|
||||
try (Connection connection = this.databaseConnector.getConnection()){
|
||||
String createSerializedEntity = "INSERT " + getSyntax("INTO ", DatabaseType.MYSQL) + getSyntax("OR REPLACE INTO ", 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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void createStackedEntities(ColdEntityStack hostStack, List<StackedEntity> stackedEntities) {
|
||||
this.runAsync(() -> {
|
||||
try (Connection connection = this.databaseConnector.getConnection()) {
|
||||
String createSerializedEntity = "REPLACE INTO " + this.getTablePrefix() + "stacked_entities (uuid, host, serialized_entity) VALUES (?, ?, ?)";
|
||||
PreparedStatement statement = connection.prepareStatement(createSerializedEntity);
|
||||
if (hostStack.getHostUniqueId() == null) return;
|
||||
for (StackedEntity entity : stackedEntities) {
|
||||
statement.setString(1, entity.getUniqueId().toString());
|
||||
statement.setInt(2, hostStack.getId());
|
||||
statement.setBytes(3, entity.getSerializedEntity());
|
||||
statement.addBatch();
|
||||
}
|
||||
statement.executeBatch();
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void updateHost(ColdEntityStack hostStack) {
|
||||
this.runAsync(() -> {
|
||||
try (Connection connection = this.databaseConnector.getConnection()) {
|
||||
String updateHost = "UPDATE " + this.getTablePrefix() + "host_entities SET uuid = ?, create_duplicates = ?, updated_at = current_timestamp WHERE id = ?";
|
||||
PreparedStatement statement = connection.prepareStatement(updateHost);
|
||||
if (hostStack.getHostUniqueId() == null) return;
|
||||
statement.setString(1, hostStack.getHostUniqueId().toString());
|
||||
statement.setInt(2, hostStack.getCreateDuplicates());
|
||||
statement.setInt(3, hostStack.getId());
|
||||
statement.executeUpdate();
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void deleteHost(ColdEntityStack stack) {
|
||||
this.runAsync(() -> {
|
||||
try (Connection connection = this.databaseConnector.getConnection()) {
|
||||
String deleteHost = "DELETE FROM " + this.getTablePrefix() + "host_entities WHERE id = ?";
|
||||
try (PreparedStatement statement = connection.prepareStatement(deleteHost)) {
|
||||
statement.setInt(1, stack.getId());
|
||||
statement.executeUpdate();
|
||||
}
|
||||
|
||||
String deleteStackedEntities = "DELETE FROM " + this.getTablePrefix() + "stacked_entities WHERE host = ?";
|
||||
try (PreparedStatement statement = connection.prepareStatement(deleteStackedEntities)) {
|
||||
statement.setInt(1, stack.getId());
|
||||
statement.executeUpdate();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void deleteStackedEntity(UUID uuid) {
|
||||
if (uuid == null)
|
||||
return;
|
||||
|
||||
this.runAsync(() -> {
|
||||
try (Connection connection = this.databaseConnector.getConnection()) {
|
||||
String deleteStackedEntity = "DELETE FROM " + this.getTablePrefix() + "stacked_entities WHERE uuid = ?";
|
||||
PreparedStatement statement = connection.prepareStatement(deleteStackedEntity);
|
||||
statement.setString(1, uuid.toString());
|
||||
statement.executeUpdate();
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void deleteStackedEntities(List<StackedEntity> entities) {
|
||||
this.runAsync(() -> {
|
||||
try (Connection connection = this.databaseConnector.getConnection()) {
|
||||
String deleteStackedEntities = "DELETE FROM " + this.getTablePrefix() + "stacked_entities WHERE uuid = ?";
|
||||
PreparedStatement statement = connection.prepareStatement(deleteStackedEntities);
|
||||
for (StackedEntity entity : entities) {
|
||||
if (entity == null) continue;
|
||||
statement.setString(1, entity.getUniqueId().toString());
|
||||
statement.addBatch();
|
||||
}
|
||||
statement.executeBatch();
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void deleteSpawner(SpawnerStack spawnerStack) {
|
||||
this.runAsync(() -> {
|
||||
try (Connection connection = this.databaseConnector.getConnection()) {
|
||||
@ -272,76 +147,6 @@ public class DataManager extends DataManagerAbstract {
|
||||
});
|
||||
}
|
||||
|
||||
public void getEntities(Consumer<Map<Integer, ColdEntityStack>> callback) {
|
||||
this.runAsync(() -> {
|
||||
try (Connection connection = this.databaseConnector.getConnection()) {
|
||||
|
||||
Map<Integer, ColdEntityStack> entities = new HashMap<>();
|
||||
|
||||
boolean mysql = Settings.MYSQL_ENABLED.getBoolean();
|
||||
int databasePurge = Settings.DATABASE_PURGE.getInt();
|
||||
String whereStatement = mysql ? "WHERE updated_at < NOW() - INTERVAL " + databasePurge + " DAY" : "WHERE updated_at <= date('now','-" + databasePurge + " day')";
|
||||
String selectOldEntities = "SELECT * FROM " + this.getTablePrefix() + "host_entities " + whereStatement;
|
||||
|
||||
try (Statement statement = connection.createStatement()) {
|
||||
List<String> toDelete = new ArrayList<>();
|
||||
|
||||
ResultSet result = statement.executeQuery(selectOldEntities);
|
||||
while (result.next()) {
|
||||
int hostId = result.getInt("id");
|
||||
toDelete.add(String.valueOf(hostId));
|
||||
}
|
||||
|
||||
if (!toDelete.isEmpty()) {
|
||||
statement.execute("DELETE FROM " + this.getTablePrefix() + "host_entities " + whereStatement);
|
||||
statement.execute("DELETE FROM " + this.getTablePrefix() + "stacked_entities WHERE host IN (" + String.join(", ", toDelete) + ")");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
String selectEntities = "SELECT * FROM " + this.getTablePrefix() + "host_entities";
|
||||
try (Statement statement = connection.createStatement()) {
|
||||
ResultSet result = statement.executeQuery(selectEntities);
|
||||
while (result.next()) {
|
||||
int hostId = result.getInt("id");
|
||||
|
||||
UUID host = UUID.fromString(result.getString("uuid"));
|
||||
|
||||
int createDuplicates = result.getInt("create_duplicates");
|
||||
|
||||
ColdEntityStack stack = new ColdEntityStack(host, hostId);
|
||||
stack.createDuplicates(createDuplicates);
|
||||
entities.put(hostId, stack);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
String selectStackedEntities = "SELECT * FROM " + this.getTablePrefix() + "stacked_entities";
|
||||
try (Statement statement = connection.createStatement()) {
|
||||
ResultSet result = statement.executeQuery(selectStackedEntities);
|
||||
while (result.next()) {
|
||||
UUID uuid = UUID.fromString(result.getString("uuid"));
|
||||
int hostId = result.getInt("host");
|
||||
byte[] serializedEntity = result.getBytes("serialized_entity");
|
||||
|
||||
ColdEntityStack stack = entities.get(hostId);
|
||||
if (stack == null) continue;
|
||||
stack.addEntityToStackSilently(new StackedEntity(uuid, serializedEntity));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
this.sync(() -> callback.accept(entities));
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void getSpawners(Consumer<Map<Location, SpawnerStack>> callback) {
|
||||
this.runAsync(() -> {
|
||||
try (Connection connection = this.databaseConnector.getConnection()){
|
||||
|
@ -26,14 +26,5 @@ public class _2_EntityStacks extends DataMigration {
|
||||
"create_duplicates INTEGER NOT NULL DEFAULT 0" +
|
||||
")");
|
||||
}
|
||||
|
||||
// Create stacked entities table
|
||||
try (Statement statement = connection.createStatement()) {
|
||||
statement.execute("CREATE TABLE IF NOT EXISTS " + tablePrefix + "stacked_entities (" +
|
||||
"uuid VARCHAR(36) PRIMARY KEY NOT NULL," +
|
||||
"host INTEGER NOT NULL," +
|
||||
"serialized_entity VARBINARY(9999) NOT NULL" +
|
||||
")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,24 +0,0 @@
|
||||
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)");
|
||||
} catch (SQLException e) {
|
||||
// Ignore
|
||||
//TODO fix it for sqlite
|
||||
}
|
||||
}
|
||||
}
|
@ -1,25 +1,23 @@
|
||||
package com.songoda.ultimatestacker.database.migrations;
|
||||
|
||||
import com.songoda.core.database.DataMigration;
|
||||
import com.songoda.core.database.MySQLConnector;
|
||||
import com.songoda.ultimatestacker.UltimateStacker;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
|
||||
public class _4_DataPurge extends DataMigration {
|
||||
public class _6_RemoveStackedEntityTable extends DataMigration {
|
||||
|
||||
public _4_DataPurge() {
|
||||
super(4);
|
||||
public _6_RemoveStackedEntityTable() {
|
||||
super(6);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void migrate(Connection connection, String tablePrefix) throws SQLException {
|
||||
public void migrate(Connection connection, String tablePrefix) {
|
||||
try (Statement statement = connection.createStatement()) {
|
||||
statement.execute("ALTER TABLE " + tablePrefix + "host_entities ADD COLUMN updated_at datetime DEFAULT NULL");
|
||||
statement.execute("DROP TABLE " + tablePrefix + "stacked_entities");
|
||||
} catch (SQLException e) {
|
||||
// Ignore
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
@ -55,7 +55,7 @@ public class GUIConvertWhat extends Gui {
|
||||
private void run(Player player) {
|
||||
if (entities) {
|
||||
convertFrom.convertEntities();
|
||||
UltimateStacker.getInstance().getEntityStackManager().tryAndLoadColdEntities();
|
||||
//UltimateStacker.getInstance().getEntityStackManager().tryAndLoadColdEntities();
|
||||
}
|
||||
if (spawners) {
|
||||
convertFrom.convertSpawners();
|
||||
|
@ -1,41 +0,0 @@
|
||||
package com.songoda.ultimatestacker.listeners;
|
||||
|
||||
import com.songoda.ultimatestacker.stackable.entity.EntityStackManager;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.world.ChunkLoadEvent;
|
||||
import org.bukkit.event.world.ChunkUnloadEvent;
|
||||
|
||||
public class ChunkListeners implements Listener {
|
||||
|
||||
private final EntityStackManager entityStackManager;
|
||||
|
||||
public ChunkListeners(EntityStackManager entityStackManager) {
|
||||
this.entityStackManager = entityStackManager;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onChunkLoad(ChunkLoadEvent event) {
|
||||
Chunk chunk = event.getChunk();
|
||||
for (Entity entity : chunk.getEntities()) {
|
||||
if (!(entity instanceof LivingEntity)) continue;
|
||||
if (entityStackManager.isEntityInColdStorage((LivingEntity) entity)) {
|
||||
entityStackManager.loadStack((LivingEntity) entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onChunkUnload(ChunkUnloadEvent event) {
|
||||
Chunk chunk = event.getChunk();
|
||||
for (Entity entity : chunk.getEntities()) {
|
||||
if (!(entity instanceof LivingEntity)) continue;
|
||||
if (entityStackManager.isStackedAndLoaded((LivingEntity) entity)) {
|
||||
entityStackManager.unloadStack((LivingEntity) entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -18,8 +18,8 @@ public class ClearLagListeners implements Listener {
|
||||
@EventHandler
|
||||
public void onClearLaggTask(EntityRemoveEvent event) {
|
||||
for (Entity entity : event.getWorld().getEntities()) {
|
||||
if (entity instanceof LivingEntity && plugin.getEntityStackManager().isStackedAndLoaded((LivingEntity)entity)) {
|
||||
plugin.getEntityStackManager().removeStack(entity);
|
||||
if (entity instanceof LivingEntity && plugin.getEntityStackManager().isStackedEntity(entity)) {
|
||||
plugin.getEntityStackManager().getStack((LivingEntity) entity).destroy();
|
||||
event.addEntity(entity);
|
||||
}
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ public class DeathListeners implements Listener {
|
||||
drops.clear();
|
||||
|
||||
if (plugin.getCustomEntityManager().getCustomEntity(entity) == null) {
|
||||
if (plugin.getEntityStackManager().isStackedAndLoaded(event.getEntity())) {
|
||||
if (plugin.getEntityStackManager().isStackedEntity(event.getEntity())) {
|
||||
plugin.getEntityStackManager().getStack(event.getEntity()).onDeath(entity, drops, custom, event.getDroppedExp(), event);
|
||||
} else {
|
||||
DropUtils.processStackedDrop(event.getEntity(), drops, event);
|
||||
@ -157,7 +157,7 @@ public class DeathListeners implements Listener {
|
||||
|
||||
if (!(event.getEntity() instanceof LivingEntity)) return;
|
||||
LivingEntity entity = (LivingEntity) event.getEntity();
|
||||
if (!plugin.getEntityStackManager().isStackedAndLoaded(entity)) return;
|
||||
if (!plugin.getEntityStackManager().isStackedEntity(entity)) return;
|
||||
EntityStack stack = plugin.getEntityStackManager().getStack(entity);
|
||||
|
||||
Player player = (Player) event.getDamager();
|
||||
|
@ -38,7 +38,7 @@ public class InteractListeners implements Listener {
|
||||
|
||||
ItemStack item = player.getInventory().getItemInHand();
|
||||
|
||||
if (!plugin.getEntityStackManager().isStackedAndLoaded(entity)) return;
|
||||
if (!plugin.getEntityStackManager().isStackedEntity(entity)) return;
|
||||
|
||||
if (item.getType() != Material.NAME_TAG && !correctFood(item, entity)) return;
|
||||
|
||||
|
@ -38,7 +38,7 @@ public class ShearListeners implements Listener {
|
||||
&& entity.getType() != EntityType.MUSHROOM_COW
|
||||
&& entity.getType() != EntityType.SNOWMAN) return;
|
||||
EntityStackManager stackManager = plugin.getEntityStackManager();
|
||||
if (!stackManager.isStackedAndLoaded(entity)) return;
|
||||
if (!stackManager.isStackedEntity(entity)) return;
|
||||
|
||||
if (event.getEntity().getType() == EntityType.SHEEP
|
||||
&& Settings.SPLIT_CHECKS.getStringList().stream().noneMatch(line -> Split.valueOf(line) == Split.SHEEP_SHEAR)
|
||||
|
@ -24,7 +24,7 @@ public class SheepDyeListeners implements Listener {
|
||||
LivingEntity entity = event.getEntity();
|
||||
|
||||
EntityStackManager stackManager = plugin.getEntityStackManager();
|
||||
if (!stackManager.isStackedAndLoaded(entity)) return;
|
||||
if (!stackManager.isStackedEntity(entity)) return;
|
||||
|
||||
if (Settings.SPLIT_CHECKS.getStringList().stream().noneMatch(line -> Split.valueOf(line) == Split.SHEEP_DYE))
|
||||
return;
|
||||
|
@ -67,12 +67,16 @@ public class SpawnerListeners implements Listener {
|
||||
|
||||
SpawnerStack spawnerStack = spawnerStackManager.getSpawner(location);
|
||||
|
||||
spawnerStack.spawn(spawnerStack.calculateSpawnCount(), "EXPLOSION_NORMAL", null, (e) -> {
|
||||
int amountToSpawn = spawnerStack.calculateSpawnCount();
|
||||
|
||||
spawnerStack.spawn(amountToSpawn, "EXPLOSION_NORMAL", null, (e) -> {
|
||||
if (Settings.NO_AI.getBoolean())
|
||||
EntityUtils.setUnaware(e);
|
||||
|
||||
if (mcmmo)
|
||||
entity.setMetadata("mcMMO: Spawned Entity", new FixedMetadataValue(plugin, true));
|
||||
|
||||
UltimateStacker.getInstance().getEntityStackManager().setStack(e, amountToSpawn);
|
||||
return true;
|
||||
}, event.getEntityType());
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ public class TameListeners implements Listener {
|
||||
LivingEntity entity = event.getEntity();
|
||||
|
||||
EntityStackManager stackManager = plugin.getEntityStackManager();
|
||||
if (!stackManager.isStackedAndLoaded(entity)) return;
|
||||
if (!stackManager.isStackedEntity(entity)) return;
|
||||
|
||||
EntityStack stack = plugin.getEntityStackManager().getStack(entity);
|
||||
|
||||
|
@ -20,13 +20,11 @@ public class EntityCurrentListener implements Listener {
|
||||
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
|
||||
public void onSpawn(EntityTransformEvent event) {
|
||||
EntityStackManager stackManager = plugin.getEntityStackManager();
|
||||
if (stackManager.isStackedAndLoaded(event.getEntity().getUniqueId())
|
||||
if (stackManager.isStackedEntity(event.getEntity())
|
||||
&& event.getEntity() instanceof LivingEntity
|
||||
&& event.getTransformedEntity() instanceof LivingEntity) {
|
||||
EntityStack stack = stackManager.updateStack((LivingEntity) event.getEntity(),
|
||||
(LivingEntity) event.getTransformedEntity());
|
||||
EntityStack stack = stackManager.updateStack((LivingEntity) event.getEntity(), (LivingEntity) event.getTransformedEntity());
|
||||
stack.releaseHost();
|
||||
stack.updateStack();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ public class EntityListeners implements Listener {
|
||||
|
||||
EntityStackManager stackManager = plugin.getEntityStackManager();
|
||||
|
||||
if (!stackManager.isStackedAndLoaded(entity)) return;
|
||||
if (!stackManager.isStackedEntity(entity)) return;
|
||||
|
||||
EntityStack stack = stackManager.getStack(entity);
|
||||
|
||||
@ -78,7 +78,7 @@ public class EntityListeners implements Listener {
|
||||
|
||||
Entity entity = event.getEntity();
|
||||
|
||||
if (entity instanceof LivingEntity && plugin.getEntityStackManager().isStackedAndLoaded((LivingEntity) entity)
|
||||
if (entity instanceof LivingEntity && plugin.getEntityStackManager().isStackedEntity(entity)
|
||||
&& Settings.DISABLE_KNOCKBACK.getBoolean()
|
||||
&& ((Player) event.getDamager()).getItemInHand().getEnchantmentLevel(Enchantment.KNOCKBACK) == 0) {
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, () -> {
|
||||
|
@ -1,169 +0,0 @@
|
||||
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;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
|
||||
import java.util.Deque;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ColdEntityStack implements Stackable {
|
||||
|
||||
protected static final UltimateStacker plugin = UltimateStacker.getInstance();
|
||||
|
||||
// The id to identify this stack in the database.
|
||||
private int id;
|
||||
|
||||
// The unique id of the stacks host.
|
||||
protected UUID hostUniqueId;
|
||||
|
||||
// These are the entities below the host.
|
||||
protected final Deque<StackedEntity> stackedEntities = new ConcurrentLinkedDeque<>();
|
||||
|
||||
// The amount of duplicates of the host to create when loaded.
|
||||
protected int createDuplicates = 0;
|
||||
|
||||
public ColdEntityStack(UUID hostUniqueId, int id) {
|
||||
this.hostUniqueId = hostUniqueId;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public ColdEntityStack(UUID hostUniqueId) {
|
||||
this.hostUniqueId = hostUniqueId;
|
||||
}
|
||||
|
||||
public StackedEntity addEntityToStackSilently(Entity entity) {
|
||||
return addEntityToStackSilently(getStackedEntity(entity));
|
||||
}
|
||||
|
||||
public List<StackedEntity> addRawEntitiesToStackSilently(List<LivingEntity> unstackedEntities) {
|
||||
List<StackedEntity> stackedEntities = unstackedEntities.stream()
|
||||
.map(this::getStackedEntity).collect(Collectors.toList());
|
||||
addEntitiesToStackSilently(stackedEntities);
|
||||
return stackedEntities;
|
||||
}
|
||||
|
||||
public void addEntitiesToStackSilently(List<StackedEntity> stackedEntities) {
|
||||
stackedEntities.removeIf(Objects::isNull);
|
||||
this.stackedEntities.addAll(stackedEntities);
|
||||
}
|
||||
|
||||
public synchronized StackedEntity addEntityToStackSilently(StackedEntity stackedEntity) {
|
||||
if (stackedEntity == null) return null;
|
||||
stackedEntities.push(stackedEntity);
|
||||
return stackedEntity;
|
||||
}
|
||||
|
||||
public void moveEntitiesFromStack(EntityStack stack, int amount) {
|
||||
List<StackedEntity> stackedEntities = stack.takeEntities(amount);
|
||||
this.stackedEntities.addAll(stackedEntities);
|
||||
plugin.getDataManager().createStackedEntities(this, stackedEntities);
|
||||
}
|
||||
|
||||
public List<StackedEntity> takeEntities(int amount) {
|
||||
List<StackedEntity> entities = new LinkedList<>();
|
||||
for (int i = 0; i < amount; i++) {
|
||||
StackedEntity entity = stackedEntities.pollFirst();
|
||||
if (entity != null)
|
||||
entities.add(entity);
|
||||
}
|
||||
plugin.getDataManager().deleteStackedEntities(entities);
|
||||
return entities;
|
||||
}
|
||||
|
||||
public List<StackedEntity> takeAllEntities() {
|
||||
List<StackedEntity> entities = new LinkedList<>(stackedEntities);
|
||||
stackedEntities.clear();
|
||||
return entities;
|
||||
}
|
||||
|
||||
public LivingEntity takeOneAndSpawnEntity(Location location) {
|
||||
if (stackedEntities.isEmpty()) return null;
|
||||
NBTEntity nbtEntity = NmsManager.getNbt().newEntity();
|
||||
nbtEntity.deSerialize(stackedEntities.getFirst().getSerializedEntity());
|
||||
|
||||
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 = null;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
newEntity = (LivingEntity) nbtEntity.spawn(location);
|
||||
|
||||
if (newEntity != null) {
|
||||
stackedEntities.removeFirst();
|
||||
plugin.getDataManager().deleteStackedEntity(newEntity.getUniqueId());
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (newEntity == null)
|
||||
plugin.getDataManager().deleteStackedEntity(hostUniqueId);
|
||||
|
||||
return newEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAmount() {
|
||||
return stackedEntities.size() + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void createDuplicates(int duplicates) {
|
||||
this.createDuplicates = duplicates;
|
||||
}
|
||||
|
||||
public int getCreateDuplicates() {
|
||||
return createDuplicates;
|
||||
}
|
||||
|
||||
protected StackedEntity getStackedEntity(Entity entity) {
|
||||
return getStackedEntity(entity, false);
|
||||
}
|
||||
|
||||
protected synchronized StackedEntity getStackedEntity(Entity entity, boolean newUUID) {
|
||||
if (entity == null) return null;
|
||||
UUID uuid = entity.getUniqueId();
|
||||
NBTEntity nbtEntity = NmsManager.getNbt().of(entity);
|
||||
|
||||
CustomEntity customEntity = plugin.getCustomEntityManager().getCustomEntity(entity);
|
||||
if (customEntity != null)
|
||||
nbtEntity.set(customEntity.getPluginName() + "_UltimateStacker", customEntity.getNBTIdentifier(entity));
|
||||
return new StackedEntity(uuid, nbtEntity.serialize());
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public UUID getHostUniqueId() {
|
||||
return hostUniqueId;
|
||||
}
|
||||
|
||||
public void setHostUniqueId(UUID hostUniqueId) {
|
||||
this.hostUniqueId = hostUniqueId;
|
||||
}
|
||||
}
|
@ -3,9 +3,12 @@ package com.songoda.ultimatestacker.stackable.entity;
|
||||
import com.songoda.core.compatibility.ServerVersion;
|
||||
import com.songoda.core.lootables.loot.Drop;
|
||||
import com.songoda.core.lootables.loot.DropUtils;
|
||||
import com.songoda.core.nms.NmsManager;
|
||||
import com.songoda.core.nms.nbt.NBTEntity;
|
||||
import com.songoda.ultimatestacker.UltimateStacker;
|
||||
import com.songoda.ultimatestacker.events.EntityStackKillEvent;
|
||||
import com.songoda.ultimatestacker.settings.Settings;
|
||||
import com.songoda.ultimatestacker.stackable.entity.custom.CustomEntity;
|
||||
import com.songoda.ultimatestacker.utils.Async;
|
||||
import com.songoda.ultimatestacker.utils.Methods;
|
||||
import org.bukkit.Bukkit;
|
||||
@ -21,96 +24,42 @@ import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public class EntityStack extends ColdEntityStack {
|
||||
public class EntityStack extends StackedEntity {
|
||||
|
||||
// This is the host entity which is not stored in serialized nbt.
|
||||
private LivingEntity hostEntity;
|
||||
private static final UltimateStacker plugin = UltimateStacker.getInstance();
|
||||
|
||||
public EntityStack(LivingEntity hostEntity) {
|
||||
super(hostEntity.getUniqueId());
|
||||
this.hostEntity = hostEntity;
|
||||
super(hostEntity);
|
||||
}
|
||||
|
||||
public EntityStack(LivingEntity hostEntity, ColdEntityStack coldEntityStack) {
|
||||
this(hostEntity);
|
||||
this.setId(coldEntityStack.getId());
|
||||
this.stackedEntities.addAll(coldEntityStack.stackedEntities);
|
||||
public EntityStack(LivingEntity hostEntity, int amount) {
|
||||
super(hostEntity, amount);
|
||||
}
|
||||
|
||||
public StackedEntity addEntityToStack(Entity entity) {
|
||||
StackedEntity stackedEntity = addEntityToStackSilently(entity);
|
||||
updateStack();
|
||||
return stackedEntity;
|
||||
public synchronized EntityStack addEntityToStack(int amount) {
|
||||
setAmount(getAmount() + amount);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StackedEntity> takeEntities(int amount) {
|
||||
List<StackedEntity> entities = super.takeEntities(amount);
|
||||
if (this.stackedEntities.isEmpty())
|
||||
destroy(true);
|
||||
return entities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StackedEntity> takeAllEntities() {
|
||||
destroy(true);
|
||||
return super.takeAllEntities();
|
||||
}
|
||||
|
||||
public void updateStack() {
|
||||
Async.run(() -> {
|
||||
if (createDuplicates != 0) {
|
||||
List<StackedEntity> 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);
|
||||
|
||||
createDuplicates = 0;
|
||||
updateNametag();
|
||||
} catch (Exception ignored) {
|
||||
//Ignored for now
|
||||
}
|
||||
}
|
||||
});
|
||||
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 synchronized EntityStack removeEntityFromStack(int amount) {
|
||||
setAmount(getAmount() - amount);
|
||||
return this;
|
||||
}
|
||||
|
||||
public LivingEntity getHostEntity() {
|
||||
if (hostEntity == null) {
|
||||
plugin.getEntityStackManager().removeStack(this.hostUniqueId);
|
||||
return null;
|
||||
}
|
||||
return hostEntity;
|
||||
}
|
||||
|
||||
public StackedEntity getHostAsStackedEntity() {
|
||||
return getStackedEntity(hostEntity);
|
||||
}
|
||||
|
||||
protected void setHostEntity(LivingEntity hostEntity) {
|
||||
this.hostEntity = hostEntity;
|
||||
this.hostUniqueId = hostEntity.getUniqueId();
|
||||
}
|
||||
|
||||
private void handleWholeStackDeath(LivingEntity killed, List<Drop> drops, boolean custom, int droppedExp, EntityDeathEvent event) {
|
||||
plugin.getDataManager().deleteHost(this);
|
||||
|
||||
EntityStack stack = plugin.getEntityStackManager().getStack(killed);
|
||||
// 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();
|
||||
@ -133,7 +82,7 @@ public class EntityStack extends ColdEntityStack {
|
||||
}
|
||||
|
||||
event.getDrops().clear();
|
||||
plugin.getEntityStackManager().removeStack(event.getEntity());
|
||||
stack.destroy();
|
||||
if (killed.getKiller() == null) return;
|
||||
plugin.addExp(killed.getKiller(), this);
|
||||
}
|
||||
@ -162,12 +111,6 @@ public class EntityStack extends ColdEntityStack {
|
||||
|
||||
newEntity.setVelocity(velocity);
|
||||
stackManager.updateStack(killed, newEntity);
|
||||
|
||||
updateStack();
|
||||
|
||||
if (stackedEntities.isEmpty()) {
|
||||
destroy();
|
||||
}
|
||||
}
|
||||
|
||||
public void onDeath(LivingEntity killed, List<Drop> drops, boolean custom, int droppedExp, EntityDeathEvent event) {
|
||||
@ -195,42 +138,37 @@ public class EntityStack extends ColdEntityStack {
|
||||
}
|
||||
}
|
||||
|
||||
public LivingEntity takeOneAndSpawnEntity(Location location) {
|
||||
if (amount <= 0) return null;
|
||||
amount--;
|
||||
LivingEntity entity = Objects.requireNonNull(location.getWorld()).spawn(location, hostEntity.getClass());
|
||||
this.hostEntity = entity;
|
||||
updateNameTag();
|
||||
return entity;
|
||||
}
|
||||
|
||||
public void releaseHost() {
|
||||
LivingEntity oldHost = hostEntity;
|
||||
LivingEntity entity = takeOneAndSpawnEntity(hostEntity.getLocation());
|
||||
if (!stackedEntities.isEmpty()) {
|
||||
destroy(false);
|
||||
if (getAmount() >= 0) {
|
||||
plugin.getEntityStackManager().updateStack(oldHost, entity);
|
||||
entity.setVelocity(new Vector(ThreadLocalRandom.current().nextDouble(-1, 1.01),
|
||||
0, ThreadLocalRandom.current().nextDouble(-1, 1.01)).normalize().multiply(0.5));
|
||||
updateNameTag();
|
||||
} else {
|
||||
destroy();
|
||||
}
|
||||
updateStack();
|
||||
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
destroy(true);
|
||||
}
|
||||
|
||||
public void destroy(boolean full) {
|
||||
if (full)
|
||||
plugin.getEntityStackManager().removeStack(this.hostUniqueId);
|
||||
if (hostEntity != null) {
|
||||
try {
|
||||
hostEntity.setCustomNameVisible(false);
|
||||
hostEntity.setCustomName(null);
|
||||
} catch (NullPointerException ignored) {}
|
||||
}
|
||||
if (hostEntity == null) return;
|
||||
Bukkit.getScheduler().runTask(plugin, hostEntity::remove);
|
||||
hostEntity = null;
|
||||
hostUniqueId = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "EntityStack{" +
|
||||
"hostEntity=" + hostEntity +
|
||||
", amount=" + amount +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import org.bukkit.ChatColor;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
|
||||
import java.util.Collection;
|
||||
@ -17,157 +18,92 @@ import java.util.UUID;
|
||||
|
||||
public class EntityStackManager {
|
||||
|
||||
// These are all stacked mobs loaded into memory.
|
||||
private static final Map<UUID, EntityStack> stacks = new HashMap<>();
|
||||
|
||||
// This will only be used for stacks that have not yet been loaded into the game.
|
||||
private static final Map<UUID, ColdEntityStack> coldStacks = new HashMap<>();
|
||||
|
||||
private final UltimateStacker plugin;
|
||||
|
||||
public EntityStackManager(UltimateStacker plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public EntityStack addStack(EntityStack stack) {
|
||||
stacks.put(stack.getHostEntity().getUniqueId(), stack);
|
||||
return stack;
|
||||
public EntityStack createStack(LivingEntity entity, int amount) {
|
||||
return new EntityStack(entity, amount);
|
||||
}
|
||||
|
||||
public boolean isStackedEntity(Entity entity) {
|
||||
return entity.hasMetadata("US_AMOUNT");
|
||||
}
|
||||
|
||||
public int getAmount(Entity entity) {
|
||||
if (!isStackedEntity(entity)) return 1;
|
||||
if (entity.getMetadata("US_AMOUNT").isEmpty()) return 1;
|
||||
return entity.getMetadata("US_AMOUNT").get(0).asInt();
|
||||
}
|
||||
|
||||
public EntityStack addStack(LivingEntity entity) {
|
||||
if (entity == null) return null;
|
||||
EntityStack stack = new EntityStack(entity);
|
||||
plugin.getDataManager().createHostEntity(stack);
|
||||
stacks.put(entity.getUniqueId(), stack);
|
||||
return stack;
|
||||
return addStack(entity, getAmount(entity) == 1 ? 1 : getAmount(entity));
|
||||
}
|
||||
|
||||
public EntityStack addStack(LivingEntity entity, int amount) {
|
||||
if (entity == null) return null;
|
||||
EntityStack stack = new EntityStack(entity);
|
||||
plugin.getDataManager().createHostEntity(stack);
|
||||
stacks.put(entity.getUniqueId(), stack);
|
||||
stack.createDuplicates(amount - 1);
|
||||
plugin.getDataManager().updateHost(stack);
|
||||
stack.updateStack();
|
||||
return stack;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public EntityStack addSerializedStack(LivingEntity entity, String customName) {
|
||||
if (customName != null && customName.contains(String.valueOf(ChatColor.COLOR_CHAR))) {
|
||||
String name = customName.replace(String.valueOf(ChatColor.COLOR_CHAR), "")
|
||||
.replace(";", "");
|
||||
if (!name.contains(":")) return null;
|
||||
String split = name.split(":")[0];
|
||||
int amount = Methods.isInt(split) ? Integer.parseInt(split) : 0;
|
||||
return addStack(entity, amount);
|
||||
if (isStackedEntity(entity)) {
|
||||
EntityStack stack = getStack(entity);
|
||||
stack.addEntityToStack(amount);
|
||||
return stack;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public EntityStack addSerializedStack(LivingEntity entity) {
|
||||
return addSerializedStack(entity, entity.getCustomName());
|
||||
public EntityStack getStack(UUID uuid) {
|
||||
Entity entity = Bukkit.getEntity(uuid);
|
||||
if (entity == null) return null;
|
||||
if (isStackedEntity(entity)) {
|
||||
if (entity instanceof LivingEntity) {
|
||||
return new EntityStack((LivingEntity) entity);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public EntityStack getStack(LivingEntity entity) {
|
||||
EntityStack stack = getStack(entity.getUniqueId());
|
||||
if (stack == null) stack = addSerializedStack(entity);
|
||||
if (!isStackedEntity(entity)) return null;
|
||||
return new EntityStack(entity);
|
||||
}
|
||||
|
||||
public EntityStack decreaseStack(Entity entity) {
|
||||
EntityStack stack = getStack((LivingEntity) entity);
|
||||
if (stack == null) return null;
|
||||
stack.removeEntityFromStack(1);
|
||||
return stack;
|
||||
}
|
||||
|
||||
public EntityStack getStack(UUID uuid) {
|
||||
return stacks.get(uuid);
|
||||
}
|
||||
|
||||
public EntityStack removeStack(Entity entity) {
|
||||
return removeStack(entity.getUniqueId());
|
||||
}
|
||||
|
||||
public EntityStack removeStack(UUID uuid) {
|
||||
EntityStack stack = stacks.remove(uuid);
|
||||
if (stack != null) {
|
||||
plugin.getDataManager().deleteHost(stack);
|
||||
stack.destroy();
|
||||
}
|
||||
|
||||
public EntityStack decreaseStack(Entity entity, int amount) {
|
||||
EntityStack stack = getStack((LivingEntity) entity);
|
||||
if (stack == null) return null;
|
||||
stack.removeEntityFromStack(amount);
|
||||
return stack;
|
||||
}
|
||||
|
||||
public Map<UUID, EntityStack> getStacks() {
|
||||
return Collections.unmodifiableMap(stacks);
|
||||
public EntityStack updateStack(LivingEntity entity) {
|
||||
EntityStack stack = getStack(entity);
|
||||
if (stack == null) return null;
|
||||
stack.updateNameTag();
|
||||
return stack;
|
||||
}
|
||||
|
||||
public EntityStack updateStack(LivingEntity oldEntity, LivingEntity newEntity) {
|
||||
EntityStack stack = stacks.remove(oldEntity.getUniqueId());
|
||||
EntityStack stack = getStack(oldEntity);
|
||||
if (stack == null) return null;
|
||||
stack.setHostEntity(newEntity);
|
||||
stacks.put(newEntity.getUniqueId(), stack);
|
||||
plugin.getDataManager().updateHost(stack);
|
||||
return stack;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public boolean isStacked(UUID entity) {
|
||||
return isStackedAndLoaded(entity);
|
||||
}
|
||||
|
||||
public boolean isStackedAndLoaded(LivingEntity entity) {
|
||||
return stacks.containsKey(entity.getUniqueId());
|
||||
}
|
||||
|
||||
public boolean isStackedAndLoaded(UUID entity) {
|
||||
return stacks.containsKey(entity);
|
||||
}
|
||||
|
||||
public boolean isEntityInColdStorage(UUID entity) {
|
||||
return coldStacks.containsKey(entity);
|
||||
}
|
||||
|
||||
public boolean isEntityInColdStorage(LivingEntity entity) {
|
||||
return isEntityInColdStorage(entity.getUniqueId());
|
||||
}
|
||||
|
||||
public void loadStack(LivingEntity entity) {
|
||||
ColdEntityStack coldStack = coldStacks.get(entity.getUniqueId());
|
||||
if (coldStack == null) return;
|
||||
EntityStack stack = new EntityStack(entity, coldStack);
|
||||
stack.updateStack();
|
||||
stacks.put(entity.getUniqueId(), stack);
|
||||
plugin.getDataManager().updateHost(coldStack);
|
||||
}
|
||||
|
||||
public void unloadStack(LivingEntity entity) {
|
||||
EntityStack stack = stacks.get(entity.getUniqueId());
|
||||
if (stack == null) return;
|
||||
ColdEntityStack coldStack = new EntityStack(entity, stack);
|
||||
int amount = stack.getAmount();
|
||||
stack.destroy();
|
||||
coldStacks.put(entity.getUniqueId(), coldStack);
|
||||
return createStack(newEntity, amount);
|
||||
}
|
||||
|
||||
public void addStacks(Collection<ColdEntityStack> entities) {
|
||||
for (ColdEntityStack stack : entities)
|
||||
coldStacks.put(stack.hostUniqueId, stack);
|
||||
}
|
||||
|
||||
public ColdEntityStack addLegacyColdStack(UUID entity, int amount) {
|
||||
ColdEntityStack stack = new ColdEntityStack(entity);
|
||||
plugin.getDataManager().createHostEntity(stack);
|
||||
stack.createDuplicates(amount - 1);
|
||||
plugin.getDataManager().updateHost(stack);
|
||||
coldStacks.put(entity, stack);
|
||||
return stack;
|
||||
}
|
||||
|
||||
public void tryAndLoadColdEntities() {
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
for (Chunk chunk : world.getLoadedChunks()) {
|
||||
for (Entity entity : chunk.getEntities()) {
|
||||
if (entity instanceof LivingEntity)
|
||||
loadStack((LivingEntity)entity);
|
||||
}
|
||||
}
|
||||
public void setStack(LivingEntity newEntity, int amount) {
|
||||
if (isStackedEntity(newEntity)) {
|
||||
EntityStack stack = getStack(newEntity);
|
||||
stack.setAmount(amount);
|
||||
System.err.println("Stacked entity already exists, updating stack amount to " + amount);
|
||||
} else {
|
||||
createStack(newEntity, amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,78 @@
|
||||
package com.songoda.ultimatestacker.stackable.entity;
|
||||
|
||||
import com.songoda.ultimatestacker.UltimateStacker;
|
||||
import com.songoda.ultimatestacker.settings.Settings;
|
||||
import com.songoda.ultimatestacker.utils.Methods;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.metadata.FixedMetadataValue;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class StackedEntity {
|
||||
|
||||
private final UUID uniqueId;
|
||||
private final byte[] serializedEntity;
|
||||
protected int amount;
|
||||
protected LivingEntity hostEntity;
|
||||
|
||||
public StackedEntity(UUID uniqueId, byte[] serializedEntity) {
|
||||
this.uniqueId = uniqueId;
|
||||
this.serializedEntity = serializedEntity;
|
||||
/**
|
||||
* Gets an existing stack from an entity or creates a new one if it doesn't exist.
|
||||
* @param entity The entity to get the stack from.
|
||||
*/
|
||||
public StackedEntity(LivingEntity entity) {
|
||||
if (entity == null) return;
|
||||
if (!UltimateStacker.getInstance().getEntityStackManager().isStackedEntity(entity)) {
|
||||
entity.setMetadata("US_AMOUNT", new FixedMetadataValue(UltimateStacker.getInstance(), 1));
|
||||
this.amount = 1;
|
||||
updateNameTag();
|
||||
} else {
|
||||
//get the amount from the entity
|
||||
this.amount = UltimateStacker.getInstance().getEntityStackManager().getAmount(entity);
|
||||
}
|
||||
this.hostEntity = entity;
|
||||
}
|
||||
|
||||
public UUID getUniqueId() {
|
||||
return uniqueId;
|
||||
/**
|
||||
* Creates a new stack or overrides an existing stack.
|
||||
* @param entity The entity to create the stack for.
|
||||
* @param amount The amount of entities in the stack.
|
||||
*/
|
||||
public StackedEntity(LivingEntity entity, int amount) {
|
||||
if (entity == null) return;
|
||||
this.hostEntity = entity;
|
||||
this.amount = amount;
|
||||
entity.setMetadata("US_AMOUNT", new FixedMetadataValue(UltimateStacker.getInstance(), amount));
|
||||
updateNameTag();
|
||||
}
|
||||
|
||||
public byte[] getSerializedEntity() {
|
||||
return serializedEntity;
|
||||
|
||||
public EntityType getType() {
|
||||
return hostEntity.getType();
|
||||
}
|
||||
|
||||
public int getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setAmount(int amount) {
|
||||
this.amount = amount;
|
||||
this.hostEntity.setMetadata("US_AMOUNT", new FixedMetadataValue(UltimateStacker.getInstance(), amount));
|
||||
updateNameTag();
|
||||
}
|
||||
|
||||
public UUID getUuid() {
|
||||
return hostEntity.getUniqueId();
|
||||
}
|
||||
|
||||
public LivingEntity getHostEntity() {
|
||||
return hostEntity;
|
||||
}
|
||||
|
||||
protected void updateNameTag() {
|
||||
if (hostEntity == null) {
|
||||
return;
|
||||
}
|
||||
hostEntity.setCustomNameVisible(!Settings.HOLOGRAMS_ON_LOOK_ENTITY.getBoolean());
|
||||
hostEntity.setCustomName(Methods.compileEntityName(hostEntity, getAmount()));
|
||||
}
|
||||
}
|
||||
|
@ -58,11 +58,14 @@ import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
public class StackingTask extends BukkitRunnable {
|
||||
public class StackingTask implements Runnable {
|
||||
|
||||
private final UltimateStacker plugin;
|
||||
private final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(4);
|
||||
|
||||
private final EntityStackManager stackManager;
|
||||
|
||||
@ -96,7 +99,12 @@ public class StackingTask extends BukkitRunnable {
|
||||
loadedWorlds.add(new SWorld(world));
|
||||
|
||||
// Start the stacking task.
|
||||
runTaskTimerAsynchronously(plugin, 0, Settings.STACK_SEARCH_TICK_SPEED.getInt());
|
||||
//runTaskTimerAsynchronously(plugin, 0, Settings.STACK_SEARCH_TICK_SPEED.getInt());
|
||||
executorService.scheduleAtFixedRate(this, 0, Settings.STACK_SEARCH_TICK_SPEED.getInt()*20L, java.util.concurrent.TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
executorService.shutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -197,32 +205,46 @@ public class StackingTask extends BukkitRunnable {
|
||||
|
||||
}
|
||||
|
||||
private void processEntity(LivingEntity livingEntity, SWorld sWorld, Location location) {
|
||||
private void processEntity(LivingEntity baseEntity, SWorld sWorld, Location location) {
|
||||
|
||||
// Check our WorldGuard flag.
|
||||
Boolean flag = WorldGuardHook.isEnabled() ? WorldGuardHook.getBooleanFlag(baseEntity.getLocation(), "mob-stacking") : null;
|
||||
if (flag != null && !flag) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the stack from the entity. It should be noted that this value will
|
||||
// be null if our entity is not a stack.
|
||||
EntityStack stack = plugin.getEntityStackManager().getStack(livingEntity);
|
||||
|
||||
// Is this entity stacked?
|
||||
boolean isStack = stack != null;
|
||||
|
||||
// The amount that is stackable.
|
||||
int amountToStack = isStack ? stack.getAmount() : 1;
|
||||
|
||||
// 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, 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;
|
||||
EntityStack baseStack = plugin.getEntityStackManager().getStack(baseEntity);
|
||||
|
||||
// Get the maximum stack size for this entity.
|
||||
int maxEntityStackSize = getEntityStackSize(livingEntity);
|
||||
int maxEntityStackSize = getEntityStackSize(baseEntity);
|
||||
|
||||
// Is this entity stacked?
|
||||
boolean isStack = baseStack != null;
|
||||
|
||||
if (isStack && baseStack.getAmount() == maxEntityStackSize) {
|
||||
// If the stack is already at the max size then we can skip it.
|
||||
return;
|
||||
}
|
||||
|
||||
// The amount that is stackable.
|
||||
int amountToStack = isStack ? baseStack.getAmount() : 1;
|
||||
|
||||
// Attempt to split our stack. If the split is successful then skip this entity.
|
||||
if (isStack && attemptSplit(baseStack, baseEntity)) return;
|
||||
|
||||
// If this entity is named, a custom entity or disabled then skip it.
|
||||
if (!isStack && (baseEntity.getCustomName() != null
|
||||
&& plugin.getCustomEntityManager().getCustomEntity(baseEntity) == null)
|
||||
|| !configurationSection.getBoolean("Mobs." + baseEntity.getType().name() + ".Enabled"))
|
||||
return;
|
||||
|
||||
|
||||
|
||||
// Get similar entities around our entity and make sure those entities are both compatible and stackable.
|
||||
List<LivingEntity> stackableFriends = new LinkedList<>();
|
||||
for (LivingEntity entity : getSimilarEntitiesAroundEntity(livingEntity, sWorld, location)) {
|
||||
for (LivingEntity entity : getSimilarEntitiesAroundEntity(baseEntity, sWorld, location)) {
|
||||
// Check to see if entity is not stackable.
|
||||
if (!isEntityStackable(entity))
|
||||
continue;
|
||||
@ -231,156 +253,56 @@ public class StackingTask extends BukkitRunnable {
|
||||
}
|
||||
|
||||
// Loop through our similar stackable entities.
|
||||
for (LivingEntity entity : stackableFriends) {
|
||||
// Make sure the entity has not already been processed.
|
||||
if (this.processed.contains(entity.getUniqueId())) continue;
|
||||
|
||||
// Check our WorldGuard flag.
|
||||
Boolean flag = WorldGuardHook.isEnabled() ? WorldGuardHook.getBooleanFlag(livingEntity.getLocation(), "mob-stacking") : null;
|
||||
if (flag != null && !flag)
|
||||
continue;
|
||||
for (LivingEntity friendlyEntity : stackableFriends) {
|
||||
// Make sure the friendlyEntity has not already been processed.
|
||||
if (this.processed.contains(friendlyEntity.getUniqueId())) continue;
|
||||
|
||||
// Get this entities friendStack.
|
||||
EntityStack friendStack = stackManager.getStack(entity);
|
||||
EntityStack friendStack = stackManager.getStack(friendlyEntity);
|
||||
|
||||
// Check to see if this entity is stacked and friendStack plus
|
||||
if (friendStack == null) continue;
|
||||
|
||||
// Check to see if this friendlyEntity is stacked and friendStack plus
|
||||
// our amount to stack is not above our max friendStack size
|
||||
// for this entity.
|
||||
if (friendStack != null && (friendStack.getAmount() + amountToStack) <= maxEntityStackSize) {
|
||||
// for this friendlyEntity.
|
||||
|
||||
// If we are a stack lets merge our stack with the just found friend stack.
|
||||
if (isStack) {
|
||||
// Get the host entity.
|
||||
StackedEntity host = stack.getHostAsStackedEntity();
|
||||
// Get all the stacked entities in our stack and add them to a list.
|
||||
List<StackedEntity> entities = stack.takeAllEntities();
|
||||
// Add the host to this list.
|
||||
entities.add(host);
|
||||
// Add the collected entities to the new stack.
|
||||
friendStack.addEntitiesToStackSilently(entities);
|
||||
// Update friend stack to display changes.
|
||||
friendStack.updateStack();
|
||||
// Push changes to the database.
|
||||
plugin.getDataManager().createStackedEntities(friendStack, entities);
|
||||
} else {
|
||||
// If we are not stacked add ourselves to the found friendStack.
|
||||
plugin.getDataManager().createStackedEntity(friendStack, friendStack.addEntityToStack(livingEntity));
|
||||
boolean overstack = (friendStack.getAmount() + amountToStack) > maxEntityStackSize;
|
||||
|
||||
if (!overstack) {
|
||||
friendStack.setAmount(friendStack.getAmount() + amountToStack);
|
||||
if (baseEntity.isLeashed())
|
||||
Bukkit.getScheduler().runTask(plugin, () -> baseEntity.getWorld()
|
||||
.dropItemNaturally(baseEntity.getLocation(), CompatibleMaterial.LEAD.getItem()));
|
||||
if (baseStack != null) {
|
||||
baseStack.destroy();
|
||||
}
|
||||
|
||||
// Drop lead if applicable then remove our entity and mark it as processed.
|
||||
if (livingEntity.isLeashed())
|
||||
Bukkit.getScheduler().runTask(plugin, () -> livingEntity.getWorld()
|
||||
.dropItemNaturally(livingEntity.getLocation(), CompatibleMaterial.LEAD.getItem()));
|
||||
Bukkit.getScheduler().runTask(plugin, livingEntity::remove);
|
||||
processed.add(livingEntity.getUniqueId());
|
||||
|
||||
return;
|
||||
} else if (friendStack == null
|
||||
&& isStack
|
||||
&& (stack.getAmount() + 1) <= maxEntityStackSize
|
||||
&& canFly(entity)
|
||||
&& Settings.ONLY_STACK_FLYING_DOWN.getBoolean()
|
||||
&& location.getY() > entity.getLocation().getY()) {
|
||||
|
||||
// Make the friend the new stack host.
|
||||
EntityStack newStack = stackManager.updateStack(livingEntity, entity);
|
||||
|
||||
if (newStack == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add our entity to that stack
|
||||
plugin.getDataManager().createStackedEntity(newStack, newStack.addEntityToStack(livingEntity));
|
||||
|
||||
// Remove our entity and mark it as processed.
|
||||
Bukkit.getScheduler().runTask(plugin, livingEntity::remove);
|
||||
processed.add(livingEntity.getUniqueId());
|
||||
processed.add(baseEntity.getUniqueId());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If our entity is stacked then skip this entity.
|
||||
if (isStack) return;
|
||||
|
||||
// Check our WorldGuard flag.
|
||||
Boolean flag = WorldGuardHook.isEnabled() ? WorldGuardHook.getBooleanFlag(livingEntity.getLocation(), "mob-stacking") : null;
|
||||
if (flag != null && !flag)
|
||||
return;
|
||||
|
||||
// Remove all stacked entities from our stackable friends.
|
||||
stackableFriends.removeIf(stackManager::isStackedAndLoaded);
|
||||
|
||||
// If the stack cap is met then delete this entity.
|
||||
if (maxPerTypeStacksPerChunk != -1
|
||||
&& (getSimilarStacksInChunk(sWorld, livingEntity) + 1) > maxPerTypeStacksPerChunk) {
|
||||
Bukkit.getScheduler().runTask(plugin, livingEntity::remove);
|
||||
this.processed.add(livingEntity.getUniqueId());
|
||||
return;
|
||||
}
|
||||
|
||||
// If there are none or not enough stackable friends left to create a new entity,
|
||||
// the stack sizes overlap then skip this entity.
|
||||
if (stackableFriends.isEmpty()
|
||||
|| stackableFriends.size() < minEntityStackSize - 1
|
||||
|| minEntityStackSize > maxEntityStackSize) return;
|
||||
|
||||
// If a stack was never found create a new one.
|
||||
EntityStack newStack = stackManager.addStack(livingEntity);
|
||||
|
||||
List<LivingEntity> livingEntities = new LinkedList<>();
|
||||
|
||||
// Loop through the unstacked and unprocessed stackable friends while not creating
|
||||
// a stack larger than the maximum.
|
||||
stackableFriends.stream().filter(entity -> !stackManager.isStackedAndLoaded(entity)
|
||||
&& !this.processed.contains(entity.getUniqueId())).limit(maxEntityStackSize).forEach(entity -> {
|
||||
|
||||
// Make sure we're not naming some poor kids pet.
|
||||
if (entity.getCustomName() != null
|
||||
&& plugin.getCustomEntityManager().getCustomEntity(entity) == null) {
|
||||
processed.add(livingEntity.getUniqueId());
|
||||
newStack.destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
// Drop lead if applicable then remove our entity and mark it as processed.
|
||||
if (entity.isLeashed()) {
|
||||
Bukkit.getScheduler().runTask(plugin, () -> entity.getWorld().dropItemNaturally(entity.getLocation(), CompatibleMaterial.LEAD.getItem()));
|
||||
}
|
||||
livingEntities.add(entity);
|
||||
Bukkit.getScheduler().runTask(plugin, entity::remove);
|
||||
processed.add(entity.getUniqueId());
|
||||
|
||||
});
|
||||
|
||||
// Add our new approved entities to the new stack and commit them to the database.
|
||||
plugin.getDataManager().createStackedEntities(newStack,
|
||||
newStack.addRawEntitiesToStackSilently(livingEntities));
|
||||
|
||||
// Update our stack.
|
||||
newStack.updateStack();
|
||||
}
|
||||
|
||||
public boolean attemptSplit(EntityStack stack, LivingEntity livingEntity) {
|
||||
int stackSize = stack.getAmount();
|
||||
public boolean attemptSplit(EntityStack baseStack, LivingEntity livingEntity) {
|
||||
int stackSize = baseStack.getAmount();
|
||||
int maxEntityStackAmount = getEntityStackSize(livingEntity);
|
||||
|
||||
if (stackSize <= maxEntityStackAmount) return false;
|
||||
|
||||
// Destroy the stack.
|
||||
stack.destroy();
|
||||
baseStack.setAmount(maxEntityStackAmount);
|
||||
|
||||
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||
for (int i = stackSize; i > 0; i -= maxEntityStackAmount) {
|
||||
LivingEntity entity = stack.takeOneAndSpawnEntity(livingEntity.getLocation());
|
||||
if (entity == null) continue;
|
||||
EntityStack newStack = plugin.getEntityStackManager().addStack(entity);
|
||||
newStack.moveEntitiesFromStack(stack, Math.min(i, maxEntityStackAmount) - 1);
|
||||
newStack.updateStack();
|
||||
}
|
||||
int finalStackSize = stackSize - maxEntityStackAmount;
|
||||
do {
|
||||
// Create a new stack, summon entity and add to stack.
|
||||
LivingEntity newEntity = (LivingEntity) livingEntity.getWorld().spawnEntity(livingEntity.getLocation(), livingEntity.getType());
|
||||
int toAdd = Math.min(finalStackSize, maxEntityStackAmount);
|
||||
EntityStack newStack = stackManager.createStack(newEntity, toAdd);
|
||||
processed.add(newEntity.getUniqueId());
|
||||
finalStackSize -= maxEntityStackAmount;
|
||||
} while (finalStackSize >= 0);
|
||||
});
|
||||
|
||||
// Remove our entity and mark it as processed.
|
||||
Bukkit.getScheduler().runTask(plugin, livingEntity::remove);
|
||||
processed.add(livingEntity.getUniqueId());
|
||||
return true;
|
||||
}
|
||||
@ -443,7 +365,7 @@ public class StackingTask extends BukkitRunnable {
|
||||
public int getSimilarStacksInChunk(SWorld sWorld, LivingEntity entity) {
|
||||
int count = 0;
|
||||
for (LivingEntity e : getNearbyEntities(sWorld, entity.getLocation(), -1, true)) {
|
||||
if (entity.getType() == e.getType() && plugin.getEntityStackManager().isStackedAndLoaded(e))
|
||||
if (entity.getType() == e.getType() && plugin.getEntityStackManager().isStackedEntity(e))
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
|
Loading…
Reference in New Issue
Block a user