EntityTamableFox recode and a few changes
- Recoded EntityTamableFox to clean the pathfinder bloat - Removed sleeping and chosenName as this data is already handled by vanilla - Improved some logic around interact event - Added a config option to enable and disable the anvil name GUI - Fixed a bug where item counts would go to zero if just one was present
This commit is contained in:
parent
a6408840b2
commit
afef958991
|
@ -1,11 +1,12 @@
|
||||||
package net.seanomik.tamablefoxes;
|
package net.seanomik.tamablefoxes;
|
||||||
|
|
||||||
import com.mojang.datafixers.Dynamic;
|
|
||||||
import net.minecraft.server.v1_15_R1.*;
|
import net.minecraft.server.v1_15_R1.*;
|
||||||
import net.seanomik.tamablefoxes.io.Config;
|
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.pathfinding.*;
|
||||||
import org.bukkit.ChatColor;
|
|
||||||
import org.bukkit.NamespacedKey;
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
|
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftEntity;
|
||||||
import org.bukkit.craftbukkit.v1_15_R1.inventory.CraftItemStack;
|
import org.bukkit.craftbukkit.v1_15_R1.inventory.CraftItemStack;
|
||||||
import org.bukkit.craftbukkit.v1_15_R1.persistence.CraftPersistentDataContainer;
|
import org.bukkit.craftbukkit.v1_15_R1.persistence.CraftPersistentDataContainer;
|
||||||
import org.bukkit.entity.Item;
|
import org.bukkit.entity.Item;
|
||||||
|
@ -13,29 +14,37 @@ import org.bukkit.persistence.PersistentDataContainer;
|
||||||
import org.bukkit.persistence.PersistentDataType;
|
import org.bukkit.persistence.PersistentDataType;
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class EntityTamableFox extends EntityFox {
|
public class EntityTamableFox extends EntityFox {
|
||||||
|
|
||||||
|
List<PathfinderGoal> untamedGoals = new ArrayList<>();
|
||||||
private boolean tamed;
|
private boolean tamed;
|
||||||
private boolean sitting;
|
private boolean sitting;
|
||||||
private boolean sleeping;
|
|
||||||
private String chosenName;
|
|
||||||
private EntityLiving owner;
|
private EntityLiving owner;
|
||||||
private UUID ownerUUID;
|
private UUID ownerUUID;
|
||||||
|
|
||||||
private FoxPathfinderGoalSit goalSit;
|
private FoxPathfinderGoalSit goalSit;
|
||||||
private PathfinderGoal goalRandomSitting;
|
|
||||||
private PathfinderGoal goalBerryPicking;
|
|
||||||
private PathfinderGoal goalFleeSun;
|
|
||||||
private PathfinderGoal goalNearestVillage;
|
|
||||||
|
|
||||||
public EntityTamableFox(EntityTypes<? extends EntityFox> entitytypes, World world) {
|
public EntityTamableFox(EntityTypes<? extends EntityFox> entitytypes, World world) {
|
||||||
super(entitytypes, world);
|
super(entitytypes, world);
|
||||||
|
|
||||||
|
clearPathFinderGoals();
|
||||||
|
initPathfinderGoals();
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
private PathfinderGoal getFoxInnerPathfinderGoal(String innerName, List<Object> args, List<Class<?>> argTypes) {
|
private PathfinderGoal getFoxInnerPathfinderGoal(String innerName, List<Object> args, List<Class<?>> argTypes) {
|
||||||
|
@ -47,18 +56,37 @@ public class EntityTamableFox extends EntityFox {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initPathfinder() {
|
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(16.0D);
|
||||||
|
|
||||||
|
this.getAttributeMap().b(GenericAttributes.ATTACK_KNOCKBACK);
|
||||||
|
|
||||||
|
this.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).setValue(0.30000001192092896D);
|
||||||
|
|
||||||
|
// Default value is 10, might want to make this configurable in the future
|
||||||
|
this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(24.0D);
|
||||||
|
|
||||||
|
// Default value is 2, might want to make this configurable in the future
|
||||||
|
this.getAttributeMap().b(GenericAttributes.ATTACK_DAMAGE).setValue(3.0D);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initPathfinderGoals() {
|
||||||
try {
|
try {
|
||||||
|
this.goalSelector.a(0, getFoxInnerPathfinderGoal("g")); // FloatGoal
|
||||||
|
|
||||||
this.goalSit = new FoxPathfinderGoalSit(this);
|
this.goalSit = new FoxPathfinderGoalSit(this);
|
||||||
this.goalSelector.a(0, getFoxInnerPathfinderGoal("g")); // Swim
|
this.goalSelector.a(1, goalSit);
|
||||||
this.goalSelector.a(1, this.goalSit);
|
|
||||||
this.goalSelector.a(1, getFoxInnerPathfinderGoal("b")); // Unknown
|
|
||||||
|
|
||||||
// Panic
|
this.goalSelector.a(1, getFoxInnerPathfinderGoal("b")); // FaceplantGoal
|
||||||
this.goalSelector.a(2, new FoxPathfinderGoalPanic(this, 2.2D));
|
this.goalSelector.a(2, new FoxPathfinderGoalPanic(this, 2.2D)); // PanicGoal
|
||||||
|
this.goalSelector.a(3, getFoxInnerPathfinderGoal("e", Arrays.asList(1.0D), Arrays.asList(double.class))); // BreedGoal
|
||||||
// Breed
|
|
||||||
this.goalSelector.a(3, getFoxInnerPathfinderGoal("n", Arrays.asList(1.0D), Arrays.asList(double.class)));
|
|
||||||
|
|
||||||
// Avoid human only if not tamed
|
// Avoid human only if not tamed
|
||||||
this.goalSelector.a(4, new PathfinderGoalAvoidTarget(this, EntityHuman.class, 16.0F, 1.6D, 1.4D, (entityliving) -> !tamed));
|
this.goalSelector.a(4, new PathfinderGoalAvoidTarget(this, EntityHuman.class, 16.0F, 1.6D, 1.4D, (entityliving) -> !tamed));
|
||||||
|
@ -76,35 +104,38 @@ public class EntityTamableFox extends EntityFox {
|
||||||
return !((EntityWolf) entityliving).isTamed();
|
return !((EntityWolf) entityliving).isTamed();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.goalSelector.a(4, new FoxPathfinderGoalMeleeAttack(this, 1.2000000476837158D, true));
|
this.goalSelector.a(4, new FoxPathfinderGoalMeleeAttack(this, 1.2000000476837158D, true));
|
||||||
this.goalSelector.a(5, new FoxPathfinderGoalFollowOwner(this, 1.3D, 10.0F, 2.0F, false));
|
this.goalSelector.a(5, new FoxPathfinderGoalFollowOwner(this, 1.3D, 10.0F, 2.0F, false));
|
||||||
this.goalSelector.a(6, getFoxInnerPathfinderGoal("u")); // Lunge shake
|
this.goalSelector.a(6, getFoxInnerPathfinderGoal("u")); // StalkPrey
|
||||||
this.goalSelector.a(7, new EntityFox.o()); // Lunge
|
this.goalSelector.a(7, new EntityFox.o()); // Pounce
|
||||||
|
|
||||||
// Flee sun
|
PathfinderGoal seekShelter = getFoxInnerPathfinderGoal("s", Arrays.asList(1.25D), Arrays.asList(double.class));
|
||||||
goalFleeSun = getFoxInnerPathfinderGoal("s", Arrays.asList(1.25D), Arrays.asList(double.class));
|
this.goalSelector.a(7, seekShelter); // SeekShelter
|
||||||
this.goalSelector.a(7, goalFleeSun);
|
untamedGoals.add(seekShelter);
|
||||||
|
|
||||||
this.goalSelector.a(8, getFoxInnerPathfinderGoal("t")); // Sleeping under trees
|
this.goalSelector.a(8, getFoxInnerPathfinderGoal("t")); // Sleep
|
||||||
this.goalSelector.a(9, getFoxInnerPathfinderGoal("h", Arrays.asList(this, 1.25D), Arrays.asList(EntityFox.class, double.class))); // Follow parent
|
this.goalSelector.a(9, getFoxInnerPathfinderGoal("h", Arrays.asList(this, 1.25D), Arrays.asList(EntityFox.class, double.class))); // FollowParent
|
||||||
|
|
||||||
// Nearest village
|
PathfinderGoal strollThroughVillage = getFoxInnerPathfinderGoal("q", Arrays.asList(32, 200), Arrays.asList(int.class, int.class));
|
||||||
goalNearestVillage = getFoxInnerPathfinderGoal("q", Arrays.asList(32, 200), Arrays.asList(int.class, int.class));
|
this.goalSelector.a(9, strollThroughVillage); // StrollThroughVillage
|
||||||
this.goalSelector.a(9, goalNearestVillage);
|
untamedGoals.add(strollThroughVillage);
|
||||||
|
|
||||||
// Pick berry bushes
|
// EatBerries (Pick berry bushes)
|
||||||
goalBerryPicking = new EntityFox.f(1.2000000476837158D, 12, 2);
|
PathfinderGoal eatBerries = new EntityFox.f(1.2000000476837158D, 12, 2);
|
||||||
this.goalSelector.a(10, goalBerryPicking);
|
this.goalSelector.a(10, eatBerries);
|
||||||
|
untamedGoals.add(eatBerries); // Maybe this should be configurable too?
|
||||||
|
|
||||||
this.goalSelector.a(10, new PathfinderGoalLeapAtTarget(this, 0.4F));
|
this.goalSelector.a(10, new PathfinderGoalLeapAtTarget(this, 0.4F));
|
||||||
this.goalSelector.a(11, new PathfinderGoalRandomStrollLand(this, 1.15D));
|
this.goalSelector.a(11, new PathfinderGoalRandomStrollLand(this, 1.15D));
|
||||||
|
|
||||||
this.goalSelector.a(11, getFoxInnerPathfinderGoal("p")); // If a item is on the ground, go to it and take it
|
this.goalSelector.a(11, getFoxInnerPathfinderGoal("p")); // SearchForItems
|
||||||
this.goalSelector.a(12, getFoxInnerPathfinderGoal("j", Arrays.asList(this, EntityHuman.class, 24.0f), Arrays.asList(EntityInsentient.class, Class.class, float.class))); // Look at player
|
this.goalSelector.a(12, getFoxInnerPathfinderGoal("j", Arrays.asList(this, EntityHuman.class, 24.0f), Arrays.asList(EntityInsentient.class, Class.class, float.class))); // LookAtPlayer
|
||||||
|
|
||||||
// The random sitting(?)
|
// PerchAndSearch (Random sitting?)
|
||||||
this.goalRandomSitting = getFoxInnerPathfinderGoal("r");
|
PathfinderGoal perchAndSearch = getFoxInnerPathfinderGoal("r");
|
||||||
this.goalSelector.a(13, goalRandomSitting);
|
this.goalSelector.a(13, perchAndSearch);
|
||||||
|
untamedGoals.add(perchAndSearch);
|
||||||
|
|
||||||
this.targetSelector.a(1, new FoxPathfinderGoalOwnerHurtByTarget(this));
|
this.targetSelector.a(1, new FoxPathfinderGoalOwnerHurtByTarget(this));
|
||||||
this.targetSelector.a(2, new FoxPathfinderGoalOwnerHurtTarget(this));
|
this.targetSelector.a(2, new FoxPathfinderGoalOwnerHurtTarget(this));
|
||||||
|
@ -122,118 +153,85 @@ public class EntityTamableFox extends EntityFox {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void clearPathFinderGoals() {
|
||||||
protected void initAttributes() {
|
Set<?> goalSet = (Set<?>) getPrivateField("d", PathfinderGoalSelector.class, goalSelector);
|
||||||
this.getAttributeMap().b(GenericAttributes.MAX_HEALTH);
|
Set<?> targetSet = (Set<?>) getPrivateField("d", PathfinderGoalSelector.class, targetSelector);
|
||||||
this.getAttributeMap().b(GenericAttributes.KNOCKBACK_RESISTANCE);
|
goalSet.clear();
|
||||||
this.getAttributeMap().b(GenericAttributes.MOVEMENT_SPEED);
|
targetSet.clear();
|
||||||
this.getAttributeMap().b(GenericAttributes.ARMOR);
|
|
||||||
this.getAttributeMap().b(GenericAttributes.ARMOR_TOUGHNESS);
|
|
||||||
this.getAttributeMap().b(GenericAttributes.FOLLOW_RANGE).setValue(16.0D);
|
|
||||||
this.getAttributeMap().b(GenericAttributes.ATTACK_KNOCKBACK);
|
|
||||||
|
|
||||||
this.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED).setValue(0.30000001192092896D);
|
Map<?, ?> goalMap = (Map<?, ?>) getPrivateField("c", PathfinderGoalSelector.class, goalSelector);
|
||||||
this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(24.0D);
|
Map<?, ?> targetMap = (Map<?, ?>) getPrivateField("c", PathfinderGoalSelector.class, targetSelector);
|
||||||
|
goalMap.clear();
|
||||||
|
targetMap.clear();
|
||||||
|
|
||||||
this.getAttributeMap().b(GenericAttributes.ATTACK_DAMAGE).setValue(3.0D);
|
EnumSet<?> goalEnumSet = (EnumSet<?>) getPrivateField("f", PathfinderGoalSelector.class, goalSelector);
|
||||||
}
|
EnumSet<?> targetEnumSet = (EnumSet<?>) getPrivateField("f", PathfinderGoalSelector.class, targetSelector);
|
||||||
|
goalEnumSet.clear();
|
||||||
public boolean isOtherFoxFamily(EntityLiving living) {
|
targetEnumSet.clear();
|
||||||
if (living instanceof EntityTamableFox) {
|
|
||||||
EntityTamableFox tamableFox = (EntityTamableFox) living;
|
|
||||||
|
|
||||||
return (tamableFox.isTamed() && tamableFox.getOwner().getUniqueID() == this.getOwner().getUniqueID());
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTamed(boolean tamed) {
|
|
||||||
this.tamed = tamed;
|
|
||||||
|
|
||||||
// Remove goals that are not needed when named, or defeats the purpose of taming
|
|
||||||
this.goalSelector.a(goalRandomSitting);
|
|
||||||
this.goalSelector.a(goalBerryPicking);
|
|
||||||
this.goalSelector.a(goalFleeSun);
|
|
||||||
this.goalSelector.a(goalNearestVillage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isTamed() {
|
public boolean isTamed() {
|
||||||
return tamed;
|
return tamed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOwner(EntityLiving entityLiving) {
|
public void setTamed(boolean tamed) {
|
||||||
this.owner = entityLiving;
|
this.tamed = tamed;
|
||||||
updateFoxVisual();
|
|
||||||
|
// Remove goals that are not needed when named, or defeats the purpose of taming
|
||||||
|
untamedGoals.forEach(goal -> goalSelector.a(goal));
|
||||||
}
|
}
|
||||||
|
|
||||||
public EntityLiving getOwner() {
|
public EntityLiving getOwner() {
|
||||||
|
if (Objects.isNull(owner)) {
|
||||||
|
if (ownerUUID == null) return null;
|
||||||
|
OfflinePlayer opOwner = TamableFoxes.getPlugin().getServer().getOfflinePlayer(UUID.fromString(ownerUUID.toString()));
|
||||||
|
if (opOwner.isOnline()) this.owner = (EntityLiving) ((CraftEntity) opOwner).getHandle();
|
||||||
|
}
|
||||||
return owner;
|
return owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOwnerUUID(UUID uuid) {
|
public void setOwner(EntityLiving entityLiving) {
|
||||||
this.ownerUUID = uuid;
|
this.owner = entityLiving;
|
||||||
}
|
this.ownerUUID = entityLiving.getUniqueID();
|
||||||
|
|
||||||
public UUID getOwnerUUID() {
|
|
||||||
return ownerUUID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setChosenName(String name) {
|
|
||||||
this.chosenName = name;
|
|
||||||
updateFoxVisual();
|
updateFoxVisual();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getChosenName() {
|
public void setOwnerUUID(UUID ownerUUID) {
|
||||||
return chosenName;
|
this.ownerUUID = ownerUUID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMouthItem(ItemStack item) {
|
public boolean isOtherFoxFamily(EntityLiving living) {
|
||||||
item.setCount(1);
|
if (living instanceof EntityTamableFox) {
|
||||||
setSlot(EnumItemSlot.MAINHAND, item);
|
EntityTamableFox tamableFox = (EntityTamableFox) living;
|
||||||
|
|
||||||
save();
|
return (tamableFox.isTamed() && tamableFox.getOwner() != null && tamableFox.getOwner().getUniqueID() == this.getOwner().getUniqueID());
|
||||||
}
|
} else {
|
||||||
|
return false;
|
||||||
public void setMouthItem(org.bukkit.inventory.ItemStack item) {
|
}
|
||||||
ItemStack itemNMS = CraftItemStack.asNMSCopy(item);
|
|
||||||
setMouthItem(itemNMS);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ItemStack getMouthItem() {
|
|
||||||
return getEquipment(EnumItemSlot.MAINHAND);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Item dropMouthItem() {
|
|
||||||
Item droppedItem = getBukkitEntity().getWorld().dropItem(getBukkitEntity().getLocation().add(0, 0, 0), CraftItemStack.asBukkitCopy(getMouthItem()));
|
|
||||||
setSlot(EnumItemSlot.MAINHAND, new net.minecraft.server.v1_15_R1.ItemStack(Items.AIR));
|
|
||||||
|
|
||||||
return droppedItem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateFoxVisual() {
|
||||||
|
new BukkitRunnable() {
|
||||||
@Override
|
@Override
|
||||||
public void setSitting(boolean sit) {
|
public void run() {
|
||||||
super.setSitting(sit);
|
goalSit.setSitting(sitting);
|
||||||
|
|
||||||
if (sleeping) {
|
if (tamed && owner != null && !hasCustomName() && Config.doesShowOwnerFoxName()) {
|
||||||
sleeping = false;
|
getBukkitEntity().setCustomName(LanguageConfig.getOwnerInFoxNameFormat().replaceAll("%player%", owner.getName()));
|
||||||
super.setSleeping(false);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}.runTask(TamableFoxes.getPlugin());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHardSitting(boolean hardSitting) {
|
||||||
|
super.setSitting(hardSitting);
|
||||||
|
this.sitting = hardSitting;
|
||||||
|
|
||||||
|
if (super.isSleeping()) super.setSleeping(false);
|
||||||
|
|
||||||
updateFoxVisual();
|
updateFoxVisual();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHardSitting(boolean sit) {
|
|
||||||
super.setSitting(sit);
|
|
||||||
this.sitting = sit;
|
|
||||||
|
|
||||||
if (sleeping) {
|
|
||||||
sleeping = false;
|
|
||||||
super.setSleeping(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
updateFoxVisual();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean toggleSitting() {
|
public boolean toggleSitting() {
|
||||||
this.sitting = !this.sitting;
|
this.sitting = !this.sitting;
|
||||||
|
@ -242,31 +240,29 @@ public class EntityTamableFox extends EntityFox {
|
||||||
return this.sitting;
|
return this.sitting;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isJumping() {
|
public ItemStack getMouthItem() {
|
||||||
return this.jumping;
|
return getEquipment(EnumItemSlot.MAINHAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateFoxVisual() {
|
public void setMouthItem(ItemStack item) {
|
||||||
new UpdateFoxRunnable().runTask(TamableFoxes.getPlugin());
|
item.setCount(1);
|
||||||
|
setSlot(EnumItemSlot.MAINHAND, item);
|
||||||
|
saveNbt();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class UpdateFoxRunnable extends BukkitRunnable {
|
public void setMouthItem(org.bukkit.inventory.ItemStack item) {
|
||||||
UpdateFoxRunnable() {
|
ItemStack itemNMS = CraftItemStack.asNMSCopy(item);
|
||||||
|
setMouthItem(itemNMS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run() {
|
public org.bukkit.entity.Item dropMouthItem() {
|
||||||
goalSit.setSitting(sitting);
|
Item droppedItem = getBukkitEntity().getWorld().dropItem(getBukkitEntity().getLocation(), CraftItemStack.asBukkitCopy(getMouthItem()));
|
||||||
|
setSlot(EnumItemSlot.MAINHAND, new net.minecraft.server.v1_15_R1.ItemStack(Items.AIR));
|
||||||
|
|
||||||
if (tamed) {
|
return droppedItem;
|
||||||
getBukkitEntity().setCustomName((chosenName != null ? chosenName : "")
|
|
||||||
+ (owner != null && Config.doesShowOwnerFoxName() ? ChatColor.RESET + " (" + owner.getName() + ")" : ""));
|
|
||||||
getBukkitEntity().setCustomNameVisible(Config.doesShowNameTags());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void save() {
|
public void saveNbt() {
|
||||||
NamespacedKey rootKey = new NamespacedKey(TamableFoxes.getPlugin(), "tamableFoxes");
|
NamespacedKey rootKey = new NamespacedKey(TamableFoxes.getPlugin(), "tamableFoxes");
|
||||||
CraftPersistentDataContainer persistentDataContainer = getBukkitEntity().getPersistentDataContainer();
|
CraftPersistentDataContainer persistentDataContainer = getBukkitEntity().getPersistentDataContainer();
|
||||||
PersistentDataContainer tamableFoxesData;
|
PersistentDataContainer tamableFoxesData;
|
||||||
|
@ -277,218 +273,10 @@ public class EntityTamableFox extends EntityFox {
|
||||||
}
|
}
|
||||||
|
|
||||||
NamespacedKey ownerKey = new NamespacedKey(TamableFoxes.getPlugin(), "owner");
|
NamespacedKey ownerKey = new NamespacedKey(TamableFoxes.getPlugin(), "owner");
|
||||||
NamespacedKey chosenNameKey = new NamespacedKey(TamableFoxes.getPlugin(), "chosenName");
|
|
||||||
NamespacedKey sittingKey = new NamespacedKey(TamableFoxes.getPlugin(), "sitting");
|
NamespacedKey sittingKey = new NamespacedKey(TamableFoxes.getPlugin(), "sitting");
|
||||||
NamespacedKey sleepingKey = new NamespacedKey(TamableFoxes.getPlugin(), "sleeping");
|
|
||||||
tamableFoxesData.set(ownerKey, PersistentDataType.STRING, getOwner() == null ? "none" : getOwner().getUniqueID().toString());
|
tamableFoxesData.set(ownerKey, PersistentDataType.STRING, getOwner() == null ? "none" : getOwner().getUniqueID().toString());
|
||||||
if (getChosenName() != null && !getChosenName().isEmpty()) {
|
|
||||||
tamableFoxesData.set(chosenNameKey, PersistentDataType.STRING, getChosenName());
|
|
||||||
}
|
|
||||||
tamableFoxesData.set(sittingKey, PersistentDataType.BYTE, (byte) (isSitting() ? 1 : 0));
|
tamableFoxesData.set(sittingKey, PersistentDataType.BYTE, (byte) (isSitting() ? 1 : 0));
|
||||||
tamableFoxesData.set(sleepingKey, PersistentDataType.BYTE, (byte) (isSleeping() ? 1 : 0));
|
|
||||||
|
|
||||||
persistentDataContainer.set(rootKey, PersistentDataType.TAG_CONTAINER, tamableFoxesData);
|
persistentDataContainer.set(rootKey, PersistentDataType.TAG_CONTAINER, tamableFoxesData);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used for all the nasty stuff below.
|
|
||||||
private static boolean isLevelAtLeast(NBTTagCompound tag, int level) {
|
|
||||||
return tag.hasKey("Bukkit.updateLevel") && tag.getInt("Bukkit.updateLevel") >= level;
|
|
||||||
}
|
|
||||||
|
|
||||||
// To remove a call to initializePathFinderGoals()
|
|
||||||
// This is all from every super class that has a method like this.
|
|
||||||
// This was needed because you cant call a "super.super.method()"
|
|
||||||
@Override
|
|
||||||
public void a(NBTTagCompound nbttagcompound) {
|
|
||||||
try {
|
|
||||||
// EntityLiving
|
|
||||||
this.setAbsorptionHearts(nbttagcompound.getFloat("AbsorptionAmount"));
|
|
||||||
if (nbttagcompound.hasKeyOfType("Attributes", 9) && this.world != null && !this.world.isClientSide) {
|
|
||||||
GenericAttributes.a(this.getAttributeMap(), nbttagcompound.getList("Attributes", 10));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nbttagcompound.hasKeyOfType("ActiveEffects", 9)) {
|
|
||||||
NBTTagList nbttaglist = nbttagcompound.getList("ActiveEffects", 10);
|
|
||||||
|
|
||||||
for(int i = 0; i < nbttaglist.size(); ++i) {
|
|
||||||
NBTTagCompound nbttagcompound1 = nbttaglist.getCompound(i);
|
|
||||||
MobEffect mobeffect = MobEffect.b(nbttagcompound1);
|
|
||||||
if (mobeffect != null) {
|
|
||||||
this.effects.put(mobeffect.getMobEffect(), mobeffect);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nbttagcompound.hasKey("Bukkit.MaxHealth")) {
|
|
||||||
NBTBase nbtbase = nbttagcompound.get("Bukkit.MaxHealth");
|
|
||||||
if (nbtbase.getTypeId() == 5) {
|
|
||||||
this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(((NBTTagFloat)nbtbase).asDouble());
|
|
||||||
} else if (nbtbase.getTypeId() == 3) {
|
|
||||||
this.getAttributeInstance(GenericAttributes.MAX_HEALTH).setValue(((NBTTagInt)nbtbase).asDouble());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nbttagcompound.hasKeyOfType("Health", 99)) {
|
|
||||||
this.setHealth(nbttagcompound.getFloat("Health"));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.hurtTicks = nbttagcompound.getShort("HurtTime");
|
|
||||||
this.deathTicks = nbttagcompound.getShort("DeathTime");
|
|
||||||
this.hurtTimestamp = nbttagcompound.getInt("HurtByTimestamp");
|
|
||||||
if (nbttagcompound.hasKeyOfType("Team", 8)) {
|
|
||||||
String s = nbttagcompound.getString("Team");
|
|
||||||
ScoreboardTeam scoreboardteam = this.world.getScoreboard().getTeam(s);
|
|
||||||
boolean flag = scoreboardteam != null && this.world.getScoreboard().addPlayerToTeam(this.getUniqueIDString(), scoreboardteam);
|
|
||||||
if (!flag) {
|
|
||||||
LOGGER.warn("Unable to add mob to team \"{}\" (that team probably doesn't exist)", s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nbttagcompound.getBoolean("FallFlying")) {
|
|
||||||
this.setFlag(7, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nbttagcompound.hasKeyOfType("SleepingX", 99) && nbttagcompound.hasKeyOfType("SleepingY", 99) && nbttagcompound.hasKeyOfType("SleepingZ", 99)) {
|
|
||||||
BlockPosition blockposition = new BlockPosition(nbttagcompound.getInt("SleepingX"), nbttagcompound.getInt("SleepingY"), nbttagcompound.getInt("SleepingZ"));
|
|
||||||
this.d(blockposition);
|
|
||||||
this.datawatcher.set(POSE, EntityPose.SLEEPING);
|
|
||||||
if (!this.justCreated) {
|
|
||||||
this.a(blockposition);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nbttagcompound.hasKeyOfType("Brain", 10)) {
|
|
||||||
this.bo = this.a(new Dynamic(DynamicOpsNBT.a, nbttagcompound.get("Brain")));
|
|
||||||
}
|
|
||||||
// EntityInsentient
|
|
||||||
NonNullList<ItemStack> by = (NonNullList<ItemStack>) Utils.getPrivateFieldValue(EntityInsentient.class, "by", this);
|
|
||||||
NonNullList<ItemStack> bx = (NonNullList<ItemStack>) Utils.getPrivateFieldValue(EntityInsentient.class, "bx", this);
|
|
||||||
|
|
||||||
boolean data;
|
|
||||||
if (nbttagcompound.hasKeyOfType("CanPickUpLoot", 1)) {
|
|
||||||
data = nbttagcompound.getBoolean("CanPickUpLoot");
|
|
||||||
if (isLevelAtLeast(nbttagcompound, 1) || data) {
|
|
||||||
this.setCanPickupLoot(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data = nbttagcompound.getBoolean("PersistenceRequired");
|
|
||||||
if (isLevelAtLeast(nbttagcompound, 1) || data) {
|
|
||||||
this.persistent = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
NBTTagList nbttaglist;
|
|
||||||
int i;
|
|
||||||
if (nbttagcompound.hasKeyOfType("ArmorItems", 9)) {
|
|
||||||
nbttaglist = nbttagcompound.getList("ArmorItems", 10);
|
|
||||||
|
|
||||||
for(i = 0; i < by.size(); ++i) {
|
|
||||||
by.set(i, ItemStack.a(nbttaglist.getCompound(i)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nbttagcompound.hasKeyOfType("HandItems", 9)) {
|
|
||||||
nbttaglist = nbttagcompound.getList("HandItems", 10);
|
|
||||||
|
|
||||||
for(i = 0; i < bx.size(); ++i) {
|
|
||||||
bx.set(i, ItemStack.a(nbttaglist.getCompound(i)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nbttagcompound.hasKeyOfType("ArmorDropChances", 9)) {
|
|
||||||
nbttaglist = nbttagcompound.getList("ArmorDropChances", 5);
|
|
||||||
|
|
||||||
for(i = 0; i < nbttaglist.size(); ++i) {
|
|
||||||
this.dropChanceArmor[i] = nbttaglist.i(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nbttagcompound.hasKeyOfType("HandDropChances", 9)) {
|
|
||||||
nbttaglist = nbttagcompound.getList("HandDropChances", 5);
|
|
||||||
|
|
||||||
for(i = 0; i < nbttaglist.size(); ++i) {
|
|
||||||
this.dropChanceHand[i] = nbttaglist.i(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nbttagcompound.hasKeyOfType("Leash", 10)) {
|
|
||||||
//this.bG = nbttagcompound.getCompound("Leash");
|
|
||||||
Utils.setPrivateFieldValue(EntityInsentient.class, "bG", this, nbttagcompound.getCompound("Leash"));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.p(nbttagcompound.getBoolean("LeftHanded"));
|
|
||||||
if (nbttagcompound.hasKeyOfType("DeathLootTable", 8)) {
|
|
||||||
this.lootTableKey = new MinecraftKey(nbttagcompound.getString("DeathLootTable"));
|
|
||||||
this.lootTableSeed = nbttagcompound.getLong("DeathLootTableSeed");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setNoAI(nbttagcompound.getBoolean("NoAI"));
|
|
||||||
// EntityAgeable
|
|
||||||
this.setAgeRaw(nbttagcompound.getInt("Age"));
|
|
||||||
this.c = nbttagcompound.getInt("ForcedAge");
|
|
||||||
this.ageLocked = nbttagcompound.getBoolean("AgeLocked");
|
|
||||||
// EntityAnimal
|
|
||||||
this.loveTicks = nbttagcompound.getInt("InLove");
|
|
||||||
this.breedCause = nbttagcompound.b("LoveCause") ? nbttagcompound.a("LoveCause") : null;
|
|
||||||
|
|
||||||
NBTTagList foxNBTTagList = nbttagcompound.getList("TrustedUUIDs", 10);
|
|
||||||
|
|
||||||
Method method = this.getClass().getSuperclass().getDeclaredMethod("b", UUID.class);
|
|
||||||
method.setAccessible(true);
|
|
||||||
for (int index = 0; index < foxNBTTagList.size(); ++index) {
|
|
||||||
//this.b(GameProfileSerializer.b(nbttaglist.getCompound(i)));
|
|
||||||
method.invoke(this, GameProfileSerializer.b(foxNBTTagList.getCompound(index)));
|
|
||||||
}
|
|
||||||
method.setAccessible(false);
|
|
||||||
|
|
||||||
this.setSleeping(nbttagcompound.getBoolean("Sleeping"));
|
|
||||||
this.setFoxType(EntityFox.Type.a(nbttagcompound.getString("Type")));
|
|
||||||
|
|
||||||
// Use super class due to the new set sitting causing errors
|
|
||||||
super.setSitting(nbttagcompound.getBoolean("Sitting"));
|
|
||||||
|
|
||||||
this.setCrouching(nbttagcompound.getBoolean("Crouching"));
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// To remove the last call to initializePathFinderGoals()
|
|
||||||
// Cant just override because its a private method
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public GroupDataEntity prepare(GeneratorAccess generatoraccess, DifficultyDamageScaler difficultydamagescaler,
|
|
||||||
EnumMobSpawn enummobspawn, GroupDataEntity groupdataentity, NBTTagCompound nbttagcompound) {
|
|
||||||
BiomeBase biomebase = generatoraccess.getBiome(new BlockPosition(this));
|
|
||||||
Type entityfox_type = Type.a(biomebase);
|
|
||||||
boolean flag = false;
|
|
||||||
if (groupdataentity instanceof i) {
|
|
||||||
entityfox_type = ((i) groupdataentity).a;
|
|
||||||
if (((i) groupdataentity).a() >= 2) {
|
|
||||||
flag = true;
|
|
||||||
} else {
|
|
||||||
((i) groupdataentity).b();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
groupdataentity = new i(entityfox_type);
|
|
||||||
((i) groupdataentity).b();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setFoxType(entityfox_type);
|
|
||||||
if (flag) {
|
|
||||||
this.setAgeRaw(-24000);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.initPathfinder();
|
|
||||||
this.a(difficultydamagescaler);
|
|
||||||
this.getAttributeInstance(GenericAttributes.FOLLOW_RANGE).addModifier(new AttributeModifier("Random spawn bonus",
|
|
||||||
this.random.nextGaussian() * 0.05D, AttributeModifier.Operation.MULTIPLY_BASE));
|
|
||||||
if (this.random.nextFloat() < 0.05F) {
|
|
||||||
this.p(true);
|
|
||||||
} else {
|
|
||||||
this.p(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return groupdataentity;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,13 +27,11 @@ import org.bukkit.inventory.EquipmentSlot;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
// @TODO:
|
// @TODO:
|
||||||
|
@ -101,12 +99,12 @@ public final class TamableFoxes extends JavaPlugin implements Listener {
|
||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
getServer().getConsoleSender().sendMessage(Utils.getPrefix() + ChatColor.YELLOW + LanguageConfig.getSavingFoxMessage());
|
getServer().getConsoleSender().sendMessage(Utils.getPrefix() + ChatColor.YELLOW + LanguageConfig.getSavingFoxMessage());
|
||||||
spawnedFoxes.forEach(EntityTamableFox::save);
|
spawnedFoxes.forEach(EntityTamableFox::saveNbt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onWorldSaveEvent(WorldSaveEvent event) {
|
public void onWorldSaveEvent(WorldSaveEvent event) {
|
||||||
spawnedFoxes.forEach(EntityTamableFox::save);
|
spawnedFoxes.forEach(EntityTamableFox::saveNbt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
|
@ -150,54 +148,41 @@ public final class TamableFoxes extends JavaPlugin implements Listener {
|
||||||
if (Utils.isTamableFox(entity)) {
|
if (Utils.isTamableFox(entity)) {
|
||||||
EntityTamableFox tamableFox = (EntityTamableFox) ((CraftEntity) entity).getHandle();
|
EntityTamableFox tamableFox = (EntityTamableFox) ((CraftEntity) entity).getHandle();
|
||||||
|
|
||||||
// Check if its tamed but ignore it if the player is holding sweet berries for breeding
|
// Check if its tamed but ignore it if the player is holding sweet berries for breeding or nametag for renaming
|
||||||
if (tamableFox.isTamed() && tamableFox.getOwner() != null && itemHand.getType() != Material.SWEET_BERRIES) {
|
if (tamableFox.isTamed() && tamableFox.getOwner() != null && itemHand.getType() != Material.SWEET_BERRIES && itemHand.getType() != Material.NAME_TAG) {
|
||||||
if (tamableFox.getOwner().getUniqueID() == player.getUniqueId()) {
|
if (tamableFox.getOwner().getUniqueID() == player.getUniqueId()) {
|
||||||
|
event.setCancelled(true);
|
||||||
if (player.isSneaking()) {
|
if (player.isSneaking()) {
|
||||||
net.minecraft.server.v1_15_R1.ItemStack foxMouth = tamableFox.getEquipment(EnumItemSlot.MAINHAND);
|
net.minecraft.server.v1_15_R1.ItemStack foxMouth = tamableFox.getEquipment(EnumItemSlot.MAINHAND);
|
||||||
|
if (!foxMouth.isEmpty()) tamableFox.dropMouthItem();
|
||||||
if (foxMouth.isEmpty() && itemHand.getType() != Material.AIR) { // Giving an item
|
if (itemHand.getType() != Material.AIR) {
|
||||||
tamableFox.setMouthItem(itemHand);
|
tamableFox.setMouthItem(itemHand);
|
||||||
itemHand.setAmount(itemHand.getAmount() - 1);
|
if (itemHand.getAmount() == 1) player.getInventory().removeItem(itemHand);
|
||||||
} else if (!foxMouth.isEmpty() && itemHand.getType() == Material.AIR) { // Taking the item
|
else itemHand.setAmount(itemHand.getAmount() - 1);
|
||||||
tamableFox.dropMouthItem();
|
|
||||||
} else if (!foxMouth.isEmpty() && itemHand.getType() != Material.AIR){ // Swapping items
|
|
||||||
// Drop item
|
|
||||||
tamableFox.dropMouthItem();
|
|
||||||
|
|
||||||
// Give item and take one away from player
|
|
||||||
tamableFox.setMouthItem(itemHand);
|
|
||||||
itemHand.setAmount(itemHand.getAmount() - 1);
|
|
||||||
}
|
}
|
||||||
} else if (itemHand.getType() == Material.NAME_TAG) {
|
|
||||||
tamableFox.setChosenName(handMeta.getDisplayName());
|
|
||||||
} else {
|
} else {
|
||||||
tamableFox.toggleSitting();
|
tamableFox.toggleSitting();
|
||||||
}
|
}
|
||||||
|
|
||||||
event.setCancelled(true);
|
|
||||||
}
|
}
|
||||||
} else if (itemHand.getType() == Material.CHICKEN && Config.canPlayerTameFox(player)) {
|
} else if (itemHand.getType() == Material.CHICKEN && Config.canPlayerTameFox(player)) {
|
||||||
if (Math.random() < 0.33D) { // tamed
|
if (Math.random() < 0.33D) { // tamed
|
||||||
tamableFox.setTamed(true);
|
tamableFox.setTamed(true);
|
||||||
tamableFox.setOwner(((CraftPlayer) player).getHandle());
|
tamableFox.setOwner(((CraftPlayer) player).getHandle());
|
||||||
// store uuid
|
|
||||||
player.getWorld().spawnParticle(Particle.HEART, entity.getLocation(), 6, 0.5D, 0.5D, 0.5D);
|
player.getWorld().spawnParticle(Particle.HEART, entity.getLocation(), 6, 0.5D, 0.5D, 0.5D);
|
||||||
|
|
||||||
// Name fox
|
|
||||||
player.sendMessage(ChatColor.RED + ChatColor.BOLD.toString() + LanguageConfig.getTamedMessage());
|
player.sendMessage(ChatColor.RED + ChatColor.BOLD.toString() + LanguageConfig.getTamedMessage());
|
||||||
|
|
||||||
|
if (Config.askForNameAfterTaming()) {
|
||||||
player.sendMessage(ChatColor.RED + LanguageConfig.getTamingAskingName());
|
player.sendMessage(ChatColor.RED + LanguageConfig.getTamingAskingName());
|
||||||
tamableFox.setChosenName("???");
|
|
||||||
|
|
||||||
//TamableFoxes.getPlugin().sqLiteSetterGetter.saveFox(tamableFox);
|
|
||||||
|
|
||||||
event.setCancelled(true);
|
|
||||||
new AnvilGUI.Builder()
|
new AnvilGUI.Builder()
|
||||||
.onComplete((plr, text) -> { // Called when the inventory output slot is clicked
|
.onComplete((plr, text) -> { // Called when the inventory output slot is clicked
|
||||||
if(!text.equals("")) {
|
if (!text.equals("")) {
|
||||||
tamableFox.setChosenName(text);
|
tamableFox.getBukkitEntity().setCustomName(text);
|
||||||
|
tamableFox.setCustomNameVisible(true);
|
||||||
plr.sendMessage(Utils.getPrefix() + ChatColor.GREEN + LanguageConfig.getTamingChosenPerfect(text));
|
plr.sendMessage(Utils.getPrefix() + ChatColor.GREEN + LanguageConfig.getTamingChosenPerfect(text));
|
||||||
tamableFox.save();
|
tamableFox.saveNbt();
|
||||||
}
|
}
|
||||||
|
|
||||||
return AnvilGUI.Response.close();
|
return AnvilGUI.Response.close();
|
||||||
|
@ -206,12 +191,14 @@ public final class TamableFoxes extends JavaPlugin implements Listener {
|
||||||
.text("Fox name") // Sets the text the GUI should start with
|
.text("Fox name") // Sets the text the GUI should start with
|
||||||
.plugin(this) // Set the plugin instance
|
.plugin(this) // Set the plugin instance
|
||||||
.open(player); // Opens the GUI for the player provided
|
.open(player); // Opens the GUI for the player provided
|
||||||
|
}
|
||||||
} else { // Tame failed
|
} else { // Tame failed
|
||||||
player.getWorld().spawnParticle(Particle.SMOKE_NORMAL, entity.getLocation(), 10, 0.3D, 0.3D, 0.3D, 0.15D);
|
player.getWorld().spawnParticle(Particle.SMOKE_NORMAL, entity.getLocation(), 10, 0.3D, 0.3D, 0.3D, 0.15D);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!player.getGameMode().equals(GameMode.CREATIVE)) {
|
if (!player.getGameMode().equals(GameMode.CREATIVE)) {
|
||||||
itemHand.setAmount(itemHand.getAmount() - 1);
|
if (itemHand.getAmount() == 1) player.getInventory().removeItem(itemHand);
|
||||||
|
else itemHand.setAmount(itemHand.getAmount() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
|
@ -248,19 +235,14 @@ public final class TamableFoxes extends JavaPlugin implements Listener {
|
||||||
public void onEntityDeathEvent(EntityDeathEvent event) {
|
public void onEntityDeathEvent(EntityDeathEvent event) {
|
||||||
Entity entity = event.getEntity();
|
Entity entity = event.getEntity();
|
||||||
if (!Utils.isTamableFox(entity)) return; // Is the entity a tamable fox?
|
if (!Utils.isTamableFox(entity)) return; // Is the entity a tamable fox?
|
||||||
|
|
||||||
// Remove the fox from storage
|
// Remove the fox from storage
|
||||||
spawnedFoxes.remove(entity);
|
spawnedFoxes.remove(entity);
|
||||||
|
|
||||||
// Notify the owner
|
// Notify the owner
|
||||||
EntityTamableFox tamableFox = (EntityTamableFox) ((CraftEntity) entity).getHandle();
|
EntityTamableFox tamableFox = (EntityTamableFox) ((CraftEntity) entity).getHandle();
|
||||||
if (tamableFox.getOwner() != null) {
|
if (tamableFox.getOwner() != null) {
|
||||||
Player owner = ((EntityPlayer) tamableFox.getOwner()).getBukkitEntity();
|
Player owner = ((EntityPlayer) tamableFox.getOwner()).getBukkitEntity();
|
||||||
owner.sendMessage(Utils.getPrefix() + ChatColor.RED + tamableFox.getChosenName() + " was killed!");
|
owner.sendMessage(Utils.getPrefix() + ChatColor.RED + (tamableFox.hasCustomName() ? tamableFox.getBukkitEntity().getCustomName() : "Your fox") + " was killed!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the fox from database
|
|
||||||
//sqLiteSetterGetter.removeFox(tamableFox);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public EntityTamableFox spawnTamableFox(Location loc, EntityFox.Type type) {
|
public EntityTamableFox spawnTamableFox(Location loc, EntityFox.Type type) {
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
package net.seanomik.tamablefoxes;
|
package net.seanomik.tamablefoxes;
|
||||||
|
|
||||||
import net.minecraft.server.v1_15_R1.EntityLiving;
|
import net.minecraft.server.v1_15_R1.EntityLiving;
|
||||||
import org.bukkit.*;
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.Chunk;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.OfflinePlayer;
|
||||||
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftEntity;
|
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftEntity;
|
||||||
import org.bukkit.craftbukkit.v1_15_R1.persistence.CraftPersistentDataContainer;
|
import org.bukkit.craftbukkit.v1_15_R1.persistence.CraftPersistentDataContainer;
|
||||||
import org.bukkit.entity.Entity;
|
|
||||||
import org.bukkit.persistence.PersistentDataContainer;
|
import org.bukkit.persistence.PersistentDataContainer;
|
||||||
import org.bukkit.persistence.PersistentDataType;
|
import org.bukkit.persistence.PersistentDataType;
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
@ -25,35 +26,6 @@ public class Utils {
|
||||||
return ChatColor.RED + "[Tamable Foxes] ";
|
return ChatColor.RED + "[Tamable Foxes] ";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object getPrivateFieldValue(Class c, String field, Object instance) {
|
|
||||||
Object value = null;
|
|
||||||
try {
|
|
||||||
Field f = c.getDeclaredField(field);
|
|
||||||
f.setAccessible(true);
|
|
||||||
value = f.get(instance);
|
|
||||||
f.setAccessible(false);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setPrivateFieldValue(Class c, String field, Object instance, Object value) {
|
|
||||||
try {
|
|
||||||
Field f = c.getDeclaredField(field);
|
|
||||||
f.setAccessible(true);
|
|
||||||
f.set(instance, value);
|
|
||||||
f.setAccessible(false);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void sendConsoleMessage(String message) {
|
|
||||||
TamableFoxes.getPlugin().getServer().getConsoleSender().sendMessage(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Class<?> getPrivateInnerClass(Class outer, String innerName) {
|
public static Class<?> getPrivateInnerClass(Class outer, String innerName) {
|
||||||
for (Class<?> declaredClass : outer.getDeclaredClasses()) {
|
for (Class<?> declaredClass : outer.getDeclaredClasses()) {
|
||||||
if (declaredClass.getSimpleName().equals(innerName)) return declaredClass;
|
if (declaredClass.getSimpleName().equals(innerName)) return declaredClass;
|
||||||
|
@ -101,35 +73,27 @@ public class Utils {
|
||||||
if (persistentDataContainer.has(rootKey, PersistentDataType.TAG_CONTAINER)) {
|
if (persistentDataContainer.has(rootKey, PersistentDataType.TAG_CONTAINER)) {
|
||||||
PersistentDataContainer tamableFoxesData = persistentDataContainer.get(rootKey, PersistentDataType.TAG_CONTAINER);
|
PersistentDataContainer tamableFoxesData = persistentDataContainer.get(rootKey, PersistentDataType.TAG_CONTAINER);
|
||||||
NamespacedKey ownerKey = new NamespacedKey(TamableFoxes.getPlugin(), "owner");
|
NamespacedKey ownerKey = new NamespacedKey(TamableFoxes.getPlugin(), "owner");
|
||||||
NamespacedKey chosenNameKey = new NamespacedKey(TamableFoxes.getPlugin(), "chosenName");
|
|
||||||
NamespacedKey sittingKey = new NamespacedKey(TamableFoxes.getPlugin(), "sitting");
|
NamespacedKey sittingKey = new NamespacedKey(TamableFoxes.getPlugin(), "sitting");
|
||||||
NamespacedKey sleepingKey = new NamespacedKey(TamableFoxes.getPlugin(), "sleeping");
|
|
||||||
|
|
||||||
String ownerUUIDString = tamableFoxesData.get(ownerKey, PersistentDataType.STRING);
|
String ownerUUIDString = tamableFoxesData.get(ownerKey, PersistentDataType.STRING);
|
||||||
String chosenName = tamableFoxesData.get(chosenNameKey, PersistentDataType.STRING);
|
|
||||||
boolean sitting = ((byte) 1) == tamableFoxesData.get(sittingKey, PersistentDataType.BYTE);
|
boolean sitting = ((byte) 1) == tamableFoxesData.get(sittingKey, PersistentDataType.BYTE);
|
||||||
boolean sleeping = ((byte) 1) == tamableFoxesData.get(sleepingKey, PersistentDataType.BYTE);
|
|
||||||
|
|
||||||
boolean tamed = false;
|
boolean tamed = false;
|
||||||
if (!ownerUUIDString.equals("none")) {
|
if (!ownerUUIDString.equals("none")) {
|
||||||
tamed = true;
|
tamed = true;
|
||||||
|
|
||||||
OfflinePlayer owner = TamableFoxes.getPlugin().getServer().getOfflinePlayer(UUID.fromString(ownerUUIDString));
|
OfflinePlayer owner = TamableFoxes.getPlugin().getServer().getOfflinePlayer(UUID.fromString(ownerUUIDString));
|
||||||
if (owner.isOnline()) {
|
if (owner.isOnline()) {
|
||||||
EntityLiving livingOwner = (EntityLiving) ((CraftEntity) owner).getHandle();
|
EntityLiving livingOwner = (EntityLiving) ((CraftEntity) owner).getHandle();
|
||||||
tamableFox.setOwner(livingOwner);
|
tamableFox.setOwner(livingOwner);
|
||||||
|
} else {
|
||||||
|
tamableFox.setOwnerUUID(UUID.fromString(ownerUUIDString));
|
||||||
}
|
}
|
||||||
|
|
||||||
tamableFox.setOwnerUUID(owner.getUniqueId());
|
|
||||||
tamableFox.setTamed(true);
|
tamableFox.setTamed(true);
|
||||||
tamableFox.setChosenName(chosenName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sitting && tamed) {
|
if (sitting && tamed) {
|
||||||
tamableFox.setHardSitting(true);
|
tamableFox.setHardSitting(true);
|
||||||
} else if (sleeping) {
|
} else {
|
||||||
tamableFox.setSleeping(true);
|
|
||||||
} else { // Avoid the foxes getting stuck sitting down.
|
|
||||||
tamableFox.setSitting(false);
|
tamableFox.setSitting(false);
|
||||||
tamableFox.setSleeping(false);
|
tamableFox.setSleeping(false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,6 @@ public class Config {
|
||||||
return plugin.getConfig().getBoolean("show-owner-in-fox-name");
|
return plugin.getConfig().getBoolean("show-owner-in-fox-name");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean doesShowNameTags() {
|
|
||||||
return plugin.getConfig().getBoolean("show-nametags");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean doesTamedAttackWildAnimals() {
|
public static boolean doesTamedAttackWildAnimals() {
|
||||||
return plugin.getConfig().getBoolean("tamed-behavior.attack-wild-animals");
|
return plugin.getConfig().getBoolean("tamed-behavior.attack-wild-animals");
|
||||||
}
|
}
|
||||||
|
@ -22,4 +18,8 @@ public class Config {
|
||||||
return !plugin.getConfig().getBoolean("enable-taming-permission") || (plugin.getConfig().getBoolean("enable-taming-permission") && (player.hasPermission("tamablefoxes.tame") || player.isOp()));
|
return !plugin.getConfig().getBoolean("enable-taming-permission") || (plugin.getConfig().getBoolean("enable-taming-permission") && (player.hasPermission("tamablefoxes.tame") || player.isOp()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean askForNameAfterTaming() {
|
||||||
|
return plugin.getConfig().getBoolean("ask-for-name-after-taming");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,6 +107,10 @@ public class LanguageConfig extends YamlConfiguration {
|
||||||
return getConfig().getString("taming-chosen-name-perfect").replaceAll("%NAME%", chosen);
|
return getConfig().getString("taming-chosen-name-perfect").replaceAll("%NAME%", chosen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getOwnerInFoxNameFormat() {
|
||||||
|
return getConfig().getString("owner-in-fox-name-format");
|
||||||
|
}
|
||||||
|
|
||||||
public static String getNoPermMessage() {
|
public static String getNoPermMessage() {
|
||||||
return getConfig().getString("no-permission");
|
return getConfig().getString("no-permission");
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ public class CommandSpawnTamableFox implements TabExecutor {
|
||||||
case "red":
|
case "red":
|
||||||
try {
|
try {
|
||||||
EntityTamableFox fox = plugin.spawnTamableFox(player.getLocation(), EntityFox.Type.RED);
|
EntityTamableFox fox = plugin.spawnTamableFox(player.getLocation(), EntityFox.Type.RED);
|
||||||
fox.save();
|
fox.saveNbt();
|
||||||
|
|
||||||
player.sendMessage(Utils.getPrefix() + ChatColor.RESET + LanguageConfig.getSpawnedFoxMessage(EntityFox.Type.RED));
|
player.sendMessage(Utils.getPrefix() + ChatColor.RESET + LanguageConfig.getSpawnedFoxMessage(EntityFox.Type.RED));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -52,7 +52,7 @@ public class CommandSpawnTamableFox implements TabExecutor {
|
||||||
case "snow":
|
case "snow":
|
||||||
try {
|
try {
|
||||||
EntityTamableFox spawnedFox = plugin.spawnTamableFox(player.getLocation(), EntityFox.Type.SNOW);
|
EntityTamableFox spawnedFox = plugin.spawnTamableFox(player.getLocation(), EntityFox.Type.SNOW);
|
||||||
spawnedFox.save();
|
spawnedFox.saveNbt();
|
||||||
|
|
||||||
player.sendMessage(Utils.getPrefix() + ChatColor.RESET + LanguageConfig.getSpawnedFoxMessage(EntityFox.Type.SNOW));
|
player.sendMessage(Utils.getPrefix() + ChatColor.RESET + LanguageConfig.getSpawnedFoxMessage(EntityFox.Type.SNOW));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|
|
@ -16,12 +16,12 @@ public class FoxPathfinderGoalPanic extends PathfinderGoalPanic {
|
||||||
|
|
||||||
public boolean a() {
|
public boolean a() {
|
||||||
try {
|
try {
|
||||||
Method eFMethod = EntityFox.class.getDeclaredMethod("eF");
|
Method isDefendingMethod = EntityFox.class.getDeclaredMethod("eF");
|
||||||
eFMethod.setAccessible(true);
|
isDefendingMethod.setAccessible(true);
|
||||||
boolean eF = (boolean) eFMethod.invoke(tamableFox);
|
boolean isDefending = (boolean) isDefendingMethod.invoke(tamableFox);
|
||||||
eFMethod.setAccessible(false);
|
isDefendingMethod.setAccessible(false);
|
||||||
|
|
||||||
return !tamableFox.isTamed() && !eF && super.a();
|
return !tamableFox.isTamed() && !isDefending && super.a();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# Config for Tamable Foxes
|
# Config for Tamable Foxes
|
||||||
show-owner-in-fox-name: true
|
show-owner-in-fox-name: true
|
||||||
show-nametags: true
|
|
||||||
enable-taming-permission: true
|
enable-taming-permission: true
|
||||||
|
ask-for-name-after-taming: false
|
||||||
|
|
||||||
tamed-behavior:
|
tamed-behavior:
|
||||||
attack-wild-animals: true
|
attack-wild-animals: true
|
|
@ -2,17 +2,15 @@ unsupported-mc-version-not-registering: "ERROR: This plugin version only support
|
||||||
unsupported-mc-version-disabling: "This plugin version only supports Spigot 1.15.X! Disabling plugin!"
|
unsupported-mc-version-disabling: "This plugin version only supports Spigot 1.15.X! Disabling plugin!"
|
||||||
success-replaced-entity: "Replaced tamable fox entity!"
|
success-replaced-entity: "Replaced tamable fox entity!"
|
||||||
error-to-replaced-entity: "Failed to replace tamable fox entity!"
|
error-to-replaced-entity: "Failed to replace tamable fox entity!"
|
||||||
|
|
||||||
saving-foxes-message: "Saving foxes."
|
saving-foxes-message: "Saving foxes."
|
||||||
|
|
||||||
taming-tamed-message: "You just tamed a wild fox!"
|
taming-tamed-message: "You just tamed a wild fox!"
|
||||||
taming-asking-for-name-message: "What do you want to call it?"
|
taming-asking-for-name-message: "What do you want to call it?"
|
||||||
taming-chosen-name-perfect: "%NAME% is perfect!"
|
taming-chosen-name-perfect: "%NAME% is perfect!"
|
||||||
|
owner-in-fox-name-format: "%player%'s Fox"
|
||||||
|
|
||||||
no-permission: "You do not have the permission for this command."
|
no-permission: "You do not have the permission for this command."
|
||||||
only-run-by-player: "Command can only be run from player state!"
|
only-run-by-player: "Command can only be run from player state!"
|
||||||
spawned-fox-message: "Spawned a %TYPE% fox."
|
spawned-fox-message: "Spawned a %TYPE% fox."
|
||||||
failed-to-spawn-message: "Failed to spawn fox!"
|
failed-to-spawn-message: "Failed to spawn fox!"
|
||||||
reloaded-message: "Reloaded"
|
reloaded-message: "Reloaded"
|
||||||
|
|
||||||
created-sql-foxes-database: "Created foxes SQLite database!"
|
|
Loading…
Reference in New Issue