diff --git a/src/main/java/me/m1chelle99/foxiemc/entity/foxie/FoxieConstants.java b/src/main/java/me/m1chelle99/foxiemc/entity/foxie/FoxieConstants.java index 915f2cd..858e08b 100644 --- a/src/main/java/me/m1chelle99/foxiemc/entity/foxie/FoxieConstants.java +++ b/src/main/java/me/m1chelle99/foxiemc/entity/foxie/FoxieConstants.java @@ -28,4 +28,6 @@ public final class FoxieConstants { // Behavior towards players public static final int STALK_PLAYER_DISTANCE = 25; public static final int AVOID_PLAYER_DISTANCE = 13; + public static final int MAX_DIST_TO_OWNER = 8; + public static final int PREFERRED_DIST_TO_OWNER = 3; } diff --git a/src/main/java/me/m1chelle99/foxiemc/entity/foxie/controls/FoxieAIControl.java b/src/main/java/me/m1chelle99/foxiemc/entity/foxie/controls/FoxieAIControl.java index 7a9a5e5..df8fe2f 100644 --- a/src/main/java/me/m1chelle99/foxiemc/entity/foxie/controls/FoxieAIControl.java +++ b/src/main/java/me/m1chelle99/foxiemc/entity/foxie/controls/FoxieAIControl.java @@ -42,6 +42,7 @@ public static void register(Foxie foxie) { foxie.goalSelector.addGoal(2, new FoxieAvoidWaterGoal(foxie)); foxie.goalSelector.addGoal(2, new FoxieAvoidCustomFluidsGoal(foxie)); + foxie.goalSelector.addGoal(3, new FoxieFollowOwnerGoal(foxie)); foxie.goalSelector.addGoal(3, new FoxieAvoidPlayerGoal(foxie)); foxie.goalSelector.addGoal(3, new FoxieLookAtPlayerGoal(foxie)); @@ -268,4 +269,14 @@ public boolean canStray() { if (activity == FoxieActivities.SeekRainShelter) return false; return activity != FoxieActivities.SearchForFood; } + + public boolean canFollowPlayer() { + var activity = this._foxie.dataControl.getActivity(); + if (activity == FoxieActivities.Panic) return false; + if (activity == FoxieActivities.Obey) return false; + if (activity == FoxieActivities.Sleep) return false; + if (activity == FoxieActivities.AvoidLava) return false; + if (activity == FoxieActivities.Attack) return false; + return activity != FoxieActivities.SeekRainShelter; + } } diff --git a/src/main/java/me/m1chelle99/foxiemc/entity/foxie/goals/FoxieFollowOwnerGoal.java b/src/main/java/me/m1chelle99/foxiemc/entity/foxie/goals/FoxieFollowOwnerGoal.java new file mode 100644 index 0000000..6ba57b1 --- /dev/null +++ b/src/main/java/me/m1chelle99/foxiemc/entity/foxie/goals/FoxieFollowOwnerGoal.java @@ -0,0 +1,135 @@ +package me.m1chelle99.foxiemc.entity.foxie.goals; + +import me.m1chelle99.foxiemc.entity.foxie.Foxie; +import me.m1chelle99.foxiemc.entity.foxie.FoxieConstants; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.goal.Goal; +import net.minecraft.world.level.block.LeavesBlock; +import net.minecraft.world.level.pathfinder.BlockPathTypes; +import net.minecraft.world.level.pathfinder.WalkNodeEvaluator; + +public final class FoxieFollowOwnerGoal extends Goal { + + private final Foxie _foxie; + private LivingEntity owner; + private float waterMalus; + private int recalculationIn; + + public FoxieFollowOwnerGoal(Foxie foxie) { + this._foxie = foxie; + } + + @Override + public boolean canUse() { + if (!this._foxie.aiControl.canFollowPlayer()) return false; + this.getOwner(); + if (this.owner == null) return false; + var maxDistance = FoxieConstants.MAX_DIST_TO_OWNER; + return this.owner.distanceTo(this._foxie) >= maxDistance; + } + + @Override + public boolean canContinueToUse() { + if (!this._foxie.aiControl.canFollowPlayer()) return false; + this.getOwner(); + if (this.owner == null) return false; + var maxDistance = FoxieConstants.MAX_DIST_TO_OWNER; + return this.owner.distanceTo(this._foxie) >= maxDistance; + } + + public void start() { + this.recalculationIn = 0; + this.waterMalus = this._foxie.getPathfindingMalus(BlockPathTypes.WATER); + this._foxie.setPathfindingMalus(BlockPathTypes.WATER, 0.0F); + } + + @Override + public void stop() { + this.owner = null; + this._foxie.getNavigation().stop(); + this._foxie.setPathfindingMalus(BlockPathTypes.WATER, this.waterMalus); + } + + public void tick() { + var maxRotation = (float)this._foxie.getMaxHeadXRot(); + this._foxie.getLookControl().setLookAt(this.owner, 10.0F, maxRotation); + + if (--this.recalculationIn > 0) return; + this.recalculationIn = 20; + + if (this._foxie.isLeashed()) return; + if (this._foxie.isPassenger()) return; + + if (this._foxie.distanceTo(this.owner) >= 50.0D) { + this.teleport(); + return; + } + + var distance = this._foxie.distanceToSqr(this.owner); + var movementSpeed = this.getMovementSpeedByDistance(distance); + this._foxie.getNavigation().moveTo(this.owner, movementSpeed); + } + + private float getMovementSpeedByDistance(double distance) { + if (distance < 8) + return 1.1F; + if (distance < 16) + return 1.2F; + if (distance < 24) + return 1.3F; + + return 1.4F; + } + + private void getOwner() { + var owner = this._foxie.getOwner(); + if (owner == null) return; + if (owner.isSpectator()) return; + if (!owner.isAlive()) return; + this.owner = owner; + } + + private void teleport() { + var blockpos = this.owner.blockPosition(); + var random = this._foxie.getRandom(); + + for (int i = 0; i < 10; ++i) { + var xMod = random.nextFloat(-5, 5); + var yMod = random.nextFloat(-2, 2); + var zMod = random.nextFloat(-5, 5); + + var succeeded = this.tryTeleport( + (int)(blockpos.getX() + xMod), + (int)(blockpos.getY() + yMod), + (int)(blockpos.getZ() + zMod) + ); + + if (succeeded) + return; + } + } + + private boolean tryTeleport(int x, int y, int z) { + if (Math.abs((double)x - this.owner.getX()) < 2.0D && + Math.abs((double)y - this.owner.getZ()) < 2.0D) + return false; + + var position = new BlockPos(x, y, z); + var level = this._foxie.level; + var foxie = this._foxie; + var types = WalkNodeEvaluator.getBlockPathTypeStatic( + level, position.mutable()); + + if (types != BlockPathTypes.WALKABLE) + return false; + + var state = level.getBlockState(position.below()); + if (state.getBlock() instanceof LeavesBlock) + return false; + + foxie.moveTo(x, y, z, foxie.getYRot(), foxie.getXRot()); + foxie.getNavigation().stop(); + return true; + } +} diff --git a/src/main/java/me/m1chelle99/foxiemc/events/ForgeServerEvents.java b/src/main/java/me/m1chelle99/foxiemc/events/ForgeServerEvents.java index 51acdc4..db6eccb 100644 --- a/src/main/java/me/m1chelle99/foxiemc/events/ForgeServerEvents.java +++ b/src/main/java/me/m1chelle99/foxiemc/events/ForgeServerEvents.java @@ -46,14 +46,30 @@ public static void onLivingSpawn(LivingSpawnEvent event) { @SubscribeEvent public static void onBiomeLoading(BiomeLoadingEvent event) { - var spawners = event.getSpawns().getSpawner(MobCategory.CREATURE); - spawners.removeIf(x -> x.type == EntityType.FOX); + var spawns = event.getSpawns(); + var spawner = spawns.getSpawner(MobCategory.CREATURE); + spawner.removeIf(x -> x.type == EntityType.FOX); - if (event.getCategory() != Biome.BiomeCategory.TAIGA) + if (event.getCategory() != Biome.BiomeCategory.TAIGA && + event.getCategory() != Biome.BiomeCategory.FOREST && + event.getCategory() != Biome.BiomeCategory.PLAINS) return; var foxie = EntityInit.FOXIE.get(); - var foxieSpawnInfo = new MobSpawnSettings.SpawnerData(foxie, 10, 2, 4); - spawners.add(foxieSpawnInfo); + + if (event.getCategory() == Biome.BiomeCategory.FOREST) { + var data = new MobSpawnSettings.SpawnerData(foxie, 12, 1, 2); + spawns.addSpawn(MobCategory.CREATURE, data); + } + + if (event.getCategory() == Biome.BiomeCategory.TAIGA) { + var data = new MobSpawnSettings.SpawnerData(foxie, 7, 1, 2); + spawns.addSpawn(MobCategory.CREATURE, data); + } + + if (event.getCategory() == Biome.BiomeCategory.PLAINS) { + var data = new MobSpawnSettings.SpawnerData(foxie, 3, 1, 1); + spawns.addSpawn(MobCategory.CREATURE, data); + } } } diff --git a/src/main/resources/assets/foxiemc/textures/entities/foxie/foxie.png b/src/main/resources/assets/foxiemc/textures/entities/foxie/foxie.png index 629462b..d12ed2f 100644 Binary files a/src/main/resources/assets/foxiemc/textures/entities/foxie/foxie.png and b/src/main/resources/assets/foxiemc/textures/entities/foxie/foxie.png differ diff --git a/src/main/resources/assets/foxiemc/textures/entities/foxie/foxie_sleep.png b/src/main/resources/assets/foxiemc/textures/entities/foxie/foxie_sleep.png index 201e36d..307d639 100644 Binary files a/src/main/resources/assets/foxiemc/textures/entities/foxie/foxie_sleep.png and b/src/main/resources/assets/foxiemc/textures/entities/foxie/foxie_sleep.png differ