UltimateStacker/src/main/java/com/songoda/ultimatestacker/tasks/StackingTask.java

278 lines
11 KiB
Java
Raw Normal View History

2018-11-06 04:33:10 +01:00
package com.songoda.ultimatestacker.tasks;
import com.songoda.ultimatestacker.UltimateStacker;
import com.songoda.ultimatestacker.entity.EntityStack;
import com.songoda.ultimatestacker.entity.EntityStackManager;
import com.songoda.ultimatestacker.utils.Methods;
import com.songoda.ultimatestacker.utils.settings.Setting;
2018-11-06 04:33:10 +01:00
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Entity;
2019-07-19 02:49:41 +02:00
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.LivingEntity;
2018-11-06 04:33:10 +01:00
import org.bukkit.scheduler.BukkitRunnable;
import java.util.ArrayList;
2019-01-15 05:45:25 +01:00
import java.util.Collections;
2018-11-06 04:33:10 +01:00
import java.util.List;
import java.util.UUID;
2019-07-19 02:49:41 +02:00
import java.util.stream.Collectors;
2018-11-06 04:33:10 +01:00
public class StackingTask extends BukkitRunnable {
private final UltimateStacker instance;
private EntityStackManager stackManager;
2019-07-19 02:49:41 +02:00
ConfigurationSection configurationSection = UltimateStacker.getInstance().getMobFile().getConfig();
private List<UUID> processed = new ArrayList<>();
2018-11-06 04:33:10 +01:00
public StackingTask(UltimateStacker instance) {
this.instance = instance;
this.stackManager = instance.getEntityStackManager();
2019-03-21 04:36:58 +01:00
// Start stacking task.
runTaskTimer(instance, 0, Setting.STACK_SEARCH_TICK_SPEED.getInt());
2018-11-06 04:33:10 +01:00
}
@Override
public void run() {
2019-07-19 02:49:41 +02:00
// Gather disabled worlds.
List<String> disabledWorlds = Setting.DISABLED_WORLDS.getStringList();
2018-11-06 04:33:10 +01:00
2019-07-19 02:49:41 +02:00
// Should entities be stacked?
if (!Setting.STACK_ENTITIES.getBoolean()) return;
// Loop through each world.
2018-11-06 04:33:10 +01:00
for (World world : Bukkit.getWorlds()) {
2019-07-19 02:49:41 +02:00
// If world is disabled then continue to the next world.
2019-04-11 08:54:59 +02:00
if (disabledWorlds.stream().anyMatch(worldStr -> world.getName().equalsIgnoreCase(worldStr))) continue;
2018-11-06 04:33:10 +01:00
2019-07-19 02:49:41 +02:00
// Get the loaded entities from the current world, reverse them and make sure they are stackable.
List<Entity> entities = new ArrayList<>(world.getEntities()).stream()
.filter(this::isEntityStackable).collect(Collectors.toList());
2019-01-15 05:45:25 +01:00
Collections.reverse(entities);
2019-07-19 02:49:41 +02:00
// Loop through the entities.
for (Entity entity : entities) {
// Make sure our entity has not already been processed.
// Skip it if it has been.
if (this.processed.contains(entity.getUniqueId())) continue;
2019-07-19 02:49:41 +02:00
// Cast our entity to living entity.
LivingEntity livingEntity = (LivingEntity) entity;
2019-07-19 02:49:41 +02:00
// Process the entity.
this.processEntity(livingEntity);
2018-11-06 04:33:10 +01:00
}
}
2019-07-19 02:49:41 +02:00
processed.clear();
}
2018-11-06 04:33:10 +01:00
2019-07-19 02:49:41 +02:00
private boolean isEntityStackable(Entity entity) {
// Make sure we have the correct entity type and that it is valid.
if (!entity.isValid()
|| !(entity instanceof LivingEntity)
|| entity instanceof HumanEntity
|| entity instanceof ArmorStand
2019-06-28 05:14:40 +02:00
2019-07-19 02:49:41 +02:00
// Make sure the entity is not in love.
|| entity.hasMetadata("inLove")
// Or in breeding cooldown.
|| entity.hasMetadata("breedCooldown")
// If only stack from spawners is enabled make sure the entity spawned from a spawner.
|| Setting.ONLY_STACK_FROM_SPAWNERS.getBoolean()
&& !(entity.hasMetadata("US_REASON")
&& entity.getMetadata("US_REASON").get(0).asString().equals("SPAWNER")))
2019-06-28 05:14:40 +02:00
return false;
2019-07-19 02:49:41 +02:00
// Cast our entity to living entity.
LivingEntity livingEntity = (LivingEntity) entity;
2019-07-19 02:49:41 +02:00
// If only stack on surface is enabled make sure the entity is on a surface then entity is stackable.
return !Setting.ONLY_STACK_ON_SURFACE.getBoolean()
|| Methods.canFly(livingEntity)
|| (livingEntity.isOnGround() || livingEntity.getLocation().getBlock().isLiquid());
2019-07-19 02:49:41 +02:00
}
2019-07-19 02:49:41 +02:00
private void processEntity(LivingEntity livingEntity) {
// Get the stack from the entity. It should be noted that this value will
// be null if our entity is not a stack.
EntityStack stack = instance.getEntityStackManager().getStack(livingEntity);
2019-07-19 02:49:41 +02:00
// Is this entity stacked?
boolean isStack = stack != null;
2018-11-06 04:33:10 +01:00
2019-07-19 02:49:41 +02:00
// The amount that is stackable.
int amountToStack = isStack ? stack.getAmount() : 1;
2019-07-19 02:49:41 +02:00
// Attempt to split our stack. If the split is successful then skip this entity.
if (isStack && attemptSplit(stack, livingEntity)) return;
// If this entity is named or disabled then skip it.
if (!isStack && livingEntity.getCustomName() != null
|| !configurationSection.getBoolean("Mobs." + livingEntity.getType().name() + ".Enabled"))
return;
// Get the minimum stack size.
int minEntityStackSize = Setting.MIN_STACK_ENTITIES.getInt();
// Get the maximum stack size for this entity.
int maxEntityStackSize = getEntityStackSize(livingEntity);
// Get similar entities around our entity and make sure those entities are both compatible and stackable.
List<LivingEntity> stackableFriends = Methods.getSimilarEntitiesAroundEntity(livingEntity)
.stream().filter(this::isEntityStackable).collect(Collectors.toList());
// Loop through our similar stackable entities.
for (LivingEntity entity : stackableFriends) {
// Make sure the entity has not already been processed.
if (this.processed.contains(entity.getUniqueId())) continue;
// Get this entities friendStack.
EntityStack friendStack = stackManager.getStack(entity);
2019-07-19 02:49:41 +02:00
// Check to see if this entity is stacked and friendStack plus
// our amount to stack is not above our max friendStack size
// for this entity.
if (friendStack != null && (friendStack.getAmount() + amountToStack) <= maxEntityStackSize) {
2019-07-19 02:49:41 +02:00
// 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
2019-07-19 02:49:41 +02:00
friendStack.mergeHealth(stack);
2019-07-19 02:49:41 +02:00
fixHealth(entity, livingEntity);
2019-06-30 02:16:01 +02:00
if (Setting.STACK_ENTITY_HEALTH.getBoolean())
2019-07-19 02:49:41 +02:00
entity.setHealth(entity.getMaxHealth() < livingEntity.getHealth()
? entity.getMaxHealth() : livingEntity.getHealth());
2019-07-19 02:49:41 +02:00
// Remove our entity and mark it as processed.
livingEntity.remove();
processed.add(livingEntity.getUniqueId());
2019-07-19 02:49:41 +02:00
return;
} else if (friendStack == null
&& isStack
&& (stack.getAmount() + 1) <= maxEntityStackSize
&& Methods.canFly(entity)
&& Setting.ONLY_STACK_FLYING_DOWN.getBoolean()
2019-07-19 02:49:41 +02:00
&& livingEntity.getLocation().getY() > entity.getLocation().getY()) {
2019-07-19 02:49:41 +02:00
// If entity has a custom name skip it.
if (entity.getCustomName() != null) continue;
2019-06-30 02:16:01 +02:00
2019-07-19 02:49:41 +02:00
// Create a new stack with the current stacks amount and add one to it.
EntityStack newStack = stackManager.addStack(entity, stack.getAmount() + 1);
2019-07-19 02:49:41 +02:00
// Fix the entities health.
newStack.mergeHealth(stack);
newStack.addHealth(livingEntity.getHealth());
fixHealth(livingEntity, entity);
2019-06-30 02:16:01 +02:00
if (Setting.STACK_ENTITY_HEALTH.getBoolean())
entity.setHealth(entity.getHealth());
2019-07-19 02:49:41 +02:00
// Remove our entities stack from the stack manager.
stackManager.removeStack(livingEntity);
2019-07-19 02:49:41 +02:00
// Remove our entity and mark it as processed.
livingEntity.remove();
processed.add(livingEntity.getUniqueId());
return;
2018-11-06 04:33:10 +01:00
}
}
2019-07-19 02:49:41 +02:00
// If our entity is stacked then skip this entity.
if (isStack) return;
2019-07-19 02:49:41 +02:00
// Remove all stacked entities from our stackable friends.
stackableFriends.removeIf(stackManager::isStacked);
2019-07-19 02:49:41 +02:00
// If there are none or not enough stackable friends left to create a new entity,
// the stack sizes overlap then skip this entity.
if (stackableFriends.isEmpty()
|| stackableFriends.size() < minEntityStackSize - 1
|| minEntityStackSize > maxEntityStackSize) return;
2019-07-19 02:49:41 +02:00
// If a stack was never found create a new one.
EntityStack newStack = stackManager.addStack(new EntityStack(livingEntity, (stackableFriends.size() + 1) >
maxEntityStackSize ? maxEntityStackSize : stackableFriends.size() + 1));
2019-07-19 02:49:41 +02:00
// Loop through the unstacked and unprocessed stackable friends while not creating
// a stack larger than the maximum.
stackableFriends.stream().filter(entity -> !stackManager.isStacked(entity)
&& !this.processed.contains(entity.getUniqueId())).limit(maxEntityStackSize).forEach(entity -> {
2019-07-19 02:49:41 +02:00
// Fix the entities health.
fixHealth(livingEntity, entity);
newStack.addHealth(entity.getHealth());
2019-07-19 02:49:41 +02:00
// Remove our entity and mark it as processed.
entity.remove();
2019-07-19 02:49:41 +02:00
processed.add(entity.getUniqueId());
});
2019-07-19 02:49:41 +02:00
// Update our stacks health.
updateHealth(newStack);
// Update our stack.
newStack.updateStack();
}
private void updateHealth(EntityStack stack) {
if (Setting.STACK_ENTITY_HEALTH.getBoolean())
stack.updateHealth(stack.getEntity());
2018-11-06 04:33:10 +01:00
}
2019-06-23 02:10:22 +02:00
public boolean attemptSplit(EntityStack stack, LivingEntity livingEntity) {
int stackSize = stack.getAmount();
int maxEntityStackAmount = getEntityStackSize(livingEntity);
if (stackSize <= maxEntityStackAmount) return false;
2019-07-19 02:50:29 +02:00
for (int i = stackSize; i > 0; i -= maxEntityStackAmount)
this.processed.add(instance.getEntityStackManager()
.addStack(Methods.newEntity(livingEntity), i > maxEntityStackAmount ? maxEntityStackAmount : i).getEntityUniqueId());
// Remove our entities stack from the stack manager.
stackManager.removeStack(livingEntity);
// Remove our entity and mark it as processed.
livingEntity.remove();
processed.add(livingEntity.getUniqueId());
return true;
}
2019-07-19 02:49:41 +02:00
private void fixHealth(LivingEntity entity, LivingEntity initialEntity) {
if (!Setting.STACK_ENTITY_HEALTH.getBoolean() && Setting.CARRY_OVER_LOWEST_HEALTH.getBoolean() && initialEntity.getHealth() < entity.getHealth())
entity.setHealth(initialEntity.getHealth());
}
2019-07-19 02:49:41 +02:00
private int getEntityStackSize(LivingEntity initialEntity) {
int maxEntityStackSize = Setting.MAX_STACK_ENTITIES.getInt();
if (configurationSection.getInt("Mobs." + initialEntity.getType().name() + ".Max Stack Size") != -1)
maxEntityStackSize = configurationSection.getInt("Mobs." + initialEntity.getType().name() + ".Max Stack Size");
return maxEntityStackSize;
}
2019-07-19 02:49:41 +02:00
2018-11-06 04:33:10 +01:00
}