jayhillx

Sea Otter 7

Nov 20th, 2025
503
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 46.74 KB | None | 0 0
  1. package com.mysticsbiomes.common.entity;
  2.  
  3. import com.mysticsbiomes.init.MysticEntities;
  4. import io.netty.buffer.ByteBuf;
  5. import net.minecraft.client.model.geom.ModelPart;
  6. import net.minecraft.client.model.geom.PartPose;
  7. import net.minecraft.core.BlockPos;
  8. import net.minecraft.nbt.CompoundTag;
  9. import net.minecraft.nbt.NbtUtils;
  10. import net.minecraft.network.codec.ByteBufCodecs;
  11. import net.minecraft.network.codec.StreamCodec;
  12. import net.minecraft.network.syncher.EntityDataAccessor;
  13. import net.minecraft.network.syncher.EntityDataSerializer;
  14. import net.minecraft.network.syncher.EntityDataSerializers;
  15. import net.minecraft.network.syncher.SynchedEntityData;
  16. import net.minecraft.server.level.ServerLevel;
  17. import net.minecraft.tags.FluidTags;
  18. import net.minecraft.tags.ItemTags;
  19. import net.minecraft.util.ByIdMap;
  20. import net.minecraft.util.Mth;
  21. import net.minecraft.util.StringRepresentable;
  22. import net.minecraft.world.InteractionHand;
  23. import net.minecraft.world.InteractionResult;
  24. import net.minecraft.world.entity.*;
  25. import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
  26. import net.minecraft.world.entity.ai.attributes.Attributes;
  27. import net.minecraft.world.entity.ai.control.BodyRotationControl;
  28. import net.minecraft.world.entity.ai.control.LookControl;
  29. import net.minecraft.world.entity.ai.control.MoveControl;
  30. import net.minecraft.world.entity.ai.goal.*;
  31. import net.minecraft.world.entity.ai.navigation.AmphibiousPathNavigation;
  32. import net.minecraft.world.entity.ai.navigation.PathNavigation;
  33. import net.minecraft.world.entity.animal.Animal;
  34. import net.minecraft.world.entity.player.Player;
  35. import net.minecraft.world.item.ItemStack;
  36. import net.minecraft.world.level.Level;
  37. import net.minecraft.world.level.LevelReader;
  38. import net.minecraft.world.level.block.Blocks;
  39. import net.minecraft.world.level.block.state.BlockState;
  40. import net.minecraft.world.level.pathfinder.*;
  41. import net.minecraft.world.phys.Vec3;
  42.  
  43. import javax.annotation.Nullable;
  44. import java.util.EnumSet;
  45. import java.util.HashMap;
  46. import java.util.Map;
  47. import java.util.Optional;
  48. import java.util.function.IntFunction;
  49. import java.util.function.Predicate;
  50.  
  51. /**
  52.  * can be tamed as pets to defend you in the water.
  53.  * they can help you find treasures, or collect fish.
  54.  * they can help you swim faster like dolphins.
  55.  * they mostly float around, unless they are feeling playful or want to get food.
  56.  * they will fall asleep at night, holding another sea otters hand nearby.
  57.  * their babies will rest on their belly until they age up.
  58.  *
  59.  * todo:
  60.  * swim around
  61.  * drift around
  62.  * hold hands
  63.  * breed
  64.  * search for food
  65.  *
  66.  * sleeping
  67.  * hold hands while sleeping
  68.  * babies sleeping on parent
  69.  * babies behavior
  70.  * search for fish
  71.  * search for seashells
  72.  * break open shells
  73.  * bring items to players
  74.  * eat
  75.  */
  76. public class SeaOtter extends Animal {
  77.     public static final EntityDataSerializer<State> SEA_OTTER_STATE = EntityDataSerializer.forValueType(State.STREAM_CODEC);
  78.     private static final EntityDataAccessor<State> DATA_STATE_ID = SynchedEntityData.defineId(SeaOtter.class, SEA_OTTER_STATE);
  79.     private static final EntityDataAccessor<Byte> DATA_FLAGS_ID = SynchedEntityData.defineId(SeaOtter.class, EntityDataSerializers.BYTE);
  80.     private int ticksSinceLastSwam;
  81.     private int ticksSpentSwimming;
  82.     @Nullable
  83.     private BlockPos surfacePos;
  84.     public final Map<ModelPart, PartPose> previousPose = new HashMap<>();
  85.     public final Map<ModelPart, PartPose> targetPose = new HashMap<>();
  86.     public final AnimationState swimmingIdleAnimationState = new AnimationState();
  87.     public final AnimationState swimmingAnimationState = new AnimationState();
  88.     public final AnimationState twirlWhileSwimmingAnimationState = new AnimationState();
  89.     public final AnimationState floatingAnimationState = new AnimationState();
  90.     public final AnimationState startFloatingAnimationState = new AnimationState();
  91.     public final AnimationState stopFloatingAnimationState = new AnimationState();
  92.     public final AnimationState sleepingWhileFloatingAnimationState = new AnimationState();
  93.     public final AnimationState eatingWhileFloatingAnimationState = new AnimationState();
  94.     public final AnimationState sitDownAnimationState = new AnimationState();
  95.     public final AnimationState sittingIdleAnimationState = new AnimationState();
  96.     public final AnimationState standUpAnimationState = new AnimationState();
  97.     public final AnimationState standingIdleAnimationState = new AnimationState();
  98.     public final AnimationState walkingAnimationState = new AnimationState();
  99.     private long inStateTicks = 0L;
  100.  
  101.     public SeaOtter(EntityType<? extends SeaOtter> type, Level level) {
  102.         super(type, level);
  103.         this.setPathfindingMalus(PathType.WATER, 0.0F);
  104.         this.moveControl = new SeaOtter.SeaOtterMoveControl(this);
  105.         this.lookControl = new SeaOtter.SeaOtterLookControl(this);
  106.     }
  107.  
  108.     public static AttributeSupplier.Builder createAttributes() {
  109.         return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 16.0F).add(Attributes.MOVEMENT_SPEED, 0.5D).add(Attributes.STEP_HEIGHT, 1.0);
  110.     }
  111.  
  112.     @Override
  113.     protected void registerGoals() {
  114.         this.goalSelector.addGoal(0, new SeaOtter.SwimToSurfaceGoal(this));
  115.         this.goalSelector.addGoal(1, new SeaOtter.SeaOtterLookAtPlayerGoal(this, 6.0F));
  116.         this.goalSelector.addGoal(2, new SeaOtter.FloatingGoal(this));
  117.         this.goalSelector.addGoal(3, new SeaOtter.SeaOtterTemptGoal(this, 0.2D, (stack) -> stack.is(ItemTags.FISHES)));
  118.         this.goalSelector.addGoal(4, new SeaOtter.SwimAroundGoal(this, 1.0D, 3));
  119.         this.goalSelector.addGoal(5, new SeaOtter.SeaOtterRandomLookAroundGoal(this));
  120.     }
  121.  
  122.     @Override
  123.     protected void defineSynchedData(SynchedEntityData.Builder builder) {
  124.         super.defineSynchedData(builder);
  125.         builder.define(DATA_STATE_ID, State.NOTHING);
  126.         builder.define(DATA_FLAGS_ID, (byte)0);
  127.     }
  128.  
  129.     @Override
  130.     public void addAdditionalSaveData(CompoundTag tag) {
  131.         super.addAdditionalSaveData(tag);
  132.         tag.putString("State", this.getState().getSerializedName());
  133.         tag.putBoolean("Floating", this.isFloating());
  134.         tag.putBoolean("Swimming", this.isSwimming());
  135.         tag.putBoolean("Sitting", this.isSitting());
  136.         tag.putInt("TicksSinceLastSwam", this.ticksSinceLastSwam);
  137.         tag.putInt("TicksSpentSwimming", this.ticksSpentSwimming);
  138.  
  139.         if (this.surfacePos != null) {
  140.             tag.put("SurfacePos", NbtUtils.writeBlockPos(this.surfacePos));
  141.         }
  142.     }
  143.  
  144.     @Override
  145.     public void readAdditionalSaveData(CompoundTag tag) {
  146.         super.readAdditionalSaveData(tag);
  147.         this.switchToState(State.fromName(tag.getString("State")));
  148.         this.setFloating(tag.getBoolean("Floating"));
  149.         this.setSwimming(tag.getBoolean("Swimming"));
  150.         this.setSitting(tag.getBoolean("Sitting"));
  151.         this.ticksSinceLastSwam = tag.getInt("TicksSinceLastSwam");
  152.         this.ticksSpentSwimming = tag.getInt("TicksSpentSwimming");
  153.  
  154.         this.surfacePos = null;
  155.         if (tag.contains("SurfacePos") && NbtUtils.readBlockPos(tag, "SurfacePos").isPresent()) {
  156.             this.surfacePos = NbtUtils.readBlockPos(tag, "SurfacePos").get();
  157.         }
  158.     }
  159.  
  160.     @Override
  161.     public AgeableMob getBreedOffspring(ServerLevel level, AgeableMob mob) {
  162.         return MysticEntities.SEA_OTTER.get().create(level);
  163.     }
  164.  
  165.     @Override
  166.     public int getMaxAirSupply() {
  167.         return 6000; /// 5 minutes
  168.     }
  169.  
  170.     @Override
  171.     public void tick() {
  172.         super.tick();
  173.         if (!this.level().isClientSide()) {
  174.             if (this.isFloating()) {
  175.                 this.ticksSinceLastSwam++;
  176.                 this.wasTouchingWater = true;
  177.                 this.setDeltaMovement(this.getDeltaMovement().multiply(1.0D, 0.0D, 1.0D));
  178.                 this.setSpeed(0.0F);
  179.                 this.setYya(0.0F);
  180.  
  181.                 if (this.getAirSupply() < this.getMaxAirSupply()) {
  182.                     this.setAirSupply(this.increaseAirSupply(this.getAirSupply()));
  183.                 }
  184.             }
  185.  
  186.             if (this.isUnderWater()) {
  187.                 if (!this.needsToSurface() && (this.getAirSupply() < 600 || !this.wantsToSwimAround() || this.hasBeenSwimmingLongEnough())) {
  188.                     this.setNeedsToSurface(true);
  189.                 }
  190.             }
  191.         }
  192.  
  193.         if (this.level().isClientSide()) {
  194.             this.setupSwimmingAnimationStates();
  195.             this.setupFloatingAnimationStates();
  196.             this.setupSittingAnimationStates();
  197.         }
  198.         this.inStateTicks++;
  199.     }
  200.  
  201.     private void setupSwimmingAnimationStates() {
  202.         switch (this.getState()) {
  203.             case SWIMMING_IDLE:
  204.                 this.swimmingIdleAnimationState.startIfStopped(this.tickCount);
  205.                 this.swimmingAnimationState.stop();
  206.                 this.twirlWhileSwimmingAnimationState.stop();
  207.                 this.floatingAnimationState.stop();
  208.                 this.startFloatingAnimationState.stop();
  209.                 this.stopFloatingAnimationState.stop();
  210.                 this.sleepingWhileFloatingAnimationState.stop();
  211.                 this.eatingWhileFloatingAnimationState.stop();
  212.                 this.sitDownAnimationState.stop();
  213.                 this.sittingIdleAnimationState.stop();
  214.                 this.standUpAnimationState.stop();
  215.                 this.standingIdleAnimationState.stop();
  216.                 this.walkingAnimationState.stop();
  217.                 break;
  218.             case SWIMMING:
  219.                 this.swimmingAnimationState.startIfStopped(this.tickCount);
  220.                 this.swimmingIdleAnimationState.stop();
  221.                 this.twirlWhileSwimmingAnimationState.stop();
  222.                 this.floatingAnimationState.stop();
  223.                 this.startFloatingAnimationState.stop();
  224.                 this.stopFloatingAnimationState.stop();
  225.                 this.sleepingWhileFloatingAnimationState.stop();
  226.                 this.eatingWhileFloatingAnimationState.stop();
  227.                 this.sitDownAnimationState.stop();
  228.                 this.sittingIdleAnimationState.stop();
  229.                 this.standUpAnimationState.stop();
  230.                 this.standingIdleAnimationState.stop();
  231.                 this.walkingAnimationState.stop();
  232.                 break;
  233.             case TWIRL_WHILE_SWIMMING:
  234.                 this.twirlWhileSwimmingAnimationState.startIfStopped(this.tickCount);
  235.                 break;
  236.         }
  237.     }
  238.  
  239.     private void setupFloatingAnimationStates() {
  240.         switch (this.getState()) {
  241.             case START_FLOATING:
  242.                 this.startFloatingAnimationState.startIfStopped(this.tickCount);
  243.                 this.swimmingIdleAnimationState.stop();
  244.                 this.swimmingAnimationState.stop();
  245.                 this.twirlWhileSwimmingAnimationState.stop();
  246.                 this.floatingAnimationState.stop();
  247.                 this.stopFloatingAnimationState.stop();
  248.                 this.sleepingWhileFloatingAnimationState.stop();
  249.                 this.eatingWhileFloatingAnimationState.stop();
  250.                 this.sitDownAnimationState.stop();
  251.                 this.sittingIdleAnimationState.stop();
  252.                 this.standUpAnimationState.stop();
  253.                 this.standingIdleAnimationState.stop();
  254.                 this.walkingAnimationState.stop();
  255.                 break;
  256.             case FLOATING:
  257.                 this.floatingAnimationState.startIfStopped(this.tickCount);
  258.                 this.swimmingIdleAnimationState.stop();
  259.                 this.swimmingAnimationState.stop();
  260.                 this.twirlWhileSwimmingAnimationState.stop();
  261.                 this.startFloatingAnimationState.stop();
  262.                 this.stopFloatingAnimationState.stop();
  263.                 this.sleepingWhileFloatingAnimationState.stop();
  264.                 this.eatingWhileFloatingAnimationState.stop();
  265.                 this.sitDownAnimationState.stop();
  266.                 this.sittingIdleAnimationState.stop();
  267.                 this.standUpAnimationState.stop();
  268.                 this.standingIdleAnimationState.stop();
  269.                 this.walkingAnimationState.stop();
  270.                 break;
  271.             case STOP_FLOATING:
  272.                 this.stopFloatingAnimationState.startIfStopped(this.tickCount);
  273.                 this.swimmingIdleAnimationState.stop();
  274.                 this.swimmingAnimationState.stop();
  275.                 this.twirlWhileSwimmingAnimationState.stop();
  276.                 this.floatingAnimationState.stop();
  277.                 this.startFloatingAnimationState.stop();
  278.                 this.sleepingWhileFloatingAnimationState.stop();
  279.                 this.eatingWhileFloatingAnimationState.stop();
  280.                 this.sitDownAnimationState.stop();
  281.                 this.sittingIdleAnimationState.stop();
  282.                 this.standUpAnimationState.stop();
  283.                 this.standingIdleAnimationState.stop();
  284.                 this.walkingAnimationState.stop();
  285.                 break;
  286.             case SLEEPING_WHILE_FLOATING:
  287.                 this.sleepingWhileFloatingAnimationState.startIfStopped(this.tickCount);
  288.                 break;
  289.             case EATING_WHILE_FLOATING:
  290.                 this.eatingWhileFloatingAnimationState.startIfStopped(this.tickCount);
  291.                 break;
  292.         }
  293.     }
  294.  
  295.     private void setupSittingAnimationStates() {
  296.         switch (this.getState()) {
  297.             case SIT_DOWN:
  298.                 this.sitDownAnimationState.startIfStopped(this.tickCount);
  299.                 this.swimmingIdleAnimationState.stop();
  300.                 this.swimmingAnimationState.stop();
  301.                 this.twirlWhileSwimmingAnimationState.stop();
  302.                 this.floatingAnimationState.stop();
  303.                 this.startFloatingAnimationState.stop();
  304.                 this.stopFloatingAnimationState.stop();
  305.                 this.sleepingWhileFloatingAnimationState.stop();
  306.                 this.eatingWhileFloatingAnimationState.stop();
  307.                 this.sittingIdleAnimationState.stop();
  308.                 this.standUpAnimationState.stop();
  309.                 this.standingIdleAnimationState.stop();
  310.                 this.walkingAnimationState.stop();
  311.                 break;
  312.             case SITTING_IDLE:
  313.                 this.sittingIdleAnimationState.startIfStopped(this.tickCount);
  314.                 this.swimmingIdleAnimationState.stop();
  315.                 this.swimmingAnimationState.stop();
  316.                 this.twirlWhileSwimmingAnimationState.stop();
  317.                 this.floatingAnimationState.stop();
  318.                 this.startFloatingAnimationState.stop();
  319.                 this.stopFloatingAnimationState.stop();
  320.                 this.sleepingWhileFloatingAnimationState.stop();
  321.                 this.eatingWhileFloatingAnimationState.stop();
  322.                 this.sitDownAnimationState.stop();
  323.                 this.standUpAnimationState.stop();
  324.                 this.standingIdleAnimationState.stop();
  325.                 this.walkingAnimationState.stop();
  326.                 break;
  327.             case STAND_UP:
  328.                 this.standUpAnimationState.startIfStopped(this.tickCount);
  329.                 this.swimmingIdleAnimationState.stop();
  330.                 this.swimmingAnimationState.stop();
  331.                 this.twirlWhileSwimmingAnimationState.stop();
  332.                 this.floatingAnimationState.stop();
  333.                 this.startFloatingAnimationState.stop();
  334.                 this.stopFloatingAnimationState.stop();
  335.                 this.sleepingWhileFloatingAnimationState.stop();
  336.                 this.eatingWhileFloatingAnimationState.stop();
  337.                 this.sitDownAnimationState.stop();
  338.                 this.sittingIdleAnimationState.stop();
  339.                 this.standingIdleAnimationState.stop();
  340.                 this.walkingAnimationState.stop();
  341.                 break;
  342.             case WALKING:
  343.                 this.walkingAnimationState.startIfStopped(this.tickCount);
  344.                 this.swimmingIdleAnimationState.stop();
  345.                 this.swimmingAnimationState.stop();
  346.                 this.twirlWhileSwimmingAnimationState.stop();
  347.                 this.floatingAnimationState.stop();
  348.                 this.startFloatingAnimationState.stop();
  349.                 this.stopFloatingAnimationState.stop();
  350.                 this.sleepingWhileFloatingAnimationState.stop();
  351.                 this.eatingWhileFloatingAnimationState.stop();
  352.                 this.sitDownAnimationState.stop();
  353.                 this.sittingIdleAnimationState.stop();
  354.                 this.standUpAnimationState.stop();
  355.                 this.standingIdleAnimationState.stop();
  356.                 break;
  357.         }
  358.     }
  359.  
  360.     @Override
  361.     public void aiStep() {
  362.         super.aiStep();
  363.         if (!this.level().isClientSide()) {
  364.             if (this.onGround() && !this.isInWater() && !this.isFloating()) {
  365.                 if (this.wantsToMove()) {
  366.                     if (this.isSitting() || this.getState() == State.SIT_DOWN) {
  367.                         if (this.getState() != State.STAND_UP) {
  368.                             this.switchToState(State.STAND_UP);
  369.                             this.setSitting(false);
  370.                         }
  371.                     }
  372.  
  373.                     if (this.getState() == State.STAND_UP && this.inStateTicks >= State.STAND_UP.animationDuration()) {
  374.                         this.switchToState(State.WALKING);
  375.                     }
  376.  
  377.                     if (!this.isSitting() && this.getState() != State.STAND_UP && this.getState() != State.WALKING) {
  378.                         this.switchToState(State.WALKING);
  379.                     }
  380.                 } else {
  381.                     if (!this.isSitting() && this.getState() != State.SIT_DOWN) {
  382.                         this.switchToState(State.SIT_DOWN);
  383.                         this.setSitting(true);
  384.                     } else if (this.getState() == State.SIT_DOWN && this.inStateTicks >= State.SIT_DOWN.animationDuration()) {
  385.                         this.switchToState(State.SITTING_IDLE);
  386.                         this.setSitting(true);
  387.                     }
  388.  
  389.                     if (this.getState() == State.STAND_UP && this.inStateTicks >= State.STAND_UP.animationDuration()) {
  390.                         this.switchToState(State.SIT_DOWN);
  391.                         this.setSitting(true);
  392.                     }
  393.                 }
  394.             }
  395.         }
  396.     }
  397.  
  398.     @Override
  399.     public void onSyncedDataUpdated(EntityDataAccessor<?> accessor) {
  400.         if (DATA_STATE_ID.equals(accessor)) {
  401.             this.inStateTicks = 0L;
  402.         }
  403.  
  404.         super.onSyncedDataUpdated(accessor);
  405.     }
  406.  
  407.     public State getState() {
  408.         return this.entityData.get(DATA_STATE_ID);
  409.     }
  410.  
  411.     public void switchToState(State state) {
  412.         if (this.getState() != state) {
  413.             this.entityData.set(DATA_STATE_ID, state);
  414.             this.inStateTicks = 0L;
  415.         }
  416.     }
  417.  
  418.     public boolean isActivelyInFloatTransition() {
  419.         return switch (this.getState()) {
  420.             case START_FLOATING, STOP_FLOATING, FLOATING -> this.inStateTicks < this.getState().animationDuration();
  421.             default -> false;
  422.         };
  423.     }
  424.  
  425.     public boolean isActivelySittingTransition() {
  426.         return switch (this.getState()) {
  427.             case SIT_DOWN, STAND_UP -> this.inStateTicks < this.getState().animationDuration();
  428.             default -> false;
  429.         };
  430.     }
  431.  
  432.     private boolean getFlag(int id) {
  433.         return (this.entityData.get(DATA_FLAGS_ID) & id) != 0;
  434.     }
  435.  
  436.     private void setFlag(int id, boolean value) {
  437.         byte flag = this.entityData.get(DATA_FLAGS_ID);
  438.         this.entityData.set(DATA_FLAGS_ID, value ? (byte)(flag | id) : (byte)(flag & ~id));
  439.     }
  440.  
  441.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  442.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  443.  
  444.     public boolean isFloating() {
  445.         return this.getFlag(1 << 1);
  446.     }
  447.  
  448.     public void setFloating(boolean value) {
  449.         this.setFlag(1 << 1, value);
  450.     }
  451.  
  452.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  453.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  454.  
  455.     public boolean isSwimming() {
  456.         return this.getFlag(1 << 2);
  457.     }
  458.  
  459.     public void setSwimming(boolean value) {
  460.         this.setFlag(1 << 2, value);
  461.     }
  462.  
  463.     /// once it's been long enough since it last swam around the sea otter will stop floating and start swimming.
  464.     public boolean wantsToSwimAround() {
  465.         return this.hasBeenLongEnoughSinceLastSwam();
  466.     }
  467.  
  468.     public boolean hasBeenLongEnoughSinceLastSwam() {
  469.         return this.ticksSinceLastSwam >= 400;
  470.     }
  471.  
  472.     public void resetTicksSinceLastSwam() {
  473.         this.ticksSinceLastSwam = 0;
  474.     }
  475.  
  476.     public boolean hasBeenSwimmingLongEnough() {
  477.         return this.ticksSpentSwimming >= 200;
  478.     }
  479.  
  480.     public void resetTicksSpentSwimming() {
  481.         this.ticksSpentSwimming = 0;
  482.     }
  483.  
  484.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  485.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  486.  
  487.     public boolean isSitting() {
  488.         return this.getFlag(1 << 3);
  489.     }
  490.  
  491.     public void setSitting(boolean value) {
  492.         this.setFlag(1 << 3, value);
  493.     }
  494.  
  495.     public void sitDown() {
  496.         if (!this.isSitting() && this.onGround() && !this.isInWater()) {
  497.             this.setSitting(true);
  498.             this.switchToState(State.SIT_DOWN);
  499.         }
  500.     }
  501.  
  502.     public void standUp() {
  503.         if (this.isSitting()) {
  504.             this.setSitting(false);
  505.             this.switchToState(State.STAND_UP);
  506.         }
  507.     }
  508.  
  509.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  510.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  511.  
  512.     @Nullable
  513.     public BlockPos getSurfacePos() {
  514.         return this.surfacePos;
  515.     }
  516.  
  517.     public void setSurfacePos(BlockPos pos) {
  518.         this.surfacePos = pos;
  519.     }
  520.  
  521.     public boolean needsToSurface() {
  522.         return this.getFlag(1 << 4);
  523.     }
  524.  
  525.     public void setNeedsToSurface(boolean value) {
  526.         this.setFlag(1 << 4, value);
  527.     }
  528.  
  529.     public boolean hasReachedSurface() {
  530.         return this.getFlag(1 << 5);
  531.     }
  532.  
  533.     public void setReachedSurface(boolean value) {
  534.         this.setFlag(1 << 5, value);
  535.     }
  536.  
  537.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  538.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  539.  
  540.     @Override
  541.     protected PathNavigation createNavigation(Level level) {
  542.         return new SeaOtter.SeaOtterPathNavigation(this, level);
  543.     }
  544.  
  545.     @Override
  546.     protected BodyRotationControl createBodyControl() {
  547.         return new SeaOtter.SeaOtterBodyRotationControl(this);
  548.     }
  549.  
  550.     @Override
  551.     public void travel(Vec3 pos) {
  552.         if (this.refuseToMove()) {
  553.             this.setDeltaMovement(this.getDeltaMovement().multiply(0.0, 1.0, 0.0));
  554.             pos = pos.multiply(0.0, 1.0, 0.0);
  555.         }
  556.  
  557.         super.travel(pos);
  558.     }
  559.  
  560.     public void pathfindDirectlyTowards(BlockPos pos, double speed) {
  561.         this.navigation.setMaxVisitedNodesMultiplier(10.0F);
  562.         this.navigation.moveTo(pos.getX() + 0.5D, pos.getY(), pos.getZ() + 0.5D, speed);
  563.     }
  564.  
  565.     public boolean refuseToMove() {
  566.         return (this.isSitting() || this.isActivelySittingTransition()) || (this.getState() == State.FLOATING);
  567.     }
  568.  
  569.     public boolean wantsToMove() {
  570.         return !this.getNavigation().isDone() || this.getTarget() != null || this.moveControl.hasWanted();
  571.     }
  572.  
  573.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  574.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  575.  
  576.     @Override
  577.     public Vec3 getViewVector(float ticks) {
  578.         Vec3 view = super.getViewVector(ticks);
  579.         if (this.isFloating()) {
  580.             return view.reverse();
  581.         }
  582.         return view;
  583.     }
  584.  
  585.     @Override
  586.     public int getMaxHeadYRot() {
  587.         if (this.isFloating()) {
  588.             return 2;
  589.         } else if (this.isSitting()) {
  590.             return 20;
  591.         } else {
  592.             return super.getMaxHeadYRot();
  593.         }
  594.     }
  595.  
  596.     @Override
  597.     public int getMaxHeadXRot() {
  598.         if (this.isFloating()) {
  599.             return 20;
  600.         } else if (this.isSitting()) {
  601.             return 20;
  602.         } else {
  603.             return super.getMaxHeadXRot();
  604.         }
  605.     }
  606.  
  607.     @Override
  608.     public boolean isFood(ItemStack stack) {
  609.         return stack.is(ItemTags.FISHES);
  610.     }
  611.  
  612.     @Override
  613.     public InteractionResult mobInteract(Player player, InteractionHand hand) {
  614.         if (!this.level().isClientSide()) {
  615.             if (player.getItemInHand(hand).isEmpty()) {
  616.                 this.setSitting(false);
  617.                 this.setFloating(true);
  618.                 this.switchToState(State.START_FLOATING);
  619.                 System.out.println("ticksSinceLastSwam: " + this.ticksSinceLastSwam);
  620.                 System.out.println("ticksSpentSwimming: " + this.ticksSpentSwimming);
  621.             }
  622.         }
  623.         return super.mobInteract(player, hand);
  624.     }
  625.  
  626.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  627.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  628.  
  629.     public static class SwimToSurfaceGoal extends Goal {
  630.         private final SeaOtter seaOtter;
  631.         @Nullable
  632.         private BlockPos blockPos;
  633.  
  634.         public SwimToSurfaceGoal(SeaOtter mob) {
  635.             this.seaOtter = mob;
  636.             this.setFlags(EnumSet.of(Flag.MOVE, Flag.LOOK));
  637.         }
  638.  
  639.         @Override
  640.         public boolean canUse() {
  641.             if (this.seaOtter.isFloating()) {
  642.                 return false;
  643.             } else if (this.seaOtter.hasBeenLongEnoughSinceLastSwam()) { /// meaning the sea otter should be swimming.
  644.                 return false;
  645.             }
  646.             return this.seaOtter.needsToSurface();
  647.         }
  648.  
  649.         @Override
  650.         public boolean canContinueToUse() {
  651.             return !this.seaOtter.hasReachedSurface();
  652.         }
  653.  
  654.         @Override
  655.         public void start() {
  656.             if (this.findNearestPos().isPresent()) {
  657.                 this.blockPos = this.findNearestPos().get();
  658.                 this.seaOtter.setSurfacePos(this.blockPos);
  659.  
  660.                 System.out.println("swimming to surface at : " + this.seaOtter.getSurfacePos());
  661.             }
  662.         }
  663.  
  664.         @Override
  665.         public void stop() {
  666.             this.seaOtter.setNeedsToSurface(false);
  667.             this.seaOtter.getNavigation().stop();
  668.  
  669.             System.out.println("reached surface");
  670.         }
  671.  
  672.         @Override
  673.         public void tick() {
  674.             this.seaOtter.setReachedSurface(false);
  675.  
  676.             if (this.blockPos == null) {
  677.                 if (this.findNearestPos().isPresent()) {
  678.                     this.blockPos = this.findNearestPos().get();
  679.                 }
  680.             } else {
  681.                 this.seaOtter.pathfindDirectlyTowards(this.blockPos, 2.5F);
  682.                 this.seaOtter.getLookControl().setLookAt(Vec3.atLowerCornerOf(this.blockPos));
  683.  
  684.                 double distanceToSurface = this.blockPos.getY() - this.seaOtter.getEyePosition().y();
  685.                 if (this.seaOtter.getEyeY() < this.blockPos.getY() && this.blockPos.distToCenterSqr(this.seaOtter.position()) <= 5.0D) {
  686.                     this.seaOtter.push(0.0D, Math.min(0.03D, distanceToSurface * 0.05D), 0.0D);
  687.                     this.seaOtter.setSpeed(2.5F * (float) Math.max(0.3D, Math.min(1.0D, distanceToSurface)));
  688.                 }
  689.  
  690.                 if (Math.abs(distanceToSurface) <= 0.2D) {
  691.                     this.seaOtter.setDeltaMovement(Vec3.ZERO);
  692.                     this.seaOtter.setSpeed(0.0F);
  693.                     this.seaOtter.setYya(0.0F);
  694.  
  695.                     /// set that the sea otter has reached the surface, ending the goal and starting the float goal.
  696.                     this.seaOtter.setReachedSurface(true);
  697.                 }
  698.             }
  699.         }
  700.  
  701.         protected Optional<BlockPos> findNearestPos() {
  702.             BlockPos pos = this.seaOtter.blockPosition();
  703.             BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos();
  704.  
  705.             for (int i = 0; (double)i <= 24; i = i > 0 ? -i : 1 - i) {
  706.                 for (int j = 0; (double)j < 24; ++j) {
  707.                     for (int k = 0; k <= j; k = k > 0 ? -k : 1 - k) {
  708.                         for (int l = k < j && k > -j ? j : 0; l <= j; l = l > 0 ? -l : 1 - l) {
  709.                             mutablePos.setWithOffset(pos, k, i - 1, l);
  710.  
  711.                             if (this.seaOtter.isWithinRestriction(mutablePos) && this.isValidTarget(this.seaOtter.level(), mutablePos)) {
  712.                                 return Optional.of(mutablePos);
  713.                             }
  714.                         }
  715.                     }
  716.                 }
  717.             }
  718.             return Optional.empty();
  719.         }
  720.  
  721.         protected boolean isValidTarget(LevelReader level, BlockPos pos) {
  722.             return level.getBlockState(pos.below()).is(Blocks.WATER) && level.getBlockState(pos).isAir();
  723.         }
  724.     }
  725.  
  726.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  727.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  728.  
  729.     public static class FloatingGoal extends Goal {
  730.         private final SeaOtter seaOtter;
  731.         private Phase phase;
  732.  
  733.         public FloatingGoal(SeaOtter mob) {
  734.             this.seaOtter = mob;
  735.             this.setFlags(EnumSet.of(Flag.MOVE));
  736.         }
  737.  
  738.         @Override
  739.         public boolean canUse() {
  740.             return this.seaOtter.hasReachedSurface() && !this.seaOtter.wantsToSwimAround();
  741.         }
  742.  
  743.         @Override
  744.         public boolean canContinueToUse() {
  745.             return this.phase != Phase.SWIMMING;
  746.         }
  747.  
  748.         @Override
  749.         public void start() {
  750.             if (!this.seaOtter.isFloating()) {
  751.                 this.seaOtter.setReachedSurface(false);
  752.                 this.seaOtter.resetTicksSinceLastSwam();
  753.  
  754.                 this.seaOtter.setFloating(true);
  755.                 this.seaOtter.switchToState(State.START_FLOATING);
  756.                 this.phase = Phase.START_FLOATING;
  757.  
  758.                 System.out.println("started floating");
  759.             }
  760.         }
  761.  
  762.         @Override
  763.         public void stop() {
  764.             this.seaOtter.setReachedSurface(false);
  765.             this.seaOtter.setNeedsToSurface(false);
  766.             this.seaOtter.setFloating(false);
  767.             this.seaOtter.switchToState(State.SWIMMING);
  768.  
  769.             System.out.println("finished floating");
  770.         }
  771.  
  772.         @Override
  773.         public void tick() {
  774.             switch (this.phase) {
  775.                 case START_FLOATING -> {
  776.                     if (this.seaOtter.inStateTicks >= State.START_FLOATING.animationDuration()) {
  777.                         this.seaOtter.switchToState(State.FLOATING);
  778.                         this.phase = Phase.FLOATING;
  779.                     }
  780.                 }
  781.                 case FLOATING -> {
  782.                     if (this.seaOtter.inStateTicks >= State.FLOATING.animationDuration() && this.wantsToBeDone()) {
  783.                         System.out.println("stopping floating");
  784.                         this.seaOtter.switchToState(State.STOP_FLOATING);
  785.                         this.phase = Phase.STOP_FLOATING;
  786.                     }
  787.                 }
  788.                 case STOP_FLOATING -> {
  789.                     if (this.seaOtter.inStateTicks >= State.STOP_FLOATING.animationDuration()) {
  790.                         this.seaOtter.switchToState(State.SWIMMING);
  791.                         this.phase = Phase.SWIMMING;
  792.                     }
  793.                 }
  794.             }
  795.         }
  796.  
  797.         private boolean wantsToBeDone() {
  798.             return this.seaOtter.wantsToSwimAround();
  799.         }
  800.  
  801.         enum Phase {
  802.             SWIMMING,
  803.             START_FLOATING,
  804.             FLOATING,
  805.             STOP_FLOATING
  806.         }
  807.     }
  808.  
  809.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  810.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  811.  
  812.     public static class SwimAroundGoal extends RandomSwimmingGoal {
  813.         private final SeaOtter seaOtter;
  814.  
  815.         public SwimAroundGoal(SeaOtter mob, double speed, int interval) {
  816.             super(mob, speed, interval);
  817.             this.seaOtter = mob;
  818.             this.setFlags(EnumSet.of(Flag.MOVE, Flag.LOOK));
  819.         }
  820.  
  821.         @Override
  822.         public boolean canUse() {
  823.             if (this.seaOtter.needsToSurface()) {
  824.                 return false;
  825.             } else if (this.seaOtter.isFloating()) {
  826.                 return false;
  827.             }
  828.  
  829.             return super.canUse();
  830.         }
  831.  
  832.         @Override
  833.         public boolean canContinueToUse() {
  834.             if (this.seaOtter.needsToSurface()) {
  835.                 return false;
  836.             } else if (this.seaOtter.hasBeenSwimmingLongEnough()) {
  837.                 return false;
  838.             }
  839.  
  840.             return super.canContinueToUse();
  841.         }
  842.  
  843.         @Override
  844.         public void start() {
  845.             super.start();
  846.             this.seaOtter.setSwimming(true);
  847.  
  848.             System.out.println("started swimming");
  849.         }
  850.  
  851.         @Override
  852.         public void stop() {
  853.             super.stop();
  854.             if (this.seaOtter.hasBeenSwimmingLongEnough()) {
  855.                 this.seaOtter.setNeedsToSurface(true);
  856.                 this.seaOtter.resetTicksSinceLastSwam();
  857.                 this.seaOtter.resetTicksSpentSwimming();
  858.  
  859.                 System.out.println("stopped swimming");
  860.             }
  861.         }
  862.  
  863.         @Override
  864.         public void tick() {
  865.             this.seaOtter.ticksSpentSwimming++;
  866.         }
  867.     }
  868.  
  869.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  870.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  871.  
  872.     public static class SeaOtterLookAtPlayerGoal extends LookAtPlayerGoal {
  873.         private final SeaOtter seaOtter;
  874.  
  875.         public SeaOtterLookAtPlayerGoal(SeaOtter mob, float distance) {
  876.             super(mob, Player.class, distance);
  877.             this.seaOtter = mob;
  878.         }
  879.  
  880.         @Override
  881.         public boolean canUse() {
  882.             return super.canUse() && !this.seaOtter.isSwimming() && !this.seaOtter.isActivelyInFloatTransition();
  883.         }
  884.     }
  885.  
  886.     public static class SeaOtterTemptGoal extends TemptGoal {
  887.         private final SeaOtter seaOtter;
  888.  
  889.         public SeaOtterTemptGoal(SeaOtter mob, double speed, Predicate<ItemStack> items) {
  890.             super(mob, speed, items, false);
  891.             this.seaOtter = mob;
  892.         }
  893.     }
  894.  
  895.     public static class SeaOtterRandomLookAroundGoal extends RandomLookAroundGoal {
  896.         private final SeaOtter seaOtter;
  897.  
  898.         public SeaOtterRandomLookAroundGoal(SeaOtter mob) {
  899.             super(mob);
  900.             this.seaOtter = mob;
  901.         }
  902.  
  903.         @Override
  904.         public boolean canUse() {
  905.             return super.canUse() && !this.seaOtter.isSwimming();
  906.         }
  907.     }
  908.  
  909.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  910.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  911.  
  912.     public static class SeaOtterMoveControl extends MoveControl {
  913.         private final SeaOtter seaOtter;
  914.  
  915.         public SeaOtterMoveControl(SeaOtter mob) {
  916.             super(mob);
  917.             this.seaOtter = mob;
  918.         }
  919.  
  920.         @Override
  921.         public void tick() {
  922.             if (this.seaOtter.isSleeping()) return;
  923.  
  924.             if (this.seaOtter.isInWater() && !this.seaOtter.isFloating()) {
  925.                 this.seaOtter.setDeltaMovement(this.seaOtter.getDeltaMovement().add(this.seaOtter.getLookAngle().scale(this.seaOtter.isFloating() ? 0.002F : 0.005F)));
  926.  
  927.                 if (this.operation == MoveControl.Operation.MOVE_TO && !this.seaOtter.getNavigation().isDone()) {
  928.                     double d0 = this.wantedX - this.seaOtter.getX();
  929.                     double d1 = this.wantedY - this.seaOtter.getY();
  930.                     double d2 = this.wantedZ - this.seaOtter.getZ();
  931.                     double d3 = d0 * d0 + d1 * d1 + d2 * d2;
  932.                     if (d3 < (double) 2.5000003E-7F) {
  933.                         this.seaOtter.setZza(0.0F);
  934.                     } else {
  935.                         float f = (float) (Mth.atan2(d2, d0) * (double) (180F / (float) Math.PI)) - 90.0F;
  936.                         this.seaOtter.setYRot(this.rotlerp(this.seaOtter.getYRot(), f, (float) 10));
  937.                         this.seaOtter.yBodyRot = this.seaOtter.getYRot();
  938.                         this.seaOtter.yHeadRot = this.seaOtter.getYRot();
  939.                         float speed = (float) (this.speedModifier * this.seaOtter.getAttributeValue(Attributes.MOVEMENT_SPEED));
  940.                         this.seaOtter.setSpeed(speed * 0.02F);
  941.  
  942.                         double d4 = Math.sqrt(d0 * d0 + d2 * d2);
  943.                         if (Math.abs(d1) > (double) 1.0E-5F || Math.abs(d4) > (double) 1.0E-5F) {
  944.                             float f3 = -((float) (Mth.atan2(d1, d4) * (double) (180F / (float) Math.PI)));
  945.                             f3 = Mth.clamp(Mth.wrapDegrees(f3), (float) (-85), (float) 85);
  946.                             this.seaOtter.setXRot(this.rotlerp(this.seaOtter.getXRot(), f3, 5.0F));
  947.                         }
  948.  
  949.                         if (d1 > 0.0D && d0 * d0 + d2 * d2 < 4.0F && d1 <= 1.0D && this.seaOtter.level().getBlockState(BlockPos.containing(this.wantedX, this.wantedY, this.wantedZ)).getFluidState().isEmpty()) {
  950.                             this.seaOtter.getJumpControl().jump();
  951.                             this.seaOtter.setSpeed(speed);
  952.                         }
  953.  
  954.                         float f6 = Mth.cos(this.seaOtter.getXRot() * ((float) Math.PI / 180F));
  955.                         float f4 = Mth.sin(this.seaOtter.getXRot() * ((float) Math.PI / 180F));
  956.                         this.seaOtter.zza = f6 * speed;
  957.                         this.seaOtter.yya = -f4 * speed;
  958.                     }
  959.                 } else {
  960.                     this.seaOtter.setSpeed(0.0F);
  961.                     this.seaOtter.setXxa(0.0F);
  962.                     this.seaOtter.setYya(0.0F);
  963.                     this.seaOtter.setZza(0.0F);
  964.                 }
  965.             } else {
  966.                 if (this.hasWanted() && this.seaOtter.isSitting()) {
  967.                     this.seaOtter.standUp();
  968.                 }
  969.  
  970.                 if (!this.seaOtter.isFloating()) {
  971.                     super.tick();
  972.                 }
  973.             }
  974.         }
  975.     }
  976.  
  977.     public static class SeaOtterLookControl extends LookControl {
  978.         private final SeaOtter seaOtter;
  979.  
  980.         public SeaOtterLookControl(SeaOtter mob) {
  981.             super(mob);
  982.             this.seaOtter = mob;
  983.         }
  984.  
  985.         @Override
  986.         protected Optional<Float> getXRotD() {
  987.             if (this.seaOtter.isFloating() && super.getXRotD().isPresent()) {
  988.                 return Optional.of(-super.getXRotD().get());
  989.             }
  990.             return super.getXRotD();
  991.         }
  992.  
  993.         @Override
  994.         protected Optional<Float> getYRotD() {
  995.             if (this.seaOtter.isFloating() && super.getYRotD().isPresent()) {
  996.                 return Optional.of(Mth.wrapDegrees(super.getYRotD().get() + 160.0F));
  997.             }
  998.             return super.getYRotD();
  999.         }
  1000.  
  1001.         @Override
  1002.         protected boolean resetXRotOnTick() {
  1003.             return this.seaOtter.isActivelyInFloatTransition();
  1004.         }
  1005.  
  1006.         @Override
  1007.         public void tick() {
  1008.             if (this.resetXRotOnTick()) {
  1009.                 this.seaOtter.setXRot(0.0F);
  1010.                 return;
  1011.             }
  1012.  
  1013.             if (this.seaOtter.isInWater() && this.seaOtter.isUnderWater()) {
  1014.                 if (this.lookAtCooldown > 0) {
  1015.                     this.lookAtCooldown--;
  1016.                     this.getYRotD().ifPresent(i -> this.seaOtter.yHeadRot = this.rotateTowards(this.seaOtter.yHeadRot, i + 20.0F, this.yMaxRotSpeed));
  1017.                     this.getXRotD().ifPresent(i -> this.seaOtter.setXRot(this.rotateTowards(this.seaOtter.getXRot(), i + 10.0F, this.xMaxRotAngle)));
  1018.                 } else {
  1019.                     if (this.seaOtter.getNavigation().isDone()) {
  1020.                         this.seaOtter.setXRot(this.rotateTowards(this.seaOtter.getXRot(), 0.0F, 5.0F));
  1021.                     }
  1022.                     this.seaOtter.yHeadRot = this.rotateTowards(this.seaOtter.yHeadRot, this.seaOtter.yBodyRot, this.yMaxRotSpeed);
  1023.                 }
  1024.  
  1025.                 float f = Mth.wrapDegrees(this.seaOtter.yHeadRot - this.seaOtter.yBodyRot);
  1026.                 if (f < (float)(-10)) {
  1027.                     this.seaOtter.yBodyRot -= 4.0F;
  1028.                 } else if (f > (float)10) {
  1029.                     this.seaOtter.yBodyRot += 4.0F;
  1030.                 }
  1031.             } else {
  1032.                 super.tick();
  1033.             }
  1034.         }
  1035.     }
  1036.  
  1037.     public static class SeaOtterBodyRotationControl extends BodyRotationControl {
  1038.         private final SeaOtter seaOtter;
  1039.  
  1040.         public SeaOtterBodyRotationControl(SeaOtter mob) {
  1041.             super(mob);
  1042.             this.seaOtter = mob;
  1043.         }
  1044.  
  1045.         @Override
  1046.         public void clientTick() {
  1047.             if (!this.seaOtter.refuseToMove() && !this.seaOtter.isFloating()) {
  1048.                 super.clientTick();
  1049.             }
  1050.         }
  1051.     }
  1052.  
  1053.     public static class SeaOtterPathNavigation extends AmphibiousPathNavigation {
  1054.         private final SeaOtter seaOtter;
  1055.  
  1056.         public SeaOtterPathNavigation(SeaOtter mob, Level level) {
  1057.             super(mob, level);
  1058.             this.seaOtter = mob;
  1059.             this.setCanFloat(true);
  1060.         }
  1061.  
  1062.         @Override
  1063.         protected PathFinder createPathFinder(int nodes) {
  1064.             this.nodeEvaluator = new AmphibiousNodeEvaluator(true);
  1065.             return new PathFinder(this.nodeEvaluator, nodes);
  1066.         }
  1067.  
  1068.         @Override
  1069.         public boolean isStableDestination(BlockPos pos) {
  1070.             BlockState belowState = this.level.getBlockState(pos.below());
  1071.             if (this.seaOtter.isInWater()) {
  1072.                 return !(belowState.isAir() || belowState.getFluidState().is(FluidTags.WATER));
  1073.             } else {
  1074.                 return !belowState.isAir();
  1075.             }
  1076.         }
  1077.     }
  1078.  
  1079.     public enum State implements StringRepresentable {
  1080.         NOTHING("nothing", 0, 0),
  1081.         SWIMMING_IDLE("swimming_idle", 1, 50),
  1082.         SWIMMING("swimming", 2, 40),
  1083.         TWIRL_WHILE_SWIMMING("twirl_while_swimming", 3, 30),
  1084.         FLOATING("floating", 4, 50),
  1085.         START_FLOATING("start_floating", 5, 30),
  1086.         STOP_FLOATING("stop_floating", 6, 25),
  1087.         SLEEPING_WHILE_FLOATING("sleeping_while_floating", 7, 0),
  1088.         EATING_WHILE_FLOATING("eating_while_floating", 8, 50),
  1089.         SIT_DOWN("sit_down", 9, 30),
  1090.         SITTING_IDLE("sitting_idle", 10, 60),
  1091.         STAND_UP("stand_up", 11, 30),
  1092.         STANDING_IDLE("standing_idle", 12, 60),
  1093.         WALKING("walking", 13, 45);
  1094.  
  1095.         private static final IntFunction<SeaOtter.State> BY_ID = ByIdMap.continuous(SeaOtter.State::id, values(), ByIdMap.OutOfBoundsStrategy.ZERO);
  1096.         public static final StreamCodec<ByteBuf, SeaOtter.State> STREAM_CODEC = ByteBufCodecs.idMapper(BY_ID, SeaOtter.State::id);
  1097.         private final String name;
  1098.         private final int id;
  1099.         private final int animationDuration;
  1100.  
  1101.         State(final String name, final int id, final int animationDuration) {
  1102.             this.name = name;
  1103.             this.id = id;
  1104.             this.animationDuration = animationDuration;
  1105.         }
  1106.  
  1107.         public static SeaOtter.State fromName(String name) {
  1108.             return StringRepresentable.fromEnum(SeaOtter.State::values).byName(name, NOTHING);
  1109.         }
  1110.  
  1111.         @Override
  1112.         public String getSerializedName() {
  1113.             return this.name;
  1114.         }
  1115.  
  1116.         private int id() {
  1117.             return this.id;
  1118.         }
  1119.  
  1120.         public int animationDuration() {
  1121.             return this.animationDuration;
  1122.         }
  1123.     }
  1124.  
  1125.     /**
  1126.      * todo: Current Actions
  1127.      *
  1128.      * actions decide what the entity wants to do.
  1129.      *      - i.e. a sea otter who wants to swim, if they're currently floating, once that is finished they will start swimming.
  1130.      *
  1131.      * que actions so when the current one is finished they will start the next one.
  1132.      *
  1133.      * actions will be paired with a reasoning.
  1134.      *      - i.e. the action "wants to swim" can have the reasoning for why it's doing that, being able to control what "wants to swim" will do exactly.
  1135.      *
  1136.      * each action has a base length, so like they can only start the next one if they're done with their current one. this is overridden in the case of
  1137.      * an emergency, like if they need to run away, or are gonna drown and need to stop looking for fish.
  1138.      */
  1139.     private enum CoreStates {
  1140.         ON_LAND,
  1141.         FLOATING_ON_SURFACE,
  1142.         SURFACE_SWIMMING,
  1143.         DEEP_SEA_SWIMMING
  1144.     }
  1145.  
  1146.     private enum ActionReasons {
  1147.         NEEDS_AIR,
  1148.         WANTS_TO_FLOAT,
  1149.         IS_BEDTIME
  1150.     }
  1151.  
  1152. }
Advertisement
Add Comment
Please, Sign In to add comment