jayhillx

Sea Otter 6

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