mirror of
https://github.com/songoda/UltimateStacker.git
synced 2025-02-17 03:41:20 +01:00
Improve stacking task speed. Add some new settings and instant stacking
This commit is contained in:
parent
711d153fcf
commit
7120f9895a
@ -101,6 +101,7 @@ public class UltimateStacker extends SongodaPlugin {
|
||||
private StackingTask stackingTask;
|
||||
private UltimateStackerApi API;
|
||||
private SuperiorSkyblock2Hook superiorSkyblock2Hook;
|
||||
private boolean instantStacking;
|
||||
|
||||
public static UltimateStacker getInstance() {
|
||||
return INSTANCE;
|
||||
@ -212,6 +213,7 @@ public class UltimateStacker extends SongodaPlugin {
|
||||
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13))
|
||||
pluginManager.registerEvents(new EntityCurrentListener(this), this);
|
||||
|
||||
this.instantStacking = Settings.STACK_ENTITIES.getBoolean() && Settings.INSTANT_STACKING.getBoolean();
|
||||
pluginManager.registerEvents(new EntityListeners(this), this);
|
||||
pluginManager.registerEvents(new ItemListeners(this), this);
|
||||
|
||||
@ -262,7 +264,11 @@ public class UltimateStacker extends SongodaPlugin {
|
||||
}
|
||||
});
|
||||
|
||||
this.stackingTask = new StackingTask(this);
|
||||
if (Settings.STACK_ENTITIES.getBoolean()) {
|
||||
//Start stacking task
|
||||
this.stackingTask = new StackingTask(this);
|
||||
}
|
||||
this.instantStacking = Settings.STACK_ENTITIES.getBoolean() && Settings.INSTANT_STACKING.getBoolean();
|
||||
final boolean useBlockHolo = Settings.BLOCK_HOLOGRAMS.getBoolean();
|
||||
this.dataManager.loadBatch(BlockStackImpl.class, "blocks").forEach((data) -> {
|
||||
BlockStack blockStack = (BlockStack) data;
|
||||
@ -301,8 +307,12 @@ public class UltimateStacker extends SongodaPlugin {
|
||||
this.setLocale(getConfig().getString("System.Language Mode"), true);
|
||||
this.locale.reloadMessages();
|
||||
|
||||
this.stackingTask.stop();
|
||||
this.stackingTask = new StackingTask(this);
|
||||
if (stackingTask != null) {
|
||||
this.stackingTask.stop();
|
||||
}
|
||||
if (Settings.STACK_ENTITIES.getBoolean()) {
|
||||
this.stackingTask = new StackingTask(this);
|
||||
}
|
||||
|
||||
this.mobFile.load();
|
||||
this.itemFile.load();
|
||||
@ -409,6 +419,10 @@ public class UltimateStacker extends SongodaPlugin {
|
||||
return superiorSkyblock2Hook;
|
||||
}
|
||||
|
||||
public boolean isInstantStacking() {
|
||||
return instantStacking;
|
||||
}
|
||||
|
||||
//////// Convenient API //////////
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,69 @@
|
||||
package com.craftaro.ultimatestacker.commands;
|
||||
|
||||
import com.craftaro.core.commands.AbstractCommand;
|
||||
import com.craftaro.core.world.SSpawner;
|
||||
import com.craftaro.third_party.com.cryptomorin.xseries.XMaterial;
|
||||
import com.craftaro.ultimatestacker.UltimateStacker;
|
||||
import com.craftaro.ultimatestacker.api.stack.spawner.SpawnerStack;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.CreatureSpawner;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class CommandForceSpawn extends AbstractCommand {
|
||||
private final UltimateStacker plugin;
|
||||
|
||||
public CommandForceSpawn(UltimateStacker plugin) {
|
||||
super(CommandType.PLAYER_ONLY, "forcespawn");
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ReturnType runCommand(CommandSender sender, String... args) {
|
||||
Player player = (Player) sender;
|
||||
|
||||
Block block = player.getTargetBlock(null, 200);
|
||||
|
||||
if (XMaterial.matchXMaterial(block.getType().name()).get() != XMaterial.SPAWNER) {
|
||||
this.plugin.getLocale().newMessage("&cThat is not a spawner...").sendPrefixedMessage(player);
|
||||
return ReturnType.FAILURE;
|
||||
}
|
||||
|
||||
//PlacedSpawner spawner = this.plugin.getSpawnerManager().getSpawnerFromWorld(block.getLocation());
|
||||
SpawnerStack spawner = this.plugin.getSpawnerStackManager().getSpawner(block.getLocation());
|
||||
if (spawner == null) {
|
||||
//it is a vanilla spawner
|
||||
CreatureSpawner vanillaSpawner = (CreatureSpawner) block.getState();
|
||||
SSpawner creatureSpawner = new SSpawner(block.getLocation());
|
||||
creatureSpawner.spawn(vanillaSpawner.getSpawnCount(), vanillaSpawner.getSpawnedType());
|
||||
} else {
|
||||
//it is an epic spawner
|
||||
spawner.spawn();
|
||||
}
|
||||
this.plugin.getLocale().newMessage("&aSpawning successful.").sendPrefixedMessage(player);
|
||||
return ReturnType.SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> onTab(CommandSender sender, String... args) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPermissionNode() {
|
||||
return "ultimatestacker.admin.forcespawn";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSyntax() {
|
||||
return "forcespawn";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Force the spawner you are looking at to spawn so long as the spawn conditions are met.";
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ import com.craftaro.core.commands.AbstractCommand;
|
||||
import com.craftaro.core.utils.TextUtils;
|
||||
import com.craftaro.ultimatestacker.UltimateStacker;
|
||||
import com.craftaro.ultimatestacker.api.stack.entity.EntityStack;
|
||||
import com.craftaro.ultimatestacker.tasks.StackingTask;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
@ -51,9 +52,12 @@ public class CommandSpawn extends AbstractCommand {
|
||||
}
|
||||
sender.sendMessage(TextUtils.formatText("&6" + list));
|
||||
} else {
|
||||
LivingEntity entity = (LivingEntity)player.getWorld().spawnEntity(player.getLocation(), type);
|
||||
EntityStack stack = plugin.getEntityStackManager().createStackedEntity(entity, Integer.parseInt(args[1]));
|
||||
plugin.getStackingTask().attemptSplit(stack, entity);
|
||||
StackingTask stackingTask = plugin.getStackingTask();
|
||||
if (stackingTask != null) {
|
||||
LivingEntity entity = (LivingEntity)player.getWorld().spawnEntity(player.getLocation(), type);
|
||||
EntityStack stack = plugin.getEntityStackManager().createStackedEntity(entity, Integer.parseInt(args[1]));
|
||||
stackingTask.attemptSplit(stack, -1);
|
||||
}
|
||||
}
|
||||
|
||||
return ReturnType.SUCCESS;
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.craftaro.ultimatestacker.listeners;
|
||||
|
||||
import com.craftaro.ultimatestacker.UltimateStacker;
|
||||
import com.craftaro.ultimatestacker.api.stack.entity.EntityStack;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
@ -17,6 +18,24 @@ public class BreedListeners implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onBread(EntityBreedEvent event) {
|
||||
//TODO: Fix breed. It removes a entity from the stack but not spawn a new one. (Splitting mechanic)
|
||||
boolean isMotherStacked = plugin.getEntityStackManager().isStackedEntity(event.getMother());
|
||||
boolean isFatherStacked = plugin.getEntityStackManager().isStackedEntity(event.getFather());
|
||||
|
||||
if (!isMotherStacked && !isFatherStacked) return;
|
||||
|
||||
if (isMotherStacked) {
|
||||
EntityStack stack = plugin.getEntityStackManager().getStackedEntity(event.getMother());
|
||||
if (stack.getAmount() <= 1) return;
|
||||
stack.releaseHost();
|
||||
}
|
||||
|
||||
if (isFatherStacked) {
|
||||
EntityStack stack = plugin.getEntityStackManager().getStackedEntity(event.getFather());
|
||||
if (stack.getAmount() <= 1) return;
|
||||
stack.releaseHost();
|
||||
}
|
||||
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, () -> {
|
||||
event.getFather().removeMetadata("breedCooldown", plugin);
|
||||
event.getMother().removeMetadata("breedCooldown", plugin);
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.craftaro.ultimatestacker.listeners.entity;
|
||||
|
||||
import com.craftaro.core.configuration.Config;
|
||||
import com.craftaro.third_party.com.cryptomorin.xseries.XMaterial;
|
||||
import com.craftaro.ultimatestacker.UltimateStacker;
|
||||
import com.craftaro.ultimatestacker.api.UltimateStackerApi;
|
||||
@ -8,6 +9,7 @@ import com.craftaro.ultimatestacker.api.stack.entity.EntityStackManager;
|
||||
import com.craftaro.ultimatestacker.api.stack.item.StackedItem;
|
||||
import com.craftaro.ultimatestacker.api.stack.spawner.SpawnerStack;
|
||||
import com.craftaro.ultimatestacker.settings.Settings;
|
||||
import com.craftaro.ultimatestacker.tasks.StackingTask;
|
||||
import com.craftaro.ultimatestacker.utils.Methods;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
@ -38,9 +40,12 @@ import java.util.List;
|
||||
public class EntityListeners implements Listener {
|
||||
|
||||
private final UltimateStacker plugin;
|
||||
private int searchRadius = Settings.SEARCH_RADIUS.getInt() * 16; //SEARCH_RADIUS is in chunks, so multiply by 16 to get blocks
|
||||
private Config mobsConfig;
|
||||
|
||||
public EntityListeners(UltimateStacker plugin) {
|
||||
this.plugin = plugin;
|
||||
mobsConfig = plugin.getMobFile();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@ -73,9 +78,7 @@ public class EntityListeners implements Listener {
|
||||
item.setAmount(Math.min(amount, item.getMaxStackSize()));
|
||||
if (amount > item.getMaxStackSize()) {
|
||||
StackedItem stackedItem = UltimateStackerApi.getStackedItemManager().getStackedItem(event.getEntity());
|
||||
if (stackedItem != null) {
|
||||
stackedItem.setAmount(amount - item.getMaxStackSize());
|
||||
}
|
||||
stackedItem.setAmount(amount - item.getMaxStackSize());
|
||||
}
|
||||
event.getEntity().setItemStack(item);
|
||||
}
|
||||
@ -102,7 +105,31 @@ public class EntityListeners implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onSpawn(CreatureSpawnEvent event) {
|
||||
event.getEntity().setMetadata("US_REASON", new FixedMetadataValue(plugin, event.getSpawnReason().name()));
|
||||
String spawnReason = event.getSpawnReason().name();
|
||||
if (plugin.isInstantStacking()) {
|
||||
LivingEntity spawningEntity = event.getEntity();
|
||||
EntityStackManager stackManager = plugin.getEntityStackManager();
|
||||
if (stackManager.isStackedEntity(spawningEntity)) return; //We don't want to stack split entities or respawned stacks
|
||||
|
||||
List<LivingEntity> stackableFriends = plugin.getStackingTask().getSimilarEntitiesAroundEntity(spawningEntity, spawningEntity.getLocation());
|
||||
if (stackableFriends.isEmpty()) {
|
||||
event.getEntity().setMetadata("US_REASON", new FixedMetadataValue(plugin, spawnReason));
|
||||
return;
|
||||
}
|
||||
|
||||
LivingEntity friendStack = stackableFriends.get(0);
|
||||
if (stackManager.isStackedEntity(friendStack)) {
|
||||
EntityStack stack = stackManager.getStackedEntity(friendStack);
|
||||
//getSimilarEntitiesAroundEntity check for max stack size, we don't need to check again
|
||||
stack.add(1);
|
||||
event.setCancelled(true);
|
||||
} else {
|
||||
stackManager.createStackedEntity(friendStack, 2);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
event.getEntity().setMetadata("US_REASON", new FixedMetadataValue(plugin, spawnReason));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
|
@ -67,6 +67,7 @@ public class LootablesManager {
|
||||
//Apply SuperiorSkyblock2 mob-drops multiplier if present
|
||||
if (superiorSkyblock2Hook.isEnabled()) {
|
||||
for (Drop drop : toDrop) {
|
||||
if (drop.getItemStack() == null) continue; //Maybe it is just exp
|
||||
drop.getItemStack().setAmount(superiorSkyblock2Hook.getDropMultiplier(entity.getLocation()) * drop.getItemStack().getAmount());
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,9 @@ public class Settings implements com.craftaro.ultimatestacker.api.Settings {
|
||||
"The speed in which a new stacks will be created.",
|
||||
"It is advised to keep this number low.");
|
||||
|
||||
public static final ConfigSetting INSTANT_STACKING = new ConfigSetting(config, "Main.Instant Stacking", false,
|
||||
"Should entities stacked into existing stacks before they spawned?");
|
||||
|
||||
public static final ConfigSetting DISABLED_WORLDS = new ConfigSetting(config, "Main.Disabled Worlds", Arrays.asList("World1", "World2", "World3"),
|
||||
"Worlds that stacking doesn't happen in.");
|
||||
|
||||
@ -45,8 +48,10 @@ public class Settings implements com.craftaro.ultimatestacker.api.Settings {
|
||||
"The maximum amount of each entity type stack allowed in a chunk.");
|
||||
|
||||
public static final ConfigSetting STACK_WHOLE_CHUNK = new ConfigSetting(config, "Entities.Stack Whole Chunk", false,
|
||||
"Should all qualifying entities in each chunk be stacked?",
|
||||
"This will override the stacking radius.");
|
||||
"Should all qualifying entities in each chunk be stacked?");
|
||||
|
||||
public static final ConfigSetting STACK_WHOLE_CHUNK_RADIUS = new ConfigSetting(config, "Entities.Stack Whole Chunk Radius", 1,
|
||||
"Radius in chunks every direction around the entity that will be stacked.", "0 means only the chunk the entity is in.");
|
||||
|
||||
public static final ConfigSetting ENTITY_NAMETAGS = new ConfigSetting(config, "Entities.Holograms Enabled", true,
|
||||
"Should holograms be displayed above stacked entities?");
|
||||
|
@ -15,6 +15,7 @@ import com.craftaro.ultimatestacker.utils.Methods;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.ExperienceOrb;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
@ -22,6 +23,8 @@ import org.bukkit.event.entity.EntityDamageEvent;
|
||||
import org.bukkit.event.entity.EntityDeathEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.metadata.FixedMetadataValue;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
@ -33,6 +36,7 @@ import java.util.UUID;
|
||||
public class EntityStackImpl implements EntityStack {
|
||||
|
||||
private final UltimateStacker plugin = UltimateStacker.getInstance();
|
||||
private final NamespacedKey STACKED_ENTITY_KEY = new NamespacedKey(plugin, "US_AMOUNT");
|
||||
private int amount;
|
||||
private LivingEntity hostEntity;
|
||||
|
||||
@ -43,15 +47,42 @@ public class EntityStackImpl implements EntityStack {
|
||||
public EntityStackImpl(LivingEntity entity) {
|
||||
if (entity == null) return;
|
||||
if (!UltimateStacker.getInstance().getEntityStackManager().isStackedEntity(entity)) {
|
||||
entity.setMetadata("US_AMOUNT", new FixedMetadataValue(UltimateStacker.getInstance(), 1));
|
||||
this.amount = 1;
|
||||
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_14)) {
|
||||
PersistentDataContainer container = entity.getPersistentDataContainer();
|
||||
if (container.has(STACKED_ENTITY_KEY, PersistentDataType.INTEGER)) {
|
||||
this.amount = container.get(STACKED_ENTITY_KEY, PersistentDataType.INTEGER);
|
||||
entity.setMetadata("US_AMOUNT", new FixedMetadataValue(UltimateStacker.getInstance(), amount));
|
||||
} else {
|
||||
entity.setMetadata("US_AMOUNT", new FixedMetadataValue(UltimateStacker.getInstance(), 1));
|
||||
this.amount = 1;
|
||||
}
|
||||
} else {
|
||||
entity.setMetadata("US_AMOUNT", new FixedMetadataValue(UltimateStacker.getInstance(), 1));
|
||||
this.amount = 1;
|
||||
}
|
||||
} else {
|
||||
//get the amount from the entity
|
||||
this.amount = entity.getMetadata("US_AMOUNT").get(0).asInt();
|
||||
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_14)) {
|
||||
PersistentDataContainer container = entity.getPersistentDataContainer();
|
||||
if (container.has(STACKED_ENTITY_KEY, PersistentDataType.INTEGER)) {
|
||||
this.amount = container.get(STACKED_ENTITY_KEY, PersistentDataType.INTEGER);
|
||||
} else {
|
||||
this.amount = getMetaCount(entity);
|
||||
}
|
||||
} else {
|
||||
this.amount = getMetaCount(entity);
|
||||
}
|
||||
}
|
||||
this.hostEntity = entity;
|
||||
}
|
||||
|
||||
private int getMetaCount(LivingEntity entity) {
|
||||
if (entity.hasMetadata("US_AMOUNT")) {
|
||||
return entity.getMetadata("US_AMOUNT").get(0).asInt();
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new stack or overrides an existing stack.
|
||||
* @param entity The entity to create the stack for.
|
||||
@ -60,8 +91,16 @@ public class EntityStackImpl implements EntityStack {
|
||||
public EntityStackImpl(LivingEntity entity, int amount) {
|
||||
if (entity == null) return;
|
||||
this.hostEntity = entity;
|
||||
if (amount <= 0) {
|
||||
throw new IllegalArgumentException("Amount must be greater than 0");
|
||||
}
|
||||
this.amount = amount;
|
||||
entity.setMetadata("US_AMOUNT", new FixedMetadataValue(UltimateStacker.getInstance(), amount));
|
||||
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_14)) {
|
||||
PersistentDataContainer container = entity.getPersistentDataContainer();
|
||||
container.set(STACKED_ENTITY_KEY, PersistentDataType.INTEGER, amount);
|
||||
} else {
|
||||
entity.setMetadata("US_AMOUNT", new FixedMetadataValue(UltimateStacker.getInstance(), amount));
|
||||
}
|
||||
updateNameTag();
|
||||
}
|
||||
|
||||
@ -78,7 +117,12 @@ public class EntityStackImpl implements EntityStack {
|
||||
@Override
|
||||
public void setAmount(int amount) {
|
||||
this.amount = amount;
|
||||
this.hostEntity.setMetadata("US_AMOUNT", new FixedMetadataValue(UltimateStacker.getInstance(), amount));
|
||||
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_14)) {
|
||||
PersistentDataContainer container = hostEntity.getPersistentDataContainer();
|
||||
container.set(STACKED_ENTITY_KEY, PersistentDataType.INTEGER, amount);
|
||||
} else {
|
||||
hostEntity.setMetadata("US_AMOUNT", new FixedMetadataValue(UltimateStacker.getInstance(), amount));
|
||||
}
|
||||
updateNameTag();
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,17 @@
|
||||
package com.craftaro.ultimatestacker.stackable.entity;
|
||||
|
||||
import com.craftaro.core.compatibility.ServerVersion;
|
||||
import com.craftaro.ultimatestacker.UltimateStacker;
|
||||
import com.craftaro.ultimatestacker.api.stack.entity.EntityStack;
|
||||
import com.craftaro.ultimatestacker.api.stack.entity.EntityStackManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.metadata.FixedMetadataValue;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import uk.antiperson.stackmob.api.StackedEntity;
|
||||
|
||||
import java.util.UUID;
|
||||
@ -15,9 +19,11 @@ import java.util.UUID;
|
||||
public class EntityStackManagerImpl implements EntityStackManager {
|
||||
|
||||
private final UltimateStacker plugin;
|
||||
private final NamespacedKey STACKED_ENTITY_KEY;
|
||||
|
||||
public EntityStackManagerImpl(UltimateStacker plugin) {
|
||||
this.plugin = plugin;
|
||||
this.STACKED_ENTITY_KEY = new NamespacedKey(plugin, "US_AMOUNT");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -29,7 +35,13 @@ public class EntityStackManagerImpl implements EntityStackManager {
|
||||
|
||||
@Override
|
||||
public boolean isStackedEntity(Entity entity) {
|
||||
return entity.hasMetadata("US_AMOUNT");
|
||||
if (entity.hasMetadata("US_AMOUNT")) {
|
||||
return true;
|
||||
}
|
||||
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_14)) {
|
||||
return entity.getPersistentDataContainer().has(STACKED_ENTITY_KEY, PersistentDataType.INTEGER);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -84,7 +84,7 @@ public class SpawnerStackImpl implements SpawnerStack {
|
||||
|
||||
@Override
|
||||
public int spawn() {
|
||||
return spawn(-1, false);
|
||||
return spawn(-1, Settings.NO_AI.getBoolean());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -46,6 +46,7 @@ import org.bukkit.inventory.EntityEquipment;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
@ -53,6 +54,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TimerTask;
|
||||
import java.util.TreeSet;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
@ -60,13 +62,14 @@ import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.craftaro.ultimatestacker.stackable.entity.Check.getChecks;
|
||||
|
||||
public class StackingTask extends TimerTask {
|
||||
|
||||
private final UltimateStacker plugin;
|
||||
private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
|
||||
private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(r -> new Thread(r, "UltimateStacker-Stacking-Thread"));
|
||||
|
||||
private final EntityStackManager stackManager;
|
||||
|
||||
@ -77,6 +80,7 @@ public class StackingTask extends TimerTask {
|
||||
private final int maxEntityStackSize = Settings.MAX_STACK_ENTITIES.getInt(),
|
||||
minEntityStackSize = Settings.MIN_STACK_ENTITIES.getInt(),
|
||||
searchRadius = Settings.SEARCH_RADIUS.getInt(),
|
||||
chunkRadius = Settings.STACK_WHOLE_CHUNK_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();
|
||||
@ -87,17 +91,19 @@ public class StackingTask extends TimerTask {
|
||||
onlyStackFromSpawners = Settings.ONLY_STACK_FROM_SPAWNERS.getBoolean(),
|
||||
onlyStackOnSurface = Settings.ONLY_STACK_ON_SURFACE.getBoolean();
|
||||
|
||||
Set<SWorld> loadedWorlds = new HashSet<>();
|
||||
private final Set<SWorld> loadedWorlds;
|
||||
|
||||
public StackingTask(UltimateStacker plugin) {
|
||||
this.plugin = plugin;
|
||||
this.stackManager = plugin.getEntityStackManager();
|
||||
// Add loaded worlds.
|
||||
for (World world : Bukkit.getWorlds())
|
||||
loadedWorlds = new HashSet<>();
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
//Filter disabled worlds to avoid continuous checks in the stacking loop
|
||||
if (isWorldDisabled(world)) continue;
|
||||
loadedWorlds.add(new SWorld(world));
|
||||
|
||||
}
|
||||
// Start the stacking task.
|
||||
//runTaskTimerAsynchronously(plugin, 0, Settings.STACK_SEARCH_TICK_SPEED.getInt());
|
||||
executorService.scheduleAtFixedRate(this, 0, (Settings.STACK_SEARCH_TICK_SPEED.getInt()*50L), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@ -107,25 +113,30 @@ public class StackingTask extends TimerTask {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
//make sure if the task running if any error occurs
|
||||
//Make sure to continue the task if any exception occurs
|
||||
try {
|
||||
// Should entities be stacked?
|
||||
if (!Settings.STACK_ENTITIES.getBoolean()) return;
|
||||
|
||||
// Loop through each world.
|
||||
for (SWorld sWorld : loadedWorlds) {
|
||||
// If world is disabled then continue to the next world.
|
||||
if (isWorldDisabled(sWorld.getWorld())) continue;
|
||||
|
||||
// Get the loaded entities from the current world and reverse them.
|
||||
List<LivingEntity> entities;
|
||||
// Get the loaded entities from the current world and reverse them.
|
||||
try {
|
||||
entities = getLivingEntitiesSync(sWorld).get();
|
||||
} catch (ExecutionException | InterruptedException ex) {
|
||||
ex.printStackTrace();
|
||||
continue;
|
||||
}
|
||||
Collections.reverse(entities);
|
||||
|
||||
//Filter non-stackable entities to improve performance on main thread
|
||||
entities.removeIf(this::isEntityNotStackable);
|
||||
|
||||
|
||||
for (LivingEntity entity : entities) {
|
||||
// Check our WorldGuard flag.
|
||||
Boolean flag = WorldGuardHook.isEnabled() ? WorldGuardHook.getBooleanFlag(entity.getLocation(), "mob-stacking") : null; //Does this work async?
|
||||
if (flag != null && !flag) {
|
||||
entities.removeIf(entity1 -> entity1.getUniqueId().equals(entity.getUniqueId()));
|
||||
}
|
||||
}
|
||||
|
||||
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||
// Loop through the entities.
|
||||
@ -134,28 +145,26 @@ public class StackingTask extends TimerTask {
|
||||
// Skip it if it has been.
|
||||
if (this.processed.contains(entity.getUniqueId())) continue;
|
||||
|
||||
// Check to see if entity is not stackable.
|
||||
if (!isEntityStackable(entity)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get entity location to pass around as its faster this way.
|
||||
Location location = entity.getLocation();
|
||||
|
||||
// Process the entity.
|
||||
this.processEntity(entity, sWorld, location);
|
||||
this.processEntity(entity, location);
|
||||
}
|
||||
});
|
||||
}
|
||||
// Clear caches in preparation for the next run.
|
||||
} catch (Exception ignored) {
|
||||
|
||||
} finally {
|
||||
// Make sure we clear the processed list.
|
||||
this.processed.clear();
|
||||
} catch (Exception ignored) {}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private Future<List<LivingEntity>> getLivingEntitiesSync(SWorld sWorld) {
|
||||
CompletableFuture<List<LivingEntity>> future = new CompletableFuture<>();
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(this.plugin, () -> future.complete(sWorld.getLivingEntities()));
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
@ -169,7 +178,11 @@ public class StackingTask extends TimerTask {
|
||||
return disabledWorlds.stream().anyMatch(worldStr -> world.getName().equalsIgnoreCase(worldStr));
|
||||
}
|
||||
|
||||
private boolean isEntityStackable(Entity entity) {
|
||||
//Returns true if the entity is not stackable, and it will be removed from the list
|
||||
private boolean isEntityNotStackable(LivingEntity entity) {
|
||||
if (isMaxStack(entity)) return true;
|
||||
|
||||
|
||||
// Make sure we have the correct entity type and that it is valid.
|
||||
if (!entity.isValid()
|
||||
|| entity instanceof HumanEntity
|
||||
@ -178,187 +191,182 @@ public class StackingTask extends TimerTask {
|
||||
// Make sure the entity is not in love.
|
||||
|| entity.hasMetadata("inLove")
|
||||
// Or in breeding cooldown.
|
||||
|| entity.hasMetadata("breedCooldown"))
|
||||
return false;
|
||||
|
||||
if (!configurationSection.getBoolean("Mobs." + entity.getType().name() + ".Enabled")) {
|
||||
return false;
|
||||
|| entity.hasMetadata("breedCooldown")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Allow spawn if stackreasons are set and match, or if from a spawner
|
||||
if (!configurationSection.getBoolean("Mobs." + entity.getType().name() + ".Enabled")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Allow spawn if stack reasons are set and match, or if from a spawner
|
||||
final String spawnReason = entity.hasMetadata("US_REASON") && !entity.getMetadata("US_REASON").isEmpty()
|
||||
? entity.getMetadata("US_REASON").get(0).asString() : null;
|
||||
List<String> stackReasons;
|
||||
if (onlyStackFromSpawners) {
|
||||
// If only stack from spawners is enabled, make sure the entity spawned from a spawner.
|
||||
if (!"SPAWNER".equals(spawnReason))
|
||||
return false;
|
||||
if (!"SPAWNER".equals(spawnReason)) {
|
||||
return true;
|
||||
}
|
||||
} else if (!(stackReasons = this.stackReasons).isEmpty() && !stackReasons.contains(spawnReason)) {
|
||||
// Only stack if on the list of events to stack
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Cast our entity to living entity.
|
||||
LivingEntity livingEntity = (LivingEntity) entity;
|
||||
|
||||
// If only stack on surface is enabled make sure the entity is on a surface then entity is stackable.
|
||||
return !onlyStackOnSurface
|
||||
|| canFly(livingEntity)
|
||||
|| entity.getType().name().equals("SHULKER")
|
||||
|
||||
|| (livingEntity.isOnGround()
|
||||
|| (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)
|
||||
&& livingEntity.isSwimming()));
|
||||
|
||||
//return !onlyStackOnSurface || canFly(entity) || entity.getType().name().equals("SHULKER") || ((entity).isOnGround() || (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13) && (entity).isSwimming()));
|
||||
return onlyStackOnSurface && canFly(entity) && !entity.getType().name().equals("SHULKER") && !entity.isOnGround() && !(ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13) && (entity).isSwimming());
|
||||
}
|
||||
|
||||
private void processEntity(LivingEntity baseEntity, SWorld sWorld, Location location) {
|
||||
|
||||
// Check our WorldGuard flag.
|
||||
Boolean flag = WorldGuardHook.isEnabled() ? WorldGuardHook.getBooleanFlag(baseEntity.getLocation(), "mob-stacking") : null;
|
||||
if (flag != null && !flag) {
|
||||
return;
|
||||
}
|
||||
|
||||
private void processEntity(LivingEntity baseEntity, Location location) {
|
||||
// Get the stack from the entity. It should be noted that this value will
|
||||
// be null if our entity is not a stack.
|
||||
EntityStack baseStack = plugin.getEntityStackManager().getStackedEntity(baseEntity);
|
||||
|
||||
// Get the maximum stack size for this entity.
|
||||
int maxEntityStackSize = getEntityStackSize(baseEntity);
|
||||
int maxEntityStackSize = getEntityMaxStackSize(baseEntity);
|
||||
|
||||
// Is this entity stacked?
|
||||
boolean isStack = baseStack != null;
|
||||
|
||||
if (isStack && baseStack.getAmount() == maxEntityStackSize) {
|
||||
// If the stack is already at the max size then we can skip it.
|
||||
processed.add(baseEntity.getUniqueId());
|
||||
// The amount that is stackable.
|
||||
int baseSize = isStack ? baseStack.getAmount() : 1;
|
||||
|
||||
// Attempt to split overstacked entities.
|
||||
// If this is successful, we can return because the entity was processed
|
||||
if (isStack && attemptSplit(baseStack, maxEntityStackSize)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The amount that is stackable.
|
||||
int amountToStack = isStack ? baseStack.getAmount() : 1;
|
||||
|
||||
// Attempt to split our stack. If the split is successful then skip this entity.
|
||||
if (isStack && attemptSplit(baseStack, baseEntity)) return;
|
||||
|
||||
// If this entity is named, a custom entity or disabled then skip it.
|
||||
if (!isStack && (baseEntity.getCustomName() != null
|
||||
&& plugin.getCustomEntityManager().getCustomEntity(baseEntity) == null)
|
||||
|| !configurationSection.getBoolean("Mobs." + baseEntity.getType().name() + ".Enabled")) {
|
||||
// If this entity is named or a custom entity skip it.
|
||||
if (!isStack && (baseEntity.getCustomName() != null && plugin.getCustomEntityManager().getCustomEntity(baseEntity) != null)) {
|
||||
processed.add(baseEntity.getUniqueId());
|
||||
return;
|
||||
}
|
||||
|
||||
// Get similar entities around our entity and make sure those entities are both compatible and stackable.
|
||||
List<LivingEntity> stackableFriends = new LinkedList<>();
|
||||
List<LivingEntity> list = getSimilarEntitiesAroundEntity(baseEntity, sWorld, location);
|
||||
for (LivingEntity entity : list) {
|
||||
// Check to see if entity is not stackable.
|
||||
if (!isEntityStackable(entity))
|
||||
continue;
|
||||
// Add this entity to our stackable friends.
|
||||
stackableFriends.add(entity);
|
||||
}
|
||||
List<LivingEntity> stackableFriends = getSimilarEntitiesAroundEntity(baseEntity, location);
|
||||
|
||||
//Total entities that can be stacked into the base entity
|
||||
int maxStackable = maxEntityStackSize - baseSize;
|
||||
int toStack = 0;
|
||||
List<LivingEntity> remove = new ArrayList<>();
|
||||
|
||||
// Loop through our similar stackable entities.
|
||||
for (LivingEntity friendlyEntity : stackableFriends) {
|
||||
// Make sure the friendlyEntity has not already been processed.
|
||||
if (this.processed.contains(friendlyEntity.getUniqueId())) continue;
|
||||
|
||||
// Get this entities friendStack.
|
||||
// Process similar entities.
|
||||
EntityStack friendStack = stackManager.getStackedEntity(friendlyEntity);
|
||||
int amount = friendStack != null ? friendStack.getAmount() : 1;
|
||||
|
||||
// Check to see if this friendlyEntity is stacked and friendStack plus
|
||||
// our amount to stack is not above our max friendStack size
|
||||
// for this friendlyEntity.
|
||||
|
||||
boolean overstack = (amount + amountToStack) > maxEntityStackSize;
|
||||
|
||||
if (!overstack) {
|
||||
stackManager.createStackedEntity(friendlyEntity, amount + amountToStack);
|
||||
processed.add(baseEntity.getUniqueId());
|
||||
|
||||
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||
if (baseEntity.isLeashed()) {
|
||||
baseEntity.getWorld().dropItemNaturally(baseEntity.getLocation(), XMaterial.LEAD.parseItem());
|
||||
}
|
||||
baseEntity.remove();
|
||||
});
|
||||
return;
|
||||
if (toStack + amount <= maxStackable) {
|
||||
toStack += amount;
|
||||
remove.add(friendlyEntity);
|
||||
continue;
|
||||
}
|
||||
break; //We max, exit loop
|
||||
}
|
||||
|
||||
//Nothing to stack
|
||||
if (toStack == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Add to base stack and remove stacked friends
|
||||
stackManager.createStackedEntity(baseEntity, baseSize + toStack);
|
||||
processed.add(baseEntity.getUniqueId());
|
||||
|
||||
//Remove merged entities
|
||||
//We in sync, so we can remove entities
|
||||
for (LivingEntity entity : remove) {
|
||||
processed.add(entity.getUniqueId());
|
||||
entity.remove();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean attemptSplit(EntityStack baseStack, LivingEntity livingEntity) {
|
||||
/**
|
||||
* This method splitting overstacked entities into new stacks.
|
||||
* Must be called synchronously.
|
||||
* @param baseStack The base stack to check for splitting.
|
||||
* @param maxEntityStackSize The maximum stack size for the entity. -1 if we need to calculate it.
|
||||
* @return True if the split was successful, false otherwise.
|
||||
*/
|
||||
public boolean attemptSplit(EntityStack baseStack, int maxEntityStackSize) {
|
||||
LivingEntity hostEntity = baseStack.getHostEntity();
|
||||
int stackSize = baseStack.getAmount();
|
||||
int maxEntityStackAmount = getEntityStackSize(livingEntity);
|
||||
int maxEntityStackAmount = maxEntityStackSize == -1 ? getEntityMaxStackSize(hostEntity) : maxEntityStackSize;
|
||||
|
||||
if (stackSize <= maxEntityStackAmount) return false;
|
||||
|
||||
baseStack.setAmount(maxEntityStackAmount);
|
||||
|
||||
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||
int finalStackSize = stackSize - maxEntityStackAmount;
|
||||
do {
|
||||
// Create a new stack, summon entity and add to stack.
|
||||
LivingEntity newEntity = (LivingEntity) livingEntity.getWorld().spawnEntity(livingEntity.getLocation(), livingEntity.getType());
|
||||
int toAdd = Math.min(finalStackSize, maxEntityStackAmount);
|
||||
EntityStack newStack = stackManager.createStackedEntity(newEntity, toAdd);
|
||||
processed.add(newEntity.getUniqueId());
|
||||
finalStackSize -= maxEntityStackAmount;
|
||||
} while (finalStackSize >= 0);
|
||||
});
|
||||
int finalStackSize = stackSize - maxEntityStackAmount;
|
||||
do {
|
||||
// Create a new stack, summon entity and add to stack.
|
||||
LivingEntity newEntity = (LivingEntity) hostEntity.getWorld().spawnEntity(hostEntity.getLocation(), hostEntity.getType());
|
||||
int toAdd = Math.min(finalStackSize, maxEntityStackAmount);
|
||||
EntityStack newStack = stackManager.createStackedEntity(newEntity, toAdd);
|
||||
processed.add(newEntity.getUniqueId());
|
||||
finalStackSize -= maxEntityStackAmount;
|
||||
} while (finalStackSize >= 0);
|
||||
|
||||
//Mark it as processed.
|
||||
processed.add(livingEntity.getUniqueId());
|
||||
processed.add(hostEntity.getUniqueId());
|
||||
return true;
|
||||
}
|
||||
|
||||
private Set<CachedChunk> getNearbyChunks(SWorld sWorld, Location location, double radius, boolean singleChunk) {
|
||||
//get current chunk
|
||||
if (radius == -1) {
|
||||
return new HashSet<>(Collections.singletonList(new CachedChunk(sWorld, location.getChunk().getX(), location.getChunk().getZ())));
|
||||
private Set<CachedChunk> getNearbyChunks(SWorld sWorld, Location location) {
|
||||
//Only stack entities in the same chunk
|
||||
if (stackWholeChunk && chunkRadius == 0) {
|
||||
return Collections.singleton(new CachedChunk(sWorld, location.getChunk().getX(), location.getChunk().getZ()));
|
||||
}
|
||||
World world = location.getWorld();
|
||||
Set<CachedChunk> chunks = new HashSet<>();
|
||||
if (world == null) return chunks;
|
||||
if (world == null) return new HashSet<>();
|
||||
|
||||
CachedChunk firstChunk = new CachedChunk(sWorld, location);
|
||||
Set<CachedChunk> chunks = new TreeSet<>(Comparator.comparingInt(CachedChunk::getX).thenComparingInt(CachedChunk::getZ));
|
||||
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);
|
||||
//Calculate chunk coordinates we need to check
|
||||
int minX = (int) Math.floor((location.getX() - chunkRadius) / 16.0D);
|
||||
int maxX = (int) Math.floor((location.getX() + chunkRadius) / 16.0D);
|
||||
int minZ = (int) Math.floor((location.getZ() - chunkRadius) / 16.0D);
|
||||
int maxZ = (int) Math.floor((location.getZ() + chunkRadius) / 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(sWorld, x, z));
|
||||
if (x == minX || x == maxX || z == minZ || z == maxZ) {
|
||||
chunks.add(new CachedChunk(sWorld, x, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Set a bedrock in the top left corner of the chunks
|
||||
for (CachedChunk chunk : chunks) {
|
||||
int x = chunk.getX() * 16;
|
||||
int z = chunk.getZ() * 16;
|
||||
world.getBlockAt(x, 319, z).setType(XMaterial.BEDROCK.parseMaterial());
|
||||
}
|
||||
return chunks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all entities around an entity within a radius which are similar to the entity.
|
||||
* @param entity The entity to get similar entities around.
|
||||
* @param radius The radius to get entities around.
|
||||
* @param singleChunk Whether to only get entities in the same chunk as the entity.
|
||||
* @return A list of similar entities around the entity.
|
||||
*/
|
||||
private List<LivingEntity> getFriendlyStacksNearby(LivingEntity entity, double radius, boolean singleChunk) {
|
||||
public List<LivingEntity> getFriendlyStacksNearby(LivingEntity entity) {
|
||||
if (!stackWholeChunk) {
|
||||
return entity.getNearbyEntities(searchRadius/2.0, searchRadius/2.0, searchRadius/2.0)
|
||||
.stream().filter(e -> e.getType() == entity.getType() && !isMaxStack((LivingEntity) e))
|
||||
.map(e -> (LivingEntity) e).collect(Collectors.toList());
|
||||
}
|
||||
List<LivingEntity> entities = new ArrayList<>();
|
||||
try {
|
||||
Set<CachedChunk> chunks = getNearbyChunks(new SWorld(entity.getWorld()), entity.getLocation(), radius, singleChunk);
|
||||
Set<CachedChunk> chunks = getNearbyChunks(new SWorld(entity.getWorld()), entity.getLocation());
|
||||
for (CachedChunk chunk : chunks) {
|
||||
Entity[] entityList = chunk.getEntities();
|
||||
for (Entity e : entityList) {
|
||||
if (!processed.contains(e.getUniqueId()) && e.getType() == entity.getType() && e instanceof LivingEntity && e.isValid() && e.getLocation().distance(entity.getLocation()) <= radius) {
|
||||
if (e.getType() == entity.getType() && !isMaxStack((LivingEntity) e)) {
|
||||
entities.add((LivingEntity) e);
|
||||
}
|
||||
}
|
||||
@ -370,10 +378,10 @@ public class StackingTask extends TimerTask {
|
||||
return entities;
|
||||
}
|
||||
|
||||
public List<LivingEntity> getSimilarEntitiesAroundEntity(LivingEntity initialEntity, SWorld sWorld, Location location) {
|
||||
public List<LivingEntity> getSimilarEntitiesAroundEntity(LivingEntity initialEntity, Location location) {
|
||||
try {
|
||||
// Create a list of all entities around the initial entity of the same type.
|
||||
List<LivingEntity> entityList = new LinkedList<>(getFriendlyStacksNearby(initialEntity, searchRadius, stackWholeChunk));
|
||||
List<LivingEntity> entityList = new ArrayList<>(getFriendlyStacksNearby(initialEntity));
|
||||
|
||||
CustomEntity customEntity = plugin.getCustomEntityManager().getCustomEntity(initialEntity);
|
||||
if (customEntity != null)
|
||||
@ -641,16 +649,20 @@ public class StackingTask extends TimerTask {
|
||||
|| (equipment.getBoots() != null && equipment.getBoots().getType() != Material.AIR));
|
||||
}
|
||||
|
||||
private int getEntityStackSize(LivingEntity initialEntity) {
|
||||
Integer max = entityStackSizes.get(initialEntity.getType());
|
||||
if (max == null) {
|
||||
max = configurationSection.getInt("Mobs." + initialEntity.getType().name() + ".Max Stack Size");
|
||||
if (max == -1) {
|
||||
max = maxEntityStackSize;
|
||||
private int getEntityMaxStackSize(LivingEntity initialEntity) {
|
||||
return entityStackSizes.computeIfAbsent(initialEntity.getType(), type -> {
|
||||
int maxStackSize = configurationSection.getInt("Mobs." + initialEntity.getType().name() + ".Max Stack Size");
|
||||
if (maxStackSize == -1) {
|
||||
maxStackSize = maxEntityStackSize;
|
||||
}
|
||||
entityStackSizes.put(initialEntity.getType(), max);
|
||||
}
|
||||
return max;
|
||||
return maxStackSize;
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isMaxStack(LivingEntity livingEntity) {
|
||||
EntityStack stack = stackManager.getStackedEntity(livingEntity);
|
||||
if (stack == null) return false;
|
||||
return stack.getAmount() >= getEntityMaxStackSize(livingEntity);
|
||||
}
|
||||
|
||||
public boolean canFly(LivingEntity entity) {
|
||||
|
Loading…
Reference in New Issue
Block a user