diff --git a/dist/pom.xml b/dist/pom.xml
index 6e6832046..56657b7a3 100644
--- a/dist/pom.xml
+++ b/dist/pom.xml
@@ -4,7 +4,7 @@
net.citizensnpcs
citizens-parent
- 2.0.21-SNAPSHOT
+ 2.0.22-SNAPSHOT
citizens
pom
@@ -55,5 +55,12 @@
jar
compile
+
+ ${project.groupId}
+ citizens-v1_12_R1
+ ${project.version}
+ jar
+ compile
+
\ No newline at end of file
diff --git a/main/pom.xml b/main/pom.xml
index a2698723c..ce3cf6a08 100644
--- a/main/pom.xml
+++ b/main/pom.xml
@@ -6,14 +6,14 @@
net.citizensnpcs
citizens-parent
- 2.0.21-SNAPSHOT
+ 2.0.22-SNAPSHOT
citizens-main
UTF-8
- 1.11-R0.1-SNAPSHOT
- 2.0.21-SNAPSHOT
+ 1.12-pre6-SNAPSHOT
+ 2.0.22-SNAPSHOT
1.5.4
1.4.12
Unknown
diff --git a/main/src/main/java/net/citizensnpcs/util/Util.java b/main/src/main/java/net/citizensnpcs/util/Util.java
index bcaac4112..6383b76f5 100644
--- a/main/src/main/java/net/citizensnpcs/util/Util.java
+++ b/main/src/main/java/net/citizensnpcs/util/Util.java
@@ -94,8 +94,9 @@ public class Util {
switch (type) {
case BAT:
case BLAZE:
- case GHAST:
case ENDER_DRAGON:
+ case GHAST:
+ case PARROT:
case WITHER:
return true;
default:
diff --git a/pom.xml b/pom.xml
index 56434a632..670ac04b6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,11 +7,12 @@
pom
net.citizensnpcs
citizens-parent
- 2.0.21-SNAPSHOT
+ 2.0.22-SNAPSHOT
main
v1_10_R1
v1_11_R1
+ v1_12_R1
dist
\ No newline at end of file
diff --git a/v1_10_R1/pom.xml b/v1_10_R1/pom.xml
index a253af287..6c1845438 100644
--- a/v1_10_R1/pom.xml
+++ b/v1_10_R1/pom.xml
@@ -5,7 +5,7 @@
net.citizensnpcs
citizens-parent
- 2.0.21-SNAPSHOT
+ 2.0.22-SNAPSHOT
citizens-v1_10_R1
diff --git a/v1_11_R1/pom.xml b/v1_11_R1/pom.xml
index 174f04c8b..e3d8c91b5 100644
--- a/v1_11_R1/pom.xml
+++ b/v1_11_R1/pom.xml
@@ -5,7 +5,7 @@
net.citizensnpcs
citizens-parent
- 2.0.21-SNAPSHOT
+ 2.0.22-SNAPSHOT
citizens-v1_11_R1
diff --git a/v1_11_R1/src/main/java/net/citizensnpcs/nms/v1_11_R1/util/NMSImpl.java b/v1_11_R1/src/main/java/net/citizensnpcs/nms/v1_11_R1/util/NMSImpl.java
index 542db4502..b88fb0536 100644
--- a/v1_11_R1/src/main/java/net/citizensnpcs/nms/v1_11_R1/util/NMSImpl.java
+++ b/v1_11_R1/src/main/java/net/citizensnpcs/nms/v1_11_R1/util/NMSImpl.java
@@ -954,7 +954,7 @@ public class NMSImpl implements NMSBridge {
@Override
public void setWitherCharged(Wither wither, boolean charged) {
EntityWither handle = ((CraftWither) wither).getHandle();
- handle.l(charged ? 20 : 0);
+ handle.g(charged ? 20 : 0);
}
@Override
@@ -1445,7 +1445,7 @@ public class NMSImpl implements NMSBridge {
}
public static void stopNavigation(NavigationAbstract navigation) {
- navigation.n();
+ navigation.o();
}
public static void updateAI(EntityLiving entity) {
diff --git a/v1_12_R1/pom.xml b/v1_12_R1/pom.xml
new file mode 100644
index 000000000..2c5ef7ae7
--- /dev/null
+++ b/v1_12_R1/pom.xml
@@ -0,0 +1,77 @@
+
+
+ 4.0.0
+
+ net.citizensnpcs
+ citizens-parent
+ 2.0.22-SNAPSHOT
+
+ citizens-v1_12_R1
+
+
+ UTF-8
+ 1.12-pre6-SNAPSHOT
+
+
+
+
+ everything
+ http://repo.citizensnpcs.co
+
+
+
+
+
+ ${project.groupId}
+ citizens-main
+ ${project.version}
+ jar
+ provided
+
+
+ org.bukkit
+ craftbukkit
+ ${craftbukkit.version}
+ jar
+ provided
+
+
+
+
+ clean package install
+ ${basedir}/src/main/java
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 2.3.2
+
+
+ 1.6
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 2.3.2
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 2.1
+
+
+ package
+
+ shade
+
+
+
+
+
+
+
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/BatController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/BatController.java
new file mode 100644
index 000000000..203476858
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/BatController.java
@@ -0,0 +1,174 @@
+package net.citizensnpcs.nms.v1_12_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftBat;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.entity.Bat;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.DamageSource;
+import net.minecraft.server.v1_12_R1.EntityBat;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class BatController extends MobEntityController {
+ public BatController() {
+ super(EntityBatNPC.class);
+ }
+
+ @Override
+ public Bat getBukkitEntity() {
+ return (Bat) super.getBukkitEntity();
+ }
+
+ public static class BatNPC extends CraftBat implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public BatNPC(EntityBatNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+
+ public static class EntityBatNPC extends EntityBat implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityBatNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityBatNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ setFlying(false);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new BatNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null) {
+ return super.isLeashed();
+ }
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ if (npc == null) {
+ super.M();
+ } else {
+ NMSImpl.updateAI(this);
+ npc.update();
+ }
+ }
+
+ public void setFlying(boolean flying) {
+ setAsleep(flying);
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/BlazeController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/BlazeController.java
new file mode 100644
index 000000000..77773bae4
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/BlazeController.java
@@ -0,0 +1,165 @@
+package net.citizensnpcs.nms.v1_12_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftBlaze;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.entity.Blaze;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.DamageSource;
+import net.minecraft.server.v1_12_R1.EntityBlaze;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class BlazeController extends MobEntityController {
+ public BlazeController() {
+ super(EntityBlazeNPC.class);
+ }
+
+ @Override
+ public Blaze getBukkitEntity() {
+ return (Blaze) super.getBukkitEntity();
+ }
+
+ public static class BlazeNPC extends CraftBlaze implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public BlazeNPC(EntityBlazeNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+
+ public static class EntityBlazeNPC extends EntityBlaze implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityBlazeNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityBlazeNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new BlazeNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ if (npc != null) {
+ npc.update();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/CaveSpiderController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/CaveSpiderController.java
new file mode 100644
index 000000000..f39793dc3
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/CaveSpiderController.java
@@ -0,0 +1,210 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftCaveSpider;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.entity.CaveSpider;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityCaveSpider;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class CaveSpiderController extends MobEntityController {
+ public CaveSpiderController() {
+ super(EntityCaveSpiderNPC.class);
+ }
+
+ @Override
+ public CaveSpider getBukkitEntity() {
+ return (CaveSpider) super.getBukkitEntity();
+ }
+
+ public static class CaveSpiderNPC extends CraftCaveSpider implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public CaveSpiderNPC(EntityCaveSpiderNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+
+ public static class EntityCaveSpiderNPC extends EntityCaveSpider implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityCaveSpiderNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityCaveSpiderNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new CaveSpiderNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null) {
+ return super.isLeashed();
+ }
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault)) {
+ return super.isLeashed();
+ }
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void setSize(float f, float f1) {
+ if (npc == null) {
+ super.setSize(f, f1);
+ } else {
+ NMSImpl.setSize(this, f, f1, justCreated);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/ChickenController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/ChickenController.java
new file mode 100644
index 000000000..89c0b4c6c
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/ChickenController.java
@@ -0,0 +1,218 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftChicken;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.entity.Chicken;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityChicken;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class ChickenController extends MobEntityController {
+ public ChickenController() {
+ super(EntityChickenNPC.class);
+ }
+
+ @Override
+ public Chicken getBukkitEntity() {
+ return (Chicken) super.getBukkitEntity();
+ }
+
+ public static class ChickenNPC extends CraftChicken implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public ChickenNPC(EntityChickenNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+
+ public static class EntityChickenNPC extends EntityChicken implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityChickenNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityChickenNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ public void a(boolean flag) {
+ float oldw = width;
+ float oldl = length;
+ super.a(flag);
+ if (oldw != width || oldl != length) {
+ this.setPosition(locX - 0.01, locY, locZ - 0.01);
+ this.setPosition(locX + 0.01, locY, locZ + 0.01);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new ChickenNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void n() {
+ if (npc != null) {
+ this.bC = 100; // egg timer
+ }
+ super.n();
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/CowController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/CowController.java
new file mode 100644
index 000000000..19ef84ebf
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/CowController.java
@@ -0,0 +1,211 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftCow;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.entity.Cow;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityCow;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class CowController extends MobEntityController {
+ public CowController() {
+ super(EntityCowNPC.class);
+ }
+
+ @Override
+ public Cow getBukkitEntity() {
+ return (Cow) super.getBukkitEntity();
+ }
+
+ public static class CowNPC extends CraftCow implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public CowNPC(EntityCowNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+
+ public static class EntityCowNPC extends EntityCow implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityCowNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityCowNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+
+ }
+ }
+
+ @Override
+ public void a(boolean flag) {
+ float oldw = width;
+ float oldl = length;
+ super.a(flag);
+ if (oldw != width || oldl != length) {
+ this.setPosition(locX - 0.01, locY, locZ - 0.01);
+ this.setPosition(locX + 0.01, locY, locZ + 0.01);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new CowNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/CreeperController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/CreeperController.java
new file mode 100644
index 000000000..0cc53b1c3
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/CreeperController.java
@@ -0,0 +1,221 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftCreeper;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.entity.Creeper;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityCreeper;
+import net.minecraft.server.v1_12_R1.EntityLightning;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class CreeperController extends MobEntityController {
+ public CreeperController() {
+ super(EntityCreeperNPC.class);
+ }
+
+ @Override
+ public Creeper getBukkitEntity() {
+ return (Creeper) super.getBukkitEntity();
+ }
+
+ public static class CreeperNPC extends CraftCreeper implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public CreeperNPC(EntityCreeperNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+
+ public static class EntityCreeperNPC extends EntityCreeper implements NPCHolder {
+ private boolean allowPowered;
+ private final CitizensNPC npc;
+
+ public EntityCreeperNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityCreeperNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null)
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true)) {
+ super.f(x, y, z);
+ }
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new CreeperNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void onLightningStrike(EntityLightning entitylightning) {
+ if (npc == null || allowPowered) {
+ super.onLightningStrike(entitylightning);
+ }
+ }
+
+ public void setAllowPowered(boolean allowPowered) {
+ this.allowPowered = allowPowered;
+ }
+
+ @Override
+ public void setSize(float f, float f1) {
+ if (npc == null) {
+ super.setSize(f, f1);
+ } else {
+ NMSImpl.setSize(this, f, f1, justCreated);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/EnderDragonController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/EnderDragonController.java
new file mode 100644
index 000000000..b6c7e4049
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/EnderDragonController.java
@@ -0,0 +1,181 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEnderDragon;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.entity.EnderDragon;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.EntityEnderDragon;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class EnderDragonController extends MobEntityController {
+ public EnderDragonController() {
+ super(EntityEnderDragonNPC.class);
+ }
+
+ @Override
+ public EnderDragon getBukkitEntity() {
+ return (EnderDragon) super.getBukkitEntity();
+ }
+
+ public static class EnderDragonNPC extends CraftEnderDragon implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EnderDragonNPC(EntityEnderDragonNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+
+ public static class EntityEnderDragonNPC extends EntityEnderDragon implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityEnderDragonNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityEnderDragonNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null)
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new EnderDragonNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ private float getCorrectYaw(double tX, double tZ) {
+ if (locZ > tZ)
+ return (float) (-Math.toDegrees(Math.atan((locX - tX) / (locZ - tZ))));
+ if (locZ < tZ) {
+ return (float) (-Math.toDegrees(Math.atan((locX - tX) / (locZ - tZ)))) + 180.0F;
+ }
+ return yaw;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void n() {
+ if (npc != null) {
+ npc.update();
+ if (motX != 0 || motY != 0 || motZ != 0) {
+ motX *= 0.98;
+ motY *= 0.98;
+ motZ *= 0.98;
+ yaw = getCorrectYaw(locX + motX, locZ + motZ);
+ setPosition(locX + motX, locY + motY, locZ + motZ);
+ }
+ } else {
+ super.n();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/EndermanController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/EndermanController.java
new file mode 100644
index 000000000..8f3c4b9aa
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/EndermanController.java
@@ -0,0 +1,215 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEnderman;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.entity.Enderman;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityEnderman;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class EndermanController extends MobEntityController {
+ public EndermanController() {
+ super(EntityEndermanNPC.class);
+ }
+
+ @Override
+ public Enderman getBukkitEntity() {
+ return (Enderman) super.getBukkitEntity();
+ }
+
+ public static class EndermanNPC extends CraftEnderman implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EndermanNPC(EntityEndermanNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+
+ public static class EntityEndermanNPC extends EntityEnderman implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityEndermanNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityEndermanNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null)
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new EndermanNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ public boolean j(double d1, double d2, double d3) {
+ if (npc == null) {
+ return super.j(d1, d2, d3);
+ }
+ return false;
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void setSize(float f, float f1) {
+ if (npc == null) {
+ super.setSize(f, f1);
+ } else {
+ NMSImpl.setSize(this, f, f1, justCreated);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/EndermiteController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/EndermiteController.java
new file mode 100644
index 000000000..cd02922ae
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/EndermiteController.java
@@ -0,0 +1,206 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEndermite;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.entity.Endermite;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityEndermite;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class EndermiteController extends MobEntityController {
+ public EndermiteController() {
+ super(EntityEndermiteNPC.class);
+ }
+
+ @Override
+ public Endermite getBukkitEntity() {
+ return (Endermite) super.getBukkitEntity();
+ }
+
+ public static class EndermiteNPC extends CraftEndermite implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EndermiteNPC(EntityEndermiteNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+
+ public static class EntityEndermiteNPC extends EntityEndermite implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityEndermiteNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityEndermiteNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null)
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new EndermiteNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null)
+ npc.update();
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void setSize(float f, float f1) {
+ if (npc == null) {
+ super.setSize(f, f1);
+ } else {
+ NMSImpl.setSize(this, f, f1, justCreated);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/EntityHumanNPC.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/EntityHumanNPC.java
new file mode 100644
index 000000000..36d18b0f6
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/EntityHumanNPC.java
@@ -0,0 +1,502 @@
+package net.citizensnpcs.nms.v1_12_R1.entity;
+
+import java.io.IOException;
+import java.net.Socket;
+import java.util.List;
+import java.util.Map;
+
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+import org.bukkit.metadata.MetadataValue;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.util.Vector;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+import com.mojang.authlib.GameProfile;
+
+import net.citizensnpcs.Settings.Setting;
+import net.citizensnpcs.api.CitizensAPI;
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.MetadataStore;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.api.trait.trait.Inventory;
+import net.citizensnpcs.nms.v1_12_R1.network.EmptyNetHandler;
+import net.citizensnpcs.nms.v1_12_R1.network.EmptyNetworkManager;
+import net.citizensnpcs.nms.v1_12_R1.network.EmptySocket;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.nms.v1_12_R1.util.PlayerControllerJump;
+import net.citizensnpcs.nms.v1_12_R1.util.PlayerControllerLook;
+import net.citizensnpcs.nms.v1_12_R1.util.PlayerControllerMove;
+import net.citizensnpcs.nms.v1_12_R1.util.PlayerNavigation;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.npc.skin.SkinPacketTracker;
+import net.citizensnpcs.npc.skin.SkinnableEntity;
+import net.citizensnpcs.trait.Gravity;
+import net.citizensnpcs.util.NMS;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.AttributeInstance;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.ChatComponentText;
+import net.minecraft.server.v1_12_R1.DamageSource;
+import net.minecraft.server.v1_12_R1.Entity;
+import net.minecraft.server.v1_12_R1.EntityHuman;
+import net.minecraft.server.v1_12_R1.EntityPlayer;
+import net.minecraft.server.v1_12_R1.EnumGamemode;
+import net.minecraft.server.v1_12_R1.EnumItemSlot;
+import net.minecraft.server.v1_12_R1.EnumProtocolDirection;
+import net.minecraft.server.v1_12_R1.GenericAttributes;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.IChatBaseComponent;
+import net.minecraft.server.v1_12_R1.MathHelper;
+import net.minecraft.server.v1_12_R1.MinecraftServer;
+import net.minecraft.server.v1_12_R1.NavigationAbstract;
+import net.minecraft.server.v1_12_R1.NetworkManager;
+import net.minecraft.server.v1_12_R1.Packet;
+import net.minecraft.server.v1_12_R1.PacketPlayOutEntityEquipment;
+import net.minecraft.server.v1_12_R1.PacketPlayOutEntityHeadRotation;
+import net.minecraft.server.v1_12_R1.PathType;
+import net.minecraft.server.v1_12_R1.PlayerInteractManager;
+import net.minecraft.server.v1_12_R1.WorldServer;
+
+public class EntityHumanNPC extends EntityPlayer implements NPCHolder, SkinnableEntity {
+ private final Map bz = Maps.newEnumMap(PathType.class);
+ private PlayerControllerJump controllerJump;
+ private PlayerControllerLook controllerLook;
+ private PlayerControllerMove controllerMove;
+ private int jumpTicks = 0;
+ private PlayerNavigation navigation;
+ private final CitizensNPC npc;
+ private final Location packetLocationCache = new Location(null, 0, 0, 0);
+ private final SkinPacketTracker skinTracker;
+ private int updateCounter = 0;
+
+ public EntityHumanNPC(MinecraftServer minecraftServer, WorldServer world, GameProfile gameProfile,
+ PlayerInteractManager playerInteractManager, NPC npc) {
+ super(minecraftServer, world, gameProfile, playerInteractManager);
+
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ skinTracker = new SkinPacketTracker(this);
+ playerInteractManager.setGameMode(EnumGamemode.SURVIVAL);
+ initialise(minecraftServer);
+ } else {
+ skinTracker = null;
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ public float a(PathType pathtype) {
+ return this.bz.containsKey(pathtype) ? this.bz.get(pathtype).floatValue() : pathtype.a();
+ }
+
+ public void a(PathType pathtype, float f) {
+ this.bz.put(pathtype, Float.valueOf(f));
+ }
+
+ @Override
+ public void B_() {
+ super.B_();
+ if (npc == null)
+ return;
+ if (updateCounter + 1 > Setting.PACKET_UPDATE_DELAY.asInt()) {
+ updateEffects = true;
+ }
+ livingEntityBaseTick();
+
+ boolean navigating = npc.getNavigator().isNavigating();
+ updatePackets(navigating);
+ if (!navigating && getBukkitEntity() != null && npc.getTrait(Gravity.class).hasGravity()
+ && Util.isLoaded(getBukkitEntity().getLocation(LOADED_LOCATION))) {
+ g(0, 0);
+ }
+ if (Math.abs(motX) < EPSILON && Math.abs(motY) < EPSILON && Math.abs(motZ) < EPSILON) {
+ motX = motY = motZ = 0;
+ }
+ if (navigating) {
+ if (!NMSImpl.isNavigationFinished(navigation)) {
+ NMSImpl.updateNavigation(navigation);
+ }
+ moveOnCurrentHeading();
+ }
+ NMSImpl.updateAI(this);
+
+ if (noDamageTicks > 0) {
+ --noDamageTicks;
+ }
+
+ npc.update();
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean damageEntity(DamageSource damagesource, float f) {
+ // knock back velocity is cancelled and sent to client for handling when
+ // the entity is a player. there is no client so make this happen
+ // manually.
+ boolean damaged = super.damageEntity(damagesource, f);
+ if (damaged && velocityChanged) {
+ velocityChanged = false;
+ Bukkit.getScheduler().runTask(CitizensAPI.getPlugin(), new Runnable() {
+ @Override
+ public void run() {
+ EntityHumanNPC.this.velocityChanged = true;
+ }
+ });
+ }
+ return damaged;
+ }
+
+ @Override
+ public void die(DamageSource damagesource) {
+ // players that die are not normally removed from the world. when the
+ // NPC dies, we are done with the instance and it should be removed.
+ if (dead) {
+ return;
+ }
+ super.die(damagesource);
+ Bukkit.getScheduler().runTaskLater(CitizensAPI.getPlugin(), new Runnable() {
+ @Override
+ public void run() {
+ world.removeEntity(EntityHumanNPC.this);
+ }
+ }, 35); // give enough time for death and smoke animation
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true)) {
+ super.f(x, y, z);
+ }
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftPlayer getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new PlayerNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ public PlayerControllerJump getControllerJump() {
+ return controllerJump;
+ }
+
+ public PlayerControllerMove getControllerMove() {
+ return controllerMove;
+ }
+
+ public NavigationAbstract getNavigation() {
+ return navigation;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public IChatBaseComponent getPlayerListName() {
+ if (Setting.REMOVE_PLAYERS_FROM_PLAYER_LIST.asBoolean()) {
+ return new ChatComponentText("");
+ }
+ return super.getPlayerListName();
+ }
+
+ @Override
+ public String getSkinName() {
+ MetadataStore meta = npc.data();
+
+ String skinName = meta.get(NPC.PLAYER_SKIN_UUID_METADATA);
+ if (skinName == null) {
+ skinName = ChatColor.stripColor(getName());
+ }
+ return skinName.toLowerCase();
+ }
+
+ @Override
+ public SkinPacketTracker getSkinTracker() {
+ return skinTracker;
+ }
+
+ private void initialise(MinecraftServer minecraftServer) {
+ Socket socket = new EmptySocket();
+ NetworkManager conn = null;
+ try {
+ conn = new EmptyNetworkManager(EnumProtocolDirection.CLIENTBOUND);
+ playerConnection = new EmptyNetHandler(minecraftServer, conn, this);
+ conn.setPacketListener(playerConnection);
+ socket.close();
+ } catch (IOException e) {
+ // swallow
+ }
+
+ AttributeInstance range = getAttributeInstance(GenericAttributes.FOLLOW_RANGE);
+ if (range == null) {
+ range = getAttributeMap().b(GenericAttributes.FOLLOW_RANGE);
+ }
+ range.setValue(Setting.DEFAULT_PATHFINDING_RANGE.asDouble());
+
+ controllerJump = new PlayerControllerJump(this);
+ controllerLook = new PlayerControllerLook(this);
+ controllerMove = new PlayerControllerMove(this);
+ navigation = new PlayerNavigation(this, world);
+ NMS.setStepHeight(getBukkitEntity(), 1); // the default (0) breaks step climbing
+
+ setSkinFlags((byte) 0xFF);
+ }
+
+ @Override
+ public boolean isCollidable() {
+ return npc == null ? super.isCollidable() : npc.data().get(NPC.COLLIDABLE_METADATA, true);
+ }
+
+ public boolean isNavigating() {
+ return npc.getNavigator().isNavigating();
+ }
+
+ public void livingEntityBaseTick() {
+ cA();
+ this.aC = this.aD;
+ this.aJ = this.aK;
+ if (this.hurtTicks > 0) {
+ this.hurtTicks -= 1;
+ }
+ tickPotionEffects();
+ this.aZ = this.aY;
+ this.aO = this.aN;
+ this.aQ = this.aP;
+ this.lastYaw = this.yaw;
+ this.lastPitch = this.pitch;
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+
+ private void moveOnCurrentHeading() {
+ if (bd) {
+ if (onGround && jumpTicks == 0) {
+ cs();
+ jumpTicks = 10;
+ }
+ } else {
+ jumpTicks = 0;
+ }
+ be *= 0.98F;
+ bg *= 0.98F;
+ bh *= 0.9F;
+ a(be, bf, bg); // movement method
+ NMS.setHeadYaw(getBukkitEntity(), yaw);
+ if (jumpTicks > 0) {
+ jumpTicks--;
+ }
+ }
+
+ public void setMoveDestination(double x, double y, double z, double speed) {
+ controllerMove.a(x, y, z, speed);
+ }
+
+ public void setShouldJump() {
+ controllerJump.a();
+ }
+
+ @Override
+ public void setSkinFlags(byte flags) {
+ // set skin flag byte
+ getDataWatcher().set(EntityHuman.br, flags);
+ }
+
+ @Override
+ public void setSkinName(String name) {
+ setSkinName(name, false);
+ }
+
+ @Override
+ public void setSkinName(String name, boolean forceUpdate) {
+ Preconditions.checkNotNull(name);
+
+ npc.data().setPersistent(NPC.PLAYER_SKIN_UUID_METADATA, name.toLowerCase());
+ skinTracker.notifySkinChange(forceUpdate);
+ }
+
+ public void setTargetLook(Entity target, float yawOffset, float renderOffset) {
+ controllerLook.a(target, yawOffset, renderOffset);
+ }
+
+ public void setTargetLook(Location target) {
+ controllerLook.a(target.getX(), target.getY(), target.getZ(), 10, 40);
+ }
+
+ public void updateAI() {
+ controllerMove.a();
+ controllerLook.a();
+ controllerJump.b();
+ }
+
+ private void updatePackets(boolean navigating) {
+ if (updateCounter++ <= Setting.PACKET_UPDATE_DELAY.asInt())
+ return;
+
+ updateCounter = 0;
+ Location current = getBukkitEntity().getLocation(packetLocationCache);
+ Packet>[] packets = new Packet[navigating ? EnumItemSlot.values().length : EnumItemSlot.values().length + 1];
+ if (!navigating) {
+ packets[5] = new PacketPlayOutEntityHeadRotation(this,
+ (byte) MathHelper.d(NMSImpl.getHeadYaw(this) * 256.0F / 360.0F));
+ }
+ int i = 0;
+ for (EnumItemSlot slot : EnumItemSlot.values()) {
+ packets[i++] = new PacketPlayOutEntityEquipment(getId(), slot, getEquipment(slot));
+ }
+ NMSImpl.sendPacketsNearby(getBukkitEntity(), current, packets);
+ }
+
+ public void updatePathfindingRange(float pathfindingRange) {
+ this.navigation.setRange(pathfindingRange);
+ }
+
+ public static class PlayerNPC extends CraftPlayer implements NPCHolder, SkinnableEntity {
+ private final CraftServer cserver;
+ private final CitizensNPC npc;
+
+ private PlayerNPC(EntityHumanNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ this.cserver = (CraftServer) Bukkit.getServer();
+ npc.getTrait(Inventory.class);
+ }
+
+ @Override
+ public Player getBukkitEntity() {
+ return this;
+ }
+
+ @Override
+ public EntityHumanNPC getHandle() {
+ return (EntityHumanNPC) this.entity;
+ }
+
+ @Override
+ public List getMetadata(String metadataKey) {
+ return cserver.getEntityMetadata().getMetadata(this, metadataKey);
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public String getSkinName() {
+ return ((SkinnableEntity) this.entity).getSkinName();
+ }
+
+ @Override
+ public SkinPacketTracker getSkinTracker() {
+ return ((SkinnableEntity) this.entity).getSkinTracker();
+ }
+
+ @Override
+ public boolean hasMetadata(String metadataKey) {
+ return cserver.getEntityMetadata().hasMetadata(this, metadataKey);
+ }
+
+ @Override
+ public void removeMetadata(String metadataKey, Plugin owningPlugin) {
+ cserver.getEntityMetadata().removeMetadata(this, metadataKey, owningPlugin);
+ }
+
+ @Override
+ public void setMetadata(String metadataKey, MetadataValue newMetadataValue) {
+ cserver.getEntityMetadata().setMetadata(this, metadataKey, newMetadataValue);
+ }
+
+ @Override
+ public void setSkinFlags(byte flags) {
+ ((SkinnableEntity) this.entity).setSkinFlags(flags);
+ }
+
+ @Override
+ public void setSkinName(String name) {
+ ((SkinnableEntity) this.entity).setSkinName(name);
+ }
+
+ @Override
+ public void setSkinName(String skinName, boolean forceUpdate) {
+ ((SkinnableEntity) this.entity).setSkinName(skinName, forceUpdate);
+ }
+ }
+
+ private static final float EPSILON = 0.005F;
+ private static final Location LOADED_LOCATION = new Location(null, 0, 0, 0);
+}
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/EvokerController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/EvokerController.java
new file mode 100644
index 000000000..e788e1373
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/EvokerController.java
@@ -0,0 +1,199 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEvoker;
+import org.bukkit.entity.Evoker;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityEvoker;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class EvokerController extends MobEntityController {
+ public EvokerController() {
+ super(EntityEvokerNPC.class);
+ }
+
+ @Override
+ public Evoker getBukkitEntity() {
+ return (Evoker) super.getBukkitEntity();
+ }
+
+ public static class EntityEvokerNPC extends EntityEvoker implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityEvokerNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityEvokerNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new EvokerNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+ }
+
+ public static class EvokerNPC extends CraftEvoker implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EvokerNPC(EntityEvokerNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/GhastController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/GhastController.java
new file mode 100644
index 000000000..589165fa7
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/GhastController.java
@@ -0,0 +1,171 @@
+package net.citizensnpcs.nms.v1_12_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftGhast;
+import org.bukkit.entity.Ghast;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.DamageSource;
+import net.minecraft.server.v1_12_R1.EntityGhast;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class GhastController extends MobEntityController {
+ public GhastController() {
+ super(EntityGhastNPC.class);
+ }
+
+ @Override
+ public Ghast getBukkitEntity() {
+ return (Ghast) super.getBukkitEntity();
+ }
+
+ public static class EntityGhastNPC extends EntityGhast implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityGhastNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityGhastNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ public boolean cA() {
+ return npc != null;
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new GhastNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ if (npc != null) {
+ npc.update();
+ }
+ super.M();
+ }
+ }
+
+ public static class GhastNPC extends CraftGhast implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public GhastNPC(EntityGhastNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/GiantController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/GiantController.java
new file mode 100644
index 000000000..b18f12a6e
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/GiantController.java
@@ -0,0 +1,208 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftGiant;
+import org.bukkit.entity.Giant;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.DamageSource;
+import net.minecraft.server.v1_12_R1.EntityGiantZombie;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class GiantController extends MobEntityController {
+ public GiantController() {
+ super(EntityGiantNPC.class);
+ }
+
+ @Override
+ public Giant getBukkitEntity() {
+ return (Giant) super.getBukkitEntity();
+ }
+
+ public static class EntityGiantNPC extends EntityGiantZombie implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityGiantNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityGiantNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null)
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new GiantNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void setSize(float f, float f1) {
+ if (npc == null) {
+ super.setSize(f, f1);
+ } else {
+ NMSImpl.setSize(this, f, f1, justCreated);
+ }
+ }
+ }
+
+ public static class GiantNPC extends CraftGiant implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public GiantNPC(EntityGiantNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/GuardianController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/GuardianController.java
new file mode 100644
index 000000000..92996e5c7
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/GuardianController.java
@@ -0,0 +1,210 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftGuardian;
+import org.bukkit.entity.Guardian;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityGuardian;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class GuardianController extends MobEntityController {
+ public GuardianController() {
+ super(EntityGuardianNPC.class);
+ }
+
+ @Override
+ public Guardian getBukkitEntity() {
+ return (Guardian) super.getBukkitEntity();
+ }
+
+ public static class EntityGuardianNPC extends EntityGuardian implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityGuardianNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityGuardianNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new GuardianNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void n() {
+ if (npc == null) {
+ super.n();
+ } else {
+ NMSImpl.updateAI(this);
+ npc.update();
+ }
+ }
+
+ @Override
+ public void setSize(float f, float f1) {
+ if (npc == null) {
+ super.setSize(f, f1);
+ } else {
+ NMSImpl.setSize(this, f, f1, justCreated);
+ }
+ }
+ }
+
+ public static class GuardianNPC extends CraftGuardian implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public GuardianNPC(EntityGuardianNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/GuardianElderController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/GuardianElderController.java
new file mode 100644
index 000000000..af7474e06
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/GuardianElderController.java
@@ -0,0 +1,210 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftElderGuardian;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.entity.ElderGuardian;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityGuardianElder;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class GuardianElderController extends MobEntityController {
+ public GuardianElderController() {
+ super(EntityGuardianElderNPC.class);
+ }
+
+ @Override
+ public ElderGuardian getBukkitEntity() {
+ return (ElderGuardian) super.getBukkitEntity();
+ }
+
+ public static class EntityGuardianElderNPC extends EntityGuardianElder implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityGuardianElderNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityGuardianElderNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new GuardianElderNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void n() {
+ if (npc == null) {
+ super.n();
+ } else {
+ NMSImpl.updateAI(this);
+ npc.update();
+ }
+ }
+
+ @Override
+ public void setSize(float f, float f1) {
+ if (npc == null) {
+ super.setSize(f, f1);
+ } else {
+ NMSImpl.setSize(this, f, f1, justCreated);
+ }
+ }
+ }
+
+ public static class GuardianElderNPC extends CraftElderGuardian implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public GuardianElderNPC(EntityGuardianElderNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/HorseController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/HorseController.java
new file mode 100644
index 000000000..b2f4e4df7
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/HorseController.java
@@ -0,0 +1,221 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftHorse;
+import org.bukkit.entity.Horse;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.trait.HorseModifiers;
+import net.citizensnpcs.util.NMS;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityHorse;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class HorseController extends MobEntityController {
+ public HorseController() {
+ super(EntityHorseNPC.class);
+ }
+
+ @Override
+ public Horse getBukkitEntity() {
+ return (Horse) super.getBukkitEntity();
+ }
+
+ @Override
+ public void spawn(Location at, NPC npc) {
+ npc.getTrait(HorseModifiers.class);
+ super.spawn(at, npc);
+ }
+
+ public static class EntityHorseNPC extends EntityHorse implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityHorseNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityHorseNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ ((Horse) getBukkitEntity()).setDomestication(((Horse) getBukkitEntity()).getMaxDomestication());
+ }
+ }
+
+ @Override
+ public void a(boolean flag) {
+ float oldw = width;
+ float oldl = length;
+ super.a(flag);
+ if (oldw != width || oldl != length) {
+ this.setPosition(locX - 0.01, locY, locZ - 0.01);
+ this.setPosition(locX + 0.01, locY, locZ + 0.01);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new HorseNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null) {
+ NMS.setStepHeight(getBukkitEntity(), 1);
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+ }
+
+ public static class HorseNPC extends CraftHorse implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public HorseNPC(EntityHorseNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/HorseDonkeyController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/HorseDonkeyController.java
new file mode 100644
index 000000000..77f4b6f0f
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/HorseDonkeyController.java
@@ -0,0 +1,221 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftDonkey;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.entity.Donkey;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.trait.HorseModifiers;
+import net.citizensnpcs.util.NMS;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityHorseDonkey;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class HorseDonkeyController extends MobEntityController {
+ public HorseDonkeyController() {
+ super(EntityHorseDonkeyNPC.class);
+ }
+
+ @Override
+ public Donkey getBukkitEntity() {
+ return (Donkey) super.getBukkitEntity();
+ }
+
+ @Override
+ public void spawn(Location at, NPC npc) {
+ npc.addTrait(HorseModifiers.class);
+ super.spawn(at, npc);
+ }
+
+ public static class EntityHorseDonkeyNPC extends EntityHorseDonkey implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityHorseDonkeyNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityHorseDonkeyNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ ((Donkey) getBukkitEntity()).setDomestication(((Donkey) getBukkitEntity()).getMaxDomestication());
+ }
+ }
+
+ @Override
+ public void a(boolean flag) {
+ float oldw = width;
+ float oldl = length;
+ super.a(flag);
+ if (oldw != width || oldl != length) {
+ this.setPosition(locX - 0.01, locY, locZ - 0.01);
+ this.setPosition(locX + 0.01, locY, locZ + 0.01);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new HorseDonkeyNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null) {
+ NMS.setStepHeight(getBukkitEntity(), 1);
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+ }
+
+ public static class HorseDonkeyNPC extends CraftDonkey implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public HorseDonkeyNPC(EntityHorseDonkeyNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/HorseMuleController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/HorseMuleController.java
new file mode 100644
index 000000000..5390ffe45
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/HorseMuleController.java
@@ -0,0 +1,221 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftMule;
+import org.bukkit.entity.Mule;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.trait.HorseModifiers;
+import net.citizensnpcs.util.NMS;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityHorseMule;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class HorseMuleController extends MobEntityController {
+ public HorseMuleController() {
+ super(EntityHorseMuleNPC.class);
+ }
+
+ @Override
+ public Mule getBukkitEntity() {
+ return (Mule) super.getBukkitEntity();
+ }
+
+ @Override
+ public void spawn(Location at, NPC npc) {
+ npc.getTrait(HorseModifiers.class);
+ super.spawn(at, npc);
+ }
+
+ public static class EntityHorseMuleNPC extends EntityHorseMule implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityHorseMuleNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityHorseMuleNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ ((Mule) getBukkitEntity()).setDomestication(((Mule) getBukkitEntity()).getMaxDomestication());
+ }
+ }
+
+ @Override
+ public void a(boolean flag) {
+ float oldw = width;
+ float oldl = length;
+ super.a(flag);
+ if (oldw != width || oldl != length) {
+ this.setPosition(locX - 0.01, locY, locZ - 0.01);
+ this.setPosition(locX + 0.01, locY, locZ + 0.01);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new HorseMuleNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null) {
+ NMS.setStepHeight(getBukkitEntity(), 1);
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+ }
+
+ public static class HorseMuleNPC extends CraftMule implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public HorseMuleNPC(EntityHorseMuleNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/HorseSkeletonController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/HorseSkeletonController.java
new file mode 100644
index 000000000..2b96e369c
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/HorseSkeletonController.java
@@ -0,0 +1,222 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftSkeletonHorse;
+import org.bukkit.entity.SkeletonHorse;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.trait.HorseModifiers;
+import net.citizensnpcs.util.NMS;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityHorseSkeleton;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class HorseSkeletonController extends MobEntityController {
+ public HorseSkeletonController() {
+ super(EntityHorseSkeletonNPC.class);
+ }
+
+ @Override
+ public SkeletonHorse getBukkitEntity() {
+ return (SkeletonHorse) super.getBukkitEntity();
+ }
+
+ @Override
+ public void spawn(Location at, NPC npc) {
+ npc.getTrait(HorseModifiers.class);
+ super.spawn(at, npc);
+ }
+
+ public static class EntityHorseSkeletonNPC extends EntityHorseSkeleton implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityHorseSkeletonNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityHorseSkeletonNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ ((SkeletonHorse) getBukkitEntity())
+ .setDomestication(((SkeletonHorse) getBukkitEntity()).getMaxDomestication());
+ }
+ }
+
+ @Override
+ public void a(boolean flag) {
+ float oldw = width;
+ float oldl = length;
+ super.a(flag);
+ if (oldw != width || oldl != length) {
+ this.setPosition(locX - 0.01, locY, locZ - 0.01);
+ this.setPosition(locX + 0.01, locY, locZ + 0.01);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new HorseSkeletonNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null) {
+ NMS.setStepHeight(getBukkitEntity(), 1);
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+ }
+
+ public static class HorseSkeletonNPC extends CraftSkeletonHorse implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public HorseSkeletonNPC(EntityHorseSkeletonNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/HorseZombieController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/HorseZombieController.java
new file mode 100644
index 000000000..8be467e7e
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/HorseZombieController.java
@@ -0,0 +1,222 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftZombieHorse;
+import org.bukkit.entity.ZombieHorse;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.trait.HorseModifiers;
+import net.citizensnpcs.util.NMS;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityHorseZombie;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class HorseZombieController extends MobEntityController {
+ public HorseZombieController() {
+ super(EntityHorseZombieNPC.class);
+ }
+
+ @Override
+ public ZombieHorse getBukkitEntity() {
+ return (ZombieHorse) super.getBukkitEntity();
+ }
+
+ @Override
+ public void spawn(Location at, NPC npc) {
+ npc.getTrait(HorseModifiers.class);
+ super.spawn(at, npc);
+ }
+
+ public static class EntityHorseZombieNPC extends EntityHorseZombie implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityHorseZombieNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityHorseZombieNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ ((ZombieHorse) getBukkitEntity())
+ .setDomestication(((ZombieHorse) getBukkitEntity()).getMaxDomestication());
+ }
+ }
+
+ @Override
+ public void a(boolean flag) {
+ float oldw = width;
+ float oldl = length;
+ super.a(flag);
+ if (oldw != width || oldl != length) {
+ this.setPosition(locX - 0.01, locY, locZ - 0.01);
+ this.setPosition(locX + 0.01, locY, locZ + 0.01);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new HorseZombieNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null) {
+ NMS.setStepHeight(getBukkitEntity(), 1);
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+ }
+
+ public static class HorseZombieNPC extends CraftZombieHorse implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public HorseZombieNPC(EntityHorseZombieNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/HumanController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/HumanController.java
new file mode 100644
index 000000000..86986a5b4
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/HumanController.java
@@ -0,0 +1,142 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import java.util.UUID;
+import java.util.regex.Pattern;
+
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.v1_12_R1.CraftWorld;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.Player;
+import org.bukkit.scoreboard.Scoreboard;
+import org.bukkit.scoreboard.Team;
+
+import com.mojang.authlib.GameProfile;
+
+import net.citizensnpcs.Settings.Setting;
+import net.citizensnpcs.api.CitizensAPI;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.api.util.Colorizer;
+import net.citizensnpcs.npc.AbstractEntityController;
+import net.citizensnpcs.npc.skin.Skin;
+import net.citizensnpcs.npc.skin.SkinnableEntity;
+import net.citizensnpcs.util.NMS;
+import net.minecraft.server.v1_12_R1.PlayerInteractManager;
+import net.minecraft.server.v1_12_R1.WorldServer;
+
+public class HumanController extends AbstractEntityController {
+ public HumanController() {
+ super();
+ }
+
+ @Override
+ protected Entity createEntity(final Location at, final NPC npc) {
+ final WorldServer nmsWorld = ((CraftWorld) at.getWorld()).getHandle();
+ String coloredName = Colorizer.parseColors(npc.getFullName());
+
+ String name = coloredName, prefix = null, suffix = null;
+ if (coloredName.length() > 16) {
+ prefix = coloredName.substring(0, 16);
+ if (coloredName.length() > 30) {
+ int len = 30;
+ name = coloredName.substring(16, 30);
+ if (NON_ALPHABET_MATCHER.matcher(name).matches()) {
+ if (coloredName.length() >= 32) {
+ len = 32;
+ name = coloredName.substring(16, 32);
+ } else if (coloredName.length() == 31) {
+ len = 31;
+ name = coloredName.substring(16, 31);
+ }
+ } else {
+ name = ChatColor.RESET + name;
+ }
+ suffix = coloredName.substring(len);
+ } else {
+ name = coloredName.substring(16);
+ if (!NON_ALPHABET_MATCHER.matcher(name).matches()) {
+ name = ChatColor.RESET + name;
+ }
+ if (name.length() > 16) {
+ suffix = name.substring(16);
+ name = name.substring(0, 16);
+ }
+ }
+ coloredName = coloredName.substring(0, 16);
+ }
+
+ final String prefixCapture = prefix, suffixCapture = suffix;
+
+ UUID uuid = npc.getUniqueId();
+ if (uuid.version() == 4) { // clear version
+ long msb = uuid.getMostSignificantBits();
+ msb &= ~0x0000000000004000L;
+ msb |= 0x0000000000002000L;
+ uuid = new UUID(msb, uuid.getLeastSignificantBits());
+ }
+
+ final GameProfile profile = new GameProfile(uuid, name);
+
+ final EntityHumanNPC handle = new EntityHumanNPC(nmsWorld.getServer().getServer(), nmsWorld, profile,
+ new PlayerInteractManager(nmsWorld), npc);
+
+ Skin skin = handle.getSkinTracker().getSkin();
+ if (skin != null) {
+ skin.apply(handle);
+ }
+
+ Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), new Runnable() {
+ @Override
+ public void run() {
+ if (getBukkitEntity() == null || !getBukkitEntity().isValid())
+ return;
+ boolean removeFromPlayerList = npc.data().get("removefromplayerlist",
+ Setting.REMOVE_PLAYERS_FROM_PLAYER_LIST.asBoolean());
+ NMS.addOrRemoveFromPlayerList(getBukkitEntity(),
+ npc.data().get("removefromplayerlist", removeFromPlayerList));
+
+ if (Setting.USE_SCOREBOARD_TEAMS.asBoolean()) {
+ Scoreboard scoreboard = Bukkit.getScoreboardManager().getMainScoreboard();
+ String teamName = profile.getId().toString().substring(0, 16);
+
+ Team team = scoreboard.getTeam(teamName);
+ if (team == null) {
+ team = scoreboard.registerNewTeam(teamName);
+ if (prefixCapture != null) {
+ team.setPrefix(prefixCapture);
+ }
+ if (suffixCapture != null) {
+ team.setSuffix(suffixCapture);
+ }
+ }
+ team.addPlayer(handle.getBukkitEntity());
+
+ handle.getNPC().data().set(NPC.SCOREBOARD_FAKE_TEAM_NAME_METADATA, teamName);
+ }
+ }
+ }, 20);
+
+ handle.getBukkitEntity().setSleepingIgnored(true);
+
+ return handle.getBukkitEntity();
+ }
+
+ @Override
+ public Player getBukkitEntity() {
+ return (Player) super.getBukkitEntity();
+ }
+
+ @Override
+ public void remove() {
+ Player entity = getBukkitEntity();
+ if (entity != null) {
+ NMS.removeFromWorld(entity);
+ SkinnableEntity npc = entity instanceof SkinnableEntity ? (SkinnableEntity) entity : null;
+ npc.getSkinTracker().onRemoveNPC();
+ }
+ super.remove();
+ }
+
+ private static Pattern NON_ALPHABET_MATCHER = Pattern.compile(".*[^A-Za-z0-9_].*");
+}
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/IllusionerController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/IllusionerController.java
new file mode 100644
index 000000000..198196bd5
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/IllusionerController.java
@@ -0,0 +1,199 @@
+package net.citizensnpcs.nms.v1_12_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftIllusioner;
+import org.bukkit.entity.Illusioner;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.DamageSource;
+import net.minecraft.server.v1_12_R1.EntityIllagerIllusioner;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class IllusionerController extends MobEntityController {
+ public IllusionerController() {
+ super(EntityIllusionerNPC.class);
+ }
+
+ @Override
+ public Illusioner getBukkitEntity() {
+ return (Illusioner) super.getBukkitEntity();
+ }
+
+ public static class EntityIllusionerNPC extends EntityIllagerIllusioner implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityIllusionerNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityIllusionerNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new IllusionerNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+ }
+
+ public static class IllusionerNPC extends CraftIllusioner implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public IllusionerNPC(EntityIllusionerNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/IronGolemController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/IronGolemController.java
new file mode 100644
index 000000000..70dfbad80
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/IronGolemController.java
@@ -0,0 +1,207 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftIronGolem;
+import org.bukkit.entity.IronGolem;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityIronGolem;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class IronGolemController extends MobEntityController {
+ public IronGolemController() {
+ super(EntityIronGolemNPC.class);
+ }
+
+ @Override
+ public IronGolem getBukkitEntity() {
+ return (IronGolem) super.getBukkitEntity();
+ }
+
+ public static class EntityIronGolemNPC extends EntityIronGolem implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityIronGolemNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityIronGolemNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null)
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new IronGolemNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void setSize(float f, float f1) {
+ if (npc == null) {
+ super.setSize(f, f1);
+ } else {
+ NMSImpl.setSize(this, f, f1, justCreated);
+ }
+ }
+ }
+
+ public static class IronGolemNPC extends CraftIronGolem implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public IronGolemNPC(EntityIronGolemNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/LlamaController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/LlamaController.java
new file mode 100644
index 000000000..1013e8cd5
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/LlamaController.java
@@ -0,0 +1,222 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftLlama;
+import org.bukkit.entity.Llama;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.trait.HorseModifiers;
+import net.citizensnpcs.util.NMS;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityLlama;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class LlamaController extends MobEntityController {
+ public LlamaController() {
+ super(EntityLlamaNPC.class);
+ }
+
+ @Override
+ public Llama getBukkitEntity() {
+ return (Llama) super.getBukkitEntity();
+ }
+
+ @Override
+ public void spawn(Location at, NPC npc) {
+ npc.getTrait(HorseModifiers.class);
+ super.spawn(at, npc);
+ }
+
+ public static class EntityLlamaNPC extends EntityLlama implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityLlamaNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityLlamaNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ ((Llama) getBukkitEntity()).setDomestication(((Llama) getBukkitEntity()).getMaxDomestication());
+ }
+ }
+
+ @Override
+ public void a(boolean flag) {
+ float oldw = width;
+ float oldl = length;
+ super.a(flag);
+ if (oldw != width || oldl != length) {
+ this.setPosition(locX - 0.01, locY, locZ - 0.01);
+ this.setPosition(locX + 0.01, locY, locZ + 0.01);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new LlamaNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ if (npc == null) {
+ super.M();
+ } else {
+ NMS.setStepHeight(getBukkitEntity(), 1);
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+ }
+
+ public static class LlamaNPC extends CraftLlama implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public LlamaNPC(EntityLlamaNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/MagmaCubeController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/MagmaCubeController.java
new file mode 100644
index 000000000..fae8fa950
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/MagmaCubeController.java
@@ -0,0 +1,210 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftMagmaCube;
+import org.bukkit.entity.MagmaCube;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.nms.v1_12_R1.util.PlayerControllerMove;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityMagmaCube;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class MagmaCubeController extends MobEntityController {
+ public MagmaCubeController() {
+ super(EntityMagmaCubeNPC.class);
+ }
+
+ @Override
+ public MagmaCube getBukkitEntity() {
+ return (MagmaCube) super.getBukkitEntity();
+ }
+
+ public static class EntityMagmaCubeNPC extends EntityMagmaCube implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityMagmaCubeNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityMagmaCubeNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ setSize(3, true);
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ this.moveController = new PlayerControllerMove(this);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ public void B_() {
+ super.B_();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null)
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new MagmaCubeNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void setSize(float f, float f1) {
+ if (npc == null) {
+ super.setSize(f, f1);
+ } else {
+ NMSImpl.setSize(this, f, f1, justCreated);
+ }
+ }
+ }
+
+ public static class MagmaCubeNPC extends CraftMagmaCube implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public MagmaCubeNPC(EntityMagmaCubeNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/MobEntityController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/MobEntityController.java
new file mode 100644
index 000000000..c3b923edb
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/MobEntityController.java
@@ -0,0 +1,61 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import java.lang.reflect.Constructor;
+import java.util.Map;
+
+import org.bukkit.Location;
+import org.bukkit.block.BlockFace;
+import org.bukkit.craftbukkit.v1_12_R1.CraftWorld;
+import org.bukkit.entity.Entity;
+
+import com.google.common.collect.Maps;
+
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.npc.AbstractEntityController;
+import net.minecraft.server.v1_12_R1.World;
+
+public abstract class MobEntityController extends AbstractEntityController {
+ private final Constructor> constructor;
+
+ protected MobEntityController(Class> clazz) {
+ super(clazz);
+ this.constructor = getConstructor(clazz);
+ }
+
+ @Override
+ protected Entity createEntity(Location at, NPC npc) {
+ net.minecraft.server.v1_12_R1.Entity entity = createEntityFromClass(((CraftWorld) at.getWorld()).getHandle(),
+ npc);
+ entity.setPositionRotation(at.getX(), at.getY(), at.getZ(), at.getYaw(), at.getPitch());
+
+ // entity.onGround isn't updated right away - we approximate here so
+ // that things like pathfinding still work *immediately* after spawn.
+ org.bukkit.Material beneath = at.getBlock().getRelative(BlockFace.DOWN).getType();
+ if (beneath.isBlock()) {
+ entity.onGround = true;
+ }
+ return entity.getBukkitEntity();
+ }
+
+ private net.minecraft.server.v1_12_R1.Entity createEntityFromClass(Object... args) {
+ try {
+ return (net.minecraft.server.v1_12_R1.Entity) constructor.newInstance(args);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ return null;
+ }
+ }
+
+ private static Constructor> getConstructor(Class> clazz) {
+ Constructor> constructor = CONSTRUCTOR_CACHE.get(clazz);
+ if (constructor != null)
+ return constructor;
+ try {
+ return clazz.getConstructor(World.class, NPC.class);
+ } catch (Exception ex) {
+ throw new IllegalStateException("unable to find an entity constructor");
+ }
+ }
+
+ private static final Map, Constructor>> CONSTRUCTOR_CACHE = Maps.newHashMap();
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/MushroomCowController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/MushroomCowController.java
new file mode 100644
index 000000000..c455b780c
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/MushroomCowController.java
@@ -0,0 +1,209 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftMushroomCow;
+import org.bukkit.entity.MushroomCow;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityMushroomCow;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class MushroomCowController extends MobEntityController {
+
+ public MushroomCowController() {
+ super(EntityMushroomCowNPC.class);
+ }
+
+ @Override
+ public MushroomCow getBukkitEntity() {
+ return (MushroomCow) super.getBukkitEntity();
+ }
+
+ public static class EntityMushroomCowNPC extends EntityMushroomCow implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityMushroomCowNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityMushroomCowNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ public void a(boolean flag) {
+ float oldw = width;
+ float oldl = length;
+ super.a(flag);
+ if (oldw != width || oldl != length) {
+ this.setPosition(locX - 0.01, locY, locZ - 0.01);
+ this.setPosition(locX + 0.01, locY, locZ + 0.01);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null)
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new MushroomCowNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null)
+ npc.update();
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+ }
+
+ public static class MushroomCowNPC extends CraftMushroomCow implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public MushroomCowNPC(EntityMushroomCowNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/OcelotController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/OcelotController.java
new file mode 100644
index 000000000..86b93c2de
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/OcelotController.java
@@ -0,0 +1,208 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftOcelot;
+import org.bukkit.entity.Ocelot;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityOcelot;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class OcelotController extends MobEntityController {
+ public OcelotController() {
+ super(EntityOcelotNPC.class);
+ }
+
+ @Override
+ public Ocelot getBukkitEntity() {
+ return (Ocelot) super.getBukkitEntity();
+ }
+
+ public static class EntityOcelotNPC extends EntityOcelot implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityOcelotNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityOcelotNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ public void a(boolean flag) {
+ float oldw = width;
+ float oldl = length;
+ super.a(flag);
+ if (oldw != width || oldl != length) {
+ this.setPosition(locX - 0.01, locY, locZ - 0.01);
+ this.setPosition(locX + 0.01, locY, locZ + 0.01);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null)
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new OcelotNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null)
+ npc.update();
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+ }
+
+ public static class OcelotNPC extends CraftOcelot implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public OcelotNPC(EntityOcelotNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/ParrotController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/ParrotController.java
new file mode 100644
index 000000000..26f9fabd1
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/ParrotController.java
@@ -0,0 +1,180 @@
+package net.citizensnpcs.nms.v1_12_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftParrot;
+import org.bukkit.entity.Parrot;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.DamageSource;
+import net.minecraft.server.v1_12_R1.EntityHuman;
+import net.minecraft.server.v1_12_R1.EntityParrot;
+import net.minecraft.server.v1_12_R1.EnumHand;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class ParrotController extends MobEntityController {
+ public ParrotController() {
+ super(EntityParrotNPC.class);
+ }
+
+ @Override
+ public Parrot getBukkitEntity() {
+ return (Parrot) super.getBukkitEntity();
+ }
+
+ public static class EntityParrotNPC extends EntityParrot implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityParrotNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityParrotNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ public boolean a(EntityHuman paramEntityHuman, EnumHand paramEnumHand) {
+ // block feeding
+ if (npc == null || !npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true)) {
+ return super.a(paramEntityHuman, paramEnumHand);
+ }
+ return false;
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new ParrotNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null) {
+ return super.isLeashed();
+ }
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ if (npc == null) {
+ super.M();
+ } else {
+ NMSImpl.updateAI(this);
+ npc.update();
+ }
+ }
+ }
+
+ public static class ParrotNPC extends CraftParrot implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public ParrotNPC(EntityParrotNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/PigController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/PigController.java
new file mode 100644
index 000000000..719cf4783
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/PigController.java
@@ -0,0 +1,218 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPig;
+import org.bukkit.entity.Pig;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityLightning;
+import net.minecraft.server.v1_12_R1.EntityPig;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class PigController extends MobEntityController {
+ public PigController() {
+ super(EntityPigNPC.class);
+ }
+
+ @Override
+ public Pig getBukkitEntity() {
+ return (Pig) super.getBukkitEntity();
+ }
+
+ public static class EntityPigNPC extends EntityPig implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityPigNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityPigNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ public void a(boolean flag) {
+ float oldw = width;
+ float oldl = length;
+ super.a(flag);
+ if (oldw != width || oldl != length) {
+ this.setPosition(locX - 0.01, locY, locZ - 0.01);
+ this.setPosition(locX + 0.01, locY, locZ + 0.01);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new PigNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void onLightningStrike(EntityLightning entitylightning) {
+ if (npc == null) {
+ super.onLightningStrike(entitylightning);
+ }
+ }
+ }
+
+ public static class PigNPC extends CraftPig implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public PigNPC(EntityPigNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/PigZombieController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/PigZombieController.java
new file mode 100644
index 000000000..6bc663391
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/PigZombieController.java
@@ -0,0 +1,200 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPigZombie;
+import org.bukkit.entity.PigZombie;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityPigZombie;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class PigZombieController extends MobEntityController {
+
+ public PigZombieController() {
+ super(EntityPigZombieNPC.class);
+ }
+
+ @Override
+ public PigZombie getBukkitEntity() {
+ return (PigZombie) super.getBukkitEntity();
+ }
+
+ public static class EntityPigZombieNPC extends EntityPigZombie implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityPigZombieNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityPigZombieNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null)
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true)) {
+ super.f(x, y, z);
+ }
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new PigZombieNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+ }
+
+ public static class PigZombieNPC extends CraftPigZombie implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public PigZombieNPC(EntityPigZombieNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/PolarBearController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/PolarBearController.java
new file mode 100644
index 000000000..7885d67c5
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/PolarBearController.java
@@ -0,0 +1,177 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPolarBear;
+import org.bukkit.entity.PolarBear;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.EntityPolarBear;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class PolarBearController extends MobEntityController {
+ public PolarBearController() {
+ super(EntityPolarBearNPC.class);
+ }
+
+ @Override
+ public PolarBear getBukkitEntity() {
+ return (PolarBear) super.getBukkitEntity();
+ }
+
+ public static class EntityPolarBearNPC extends EntityPolarBear implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityPolarBearNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityPolarBearNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ public void a(boolean flag) {
+ float oldw = width;
+ float oldl = length;
+ super.a(flag);
+ if (oldw != width || oldl != length) {
+ this.setPosition(locX - 0.01, locY, locZ - 0.01);
+ this.setPosition(locX + 0.01, locY, locZ + 0.01);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new PolarBearNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null) {
+ return super.isLeashed();
+ }
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+ }
+
+ public static class PolarBearNPC extends CraftPolarBear implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public PolarBearNPC(EntityPolarBearNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/RabbitController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/RabbitController.java
new file mode 100644
index 000000000..d1bc1ebc2
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/RabbitController.java
@@ -0,0 +1,230 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftRabbit;
+import org.bukkit.entity.Rabbit;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityLiving;
+import net.minecraft.server.v1_12_R1.EntityRabbit;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class RabbitController extends MobEntityController {
+ public RabbitController() {
+ super(EntityRabbitNPC.class);
+ }
+
+ @Override
+ public Rabbit getBukkitEntity() {
+ return (Rabbit) super.getBukkitEntity();
+ }
+
+ public static class EntityRabbitNPC extends EntityRabbit implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityRabbitNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityRabbitNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ public void a(boolean flag) {
+ float oldw = width;
+ float oldl = length;
+ super.a(flag);
+ if (oldw != width || oldl != length) {
+ this.setPosition(locX - 0.01, locY, locZ - 0.01);
+ this.setPosition(locX + 0.01, locY, locZ + 0.01);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new RabbitNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public EntityLiving getGoalTarget() {
+ return npc != null ? null : super.getGoalTarget();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ if (npc != null) {
+ super.M();
+ this.bd = npc.getNavigator().isNavigating();
+ npc.update();
+ } else {
+ super.M();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void setRabbitType(int i) {
+ if (npc != null) {
+ if (NMSImpl.getRabbitTypeField() == null)
+ return;
+ this.datawatcher.set(NMSImpl.getRabbitTypeField(), i);
+ return;
+ }
+ super.setRabbitType(i);
+ }
+ }
+
+ public static class RabbitNPC extends CraftRabbit implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public RabbitNPC(EntityRabbitNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/SheepController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/SheepController.java
new file mode 100644
index 000000000..9cb24f626
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/SheepController.java
@@ -0,0 +1,208 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftSheep;
+import org.bukkit.entity.Sheep;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntitySheep;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class SheepController extends MobEntityController {
+ public SheepController() {
+ super(EntitySheepNPC.class);
+ }
+
+ @Override
+ public Sheep getBukkitEntity() {
+ return (Sheep) super.getBukkitEntity();
+ }
+
+ public static class EntitySheepNPC extends EntitySheep implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntitySheepNPC(World world) {
+ this(world, null);
+ }
+
+ public EntitySheepNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ public void a(boolean flag) {
+ float oldw = width;
+ float oldl = length;
+ super.a(flag);
+ if (oldw != width || oldl != length) {
+ this.setPosition(locX - 0.01, locY, locZ - 0.01);
+ this.setPosition(locX + 0.01, locY, locZ + 0.01);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null)
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new SheepNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null)
+ npc.update();
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+ }
+
+ public static class SheepNPC extends CraftSheep implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public SheepNPC(EntitySheepNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/ShulkerController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/ShulkerController.java
new file mode 100644
index 000000000..1d2fdd484
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/ShulkerController.java
@@ -0,0 +1,220 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftShulker;
+import org.bukkit.entity.Shulker;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityAIBodyControl;
+import net.minecraft.server.v1_12_R1.EntityShulker;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class ShulkerController extends MobEntityController {
+ public ShulkerController() {
+ super(EntityShulkerNPC.class);
+ }
+
+ @Override
+ public Shulker getBukkitEntity() {
+ return (Shulker) super.getBukkitEntity();
+ }
+
+ public static class EntityShulkerNPC extends EntityShulker implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityShulkerNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityShulkerNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.B_();
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null)
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new ShulkerNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void n() {
+ if (npc == null) {
+ super.n();
+ }
+ }
+
+ @Override
+ protected EntityAIBodyControl s() {
+ return new EntityAIBodyControl(this);
+ }
+
+ @Override
+ public void setSize(float f, float f1) {
+ if (npc == null) {
+ super.setSize(f, f1);
+ } else {
+ NMSImpl.setSize(this, f, f1, justCreated);
+ }
+ }
+ }
+
+ public static class ShulkerNPC extends CraftShulker implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public ShulkerNPC(EntityShulkerNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/SilverfishController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/SilverfishController.java
new file mode 100644
index 000000000..042b7470e
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/SilverfishController.java
@@ -0,0 +1,205 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftSilverfish;
+import org.bukkit.entity.Silverfish;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntitySilverfish;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class SilverfishController extends MobEntityController {
+ public SilverfishController() {
+ super(EntitySilverfishNPC.class);
+ }
+
+ @Override
+ public Silverfish getBukkitEntity() {
+ return (Silverfish) super.getBukkitEntity();
+ }
+
+ public static class EntitySilverfishNPC extends EntitySilverfish implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntitySilverfishNPC(World world) {
+ this(world, null);
+ }
+
+ public EntitySilverfishNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null)
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new SilverfishNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null)
+ npc.update();
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void setSize(float f, float f1) {
+ if (npc == null) {
+ super.setSize(f, f1);
+ } else {
+ NMSImpl.setSize(this, f, f1, justCreated);
+ }
+ }
+ }
+
+ public static class SilverfishNPC extends CraftSilverfish implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public SilverfishNPC(EntitySilverfishNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/SkeletonController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/SkeletonController.java
new file mode 100644
index 000000000..b9e9a6882
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/SkeletonController.java
@@ -0,0 +1,206 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftSkeleton;
+import org.bukkit.entity.Skeleton;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntitySkeleton;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class SkeletonController extends MobEntityController {
+ public SkeletonController() {
+ super(EntitySkeletonNPC.class);
+ }
+
+ @Override
+ public Skeleton getBukkitEntity() {
+ return (Skeleton) super.getBukkitEntity();
+ }
+
+ public static class EntitySkeletonNPC extends EntitySkeleton implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntitySkeletonNPC(World world) {
+ this(world, null);
+ }
+
+ public EntitySkeletonNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null)
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new SkeletonNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void setSize(float f, float f1) {
+ if (npc == null) {
+ super.setSize(f, f1);
+ } else {
+ NMSImpl.setSize(this, f, f1, justCreated);
+ }
+ }
+ }
+
+ public static class SkeletonNPC extends CraftSkeleton implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public SkeletonNPC(EntitySkeletonNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/SkeletonStrayController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/SkeletonStrayController.java
new file mode 100644
index 000000000..03a974e6b
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/SkeletonStrayController.java
@@ -0,0 +1,206 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftStray;
+import org.bukkit.entity.Stray;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntitySkeletonStray;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class SkeletonStrayController extends MobEntityController {
+ public SkeletonStrayController() {
+ super(EntityStrayNPC.class);
+ }
+
+ @Override
+ public Stray getBukkitEntity() {
+ return (Stray) super.getBukkitEntity();
+ }
+
+ public static class EntityStrayNPC extends EntitySkeletonStray implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityStrayNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityStrayNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null)
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new StrayNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void setSize(float f, float f1) {
+ if (npc == null) {
+ super.setSize(f, f1);
+ } else {
+ NMSImpl.setSize(this, f, f1, justCreated);
+ }
+ }
+ }
+
+ public static class StrayNPC extends CraftStray implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public StrayNPC(EntityStrayNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/SkeletonWitherController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/SkeletonWitherController.java
new file mode 100644
index 000000000..032d6d9e1
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/SkeletonWitherController.java
@@ -0,0 +1,206 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftWitherSkeleton;
+import org.bukkit.entity.WitherSkeleton;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntitySkeletonWither;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class SkeletonWitherController extends MobEntityController {
+ public SkeletonWitherController() {
+ super(EntitySkeletonWitherNPC.class);
+ }
+
+ @Override
+ public WitherSkeleton getBukkitEntity() {
+ return (WitherSkeleton) super.getBukkitEntity();
+ }
+
+ public static class EntitySkeletonWitherNPC extends EntitySkeletonWither implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntitySkeletonWitherNPC(World world) {
+ this(world, null);
+ }
+
+ public EntitySkeletonWitherNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null)
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new SkeletonWitherNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void setSize(float f, float f1) {
+ if (npc == null) {
+ super.setSize(f, f1);
+ } else {
+ NMSImpl.setSize(this, f, f1, justCreated);
+ }
+ }
+ }
+
+ public static class SkeletonWitherNPC extends CraftWitherSkeleton implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public SkeletonWitherNPC(EntitySkeletonWitherNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/SlimeController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/SlimeController.java
new file mode 100644
index 000000000..34c3c49b1
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/SlimeController.java
@@ -0,0 +1,218 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftSlime;
+import org.bukkit.entity.Slime;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.nms.v1_12_R1.util.PlayerControllerMove;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityHuman;
+import net.minecraft.server.v1_12_R1.EntitySlime;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class SlimeController extends MobEntityController {
+ public SlimeController() {
+ super(EntitySlimeNPC.class);
+ }
+
+ @Override
+ public Slime getBukkitEntity() {
+ return (Slime) super.getBukkitEntity();
+ }
+
+ public static class EntitySlimeNPC extends EntitySlime implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntitySlimeNPC(World world) {
+ this(world, null);
+ }
+
+ public EntitySlimeNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ setSize(3, true);
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ this.moveController = new PlayerControllerMove(this);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ public void B_() {
+ super.B_();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public void d(EntityHuman human) {
+ if (npc == null) {
+ super.d(human);
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new SlimeNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void setSize(float f, float f1) {
+ if (npc == null) {
+ super.setSize(f, f1);
+ } else {
+ NMSImpl.setSize(this, f, f1, justCreated);
+ }
+ }
+ }
+
+ public static class SlimeNPC extends CraftSlime implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public SlimeNPC(EntitySlimeNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/SnowmanController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/SnowmanController.java
new file mode 100644
index 000000000..adfcd4760
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/SnowmanController.java
@@ -0,0 +1,218 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftSnowman;
+import org.bukkit.entity.Snowman;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntitySnowman;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class SnowmanController extends MobEntityController {
+ public SnowmanController() {
+ super(EntitySnowmanNPC.class);
+ }
+
+ @Override
+ public Snowman getBukkitEntity() {
+ return (Snowman) super.getBukkitEntity();
+ }
+
+ public static class EntitySnowmanNPC extends EntitySnowman implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntitySnowmanNPC(World world) {
+ this(world, null);
+ }
+
+ public EntitySnowmanNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null)
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new SnowmanNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void n() {
+ boolean allowsGriefing = this.world.getGameRules().getBoolean("mobGriefing");
+ if (npc != null) {
+ this.world.getGameRules().set("mobGriefing", "false");
+ }
+ super.n();
+ if (npc != null) {
+ this.world.getGameRules().set("mobGriefing", Boolean.toString(allowsGriefing));
+ }
+ }
+
+ @Override
+ public void setSize(float f, float f1) {
+ if (npc == null) {
+ super.setSize(f, f1);
+ } else {
+ NMSImpl.setSize(this, f, f1, justCreated);
+ }
+ }
+ }
+
+ public static class SnowmanNPC extends CraftSnowman implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public SnowmanNPC(EntitySnowmanNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/SpiderController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/SpiderController.java
new file mode 100644
index 000000000..adc039bdd
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/SpiderController.java
@@ -0,0 +1,206 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftSpider;
+import org.bukkit.entity.Spider;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntitySpider;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class SpiderController extends MobEntityController {
+ public SpiderController() {
+ super(EntitySpiderNPC.class);
+ }
+
+ @Override
+ public Spider getBukkitEntity() {
+ return (Spider) super.getBukkitEntity();
+ }
+
+ public static class EntitySpiderNPC extends EntitySpider implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntitySpiderNPC(World world) {
+ this(world, null);
+ }
+
+ public EntitySpiderNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null)
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new SpiderNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null)
+ npc.update();
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void setSize(float f, float f1) {
+ if (npc == null) {
+ super.setSize(f, f1);
+ } else {
+ NMSImpl.setSize(this, f, f1, justCreated);
+ }
+ }
+
+ }
+
+ public static class SpiderNPC extends CraftSpider implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public SpiderNPC(EntitySpiderNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/SquidController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/SquidController.java
new file mode 100644
index 000000000..d8c273dfc
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/SquidController.java
@@ -0,0 +1,198 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftSquid;
+import org.bukkit.entity.Squid;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntitySquid;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class SquidController extends MobEntityController {
+ public SquidController() {
+ super(EntitySquidNPC.class);
+ }
+
+ @Override
+ public Squid getBukkitEntity() {
+ return (Squid) super.getBukkitEntity();
+ }
+
+ public static class EntitySquidNPC extends EntitySquid implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntitySquidNPC(World world) {
+ this(world, null);
+ }
+
+ public EntitySquidNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null)
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new SquidNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void setSize(float f, float f1) {
+ if (npc == null) {
+ super.setSize(f, f1);
+ } else {
+ NMSImpl.setSize(this, f, f1, justCreated);
+ }
+ }
+ }
+
+ public static class SquidNPC extends CraftSquid implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public SquidNPC(EntitySquidNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/VexController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/VexController.java
new file mode 100644
index 000000000..367af103f
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/VexController.java
@@ -0,0 +1,165 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftVex;
+import org.bukkit.entity.Vex;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.EntityVex;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class VexController extends MobEntityController {
+ public VexController() {
+ super(EntityVexNPC.class);
+ }
+
+ @Override
+ public Vex getBukkitEntity() {
+ return (Vex) super.getBukkitEntity();
+ }
+
+ public static class EntityVexNPC extends EntityVex implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityVexNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityVexNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new VexNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null) {
+ return super.isLeashed();
+ }
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+ }
+
+ public static class VexNPC extends CraftVex implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public VexNPC(EntityVexNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/VillagerController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/VillagerController.java
new file mode 100644
index 000000000..61beb8661
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/VillagerController.java
@@ -0,0 +1,245 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import java.util.List;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftVillager;
+import org.bukkit.entity.Villager;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityHuman;
+import net.minecraft.server.v1_12_R1.EntityVillager;
+import net.minecraft.server.v1_12_R1.EnumHand;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.MerchantRecipe;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class VillagerController extends MobEntityController {
+ public VillagerController() {
+ super(EntityVillagerNPC.class);
+ }
+
+ @Override
+ public Villager getBukkitEntity() {
+ return (Villager) super.getBukkitEntity();
+ }
+
+ public static class EntityVillagerNPC extends EntityVillager implements NPCHolder {
+ private boolean blockingATrade;
+ private boolean blockTrades = true;
+ private final CitizensNPC npc;
+
+ public EntityVillagerNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityVillagerNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ public void a(boolean flag) {
+ float oldw = width;
+ float oldl = length;
+ super.a(flag);
+ if (oldw != width || oldl != length) {
+ this.setPosition(locX - 0.01, locY, locZ - 0.01);
+ this.setPosition(locX + 0.01, locY, locZ + 0.01);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ public boolean a(EntityHuman entityhuman, EnumHand enumhand) {
+ if (npc != null && blockTrades) {
+ blockingATrade = true;
+ List list = getOffers(entityhuman);
+ if (list != null) {
+ list.clear();
+ }
+ }
+ return super.a(entityhuman, enumhand);
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public boolean dk() {
+ if (blockingATrade) {
+ blockingATrade = false;
+ return true;
+ }
+ return super.dk();
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new VillagerNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ public boolean isBlockingTrades() {
+ return blockTrades;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+
+ public void setBlockTrades(boolean blocked) {
+ this.blockTrades = blocked;
+ }
+ }
+
+ public static class VillagerNPC extends CraftVillager implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public VillagerNPC(EntityVillagerNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/VindicatorController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/VindicatorController.java
new file mode 100644
index 000000000..ba2237cf2
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/VindicatorController.java
@@ -0,0 +1,209 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftVindicator;
+import org.bukkit.entity.Vindicator;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityVindicator;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class VindicatorController extends MobEntityController {
+ public VindicatorController() {
+ super(EntityVindicatorNPC.class);
+ }
+
+ @Override
+ public Vindicator getBukkitEntity() {
+ return (Vindicator) super.getBukkitEntity();
+ }
+
+ public static class EntityVindicatorNPC extends EntityVindicator implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityVindicatorNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityVindicatorNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ public void a(boolean flag) {
+ float oldw = width;
+ float oldl = length;
+ super.a(flag);
+ if (oldw != width || oldl != length) {
+ this.setPosition(locX - 0.01, locY, locZ - 0.01);
+ this.setPosition(locX + 0.01, locY, locZ + 0.01);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new VindicatorNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+ }
+
+ public static class VindicatorNPC extends CraftVindicator implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public VindicatorNPC(EntityVindicatorNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/WitchController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/WitchController.java
new file mode 100644
index 000000000..2bb41875b
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/WitchController.java
@@ -0,0 +1,205 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftWitch;
+import org.bukkit.entity.Witch;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityWitch;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class WitchController extends MobEntityController {
+ public WitchController() {
+ super(EntityWitchNPC.class);
+ }
+
+ @Override
+ public Witch getBukkitEntity() {
+ return (Witch) super.getBukkitEntity();
+ }
+
+ public static class EntityWitchNPC extends EntityWitch implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityWitchNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityWitchNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null)
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new WitchNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null)
+ npc.update();
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void setSize(float f, float f1) {
+ if (npc == null) {
+ super.setSize(f, f1);
+ } else {
+ NMSImpl.setSize(this, f, f1, justCreated);
+ }
+ }
+ }
+
+ public static class WitchNPC extends CraftWitch implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public WitchNPC(EntityWitchNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/WitherController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/WitherController.java
new file mode 100644
index 000000000..5351dc071
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/WitherController.java
@@ -0,0 +1,169 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftWither;
+import org.bukkit.entity.Wither;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.EntityWither;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class WitherController extends MobEntityController {
+ public WitherController() {
+ super(EntityWitherNPC.class);
+ }
+
+ @Override
+ public Wither getBukkitEntity() {
+ return (Wither) super.getBukkitEntity();
+ }
+
+ public static class EntityWitherNPC extends EntityWither implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityWitherNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityWitherNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null)
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new WitherNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public int m(int i) {
+ return npc == null ? super.m(i) : 0;
+ }
+
+ @Override
+ protected void M() {
+ if (npc == null) {
+ super.M();
+ } else {
+ npc.update();
+ }
+ }
+ }
+
+ public static class WitherNPC extends CraftWither implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public WitherNPC(EntityWitherNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/WolfController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/WolfController.java
new file mode 100644
index 000000000..b53f30b54
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/WolfController.java
@@ -0,0 +1,222 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftWolf;
+import org.bukkit.entity.Wolf;
+import org.bukkit.event.entity.EntityTargetEvent;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityLiving;
+import net.minecraft.server.v1_12_R1.EntityWolf;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class WolfController extends MobEntityController {
+ public WolfController() {
+ super(EntityWolfNPC.class);
+ }
+
+ @Override
+ public Wolf getBukkitEntity() {
+ return (Wolf) super.getBukkitEntity();
+ }
+
+ public static class EntityWolfNPC extends EntityWolf implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityWolfNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityWolfNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ public void a(boolean flag) {
+ float oldw = width;
+ float oldl = length;
+ super.a(flag);
+ if (oldw != width || oldl != length) {
+ this.setPosition(locX - 0.01, locY, locZ - 0.01);
+ this.setPosition(locX + 0.01, locY, locZ + 0.01);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new WolfNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean setGoalTarget(EntityLiving entityliving, EntityTargetEvent.TargetReason reason, boolean fire) {
+ return npc == null ? super.setGoalTarget(killer, reason, fire) : false;
+ }
+ }
+
+ public static class WolfNPC extends CraftWolf implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public WolfNPC(EntityWolfNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void setSitting(boolean sitting) {
+ getHandle().setSitting(sitting);
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/ZombieController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/ZombieController.java
new file mode 100644
index 000000000..aa16cb60d
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/ZombieController.java
@@ -0,0 +1,197 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftZombie;
+import org.bukkit.entity.Zombie;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityZombie;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class ZombieController extends MobEntityController {
+ public ZombieController() {
+ super(EntityZombieNPC.class);
+ }
+
+ @Override
+ public Zombie getBukkitEntity() {
+ return (Zombie) super.getBukkitEntity();
+ }
+
+ public static class EntityZombieNPC extends EntityZombie implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityZombieNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityZombieNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null)
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new ZombieNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+ }
+
+ public static class ZombieNPC extends CraftZombie implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public ZombieNPC(EntityZombieNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/ZombieHuskController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/ZombieHuskController.java
new file mode 100644
index 000000000..6392548e9
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/ZombieHuskController.java
@@ -0,0 +1,197 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftHusk;
+import org.bukkit.entity.Husk;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityZombieHusk;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class ZombieHuskController extends MobEntityController {
+ public ZombieHuskController() {
+ super(EntityZombieHuskNPC.class);
+ }
+
+ @Override
+ public Husk getBukkitEntity() {
+ return (Husk) super.getBukkitEntity();
+ }
+
+ public static class EntityZombieHuskNPC extends EntityZombieHusk implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityZombieHuskNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityZombieHuskNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ protected SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null)
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ protected SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new ZombieHuskNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+ }
+
+ public static class ZombieHuskNPC extends CraftHusk implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public ZombieHuskNPC(EntityZombieHuskNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/ZombieVillagerController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/ZombieVillagerController.java
new file mode 100644
index 000000000..213797bed
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/ZombieVillagerController.java
@@ -0,0 +1,197 @@
+package net.citizensnpcs.nms.v1_12_R1.entity; import net.minecraft.server.v1_12_R1.DamageSource;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftVillagerZombie;
+import org.bukkit.entity.ZombieVillager;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCEnderTeleportEvent;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityZombieVillager;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.SoundEffect;
+import net.minecraft.server.v1_12_R1.World;
+
+public class ZombieVillagerController extends MobEntityController {
+ public ZombieVillagerController() {
+ super(EntityZombieVillagerNPC.class);
+ }
+
+ @Override
+ public ZombieVillager getBukkitEntity() {
+ return (ZombieVillager) super.getBukkitEntity();
+ }
+
+ public static class EntityZombieVillagerNPC extends EntityZombieVillager implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityZombieVillagerNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityZombieVillagerNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected void a(double d0, boolean flag, IBlockData block, BlockPosition blockposition) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(d0, flag, block, blockposition);
+ }
+ }
+
+ @Override
+ public SoundEffect cd() {
+ return NMSImpl.getSoundEffect(npc, super.cd(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ public SoundEffect d(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.d(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null)
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void e(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(f, f1);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null)
+ super.enderTeleportTo(d0, d1, d2);
+ NPCEnderTeleportEvent event = new NPCEnderTeleportEvent(npc);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ super.enderTeleportTo(d0, d1, d2);
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public void a(float f, float f1, float f2) {
+ if (npc == null || !npc.isFlyable()) {
+ super.a(f, f1, f2);
+ } else {
+ NMSImpl.flyingMoveLogic(this, f, f1, f2);
+ }
+ }
+
+ @Override
+ public SoundEffect F() {
+ return NMSImpl.getSoundEffect(npc, super.F(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new ZombieVillagerNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean isLeashed() {
+ if (npc == null)
+ return super.isLeashed();
+ boolean protectedDefault = npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true);
+ if (!protectedDefault || !npc.data().get(NPC.LEASH_PROTECTED_METADATA, protectedDefault))
+ return super.isLeashed();
+ if (super.isLeashed()) {
+ unleash(true, false); // clearLeash with client update
+ }
+ return false; // shouldLeash
+ }
+
+ @Override
+ protected void L() {
+ if (npc == null) {
+ super.L();
+ }
+ }
+
+ @Override
+ public void M() {
+ super.M();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean m_() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.m_();
+ } else {
+ return false;
+ }
+ }
+ }
+
+ public static class ZombieVillagerNPC extends CraftVillagerZombie implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public ZombieVillagerNPC(EntityZombieVillagerNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/AreaEffectCloudController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/AreaEffectCloudController.java
new file mode 100644
index 000000000..2be2baca8
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/AreaEffectCloudController.java
@@ -0,0 +1,115 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftAreaEffectCloud;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.entity.AreaEffectCloud;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.EntityAreaEffectCloud;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+
+public class AreaEffectCloudController extends MobEntityController {
+ public AreaEffectCloudController() {
+ super(EntityAreaEffectCloudNPC.class);
+ }
+
+ @Override
+ public AreaEffectCloud getBukkitEntity() {
+ return (AreaEffectCloud) super.getBukkitEntity();
+ }
+
+ public static class AreaEffectCloudNPC extends CraftAreaEffectCloud implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public AreaEffectCloudNPC(EntityAreaEffectCloudNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+
+ public static class EntityAreaEffectCloudNPC extends EntityAreaEffectCloud implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityAreaEffectCloudNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityAreaEffectCloudNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.B_();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new AreaEffectCloudNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/ArmorStandController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/ArmorStandController.java
new file mode 100644
index 000000000..f0613caa0
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/ArmorStandController.java
@@ -0,0 +1,131 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftArmorStand;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.entity.ArmorStand;
+import org.bukkit.entity.Player;
+import org.bukkit.event.player.PlayerInteractEntityEvent;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.EntityArmorStand;
+import net.minecraft.server.v1_12_R1.EntityHuman;
+import net.minecraft.server.v1_12_R1.EnumHand;
+import net.minecraft.server.v1_12_R1.EnumInteractionResult;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.Vec3D;
+import net.minecraft.server.v1_12_R1.World;
+
+public class ArmorStandController extends MobEntityController {
+ public ArmorStandController() {
+ super(EntityArmorStandNPC.class);
+ }
+
+ @Override
+ public ArmorStand getBukkitEntity() {
+ return (ArmorStand) super.getBukkitEntity();
+ }
+
+ public static class ArmorStandNPC extends CraftArmorStand implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public ArmorStandNPC(EntityArmorStandNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+
+ public static class EntityArmorStandNPC extends EntityArmorStand implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityArmorStandNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityArmorStandNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public EnumInteractionResult a(EntityHuman entityhuman, Vec3D vec3d, EnumHand enumhand) {
+ if (npc == null) {
+ return super.a(entityhuman, vec3d, enumhand);
+ }
+ PlayerInteractEntityEvent event = new PlayerInteractEntityEvent((Player) entityhuman.getBukkitEntity(),
+ getBukkitEntity());
+ Bukkit.getPluginManager().callEvent(event);
+ return event.isCancelled() ? EnumInteractionResult.FAIL : EnumInteractionResult.SUCCESS;
+ }
+
+ @Override
+ public void B_() {
+ super.B_();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new ArmorStandNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/BoatController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/BoatController.java
new file mode 100644
index 000000000..6504865ad
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/BoatController.java
@@ -0,0 +1,125 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftBoat;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.entity.Boat;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.EntityBoat;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+
+public class BoatController extends MobEntityController {
+ public BoatController() {
+ super(EntityBoatNPC.class);
+ }
+
+ @Override
+ public Boat getBukkitEntity() {
+ return (Boat) super.getBukkitEntity();
+ }
+
+ public static class BoatNPC extends CraftBoat implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public BoatNPC(EntityBoatNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+
+ public static class EntityBoatNPC extends EntityBoat implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityBoatNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityBoatNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.B_();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new BoatNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void setSize(float f, float f1) {
+ if (npc == null) {
+ super.setSize(f, f1);
+ } else {
+ NMSImpl.setSize(this, f, f1, justCreated);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/DragonFireballController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/DragonFireballController.java
new file mode 100644
index 000000000..08890af62
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/DragonFireballController.java
@@ -0,0 +1,128 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftDragonFireball;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.entity.DragonFireball;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.EntityDragonFireball;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+
+public class DragonFireballController extends MobEntityController {
+ public DragonFireballController() {
+ super(EntityDragonFireballNPC.class);
+ }
+
+ @Override
+ public DragonFireball getBukkitEntity() {
+ return (DragonFireball) super.getBukkitEntity();
+ }
+
+ public static class DragonFireballNPC extends CraftDragonFireball implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public DragonFireballNPC(EntityDragonFireballNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+
+ public static class EntityDragonFireballNPC extends EntityDragonFireball implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityDragonFireballNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityDragonFireballNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new DragonFireballNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true)) {
+ super.B_();
+ }
+ } else {
+ super.B_();
+ }
+ }
+
+ @Override
+ public void setSize(float f, float f1) {
+ if (npc == null) {
+ super.setSize(f, f1);
+ } else {
+ NMSImpl.setSize(this, f, f1, justCreated);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/EggController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/EggController.java
new file mode 100644
index 000000000..e360d6f00
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/EggController.java
@@ -0,0 +1,134 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.npc.AbstractEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.EntityEgg;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+import net.minecraft.server.v1_12_R1.WorldServer;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.CraftWorld;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEgg;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.entity.Egg;
+import org.bukkit.entity.Entity;
+import org.bukkit.util.Vector;
+
+public class EggController extends AbstractEntityController {
+ public EggController() {
+ super(EntityEggNPC.class);
+ }
+
+ @Override
+ protected Entity createEntity(Location at, NPC npc) {
+ WorldServer ws = ((CraftWorld) at.getWorld()).getHandle();
+ final EntityEggNPC handle = new EntityEggNPC(ws, npc, at.getX(), at.getY(), at.getZ());
+ return handle.getBukkitEntity();
+ }
+
+ @Override
+ public Egg getBukkitEntity() {
+ return (Egg) super.getBukkitEntity();
+ }
+
+ public static class EggNPC extends CraftEgg implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EggNPC(EntityEggNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+
+ public static class EntityEggNPC extends EntityEgg implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityEggNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityEggNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ public EntityEggNPC(World world, NPC npc, double d0, double d1, double d2) {
+ super(world, d0, d1, d2);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new EggNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true)) {
+ super.B_();
+ }
+ } else {
+ super.B_();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/EnderCrystalController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/EnderCrystalController.java
new file mode 100644
index 000000000..f548c8095
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/EnderCrystalController.java
@@ -0,0 +1,115 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.EntityEnderCrystal;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEnderCrystal;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.entity.EnderCrystal;
+import org.bukkit.util.Vector;
+
+public class EnderCrystalController extends MobEntityController {
+ public EnderCrystalController() {
+ super(EntityEnderCrystalNPC.class);
+ }
+
+ @Override
+ public EnderCrystal getBukkitEntity() {
+ return (EnderCrystal) super.getBukkitEntity();
+ }
+
+ public static class EnderCrystalNPC extends CraftEnderCrystal implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EnderCrystalNPC(EntityEnderCrystalNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+
+ public static class EntityEnderCrystalNPC extends EntityEnderCrystal implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityEnderCrystalNPC(World world) {
+ this(world, null);
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ public EntityEnderCrystalNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new EnderCrystalNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.B_();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/EnderPearlController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/EnderPearlController.java
new file mode 100644
index 000000000..3871db4fb
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/EnderPearlController.java
@@ -0,0 +1,118 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEnderPearl;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.entity.EnderPearl;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.EntityEnderPearl;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+
+public class EnderPearlController extends MobEntityController {
+ public EnderPearlController() {
+ super(EntityEnderPearlNPC.class);
+ }
+
+ @Override
+ public EnderPearl getBukkitEntity() {
+ return (EnderPearl) super.getBukkitEntity();
+ }
+
+ public static class EnderPearlNPC extends CraftEnderPearl implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EnderPearlNPC(EntityEnderPearlNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+
+ public static class EntityEnderPearlNPC extends EntityEnderPearl implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityEnderPearlNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityEnderPearlNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new EnderPearlNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true)) {
+ super.B_();
+ }
+ } else {
+ super.B_();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/EnderSignalController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/EnderSignalController.java
new file mode 100644
index 000000000..3335417ad
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/EnderSignalController.java
@@ -0,0 +1,115 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.EntityEnderSignal;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEnderSignal;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.entity.EnderSignal;
+import org.bukkit.util.Vector;
+
+public class EnderSignalController extends MobEntityController {
+ public EnderSignalController() {
+ super(EntityEnderSignalNPC.class);
+ }
+
+ @Override
+ public EnderSignal getBukkitEntity() {
+ return (EnderSignal) super.getBukkitEntity();
+ }
+
+ public static class EnderSignalNPC extends CraftEnderSignal implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EnderSignalNPC(EntityEnderSignalNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+
+ public static class EntityEnderSignalNPC extends EntityEnderSignal implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityEnderSignalNPC(World world) {
+ this(world, null);
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ public EntityEnderSignalNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new EnderSignalNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.B_();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/EvokerFangsController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/EvokerFangsController.java
new file mode 100644
index 000000000..53f37af1e
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/EvokerFangsController.java
@@ -0,0 +1,131 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEvokerFangs;
+import org.bukkit.entity.EvokerFangs;
+import org.bukkit.entity.Player;
+import org.bukkit.event.player.PlayerInteractEntityEvent;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.EntityEvokerFangs;
+import net.minecraft.server.v1_12_R1.EntityHuman;
+import net.minecraft.server.v1_12_R1.EnumHand;
+import net.minecraft.server.v1_12_R1.EnumInteractionResult;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.Vec3D;
+import net.minecraft.server.v1_12_R1.World;
+
+public class EvokerFangsController extends MobEntityController {
+ public EvokerFangsController() {
+ super(EntityEvokerFangsNPC.class);
+ }
+
+ @Override
+ public EvokerFangs getBukkitEntity() {
+ return (EvokerFangs) super.getBukkitEntity();
+ }
+
+ public static class EntityEvokerFangsNPC extends EntityEvokerFangs implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityEvokerFangsNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityEvokerFangsNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public EnumInteractionResult a(EntityHuman entityhuman, Vec3D vec3d, EnumHand enumhand) {
+ if (npc == null) {
+ return super.a(entityhuman, vec3d, enumhand);
+ }
+ PlayerInteractEntityEvent event = new PlayerInteractEntityEvent((Player) entityhuman.getBukkitEntity(),
+ getBukkitEntity());
+ Bukkit.getPluginManager().callEvent(event);
+ return event.isCancelled() ? EnumInteractionResult.FAIL : EnumInteractionResult.SUCCESS;
+ }
+
+ @Override
+ public void B_() {
+ super.B_();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new EvokerFangsNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+
+ public static class EvokerFangsNPC extends CraftEvokerFangs implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EvokerFangsNPC(EntityEvokerFangsNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/ExperienceOrbController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/ExperienceOrbController.java
new file mode 100644
index 000000000..7879cda27
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/ExperienceOrbController.java
@@ -0,0 +1,115 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.EntityExperienceOrb;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftExperienceOrb;
+import org.bukkit.entity.ExperienceOrb;
+import org.bukkit.util.Vector;
+
+public class ExperienceOrbController extends MobEntityController {
+ public ExperienceOrbController() {
+ super(EntityExperienceOrbNPC.class);
+ }
+
+ @Override
+ public ExperienceOrb getBukkitEntity() {
+ return (ExperienceOrb) super.getBukkitEntity();
+ }
+
+ public static class EntityExperienceOrbNPC extends EntityExperienceOrb implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityExperienceOrbNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityExperienceOrbNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new ExperienceOrbNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.B_();
+ }
+ }
+ }
+
+ public static class ExperienceOrbNPC extends CraftExperienceOrb implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public ExperienceOrbNPC(EntityExperienceOrbNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/FallingBlockController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/FallingBlockController.java
new file mode 100644
index 000000000..f01ac4c48
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/FallingBlockController.java
@@ -0,0 +1,171 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.CraftWorld;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftFallingBlock;
+import org.bukkit.craftbukkit.v1_12_R1.util.CraftMagicNumbers;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.FallingBlock;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.AbstractEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.Block;
+import net.minecraft.server.v1_12_R1.Blocks;
+import net.minecraft.server.v1_12_R1.EntityFallingBlock;
+import net.minecraft.server.v1_12_R1.EnumMoveType;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+import net.minecraft.server.v1_12_R1.WorldServer;
+
+public class FallingBlockController extends AbstractEntityController {
+ public FallingBlockController() {
+ super(EntityFallingBlockNPC.class);
+ }
+
+ @Override
+ protected Entity createEntity(Location at, NPC npc) {
+ WorldServer ws = ((CraftWorld) at.getWorld()).getHandle();
+ Block id = Blocks.STONE;
+ int data = npc.data().get(NPC.ITEM_DATA_METADATA, npc.data().get("falling-block-data", 0));
+ if (npc.data().has("falling-block-id") || npc.data().has(NPC.ITEM_ID_METADATA)) {
+ id = CraftMagicNumbers.getBlock(Material.getMaterial(
+ npc.data(). get(NPC.ITEM_ID_METADATA, npc.data(). get("falling-block-id"))));
+ }
+ final EntityFallingBlockNPC handle = new EntityFallingBlockNPC(ws, npc, at.getX(), at.getY(), at.getZ(),
+ id.fromLegacyData(data));
+ return handle.getBukkitEntity();
+ }
+
+ @Override
+ public FallingBlock getBukkitEntity() {
+ return (FallingBlock) super.getBukkitEntity();
+ }
+
+ public static class EntityFallingBlockNPC extends EntityFallingBlock implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityFallingBlockNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityFallingBlockNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ public EntityFallingBlockNPC(World world, NPC npc, double d0, double d1, double d2, IBlockData data) {
+ super(world, d0, d1, d2, data);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ if (Math.abs(motX) > EPSILON || Math.abs(motY) > EPSILON || Math.abs(motZ) > EPSILON) {
+ motX *= 0.98;
+ motY *= 0.98;
+ motZ *= 0.98;
+ move(EnumMoveType.SELF, motX, motY, motZ);
+ }
+ } else {
+ super.B_();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new FallingBlockNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void setSize(float f, float f1) {
+ if (npc == null) {
+ super.setSize(f, f1);
+ } else {
+ NMSImpl.setSize(this, f, f1, justCreated);
+ }
+ }
+
+ private static final double EPSILON = 0.001;
+ }
+
+ public static class FallingBlockNPC extends CraftFallingBlock implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public FallingBlockNPC(EntityFallingBlockNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ public void setType(Material material, int data) {
+ npc.data().setPersistent(NPC.ITEM_ID_METADATA, material.name());
+ npc.data().setPersistent(NPC.ITEM_DATA_METADATA, data);
+ if (npc.isSpawned()) {
+ npc.despawn();
+ npc.spawn(npc.getStoredLocation());
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/FireworkController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/FireworkController.java
new file mode 100644
index 000000000..f7addca00
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/FireworkController.java
@@ -0,0 +1,115 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.EntityFireworks;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftFirework;
+import org.bukkit.entity.Firework;
+import org.bukkit.util.Vector;
+
+public class FireworkController extends MobEntityController {
+ public FireworkController() {
+ super(EntityFireworkNPC.class);
+ }
+
+ @Override
+ public Firework getBukkitEntity() {
+ return (Firework) super.getBukkitEntity();
+ }
+
+ public static class EntityFireworkNPC extends EntityFireworks implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityFireworkNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityFireworkNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new FireworkNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.B_();
+ }
+ }
+ }
+
+ public static class FireworkNPC extends CraftFirework implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public FireworkNPC(EntityFireworkNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/FishingHookController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/FishingHookController.java
new file mode 100644
index 000000000..425cc2163
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/FishingHookController.java
@@ -0,0 +1,115 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftFish;
+import org.bukkit.entity.FishHook;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.EntityFishingHook;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+
+public class FishingHookController extends MobEntityController {
+ public FishingHookController() {
+ super(EntityFishingHookNPC.class);
+ }
+
+ @Override
+ public FishHook getBukkitEntity() {
+ return (FishHook) super.getBukkitEntity();
+ }
+
+ public static class EntityFishingHookNPC extends EntityFishingHook implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityFishingHookNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityFishingHookNPC(World world, NPC npc) {
+ super(world, null);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.B_();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new FishingHookNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+
+ public static class FishingHookNPC extends CraftFish implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public FishingHookNPC(EntityFishingHookNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/ItemController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/ItemController.java
new file mode 100644
index 000000000..1ceb3c8fe
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/ItemController.java
@@ -0,0 +1,153 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.npc.AbstractEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.EntityHuman;
+import net.minecraft.server.v1_12_R1.EntityItem;
+import net.minecraft.server.v1_12_R1.ItemStack;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+import net.minecraft.server.v1_12_R1.WorldServer;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.CraftWorld;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftItem;
+import org.bukkit.craftbukkit.v1_12_R1.inventory.CraftItemStack;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.Item;
+import org.bukkit.util.Vector;
+
+public class ItemController extends AbstractEntityController {
+ public ItemController() {
+ super(EntityItemNPC.class);
+ }
+
+ @Override
+ protected Entity createEntity(Location at, NPC npc) {
+ WorldServer ws = ((CraftWorld) at.getWorld()).getHandle();
+ Material id = Material.STONE;
+ int data = npc.data().get(NPC.ITEM_DATA_METADATA, npc.data().get("falling-block-data", 0));
+ if (npc.data().has(NPC.ITEM_ID_METADATA)) {
+ id = Material.getMaterial(npc.data(). get(NPC.ITEM_ID_METADATA));
+ }
+ final EntityItemNPC handle = new EntityItemNPC(ws, npc, at.getX(), at.getY(), at.getZ(),
+ CraftItemStack.asNMSCopy(new org.bukkit.inventory.ItemStack(id, 1, (short) data)));
+ return handle.getBukkitEntity();
+ }
+
+ @Override
+ public Item getBukkitEntity() {
+ return (Item) super.getBukkitEntity();
+ }
+
+ public static class EntityItemNPC extends EntityItem implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityItemNPC(World world) {
+ super(world);
+ this.npc = null;
+ }
+
+ public EntityItemNPC(World world, NPC npc, double x, double y, double z, ItemStack stack) {
+ super(world, x, y, z, stack);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public void d(EntityHuman entityhuman) {
+ if (npc == null) {
+ super.d(entityhuman);
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new ItemNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.B_();
+ }
+ }
+ }
+
+ public static class ItemNPC extends CraftItem implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public ItemNPC(EntityItemNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ public void setType(Material material, int data) {
+ npc.data().setPersistent(NPC.ITEM_ID_METADATA, material.name());
+ npc.data().setPersistent(NPC.ITEM_DATA_METADATA, data);
+ if (npc.isSpawned()) {
+ npc.despawn();
+ npc.spawn(npc.getStoredLocation());
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/ItemFrameController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/ItemFrameController.java
new file mode 100644
index 000000000..c75ffd451
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/ItemFrameController.java
@@ -0,0 +1,150 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftItemFrame;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.ItemFrame;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.EntityItemFrame;
+import net.minecraft.server.v1_12_R1.EnumDirection;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+
+public class ItemFrameController extends MobEntityController {
+ public ItemFrameController() {
+ super(EntityItemFrameNPC.class);
+ }
+
+ @Override
+ protected Entity createEntity(Location at, NPC npc) {
+ Entity e = super.createEntity(at, npc);
+ EntityItemFrame item = (EntityItemFrame) ((CraftEntity) e).getHandle();
+ item.setDirection(EnumDirection.EAST);
+ item.blockPosition = new BlockPosition(at.getX(), at.getY(), at.getZ());
+ return e;
+ }
+
+ @Override
+ public ItemFrame getBukkitEntity() {
+ return (ItemFrame) super.getBukkitEntity();
+ }
+
+ public static class EntityItemFrameNPC extends EntityItemFrame implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityItemFrameNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityItemFrameNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new ItemFrameNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public boolean survives() {
+ return npc == null || !npc.isProtected() ? super.survives() : true;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.B_();
+ }
+ }
+ }
+
+ public static class ItemFrameNPC extends CraftItemFrame implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public ItemFrameNPC(EntityItemFrameNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ Material id = Material.STONE;
+ int data = npc.data().get(NPC.ITEM_DATA_METADATA, npc.data().get("falling-block-data", 0));
+ if (npc.data().has(NPC.ITEM_ID_METADATA)) {
+ id = Material.getMaterial(npc.data(). get(NPC.ITEM_ID_METADATA));
+ }
+ getItem().setType(id);
+ getItem().setDurability((short) data);
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ public void setType(Material material, int data) {
+ npc.data().setPersistent(NPC.ITEM_ID_METADATA, material.name());
+ npc.data().setPersistent(NPC.ITEM_DATA_METADATA, data);
+ if (npc.isSpawned()) {
+ npc.despawn();
+ npc.spawn(npc.getStoredLocation());
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/LargeFireballController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/LargeFireballController.java
new file mode 100644
index 000000000..8207c5b02
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/LargeFireballController.java
@@ -0,0 +1,128 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftLargeFireball;
+import org.bukkit.entity.LargeFireball;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.EntityLargeFireball;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+
+public class LargeFireballController extends MobEntityController {
+ public LargeFireballController() {
+ super(EntityLargeFireballNPC.class);
+ }
+
+ @Override
+ public LargeFireball getBukkitEntity() {
+ return (LargeFireball) super.getBukkitEntity();
+ }
+
+ public static class EntityLargeFireballNPC extends EntityLargeFireball implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityLargeFireballNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityLargeFireballNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new LargeFireballNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void setSize(float f, float f1) {
+ if (npc == null) {
+ super.setSize(f, f1);
+ } else {
+ NMSImpl.setSize(this, f, f1, justCreated);
+ }
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true)) {
+ super.B_();
+ }
+ } else {
+ super.B_();
+ }
+ }
+ }
+
+ public static class LargeFireballNPC extends CraftLargeFireball implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public LargeFireballNPC(EntityLargeFireballNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/LeashController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/LeashController.java
new file mode 100644
index 000000000..6b555a7c5
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/LeashController.java
@@ -0,0 +1,120 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.EntityLeash;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftLeash;
+import org.bukkit.entity.LeashHitch;
+import org.bukkit.util.Vector;
+
+public class LeashController extends MobEntityController {
+ public LeashController() {
+ super(EntityLeashNPC.class);
+ }
+
+ @Override
+ public LeashHitch getBukkitEntity() {
+ return (LeashHitch) super.getBukkitEntity();
+ }
+
+ public static class EntityLeashNPC extends EntityLeash implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityLeashNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityLeashNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new LeashNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.B_();
+ }
+ }
+
+ @Override
+ public boolean survives() {
+ return npc == null || !npc.isProtected() ? super.survives() : true;
+ }
+ }
+
+ public static class LeashNPC extends CraftLeash implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public LeashNPC(EntityLeashNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/LlamaSpitController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/LlamaSpitController.java
new file mode 100644
index 000000000..e2929677c
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/LlamaSpitController.java
@@ -0,0 +1,136 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.CraftWorld;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftLlamaSpit;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.LlamaSpit;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.npc.AbstractEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.EntityLlama;
+import net.minecraft.server.v1_12_R1.EntityLlamaSpit;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+import net.minecraft.server.v1_12_R1.WorldServer;
+
+public class LlamaSpitController extends AbstractEntityController {
+ public LlamaSpitController() {
+ super(EntityLlamaSpitNPC.class);
+ }
+
+ @Override
+ protected Entity createEntity(Location at, NPC npc) {
+ WorldServer ws = ((CraftWorld) at.getWorld()).getHandle();
+ final EntityLlamaSpitNPC handle = new EntityLlamaSpitNPC(ws, npc);
+ handle.setPositionRotation(at.getX(), at.getY(), at.getZ(), at.getPitch(), at.getYaw());
+ return handle.getBukkitEntity();
+ }
+
+ @Override
+ public LlamaSpit getBukkitEntity() {
+ return (LlamaSpit) super.getBukkitEntity();
+ }
+
+ public static class EntityLlamaSpitNPC extends EntityLlamaSpit implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityLlamaSpitNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityLlamaSpitNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ public EntityLlamaSpitNPC(World world, NPC npc, EntityLlama entity) {
+ super(world, entity);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true)) {
+ super.B_();
+ }
+ } else {
+ super.B_();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new LlamaSpitNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+
+ public static class LlamaSpitNPC extends CraftLlamaSpit implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public LlamaSpitNPC(EntityLlamaSpitNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/MinecartChestController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/MinecartChestController.java
new file mode 100644
index 000000000..49cdd3e14
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/MinecartChestController.java
@@ -0,0 +1,125 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftMinecartChest;
+import org.bukkit.entity.Minecart;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.DamageSource;
+import net.minecraft.server.v1_12_R1.EntityMinecartChest;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+
+public class MinecartChestController extends MobEntityController {
+ public MinecartChestController() {
+ super(EntityMinecartChestNPC.class);
+ }
+
+ @Override
+ public Minecart getBukkitEntity() {
+ return (Minecart) super.getBukkitEntity();
+ }
+
+ public static class EntityMinecartChestNPC extends EntityMinecartChest implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityMinecartChestNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityMinecartChestNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public boolean damageEntity(DamageSource damagesource, float f) {
+ if (npc == null || !npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ return super.damageEntity(damagesource, f);
+ return false;
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new MinecartChestNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ NMSImpl.minecartItemLogic(this);
+ } else {
+ super.B_();
+ }
+ }
+ }
+
+ public static class MinecartChestNPC extends CraftMinecartChest implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public MinecartChestNPC(EntityMinecartChestNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/MinecartCommandController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/MinecartCommandController.java
new file mode 100644
index 000000000..a66a9648b
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/MinecartCommandController.java
@@ -0,0 +1,125 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftMinecartCommand;
+import org.bukkit.entity.Minecart;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.DamageSource;
+import net.minecraft.server.v1_12_R1.EntityMinecartCommandBlock;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+
+public class MinecartCommandController extends MobEntityController {
+ public MinecartCommandController() {
+ super(EntityMinecartCommandNPC.class);
+ }
+
+ @Override
+ public Minecart getBukkitEntity() {
+ return (Minecart) super.getBukkitEntity();
+ }
+
+ public static class EntityMinecartCommandNPC extends EntityMinecartCommandBlock implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityMinecartCommandNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityMinecartCommandNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public boolean damageEntity(DamageSource damagesource, float f) {
+ if (npc == null || !npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ return super.damageEntity(damagesource, f);
+ return false;
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new MinecartCommandNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ NMSImpl.minecartItemLogic(this);
+ } else {
+ super.B_();
+ }
+ }
+ }
+
+ public static class MinecartCommandNPC extends CraftMinecartCommand implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public MinecartCommandNPC(EntityMinecartCommandNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/MinecartFurnaceController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/MinecartFurnaceController.java
new file mode 100644
index 000000000..eaaeb864c
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/MinecartFurnaceController.java
@@ -0,0 +1,125 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftMinecartFurnace;
+import org.bukkit.entity.Minecart;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.DamageSource;
+import net.minecraft.server.v1_12_R1.EntityMinecartFurnace;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+
+public class MinecartFurnaceController extends MobEntityController {
+ public MinecartFurnaceController() {
+ super(EntityMinecartFurnaceNPC.class);
+ }
+
+ @Override
+ public Minecart getBukkitEntity() {
+ return (Minecart) super.getBukkitEntity();
+ }
+
+ public static class EntityMinecartFurnaceNPC extends EntityMinecartFurnace implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityMinecartFurnaceNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityMinecartFurnaceNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public boolean damageEntity(DamageSource damagesource, float f) {
+ if (npc == null || !npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ return super.damageEntity(damagesource, f);
+ return false;
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new MinecartFurnaceNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ NMSImpl.minecartItemLogic(this);
+ } else {
+ super.B_();
+ }
+ }
+ }
+
+ public static class MinecartFurnaceNPC extends CraftMinecartFurnace implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public MinecartFurnaceNPC(EntityMinecartFurnaceNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/MinecartHopperController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/MinecartHopperController.java
new file mode 100644
index 000000000..b12a90a1a
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/MinecartHopperController.java
@@ -0,0 +1,99 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import org.bukkit.entity.Minecart;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.DamageSource;
+import net.minecraft.server.v1_12_R1.EntityMinecartHopper;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+
+public class MinecartHopperController extends MobEntityController {
+ public MinecartHopperController() {
+ super(EntityMinecartHopperNPC.class);
+ }
+
+ @Override
+ public Minecart getBukkitEntity() {
+ return (Minecart) super.getBukkitEntity();
+ }
+
+ public static class EntityMinecartHopperNPC extends EntityMinecartHopper implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityMinecartHopperNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityMinecartHopperNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public boolean damageEntity(DamageSource damagesource, float f) {
+ if (npc == null || !npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ return super.damageEntity(damagesource, f);
+ return false;
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ NMSImpl.minecartItemLogic(this);
+ } else {
+ super.B_();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/MinecartRideableController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/MinecartRideableController.java
new file mode 100644
index 000000000..90c780ded
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/MinecartRideableController.java
@@ -0,0 +1,125 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftMinecartRideable;
+import org.bukkit.entity.Minecart;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.DamageSource;
+import net.minecraft.server.v1_12_R1.EntityMinecartRideable;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+
+public class MinecartRideableController extends MobEntityController {
+ public MinecartRideableController() {
+ super(EntityMinecartRideableNPC.class);
+ }
+
+ @Override
+ public Minecart getBukkitEntity() {
+ return (Minecart) super.getBukkitEntity();
+ }
+
+ public static class EntityMinecartRideableNPC extends EntityMinecartRideable implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityMinecartRideableNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityMinecartRideableNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ NMSImpl.minecartItemLogic(this);
+ } else {
+ super.B_();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public boolean damageEntity(DamageSource damagesource, float f) {
+ if (npc == null || !npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ return super.damageEntity(damagesource, f);
+ return false;
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new MinecartRideableNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+
+ public static class MinecartRideableNPC extends CraftMinecartRideable implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public MinecartRideableNPC(EntityMinecartRideableNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/MinecartSpawnerController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/MinecartSpawnerController.java
new file mode 100644
index 000000000..a3887ba4d
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/MinecartSpawnerController.java
@@ -0,0 +1,99 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import org.bukkit.entity.Minecart;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.DamageSource;
+import net.minecraft.server.v1_12_R1.EntityMinecartMobSpawner;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+
+public class MinecartSpawnerController extends MobEntityController {
+ public MinecartSpawnerController() {
+ super(EntityMinecartSpawnerNPC.class);
+ }
+
+ @Override
+ public Minecart getBukkitEntity() {
+ return (Minecart) super.getBukkitEntity();
+ }
+
+ public static class EntityMinecartSpawnerNPC extends EntityMinecartMobSpawner implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityMinecartSpawnerNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityMinecartSpawnerNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public boolean damageEntity(DamageSource damagesource, float f) {
+ if (npc == null || !npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ return super.damageEntity(damagesource, f);
+ return false;
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ NMSImpl.minecartItemLogic(this);
+ } else {
+ super.B_();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/MinecartTNTController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/MinecartTNTController.java
new file mode 100644
index 000000000..9e80d8b87
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/MinecartTNTController.java
@@ -0,0 +1,99 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import org.bukkit.entity.Minecart;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.DamageSource;
+import net.minecraft.server.v1_12_R1.EntityMinecartTNT;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+
+public class MinecartTNTController extends MobEntityController {
+ public MinecartTNTController() {
+ super(EntityMinecartTNTNPC.class);
+ }
+
+ @Override
+ public Minecart getBukkitEntity() {
+ return (Minecart) super.getBukkitEntity();
+ }
+
+ public static class EntityMinecartTNTNPC extends EntityMinecartTNT implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityMinecartTNTNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityMinecartTNTNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public boolean damageEntity(DamageSource damagesource, float f) {
+ if (npc == null || !npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ return super.damageEntity(damagesource, f);
+ return false;
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ NMSImpl.minecartItemLogic(this);
+ } else {
+ super.B_();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/PaintingController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/PaintingController.java
new file mode 100644
index 000000000..5649db784
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/PaintingController.java
@@ -0,0 +1,120 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.EntityPainting;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPainting;
+import org.bukkit.entity.Painting;
+import org.bukkit.util.Vector;
+
+public class PaintingController extends MobEntityController {
+ public PaintingController() {
+ super(EntityPaintingNPC.class);
+ }
+
+ @Override
+ public Painting getBukkitEntity() {
+ return (Painting) super.getBukkitEntity();
+ }
+
+ public static class EntityPaintingNPC extends EntityPainting implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityPaintingNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityPaintingNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new PaintingNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.B_();
+ }
+ }
+
+ @Override
+ public boolean survives() {
+ return npc == null || !npc.isProtected() ? super.survives() : true;
+ }
+ }
+
+ public static class PaintingNPC extends CraftPainting implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public PaintingNPC(EntityPaintingNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/ShulkerBulletController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/ShulkerBulletController.java
new file mode 100644
index 000000000..ce25828a8
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/ShulkerBulletController.java
@@ -0,0 +1,115 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftShulkerBullet;
+import org.bukkit.entity.ShulkerBullet;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.EntityShulkerBullet;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+
+public class ShulkerBulletController extends MobEntityController {
+ public ShulkerBulletController() {
+ super(EntityShulkerBulletNPC.class);
+ }
+
+ @Override
+ public ShulkerBullet getBukkitEntity() {
+ return (ShulkerBullet) super.getBukkitEntity();
+ }
+
+ public static class EntityShulkerBulletNPC extends EntityShulkerBullet implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityShulkerBulletNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityShulkerBulletNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new ShulkerBulletNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.B_();
+ }
+ }
+ }
+
+ public static class ShulkerBulletNPC extends CraftShulkerBullet implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public ShulkerBulletNPC(EntityShulkerBulletNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/SmallFireballController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/SmallFireballController.java
new file mode 100644
index 000000000..b9e6e8126
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/SmallFireballController.java
@@ -0,0 +1,118 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftSmallFireball;
+import org.bukkit.entity.SmallFireball;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.EntitySmallFireball;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+
+public class SmallFireballController extends MobEntityController {
+ public SmallFireballController() {
+ super(EntitySmallFireballNPC.class);
+ }
+
+ @Override
+ public SmallFireball getBukkitEntity() {
+ return (SmallFireball) super.getBukkitEntity();
+ }
+
+ public static class EntitySmallFireballNPC extends EntitySmallFireball implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntitySmallFireballNPC(World world) {
+ this(world, null);
+ }
+
+ public EntitySmallFireballNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new SmallFireballNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true)) {
+ super.B_();
+ }
+ } else {
+ super.B_();
+ }
+ }
+ }
+
+ public static class SmallFireballNPC extends CraftSmallFireball implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public SmallFireballNPC(EntitySmallFireballNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/SnowballController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/SnowballController.java
new file mode 100644
index 000000000..8cdce40c8
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/SnowballController.java
@@ -0,0 +1,115 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.EntitySnowball;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftSnowball;
+import org.bukkit.entity.Snowball;
+import org.bukkit.util.Vector;
+
+public class SnowballController extends MobEntityController {
+ public SnowballController() {
+ super(EntitySnowballNPC.class);
+ }
+
+ @Override
+ public Snowball getBukkitEntity() {
+ return (Snowball) super.getBukkitEntity();
+ }
+
+ public static class SnowballNPC extends CraftSnowball implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public SnowballNPC(EntitySnowballNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+
+ public static class EntitySnowballNPC extends EntitySnowball implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntitySnowballNPC(World world) {
+ this(world, null);
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ public EntitySnowballNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new SnowballNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.B_();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/SpectralArrowController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/SpectralArrowController.java
new file mode 100644
index 000000000..acf8269c0
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/SpectralArrowController.java
@@ -0,0 +1,115 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftArrow;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.entity.Arrow;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.EntitySpectralArrow;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+
+public class SpectralArrowController extends MobEntityController {
+ public SpectralArrowController() {
+ super(EntitySpectralArrowNPC.class);
+ }
+
+ @Override
+ public Arrow getBukkitEntity() {
+ return (Arrow) super.getBukkitEntity();
+ }
+
+ public static class EntitySpectralArrowNPC extends EntitySpectralArrow implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntitySpectralArrowNPC(World world) {
+ this(world, null);
+ }
+
+ public EntitySpectralArrowNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new SpectralArrowNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.B_();
+ }
+ }
+ }
+
+ public static class SpectralArrowNPC extends CraftArrow implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public SpectralArrowNPC(EntitySpectralArrowNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/TNTPrimedController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/TNTPrimedController.java
new file mode 100644
index 000000000..1ac2853e2
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/TNTPrimedController.java
@@ -0,0 +1,115 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.EntityTNTPrimed;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftTNTPrimed;
+import org.bukkit.entity.TNTPrimed;
+import org.bukkit.util.Vector;
+
+public class TNTPrimedController extends MobEntityController {
+ public TNTPrimedController() {
+ super(EntityTNTPrimedNPC.class);
+ }
+
+ @Override
+ public TNTPrimed getBukkitEntity() {
+ return (TNTPrimed) super.getBukkitEntity();
+ }
+
+ public static class EntityTNTPrimedNPC extends EntityTNTPrimed implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityTNTPrimedNPC(World world) {
+ this(world, null);
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ public EntityTNTPrimedNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new TNTPrimedNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.B_();
+ }
+ }
+ }
+
+ public static class TNTPrimedNPC extends CraftTNTPrimed implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public TNTPrimedNPC(EntityTNTPrimedNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/ThrownExpBottleController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/ThrownExpBottleController.java
new file mode 100644
index 000000000..9101246dc
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/ThrownExpBottleController.java
@@ -0,0 +1,118 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftThrownExpBottle;
+import org.bukkit.entity.ThrownExpBottle;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.EntityThrownExpBottle;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+
+public class ThrownExpBottleController extends MobEntityController {
+ public ThrownExpBottleController() {
+ super(EntityThrownExpBottleNPC.class);
+ }
+
+ @Override
+ public ThrownExpBottle getBukkitEntity() {
+ return (ThrownExpBottle) super.getBukkitEntity();
+ }
+
+ public static class EntityThrownExpBottleNPC extends EntityThrownExpBottle implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityThrownExpBottleNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityThrownExpBottleNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new ThrownExpBottleNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true)) {
+ super.B_();
+ }
+ } else {
+ super.B_();
+ }
+ }
+ }
+
+ public static class ThrownExpBottleNPC extends CraftThrownExpBottle implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public ThrownExpBottleNPC(EntityThrownExpBottleNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/ThrownPotionController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/ThrownPotionController.java
new file mode 100644
index 000000000..74d504561
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/ThrownPotionController.java
@@ -0,0 +1,134 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftLingeringPotion;
+import org.bukkit.entity.ThrownPotion;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.EntityPotion;
+import net.minecraft.server.v1_12_R1.Items;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+
+public class ThrownPotionController extends MobEntityController {
+ public ThrownPotionController() {
+ super(EntityThrownPotionNPC.class);
+ }
+
+ @Override
+ public ThrownPotion getBukkitEntity() {
+ return (ThrownPotion) super.getBukkitEntity();
+ }
+
+ public static class EntityThrownPotionNPC extends EntityPotion implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityThrownPotionNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityThrownPotionNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ if (getItem() != null && getItem().getItem().equals(Items.LINGERING_POTION)) {
+ bukkitEntity = new LingeringThrownPotionNPC(this);
+ } else {
+ bukkitEntity = new SplashThrownPotionNPC(this);
+ }
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.B_();
+ }
+ }
+ }
+
+ public static class LingeringThrownPotionNPC extends CraftLingeringPotion implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public LingeringThrownPotionNPC(EntityThrownPotionNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+
+ public static class SplashThrownPotionNPC extends CraftLingeringPotion implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public SplashThrownPotionNPC(EntityThrownPotionNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/TippedArrowController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/TippedArrowController.java
new file mode 100644
index 000000000..94781b781
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/TippedArrowController.java
@@ -0,0 +1,115 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftArrow;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.entity.Arrow;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.EntityTippedArrow;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+
+public class TippedArrowController extends MobEntityController {
+ public TippedArrowController() {
+ super(EntityTippedArrowNPC.class);
+ }
+
+ @Override
+ public Arrow getBukkitEntity() {
+ return (Arrow) super.getBukkitEntity();
+ }
+
+ public static class EntityTippedArrowNPC extends EntityTippedArrow implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityTippedArrowNPC(World world) {
+ this(world, null);
+ }
+
+ public EntityTippedArrowNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new TippedArrowNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.B_();
+ }
+ }
+ }
+
+ public static class TippedArrowNPC extends CraftArrow implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public TippedArrowNPC(EntityTippedArrowNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/WitherSkullController.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/WitherSkullController.java
new file mode 100644
index 000000000..b992fbcd6
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/entity/nonliving/WitherSkullController.java
@@ -0,0 +1,115 @@
+package net.citizensnpcs.nms.v1_12_R1.entity.nonliving;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_12_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.EntityWitherSkull;
+import net.minecraft.server.v1_12_R1.NBTTagCompound;
+import net.minecraft.server.v1_12_R1.World;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftWitherSkull;
+import org.bukkit.entity.WitherSkull;
+import org.bukkit.util.Vector;
+
+public class WitherSkullController extends MobEntityController {
+ public WitherSkullController() {
+ super(EntityWitherSkullNPC.class);
+ }
+
+ @Override
+ public WitherSkull getBukkitEntity() {
+ return (WitherSkull) super.getBukkitEntity();
+ }
+
+ public static class EntityWitherSkullNPC extends EntityWitherSkull implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityWitherSkullNPC(World world) {
+ this(world, null);
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ public EntityWitherSkullNPC(World world, NPC npc) {
+ super(world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_12_R1.Entity entity) {
+ // this method is called by both the entities involved - cancelling
+ // it will not stop the NPC from moving.
+ super.collide(entity);
+ if (npc != null) {
+ Util.callCollisionEvent(npc, entity.getBukkitEntity());
+ }
+ }
+
+ @Override
+ public void f(double x, double y, double z) {
+ if (npc == null) {
+ super.f(x, y, z);
+ return;
+ }
+ if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true))
+ super.f(x, y, z);
+ return;
+ }
+ Vector vector = new Vector(x, y, z);
+ NPCPushEvent event = Util.callPushEvent(npc, vector);
+ if (!event.isCancelled()) {
+ vector = event.getCollisionVector();
+ super.f(vector.getX(), vector.getY(), vector.getZ());
+ }
+ // when another entity collides, this method is called to push the
+ // NPC so we prevent it from doing anything if the event is
+ // cancelled.
+ }
+
+ @Override
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new WitherSkullNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void B_() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.B_();
+ }
+ }
+ }
+
+ public static class WitherSkullNPC extends CraftWitherSkull implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public WitherSkullNPC(EntityWitherSkullNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/network/EmptyChannel.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/network/EmptyChannel.java
new file mode 100644
index 000000000..b79cca589
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/network/EmptyChannel.java
@@ -0,0 +1,80 @@
+package net.citizensnpcs.nms.v1_12_R1.network;
+
+import java.net.SocketAddress;
+
+import io.netty.channel.AbstractChannel;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelConfig;
+import io.netty.channel.ChannelMetadata;
+import io.netty.channel.ChannelOutboundBuffer;
+import io.netty.channel.DefaultChannelConfig;
+import io.netty.channel.EventLoop;
+
+public class EmptyChannel extends AbstractChannel {
+ private final ChannelConfig config = new DefaultChannelConfig(this);
+
+ public EmptyChannel(Channel parent) {
+ super(parent);
+ }
+
+ @Override
+ public ChannelConfig config() {
+ config.setAutoRead(true);
+ return config;
+ }
+
+ @Override
+ protected void doBeginRead() throws Exception {
+ }
+
+ @Override
+ protected void doBind(SocketAddress arg0) throws Exception {
+ }
+
+ @Override
+ protected void doClose() throws Exception {
+ }
+
+ @Override
+ protected void doDisconnect() throws Exception {
+ }
+
+ @Override
+ protected void doWrite(ChannelOutboundBuffer arg0) throws Exception {
+ }
+
+ @Override
+ public boolean isActive() {
+ return false;
+ }
+
+ @Override
+ protected boolean isCompatible(EventLoop arg0) {
+ return true;
+ }
+
+ @Override
+ public boolean isOpen() {
+ return false;
+ }
+
+ @Override
+ protected SocketAddress localAddress0() {
+ return null;
+ }
+
+ @Override
+ public ChannelMetadata metadata() {
+ return new ChannelMetadata(true);
+ }
+
+ @Override
+ protected AbstractUnsafe newUnsafe() {
+ return null;
+ }
+
+ @Override
+ protected SocketAddress remoteAddress0() {
+ return null;
+ }
+}
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/network/EmptyNetHandler.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/network/EmptyNetHandler.java
new file mode 100644
index 000000000..6152d8ca3
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/network/EmptyNetHandler.java
@@ -0,0 +1,17 @@
+package net.citizensnpcs.nms.v1_12_R1.network;
+
+import net.minecraft.server.v1_12_R1.EntityPlayer;
+import net.minecraft.server.v1_12_R1.MinecraftServer;
+import net.minecraft.server.v1_12_R1.NetworkManager;
+import net.minecraft.server.v1_12_R1.Packet;
+import net.minecraft.server.v1_12_R1.PlayerConnection;
+
+public class EmptyNetHandler extends PlayerConnection {
+ public EmptyNetHandler(MinecraftServer minecraftServer, NetworkManager networkManager, EntityPlayer entityPlayer) {
+ super(minecraftServer, networkManager, entityPlayer);
+ }
+
+ @Override
+ public void sendPacket(Packet> packet) {
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/network/EmptyNetworkManager.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/network/EmptyNetworkManager.java
new file mode 100644
index 000000000..d05412f62
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/network/EmptyNetworkManager.java
@@ -0,0 +1,19 @@
+package net.citizensnpcs.nms.v1_12_R1.network;
+
+import java.io.IOException;
+
+import net.citizensnpcs.nms.v1_12_R1.util.NMSImpl;
+import net.minecraft.server.v1_12_R1.EnumProtocolDirection;
+import net.minecraft.server.v1_12_R1.NetworkManager;
+
+public class EmptyNetworkManager extends NetworkManager {
+ public EmptyNetworkManager(EnumProtocolDirection flag) throws IOException {
+ super(flag);
+ NMSImpl.initNetworkManager(this);
+ }
+
+ @Override
+ public boolean isConnected() {
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/network/EmptySocket.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/network/EmptySocket.java
new file mode 100644
index 000000000..89d5ccce5
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/network/EmptySocket.java
@@ -0,0 +1,21 @@
+package net.citizensnpcs.nms.v1_12_R1.network;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+
+public class EmptySocket extends Socket {
+ @Override
+ public InputStream getInputStream() {
+ return new ByteArrayInputStream(EMPTY);
+ }
+
+ @Override
+ public OutputStream getOutputStream() {
+ return new ByteArrayOutputStream(10);
+ }
+
+ private static final byte[] EMPTY = new byte[50];
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/trait/Commands.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/trait/Commands.java
new file mode 100644
index 000000000..1a03a4af0
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/trait/Commands.java
@@ -0,0 +1,47 @@
+package net.citizensnpcs.nms.v1_12_R1.trait;
+
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.EntityType;
+import org.bukkit.entity.Llama.Color;
+
+import net.citizensnpcs.api.command.Command;
+import net.citizensnpcs.api.command.CommandContext;
+import net.citizensnpcs.api.command.Requirements;
+import net.citizensnpcs.api.command.exception.CommandException;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.api.util.Messaging;
+import net.citizensnpcs.util.Messages;
+import net.citizensnpcs.util.Util;
+
+public class Commands {
+ @Command(
+ aliases = { "npc" },
+ usage = "llama (--color color) (--strength strength)",
+ desc = "Sets llama modifiers",
+ modifiers = { "llama" },
+ min = 1,
+ max = 1,
+ permission = "citizens.npc.llama")
+ @Requirements(selected = true, ownership = true, types = EntityType.LLAMA)
+ public void llama(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
+ LlamaTrait trait = npc.getTrait(LlamaTrait.class);
+ String output = "";
+ if (args.hasValueFlag("color") || args.hasValueFlag("colour")) {
+ String colorRaw = args.getFlag("color", args.getFlag("colour"));
+ Color color = Util.matchEnum(Color.values(), colorRaw);
+ if (color == null) {
+ String valid = Util.listValuesPretty(Color.values());
+ throw new CommandException(Messages.INVALID_LLAMA_COLOR, valid);
+ }
+ trait.setColor(color);
+ output += Messaging.tr(Messages.LLAMA_COLOR_SET, Util.prettyEnum(color));
+ }
+ if (args.hasValueFlag("strength")) {
+ trait.setStrength(Math.max(1, Math.min(5, args.getFlagInteger("strength"))));
+ output += Messaging.tr(Messages.LLAMA_STRENGTH_SET, args.getFlagInteger("strength"));
+ }
+ if (!output.isEmpty()) {
+ Messaging.send(sender, output);
+ }
+ }
+}
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/trait/LlamaTrait.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/trait/LlamaTrait.java
new file mode 100644
index 000000000..18029f5b6
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/trait/LlamaTrait.java
@@ -0,0 +1,37 @@
+package net.citizensnpcs.nms.v1_12_R1.trait;
+
+import org.bukkit.entity.Llama;
+import org.bukkit.entity.Llama.Color;
+
+import net.citizensnpcs.api.persistence.Persist;
+import net.citizensnpcs.api.trait.Trait;
+import net.citizensnpcs.api.trait.TraitName;
+
+@TraitName("llamatrait")
+public class LlamaTrait extends Trait {
+ @Persist
+ private Color color = Color.BROWN;
+ @Persist
+ private int strength = 3;
+
+ public LlamaTrait() {
+ super("llamatrait");
+ }
+
+ @Override
+ public void run() {
+ if (npc.isSpawned() && npc.getEntity() instanceof Llama) {
+ Llama llama = (Llama) npc.getEntity();
+ llama.setColor(color);
+ llama.setStrength(strength);
+ }
+ }
+
+ public void setColor(Llama.Color color) {
+ this.color = color;
+ }
+
+ public void setStrength(int strength) {
+ this.strength = strength;
+ }
+}
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/util/CitizensBlockBreaker.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/util/CitizensBlockBreaker.java
new file mode 100644
index 000000000..ae3d250aa
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/util/CitizensBlockBreaker.java
@@ -0,0 +1,173 @@
+package net.citizensnpcs.nms.v1_12_R1.util;
+
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_12_R1.inventory.CraftItemStack;
+import org.bukkit.entity.Player;
+
+import net.citizensnpcs.api.ai.tree.BehaviorStatus;
+import net.citizensnpcs.api.npc.BlockBreaker;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.PlayerAnimation;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_12_R1.BlockPosition;
+import net.minecraft.server.v1_12_R1.Blocks;
+import net.minecraft.server.v1_12_R1.EnchantmentManager;
+import net.minecraft.server.v1_12_R1.Entity;
+import net.minecraft.server.v1_12_R1.EntityLiving;
+import net.minecraft.server.v1_12_R1.EntityPlayer;
+import net.minecraft.server.v1_12_R1.EnumItemSlot;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.ItemStack;
+import net.minecraft.server.v1_12_R1.Material;
+import net.minecraft.server.v1_12_R1.MobEffects;
+
+public class CitizensBlockBreaker extends BlockBreaker {
+ private final BlockBreakerConfiguration configuration;
+ private int currentDamage;
+ private int currentTick;
+ private final Entity entity;
+ private boolean isDigging = true;
+ private final Location location;
+ private int startDigTick;
+ private final int x, y, z;
+
+ public CitizensBlockBreaker(org.bukkit.entity.Entity entity, org.bukkit.block.Block target,
+ BlockBreakerConfiguration config) {
+ this.entity = ((CraftEntity) entity).getHandle();
+ this.x = target.getX();
+ this.y = target.getY();
+ this.z = target.getZ();
+ this.location = target.getLocation();
+ this.startDigTick = (int) (System.currentTimeMillis() / 50);
+ this.configuration = config;
+ }
+
+ private double distanceSquared() {
+ return Math.pow(entity.locX - x, 2) + Math.pow(entity.locY - y, 2) + Math.pow(entity.locZ - z, 2);
+ }
+
+ private net.minecraft.server.v1_12_R1.ItemStack getCurrentItem() {
+ return configuration.item() != null ? CraftItemStack.asNMSCopy(configuration.item())
+ : entity instanceof EntityLiving ? ((EntityLiving) entity).getEquipment(EnumItemSlot.MAINHAND) : null;
+ }
+
+ private float getStrength(IBlockData block) {
+ float base = block.getBlock().a(block, null, new BlockPosition(0, 0, 0));
+ return base < 0.0F ? 0.0F : (!isDestroyable(block) ? 1.0F / base / 100.0F : strengthMod(block) / base / 30.0F);
+ }
+
+ private boolean isDestroyable(IBlockData block) {
+ if (block.getMaterial().isAlwaysDestroyable()) {
+ return true;
+ } else {
+ ItemStack current = getCurrentItem();
+ return current != null ? current.b(block) : false;
+ }
+ }
+
+ @Override
+ public void reset() {
+ if (configuration.callback() != null) {
+ configuration.callback().run();
+ }
+ isDigging = false;
+ setBlockDamage(currentDamage = -1);
+ }
+
+ @Override
+ public BehaviorStatus run() {
+ if (entity.dead) {
+ return BehaviorStatus.FAILURE;
+ }
+ if (!isDigging) {
+ return BehaviorStatus.SUCCESS;
+ }
+ currentTick = (int) (System.currentTimeMillis() / 50); // CraftBukkit
+ if (configuration.radiusSquared() > 0 && distanceSquared() >= configuration.radiusSquared()) {
+ startDigTick = currentTick;
+ if (entity instanceof NPCHolder) {
+ NPC npc = ((NPCHolder) entity).getNPC();
+ if (npc != null && !npc.getNavigator().isNavigating()) {
+ npc.getNavigator()
+ .setTarget(entity.world.getWorld().getBlockAt(x, y, z).getLocation().add(0, 1, 0));
+ }
+ }
+ return BehaviorStatus.RUNNING;
+ }
+ Util.faceLocation(entity.getBukkitEntity(), location);
+ if (entity instanceof EntityPlayer) {
+ PlayerAnimation.ARM_SWING.play((Player) entity.getBukkitEntity());
+ }
+ IBlockData block = entity.world.getType(new BlockPosition(x, y, z));
+ if (block == null || block == Blocks.AIR) {
+ return BehaviorStatus.SUCCESS;
+ } else {
+ int tickDifference = currentTick - startDigTick;
+ float damage = getStrength(block) * (tickDifference + 1) * configuration.blockStrengthModifier();
+ if (damage >= 1F) {
+ entity.world.getWorld().getBlockAt(x, y, z)
+ .breakNaturally(CraftItemStack.asCraftMirror(getCurrentItem()));
+ return BehaviorStatus.SUCCESS;
+ }
+ int modifiedDamage = (int) (damage * 10.0F);
+ if (modifiedDamage != currentDamage) {
+ setBlockDamage(modifiedDamage);
+ currentDamage = modifiedDamage;
+ }
+ }
+ return BehaviorStatus.RUNNING;
+ }
+
+ private void setBlockDamage(int modifiedDamage) {
+ entity.world.c(entity.getId(), new BlockPosition(x, y, z), modifiedDamage);
+ }
+
+ @Override
+ public boolean shouldExecute() {
+ return entity.world.getType(new BlockPosition(x, y, z)).getBlock() != Blocks.AIR;
+ }
+
+ private float strengthMod(IBlockData block) {
+ ItemStack itemstack = getCurrentItem();
+ float f = itemstack.a(block);
+ if (entity instanceof EntityLiving) {
+ EntityLiving handle = (EntityLiving) entity;
+ if (f > 1.0F) {
+ int i = EnchantmentManager.getDigSpeedEnchantmentLevel(handle);
+ if (i > 0) {
+ f += i * i + 1;
+ }
+ }
+ if (handle.hasEffect(MobEffects.FASTER_DIG)) {
+ f *= (1.0F + (handle.getEffect(MobEffects.FASTER_DIG).getAmplifier() + 1) * 0.2F);
+ }
+ if (handle.hasEffect(MobEffects.SLOWER_DIG)) {
+ float f1 = 1.0F;
+ switch (handle.getEffect(MobEffects.SLOWER_DIG).getAmplifier()) {
+ case 0:
+ f1 = 0.3F;
+ break;
+ case 1:
+ f1 = 0.09F;
+ break;
+ case 2:
+ f1 = 0.0027F;
+ break;
+ case 3:
+ default:
+ f1 = 8.1E-4F;
+ }
+ f *= f1;
+ }
+ if ((handle.a(Material.WATER)) && (!EnchantmentManager.i(handle))) {
+ f /= 5.0F;
+ }
+ }
+ if (!entity.onGround) {
+ f /= 5.0F;
+ }
+ return f;
+ }
+}
\ No newline at end of file
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/util/CustomEntityRegistry.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/util/CustomEntityRegistry.java
new file mode 100644
index 000000000..ee687b477
--- /dev/null
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/util/CustomEntityRegistry.java
@@ -0,0 +1,92 @@
+package net.citizensnpcs.nms.v1_12_R1.util;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+import com.google.common.collect.Maps;
+
+import net.minecraft.server.v1_12_R1.Entity;
+import net.minecraft.server.v1_12_R1.MinecraftKey;
+import net.minecraft.server.v1_12_R1.RegistryMaterials;
+
+@SuppressWarnings("rawtypes")
+public class CustomEntityRegistry extends RegistryMaterials {
+ private final BiMap> entities = HashBiMap.create();
+ private final BiMap, MinecraftKey> entityClasses = this.entities.inverse();
+ private final Map, Integer> entityIds = Maps.newHashMap();
+ private final RegistryMaterials> wrapped;
+
+ public CustomEntityRegistry(RegistryMaterials> original) {
+ this.wrapped = original;
+ }
+
+ @Override
+ public void a(int code, Object key, Object v) {
+ put(code, (MinecraftKey) key, (Class extends Entity>) v);
+ }
+
+ @Override
+ public int a(Object key) {
+ if (entityIds.containsKey(key)) {
+ return entityIds.get(key);
+ }
+
+ return wrapped.a((Class extends Entity>) key);
+ }
+
+ @Override
+ public Object a(Random paramRandom) {
+ return wrapped.a(paramRandom);
+ }
+
+ @Override
+ public MinecraftKey b(Object value) {
+ if (entityClasses.containsKey(value)) {
+ return entityClasses.get(value);
+ }
+
+ return wrapped.b((Class extends Entity>) value);
+ }
+
+ @Override
+ public boolean d(Object paramK) {
+ return wrapped.d((MinecraftKey) paramK);
+ }
+
+ @Override
+ public Class extends Entity> get(Object key) {
+ if (entities.containsKey(key)) {
+ return entities.get(key);
+ }
+
+ return wrapped.get((MinecraftKey) key);
+ }
+
+ @Override
+ public Object getId(int paramInt) {
+ return wrapped.getId(paramInt);
+ }
+
+ public RegistryMaterials> getWrapped() {
+ return wrapped;
+ }
+
+ @Override
+ public Iterator