diff --git a/dist/pom.xml b/dist/pom.xml
index d5b285a40..b74e14cbe 100644
--- a/dist/pom.xml
+++ b/dist/pom.xml
@@ -4,7 +4,7 @@
net.citizensnpcs
citizens-parent
- 2.0.24-SNAPSHOT
+ 2.0.25-SNAPSHOT
citizens
pom
@@ -78,6 +78,13 @@
${project.version}
jar
compile
+
+
+ ${project.groupId}
+ citizens-v1_14_R1
+ ${project.version}
+ jar
+ compile
\ No newline at end of file
diff --git a/main/pom.xml b/main/pom.xml
index 57b4d80d9..6d13a2948 100644
--- a/main/pom.xml
+++ b/main/pom.xml
@@ -6,13 +6,13 @@
net.citizensnpcs
citizens-parent
- 2.0.24-SNAPSHOT
+ 2.0.25-SNAPSHOT
citizens-main
UTF-8
- 1.13.2-R0.1-SNAPSHOT
+ 1.14-pre5-SNAPSHOT
${project.version}
1.4.12
1.4
diff --git a/main/src/main/java/net/citizensnpcs/commands/NPCCommands.java b/main/src/main/java/net/citizensnpcs/commands/NPCCommands.java
index 58cf5a183..d2ab88967 100644
--- a/main/src/main/java/net/citizensnpcs/commands/NPCCommands.java
+++ b/main/src/main/java/net/citizensnpcs/commands/NPCCommands.java
@@ -8,7 +8,6 @@ import java.util.Comparator;
import java.util.List;
import java.util.UUID;
-import org.apache.commons.lang3.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.DyeColor;
@@ -1269,7 +1268,7 @@ public class NPCCommands {
Profession parsed = Util.matchEnum(Profession.values(), profession.toUpperCase());
if (parsed == null) {
throw new CommandException(Messages.INVALID_PROFESSION, args.getString(1),
- StringUtils.join(Profession.values(), ","));
+ Joiner.on(',').join(Profession.values()));
}
npc.getTrait(VillagerProfession.class).setProfession(parsed);
Messaging.sendTr(sender, Messages.PROFESSION_SET, npc.getName(), profession);
@@ -1288,7 +1287,7 @@ public class NPCCommands {
try {
type = Rabbit.Type.valueOf(args.getString(1).toUpperCase());
} catch (IllegalArgumentException ex) {
- throw new CommandException(Messages.INVALID_RABBIT_TYPE, StringUtils.join(Rabbit.Type.values(), ","));
+ throw new CommandException(Messages.INVALID_RABBIT_TYPE, Joiner.on(',').join(Rabbit.Type.values()));
}
npc.getTrait(RabbitType.class).setType(type);
Messaging.sendTr(sender, Messages.RABBIT_TYPE_SET, npc.getName(), type.name());
diff --git a/main/src/main/java/net/citizensnpcs/util/Messages.java b/main/src/main/java/net/citizensnpcs/util/Messages.java
index 50f2aaa57..8505b6947 100644
--- a/main/src/main/java/net/citizensnpcs/util/Messages.java
+++ b/main/src/main/java/net/citizensnpcs/util/Messages.java
@@ -21,6 +21,9 @@ public class Messages {
public static final String BEHAVIOURS_ADDED = "citizens.commands.npc.behaviour.added";
public static final String BEHAVIOURS_REMOVED = "citizens.commands.npc.behaviour.removed";
public static final String CANNOT_TELEPORT_ACROSS_WORLDS = "citizens.commands.npc.tphere.multiworld-not-allowed";
+ public static final String CAT_STARTED_SITTING = "citizens.commands.npc.cat.sitting-start";
+ public static final String CAT_STOPPED_SITTING = "citizens.commands.npc.cat.sitting-stop";
+ public static final String CAT_TYPE_SET = "citizens.commands.npc.cat.type-set";
public static final String CHAT_TRIGGER_PROMPT = "citizens.editors.waypoints.triggers.chat.prompt";
public static final String CITIZENS_IMPLEMENTATION_DISABLED = "citizens.changed-implementation";
public static final String CITIZENS_INCOMPATIBLE = "citizens.notifications.incompatible-version";
@@ -106,12 +109,14 @@ public class Messages {
public static final String INVALID_AGE = "citizens.commands.npc.age.invalid-age";
public static final String INVALID_ANCHOR_NAME = "citizens.commands.npc.anchor.invalid-name";
public static final String INVALID_ANIMATION = "citizens.editors.waypoints.triggers.animation.invalid-animation";
+ public static final String INVALID_CAT_TYPE = "citizens.commands.npc.cat.invalid-type";
public static final String INVALID_ENTITY_TYPE = "citizens.commands.npc.type.invalid";
public static final String INVALID_HORSE_COLOR = "citizens.commands.npc.horse.invalid-color";
public static final String INVALID_HORSE_STYLE = "citizens.commands.npc.horse.invalid-style";
public static final String INVALID_HORSE_VARIANT = "citizens.commands.npc.horse.invalid-variant";
public static final String INVALID_LLAMA_COLOR = "citizens.commands.npc.llama.invalid-color";
public static final String INVALID_OCELOT_TYPE = "citizens.commands.npc.ocelot.invalid-type";
+ public static final String INVALID_PANDA_GENE = "citizens.commands.npc.panda.invalid-gene";
public static final String INVALID_PARROT_VARIANT = "citizens.commands.npc.parrot.invalid-variant";
public static final String INVALID_POSE_NAME = "citizens.commands.npc.pose.invalid-name";
public static final String INVALID_PROFESSION = "citizens.commands.npc.profession.invalid-profession";
@@ -181,6 +186,8 @@ public class Messages {
public static final String OVER_NPC_LIMIT = "citizens.limits.over-npc-limit";
public static final String OWNER_SET = "citizens.commands.npc.owner.set";
public static final String OWNER_SET_SERVER = "citizens.commands.npc.owner.set-server";
+ public static final String PANDA_HIDDEN_GENE_SET = "citizens.commands.npc.panda.hidden-gene-set";
+ public static final String PANDA_MAIN_GENE_SET = "citizens.commands.npc.panda.main-gene-set";
public static final String PARROT_VARIANT_SET = "citizens.commands.npc.parrot.variant-set";
public static final String PASSIVE_SET = "citizens.commands.npc.passive.set";
public static final String PASSIVE_UNSET = "citizens.commands.npc.passive.unset";
diff --git a/main/src/main/java/net/citizensnpcs/util/NMS.java b/main/src/main/java/net/citizensnpcs/util/NMS.java
index 1fae632b8..aae87e905 100644
--- a/main/src/main/java/net/citizensnpcs/util/NMS.java
+++ b/main/src/main/java/net/citizensnpcs/util/NMS.java
@@ -11,6 +11,7 @@ import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.FishHook;
import org.bukkit.entity.LivingEntity;
+import org.bukkit.entity.Ocelot;
import org.bukkit.entity.Player;
import org.bukkit.entity.Tameable;
import org.bukkit.entity.Wither;
@@ -294,6 +295,10 @@ public class NMS {
BRIDGE.setShouldJump(entity);
}
+ public static void setSitting(Ocelot ocelot, boolean sitting) {
+ BRIDGE.setSitting(ocelot, sitting);
+ }
+
public static void setSitting(Tameable tameable, boolean sitting) {
BRIDGE.setSitting(tameable, sitting);
}
diff --git a/main/src/main/java/net/citizensnpcs/util/NMSBridge.java b/main/src/main/java/net/citizensnpcs/util/NMSBridge.java
index c994cb28e..d3b7b2182 100644
--- a/main/src/main/java/net/citizensnpcs/util/NMSBridge.java
+++ b/main/src/main/java/net/citizensnpcs/util/NMSBridge.java
@@ -9,6 +9,7 @@ import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.FishHook;
import org.bukkit.entity.LivingEntity;
+import org.bukkit.entity.Ocelot;
import org.bukkit.entity.Player;
import org.bukkit.entity.Tameable;
import org.bukkit.entity.Wither;
@@ -125,6 +126,8 @@ public interface NMSBridge {
public void setShouldJump(Entity entity);
+ public void setSitting(Ocelot ocelot, boolean sitting);
+
public void setSitting(Tameable tameable, boolean sitting);
public void setStepHeight(Entity entity, float height);
diff --git a/main/src/main/resources/messages_en.properties b/main/src/main/resources/messages_en.properties
index 1d9949939..33387b2f9 100644
--- a/main/src/main/resources/messages_en.properties
+++ b/main/src/main/resources/messages_en.properties
@@ -25,6 +25,10 @@ citizens.commands.npc.anchor.removed=Anchor removed.
citizens.commands.npc.behaviour.added=Behaviours added.
citizens.commands.npc.behaviour.help=The scripts argument is a comma-separated list of file names. Scripts will be loaded automatically and run every tick. Use the [[-r]] flag to remove behaviours.
citizens.commands.npc.behaviour.removed=Behaviours removed.
+citizens.commands.npc.cat.invalid-type=Invalid type specified. Valid types are [[{0}]].
+citizens.commands.npc.cat.sitting-start=[[{0}]] started sitting.
+citizens.commands.npc.cat.sitting-stop=[[{0}]] stopped sitting.
+citizens.commands.npc.cat.type-set=Type set to [[{0}]].
citizens.commands.npc.collidable.set=[[{0}]] will now collide with entities.
citizens.commands.npc.collidable.unset=[[{0}]] will no longer collide with entities.
citizens.commands.npc.controllable.not-controllable=[[{0}]] is not controllable.
@@ -82,6 +86,9 @@ citizens.commands.npc.owner.already-owner={0} is already the owner of [[{1}]].
citizens.commands.npc.owner.owner=[[{0}]]''s owner is [[{1}]].
citizens.commands.npc.owner.set-server=[[The server]] is now the owner of [[{0}]].
citizens.commands.npc.owner.set=[[{1}]] is now the owner of [[{0}]].
+citizens.commands.npc.panda.invalid-gene=Invalid gene. Valid genes are [[{0}]].
+citizens.commands.npc.panda.main-gene-set=Main gene set to [[{0}]].
+citizens.commands.npc.panda.hidden-gene-set=Hidden gene set to [[{0}]].
citizens.commands.npc.passive.set=[[{0}]] will no longer damage entities.
citizens.commands.npc.passive.unset=[[{0}]] will now damage entities.
citizens.commands.npc.pathfindingrange.set=Pathfinding range set to [[{0}]].
diff --git a/main/src/main/resources/plugin.yml b/main/src/main/resources/plugin.yml
index 013d1ae7e..292c5975d 100644
--- a/main/src/main/resources/plugin.yml
+++ b/main/src/main/resources/plugin.yml
@@ -4,7 +4,7 @@ softdepend: [Vault]
version: ${project.version} (build ${BUILD_NUMBER})
main: net.citizensnpcs.Citizens
website: http://www.citizensnpcs.co
-api-version: "1.13"
+api-version: "1.14"
commands:
traitc:
aliases: [trc]
diff --git a/pom.xml b/pom.xml
index 49858900a..30247158f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,10 +7,10 @@
pom
net.citizensnpcs
citizens-parent
- 2.0.24-SNAPSHOT
+ 2.0.25-SNAPSHOT
Unknown
- 2.0.24
+ 2.0.25
clean package install
@@ -22,6 +22,7 @@
v1_11_R1
v1_12_R1
v1_13_R2
+ v1_14_R1
dist
\ No newline at end of file
diff --git a/v1_10_R1/pom.xml b/v1_10_R1/pom.xml
index a371b7910..ced3f0fa5 100644
--- a/v1_10_R1/pom.xml
+++ b/v1_10_R1/pom.xml
@@ -5,7 +5,7 @@
net.citizensnpcs
citizens-parent
- 2.0.24-SNAPSHOT
+ 2.0.25-SNAPSHOT
citizens-v1_10_R1
diff --git a/v1_10_R1/src/main/java/net/citizensnpcs/nms/v1_10_R1/util/NMSImpl.java b/v1_10_R1/src/main/java/net/citizensnpcs/nms/v1_10_R1/util/NMSImpl.java
index 095b9fe9b..dcf6969ed 100644
--- a/v1_10_R1/src/main/java/net/citizensnpcs/nms/v1_10_R1/util/NMSImpl.java
+++ b/v1_10_R1/src/main/java/net/citizensnpcs/nms/v1_10_R1/util/NMSImpl.java
@@ -34,6 +34,7 @@ import org.bukkit.craftbukkit.v1_10_R1.event.CraftEventFactory;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.FishHook;
import org.bukkit.entity.LivingEntity;
+import org.bukkit.entity.Ocelot;
import org.bukkit.entity.Player;
import org.bukkit.entity.Shulker;
import org.bukkit.entity.Tameable;
@@ -882,6 +883,11 @@ public class NMSImpl implements NMSBridge {
}
}
+ @Override
+ public void setSitting(Ocelot ocelot, boolean sitting) {
+ setSitting((Tameable) ocelot, sitting);
+ }
+
@Override
public void setSitting(Tameable tameable, boolean sitting) {
((EntityTameableAnimal) NMSImpl.getHandle((LivingEntity) tameable)).setSitting(sitting);
diff --git a/v1_11_R1/pom.xml b/v1_11_R1/pom.xml
index 3330c6de4..83814931c 100644
--- a/v1_11_R1/pom.xml
+++ b/v1_11_R1/pom.xml
@@ -5,7 +5,7 @@
net.citizensnpcs
citizens-parent
- 2.0.24-SNAPSHOT
+ 2.0.25-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 96855483b..ab5bea7ee 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
@@ -34,6 +34,7 @@ import org.bukkit.craftbukkit.v1_11_R1.event.CraftEventFactory;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.FishHook;
import org.bukkit.entity.LivingEntity;
+import org.bukkit.entity.Ocelot;
import org.bukkit.entity.Player;
import org.bukkit.entity.Shulker;
import org.bukkit.entity.Tameable;
@@ -941,6 +942,11 @@ public class NMSImpl implements NMSBridge {
}
}
+ @Override
+ public void setSitting(Ocelot ocelot, boolean sitting) {
+ setSitting((Tameable) ocelot, sitting);
+ }
+
@Override
public void setSitting(Tameable tameable, boolean sitting) {
((EntityTameableAnimal) NMSImpl.getHandle((LivingEntity) tameable)).setSitting(sitting);
diff --git a/v1_12_R1/pom.xml b/v1_12_R1/pom.xml
index eb0a0c394..b97043720 100644
--- a/v1_12_R1/pom.xml
+++ b/v1_12_R1/pom.xml
@@ -5,7 +5,7 @@
net.citizensnpcs
citizens-parent
- 2.0.24-SNAPSHOT
+ 2.0.25-SNAPSHOT
citizens-v1_12_R1
diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/util/NMSImpl.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/util/NMSImpl.java
index 6542db6f1..e52310362 100644
--- a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/util/NMSImpl.java
+++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/util/NMSImpl.java
@@ -34,6 +34,7 @@ import org.bukkit.craftbukkit.v1_12_R1.event.CraftEventFactory;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.FishHook;
import org.bukkit.entity.LivingEntity;
+import org.bukkit.entity.Ocelot;
import org.bukkit.entity.Player;
import org.bukkit.entity.Shulker;
import org.bukkit.entity.Tameable;
@@ -955,6 +956,11 @@ public class NMSImpl implements NMSBridge {
}
}
+ @Override
+ public void setSitting(Ocelot ocelot, boolean sitting) {
+ setSitting((Tameable) ocelot, sitting);
+ }
+
@Override
public void setSitting(Tameable tameable, boolean sitting) {
((EntityTameableAnimal) NMSImpl.getHandle((LivingEntity) tameable)).setSitting(sitting);
diff --git a/v1_13_R2/pom.xml b/v1_13_R2/pom.xml
index 00c192c87..06b974828 100644
--- a/v1_13_R2/pom.xml
+++ b/v1_13_R2/pom.xml
@@ -5,7 +5,7 @@
net.citizensnpcs
citizens-parent
- 2.0.24-SNAPSHOT
+ 2.0.25-SNAPSHOT
citizens-v1_13_R2
diff --git a/v1_13_R2/src/main/java/net/citizensnpcs/nms/v1_13_R2/entity/EntityHumanNPC.java b/v1_13_R2/src/main/java/net/citizensnpcs/nms/v1_13_R2/entity/EntityHumanNPC.java
index d67c15377..7a9d0780c 100644
--- a/v1_13_R2/src/main/java/net/citizensnpcs/nms/v1_13_R2/entity/EntityHumanNPC.java
+++ b/v1_13_R2/src/main/java/net/citizensnpcs/nms/v1_13_R2/entity/EntityHumanNPC.java
@@ -332,7 +332,7 @@ public class EntityHumanNPC extends EntityPlayer implements NPCHolder, Skinnable
private void moveOnCurrentHeading() {
if (bg) {
if (onGround && jumpTicks == 0) {
- cG();
+ cH();
jumpTicks = 10;
}
} else {
diff --git a/v1_13_R2/src/main/java/net/citizensnpcs/nms/v1_13_R2/entity/RabbitController.java b/v1_13_R2/src/main/java/net/citizensnpcs/nms/v1_13_R2/entity/RabbitController.java
index 2164c30db..9e42d8502 100644
--- a/v1_13_R2/src/main/java/net/citizensnpcs/nms/v1_13_R2/entity/RabbitController.java
+++ b/v1_13_R2/src/main/java/net/citizensnpcs/nms/v1_13_R2/entity/RabbitController.java
@@ -190,7 +190,9 @@ public class RabbitController extends MobEntityController {
public void mobTick() {
if (npc != null) {
super.mobTick();
- NMS.setShouldJump(getBukkitEntity());
+ if (npc.getNavigator().isNavigating()) {
+ NMS.setShouldJump(getBukkitEntity());
+ }
npc.update();
} else {
super.mobTick();
diff --git a/v1_13_R2/src/main/java/net/citizensnpcs/nms/v1_13_R2/util/NMSImpl.java b/v1_13_R2/src/main/java/net/citizensnpcs/nms/v1_13_R2/util/NMSImpl.java
index a88be6562..42533bd87 100644
--- a/v1_13_R2/src/main/java/net/citizensnpcs/nms/v1_13_R2/util/NMSImpl.java
+++ b/v1_13_R2/src/main/java/net/citizensnpcs/nms/v1_13_R2/util/NMSImpl.java
@@ -34,6 +34,7 @@ import org.bukkit.craftbukkit.v1_13_R2.event.CraftEventFactory;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.FishHook;
import org.bukkit.entity.LivingEntity;
+import org.bukkit.entity.Ocelot;
import org.bukkit.entity.Player;
import org.bukkit.entity.Shulker;
import org.bukkit.entity.Tameable;
@@ -981,6 +982,11 @@ public class NMSImpl implements NMSBridge {
}
}
+ @Override
+ public void setSitting(Ocelot ocelot, boolean sitting) {
+ setSitting((Tameable) ocelot, sitting);
+ }
+
@Override
public void setSitting(Tameable tameable, boolean sitting) {
((EntityTameableAnimal) NMSImpl.getHandle((LivingEntity) tameable)).setSitting(sitting);
@@ -988,7 +994,7 @@ public class NMSImpl implements NMSBridge {
@Override
public void setStepHeight(org.bukkit.entity.Entity entity, float height) {
- NMSImpl.getHandle(entity).P = height;
+ NMSImpl.getHandle(entity).Q = height;
}
@Override
@@ -1002,7 +1008,7 @@ public class NMSImpl implements NMSBridge {
@Override
public void setWitherCharged(Wither wither, boolean charged) {
EntityWither handle = ((CraftWither) wither).getHandle();
- handle.g(charged ? 20 : 0);
+ handle.d(charged ? 20 : 0);
}
@Override
@@ -1320,7 +1326,8 @@ public class NMSImpl implements NMSBridge {
} else {
float f9 = 0.91F;
BoundingBox bb = NMSBoundingBox.wrap(entity.getBoundingBox());
- BlockPosition.PooledBlockPosition blockposition_b = BlockPosition.PooledBlockPosition.d(entity.locX, bb.minY - 1.0D, entity.locZ);
+ BlockPosition.PooledBlockPosition blockposition_b = BlockPosition.PooledBlockPosition.d(entity.locX,
+ bb.minY - 1.0D, entity.locZ);
Throwable throwable = null;
float f4;
float f3;
@@ -1407,7 +1414,8 @@ public class NMSImpl implements NMSBridge {
entity.aK += entity.aJ;
}
- private static BlockPosition.PooledBlockPosition getBlockPositionBE(BlockPosition.PooledBlockPosition blockPos, double x, double y, double z) {
+ private static BlockPosition.PooledBlockPosition getBlockPositionBE(BlockPosition.PooledBlockPosition blockPos,
+ double x, double y, double z) {
try {
return blockPos.c(x, y, z);
} catch (NoSuchMethodError ex) {
@@ -1596,7 +1604,7 @@ public class NMSImpl implements NMSBridge {
public static void stopNavigation(NavigationAbstract navigation) {
navigation.q();
- }
+ };
public static void updateAI(EntityLiving entity) {
if (entity instanceof EntityInsentient) {
@@ -1609,7 +1617,7 @@ public class NMSImpl implements NMSBridge {
} else if (entity instanceof EntityHumanNPC) {
((EntityHumanNPC) entity).updateAI();
}
- };
+ }
public static void updateNavigation(NavigationAbstract navigation) {
navigation.d();
@@ -1619,8 +1627,8 @@ public class NMSImpl implements NMSBridge {
private static final Set BAD_CONTROLLER_LOOK = EnumSet.of(EntityType.POLAR_BEAR, EntityType.SILVERFISH,
EntityType.SHULKER, EntityType.ENDERMITE, EntityType.ENDER_DRAGON, EntityType.BAT, EntityType.SLIME,
EntityType.MAGMA_CUBE, EntityType.HORSE, EntityType.GHAST);
- private static final Method BLOCK_POSITION_B_D = NMS.getMethod(BlockPosition.PooledBlockPosition.class, "e", false, double.class,
- double.class, double.class);
+ private static final Method BLOCK_POSITION_B_D = NMS.getMethod(BlockPosition.PooledBlockPosition.class, "e", false,
+ double.class, double.class, double.class);
private static final Field CRAFT_BOSSBAR_HANDLE_FIELD = NMS.getField(CraftBossBar.class, "handle");
private static final float DEFAULT_SPEED = 1F;
private static final Field ENDERDRAGON_BATTLE_BAR_FIELD = NMS.getField(EnderDragonBattle.class, "c", false);
diff --git a/v1_13_R2/src/main/java/net/citizensnpcs/nms/v1_13_R2/util/PlayerControllerMove.java b/v1_13_R2/src/main/java/net/citizensnpcs/nms/v1_13_R2/util/PlayerControllerMove.java
index af1c0e141..3f5959b22 100644
--- a/v1_13_R2/src/main/java/net/citizensnpcs/nms/v1_13_R2/util/PlayerControllerMove.java
+++ b/v1_13_R2/src/main/java/net/citizensnpcs/nms/v1_13_R2/util/PlayerControllerMove.java
@@ -43,7 +43,7 @@ public class PlayerControllerMove extends ControllerMove {
double d2 = this.c - i;
double d3 = d0 * d0 + d2 * d2 + d1 * d1;
if (d3 < 2.500000277905201E-007D) {
- this.a.bi = (0.0F);
+ this.a.bj = (0.0F); // bi
return;
}
float f = (float) Math.toDegrees(Math.atan2(d1, d0)) - 90.0F;
diff --git a/v1_14_R1/pom.xml b/v1_14_R1/pom.xml
new file mode 100644
index 000000000..d74a93bbc
--- /dev/null
+++ b/v1_14_R1/pom.xml
@@ -0,0 +1,77 @@
+
+
+ 4.0.0
+
+ net.citizensnpcs
+ citizens-parent
+ 2.0.25-SNAPSHOT
+
+ citizens-v1_14_R1
+
+
+ UTF-8
+ 1.14-pre5-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.8
+
+
+
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/BatController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/BatController.java
new file mode 100644
index 000000000..6a13dd261
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/BatController.java
@@ -0,0 +1,179 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import net.minecraft.server.v1_14_R1.Vec3D;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftBat;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityBat;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityBat> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityBatNPC(EntityTypes extends EntityBat> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ setFlying(false);
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean d(NBTTagCompound save) {
+ return npc == null ? super.d(save) : false;
+ }
+
+ @Override
+ public SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new BatNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @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 void mobTick() {
+ if (npc == null) {
+ super.mobTick();
+ } else {
+ NMSImpl.updateAI(this);
+ npc.update();
+ }
+ }
+
+ public void setFlying(boolean flying) {
+ setAsleep(flying);
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/BlazeController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/BlazeController.java
new file mode 100644
index 000000000..4d1e8b0fc
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/BlazeController.java
@@ -0,0 +1,170 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import net.minecraft.server.v1_14_R1.Vec3D;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftBlaze;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityBlaze;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityBlaze> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityBlazeNPC(EntityTypes extends EntityBlaze> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new BlazeNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @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 void mobTick() {
+ if (npc != null) {
+ npc.update();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/CatController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/CatController.java
new file mode 100644
index 000000000..3bf068af6
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/CatController.java
@@ -0,0 +1,217 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftCat;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.entity.Cat;
+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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.DataWatcherObject;
+import net.minecraft.server.v1_14_R1.EntityCat;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_R1.World;
+
+public class CatController extends MobEntityController {
+ public CatController() {
+ super(EntityCatNPC.class);
+ }
+
+ @Override
+ public Cat getBukkitEntity() {
+ return (Cat) super.getBukkitEntity();
+ }
+
+ public static class CatNPC extends CraftCat implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public CatNPC(EntityCatNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+
+ public static class EntityCatNPC extends EntityCat implements NPCHolder {
+ boolean calledNMSHeight = false;
+ private final CitizensNPC npc;
+
+ public EntityCatNPC(EntityTypes extends EntityCat> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityCatNPC(EntityTypes extends EntityCat> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+
+ }
+ }
+
+ @Override
+ public void a(DataWatcherObject> datawatcherobject) {
+ if (npc != null && !calledNMSHeight) {
+ calledNMSHeight = true;
+ NMSImpl.checkAndUpdateHeight(this, datawatcherobject);
+ calledNMSHeight = false;
+ }
+ super.a(datawatcherobject);
+ }
+
+ @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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new CatNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/CaveSpiderController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/CaveSpiderController.java
new file mode 100644
index 000000000..322233619
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/CaveSpiderController.java
@@ -0,0 +1,215 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftCaveSpider;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityCaveSpider;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityCaveSpider> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityCaveSpiderNPC(EntityTypes extends EntityCaveSpider> types, World world, NPC npc) {
+ super(types, 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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new CaveSpiderNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public void updateSize() {
+ if (npc == null) {
+ super.updateSize();
+ } else {
+ NMSImpl.setSize(this, justCreated);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/ChickenController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/ChickenController.java
new file mode 100644
index 000000000..f1931b759
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/ChickenController.java
@@ -0,0 +1,239 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import java.lang.reflect.Method;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftChicken;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.NMS;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.DataWatcherObject;
+import net.minecraft.server.v1_14_R1.EntityChicken;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_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 {
+ boolean calledNMSHeight = false;
+
+ private final CitizensNPC npc;
+
+ public EntityChickenNPC(EntityTypes extends EntityChicken> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityChickenNPC(EntityTypes extends EntityChicken> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ public void a(DataWatcherObject> datawatcherobject) {
+ if (npc != null && !calledNMSHeight) {
+ calledNMSHeight = true;
+ NMSImpl.checkAndUpdateHeight(this, datawatcherobject);
+ calledNMSHeight = false;
+ }
+
+ super.a(datawatcherobject);
+ }
+
+ @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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new ChickenNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public void movementTick() {
+ if (npc != null) {
+ this.eggLayTime = 100; // egg timer
+ }
+ try {
+ super.movementTick();
+ } catch (NoSuchMethodError ex) {
+ try {
+ MOVEMENT_TICK.invoke(this);
+ } catch (Throwable ex2) {
+ ex2.printStackTrace();
+ }
+ }
+ }
+
+ private static final Method MOVEMENT_TICK = NMS.getMethod(EntityChicken.class, "k", false);
+ }
+}
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/CodController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/CodController.java
new file mode 100644
index 000000000..1169303f1
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/CodController.java
@@ -0,0 +1,208 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import net.minecraft.server.v1_14_R1.Vec3D;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftCod;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.entity.Cod;
+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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.ControllerMove;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityCod;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.World;
+
+public class CodController extends MobEntityController {
+ public CodController() {
+ super(EntityCodNPC.class);
+ }
+
+ @Override
+ public Cod getBukkitEntity() {
+ return (Cod) super.getBukkitEntity();
+ }
+
+ public static class CodNPC extends CraftCod implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public CodNPC(EntityCodNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+
+ public static class EntityCodNPC extends EntityCod implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityCodNPC(EntityTypes extends EntityCod> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityCodNPC(EntityTypes extends EntityCod> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ this.moveController = new ControllerMove(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 e(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void b(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new CodNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @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 void mobTick() {
+ if (npc != null) {
+ NMSImpl.setNotInSchool(this);
+ }
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/CowController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/CowController.java
new file mode 100644
index 000000000..f6fd55c59
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/CowController.java
@@ -0,0 +1,217 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftCow;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.DataWatcherObject;
+import net.minecraft.server.v1_14_R1.EntityCow;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_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 {
+ boolean calledNMSHeight = false;
+ private final CitizensNPC npc;
+
+ public EntityCowNPC(EntityTypes extends EntityCow> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityCowNPC(EntityTypes extends EntityCow> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+
+ }
+ }
+
+ @Override
+ public void a(DataWatcherObject> datawatcherobject) {
+ if (npc != null && !calledNMSHeight) {
+ calledNMSHeight = true;
+ NMSImpl.checkAndUpdateHeight(this, datawatcherobject);
+ calledNMSHeight = false;
+ }
+ super.a(datawatcherobject);
+ }
+
+ @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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new CowNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/CreeperController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/CreeperController.java
new file mode 100644
index 000000000..d3ca55a7c
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/CreeperController.java
@@ -0,0 +1,226 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftCreeper;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityCreeper;
+import net.minecraft.server.v1_14_R1.EntityLightning;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityCreeper> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityCreeperNPC(EntityTypes extends EntityCreeper> types, World world, NPC npc) {
+ super(types, 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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new CreeperNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public void onLightningStrike(EntityLightning entitylightning) {
+ if (npc == null || allowPowered) {
+ super.onLightningStrike(entitylightning);
+ }
+ }
+
+ public void setAllowPowered(boolean allowPowered) {
+ this.allowPowered = allowPowered;
+ }
+
+ @Override
+ public void updateSize() {
+ if (npc == null) {
+ super.updateSize();
+ } else {
+ NMSImpl.setSize(this, justCreated);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/DolphinController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/DolphinController.java
new file mode 100644
index 000000000..d65efdc93
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/DolphinController.java
@@ -0,0 +1,204 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import net.minecraft.server.v1_14_R1.Vec3D;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftDolphin;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.entity.Dolphin;
+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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityDolphin;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.World;
+
+public class DolphinController extends MobEntityController {
+ public DolphinController() {
+ super(EntityDolphinNPC.class);
+ }
+
+ @Override
+ public Dolphin getBukkitEntity() {
+ return (Dolphin) super.getBukkitEntity();
+ }
+
+ public static class DolphinNPC extends CraftDolphin implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public DolphinNPC(EntityDolphinNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+
+ public static class EntityDolphinNPC extends EntityDolphin implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityDolphinNPC(EntityTypes extends EntityDolphin> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityDolphinNPC(EntityTypes extends EntityDolphin> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ this.setNoAI(true);
+ }
+ }
+
+ @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 e(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void b(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new DolphinNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/DrownedController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/DrownedController.java
new file mode 100644
index 000000000..9c2991a4b
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/DrownedController.java
@@ -0,0 +1,203 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import net.minecraft.server.v1_14_R1.Vec3D;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftDrowned;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.entity.Drowned;
+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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityDrowned;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.World;
+
+public class DrownedController extends MobEntityController {
+ public DrownedController() {
+ super(EntityDrownedNPC.class);
+ }
+
+ @Override
+ public Drowned getBukkitEntity() {
+ return (Drowned) super.getBukkitEntity();
+ }
+
+ public static class DrownedNPC extends CraftDrowned implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public DrownedNPC(EntityDrownedNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+
+ public static class EntityDrownedNPC extends EntityDrowned implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityDrownedNPC(EntityTypes extends EntityDrowned> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityDrownedNPC(EntityTypes extends EntityDrowned> types, World world, NPC npc) {
+ super(types, 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 e(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void b(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new DrownedNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/EnderDragonController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/EnderDragonController.java
new file mode 100644
index 000000000..d2da294ef
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/EnderDragonController.java
@@ -0,0 +1,186 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEnderDragon;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityEnderDragon;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityEnderDragon> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityEnderDragonNPC(EntityTypes extends EntityEnderDragon> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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);
+ return;
+ }
+ 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 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
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @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 void movementTick() {
+ if (npc != null) {
+ npc.update();
+ Vec3D mot = getMot();
+ if (mot.getX() != 0 || mot.getY() != 0 || mot.getZ() != 0) {
+ mot = mot.d(0.98, 0.98, 0.98);
+ yaw = getCorrectYaw(locX + mot.getX(), locZ + mot.getZ());
+ setPosition(locX + mot.getX(), locY + mot.getY(), locZ + mot.getZ());
+ setMot(mot);
+ }
+ } else {
+ super.movementTick();
+ }
+ }
+ }
+}
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/EndermanController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/EndermanController.java
new file mode 100644
index 000000000..6a193f8cf
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/EndermanController.java
@@ -0,0 +1,220 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEnderman;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityEnderman;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityEnderman> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityEndermanNPC(EntityTypes extends EntityEnderman> types, World world, NPC npc) {
+ super(types, 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 boolean a(double d1, double d2, double d3, boolean b) {
+ if (npc == null) {
+ return super.a(d1, d2, d3, b);
+ }
+ return false;
+ }
+
+ @Override
+ public void b(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new EndermanNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public void updateSize() {
+ if (npc == null) {
+ super.updateSize();
+ } else {
+ NMSImpl.setSize(this, justCreated);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/EndermiteController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/EndermiteController.java
new file mode 100644
index 000000000..ef1b23cea
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/EndermiteController.java
@@ -0,0 +1,211 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEndermite;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityEndermite;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityEndermite> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityEndermiteNPC(EntityTypes extends EntityEndermite> types, World world, NPC npc) {
+ super(types, 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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new EndermiteNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null)
+ npc.update();
+ }
+
+ @Override
+ public void updateSize() {
+ if (npc == null) {
+ super.updateSize();
+ } else {
+ NMSImpl.setSize(this, justCreated);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/EntityHumanNPC.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/EntityHumanNPC.java
new file mode 100644
index 000000000..b9e9f0f5f
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/EntityHumanNPC.java
@@ -0,0 +1,549 @@
+package net.citizensnpcs.nms.v1_14_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_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.network.EmptyNetHandler;
+import net.citizensnpcs.nms.v1_14_R1.network.EmptyNetworkManager;
+import net.citizensnpcs.nms.v1_14_R1.network.EmptySocket;
+import net.citizensnpcs.nms.v1_14_R1.util.EmptyAdvancementDataPlayer;
+import net.citizensnpcs.nms.v1_14_R1.util.NMSImpl;
+import net.citizensnpcs.nms.v1_14_R1.util.PlayerControllerJump;
+import net.citizensnpcs.nms.v1_14_R1.util.PlayerControllerLook;
+import net.citizensnpcs.nms.v1_14_R1.util.PlayerControllerMove;
+import net.citizensnpcs.nms.v1_14_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_14_R1.AttributeInstance;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.ChatComponentText;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.Entity;
+import net.minecraft.server.v1_14_R1.EntityHuman;
+import net.minecraft.server.v1_14_R1.EntityPlayer;
+import net.minecraft.server.v1_14_R1.EnumGamemode;
+import net.minecraft.server.v1_14_R1.EnumItemSlot;
+import net.minecraft.server.v1_14_R1.EnumProtocolDirection;
+import net.minecraft.server.v1_14_R1.GenericAttributes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.IChatBaseComponent;
+import net.minecraft.server.v1_14_R1.MathHelper;
+import net.minecraft.server.v1_14_R1.MinecraftServer;
+import net.minecraft.server.v1_14_R1.NavigationAbstract;
+import net.minecraft.server.v1_14_R1.NetworkManager;
+import net.minecraft.server.v1_14_R1.Packet;
+import net.minecraft.server.v1_14_R1.PacketPlayOutEntityEquipment;
+import net.minecraft.server.v1_14_R1.PacketPlayOutEntityHeadRotation;
+import net.minecraft.server.v1_14_R1.PathType;
+import net.minecraft.server.v1_14_R1.PlayerInteractManager;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_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 boolean isTracked = false;
+ 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 boolean a(EntityPlayer entityplayer) {
+ if (npc != null && !isTracked) {
+ return false;
+ }
+ return super.a(entityplayer);
+ }
+
+ 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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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() {
+ super.die();
+ getAdvancementData().a();
+ }
+
+ @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() {
+ ((WorldServer) world).removeEntity(EntityHumanNPC.this);
+ }
+ }, 35); // give enough time for death and smoke animation
+ }
+
+ @Override
+ public void e(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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);
+
+ EmptyAdvancementDataPlayer.clear(this.getAdvancementData());
+ NMSImpl.setAdvancement(this.getBukkitEntity(),
+ new EmptyAdvancementDataPlayer(minecraftServer, CitizensAPI.getDataFolder().getParentFile(), this));
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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() {
+ entityBaseTick();
+ this.aB = this.aC;
+ if (this.hurtTicks > 0) {
+ this.hurtTicks -= 1;
+ }
+ tickPotionEffects();
+ this.aW = this.aV;
+ this.aL = this.aK;
+ this.aN = this.aM;
+ this.lastYaw = this.yaw;
+ this.lastPitch = this.pitch;
+ }
+
+ private void moveOnCurrentHeading() {
+ if (jumping) {
+ if (onGround && jumpTicks == 0) {
+ jump();
+ jumpTicks = 10;
+ }
+ } else {
+ jumpTicks = 0;
+ }
+ bb *= 0.98F;
+ bd *= 0.98F;
+ be *= 0.9F;
+ e(new Vec3D(this.bb, this.bc, this.bd)); // 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.jump();
+ }
+
+ @Override
+ public void setSkinFlags(byte flags) {
+ // set skin flag byte
+ getDataWatcher().set(EntityHuman.bt, 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);
+ }
+
+ @Override
+ public void setSkinPersistent(String skinName, String signature, String data) {
+ Preconditions.checkNotNull(skinName);
+ Preconditions.checkNotNull(signature);
+ Preconditions.checkNotNull(data);
+
+ npc.data().setPersistent(NPC.PLAYER_SKIN_UUID_METADATA, skinName.toLowerCase());
+ npc.data().setPersistent(NPC.PLAYER_SKIN_TEXTURE_PROPERTIES_SIGN_METADATA, signature);
+ npc.data().setPersistent(NPC.PLAYER_SKIN_TEXTURE_PROPERTIES_METADATA, data);
+ npc.data().setPersistent(NPC.PLAYER_SKIN_USE_LATEST, false);
+ npc.data().setPersistent("cached-skin-uuid-name", skinName.toLowerCase());
+ skinTracker.notifySkinChange(false);
+ }
+
+ 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 setTracked() {
+ isTracked = true;
+ }
+
+ @Override
+ public void tick() {
+ super.tick();
+ if (npc == null)
+ return;
+ this.noclip = isSpectator();
+ if (updateCounter + 1 > Setting.PACKET_UPDATE_DELAY.asInt()) {
+ updateEffects = true;
+ }
+ Bukkit.getServer().getPluginManager().unsubscribeFromPermission("bukkit.broadcast.user", bukkitEntity);
+ livingEntityBaseTick();
+
+ boolean navigating = npc.getNavigator().isNavigating();
+ updatePackets(navigating);
+ if (!navigating && getBukkitEntity() != null && npc.getTrait(Gravity.class).hasGravity()
+ && Util.isLoaded(getBukkitEntity().getLocation(LOADED_LOCATION))) {
+ a(0, 0, 0);
+ }
+ Vec3D mot = getMot();
+ if (Math.abs(mot.getX()) < EPSILON && Math.abs(mot.getY()) < EPSILON && Math.abs(mot.getZ()) < EPSILON) {
+ setMot(new Vec3D(0, 0, 0));
+ }
+ if (navigating) {
+ if (!NMSImpl.isNavigationFinished(navigation)) {
+ NMSImpl.updateNavigation(navigation);
+ }
+ moveOnCurrentHeading();
+ }
+ NMSImpl.updateAI(this);
+
+ if (noDamageTicks > 0) {
+ --noDamageTicks;
+ }
+
+ npc.update();
+ }
+
+ 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);
+ }
+
+ @Override
+ public void setSkinPersistent(String skinName, String signature, String data) {
+ ((SkinnableEntity) this.entity).setSkinPersistent(skinName, signature, data);
+ }
+ }
+
+ private static final float EPSILON = 0.005F;
+ private static final Location LOADED_LOCATION = new Location(null, 0, 0, 0);
+}
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/EvokerController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/EvokerController.java
new file mode 100644
index 000000000..c61e49828
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/EvokerController.java
@@ -0,0 +1,205 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import net.minecraft.server.v1_14_R1.Vec3D;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityEvoker;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityEvoker> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityEvokerNPC(EntityTypes extends EntityEvoker> types, World world, NPC npc) {
+ super(types, 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 e(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void b(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new EvokerNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/FoxController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/FoxController.java
new file mode 100644
index 000000000..2dfffa79f
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/FoxController.java
@@ -0,0 +1,217 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftFox;
+import org.bukkit.entity.Fox;
+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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.DataWatcherObject;
+import net.minecraft.server.v1_14_R1.EntityFox;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_R1.World;
+
+public class FoxController extends MobEntityController {
+ public FoxController() {
+ super(EntityFoxNPC.class);
+ }
+
+ @Override
+ public Fox getBukkitEntity() {
+ return (Fox) super.getBukkitEntity();
+ }
+
+ public static class EntityFoxNPC extends EntityFox implements NPCHolder {
+ boolean calledNMSHeight = false;
+ private final CitizensNPC npc;
+
+ public EntityFoxNPC(EntityTypes extends EntityFox> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityFoxNPC(EntityTypes extends EntityFox> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+
+ }
+ }
+
+ @Override
+ public void a(DataWatcherObject> datawatcherobject) {
+ if (npc != null && !calledNMSHeight) {
+ calledNMSHeight = true;
+ NMSImpl.checkAndUpdateHeight(this, datawatcherobject);
+ calledNMSHeight = false;
+ }
+ super.a(datawatcherobject);
+ }
+
+ @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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new FoxNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+ }
+
+ public static class FoxNPC extends CraftFox implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public FoxNPC(EntityFoxNPC 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/GhastController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/GhastController.java
new file mode 100644
index 000000000..79fc58bfc
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/GhastController.java
@@ -0,0 +1,176 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import net.minecraft.server.v1_14_R1.Vec3D;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityGhast;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityGhast> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityGhastNPC(EntityTypes extends EntityGhast> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new GhastNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @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 isRiptiding() {
+ return npc != null;
+ }
+
+ @Override
+ public void mobTick() {
+ if (npc != null) {
+ npc.update();
+ }
+ super.mobTick();
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/GiantController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/GiantController.java
new file mode 100644
index 000000000..f4d7c17e7
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/GiantController.java
@@ -0,0 +1,212 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityGiantZombie;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityGiantZombie> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityGiantNPC(EntityTypes extends EntityGiantZombie> types, World world, NPC npc) {
+ super(types, 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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new GiantNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public void updateSize() {
+ if (npc == null) {
+ super.updateSize();
+ } else {
+ NMSImpl.setSize(this, 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/GuardianController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/GuardianController.java
new file mode 100644
index 000000000..faa8ad881
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/GuardianController.java
@@ -0,0 +1,228 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import java.lang.reflect.Method;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.NMS;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityGuardian;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityGuardian> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityGuardianNPC(EntityTypes extends EntityGuardian> types, World world, NPC npc) {
+ super(types, 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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new GuardianNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void movementTick() {
+ if (npc == null) {
+ try {
+ super.movementTick();
+ } catch (NoSuchMethodError ex) {
+ try {
+ MOVEMENT_TICK.invoke(this);
+ } catch (Throwable ex2) {
+ ex2.printStackTrace();
+ }
+ }
+ } else {
+ NMSImpl.updateAI(this);
+ npc.update();
+ }
+ }
+
+ @Override
+ public void updateSize() {
+ if (npc == null) {
+ super.updateSize();
+ } else {
+ NMSImpl.setSize(this, justCreated);
+ }
+ }
+
+ private static final Method MOVEMENT_TICK = NMS.getMethod(EntityGuardian.class, "k", false);
+ }
+
+ 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;
+ }
+ }
+}
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/GuardianElderController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/GuardianElderController.java
new file mode 100644
index 000000000..0794ca5df
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/GuardianElderController.java
@@ -0,0 +1,228 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import java.lang.reflect.Method;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftElderGuardian;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.NMS;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityGuardianElder;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityGuardianElder> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityGuardianElderNPC(EntityTypes extends EntityGuardianElder> types, World world, NPC npc) {
+ super(types, 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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new GuardianElderNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void movementTick() {
+ if (npc == null) {
+ try {
+ super.movementTick();
+ } catch (NoSuchMethodError ex) {
+ try {
+ MOVEMENT_TICK.invoke(this);
+ } catch (Throwable ex2) {
+ ex2.printStackTrace();
+ }
+ }
+ } else {
+ NMSImpl.updateAI(this);
+ npc.update();
+ }
+ }
+
+ @Override
+ public void updateSize() {
+ if (npc == null) {
+ super.updateSize();
+ } else {
+ NMSImpl.setSize(this, justCreated);
+ }
+ }
+
+ private static final Method MOVEMENT_TICK = NMS.getMethod(EntityGuardianElder.class, "k", false);
+ }
+
+ 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;
+ }
+ }
+}
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/HorseController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/HorseController.java
new file mode 100644
index 000000000..3158851af
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/HorseController.java
@@ -0,0 +1,229 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_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_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.DataWatcherObject;
+import net.minecraft.server.v1_14_R1.EntityHorse;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_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 {
+ boolean calledNMSHeight = false;
+
+ private final CitizensNPC npc;
+
+ public EntityHorseNPC(EntityTypes extends EntityHorse> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityHorseNPC(EntityTypes extends EntityHorse> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ ((Horse) getBukkitEntity()).setDomestication(((Horse) getBukkitEntity()).getMaxDomestication());
+ }
+ }
+
+ @Override
+ public void a(DataWatcherObject> datawatcherobject) {
+ if (npc != null && !calledNMSHeight) {
+ calledNMSHeight = true;
+ NMSImpl.checkAndUpdateHeight(this, datawatcherobject);
+ calledNMSHeight = false;
+ }
+
+ super.a(datawatcherobject);
+ }
+
+ @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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new HorseNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ NMS.setStepHeight(getBukkitEntity(), 1);
+ npc.update();
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/HorseDonkeyController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/HorseDonkeyController.java
new file mode 100644
index 000000000..e31f744be
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/HorseDonkeyController.java
@@ -0,0 +1,229 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftDonkey;
+import org.bukkit.craftbukkit.v1_14_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_14_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_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.DataWatcherObject;
+import net.minecraft.server.v1_14_R1.EntityHorseDonkey;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_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 {
+ boolean calledNMSHeight = false;
+
+ private final CitizensNPC npc;
+
+ public EntityHorseDonkeyNPC(EntityTypes extends EntityHorseDonkey> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityHorseDonkeyNPC(EntityTypes extends EntityHorseDonkey> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ ((Donkey) getBukkitEntity()).setDomestication(((Donkey) getBukkitEntity()).getMaxDomestication());
+ }
+ }
+
+ @Override
+ public void a(DataWatcherObject> datawatcherobject) {
+ if (npc != null && !calledNMSHeight) {
+ calledNMSHeight = true;
+ NMSImpl.checkAndUpdateHeight(this, datawatcherobject);
+ calledNMSHeight = false;
+ }
+
+ super.a(datawatcherobject);
+ }
+
+ @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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new HorseDonkeyNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ NMS.setStepHeight(getBukkitEntity(), 1);
+ npc.update();
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/HorseMuleController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/HorseMuleController.java
new file mode 100644
index 000000000..756354a21
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/HorseMuleController.java
@@ -0,0 +1,229 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_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_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.DataWatcherObject;
+import net.minecraft.server.v1_14_R1.EntityHorseMule;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_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 {
+ boolean calledNMSHeight = false;
+
+ private final CitizensNPC npc;
+
+ public EntityHorseMuleNPC(EntityTypes extends EntityHorseMule> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityHorseMuleNPC(EntityTypes extends EntityHorseMule> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ ((Mule) getBukkitEntity()).setDomestication(((Mule) getBukkitEntity()).getMaxDomestication());
+ }
+ }
+
+ @Override
+ public void a(DataWatcherObject> datawatcherobject) {
+ if (npc != null && !calledNMSHeight) {
+ calledNMSHeight = true;
+ NMSImpl.checkAndUpdateHeight(this, datawatcherobject);
+ calledNMSHeight = false;
+ }
+
+ super.a(datawatcherobject);
+ }
+
+ @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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new HorseMuleNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ NMS.setStepHeight(getBukkitEntity(), 1);
+ npc.update();
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/HorseSkeletonController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/HorseSkeletonController.java
new file mode 100644
index 000000000..597a74d1b
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/HorseSkeletonController.java
@@ -0,0 +1,230 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_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_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.DataWatcherObject;
+import net.minecraft.server.v1_14_R1.EntityHorseSkeleton;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_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 {
+ boolean calledNMSHeight = false;
+
+ private final CitizensNPC npc;
+
+ public EntityHorseSkeletonNPC(EntityTypes extends EntityHorseSkeleton> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityHorseSkeletonNPC(EntityTypes extends EntityHorseSkeleton> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ ((SkeletonHorse) getBukkitEntity())
+ .setDomestication(((SkeletonHorse) getBukkitEntity()).getMaxDomestication());
+ }
+ }
+
+ @Override
+ public void a(DataWatcherObject> datawatcherobject) {
+ if (npc != null && !calledNMSHeight) {
+ calledNMSHeight = true;
+ NMSImpl.checkAndUpdateHeight(this, datawatcherobject);
+ calledNMSHeight = false;
+ }
+
+ super.a(datawatcherobject);
+ }
+
+ @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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new HorseSkeletonNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ NMS.setStepHeight(getBukkitEntity(), 1);
+ npc.update();
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/HorseZombieController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/HorseZombieController.java
new file mode 100644
index 000000000..58fe415f6
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/HorseZombieController.java
@@ -0,0 +1,230 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_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_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.DataWatcherObject;
+import net.minecraft.server.v1_14_R1.EntityHorseZombie;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_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 {
+ boolean calledNMSHeight = false;
+
+ private final CitizensNPC npc;
+
+ public EntityHorseZombieNPC(EntityTypes extends EntityHorseZombie> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityHorseZombieNPC(EntityTypes extends EntityHorseZombie> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ ((ZombieHorse) getBukkitEntity())
+ .setDomestication(((ZombieHorse) getBukkitEntity()).getMaxDomestication());
+ }
+ }
+
+ @Override
+ public void a(DataWatcherObject> datawatcherobject) {
+ if (npc != null && !calledNMSHeight) {
+ calledNMSHeight = true;
+ NMSImpl.checkAndUpdateHeight(this, datawatcherobject);
+ calledNMSHeight = false;
+ }
+
+ super.a(datawatcherobject);
+ }
+
+ @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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new HorseZombieNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ NMS.setStepHeight(getBukkitEntity(), 1);
+ npc.update();
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/HumanController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/HumanController.java
new file mode 100644
index 000000000..2baca2255
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/HumanController.java
@@ -0,0 +1,126 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import net.minecraft.server.v1_14_R1.Vec3D;
+
+import java.util.UUID;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.v1_14_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.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.PlayerInteractManager;
+import net.minecraft.server.v1_14_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[] nameSplit = Util.splitPlayerName(coloredName);
+ String name = nameSplit[0];
+
+ final String prefixCapture = nameSplit[1], suffixCapture = nameSplit[2];
+
+ 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(), 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) {
+ if (Setting.USE_SCOREBOARD_TEAMS.asBoolean()) {
+ String teamName = entity.getUniqueId().toString().substring(0, 16);
+ Scoreboard scoreboard = Bukkit.getScoreboardManager().getMainScoreboard();
+ Team team = scoreboard.getTeam(teamName);
+ if (team != null && team.hasPlayer(entity)) {
+ if (team.getSize() == 1) {
+ team.setPrefix("");
+ team.setSuffix("");
+ }
+ team.removePlayer(entity);
+ }
+ }
+ NMS.removeFromWorld(entity);
+ SkinnableEntity npc = entity instanceof SkinnableEntity ? (SkinnableEntity) entity : null;
+ npc.getSkinTracker().onRemoveNPC();
+ }
+ NMS.remove(entity);
+ // Paper decided to break Spigot compatibility.
+ // super.remove();
+ }
+}
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/IllusionerController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/IllusionerController.java
new file mode 100644
index 000000000..5ec8f5c03
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/IllusionerController.java
@@ -0,0 +1,204 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import net.minecraft.server.v1_14_R1.Vec3D;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityIllagerIllusioner;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityIllagerIllusioner> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityIllusionerNPC(EntityTypes extends EntityIllagerIllusioner> types, World world, NPC npc) {
+ super(types, 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 e(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void b(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new IllusionerNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/IronGolemController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/IronGolemController.java
new file mode 100644
index 000000000..3929f0786
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/IronGolemController.java
@@ -0,0 +1,212 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityIronGolem;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityIronGolem> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityIronGolemNPC(EntityTypes extends EntityIronGolem> types, World world, NPC npc) {
+ super(types, 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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new IronGolemNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public void updateSize() {
+ if (npc == null) {
+ super.updateSize();
+ } else {
+ NMSImpl.setSize(this, 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/LlamaController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/LlamaController.java
new file mode 100644
index 000000000..ed56548cc
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/LlamaController.java
@@ -0,0 +1,230 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_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_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.DataWatcherObject;
+import net.minecraft.server.v1_14_R1.EntityLlama;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_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 {
+ boolean calledNMSHeight = false;
+
+ private final CitizensNPC npc;
+
+ public EntityLlamaNPC(EntityTypes extends EntityLlama> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityLlamaNPC(EntityTypes extends EntityLlama> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ ((Llama) getBukkitEntity()).setDomestication(((Llama) getBukkitEntity()).getMaxDomestication());
+ }
+ }
+
+ @Override
+ public void a(DataWatcherObject> datawatcherobject) {
+ if (npc != null && !calledNMSHeight) {
+ calledNMSHeight = true;
+ NMSImpl.checkAndUpdateHeight(this, datawatcherobject);
+ calledNMSHeight = false;
+ }
+
+ super.a(datawatcherobject);
+ }
+
+ @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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new LlamaNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void mobTick() {
+ if (npc == null) {
+ super.mobTick();
+ } else {
+ NMS.setStepHeight(getBukkitEntity(), 1);
+ npc.update();
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/MagmaCubeController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/MagmaCubeController.java
new file mode 100644
index 000000000..4198406d5
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/MagmaCubeController.java
@@ -0,0 +1,223 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.nms.v1_14_R1.util.PlayerControllerMove;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityHuman;
+import net.minecraft.server.v1_14_R1.EntityMagmaCube;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityMagmaCube> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityMagmaCubeNPC(EntityTypes extends EntityMagmaCube> types, World world, NPC npc) {
+ super(types, 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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new MagmaCubeNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void pickup(EntityHuman human) {
+ if (npc == null) {
+ super.pickup(human);
+ }
+ }
+
+ @Override
+ public void tick() {
+ super.tick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public void updateSize() {
+ if (npc == null) {
+ super.updateSize();
+ } else {
+ NMSImpl.setSize(this, 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/MobEntityController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/MobEntityController.java
new file mode 100644
index 000000000..e3eba0e58
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/MobEntityController.java
@@ -0,0 +1,66 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import java.lang.reflect.Constructor;
+import java.util.Map;
+
+import org.bukkit.Location;
+import org.bukkit.block.BlockFace;
+import org.bukkit.craftbukkit.v1_14_R1.CraftWorld;
+import org.bukkit.entity.Entity;
+
+import com.google.common.collect.Maps;
+
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.AbstractEntityController;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.World;
+
+public abstract class MobEntityController extends AbstractEntityController {
+ private final Class> clazz;
+ private final Constructor> constructor;
+
+ protected MobEntityController(Class> clazz) {
+ super(clazz);
+ this.constructor = getConstructor(clazz);
+ this.clazz = clazz;
+ }
+
+ @Override
+ protected Entity createEntity(Location at, NPC npc) {
+ EntityTypes> type = NMSImpl.getEntityType(clazz);
+ net.minecraft.server.v1_14_R1.Entity entity = createEntityFromClass(type,
+ ((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_14_R1.Entity createEntityFromClass(Object... args) {
+ try {
+ return (net.minecraft.server.v1_14_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(EntityTypes.class, 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/MushroomCowController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/MushroomCowController.java
new file mode 100644
index 000000000..7f25a09ca
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/MushroomCowController.java
@@ -0,0 +1,217 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.DataWatcherObject;
+import net.minecraft.server.v1_14_R1.EntityMushroomCow;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_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 {
+ boolean calledNMSHeight = false;
+
+ private final CitizensNPC npc;
+
+ public EntityMushroomCowNPC(EntityTypes extends EntityMushroomCow> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityMushroomCowNPC(EntityTypes extends EntityMushroomCow> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ public void a(DataWatcherObject> datawatcherobject) {
+ if (npc != null && !calledNMSHeight) {
+ calledNMSHeight = true;
+ NMSImpl.checkAndUpdateHeight(this, datawatcherobject);
+ calledNMSHeight = false;
+ }
+
+ super.a(datawatcherobject);
+ }
+
+ @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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new MushroomCowNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null)
+ npc.update();
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/OcelotController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/OcelotController.java
new file mode 100644
index 000000000..7baa8dd80
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/OcelotController.java
@@ -0,0 +1,224 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.DataWatcherObject;
+import net.minecraft.server.v1_14_R1.EntityOcelot;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_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 {
+ boolean calledNMSHeight = false;
+ private final CitizensNPC npc;
+
+ public EntityOcelotNPC(EntityTypes extends EntityOcelot> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityOcelotNPC(EntityTypes extends EntityOcelot> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ public void a(DataWatcherObject> datawatcherobject) {
+ if (npc != null && !calledNMSHeight) {
+ calledNMSHeight = true;
+ NMSImpl.checkAndUpdateHeight(this, datawatcherobject);
+ calledNMSHeight = false;
+ }
+
+ super.a(datawatcherobject);
+ }
+
+ @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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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
+ protected void dV() {
+ if (npc == null) {
+ super.dV();
+ }
+ }
+
+ @Override
+ public void e(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new OcelotNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/PandaController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/PandaController.java
new file mode 100644
index 000000000..86a7a30b4
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/PandaController.java
@@ -0,0 +1,217 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPanda;
+import org.bukkit.entity.Panda;
+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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.DataWatcherObject;
+import net.minecraft.server.v1_14_R1.EntityPanda;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_R1.World;
+
+public class PandaController extends MobEntityController {
+ public PandaController() {
+ super(EntityPandaNPC.class);
+ }
+
+ @Override
+ public Panda getBukkitEntity() {
+ return (Panda) super.getBukkitEntity();
+ }
+
+ public static class EntityPandaNPC extends EntityPanda implements NPCHolder {
+ boolean calledNMSHeight = false;
+ private final CitizensNPC npc;
+
+ public EntityPandaNPC(EntityTypes extends EntityPanda> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityPandaNPC(EntityTypes extends EntityPanda> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+
+ }
+ }
+
+ @Override
+ public void a(DataWatcherObject> datawatcherobject) {
+ if (npc != null && !calledNMSHeight) {
+ calledNMSHeight = true;
+ NMSImpl.checkAndUpdateHeight(this, datawatcherobject);
+ calledNMSHeight = false;
+ }
+ super.a(datawatcherobject);
+ }
+
+ @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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new PandaNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+ }
+
+ public static class PandaNPC extends CraftPanda implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public PandaNPC(EntityPandaNPC 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/ParrotController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/ParrotController.java
new file mode 100644
index 000000000..b2487ced6
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/ParrotController.java
@@ -0,0 +1,183 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityHuman;
+import net.minecraft.server.v1_14_R1.EntityParrot;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.EnumHand;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityParrot> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityParrotNPC(EntityTypes extends EntityParrot> types, World world, NPC npc) {
+ super(types, 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 void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new ParrotNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @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 void mobTick() {
+ if (npc == null) {
+ super.mobTick();
+ } 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/PhantomController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/PhantomController.java
new file mode 100644
index 000000000..06845a73d
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/PhantomController.java
@@ -0,0 +1,245 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import java.lang.reflect.Method;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPhantom;
+import org.bukkit.entity.Phantom;
+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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.NMS;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.ControllerLook;
+import net.minecraft.server.v1_14_R1.ControllerMove;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityPhantom;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.EnumDifficulty;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_R1.World;
+
+public class PhantomController extends MobEntityController {
+ public PhantomController() {
+ super(EntityPhantomNPC.class);
+ }
+
+ @Override
+ public Phantom getBukkitEntity() {
+ return (Phantom) super.getBukkitEntity();
+ }
+
+ public static class EntityPhantomNPC extends EntityPhantom implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityPhantomNPC(EntityTypes extends EntityPhantom> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityPhantomNPC(EntityTypes extends EntityPhantom> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ setNoAI(true);
+ this.moveController = new ControllerMove(this);
+ this.lookController = new ControllerLook(this);
+ // TODO: phantom pitch reversed
+ }
+ }
+
+ @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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 dS() {
+ if (npc == null || !npc.isProtected())
+ return super.dS();
+ return false;
+ }
+
+ @Override
+ public void e(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new PhantomNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void movementTick() {
+ try {
+ super.movementTick();
+ } catch (NoSuchMethodError ex) {
+ try {
+ MOVEMENT_TICK.invoke(this);
+ } catch (Throwable ex2) {
+ ex2.printStackTrace();
+ }
+ }
+ if (npc != null) {
+ if (npc.isProtected()) {
+ this.setOnFire(0);
+ }
+ npc.update();
+ }
+ }
+
+ @Override
+ public void tick() {
+ // avoid suicide
+ boolean resetDifficulty = this.world.getDifficulty() == EnumDifficulty.PEACEFUL;
+ if (npc != null && resetDifficulty) {
+ this.world.getWorldData().setDifficulty(EnumDifficulty.NORMAL);
+ }
+ super.tick();
+ if (npc != null && resetDifficulty) {
+ this.world.getWorldData().setDifficulty(EnumDifficulty.PEACEFUL);
+ }
+ }
+
+ private static final Method MOVEMENT_TICK = NMS.getMethod(EntityPhantom.class, "k", false);
+ }
+
+ public static class PhantomNPC extends CraftPhantom implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public PhantomNPC(EntityPhantomNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/PigController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/PigController.java
new file mode 100644
index 000000000..7bd92781b
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/PigController.java
@@ -0,0 +1,232 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.DataWatcherObject;
+import net.minecraft.server.v1_14_R1.EntityLightning;
+import net.minecraft.server.v1_14_R1.EntityPig;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_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 {
+ boolean calledNMSHeight = false;
+
+ private final CitizensNPC npc;
+
+ public EntityPigNPC(EntityTypes extends EntityPig> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityPigNPC(EntityTypes extends EntityPig> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ public void a(DataWatcherObject> datawatcherobject) {
+ if (npc != null && !calledNMSHeight) {
+ calledNMSHeight = true;
+ NMSImpl.checkAndUpdateHeight(this, datawatcherobject);
+ calledNMSHeight = false;
+ }
+
+ super.a(datawatcherobject);
+ }
+
+ @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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 dD() {
+ // block carrot-on-a-stick behaviour
+ return npc == null ? super.dD() : false;
+ }
+
+ @Override
+ public void e(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new PigNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/PigZombieController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/PigZombieController.java
new file mode 100644
index 000000000..36c658b95
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/PigZombieController.java
@@ -0,0 +1,206 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import net.minecraft.server.v1_14_R1.Vec3D;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityPigZombie;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityPigZombie> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityPigZombieNPC(EntityTypes extends EntityPigZombie> types, World world, NPC npc) {
+ super(types, 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 e(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void b(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new PigZombieNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/PillagerController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/PillagerController.java
new file mode 100644
index 000000000..4527f24d8
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/PillagerController.java
@@ -0,0 +1,217 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPillager;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.entity.Pillager;
+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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.DataWatcherObject;
+import net.minecraft.server.v1_14_R1.EntityPillager;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_R1.World;
+
+public class PillagerController extends MobEntityController {
+ public PillagerController() {
+ super(EntityPillagerNPC.class);
+ }
+
+ @Override
+ public Pillager getBukkitEntity() {
+ return (Pillager) super.getBukkitEntity();
+ }
+
+ public static class PillagerNPC extends CraftPillager implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public PillagerNPC(EntityPillagerNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+
+ public static class EntityPillagerNPC extends EntityPillager implements NPCHolder {
+ boolean calledNMSHeight = false;
+ private final CitizensNPC npc;
+
+ public EntityPillagerNPC(EntityTypes extends EntityPillager> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityPillagerNPC(EntityTypes extends EntityPillager> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+
+ }
+ }
+
+ @Override
+ public void a(DataWatcherObject> datawatcherobject) {
+ if (npc != null && !calledNMSHeight) {
+ calledNMSHeight = true;
+ NMSImpl.checkAndUpdateHeight(this, datawatcherobject);
+ calledNMSHeight = false;
+ }
+ super.a(datawatcherobject);
+ }
+
+ @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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new PillagerNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/PolarBearController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/PolarBearController.java
new file mode 100644
index 000000000..b355ea13a
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/PolarBearController.java
@@ -0,0 +1,184 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.DataWatcherObject;
+import net.minecraft.server.v1_14_R1.EntityPolarBear;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_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 {
+ boolean calledNMSHeight = false;
+
+ private final CitizensNPC npc;
+
+ public EntityPolarBearNPC(EntityTypes extends EntityPolarBear> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityPolarBearNPC(EntityTypes extends EntityPolarBear> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ public void a(DataWatcherObject> datawatcherobject) {
+ if (npc != null && !calledNMSHeight) {
+ calledNMSHeight = true;
+ NMSImpl.checkAndUpdateHeight(this, datawatcherobject);
+ calledNMSHeight = false;
+ }
+
+ super.a(datawatcherobject);
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new PolarBearNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/PufferFishController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/PufferFishController.java
new file mode 100644
index 000000000..e35e99606
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/PufferFishController.java
@@ -0,0 +1,208 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import net.minecraft.server.v1_14_R1.Vec3D;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPufferFish;
+import org.bukkit.entity.PufferFish;
+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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.ControllerMove;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityPufferFish;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.World;
+
+public class PufferFishController extends MobEntityController {
+ public PufferFishController() {
+ super(EntityPufferFishNPC.class);
+ }
+
+ @Override
+ public PufferFish getBukkitEntity() {
+ return (PufferFish) super.getBukkitEntity();
+ }
+
+ public static class EntityPufferFishNPC extends EntityPufferFish implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityPufferFishNPC(EntityTypes extends EntityPufferFish> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityPufferFishNPC(EntityTypes extends EntityPufferFish> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ this.moveController = new ControllerMove(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 e(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void b(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new PufferFishNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @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 void mobTick() {
+ if (npc != null) {
+ NMSImpl.setNotInSchool(this);
+ }
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+ }
+
+ public static class PufferFishNPC extends CraftPufferFish implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public PufferFishNPC(EntityPufferFishNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/RabbitController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/RabbitController.java
new file mode 100644
index 000000000..0d727961d
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/RabbitController.java
@@ -0,0 +1,241 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.NMS;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.DataWatcherObject;
+import net.minecraft.server.v1_14_R1.EntityLiving;
+import net.minecraft.server.v1_14_R1.EntityRabbit;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_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 {
+ boolean calledNMSHeight = false;
+
+ private final CitizensNPC npc;
+
+ public EntityRabbitNPC(EntityTypes extends EntityRabbit> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityRabbitNPC(EntityTypes extends EntityRabbit> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ public void a(DataWatcherObject> datawatcherobject) {
+ if (npc != null && !calledNMSHeight) {
+ calledNMSHeight = true;
+ NMSImpl.checkAndUpdateHeight(this, datawatcherobject);
+ calledNMSHeight = false;
+ }
+
+ super.a(datawatcherobject);
+ }
+
+ @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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 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
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void mobTick() {
+ if (npc != null) {
+ super.mobTick();
+ if (npc.getNavigator().isNavigating()) {
+ NMS.setShouldJump(getBukkitEntity());
+ }
+ npc.update();
+ } else {
+ super.mobTick();
+ }
+ }
+
+ @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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/RavagerController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/RavagerController.java
new file mode 100644
index 000000000..3144a55e6
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/RavagerController.java
@@ -0,0 +1,217 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftRavager;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.entity.Ravager;
+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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.DataWatcherObject;
+import net.minecraft.server.v1_14_R1.EntityRavager;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_R1.World;
+
+public class RavagerController extends MobEntityController {
+ public RavagerController() {
+ super(EntityRavagerNPC.class);
+ }
+
+ @Override
+ public Ravager getBukkitEntity() {
+ return (Ravager) super.getBukkitEntity();
+ }
+
+ public static class RavagerNPC extends CraftRavager implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public RavagerNPC(EntityRavagerNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+
+ public static class EntityRavagerNPC extends EntityRavager implements NPCHolder {
+ boolean calledNMSHeight = false;
+ private final CitizensNPC npc;
+
+ public EntityRavagerNPC(EntityTypes extends EntityRavager> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityRavagerNPC(EntityTypes extends EntityRavager> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+
+ }
+ }
+
+ @Override
+ public void a(DataWatcherObject> datawatcherobject) {
+ if (npc != null && !calledNMSHeight) {
+ calledNMSHeight = true;
+ NMSImpl.checkAndUpdateHeight(this, datawatcherobject);
+ calledNMSHeight = false;
+ }
+ super.a(datawatcherobject);
+ }
+
+ @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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new RavagerNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/SalmonController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/SalmonController.java
new file mode 100644
index 000000000..ed5212e4f
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/SalmonController.java
@@ -0,0 +1,208 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import net.minecraft.server.v1_14_R1.Vec3D;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftSalmon;
+import org.bukkit.entity.Salmon;
+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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.ControllerMove;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntitySalmon;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.World;
+
+public class SalmonController extends MobEntityController {
+ public SalmonController() {
+ super(EntitySalmonNPC.class);
+ }
+
+ @Override
+ public Salmon getBukkitEntity() {
+ return (Salmon) super.getBukkitEntity();
+ }
+
+ public static class EntitySalmonNPC extends EntitySalmon implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntitySalmonNPC(EntityTypes extends EntitySalmon> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntitySalmonNPC(EntityTypes extends EntitySalmon> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ this.moveController = new ControllerMove(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 e(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void b(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new SalmonNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @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 void mobTick() {
+ if (npc != null) {
+ NMSImpl.setNotInSchool(this);
+ }
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+ }
+
+ public static class SalmonNPC extends CraftSalmon implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public SalmonNPC(EntitySalmonNPC 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/SheepController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/SheepController.java
new file mode 100644
index 000000000..d0acc75ed
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/SheepController.java
@@ -0,0 +1,216 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.DataWatcherObject;
+import net.minecraft.server.v1_14_R1.EntitySheep;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_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 {
+ boolean calledNMSHeight = false;
+
+ private final CitizensNPC npc;
+
+ public EntitySheepNPC(EntityTypes extends EntitySheep> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntitySheepNPC(EntityTypes extends EntitySheep> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ public void a(DataWatcherObject> datawatcherobject) {
+ if (npc != null && !calledNMSHeight) {
+ calledNMSHeight = true;
+ NMSImpl.checkAndUpdateHeight(this, datawatcherobject);
+ calledNMSHeight = false;
+ }
+
+ super.a(datawatcherobject);
+ }
+
+ @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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new SheepNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null)
+ npc.update();
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/ShulkerController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/ShulkerController.java
new file mode 100644
index 000000000..e9c08c8fd
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/ShulkerController.java
@@ -0,0 +1,239 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import net.minecraft.server.v1_14_R1.Vec3D;
+
+import java.lang.reflect.Method;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.NMS;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityAIBodyControl;
+import net.minecraft.server.v1_14_R1.EntityShulker;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityShulker> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityShulkerNPC(EntityTypes extends EntityShulker> types, World world, NPC npc) {
+ super(types, 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 e(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void b(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new ShulkerNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @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 void movementTick() {
+ if (npc == null) {
+ try {
+ super.movementTick();
+ } catch (NoSuchMethodError ex) {
+ try {
+ MOVEMENT_TICK.invoke(this);
+ } catch (Throwable ex2) {
+ ex2.printStackTrace();
+ }
+ }
+ }
+ }
+
+ @Override
+ protected EntityAIBodyControl o() {
+ return new EntityAIBodyControl(this);
+ }
+
+ @Override
+ public void updateSize() {
+ if (npc == null) {
+ super.updateSize();
+ } else {
+ NMSImpl.setSize(this, justCreated);
+ }
+ }
+
+ @Override
+ public void tick() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.tick();
+ }
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ private static final Method MOVEMENT_TICK = NMS.getMethod(EntityShulker.class, "k", false);
+ }
+
+ 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;
+ }
+ }
+}
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/SilverfishController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/SilverfishController.java
new file mode 100644
index 000000000..8615624f1
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/SilverfishController.java
@@ -0,0 +1,209 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import net.minecraft.server.v1_14_R1.Vec3D;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntitySilverfish;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntitySilverfish> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntitySilverfishNPC(EntityTypes extends EntitySilverfish> types, World world, NPC npc) {
+ super(types, 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 e(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void b(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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
+ public CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new SilverfishNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null)
+ npc.update();
+ }
+
+ @Override
+ public void updateSize() {
+ if (npc == null) {
+ super.updateSize();
+ } else {
+ NMSImpl.setSize(this, justCreated);
+ }
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/SkeletonController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/SkeletonController.java
new file mode 100644
index 000000000..5bbf5fff1
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/SkeletonController.java
@@ -0,0 +1,212 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import net.minecraft.server.v1_14_R1.Vec3D;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntitySkeleton;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntitySkeleton> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntitySkeletonNPC(EntityTypes extends EntitySkeleton> types, World world, NPC npc) {
+ super(types, 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 e(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void b(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new SkeletonNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public void updateSize() {
+ if (npc == null) {
+ super.updateSize();
+ } else {
+ NMSImpl.setSize(this, justCreated);
+ }
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/SkeletonStrayController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/SkeletonStrayController.java
new file mode 100644
index 000000000..35646c2e9
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/SkeletonStrayController.java
@@ -0,0 +1,212 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import net.minecraft.server.v1_14_R1.Vec3D;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntitySkeletonStray;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntitySkeletonStray> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityStrayNPC(EntityTypes extends EntitySkeletonStray> types, World world, NPC npc) {
+ super(types, 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 e(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void b(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new StrayNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public void updateSize() {
+ if (npc == null) {
+ super.updateSize();
+ } else {
+ NMSImpl.setSize(this, justCreated);
+ }
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/SkeletonWitherController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/SkeletonWitherController.java
new file mode 100644
index 000000000..7cc2ac45c
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/SkeletonWitherController.java
@@ -0,0 +1,212 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import net.minecraft.server.v1_14_R1.Vec3D;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntitySkeletonWither;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntitySkeletonWither> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntitySkeletonWitherNPC(EntityTypes extends EntitySkeletonWither> types, World world, NPC npc) {
+ super(types, 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 e(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void b(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new SkeletonWitherNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public void updateSize() {
+ if (npc == null) {
+ super.updateSize();
+ } else {
+ NMSImpl.setSize(this, justCreated);
+ }
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/SlimeController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/SlimeController.java
new file mode 100644
index 000000000..adfc3fcee
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/SlimeController.java
@@ -0,0 +1,223 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.nms.v1_14_R1.util.PlayerControllerMove;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityHuman;
+import net.minecraft.server.v1_14_R1.EntitySlime;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntitySlime> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntitySlimeNPC(EntityTypes extends EntitySlime> types, World world, NPC npc) {
+ super(types, 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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new SlimeNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void pickup(EntityHuman human) {
+ if (npc == null) {
+ super.pickup(human);
+ }
+ }
+
+ @Override
+ public void tick() {
+ super.tick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public void updateSize() {
+ if (npc == null) {
+ super.updateSize();
+ } else {
+ NMSImpl.setSize(this, 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/SnowmanController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/SnowmanController.java
new file mode 100644
index 000000000..486cd11e4
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/SnowmanController.java
@@ -0,0 +1,238 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import net.minecraft.server.v1_14_R1.Vec3D;
+
+import java.lang.reflect.Method;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.NMS;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntitySnowman;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntitySnowman> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntitySnowmanNPC(EntityTypes extends EntitySnowman> types, World world, NPC npc) {
+ super(types, 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 e(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void b(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new SnowmanNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public void movementTick() {
+ boolean allowsGriefing = this.world.getGameRules().getBoolean("mobGriefing");
+ if (npc != null) {
+ this.world.getGameRules().set("mobGriefing", "false", this.world.getMinecraftServer());
+ }
+ try {
+ super.movementTick();
+ } catch (NoSuchMethodError ex) {
+ try {
+ MOVEMENT_TICK.invoke(this);
+ } catch (Throwable ex2) {
+ ex2.printStackTrace();
+ }
+ }
+ if (npc != null) {
+ this.world.getGameRules().set("mobGriefing", Boolean.toString(allowsGriefing),
+ this.world.getMinecraftServer());
+ }
+ }
+
+ @Override
+ public void updateSize() {
+ if (npc == null) {
+ super.updateSize();
+ } else {
+ NMSImpl.setSize(this, justCreated);
+ }
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ private static final Method MOVEMENT_TICK = NMS.getMethod(EntitySnowman.class, "k", false);
+ }
+
+ 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;
+ }
+ }
+}
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/SpiderController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/SpiderController.java
new file mode 100644
index 000000000..e6a108a89
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/SpiderController.java
@@ -0,0 +1,212 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import net.minecraft.server.v1_14_R1.Vec3D;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntitySpider;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntitySpider> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntitySpiderNPC(EntityTypes extends EntitySpider> types, World world, NPC npc) {
+ super(types, 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 e(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void b(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new SpiderNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null)
+ npc.update();
+ }
+
+ @Override
+ public void updateSize() {
+ if (npc == null) {
+ super.updateSize();
+ } else {
+ NMSImpl.setSize(this, justCreated);
+ }
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/SquidController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/SquidController.java
new file mode 100644
index 000000000..9c65f5684
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/SquidController.java
@@ -0,0 +1,204 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import net.minecraft.server.v1_14_R1.Vec3D;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntitySquid;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntitySquid> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntitySquidNPC(EntityTypes extends EntitySquid> types, World world, NPC npc) {
+ super(types, 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 e(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void b(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new SquidNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @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 void updateSize() {
+ if (npc == null) {
+ super.updateSize();
+ } else {
+ NMSImpl.setSize(this, justCreated);
+ }
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/TraderLlamaController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/TraderLlamaController.java
new file mode 100644
index 000000000..a3d174757
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/TraderLlamaController.java
@@ -0,0 +1,231 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftTraderLlama;
+import org.bukkit.entity.TraderLlama;
+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_14_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_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.DataWatcherObject;
+import net.minecraft.server.v1_14_R1.EntityLLamaTrader;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_R1.World;
+
+public class TraderLlamaController extends MobEntityController {
+ public TraderLlamaController() {
+ super(EntityTraderLlamaNPC.class);
+ }
+
+ @Override
+ public TraderLlama getBukkitEntity() {
+ return (TraderLlama) super.getBukkitEntity();
+ }
+
+ @Override
+ public void spawn(Location at, NPC npc) {
+ npc.getTrait(HorseModifiers.class);
+ super.spawn(at, npc);
+ }
+
+ public static class EntityTraderLlamaNPC extends EntityLLamaTrader implements NPCHolder {
+ boolean calledNMSHeight = false;
+
+ private final CitizensNPC npc;
+
+ public EntityTraderLlamaNPC(EntityTypes extends EntityLLamaTrader> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityTraderLlamaNPC(EntityTypes extends EntityLLamaTrader> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ ((TraderLlama) getBukkitEntity())
+ .setDomestication(((TraderLlama) getBukkitEntity()).getMaxDomestication());
+ }
+ }
+
+ @Override
+ public void a(DataWatcherObject> datawatcherobject) {
+ if (npc != null && !calledNMSHeight) {
+ calledNMSHeight = true;
+ NMSImpl.checkAndUpdateHeight(this, datawatcherobject);
+ calledNMSHeight = false;
+ }
+
+ super.a(datawatcherobject);
+ }
+
+ @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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder)) {
+ bukkitEntity = new TraderLlamaNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void mobTick() {
+ if (npc == null) {
+ super.mobTick();
+ } else {
+ NMS.setStepHeight(getBukkitEntity(), 1);
+ npc.update();
+ }
+ }
+ }
+
+ public static class TraderLlamaNPC extends CraftTraderLlama implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public TraderLlamaNPC(EntityTraderLlamaNPC 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/TropicalFishController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/TropicalFishController.java
new file mode 100644
index 000000000..4d14ac5c8
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/TropicalFishController.java
@@ -0,0 +1,208 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import net.minecraft.server.v1_14_R1.Vec3D;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftTropicalFish;
+import org.bukkit.entity.TropicalFish;
+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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.ControllerMove;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityTropicalFish;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.World;
+
+public class TropicalFishController extends MobEntityController {
+ public TropicalFishController() {
+ super(EntityTropicalFishNPC.class);
+ }
+
+ @Override
+ public TropicalFish getBukkitEntity() {
+ return (TropicalFish) super.getBukkitEntity();
+ }
+
+ public static class EntityTropicalFishNPC extends EntityTropicalFish implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityTropicalFishNPC(EntityTypes extends EntityTropicalFish> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityTropicalFishNPC(EntityTypes extends EntityTropicalFish> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ this.moveController = new ControllerMove(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 e(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void b(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new TropicalFishNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @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 void mobTick() {
+ if (npc != null) {
+ NMSImpl.setNotInSchool(this);
+ }
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+ }
+
+ public static class TropicalFishNPC extends CraftTropicalFish implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public TropicalFishNPC(EntityTropicalFishNPC 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/TurtleController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/TurtleController.java
new file mode 100644
index 000000000..d9478a948
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/TurtleController.java
@@ -0,0 +1,219 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftTurtle;
+import org.bukkit.entity.Turtle;
+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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.ControllerJump;
+import net.minecraft.server.v1_14_R1.ControllerMove;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityInsentient;
+import net.minecraft.server.v1_14_R1.EntityTurtle;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_R1.World;
+
+public class TurtleController extends MobEntityController {
+ public TurtleController() {
+ super(EntityTurtleNPC.class);
+ }
+
+ @Override
+ public Turtle getBukkitEntity() {
+ return (Turtle) super.getBukkitEntity();
+ }
+
+ public static class EntityTurtleNPC extends EntityTurtle implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityTurtleNPC(EntityTypes extends EntityTurtle> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityTurtleNPC(EntityTypes extends EntityTurtle> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ this.moveController = new ControllerMove(this);
+ this.bt = new EmptyControllerJump(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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new TurtleNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ static class EmptyControllerJump extends ControllerJump {
+
+ public EmptyControllerJump(EntityInsentient var1) {
+ super(var1);
+ }
+
+ @Override
+ public void b() {
+ this.a = false;
+ }
+ }
+ }
+
+ public static class TurtleNPC extends CraftTurtle implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public TurtleNPC(EntityTurtleNPC entity) {
+ super((CraftServer) Bukkit.getServer(), entity);
+ this.npc = entity.npc;
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+ }
+}
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/VexController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/VexController.java
new file mode 100644
index 000000000..f2d611eb7
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/VexController.java
@@ -0,0 +1,172 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import net.minecraft.server.v1_14_R1.Vec3D;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.EntityVex;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityVex> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityVexNPC(EntityTypes extends EntityVex> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ setNoGravity(true);
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new VexNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/VillagerController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/VillagerController.java
new file mode 100644
index 000000000..de1aebca1
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/VillagerController.java
@@ -0,0 +1,261 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import java.util.List;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.DataWatcherObject;
+import net.minecraft.server.v1_14_R1.EntityHuman;
+import net.minecraft.server.v1_14_R1.EntityLightning;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.EntityVillager;
+import net.minecraft.server.v1_14_R1.EnumHand;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.MerchantRecipe;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_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;
+ boolean calledNMSHeight = false;
+
+ private final CitizensNPC npc;
+
+ public EntityVillagerNPC(EntityTypes extends EntityVillager> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityVillagerNPC(EntityTypes extends EntityVillager> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ public void a(DataWatcherObject> datawatcherobject) {
+ if (npc != null && !calledNMSHeight) {
+ calledNMSHeight = true;
+ NMSImpl.checkAndUpdateHeight(this, datawatcherobject);
+ calledNMSHeight = false;
+ }
+
+ super.a(datawatcherobject);
+ }
+
+ @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();
+ if (list != null) {
+ list.clear();
+ }
+ }
+ return super.a(entityhuman, enumhand);
+ }
+
+ @Override
+ public void b(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 dX() {
+ if (blockingATrade) {
+ blockingATrade = false;
+ return true;
+ }
+ return super.dX();
+ }
+
+ @Override
+ public void e(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new VillagerNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ public boolean isBlockingTrades() {
+ return blockTrades;
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public void onLightningStrike(EntityLightning entitylightning) {
+ if (npc == null) {
+ super.onLightningStrike(entitylightning);
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/VindicatorController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/VindicatorController.java
new file mode 100644
index 000000000..d6ec231f6
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/VindicatorController.java
@@ -0,0 +1,217 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.DataWatcherObject;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.EntityVindicator;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_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 {
+ boolean calledNMSHeight = false;
+
+ private final CitizensNPC npc;
+
+ public EntityVindicatorNPC(EntityTypes extends EntityVindicator> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityVindicatorNPC(EntityTypes extends EntityVindicator> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ public void a(DataWatcherObject> datawatcherobject) {
+ if (npc != null && !calledNMSHeight) {
+ calledNMSHeight = true;
+ NMSImpl.checkAndUpdateHeight(this, datawatcherobject);
+ calledNMSHeight = false;
+ }
+
+ super.a(datawatcherobject);
+ }
+
+ @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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new VindicatorNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/WanderingTraderController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/WanderingTraderController.java
new file mode 100644
index 000000000..e367da506
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/WanderingTraderController.java
@@ -0,0 +1,260 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import java.util.List;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftWanderingTrader;
+import org.bukkit.entity.WanderingTrader;
+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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.DataWatcherObject;
+import net.minecraft.server.v1_14_R1.EntityHuman;
+import net.minecraft.server.v1_14_R1.EntityLightning;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.EntityVillagerTrader;
+import net.minecraft.server.v1_14_R1.EnumHand;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.MerchantRecipe;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_R1.World;
+
+public class WanderingTraderController extends MobEntityController {
+ public WanderingTraderController() {
+ super(EntityWanderingTraderNPC.class);
+ }
+
+ @Override
+ public WanderingTrader getBukkitEntity() {
+ return (WanderingTrader) super.getBukkitEntity();
+ }
+
+ public static class EntityWanderingTraderNPC extends EntityVillagerTrader implements NPCHolder {
+ private boolean blockingATrade;
+ private boolean blockTrades = true;
+ boolean calledNMSHeight = false;
+ private final CitizensNPC npc;
+
+ public EntityWanderingTraderNPC(EntityTypes extends EntityVillagerTrader> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityWanderingTraderNPC(EntityTypes extends EntityVillagerTrader> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ public void a(DataWatcherObject> datawatcherobject) {
+ if (npc != null && !calledNMSHeight) {
+ calledNMSHeight = true;
+ NMSImpl.checkAndUpdateHeight(this, datawatcherobject);
+ calledNMSHeight = false;
+ }
+
+ super.a(datawatcherobject);
+ }
+
+ @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();
+ if (list != null) {
+ list.clear();
+ }
+ }
+ return super.a(entityhuman, enumhand);
+ }
+
+ @Override
+ public void b(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 dX() {
+ if (blockingATrade) {
+ blockingATrade = false;
+ return true;
+ }
+ return super.dX();
+ }
+
+ @Override
+ public void e(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new WanderingTraderNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ public boolean isBlockingTrades() {
+ return blockTrades;
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public void onLightningStrike(EntityLightning entitylightning) {
+ if (npc == null) {
+ super.onLightningStrike(entitylightning);
+ }
+ }
+
+ public void setBlockTrades(boolean blocked) {
+ this.blockTrades = blocked;
+ }
+ }
+
+ public static class WanderingTraderNPC extends CraftWanderingTrader implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public WanderingTraderNPC(EntityWanderingTraderNPC 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/WitchController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/WitchController.java
new file mode 100644
index 000000000..c5ab9257b
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/WitchController.java
@@ -0,0 +1,211 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import net.minecraft.server.v1_14_R1.Vec3D;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.EntityWitch;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityWitch> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityWitchNPC(EntityTypes extends EntityWitch> types, World world, NPC npc) {
+ super(types, 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 e(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void b(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new WitchNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null)
+ npc.update();
+ }
+
+ @Override
+ public void updateSize() {
+ if (npc == null) {
+ super.updateSize();
+ } else {
+ NMSImpl.setSize(this, justCreated);
+ }
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/WitherController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/WitherController.java
new file mode 100644
index 000000000..2c403b62c
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/WitherController.java
@@ -0,0 +1,175 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import net.minecraft.server.v1_14_R1.Vec3D;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.EntityWither;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityWither> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityWitherNPC(EntityTypes extends EntityWither> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new WitherNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @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 int l(int i) {
+ return npc == null ? super.l(i) : 0;
+ }
+
+ @Override
+ protected void mobTick() {
+ if (npc == null) {
+ super.mobTick();
+ } 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/WolfController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/WolfController.java
new file mode 100644
index 000000000..520fa7be8
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/WolfController.java
@@ -0,0 +1,229 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.DataWatcherObject;
+import net.minecraft.server.v1_14_R1.EntityLiving;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.EntityWolf;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_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 {
+ boolean calledNMSHeight = false;
+
+ private final CitizensNPC npc;
+
+ public EntityWolfNPC(EntityTypes extends EntityWolf> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityWolfNPC(EntityTypes extends EntityWolf> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ if (npc != null) {
+ NMSImpl.clearGoals(goalSelector, targetSelector);
+ }
+ }
+
+ @Override
+ public void a(DataWatcherObject> datawatcherobject) {
+ if (npc != null && !calledNMSHeight) {
+ calledNMSHeight = true;
+ NMSImpl.checkAndUpdateHeight(this, datawatcherobject);
+ calledNMSHeight = false;
+ }
+
+ super.a(datawatcherobject);
+ }
+
+ @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(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void enderTeleportTo(double d0, double d1, double d2) {
+ if (npc == null) {
+ super.enderTeleportTo(d0, d1, d2);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new WolfNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } else {
+ return false;
+ }
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean setGoalTarget(EntityLiving entityliving, EntityTargetEvent.TargetReason reason, boolean fire) {
+ return npc == null || this.equals(entityliving) ? super.setGoalTarget(entityliving, 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/ZombieController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/ZombieController.java
new file mode 100644
index 000000000..05d5b9b85
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/ZombieController.java
@@ -0,0 +1,203 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import net.minecraft.server.v1_14_R1.Vec3D;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.EntityZombie;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityZombie> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityZombieNPC(EntityTypes extends EntityZombie> types, World world, NPC npc) {
+ super(types, 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 e(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void b(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new ZombieNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/ZombieHuskController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/ZombieHuskController.java
new file mode 100644
index 000000000..7e3bd98f1
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/ZombieHuskController.java
@@ -0,0 +1,203 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import net.minecraft.server.v1_14_R1.Vec3D;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.EntityZombieHusk;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityZombieHusk> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityZombieHuskNPC(EntityTypes extends EntityZombieHusk> types, World world, NPC npc) {
+ super(types, 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 e(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void b(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new ZombieHuskNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ protected SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ protected SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/ZombieVillagerController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/ZombieVillagerController.java
new file mode 100644
index 000000000..b4ae048fb
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/ZombieVillagerController.java
@@ -0,0 +1,203 @@
+package net.citizensnpcs.nms.v1_14_R1.entity;
+
+import net.minecraft.server.v1_14_R1.Vec3D;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.EntityZombieVillager;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.SoundEffect;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityZombieVillager> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityZombieVillagerNPC(EntityTypes extends EntityZombieVillager> types, World world, NPC npc) {
+ super(types, 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 e(Vec3D vec3d) {
+ if (npc == null || !npc.isFlyable()) {
+ super.e(vec3d);
+ } else {
+ NMSImpl.flyingMoveLogic(this, vec3d);
+ }
+ }
+
+ @Override
+ public void b(float f, float f1) {
+ if (npc == null || !npc.isFlyable()) {
+ super.b(f, f1);
+ }
+ }
+
+ @Override
+ protected void checkDespawn() {
+ if (npc == null) {
+ super.checkDespawn();
+ }
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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);
+ return;
+ }
+ 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 CraftEntity getBukkitEntity() {
+ if (npc != null && !(bukkitEntity instanceof NPCHolder))
+ bukkitEntity = new ZombieVillagerNPC(this);
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public SoundEffect getSoundAmbient() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundAmbient(), NPC.AMBIENT_SOUND_METADATA);
+ }
+
+ @Override
+ public SoundEffect getSoundDeath() {
+ return NMSImpl.getSoundEffect(npc, super.getSoundDeath(), NPC.DEATH_SOUND_METADATA);
+ }
+
+ @Override
+ public SoundEffect getSoundHurt(DamageSource damagesource) {
+ return NMSImpl.getSoundEffect(npc, super.getSoundHurt(damagesource), NPC.HURT_SOUND_METADATA);
+ }
+
+ @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 void mobTick() {
+ super.mobTick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+
+ @Override
+ public boolean isClimbing() {
+ if (npc == null || !npc.isFlyable()) {
+ return super.isClimbing();
+ } 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/AreaEffectCloudController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/AreaEffectCloudController.java
new file mode 100644
index 000000000..0f1b64aa0
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/AreaEffectCloudController.java
@@ -0,0 +1,116 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftAreaEffectCloud;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.EntityAreaEffectCloud;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityAreaEffectCloud> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityAreaEffectCloudNPC(EntityTypes extends EntityAreaEffectCloud> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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;
+ }
+
+ @Override
+ public void tick() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.tick();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/ArmorStandController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/ArmorStandController.java
new file mode 100644
index 000000000..78478af36
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/ArmorStandController.java
@@ -0,0 +1,132 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftArmorStand;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.EntityArmorStand;
+import net.minecraft.server.v1_14_R1.EntityHuman;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.EnumHand;
+import net.minecraft.server.v1_14_R1.EnumInteractionResult;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityArmorStand> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityArmorStandNPC(EntityTypes extends EntityArmorStand> types, World world, NPC npc) {
+ super(types, 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 collide(net.minecraft.server.v1_14_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;
+ }
+
+ @Override
+ public void tick() {
+ super.tick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/BoatController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/BoatController.java
new file mode 100644
index 000000000..002452552
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/BoatController.java
@@ -0,0 +1,126 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftBoat;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.entity.MobEntityController;
+import net.citizensnpcs.nms.v1_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.EntityBoat;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityBoat> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityBoatNPC(EntityTypes extends EntityBoat> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 updateSize() {
+ if (npc == null) {
+ super.updateSize();
+ } else {
+ NMSImpl.setSize(this, justCreated);
+ }
+ }
+
+ @Override
+ public void tick() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.tick();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/DragonFireballController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/DragonFireballController.java
new file mode 100644
index 000000000..cc649ac62
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/DragonFireballController.java
@@ -0,0 +1,129 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftDragonFireball;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.entity.MobEntityController;
+import net.citizensnpcs.nms.v1_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.EntityDragonFireball;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityDragonFireball> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityDragonFireballNPC(EntityTypes extends EntityDragonFireball> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 updateSize() {
+ if (npc == null) {
+ super.updateSize();
+ } else {
+ NMSImpl.setSize(this, justCreated);
+ }
+ }
+
+ @Override
+ public void tick() {
+ if (npc != null) {
+ npc.update();
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true)) {
+ super.tick();
+ }
+ } else {
+ super.tick();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/EggController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/EggController.java
new file mode 100644
index 000000000..f0870d3e1
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/EggController.java
@@ -0,0 +1,135 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.CraftWorld;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEgg;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.entity.Egg;
+import org.bukkit.entity.Entity;
+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_14_R1.EntityEgg;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.World;
+import net.minecraft.server.v1_14_R1.WorldServer;
+
+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(EntityTypes extends EntityEgg> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityEggNPC(EntityTypes extends EntityEgg> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ 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_14_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 EggNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void tick() {
+ if (npc != null) {
+ npc.update();
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true)) {
+ super.tick();
+ }
+ } else {
+ super.tick();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/EnderCrystalController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/EnderCrystalController.java
new file mode 100644
index 000000000..f5b1e69ee
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/EnderCrystalController.java
@@ -0,0 +1,116 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEnderCrystal;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.entity.EnderCrystal;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_14_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.EntityEnderCrystal;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.World;
+
+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(EntityTypes extends EntityEnderCrystal> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityEnderCrystalNPC(EntityTypes extends EntityEnderCrystal> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 EnderCrystalNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void tick() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.tick();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/EnderPearlController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/EnderPearlController.java
new file mode 100644
index 000000000..349020810
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/EnderPearlController.java
@@ -0,0 +1,119 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEnderPearl;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.EntityEnderPearl;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityEnderPearl> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityEnderPearlNPC(EntityTypes extends EntityEnderPearl> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 tick() {
+ if (npc != null) {
+ npc.update();
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true)) {
+ super.tick();
+ }
+ } else {
+ super.tick();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/EnderSignalController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/EnderSignalController.java
new file mode 100644
index 000000000..e6880a8c2
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/EnderSignalController.java
@@ -0,0 +1,116 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEnderSignal;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.entity.EnderSignal;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_14_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.EntityEnderSignal;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.World;
+
+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(EntityTypes extends EntityEnderSignal> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityEnderSignalNPC(EntityTypes extends EntityEnderSignal> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 EnderSignalNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void tick() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.tick();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/EvokerFangsController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/EvokerFangsController.java
new file mode 100644
index 000000000..82e1feb0c
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/EvokerFangsController.java
@@ -0,0 +1,132 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.EntityEvokerFangs;
+import net.minecraft.server.v1_14_R1.EntityHuman;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.EnumHand;
+import net.minecraft.server.v1_14_R1.EnumInteractionResult;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityEvokerFangs> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityEvokerFangsNPC(EntityTypes extends EntityEvokerFangs> types, World world, NPC npc) {
+ super(types, 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 collide(net.minecraft.server.v1_14_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;
+ }
+
+ @Override
+ public void tick() {
+ super.tick();
+ if (npc != null) {
+ npc.update();
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/ExperienceOrbController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/ExperienceOrbController.java
new file mode 100644
index 000000000..b4fcca221
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/ExperienceOrbController.java
@@ -0,0 +1,116 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftExperienceOrb;
+import org.bukkit.entity.ExperienceOrb;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_14_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.EntityExperienceOrb;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.World;
+
+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(EntityTypes extends EntityExperienceOrb> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityExperienceOrbNPC(EntityTypes extends EntityExperienceOrb> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 tick() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.tick();
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/FallingBlockController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/FallingBlockController.java
new file mode 100644
index 000000000..1c0e1e75a
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/FallingBlockController.java
@@ -0,0 +1,177 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.CraftWorld;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftFallingBlock;
+import org.bukkit.craftbukkit.v1_14_R1.util.CraftMagicNumbers;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.FallingBlock;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.DespawnReason;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.event.SpawnReason;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_14_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_14_R1.Block;
+import net.minecraft.server.v1_14_R1.Blocks;
+import net.minecraft.server.v1_14_R1.EntityFallingBlock;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.EnumMoveType;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.Vec3D;
+import net.minecraft.server.v1_14_R1.World;
+import net.minecraft.server.v1_14_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));
+ // TODO: how to incorporate this - probably delete?
+ 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.getBlockData());
+ 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(EntityTypes extends EntityFallingBlock> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityFallingBlockNPC(EntityTypes extends EntityFallingBlock> types, World world, NPC npc) {
+ super(types, 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 collide(net.minecraft.server.v1_14_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 tick() {
+ if (npc != null) {
+ npc.update();
+ Vec3D mot = getMot();
+ if (Math.abs(mot.getX()) > EPSILON || Math.abs(mot.getY()) > EPSILON
+ || Math.abs(mot.getZ()) > EPSILON) {
+ mot = mot.d(0.98, 0.98, 0.98);
+ setMot(mot);
+ move(EnumMoveType.SELF, mot);
+ }
+ } else {
+ super.tick();
+ }
+ }
+
+ @Override
+ public void updateSize() {
+ if (npc == null) {
+ super.updateSize();
+ } else {
+ NMSImpl.setSize(this, 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(DespawnReason.PENDING_RESPAWN);
+ npc.spawn(npc.getStoredLocation(), SpawnReason.RESPAWN);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/FireworkController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/FireworkController.java
new file mode 100644
index 000000000..97f833a0e
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/FireworkController.java
@@ -0,0 +1,116 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftFirework;
+import org.bukkit.entity.Firework;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_14_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.EntityFireworks;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.World;
+
+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(EntityTypes extends EntityFireworks> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityFireworkNPC(EntityTypes extends EntityFireworks> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 FireworkNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void tick() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.tick();
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/FishingHookController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/FishingHookController.java
new file mode 100644
index 000000000..aac0d9c26
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/FishingHookController.java
@@ -0,0 +1,116 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftFishHook;
+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_14_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.EntityFishingHook;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityFishingHook> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityFishingHookNPC(EntityTypes extends EntityFishingHook> types, World world, NPC npc) {
+ super(null, world, 0, 0); // TODO this is totally broken
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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;
+ }
+
+ @Override
+ public void tick() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.tick();
+ }
+ }
+ }
+
+ public static class FishingHookNPC extends CraftFishHook 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/ItemController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/ItemController.java
new file mode 100644
index 000000000..2311fc5bd
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/ItemController.java
@@ -0,0 +1,156 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.CraftWorld;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftItem;
+import org.bukkit.craftbukkit.v1_14_R1.inventory.CraftItemStack;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.Item;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.DespawnReason;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.event.SpawnReason;
+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_14_R1.EntityHuman;
+import net.minecraft.server.v1_14_R1.EntityItem;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.ItemStack;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.World;
+import net.minecraft.server.v1_14_R1.WorldServer;
+
+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(EntityTypes extends EntityItem> types, World world) {
+ super(types, 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_14_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 ItemNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void pickup(EntityHuman entityhuman) {
+ if (npc == null) {
+ super.pickup(entityhuman);
+ }
+ }
+
+ @Override
+ public void tick() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.tick();
+ }
+ }
+ }
+
+ 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(DespawnReason.PENDING_RESPAWN);
+ npc.spawn(npc.getStoredLocation(), SpawnReason.RESPAWN);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/ItemFrameController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/ItemFrameController.java
new file mode 100644
index 000000000..bb75371f6
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/ItemFrameController.java
@@ -0,0 +1,153 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftItemFrame;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.ItemFrame;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.DespawnReason;
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.event.SpawnReason;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_14_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.EntityItemFrame;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.EnumDirection;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityItemFrame> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityItemFrameNPC(EntityTypes extends EntityItemFrame> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 tick() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.tick();
+ }
+ }
+ }
+
+ 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(DespawnReason.PENDING_RESPAWN);
+ npc.spawn(npc.getStoredLocation(), SpawnReason.RESPAWN);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/LargeFireballController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/LargeFireballController.java
new file mode 100644
index 000000000..6169943c0
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/LargeFireballController.java
@@ -0,0 +1,129 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.entity.MobEntityController;
+import net.citizensnpcs.nms.v1_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.EntityLargeFireball;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityLargeFireball> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityLargeFireballNPC(EntityTypes extends EntityLargeFireball> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 updateSize() {
+ if (npc == null) {
+ super.updateSize();
+ } else {
+ NMSImpl.setSize(this, justCreated);
+ }
+ }
+
+ @Override
+ public void tick() {
+ if (npc != null) {
+ npc.update();
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true)) {
+ super.tick();
+ }
+ } else {
+ super.tick();
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/LeashController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/LeashController.java
new file mode 100644
index 000000000..434e5ca0c
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/LeashController.java
@@ -0,0 +1,121 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftLeash;
+import org.bukkit.entity.LeashHitch;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_14_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.EntityLeash;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.World;
+
+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(EntityTypes extends EntityLeash> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityLeashNPC(EntityTypes extends EntityLeash> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 boolean survives() {
+ return npc == null || !npc.isProtected() ? super.survives() : true;
+ }
+
+ @Override
+ public void tick() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.tick();
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/LlamaSpitController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/LlamaSpitController.java
new file mode 100644
index 000000000..4560d483a
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/LlamaSpitController.java
@@ -0,0 +1,139 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.CraftWorld;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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.nms.v1_14_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_14_R1.EntityLlama;
+import net.minecraft.server.v1_14_R1.EntityLlamaSpit;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.World;
+import net.minecraft.server.v1_14_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(
+ NMSImpl. getEntityType(EntityLlamaSpitNPC.class), 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(EntityTypes extends EntityLlamaSpit> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityLlamaSpitNPC(EntityTypes extends EntityLlamaSpit> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ public EntityLlamaSpitNPC(World world, NPC npc, EntityLlama entity) {
+ super(world, entity);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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;
+ }
+
+ @Override
+ public void tick() {
+ if (npc != null) {
+ npc.update();
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true)) {
+ super.tick();
+ }
+ } else {
+ super.tick();
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/MinecartChestController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/MinecartChestController.java
new file mode 100644
index 000000000..b8dba9045
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/MinecartChestController.java
@@ -0,0 +1,126 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.entity.MobEntityController;
+import net.citizensnpcs.nms.v1_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityMinecartChest;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityMinecartChest> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityMinecartChestNPC(EntityTypes extends EntityMinecartChest> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 tick() {
+ super.tick();
+ if (npc != null) {
+ npc.update();
+ NMSImpl.minecartItemLogic(this);
+ }
+ }
+
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/MinecartCommandController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/MinecartCommandController.java
new file mode 100644
index 000000000..681d765e8
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/MinecartCommandController.java
@@ -0,0 +1,125 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.entity.MobEntityController;
+import net.citizensnpcs.nms.v1_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityMinecartCommandBlock;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityMinecartCommandBlock> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityMinecartCommandNPC(EntityTypes extends EntityMinecartCommandBlock> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 tick() {
+ super.tick();
+ if (npc != null) {
+ npc.update();
+ NMSImpl.minecartItemLogic(this);
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/MinecartFurnaceController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/MinecartFurnaceController.java
new file mode 100644
index 000000000..e444353c1
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/MinecartFurnaceController.java
@@ -0,0 +1,125 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.entity.MobEntityController;
+import net.citizensnpcs.nms.v1_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityMinecartFurnace;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityMinecartFurnace> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityMinecartFurnaceNPC(EntityTypes extends EntityMinecartFurnace> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 tick() {
+ super.tick();
+ if (npc != null) {
+ npc.update();
+ NMSImpl.minecartItemLogic(this);
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/MinecartHopperController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/MinecartHopperController.java
new file mode 100644
index 000000000..496609369
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/MinecartHopperController.java
@@ -0,0 +1,99 @@
+package net.citizensnpcs.nms.v1_14_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_14_R1.entity.MobEntityController;
+import net.citizensnpcs.nms.v1_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityMinecartHopper;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityMinecartHopper> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityMinecartHopperNPC(EntityTypes extends EntityMinecartHopper> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 tick() {
+ super.tick();
+ if (npc != null) {
+ npc.update();
+ NMSImpl.minecartItemLogic(this);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/MinecartRideableController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/MinecartRideableController.java
new file mode 100644
index 000000000..fe5601359
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/MinecartRideableController.java
@@ -0,0 +1,125 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.entity.MobEntityController;
+import net.citizensnpcs.nms.v1_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityMinecartRideable;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityMinecartRideable> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityMinecartRideableNPC(EntityTypes extends EntityMinecartRideable> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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;
+ }
+
+ @Override
+ public void tick() {
+ super.tick();
+ if (npc != null) {
+ npc.update();
+ NMSImpl.minecartItemLogic(this);
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/MinecartSpawnerController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/MinecartSpawnerController.java
new file mode 100644
index 000000000..edbb39bfa
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/MinecartSpawnerController.java
@@ -0,0 +1,100 @@
+package net.citizensnpcs.nms.v1_14_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_14_R1.entity.MobEntityController;
+import net.citizensnpcs.nms.v1_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityMinecartMobSpawner;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityMinecartMobSpawner> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityMinecartSpawnerNPC(EntityTypes extends EntityMinecartMobSpawner> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 tick() {
+ super.tick();
+ if (npc != null) {
+ npc.update();
+ NMSImpl.minecartItemLogic(this);
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/MinecartTNTController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/MinecartTNTController.java
new file mode 100644
index 000000000..21796b940
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/MinecartTNTController.java
@@ -0,0 +1,99 @@
+package net.citizensnpcs.nms.v1_14_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_14_R1.entity.MobEntityController;
+import net.citizensnpcs.nms.v1_14_R1.util.NMSImpl;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.DamageSource;
+import net.minecraft.server.v1_14_R1.EntityMinecartTNT;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityMinecartTNT> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityMinecartTNTNPC(EntityTypes extends EntityMinecartTNT> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 tick() {
+ super.tick();
+ if (npc != null) {
+ npc.update();
+ NMSImpl.minecartItemLogic(this);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/PaintingController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/PaintingController.java
new file mode 100644
index 000000000..9b8327450
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/PaintingController.java
@@ -0,0 +1,121 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPainting;
+import org.bukkit.entity.Painting;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_14_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.EntityPainting;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.World;
+
+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(EntityTypes extends EntityPainting> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityPaintingNPC(EntityTypes extends EntityPainting> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 PaintingNPC(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 tick() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.tick();
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/ShulkerBulletController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/ShulkerBulletController.java
new file mode 100644
index 000000000..5bb480913
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/ShulkerBulletController.java
@@ -0,0 +1,116 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.EntityShulkerBullet;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityShulkerBullet> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityShulkerBulletNPC(EntityTypes extends EntityShulkerBullet> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 tick() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.tick();
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/SmallFireballController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/SmallFireballController.java
new file mode 100644
index 000000000..fb8c158f2
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/SmallFireballController.java
@@ -0,0 +1,119 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.EntitySmallFireball;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntitySmallFireball> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntitySmallFireballNPC(EntityTypes extends EntitySmallFireball> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 tick() {
+ if (npc != null) {
+ npc.update();
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true)) {
+ super.tick();
+ }
+ } else {
+ super.tick();
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/SnowballController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/SnowballController.java
new file mode 100644
index 000000000..b811c861b
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/SnowballController.java
@@ -0,0 +1,116 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftSnowball;
+import org.bukkit.entity.Snowball;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_14_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.EntitySnowball;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.World;
+
+public class SnowballController extends MobEntityController {
+ public SnowballController() {
+ super(EntitySnowballNPC.class);
+ }
+
+ @Override
+ public Snowball getBukkitEntity() {
+ return (Snowball) super.getBukkitEntity();
+ }
+
+ public static class EntitySnowballNPC extends EntitySnowball implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntitySnowballNPC(EntityTypes extends EntitySnowball> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntitySnowballNPC(EntityTypes extends EntitySnowball> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 SnowballNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void tick() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.tick();
+ }
+ }
+ }
+
+ 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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/SpectralArrowController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/SpectralArrowController.java
new file mode 100644
index 000000000..16132725c
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/SpectralArrowController.java
@@ -0,0 +1,116 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftArrow;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.EntitySpectralArrow;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntitySpectralArrow> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntitySpectralArrowNPC(EntityTypes extends EntitySpectralArrow> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 tick() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.tick();
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/TNTPrimedController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/TNTPrimedController.java
new file mode 100644
index 000000000..10c67402a
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/TNTPrimedController.java
@@ -0,0 +1,116 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftTNTPrimed;
+import org.bukkit.entity.TNTPrimed;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_14_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.EntityTNTPrimed;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.World;
+
+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(EntityTypes extends EntityTNTPrimed> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityTNTPrimedNPC(EntityTypes extends EntityTNTPrimed> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 TNTPrimedNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void tick() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.tick();
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/ThrownExpBottleController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/ThrownExpBottleController.java
new file mode 100644
index 000000000..f6b9ae71b
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/ThrownExpBottleController.java
@@ -0,0 +1,119 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.EntityThrownExpBottle;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityThrownExpBottle> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityThrownExpBottleNPC(EntityTypes extends EntityThrownExpBottle> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 tick() {
+ if (npc != null) {
+ npc.update();
+ if (!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true)) {
+ super.tick();
+ }
+ } else {
+ super.tick();
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/ThrownPotionController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/ThrownPotionController.java
new file mode 100644
index 000000000..f9d8da531
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/ThrownPotionController.java
@@ -0,0 +1,135 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftThrownPotion;
+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_14_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.EntityPotion;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.Items;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityPotion> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityThrownPotionNPC(EntityTypes extends EntityPotion> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 tick() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.tick();
+ }
+ }
+ }
+
+ public static class LingeringThrownPotionNPC extends CraftThrownPotion 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 CraftThrownPotion 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/ThrownTridentController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/ThrownTridentController.java
new file mode 100644
index 000000000..b3f5e6a98
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/ThrownTridentController.java
@@ -0,0 +1,116 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftTrident;
+import org.bukkit.entity.Trident;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_14_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.EntityThrownTrident;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.World;
+
+public class ThrownTridentController extends MobEntityController {
+ public ThrownTridentController() {
+ super(EntityThrownTridentNPC.class);
+ }
+
+ @Override
+ public Trident getBukkitEntity() {
+ return (Trident) super.getBukkitEntity();
+ }
+
+ public static class EntityThrownTridentNPC extends EntityThrownTrident implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public EntityThrownTridentNPC(EntityTypes extends EntityThrownTrident> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityThrownTridentNPC(EntityTypes extends EntityThrownTrident> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 ThrownTridentNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void tick() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.tick();
+ }
+ }
+ }
+
+ public static class ThrownTridentNPC extends CraftTrident implements NPCHolder {
+ private final CitizensNPC npc;
+
+ public ThrownTridentNPC(EntityThrownTridentNPC 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/TippedArrowController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/TippedArrowController.java
new file mode 100644
index 000000000..f123bdcfa
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/TippedArrowController.java
@@ -0,0 +1,116 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftArrow;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.EntityTippedArrow;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_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(EntityTypes extends EntityTippedArrow> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityTippedArrowNPC(EntityTypes extends EntityTippedArrow> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 tick() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.tick();
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/WitherSkullController.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/WitherSkullController.java
new file mode 100644
index 000000000..49dfa426c
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/entity/nonliving/WitherSkullController.java
@@ -0,0 +1,116 @@
+package net.citizensnpcs.nms.v1_14_R1.entity.nonliving;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_14_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftWitherSkull;
+import org.bukkit.entity.WitherSkull;
+import org.bukkit.util.Vector;
+
+import net.citizensnpcs.api.event.NPCPushEvent;
+import net.citizensnpcs.api.npc.NPC;
+import net.citizensnpcs.nms.v1_14_R1.entity.MobEntityController;
+import net.citizensnpcs.npc.CitizensNPC;
+import net.citizensnpcs.npc.ai.NPCHolder;
+import net.citizensnpcs.util.Util;
+import net.minecraft.server.v1_14_R1.EntityTypes;
+import net.minecraft.server.v1_14_R1.EntityWitherSkull;
+import net.minecraft.server.v1_14_R1.NBTTagCompound;
+import net.minecraft.server.v1_14_R1.World;
+
+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(EntityTypes extends EntityWitherSkull> types, World world) {
+ this(types, world, null);
+ }
+
+ public EntityWitherSkullNPC(EntityTypes extends EntityWitherSkull> types, World world, NPC npc) {
+ super(types, world);
+ this.npc = (CitizensNPC) npc;
+ }
+
+ @Override
+ public void collide(net.minecraft.server.v1_14_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 WitherSkullNPC(this);
+ }
+ return super.getBukkitEntity();
+ }
+
+ @Override
+ public NPC getNPC() {
+ return npc;
+ }
+
+ @Override
+ public void tick() {
+ if (npc != null) {
+ npc.update();
+ } else {
+ super.tick();
+ }
+ }
+ }
+
+ 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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/network/EmptyChannel.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/network/EmptyChannel.java
new file mode 100644
index 000000000..f1b8adbc6
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/network/EmptyChannel.java
@@ -0,0 +1,80 @@
+package net.citizensnpcs.nms.v1_14_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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/network/EmptyNetHandler.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/network/EmptyNetHandler.java
new file mode 100644
index 000000000..340f869f1
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/network/EmptyNetHandler.java
@@ -0,0 +1,17 @@
+package net.citizensnpcs.nms.v1_14_R1.network;
+
+import net.minecraft.server.v1_14_R1.EntityPlayer;
+import net.minecraft.server.v1_14_R1.MinecraftServer;
+import net.minecraft.server.v1_14_R1.NetworkManager;
+import net.minecraft.server.v1_14_R1.Packet;
+import net.minecraft.server.v1_14_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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/network/EmptyNetworkManager.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/network/EmptyNetworkManager.java
new file mode 100644
index 000000000..938f72b28
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/network/EmptyNetworkManager.java
@@ -0,0 +1,25 @@
+package net.citizensnpcs.nms.v1_14_R1.network;
+
+import java.io.IOException;
+
+import io.netty.util.concurrent.GenericFutureListener;
+import net.citizensnpcs.nms.v1_14_R1.util.NMSImpl;
+import net.minecraft.server.v1_14_R1.EnumProtocolDirection;
+import net.minecraft.server.v1_14_R1.NetworkManager;
+import net.minecraft.server.v1_14_R1.Packet;
+
+public class EmptyNetworkManager extends NetworkManager {
+ public EmptyNetworkManager(EnumProtocolDirection flag) throws IOException {
+ super(flag);
+ NMSImpl.initNetworkManager(this);
+ }
+
+ @Override
+ public boolean isConnected() {
+ return true;
+ }
+
+ @Override
+ public void sendPacket(Packet packet, GenericFutureListener genericfuturelistener) {
+ }
+}
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/network/EmptySocket.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/network/EmptySocket.java
new file mode 100644
index 000000000..c8946d741
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/network/EmptySocket.java
@@ -0,0 +1,21 @@
+package net.citizensnpcs.nms.v1_14_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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/trait/BossBarTrait.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/trait/BossBarTrait.java
new file mode 100644
index 000000000..a5a094bbf
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/trait/BossBarTrait.java
@@ -0,0 +1,74 @@
+package net.citizensnpcs.nms.v1_14_R1.trait;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.bukkit.boss.BarColor;
+import org.bukkit.boss.BarFlag;
+import org.bukkit.boss.BossBar;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.EntityType;
+
+import com.google.common.collect.Lists;
+
+import net.citizensnpcs.api.persistence.Persist;
+import net.citizensnpcs.api.trait.Trait;
+import net.citizensnpcs.api.trait.TraitName;
+import net.citizensnpcs.nms.v1_14_R1.util.NMSImpl;
+
+@TraitName("bossbar")
+public class BossBarTrait extends Trait {
+ @Persist("color")
+ private BarColor color = null;
+ @Persist("flags")
+ private List flags = Lists.newArrayList();
+ @Persist("title")
+ private String title = null;
+ @Persist("visible")
+ private boolean visible = true;
+
+ public BossBarTrait() {
+ super("bossbar");
+ }
+
+ private boolean isBoss(Entity entity) {
+ return entity.getType() == EntityType.ENDER_DRAGON || entity.getType() == EntityType.WITHER
+ || entity.getType() == EntityType.GUARDIAN;
+ }
+
+ @Override
+ public void run() {
+ if (!npc.isSpawned() || !isBoss(npc.getEntity()))
+ return;
+ BossBar bar = NMSImpl.getBossBar(npc.getEntity());
+ bar.setVisible(visible);
+ if (color != null) {
+ bar.setColor(color);
+ }
+ if (title != null) {
+ bar.setTitle(title);
+ }
+ for (BarFlag flag : BarFlag.values()) {
+ bar.removeFlag(flag);
+ }
+ for (BarFlag flag : flags) {
+ bar.addFlag(flag);
+ }
+ }
+
+ public void setColor(BarColor color) {
+ this.color = color;
+ }
+
+ public void setFlags(Collection flags) {
+ this.flags = Lists.newArrayList(flags);
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public void setVisible(boolean visible) {
+ this.visible = visible;
+ }
+}
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/trait/CatTrait.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/trait/CatTrait.java
new file mode 100644
index 000000000..4406bae96
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/trait/CatTrait.java
@@ -0,0 +1,36 @@
+package net.citizensnpcs.nms.v1_14_R1.trait;
+
+import org.bukkit.entity.Cat;
+
+import net.citizensnpcs.api.persistence.Persist;
+import net.citizensnpcs.api.trait.Trait;
+import net.citizensnpcs.api.trait.TraitName;
+
+@TraitName("cattrait")
+public class CatTrait extends Trait {
+ @Persist
+ private boolean sitting = false;
+ @Persist
+ private Cat.Type type = Cat.Type.BLACK;
+
+ public CatTrait() {
+ super("cattrait");
+ }
+
+ @Override
+ public void run() {
+ if (npc.isSpawned() && npc.getEntity() instanceof Cat) {
+ Cat cat = (Cat) npc.getEntity();
+ cat.setSitting(sitting);
+ cat.setCatType(type);
+ }
+ }
+
+ public void setSitting(boolean sitting) {
+ this.sitting = sitting;
+ }
+
+ public void setType(Cat.Type type) {
+ this.type = type;
+ }
+}
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/trait/Commands.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/trait/Commands.java
new file mode 100644
index 000000000..85269d66a
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/trait/Commands.java
@@ -0,0 +1,326 @@
+package net.citizensnpcs.nms.v1_14_R1.trait;
+
+import java.util.List;
+
+import org.bukkit.DyeColor;
+import org.bukkit.boss.BarColor;
+import org.bukkit.boss.BarFlag;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Cat;
+import org.bukkit.entity.EntityType;
+import org.bukkit.entity.Llama.Color;
+import org.bukkit.entity.Panda;
+import org.bukkit.entity.Parrot.Variant;
+import org.bukkit.entity.TropicalFish.Pattern;
+
+import com.google.common.base.Splitter;
+import com.google.common.collect.Lists;
+
+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.command.exception.CommandUsageException;
+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 = "bossbar --color [color] --title [title] --visible [visible] --flags [flags]",
+ desc = "Edit bossbar properties",
+ modifiers = { "bossbar" },
+ min = 1,
+ max = 1)
+ @Requirements(selected = true, ownership = true, types = { EntityType.WITHER, EntityType.ENDER_DRAGON })
+ public void bossbar(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
+ BossBarTrait trait = npc.getTrait(BossBarTrait.class);
+ if (args.hasValueFlag("color")) {
+ BarColor color = Util.matchEnum(BarColor.values(), args.getFlag("color"));
+ trait.setColor(color);
+ }
+ if (args.hasValueFlag("title")) {
+ trait.setTitle(args.getFlag("title"));
+ }
+ if (args.hasValueFlag("visible")) {
+ trait.setVisible(Boolean.parseBoolean(args.getFlag("visible")));
+ }
+ if (args.hasValueFlag("flags")) {
+ List flags = Lists.newArrayList();
+ for (String s : Splitter.on(',').omitEmptyStrings().trimResults().split(args.getFlag("flags"))) {
+ BarFlag flag = Util.matchEnum(BarFlag.values(), s);
+ if (flag != null) {
+ flags.add(flag);
+ }
+ }
+ trait.setFlags(flags);
+ }
+ }
+
+ @Command(
+ aliases = { "npc" },
+ usage = "cat (-s/-n) --type type",
+ desc = "Sets cat modifiers",
+ modifiers = { "cat" },
+ min = 1,
+ max = 1,
+ permission = "citizens.npc.cat")
+ @Requirements(selected = true, ownership = true, types = EntityType.CAT)
+ public void cat(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
+ CatTrait trait = npc.getTrait(CatTrait.class);
+ String output = "";
+ if (args.hasValueFlag("type")) {
+ if (args.getFlagInteger("size") <= 0) {
+ throw new CommandUsageException();
+ }
+ Cat.Type type = Util.matchEnum(Cat.Type.values(), args.getFlag("type"));
+ if (type == null) {
+ throw new CommandUsageException(Messages.INVALID_CAT_TYPE, Util.listValuesPretty(Cat.Type.values()));
+ }
+ trait.setType(type);
+ output += ' ' + Messaging.tr(Messages.CAT_TYPE_SET, args.getFlag("type"));
+ }
+ if (args.hasFlag('s')) {
+ trait.setSitting(true);
+ output += ' ' + Messaging.tr(Messages.CAT_STARTED_SITTING);
+ } else if (args.hasFlag('n')) {
+ trait.setSitting(false);
+ output += ' ' + Messaging.tr(Messages.CAT_STOPPED_SITTING);
+ }
+ if (!output.isEmpty()) {
+ Messaging.send(sender, output.trim());
+ } else {
+ throw new CommandUsageException();
+ }
+ }
+
+ @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, EntityType.TRADER_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);
+ }
+ }
+
+ @Command(
+ aliases = { "npc" },
+ usage = "panda --gene (main gene) --hgene (hidden gene)",
+ desc = "Sets panda modifiers",
+ modifiers = { "panda" },
+ min = 1,
+ max = 1,
+ permission = "citizens.npc.panda")
+ @Requirements(selected = true, ownership = true, types = EntityType.PANDA)
+ public void panda(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
+ PandaTrait trait = npc.getTrait(PandaTrait.class);
+ String output = "";
+ if (args.hasValueFlag("gene")) {
+ if (args.getFlagInteger("size") <= 0) {
+ throw new CommandUsageException();
+ }
+ Panda.Gene gene = Util.matchEnum(Panda.Gene.values(), args.getFlag("gene"));
+ if (gene == null) {
+ throw new CommandUsageException(Messages.INVALID_PANDA_GENE,
+ Util.listValuesPretty(Panda.Gene.values()));
+ }
+ trait.setMainGene(gene);
+ output += ' ' + Messaging.tr(Messages.PANDA_MAIN_GENE_SET, args.getFlag("gene"));
+ }
+ if (args.hasValueFlag("hgene")) {
+ if (args.getFlagInteger("size") <= 0) {
+ throw new CommandUsageException();
+ }
+ Panda.Gene gene = Util.matchEnum(Panda.Gene.values(), args.getFlag("hgene"));
+ if (gene == null) {
+ throw new CommandUsageException(Messages.INVALID_PANDA_GENE,
+ Util.listValuesPretty(Panda.Gene.values()));
+ }
+ trait.setMainGene(gene);
+ output += ' ' + Messaging.tr(Messages.PANDA_HIDDEN_GENE_SET, args.getFlag("hgene"));
+ }
+ if (!output.isEmpty()) {
+ Messaging.send(sender, output.trim());
+ } else {
+ throw new CommandUsageException();
+ }
+ }
+
+ @Command(
+ aliases = { "npc" },
+ usage = "parrot (--variant variant)",
+ desc = "Sets parrot modifiers",
+ modifiers = { "parrot" },
+ min = 1,
+ max = 1,
+ permission = "citizens.npc.parrot")
+ @Requirements(selected = true, ownership = true, types = EntityType.PARROT)
+ public void parrot(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
+ ParrotTrait trait = npc.getTrait(ParrotTrait.class);
+ String output = "";
+ if (args.hasValueFlag("variant")) {
+ String variantRaw = args.getFlag("variant");
+ Variant variant = Util.matchEnum(Variant.values(), variantRaw);
+ if (variant == null) {
+ String valid = Util.listValuesPretty(Variant.values());
+ throw new CommandException(Messages.INVALID_PARROT_VARIANT, valid);
+ }
+ trait.setVariant(variant);
+ output += Messaging.tr(Messages.PARROT_VARIANT_SET, Util.prettyEnum(variant));
+ }
+ if (!output.isEmpty()) {
+ Messaging.send(sender, output);
+ }
+ }
+
+ @Command(
+ aliases = { "npc" },
+ usage = "phantom (--size size)",
+ desc = "Sets phantom modifiers",
+ modifiers = { "phantom" },
+ min = 1,
+ max = 1,
+ permission = "citizens.npc.phantom")
+ @Requirements(selected = true, ownership = true, types = EntityType.PHANTOM)
+ public void phantom(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
+ PhantomTrait trait = npc.getTrait(PhantomTrait.class);
+ String output = "";
+ if (args.hasValueFlag("size")) {
+ if (args.getFlagInteger("size") <= 0) {
+ throw new CommandUsageException();
+ }
+ trait.setSize(args.getFlagInteger("size"));
+ output += Messaging.tr(Messages.PHANTOM_STATE_SET, args.getFlagInteger("size"));
+ }
+ if (!output.isEmpty()) {
+ Messaging.send(sender, output);
+ } else {
+ throw new CommandUsageException();
+ }
+ }
+
+ @Command(
+ aliases = { "npc" },
+ usage = "pufferfish (--state state)",
+ desc = "Sets pufferfish modifiers",
+ modifiers = { "pufferfish" },
+ min = 1,
+ max = 1,
+ permission = "citizens.npc.pufferfish")
+ @Requirements(selected = true, ownership = true, types = EntityType.PUFFERFISH)
+ public void pufferfish(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
+ PufferFishTrait trait = npc.getTrait(PufferFishTrait.class);
+ String output = "";
+ if (args.hasValueFlag("state")) {
+ int state = Math.min(Math.max(args.getFlagInteger("state"), 0), 3);
+ trait.setPuffState(state);
+ output += Messaging.tr(Messages.PUFFERFISH_STATE_SET, state);
+ }
+ if (!output.isEmpty()) {
+ Messaging.send(sender, output);
+ }
+ }
+
+ @Command(
+ aliases = { "npc" },
+ usage = "shulker (--peek [peek] --color [color])",
+ desc = "Sets shulker modifiers.",
+ modifiers = { "shulker" },
+ min = 1,
+ max = 1,
+ permission = "citizens.npc.shulker")
+ @Requirements(selected = true, ownership = true, types = { EntityType.SHULKER })
+ public void shulker(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
+ ShulkerTrait trait = npc.getTrait(ShulkerTrait.class);
+ boolean hasArg = false;
+ if (args.hasValueFlag("peek")) {
+ int peek = (byte) args.getFlagInteger("peek");
+ trait.setPeek(peek);
+ Messaging.sendTr(sender, Messages.SHULKER_PEEK_SET, npc.getName(), peek);
+ hasArg = true;
+ }
+ if (args.hasValueFlag("color")) {
+ DyeColor color = Util.matchEnum(DyeColor.values(), args.getFlag("color"));
+ if (color == null) {
+ Messaging.sendErrorTr(sender, Messages.INVALID_SHULKER_COLOR, Util.listValuesPretty(DyeColor.values()));
+ return;
+ }
+ trait.setColor(color);
+ Messaging.sendTr(sender, Messages.SHULKER_COLOR_SET, npc.getName(), Util.prettyEnum(color));
+ hasArg = true;
+ }
+ if (!hasArg) {
+ throw new CommandUsageException();
+ }
+ }
+
+ @Command(
+ aliases = { "npc" },
+ usage = "tfish (--body color) (--pattern pattern) (--patterncolor color)",
+ desc = "Sets tropical fish modifiers",
+ modifiers = { "tfish" },
+ min = 1,
+ max = 1,
+ permission = "citizens.npc.tropicalfish")
+ @Requirements(selected = true, ownership = true, types = EntityType.TROPICAL_FISH)
+ public void tropicalfish(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
+ TropicalFishTrait trait = npc.getTrait(TropicalFishTrait.class);
+ String output = "";
+ if (args.hasValueFlag("body")) {
+ DyeColor color = Util.matchEnum(DyeColor.values(), args.getFlag("body"));
+ if (color == null) {
+ throw new CommandException(Messages.INVALID_TROPICALFISH_COLOR,
+ Util.listValuesPretty(DyeColor.values()));
+ }
+ trait.setBodyColor(color);
+ output += Messaging.tr(Messages.TROPICALFISH_BODY_COLOR_SET, Util.prettyEnum(color));
+ }
+ if (args.hasValueFlag("patterncolor")) {
+ DyeColor color = Util.matchEnum(DyeColor.values(), args.getFlag("patterncolor"));
+ if (color == null) {
+ throw new CommandException(Messages.INVALID_TROPICALFISH_COLOR,
+ Util.listValuesPretty(DyeColor.values()));
+ }
+ trait.setPatternColor(color);
+ output += Messaging.tr(Messages.TROPICALFISH_PATTERN_COLOR_SET, Util.prettyEnum(color));
+ }
+ if (args.hasValueFlag("pattern")) {
+ Pattern pattern = Util.matchEnum(Pattern.values(), args.getFlag("pattern"));
+ if (pattern == null) {
+ throw new CommandException(Messages.INVALID_TROPICALFISH_PATTERN,
+ Util.listValuesPretty(Pattern.values()));
+ }
+ trait.setPattern(pattern);
+ output += Messaging.tr(Messages.TROPICALFISH_PATTERN_SET, Util.prettyEnum(pattern));
+ }
+ if (!output.isEmpty()) {
+ Messaging.send(sender, output);
+ } else {
+ throw new CommandUsageException();
+ }
+ }
+}
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/trait/LlamaTrait.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/trait/LlamaTrait.java
new file mode 100644
index 000000000..f682a712a
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/trait/LlamaTrait.java
@@ -0,0 +1,37 @@
+package net.citizensnpcs.nms.v1_14_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_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/trait/PandaTrait.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/trait/PandaTrait.java
new file mode 100644
index 000000000..a75097bca
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/trait/PandaTrait.java
@@ -0,0 +1,39 @@
+package net.citizensnpcs.nms.v1_14_R1.trait;
+
+import org.bukkit.entity.Panda;
+
+import net.citizensnpcs.api.persistence.Persist;
+import net.citizensnpcs.api.trait.Trait;
+import net.citizensnpcs.api.trait.TraitName;
+
+@TraitName("pandatrait")
+public class PandaTrait extends Trait {
+ @Persist
+ private Panda.Gene hiddenGene;
+ @Persist
+ private Panda.Gene mainGene = Panda.Gene.NORMAL;
+
+ public PandaTrait() {
+ super("pandatrait");
+ }
+
+ @Override
+ public void run() {
+ if (npc.isSpawned() && npc.getEntity() instanceof Panda) {
+ Panda panda = (Panda) npc.getEntity();
+ panda.setMainGene(mainGene);
+ if (hiddenGene != null) {
+ panda.setHiddenGene(hiddenGene);
+ }
+ }
+ }
+
+ public void setHiddenGene(Panda.Gene gene) {
+ this.hiddenGene = gene;
+ }
+
+ public void setMainGene(Panda.Gene gene) {
+ this.mainGene = gene;
+ }
+
+}
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/trait/ParrotTrait.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/trait/ParrotTrait.java
new file mode 100644
index 000000000..03a50bf05
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/trait/ParrotTrait.java
@@ -0,0 +1,30 @@
+package net.citizensnpcs.nms.v1_14_R1.trait;
+
+import org.bukkit.entity.Parrot;
+import org.bukkit.entity.Parrot.Variant;
+
+import net.citizensnpcs.api.persistence.Persist;
+import net.citizensnpcs.api.trait.Trait;
+import net.citizensnpcs.api.trait.TraitName;
+
+@TraitName("parrottrait")
+public class ParrotTrait extends Trait {
+ @Persist
+ private Variant variant = Variant.BLUE;
+
+ public ParrotTrait() {
+ super("parrottrait");
+ }
+
+ @Override
+ public void run() {
+ if (npc.isSpawned() && npc.getEntity() instanceof Parrot) {
+ Parrot parrot = (Parrot) npc.getEntity();
+ parrot.setVariant(variant);
+ }
+ }
+
+ public void setVariant(Parrot.Variant variant) {
+ this.variant = variant;
+ }
+}
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/trait/PhantomTrait.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/trait/PhantomTrait.java
new file mode 100644
index 000000000..8e7e9947d
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/trait/PhantomTrait.java
@@ -0,0 +1,29 @@
+package net.citizensnpcs.nms.v1_14_R1.trait;
+
+import org.bukkit.entity.Phantom;
+
+import net.citizensnpcs.api.persistence.Persist;
+import net.citizensnpcs.api.trait.Trait;
+import net.citizensnpcs.api.trait.TraitName;
+
+@TraitName("phantomtrait")
+public class PhantomTrait extends Trait {
+ @Persist
+ private int size = 1;
+
+ public PhantomTrait() {
+ super("phantomtrait");
+ }
+
+ @Override
+ public void run() {
+ if (npc.isSpawned() && npc.getEntity() instanceof Phantom) {
+ Phantom phantom = (Phantom) npc.getEntity();
+ phantom.setSize(size);
+ }
+ }
+
+ public void setSize(int size) {
+ this.size = size;
+ }
+}
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/trait/PufferFishTrait.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/trait/PufferFishTrait.java
new file mode 100644
index 000000000..fba57ac48
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/trait/PufferFishTrait.java
@@ -0,0 +1,29 @@
+package net.citizensnpcs.nms.v1_14_R1.trait;
+
+import org.bukkit.entity.PufferFish;
+
+import net.citizensnpcs.api.persistence.Persist;
+import net.citizensnpcs.api.trait.Trait;
+import net.citizensnpcs.api.trait.TraitName;
+
+@TraitName("pufferfishtrait")
+public class PufferFishTrait extends Trait {
+ @Persist
+ private int puffState = 1;
+
+ public PufferFishTrait() {
+ super("pufferfishtrait");
+ }
+
+ @Override
+ public void run() {
+ if (npc.isSpawned() && npc.getEntity() instanceof PufferFish) {
+ PufferFish puffer = (PufferFish) npc.getEntity();
+ puffer.setPuffState(puffState);
+ }
+ }
+
+ public void setPuffState(int state) {
+ this.puffState = state;
+ }
+}
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/trait/ShulkerTrait.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/trait/ShulkerTrait.java
new file mode 100644
index 000000000..bf58e7f96
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/trait/ShulkerTrait.java
@@ -0,0 +1,51 @@
+package net.citizensnpcs.nms.v1_14_R1.trait;
+
+import org.bukkit.DyeColor;
+import org.bukkit.entity.Shulker;
+
+import net.citizensnpcs.api.persistence.Persist;
+import net.citizensnpcs.api.trait.Trait;
+import net.citizensnpcs.api.trait.TraitName;
+import net.citizensnpcs.nms.v1_14_R1.util.NMSImpl;
+import net.citizensnpcs.util.NMS;
+
+@TraitName("shulkertrait")
+public class ShulkerTrait extends Trait {
+ @Persist("color")
+ private DyeColor color = DyeColor.PURPLE;
+ private int lastPeekSet = 0;
+ @Persist("peek")
+ private int peek = 0;
+
+ public ShulkerTrait() {
+ super("shulkertrait");
+ }
+
+ @Override
+ public void onSpawn() {
+ setPeek(peek);
+ }
+
+ @Override
+ public void run() {
+ if (color == null) {
+ color = DyeColor.PURPLE;
+ }
+ if (npc.getEntity() instanceof Shulker) {
+ if (peek != lastPeekSet) {
+ NMS.setPeekShulker((Shulker) npc.getEntity(), peek);
+ lastPeekSet = peek;
+ }
+ NMSImpl.setShulkerColor((Shulker) npc.getEntity(), color);
+ }
+ }
+
+ public void setColor(DyeColor color) {
+ this.color = color;
+ }
+
+ public void setPeek(int peek) {
+ this.peek = peek;
+ lastPeekSet = -1;
+ }
+}
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/trait/TropicalFishTrait.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/trait/TropicalFishTrait.java
new file mode 100644
index 000000000..7430eae8d
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/trait/TropicalFishTrait.java
@@ -0,0 +1,45 @@
+package net.citizensnpcs.nms.v1_14_R1.trait;
+
+import org.bukkit.DyeColor;
+import org.bukkit.entity.TropicalFish;
+import org.bukkit.entity.TropicalFish.Pattern;
+
+import net.citizensnpcs.api.persistence.Persist;
+import net.citizensnpcs.api.trait.Trait;
+import net.citizensnpcs.api.trait.TraitName;
+
+@TraitName("tropicalfishtrait")
+public class TropicalFishTrait extends Trait {
+ @Persist
+ private DyeColor bodyColor = DyeColor.BLUE;
+ @Persist
+ private Pattern pattern = Pattern.BRINELY;
+ @Persist
+ private DyeColor patternColor = DyeColor.BLUE;
+
+ public TropicalFishTrait() {
+ super("tropicalfishtrait");
+ }
+
+ @Override
+ public void run() {
+ if (npc.isSpawned() && npc.getEntity() instanceof TropicalFish) {
+ TropicalFish fish = (TropicalFish) npc.getEntity();
+ fish.setBodyColor(bodyColor);
+ fish.setPatternColor(patternColor);
+ fish.setPattern(pattern);
+ }
+ }
+
+ public void setBodyColor(DyeColor color) {
+ this.bodyColor = color;
+ }
+
+ public void setPattern(Pattern pattern) {
+ this.pattern = pattern;
+ }
+
+ public void setPatternColor(DyeColor color) {
+ this.patternColor = color;
+ }
+}
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/util/CitizensBlockBreaker.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/util/CitizensBlockBreaker.java
new file mode 100644
index 000000000..47c76cbf7
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/util/CitizensBlockBreaker.java
@@ -0,0 +1,177 @@
+package net.citizensnpcs.nms.v1_14_R1.util;
+
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.v1_14_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_14_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_14_R1.BlockPosition;
+import net.minecraft.server.v1_14_R1.Blocks;
+import net.minecraft.server.v1_14_R1.EnchantmentManager;
+import net.minecraft.server.v1_14_R1.Entity;
+import net.minecraft.server.v1_14_R1.EntityLiving;
+import net.minecraft.server.v1_14_R1.EntityPlayer;
+import net.minecraft.server.v1_14_R1.EnumItemSlot;
+import net.minecraft.server.v1_14_R1.IBlockData;
+import net.minecraft.server.v1_14_R1.ItemStack;
+import net.minecraft.server.v1_14_R1.MobEffects;
+import net.minecraft.server.v1_14_R1.TagsFluid;
+import net.minecraft.server.v1_14_R1.WorldServer;
+
+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_14_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.getBlock() == 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) {
+ ((WorldServer) entity.world).a(entity.getId(), new BlockPosition(x, y, z), modifiedDamage); // TODO: does this
+ // work?
+ }
+
+ @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(TagsFluid.WATER) && !EnchantmentManager.h(handle)) {
+ f /= 5.0F;
+ }
+
+ }
+ if (!entity.onGround) {
+ f /= 5.0F;
+ }
+ return f;
+ }
+}
\ No newline at end of file
diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/util/CustomEntityRegistry.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/util/CustomEntityRegistry.java
new file mode 100644
index 000000000..e2368ca15
--- /dev/null
+++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/util/CustomEntityRegistry.java
@@ -0,0 +1,209 @@
+package net.citizensnpcs.nms.v1_14_R1.util;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Optional;
+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_14_R1.*;
+
+@SuppressWarnings("rawtypes")
+public class CustomEntityRegistry extends RegistryBlocks {
+ private final BiMap entities = HashBiMap.create();
+ private final BiMap entityClasses = this.entities.inverse();
+ private final Map entityIds = Maps.newHashMap();
+ private final RegistryMaterials> wrapped;
+
+ public CustomEntityRegistry(RegistryBlocks> original) {
+ super(original.a().b());
+ this.wrapped = original;
+ }
+
+ @Override
+ public int a(Object key) {
+ if (entityIds.containsKey(key)) {
+ return entityIds.get(key);
+ }
+
+ return wrapped.a((EntityTypes) key);
+ }
+
+ @Override
+ public Object a(Random paramRandom) {
+ return wrapped.a(paramRandom);
+ }
+
+ public EntityTypes findType(Class> search) {
+ return minecraftClassMap.inverse().get(search);
+ /*
+ for (Object type : wrapped) {
+ if (minecraftClassMap.get(type) == search) {
+ return (EntityTypes) type;
+ }
+ }
+ return null;
+ */
+ }
+
+ @Override
+ public Object fromId(int var0) {
+ return this.wrapped.fromId(var0);
+ }
+
+ @Override
+ public EntityTypes get(MinecraftKey key) {
+ if (entities.containsKey(key)) {
+ return entities.get(key);
+ }
+
+ return wrapped.get(key);
+ }
+
+ @Override
+ public MinecraftKey getKey(Object value) {
+ if (entityClasses.containsKey(value)) {
+ return entityClasses.get(value);
+ }
+
+ return wrapped.getKey((EntityTypes) value);
+ }
+
+ @Override
+ public Optional getOptional(MinecraftKey var0) {
+ if (entities.containsKey(var0)) {
+ return Optional.of(entities.get(var0));
+ }
+
+ return Optional.ofNullable(this.wrapped.get(var0));
+ }
+
+ public RegistryMaterials> getWrapped() {
+ return wrapped;
+ }
+
+ @Override
+ public Iterator