diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 4dee702..5ee6e24 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -2,16 +2,28 @@
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -52,7 +64,7 @@
-
+
@@ -64,15 +76,25 @@
-
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -80,6 +102,13 @@
+
+
+
+
+
+
+
@@ -114,6 +143,7 @@
+
@@ -176,168 +206,81 @@
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
+
+
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index aad0193..89e16a4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
net.seanomik
tamablefoxes
- 1.6.1-SNAPSHOT
+ 1.7-SNAPSHOT
jar
Tamablefoxes
@@ -39,8 +39,8 @@
shade
- D:\Code\java\spigotPlugins\_TEST_SERVER_1.15.2_\plugins\TamableFoxes-MC-v1.15.X-v${project.version}.jar
-
+ D:\Code\java\spigotPlugins\_TEST_SERVER_1.16.1_\plugins\TamableFoxes-MC-v1.15.X-v1.16.X-v${project.version}.jar
+
false
@@ -72,22 +72,22 @@
+ local.spigot.nms
+ AllSpigotNMS
+ LATEST
+ system
+ ${project.basedir}/spigot-14-15-16-nms.jar
+
+
org.spigotmc
- spigot
- 1.15.2-R0.1-SNAPSHOT
+ spigot-api
+ 1.14.4-R0.1-SNAPSHOT
provided
com.github.WesJD.AnvilGUI
anvilgui
- 478e0c1
+ master-ef71db62ec-1
-
diff --git a/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15/command/CommandSpawnTamableFox.java b/src/main/java/net/seanomik/tamablefoxes/CommandSpawnTamableFox.java
similarity index 79%
rename from src/main/java/net/seanomik/tamablefoxes/versions/version_1_15/command/CommandSpawnTamableFox.java
rename to src/main/java/net/seanomik/tamablefoxes/CommandSpawnTamableFox.java
index 1b0e586..715e9d9 100644
--- a/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15/command/CommandSpawnTamableFox.java
+++ b/src/main/java/net/seanomik/tamablefoxes/CommandSpawnTamableFox.java
@@ -1,9 +1,6 @@
-package net.seanomik.tamablefoxes.versions.version_1_15.command;
+package net.seanomik.tamablefoxes;
-import net.seanomik.tamablefoxes.EntityTamableFox;
-import net.seanomik.tamablefoxes.TamableFoxes;
-import net.minecraft.server.v1_15_R1.EntityFox;
-import net.seanomik.tamablefoxes.Utils;
+import net.seanomik.tamablefoxes.versions.NMSInterface;
import net.seanomik.tamablefoxes.io.LanguageConfig;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
@@ -40,8 +37,8 @@ public class CommandSpawnTamableFox implements TabExecutor {
switch (args[0]) {
case "red":
try {
- EntityTamableFox fox = plugin.spawnTamableFox(player.getLocation(), EntityFox.Type.RED);
- player.sendMessage(Utils.getPrefix() + ChatColor.RESET + LanguageConfig.getSpawnedFoxMessage(EntityFox.Type.RED));
+ plugin.nmsInterface.spawnTamableFox(player.getLocation(), NMSInterface.FoxType.RED);
+ player.sendMessage(Utils.getPrefix() + ChatColor.RESET + LanguageConfig.getSpawnedFoxMessage(NMSInterface.FoxType.RED));
} catch (Exception e) {
e.printStackTrace();
player.sendMessage(Utils.getPrefix() + ChatColor.RED + LanguageConfig.getFailureSpawn());
@@ -49,8 +46,8 @@ public class CommandSpawnTamableFox implements TabExecutor {
break;
case "snow":
try {
- EntityTamableFox spawnedFox = plugin.spawnTamableFox(player.getLocation(), EntityFox.Type.SNOW);
- player.sendMessage(Utils.getPrefix() + ChatColor.RESET + LanguageConfig.getSpawnedFoxMessage(EntityFox.Type.SNOW));
+ plugin.nmsInterface.spawnTamableFox(player.getLocation(), NMSInterface.FoxType.SNOW);
+ player.sendMessage(Utils.getPrefix() + ChatColor.RESET + LanguageConfig.getSpawnedFoxMessage(NMSInterface.FoxType.SNOW));
} catch (Exception e) {
e.printStackTrace();
player.sendMessage(Utils.getPrefix() + ChatColor.RED + LanguageConfig.getFailureSpawn());
diff --git a/src/main/java/net/seanomik/tamablefoxes/TamableFoxes.java b/src/main/java/net/seanomik/tamablefoxes/TamableFoxes.java
index 0a7dd2e..4b25dc8 100644
--- a/src/main/java/net/seanomik/tamablefoxes/TamableFoxes.java
+++ b/src/main/java/net/seanomik/tamablefoxes/TamableFoxes.java
@@ -1,62 +1,47 @@
package net.seanomik.tamablefoxes;
-import net.minecraft.server.v1_15_R1.*;
-import net.seanomik.tamablefoxes.versions.version_1_15.command.CommandSpawnTamableFox;
+import net.seanomik.tamablefoxes.versions.NMSInterface;
+import net.seanomik.tamablefoxes.versions.version_1_15_R1.NMSInterface_1_15_R1;
import net.seanomik.tamablefoxes.io.LanguageConfig;
+import net.seanomik.tamablefoxes.versions.version_1_16_R1.NMSInterface_1_16_R1;
import org.bukkit.*;
-import org.bukkit.craftbukkit.v1_15_R1.entity.CraftEntity;
-import org.bukkit.entity.EntityType;
import org.bukkit.event.Listener;
import org.bukkit.plugin.java.JavaPlugin;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-
// @TODO:
-/* @CHANGELOG (1.6.1-SNAPSHOT):
- * Fix a bug of duplicating water/lava buckets.
+/* @CHANGELOG (1.7-SNAPSHOT):
+ * Update to Minecraft 1.16.1.
+ * This jar file will also work with Minecraft 1.15.2, and 1.16.1.
*/
public final class TamableFoxes extends JavaPlugin implements Listener {
private static TamableFoxes plugin;
private boolean versionSupported = true;
+ public NMSInterface nmsInterface;
+
@Override
public void onLoad() {
plugin = this;
LanguageConfig.getConfig().saveDefault();
- String version = Bukkit.getServer().getClass().getPackage().getName();
- if (!version.equals("org.bukkit.craftbukkit.v1_15_R1")) {
+ String version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
+ if (version.equals("v1_15_R1")) {
+ nmsInterface = new NMSInterface_1_15_R1();
+ } else if (version.equals("v1_16_R1")) {
+ nmsInterface = new NMSInterface_1_16_R1();
+ } else {
Bukkit.getServer().getConsoleSender().sendMessage(Utils.getPrefix() + ChatColor.RED + LanguageConfig.getUnsupportedMCVersionRegister());
versionSupported = false;
return;
}
- try { // Replace the fox entity
- Field field = EntityTypes.FOX.getClass().getDeclaredField("ba");
- field.setAccessible(true);
-
- // If the field is final, then make it non final
- if ((field.getModifiers() & Modifier.FINAL) == Modifier.FINAL) {
- Field fieldMutable = field.getClass().getDeclaredField("modifiers");
- fieldMutable.setAccessible(true);
- fieldMutable.set(field, fieldMutable.getInt(field) & ~Modifier.FINAL);
- fieldMutable.setAccessible(false);
- }
-
- field.set(EntityTypes.FOX, (EntityTypes.b) (type, world) -> new EntityTamableFox(type, world));
-
- field.setAccessible(false);
-
- getServer().getConsoleSender().sendMessage(Utils.getPrefix() + ChatColor.GREEN + LanguageConfig.getSuccessReplaced());
- } catch (Exception e) {
- //e.printStackTrace();
- getServer().getConsoleSender().sendMessage(Utils.getPrefix() + ChatColor.RED + LanguageConfig.getFailureReplace());
- }
+ // Display starting message
+ Bukkit.getServer().getConsoleSender().sendMessage(Utils.getPrefix() + ChatColor.YELLOW + LanguageConfig.getMCVersionLoading(version));
+ nmsInterface.registerCustomFoxEntity();
}
@Override
@@ -80,15 +65,6 @@ public final class TamableFoxes extends JavaPlugin implements Listener {
getServer().getConsoleSender().sendMessage(Utils.getPrefix() + ChatColor.YELLOW + LanguageConfig.getSavingFoxMessage());
}
-
- public EntityTamableFox spawnTamableFox(Location loc, EntityFox.Type type) {
- EntityTamableFox tamableFox = (EntityTamableFox) ((CraftEntity) loc.getWorld().spawnEntity(loc, EntityType.FOX)).getHandle();
- tamableFox.setFoxType(type);
-
- return tamableFox;
- }
-
-
public static TamableFoxes getPlugin() {
return plugin;
}
diff --git a/src/main/java/net/seanomik/tamablefoxes/io/LanguageConfig.java b/src/main/java/net/seanomik/tamablefoxes/io/LanguageConfig.java
index 386b946..4013961 100644
--- a/src/main/java/net/seanomik/tamablefoxes/io/LanguageConfig.java
+++ b/src/main/java/net/seanomik/tamablefoxes/io/LanguageConfig.java
@@ -1,8 +1,7 @@
package net.seanomik.tamablefoxes.io;
-import net.minecraft.server.v1_15_R1.EntityFox;
-import net.minecraft.server.v1_15_R1.IChatBaseComponent;
import net.seanomik.tamablefoxes.TamableFoxes;
+import net.seanomik.tamablefoxes.versions.NMSInterface;
import org.bukkit.ChatColor;
import org.bukkit.configuration.file.YamlConfiguration;
@@ -83,6 +82,11 @@ public class LanguageConfig extends YamlConfiguration {
return (super.getString(path).isEmpty()) ? super.getString(path) : ChatColor.translateAlternateColorCodes('&', super.getString(path));
}
+ // This is the text that shows when registering the custom entity
+ public static String getMCVersionLoading(String mcVersionStr) {
+ return getConfig().getString("mc-version-loading").replaceAll("%MC_VERSION%", mcVersionStr);
+ }
+
// Get the error that shows during register when they try to run the plugin on an unsupported mc version.
public static String getUnsupportedMCVersionRegister() {
return getConfig().getString("unsupported-mc-version-not-registering");
@@ -136,7 +140,7 @@ public class LanguageConfig extends YamlConfiguration {
return getConfig().getString("only-run-by-player");
}
- public static String getSpawnedFoxMessage(EntityFox.Type type) {
+ public static String getSpawnedFoxMessage(NMSInterface.FoxType type) {
String typeStr = ((type == type.SNOW) ? ChatColor.AQUA + "Snow" : ChatColor.RED + "Red") + ChatColor.RESET;
return getConfig().getString("spawned-fox-message").replaceAll("%TYPE%", typeStr);
}
diff --git a/src/main/java/net/seanomik/tamablefoxes/versions/NMSInterface.java b/src/main/java/net/seanomik/tamablefoxes/versions/NMSInterface.java
new file mode 100644
index 0000000..c895e06
--- /dev/null
+++ b/src/main/java/net/seanomik/tamablefoxes/versions/NMSInterface.java
@@ -0,0 +1,15 @@
+package net.seanomik.tamablefoxes.versions;
+
+//import net.minecraft.server.v1_15_R1.EntityFox;
+import net.seanomik.tamablefoxes.TamableFoxes;
+import org.bukkit.Location;
+
+public interface NMSInterface {
+ enum FoxType {
+ RED,
+ SNOW
+ }
+
+ public void registerCustomFoxEntity();
+ public void spawnTamableFox(Location loc, FoxType type);
+}
\ No newline at end of file
diff --git a/src/main/java/net/seanomik/tamablefoxes/EntityTamableFox.java b/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15_R1/EntityTamableFox.java
similarity index 98%
rename from src/main/java/net/seanomik/tamablefoxes/EntityTamableFox.java
rename to src/main/java/net/seanomik/tamablefoxes/versions/version_1_15_R1/EntityTamableFox.java
index e879d7c..067a22b 100644
--- a/src/main/java/net/seanomik/tamablefoxes/EntityTamableFox.java
+++ b/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15_R1/EntityTamableFox.java
@@ -1,18 +1,20 @@
-package net.seanomik.tamablefoxes;
+package net.seanomik.tamablefoxes.versions.version_1_15_R1;
import net.minecraft.server.v1_15_R1.*;
+import net.seanomik.tamablefoxes.TamableFoxes;
+import net.seanomik.tamablefoxes.Utils;
import net.seanomik.tamablefoxes.io.Config;
import net.seanomik.tamablefoxes.io.LanguageConfig;
-import net.seanomik.tamablefoxes.versions.version_1_15.pathfinding.*;
+import net.seanomik.tamablefoxes.versions.version_1_15_R1.pathfinding.*;
import net.wesjd.anvilgui.AnvilGUI;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
+import org.bukkit.craftbukkit.libs.jline.internal.Nullable;
import org.bukkit.craftbukkit.v1_15_R1.event.CraftEventFactory;
import org.bukkit.craftbukkit.v1_15_R1.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityRegainHealthEvent;
-import javax.annotation.Nullable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
diff --git a/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15_R1/NMSInterface_1_15_R1.java b/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15_R1/NMSInterface_1_15_R1.java
new file mode 100644
index 0000000..e700421
--- /dev/null
+++ b/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15_R1/NMSInterface_1_15_R1.java
@@ -0,0 +1,48 @@
+package net.seanomik.tamablefoxes.versions.version_1_15_R1;
+
+import net.minecraft.server.v1_15_R1.EntityFox;
+import net.minecraft.server.v1_15_R1.EntityTypes;
+import net.seanomik.tamablefoxes.TamableFoxes;
+import net.seanomik.tamablefoxes.Utils;
+import net.seanomik.tamablefoxes.io.LanguageConfig;
+import net.seanomik.tamablefoxes.versions.NMSInterface;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.v1_15_R1.entity.CraftEntity;
+import org.bukkit.entity.EntityType;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+public class NMSInterface_1_15_R1 implements NMSInterface {
+ @Override
+ public void registerCustomFoxEntity() {
+ try { // Replace the fox entity
+ Field field = EntityTypes.FOX.getClass().getDeclaredField("ba");
+ field.setAccessible(true);
+
+ // If the field is final, then make it non final
+ if ((field.getModifiers() & Modifier.FINAL) == Modifier.FINAL) {
+ Field fieldMutable = field.getClass().getDeclaredField("modifiers");
+ fieldMutable.setAccessible(true);
+ fieldMutable.set(field, fieldMutable.getInt(field) & ~Modifier.FINAL);
+ fieldMutable.setAccessible(false);
+ }
+
+ field.set(EntityTypes.FOX, (EntityTypes.b) (type, world) -> new EntityTamableFox(type, world));
+
+ field.setAccessible(false);
+
+ Bukkit.getServer().getConsoleSender().sendMessage(Utils.getPrefix() + ChatColor.GREEN + LanguageConfig.getSuccessReplaced());
+ } catch (Exception e) {
+ Bukkit.getServer().getConsoleSender().sendMessage(Utils.getPrefix() + ChatColor.RED + LanguageConfig.getFailureReplace());
+ }
+ }
+
+ @Override
+ public void spawnTamableFox(Location loc, FoxType type) {
+ EntityTamableFox tamableFox = (EntityTamableFox) ((CraftEntity) loc.getWorld().spawnEntity(loc, EntityType.FOX)).getHandle();
+ tamableFox.setFoxType( (type == FoxType.RED) ? EntityFox.Type.RED : EntityFox.Type.SNOW );
+ }
+}
diff --git a/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15/pathfinding/FoxPathfinderGoalFollowOwner.java b/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15_R1/pathfinding/FoxPathfinderGoalFollowOwner.java
similarity index 94%
rename from src/main/java/net/seanomik/tamablefoxes/versions/version_1_15/pathfinding/FoxPathfinderGoalFollowOwner.java
rename to src/main/java/net/seanomik/tamablefoxes/versions/version_1_15_R1/pathfinding/FoxPathfinderGoalFollowOwner.java
index 213d472..2530c8b 100644
--- a/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15/pathfinding/FoxPathfinderGoalFollowOwner.java
+++ b/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15_R1/pathfinding/FoxPathfinderGoalFollowOwner.java
@@ -1,139 +1,139 @@
-package net.seanomik.tamablefoxes.versions.version_1_15.pathfinding;
-
-import net.seanomik.tamablefoxes.EntityTamableFox;
-import net.minecraft.server.v1_15_R1.*;
-import org.bukkit.Location;
-import org.bukkit.craftbukkit.v1_15_R1.entity.CraftEntity;
-import org.bukkit.event.entity.EntityTeleportEvent;
-
-import java.util.EnumSet;
-
-public class FoxPathfinderGoalFollowOwner extends PathfinderGoal {
- private final EntityTamableFox a;
- private EntityLiving b;
- private final IWorldReader c;
- private final double d;
- private final NavigationAbstract e;
- private int f;
- private final float g;
- private final float h;
- private float i;
- private final boolean j;
-
- public FoxPathfinderGoalFollowOwner(EntityTamableFox entityTamableFox, double d0, float f, float f1, boolean flag) {
- this.a = entityTamableFox;
- this.c = entityTamableFox.world;
- this.d = d0;
- this.e = entityTamableFox.getNavigation();
- this.h = f;
- this.g = f1;
- this.j = flag;
- this.a(EnumSet.of(Type.MOVE, Type.LOOK));
- if (!(entityTamableFox.getNavigation() instanceof Navigation) && !(entityTamableFox.getNavigation() instanceof NavigationFlying)) {
- throw new IllegalArgumentException("Unsupported mob type for FollowOwnerGoal");
- }
- }
-
- public boolean a() {
- EntityLiving entityliving = this.a.getOwner();
- if (entityliving == null) {
- return false;
- } else if (entityliving.isSpectator()) {
- return false;
- } else if (this.a.isSitting()) {
- return false;
- } else if (this.a.h(entityliving) < (double)(this.h * this.h)) {
- return false;
- } else {
- this.b = entityliving;
- return true;
- }
- }
-
- public boolean b() {
- return !this.e.m() && (!this.a.isSitting() && this.a.h(this.b) > (double) (this.g * this.g));
- }
-
- public void c() {
- this.f = 0;
- this.i = this.a.a(PathType.WATER);
- this.a.a(PathType.WATER, 0.0F);
- }
-
- public void d() {
- this.b = null;
- this.e.o();
- this.a.a(PathType.WATER, this.i);
- }
-
- public void e() {
- this.a.getControllerLook().a(this.b, 10.0F, (float)this.a.dU());
- if (--this.f <= 0) {
- this.f = 10;
- if (!this.a.isLeashed() && !this.a.isPassenger()) {
- if (this.a.h(this.b) >= 144.0D) {
- this.g();
- } else {
- this.e.a(this.b, this.d);
- }
- }
- }
-
- }
-
- private void g() {
- BlockPosition blockposition = new BlockPosition(this.b);
-
- for(int i = 0; i < 10; ++i) {
- int j = this.a(-3, 3);
- int k = this.a(-1, 1);
- int l = this.a(-3, 3);
- boolean flag = this.a(blockposition.getX() + j, blockposition.getY() + k, blockposition.getZ() + l);
- if (flag) {
- return;
- }
- }
-
- }
-
- private boolean a(int i, int j, int k) {
- if (Math.abs((double)i - this.b.locX()) < 2.0D && Math.abs((double)k - this.b.locZ()) < 2.0D) {
- return false;
- } else if (!this.a(new BlockPosition(i, j, k))) {
- return false;
- } else {
- CraftEntity entity = this.a.getBukkitEntity();
- Location to = new Location(entity.getWorld(), (double)((float)i + 0.5F), (double)j, (double)((float)k + 0.5F), this.a.yaw, this.a.pitch);
- EntityTeleportEvent event = new EntityTeleportEvent(entity, entity.getLocation(), to);
- this.a.world.getServer().getPluginManager().callEvent(event);
- if (event.isCancelled()) {
- return false;
- } else {
- to = event.getTo();
- this.a.setPositionRotation(to.getX(), to.getY(), to.getZ(), to.getYaw(), to.getPitch());
- this.e.o();
- return true;
- }
- }
- }
-
- private boolean a(BlockPosition blockposition) {
- PathType pathtype = PathfinderNormal.b(this.c, blockposition.getX(), blockposition.getY(), blockposition.getZ());
- if (pathtype != PathType.WALKABLE) {
- return false;
- } else {
- IBlockData iblockdata = this.c.getType(blockposition.down());
- if (!this.j && iblockdata.getBlock() instanceof BlockLeaves) {
- return false;
- } else {
- BlockPosition blockposition1 = blockposition.b(new BlockPosition(this.a));
- return this.c.getCubes(this.a, this.a.getBoundingBox().a(blockposition1));
- }
- }
- }
-
- private int a(int i, int j) {
- return this.a.getRandom().nextInt(j - i + 1) + i;
- }
-
-}
+package net.seanomik.tamablefoxes.versions.version_1_15_R1.pathfinding;
+
+import net.seanomik.tamablefoxes.versions.version_1_15_R1.EntityTamableFox;
+import net.minecraft.server.v1_15_R1.*;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.v1_15_R1.entity.CraftEntity;
+import org.bukkit.event.entity.EntityTeleportEvent;
+
+import java.util.EnumSet;
+
+public class FoxPathfinderGoalFollowOwner extends PathfinderGoal {
+ private final EntityTamableFox a;
+ private EntityLiving b;
+ private final IWorldReader c;
+ private final double d;
+ private final NavigationAbstract e;
+ private int f;
+ private final float g;
+ private final float h;
+ private float i;
+ private final boolean j;
+
+ public FoxPathfinderGoalFollowOwner(EntityTamableFox entityTamableFox, double d0, float f, float f1, boolean flag) {
+ this.a = entityTamableFox;
+ this.c = entityTamableFox.world;
+ this.d = d0;
+ this.e = entityTamableFox.getNavigation();
+ this.h = f;
+ this.g = f1;
+ this.j = flag;
+ this.a(EnumSet.of(Type.MOVE, Type.LOOK));
+ if (!(entityTamableFox.getNavigation() instanceof Navigation) && !(entityTamableFox.getNavigation() instanceof NavigationFlying)) {
+ throw new IllegalArgumentException("Unsupported mob type for FollowOwnerGoal");
+ }
+ }
+
+ public boolean a() {
+ EntityLiving entityliving = this.a.getOwner();
+ if (entityliving == null) {
+ return false;
+ } else if (entityliving.isSpectator()) {
+ return false;
+ } else if (this.a.isSitting()) {
+ return false;
+ } else if (this.a.h(entityliving) < (double)(this.h * this.h)) {
+ return false;
+ } else {
+ this.b = entityliving;
+ return true;
+ }
+ }
+
+ public boolean b() {
+ return !this.e.m() && (!this.a.isSitting() && this.a.h(this.b) > (double) (this.g * this.g));
+ }
+
+ public void c() {
+ this.f = 0;
+ this.i = this.a.a(PathType.WATER);
+ this.a.a(PathType.WATER, 0.0F);
+ }
+
+ public void d() {
+ this.b = null;
+ this.e.o();
+ this.a.a(PathType.WATER, this.i);
+ }
+
+ public void e() {
+ this.a.getControllerLook().a(this.b, 10.0F, (float)this.a.dU());
+ if (--this.f <= 0) {
+ this.f = 10;
+ if (!this.a.isLeashed() && !this.a.isPassenger()) {
+ if (this.a.h(this.b) >= 144.0D) {
+ this.g();
+ } else {
+ this.e.a(this.b, this.d);
+ }
+ }
+ }
+
+ }
+
+ private void g() {
+ BlockPosition blockposition = new BlockPosition(this.b);
+
+ for(int i = 0; i < 10; ++i) {
+ int j = this.a(-3, 3);
+ int k = this.a(-1, 1);
+ int l = this.a(-3, 3);
+ boolean flag = this.a(blockposition.getX() + j, blockposition.getY() + k, blockposition.getZ() + l);
+ if (flag) {
+ return;
+ }
+ }
+
+ }
+
+ private boolean a(int i, int j, int k) {
+ if (Math.abs((double)i - this.b.locX()) < 2.0D && Math.abs((double)k - this.b.locZ()) < 2.0D) {
+ return false;
+ } else if (!this.a(new BlockPosition(i, j, k))) {
+ return false;
+ } else {
+ CraftEntity entity = this.a.getBukkitEntity();
+ Location to = new Location(entity.getWorld(), (double)((float)i + 0.5F), (double)j, (double)((float)k + 0.5F), this.a.yaw, this.a.pitch);
+ EntityTeleportEvent event = new EntityTeleportEvent(entity, entity.getLocation(), to);
+ this.a.world.getServer().getPluginManager().callEvent(event);
+ if (event.isCancelled()) {
+ return false;
+ } else {
+ to = event.getTo();
+ this.a.setPositionRotation(to.getX(), to.getY(), to.getZ(), to.getYaw(), to.getPitch());
+ this.e.o();
+ return true;
+ }
+ }
+ }
+
+ private boolean a(BlockPosition blockposition) {
+ PathType pathtype = PathfinderNormal.b(this.c, blockposition.getX(), blockposition.getY(), blockposition.getZ());
+ if (pathtype != PathType.WALKABLE) {
+ return false;
+ } else {
+ IBlockData iblockdata = this.c.getType(blockposition.down());
+ if (!this.j && iblockdata.getBlock() instanceof BlockLeaves) {
+ return false;
+ } else {
+ BlockPosition blockposition1 = blockposition.b(new BlockPosition(this.a));
+ return this.c.getCubes(this.a, this.a.getBoundingBox().a(blockposition1));
+ }
+ }
+ }
+
+ private int a(int i, int j) {
+ return this.a.getRandom().nextInt(j - i + 1) + i;
+ }
+
+}
diff --git a/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15/pathfinding/FoxPathfinderGoalHurtByTarget.java b/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15_R1/pathfinding/FoxPathfinderGoalHurtByTarget.java
similarity index 96%
rename from src/main/java/net/seanomik/tamablefoxes/versions/version_1_15/pathfinding/FoxPathfinderGoalHurtByTarget.java
rename to src/main/java/net/seanomik/tamablefoxes/versions/version_1_15_R1/pathfinding/FoxPathfinderGoalHurtByTarget.java
index 1c8a65a..ccc72ca 100644
--- a/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15/pathfinding/FoxPathfinderGoalHurtByTarget.java
+++ b/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15_R1/pathfinding/FoxPathfinderGoalHurtByTarget.java
@@ -1,6 +1,6 @@
-package net.seanomik.tamablefoxes.versions.version_1_15.pathfinding;
+package net.seanomik.tamablefoxes.versions.version_1_15_R1.pathfinding;
-import net.seanomik.tamablefoxes.EntityTamableFox;
+import net.seanomik.tamablefoxes.versions.version_1_15_R1.EntityTamableFox;
import net.minecraft.server.v1_15_R1.*;
import org.bukkit.event.entity.EntityTargetEvent.TargetReason;
diff --git a/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15/pathfinding/FoxPathfinderGoalMeleeAttack.java b/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15_R1/pathfinding/FoxPathfinderGoalMeleeAttack.java
similarity index 84%
rename from src/main/java/net/seanomik/tamablefoxes/versions/version_1_15/pathfinding/FoxPathfinderGoalMeleeAttack.java
rename to src/main/java/net/seanomik/tamablefoxes/versions/version_1_15_R1/pathfinding/FoxPathfinderGoalMeleeAttack.java
index c8a65b7..d1c9c7c 100644
--- a/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15/pathfinding/FoxPathfinderGoalMeleeAttack.java
+++ b/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15_R1/pathfinding/FoxPathfinderGoalMeleeAttack.java
@@ -1,37 +1,37 @@
-package net.seanomik.tamablefoxes.versions.version_1_15.pathfinding;
-
-import net.minecraft.server.v1_15_R1.EntityLiving;
-import net.minecraft.server.v1_15_R1.PathfinderGoalMeleeAttack;
-import net.minecraft.server.v1_15_R1.SoundEffects;
-import net.seanomik.tamablefoxes.EntityTamableFox;
-
-public class FoxPathfinderGoalMeleeAttack extends PathfinderGoalMeleeAttack {
- EntityTamableFox tamableFox;
- EntityLiving enemy;
-
- public FoxPathfinderGoalMeleeAttack(EntityTamableFox tamableFox, double d0, boolean flag) {
- super(tamableFox, d0, flag);
- this.tamableFox = tamableFox;
- }
-
- protected void a(EntityLiving entityliving, double d0) {
- double d1 = this.a(entityliving);
- this.enemy = entityliving;
-
- if (d0 <= d1 && this.b <= 0) {
- this.b = 20;
- this.a.B(entityliving);
- tamableFox.a(SoundEffects.ENTITY_FOX_BITE, 1.0F, 1.0F);
- }
-
- }
-
- public void c() {
- tamableFox.u(false);
- super.c();
- }
-
- public boolean a() {
- return !tamableFox.isSitting() && !tamableFox.isSleeping() && !tamableFox.isCrouching() && !tamableFox.es() && super.a();
- }
-}
+package net.seanomik.tamablefoxes.versions.version_1_15_R1.pathfinding;
+
+import net.minecraft.server.v1_15_R1.EntityLiving;
+import net.minecraft.server.v1_15_R1.PathfinderGoalMeleeAttack;
+import net.minecraft.server.v1_15_R1.SoundEffects;
+import net.seanomik.tamablefoxes.versions.version_1_15_R1.EntityTamableFox;
+
+public class FoxPathfinderGoalMeleeAttack extends PathfinderGoalMeleeAttack {
+ EntityTamableFox tamableFox;
+ EntityLiving enemy;
+
+ public FoxPathfinderGoalMeleeAttack(EntityTamableFox tamableFox, double d0, boolean flag) {
+ super(tamableFox, d0, flag);
+ this.tamableFox = tamableFox;
+ }
+
+ protected void a(EntityLiving entityliving, double d0) {
+ double d1 = this.a(entityliving);
+ this.enemy = entityliving;
+
+ if (d0 <= d1 && this.b <= 0) {
+ this.b = 20;
+ this.a.B(entityliving);
+ tamableFox.a(SoundEffects.ENTITY_FOX_BITE, 1.0F, 1.0F);
+ }
+
+ }
+
+ public void c() {
+ tamableFox.u(false);
+ super.c();
+ }
+
+ public boolean a() {
+ return !tamableFox.isSitting() && !tamableFox.isSleeping() && !tamableFox.isCrouching() && !tamableFox.es() && super.a();
+ }
+}
diff --git a/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15/pathfinding/FoxPathfinderGoalOwnerHurtByTarget.java b/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15_R1/pathfinding/FoxPathfinderGoalOwnerHurtByTarget.java
similarity index 87%
rename from src/main/java/net/seanomik/tamablefoxes/versions/version_1_15/pathfinding/FoxPathfinderGoalOwnerHurtByTarget.java
rename to src/main/java/net/seanomik/tamablefoxes/versions/version_1_15_R1/pathfinding/FoxPathfinderGoalOwnerHurtByTarget.java
index 709ad1c..880a7e1 100644
--- a/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15/pathfinding/FoxPathfinderGoalOwnerHurtByTarget.java
+++ b/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15_R1/pathfinding/FoxPathfinderGoalOwnerHurtByTarget.java
@@ -1,48 +1,48 @@
-package net.seanomik.tamablefoxes.versions.version_1_15.pathfinding;
-
-import net.seanomik.tamablefoxes.EntityTamableFox;
-import net.minecraft.server.v1_15_R1.EntityLiving;
-import net.minecraft.server.v1_15_R1.PathfinderGoalTarget;
-import net.minecraft.server.v1_15_R1.PathfinderTargetCondition;
-import org.bukkit.event.entity.EntityTargetEvent.TargetReason;
-
-import java.util.EnumSet;
-
-public class FoxPathfinderGoalOwnerHurtByTarget extends PathfinderGoalTarget {
-
- private final EntityTamableFox a;
- private EntityLiving b;
- private int c;
-
- public FoxPathfinderGoalOwnerHurtByTarget(EntityTamableFox tamableFox) {
- super(tamableFox, false);
- this.a = tamableFox;
- this.a(EnumSet.of(Type.TARGET));
- }
-
- public boolean a() {
- if (this.a.isTamed() && !this.a.isSitting()) {
- EntityLiving entityliving = this.a.getOwner();
- if (entityliving == null) {
- return false;
- } else {
- this.b = entityliving.getLastDamager();
- int i = entityliving.cI();
- return i != this.c && this.a(this.b, PathfinderTargetCondition.a) && this.a.a(this.b, entityliving);
- }
- } else {
- return false;
- }
- }
-
- public void c() {
- this.e.setGoalTarget(this.b, TargetReason.TARGET_ATTACKED_OWNER, true);
- EntityLiving entityliving = this.a.getOwner();
- if (entityliving != null) {
- this.c = entityliving.cI();
- }
-
- super.c();
- }
-
-}
+package net.seanomik.tamablefoxes.versions.version_1_15_R1.pathfinding;
+
+import net.seanomik.tamablefoxes.versions.version_1_15_R1.EntityTamableFox;
+import net.minecraft.server.v1_15_R1.EntityLiving;
+import net.minecraft.server.v1_15_R1.PathfinderGoalTarget;
+import net.minecraft.server.v1_15_R1.PathfinderTargetCondition;
+import org.bukkit.event.entity.EntityTargetEvent.TargetReason;
+
+import java.util.EnumSet;
+
+public class FoxPathfinderGoalOwnerHurtByTarget extends PathfinderGoalTarget {
+
+ private final EntityTamableFox a;
+ private EntityLiving b;
+ private int c;
+
+ public FoxPathfinderGoalOwnerHurtByTarget(EntityTamableFox tamableFox) {
+ super(tamableFox, false);
+ this.a = tamableFox;
+ this.a(EnumSet.of(Type.TARGET));
+ }
+
+ public boolean a() {
+ if (this.a.isTamed() && !this.a.isSitting()) {
+ EntityLiving entityliving = this.a.getOwner();
+ if (entityliving == null) {
+ return false;
+ } else {
+ this.b = entityliving.getLastDamager();
+ int i = entityliving.cI();
+ return i != this.c && this.a(this.b, PathfinderTargetCondition.a) && this.a.a(this.b, entityliving);
+ }
+ } else {
+ return false;
+ }
+ }
+
+ public void c() {
+ this.e.setGoalTarget(this.b, TargetReason.TARGET_ATTACKED_OWNER, true);
+ EntityLiving entityliving = this.a.getOwner();
+ if (entityliving != null) {
+ this.c = entityliving.cI();
+ }
+
+ super.c();
+ }
+
+}
diff --git a/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15/pathfinding/FoxPathfinderGoalOwnerHurtTarget.java b/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15_R1/pathfinding/FoxPathfinderGoalOwnerHurtTarget.java
similarity index 88%
rename from src/main/java/net/seanomik/tamablefoxes/versions/version_1_15/pathfinding/FoxPathfinderGoalOwnerHurtTarget.java
rename to src/main/java/net/seanomik/tamablefoxes/versions/version_1_15_R1/pathfinding/FoxPathfinderGoalOwnerHurtTarget.java
index dd6a59c..b5e3350 100644
--- a/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15/pathfinding/FoxPathfinderGoalOwnerHurtTarget.java
+++ b/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15_R1/pathfinding/FoxPathfinderGoalOwnerHurtTarget.java
@@ -1,47 +1,47 @@
-package net.seanomik.tamablefoxes.versions.version_1_15.pathfinding;
-
-import net.minecraft.server.v1_15_R1.EntityLiving;
-import net.minecraft.server.v1_15_R1.PathfinderGoalTarget;
-import net.minecraft.server.v1_15_R1.PathfinderTargetCondition;
-import net.seanomik.tamablefoxes.EntityTamableFox;
-import org.bukkit.event.entity.EntityTargetEvent.TargetReason;
-
-import java.util.EnumSet;
-
-public class FoxPathfinderGoalOwnerHurtTarget extends PathfinderGoalTarget {
- private final EntityTamableFox fox;
- private EntityLiving hitEntity;
- private int c;
-
- public FoxPathfinderGoalOwnerHurtTarget(EntityTamableFox entityTamableFox) {
- super(entityTamableFox, false);
- this.fox = entityTamableFox;
- this.a(EnumSet.of(Type.TARGET));
- }
-
- public boolean a() {
- if (fox.isTamed() && !fox.isSitting()) {
- EntityLiving entityliving = fox.getOwner();
- if (entityliving == null) {
- e.setGoalTarget(null);
- return false;
- } else {
- hitEntity = entityliving.cJ();
- int i = entityliving.cK();
- return i != this.c && this.a(hitEntity, PathfinderTargetCondition.a) && fox.a(hitEntity, entityliving);
- }
- } else {
- return false;
- }
- }
-
- public void c() {
- this.e.setGoalTarget(hitEntity, TargetReason.OWNER_ATTACKED_TARGET, true);
- EntityLiving entityliving = fox.getOwner();
- if (entityliving != null) {
- this.c = entityliving.cK();
- }
-
- super.c();
- }
+package net.seanomik.tamablefoxes.versions.version_1_15_R1.pathfinding;
+
+import net.minecraft.server.v1_15_R1.EntityLiving;
+import net.minecraft.server.v1_15_R1.PathfinderGoalTarget;
+import net.minecraft.server.v1_15_R1.PathfinderTargetCondition;
+import net.seanomik.tamablefoxes.versions.version_1_15_R1.EntityTamableFox;
+import org.bukkit.event.entity.EntityTargetEvent.TargetReason;
+
+import java.util.EnumSet;
+
+public class FoxPathfinderGoalOwnerHurtTarget extends PathfinderGoalTarget {
+ private final EntityTamableFox fox;
+ private EntityLiving hitEntity;
+ private int c;
+
+ public FoxPathfinderGoalOwnerHurtTarget(EntityTamableFox entityTamableFox) {
+ super(entityTamableFox, false);
+ this.fox = entityTamableFox;
+ this.a(EnumSet.of(Type.TARGET));
+ }
+
+ public boolean a() {
+ if (fox.isTamed() && !fox.isSitting()) {
+ EntityLiving entityliving = fox.getOwner();
+ if (entityliving == null) {
+ e.setGoalTarget(null);
+ return false;
+ } else {
+ hitEntity = entityliving.cJ();
+ int i = entityliving.cK();
+ return i != this.c && this.a(hitEntity, PathfinderTargetCondition.a) && fox.a(hitEntity, entityliving);
+ }
+ } else {
+ return false;
+ }
+ }
+
+ public void c() {
+ this.e.setGoalTarget(hitEntity, TargetReason.OWNER_ATTACKED_TARGET, true);
+ EntityLiving entityliving = fox.getOwner();
+ if (entityliving != null) {
+ this.c = entityliving.cK();
+ }
+
+ super.c();
+ }
}
\ No newline at end of file
diff --git a/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15/pathfinding/FoxPathfinderGoalPanic.java b/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15_R1/pathfinding/FoxPathfinderGoalPanic.java
similarity index 85%
rename from src/main/java/net/seanomik/tamablefoxes/versions/version_1_15/pathfinding/FoxPathfinderGoalPanic.java
rename to src/main/java/net/seanomik/tamablefoxes/versions/version_1_15_R1/pathfinding/FoxPathfinderGoalPanic.java
index 41d5682..fb8bb35 100644
--- a/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15/pathfinding/FoxPathfinderGoalPanic.java
+++ b/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15_R1/pathfinding/FoxPathfinderGoalPanic.java
@@ -1,8 +1,8 @@
-package net.seanomik.tamablefoxes.versions.version_1_15.pathfinding;
+package net.seanomik.tamablefoxes.versions.version_1_15_R1.pathfinding;
import net.minecraft.server.v1_15_R1.EntityFox;
import net.minecraft.server.v1_15_R1.PathfinderGoalPanic;
-import net.seanomik.tamablefoxes.EntityTamableFox;
+import net.seanomik.tamablefoxes.versions.version_1_15_R1.EntityTamableFox;
import java.lang.reflect.Method;
diff --git a/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15/pathfinding/FoxPathfinderGoalSit.java b/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15_R1/pathfinding/FoxPathfinderGoalSit.java
similarity index 89%
rename from src/main/java/net/seanomik/tamablefoxes/versions/version_1_15/pathfinding/FoxPathfinderGoalSit.java
rename to src/main/java/net/seanomik/tamablefoxes/versions/version_1_15_R1/pathfinding/FoxPathfinderGoalSit.java
index e682333..24cdb0d 100644
--- a/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15/pathfinding/FoxPathfinderGoalSit.java
+++ b/src/main/java/net/seanomik/tamablefoxes/versions/version_1_15_R1/pathfinding/FoxPathfinderGoalSit.java
@@ -1,6 +1,6 @@
-package net.seanomik.tamablefoxes.versions.version_1_15.pathfinding;
+package net.seanomik.tamablefoxes.versions.version_1_15_R1.pathfinding;
-import net.seanomik.tamablefoxes.EntityTamableFox;
+import net.seanomik.tamablefoxes.versions.version_1_15_R1.EntityTamableFox;
import net.minecraft.server.v1_15_R1.EntityLiving;
import net.minecraft.server.v1_15_R1.PathfinderGoal;
diff --git a/src/main/java/net/seanomik/tamablefoxes/versions/version_1_16_R1/EntityTamableFox.java b/src/main/java/net/seanomik/tamablefoxes/versions/version_1_16_R1/EntityTamableFox.java
new file mode 100644
index 0000000..801dd1a
--- /dev/null
+++ b/src/main/java/net/seanomik/tamablefoxes/versions/version_1_16_R1/EntityTamableFox.java
@@ -0,0 +1,550 @@
+package net.seanomik.tamablefoxes.versions.version_1_16_R1;
+
+import net.minecraft.server.v1_16_R1.*;
+import net.seanomik.tamablefoxes.TamableFoxes;
+import net.seanomik.tamablefoxes.Utils;
+import net.seanomik.tamablefoxes.io.Config;
+import net.seanomik.tamablefoxes.io.LanguageConfig;
+import net.seanomik.tamablefoxes.versions.version_1_16_R1.pathfinding.*;
+import net.wesjd.anvilgui.AnvilGUI;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.craftbukkit.libs.jline.internal.Nullable;
+import org.bukkit.craftbukkit.v1_16_R1.event.CraftEventFactory;
+import org.bukkit.craftbukkit.v1_16_R1.inventory.CraftItemStack;
+import org.bukkit.entity.Player;
+import org.bukkit.event.entity.EntityRegainHealthEvent;
+
+import java.lang.reflect.Field;
+import java.util.*;
+import java.util.function.Predicate;
+
+public class EntityTamableFox extends EntityFox {
+
+ protected static final DataWatcherObject tamed;
+ protected static final DataWatcherObject> ownerUUID;
+
+ private static final DataWatcherObject bw; // DATA_FLAGS_ID
+ private static final Predicate bC; // AVOID_PLAYERS
+
+ static {
+ tamed = DataWatcher.a(EntityTamableFox.class, DataWatcherRegistry.a);
+ ownerUUID = DataWatcher.a(EntityTamableFox.class, DataWatcherRegistry.o);
+
+ bw = DataWatcher.a(EntityFox.class, DataWatcherRegistry.a);
+ bC = (entity) -> !entity.bt() && IEntitySelector.e.test(entity);
+ }
+
+ List untamedGoals;
+ private FoxPathfinderGoalSit goalSit;
+
+ public EntityTamableFox(EntityTypes extends EntityFox> entitytypes, World world) {
+ super(entitytypes, world);
+ }
+
+ @Override
+ public void initPathfinder() {
+ try {
+ this.goalSit = new FoxPathfinderGoalSit(this);
+ this.goalSelector.a(1, goalSit);
+
+ // Wild animal attacking
+ Field landTargetGoal = this.getClass().getSuperclass().getDeclaredField("bD"); // landTargetGoal
+ landTargetGoal.setAccessible(true);
+ landTargetGoal.set(this, new PathfinderGoalNearestAttackableTarget(this, EntityAnimal.class, 10, false, false, (entityliving) -> {
+ return (!isTamed() || (Config.doesTamedAttackWildAnimals() && isTamed())) && (entityliving instanceof EntityChicken || entityliving instanceof EntityRabbit);
+ }));
+
+ Field turtleEggTargetGoal = this.getClass().getSuperclass().getDeclaredField("bE"); // turtleEggTargetGoal
+ turtleEggTargetGoal.setAccessible(true);
+ turtleEggTargetGoal.set(this, new PathfinderGoalNearestAttackableTarget(this, EntityTurtle.class, 10, false, false, (entityLiving) -> {
+ return (!isTamed() || (Config.doesTamedAttackWildAnimals() && isTamed())) && EntityTurtle.bv.test((EntityLiving) entityLiving);
+ }));
+
+ Field fishTargetGoal = this.getClass().getSuperclass().getDeclaredField("bF"); // fishTargetGoal
+ fishTargetGoal.setAccessible(true);
+ fishTargetGoal.set(this, new PathfinderGoalNearestAttackableTarget(this, EntityFish.class, 20, false, false, (entityliving) -> {
+ return (!isTamed() || (Config.doesTamedAttackWildAnimals() && isTamed())) && entityliving instanceof EntityFishSchool;
+ }));
+
+ this.goalSelector.a(0, getFoxInnerPathfinderGoal("g")); // FoxFloatGoal
+ this.goalSelector.a(1, getFoxInnerPathfinderGoal("b")); // FaceplantGoal
+ this.goalSelector.a(2, new FoxPathfinderGoalPanic(this, 2.2D)); // FoxPanicGoal
+ this.goalSelector.a(3, getFoxInnerPathfinderGoal("e", Arrays.asList(1.0D), Arrays.asList(double.class))); // FoxBreedGoal
+
+ this.goalSelector.a(4, new PathfinderGoalAvoidTarget(this, EntityHuman.class, 16.0F, 1.6D, 1.4D, (entityliving) -> {
+ return !isTamed() && bC.test((EntityLiving) entityliving);
+ }));
+ this.goalSelector.a(4, new PathfinderGoalAvoidTarget(this, EntityWolf.class, 8.0F, 1.6D, 1.4D, (entityliving) -> {
+ return !((EntityWolf)entityliving).isTamed() && !this.isDefending();
+ }));
+ this.goalSelector.a(4, new PathfinderGoalAvoidTarget(this, EntityPolarBear.class, 8.0F, 1.6D, 1.4D, (entityliving) -> {
+ return !this.isDefending();
+ }));
+
+ this.goalSelector.a(5, getFoxInnerPathfinderGoal("u")); // StalkPreyGoal
+ this.goalSelector.a(6, new EntityFox.o()); // FoxPounceGoal
+ this.goalSelector.a(7, getFoxInnerPathfinderGoal("l", Arrays.asList(1.2000000476837158D, true), Arrays.asList(double.class, boolean.class))); // FoxMeleeAttackGoal
+ this.goalSelector.a(8, getFoxInnerPathfinderGoal("h", Arrays.asList(this, 1.25D), Arrays.asList(EntityFox.class, double.class))); // FoxFollowParentGoal
+ this.goalSelector.a(8, new FoxPathfinderGoalSleepWithOwner(this));
+ this.goalSelector.a(9, new FoxPathfinderGoalFollowOwner(this, 1.3D, 10.0F, 2.0F, false));
+ this.goalSelector.a(10, new PathfinderGoalLeapAtTarget(this, 0.4F));
+ this.goalSelector.a(11, new PathfinderGoalRandomStrollLand(this, 1.0D));
+ this.goalSelector.a(11, getFoxInnerPathfinderGoal("p")); // FoxSearchForItemsGoal
+ this.goalSelector.a(12, getFoxInnerPathfinderGoal("j", Arrays.asList(this, EntityHuman.class, 24.0f),
+ Arrays.asList(EntityInsentient.class, Class.class, float.class))); // LookAtPlayer
+
+ //this.goalSelector.a(10, new EntityFox.f(1.2000000476837158D, 12, 2));
+
+ this.targetSelector.a(1, new FoxPathfinderGoalOwnerHurtByTarget(this));
+ this.targetSelector.a(2, new FoxPathfinderGoalOwnerHurtTarget(this));
+ this.targetSelector.a(3, (new FoxPathfinderGoalHurtByTarget(this)).a(new Class[0]));
+
+ // Assign all the untamed goals that will later be removed.
+ untamedGoals = new ArrayList<>();
+
+ // SleepGoal
+ PathfinderGoal sleep = getFoxInnerPathfinderGoal("t");
+ this.goalSelector.a(7, sleep);
+ untamedGoals.add(sleep);
+
+ // PerchAndSearch (Random sitting?)
+ PathfinderGoal perchAndSearch = getFoxInnerPathfinderGoal("r");
+ this.goalSelector.a(13, perchAndSearch);
+ untamedGoals.add(perchAndSearch);
+
+ // FoxEatBerriesGoal (Pick berry bushes)
+ PathfinderGoal eatBerries = new f(1.2000000476837158D, 12, 2);
+ this.goalSelector.a(11, eatBerries);
+ untamedGoals.add(eatBerries); // Maybe this should be configurable too?
+
+ // SeekShelterGoal
+ PathfinderGoal seekShelter = getFoxInnerPathfinderGoal("s", Arrays.asList(1.25D), Arrays.asList(double.class));
+ this.goalSelector.a(6, seekShelter);
+ untamedGoals.add(seekShelter);
+
+ PathfinderGoal strollThroughVillage = getFoxInnerPathfinderGoal("q", Arrays.asList(32, 200), Arrays.asList(int.class, int.class));
+ this.goalSelector.a(9, strollThroughVillage); // StrollThroughVillage
+ untamedGoals.add(strollThroughVillage);
+
+ // This is DefendTrustedTargetGoal so I don't think its needed
+ /*this.targetSelector.a(3, new EntityFox.a(EntityLiving.class, false, false, (entityliving) -> {
+ return bA.test(entityliving) && !this.c(entityliving.getUniqueID());
+ }));*/
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /* I need to find out a new way to do this.
+ * 1.16.1 introduced a new way that attributes are created. These methods are static methods
+ * which makes it so I can't override them. Each entity also has a unique method name.
+ */
+ /*protected void initAttributes() {
+ this.getAttributeMap().b(GenericAttributes.MAX_HEALTH);
+ this.getAttributeMap().b(GenericAttributes.KNOCKBACK_RESISTANCE);
+ this.getAttributeMap().b(GenericAttributes.MOVEMENT_SPEED);
+ this.getAttributeMap().b(GenericAttributes.ARMOR);
+ this.getAttributeMap().b(GenericAttributes.ARMOR_TOUGHNESS);
+
+ // Default value is 32, might want to make this configurable in the future
+ this.getAttributeMap().b(GenericAttributes.FOLLOW_RANGE);//.setValue(32.0D);
+ EntityLiving.cK().a(GenericAttributes.FOLLOW_RANGE, 16.0D).
+ //this.ck(GenericAttributes.FOLLOW_RANGE, 32.0D);
+
+ this.getAttributeMap().b(GenericAttributes.ATTACK_KNOCKBACK);
+
+ this.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).setValue(0.30000001192092896D);
+
+ if (!isTamed()) {
+ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(10.0D);
+ this.getAttributeMap().b(GenericAttributes.ATTACK_DAMAGE).setValue(2.0D);
+ } else {
+ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(24.0D);
+ this.getAttributeInstance(GenericAttributes.ATTACK_DAMAGE).setValue(3.0D);
+ }
+ }*/
+
+ // deobf: getFlag
+ private boolean t(int i) {
+ return ((Byte)this.datawatcher.get(bw) & i) != 0;
+ }
+
+ // deobf: 'isDefending' from 'fc'
+ public boolean isDefending() {
+ return this.t(128);
+ }
+
+ // deobf: setFlag
+ /*public void d(int i, boolean flag) {
+ if (flag) {
+ this.datawatcher.set(bw, (byte)((Byte)this.datawatcher.get(bw) | i));
+ } else {
+ this.datawatcher.set(bw, (byte)((Byte)this.datawatcher.get(bw) & ~i));
+ }
+ }*/
+
+ /*public void x(boolean flag) {
+ this.datawatcher.set(bA, flag);
+ }*/
+
+ public static Object getPrivateField(String fieldName, Class clazz, Object object) {
+ Field field;
+ Object o = null;
+
+ try {
+ field = clazz.getDeclaredField(fieldName);
+ field.setAccessible(true);
+ o = field.get(object);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ e.printStackTrace();
+ }
+
+ return o;
+ }
+
+ protected void initDatawatcher() {
+ super.initDatawatcher();
+ this.datawatcher.register(tamed, (byte) 0);
+ this.datawatcher.register(ownerUUID, Optional.empty());
+ }
+
+ @Override
+ public void saveData(NBTTagCompound compound) {
+ super.saveData(compound);
+ if (this.getOwnerUUID() == null) {
+ compound.setString("OwnerUUID", "");
+ } else {
+ compound.setString("OwnerUUID", this.getOwnerUUID().toString());
+ }
+
+ compound.setBoolean("Sitting", this.isSitting());
+ }
+
+ public void loadData(NBTTagCompound compound) {
+ super.loadData(compound);
+ String ownerUuid;
+
+ if (compound.hasKeyOfType("OwnerUUID", 8)) {
+ ownerUuid = compound.getString("OwnerUUID");
+ } else {
+ String var2 = compound.getString("Owner");
+ ownerUuid = NameReferencingFileConverter.a(this.getMinecraftServer(), var2).toString();
+ }
+
+ if (!ownerUuid.isEmpty()) {
+ try {
+ this.setOwnerUUID(UUID.fromString(ownerUuid));
+ this.setTamed(true);
+ } catch (Throwable throwable) {
+ this.setTamed(false);
+ }
+ }
+
+ if (this.goalSit != null) {
+ this.goalSit.setSitting(compound.getBoolean("Sitting"));
+ }
+
+ this.setSitting(compound.getBoolean("Sitting"));
+ }
+
+ public boolean isTamed() {
+ return ((Byte) this.datawatcher.get(tamed) & 4) != 0;
+ }
+
+ public void setTamed(boolean tamed_) {
+ byte isTamed = this.datawatcher.get(tamed);
+ if (tamed_) {
+ this.datawatcher.set(tamed, (byte) (isTamed | 4));
+ } else {
+ this.datawatcher.set(tamed, (byte) (isTamed & -5));
+ }
+ this.reassessTameGoals();
+
+ if (tamed_) {
+ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(24.0D);
+ this.getAttributeInstance(GenericAttributes.ATTACK_DAMAGE).setValue(3.0D);
+ this.setHealth(this.getMaxHealth());
+ } else {
+ this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(10.0D);
+ this.getAttributeInstance(GenericAttributes.ATTACK_DAMAGE).setValue(2.0D);
+ }
+ }
+
+ // Remove untamed goals if its tamed.
+ private void reassessTameGoals() {
+ if (!isTamed()) return;
+
+ for (PathfinderGoal untamedGoal : untamedGoals) {
+ this.goalSelector.a(untamedGoal);
+ }
+ }
+
+ // deobf: mobInteract
+ public EnumInteractionResult b(EntityHuman entityhuman, EnumHand enumhand) {
+ ItemStack itemstack = entityhuman.b(enumhand);
+ Item item = itemstack.getItem();
+
+ if (itemstack.getItem() instanceof ItemMonsterEgg) {
+ return super.a(entityhuman, enumhand);
+ } else {
+ if (this.isTamed()) {
+
+ // Heal the fox if its health is below the max.
+ if (item.isFood() && item.getFoodInfo().c() && this.getHealth() < this.getMaxHealth()) {
+ // Only remove the item from the player if they're in survival mode.
+ if (!entityhuman.abilities.canInstantlyBuild) {
+ itemstack.subtract(1);
+ }
+
+ this.heal((float)item.getFoodInfo().getNutrition(), EntityRegainHealthEvent.RegainReason.EATING);
+ return EnumInteractionResult.CONSUME;
+ }
+
+ if (isOwnedBy(entityhuman)) {
+ // This super method checks if the fox can breed or not.
+ EnumInteractionResult flag = super.b(entityhuman, enumhand);
+
+ // If the player is not sneaking and the fox cannot breed, then make the fox sit.
+ // @TODO: Do I need to use this.eQ() instead of flag != EnumInteractionResult.SUCCESS?
+ if (!entityhuman.isSneaking() && (flag != EnumInteractionResult.SUCCESS || this.isBaby())) {
+ this.goalSit.setSitting(!this.isSitting());
+ return flag;
+ } else if (entityhuman.isSneaking()) { // Swap/Put/Take item from fox.
+ // Ignore buckets since they can be easily duplicated.
+ if (itemstack.getItem() == Items.BUCKET || itemstack.getItem() == Items.LAVA_BUCKET || itemstack.getItem() == Items.WATER_BUCKET) {
+ return EnumInteractionResult.PASS;
+ }
+
+ if (!this.getEquipment(EnumItemSlot.MAINHAND).isEmpty()) {
+ getBukkitEntity().getWorld().dropItem(getBukkitEntity().getLocation(), CraftItemStack.asBukkitCopy(this.getEquipment(EnumItemSlot.MAINHAND)));
+ this.setSlot(EnumItemSlot.MAINHAND, new ItemStack(Items.AIR));
+ }
+
+ // Run this task async to make sure to not slow the server down.
+ // This is needed due to the item being remove as soon as its put in the foxes mouth.
+ Bukkit.getScheduler().runTaskLaterAsynchronously(TamableFoxes.getPlugin(), ()-> {
+ // Put item in mouth
+ if (item != Items.AIR) {
+ ItemStack c = itemstack.cloneItemStack();
+ c.setCount(1);
+
+ // Only remove the item from the player if they're in survival mode.
+ if (!entityhuman.abilities.canInstantlyBuild) {
+ itemstack.subtract(1);
+ }
+
+ this.setSlot(EnumItemSlot.MAINHAND, c);
+ }
+ }, (long) 0.1);
+
+ return EnumInteractionResult.SUCCESS;
+ //return true;
+ }
+ }
+ } else if (item == Items.CHICKEN) {
+ // Check if the player has permissions to tame the fox
+ if (Config.canPlayerTameFox((Player) entityhuman.getBukkitEntity())) {
+ // Only remove the item from the player if they're in survival mode.
+ if (!entityhuman.abilities.canInstantlyBuild) {
+ itemstack.subtract(1);
+ }
+
+ // 0.33% chance to tame the fox, also check if the called tame entity event is cancelled or not.
+ if (this.random.nextInt(3) == 0 && !CraftEventFactory.callEntityTameEvent(this, entityhuman).isCancelled()) {
+ this.tame(entityhuman);
+
+ // Remove all navigation when tamed.
+ this.navigation.o();
+ this.setGoalTarget(null);
+ this.goalSit.setSitting(true);
+
+ getBukkitEntity().getWorld().spawnParticle(org.bukkit.Particle.HEART, getBukkitEntity().getLocation(), 6, 0.5D, 0.5D, 0.5D);
+
+ // Give player tamed message.
+ ((Player) entityhuman.getBukkitEntity()).sendMessage(Utils.getPrefix() + ChatColor.GREEN + LanguageConfig.getTamedMessage());
+
+ // Let the player choose the new fox's name if its enabled in config.
+ if (Config.askForNameAfterTaming()) {
+ Player player = (Player) entityhuman.getBukkitEntity();
+
+ player.sendMessage(Utils.getPrefix() + ChatColor.RED + LanguageConfig.getTamingAskingName());
+ new AnvilGUI.Builder()
+ .onComplete((plr, input) -> { // Called when the inventory output slot is clicked
+ if (!input.equals("")) {
+ org.bukkit.entity.Entity tamableFox = this.getBukkitEntity();
+
+ // This will auto format the name for config settings.
+ String foxName = LanguageConfig.getFoxNameFormat(input, player.getDisplayName());
+
+ tamableFox.setCustomName(foxName);
+ tamableFox.setCustomNameVisible(true);
+ plr.sendMessage(Utils.getPrefix() + ChatColor.GREEN + LanguageConfig.getTamingChosenPerfect(input));
+ }
+
+ return AnvilGUI.Response.close();
+ })
+ .text("Fox name") // Sets the text the GUI should start with
+ .plugin(TamableFoxes.getPlugin()) // Set the plugin instance
+ .open(player); // Opens the GUI for the player provided
+ }
+ } else {
+ getBukkitEntity().getWorld().spawnParticle(org.bukkit.Particle.SMOKE_NORMAL, getBukkitEntity().getLocation(), 10, 0.2D, 0.2D, 0.2D, 0.15D);
+ }
+ }
+
+ return EnumInteractionResult.SUCCESS;
+ }
+
+ return super.b(entityhuman, enumhand);
+ }
+ }
+
+ @Override
+ public EntityTamableFox createChild(EntityAgeable entityageable) {
+ EntityTamableFox entityFox = (EntityTamableFox) EntityTypes.FOX.a(this.world);
+ entityFox.setFoxType(this.getFoxType());
+
+ UUID uuid = this.getOwnerUUID();
+ if (uuid != null) {
+ entityFox.setOwnerUUID(uuid);
+ entityFox.setTamed(true);
+ }
+
+ return entityFox;
+ }
+
+ public boolean mate(EntityAnimal entityanimal) {
+ if (entityanimal == this) {
+ return false;
+ } else if (!(entityanimal instanceof EntityTamableFox)) {
+ return false;
+ } else {
+ EntityTamableFox entityFox = (EntityTamableFox) entityanimal;
+ return (!entityFox.isSitting() && (this.isInLove() && entityFox.isInLove()));
+ }
+ }
+
+ @Nullable
+ public UUID getOwnerUUID() {
+ return (UUID) ((Optional) this.datawatcher.get(ownerUUID)).orElse(null);
+ }
+
+ public void setOwnerUUID(@Nullable UUID ownerUuid) {
+ this.datawatcher.set(ownerUUID, Optional.ofNullable(ownerUuid));
+ }
+
+ public void tame(EntityHuman owner) {
+ this.setTamed(true);
+ this.setOwnerUUID(owner.getUniqueID());
+
+ // Give the player the taming advancement.
+ if (owner instanceof EntityPlayer) {
+ CriterionTriggers.x.a((EntityPlayer)owner, this);
+ }
+ }
+
+ @Nullable
+ public EntityLiving getOwner() {
+ try {
+ UUID ownerUuid = this.getOwnerUUID();
+ return ownerUuid == null ? null : this.world.b(ownerUuid);
+ } catch (IllegalArgumentException var2) {
+ return null;
+ }
+ }
+
+ // Only attack entity if its not attacking owner.
+ @Override
+ public boolean d(EntityLiving entity) {
+ return !this.isOwnedBy(entity) && super.d(entity);
+ }
+
+ public boolean isOwnedBy(EntityLiving entity) {
+ return entity == this.getOwner();
+ }
+
+ /*
+ deobf: wantsToAttack (Copied from EntityWolf)
+ This code being from EntityWolf also means that wolves will want to attack foxes
+ Our life would be so much easier if we could extend both EntityFox and EntityTameableAnimal
+ */
+ public boolean a(EntityLiving entityliving, EntityLiving entityliving1) {
+ if (!(entityliving instanceof EntityCreeper) && !(entityliving instanceof EntityGhast)) {
+ if (entityliving instanceof EntityTamableFox) {
+ EntityTamableFox entityFox = (EntityTamableFox) entityliving;
+ return !entityFox.isTamed() || entityFox.getOwner() != entityliving1;
+ } else {
+ return (!(entityliving instanceof EntityHuman)
+ || !(entityliving1 instanceof EntityHuman) ||
+ ((EntityHuman) entityliving1).a((EntityHuman) entityliving)) && ((!(entityliving instanceof EntityHorseAbstract)
+ || !((EntityHorseAbstract) entityliving).isTamed()) && (!(entityliving instanceof EntityTameableAnimal)
+ || !((EntityTameableAnimal) entityliving).isTamed()));
+ }
+ } else {
+ return false;
+ }
+ }
+
+ // Set the scoreboard team to the same as the owner if its tamed.
+ public ScoreboardTeamBase getScoreboardTeam() {
+ if (this.isTamed()) {
+ EntityLiving var0 = this.getOwner();
+ if (var0 != null) {
+ return var0.getScoreboardTeam();
+ }
+ }
+
+ return super.getScoreboardTeam();
+ }
+
+ // Override isAlliedTo (Entity::r(Entity))
+ public boolean r(Entity entity) {
+ if (this.isTamed()) {
+ EntityLiving entityOwner = this.getOwner();
+ if (entity == entityOwner) {
+ return true;
+ }
+
+ if (entityOwner != null) {
+ return entityOwner.r(entity);
+ }
+ }
+ return super.r(entity);
+ }
+
+ // When the fox dies, show a chat message.
+ public void die(DamageSource damageSource) {
+ if (!this.world.isClientSide && this.world.getGameRules().getBoolean(GameRules.SHOW_DEATH_MESSAGES) && this.getOwner() instanceof EntityPlayer) {
+ this.getOwner().sendMessage(this.getCombatTracker().getDeathMessage(), getOwnerUUID());
+ }
+
+ super.die(damageSource);
+ }
+
+
+ private PathfinderGoal getFoxInnerPathfinderGoal(String innerName, List