mirror of
https://github.com/CitizensDev/Citizens2.git
synced 2024-11-29 22:23:59 +01:00
Merge AIController and Navigator
This commit is contained in:
parent
01fa072112
commit
ca3790fde1
@ -1,8 +1,8 @@
|
|||||||
package net.citizensnpcs;
|
package net.citizensnpcs;
|
||||||
|
|
||||||
import net.citizensnpcs.api.npc.NPC;
|
import net.citizensnpcs.api.npc.NPC;
|
||||||
|
import net.citizensnpcs.npc.CitizensNPC;
|
||||||
import net.citizensnpcs.npc.CitizensNPCManager;
|
import net.citizensnpcs.npc.CitizensNPCManager;
|
||||||
import net.citizensnpcs.npc.ai.CitizensNavigator;
|
|
||||||
|
|
||||||
public class NPCUpdater implements Runnable {
|
public class NPCUpdater implements Runnable {
|
||||||
private final CitizensNPCManager npcManager;
|
private final CitizensNPCManager npcManager;
|
||||||
@ -14,6 +14,6 @@ public class NPCUpdater implements Runnable {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
for (NPC npc : npcManager)
|
for (NPC npc : npcManager)
|
||||||
((CitizensNavigator) npc.getNavigator()).update();
|
((CitizensNPC) npc).update();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,26 +3,27 @@ package net.citizensnpcs.npc;
|
|||||||
import net.citizensnpcs.api.event.NPCDespawnEvent;
|
import net.citizensnpcs.api.event.NPCDespawnEvent;
|
||||||
import net.citizensnpcs.api.event.NPCSpawnEvent;
|
import net.citizensnpcs.api.event.NPCSpawnEvent;
|
||||||
import net.citizensnpcs.api.npc.AbstractNPC;
|
import net.citizensnpcs.api.npc.AbstractNPC;
|
||||||
import net.citizensnpcs.api.npc.ai.Navigator;
|
|
||||||
import net.citizensnpcs.api.npc.trait.trait.SpawnLocation;
|
import net.citizensnpcs.api.npc.trait.trait.SpawnLocation;
|
||||||
import net.citizensnpcs.api.npc.trait.trait.Spawned;
|
import net.citizensnpcs.api.npc.trait.trait.Spawned;
|
||||||
import net.citizensnpcs.npc.ai.CitizensNavigator;
|
import net.citizensnpcs.npc.ai.CitizensAI;
|
||||||
import net.citizensnpcs.util.Messaging;
|
import net.citizensnpcs.util.Messaging;
|
||||||
|
import net.minecraft.server.EntityLiving;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.entity.Entity;
|
import org.bukkit.entity.LivingEntity;
|
||||||
|
|
||||||
public abstract class CitizensNPC extends AbstractNPC {
|
public abstract class CitizensNPC extends AbstractNPC {
|
||||||
protected final CitizensNPCManager manager;
|
protected final CitizensNPCManager manager;
|
||||||
protected net.minecraft.server.Entity mcEntity;
|
protected final CitizensAI ai = new CitizensAI(this);
|
||||||
|
protected EntityLiving mcEntity;
|
||||||
|
|
||||||
protected CitizensNPC(CitizensNPCManager manager, int id, String name) {
|
protected CitizensNPC(CitizensNPCManager manager, int id, String name) {
|
||||||
super(id, name);
|
super(id, name);
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract net.minecraft.server.Entity createHandle(Location loc);
|
protected abstract EntityLiving createHandle(Location loc);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean despawn() {
|
public boolean despawn() {
|
||||||
@ -40,17 +41,17 @@ public abstract class CitizensNPC extends AbstractNPC {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Entity getBukkitEntity() {
|
public LivingEntity getBukkitEntity() {
|
||||||
return getHandle().getBukkitEntity();
|
return (LivingEntity) getHandle().getBukkitEntity();
|
||||||
}
|
}
|
||||||
|
|
||||||
public net.minecraft.server.Entity getHandle() {
|
public EntityLiving getHandle() {
|
||||||
return mcEntity;
|
return mcEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Navigator getNavigator() {
|
public CitizensAI getAI() {
|
||||||
return new CitizensNavigator(this);
|
return new CitizensAI(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -86,4 +87,8 @@ public abstract class CitizensNPC extends AbstractNPC {
|
|||||||
addTrait(new Spawned(true));
|
addTrait(new Spawned(true));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void update() {
|
||||||
|
ai.update();
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,43 +1,28 @@
|
|||||||
package net.citizensnpcs.npc.ai;
|
package net.citizensnpcs.npc.ai;
|
||||||
|
|
||||||
import net.citizensnpcs.api.npc.ai.Navigator;
|
import net.citizensnpcs.api.npc.ai.AI;
|
||||||
import net.citizensnpcs.api.npc.ai.NavigatorCallback;
|
import net.citizensnpcs.api.npc.ai.Goal;
|
||||||
|
import net.citizensnpcs.api.npc.ai.NavigationCallback;
|
||||||
import net.citizensnpcs.npc.CitizensNPC;
|
import net.citizensnpcs.npc.CitizensNPC;
|
||||||
import net.citizensnpcs.trait.LookClose;
|
import net.citizensnpcs.util.Messaging;
|
||||||
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.entity.Entity;
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.LivingEntity;
|
import org.bukkit.entity.LivingEntity;
|
||||||
|
|
||||||
public class CitizensNavigator implements Navigator {
|
public class CitizensAI implements AI {
|
||||||
private final CitizensNPC npc;
|
|
||||||
private PathStrategy executing;
|
private PathStrategy executing;
|
||||||
|
private Runnable ai;
|
||||||
|
private final CitizensNPC npc;
|
||||||
|
|
||||||
public CitizensNavigator(CitizensNPC npc) {
|
public CitizensAI(CitizensNPC npc) {
|
||||||
this.npc = npc;
|
this.npc = npc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerCallback(NavigatorCallback callback) {
|
public void addGoal(int priority, Goal goal) {
|
||||||
}
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
public void update() {
|
|
||||||
if (npc.getHandle() != null && npc.getHandle().world.findNearbyPlayer(npc.getHandle(), 5) != null)
|
|
||||||
if (npc.getTrait(LookClose.class).shouldLookClose()
|
|
||||||
&& npc.getHandle().world.findNearbyPlayer(npc.getHandle(), 5) != null)
|
|
||||||
faceEntity(npc.getHandle().world.findNearbyPlayer(npc.getHandle(), 5).getBukkitEntity());
|
|
||||||
if (executing != null)
|
|
||||||
executing.update();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setDestination(Location destination) {
|
|
||||||
executing = new MoveStrategy(npc, destination);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setTarget(LivingEntity target, boolean aggressive) {
|
|
||||||
executing = new TargetStrategy(npc, target, aggressive);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void faceEntity(Entity target) {
|
private void faceEntity(Entity target) {
|
||||||
@ -61,4 +46,38 @@ public class CitizensNavigator implements Navigator {
|
|||||||
npc.getHandle().yaw = (float) yaw - 90;
|
npc.getHandle().yaw = (float) yaw - 90;
|
||||||
npc.getHandle().pitch = (float) pitch;
|
npc.getHandle().pitch = (float) pitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerNavigationCallback(NavigationCallback callback) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAI(Runnable ai) {
|
||||||
|
this.ai = ai;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDestination(Location destination) {
|
||||||
|
executing = new MoveStrategy(npc, destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTarget(LivingEntity target, boolean aggressive) {
|
||||||
|
executing = new TargetStrategy(npc, target, aggressive);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update() {
|
||||||
|
if (executing != null && executing.update()) {
|
||||||
|
executing = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ai != null) {
|
||||||
|
try {
|
||||||
|
ai.run();
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
Messaging.log("Unexpected error while running ai " + ai);
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -24,13 +24,27 @@ public class TargetStrategy implements PathStrategy {
|
|||||||
if (target == null || target.dead)
|
if (target == null || target.dead)
|
||||||
return true;
|
return true;
|
||||||
current = new MoveStrategy(handle, handle.world.findPath(handle, target, 16F));
|
current = new MoveStrategy(handle, handle.world.findPath(handle, target, 16F));
|
||||||
if (aggro)
|
if (aggro && canAttack()) {
|
||||||
if (handle instanceof EntityMonster)
|
if (handle instanceof EntityMonster) {
|
||||||
((EntityMonster) handle).d(target);
|
((EntityMonster) handle).d(target);
|
||||||
else if (handle instanceof EntityHuman)
|
} else if (handle instanceof EntityHuman) {
|
||||||
((EntityHuman) handle).attack(target);
|
((EntityHuman) handle).attack(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
current.update();
|
current.update();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean canAttack() {
|
||||||
|
return handle.attackTicks == 0
|
||||||
|
&& (handle.boundingBox.e > target.boundingBox.b && handle.boundingBox.b < target.boundingBox.e)
|
||||||
|
&& distanceSquared() <= ATTACK_DISTANCE && handle.g(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final double ATTACK_DISTANCE = 1.75 * 1.75;
|
||||||
|
|
||||||
|
private double distanceSquared() {
|
||||||
|
return handle.getBukkitEntity().getLocation().distanceSquared(target.getBukkitEntity().getLocation());
|
||||||
|
}
|
||||||
}
|
}
|
@ -5,12 +5,9 @@ import net.citizensnpcs.npc.CitizensNPCManager;
|
|||||||
import net.citizensnpcs.resource.lib.EntityHumanNPC;
|
import net.citizensnpcs.resource.lib.EntityHumanNPC;
|
||||||
import net.minecraft.server.EntityLiving;
|
import net.minecraft.server.EntityLiving;
|
||||||
import net.minecraft.server.ItemInWorldManager;
|
import net.minecraft.server.ItemInWorldManager;
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
import net.minecraft.server.WorldServer;
|
import net.minecraft.server.WorldServer;
|
||||||
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Server;
|
|
||||||
import org.bukkit.craftbukkit.CraftServer;
|
|
||||||
import org.bukkit.craftbukkit.CraftWorld;
|
import org.bukkit.craftbukkit.CraftWorld;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
@ -24,8 +21,13 @@ public class CitizensHumanNPC extends CitizensNPC {
|
|||||||
return (Player) getHandle().getBukkitEntity();
|
return (Player) getHandle().getBukkitEntity();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static MinecraftServer getMinecraftServer(Server server) {
|
@Override
|
||||||
return ((CraftServer) server).getServer();
|
public void update() {
|
||||||
|
super.update();
|
||||||
|
if (mcEntity.noDamageTicks > 0)
|
||||||
|
mcEntity.noDamageTicks--;
|
||||||
|
if (mcEntity.attackTicks > 0)
|
||||||
|
mcEntity.attackTicks--;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
83
src/net/citizensnpcs/npc/entity/CitizensMobNPC.java
Normal file
83
src/net/citizensnpcs/npc/entity/CitizensMobNPC.java
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
package net.citizensnpcs.npc.entity;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import net.citizensnpcs.npc.CitizensNPC;
|
||||||
|
import net.citizensnpcs.npc.CitizensNPCManager;
|
||||||
|
import net.minecraft.server.Entity;
|
||||||
|
import net.minecraft.server.EntityLiving;
|
||||||
|
import net.minecraft.server.EntityTypes;
|
||||||
|
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.craftbukkit.CraftWorld;
|
||||||
|
import org.bukkit.entity.LivingEntity;
|
||||||
|
|
||||||
|
public abstract class CitizensMobNPC extends CitizensNPC {
|
||||||
|
private final Constructor<? extends EntityLiving> constructor;
|
||||||
|
|
||||||
|
protected CitizensMobNPC(CitizensNPCManager manager, int id, String name, Class<? extends EntityLiving> clazz) {
|
||||||
|
super(manager, id, name);
|
||||||
|
try {
|
||||||
|
this.constructor = clazz.getConstructor(World.class);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new IllegalStateException("unable to find an entity constructor");
|
||||||
|
}
|
||||||
|
if (!classToInt.containsKey(clazz))
|
||||||
|
registerEntityClass(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
private EntityLiving createEntityFromClass(net.minecraft.server.World world) {
|
||||||
|
try {
|
||||||
|
return constructor.newInstance(world);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected EntityLiving createHandle(Location loc) {
|
||||||
|
EntityLiving entity = createEntityFromClass(((CraftWorld) loc.getWorld()).getHandle());
|
||||||
|
mcEntity.setPositionRotation(loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch());
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LivingEntity getBukkitEntity() {
|
||||||
|
return (LivingEntity) getHandle().getBukkitEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<Class<? extends Entity>, Integer> classToInt;
|
||||||
|
private static Map<Integer, Class<? extends Entity>> intToClass;
|
||||||
|
|
||||||
|
private static void registerEntityClass(Class<? extends Entity> clazz) {
|
||||||
|
Class<?> search = clazz;
|
||||||
|
while ((search = search.getSuperclass()) != null && Entity.class.isAssignableFrom(search)) {
|
||||||
|
if (!classToInt.containsKey(search))
|
||||||
|
continue;
|
||||||
|
int code = classToInt.get(search);
|
||||||
|
intToClass.put(code, clazz);
|
||||||
|
classToInt.put(clazz, code);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("unable to find valid entity superclass");
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
Field field = EntityTypes.class.getDeclaredField("d");
|
||||||
|
field.setAccessible(true);
|
||||||
|
intToClass = (Map<Integer, Class<? extends Entity>>) field.get(null);
|
||||||
|
field = EntityTypes.class.getDeclaredField("e");
|
||||||
|
field.setAccessible(true);
|
||||||
|
classToInt = (Map<Class<? extends Entity>, Integer>) field.get(null);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Unable to fetch entity class mapping - is Citizens updated for this version of CraftBukkit?");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
74
src/net/citizensnpcs/resource/lib/entity/EntityHumanNPC.java
Normal file
74
src/net/citizensnpcs/resource/lib/entity/EntityHumanNPC.java
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
package net.citizensnpcs.resource.lib.entity;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import net.citizensnpcs.resource.lib.NPCNetHandler;
|
||||||
|
import net.citizensnpcs.resource.lib.NPCNetworkManager;
|
||||||
|
import net.citizensnpcs.resource.lib.NPCSocket;
|
||||||
|
import net.citizensnpcs.util.Messaging;
|
||||||
|
import net.minecraft.server.EntityPlayer;
|
||||||
|
import net.minecraft.server.ItemInWorldManager;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.NetHandler;
|
||||||
|
import net.minecraft.server.NetworkManager;
|
||||||
|
import net.minecraft.server.World;
|
||||||
|
|
||||||
|
import org.bukkit.craftbukkit.entity.CraftEntity;
|
||||||
|
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public class EntityHumanNPC extends EntityPlayer {
|
||||||
|
|
||||||
|
public EntityHumanNPC(MinecraftServer minecraftServer, World world, String string,
|
||||||
|
ItemInWorldManager itemInWorldManager) {
|
||||||
|
super(minecraftServer, world, string, itemInWorldManager);
|
||||||
|
itemInWorldManager.setGameMode(0);
|
||||||
|
|
||||||
|
NPCSocket socket = new NPCSocket();
|
||||||
|
NetworkManager netMgr = new NPCNetworkManager(socket, "npc mgr", new NetHandler() {
|
||||||
|
@Override
|
||||||
|
public boolean c() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
netServerHandler = new NPCNetHandler(minecraftServer, netMgr, this);
|
||||||
|
netMgr.a(netServerHandler);
|
||||||
|
|
||||||
|
try {
|
||||||
|
socket.close();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CraftPlayer getBukkitEntity() {
|
||||||
|
if (bukkitEntity == null) {
|
||||||
|
super.getBukkitEntity();
|
||||||
|
removeFromPlayerMap(name);
|
||||||
|
// Bukkit uses a map of player names to CraftPlayer instances to
|
||||||
|
// solve a reconnect issue, so NPC names will conflict with ordinary
|
||||||
|
// player names. Workaround.
|
||||||
|
}
|
||||||
|
return super.getBukkitEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeFromPlayerMap(String name) {
|
||||||
|
if (players != null)
|
||||||
|
players.remove(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, CraftPlayer> players;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
Field f = CraftEntity.class.getDeclaredField("players");
|
||||||
|
f.setAccessible(true);
|
||||||
|
players = (Map<String, CraftPlayer>) f.get(null);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Messaging.log("Unable to fetch player map from CraftEntity: " + ex.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user