Citizens2/main/src/main/java/net/citizensnpcs/trait/FollowTrait.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;
}
}