mirror of
https://github.com/songoda/UltimateStacker.git
synced 2025-02-05 05:51:22 +01:00
Fix Stacking Task, fix loot tables for non stacked mobs. Add last player damage to mobs. Performance improvements.
This commit is contained in:
parent
9f77b48974
commit
1142fb0e6a
@ -78,7 +78,12 @@ public class EntityListeners implements Listener {
|
||||
|
||||
Entity entity = event.getEntity();
|
||||
|
||||
if (entity instanceof LivingEntity && plugin.getEntityStackManager().isStackedEntity(entity)
|
||||
if (!(entity instanceof LivingEntity)) return;
|
||||
if (event.getDamager() instanceof Player) {
|
||||
plugin.getEntityStackManager().setLastPlayerDamage(entity, (Player) event.getDamager());
|
||||
}
|
||||
|
||||
if (plugin.getEntityStackManager().isStackedEntity(entity)
|
||||
&& Settings.DISABLE_KNOCKBACK.getBoolean()
|
||||
&& ((Player) event.getDamager()).getItemInHand().getEnchantmentLevel(Enchantment.KNOCKBACK) == 0) {
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, () -> {
|
||||
|
@ -116,12 +116,23 @@ public class EntityStack extends StackedEntity {
|
||||
killed.setCustomName(null);
|
||||
killed.setCustomNameVisible(false);
|
||||
|
||||
//replace %player% in drop commands with the last player to damage the entity
|
||||
String lastDamage = plugin.getEntityStackManager().getLastPlayerDamage(killed);
|
||||
if (lastDamage != null) {
|
||||
drops.forEach(drop -> {
|
||||
if (drop.getCommand() != null) {
|
||||
drop.setCommand(drop.getCommand().replace("%player%", lastDamage));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
boolean killWholeStack = Settings.KILL_WHOLE_STACK_ON_DEATH.getBoolean()
|
||||
|| plugin.getMobFile().getBoolean("Mobs." + killed.getType().name() + ".Kill Whole Stack");
|
||||
|
||||
if (killWholeStack && getAmount() != 1) {
|
||||
if (killWholeStack && getAmount() > 1) {
|
||||
handleWholeStackDeath(killed, drops, custom, droppedExp, event);
|
||||
} else if (getAmount() != 1) {
|
||||
return;
|
||||
} else if (getAmount() > 1) {
|
||||
List<String> reasons = Settings.INSTANT_KILL.getStringList();
|
||||
EntityDamageEvent lastDamageCause = killed.getLastDamageCause();
|
||||
|
||||
@ -134,6 +145,7 @@ public class EntityStack extends StackedEntity {
|
||||
}
|
||||
}
|
||||
}
|
||||
System.err.println("Single death");
|
||||
handleSingleStackDeath(killed, drops, droppedExp, event);
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,8 @@ import org.bukkit.World;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.metadata.FixedMetadataValue;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@ -38,6 +40,19 @@ public class EntityStackManager {
|
||||
return entity.getMetadata("US_AMOUNT").get(0).asInt();
|
||||
}
|
||||
|
||||
public String getLastPlayerDamage(Entity entity) {
|
||||
if (!entity.hasMetadata("US_LAST_PLAYER_DAMAGE")) return null;
|
||||
if (entity.getMetadata("US_LAST_PLAYER_DAMAGE").isEmpty()) return null;
|
||||
return entity.getMetadata("US_LAST_PLAYER_DAMAGE").get(0).asString();
|
||||
}
|
||||
|
||||
public void setLastPlayerDamage(Entity entity, Player player) {
|
||||
if (player == null) return;
|
||||
if (entity == null) return;
|
||||
if (entity instanceof Player) return;
|
||||
entity.setMetadata("US_LAST_PLAYER_DAMAGE", new FixedMetadataValue(plugin, player.getName()));
|
||||
}
|
||||
|
||||
public EntityStack addStack(LivingEntity entity) {
|
||||
return addStack(entity, getAmount(entity) == 1 ? 1 : getAmount(entity));
|
||||
}
|
||||
|
@ -44,25 +44,31 @@ import org.bukkit.entity.TropicalFish;
|
||||
import org.bukkit.entity.Villager;
|
||||
import org.bukkit.entity.Wolf;
|
||||
import org.bukkit.entity.Zombie;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import org.bukkit.inventory.EntityEquipment;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TimerTask;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class StackingTask implements Runnable {
|
||||
public class StackingTask extends TimerTask {
|
||||
|
||||
private final UltimateStacker plugin;
|
||||
private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
|
||||
@ -99,7 +105,7 @@ public class StackingTask implements Runnable {
|
||||
|
||||
// Start the stacking task.
|
||||
//runTaskTimerAsynchronously(plugin, 0, Settings.STACK_SEARCH_TICK_SPEED.getInt());
|
||||
executorService.scheduleAtFixedRate(this, 0, Settings.STACK_SEARCH_TICK_SPEED.getInt()*20L, java.util.concurrent.TimeUnit.MILLISECONDS);
|
||||
executorService.scheduleAtFixedRate(this, 0, (Settings.STACK_SEARCH_TICK_SPEED.getInt()*50L), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
@ -108,44 +114,48 @@ public class StackingTask implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
// Should entities be stacked?
|
||||
if (!Settings.STACK_ENTITIES.getBoolean()) return;
|
||||
//make sure if the task running if any error 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;
|
||||
// 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;
|
||||
try {
|
||||
entities = getLivingEntitiesSync(sWorld).get();
|
||||
} catch (ExecutionException | InterruptedException ex) {
|
||||
ex.printStackTrace();
|
||||
continue;
|
||||
}
|
||||
Collections.reverse(entities);
|
||||
|
||||
// Loop through the entities.
|
||||
for (LivingEntity entity : entities) {
|
||||
// Get entity location to pass around as its faster this way.
|
||||
Location location = entity.getLocation();
|
||||
|
||||
// Check to see if entity is not stackable.
|
||||
if (!isEntityStackable(entity))
|
||||
// Get the loaded entities from the current world and reverse them.
|
||||
List<LivingEntity> entities;
|
||||
try {
|
||||
entities = getLivingEntitiesSync(sWorld).get();
|
||||
} catch (ExecutionException | InterruptedException ex) {
|
||||
ex.printStackTrace();
|
||||
continue;
|
||||
}
|
||||
Collections.reverse(entities);
|
||||
|
||||
// Make sure our entity has not already been processed.
|
||||
// Skip it if it has been.
|
||||
if (this.processed.contains(entity.getUniqueId())) continue;
|
||||
// Loop through the entities.
|
||||
for (LivingEntity entity : entities) {
|
||||
// Make sure our entity has not already been processed.
|
||||
// Skip it if it has been.
|
||||
if (this.processed.contains(entity.getUniqueId())) continue;
|
||||
|
||||
// Process the entity.
|
||||
this.processEntity(entity, sWorld, location);
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Clear caches in preparation for the next run.
|
||||
this.processed.clear();
|
||||
this.cachedChunks.clear();
|
||||
// Clear caches in preparation for the next run.
|
||||
this.processed.clear();
|
||||
this.cachedChunks.clear();
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
|
||||
private Future<List<LivingEntity>> getLivingEntitiesSync(SWorld sWorld) {
|
||||
@ -186,9 +196,10 @@ public class StackingTask implements Runnable {
|
||||
// If only stack from spawners is enabled, make sure the entity spawned from a spawner.
|
||||
if (!"SPAWNER".equals(spawnReason))
|
||||
return false;
|
||||
} else if (!(stackReasons = this.stackReasons).isEmpty() && !stackReasons.contains(spawnReason))
|
||||
} else if (!(stackReasons = this.stackReasons).isEmpty() && !stackReasons.contains(spawnReason)) {
|
||||
// Only stack if on the list of events to stack
|
||||
return false;
|
||||
}
|
||||
|
||||
// Cast our entity to living entity.
|
||||
LivingEntity livingEntity = (LivingEntity) entity;
|
||||
@ -224,6 +235,7 @@ public class StackingTask implements Runnable {
|
||||
|
||||
if (isStack && baseStack.getAmount() == maxEntityStackSize) {
|
||||
// If the stack is already at the max size then we can skip it.
|
||||
processed.add(baseEntity.getUniqueId());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -236,10 +248,10 @@ public class StackingTask implements Runnable {
|
||||
// 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"))
|
||||
|| !configurationSection.getBoolean("Mobs." + baseEntity.getType().name() + ".Enabled")) {
|
||||
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<>();
|
||||
@ -258,24 +270,24 @@ public class StackingTask implements Runnable {
|
||||
|
||||
// Get this entities friendStack.
|
||||
EntityStack friendStack = stackManager.getStack(friendlyEntity);
|
||||
|
||||
if (friendStack == null) continue;
|
||||
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 = (friendStack.getAmount() + amountToStack) > maxEntityStackSize;
|
||||
boolean overstack = (amount + amountToStack) > maxEntityStackSize;
|
||||
|
||||
if (!overstack) {
|
||||
friendStack.setAmount(friendStack.getAmount() + amountToStack);
|
||||
if (baseEntity.isLeashed())
|
||||
Bukkit.getScheduler().runTask(plugin, () -> baseEntity.getWorld()
|
||||
.dropItemNaturally(baseEntity.getLocation(), CompatibleMaterial.LEAD.getItem()));
|
||||
if (baseStack != null) {
|
||||
baseStack.destroy();
|
||||
}
|
||||
stackManager.createStack(friendlyEntity, amount + amountToStack);
|
||||
processed.add(baseEntity.getUniqueId());
|
||||
|
||||
Bukkit.getScheduler().runTask(plugin, () -> {
|
||||
if (baseEntity.isLeashed()) {
|
||||
baseEntity.getWorld().dropItemNaturally(baseEntity.getLocation(), CompatibleMaterial.LEAD.getItem());
|
||||
}
|
||||
baseEntity.remove();
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -301,12 +313,16 @@ public class StackingTask implements Runnable {
|
||||
} while (finalStackSize >= 0);
|
||||
});
|
||||
|
||||
// Remove our entity and mark it as processed.
|
||||
//Mark it as processed.
|
||||
processed.add(livingEntity.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())));
|
||||
}
|
||||
World world = location.getWorld();
|
||||
Set<CachedChunk> chunks = new HashSet<>();
|
||||
if (world == null) return chunks;
|
||||
@ -330,55 +346,31 @@ public class StackingTask implements Runnable {
|
||||
return chunks;
|
||||
}
|
||||
|
||||
private List<LivingEntity> getNearbyEntities(SWorld sWorld, Location location, double radius, boolean singleChunk) {
|
||||
/**
|
||||
* 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) {
|
||||
List<LivingEntity> entities = new ArrayList<>();
|
||||
for (CachedChunk chunk : getNearbyChunks(sWorld, location, radius, singleChunk)) {
|
||||
if (chunk == null) continue;
|
||||
Entity[] entityArray;
|
||||
if (cachedChunks.containsKey(chunk)) {
|
||||
entityArray = cachedChunks.get(chunk);
|
||||
} else {
|
||||
try {
|
||||
entityArray = getEntitiesInChunkSync(chunk).get();
|
||||
cachedChunks.put(chunk, entityArray);
|
||||
} catch (ExecutionException | InterruptedException ex) {
|
||||
ex.printStackTrace();
|
||||
continue;
|
||||
Set<CachedChunk> chunks = getNearbyChunks(new SWorld(entity.getWorld()), entity.getLocation(), radius, singleChunk);
|
||||
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) {
|
||||
entities.add((LivingEntity) e);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
entities.removeIf(entity1 -> entity1.equals(entity));
|
||||
return entities;
|
||||
}
|
||||
|
||||
public int getSimilarStacksInChunk(SWorld sWorld, LivingEntity entity) {
|
||||
int count = 0;
|
||||
for (LivingEntity e : getNearbyEntities(sWorld, entity.getLocation(), -1, true)) {
|
||||
if (entity.getType() == e.getType() && plugin.getEntityStackManager().isStackedEntity(e))
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public List<LivingEntity> getSimilarEntitiesAroundEntity(LivingEntity initialEntity, SWorld sWorld, 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(sWorld, location, searchRadius, stackWholeChunk)) {
|
||||
if (entity.getType() != initialEntity.getType() || entity == initialEntity)
|
||||
continue;
|
||||
entityList.add(entity);
|
||||
}
|
||||
List<LivingEntity> entityList = new LinkedList<>(getFriendlyStacksNearby(initialEntity, searchRadius, stackWholeChunk));
|
||||
|
||||
CustomEntity customEntity = plugin.getCustomEntityManager().getCustomEntity(initialEntity);
|
||||
if (customEntity != null)
|
||||
|
Loading…
Reference in New Issue
Block a user