2023-05-25 19:20:03 +02:00
|
|
|
package com.craftaro.ultimatestacker.stackable.entity;
|
|
|
|
|
2023-05-30 11:21:46 +02:00
|
|
|
import com.craftaro.ultimatestacker.UltimateStacker;
|
2023-05-25 19:20:03 +02:00
|
|
|
import com.craftaro.ultimatestacker.api.events.entity.EntityStackKillEvent;
|
2023-05-30 11:21:46 +02:00
|
|
|
import com.craftaro.ultimatestacker.api.stack.entity.EntityStack;
|
|
|
|
import com.craftaro.ultimatestacker.settings.Settings;
|
2023-05-25 19:20:03 +02:00
|
|
|
import com.craftaro.ultimatestacker.utils.Async;
|
|
|
|
import com.craftaro.ultimatestacker.utils.Methods;
|
2021-03-01 17:02:36 +01:00
|
|
|
import com.songoda.core.compatibility.ServerVersion;
|
2021-06-14 01:30:48 +02:00
|
|
|
import com.songoda.core.lootables.loot.Drop;
|
|
|
|
import com.songoda.core.lootables.loot.DropUtils;
|
2023-05-06 12:58:54 +02:00
|
|
|
import com.songoda.core.utils.EntityUtils;
|
2020-08-25 01:01:11 +02:00
|
|
|
import org.bukkit.Bukkit;
|
|
|
|
import org.bukkit.Location;
|
2023-05-25 19:20:03 +02:00
|
|
|
import org.bukkit.entity.EntityType;
|
2020-08-25 01:01:11 +02:00
|
|
|
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;
|
2023-05-25 19:20:03 +02:00
|
|
|
import org.bukkit.metadata.FixedMetadataValue;
|
2020-08-25 01:01:11 +02:00
|
|
|
import org.bukkit.util.Vector;
|
|
|
|
|
|
|
|
import java.util.List;
|
2023-02-04 14:48:13 +01:00
|
|
|
import java.util.Objects;
|
2023-05-25 19:20:03 +02:00
|
|
|
import java.util.UUID;
|
|
|
|
|
|
|
|
public class EntityStackImpl implements EntityStack {
|
|
|
|
|
|
|
|
private final UltimateStacker plugin = UltimateStacker.getInstance();
|
|
|
|
private int amount;
|
|
|
|
private LivingEntity hostEntity;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets an existing stack from an entity or creates a new one if it doesn't exist.
|
|
|
|
* @param entity The entity to get the stack from.
|
|
|
|
*/
|
|
|
|
public 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;
|
|
|
|
updateNameTag();
|
|
|
|
} else {
|
|
|
|
//get the amount from the entity
|
|
|
|
this.amount = UltimateStacker.getInstance().getEntityStackManager().getStackedEntity(entity).getAmount();
|
|
|
|
}
|
|
|
|
this.hostEntity = entity;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates a new stack or overrides an existing stack.
|
|
|
|
* @param entity The entity to create the stack for.
|
|
|
|
* @param amount The amount of entities in the stack.
|
|
|
|
*/
|
|
|
|
public EntityStackImpl(LivingEntity entity, int amount) {
|
|
|
|
if (entity == null) return;
|
|
|
|
this.hostEntity = entity;
|
|
|
|
this.amount = amount;
|
|
|
|
entity.setMetadata("US_AMOUNT", new FixedMetadataValue(UltimateStacker.getInstance(), amount));
|
|
|
|
updateNameTag();
|
|
|
|
}
|
2020-08-25 01:01:11 +02:00
|
|
|
|
2023-05-25 19:20:03 +02:00
|
|
|
@Override
|
|
|
|
public EntityType getType() {
|
|
|
|
return hostEntity.getType();
|
|
|
|
}
|
2020-08-25 01:01:11 +02:00
|
|
|
|
2023-05-25 19:20:03 +02:00
|
|
|
@Override
|
|
|
|
public int getAmount() {
|
|
|
|
return amount;
|
|
|
|
}
|
2020-08-25 01:01:11 +02:00
|
|
|
|
2023-05-25 19:20:03 +02:00
|
|
|
@Override
|
|
|
|
public void setAmount(int amount) {
|
|
|
|
this.amount = amount;
|
|
|
|
this.hostEntity.setMetadata("US_AMOUNT", new FixedMetadataValue(UltimateStacker.getInstance(), amount));
|
|
|
|
updateNameTag();
|
2020-08-25 01:01:11 +02:00
|
|
|
}
|
|
|
|
|
2023-05-25 19:20:03 +02:00
|
|
|
@Override
|
|
|
|
public void add(int amount) {
|
|
|
|
this.amount += amount;
|
2020-08-25 01:01:11 +02:00
|
|
|
}
|
|
|
|
|
2023-05-25 19:20:03 +02:00
|
|
|
@Override
|
|
|
|
public void take(int amount) {
|
|
|
|
this.amount -= amount;
|
2020-09-01 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
2023-05-25 19:20:03 +02:00
|
|
|
@Override
|
|
|
|
public UUID getUuid() {
|
|
|
|
return hostEntity.getUniqueId();
|
2020-08-25 01:01:11 +02:00
|
|
|
}
|
|
|
|
|
2023-05-25 19:20:03 +02:00
|
|
|
@Override
|
2020-08-25 01:01:11 +02:00
|
|
|
public LivingEntity getHostEntity() {
|
|
|
|
return hostEntity;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void handleWholeStackDeath(LivingEntity killed, List<Drop> drops, boolean custom, int droppedExp, EntityDeathEvent event) {
|
|
|
|
|
2023-05-25 19:20:03 +02:00
|
|
|
EntityStack stack = plugin.getEntityStackManager().getStackedEntity(killed);
|
2021-05-27 21:36:34 +02:00
|
|
|
// In versions 1.14 and below experience is not dropping. Because of this we are doing this ourselves.
|
|
|
|
if (ServerVersion.isServerVersionAtOrBelow(ServerVersion.V1_14)) {
|
|
|
|
Location killedLocation = killed.getLocation();
|
|
|
|
if (droppedExp > 0)
|
|
|
|
killedLocation.getWorld().spawn(killedLocation, ExperienceOrb.class).setExperience(droppedExp * getAmount());
|
|
|
|
} else {
|
|
|
|
event.setDroppedExp(droppedExp * getAmount());
|
|
|
|
}
|
2021-05-27 21:13:43 +02:00
|
|
|
|
2020-08-25 01:01:11 +02:00
|
|
|
|
2023-01-02 13:38:58 +01:00
|
|
|
if (plugin.getCustomEntityManager().getCustomEntity(killed) == null) {
|
|
|
|
Async.run(() -> {
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
DropUtils.processStackedDrop(killed, plugin.getLootablesManager().getDrops(killed, getAmount()), event);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
event.getDrops().clear();
|
2023-05-25 19:20:03 +02:00
|
|
|
destroy();
|
2020-08-25 01:01:11 +02:00
|
|
|
if (killed.getKiller() == null) return;
|
2020-08-31 17:40:05 +02:00
|
|
|
plugin.addExp(killed.getKiller(), this);
|
2020-08-25 01:01:11 +02:00
|
|
|
}
|
|
|
|
|
2021-03-01 17:02:36 +01:00
|
|
|
private void handleSingleStackDeath(LivingEntity killed, List<Drop> drops, int droppedExp, EntityDeathEvent event) {
|
2023-01-02 13:38:58 +01:00
|
|
|
Bukkit.getPluginManager().callEvent(new EntityStackKillEvent(this, false));
|
|
|
|
|
2021-10-17 02:23:36 +02:00
|
|
|
Vector velocity = killed.getVelocity().clone();
|
2020-08-25 01:01:11 +02:00
|
|
|
killed.remove();
|
|
|
|
LivingEntity newEntity = takeOneAndSpawnEntity(killed.getLocation());
|
2023-01-02 13:38:58 +01:00
|
|
|
if (newEntity == null) {
|
|
|
|
return;
|
|
|
|
}
|
2020-08-25 01:01:11 +02:00
|
|
|
|
2021-03-01 17:02:36 +01:00
|
|
|
// In versions 1.14 and below experience is not dropping. Because of this we are doing this ourselves.
|
|
|
|
if (ServerVersion.isServerVersionAtOrBelow(ServerVersion.V1_14)) {
|
|
|
|
Location killedLocation = killed.getLocation();
|
|
|
|
if (droppedExp > 0)
|
|
|
|
killedLocation.getWorld().spawn(killedLocation, ExperienceOrb.class).setExperience(droppedExp);
|
|
|
|
}
|
2023-01-02 13:38:58 +01:00
|
|
|
if (plugin.getCustomEntityManager().getCustomEntity(killed) == null) {
|
|
|
|
DropUtils.processStackedDrop(killed, drops, event);
|
|
|
|
}
|
2020-08-25 01:01:11 +02:00
|
|
|
|
2021-10-17 02:23:36 +02:00
|
|
|
newEntity.setVelocity(velocity);
|
2023-05-25 19:20:03 +02:00
|
|
|
plugin.getEntityStackManager().updateStack(killed, newEntity);
|
2020-08-25 01:01:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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");
|
|
|
|
|
2023-02-22 09:59:28 +01:00
|
|
|
if (killWholeStack && getAmount() > 1) {
|
2020-08-25 01:01:11 +02:00
|
|
|
handleWholeStackDeath(killed, drops, custom, droppedExp, event);
|
2023-02-22 09:59:28 +01:00
|
|
|
} else if (getAmount() > 1) {
|
2020-08-25 01:01:11 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2023-03-29 21:21:00 +02:00
|
|
|
handleSingleStackDeath(killed, drops, droppedExp, event);
|
2020-08-25 01:01:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-25 19:20:03 +02:00
|
|
|
@Override
|
2023-02-05 13:14:44 +01:00
|
|
|
public synchronized LivingEntity takeOneAndSpawnEntity(Location location) {
|
2023-02-04 14:48:13 +01:00
|
|
|
if (amount <= 0) return null;
|
|
|
|
LivingEntity entity = Objects.requireNonNull(location.getWorld()).spawn(location, hostEntity.getClass());
|
2023-05-06 12:58:54 +02:00
|
|
|
if (Settings.NO_AI.getBoolean()) {
|
|
|
|
EntityUtils.setUnaware(entity);
|
|
|
|
}
|
2023-02-04 14:48:13 +01:00
|
|
|
this.hostEntity = entity;
|
2023-02-05 13:14:44 +01:00
|
|
|
setAmount(amount--);
|
2023-02-04 14:48:13 +01:00
|
|
|
updateNameTag();
|
|
|
|
return entity;
|
|
|
|
}
|
|
|
|
|
2023-05-25 19:20:03 +02:00
|
|
|
@Override
|
2023-02-05 13:14:44 +01:00
|
|
|
public synchronized void releaseHost() {
|
2020-08-25 01:01:11 +02:00
|
|
|
LivingEntity oldHost = hostEntity;
|
|
|
|
LivingEntity entity = takeOneAndSpawnEntity(hostEntity.getLocation());
|
2023-02-04 14:48:13 +01:00
|
|
|
if (getAmount() >= 0) {
|
2020-08-25 01:01:11 +02:00
|
|
|
plugin.getEntityStackManager().updateStack(oldHost, entity);
|
2023-02-04 14:48:13 +01:00
|
|
|
updateNameTag();
|
2020-08-25 01:01:11 +02:00
|
|
|
} else {
|
|
|
|
destroy();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-25 19:20:03 +02:00
|
|
|
@Override
|
2023-02-05 13:14:44 +01:00
|
|
|
public synchronized void destroy() {
|
2023-02-04 14:48:13 +01:00
|
|
|
if (hostEntity == null) return;
|
|
|
|
Bukkit.getScheduler().runTask(plugin, hostEntity::remove);
|
2020-08-25 01:01:11 +02:00
|
|
|
hostEntity = null;
|
|
|
|
}
|
|
|
|
|
2023-05-25 19:20:03 +02:00
|
|
|
private void updateNameTag() {
|
|
|
|
if (hostEntity == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
hostEntity.setCustomNameVisible(!Settings.HOLOGRAMS_ON_LOOK_ENTITY.getBoolean());
|
|
|
|
hostEntity.setCustomName(Methods.compileEntityName(hostEntity, getAmount()));
|
2020-08-25 01:01:11 +02:00
|
|
|
}
|
|
|
|
}
|