Advertisement
jayhillx

Sea Otter 2

Apr 23rd, 2024
704
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 13.07 KB | None | 0 0
  1. package com.mysticsbiomes.common.entity.animal;
  2.  
  3. import com.mysticsbiomes.init.MysticEntities;
  4. import com.mysticsbiomes.init.MysticItems;
  5. import net.minecraft.core.BlockPos;
  6. import net.minecraft.nbt.CompoundTag;
  7. import net.minecraft.network.syncher.EntityDataAccessor;
  8. import net.minecraft.network.syncher.EntityDataSerializers;
  9. import net.minecraft.network.syncher.SynchedEntityData;
  10. import net.minecraft.server.level.ServerLevel;
  11. import net.minecraft.util.Mth;
  12. import net.minecraft.world.InteractionHand;
  13. import net.minecraft.world.InteractionResult;
  14. import net.minecraft.world.entity.*;
  15. import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
  16. import net.minecraft.world.entity.ai.attributes.Attributes;
  17. import net.minecraft.world.entity.ai.behavior.BehaviorUtils;
  18. import net.minecraft.world.entity.ai.control.MoveControl;
  19. import net.minecraft.world.entity.ai.control.SmoothSwimmingLookControl;
  20. import net.minecraft.world.entity.ai.control.SmoothSwimmingMoveControl;
  21. import net.minecraft.world.entity.ai.goal.*;
  22. import net.minecraft.world.entity.ai.navigation.PathNavigation;
  23. import net.minecraft.world.entity.ai.navigation.WaterBoundPathNavigation;
  24. import net.minecraft.world.entity.ai.util.DefaultRandomPos;
  25. import net.minecraft.world.entity.animal.Animal;
  26. import net.minecraft.world.entity.player.Player;
  27. import net.minecraft.world.item.Items;
  28. import net.minecraft.world.item.crafting.Ingredient;
  29. import net.minecraft.world.level.Level;
  30. import net.minecraft.world.level.LevelReader;
  31. import net.minecraft.world.level.block.state.BlockState;
  32. import net.minecraft.world.level.pathfinder.BlockPathTypes;
  33. import net.minecraft.world.level.pathfinder.PathComputationType;
  34. import net.minecraft.world.level.pathfinder.PathFinder;
  35. import net.minecraft.world.level.pathfinder.SwimNodeEvaluator;
  36. import net.minecraft.world.phys.Vec3;
  37.  
  38. import javax.annotation.Nullable;
  39. import java.util.EnumSet;
  40.  
  41. /**
  42.  * swims on the surface.
  43.  * only swims underwater fully when playing or searching for food.
  44.  */
  45. public class SeaOtter extends Animal {
  46.     private static final EntityDataAccessor<Boolean> DATA_FLOATING_ID = SynchedEntityData.defineId(SeaOtter.class, EntityDataSerializers.BOOLEAN);
  47.     private static final EntityDataAccessor<Boolean> DATA_SWIMMING_ID = SynchedEntityData.defineId(SeaOtter.class, EntityDataSerializers.BOOLEAN);
  48.     int ticksSinceSearchedForFood;
  49.     int cooldownBeforeFindingFoodAgain;
  50.     boolean needsToSurface;
  51.  
  52.     public final AnimationState idleAnimationState = new AnimationState();
  53.  
  54.     public SeaOtter(EntityType<? extends SeaOtter> type, Level level) {
  55.         super(type, level);
  56.         this.setPathfindingMalus(BlockPathTypes.WATER, 0.0F);
  57.         this.moveControl = new SeaOtter.SeaOtterMoveControl(this);
  58.         this.lookControl = new SmoothSwimmingLookControl(this, 10);
  59.     }
  60.  
  61.     protected void defineSynchedData() {
  62.         super.defineSynchedData();
  63.         this.entityData.define(DATA_FLOATING_ID, false);
  64.         this.entityData.define(DATA_SWIMMING_ID, false);
  65.     }
  66.  
  67.     protected void registerGoals() {
  68.         this.goalSelector.addGoal(1, new SeaOtter.SearchForFoodGoal());
  69.         this.goalSelector.addGoal(2, new SeaOtter.FloatAtSurfaceGoal());
  70.         this.goalSelector.addGoal(2, new SeaOtter.SwimToSurfaceGoal(this, 1.0D, 16));
  71.         this.goalSelector.addGoal(3, new SeaOtter.SwimAroundGoal(this, 1.0D, 10));
  72.         this.goalSelector.addGoal(4, new LookAtPlayerGoal(this, Player.class, 6.0F));
  73.         this.goalSelector.addGoal(5, new RandomLookAroundGoal(this));
  74.     }
  75.  
  76.     public static AttributeSupplier.Builder createAttributes() {
  77.         return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 16.0F).add(Attributes.MOVEMENT_SPEED, 0.25D);
  78.     }
  79.  
  80.     public void addAdditionalSaveData(CompoundTag tag) {
  81.         super.addAdditionalSaveData(tag);
  82.         tag.putBoolean("Floating", this.isFloating());
  83.         tag.putBoolean("Swimming", this.isSwimming());
  84.     }
  85.  
  86.     public void readAdditionalSaveData(CompoundTag tag) {
  87.         super.readAdditionalSaveData(tag);
  88.         this.setFloating(tag.getBoolean("Floating"));
  89.         this.setSwimming(tag.getBoolean("Swimming"));
  90.     }
  91.  
  92.     public AgeableMob getBreedOffspring(ServerLevel level, AgeableMob mob) {
  93.         return MysticEntities.SEA_OTTER.get().create(level);
  94.     }
  95.  
  96.     public MobType getMobType() {
  97.         return MobType.WATER;
  98.     }
  99.  
  100.     // TICKS & A.I.
  101.  
  102.     public void tick() {
  103.         super.tick();
  104.  
  105.         if (this.level().isClientSide) {
  106.             this.idleAnimationState.animateWhen(this.isFloating(), this.tickCount);
  107.         }
  108.     }
  109.  
  110.     public void aiStep() {
  111.         super.aiStep();
  112.         ++this.ticksSinceSearchedForFood;
  113.  
  114.         if (this.cooldownBeforeFindingFoodAgain > 0) {
  115.             --this.cooldownBeforeFindingFoodAgain;
  116.         }
  117.  
  118.         if (this.isFloating()) {
  119.             this.setDeltaMovement(this.getDeltaMovement().multiply(1.0D, 0.0D, 1.0D));
  120.             this.setYya(0.0F);
  121.         }
  122.  
  123.         if (this.isUnderWater() && (this.getAirSupply() < 200 || this.random.nextFloat() <= 0.001F)) {
  124.             this.setNeedsToSurface(true);
  125.         }
  126.     }
  127.  
  128.     // NAVIGATION & MOVEMENT
  129.  
  130.     protected PathNavigation createNavigation(Level level) {
  131.         return new SeaOtter.SeaOtterPathNavigation(this, level);
  132.     }
  133.  
  134.     public void travel(Vec3 vec3) {
  135.         if (this.isEffectiveAi() && this.isInWater()) {
  136.             this.moveRelative(this.getSpeed(), vec3);
  137.             this.move(MoverType.SELF, this.getDeltaMovement());
  138.             this.setDeltaMovement(this.getDeltaMovement().scale(0.9D));
  139.         } else {
  140.             super.travel(vec3);
  141.         }
  142.     }
  143.  
  144.     public int getMaxAirSupply() {
  145.         return 6000;
  146.     }
  147.  
  148.     public boolean isFloating() {
  149.         return this.entityData.get(DATA_FLOATING_ID);
  150.     }
  151.  
  152.     public void setFloating(boolean value) {
  153.         this.entityData.set(DATA_FLOATING_ID, value);
  154.         this.entityData.set(DATA_SWIMMING_ID, !value);
  155.     }
  156.  
  157.     public boolean isSwimming() {
  158.         return this.entityData.get(DATA_SWIMMING_ID);
  159.     }
  160.  
  161.     public void setSwimming(boolean value) {
  162.         this.entityData.set(DATA_SWIMMING_ID, value);
  163.         this.entityData.set(DATA_FLOATING_ID, !value);
  164.     }
  165.  
  166.     public boolean wantsToSearchForFood() {
  167.         return this.ticksSinceSearchedForFood > 200;
  168.     }
  169.  
  170.     /**
  171.      * @return when they need to breath above water, to eat, or to sleep.
  172.      */
  173.     public boolean needsToSurface() {
  174.         return this.needsToSurface;
  175.     }
  176.  
  177.     public void setNeedsToSurface(boolean needsToSurface) {
  178.         this.needsToSurface = needsToSurface;
  179.     }
  180.  
  181.     @Override
  182.     public InteractionResult mobInteract(Player player, InteractionHand hand) {
  183.         boolean flag = player.getItemInHand(hand).is(Items.STICK);
  184.         this.setFloating(flag);
  185.         this.setSwimming(!flag);
  186.         return super.mobInteract(player, hand);
  187.     }
  188.  
  189.     // TODO: GOALS
  190.  
  191.     class FloatAtSurfaceGoal extends Goal {
  192.  
  193.         public boolean canUse() {
  194.             return !SeaOtter.this.isSwimming() || !SeaOtter.this.wantsToSearchForFood();
  195.         }
  196.  
  197.         public void start() {
  198.             SeaOtter.this.setFloating(true);
  199.         }
  200.     }
  201.  
  202.     class SwimToSurfaceGoal extends MoveToBlockGoal {
  203.  
  204.         SwimToSurfaceGoal(PathfinderMob mob, double speed, int range) {
  205.             super(mob, speed, range);
  206.             this.setFlags(EnumSet.of(Flag.MOVE, Flag.LOOK));
  207.         }
  208.  
  209.         public boolean canUse() {
  210.             return super.canUse() && SeaOtter.this.needsToSurface() && !SeaOtter.this.isFloating() && !SeaOtter.this.onGround();
  211.         }
  212.  
  213.         public void stop() {
  214.             SeaOtter.this.setNeedsToSurface(false);
  215.             SeaOtter.this.getNavigation().stop();
  216.         }
  217.  
  218.         protected boolean isValidTarget(LevelReader reader, BlockPos pos) {
  219.             return reader.getBlockState(pos.above()).isAir();
  220.         }
  221.     }
  222.  
  223.     class SwimAroundGoal extends RandomSwimmingGoal {
  224.  
  225.         SwimAroundGoal(PathfinderMob mob, double speed, int interval) {
  226.             super(mob, speed, interval);
  227.         }
  228.  
  229.         public boolean canUse() {
  230.             return super.canUse() && !SeaOtter.this.isFloating();
  231.         }
  232.  
  233.         public boolean canContinueToUse() {
  234.             return super.canContinueToUse() && !SeaOtter.this.isFloating();
  235.         }
  236.  
  237.         public void start() {
  238.             super.start();
  239.             SeaOtter.this.setSwimming(true);
  240.         }
  241.     }
  242.  
  243.     class SearchForFoodGoal extends Goal {
  244.         int ticks;
  245.  
  246.         public boolean canUse() {
  247.             return SeaOtter.this.wantsToSearchForFood() && SeaOtter.this.cooldownBeforeFindingFoodAgain <= 0;
  248.         }
  249.  
  250.         public boolean canContinueToUse() {
  251.             return !this.hasSearchedLongEnough();
  252.         }
  253.  
  254.         public void start() {
  255.             this.ticks = 0;
  256.             SeaOtter.this.setSwimming(true);
  257.         }
  258.  
  259.         public void stop() {
  260.             if (this.hasSearchedLongEnough()) {
  261.                 SeaOtter.this.cooldownBeforeFindingFoodAgain = 200;
  262.                 SeaOtter.this.setFloating(true);
  263.             }
  264.  
  265.             this.ticks = 0;
  266.         }
  267.  
  268.         private boolean hasSearchedLongEnough() {
  269.             return this.ticks > 200;
  270.         }
  271.  
  272.         public void tick() {
  273.             ++this.ticks;
  274.         }
  275.     }
  276.  
  277.     // TODO: NAVIGATION & CONTROLS
  278.  
  279.     class SeaOtterMoveControl extends MoveControl {
  280.  
  281.         public SeaOtterMoveControl(Mob mob) {
  282.             super(mob);
  283.         }
  284.  
  285.         @Override
  286.         public void tick() {
  287.             if (SeaOtter.this.isInWater()) {
  288.                 SeaOtter.this.setDeltaMovement(SeaOtter.this.getDeltaMovement().add(SeaOtter.this.getLookAngle().scale(SeaOtter.this.isFloating() ? 0.002F : 0.005F)));
  289.  
  290.                 if (!SeaOtter.this.isFloating()) {
  291.                     if (this.operation == Operation.MOVE_TO && !this.mob.getNavigation().isDone()) {
  292.                         double d0 = this.wantedX - this.mob.getX();
  293.                         double d1 = this.wantedY - this.mob.getY();
  294.                         double d2 = this.wantedZ - this.mob.getZ();
  295.                         double distanceSqr = d0 * d0 + d1 * d1 + d2 * d2;
  296.  
  297.                         if (distanceSqr < (double) 2.5000003E-7F) {
  298.                             this.mob.setZza(0.0F);
  299.                         } else {
  300.                             float yRot = (float) (Mth.atan2(d2, d0) * (double) (180F / (float) Math.PI)) - 90.0F;
  301.                             this.mob.setYRot(this.rotlerp(this.mob.getYRot(), yRot, 40.0F));
  302.                             this.mob.yBodyRot = this.mob.getYRot();
  303.                             this.mob.yHeadRot = this.mob.getYRot();
  304.                             float speed = (float) (this.speedModifier * this.mob.getAttributeValue(Attributes.MOVEMENT_SPEED));
  305.                             this.mob.setSpeed(speed * 0.2F);
  306.  
  307.                             double horizontalDistance = Math.sqrt(d0 * d0 + d2 * d2);
  308.                             if (Math.abs(d1) > (double) 1.0E-5F || Math.abs(horizontalDistance) > (double) 1.0E-5F) {
  309.                                 float xRot = -((float) (Mth.atan2(d1, horizontalDistance) * (double) (180F / (float) Math.PI)));
  310.                                 xRot = Mth.clamp(Mth.wrapDegrees(xRot), -180.0F, 180.0F);
  311.                                 this.mob.setXRot(this.rotlerp(this.mob.getXRot(), xRot, 45.0F));
  312.                             }
  313.  
  314.                             BlockPos wantedPos = new BlockPos((int) this.wantedX, (int) this.wantedY, (int) this.wantedZ);
  315.                             BlockState wantedBlockState = this.mob.level().getBlockState(wantedPos);
  316.  
  317.                             if (d1 > (double) this.mob.maxUpStep() && d0 * d0 + d2 * d2 < 4.0F && d1 <= 1.0D && wantedBlockState.getFluidState().isEmpty()) {
  318.                                 this.mob.getJumpControl().jump();
  319.                                 this.mob.setSpeed(speed);
  320.                             }
  321.  
  322.                             float f0 = Mth.cos(this.mob.getXRot() * ((float) Math.PI / 180F));
  323.                             float f1 = Mth.sin(this.mob.getXRot() * ((float) Math.PI / 180F));
  324.                             this.mob.zza = f0 * speed;
  325.                             this.mob.yya = -f1 * (speed);
  326.                         }
  327.                     } else {
  328.                         this.mob.setSpeed(0.0F);
  329.                         this.mob.setXxa(0.0F);
  330.                         this.mob.setYya(0.0F);
  331.                         this.mob.setZza(0.0F);
  332.                     }
  333.                 }
  334.             } else {
  335.                 super.tick();
  336.             }
  337.         }
  338.     }
  339.  
  340.     static class SeaOtterPathNavigation extends WaterBoundPathNavigation {
  341.  
  342.         public SeaOtterPathNavigation(Mob mob, Level level) {
  343.             super(mob, level);
  344.         }
  345.  
  346.         protected PathFinder createPathFinder(int nodes) {
  347.             this.nodeEvaluator = new SwimNodeEvaluator(true);
  348.             return new PathFinder(this.nodeEvaluator, nodes);
  349.         }
  350.  
  351.         protected boolean canUpdatePath() {
  352.             return true;
  353.         }
  354.     }
  355.  
  356. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement