jayhillx

Sea Otter 4

Jul 29th, 2025
124
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 14.68 KB | None | 0 0
  1. package com.mysticsbiomes.common.entity;
  2.  
  3. import com.mysticsbiomes.init.MysticBlocks;
  4. import com.mysticsbiomes.init.MysticEntities;
  5. import io.netty.buffer.ByteBuf;
  6. import net.minecraft.nbt.CompoundTag;
  7. import net.minecraft.network.codec.ByteBufCodecs;
  8. import net.minecraft.network.codec.StreamCodec;
  9. import net.minecraft.network.syncher.EntityDataAccessor;
  10. import net.minecraft.network.syncher.EntityDataSerializer;
  11. import net.minecraft.network.syncher.EntityDataSerializers;
  12. import net.minecraft.network.syncher.SynchedEntityData;
  13. import net.minecraft.server.level.ServerLevel;
  14. import net.minecraft.tags.ItemTags;
  15. import net.minecraft.util.ByIdMap;
  16. import net.minecraft.util.StringRepresentable;
  17. import net.minecraft.world.InteractionHand;
  18. import net.minecraft.world.InteractionResult;
  19. import net.minecraft.world.entity.*;
  20. import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
  21. import net.minecraft.world.entity.ai.attributes.Attributes;
  22. import net.minecraft.world.entity.ai.control.LookControl;
  23. import net.minecraft.world.entity.ai.control.MoveControl;
  24. import net.minecraft.world.entity.ai.goal.*;
  25. import net.minecraft.world.entity.animal.Animal;
  26. import net.minecraft.world.entity.player.Player;
  27. import net.minecraft.world.item.ItemStack;
  28. import net.minecraft.world.item.crafting.Ingredient;
  29. import net.minecraft.world.level.Level;
  30. import net.minecraft.world.level.block.Blocks;
  31.  
  32. import java.util.function.IntFunction;
  33.  
  34. /**
  35.  * can be tamed as pets to defend you in the water.
  36.  * they can help you find treasures, or collect fish.
  37.  * they can help you swim faster like dolphins.
  38.  * they mostly float around, unless they are feeling playful or want to get food.
  39.  * they will fall asleep at night, holding another sea otters hand nearby.
  40.  * their babies will rest on their belly until they age up.
  41.  */
  42. public class SeaOtter extends Animal {
  43.     public static final EntityDataSerializer<State> SEA_OTTER_STATE = EntityDataSerializer.forValueType(SeaOtter.State.STREAM_CODEC);
  44.     private static final EntityDataAccessor<State> DATA_STATE_ID = SynchedEntityData.defineId(SeaOtter.class, SEA_OTTER_STATE);
  45.     private static final EntityDataAccessor<Boolean> DATA_FLOATING_ID = SynchedEntityData.defineId(SeaOtter.class, EntityDataSerializers.BOOLEAN);
  46.  
  47.     public SeaOtter.StartFloatingGoal startFloatingGoal;
  48.  
  49.     public final AnimationState idleInWaterAnimationState = new AnimationState();
  50.     public final AnimationState swimmingAnimationState = new AnimationState();
  51.     public final AnimationState glideWhileSwimmingAnimationState = new AnimationState();
  52.     public final AnimationState twirlWhileSwimmingAnimationState = new AnimationState();
  53.     public final AnimationState floatingAnimationState = new AnimationState();
  54.     public final AnimationState swimmingWhileFloatingAnimationState = new AnimationState();
  55.     public final AnimationState twirlWhileFloatingAnimationState = new AnimationState();
  56.     public final AnimationState startFloatingAnimationState = new AnimationState();
  57.     public final AnimationState stopFloatingAnimationState = new AnimationState();
  58.     public final AnimationState idleOnLandAnimationState = new AnimationState();
  59.     public final AnimationState walkingAnimationState = new AnimationState();
  60.     public final AnimationState startWalkingAnimationState = new AnimationState();
  61.     public final AnimationState stopWalkingAnimationState = new AnimationState();
  62.     private long inStateTicks = 0L;
  63.  
  64.     public SeaOtter(EntityType<? extends SeaOtter> type, Level level) {
  65.         super(type, level);
  66.         this.moveControl = new MoveControl(this);
  67.         this.lookControl = new LookControl(this);
  68.     }
  69.  
  70.     public static AttributeSupplier.Builder createAttributes() {
  71.         return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 16.0F).add(Attributes.MOVEMENT_SPEED, 1.0D);
  72.     }
  73.  
  74.     @Override
  75.     protected void registerGoals() {
  76.         this.startFloatingGoal = new SeaOtter.StartFloatingGoal(this);
  77.         this.goalSelector.addGoal(0, this.startFloatingGoal);
  78.         this.goalSelector.addGoal(1, new TemptGoal(this, 1.0D, (stack) -> stack.is(ItemTags.FISHES), false));
  79.         this.goalSelector.addGoal(2, new LookAtPlayerGoal(this, Player.class, 6.0F));
  80.         this.goalSelector.addGoal(3, new RandomLookAroundGoal(this));
  81.         //this.goalSelector.addGoal(3, new WaterAvoidingRandomStrollGoal(this, 0.2D));
  82.     }
  83.  
  84.     @Override
  85.     protected void defineSynchedData(SynchedEntityData.Builder builder) {
  86.         super.defineSynchedData(builder);
  87.         builder.define(DATA_STATE_ID, State.IDLE_IN_WATER);
  88.         builder.define(DATA_FLOATING_ID, false);
  89.     }
  90.  
  91.     @Override
  92.     public void addAdditionalSaveData(CompoundTag tag) {
  93.         super.addAdditionalSaveData(tag);
  94.         tag.putString("State", this.getState().getSerializedName());
  95.         tag.putBoolean("Floating", this.isFloating());
  96.     }
  97.  
  98.     @Override
  99.     public void readAdditionalSaveData(CompoundTag tag) {
  100.         super.readAdditionalSaveData(tag);
  101.         this.switchToState(SeaOtter.State.fromName(tag.getString("State")));
  102.         this.setFloating(tag.getBoolean("Floating"));
  103.     }
  104.  
  105.     @Override
  106.     public AgeableMob getBreedOffspring(ServerLevel level, AgeableMob mob) {
  107.         return MysticEntities.SEA_OTTER.get().create(level);
  108.     }
  109.  
  110.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  111.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  112.  
  113.     @Override
  114.     public void tick() {
  115.         super.tick();
  116.         if (this.level().isClientSide()) {
  117.             this.setupSwimmingAnimationStates();
  118.             this.setupFloatingAnimationStates();
  119.             this.setupWalkingAnimationStates();
  120.         }
  121.  
  122.         this.inStateTicks++;
  123.     }
  124.  
  125.     @Override
  126.     public void aiStep() {
  127.         super.aiStep();
  128.     }
  129.  
  130.     @Override
  131.     public void onSyncedDataUpdated(EntityDataAccessor<?> accessor) {
  132.         if (DATA_STATE_ID.equals(accessor)) {
  133.             this.inStateTicks = 0L;
  134.         }
  135.  
  136.         super.onSyncedDataUpdated(accessor);
  137.     }
  138.  
  139.     public SeaOtter.State getState() {
  140.         return this.entityData.get(DATA_STATE_ID);
  141.     }
  142.  
  143.     public void switchToState(SeaOtter.State state) {
  144.         this.entityData.set(DATA_STATE_ID, state);
  145.     }
  146.  
  147.     private void setupSwimmingAnimationStates() {
  148.         switch (this.getState()) {
  149.             case IDLE_IN_WATER:
  150.                 this.idleInWaterAnimationState.stop();
  151.                 break;
  152.             case GLIDE_WHILE_SWIMMING:
  153.                 this.swimmingAnimationState.stop();
  154.                 this.glideWhileSwimmingAnimationState.startIfStopped(this.tickCount);
  155.                 break;
  156.             case TWIRL_WHILE_SWIMMING:
  157.                 this.twirlWhileSwimmingAnimationState.startIfStopped(this.tickCount);
  158.                 break;
  159.         }
  160.     }
  161.  
  162.     private void setupFloatingAnimationStates() {
  163.         switch (this.getState()) {
  164.             case START_FLOATING:
  165.                 this.idleInWaterAnimationState.stop();
  166.                 this.swimmingAnimationState.stop();
  167.                 this.stopFloatingAnimationState.stop();
  168.                 this.startFloatingAnimationState.startIfStopped(this.tickCount);
  169.                 break;
  170.             case FLOATING:
  171.                 this.idleInWaterAnimationState.stop();
  172.                 this.startFloatingAnimationState.stop();
  173.                 this.stopFloatingAnimationState.stop();
  174.                 this.floatingAnimationState.startIfStopped(this.tickCount);
  175.                 break;
  176.             case STOP_FLOATING:
  177.                 this.idleInWaterAnimationState.stop();
  178.                 this.floatingAnimationState.stop();
  179.                 this.startFloatingAnimationState.stop();
  180.                 this.stopFloatingAnimationState.start(this.tickCount);
  181.                 break;
  182.             case SWIMMING_WHILE_FLOATING:
  183.                 this.swimmingWhileFloatingAnimationState.startIfStopped(this.tickCount);
  184.                 break;
  185.             case TWIRL_WHILE_FLOATING:
  186.                 this.twirlWhileFloatingAnimationState.startIfStopped(this.tickCount);
  187.                 break;
  188.         }
  189.     }
  190.  
  191.     private void setupWalkingAnimationStates() {
  192.         switch (this.getState()) {
  193.             case IDLE_ON_LAND:
  194.                 this.idleOnLandAnimationState.stop();
  195.                 break;
  196.             case WALKING:
  197.                 this.idleOnLandAnimationState.stop();
  198.                 this.walkingAnimationState.startIfStopped(this.tickCount);
  199.                 break;
  200.             case START_WALKING:
  201.                 this.idleOnLandAnimationState.stop();
  202.                 this.startWalkingAnimationState.startIfStopped(this.tickCount);
  203.                 break;
  204.             case STOP_WALKING:
  205.                 this.walkingAnimationState.stop();
  206.                 this.stopWalkingAnimationState.startIfStopped(this.tickCount);
  207.                 break;
  208.         }
  209.     }
  210.  
  211.     public boolean isFloating() {
  212.         return this.entityData.get(DATA_FLOATING_ID);
  213.     }
  214.  
  215.     public void setFloating(boolean value) {
  216.         this.entityData.set(DATA_FLOATING_ID, value);
  217.     }
  218.  
  219.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  220.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  221.  
  222.     @Override
  223.     public InteractionResult mobInteract(Player player, InteractionHand hand) {
  224.  
  225.         if (player.getItemInHand(hand).isEmpty()) {
  226.             if (this.startFloatingGoal != null) {
  227.                 this.startFloatingGoal.flag = true;
  228.             }
  229.         }
  230.  
  231.         return super.mobInteract(player, hand);
  232.     }
  233.  
  234.     /// sounds
  235.  
  236.     @Override
  237.     public boolean isFood(ItemStack stack) {
  238.         return false;
  239.     }
  240.  
  241.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  242.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  243.  
  244.     public static class StartFloatingGoal extends Goal {
  245.         private final SeaOtter mob;
  246.         private Phase phase = Phase.NONE;
  247.         public boolean flag;
  248.  
  249.         public StartFloatingGoal(SeaOtter mob) {
  250.             this.mob = mob;
  251.         }
  252.  
  253.         @Override
  254.         public boolean canUse() {
  255.             return this.flag;
  256.         }
  257.  
  258.         @Override
  259.         public void start() {
  260.             this.mob.switchToState(State.START_FLOATING);
  261.             this.mob.inStateTicks = 0L;
  262.             this.phase = Phase.START_FLOATING;
  263.         }
  264.  
  265.         @Override
  266.         public boolean canContinueToUse() {
  267.             return this.phase != Phase.NONE;
  268.         }
  269.  
  270.         @Override
  271.         public void tick() {
  272.             switch (this.phase) {
  273.                 case START_FLOATING -> {
  274.                     if (this.mob.inStateTicks >= State.START_FLOATING.animationDuration()) {
  275.                         this.mob.switchToState(State.FLOATING);
  276.                         this.mob.setFloating(true);
  277.                         this.mob.inStateTicks = 0L;
  278.                         this.phase = Phase.FLOATING;
  279.                     }
  280.                 }
  281.                 case FLOATING -> {
  282.                     if (this.mob.inStateTicks >= State.FLOATING.animationDuration()) {
  283.                         this.mob.switchToState(State.STOP_FLOATING);
  284.                         this.mob.setFloating(true);
  285.                         this.mob.inStateTicks = 0L;
  286.                         this.phase = Phase.STOP_FLOATING;
  287.                     }
  288.                 }
  289.                 case STOP_FLOATING -> {
  290.                     if (this.mob.inStateTicks >= State.STOP_FLOATING.animationDuration()) {
  291.                         this.phase = Phase.NONE;
  292.                         this.mob.setFloating(true);
  293.                         this.flag = false;
  294.                     }
  295.                 }
  296.             }
  297.         }
  298.  
  299.         @Override
  300.         public void stop() {
  301.             // Ensure proper cleanup if interrupted
  302.             this.mob.switchToState(State.IDLE_IN_WATER);
  303.             this.mob.setFloating(false);
  304.             this.phase = Phase.NONE;
  305.             this.flag = false;
  306.         }
  307.  
  308.         enum Phase {
  309.             NONE,
  310.             START_FLOATING,
  311.             FLOATING,
  312.             STOP_FLOATING
  313.         }
  314.     }
  315.  
  316.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  317.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  318.  
  319.     public enum State implements StringRepresentable {
  320.         IDLE_IN_WATER("idle_in_water", 0, 50),
  321.         SWIMMING("swimming", 1, 40),
  322.         GLIDE_WHILE_SWIMMING("glide_while_swimming", 2, 40),
  323.         TWIRL_WHILE_SWIMMING("twirl_while_swimming", 3, 30),
  324.         FLOATING("floating", 4, 50),
  325.         START_FLOATING("start_floating", 5, 25),
  326.         STOP_FLOATING("stop_floating", 6, 35),
  327.         SWIMMING_WHILE_FLOATING("swimming_while_floating", 7, 50),
  328.         TWIRL_WHILE_FLOATING("twirl_while_floating", 8, 55),
  329.         IDLE_ON_LAND("idle_on_land", 9, 60),
  330.         WALKING("walking", 10, 45),
  331.         START_WALKING("start_walking", 11, 40),
  332.         STOP_WALKING("stop_walking", 12, 30);
  333.  
  334.         private static final IntFunction<SeaOtter.State> BY_ID = ByIdMap.continuous(SeaOtter.State::id, values(), ByIdMap.OutOfBoundsStrategy.ZERO);
  335.         public static final StreamCodec<ByteBuf, SeaOtter.State> STREAM_CODEC = ByteBufCodecs.idMapper(BY_ID, SeaOtter.State::id);
  336.         private final String name;
  337.         private final int id;
  338.         private final int animationDuration;
  339.  
  340.         State(final String name, final int id, final int animationDuration) {
  341.             this.name = name;
  342.             this.id = id;
  343.             this.animationDuration = animationDuration;
  344.         }
  345.  
  346.         public static SeaOtter.State fromName(String name) {
  347.             return StringRepresentable.fromEnum(SeaOtter.State::values).byName(name, IDLE_IN_WATER);
  348.         }
  349.  
  350.         @Override
  351.         public String getSerializedName() {
  352.             return this.name;
  353.         }
  354.  
  355.         private int id() {
  356.             return this.id;
  357.         }
  358.  
  359.         public int animationDuration() {
  360.             return this.animationDuration;
  361.         }
  362.     }
  363.    
  364. }
Advertisement
Add Comment
Please, Sign In to add comment