Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package com.mysticsbiomes.common.entity;
- import com.mysticsbiomes.init.MysticBlocks;
- import com.mysticsbiomes.init.MysticEntities;
- import io.netty.buffer.ByteBuf;
- import net.minecraft.nbt.CompoundTag;
- import net.minecraft.network.codec.ByteBufCodecs;
- import net.minecraft.network.codec.StreamCodec;
- import net.minecraft.network.syncher.EntityDataAccessor;
- import net.minecraft.network.syncher.EntityDataSerializer;
- import net.minecraft.network.syncher.EntityDataSerializers;
- import net.minecraft.network.syncher.SynchedEntityData;
- import net.minecraft.server.level.ServerLevel;
- import net.minecraft.tags.ItemTags;
- import net.minecraft.util.ByIdMap;
- import net.minecraft.util.StringRepresentable;
- import net.minecraft.world.InteractionHand;
- import net.minecraft.world.InteractionResult;
- import net.minecraft.world.entity.*;
- import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
- import net.minecraft.world.entity.ai.attributes.Attributes;
- import net.minecraft.world.entity.ai.control.LookControl;
- import net.minecraft.world.entity.ai.control.MoveControl;
- import net.minecraft.world.entity.ai.goal.*;
- import net.minecraft.world.entity.animal.Animal;
- import net.minecraft.world.entity.player.Player;
- import net.minecraft.world.item.ItemStack;
- import net.minecraft.world.item.crafting.Ingredient;
- import net.minecraft.world.level.Level;
- import net.minecraft.world.level.block.Blocks;
- import java.util.function.IntFunction;
- /**
- * can be tamed as pets to defend you in the water.
- * they can help you find treasures, or collect fish.
- * they can help you swim faster like dolphins.
- * they mostly float around, unless they are feeling playful or want to get food.
- * they will fall asleep at night, holding another sea otters hand nearby.
- * their babies will rest on their belly until they age up.
- */
- public class SeaOtter extends Animal {
- public static final EntityDataSerializer<State> SEA_OTTER_STATE = EntityDataSerializer.forValueType(SeaOtter.State.STREAM_CODEC);
- private static final EntityDataAccessor<State> DATA_STATE_ID = SynchedEntityData.defineId(SeaOtter.class, SEA_OTTER_STATE);
- private static final EntityDataAccessor<Boolean> DATA_FLOATING_ID = SynchedEntityData.defineId(SeaOtter.class, EntityDataSerializers.BOOLEAN);
- public SeaOtter.StartFloatingGoal startFloatingGoal;
- public final AnimationState idleInWaterAnimationState = new AnimationState();
- public final AnimationState swimmingAnimationState = new AnimationState();
- public final AnimationState glideWhileSwimmingAnimationState = new AnimationState();
- public final AnimationState twirlWhileSwimmingAnimationState = new AnimationState();
- public final AnimationState floatingAnimationState = new AnimationState();
- public final AnimationState swimmingWhileFloatingAnimationState = new AnimationState();
- public final AnimationState twirlWhileFloatingAnimationState = new AnimationState();
- public final AnimationState startFloatingAnimationState = new AnimationState();
- public final AnimationState stopFloatingAnimationState = new AnimationState();
- public final AnimationState idleOnLandAnimationState = new AnimationState();
- public final AnimationState walkingAnimationState = new AnimationState();
- public final AnimationState startWalkingAnimationState = new AnimationState();
- public final AnimationState stopWalkingAnimationState = new AnimationState();
- private long inStateTicks = 0L;
- public SeaOtter(EntityType<? extends SeaOtter> type, Level level) {
- super(type, level);
- this.moveControl = new MoveControl(this);
- this.lookControl = new LookControl(this);
- }
- public static AttributeSupplier.Builder createAttributes() {
- return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 16.0F).add(Attributes.MOVEMENT_SPEED, 1.0D);
- }
- @Override
- protected void registerGoals() {
- this.startFloatingGoal = new SeaOtter.StartFloatingGoal(this);
- this.goalSelector.addGoal(0, this.startFloatingGoal);
- this.goalSelector.addGoal(1, new TemptGoal(this, 1.0D, (stack) -> stack.is(ItemTags.FISHES), false));
- this.goalSelector.addGoal(2, new LookAtPlayerGoal(this, Player.class, 6.0F));
- this.goalSelector.addGoal(3, new RandomLookAroundGoal(this));
- //this.goalSelector.addGoal(3, new WaterAvoidingRandomStrollGoal(this, 0.2D));
- }
- @Override
- protected void defineSynchedData(SynchedEntityData.Builder builder) {
- super.defineSynchedData(builder);
- builder.define(DATA_STATE_ID, State.IDLE_IN_WATER);
- builder.define(DATA_FLOATING_ID, false);
- }
- @Override
- public void addAdditionalSaveData(CompoundTag tag) {
- super.addAdditionalSaveData(tag);
- tag.putString("State", this.getState().getSerializedName());
- tag.putBoolean("Floating", this.isFloating());
- }
- @Override
- public void readAdditionalSaveData(CompoundTag tag) {
- super.readAdditionalSaveData(tag);
- this.switchToState(SeaOtter.State.fromName(tag.getString("State")));
- this.setFloating(tag.getBoolean("Floating"));
- }
- @Override
- public AgeableMob getBreedOffspring(ServerLevel level, AgeableMob mob) {
- return MysticEntities.SEA_OTTER.get().create(level);
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- @Override
- public void tick() {
- super.tick();
- if (this.level().isClientSide()) {
- this.setupSwimmingAnimationStates();
- this.setupFloatingAnimationStates();
- this.setupWalkingAnimationStates();
- }
- this.inStateTicks++;
- }
- @Override
- public void aiStep() {
- super.aiStep();
- }
- @Override
- public void onSyncedDataUpdated(EntityDataAccessor<?> accessor) {
- if (DATA_STATE_ID.equals(accessor)) {
- this.inStateTicks = 0L;
- }
- super.onSyncedDataUpdated(accessor);
- }
- public SeaOtter.State getState() {
- return this.entityData.get(DATA_STATE_ID);
- }
- public void switchToState(SeaOtter.State state) {
- this.entityData.set(DATA_STATE_ID, state);
- }
- private void setupSwimmingAnimationStates() {
- switch (this.getState()) {
- case IDLE_IN_WATER:
- this.idleInWaterAnimationState.stop();
- break;
- case GLIDE_WHILE_SWIMMING:
- this.swimmingAnimationState.stop();
- this.glideWhileSwimmingAnimationState.startIfStopped(this.tickCount);
- break;
- case TWIRL_WHILE_SWIMMING:
- this.twirlWhileSwimmingAnimationState.startIfStopped(this.tickCount);
- break;
- }
- }
- private void setupFloatingAnimationStates() {
- switch (this.getState()) {
- case START_FLOATING:
- this.idleInWaterAnimationState.stop();
- this.swimmingAnimationState.stop();
- this.stopFloatingAnimationState.stop();
- this.startFloatingAnimationState.startIfStopped(this.tickCount);
- break;
- case FLOATING:
- this.idleInWaterAnimationState.stop();
- this.startFloatingAnimationState.stop();
- this.stopFloatingAnimationState.stop();
- this.floatingAnimationState.startIfStopped(this.tickCount);
- break;
- case STOP_FLOATING:
- this.idleInWaterAnimationState.stop();
- this.floatingAnimationState.stop();
- this.startFloatingAnimationState.stop();
- this.stopFloatingAnimationState.start(this.tickCount);
- break;
- case SWIMMING_WHILE_FLOATING:
- this.swimmingWhileFloatingAnimationState.startIfStopped(this.tickCount);
- break;
- case TWIRL_WHILE_FLOATING:
- this.twirlWhileFloatingAnimationState.startIfStopped(this.tickCount);
- break;
- }
- }
- private void setupWalkingAnimationStates() {
- switch (this.getState()) {
- case IDLE_ON_LAND:
- this.idleOnLandAnimationState.stop();
- break;
- case WALKING:
- this.idleOnLandAnimationState.stop();
- this.walkingAnimationState.startIfStopped(this.tickCount);
- break;
- case START_WALKING:
- this.idleOnLandAnimationState.stop();
- this.startWalkingAnimationState.startIfStopped(this.tickCount);
- break;
- case STOP_WALKING:
- this.walkingAnimationState.stop();
- this.stopWalkingAnimationState.startIfStopped(this.tickCount);
- break;
- }
- }
- public boolean isFloating() {
- return this.entityData.get(DATA_FLOATING_ID);
- }
- public void setFloating(boolean value) {
- this.entityData.set(DATA_FLOATING_ID, value);
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- @Override
- public InteractionResult mobInteract(Player player, InteractionHand hand) {
- if (player.getItemInHand(hand).isEmpty()) {
- if (this.startFloatingGoal != null) {
- this.startFloatingGoal.flag = true;
- }
- }
- return super.mobInteract(player, hand);
- }
- /// sounds
- @Override
- public boolean isFood(ItemStack stack) {
- return false;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- public static class StartFloatingGoal extends Goal {
- private final SeaOtter mob;
- private Phase phase = Phase.NONE;
- public boolean flag;
- public StartFloatingGoal(SeaOtter mob) {
- this.mob = mob;
- }
- @Override
- public boolean canUse() {
- return this.flag;
- }
- @Override
- public void start() {
- this.mob.switchToState(State.START_FLOATING);
- this.mob.inStateTicks = 0L;
- this.phase = Phase.START_FLOATING;
- }
- @Override
- public boolean canContinueToUse() {
- return this.phase != Phase.NONE;
- }
- @Override
- public void tick() {
- switch (this.phase) {
- case START_FLOATING -> {
- if (this.mob.inStateTicks >= State.START_FLOATING.animationDuration()) {
- this.mob.switchToState(State.FLOATING);
- this.mob.setFloating(true);
- this.mob.inStateTicks = 0L;
- this.phase = Phase.FLOATING;
- }
- }
- case FLOATING -> {
- if (this.mob.inStateTicks >= State.FLOATING.animationDuration()) {
- this.mob.switchToState(State.STOP_FLOATING);
- this.mob.setFloating(true);
- this.mob.inStateTicks = 0L;
- this.phase = Phase.STOP_FLOATING;
- }
- }
- case STOP_FLOATING -> {
- if (this.mob.inStateTicks >= State.STOP_FLOATING.animationDuration()) {
- this.phase = Phase.NONE;
- this.mob.setFloating(true);
- this.flag = false;
- }
- }
- }
- }
- @Override
- public void stop() {
- // Ensure proper cleanup if interrupted
- this.mob.switchToState(State.IDLE_IN_WATER);
- this.mob.setFloating(false);
- this.phase = Phase.NONE;
- this.flag = false;
- }
- enum Phase {
- NONE,
- START_FLOATING,
- FLOATING,
- STOP_FLOATING
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- public enum State implements StringRepresentable {
- IDLE_IN_WATER("idle_in_water", 0, 50),
- SWIMMING("swimming", 1, 40),
- GLIDE_WHILE_SWIMMING("glide_while_swimming", 2, 40),
- TWIRL_WHILE_SWIMMING("twirl_while_swimming", 3, 30),
- FLOATING("floating", 4, 50),
- START_FLOATING("start_floating", 5, 25),
- STOP_FLOATING("stop_floating", 6, 35),
- SWIMMING_WHILE_FLOATING("swimming_while_floating", 7, 50),
- TWIRL_WHILE_FLOATING("twirl_while_floating", 8, 55),
- IDLE_ON_LAND("idle_on_land", 9, 60),
- WALKING("walking", 10, 45),
- START_WALKING("start_walking", 11, 40),
- STOP_WALKING("stop_walking", 12, 30);
- private static final IntFunction<SeaOtter.State> BY_ID = ByIdMap.continuous(SeaOtter.State::id, values(), ByIdMap.OutOfBoundsStrategy.ZERO);
- public static final StreamCodec<ByteBuf, SeaOtter.State> STREAM_CODEC = ByteBufCodecs.idMapper(BY_ID, SeaOtter.State::id);
- private final String name;
- private final int id;
- private final int animationDuration;
- State(final String name, final int id, final int animationDuration) {
- this.name = name;
- this.id = id;
- this.animationDuration = animationDuration;
- }
- public static SeaOtter.State fromName(String name) {
- return StringRepresentable.fromEnum(SeaOtter.State::values).byName(name, IDLE_IN_WATER);
- }
- @Override
- public String getSerializedName() {
- return this.name;
- }
- private int id() {
- return this.id;
- }
- public int animationDuration() {
- return this.animationDuration;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment