Tried to add 1.20.4 support

This commit is contained in:
madi308 2024-03-08 10:20:56 +02:00
parent 6c65256c7f
commit 3fc8db17ce
32 changed files with 1416 additions and 19 deletions

View File

@ -19,7 +19,7 @@
</repository> </repository>
<repository> <repository>
<id>codemc-snapshots</id> <id>codemc-snapshots</id>
<url>https://repo.codemc.io/repository/maven-snapshots/</url> <url>https://repo.codemc.io/repository/nms/</url>
</repository> </repository>
</repositories> </repositories>

View File

@ -19,7 +19,7 @@
</repository> </repository>
<repository> <repository>
<id>codemc-snapshots</id> <id>codemc-snapshots</id>
<url>https://repo.codemc.io/repository/maven-snapshots/</url> <url>https://repo.codemc.io/repository/nms/</url>
</repository> </repository>
</repositories> </repositories>

View File

@ -19,7 +19,7 @@
</repository> </repository>
<repository> <repository>
<id>codemc-snapshots</id> <id>codemc-snapshots</id>
<url>https://repo.codemc.io/repository/maven-snapshots/</url> <url>https://repo.codemc.io/repository/nms/</url>
</repository> </repository>
</repositories> </repositories>

View File

@ -19,7 +19,7 @@
</repository> </repository>
<repository> <repository>
<id>codemc-snapshots</id> <id>codemc-snapshots</id>
<url>https://repo.codemc.io/repository/maven-snapshots/</url> <url>https://repo.codemc.io/repository/nms/</url>
</repository> </repository>
</repositories> </repositories>

View File

@ -19,7 +19,7 @@
</repository> </repository>
<repository> <repository>
<id>codemc-snapshots</id> <id>codemc-snapshots</id>
<url>https://repo.codemc.io/repository/maven-snapshots/</url> <url>https://repo.codemc.io/repository/nms/</url>
</repository> </repository>
</repositories> </repositories>

View File

@ -57,7 +57,7 @@
</repository> </repository>
<repository> <repository>
<id>codemc-snapshots</id> <id>codemc-snapshots</id>
<url>https://repo.codemc.io/repository/maven-snapshots/</url> <url>https://repo.codemc.io/repository/nms/</url>
</repository> </repository>
</repositories> </repositories>

View File

@ -57,7 +57,7 @@
</repository> </repository>
<repository> <repository>
<id>codemc-snapshots</id> <id>codemc-snapshots</id>
<url>https://repo.codemc.io/repository/maven-snapshots/</url> <url>https://repo.codemc.io/repository/nms/</url>
</repository> </repository>
</repositories> </repositories>

View File

@ -57,7 +57,7 @@
</repository> </repository>
<repository> <repository>
<id>codemc-snapshots</id> <id>codemc-snapshots</id>
<url>https://repo.codemc.io/repository/maven-snapshots/</url> <url>https://repo.codemc.io/repository/nms/</url>
</repository> </repository>
</repositories> </repositories>

View File

@ -57,7 +57,7 @@
</repository> </repository>
<repository> <repository>
<id>codemc-snapshots</id> <id>codemc-snapshots</id>
<url>https://repo.codemc.io/repository/maven-snapshots/</url> <url>https://repo.codemc.io/repository/nms/</url>
</repository> </repository>
</repositories> </repositories>

View File

@ -57,7 +57,7 @@
</repository> </repository>
<repository> <repository>
<id>codemc-snapshots</id> <id>codemc-snapshots</id>
<url>https://repo.codemc.io/repository/maven-snapshots/</url> <url>https://repo.codemc.io/repository/nms/</url>
</repository> </repository>
</repositories> </repositories>

View File

@ -57,7 +57,7 @@
</repository> </repository>
<repository> <repository>
<id>codemc-snapshots</id> <id>codemc-snapshots</id>
<url>https://repo.codemc.io/repository/maven-snapshots/</url> <url>https://repo.codemc.io/repository/nms/</url>
</repository> </repository>
</repositories> </repositories>

View File

@ -57,7 +57,7 @@
</repository> </repository>
<repository> <repository>
<id>codemc-snapshots</id> <id>codemc-snapshots</id>
<url>https://repo.codemc.io/repository/maven-snapshots/</url> <url>https://repo.codemc.io/repository/nms/</url>
</repository> </repository>
</repositories> </repositories>

View File

@ -57,7 +57,7 @@
</repository> </repository>
<repository> <repository>
<id>codemc-snapshots</id> <id>codemc-snapshots</id>
<url>https://repo.codemc.io/repository/maven-snapshots/</url> <url>https://repo.codemc.io/repository/nms/</url>
</repository> </repository>
</repositories> </repositories>

View File

@ -57,7 +57,7 @@
</repository> </repository>
<repository> <repository>
<id>codemc-snapshots</id> <id>codemc-snapshots</id>
<url>https://repo.codemc.io/repository/maven-snapshots/</url> <url>https://repo.codemc.io/repository/nms/</url>
</repository> </repository>
</repositories> </repositories>

View File

@ -57,7 +57,7 @@
</repository> </repository>
<repository> <repository>
<id>codemc-snapshots</id> <id>codemc-snapshots</id>
<url>https://repo.codemc.io/repository/maven-snapshots/</url> <url>https://repo.codemc.io/repository/nms/</url>
</repository> </repository>
</repositories> </repositories>

View File

@ -57,7 +57,7 @@
</repository> </repository>
<repository> <repository>
<id>codemc-snapshots</id> <id>codemc-snapshots</id>
<url>https://repo.codemc.io/repository/maven-snapshots/</url> <url>https://repo.codemc.io/repository/nms/</url>
</repository> </repository>
</repositories> </repositories>

84
1_20_R3/pom.xml Normal file
View File

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.seanomik</groupId>
<artifactId>tamablefoxes-parent</artifactId>
<version>2.2.11-SNAPSHOT</version>
</parent>
<build>
<plugins>
<plugin>
<groupId>net.md-5</groupId>
<artifactId>specialsource-maven-plugin</artifactId>
<version>1.2.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>remap</goal>
</goals>
<id>remap-obf</id>
<configuration>
<srgIn>org.spigotmc:minecraft-server:1.20.4-R0.1-SNAPSHOT:txt:maps-mojang</srgIn>
<reverse>true</reverse>
<remappedDependencies>org.spigotmc:spigot:1.20.4-R0.1-SNAPSHOT:jar:remapped-mojang</remappedDependencies>
<remappedArtifactAttached>true</remappedArtifactAttached>
<remappedClassifierName>remapped-obf</remappedClassifierName>
</configuration>
</execution>
<execution>
<phase>package</phase>
<goals>
<goal>remap</goal>
</goals>
<id>remap-spigot</id>
<configuration>
<inputFile>${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar</inputFile>
<srgIn>org.spigotmc:minecraft-server:1.20.4-R0.1-SNAPSHOT:csrg:maps-spigot</srgIn>
<remappedDependencies>org.spigotmc:spigot:1.20.4-R0.1-SNAPSHOT:jar:remapped-obf</remappedDependencies>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<artifactId>tamablefoxes_v1_20_R3</artifactId>
<repositories>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
<repository>
<id>codemc-snapshots</id>
<url>https://repo.codemc.io/repository/nms/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>net.seanomik</groupId>
<artifactId>tamablefoxes-util</artifactId>
<version>${project.parent.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>1.20.4-R0.1-SNAPSHOT</version>
<classifier>remapped-mojang</classifier>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.wesjd</groupId>
<artifactId>anvilgui</artifactId>
<version>1.7.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,624 @@
package net.seanomik.tamablefoxes.versions.version_1_20_R3;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Predicate;
import javax.annotation.Nullable;
import net.minecraft.advancements.CriteriaTriggers;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.AgeableMob;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.TamableAnimal;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.goal.AvoidEntityGoal;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.entity.ai.goal.LeapAtTargetGoal;
import net.minecraft.world.entity.ai.goal.RandomStrollGoal;
import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
import net.minecraft.world.entity.animal.AbstractFish;
import net.minecraft.world.entity.animal.AbstractSchoolingFish;
import net.minecraft.world.entity.animal.Animal;
import net.minecraft.world.entity.animal.Chicken;
import net.minecraft.world.entity.animal.Fox;
import net.minecraft.world.entity.animal.PolarBear;
import net.minecraft.world.entity.animal.Rabbit;
import net.minecraft.world.entity.animal.Turtle;
import net.minecraft.world.entity.animal.Wolf;
import net.minecraft.world.entity.animal.horse.AbstractHorse;
import net.minecraft.world.entity.monster.Creeper;
import net.minecraft.world.entity.monster.Ghast;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.BucketItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.NameTagItem;
import net.minecraft.world.item.SpawnEggItem;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.Level;
import net.minecraft.world.scores.PlayerTeam;
import net.seanomik.tamablefoxes.util.Utils;
import net.seanomik.tamablefoxes.util.io.Config;
import net.seanomik.tamablefoxes.util.io.LanguageConfig;
import net.seanomik.tamablefoxes.util.io.sqlite.SQLiteHelper;
import net.seanomik.tamablefoxes.versions.version_1_20_R3.pathfinding.*;
import net.wesjd.anvilgui.AnvilGUI;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
import org.bukkit.craftbukkit.v1_20_R3.event.CraftEventFactory;
import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack;
import org.bukkit.event.entity.EntityRegainHealthEvent;
public class EntityTamableFox extends Fox {
protected static final EntityDataAccessor<Boolean> tamed;
protected static final EntityDataAccessor<Optional<UUID>> ownerUUID;
//private static final EntityDataAccessor<Byte> bw; // DATA_FLAGS_ID
private static final Predicate<Entity> AVOID_PLAYERS; // AVOID_PLAYERS
static {
tamed = SynchedEntityData.defineId(EntityTamableFox.class, EntityDataSerializers.BOOLEAN);
ownerUUID = SynchedEntityData.defineId(EntityTamableFox.class, EntityDataSerializers.OPTIONAL_UUID);
AVOID_PLAYERS = (entity) -> !entity.isCrouching();// && EntitySelector.test(entity);
}
List<Goal> untamedGoals;
private FoxPathfinderGoalSitWhenOrdered goalSitWhenOrdered;
private FoxPathfinderGoalSleepWhenOrdered goalSleepWhenOrdered;
public EntityTamableFox(EntityType<? extends Fox> entitytype, Level world) {
super(entitytype, world);
this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(0.33000001192092896D); // Set movement speed
if (isTamed()) {
this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(24.0D);
this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(3.0D);
this.setHealth(this.getMaxHealth());
} else {
this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(10.0D);
this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(2.0D);
}
this.setTamed(false);
}
@Override
public void registerGoals() {
try {
this.goalSitWhenOrdered = new FoxPathfinderGoalSitWhenOrdered(this);
this.goalSelector.addGoal(1, goalSitWhenOrdered);
this.goalSleepWhenOrdered = new FoxPathfinderGoalSleepWhenOrdered(this);
this.goalSelector.addGoal(1, goalSleepWhenOrdered);
// For reflection, we must use the non remapped names, since this is done at runtime
// and the user will be using a normal spigot jar.
// Wild animal attacking
Field landTargetGoal = this.getClass().getSuperclass().getDeclaredField("ck"); // landTargetGoal
landTargetGoal.setAccessible(true);
landTargetGoal.set(this, new NearestAttackableTargetGoal(this, Animal.class, 10, false, false, (entityliving) -> {
return (!isTamed() || (Config.doesTamedAttackWildAnimals() && isTamed())) && (entityliving instanceof Chicken || entityliving instanceof Rabbit);
}));
Field turtleEggTargetGoal = this.getClass().getSuperclass().getDeclaredField("cl"); // turtleEggTargetGoal
turtleEggTargetGoal.setAccessible(true);
turtleEggTargetGoal.set(this, new NearestAttackableTargetGoal(this, Turtle.class, 10, false, false, Turtle.BABY_ON_LAND_SELECTOR));
Field fishTargetGoal = this.getClass().getSuperclass().getDeclaredField("cm"); // fishTargetGoal
fishTargetGoal.setAccessible(true);
fishTargetGoal.set(this, new NearestAttackableTargetGoal(this, AbstractFish.class, 20, false, false, (entityliving) -> {
return (!isTamed() || (Config.doesTamedAttackWildAnimals() && isTamed())) && entityliving instanceof AbstractSchoolingFish;
}));
this.goalSelector.addGoal(0, getFoxInnerPathfinderGoal("g")); // FoxFloatGoal
this.goalSelector.addGoal(1, getFoxInnerPathfinderGoal("b")); // FaceplantGoal
this.goalSelector.addGoal(2, new FoxPathfinderGoalPanic(this, 2.2D));
this.goalSelector.addGoal(2, new FoxPathfinderGoalSleepWithOwner(this));
this.goalSelector.addGoal(3, getFoxInnerPathfinderGoal("e", Arrays.asList(1.0D), Arrays.asList(double.class))); // FoxBreedGoal
this.goalSelector.addGoal(4, new AvoidEntityGoal(this, Player.class, 16.0F, 1.6D, 1.4D, (entityliving) -> {
return !isTamed() && AVOID_PLAYERS.test((LivingEntity) entityliving) && !this.isDefending();
}));
this.goalSelector.addGoal(4, new AvoidEntityGoal(this, Wolf.class, 8.0F, 1.6D, 1.4D, (entityliving) -> {
return !((Wolf)entityliving).isTame() && !this.isDefending();
}));
this.goalSelector.addGoal(4, new AvoidEntityGoal(this, PolarBear.class, 8.0F, 1.6D, 1.4D, (entityliving) -> {
return !this.isDefending();
}));
this.goalSelector.addGoal(5, getFoxInnerPathfinderGoal("u")); // StalkPreyGoal
this.goalSelector.addGoal(6, new FoxPounceGoal());
this.goalSelector.addGoal(7, getFoxInnerPathfinderGoal("l", Arrays.asList(1.2000000476837158D, true), Arrays.asList(double.class, boolean.class))); // FoxMeleeAttackGoal
this.goalSelector.addGoal(8, getFoxInnerPathfinderGoal("h", Arrays.asList(this, 1.25D), Arrays.asList(Fox.class, double.class))); // FoxFollowParentGoal
//this.goalSelector.addGoal(8, new FoxPathfinderGoalSleepWithOwner(this));
this.goalSelector.addGoal(9, new FoxPathfinderGoalFollowOwner(this, 1.3D, 10.0F, 2.0F, false));
this.goalSelector.addGoal(10, new LeapAtTargetGoal(this, 0.4F));
this.goalSelector.addGoal(11, new RandomStrollGoal(this, 1.0D));
this.goalSelector.addGoal(11, getFoxInnerPathfinderGoal("p")); // FoxSearchForItemsGoal
this.goalSelector.addGoal(12, getFoxInnerPathfinderGoal("j", Arrays.asList(this, Player.class, 24.0f),
Arrays.asList(Mob.class, Class.class, float.class))); // LookAtPlayer
this.targetSelector.addGoal(1, new FoxPathfinderGoalOwnerHurtByTarget(this));
this.targetSelector.addGoal(2, new FoxPathfinderGoalOwnerHurtTarget(this));
this.targetSelector.addGoal(3, (new FoxPathfinderGoalHurtByTarget(this)).setAlertOthers(new Class[0]));
// Assign all the untamed goals that will later be removed.
untamedGoals = new ArrayList<>();
// SleepGoal
Goal sleep = getFoxInnerPathfinderGoal("t");
this.goalSelector.addGoal(7, sleep);
untamedGoals.add(sleep);
// PerchAndSearchGoal
Goal perchAndSearch = getFoxInnerPathfinderGoal("r");
this.goalSelector.addGoal(13, perchAndSearch);
untamedGoals.add(perchAndSearch);
Goal eatBerries = new FoxEatBerriesGoal(1.2000000476837158D, 12, 2);
this.goalSelector.addGoal(11, eatBerries);
untamedGoals.add(eatBerries); // Maybe this should be configurable too?
// SeekShelterGoal
Goal seekShelter = getFoxInnerPathfinderGoal("s", Arrays.asList(1.25D), Arrays.asList(double.class));
this.goalSelector.addGoal(6, seekShelter);
untamedGoals.add(seekShelter);
// FoxStrollThroughVillageGoal
Goal strollThroughVillage = getFoxInnerPathfinderGoal("q", Arrays.asList(32, 200), Arrays.asList(int.class, int.class));
this.goalSelector.addGoal(9, strollThroughVillage);
untamedGoals.add(strollThroughVillage);
} catch (Exception e) {
e.printStackTrace();
}
}
protected EntityDataAccessor<Byte> getDataFlagsId() throws NoSuchFieldException, IllegalAccessException {
Field dataFlagsField = Fox.class.getDeclaredField("bY"); // DATA_FLAGS_ID
dataFlagsField.setAccessible(true);
EntityDataAccessor<Byte> dataFlagsId = (EntityDataAccessor<Byte>) dataFlagsField.get(null);
dataFlagsField.setAccessible(false);
return dataFlagsId;
}
protected boolean getFlag(int i) {
try {
EntityDataAccessor<Byte> dataFlagsId = getDataFlagsId();
return ((Byte)super.entityData.get(dataFlagsId) & i) != 0;
} catch (IllegalAccessException | NoSuchFieldException e) {
e.printStackTrace();
}
return false;
}
protected void setFlag(int i, boolean flag) {
try {
EntityDataAccessor<Byte> dataFlagsId = getDataFlagsId();
if (flag) {
this.entityData.set(dataFlagsId, (byte)((Byte)this.entityData.get(dataFlagsId) | i));
} else {
this.entityData.set(dataFlagsId, (byte)((Byte)this.entityData.get(dataFlagsId) & ~i));
}
} catch (IllegalAccessException | NoSuchFieldException e) {
e.printStackTrace();
}
}
public boolean isDefending() {
return getFlag(128);
}
public void setDefending(boolean defending) {
setFlag(128, defending);
}
@Override
protected void defineSynchedData() {
super.defineSynchedData();
this.entityData.define(tamed, false);
this.entityData.define(ownerUUID, Optional.empty());
}
@Override
public void addAdditionalSaveData(CompoundTag compound) {
super.addAdditionalSaveData(compound);
if (this.getOwnerUUID() == null) {
compound.putUUID("OwnerUUID", new UUID(0L, 0L));
} else {
compound.putUUID("OwnerUUID", this.getOwnerUUID());
}
compound.putBoolean("Sitting", this.goalSitWhenOrdered.isOrderedToSit());
compound.putBoolean("Sleeping", this.goalSleepWhenOrdered.isOrderedToSleep());
}
@Override
public void readAdditionalSaveData(CompoundTag compound) {
super.readAdditionalSaveData(compound);
UUID ownerUuid = null;
if (compound.contains("OwnerUUID")) {
try {
ownerUuid = compound.getUUID("OwnerUUID");
} catch (IllegalArgumentException e) {
String uuidStr = compound.getString("OwnerUUID");
if (!uuidStr.isEmpty()) {
ownerUuid = UUID.fromString(uuidStr);
} else {
ownerUuid = null;
}
}
}
if (ownerUuid != null && !ownerUuid.equals(new UUID(0, 0))) {
this.setOwnerUUID(ownerUuid);
this.setTamed(true);
} else {
this.setTamed(false);
}
if (this.goalSitWhenOrdered != null) {
this.goalSitWhenOrdered.setOrderedToSit(compound.getBoolean("Sitting"));
}
if (this.goalSleepWhenOrdered != null) {
this.goalSleepWhenOrdered.setOrderedToSleep(compound.getBoolean("Sleeping"));
}
if (!this.isTamed()) {
goalSitWhenOrdered.setOrderedToSit(false);
goalSleepWhenOrdered.setOrderedToSleep(false);
}
}
public boolean isTamed() {
UUID ownerUuid = getOwnerUUID();
return this.entityData.get(tamed) && (ownerUuid != null && !ownerUuid.equals(new UUID(0, 0)));
}
public void setTamed(boolean tamed) {
this.entityData.set(EntityTamableFox.tamed, tamed);
this.reassessTameGoals();
if (tamed) {
this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(24.0D);
this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(3.0D);
} else {
this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(10.0D);
this.getAttribute(Attributes.ATTACK_DAMAGE).setBaseValue(2.0D);
}
this.setHealth(this.getMaxHealth());
}
// Remove untamed goals if its tamed.
private void reassessTameGoals() {
if (!isTamed()) return;
for (Goal untamedGoal : untamedGoals) {
this.goalSelector.removeGoal(untamedGoal);
}
}
public void rename(org.bukkit.entity.Player player) {
new AnvilGUI.Builder()
.onClick((slot, stateSnapshot) -> {
String text = stateSnapshot.getText();
if (slot == AnvilGUI.Slot.OUTPUT && !text.isEmpty()) {
org.bukkit.entity.Entity tamableFox = this.getBukkitEntity();
// This will auto format the name for config settings.
String foxName = LanguageConfig.getFoxNameFormat(text, player.getDisplayName());
tamableFox.setCustomName(foxName);
tamableFox.setCustomNameVisible(true);
if (!LanguageConfig.getTamingChosenPerfect(text).equalsIgnoreCase("disabled")) {
stateSnapshot.getPlayer().sendMessage(Config.getPrefix() + ChatColor.GREEN + LanguageConfig.getTamingChosenPerfect(text));
}
} else if (!LanguageConfig.getTamingChosenPerfect(text).equalsIgnoreCase("disabled")) {
stateSnapshot.getPlayer().sendMessage(Config.getPrefix() + ChatColor.GRAY + "The fox was not named");
}
return Arrays.asList(AnvilGUI.ResponseAction.close());
})
.text("Fox name")
.title("Name your new friend!")
.plugin(Utils.tamableFoxesPlugin)
.open(player);
}
@Override
public InteractionResult mobInteract(Player entityhuman, InteractionHand enumhand) {
ItemStack itemstack = entityhuman.getItemInHand(enumhand);
Item item = itemstack.getItem();
if (itemstack.getItem() instanceof SpawnEggItem) {
return super.mobInteract(entityhuman, enumhand);
} else {
if (this.isTamed()) {
// Heal the fox if its health is below the max.
if (item.isEdible() && item.getFoodProperties().isMeat() && this.getHealth() < this.getMaxHealth()) {
// Only remove the item from the player if they're in survival mode.
org.bukkit.entity.Player player = (org.bukkit.entity.Player) entityhuman.getBukkitEntity();
if (player.getGameMode() != GameMode.CREATIVE ) {
itemstack.shrink(1);
}
this.heal((float)item.getFoodProperties().getNutrition(), EntityRegainHealthEvent.RegainReason.EATING);
return InteractionResult.CONSUME;
}
if (isOwnedBy(entityhuman) && enumhand == InteractionHand.MAIN_HAND) {
// This super method checks if the fox can breed or not.
InteractionResult flag = super.mobInteract(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.isCrouching() && (flag != InteractionResult.SUCCESS || this.isBaby())) {
// Show the rename menu again when trying to use a nametag on the fox.
if (itemstack.getItem() instanceof NameTagItem) {
org.bukkit.entity.Player player = (org.bukkit.entity.Player) entityhuman.getBukkitEntity();
rename(player);
return InteractionResult.PASS;
}
this.goalSleepWhenOrdered.setOrderedToSleep(false);
this.goalSitWhenOrdered.setOrderedToSit(!this.isOrderedToSit());
return InteractionResult.SUCCESS;
} else if (entityhuman.isCrouching()) { // Swap/Put/Take item from fox.
// Ignore buckets since they can be easily duplicated.
if (itemstack.getItem() instanceof BucketItem) {
return InteractionResult.PASS;
}
// If the fox has something in its mouth and the player has something in its hand, empty it.
if (this.hasItemInSlot(EquipmentSlot.MAINHAND)) {
getBukkitEntity().getWorld().dropItem(getBukkitEntity().getLocation(), CraftItemStack.asBukkitCopy(this.getItemBySlot(EquipmentSlot.MAINHAND)));
this.setItemSlot(EquipmentSlot.MAINHAND, new ItemStack(Items.AIR), false);
} // Check if the player's hand is empty and if it is, make the fox sleep.
// The reason its here is to make sure that we don't take the item
// from its mouth and make it sleep in a single click.
else if (!entityhuman.hasItemInSlot(EquipmentSlot.MAINHAND)) {
this.goalSitWhenOrdered.setOrderedToSit(false);
this.goalSleepWhenOrdered.setOrderedToSleep(!this.goalSleepWhenOrdered.isOrderedToSleep());
}
// Run this task async to make sure to not slow the server down.
// This is needed due to the item being removed as soon as its put in the foxes mouth.
Bukkit.getScheduler().runTaskLaterAsynchronously(Utils.tamableFoxesPlugin, ()-> {
// Put item in mouth
if (entityhuman.hasItemInSlot(EquipmentSlot.MAINHAND)) {
ItemStack c = itemstack.copy();
c.setCount(1);
// Only remove the item from the player if they're in survival mode.
org.bukkit.entity.Player player = (org.bukkit.entity.Player) entityhuman.getBukkitEntity();
if (player.getGameMode() != GameMode.CREATIVE ) {
itemstack.shrink(1);
}
this.setItemSlot(EquipmentSlot.MAINHAND, c, false);
}
}, 1L);
return InteractionResult.SUCCESS;
}
}
} else if (item == Items.CHICKEN) {
// Check if the player has permissions to tame the fox
if (Config.canPlayerTameFox((org.bukkit.entity.Player) entityhuman.getBukkitEntity())) {
// Only remove the item from the player if they're in survival mode.
org.bukkit.entity.Player player = (org.bukkit.entity.Player) entityhuman.getBukkitEntity();
if (player.getGameMode() != GameMode.CREATIVE ) {
itemstack.shrink(1);
}
SQLiteHelper sqLiteHelper = SQLiteHelper.getInstance(Utils.tamableFoxesPlugin);
int maxTameCount = Config.getMaxPlayerFoxTames();
if ( !((org.bukkit.entity.Player) entityhuman.getBukkitEntity()).hasPermission("tamablefoxes.tame.unlimited") && maxTameCount > 0 && sqLiteHelper.getPlayerFoxAmount(entityhuman.getUUID()) >= maxTameCount) {
if (!LanguageConfig.getFoxDoesntTrust().equalsIgnoreCase("disabled")) {
((org.bukkit.entity.Player) entityhuman.getBukkitEntity()).sendMessage(Config.getPrefix() + ChatColor.RED + LanguageConfig.getFoxDoesntTrust());
}
return InteractionResult.SUCCESS;
}
// 0.33% chance to tame the fox, also check if the called tame entity event is cancelled or not.
if (this.getRandom().nextInt(3) == 0 && !CraftEventFactory.callEntityTameEvent(this, entityhuman).isCancelled()) {
this.tame(entityhuman);
this.navigation.stop();
this.goalSitWhenOrdered.setOrderedToSit(true);
if (maxTameCount > 0) {
sqLiteHelper.addPlayerFoxAmount(entityhuman.getUUID(), 1);
}
getBukkitEntity().getWorld().spawnParticle(org.bukkit.Particle.HEART, getBukkitEntity().getLocation(), 6, 0.5D, 0.5D, 0.5D);
// Give player tamed message.
if (!LanguageConfig.getTamedMessage().equalsIgnoreCase("disabled")) {
((org.bukkit.entity.Player) entityhuman.getBukkitEntity()).sendMessage(Config.getPrefix() + ChatColor.GREEN + LanguageConfig.getTamedMessage());
}
// Let the player choose the new fox's name if its enabled in config.
if (Config.askForNameAfterTaming()) {
if (!LanguageConfig.getTamingAskingName().equalsIgnoreCase("disabled")) {
player.sendMessage(Config.getPrefix() + ChatColor.RED + LanguageConfig.getTamingAskingName());
}
rename(player);
}
} else {
getBukkitEntity().getWorld().spawnParticle(org.bukkit.Particle.SMOKE_NORMAL, getBukkitEntity().getLocation(), 10, 0.2D, 0.2D, 0.2D, 0.15D);
}
}
return InteractionResult.SUCCESS;
}
return super.mobInteract(entityhuman, enumhand);
}
}
@Override
public EntityTamableFox getBreedOffspring(ServerLevel worldserver, AgeableMob entityageable) {
EntityTamableFox entityfox = (EntityTamableFox) EntityType.FOX.create(worldserver);
entityfox.setVariant(this.getRandom().nextBoolean() ? this.getVariant() : ((Fox)entityageable).getVariant());
UUID uuid = this.getOwnerUUID();
if (uuid != null) {
entityfox.setOwnerUUID(uuid);
entityfox.setTamed(true);
}
return entityfox;
}
@Nullable
public UUID getOwnerUUID() {
return (UUID) ((Optional) this.entityData.get(ownerUUID)).orElse(null);
}
public void setOwnerUUID(@Nullable UUID ownerUuid) {
this.entityData.set(ownerUUID, Optional.ofNullable(ownerUuid));
}
public void tame(Player owner) {
this.setTamed(true);
this.setOwnerUUID(owner.getUUID());
// Give the player the taming advancement.
if (owner instanceof ServerPlayer) {
CriteriaTriggers.TAME_ANIMAL.trigger((ServerPlayer) owner, this);
}
}
@Nullable
public LivingEntity getOwner() {
try {
UUID ownerUuid = this.getOwnerUUID();
return ownerUuid == null ? null : this.getCommandSenderWorld().getPlayerByUUID(ownerUuid);
} catch (IllegalArgumentException var2) {
return null;
}
}
// Only attack entity if its not attacking owner.
@Override
public boolean canAttack(LivingEntity entity) {
return !this.isOwnedBy(entity) && super.canAttack(entity);
}
public boolean isOwnedBy(LivingEntity 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 wantsToAttack(LivingEntity entityliving, LivingEntity entityliving1) {
if (!(entityliving instanceof Creeper) && !(entityliving instanceof Ghast)) {
if (entityliving instanceof EntityTamableFox) {
EntityTamableFox entityFox = (EntityTamableFox) entityliving;
return !entityFox.isTamed() || entityFox.getOwner() != entityliving1;
} else {
return (!(entityliving instanceof Player)
|| !(entityliving1 instanceof Player) ||
((Player) entityliving1).canHarmPlayer((Player) entityliving)) && ((!(entityliving instanceof AbstractHorse)
|| !((AbstractHorse) entityliving).isTamed()) && (!(entityliving instanceof TamableAnimal)
|| !((TamableAnimal) entityliving).isTame()));
}
} else {
return false;
}
}
// Set the scoreboard team to the same as the owner if its tamed.
@Override
public PlayerTeam getTeam() {
if (this.isTamed()) {
LivingEntity var0 = this.getOwner();
if (var0 != null) {
return var0.getTeam();
}
}
return super.getTeam();
}
// Override isAlliedTo (Entity::r(Entity))
@Override
public boolean isAlliedTo(Entity entity) {
if (this.isTamed()) {
LivingEntity entityOwner = this.getOwner();
if (entity == entityOwner) {
return true;
}
if (entityOwner != null) {
return entityOwner.isAlliedTo(entity);
}
}
return super.isAlliedTo(entity);
}
// When the fox dies, show a chat message, and remove the player's stored tamed foxed.
@Override
public void die(DamageSource damageSource) {
if (!this.getCommandSenderWorld().isClientSide && this.getCommandSenderWorld().getGameRules().getBoolean(GameRules.RULE_SHOWDEATHMESSAGES) && this.getOwner() instanceof ServerPlayer) {
//this.getOwner().sendMessage(this.getCombatTracker().getDeathMessage(), getOwnerUUID());
this.getOwner().sendSystemMessage(this.getCombatTracker().getDeathMessage());
}
// Remove the amount of foxes the player has tamed if the limit is enabled.
if (Config.getMaxPlayerFoxTames() > 0 && this.getOwner() != null) {
SQLiteHelper sqliteHelper = SQLiteHelper.getInstance(Utils.tamableFoxesPlugin);
sqliteHelper.removePlayerFoxAmount(this.getOwner().getUUID(), 1);
}
super.die(damageSource);
}
private Goal getFoxInnerPathfinderGoal(String innerName, List<Object> args, List<Class<?>> argTypes) {
return (Goal) Utils.instantiatePrivateInnerClass(Fox.class, innerName, this, args, argTypes);
}
private Goal getFoxInnerPathfinderGoal(String innerName) {
return (Goal) Utils.instantiatePrivateInnerClass(Fox.class, innerName, this, Arrays.asList(), Arrays.asList());
}
public boolean isOrderedToSit() { return this.goalSitWhenOrdered.isOrderedToSit(); }
public void setOrderedToSit(boolean flag) { this.goalSitWhenOrdered.setOrderedToSit(flag); }
public boolean isOrderedToSleep() { return this.goalSleepWhenOrdered.isOrderedToSleep(); }
public void setOrderedToSleep(boolean flag) { this.goalSleepWhenOrdered.setOrderedToSleep(flag); }
}

View File

@ -0,0 +1,53 @@
package net.seanomik.tamablefoxes.versions.version_1_20_R3;
import java.lang.reflect.Field;
import java.util.UUID;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.animal.Fox;
import net.seanomik.tamablefoxes.util.FieldHelper;
import net.seanomik.tamablefoxes.util.NMSInterface;
import net.seanomik.tamablefoxes.util.io.Config;
import net.seanomik.tamablefoxes.util.io.LanguageConfig;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_20_R3.entity.CraftEntity;
import org.bukkit.entity.Player;
public class NMSInterface_1_20_R3 implements NMSInterface {
@Override
public void registerCustomFoxEntity() {
try { // Replace the fox entity
Field field = EntityType.FOX.getClass().getDeclaredField("bz"); // bz = factory
FieldHelper.setFieldUsingUnsafe(field, EntityType.FOX, (EntityType.EntityFactory<Fox>) EntityTamableFox::new);
Bukkit.getServer().getConsoleSender().sendMessage(Config.getPrefix() + ChatColor.GREEN + LanguageConfig.getSuccessReplaced());
} catch (Exception e) {
Bukkit.getServer().getConsoleSender().sendMessage(Config.getPrefix() + ChatColor.RED + LanguageConfig.getFailureReplace());
e.printStackTrace();
}
}
@Override
public void spawnTamableFox(Location loc, FoxType type) {
EntityTamableFox tamableFox = (EntityTamableFox) ((CraftEntity) loc.getWorld().spawnEntity(loc, org.bukkit.entity.EntityType.FOX)).getHandle();
tamableFox.setVariant((type == FoxType.RED) ? Fox.Type.RED : Fox.Type.SNOW);
}
@Override
public void changeFoxOwner(org.bukkit.entity.Fox fox, Player newOwner) {
EntityTamableFox tamableFox = (EntityTamableFox) ((CraftEntity) fox).getHandle();
tamableFox.setOwnerUUID(newOwner.getUniqueId());
}
@Override
public UUID getFoxOwner(org.bukkit.entity.Fox fox) {
EntityTamableFox tamableFox = (EntityTamableFox) ((CraftEntity) fox).getHandle();
return tamableFox.getOwnerUUID();
}
@Override
public void renameFox(org.bukkit.entity.Fox fox, Player player) {
EntityTamableFox tamableFox = (EntityTamableFox) ((CraftEntity) fox).getHandle();
tamableFox.rename(player);
}
}

View File

@ -0,0 +1,151 @@
package net.seanomik.tamablefoxes.versions.version_1_20_R3.pathfinding;
import java.util.EnumSet;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.entity.ai.navigation.FlyingPathNavigation;
import net.minecraft.world.entity.ai.navigation.GroundPathNavigation;
import net.minecraft.world.entity.ai.navigation.PathNavigation;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.LeavesBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.pathfinder.BlockPathTypes;
import net.minecraft.world.level.pathfinder.WalkNodeEvaluator;
import net.seanomik.tamablefoxes.versions.version_1_20_R3.EntityTamableFox;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_20_R3.entity.CraftEntity;
import org.bukkit.event.entity.EntityTeleportEvent;
public class FoxPathfinderGoalFollowOwner extends Goal {
public static final int TELEPORT_WHEN_DISTANCE_IS = 12;
private static final int MIN_HORIZONTAL_DISTANCE_FROM_PLAYER_WHEN_TELEPORTING = 2;
private static final int MAX_HORIZONTAL_DISTANCE_FROM_PLAYER_WHEN_TELEPORTING = 3;
private static final int MAX_VERTICAL_DISTANCE_FROM_PLAYER_WHEN_TELEPORTING = 1;
private final EntityTamableFox tamableFox;
private LivingEntity owner;
private final LevelReader level;
private final double speedModifier;
private final PathNavigation navigation;
private int timeToRecalcPath;
private final float stopDistance;
private final float startDistance;
private float oldWaterCost;
private final boolean canFly;
public FoxPathfinderGoalFollowOwner(EntityTamableFox entityfox, double d0, float f, float f1, boolean flag) {
this.tamableFox = entityfox;
this.level = entityfox.level();
this.speedModifier = d0;
this.navigation = entityfox.getNavigation();
this.startDistance = f;
this.stopDistance = f1;
this.canFly = flag;
this.setFlags(EnumSet.of(Flag.MOVE, Flag.LOOK));
if (!(entityfox.getNavigation() instanceof GroundPathNavigation) && !(entityfox.getNavigation() instanceof FlyingPathNavigation)) {
throw new IllegalArgumentException("Unsupported mob type for FoxPathfinderGoalFollowOwner");
}
}
public boolean canUse() {
LivingEntity entityliving = this.tamableFox.getOwner();
if (entityliving == null) {
return false;
} else if (entityliving.isSpectator()) {
return false;
} else if (this.tamableFox.isOrderedToSit() || this.tamableFox.isOrderedToSleep()) {
return false;
} else if (this.tamableFox.distanceToSqr(entityliving) < (double)(this.startDistance * this.startDistance)) {
return false;
} else {
this.owner = entityliving;
return true;
}
}
public boolean canContinueToUse() {
return !this.navigation.isDone() && (!this.tamableFox.isOrderedToSit() && !this.tamableFox.isOrderedToSleep() && this.tamableFox.distanceToSqr(this.owner) > (double) (this.stopDistance * this.stopDistance));
}
public void start() {
this.timeToRecalcPath = 0;
this.oldWaterCost = this.tamableFox.getPathfindingMalus(BlockPathTypes.WATER);
this.tamableFox.setPathfindingMalus(BlockPathTypes.WATER, 0.0F);
}
public void stop() {
this.owner = null;
this.navigation.stop();
this.tamableFox.setPathfindingMalus(BlockPathTypes.WATER, this.oldWaterCost);
}
public void tick() {
this.tamableFox.getLookControl().setLookAt(this.owner, 10.0F, (float)this.tamableFox.getMaxHeadXRot());
if (--this.timeToRecalcPath <= 0) {
this.timeToRecalcPath = 10;
if (!this.tamableFox.isLeashed() && !this.tamableFox.isPassenger()) {
if (this.tamableFox.distanceToSqr(this.owner) >= 144.0D) {
this.teleportToOwner();
} else {
this.navigation.moveTo(this.owner, this.speedModifier);
}
}
}
}
private void teleportToOwner() {
BlockPos blockposition = this.owner.blockPosition();
for(int i = 0; i < 10; ++i) {
int j = this.randomIntInclusive(-3, 3);
int k = this.randomIntInclusive(-1, 1);
int l = this.randomIntInclusive(-3, 3);
boolean flag = this.maybeTeleportTo(blockposition.getX() + j, blockposition.getY() + k, blockposition.getZ() + l);
if (flag) {
return;
}
}
}
private boolean maybeTeleportTo(int i, int j, int k) {
if (Math.abs((double)i - this.owner.getX()) < 2.0D && Math.abs((double)k - this.owner.getZ()) < 2.0D) {
return false;
} else if (!this.canTeleportTo(new BlockPos(i, j, k))) {
return false;
} else {
CraftEntity entity = this.tamableFox.getBukkitEntity();
Location to = new Location(entity.getWorld(), (double)i + 0.5D, (double)j, (double)k + 0.5D, this.tamableFox.getYRot(), this.tamableFox.getXRot());
EntityTeleportEvent event = new EntityTeleportEvent(entity, entity.getLocation(), to);
this.tamableFox.level().getCraftServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return false;
} else {
to = event.getTo();
this.tamableFox.moveTo(to.getX(), to.getY(), to.getZ(), to.getYaw(), to.getPitch());
this.navigation.stop();
return true;
}
}
}
private boolean canTeleportTo(BlockPos blockposition) {
BlockPathTypes pathtype = WalkNodeEvaluator.getBlockPathTypeStatic(this.level, blockposition.mutable());
if (pathtype != BlockPathTypes.WALKABLE) {
return false;
} else {
BlockState iblockdata = this.level.getBlockState(blockposition.below());
if (!this.canFly && iblockdata.getBlock() instanceof LeavesBlock) {
return false;
} else {
BlockPos blockposition1 = blockposition.subtract(this.tamableFox.blockPosition());
return this.level.noCollision(this.tamableFox, this.tamableFox.getBoundingBox().move(blockposition1));
}
}
}
private int randomIntInclusive(int i, int j) {
return this.tamableFox.getRandom().nextInt(j - i + 1) + i;
}
}

View File

@ -0,0 +1,122 @@
package net.seanomik.tamablefoxes.versions.version_1_20_R3.pathfinding;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
import net.minecraft.world.entity.EntitySelector;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.PathfinderMob;
import net.minecraft.world.entity.ai.goal.target.TargetGoal;
import net.minecraft.world.entity.ai.targeting.TargetingConditions;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.phys.AABB;
import net.seanomik.tamablefoxes.versions.version_1_20_R3.EntityTamableFox;
import org.bukkit.event.entity.EntityTargetEvent.TargetReason;
public class FoxPathfinderGoalHurtByTarget extends TargetGoal {
private static final TargetingConditions HURT_BY_TARGETING = TargetingConditions.forCombat().ignoreLineOfSight().ignoreInvisibilityTesting();
private static final int ALERT_RANGE_Y = 10;
private boolean alertSameType;
private int timestamp;
private final Class<?>[] toIgnoreDamage;
private Class<?>[] toIgnoreAlert;
public FoxPathfinderGoalHurtByTarget(PathfinderMob entitycreature, Class<?>... aclass) {
super(entitycreature, true);
this.toIgnoreDamage = aclass;
this.setFlags(EnumSet.of(Flag.TARGET));
}
public boolean canUse() {
int i = this.mob.getLastHurtByMobTimestamp();
LivingEntity entityliving = this.mob.getLastHurtByMob();
if (i != this.timestamp && entityliving != null) {
if (entityliving.getType() == EntityType.PLAYER && this.mob.level().getGameRules().getBoolean(GameRules.RULE_UNIVERSAL_ANGER)) {
return false;
} else {
Class[] aclass = this.toIgnoreDamage;
int j = aclass.length;
for(int k = 0; k < j; ++k) {
Class<?> oclass = aclass[k];
if (oclass.isAssignableFrom(entityliving.getClass())) {
return false;
}
}
return this.canAttack(entityliving, HURT_BY_TARGETING);
}
} else {
return false;
}
}
public FoxPathfinderGoalHurtByTarget setAlertOthers(Class<?>... aclass) {
this.alertSameType = true;
this.toIgnoreAlert = aclass;
return this;
}
public void start() {
this.mob.setTarget(this.mob.getLastHurtByMob(), TargetReason.TARGET_ATTACKED_ENTITY, true);
this.targetMob = this.mob.getTarget();
this.timestamp = this.mob.getLastHurtByMobTimestamp();
this.unseenMemoryTicks = 300;
if (this.alertSameType) {
this.alertOthers();
}
super.start();
}
protected void alertOthers() {
double d0 = this.getFollowDistance();
AABB axisalignedbb = AABB.unitCubeFromLowerCorner(this.mob.position()).inflate(d0, 10.0D, d0);
List<? extends Mob> list = this.mob.level().getEntitiesOfClass(this.mob.getClass(), axisalignedbb, EntitySelector.NO_SPECTATORS);
Iterator iterator = list.iterator();
while(true) {
Mob entityinsentient;
boolean flag;
do {
do {
do {
do {
do {
if (!iterator.hasNext()) {
return;
}
entityinsentient = (Mob)iterator.next();
} while(this.mob == entityinsentient);
} while(entityinsentient.getTarget() != null);
} while(this.mob instanceof EntityTamableFox && ((EntityTamableFox)this.mob).getOwner() != ((EntityTamableFox)entityinsentient).getOwner());
} while(entityinsentient.isAlliedTo(this.mob.getLastHurtByMob()));
if (this.toIgnoreAlert == null) {
break;
}
flag = false;
Class[] aclass = this.toIgnoreAlert;
int i = aclass.length;
for(int j = 0; j < i; ++j) {
Class<?> oclass = aclass[j];
if (entityinsentient.getClass() == oclass) {
flag = true;
break;
}
}
} while(flag);
this.alertOther(entityinsentient, this.mob.getLastHurtByMob());
}
}
protected void alertOther(Mob entityinsentient, LivingEntity entityliving) {
entityinsentient.setTarget(entityliving, TargetReason.TARGET_ATTACKED_NEARBY_ENTITY, true);
}
}

View File

@ -0,0 +1,54 @@
package net.seanomik.tamablefoxes.versions.version_1_20_R3.pathfinding;
import java.util.EnumSet;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.goal.target.TargetGoal;
import net.minecraft.world.entity.ai.targeting.TargetingConditions;
import net.seanomik.tamablefoxes.versions.version_1_20_R3.EntityTamableFox;
import org.bukkit.event.entity.EntityTargetEvent.TargetReason;
public class FoxPathfinderGoalOwnerHurtByTarget extends TargetGoal {
private final EntityTamableFox tameAnimal;
private LivingEntity ownerLastHurtBy;
private int timestamp;
public FoxPathfinderGoalOwnerHurtByTarget(EntityTamableFox entitytameableanimal) {
super(entitytameableanimal, false);
this.tameAnimal = entitytameableanimal;
this.setFlags(EnumSet.of(Flag.TARGET));
}
public boolean canUse() {
if (this.tameAnimal.isTamed() && !this.tameAnimal.isOrderedToSit() && !this.tameAnimal.isOrderedToSleep()) {
LivingEntity entityliving = this.tameAnimal.getOwner();
if (entityliving == null) {
return false;
} else {
this.ownerLastHurtBy = entityliving.getLastHurtByMob();
int i = entityliving.getLastHurtByMobTimestamp();
return i != this.timestamp && this.canAttack(this.ownerLastHurtBy, TargetingConditions.DEFAULT) && this.tameAnimal.wantsToAttack(this.ownerLastHurtBy, entityliving);
}
} else {
return false;
}
}
public void start() {
this.mob.setTarget(this.ownerLastHurtBy, TargetReason.TARGET_ATTACKED_OWNER, true);
LivingEntity entityliving = this.tameAnimal.getOwner();
if (entityliving != null) {
this.timestamp = entityliving.getLastHurtByMobTimestamp();
}
tameAnimal.setDefending(false);
super.start();
}
@Override
public void stop() {
tameAnimal.setDefending(false);
super.stop();
}
}

View File

@ -0,0 +1,55 @@
package net.seanomik.tamablefoxes.versions.version_1_20_R3.pathfinding;
import java.util.EnumSet;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.goal.target.TargetGoal;
import net.minecraft.world.entity.ai.targeting.TargetingConditions;
import net.seanomik.tamablefoxes.versions.version_1_20_R3.EntityTamableFox;
import org.bukkit.event.entity.EntityTargetEvent.TargetReason;
public class FoxPathfinderGoalOwnerHurtTarget extends TargetGoal {
private final EntityTamableFox tameAnimal;
private LivingEntity ownerLastHurt;
private int timestamp;
public FoxPathfinderGoalOwnerHurtTarget(EntityTamableFox entitytameableanimal) {
super(entitytameableanimal, false);
this.tameAnimal = entitytameableanimal;
this.setFlags(EnumSet.of(Flag.TARGET));
}
public boolean canUse() {
if (this.tameAnimal.isTamed() && !this.tameAnimal.isOrderedToSit() && !this.tameAnimal.isOrderedToSleep()) {
LivingEntity entityliving = this.tameAnimal.getOwner();
if (entityliving == null) {
return false;
} else {
this.ownerLastHurt = entityliving.getLastHurtMob();
int i = entityliving.getLastHurtMobTimestamp();
return i != this.timestamp && this.canAttack(this.ownerLastHurt, TargetingConditions.DEFAULT) && this.tameAnimal.wantsToAttack(this.ownerLastHurt, entityliving);
}
} else {
return false;
}
}
public void start() {
this.mob.setTarget(this.ownerLastHurt, TargetReason.OWNER_ATTACKED_TARGET, true);
LivingEntity entityliving = this.tameAnimal.getOwner();
if (entityliving != null) {
this.timestamp = entityliving.getLastHurtMobTimestamp();
}
tameAnimal.setDefending(true);
super.start();
}
@Override
public void stop() {
tameAnimal.setDefending(false);
super.stop();
}
}

View File

@ -0,0 +1,21 @@
package net.seanomik.tamablefoxes.versions.version_1_20_R3.pathfinding;
import net.minecraft.world.entity.ai.goal.PanicGoal;
import net.seanomik.tamablefoxes.versions.version_1_20_R3.EntityTamableFox;
public class FoxPathfinderGoalPanic extends PanicGoal {
EntityTamableFox tamableFox;
public FoxPathfinderGoalPanic(EntityTamableFox tamableFox, double d0) {
super(tamableFox, d0);
this.tamableFox = tamableFox;
}
public boolean canUse() {
if (tamableFox.isTamed()) {
return tamableFox.getHealth() < 2.0f && super.canUse();
}
return tamableFox.isDefending() && super.canUse();
}
}

View File

@ -0,0 +1,55 @@
package net.seanomik.tamablefoxes.versions.version_1_20_R3.pathfinding;
import java.util.EnumSet;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.goal.Goal;
import net.seanomik.tamablefoxes.util.Utils;
import net.seanomik.tamablefoxes.versions.version_1_20_R3.EntityTamableFox;
import org.bukkit.Bukkit;
public class FoxPathfinderGoalSitWhenOrdered extends Goal {
private final EntityTamableFox mob;
private boolean orderedToSit;
public FoxPathfinderGoalSitWhenOrdered(EntityTamableFox entitytameableanimal) {
this.mob = entitytameableanimal;
this.setFlags(EnumSet.of(Flag.JUMP, Flag.MOVE));
}
public boolean canContinueToUse() {
return this.orderedToSit;
}
public boolean canUse() {
if (!this.mob.isTamed()) {
return this.orderedToSit && this.mob.getTarget() == null;
} else if (this.mob.isInWaterOrBubble()) {
return false;
} else if (this.mob.isFallFlying()) {
return false;
} else {
LivingEntity entityliving = this.mob.getOwner();
return entityliving == null || ((!(this.mob.distanceToSqr(entityliving) < 144.0D) || entityliving.getLastHurtByMob() == null) && this.mob.isOrderedToSit());
}
}
public void start() {
// For some reason it needs to be ran later to not have the fox slide across the floor.
Bukkit.getScheduler().runTaskLater(Utils.tamableFoxesPlugin, () -> {
this.mob.getNavigation().stop();
this.mob.setSitting(true);
this.orderedToSit = true;
}, 1L);
}
public void stop() {
this.mob.setSitting(false);
this.orderedToSit = false;
}
public boolean isOrderedToSit() { return this.orderedToSit; }
public void setOrderedToSit(boolean flag) {
this.orderedToSit = flag;
}
}

View File

@ -0,0 +1,50 @@
package net.seanomik.tamablefoxes.versions.version_1_20_R3.pathfinding;
import java.util.EnumSet;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.goal.Goal;
import net.seanomik.tamablefoxes.versions.version_1_20_R3.EntityTamableFox;
public class FoxPathfinderGoalSleepWhenOrdered extends Goal {
private final EntityTamableFox mob;
private boolean orderedToSleep;
public FoxPathfinderGoalSleepWhenOrdered(EntityTamableFox entitytameableanimal) {
this.mob = entitytameableanimal;
this.setFlags(EnumSet.of(Flag.JUMP, Flag.MOVE));
}
public boolean canContinueToUse() {
return this.orderedToSleep;
}
public boolean canUse() {
if (!this.mob.isTamed()) {
return this.orderedToSleep && this.mob.getTarget() == null;
} else if (this.mob.isInWaterOrBubble()) {
return false;
} else if (this.mob.isFallFlying()) {
return false;
} else {
LivingEntity entityliving = this.mob.getOwner();
return entityliving == null || ((!(this.mob.distanceToSqr(entityliving) < 144.0D) || entityliving.getLastHurtByMob() == null) && this.mob.isOrderedToSleep());
}
}
public void start() {
this.mob.getNavigation().stop();
this.mob.setSleeping(true);
this.orderedToSleep = true;
}
public void stop() {
this.mob.setSleeping(false);
this.orderedToSleep = false;
}
public boolean isOrderedToSleep() { return this.orderedToSleep; }
public void setOrderedToSleep(boolean flag) {
this.orderedToSleep = flag;
}
}

View File

@ -0,0 +1,111 @@
package net.seanomik.tamablefoxes.versions.version_1_20_R3.pathfinding;
import java.util.Iterator;
import java.util.List;
import net.minecraft.core.BlockPos;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.block.BedBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
import net.seanomik.tamablefoxes.versions.version_1_20_R3.EntityTamableFox;
// From class EntityCat#b
public class FoxPathfinderGoalSleepWithOwner extends Goal {
private final EntityTamableFox fox;
private Player ownerPlayer;
private BlockPos goalPos;
private int onBedTicks;
public FoxPathfinderGoalSleepWithOwner(EntityTamableFox entityTamableFox) {
this.fox = entityTamableFox;
}
public boolean canUse() {
if (!this.fox.isTamed()) {
return false;
} else if (this.fox.isOrderedToSleep()) {
return false;
} else {
LivingEntity entityliving = this.fox.getOwner();
if (entityliving instanceof Player) {
this.ownerPlayer = (Player)entityliving;
if (!entityliving.isSleeping()) {
return false;
}
if (this.fox.distanceToSqr(this.ownerPlayer) > 100.0D) {
return false;
}
BlockPos blockposition = this.ownerPlayer.blockPosition();
BlockState iblockdata = this.fox.level().getBlockState(blockposition);
if (iblockdata.is(BlockTags.BEDS)) {
this.goalPos = (BlockPos)iblockdata.getOptionalValue(BedBlock.FACING).map((enumdirection) -> {
return blockposition.relative(enumdirection.getOpposite());
}).orElseGet(() -> {
return new BlockPos(blockposition);
});
return !this.spaceIsOccupied();
}
}
return false;
}
}
private boolean spaceIsOccupied() {
List<EntityTamableFox> list = this.fox.level().getEntitiesOfClass(EntityTamableFox.class, (new AABB(this.goalPos)).inflate(2.0D));
Iterator iterator = list.iterator();
EntityTamableFox entityTamableFox;
do {
do {
if (!iterator.hasNext()) {
return false;
}
entityTamableFox = (EntityTamableFox)iterator.next();
} while(entityTamableFox == this.fox);
} while(!entityTamableFox.isSleeping());// && !entityTamableFox.isRelaxStateOne());
return true;
}
public boolean canContinueToUse() {
return this.fox.isTamed() && !this.fox.isOrderedToSleep() && this.ownerPlayer != null && this.ownerPlayer.isSleeping() && this.goalPos != null && !this.spaceIsOccupied();
}
public void start() {
if (this.goalPos != null) {
this.fox.setSitting(false);
this.fox.getNavigation().moveTo((double)this.goalPos.getX(), (double)this.goalPos.getY(), (double)this.goalPos.getZ(), 1.100000023841858D);
}
}
public void stop() {
this.fox.setSleeping(false);
this.onBedTicks = 0;
this.fox.getNavigation().stop();
}
public void tick() {
if (this.ownerPlayer != null && this.goalPos != null) {
this.fox.setSitting(false);
this.fox.getNavigation().moveTo((double)this.goalPos.getX(), (double)this.goalPos.getY(), (double)this.goalPos.getZ(), 1.100000023841858D);
if (this.fox.distanceToSqr(this.ownerPlayer) < 2.5D) {
++this.onBedTicks;
if (this.onBedTicks > 16) {
this.fox.setSleeping(true);
} else {
this.fox.lookAt(this.ownerPlayer, 45.0F, 45.0F);
}
} else {
this.fox.setSleeping(false);
}
}
}
}

View File

@ -93,7 +93,7 @@
</repository> </repository>
<repository> <repository>
<id>codemc-snapshots</id> <id>codemc-snapshots</id>
<url>https://repo.codemc.io/repository/maven-snapshots/</url> <url>https://repo.codemc.io/repository/nms/</url>
</repository> </repository>
</repositories> </repositories>
@ -195,6 +195,12 @@
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency>
<groupId>net.seanomik</groupId>
<artifactId>tamablefoxes_v1_20_R3</artifactId>
<version>${project.parent.version}</version>
<scope>compile</scope>
</dependency>
<!-- End of entity implementations --> <!-- End of entity implementations -->
<dependency> <dependency>
<groupId>org.bstats</groupId> <groupId>org.bstats</groupId>

View File

@ -22,6 +22,7 @@ import net.seanomik.tamablefoxes.versions.version_1_19_2_R1.NMSInterface_1_19_2_
import net.seanomik.tamablefoxes.versions.version_1_19_3_R1.NMSInterface_1_19_3_R1; import net.seanomik.tamablefoxes.versions.version_1_19_3_R1.NMSInterface_1_19_3_R1;
import net.seanomik.tamablefoxes.versions.version_1_19_R3.NMSInterface_1_19_4_R1; import net.seanomik.tamablefoxes.versions.version_1_19_R3.NMSInterface_1_19_4_R1;
import net.seanomik.tamablefoxes.versions.version_1_20_R1.NMSInterface_1_20_R1; import net.seanomik.tamablefoxes.versions.version_1_20_R1.NMSInterface_1_20_R1;
import net.seanomik.tamablefoxes.versions.version_1_20_R3.NMSInterface_1_20_R3;
import org.bstats.bukkit.Metrics; import org.bstats.bukkit.Metrics;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
@ -90,7 +91,10 @@ public final class TamableFoxes extends JavaPlugin implements Listener {
nmsInterface = new NMSInterface_1_19_4_R1(); nmsInterface = new NMSInterface_1_19_4_R1();
} else if (versionDouble == 20D || versionDouble == 20.1D) { } else if (versionDouble == 20D || versionDouble == 20.1D) {
nmsInterface = new NMSInterface_1_20_R1(); nmsInterface = new NMSInterface_1_20_R1();
} else { } else if (versionDouble == 20.3D || versionDouble == 20.4D) {
nmsInterface = new NMSInterface_1_20_R3();
} else {
Bukkit.getServer().getConsoleSender().sendMessage(Config.getPrefix() + ChatColor.RED + LanguageConfig.getUnsupportedMCVersionRegister()); Bukkit.getServer().getConsoleSender().sendMessage(Config.getPrefix() + ChatColor.RED + LanguageConfig.getUnsupportedMCVersionRegister());
Bukkit.getServer().getConsoleSender().sendMessage(Config.getPrefix() + ChatColor.RED + "You're trying to run MC version " + specificVersion + " which is not supported!"); Bukkit.getServer().getConsoleSender().sendMessage(Config.getPrefix() + ChatColor.RED + "You're trying to run MC version " + specificVersion + " which is not supported!");
Bukkit.getServer().getConsoleSender().sendMessage(Config.getPrefix() + "Disabling plugin..."); Bukkit.getServer().getConsoleSender().sendMessage(Config.getPrefix() + "Disabling plugin...");

View File

@ -1,5 +1,6 @@
package net.seanomik.tamablefoxes.util; package net.seanomik.tamablefoxes.util;
import org.bukkit.Bukkit;
import sun.misc.Unsafe; import sun.misc.Unsafe;
import java.lang.reflect.Field; import java.lang.reflect.Field;
@ -11,14 +12,18 @@ public final class FieldHelper {
public static void setFieldUsingUnsafe(final Field field, final Object object, final Object newValue) { public static void setFieldUsingUnsafe(final Field field, final Object object, final Object newValue) {
try { try {
field.setAccessible(true); field.setAccessible(true);
System.out.println("field on accessible");
int fieldModifiersMask = field.getModifiers(); int fieldModifiersMask = field.getModifiers();
boolean isFinalModifierPresent = (fieldModifiersMask & Modifier.FINAL) == Modifier.FINAL; boolean isFinalModifierPresent = (fieldModifiersMask & Modifier.FINAL) == Modifier.FINAL;
if (isFinalModifierPresent) { if (isFinalModifierPresent) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> { AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
try { try {
sun.misc.Unsafe unsafe = getUnsafe(); sun.misc.Unsafe unsafe = getUnsafe();
System.out.println("unsafe on käes");
long offset = unsafe.objectFieldOffset(field); long offset = unsafe.objectFieldOffset(field);
System.out.println("offset mida iganes");
setFieldUsingUnsafe(object, field.getType(), offset, newValue, unsafe); setFieldUsingUnsafe(object, field.getType(), offset, newValue, unsafe);
System.out.println("see teine setfieldusingunsafe sai hakkama");
return null; return null;
} catch (Throwable t) { } catch (Throwable t) {
throw new RuntimeException(t); throw new RuntimeException(t);

View File

@ -19,4 +19,5 @@ java -jar ./BuildTools.jar --rev 1.19.2 --remapped --compile-if-changed
java -jar ./BuildTools.jar --rev 1.19.3 --remapped --compile-if-changed java -jar ./BuildTools.jar --rev 1.19.3 --remapped --compile-if-changed
java -jar ./BuildTools.jar --rev 1.19.4 --remapped --compile-if-changed java -jar ./BuildTools.jar --rev 1.19.4 --remapped --compile-if-changed
java -jar ./BuildTools.jar --rev 1.20 --remapped --compile-if-changed java -jar ./BuildTools.jar --rev 1.20 --remapped --compile-if-changed
java -jar ./BuildTools.jar --rev 1.21 --remapped --compile-if-changed java -jar ./BuildTools.jar --rev 1.21 --remapped --compile-if-changed
java -jar ./BuildTools.jar --rev 1.20.4 --remapped --compile-if-changed

View File

@ -13,6 +13,7 @@
<module>Plugin</module> <module>Plugin</module>
<module>Utility</module> <module>Utility</module>
<module>1_20_R3</module>
<module>1_20_R1</module> <module>1_20_R1</module>
<module>1_19_R3</module> <module>1_19_R3</module>