138 lines
3.9 KiB
Java
138 lines
3.9 KiB
Java
package net.citizensnpcs.trait;
|
|
|
|
import java.util.UUID;
|
|
|
|
import org.bukkit.Bukkit;
|
|
import org.bukkit.entity.Entity;
|
|
import org.bukkit.entity.Player;
|
|
import org.bukkit.entity.Projectile;
|
|
import org.bukkit.event.EventHandler;
|
|
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
|
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
|
|
|
|
import net.citizensnpcs.Settings.Setting;
|
|
import net.citizensnpcs.api.ai.flocking.Flocker;
|
|
import net.citizensnpcs.api.ai.flocking.RadiusNPCFlock;
|
|
import net.citizensnpcs.api.ai.flocking.SeparationBehavior;
|
|
import net.citizensnpcs.api.persistence.Persist;
|
|
import net.citizensnpcs.api.trait.Trait;
|
|
import net.citizensnpcs.api.trait.TraitName;
|
|
|
|
/**
|
|
* Persists a {@link Player} to follow while spawned. Optionally allows protecting of the player as well.
|
|
*/
|
|
@TraitName("followtrait")
|
|
public class FollowTrait extends Trait {
|
|
private Entity entity;
|
|
private Flocker flock;
|
|
@Persist
|
|
private UUID followingUUID;
|
|
@Persist
|
|
private double margin = -1;
|
|
@Persist
|
|
private boolean protect;
|
|
|
|
public FollowTrait() {
|
|
super("followtrait");
|
|
}
|
|
|
|
/**
|
|
* Sets the {@link Entity} to follow
|
|
*/
|
|
public void follow(Entity entity) {
|
|
this.followingUUID = entity == null ? null : entity.getUniqueId();
|
|
if (npc.getNavigator().isNavigating() && this.entity != null && npc.getNavigator().getEntityTarget() != null
|
|
&& this.entity == npc.getNavigator().getEntityTarget().getTarget()) {
|
|
npc.getNavigator().cancelNavigation();
|
|
}
|
|
this.entity = null;
|
|
}
|
|
|
|
public Entity getFollowing() {
|
|
return entity;
|
|
}
|
|
|
|
public double getFollowingMargin() {
|
|
return margin;
|
|
}
|
|
|
|
/**
|
|
* Returns whether the trait is actively following a {@link Entity}.
|
|
*/
|
|
public boolean isActive() {
|
|
return npc.isSpawned() && entity != null;
|
|
}
|
|
|
|
public boolean isEnabled() {
|
|
return followingUUID != null;
|
|
}
|
|
|
|
@Override
|
|
public void onDespawn() {
|
|
flock = null;
|
|
}
|
|
|
|
@EventHandler
|
|
private void onEntityDamage(EntityDamageByEntityEvent event) {
|
|
if (isActive() && protect && event.getEntity().equals(entity)) {
|
|
Entity damager = event.getDamager();
|
|
if (event.getEntity() instanceof Projectile) {
|
|
Projectile projectile = (Projectile) event.getEntity();
|
|
if (projectile.getShooter() instanceof Entity) {
|
|
damager = (Entity) projectile.getShooter();
|
|
}
|
|
}
|
|
npc.getNavigator().setTarget(damager, true);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onSpawn() {
|
|
flock = new Flocker(npc, new RadiusNPCFlock(4, 0), new SeparationBehavior(1));
|
|
}
|
|
|
|
@Override
|
|
public void run() {
|
|
if (entity == null || !entity.isValid()) {
|
|
if (followingUUID == null)
|
|
return;
|
|
entity = Bukkit.getPlayer(followingUUID);
|
|
if (entity == null) {
|
|
entity = Bukkit.getEntity(followingUUID);
|
|
}
|
|
if (entity == null)
|
|
return;
|
|
}
|
|
if (!isActive())
|
|
return;
|
|
|
|
if (!npc.getEntity().getWorld().equals(entity.getWorld())) {
|
|
if (Setting.FOLLOW_ACROSS_WORLDS.asBoolean()) {
|
|
npc.teleport(entity.getLocation(), TeleportCause.PLUGIN);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (!npc.getNavigator().isNavigating()) {
|
|
npc.getNavigator().setTarget(entity, false);
|
|
if (margin > 0) {
|
|
npc.getNavigator().getLocalParameters().distanceMargin(margin);
|
|
}
|
|
|
|
} else {
|
|
flock.run();
|
|
}
|
|
}
|
|
|
|
public void setFollowingMargin(double margin) {
|
|
this.margin = margin;
|
|
}
|
|
|
|
/**
|
|
* Sets whether to protect the followed Entity (similar to wolves in Minecraft, attack whoever attacks the entity).
|
|
*/
|
|
public void setProtect(boolean protect) {
|
|
this.protect = protect;
|
|
}
|
|
}
|