Merge branch 'development'

This commit is contained in:
Brianna 2020-08-24 18:01:35 -05:00
commit ae389b64ec
43 changed files with 1822 additions and 1333 deletions

14
pom.xml
View File

@ -2,7 +2,7 @@
<groupId>com.songoda</groupId>
<artifactId>UltimateStacker</artifactId>
<modelVersion>4.0.0</modelVersion>
<version>1.11.20</version>
<version>2</version>
<build>
<defaultGoal>clean install</defaultGoal>
<finalName>UltimateStacker-${project.version}</finalName>
@ -116,20 +116,20 @@
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>1.16.1</version>
<version>1.16.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.songoda</groupId>
<artifactId>Lootables</artifactId>
<version>1.0.8</version>
</dependency>
<dependency>
<groupId>com.songoda</groupId>
<artifactId>SongodaCore</artifactId>
<version>LATEST</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.songoda</groupId>
<artifactId>Lootables</artifactId>
<version>1.0.8</version>
</dependency>
<dependency>
<groupId>com.gamingmesh</groupId>
<artifactId>jobs</artifactId>

View File

@ -17,8 +17,8 @@ import com.songoda.core.utils.TextUtils;
import com.songoda.ultimatestacker.commands.*;
import com.songoda.ultimatestacker.database.DataManager;
import com.songoda.ultimatestacker.database.migrations._1_InitialMigration;
import com.songoda.ultimatestacker.entity.EntityStack;
import com.songoda.ultimatestacker.entity.EntityStackManager;
import com.songoda.ultimatestacker.database.migrations._2_EntityStacks;
import com.songoda.ultimatestacker.database.migrations._3_BlockStacks;
import com.songoda.ultimatestacker.hook.StackerHook;
import com.songoda.ultimatestacker.hook.hooks.JobsHook;
import com.songoda.ultimatestacker.listeners.*;
@ -27,20 +27,22 @@ import com.songoda.ultimatestacker.listeners.item.ItemLegacyListener;
import com.songoda.ultimatestacker.listeners.item.ItemListeners;
import com.songoda.ultimatestacker.lootables.LootablesManager;
import com.songoda.ultimatestacker.settings.Settings;
import com.songoda.ultimatestacker.spawner.SpawnerStack;
import com.songoda.ultimatestacker.spawner.SpawnerStackManager;
import com.songoda.ultimatestacker.stackable.Hologramable;
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.spawner.SpawnerStack;
import com.songoda.ultimatestacker.stackable.spawner.SpawnerStackManager;
import com.songoda.ultimatestacker.storage.Storage;
import com.songoda.ultimatestacker.storage.StorageRow;
import com.songoda.ultimatestacker.storage.types.StorageYaml;
import com.songoda.ultimatestacker.tasks.StackingTask;
import com.songoda.ultimatestacker.utils.EntityUtils;
import com.songoda.ultimatestacker.utils.Methods;
import org.apache.commons.lang.WordUtils;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.CreatureSpawner;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
@ -65,6 +67,7 @@ public class UltimateStacker extends SongodaPlugin {
private final List<StackerHook> stackerHooks = new ArrayList<>();
private EntityStackManager entityStackManager;
private SpawnerStackManager spawnerStackManager;
private BlockStackManager blockStackManager;
private LootablesManager lootablesManager;
private CommandManager commandManager;
private StackingTask stackingTask;
@ -73,8 +76,6 @@ public class UltimateStacker extends SongodaPlugin {
private DataMigrationManager dataMigrationManager;
private DataManager dataManager;
private EntityUtils entityUtils;
public static UltimateStacker getInstance() {
return INSTANCE;
}
@ -118,8 +119,6 @@ public class UltimateStacker extends SongodaPlugin {
new CommandConvert(guiManager)
);
this.entityUtils = new EntityUtils();
this.lootablesManager = new LootablesManager();
this.lootablesManager.createDefaultLootables();
this.getLootablesManager().getLootManager().loadLootables();
@ -153,8 +152,8 @@ public class UltimateStacker extends SongodaPlugin {
spawnerFile.saveChanges();
this.spawnerStackManager = new SpawnerStackManager();
this.entityStackManager = new EntityStackManager();
this.stackingTask = new StackingTask(this);
this.entityStackManager = new EntityStackManager(this);
this.blockStackManager = new BlockStackManager();
guiManager.init();
PluginManager pluginManager = Bukkit.getPluginManager();
@ -185,33 +184,6 @@ public class UltimateStacker extends SongodaPlugin {
}
HologramManager.load(this);
// Legacy Data
Bukkit.getScheduler().runTaskLater(this, () -> {
File folder = getDataFolder();
File dataFile = new File(folder, "data.yml");
if (dataFile.exists()) {
Storage storage = new StorageYaml(this);
if (storage.containsGroup("spawners")) {
for (StorageRow row : storage.getRowsByGroup("spawners")) {
try {
Location location = Methods.unserializeLocation(row.getKey());
SpawnerStack stack = new SpawnerStack(
location,
row.get("amount").asInt());
getDataManager().createSpawner(stack);
} catch (Exception e) {
console.sendMessage("Failed to load spawner.");
e.printStackTrace();
}
}
}
dataFile.delete();
}
}, 10);
// Database stuff, go!
try {
if (Settings.MYSQL_ENABLED.getBoolean()) {
@ -235,17 +207,72 @@ public class UltimateStacker extends SongodaPlugin {
this.dataManager = new DataManager(this.databaseConnector, this);
this.dataMigrationManager = new DataMigrationManager(this.databaseConnector, this.dataManager,
new _1_InitialMigration());
new _1_InitialMigration(),
new _2_EntityStacks(),
new _3_BlockStacks());
this.dataMigrationManager.runMigrations();
}
Bukkit.getScheduler().runTaskLater(this, () -> {
final boolean useHolo = Settings.SPAWNER_HOLOGRAMS.getBoolean();
this.dataManager.getSpawners((spawners) -> {
this.spawnerStackManager.addSpawners(spawners);
if (useHolo)
loadHolograms();
});
}, 20L);
@Override
public void onDataLoad() {
// Legacy Data
File folder = getDataFolder();
File dataFile = new File(folder, "data.yml");
if (dataFile.exists()) {
Storage storage = new StorageYaml(this);
if (storage.containsGroup("spawners")) {
for (StorageRow row : storage.getRowsByGroup("spawners")) {
try {
Location location = Methods.unserializeLocation(row.getKey());
SpawnerStack stack = new SpawnerStack(
location,
row.get("amount").asInt());
getDataManager().createSpawner(stack);
} catch (Exception e) {
console.sendMessage("Failed to load spawner.");
e.printStackTrace();
}
}
}
dataFile.delete();
}
// Load current data.
final boolean useSpawnerHolo = Settings.SPAWNER_HOLOGRAMS.getBoolean();
this.dataManager.getSpawners((spawners) -> {
this.spawnerStackManager.addSpawners(spawners);
if (useSpawnerHolo) {
if (spawners.isEmpty()) return;
for (SpawnerStack spawner : spawners.values()) {
if (spawner.getLocation().getWorld() != null) {
updateHologram(spawner);
}
}
}
});
this.dataManager.getEntities((entities) -> {
entityStackManager.addStacks(entities.values());
entityStackManager.tryAndLoadColdEntities();
this.stackingTask = new StackingTask(this);
getServer().getPluginManager().registerEvents(new ChunkListeners(this), this);
});
final boolean useBlockHolo = Settings.SPAWNER_HOLOGRAMS.getBoolean();
this.dataManager.getBlocks((blocks) -> {
this.blockStackManager.addBlocks(blocks);
if (useBlockHolo) {
if (blocks.isEmpty()) return;
for (BlockStack stack : blocks.values()) {
if (stack.getLocation().getWorld() != null) {
updateHologram(stack);
}
}
}
});
}
public void addExp(Player player, EntityStack stack) {
@ -269,8 +296,6 @@ public class UltimateStacker extends SongodaPlugin {
this.setLocale(getConfig().getString("System.Language Mode"), true);
this.locale.reloadMessages();
this.entityUtils = new EntityUtils();
this.stackingTask.cancel();
this.stackingTask = new StackingTask(this);
@ -281,7 +306,8 @@ public class UltimateStacker extends SongodaPlugin {
}
public boolean spawnersEnabled() {
return !this.getServer().getPluginManager().isPluginEnabled("EpicSpawners") && Settings.SPAWNERS_ENABLED.getBoolean();
return !this.getServer().getPluginManager().isPluginEnabled("EpicSpawners")
&& Settings.SPAWNERS_ENABLED.getBoolean();
}
public CommandManager getCommandManager() {
@ -316,10 +342,6 @@ public class UltimateStacker extends SongodaPlugin {
return spawnerFile;
}
public EntityUtils getEntityUtils() {
return entityUtils;
}
public DatabaseConnector getDatabaseConnector() {
return databaseConnector;
}
@ -332,45 +354,20 @@ public class UltimateStacker extends SongodaPlugin {
return guiManager;
}
void loadHolograms() {
Collection<SpawnerStack> spawners = getSpawnerStackManager().getStacks();
if (spawners.isEmpty()) return;
for (SpawnerStack spawner : spawners) {
if (spawner.getLocation().getWorld() != null) {
updateHologram(spawner);
}
}
public BlockStackManager getBlockStackManager() {
return blockStackManager;
}
public void clearHologram(SpawnerStack stack) {
HologramManager.removeHologram(stack.getLocation());
}
public void updateHologram(SpawnerStack stack) {
public void updateHologram(Hologramable stack) {
// are holograms enabled?
if (!Settings.SPAWNER_HOLOGRAMS.getBoolean() || !HologramManager.getManager().isEnabled()) return;
Block block = stack.getLocation().getBlock();
if (block.getType() != CompatibleMaterial.SPAWNER.getBlockMaterial()) return;
// grab the spawner block
CreatureSpawner creatureSpawner = (CreatureSpawner) block.getState();
String name = Methods.compileSpawnerName(creatureSpawner.getSpawnedType(), stack.getAmount());
if (!stack.areHologramsEnabled() && !HologramManager.getManager().isEnabled()) return;
// create the hologram
HologramManager.updateHologram(stack.getLocation(), name);
HologramManager.updateHologram(stack.getLocation(), stack.getHologramName());
}
public void removeHologram(Block block) {
HologramManager.removeHologram(block.getLocation());
}
public void updateHologram(Block block) {
// verify that this is a spawner
if (block.getType() != CompatibleMaterial.SPAWNER.getMaterial()) return;
// are holograms enabled?
if (!Settings.SPAWNER_HOLOGRAMS.getBoolean() || !HologramManager.getManager().isEnabled()) return;
// update this hologram in a tick
SpawnerStack spawner = getSpawnerStackManager().getSpawner(block);
Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(this, () -> updateHologram(spawner), 10L);
public void removeHologram(Hologramable stack) {
HologramManager.removeHologram(stack.getLocation());
}
//////// Convenient API //////////

View File

@ -2,19 +2,11 @@ package com.songoda.ultimatestacker.commands;
import com.songoda.core.commands.AbstractCommand;
import com.songoda.lootables.gui.GuiEditor;
import com.songoda.lootables.gui.GuiLootableEditor;
import com.songoda.ultimatestacker.UltimateStacker;
import com.songoda.ultimatestacker.entity.EntityStack;
import com.songoda.ultimatestacker.utils.Methods;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class CommandLootables extends AbstractCommand {

View File

@ -3,13 +3,14 @@ package com.songoda.ultimatestacker.commands;
import com.songoda.core.commands.AbstractCommand;
import com.songoda.core.utils.TextUtils;
import com.songoda.ultimatestacker.UltimateStacker;
import com.songoda.ultimatestacker.entity.EntityStackManager;
import com.songoda.ultimatestacker.stackable.entity.EntityStackManager;
import com.songoda.ultimatestacker.utils.Methods;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import java.util.Arrays;
@ -42,9 +43,9 @@ public class CommandRemoveAll extends AbstractCommand {
EntityStackManager stackManager = instance.getEntityStackManager();
for (World world : Bukkit.getWorlds()) {
for (Entity entityO : world.getEntities()) {
if (entityO instanceof Player) continue;
if (entityO instanceof Player || !(entityO instanceof LivingEntity)) continue;
if (entityO.getType() != EntityType.DROPPED_ITEM && (stackManager.isStacked(entityO) || all) && type.equalsIgnoreCase("entities")) {
if (entityO.getType() != EntityType.DROPPED_ITEM && (stackManager.isStackedAndLoaded((LivingEntity)entityO) || all) && type.equalsIgnoreCase("entities")) {
entityO.remove();
amountRemoved++;
} else if (entityO.getType() == EntityType.DROPPED_ITEM && type.equalsIgnoreCase("items")) {

View File

@ -2,16 +2,17 @@ package com.songoda.ultimatestacker.commands;
import com.songoda.core.commands.AbstractCommand;
import com.songoda.ultimatestacker.UltimateStacker;
import com.songoda.ultimatestacker.entity.EntityStack;
import com.songoda.ultimatestacker.stackable.entity.EntityStack;
import com.songoda.ultimatestacker.utils.Methods;
import org.bukkit.Material;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
@ -30,7 +31,7 @@ public class CommandSpawn extends AbstractCommand {
@Override
protected ReturnType runCommand(CommandSender sender, String... args) {
Player p = (Player) sender;
Player player = (Player) sender;
if (args.length < 2) return ReturnType.SYNTAX_ERROR;
@ -52,9 +53,11 @@ public class CommandSpawn extends AbstractCommand {
}
sender.sendMessage(Methods.formatText("&6" + list));
} else {
Entity entity = p.getWorld().spawnEntity(p.getLocation(), type);
EntityStack stack = instance.getEntityStackManager().addStack(entity.getUniqueId(), (Methods.isInt(args[1])) ? Integer.parseInt(args[1]) : 1);
instance.getStackingTask().attemptSplit(stack, (LivingEntity) entity);
LivingEntity entity = (LivingEntity)player.getWorld().spawnEntity(player.getTargetBlock((Set<Material>)null, 200).getLocation(), type);
EntityStack stack = instance.getEntityStackManager().addStack(entity);
stack.createDuplicates(((Methods.isInt(args[1])) ? Integer.parseInt(args[1]) : 1) - 1);
stack.updateStack();
instance.getStackingTask().attemptSplit(stack, entity);
}
return ReturnType.SUCCESS;

View File

@ -1,7 +1,7 @@
package com.songoda.ultimatestacker.convert;
import com.songoda.ultimatestacker.UltimateStacker;
import com.songoda.ultimatestacker.entity.EntityStackManager;
import com.songoda.ultimatestacker.stackable.entity.EntityStackManager;
import org.bukkit.Bukkit;
import uk.antiperson.stackmob.StackMob;
@ -38,11 +38,10 @@ public class StackMobConvert implements Convert {
public void convertEntities() {
EntityStackManager entityStackManager = plugin.getEntityStackManager();
for (Map.Entry<UUID, Integer> entry : stackMob.getStorageManager().getAmountCache().entrySet()) {
if (!entityStackManager.isStacked(entry.getKey())) {
entityStackManager.addStack(entry.getKey(), entry.getValue());
if (!entityStackManager.isStackedAndLoaded(entry.getKey())) {
entityStackManager.addLegacyColdStack(entry.getKey(), entry.getValue());
continue;
}
entityStackManager.getStack(entry.getKey()).setAmount(entry.getValue());
}
}

View File

@ -3,21 +3,27 @@ package com.songoda.ultimatestacker.convert;
import com.bgsoftware.wildstacker.WildStackerPlugin;
import com.bgsoftware.wildstacker.api.WildStackerAPI;
import com.bgsoftware.wildstacker.api.objects.StackedSpawner;
import com.songoda.core.database.DatabaseConnector;
import com.songoda.core.database.SQLiteConnector;
import com.songoda.ultimatestacker.UltimateStacker;
import com.songoda.ultimatestacker.entity.EntityStackManager;
import com.songoda.ultimatestacker.spawner.SpawnerStack;
import com.songoda.ultimatestacker.stackable.entity.EntityStackManager;
import com.songoda.ultimatestacker.stackable.spawner.SpawnerStack;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.block.CreatureSpawner;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.UUID;
public class WildStackerConvert implements Convert {
private WildStackerPlugin wildStacker;
private final UltimateStacker plugin;
public WildStackerConvert() {
this.plugin = UltimateStacker.getInstance();
this.wildStacker = (WildStackerPlugin) Bukkit.getPluginManager().getPlugin("WildStacker");
}
@Override
@ -38,18 +44,21 @@ public class WildStackerConvert implements Convert {
@Override
public void convertEntities() {
EntityStackManager entityStackManager = plugin.getEntityStackManager();
for (World world : Bukkit.getWorlds()) {
for (Entity entity : world.getEntities()) {
if (!(entity instanceof LivingEntity)) continue;
if (!entityStackManager.isStacked(entity)) {
entityStackManager
.addStack(entity, WildStackerAPI.getEntityAmount((LivingEntity)entity));
continue;
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);
}
entityStackManager
.getStack(entity).setAmount(WildStackerAPI.getEntityAmount((LivingEntity)entity));
}
}
});
}

View File

@ -1,20 +1,24 @@
package com.songoda.ultimatestacker.database;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.core.database.DataManagerAbstract;
import com.songoda.core.database.DatabaseConnector;
import com.songoda.ultimatestacker.spawner.SpawnerStack;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
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;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.plugin.Plugin;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.*;
import java.util.function.Consumer;
public class DataManager extends DataManagerAbstract {
public DataManager(DatabaseConnector databaseConnector, Plugin plugin) {
@ -49,7 +53,7 @@ public class DataManager extends DataManagerAbstract {
public void createSpawner(SpawnerStack spawnerStack) {
this.async(() -> this.databaseConnector.connect(connection -> {
this.queueAsync(() -> this.databaseConnector.connect(connection -> {
String createSpawner = "INSERT INTO " + this.getTablePrefix() + "spawners (amount, world, x, y, z) VALUES (?, ?, ?, ?, ?)";
try (PreparedStatement statement = connection.prepareStatement(createSpawner)) {
@ -61,8 +65,137 @@ public class DataManager extends DataManagerAbstract {
statement.setInt(5, spawnerStack.getZ());
statement.executeUpdate();
}
int spawnerId = this.lastInsertedId(connection);
int spawnerId = this.lastInsertedId(connection, "spawners");
this.sync(() -> spawnerStack.setId(spawnerId));
}), "create");
}
public void updateBlock(BlockStack blockStack) {
this.async(() -> this.databaseConnector.connect(connection -> {
if (blockStack.getAmount() == 0) return;
String updateBlock = "UPDATE " + this.getTablePrefix() + "blocks SET amount = ? WHERE id = ?";
try (PreparedStatement statement = connection.prepareStatement(updateBlock)) {
statement.setInt(1, blockStack.getAmount());
statement.setInt(2, blockStack.getId());
statement.executeUpdate();
}
}));
}
public void createBlock(BlockStack blockStack) {
this.queueAsync(() -> this.databaseConnector.connect(connection -> {
String createSpawner = "INSERT INTO " + this.getTablePrefix() + "blocks (amount, material, world, x, y, z) VALUES (?, ?, ?, ?, ?, ?)";
try (PreparedStatement statement = connection.prepareStatement(createSpawner)) {
statement.setInt(1, blockStack.getAmount());
statement.setString(2, blockStack.getMaterial().name());
statement.setString(3, blockStack.getWorld().getName());
statement.setInt(4, blockStack.getX());
statement.setInt(5, blockStack.getY());
statement.setInt(6, blockStack.getZ());
statement.executeUpdate();
}
int blockId = this.lastInsertedId(connection, "blocks");
this.sync(() -> blockStack.setId(blockId));
}), "create");
}
public void createHostEntity(ColdEntityStack stack) {
this.queueAsync(() -> this.databaseConnector.connect(connection -> {
if (stack.getHostUniqueId() == null) return;
String createSerializedEntity = "INSERT INTO " + this.getTablePrefix() + "host_entities (uuid, create_duplicates) VALUES (?, ?)";
try (PreparedStatement statement = connection.prepareStatement(createSerializedEntity)) {
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));
}), "create");
}
public void createStackedEntity(EntityStack hostStack, StackedEntity stackedEntity) {
this.queueAsync(() -> this.databaseConnector.connect(connection -> {
if (hostStack.getHostUniqueId() == null) return;
String createSerializedEntity = "INSERT INTO " + this.getTablePrefix() + "stacked_entities (uuid, host, serialized_entity) VALUES (?, ?, ?)";
try (PreparedStatement statement = connection.prepareStatement(createSerializedEntity)) {
statement.setString(1, stackedEntity.getUniqueId().toString());
statement.setInt(2, hostStack.getId());
statement.setBytes(3, stackedEntity.getSerializedEntity());
statement.executeUpdate();
}
}), "create");
}
public void createStackedEntities(ColdEntityStack hostStack, List<StackedEntity> stackedEntities) {
this.queueAsync(() -> this.databaseConnector.connect(connection -> {
if (hostStack.getHostUniqueId() == null) return;
String createSerializedEntity = "INSERT INTO " + this.getTablePrefix() + "stacked_entities (uuid, host, serialized_entity) VALUES (?, ?, ?)";
try (PreparedStatement statement = connection.prepareStatement(createSerializedEntity)) {
for (StackedEntity entity : stackedEntities) {
statement.setString(1, entity.getUniqueId().toString());
statement.setInt(2, hostStack.getId());
statement.setBytes(3, entity.getSerializedEntity());
statement.addBatch();
}
statement.executeBatch();
}
}), "create");
}
public void updateHost(ColdEntityStack hostStack) {
this.async(() -> this.databaseConnector.connect(connection -> {
if (hostStack.getHostUniqueId() == null) return;
String updateHost = "UPDATE " + this.getTablePrefix() + "host_entities SET uuid = ?, create_duplicates = ? WHERE id = ?";
try (PreparedStatement statement = connection.prepareStatement(updateHost)) {
statement.setString(1, hostStack.getHostUniqueId().toString());
statement.setInt(2, hostStack.getCreateDuplicates());
statement.setInt(3, hostStack.getId());
statement.executeUpdate();
}
}));
}
public void deleteHost(ColdEntityStack stack) {
this.async(() -> this.databaseConnector.connect(connection -> {
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();
}
}));
}
public void deleteStackedEntity(UUID uuid) {
this.async(() -> this.databaseConnector.connect(connection -> {
String deleteStackedEntity = "DELETE FROM " + this.getTablePrefix() + "stacked_entities WHERE uuid = ?";
try (PreparedStatement statement = connection.prepareStatement(deleteStackedEntity)) {
statement.setString(1, uuid.toString());
statement.executeUpdate();
}
}));
}
public void deleteStackedEntities(List<StackedEntity> entities) {
this.async(() -> this.databaseConnector.connect(connection -> {
String deleteStackedEntities = "DELETE FROM " + this.getTablePrefix() + "stacked_entities WHERE uuid = ?";
try (PreparedStatement statement = connection.prepareStatement(deleteStackedEntities)) {
for (StackedEntity entity : entities) {
if (entity == null) continue;
statement.setString(1, entity.getUniqueId().toString());
statement.addBatch();
}
statement.executeBatch();
}
}));
}
@ -76,6 +209,59 @@ public class DataManager extends DataManagerAbstract {
}));
}
public void deleteBlock(BlockStack blockStack) {
this.async(() -> this.databaseConnector.connect(connection -> {
String deleteBlock = "DELETE FROM " + this.getTablePrefix() + "blocks WHERE id = ?";
try (PreparedStatement statement = connection.prepareStatement(deleteBlock)) {
statement.setInt(1, blockStack.getId());
statement.executeUpdate();
}
}));
}
public void getEntities(Consumer<Map<Integer, ColdEntityStack>> callback) {
this.async(() -> this.databaseConnector.connect(connection -> {
Map<Integer, ColdEntityStack> entities = new HashMap<>();
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));
}));
}
public void getSpawners(Consumer<Map<Location, SpawnerStack>> callback) {
this.async(() -> this.databaseConnector.connect(connection -> {
String selectSpawners = "SELECT * FROM " + this.getTablePrefix() + "spawners";
@ -87,7 +273,7 @@ public class DataManager extends DataManagerAbstract {
while (result.next()) {
World world = Bukkit.getWorld(result.getString("world"));
if(world == null)
if (world == null)
continue;
int spawnerId = result.getInt("id");
@ -110,4 +296,41 @@ public class DataManager extends DataManagerAbstract {
this.sync(() -> callback.accept(spawners));
}));
}
public void getBlocks(Consumer<Map<Location, BlockStack>> callback) {
this.async(() -> this.databaseConnector.connect(connection -> {
String selectBlocks = "SELECT * FROM " + this.getTablePrefix() + "blocks";
Map<Location, BlockStack> blocks = new HashMap<>();
try (Statement statement = connection.createStatement()) {
ResultSet result = statement.executeQuery(selectBlocks);
while (result.next()) {
World world = Bukkit.getWorld(result.getString("world"));
if (world == null)
continue;
int blockId = result.getInt("id");
CompatibleMaterial material = CompatibleMaterial.getMaterial(result.getString("material"));
int amount = result.getInt("amount");
int x = result.getInt("x");
int y = result.getInt("y");
int z = result.getInt("z");
Location location = new Location(world, x, y, z);
BlockStack blockStack = new BlockStack(material, location, amount);
blockStack.setId(blockId);
blocks.put(location, blockStack);
}
} catch (Exception e) {
e.printStackTrace();
}
this.sync(() -> callback.accept(blocks));
}));
}
}

View File

@ -0,0 +1,39 @@
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 _2_EntityStacks extends DataMigration {
public _2_EntityStacks() {
super(2);
}
@Override
public void migrate(Connection connection, String tablePrefix) throws SQLException {
String autoIncrement = UltimateStacker.getInstance().getDatabaseConnector() instanceof MySQLConnector ? " AUTO_INCREMENT" : "";
// Create host entities table
try (Statement statement = connection.createStatement()) {
statement.execute("CREATE TABLE " + tablePrefix + "host_entities (" +
"id INTEGER PRIMARY KEY" + autoIncrement + ", " +
"uuid VARCHAR(36) NOT NULL," +
"create_duplicates INTEGER NOT NULL DEFAULT 0" +
")");
}
// Create stacked entities table
try (Statement statement = connection.createStatement()) {
statement.execute("CREATE TABLE " + tablePrefix + "stacked_entities (" +
"uuid VARCHAR(36) PRIMARY KEY NOT NULL," +
"host INTEGER NOT NULL," +
"serialized_entity VARBINARY NOT NULL" +
")");
}
}
}

View File

@ -0,0 +1,34 @@
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 _3_BlockStacks extends DataMigration {
public _3_BlockStacks() {
super(3);
}
@Override
public void migrate(Connection connection, String tablePrefix) throws SQLException {
String autoIncrement = UltimateStacker.getInstance().getDatabaseConnector() instanceof MySQLConnector ? " AUTO_INCREMENT" : "";
// Create blocks table
try (Statement statement = connection.createStatement()) {
statement.execute("CREATE TABLE " + tablePrefix + "blocks (" +
"id INTEGER PRIMARY KEY" + autoIncrement + ", " +
"amount INTEGER NOT NULL," +
"material STRING NOT NULL," +
"world TEXT NOT NULL, " +
"x DOUBLE NOT NULL, " +
"y DOUBLE NOT NULL, " +
"z DOUBLE NOT NULL " +
")");
}
}
}

View File

@ -1,274 +0,0 @@
package com.songoda.ultimatestacker.entity;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.core.compatibility.ServerVersion;
import com.songoda.core.utils.EntityUtils;
import com.songoda.lootables.loot.Drop;
import com.songoda.lootables.loot.DropUtils;
import com.songoda.ultimatestacker.UltimateStacker;
import com.songoda.ultimatestacker.settings.Settings;
import com.songoda.ultimatestacker.utils.Methods;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.ExperienceOrb;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.metadata.MetadataStoreBase;
import org.bukkit.metadata.MetadataValue;
import org.bukkit.plugin.Plugin;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedDeque;
public class EntityStack {
private UUID entity;
private int amount;
private final Deque<Double> health = new ConcurrentLinkedDeque<>();
final Object healthLock = new Object();
UltimateStacker plugin = UltimateStacker.getInstance();
public EntityStack(LivingEntity entity, int amount) {
this(entity.getUniqueId(), amount);
this.addHealth(entity.getHealth());
}
public EntityStack(UUID uuid, int amount) {
this.entity = uuid;
this.setAmount(amount);
}
public void updateStack() {
if (!Settings.ENTITY_HOLOGRAMS.getBoolean()) return;
Bukkit.getScheduler().scheduleSyncDelayedTask(UltimateStacker.getInstance(), () -> {
Entity entit = getEntityByUniqueId(this.entity);
if (entit == null ||
!UltimateStacker.getInstance().getEntityStackManager().isStacked(entity)) return;
entit.setCustomNameVisible(!Settings.HOLOGRAMS_ON_LOOK_ENTITY.getBoolean());
entit.setCustomName(Methods.compileEntityName(entit, amount));
}, entity == null ? 1L : 0L);
}
public LivingEntity getEntity() {
LivingEntity entity = getEntityByUniqueId(this.entity);
if (entity == null) {
UltimateStacker.getInstance().getEntityStackManager().removeStack(this.entity);
return null;
}
return entity;
}
protected void setEntity(Entity entity) {
this.entity = entity.getUniqueId();
}
public void addAmount(int amount) {
this.amount = this.amount + amount;
updateStack();
}
public UUID getEntityUniqueId() {
return entity;
}
public int getAmount() {
return amount;
}
public void setAmount(int amount) {
if (amount == 1) {
Entity entity = getEntityByUniqueId(this.entity);
if (entity == null) return;
UltimateStacker.getInstance().getEntityStackManager().removeStack(this.entity);
entity.setCustomName(null);
entity.setCustomNameVisible(false);
return;
}
this.amount = amount;
if (amount != 0)
updateStack();
}
private LivingEntity getEntityByUniqueId(UUID uniqueId) {
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_12))
return (LivingEntity) Bukkit.getEntity(uniqueId);
for (World world : Bukkit.getWorlds()) {
for (Entity entity : world.getEntities()) {
if (entity.getUniqueId().equals(uniqueId))
return (LivingEntity) entity;
}
}
return null;
}
private void handleWholeStackDeath(LivingEntity killed, List<Drop> drops, boolean custom, int droppedExp, EntityDeathEvent event) {
UltimateStacker.getInstance().getEntityStackManager().removeStack(event.getEntity());
Location killedLocation = killed.getLocation();
List<Drop> preStackedDrops = new ArrayList<>();
for (int i = 1; i < amount; i++) {
if (i == 1) {
drops.removeIf(it -> it.getItemStack() != null
&& it.getItemStack().isSimilar(killed.getEquipment().getItemInHand()));
for (ItemStack item : killed.getEquipment().getArmorContents()) {
drops.removeIf(it -> it.getItemStack() != null && it.getItemStack().isSimilar(item));
}
}
if (custom)
drops = plugin.getLootablesManager().getDrops(killed);
preStackedDrops.addAll(drops);
}
if (!preStackedDrops.isEmpty())
DropUtils.processStackedDrop(killed, preStackedDrops, event);
if (droppedExp > 0)
killedLocation.getWorld().spawn(killedLocation, ExperienceOrb.class).setExperience(droppedExp * amount);
if (killed.getKiller() == null) return;
UltimateStacker.getInstance().addExp(killed.getKiller(), this);
}
private void handleSingleStackDeath(LivingEntity killed, List<Drop> drops, EntityDeathEvent event) {
EntityStackManager stackManager = plugin.getEntityStackManager();
LivingEntity newEntity = plugin.getEntityUtils().newEntity(killed);
updateHealth(newEntity);
newEntity.getEquipment().clear();
if (killed.getType().name().equals("PIG_ZOMBIE"))
newEntity.getEquipment().setItemInHand(CompatibleMaterial.GOLDEN_SWORD.getItem());
if (Settings.CARRY_OVER_METADATA_ON_DEATH.getBoolean()) {
for (Map.Entry<String, MetadataValue> entry : getMetadata(killed).entrySet())
newEntity.setMetadata(entry.getKey(), entry.getValue());
}
if (!EntityUtils.isAware(killed))
EntityUtils.setUnaware(newEntity);
DropUtils.processStackedDrop(killed, drops, event);
EntityStack entityStack = stackManager.updateStack(killed, newEntity);
entityStack.addAmount(-1);
if (entityStack.getAmount() <= 1) {
stackManager.removeStack(newEntity);
newEntity.setCustomNameVisible(false);
newEntity.setCustomName(null);
}
}
static final int metaCarryOverMin = Settings.META_CARRY_OVER_MIN.getInt() * 20;
public Map<String, MetadataValue> getMetadata(LivingEntity subject) {
Map<String, MetadataValue> v = new HashMap<>();
if (subject.getTicksLived() >= metaCarryOverMin) return v;
Map<String, Map<Plugin, MetadataValue>> metadataMap = null;
try {
Object entityMetadata = methodGetEntityMetadata.invoke(Bukkit.getServer());
metadataMap = (Map) fieldMetadataMap.get(entityMetadata);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
if (metadataMap == null) return v;
for (Map.Entry<String, Map<Plugin, MetadataValue>> entry : metadataMap.entrySet()) {
if (!entry.getKey().startsWith(subject.getUniqueId().toString())) continue;
String key = entry.getKey().split(":")[1];
for (MetadataValue value : entry.getValue().values())
v.put(key, value);
}
return v;
}
private static Method methodGetEntityMetadata;
private static Field fieldMetadataMap;
static {
try {
String ver = Bukkit.getServer().getClass().getPackage().getName().substring(23);
Class<?> clazzCraftServer = Class.forName("org.bukkit.craftbukkit." + ver + ".CraftServer");
methodGetEntityMetadata = clazzCraftServer.getDeclaredMethod("getEntityMetadata");
fieldMetadataMap = MetadataStoreBase.class.getDeclaredField("metadataMap");
} catch (NoSuchFieldException | ClassNotFoundException | NoSuchMethodException e) {
e.printStackTrace();
}
fieldMetadataMap.setAccessible(true);
}
public void onDeath(LivingEntity killed, List<Drop> drops, boolean custom, int droppedExp, EntityDeathEvent event) {
killed.setCustomName(null);
killed.setCustomNameVisible(false);
boolean killWholeStack = Settings.KILL_WHOLE_STACK_ON_DEATH.getBoolean()
|| plugin.getMobFile().getBoolean("Mobs." + killed.getType().name() + ".Kill Whole Stack");
if (killWholeStack && getAmount() != 1) {
handleWholeStackDeath(killed, drops, custom, droppedExp, event);
} else if (getAmount() != 1) {
List<String> reasons = Settings.INSTANT_KILL.getStringList();
EntityDamageEvent lastDamageCause = killed.getLastDamageCause();
if (lastDamageCause != null) {
EntityDamageEvent.DamageCause cause = lastDamageCause.getCause();
for (String s : reasons) {
if (!cause.name().equalsIgnoreCase(s)) continue;
handleWholeStackDeath(killed, drops, custom, Settings.NO_EXP_INSTANT_KILL.getBoolean() ? 0 : droppedExp, event);
return;
}
}
handleSingleStackDeath(killed, drops, event);
}
}
public void updateHealth(LivingEntity entity) {
if (entity == null) return;
synchronized (healthLock) {
entity.setHealth(Settings.STACK_ENTITY_HEALTH.getBoolean()
&& !health.isEmpty()
? (health.getFirst() > entity.getMaxHealth() ? entity.getMaxHealth() : health.removeFirst())
: entity.getMaxHealth());
}
}
public void addHealth(double health) {
synchronized (healthLock) {
this.health.addLast(health);
}
}
public void mergeHealth(EntityStack stack) {
synchronized (healthLock) {
this.health.addAll(stack.health);
}
}
@Override
public String toString() {
return "EntityStack:{"
+ "Entity:\"" + entity.toString() + "\","
+ "Amount:\"" + amount + "\","
+ "}";
}
}

View File

@ -1,92 +0,0 @@
package com.songoda.ultimatestacker.entity;
import com.songoda.ultimatestacker.utils.Methods;
import org.bukkit.ChatColor;
import org.bukkit.entity.Entity;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class EntityStackManager {
// These are all stacked mobs loaded into memory.
private static final Map<UUID, EntityStack> stacks = new HashMap<>();
public EntityStack addStack(EntityStack stack) {
stacks.put(stack.getEntityUniqueId(), stack);
return stack;
}
public EntityStack addStack(Entity entity, int amount) {
return addStack(entity.getUniqueId(), amount);
}
public EntityStack addStack(UUID uuid, int amount) {
EntityStack stack = new EntityStack(uuid, amount);
stacks.put(uuid, stack);
return stack;
}
public EntityStack addSerializedStack(Entity 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);
}
return null;
}
public EntityStack addSerializedStack(Entity entity) {
return addSerializedStack(entity, entity.getCustomName());
}
public EntityStack getStack(Entity entity) {
EntityStack stack = getStack(entity.getUniqueId());
if (stack == null) stack = addSerializedStack(entity);
return stack;
}
public EntityStack getStack(UUID uuid) {
return stacks.get(uuid);
}
public boolean isStacked(Entity entity) {
if (entity == null) return false;
boolean isStacked = isStacked(entity.getUniqueId());
if (!isStacked && addSerializedStack(entity) != null) {
return true;
}
return isStacked(entity.getUniqueId());
}
public boolean isStacked(UUID uuid) {
return stacks.containsKey(uuid);
}
public EntityStack removeStack(UUID entity) {
return stacks.remove(entity);
}
public EntityStack removeStack(Entity entity) {
return stacks.remove(entity.getUniqueId());
}
public Map<UUID, EntityStack> getStacks() {
return Collections.unmodifiableMap(stacks);
}
public EntityStack updateStack(Entity oldEntity, Entity newEntity) {
EntityStack stack = stacks.remove(oldEntity.getUniqueId());
if (stack == null) return null;
stack.setEntity(newEntity);
stacks.put(newEntity.getUniqueId(), stack);
return stack;
}
}

View File

@ -3,6 +3,7 @@ package com.songoda.ultimatestacker.gui;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.core.gui.Gui;
import com.songoda.core.gui.GuiUtils;
import com.songoda.ultimatestacker.UltimateStacker;
import com.songoda.ultimatestacker.convert.Convert;
import com.songoda.ultimatestacker.utils.Methods;
import org.bukkit.ChatColor;
@ -53,6 +54,7 @@ public class GUIConvertWhat extends Gui {
void run(Player player) {
if (entities) {
convertFrom.convertEntities();
UltimateStacker.getInstance().getEntityStackManager().tryAndLoadColdEntities();
}
if (spawners) {
convertFrom.convertSpawners();

View File

@ -1,6 +1,6 @@
package com.songoda.ultimatestacker.hook;
import com.songoda.ultimatestacker.entity.EntityStack;
import com.songoda.ultimatestacker.stackable.entity.EntityStack;
import org.bukkit.entity.Player;
public interface StackerHook {

View File

@ -4,7 +4,7 @@ import com.gamingmesh.jobs.Jobs;
import com.gamingmesh.jobs.actions.EntityActionInfo;
import com.gamingmesh.jobs.container.ActionType;
import com.gamingmesh.jobs.container.JobsPlayer;
import com.songoda.ultimatestacker.entity.EntityStack;
import com.songoda.ultimatestacker.stackable.entity.EntityStack;
import com.songoda.ultimatestacker.hook.StackerHook;
import org.bukkit.GameMode;
import org.bukkit.entity.Entity;
@ -22,7 +22,7 @@ public class JobsHook implements StackerHook {
return;
for (int i = 1; i < entityStack.getAmount(); i++) {
Entity entity = entityStack.getEntity();
Entity entity = entityStack.getHostEntity();
EntityActionInfo eInfo = new EntityActionInfo(entity, ActionType.KILL);
Jobs.action(jPlayer, eInfo, entity);
}

View File

@ -1,5 +1,6 @@
package com.songoda.ultimatestacker.listeners;
import com.songoda.core.compatibility.CompatibleHand;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.core.nms.NmsManager;
import com.songoda.core.nms.nbt.NBTItem;
@ -7,11 +8,13 @@ import com.songoda.ultimatestacker.UltimateStacker;
import com.songoda.ultimatestacker.events.SpawnerBreakEvent;
import com.songoda.ultimatestacker.events.SpawnerPlaceEvent;
import com.songoda.ultimatestacker.settings.Settings;
import com.songoda.ultimatestacker.spawner.SpawnerStack;
import com.songoda.ultimatestacker.stackable.block.BlockStack;
import com.songoda.ultimatestacker.stackable.block.BlockStackManager;
import com.songoda.ultimatestacker.stackable.spawner.SpawnerStack;
import com.songoda.ultimatestacker.utils.Methods;
import java.util.ArrayList;
import org.apache.commons.lang.math.NumberUtils;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.block.Block;
import org.bukkit.block.CreatureSpawner;
import org.bukkit.enchantments.Enchantment;
@ -28,8 +31,7 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.BlockStateMeta;
import java.util.List;
import org.bukkit.event.block.BlockExplodeEvent;
import org.bukkit.event.entity.EntityExplodeEvent;
import java.util.Map;
public class BlockListeners implements Listener {
@ -40,18 +42,79 @@ public class BlockListeners implements Listener {
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onSpawnerInteract(PlayerInteractEvent event) {
public void onBlockInteract(PlayerInteractEvent event) {
Block block = event.getClickedBlock();
Player player = event.getPlayer();
ItemStack item = event.getPlayer().getInventory().getItemInHand();
if (block == null
|| block.getType() != CompatibleMaterial.SPAWNER.getMaterial()
if (block == null) return;
if (Settings.STACK_BLOCKS.getBoolean()) {
CompatibleHand hand = CompatibleHand.getHand(event);
ItemStack inHand = hand.getItem(player);
BlockStackManager blockStackManager = plugin.getBlockStackManager();
boolean isStacked = blockStackManager.isBlock(block.getLocation());
CompatibleMaterial blockType = CompatibleMaterial.getMaterial(block);
if (isStacked || Settings.STACKABLE_BLOCKS.getStringList().contains(blockType.name())) {
BlockStack stack = blockStackManager.getBlock(block, blockType);
if (event.getAction() == Action.RIGHT_CLICK_BLOCK) {
if (!isStacked) plugin.getDataManager().createBlock(stack);
if (stack.getMaterial() == CompatibleMaterial.getMaterial(inHand)) {
int amountToAdd = player.isSneaking() || Settings.ALWAYS_ADD_ALL.getBoolean() ? inHand.getAmount() : 1;
if (!isStacked) amountToAdd ++;
stack.add(amountToAdd);
event.setCancelled(true);
if (player.getGameMode() != GameMode.CREATIVE)
hand.takeItem(player, amountToAdd);
plugin.updateHologram(stack);
}
plugin.getDataManager().updateBlock(stack);
} else if (event.getAction() == Action.LEFT_CLICK_BLOCK && stack.getAmount() != 0) {
event.setCancelled(true);
int amountToRemove = player.isSneaking()
? Math.min(Settings.MAX_REMOVEABLE.getInt(), stack.getAmount()) - 1 : 1;
ItemStack removed = stack.getMaterial().getItem();
removed.setAmount(amountToRemove);
stack.take(amountToRemove);
int maxStack = removed.getMaxStackSize();
while (amountToRemove > 0) {
int subtract = Math.min(amountToRemove, maxStack);
amountToRemove -= subtract;
ItemStack newItem = removed.clone();
newItem.setAmount(subtract);
if (Settings.ADD_TO_INVENTORY.getBoolean()) {
Map<Integer, ItemStack> result = player.getInventory().addItem(newItem);
if (result.get(0) != null) {
amountToRemove += result.get(0).getAmount();
break;
}
} else {
block.getWorld().dropItemNaturally(block.getLocation().clone().add(.5, 1, .5), newItem);
}
}
stack.add(amountToRemove);
if (stack.getAmount() < 2)
stack.destroy();
else {
plugin.updateHologram(stack);
plugin.getDataManager().updateBlock(stack);
}
}
}
}
if (block.getType() != CompatibleMaterial.SPAWNER.getMaterial()
|| item.getType() != CompatibleMaterial.SPAWNER.getMaterial()
|| event.getAction() == Action.LEFT_CLICK_BLOCK) return;
List<String> disabledWorlds = Settings.DISABLED_WORLDS.getStringList();
if (disabledWorlds.stream().anyMatch(worldStr -> event.getPlayer().getWorld().getName().equalsIgnoreCase(worldStr))) return;
if (disabledWorlds.stream().anyMatch(worldStr -> event.getPlayer().getWorld().getName().equalsIgnoreCase(worldStr)))
return;
if (!plugin.spawnersEnabled()) return;
@ -101,42 +164,36 @@ public class BlockListeners implements Listener {
Methods.takeItem(player, itemAmount);
}
}
plugin.updateHologram(block);
}
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onSpawnerPlace(BlockPlaceEvent event) {
public void onBlockPlace(BlockPlaceEvent event) {
Block block = event.getBlock();
Player player = event.getPlayer();
if (!event.isCancelled()) {
if (block.getType() != CompatibleMaterial.SPAWNER.getMaterial()
|| !(block.getState() instanceof CreatureSpawner) // Needed for a DataPack
|| !plugin.spawnersEnabled())
return;
if (block.getType() != CompatibleMaterial.SPAWNER.getMaterial()
|| !(block.getState() instanceof CreatureSpawner) // Needed for a DataPack
|| !plugin.spawnersEnabled())
return;
CreatureSpawner cs = (CreatureSpawner) block.getState();
CreatureSpawner cs2 = (CreatureSpawner) ((BlockStateMeta) event.getItemInHand().getItemMeta()).getBlockState();
int amount = getSpawnerAmount(event.getItemInHand());
CreatureSpawner cs = (CreatureSpawner) block.getState();
CreatureSpawner cs2 = (CreatureSpawner) ((BlockStateMeta) event.getItemInHand().getItemMeta()).getBlockState();
int amount = getSpawnerAmount(event.getItemInHand());
SpawnerPlaceEvent placeEvent = new SpawnerPlaceEvent(player, block, cs2.getSpawnedType(), amount);
Bukkit.getPluginManager().callEvent(placeEvent);
if (placeEvent.isCancelled()) {
event.setCancelled(true);
return;
}
SpawnerStack stack = plugin.getSpawnerStackManager().addSpawner(new SpawnerStack(block.getLocation(), amount));
plugin.getDataManager().createSpawner(stack);
cs.setSpawnedType(cs2.getSpawnedType());
cs.update();
plugin.updateHologram(stack);
SpawnerPlaceEvent placeEvent = new SpawnerPlaceEvent(player, block, cs2.getSpawnedType(), amount);
Bukkit.getPluginManager().callEvent(placeEvent);
if (placeEvent.isCancelled()) {
event.setCancelled(true);
return;
}
plugin.updateHologram(block);
SpawnerStack stack = plugin.getSpawnerStackManager().addSpawner(new SpawnerStack(block.getLocation(), amount));
plugin.getDataManager().createSpawner(stack);
cs.setSpawnedType(cs2.getSpawnedType());
cs.update();
plugin.updateHologram(stack);
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
@ -175,7 +232,7 @@ public class BlockListeners implements Listener {
if (remove) {
event.setCancelled(false);
plugin.clearHologram(stack);
plugin.removeHologram(stack);
SpawnerStack spawnerStack = plugin.getSpawnerStackManager().removeSpawner(block.getLocation());
plugin.getDataManager().deleteSpawner(spawnerStack);
} else {

View File

@ -0,0 +1,42 @@
package com.songoda.ultimatestacker.listeners;
import com.songoda.ultimatestacker.UltimateStacker;
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(UltimateStacker plugin) {
this.entityStackManager = plugin.getEntityStackManager();
}
@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);
}
}
}
}

View File

@ -3,6 +3,7 @@ package com.songoda.ultimatestacker.listeners;
import com.songoda.ultimatestacker.UltimateStacker;
import me.minebuilders.clearlag.events.EntityRemoveEvent;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
@ -17,7 +18,7 @@ public class ClearLagListeners implements Listener {
@EventHandler
public void onClearLaggTask(EntityRemoveEvent event) {
for (Entity entity : event.getWorld().getEntities()) {
if (instance.getEntityStackManager().isStacked(entity)) {
if (entity instanceof LivingEntity && instance.getEntityStackManager().isStackedAndLoaded((LivingEntity)entity)) {
instance.getEntityStackManager().removeStack(entity);
event.addEntity(entity);
}

View File

@ -5,7 +5,7 @@ import com.songoda.core.compatibility.ServerVersion;
import com.songoda.lootables.loot.Drop;
import com.songoda.lootables.loot.DropUtils;
import com.songoda.ultimatestacker.UltimateStacker;
import com.songoda.ultimatestacker.entity.EntityStack;
import com.songoda.ultimatestacker.stackable.entity.EntityStack;
import com.songoda.ultimatestacker.settings.Settings;
import org.bukkit.GameRule;
import org.bukkit.Material;
@ -57,7 +57,7 @@ public class DeathListeners implements Listener {
&& !event.getEntity().getWorld().getGameRuleValue(GameRule.DO_MOB_LOOT))
drops.clear();
if (instance.getEntityStackManager().isStacked(event.getEntity()))
if (instance.getEntityStackManager().isStackedAndLoaded(event.getEntity()))
instance.getEntityStackManager().getStack(event.getEntity())
.onDeath(event.getEntity(), drops, custom, event.getDroppedExp(), event);
else
@ -115,8 +115,11 @@ public class DeathListeners implements Listener {
public void onEntityHit(EntityDamageByEntityEvent event) {
if (!(event.getDamager() instanceof Player) || ServerVersion.isServerVersionAtOrBelow(ServerVersion.V1_12))
return;
if (!instance.getEntityStackManager().isStacked(event.getEntity())) return;
EntityStack stack = instance.getEntityStackManager().getStack(event.getEntity());
if (!(event.getEntity() instanceof LivingEntity)) return;
LivingEntity entity = (LivingEntity) event.getEntity();
if (!instance.getEntityStackManager().isStackedAndLoaded(entity)) return;
EntityStack stack = instance.getEntityStackManager().getStack(entity);
if (Settings.KILL_WHOLE_STACK_ON_DEATH.getBoolean() && Settings.REALISTIC_DAMAGE.getBoolean()) {
Player player = (Player) event.getDamager();

View File

@ -2,10 +2,10 @@ package com.songoda.ultimatestacker.listeners;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.ultimatestacker.UltimateStacker;
import com.songoda.ultimatestacker.entity.EntityStack;
import com.songoda.ultimatestacker.entity.EntityStackManager;
import com.songoda.ultimatestacker.settings.Settings;
import com.songoda.ultimatestacker.spawner.SpawnerStack;
import com.songoda.ultimatestacker.stackable.entity.EntityStack;
import com.songoda.ultimatestacker.stackable.entity.EntityStackManager;
import com.songoda.ultimatestacker.stackable.spawner.SpawnerStack;
import com.songoda.ultimatestacker.utils.Methods;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@ -17,12 +17,11 @@ import org.bukkit.entity.*;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.entity.EntityTransformEvent;
import org.bukkit.event.entity.ItemSpawnEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.util.Vector;
import java.util.ArrayList;
@ -38,15 +37,15 @@ public class EntityListeners implements Listener {
}
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onSpawn(CreatureSpawnEvent event) {
LivingEntity entity = event.getEntity();
entity.setMetadata("US_REASON", new FixedMetadataValue(plugin, event.getSpawnReason().name()));
if (event.getSpawnReason().name().equals("DROWNED")
|| event.getSpawnReason() == CreatureSpawnEvent.SpawnReason.LIGHTNING) {
String name = event.getEntity().getCustomName();
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin,
() -> plugin.getEntityStackManager().addSerializedStack(entity, name), 1L);
public void onSpawn(EntityTransformEvent event) {
EntityStackManager stackManager = plugin.getEntityStackManager();
if (stackManager.isStackedAndLoaded(event.getEntity().getUniqueId())
&& event.getEntity() instanceof LivingEntity
&& event.getTransformedEntity() instanceof LivingEntity) {
EntityStack stack = stackManager.updateStack((LivingEntity) event.getEntity(),
(LivingEntity) event.getTransformedEntity());
stack.releaseHost();
stack.updateStack();
}
}
@ -63,11 +62,15 @@ public class EntityListeners implements Listener {
if (entities.isEmpty()) return;
Entity entity = entities.get(0);
Entity nonLivingEntity = entities.get(0);
if (!(nonLivingEntity instanceof LivingEntity)) return;
LivingEntity entity = (LivingEntity) nonLivingEntity;
EntityStackManager stackManager = plugin.getEntityStackManager();
if (!stackManager.isStacked(entity)) return;
if (!stackManager.isStackedAndLoaded(entity)) return;
EntityStack stack = stackManager.getStack(entity);
@ -83,7 +86,9 @@ public class EntityListeners implements Listener {
public void onHurt(EntityDamageByEntityEvent event) {
if (!Settings.STACK_ENTITIES.getBoolean() || !(event.getDamager() instanceof Player)) return;
if (plugin.getEntityStackManager().isStacked(event.getEntity())
Entity entity = event.getEntity();
if (entity instanceof LivingEntity && plugin.getEntityStackManager().isStackedAndLoaded((LivingEntity) entity)
&& Settings.DISABLE_KNOCKBACK.getBoolean()
&& ((Player) event.getDamager()).getItemInHand().getEnchantmentLevel(Enchantment.KNOCKBACK) == 0) {
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, () -> {
@ -127,7 +132,7 @@ public class EntityListeners implements Listener {
SpawnerStack spawnerStack = plugin.getSpawnerStackManager().removeSpawner(spawnLocation);
plugin.getDataManager().deleteSpawner(spawnerStack);
plugin.removeHologram(block);
plugin.removeHologram(spawnerStack);
}
}

View File

@ -3,8 +3,8 @@ package com.songoda.ultimatestacker.listeners;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.core.compatibility.ServerVersion;
import com.songoda.ultimatestacker.UltimateStacker;
import com.songoda.ultimatestacker.entity.EntityStack;
import com.songoda.ultimatestacker.entity.Split;
import com.songoda.ultimatestacker.stackable.entity.EntityStack;
import com.songoda.ultimatestacker.stackable.entity.Split;
import com.songoda.ultimatestacker.settings.Settings;
import org.bukkit.Bukkit;
import org.bukkit.Material;
@ -38,7 +38,7 @@ public class InteractListeners implements Listener {
ItemStack item = player.getInventory().getItemInHand();
if (!plugin.getEntityStackManager().isStacked(entity)) return;
if (!plugin.getEntityStackManager().isStackedAndLoaded(entity)) return;
if (item.getType() != Material.NAME_TAG && !correctFood(item, entity)) return;
@ -56,7 +56,7 @@ public class InteractListeners implements Listener {
else if (entity instanceof Ageable && !((Ageable) entity).isAdult())
return;
plugin.getEntityUtils().splitFromStack(entity);
stack.releaseHost();
if (item.getType() == Material.NAME_TAG) {
entity.setCustomName(item.getItemMeta().getDisplayName());

View File

@ -3,9 +3,9 @@ package com.songoda.ultimatestacker.listeners;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.core.compatibility.ServerVersion;
import com.songoda.ultimatestacker.UltimateStacker;
import com.songoda.ultimatestacker.entity.EntityStack;
import com.songoda.ultimatestacker.entity.EntityStackManager;
import com.songoda.ultimatestacker.entity.Split;
import com.songoda.ultimatestacker.stackable.entity.EntityStack;
import com.songoda.ultimatestacker.stackable.entity.EntityStackManager;
import com.songoda.ultimatestacker.stackable.entity.Split;
import com.songoda.ultimatestacker.settings.Settings;
import org.bukkit.Material;
import org.bukkit.World;
@ -28,13 +28,13 @@ public class ShearListeners implements Listener {
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onShear(PlayerShearEntityEvent event) {
Entity entity = event.getEntity();
LivingEntity entity = (LivingEntity)event.getEntity();
if (entity.getType() != EntityType.SHEEP
&& entity.getType() != EntityType.MUSHROOM_COW
&& entity.getType() != EntityType.SNOWMAN) return;
EntityStackManager stackManager = plugin.getEntityStackManager();
if (!stackManager.isStacked(entity)) return;
if (!stackManager.isStackedAndLoaded(entity)) return;
if (event.getEntity().getType() == EntityType.SHEEP
&& Settings.SPLIT_CHECKS.getStringList().stream().noneMatch(line -> Split.valueOf(line) == Split.SHEEP_SHEAR)
@ -45,9 +45,10 @@ public class ShearListeners implements Listener {
return;
EntityStack stack = stackManager.getStack(entity);
if (Settings.SHEAR_IN_ONE_CLICK.getBoolean()) {
World world = entity.getLocation().getWorld();
EntityStack stack = stackManager.getStack(entity);
int amount = stack.getAmount() - 1;
ItemStack item = getDrop(entity);
if (item == null)
@ -76,7 +77,7 @@ public class ShearListeners implements Listener {
world.dropItemNaturally(entity.getLocation(), clone);
}
} else
plugin.getEntityUtils().splitFromStack((LivingEntity) entity);
stack.releaseHost();
}
private ItemStack getDrop(Entity entity) {

View File

@ -1,8 +1,9 @@
package com.songoda.ultimatestacker.listeners;
import com.songoda.ultimatestacker.UltimateStacker;
import com.songoda.ultimatestacker.entity.EntityStackManager;
import com.songoda.ultimatestacker.entity.Split;
import com.songoda.ultimatestacker.stackable.entity.EntityStack;
import com.songoda.ultimatestacker.stackable.entity.EntityStackManager;
import com.songoda.ultimatestacker.stackable.entity.Split;
import com.songoda.ultimatestacker.settings.Settings;
import org.bukkit.entity.*;
import org.bukkit.event.EventHandler;
@ -23,11 +24,13 @@ public class SheepDyeListeners implements Listener {
LivingEntity entity = event.getEntity();
EntityStackManager stackManager = plugin.getEntityStackManager();
if (!stackManager.isStacked(entity)) return;
if (!stackManager.isStackedAndLoaded(entity)) return;
if (Settings.SPLIT_CHECKS.getStringList().stream().noneMatch(line -> Split.valueOf(line) == Split.SHEEP_DYE))
return;
plugin.getEntityUtils().splitFromStack(entity);
EntityStack stack = stackManager.getStack(entity);
if (stack == null) return;
stack.releaseHost();
}
}

View File

@ -3,10 +3,10 @@ package com.songoda.ultimatestacker.listeners;
import com.songoda.core.compatibility.ServerVersion;
import com.songoda.core.nms.NmsManager;
import com.songoda.ultimatestacker.UltimateStacker;
import com.songoda.ultimatestacker.entity.EntityStack;
import com.songoda.ultimatestacker.stackable.entity.EntityStack;
import com.songoda.ultimatestacker.settings.Settings;
import com.songoda.ultimatestacker.spawner.SpawnerStack;
import com.songoda.ultimatestacker.spawner.SpawnerStackManager;
import com.songoda.ultimatestacker.stackable.spawner.SpawnerStack;
import com.songoda.ultimatestacker.stackable.spawner.SpawnerStackManager;
import com.songoda.ultimatestacker.utils.Methods;
import com.songoda.ultimatestacker.utils.Reflection;
import org.bukkit.GameMode;
@ -44,7 +44,9 @@ public class SpawnerListeners implements Listener {
spawnerStack.initialize();
EntityStack stack = plugin.getEntityStackManager().addStack(event.getEntity().getUniqueId(), spawnerStack.calculateSpawnCount());
EntityStack stack = plugin.getEntityStackManager().addStack((LivingEntity)event.getEntity());
stack.createDuplicates(spawnerStack.calculateSpawnCount());
stack.updateStack();
plugin.getStackingTask().attemptSplit(stack, (LivingEntity) event.getEntity());
}

View File

@ -1,18 +1,13 @@
package com.songoda.ultimatestacker.listeners;
import com.songoda.ultimatestacker.UltimateStacker;
import com.songoda.ultimatestacker.entity.EntityStack;
import com.songoda.ultimatestacker.entity.EntityStackManager;
import org.bukkit.entity.Entity;
import com.songoda.ultimatestacker.stackable.entity.EntityStack;
import com.songoda.ultimatestacker.stackable.entity.EntityStackManager;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Tameable;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityTameEvent;
import org.bukkit.util.Vector;
import java.util.concurrent.ThreadLocalRandom;
public class TameListeners implements Listener {
@ -24,27 +19,15 @@ public class TameListeners implements Listener {
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onTame(EntityTameEvent event) {
Entity entity = event.getEntity();
LivingEntity entity = event.getEntity();
EntityStackManager stackManager = plugin.getEntityStackManager();
if (!stackManager.isStacked(entity)) return;
Tameable tameable = (Tameable) entity;
if (!stackManager.isStackedAndLoaded(entity)) return;
EntityStack stack = plugin.getEntityStackManager().getStack(entity);
if (stack.getAmount() <= 1) return;
LivingEntity newEntity = plugin.getEntityUtils().newEntity((LivingEntity) tameable);
EntityStack second = plugin.getEntityStackManager().addStack(new EntityStack(newEntity, stack.getAmount() - 1));
stack.setAmount(1);
second.setAmount(stack.getAmount() - 1);
plugin.getEntityStackManager().removeStack(entity);
entity.setVelocity(getRandomVector());
}
private Vector getRandomVector() {
return new Vector(ThreadLocalRandom.current().nextDouble(-1, 1.01), 0, ThreadLocalRandom.current().nextDouble(-1, 1.01)).normalize().multiply(0.5);
stack.releaseHost();
}
}

View File

@ -479,7 +479,7 @@ public class LootablesManager {
new LootBuilder()
.setChildDropCount(1)
.addOnlyDropFors(EntityType.SKELETON,
ServerVersion.isServerVersionAtLeast(ServerVersion.V1_10) ? EntityType.STRAY : null)
ServerVersion.isServerVersionAtLeast(ServerVersion.V1_11) ? EntityType.STRAY : null)
.addChildLoot(new LootBuilder().setMaterial(CompatibleMaterial.MUSIC_DISC_11).build(),
new LootBuilder().setMaterial(CompatibleMaterial.MUSIC_DISC_13).build(),
new LootBuilder().setMaterial(CompatibleMaterial.MUSIC_DISC_BLOCKS).build(),

View File

@ -3,8 +3,9 @@ package com.songoda.ultimatestacker.settings;
import com.songoda.core.configuration.Config;
import com.songoda.core.configuration.ConfigSetting;
import com.songoda.ultimatestacker.UltimateStacker;
import com.songoda.ultimatestacker.entity.Check;
import com.songoda.ultimatestacker.entity.Split;
import com.songoda.ultimatestacker.stackable.entity.Check;
import com.songoda.ultimatestacker.stackable.entity.Split;
import jdk.nashorn.internal.ir.LiteralNode;
import java.util.Arrays;
import java.util.Collections;
@ -48,7 +49,7 @@ public class Settings {
"Should all qualifying entities in each chunk be stacked?",
"This will override the stacking radius.");
public static final ConfigSetting ENTITY_HOLOGRAMS = new ConfigSetting(config, "Entities.Holograms Enabled", true,
public static final ConfigSetting ENTITY_NAMETAGS = new ConfigSetting(config, "Entities.Holograms Enabled", true,
"Should holograms be displayed above stacked entities?");
public static final ConfigSetting HOLOGRAMS_ON_LOOK_ENTITY = new ConfigSetting(config, "Entities.Only Show Holograms On Look", false,
@ -110,18 +111,6 @@ public class Settings {
"\"NAME_TAG\", \"MUSHROOM_SHEAR\", \"SHEEP_SHEAR\", \"SNOWMAN_DERP\",",
"\"SHEEP_DYE\", \"ENTITY_BREED\".");
public static final ConfigSetting KEEP_FIRE = new ConfigSetting(config, "Entities.Keep Fire", true,
"Should fire ticks persist to the next entity when an entity dies?");
public static final ConfigSetting KEEP_POTION = new ConfigSetting(config, "Entities.Keep Potion Effects", true,
"Should potion effects persist to the next entity when an entity dies?");
public static final ConfigSetting CARRY_OVER_LOWEST_HEALTH = new ConfigSetting(config, "Entities.Carry Over Lowest Health", false,
"Should the lowest health be carried over when stacked?",
"This should not be used in collaboration with 'Stack Entity Health'.",
"If it is used this setting will be overrode.");
public static final ConfigSetting ONLY_STACK_FROM_SPAWNERS = new ConfigSetting(config, "Entities.Only Stack From Spawners", false,
"Should entities only be stacked if they originate from a spawner?",
"It should be noted that the identifier that tells the plugin",
@ -141,17 +130,6 @@ public class Settings {
"\"SHOULDER_ENTITY\", \"DROWNED\", \"SHEARED\", \"EXPLOSION\",",
"\"CUSTOM\", \"DEFAULT\".");
public static final ConfigSetting CARRY_OVER_METADATA_ON_DEATH = new ConfigSetting(config, "Entities.Carry Over Metadata On Death", true,
"With this enabled any metadata assigned from supported plugins such",
"as EpicSpawners and mcMMO will be preserved when the entity is killed.");
public static final ConfigSetting META_CARRY_OVER_MIN = new ConfigSetting(config, "Entities.Meta Carry Over Min", 10,
"The amount of time in seconds an entity needs to have lived",
"for in order for their metadata to be carried over to their next",
"stack on death. Setting this value to zero may improve compatibility",
"with other plugins but this will be at the cost of performance if you",
"have a lot of grinders on your server.");
public static final ConfigSetting WEAPONS_ARENT_EQUIPMENT = new ConfigSetting(config, "Entities.Weapons Arent Equipment", false,
"This allows entities holding weapons to stack. Enchanted weapons are excluded.",
"If you would like to disable the stacked entity check you can do that by removing",
@ -161,12 +139,6 @@ public class Settings {
"Should entities only be stacked if they are touching the ground",
"or swimming? This does not effect flying entities.");
public static final ConfigSetting STACK_ENTITY_HEALTH = new ConfigSetting(config, "Entities.Stack Entity Health", true,
"Should entity health be stacked? When enabled Entity stacks will",
"remember the health of all entities inside of the stack. This",
"works the best with 'Only Stack On Surface enabled' as entities",
"falling out of grinders may stack before hitting the ground.");
public static final ConfigSetting ONLY_STACK_FLYING_DOWN = new ConfigSetting(config, "Entities.Only Stack Flying Down", true,
"Should entities that fly only stack with entities that are lower on the",
"Y axis. This is important for grinders so that flying entities don't continuously",
@ -255,6 +227,31 @@ public class Settings {
"The text displayed above a stacked spawner where {TYPE} refers to",
"The entities type and {AMT} is the amount currently stacked.");
public static final ConfigSetting STACK_BLOCKS = new ConfigSetting(config, "Blocks.Enabled", true,
"Should blocks be stacked?");
public static final ConfigSetting BLOCK_HOLOGRAMS = new ConfigSetting(config, "Blocks.Holograms Enabled", true,
"Should holograms be displayed above stacked blocks?");
public static final ConfigSetting STACKABLE_BLOCKS = new ConfigSetting(config, "Blocks.Stackable Blocks", Collections.singletonList("DIAMOND_BLOCK"),
"What blocks should be stackable?");
public static final ConfigSetting ALWAYS_ADD_ALL = new ConfigSetting(config, "Blocks.Always Add All", false,
"Should the whole stack the player is holding always",
"be added to the stack regardless of if they are sneaking or not?");
public static final ConfigSetting MAX_REMOVEABLE = new ConfigSetting(config, "Blocks.Max Removeable", 64,
"What should be the max amount that can be removed with",
"a single click? Keep in mind high numbers could cause lag.");
public static final ConfigSetting ADD_TO_INVENTORY = new ConfigSetting(config, "Blocks.Add To Inventory", false,
"Should blocks be added directly to the inventory when removed?");
public static final ConfigSetting NAME_FORMAT_BLOCK = new ConfigSetting(config, "Blocks.Name Format", "&6{AMT}x &f{TYPE}",
"The text displayed above a stacked block where {TYPE} refers to",
"The entities type and {AMT} is the amount currently stacked.");
public static final ConfigSetting LANGUGE_MODE = new ConfigSetting(config, "System.Language Mode", "en_US",
"The enabled language file.",
"More language files (if available) can be found in the plugins data folder.");

View File

@ -0,0 +1,12 @@
package com.songoda.ultimatestacker.stackable;
import org.bukkit.Location;
public interface Hologramable {
Location getLocation();
String getHologramName();
boolean areHologramsEnabled();
}

View File

@ -0,0 +1,7 @@
package com.songoda.ultimatestacker.stackable;
public interface Stackable {
int getAmount();
}

View File

@ -0,0 +1,111 @@
package com.songoda.ultimatestacker.stackable.block;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.ultimatestacker.UltimateStacker;
import com.songoda.ultimatestacker.settings.Settings;
import com.songoda.ultimatestacker.stackable.Hologramable;
import com.songoda.ultimatestacker.stackable.Stackable;
import com.songoda.ultimatestacker.utils.Methods;
import org.bukkit.Location;
import org.bukkit.World;
public class BlockStack implements Stackable, Hologramable {
// The id that identifies this stack in the database.
private int id;
private int amount = 0;
private final CompatibleMaterial material;
private final Location location;
public BlockStack(CompatibleMaterial material, Location location) {
this.material = material;
this.location = location;
}
public BlockStack(CompatibleMaterial material, Location location, int amount) {
this.amount = amount;
this.material = material;
this.location = location;
}
@Override
public int getAmount() {
return amount;
}
public void add(int amount) {
this.amount = this.amount + amount;
}
public void take(int amount) {
this.amount = this.amount - amount;
}
public int getX() {
return location.getBlockX();
}
public int getY() {
return location.getBlockY();
}
public int getZ() {
return location.getBlockZ();
}
public World getWorld() {
return location.getWorld();
}
public void destroy() {
amount = 0;
UltimateStacker plugin = UltimateStacker.getInstance();
plugin.getBlockStackManager().removeBlock(location);
plugin.removeHologram(this);
plugin.getDataManager().deleteBlock(this);
}
@Override
public Location getLocation() {
return location;
}
public CompatibleMaterial getMaterial() {
return material;
}
@Override
public String getHologramName() {
String nameFormat = Settings.NAME_FORMAT_BLOCK.getString();
String displayName = Methods.formatText(material.name().toLowerCase().replace("_", " "), true);
nameFormat = nameFormat.replace("{TYPE}", displayName);
nameFormat = nameFormat.replace("{AMT}", Integer.toString(amount));
return Methods.formatText(nameFormat).trim();
}
@Override
public boolean areHologramsEnabled() {
return Settings.BLOCK_HOLOGRAMS.getBoolean();
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "BlockStack{" +
"id=" + id +
", amount=" + amount +
", material=" + material +
", location=" + location +
'}';
}
}

View File

@ -0,0 +1,53 @@
package com.songoda.ultimatestacker.stackable.block;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.ultimatestacker.stackable.spawner.SpawnerStack;
import org.bukkit.Location;
import org.bukkit.block.Block;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class BlockStackManager {
private final Map<Location, BlockStack> registeredBlocks = new HashMap<>();
public void addBlocks(Map<Location, BlockStack> blocks) {
this.registeredBlocks.putAll(blocks);
}
public BlockStack addBlock(BlockStack blockStack) {
this.registeredBlocks.put(roundLocation(blockStack.getLocation()), blockStack);
return blockStack;
}
public BlockStack removeBlock(Location location) {
return registeredBlocks.remove(roundLocation(location));
}
public BlockStack getBlock(Location location, CompatibleMaterial material) {
return this.registeredBlocks.computeIfAbsent(location, b -> new BlockStack(material, location));
}
public BlockStack getBlock(Block block, CompatibleMaterial material) {
return this.getBlock(block.getLocation(), material);
}
public boolean isBlock(Location location) {
return this.registeredBlocks.get(location) != null;
}
public Collection<BlockStack> getStacks() {
return Collections.unmodifiableCollection(this.registeredBlocks.values());
}
private Location roundLocation(Location location) {
location = location.clone();
location.setX(location.getBlockX());
location.setY(location.getBlockY());
location.setZ(location.getBlockZ());
return location;
}
}

View File

@ -1,4 +1,4 @@
package com.songoda.ultimatestacker.entity;
package com.songoda.ultimatestacker.stackable.entity;
import java.util.ArrayList;
import java.util.HashMap;
@ -15,31 +15,31 @@ public enum Check {
ANIMAL_OWNER(true),
SKELETON_TYPE(true),
ZOMBIE_BABY(true),
HAS_EQUIPMENT(true),
HAS_EQUIPMENT(false),
SLIME_SIZE(true),
PIG_SADDLE(true),
SHEEP_SHEARED(true),
SHEEP_COLOR(true),
SHEEP_COLOR(false),
SNOWMAN_DERPED(true),
WOLF_COLLAR_COLOR(true),
OCELOT_TYPE(true),
HORSE_COLOR(true),
OCELOT_TYPE(false),
HORSE_COLOR(false),
HORSE_STYLE(true),
HORSE_CARRYING_CHEST(true),
HORSE_HAS_ARMOR(true),
HORSE_HAS_SADDLE(true),
HORSE_JUMP(true),
RABBIT_TYPE(true),
RABBIT_TYPE(false),
VILLAGER_PROFESSION(true),
LLAMA_COLOR(true),
LLAMA_COLOR(false),
LLAMA_STRENGTH(true),
PARROT_TYPE(true),
PARROT_TYPE(false),
PUFFERFISH_STATE(true),
TROPICALFISH_PATTERN(true),
TROPICALFISH_BODY_COLOR(true),
TROPICALFISH_PATTERN_COLOR(true),
PHANTOM_SIZE(true),
CAT_TYPE(true);
CAT_TYPE(false);
private final boolean isEnabledByDefault;
private final static Map<String, Check> checks = new HashMap();

View File

@ -0,0 +1,137 @@
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.Stackable;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import java.util.*;
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 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) {
NBTEntity nbtEntity = NmsManager.getNbt().newEntity();
nbtEntity.deSerialize(stackedEntities.getFirst().getSerializedEntity());
LivingEntity newEntity = (LivingEntity)nbtEntity.spawn(location);
stackedEntities.removeFirst();
plugin.getDataManager().deleteStackedEntity(newEntity.getUniqueId());
return newEntity;
}
@Override
public int getAmount() {
return stackedEntities.size() + 1;
}
public void createDuplicates(int duplicates) {
this.createDuplicates = duplicates;
}
public int getCreateDuplicates() {
return createDuplicates;
}
protected StackedEntity getStackedEntity(Entity entity) {
return getStackedEntity(entity, false);
}
protected StackedEntity getStackedEntity(Entity entity, boolean newUUID) {
UUID uuid = entity.getUniqueId();
NBTEntity nbtEntity = NmsManager.getNbt().of(entity);
if (newUUID) {
uuid = UUID.randomUUID();
nbtEntity.set("UUID", uuid);
}
return new StackedEntity(uuid, nbtEntity.serialize("Attributes"));
}
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;
}
}

View File

@ -0,0 +1,192 @@
package com.songoda.ultimatestacker.stackable.entity;
import com.songoda.lootables.loot.Drop;
import com.songoda.lootables.loot.DropUtils;
import com.songoda.ultimatestacker.UltimateStacker;
import com.songoda.ultimatestacker.settings.Settings;
import com.songoda.ultimatestacker.utils.Methods;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Entity;
import org.bukkit.entity.ExperienceOrb;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
public class EntityStack extends ColdEntityStack {
// This is the host entity which is not stored in serialized nbt.
private LivingEntity hostEntity;
public EntityStack(LivingEntity hostEntity) {
super(hostEntity.getUniqueId());
this.hostEntity = hostEntity;
}
public EntityStack(LivingEntity hostEntity, ColdEntityStack coldEntityStack) {
this(hostEntity);
this.setId(coldEntityStack.getId());
this.stackedEntities.addAll(coldEntityStack.stackedEntities);
}
public StackedEntity addEntityToStack(Entity entity) {
StackedEntity stackedEntity = addEntityToStackSilently(entity);
updateStack();
return stackedEntity;
}
public void updateStack() {
if (createDuplicates != 0) {
List<StackedEntity> stackedEntities = new ArrayList<>();
for (int i = 0; i < createDuplicates; i++)
stackedEntities.add(addEntityToStackSilently(getStackedEntity(hostEntity, true)));
plugin.getDataManager().createStackedEntities(this, stackedEntities);
createDuplicates = 0;
}
if (!Settings.ENTITY_NAMETAGS.getBoolean()) return;
Bukkit.getScheduler().scheduleSyncDelayedTask(UltimateStacker.getInstance(), () -> {
if (hostEntity == null) return;
hostEntity.setCustomNameVisible(!Settings.HOLOGRAMS_ON_LOOK_ENTITY.getBoolean());
hostEntity.setCustomName(Methods.compileEntityName(hostEntity, getAmount()));
}, hostEntity == null ? 1L : 0L);
}
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.getEntityStackManager().removeStack(event.getEntity());
plugin.getDataManager().deleteHost(this);
Location killedLocation = killed.getLocation();
List<Drop> preStackedDrops = new ArrayList<>();
for (int i = 1; i < getAmount(); i++) {
if (i == 1) {
drops.removeIf(it -> it.getItemStack() != null
&& it.getItemStack().isSimilar(killed.getEquipment().getItemInHand()));
for (ItemStack item : killed.getEquipment().getArmorContents()) {
drops.removeIf(it -> it.getItemStack() != null && it.getItemStack().isSimilar(item));
}
}
if (custom)
drops = plugin.getLootablesManager().getDrops(killed);
preStackedDrops.addAll(drops);
}
if (!preStackedDrops.isEmpty())
DropUtils.processStackedDrop(killed, preStackedDrops, event);
if (droppedExp > 0)
killedLocation.getWorld().spawn(killedLocation, ExperienceOrb.class).setExperience(droppedExp * getAmount());
if (killed.getKiller() == null) return;
UltimateStacker.getInstance().addExp(killed.getKiller(), this);
}
private void handleSingleStackDeath(LivingEntity killed, List<Drop> drops, EntityDeathEvent event) {
EntityStackManager stackManager = plugin.getEntityStackManager();
killed.remove();
LivingEntity newEntity = takeOneAndSpawnEntity(killed.getLocation());
//if (!EntityUtils.isAware(killed))
// EntityUtils.setUnaware(newEntity);
DropUtils.processStackedDrop(killed, drops, event);
newEntity.setVelocity(killed.getVelocity());
stackManager.updateStack(killed, newEntity);
updateStack();
if (stackedEntities.isEmpty())
destroy();
}
public void onDeath(LivingEntity killed, List<Drop> drops, boolean custom, int droppedExp, EntityDeathEvent event) {
killed.setCustomName(null);
killed.setCustomNameVisible(false);
boolean killWholeStack = Settings.KILL_WHOLE_STACK_ON_DEATH.getBoolean()
|| plugin.getMobFile().getBoolean("Mobs." + killed.getType().name() + ".Kill Whole Stack");
if (killWholeStack && getAmount() != 1) {
handleWholeStackDeath(killed, drops, custom, droppedExp, event);
} else if (getAmount() != 1) {
List<String> reasons = Settings.INSTANT_KILL.getStringList();
EntityDamageEvent lastDamageCause = killed.getLastDamageCause();
if (lastDamageCause != null) {
EntityDamageEvent.DamageCause cause = lastDamageCause.getCause();
for (String s : reasons) {
if (!cause.name().equalsIgnoreCase(s)) continue;
handleWholeStackDeath(killed, drops, custom, Settings.NO_EXP_INSTANT_KILL.getBoolean() ? 0 : droppedExp, event);
return;
}
}
handleSingleStackDeath(killed, drops, event);
}
}
public void releaseHost() {
LivingEntity oldHost = hostEntity;
LivingEntity entity = takeOneAndSpawnEntity(hostEntity.getLocation());
if (!stackedEntities.isEmpty()) {
destroy(false);
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));
} else {
destroy();
}
updateStack();
}
public void destroy() {
destroy(true);
}
public void destroy(boolean full) {
if (full)
plugin.getEntityStackManager().removeStack(this.hostUniqueId);
if (hostEntity != null) {
hostEntity.setCustomNameVisible(false);
hostEntity.setCustomName(null);
}
hostEntity = null;
hostUniqueId = null;
}
@Override
public String toString() {
return "EntityStack{" +
"hostEntity=" + hostEntity +
'}';
}
}

View File

@ -0,0 +1,168 @@
package com.songoda.ultimatestacker.stackable.entity;
import com.songoda.ultimatestacker.UltimateStacker;
import com.songoda.ultimatestacker.utils.Methods;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import java.util.*;
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 addStack(LivingEntity entity) {
if (entity == null) return null;
EntityStack stack = new EntityStack(entity);
plugin.getDataManager().createHostEntity(stack);
stacks.put(entity.getUniqueId(), stack);
return stack;
}
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);
}
return null;
}
@Deprecated
public EntityStack addSerializedStack(LivingEntity entity) {
return addSerializedStack(entity, entity.getCustomName());
}
public EntityStack getStack(LivingEntity entity) {
EntityStack stack = getStack(entity.getUniqueId());
if (stack == null) stack = addSerializedStack(entity);
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();
}
return stack;
}
public Map<UUID, EntityStack> getStacks() {
return Collections.unmodifiableMap(stacks);
}
public EntityStack updateStack(LivingEntity oldEntity, LivingEntity newEntity) {
EntityStack stack = stacks.remove(oldEntity.getUniqueId());
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);
}
public void unloadStack(LivingEntity entity) {
EntityStack stack = stacks.get(entity.getUniqueId());
if (stack == null) return;
ColdEntityStack coldStack = new EntityStack(entity, stack);
stack.destroy();
coldStacks.put(entity.getUniqueId(), coldStack);
}
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);
}
}
}
}
}

View File

@ -1,4 +1,4 @@
package com.songoda.ultimatestacker.entity;
package com.songoda.ultimatestacker.stackable.entity;
public enum Split {

View File

@ -0,0 +1,22 @@
package com.songoda.ultimatestacker.stackable.entity;
import java.util.UUID;
public class StackedEntity {
private final UUID uniqueId;
private final byte[] serializedEntity;
public StackedEntity(UUID uniqueId, byte[] serializedEntity) {
this.uniqueId = uniqueId;
this.serializedEntity = serializedEntity;
}
public UUID getUniqueId() {
return uniqueId;
}
public byte[] getSerializedEntity() {
return serializedEntity;
}
}

View File

@ -1,8 +1,11 @@
package com.songoda.ultimatestacker.spawner;
package com.songoda.ultimatestacker.stackable.spawner;
import com.songoda.core.compatibility.ServerVersion;
import com.songoda.ultimatestacker.UltimateStacker;
import com.songoda.ultimatestacker.settings.Settings;
import com.songoda.ultimatestacker.stackable.Hologramable;
import com.songoda.ultimatestacker.stackable.Stackable;
import com.songoda.ultimatestacker.utils.Methods;
import com.songoda.ultimatestacker.utils.Reflection;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@ -11,7 +14,7 @@ import org.bukkit.block.CreatureSpawner;
import java.util.Random;
public class SpawnerStack {
public class SpawnerStack implements Stackable, Hologramable {
private int id;
private boolean initialized = false;
@ -19,23 +22,24 @@ public class SpawnerStack {
private final Location location;
private int amount;
private static final UltimateStacker plugin = UltimateStacker.getInstance();
public SpawnerStack(Location location, int amount) {
this.location = location;
this.amount = amount;
}
@Override
public int getAmount() {
return amount;
}
public void setAmount(int amount) {
UltimateStacker plugin = UltimateStacker.getInstance();
this.amount = amount;
plugin.getDataManager().updateSpawner(this);
}
public void updateAmount() {
UltimateStacker plugin = UltimateStacker.getInstance();
Bukkit.getScheduler().runTaskLater(plugin, () -> {
if (!(location.getBlock().getState() instanceof CreatureSpawner)) return;
int count = Settings.STACK_ENTITIES.getBoolean()
@ -73,6 +77,17 @@ public class SpawnerStack {
return location.clone();
}
@Override
public String getHologramName() {
CreatureSpawner creatureSpawner = (CreatureSpawner) location.getBlock().getState();
return Methods.compileSpawnerName(creatureSpawner.getSpawnedType(), amount);
}
@Override
public boolean areHologramsEnabled() {
return Settings.SPAWNER_HOLOGRAMS.getBoolean();
}
public int getX() {
return location.getBlockX();
}

View File

@ -1,4 +1,4 @@
package com.songoda.ultimatestacker.spawner;
package com.songoda.ultimatestacker.stackable.spawner;
import com.songoda.ultimatestacker.UltimateStacker;
import org.bukkit.Location;

View File

@ -2,8 +2,7 @@ package com.songoda.ultimatestacker.storage;
import com.songoda.core.configuration.Config;
import com.songoda.ultimatestacker.UltimateStacker;
import com.songoda.ultimatestacker.spawner.SpawnerStack;
import com.songoda.ultimatestacker.utils.Methods;
import java.util.List;
public abstract class Storage {
@ -25,11 +24,6 @@ public abstract class Storage {
public abstract void prepareSaveItem(String group, StorageItem... items);
public void updateData(UltimateStacker instance) {
for (SpawnerStack stack : instance.getSpawnerStackManager().getStacks()) {
prepareSaveItem("spawners", new StorageItem("location", Methods.serializeLocation(stack.getLocation())),
new StorageItem("amount", stack.getAmount()));
}
}
public abstract void doSave();

View File

@ -4,15 +4,19 @@ import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.core.compatibility.ServerVersion;
import com.songoda.core.hooks.WorldGuardHook;
import com.songoda.ultimatestacker.UltimateStacker;
import com.songoda.ultimatestacker.entity.EntityStack;
import com.songoda.ultimatestacker.entity.EntityStackManager;
import com.songoda.ultimatestacker.settings.Settings;
import com.songoda.ultimatestacker.utils.Methods;
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.utils.CachedChunk;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.*;
import org.bukkit.inventory.EntityEquipment;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.*;
@ -23,25 +27,31 @@ public class StackingTask extends BukkitRunnable {
private final EntityStackManager stackManager;
ConfigurationSection configurationSection = UltimateStacker.getInstance().getMobFile();
private final ConfigurationSection configurationSection = UltimateStacker.getInstance().getMobFile();
private final List<UUID> processed = new ArrayList<>();
private final Map<CachedChunk, Entity[]> cachedChunks = new HashMap<>();
private final HashMap<EntityType, Integer> entityStackSizes = new HashMap();
private final int maxEntityStackSize = Settings.MAX_STACK_ENTITIES.getInt();
private final int minEntityStackSize = Settings.MIN_STACK_ENTITIES.getInt();
private final int maxPerTypeStacksPerChunk = Settings.MAX_PER_TYPE_STACKS_PER_CHUNK.getInt();
private final List<String> disabledWorlds = Settings.DISABLED_WORLDS.getStringList();
private final boolean onlyStackFromSpawners = Settings.ONLY_STACK_FROM_SPAWNERS.getBoolean();
private final List<String> stackReasons = Settings.STACK_REASONS.getStringList();
private final boolean onlyStackOnSurface = Settings.ONLY_STACK_ON_SURFACE.getBoolean();
private final int maxEntityStackSize = Settings.MAX_STACK_ENTITIES.getInt(),
minEntityStackSize = Settings.MIN_STACK_ENTITIES.getInt(),
searchRadius = Settings.SEARCH_RADIUS.getInt(),
maxPerTypeStacksPerChunk = Settings.MAX_PER_TYPE_STACKS_PER_CHUNK.getInt();
private final List<String> disabledWorlds = Settings.DISABLED_WORLDS.getStringList(),
stackReasons = Settings.STACK_REASONS.getStringList();
private final List<Check> checks = Check.getChecks(Settings.STACK_CHECKS.getStringList());
private final boolean stackFlyingDown = Settings.ONLY_STACK_FLYING_DOWN.getBoolean(),
stackWholeChunk = Settings.STACK_WHOLE_CHUNK.getBoolean(),
weaponsArentEquipment = Settings.WEAPONS_ARENT_EQUIPMENT.getBoolean(),
onlyStackFromSpawners = Settings.ONLY_STACK_FROM_SPAWNERS.getBoolean(),
onlyStackOnSurface = Settings.ONLY_STACK_ON_SURFACE.getBoolean();
public StackingTask(UltimateStacker plugin) {
this.plugin = plugin;
this.stackManager = plugin.getEntityStackManager();
// Start stacking task.
runTaskTimer(plugin, 0, Settings.STACK_SEARCH_TICK_SPEED.getInt());
// Start the stacking task.
runTaskTimerAsynchronously(plugin, 0, Settings.STACK_SEARCH_TICK_SPEED.getInt());
}
@Override
@ -63,8 +73,9 @@ public class StackingTask extends BukkitRunnable {
// Get entity location to pass around as its faster this way.
Location location = entity.getLocation();
// Check to see if entity is stackable.
if (!isEntityStackable(entity, location)) continue;
// Check to see if entity is not stackable.
if (!isEntityStackable(entity))
continue;
// Make sure our entity has not already been processed.
// Skip it if it has been.
@ -80,14 +91,14 @@ public class StackingTask extends BukkitRunnable {
}
// Clear caches in preparation for the next run.
this.processed.clear();
plugin.getEntityUtils().clearChunkCache();
this.cachedChunks.clear();
}
public boolean isWorldDisabled(World world) {
return disabledWorlds.stream().anyMatch(worldStr -> world.getName().equalsIgnoreCase(worldStr));
}
private boolean isEntityStackable(Entity entity, Location location) {
private boolean isEntityStackable(Entity entity) {
// Make sure we have the correct entity type and that it is valid.
if (!entity.isValid()
|| !(entity instanceof LivingEntity)
@ -117,7 +128,7 @@ public class StackingTask extends BukkitRunnable {
// If only stack on surface is enabled make sure the entity is on a surface then entity is stackable.
return !onlyStackOnSurface
|| Methods.canFly(livingEntity)
|| canFly(livingEntity)
|| entity.getType().name().equals("SHULKER")
|| (livingEntity.isOnGround()
@ -150,8 +161,11 @@ public class StackingTask extends BukkitRunnable {
// Get similar entities around our entity and make sure those entities are both compatible and stackable.
List<LivingEntity> stackableFriends = new LinkedList<>();
for (LivingEntity entity : plugin.getEntityUtils().getSimilarEntitiesAroundEntity(livingEntity, location)) {
if (!isEntityStackable(entity, location)) continue;
for (LivingEntity entity : getSimilarEntitiesAroundEntity(livingEntity, location)) {
// Check to see if entity is not stackable.
if (!isEntityStackable(entity))
continue;
// Add this entity to our stackable friends.
stackableFriends.add(entity);
}
@ -173,28 +187,29 @@ public class StackingTask extends BukkitRunnable {
// for this entity.
if (friendStack != null && (friendStack.getAmount() + amountToStack) <= maxEntityStackSize) {
// Add one to the found friendStack.
friendStack.addAmount(amountToStack);
// Add our entities health to the friendStacks health.
friendStack.addHealth(entity.getHealth());
// Fix the friendStacks health.
if (!isStack)
friendStack.addHealth(entity.getHealth());
else
friendStack.mergeHealth(stack);
fixHealth(entity, livingEntity);
if (Settings.STACK_ENTITY_HEALTH.getBoolean())
entity.setHealth(entity.getMaxHealth() < livingEntity.getHealth()
? entity.getMaxHealth() : livingEntity.getHealth());
// If we are a stack lets merge our stack with the just found friend stack.
if (isStack) {
// 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(stack.getHostAsStackedEntity());
// Add the collected entities to the new stack.
friendStack.addEntitiesToStackSilently(entities);
// Update friend stack to display changes.
friendStack.updateStack();
// Destroy our stack.
stack.destroy();
// 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));
}
// Drop lead if applicable then remove our entity and mark it as processed.
if (livingEntity.isLeashed())
livingEntity.getWorld().dropItemNaturally(livingEntity.getLocation(), CompatibleMaterial.LEAD.getItem());
Bukkit.getScheduler().runTask(plugin, () -> livingEntity.getWorld()
.dropItemNaturally(livingEntity.getLocation(), CompatibleMaterial.LEAD.getItem()));
livingEntity.remove();
processed.add(livingEntity.getUniqueId());
@ -202,27 +217,19 @@ public class StackingTask extends BukkitRunnable {
} else if (friendStack == null
&& isStack
&& (stack.getAmount() + 1) <= maxEntityStackSize
&& Methods.canFly(entity)
&& canFly(entity)
&& Settings.ONLY_STACK_FLYING_DOWN.getBoolean()
&& location.getY() > entity.getLocation().getY()) {
// Create a new stack with the current stacks amount and add one to it.
EntityStack newStack = stackManager.addStack(entity, stack.getAmount() + 1);
// Make the friend the new stack host.
EntityStack newStack = stackManager.updateStack(livingEntity, entity);
// Fix the entities health.
newStack.mergeHealth(stack);
newStack.addHealth(livingEntity.getHealth());
fixHealth(livingEntity, entity);
if (Settings.STACK_ENTITY_HEALTH.getBoolean())
entity.setHealth(entity.getHealth());
// Remove our entities stack from the stack manager.
stackManager.removeStack(livingEntity);
// Add our entity to that stack
plugin.getDataManager().createStackedEntity(newStack, newStack.addEntityToStack(livingEntity));
// Remove our entity and mark it as processed.
livingEntity.remove();
processed.add(livingEntity.getUniqueId());
return;
}
}
@ -236,11 +243,11 @@ public class StackingTask extends BukkitRunnable {
return;
// Remove all stacked entities from our stackable friends.
stackableFriends.removeIf(stackManager::isStacked);
stackableFriends.removeIf(stackManager::isStackedAndLoaded);
// If the stack cap is met then delete this entity.
if (maxPerTypeStacksPerChunk != -1
&& (plugin.getEntityUtils().getSimilarStacksInChunk(livingEntity) + 1) > maxPerTypeStacksPerChunk) {
&& (getSimilarStacksInChunk(livingEntity) + 1) > maxPerTypeStacksPerChunk) {
livingEntity.remove();
this.processed.add(livingEntity.getUniqueId());
return;
@ -253,56 +260,56 @@ public class StackingTask extends BukkitRunnable {
|| minEntityStackSize > maxEntityStackSize) return;
// If a stack was never found create a new one.
EntityStack newStack = stackManager.addStack(new EntityStack(livingEntity,
Math.min((stackableFriends.size() + 1), maxEntityStackSize)));
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.isStacked(entity)
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) {
processed.add(livingEntity.getUniqueId());
newStack.addAmount(-1);
newStack.destroy();
return;
}
// Fix the entities health.
fixHealth(livingEntity, entity);
newStack.addHealth(entity.getHealth());
// Drop lead if applicable then remove our entity and mark it as processed.
if (entity.isLeashed())
entity.getWorld().dropItemNaturally(entity.getLocation(), CompatibleMaterial.LEAD.getItem());
livingEntities.add(entity);
entity.remove();
processed.add(entity.getUniqueId());
});
// Update our stacks health.
updateHealth(newStack);
// 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();
}
private void updateHealth(EntityStack stack) {
if (Settings.STACK_ENTITY_HEALTH.getBoolean())
stack.updateHealth(stack.getEntity());
}
public boolean attemptSplit(EntityStack stack, LivingEntity livingEntity) {
int stackSize = stack.getAmount();
int maxEntityStackAmount = getEntityStackSize(livingEntity);
if (stackSize <= maxEntityStackAmount) return false;
for (int i = stackSize; i > 0; i -= maxEntityStackAmount)
this.processed.add(plugin.getEntityStackManager()
.addStack(plugin.getEntityUtils().newEntity(livingEntity), Math.min(i, maxEntityStackAmount)).getEntityUniqueId());
// Destroy the stack.
stack.destroy();
// Remove our entities stack from the stack manager.
stackManager.removeStack(livingEntity);
Bukkit.getScheduler().runTask(plugin, () -> {
for (int i = stackSize; i > 0; i -= maxEntityStackAmount) {
LivingEntity entity = stack.takeOneAndSpawnEntity(livingEntity.getLocation());
EntityStack newStack = plugin.getEntityStackManager().addStack(entity);
newStack.moveEntitiesFromStack(stack, Math.min(i, maxEntityStackAmount) - 1);
newStack.updateStack();
}
});
// Remove our entity and mark it as processed.
livingEntity.remove();
@ -310,10 +317,329 @@ public class StackingTask extends BukkitRunnable {
return true;
}
private Set<CachedChunk> getNearbyChunks(Location location, double radius, boolean singleChunk) {
World world = location.getWorld();
Set<CachedChunk> chunks = new HashSet<>();
if (world == null) return chunks;
private void fixHealth(LivingEntity entity, LivingEntity initialEntity) {
if (!Settings.STACK_ENTITY_HEALTH.getBoolean() && Settings.CARRY_OVER_LOWEST_HEALTH.getBoolean() && initialEntity.getHealth() < entity.getHealth())
entity.setHealth(initialEntity.getHealth());
CachedChunk firstChunk = new CachedChunk(location);
chunks.add(firstChunk);
if (singleChunk) return chunks;
int minX = (int) Math.floor(((location.getX() - radius) - 2.0D) / 16.0D);
int maxX = (int) Math.floor(((location.getX() + radius) + 2.0D) / 16.0D);
int minZ = (int) Math.floor(((location.getZ() - radius) - 2.0D) / 16.0D);
int maxZ = (int) Math.floor(((location.getZ() + radius) + 2.0D) / 16.0D);
for (int x = minX; x <= maxX; ++x) {
for (int z = minZ; z <= maxZ; ++z) {
if (firstChunk.getX() == x && firstChunk.getZ() == z) continue;
chunks.add(new CachedChunk(world.getName(), x, z));
}
}
return chunks;
}
private List<LivingEntity> getNearbyEntities(Location location, double radius, boolean singleChunk) {
List<LivingEntity> entities = new ArrayList<>();
for (CachedChunk chunk : getNearbyChunks(location, radius, singleChunk)) {
if (chunk == null) continue;
Entity[] entityArray;
if (cachedChunks.containsKey(chunk)) {
entityArray = cachedChunks.get(chunk);
} else {
entityArray = chunk.getEntities();
cachedChunks.put(chunk, entityArray);
}
if (entityArray == null) continue;
for (Entity e : entityArray) {
if (e == null) continue;
if (e.getWorld() != location.getWorld()
|| !(e instanceof LivingEntity)
|| (!singleChunk && location.distanceSquared(e.getLocation()) >= radius * radius)) continue;
entities.add((LivingEntity) e);
}
}
return entities;
}
public int getSimilarStacksInChunk(LivingEntity entity) {
int count = 0;
for (LivingEntity e : getNearbyEntities(entity.getLocation(), -1, true)) {
if (entity.getType() == e.getType() && plugin.getEntityStackManager().isStackedAndLoaded(e))
count++;
}
return count;
}
public List<LivingEntity> getSimilarEntitiesAroundEntity(LivingEntity initialEntity, Location location) {
// Create a list of all entities around the initial entity of the same type.
List<LivingEntity> entityList = new LinkedList<>();
for (LivingEntity entity : getNearbyEntities(location, searchRadius, stackWholeChunk)) {
if (entity.getType() != initialEntity.getType() || entity == initialEntity)
continue;
entityList.add(entity);
}
if (stackFlyingDown && canFly(initialEntity))
entityList.removeIf(entity -> entity.getLocation().getY() > initialEntity.getLocation().getY());
for (Check check : checks) {
if (check == null) continue;
switch (check) {
case SPAWN_REASON: {
if (initialEntity.hasMetadata("US_REASON"))
entityList.removeIf(entity -> entity.hasMetadata("US_REASON") && !entity.getMetadata("US_REASON").get(0).asString().equals("US_REASON"));
}
case AGE: {
if (!(initialEntity instanceof Ageable)) break;
if (((Ageable) initialEntity).isAdult()) {
entityList.removeIf(entity -> !((Ageable) entity).isAdult());
} else {
entityList.removeIf(entity -> ((Ageable) entity).isAdult());
}
break;
}
case NERFED: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_9)) break;
entityList.removeIf(entity -> entity.hasAI() != initialEntity.hasAI());
}
case IS_TAMED: {
if (!(initialEntity instanceof Tameable)) break;
if (((Tameable) initialEntity).isTamed()) {
entityList.removeIf(entity -> !((Tameable) entity).isTamed());
} else {
entityList.removeIf(entity -> ((Tameable) entity).isTamed());
}
}
case ANIMAL_OWNER: {
if (!(initialEntity instanceof Tameable)) break;
Tameable tameable = ((Tameable) initialEntity);
entityList.removeIf(entity -> ((Tameable) entity).getOwner() != tameable.getOwner());
}
case PIG_SADDLE: {
if (!(initialEntity instanceof Pig)) break;
entityList.removeIf(entity -> ((Pig) entity).hasSaddle());
break;
}
case SKELETON_TYPE: {
if (!(initialEntity instanceof Skeleton)) break;
Skeleton skeleton = (Skeleton) initialEntity;
entityList.removeIf(entity -> ((Skeleton) entity).getSkeletonType() != skeleton.getSkeletonType());
break;
}
case SHEEP_COLOR: {
if (!(initialEntity instanceof Sheep)) break;
Sheep sheep = ((Sheep) initialEntity);
entityList.removeIf(entity -> ((Sheep) entity).getColor() != sheep.getColor());
break;
}
case SHEEP_SHEARED: {
if (!(initialEntity instanceof Sheep)) break;
Sheep sheep = ((Sheep) initialEntity);
if (sheep.isSheared()) {
entityList.removeIf(entity -> !((Sheep) entity).isSheared());
} else {
entityList.removeIf(entity -> ((Sheep) entity).isSheared());
}
break;
}
case SNOWMAN_DERPED: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_9)
|| !(initialEntity instanceof Snowman)) break;
Snowman snowman = ((Snowman) initialEntity);
if (snowman.isDerp()) {
entityList.removeIf(entity -> !((Snowman) entity).isDerp());
} else {
entityList.removeIf(entity -> ((Snowman) entity).isDerp());
}
break;
}
case LLAMA_COLOR: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_11)
|| !(initialEntity instanceof Llama)) break;
Llama llama = ((Llama) initialEntity);
entityList.removeIf(entity -> ((Llama) entity).getColor() != llama.getColor());
break;
}
case LLAMA_STRENGTH: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_11)
|| !(initialEntity instanceof Llama)) break;
Llama llama = ((Llama) initialEntity);
entityList.removeIf(entity -> ((Llama) entity).getStrength() != llama.getStrength());
break;
}
case VILLAGER_PROFESSION: {
if (!(initialEntity instanceof Villager)) break;
Villager villager = ((Villager) initialEntity);
entityList.removeIf(entity -> ((Villager) entity).getProfession() != villager.getProfession());
break;
}
case SLIME_SIZE: {
if (!(initialEntity instanceof Slime)) break;
Slime slime = ((Slime) initialEntity);
entityList.removeIf(entity -> ((Slime) entity).getSize() != slime.getSize());
break;
}
case HORSE_CARRYING_CHEST: {
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_11)) {
if (!(initialEntity instanceof ChestedHorse)) break;
entityList.removeIf(entity -> ((ChestedHorse) entity).isCarryingChest());
} else {
if (!(initialEntity instanceof Horse)) break;
entityList.removeIf(entity -> ((Horse) entity).isCarryingChest());
}
break;
}
case HORSE_HAS_ARMOR: {
if (!(initialEntity instanceof Horse)) break;
entityList.removeIf(entity -> ((Horse) entity).getInventory().getArmor() != null);
break;
}
case HORSE_HAS_SADDLE: {
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)
&& initialEntity instanceof AbstractHorse) {
entityList.removeIf(entity -> ((AbstractHorse) entity).getInventory().getSaddle() != null);
break;
}
if (!(initialEntity instanceof Horse)) break;
entityList.removeIf(entity -> ((Horse) entity).getInventory().getSaddle() != null);
break;
}
case HORSE_JUMP: {
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_11)) {
if (!(initialEntity instanceof AbstractHorse)) break;
AbstractHorse horse = ((AbstractHorse) initialEntity);
entityList.removeIf(entity -> ((AbstractHorse) entity).getJumpStrength() != horse.getJumpStrength());
} else {
if (!(initialEntity instanceof Horse)) break;
Horse horse = ((Horse) initialEntity);
entityList.removeIf(entity -> ((Horse) entity).getJumpStrength() != horse.getJumpStrength());
}
break;
}
case HORSE_COLOR: {
if (!(initialEntity instanceof Horse)) break;
Horse horse = ((Horse) initialEntity);
entityList.removeIf(entity -> ((Horse) entity).getColor() != horse.getColor());
break;
}
case HORSE_STYLE: {
if (!(initialEntity instanceof Horse)) break;
Horse horse = ((Horse) initialEntity);
entityList.removeIf(entity -> ((Horse) entity).getStyle() != horse.getStyle());
break;
}
case ZOMBIE_BABY: {
if (!(initialEntity instanceof Zombie)) break;
Zombie zombie = (Zombie) initialEntity;
entityList.removeIf(entity -> ((Zombie) entity).isBaby() != zombie.isBaby());
break;
}
case WOLF_COLLAR_COLOR: {
if (!(initialEntity instanceof Wolf)) break;
Wolf wolf = (Wolf) initialEntity;
entityList.removeIf(entity -> ((Wolf) entity).getCollarColor() != wolf.getCollarColor());
break;
}
case OCELOT_TYPE: {
if (!(initialEntity instanceof Ocelot)) break;
Ocelot ocelot = (Ocelot) initialEntity;
entityList.removeIf(entity -> ((Ocelot) entity).getCatType() != ocelot.getCatType());
}
case CAT_TYPE: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_14)
|| !(initialEntity instanceof Cat)) break;
Cat cat = (Cat) initialEntity;
entityList.removeIf(entity -> ((Cat) entity).getCatType() != cat.getCatType());
break;
}
case HAS_EQUIPMENT: {
if (initialEntity.getEquipment() == null) break;
boolean imEquipped = isEquipped(initialEntity);
if (imEquipped)
entityList = new ArrayList<>();
else
entityList.removeIf(this::isEquipped);
break;
}
case RABBIT_TYPE: {
if (!(initialEntity instanceof Rabbit)) break;
Rabbit rabbit = (Rabbit) initialEntity;
entityList.removeIf(entity -> ((Rabbit) entity).getRabbitType() != rabbit.getRabbitType());
break;
}
case PARROT_TYPE: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_12)
|| !(initialEntity instanceof Parrot)) break;
Parrot parrot = (Parrot) initialEntity;
entityList.removeIf(entity -> ((Parrot) entity).getVariant() != parrot.getVariant());
break;
}
case PUFFERFISH_STATE: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)
|| !(initialEntity instanceof PufferFish)) break;
PufferFish pufferFish = (PufferFish) initialEntity;
entityList.removeIf(entity -> ((PufferFish) entity).getPuffState() != pufferFish.getPuffState());
break;
}
case TROPICALFISH_PATTERN: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)
|| !(initialEntity instanceof TropicalFish)) break;
TropicalFish tropicalFish = (TropicalFish) initialEntity;
entityList.removeIf(entity -> ((TropicalFish) entity).getPattern() != tropicalFish.getPattern());
break;
}
case TROPICALFISH_PATTERN_COLOR: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)
|| !(initialEntity instanceof TropicalFish)) break;
TropicalFish tropicalFish = (TropicalFish) initialEntity;
entityList.removeIf(entity -> ((TropicalFish) entity).getPatternColor() != tropicalFish.getPatternColor());
break;
}
case TROPICALFISH_BODY_COLOR: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)
|| !(initialEntity instanceof TropicalFish)) break;
TropicalFish tropicalFish = (TropicalFish) initialEntity;
entityList.removeIf(entity -> ((TropicalFish) entity).getBodyColor() != tropicalFish.getBodyColor());
break;
}
case PHANTOM_SIZE: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)
|| !(initialEntity instanceof Phantom)) break;
Phantom phantom = (Phantom) initialEntity;
entityList.removeIf(entity -> ((Phantom) entity).getSize() != phantom.getSize());
break;
}
}
}
if (initialEntity.hasMetadata("breedCooldown")) {
entityList.removeIf(entity -> !entity.hasMetadata("breedCooldown"));
}
return entityList;
}
public boolean isEquipped(LivingEntity initialEntity) {
if (initialEntity.getEquipment() == null) return false;
EntityEquipment equipment = initialEntity.getEquipment();
return (equipment.getItemInHand().getType() != Material.AIR
&& !weaponsArentEquipment && !equipment.getItemInHand().getEnchantments().isEmpty()
|| (equipment.getHelmet() != null && equipment.getHelmet().getType() != Material.AIR)
|| (equipment.getChestplate() != null && equipment.getChestplate().getType() != Material.AIR)
|| (equipment.getLeggings() != null && equipment.getLeggings().getType() != Material.AIR)
|| (equipment.getBoots() != null && equipment.getBoots().getType() != Material.AIR));
}
private int getEntityStackSize(LivingEntity initialEntity) {
@ -327,4 +653,17 @@ public class StackingTask extends BukkitRunnable {
}
return max;
}
public boolean canFly(LivingEntity entity) {
switch (entity.getType()) {
case GHAST:
case BLAZE:
case PHANTOM:
case BAT:
case BEE:
return true;
default:
return false;
}
}
}

View File

@ -1,537 +0,0 @@
package com.songoda.ultimatestacker.utils;
import com.songoda.core.compatibility.ServerVersion;
import com.songoda.ultimatestacker.UltimateStacker;
import com.songoda.ultimatestacker.entity.Check;
import com.songoda.ultimatestacker.entity.EntityStack;
import com.songoda.ultimatestacker.settings.Settings;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.*;
import org.bukkit.inventory.EntityEquipment;
import java.util.*;
public class EntityUtils {
UltimateStacker plugin = UltimateStacker.getInstance();
private final List<Check> checks = Check.getChecks(Settings.STACK_CHECKS.getStringList());
private final boolean stackFlyingDown = Settings.ONLY_STACK_FLYING_DOWN.getBoolean(),
keepFire = Settings.KEEP_FIRE.getBoolean(),
keepPotion = Settings.KEEP_POTION.getBoolean(),
stackWholeChunk = Settings.STACK_WHOLE_CHUNK.getBoolean(),
weaponsArentEquipment = Settings.WEAPONS_ARENT_EQUIPMENT.getBoolean();
private final int searchRadius = Settings.SEARCH_RADIUS.getInt();
private final Map<CachedChunk, Entity[]> cachedChunks = new HashMap<>();
public void clearChunkCache() {
this.cachedChunks.clear();
}
private Set<CachedChunk> getNearbyChunks(Location location, double radius, boolean singleChunk) {
World world = location.getWorld();
Set<CachedChunk> chunks = new HashSet<>();
if (world == null) return chunks;
CachedChunk firstChunk = new CachedChunk(location);
chunks.add(firstChunk);
if (singleChunk) return chunks;
int minX = (int) Math.floor(((location.getX() - radius) - 2.0D) / 16.0D);
int maxX = (int) Math.floor(((location.getX() + radius) + 2.0D) / 16.0D);
int minZ = (int) Math.floor(((location.getZ() - radius) - 2.0D) / 16.0D);
int maxZ = (int) Math.floor(((location.getZ() + radius) + 2.0D) / 16.0D);
for (int x = minX; x <= maxX; ++x) {
for (int z = minZ; z <= maxZ; ++z) {
if (firstChunk.getX() == x && firstChunk.getZ() == z) continue;
chunks.add(new CachedChunk(world.getName(), x, z));
}
}
return chunks;
}
private List<LivingEntity> getNearbyEntities(Location location, double radius, boolean singleChunk) {
List<LivingEntity> entities = new ArrayList<>();
for (CachedChunk chunk : getNearbyChunks(location, radius, singleChunk)) {
Entity[] entityArray;
if (cachedChunks.containsKey(chunk)) {
entityArray = cachedChunks.get(chunk);
} else {
entityArray = chunk.getEntities();
cachedChunks.put(chunk, entityArray);
}
for (Entity e : entityArray) {
if (e.getWorld() != location.getWorld()
|| !(e instanceof LivingEntity)
|| (!singleChunk && location.distanceSquared(e.getLocation()) >= radius * radius)) continue;
entities.add((LivingEntity) e);
}
}
return entities;
}
public int getSimilarStacksInChunk(LivingEntity entity) {
int count = 0;
for (LivingEntity e : getNearbyEntities(entity.getLocation(), -1, true)) {
if (entity.getType() == e.getType() && plugin.getEntityStackManager().isStacked(e))
count++;
}
return count;
}
public LivingEntity newEntity(LivingEntity toClone) {
LivingEntity newEntity = (LivingEntity) toClone.getWorld().spawnEntity(toClone.getLocation(), toClone.getType());
Player player = toClone.getKiller();
if (player == null
|| !Settings.DISABLE_KNOCKBACK.getBoolean()
|| player.getItemInHand().getEnchantmentLevel(Enchantment.KNOCKBACK) != 0) {
newEntity.setVelocity(toClone.getVelocity());
}
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_12))
newEntity.setInvulnerable(false);
for (Check check : checks) {
switch (check) {
case AGE: {
if (!(toClone instanceof Ageable) || ((Ageable) toClone).isAdult()) break;
((Ageable) newEntity).setBaby();
break;
}
case NERFED: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_9)) break;
if (!toClone.hasAI()) newEntity.setAI(false);
}
case IS_TAMED: {
if (!(toClone instanceof Tameable)) break;
((Tameable) newEntity).setTamed(((Tameable) toClone).isTamed());
}
case ANIMAL_OWNER: {
if (!(toClone instanceof Tameable)) break;
((Tameable) newEntity).setOwner(((Tameable) toClone).getOwner());
}
case SKELETON_TYPE: {
if (!(toClone instanceof Skeleton)
|| ServerVersion.isServerVersionAtLeast(ServerVersion.V1_11)) break;
((Skeleton) newEntity).setSkeletonType(((Skeleton) toClone).getSkeletonType());
break;
}
case SHEEP_COLOR: {
if (!(toClone instanceof Sheep)) break;
((Sheep) newEntity).setColor(((Sheep) toClone).getColor());
break;
}
case SHEEP_SHEARED: {
if (!(toClone instanceof Sheep)) break;
((Sheep) newEntity).setSheared(((Sheep) toClone).isSheared());
break;
}
case SNOWMAN_DERPED: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_9)
|| !(toClone instanceof Snowman)) break;
((Snowman) newEntity).setDerp(((Snowman) toClone).isDerp());
break;
}
case LLAMA_COLOR: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_11)
|| !(toClone instanceof Llama)) break;
((Llama) newEntity).setColor(((Llama) toClone).getColor());
break;
}
case LLAMA_STRENGTH: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_11)
|| !(toClone instanceof Llama)) break;
((Llama) newEntity).setStrength(((Llama) toClone).getStrength());
break;
}
case VILLAGER_PROFESSION: {
if (!(toClone instanceof Villager)) break;
((Villager) newEntity).setProfession(((Villager) toClone).getProfession());
break;
}
case SLIME_SIZE: {
if (!(toClone instanceof Slime)) break;
((Slime) newEntity).setSize(((Slime) toClone).getSize());
break;
}
case HORSE_JUMP: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_11)
|| !(toClone instanceof AbstractHorse)) break;
((AbstractHorse) newEntity).setJumpStrength(((AbstractHorse) toClone).getJumpStrength());
break;
}
case HORSE_COLOR: {
if (!(toClone instanceof Horse)) break;
((Horse) newEntity).setColor(((Horse) toClone).getColor());
break;
}
case HORSE_STYLE: {
if (!(toClone instanceof Horse)) break;
((Horse) newEntity).setStyle(((Horse) toClone).getStyle());
break;
}
case ZOMBIE_BABY: {
if (!(toClone instanceof Zombie)) break;
((Zombie) newEntity).setBaby(((Zombie) toClone).isBaby());
break;
}
case WOLF_COLLAR_COLOR: {
if (!(toClone instanceof Wolf)) break;
((Wolf) newEntity).setCollarColor(((Wolf) toClone).getCollarColor());
break;
}
case OCELOT_TYPE: {
if (!(toClone instanceof Ocelot)
|| ServerVersion.isServerVersionAtLeast(ServerVersion.V1_14)) break;
((Ocelot) newEntity).setCatType(((Ocelot) toClone).getCatType());
}
case CAT_TYPE: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_14)
|| !(toClone instanceof Cat)) break;
((Cat) newEntity).setCatType(((Cat) toClone).getCatType());
break;
}
case RABBIT_TYPE: {
if (!(toClone instanceof Rabbit)) break;
((Rabbit) newEntity).setRabbitType(((Rabbit) toClone).getRabbitType());
break;
}
case PARROT_TYPE: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_12)
|| !(toClone instanceof Parrot)) break;
((Parrot) newEntity).setVariant(((Parrot) toClone).getVariant());
break;
}
case PUFFERFISH_STATE: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)
|| !(toClone instanceof PufferFish)) break;
((PufferFish) newEntity).setPuffState(((PufferFish) toClone).getPuffState());
break;
}
case TROPICALFISH_PATTERN: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)
|| !(toClone instanceof TropicalFish)) break;
((TropicalFish) newEntity).setPattern(((TropicalFish) toClone).getPattern());
break;
}
case TROPICALFISH_PATTERN_COLOR: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)
|| !(toClone instanceof TropicalFish)) break;
((TropicalFish) newEntity).setPatternColor(((TropicalFish) toClone).getPatternColor());
break;
}
case TROPICALFISH_BODY_COLOR: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)
|| !(toClone instanceof TropicalFish)) break;
((TropicalFish) newEntity).setBodyColor(((TropicalFish) toClone).getBodyColor());
break;
}
case PHANTOM_SIZE: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)
|| !(toClone instanceof Phantom)) break;
((Phantom) newEntity).setSize(((Phantom) toClone).getSize());
break;
}
}
}
if (keepFire)
newEntity.setFireTicks(toClone.getFireTicks());
if (keepPotion)
newEntity.addPotionEffects(toClone.getActivePotionEffects());
return newEntity;
}
public List<LivingEntity> getSimilarEntitiesAroundEntity(LivingEntity initialEntity, Location location) {
// Create a list of all entities around the initial entity of the same type.
List<LivingEntity> entityList = new LinkedList<>();
for (LivingEntity entity : getNearbyEntities(location, searchRadius, stackWholeChunk)) {
if (entity.getType() != initialEntity.getType() || entity == initialEntity)
continue;
entityList.add(entity);
}
if (stackFlyingDown && Methods.canFly(initialEntity))
entityList.removeIf(entity -> entity.getLocation().getY() > initialEntity.getLocation().getY());
for (Check check : checks) {
if (check == null) continue;
switch (check) {
case SPAWN_REASON: {
if (initialEntity.hasMetadata("US_REASON"))
entityList.removeIf(entity -> entity.hasMetadata("US_REASON") && !entity.getMetadata("US_REASON").get(0).asString().equals("US_REASON"));
}
case AGE: {
if (!(initialEntity instanceof Ageable)) break;
if (((Ageable) initialEntity).isAdult()) {
entityList.removeIf(entity -> !((Ageable) entity).isAdult());
} else {
entityList.removeIf(entity -> ((Ageable) entity).isAdult());
}
break;
}
case NERFED: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_9)) break;
entityList.removeIf(entity -> entity.hasAI() != initialEntity.hasAI());
}
case IS_TAMED: {
if (!(initialEntity instanceof Tameable)) break;
if (((Tameable) initialEntity).isTamed()) {
entityList.removeIf(entity -> !((Tameable) entity).isTamed());
} else {
entityList.removeIf(entity -> ((Tameable) entity).isTamed());
}
}
case ANIMAL_OWNER: {
if (!(initialEntity instanceof Tameable)) break;
Tameable tameable = ((Tameable) initialEntity);
entityList.removeIf(entity -> ((Tameable) entity).getOwner() != tameable.getOwner());
}
case PIG_SADDLE: {
if (!(initialEntity instanceof Pig)) break;
entityList.removeIf(entity -> ((Pig) entity).hasSaddle());
break;
}
case SKELETON_TYPE: {
if (!(initialEntity instanceof Skeleton)) break;
Skeleton skeleton = (Skeleton) initialEntity;
entityList.removeIf(entity -> ((Skeleton) entity).getSkeletonType() != skeleton.getSkeletonType());
break;
}
case SHEEP_COLOR: {
if (!(initialEntity instanceof Sheep)) break;
Sheep sheep = ((Sheep) initialEntity);
entityList.removeIf(entity -> ((Sheep) entity).getColor() != sheep.getColor());
break;
}
case SHEEP_SHEARED: {
if (!(initialEntity instanceof Sheep)) break;
Sheep sheep = ((Sheep) initialEntity);
if (sheep.isSheared()) {
entityList.removeIf(entity -> !((Sheep) entity).isSheared());
} else {
entityList.removeIf(entity -> ((Sheep) entity).isSheared());
}
break;
}
case SNOWMAN_DERPED: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_9)
|| !(initialEntity instanceof Snowman)) break;
Snowman snowman = ((Snowman) initialEntity);
if (snowman.isDerp()) {
entityList.removeIf(entity -> !((Snowman) entity).isDerp());
} else {
entityList.removeIf(entity -> ((Snowman) entity).isDerp());
}
break;
}
case LLAMA_COLOR: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_11)
|| !(initialEntity instanceof Llama)) break;
Llama llama = ((Llama) initialEntity);
entityList.removeIf(entity -> ((Llama) entity).getColor() != llama.getColor());
break;
}
case LLAMA_STRENGTH: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_11)
|| !(initialEntity instanceof Llama)) break;
Llama llama = ((Llama) initialEntity);
entityList.removeIf(entity -> ((Llama) entity).getStrength() != llama.getStrength());
break;
}
case VILLAGER_PROFESSION: {
if (!(initialEntity instanceof Villager)) break;
Villager villager = ((Villager) initialEntity);
entityList.removeIf(entity -> ((Villager) entity).getProfession() != villager.getProfession());
break;
}
case SLIME_SIZE: {
if (!(initialEntity instanceof Slime)) break;
Slime slime = ((Slime) initialEntity);
entityList.removeIf(entity -> ((Slime) entity).getSize() != slime.getSize());
break;
}
case HORSE_CARRYING_CHEST: {
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_11)) {
if (!(initialEntity instanceof ChestedHorse)) break;
entityList.removeIf(entity -> ((ChestedHorse) entity).isCarryingChest());
} else {
if (!(initialEntity instanceof Horse)) break;
entityList.removeIf(entity -> ((Horse) entity).isCarryingChest());
}
break;
}
case HORSE_HAS_ARMOR: {
if (!(initialEntity instanceof Horse)) break;
entityList.removeIf(entity -> ((Horse) entity).getInventory().getArmor() != null);
break;
}
case HORSE_HAS_SADDLE: {
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)
&& initialEntity instanceof AbstractHorse) {
entityList.removeIf(entity -> ((AbstractHorse) entity).getInventory().getSaddle() != null);
break;
}
if (!(initialEntity instanceof Horse)) break;
entityList.removeIf(entity -> ((Horse) entity).getInventory().getSaddle() != null);
break;
}
case HORSE_JUMP: {
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_11)) {
if (!(initialEntity instanceof AbstractHorse)) break;
AbstractHorse horse = ((AbstractHorse) initialEntity);
entityList.removeIf(entity -> ((AbstractHorse) entity).getJumpStrength() != horse.getJumpStrength());
} else {
if (!(initialEntity instanceof Horse)) break;
Horse horse = ((Horse) initialEntity);
entityList.removeIf(entity -> ((Horse) entity).getJumpStrength() != horse.getJumpStrength());
}
break;
}
case HORSE_COLOR: {
if (!(initialEntity instanceof Horse)) break;
Horse horse = ((Horse) initialEntity);
entityList.removeIf(entity -> ((Horse) entity).getColor() != horse.getColor());
break;
}
case HORSE_STYLE: {
if (!(initialEntity instanceof Horse)) break;
Horse horse = ((Horse) initialEntity);
entityList.removeIf(entity -> ((Horse) entity).getStyle() != horse.getStyle());
break;
}
case ZOMBIE_BABY: {
if (!(initialEntity instanceof Zombie)) break;
Zombie zombie = (Zombie) initialEntity;
entityList.removeIf(entity -> ((Zombie) entity).isBaby() != zombie.isBaby());
break;
}
case WOLF_COLLAR_COLOR: {
if (!(initialEntity instanceof Wolf)) break;
Wolf wolf = (Wolf) initialEntity;
entityList.removeIf(entity -> ((Wolf) entity).getCollarColor() != wolf.getCollarColor());
break;
}
case OCELOT_TYPE: {
if (!(initialEntity instanceof Ocelot)) break;
Ocelot ocelot = (Ocelot) initialEntity;
entityList.removeIf(entity -> ((Ocelot) entity).getCatType() != ocelot.getCatType());
}
case CAT_TYPE: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_14)
|| !(initialEntity instanceof Cat)) break;
Cat cat = (Cat) initialEntity;
entityList.removeIf(entity -> ((Cat) entity).getCatType() != cat.getCatType());
break;
}
case HAS_EQUIPMENT: {
if (initialEntity.getEquipment() == null) break;
boolean imEquipped = isEquipped(initialEntity);
if (imEquipped)
entityList = new ArrayList<>();
else
entityList.removeIf(this::isEquipped);
break;
}
case RABBIT_TYPE: {
if (!(initialEntity instanceof Rabbit)) break;
Rabbit rabbit = (Rabbit) initialEntity;
entityList.removeIf(entity -> ((Rabbit) entity).getRabbitType() != rabbit.getRabbitType());
break;
}
case PARROT_TYPE: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_12)
|| !(initialEntity instanceof Parrot)) break;
Parrot parrot = (Parrot) initialEntity;
entityList.removeIf(entity -> ((Parrot) entity).getVariant() != parrot.getVariant());
break;
}
case PUFFERFISH_STATE: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)
|| !(initialEntity instanceof PufferFish)) break;
PufferFish pufferFish = (PufferFish) initialEntity;
entityList.removeIf(entity -> ((PufferFish) entity).getPuffState() != pufferFish.getPuffState());
break;
}
case TROPICALFISH_PATTERN: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)
|| !(initialEntity instanceof TropicalFish)) break;
TropicalFish tropicalFish = (TropicalFish) initialEntity;
entityList.removeIf(entity -> ((TropicalFish) entity).getPattern() != tropicalFish.getPattern());
break;
}
case TROPICALFISH_PATTERN_COLOR: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)
|| !(initialEntity instanceof TropicalFish)) break;
TropicalFish tropicalFish = (TropicalFish) initialEntity;
entityList.removeIf(entity -> ((TropicalFish) entity).getPatternColor() != tropicalFish.getPatternColor());
break;
}
case TROPICALFISH_BODY_COLOR: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)
|| !(initialEntity instanceof TropicalFish)) break;
TropicalFish tropicalFish = (TropicalFish) initialEntity;
entityList.removeIf(entity -> ((TropicalFish) entity).getBodyColor() != tropicalFish.getBodyColor());
break;
}
case PHANTOM_SIZE: {
if (!ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)
|| !(initialEntity instanceof Phantom)) break;
Phantom phantom = (Phantom) initialEntity;
entityList.removeIf(entity -> ((Phantom) entity).getSize() != phantom.getSize());
break;
}
}
}
if (initialEntity.hasMetadata("breedCooldown")) {
entityList.removeIf(entity -> !entity.hasMetadata("breedCooldown"));
}
return entityList;
}
public boolean isEquipped(LivingEntity initialEntity) {
if (initialEntity.getEquipment() == null) return false;
EntityEquipment equipment = initialEntity.getEquipment();
return (equipment.getItemInHand().getType() != Material.AIR
&& !weaponsArentEquipment && !equipment.getItemInHand().getEnchantments().isEmpty()
|| (equipment.getHelmet() != null && equipment.getHelmet().getType() != Material.AIR)
|| (equipment.getChestplate() != null && equipment.getChestplate().getType() != Material.AIR)
|| (equipment.getLeggings() != null && equipment.getLeggings().getType() != Material.AIR)
|| (equipment.getBoots() != null && equipment.getBoots().getType() != Material.AIR));
}
public void splitFromStack(LivingEntity entity) {
UltimateStacker instance = plugin;
EntityStack stack = instance.getEntityStackManager().getStack(entity);
if (stack.getAmount() <= 1) return;
LivingEntity newEntity = newEntity(entity);
int newAmount = stack.getAmount() - 1;
if (newAmount != 1)
instance.getEntityStackManager().addStack(new EntityStack(newEntity, newAmount));
stack.setAmount(1);
instance.getEntityStackManager().removeStack(entity);
entity.setVelocity(Methods.getRandomVector());
}
}

View File

@ -106,23 +106,6 @@ public class Methods {
return info + Methods.formatText(nameFormat).trim();
}
public static boolean canFly(LivingEntity entity) {
switch (entity.getType()) {
case GHAST:
case BLAZE:
case PHANTOM:
case BAT:
case BEE:
return true;
default:
return false;
}
}
static Vector getRandomVector() {
return new Vector(ThreadLocalRandom.current().nextDouble(-1, 1.01), 0, ThreadLocalRandom.current().nextDouble(-1, 1.01)).normalize().multiply(0.5);
}
public static String compileSpawnerName(EntityType entityType, int amount) {
String nameFormat = UltimateStacker.getInstance().getConfig().getString("Spawners.Name Format");
String displayName = Methods.formatText(UltimateStacker.getInstance().getSpawnerFile().getString("Spawners." + entityType.name() + ".Display Name"));
@ -130,8 +113,7 @@ public class Methods {
nameFormat = nameFormat.replace("{TYPE}", displayName);
nameFormat = nameFormat.replace("{AMT}", Integer.toString(amount));
String info = TextUtils.convertToInvisibleString(insertSemicolon(String.valueOf(amount)) + ":");
return info + Methods.formatText(nameFormat).trim();
return Methods.formatText(nameFormat).trim();
}
public static String compileEntityName(Entity entity, int amount) {
@ -141,9 +123,7 @@ public class Methods {
nameFormat = nameFormat.replace("{TYPE}", displayName);
nameFormat = nameFormat.replace("{AMT}", Integer.toString(amount));
String info = TextUtils.convertToInvisibleString(insertSemicolon(String.valueOf(amount)) + ":");
return info + Methods.formatText(nameFormat).trim();
return Methods.formatText(nameFormat).trim();
}
public static void takeItem(Player player, int amount) {
@ -182,37 +162,6 @@ public class Methods {
return true;
}
/**
* Serializes the location of the block specified.
*
* @param b The block whose location is to be saved.
* @return The serialized data.
*/
public static String serializeLocation(Block b) {
if (b == null)
return "";
return serializeLocation(b.getLocation());
}
/**
* Serializes the location specified.
*
* @param location The location that is to be saved.
* @return The serialized data.
*/
public static String serializeLocation(Location location) {
if (location == null || location.getWorld() == null)
return "";
String w = location.getWorld().getName();
double x = location.getX();
double y = location.getY();
double z = location.getZ();
String str = w + ":" + x + ":" + y + ":" + z;
str = str.replace(".0", "").replace(".", "/");
return str;
}
private static Map<String, Location> serializeCache = new HashMap<>();
/**