From 5c7691e39ae478e240e1ec19a792f759ad864c23 Mon Sep 17 00:00:00 2001 From: Michelle-99 Date: Fri, 29 Sep 2023 02:20:47 +0200 Subject: [PATCH] Do some spawning adjustments and switch visually to red fox --- .../foxiemc/entity/foxie/FoxieConstants.java | 2 + .../entity/foxie/controls/FoxieAIControl.java | 11 ++ .../foxie/goals/FoxieFollowOwnerGoal.java | 135 ++++++++++++++++++ .../foxiemc/events/ForgeServerEvents.java | 26 +++- .../foxiemc/textures/entities/foxie/foxie.png | Bin 2072 -> 4144 bytes .../textures/entities/foxie/foxie_sleep.png | Bin 2067 -> 3980 bytes 6 files changed, 169 insertions(+), 5 deletions(-) create mode 100644 src/main/java/me/m1chelle99/foxiemc/entity/foxie/goals/FoxieFollowOwnerGoal.java 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 629462b094108e650733a6482f0175742b8a8618..d12ed2f5b88e34c9888b3ebd0445ccea5e20d0aa 100644 GIT binary patch literal 4144 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 UN$)P1zw%FSXYFKFX0a#!AE&SCm;e9( delta 2059 zcmV+m2=w=`Aea!4B!2;OQb$4nuFf3k00004XF*Lt006O%3;baP00009a7bBm000ia z000ia0czHX2><{Gtw}^dRCr$Ho84~}MHq+o9IjPcGJ6VVvaJ2gQrh!Bw&j2H#l25cMCR^-St-GATaJ#%JechByojXcR@ zW@l&T%=Ud(u%;4g+^CR_5 zkSr@3|7Pc}Udn5;?DUJTMt`Hf^w+X`U}|cvwSge~wOiM-gS(%|Ylanq@GE!z$c`O6 z?#g+!6F}+g4}V{|L^;1*85tCgA3BZztcTl? zC@bZ+i)Vbr2q~e808%`;ga`UivIfg<7xbBfnuoFZzkl)1s>^*v9NfF#<<&tLJlFxp1|M?aP#surh_!)I1<2x7aO#-< zR%irKOsI=hg73z4pdb6Z+#gUv$a|930p_L#Cd*J}j>%&KY1YAGrh~zlYbC^I{$e;1qXekB80U8s^2q~hk0W+sHa6KFn9;o9U*dJ0K)WuRAs=B;I zzkh?knpzO+%dG-5;_yO_5UNWFqkF(Jl+_2w{RoWOCaW$5o<$$y3NOKVo}}v-ozKTI zn6D^P_|wiR6oFFH!LBO83Ll&TdA?;ZKnV%N6@<5eG-W|c$ZJ#=x(88hhL(@eK$@<} zvYMup^#-{#(1vpA_sW*MkoP1zvxBmOVSmTRe21nA*lLnf05|mA5!eBayX`H5rHq6D z$}HLjQ3c2q5nl5W#(f9SHk?Pw64T4C^HXUM^mld=+`a*716e-5EEJ9x*!rq`e&O5z zV_o_EYVz5r0(`f(Abgh|U{?k3ud9IYj8U;FMvoVoPtWak7jpNM@VZY9{;3ccaDUb9 ztH8=O;QILe;l3#rS8lon1nyJwC!=F=3h)IeQ-ENgF>e@G0Wnevz}@rW2r1#AN1(u6 z@B&$&47J1haxuHnC|j>X)Lp}+fU-Fbho3qW9ZR7Atf;^ivZ%0aD97el*ZYIADNvP8 z2iYZc6o8lPT3hPxd-lZ0L)%ILc7Gat`rU=>@!84j&!zS3?bqKJ8D|v*AUN(%K*U=^ zQ(?;wLn#ox2~1PPh}cveQh+ui+J+Jz^tV6Cd9%*YS%VzwgYt1H+XoCOfauN=Xjg)= z4w@oGldw3#%kl`%>LP=X+>MGTU@H$XG$*jW-Q@6Ijuk>m=pwR9C@VNfcz+))hc~W% z+fz_W?E@gW5kly^T#GipCm08&WnQd>9|(&tL}I(J*uB(FPkqXpc;4SL;8{(+4ryy2 z;9@{bcu3t#;curAUM@}Eb!@4MI}1>V?fzl`BxOB3!2aDJro_7Eg)Zo10Ga~gf3E;V za?o0?16J(76k;nBQv9IYmVbBha(kvll|eC$bee=cJNIR?bNjNTTfb$qdkvXc{vCJ$FeC;(2*MW zHgMvR9j+`k{=S=CyS@3zOiI|Tc*R~Qz*;-BB5a3%)dj^e7{V%|seb~r1c*VGT?HKF~NfT33E~QW~ ztjB5#x&yG*l7$a^_@2AoE`L>a-w1^^ zJk)VdsVz>u@RCd0g<4i<;sIyo=iS3^e)E~T-Y)x!=pdLHL~VVq<9kY#eY=e#GyTmE zt_f^HflYK8;3CvkfX)bA99)_Nxp9>@v=6Xo-XlDU2*rsIihtIA;=GW$CY5pK%d@VL z@-~Pn0KqxUA$(JKYpeh2pj`GAH$)f0L#YR#1br1M_YWPGQXo8vlp;7emc1NF(e#fc zmZ$qiHJ?owKhR`0A=3zkjwgN=O=gbK3JQr@cR0qtJBLC zeT_2iOOTin>VL!%i`xhR!jZU6CA9<936(X+c|WK&HtD@#omkL?^`ZDg#u9VSP&>cQ zuI;I>H)3CH_(3ivxc`^qw_ZD4^jBv|bZ>+taFw}f+xWtRzquI~6j5e%lwbuHwG@!& p+k(3DH^u|0fYx_{4+dHGAN05i0aEwgf&c&j07*qoLoouX 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 201e36d30ccf43e3bbbd92cc01a5f3fd4eeed80a..307d639667b817de6c5b09b2ed37bce2f8d80f8f 100644 GIT binary patch literal 3980 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 VeHnl5+uHwSo4xxmCFb67{{XFIt5*O3 delta 2053 zcmV+g2>SPoACnM}B!2;OQb$4nuFf3k00004XF*Lt006O%3;baP00009a7bBm000ia z000ia0czHX2><{Gs7XXYRCr$Ho84<2MHq+o9BUFJjV*1hUo8f$l@&byl2kL?C#lJPOuLQ zGdnvwXWox_XJ)hMEiGRiY@fO(gX!try*s#aQ+~Me;~+0Op4#{1P{&i-<_703pBbrd zf@E3Q_%}Oq>3m+BWhb6_Df%1z>whh~2WDpWv^Efgzx?NwY<}m%dCjmw5Ps$6Z`qOg zqpqA+I{}nVeSiCzOO*55m61W==z+s|DNKLY{d4YtwY8<-4^dAV++G{XH8=z#Y0x}F zpK$u(H?FKCu)K1Wg&lldcy@YfyDKAjnegB|;FqNvNe`I1cQ!8#gPTb(`Vo8P9_-+Xa2*pypw0{(o=$v+8nR5%Ul1b9qRJ6eweQ zc6LND5*(@sFJ3%+Brk1Z6=BOZE{OhMFvvnl*bbx!TPJ)aFt_de4uM6mj&kbMx3!?G ztmGO5Sl?L5OPkOab;P)sLi>4MfEW0lU@dQzBcZM3KtWDrS4iMLFRU^kHm?!T_JPnL zBZU}IKz|4FEG!+h4D=*Rw! z6~qbwsf|rt`mF0p2y3rN);fZ^gOBXbcF*o`^?xJ;pw55ZPk9$ZAQ*j0=#cOb3uHb7 zO`G!SAUy_UwQh5;Wf8g`dNxF_Khv7^Vo2yJ9@E3>Xc-GC7YK4~_2y6=&<^V(tcdmD zliF}$4E^5c=g+x1tZw%TDYTRV;{c5bWrP&b*MOPR8n_+~2@lk959|-A59(s64pm*= zqJQ5(U`;KE_2pIp8gY0bM+nuWgwZ|V8OrJd0nnCVTBJ)fjplW3{XM>aRuRRAWd1&67m|=h3-LAo1x_+G?1oi zvaF^lWxYWz4YZ-0`n|FxFXTPR&g`Jzmb$%)hg8t4p+}&= zUGM@~pbWLc`f@S5(I{K5L)2ZvrGT{z?r-}}Vk$U|F70e^NHeDw9%?4e!L+3(lav$tM(b!41X6oBBkKLHVM z4NZlKABIvOd=r?aiV?A?I-~$?MzjqjKIm_Ml=Ehtp|b`#)(7R|Qnn8mQUKANCD5(} zWgRp{iY8%kgqP(Jp4CMLA-NkBQNUInVrWiaeY?rwy&Nlql+ZtZVX=Fuou2xXH}Sl`XTYzu( zKETC*nDCIgm%`spBfMOiyzAIf6?Yb(5ZnF50!Yewc!2%8K}?Bt&kJ49$pAD3#Q$Ca zisYcRTnDV!fhoi!6jJO15PyO{O_6K!V+BjWG?B#-lI85n?|*V}fShaUX+zssngl}| zA$!)>X|F0+T1t51`DfiaPJiUDFD|%yw6WkBN|VAZgLyd!17{AW+*3zt;M>5d`?k5V z*!cTacKOEUCo?HwC-I8CP=K{|Xhqlx0jmp&WiW(QL{kN5$NB!k3xDqVoeLMD{mCdF zE*^8&skTk2)p6b3m;KtTt^$~PRoXUXL?^6JknC$R3`zSs4Sr@VLQP|^9@-<@@VbNTja5rl2q&cOBL z0io3a1=LAx(nX(8e19Y4ulWQ(Sr0h=)*XPgmMpyggLmEaR{5*4`$j0V;h~OuN^Noc z>E~S9D%7$<6Aw7Ku;3nk?Te4y^;X$eL