Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package com.mysticsbiomes.common.entity;
- import com.mysticsbiomes.common.entity.core.SleepingAnimal;
- import com.mysticsbiomes.common.entity.core.goal.SleepGoal;
- import com.mysticsbiomes.init.MysticEntities;
- import io.netty.buffer.ByteBuf;
- import net.minecraft.core.BlockPos;
- import net.minecraft.nbt.CompoundTag;
- import net.minecraft.nbt.NbtUtils;
- 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.FluidTags;
- import net.minecraft.tags.ItemTags;
- import net.minecraft.util.ByIdMap;
- import net.minecraft.util.Mth;
- import net.minecraft.util.StringRepresentable;
- import net.minecraft.world.DifficultyInstance;
- 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.behavior.BehaviorUtils;
- import net.minecraft.world.entity.ai.control.BodyRotationControl;
- 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.ai.navigation.PathNavigation;
- import net.minecraft.world.entity.ai.navigation.WaterBoundPathNavigation;
- import net.minecraft.world.entity.animal.Animal;
- import net.minecraft.world.entity.player.Player;
- import net.minecraft.world.item.ItemStack;
- import net.minecraft.world.level.Level;
- import net.minecraft.world.level.LevelReader;
- import net.minecraft.world.level.ServerLevelAccessor;
- import net.minecraft.world.level.block.Blocks;
- import net.minecraft.world.level.block.state.BlockState;
- import net.minecraft.world.level.pathfinder.AmphibiousNodeEvaluator;
- import net.minecraft.world.level.pathfinder.Path;
- import net.minecraft.world.level.pathfinder.PathFinder;
- import net.minecraft.world.level.pathfinder.PathType;
- import net.minecraft.world.phys.Vec3;
- import javax.annotation.Nullable;
- import java.util.Optional;
- 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.
- *
- * todo:
- * sleeping
- * hold hands while sleeping
- * babies sleeping on parent
- * babies behavior
- * search for fish
- * search for seashells
- * break open shells
- * bring items to players
- * eat
- */
- public class SeaOtter extends Animal implements SleepingAnimal {
- public static final EntityDataSerializer<State> SEA_OTTER_STATE = EntityDataSerializer.forValueType(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);
- private static final EntityDataAccessor<Boolean> DATA_SITTING_ID = SynchedEntityData.defineId(SeaOtter.class, EntityDataSerializers.BOOLEAN);
- private static final EntityDataAccessor<Boolean> DATA_SLEEPING_ID = SynchedEntityData.defineId(SeaOtter.class, EntityDataSerializers.BOOLEAN);
- private int ticksSinceLastSwam;
- private boolean needsToSurface;
- @Nullable
- private BlockPos surfacePos;
- private boolean holdingBaby;
- private boolean beingHeld;
- 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 sitDownAnimationState = new AnimationState();
- public final AnimationState sittingAnimationState = new AnimationState();
- public final AnimationState standUpAnimationState = new AnimationState();
- public final AnimationState walkingAnimationState = new AnimationState();
- private long inStateTicks = 0L;
- public SeaOtter(EntityType<? extends SeaOtter> type, Level level) {
- super(type, level);
- this.setPathfindingMalus(PathType.WATER, 0.0F);
- this.moveControl = new SeaOtter.SeaOtterMoveControl(this);
- this.lookControl = new SeaOtter.SeaOtterLookControl(this);
- }
- public static AttributeSupplier.Builder createAttributes() {
- return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 16.0F).add(Attributes.MOVEMENT_SPEED, 0.5D).add(Attributes.STEP_HEIGHT, 1.0);
- }
- @Override
- protected void registerGoals() {
- this.goalSelector.addGoal(0, new SeaOtter.SwimToSurfaceGoal(this, 1.0D, 24));
- this.goalSelector.addGoal(1, new SleepGoal<>(this));
- this.goalSelector.addGoal(2, new TemptGoal(this, 0.2D, (stack) -> stack.is(ItemTags.FISHES), false));
- this.goalSelector.addGoal(3, new LookAtPlayerGoal(this, Player.class, 6.0F));
- this.goalSelector.addGoal(4, new RandomLookAroundGoal(this));
- this.goalSelector.addGoal(5, new SeaOtter.HoldBabyGoal(this));
- this.goalSelector.addGoal(5, new SeaOtter.FloatingGoal(this));
- this.goalSelector.addGoal(6, new SeaOtter.SwimAroundGoal(this, 1.0D, 10));
- }
- @Override
- protected void defineSynchedData(SynchedEntityData.Builder builder) {
- super.defineSynchedData(builder);
- builder.define(DATA_STATE_ID, State.NOTHING);
- builder.define(DATA_FLOATING_ID, false);
- builder.define(DATA_SITTING_ID, false);
- builder.define(DATA_SLEEPING_ID, false);
- }
- @Override
- public void addAdditionalSaveData(CompoundTag tag) {
- super.addAdditionalSaveData(tag);
- tag.putString("State", this.getState().getSerializedName());
- tag.putBoolean("Floating", this.isFloating());
- tag.putBoolean("Sitting", this.isSitting());
- tag.putBoolean("Sleeping", this.isSleeping());
- tag.putBoolean("HoldingBaby", this.isHoldingBaby());
- tag.putBoolean("BeingHeld", this.isBeingHeld());
- tag.putInt("TicksSinceSwam", this.ticksSinceLastSwam);
- if (this.surfacePos != null) {
- tag.put("SurfacePos", NbtUtils.writeBlockPos(this.surfacePos));
- }
- }
- @Override
- public void readAdditionalSaveData(CompoundTag tag) {
- super.readAdditionalSaveData(tag);
- this.switchToState(State.fromName(tag.getString("State")));
- this.setFloating(tag.getBoolean("Floating"));
- this.setSitting(tag.getBoolean("Sitting"));
- this.setSleeping(tag.getBoolean("Sleeping"));
- this.setHoldingBaby(tag.getBoolean("HoldingBaby"));
- this.setBeingHeld(tag.getBoolean("BeingHeld"));
- this.ticksSinceLastSwam = tag.getInt("TicksSinceSwam");
- this.surfacePos = null;
- if (tag.contains("SurfacePos") && NbtUtils.readBlockPos(tag, "SurfacePos").isPresent()) {
- this.surfacePos = NbtUtils.readBlockPos(tag, "SurfacePos").get();
- }
- }
- @Override
- public AgeableMob getBreedOffspring(ServerLevel level, AgeableMob mob) {
- return MysticEntities.SEA_OTTER.get().create(level);
- }
- @Override
- public SpawnGroupData finalizeSpawn(ServerLevelAccessor level, DifficultyInstance instance, MobSpawnType type, SpawnGroupData data) {
- return super.finalizeSpawn(level, instance, type, data);
- }
- @Override
- public int getMaxAirSupply() {
- return 6000;
- }
- @Override
- public void tick() {
- super.tick();
- if (!this.level().isClientSide()) {
- if (this.isEffectiveAi() && this.isAlive()) {
- if (this.isFloating()) {
- this.ticksSinceLastSwam++;
- this.wasTouchingWater = true;
- this.setDeltaMovement(this.getDeltaMovement().multiply(1.0D, 0.0D, 1.0D));
- if (this.getAirSupply() < this.getMaxAirSupply()) {
- this.setAirSupply(this.increaseAirSupply(this.getAirSupply()));
- }
- }
- if (this.isUnderWater()) {
- if (!this.needsToSurface() && (this.getAirSupply() < 600 || !this.wantsToSwim() || this.canSleep())) {
- this.setNeedsToSurface(true);
- }
- }
- }
- }
- if (this.level().isClientSide()) {
- this.setupSwimmingAnimationStates();
- this.setupFloatingAnimationStates();
- this.setupSittingAnimationStates();
- }
- ++this.inStateTicks;
- }
- private void setupSwimmingAnimationStates() {
- switch (this.getState()) {
- case IDLE_IN_WATER:
- this.swimmingAnimationState.stop();
- this.stopFloatingAnimationState.stop();
- this.walkingAnimationState.stop();
- this.sittingAnimationState.stop();
- this.standUpAnimationState.stop();
- this.sitDownAnimationState.stop();
- this.idleInWaterAnimationState.startIfStopped(this.tickCount);
- break;
- case SWIMMING:
- this.idleInWaterAnimationState.stop();
- this.startFloatingAnimationState.stop();
- this.floatingAnimationState.stop();
- this.stopFloatingAnimationState.stop();
- this.walkingAnimationState.stop();
- this.sittingAnimationState.stop();
- this.standUpAnimationState.stop();
- this.sitDownAnimationState.stop();
- this.swimmingAnimationState.startIfStopped(this.tickCount);
- 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.floatingAnimationState.stop();
- this.startFloatingAnimationState.startIfStopped(this.tickCount);
- break;
- case FLOATING:
- this.idleInWaterAnimationState.stop();
- this.swimmingAnimationState.stop();
- this.startFloatingAnimationState.stop();
- this.stopFloatingAnimationState.stop();
- this.floatingAnimationState.startIfStopped(this.tickCount);
- break;
- case STOP_FLOATING:
- this.idleInWaterAnimationState.stop();
- this.swimmingAnimationState.stop();
- this.floatingAnimationState.stop();
- this.startFloatingAnimationState.stop();
- this.stopFloatingAnimationState.startIfStopped(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 setupSittingAnimationStates() {
- this.idleInWaterAnimationState.stop();
- this.swimmingAnimationState.stop();
- this.glideWhileSwimmingAnimationState.stop();
- this.twirlWhileFloatingAnimationState.stop();
- switch (this.getState()) {
- case SIT_DOWN:
- this.standUpAnimationState.stop();
- this.sittingAnimationState.stop();
- this.walkingAnimationState.stop();
- this.sitDownAnimationState.startIfStopped(this.tickCount);
- break;
- case SITTING:
- this.standUpAnimationState.stop();
- this.walkingAnimationState.stop();
- this.sitDownAnimationState.stop();
- this.sittingAnimationState.startIfStopped(this.tickCount);
- break;
- case STAND_UP:
- this.sittingAnimationState.stop();
- this.walkingAnimationState.stop();
- this.sitDownAnimationState.stop();
- this.standUpAnimationState.startIfStopped(this.tickCount);
- break;
- case WALKING:
- this.sitDownAnimationState.stop();
- this.sittingAnimationState.stop();
- this.standUpAnimationState.stop();
- this.walkingAnimationState.startIfStopped(this.tickCount);
- break;
- }
- }
- @Override
- public void aiStep() {
- super.aiStep();
- if (!this.level().isClientSide()) {
- if (this.onGround() && !this.isInWater() && !this.isFloating()) {
- if (this.wantsToMove()) {
- if (this.isSitting() || this.getState() == State.SIT_DOWN) {
- if (this.getState() != State.STAND_UP) {
- this.switchToState(State.STAND_UP);
- this.setSitting(false);
- }
- }
- if (this.getState() == State.STAND_UP && this.inStateTicks >= State.STAND_UP.animationDuration()) {
- this.switchToState(State.WALKING);
- }
- if (!this.isSitting() && this.getState() != State.STAND_UP && this.getState() != State.WALKING) {
- this.switchToState(State.WALKING);
- }
- } else {
- if (!this.isSitting() && this.getState() != State.SIT_DOWN) {
- this.switchToState(State.SIT_DOWN);
- this.setSitting(true);
- } else if (this.getState() == State.SIT_DOWN && this.inStateTicks >= State.SIT_DOWN.animationDuration()) {
- this.switchToState(State.SITTING);
- this.setSitting(true);
- }
- if (this.getState() == State.STAND_UP && this.inStateTicks >= State.STAND_UP.animationDuration()) {
- this.switchToState(State.SIT_DOWN);
- this.setSitting(true);
- }
- }
- }
- }
- }
- @Override
- public void onSyncedDataUpdated(EntityDataAccessor<?> accessor) {
- if (DATA_STATE_ID.equals(accessor)) {
- this.inStateTicks = 0L;
- }
- super.onSyncedDataUpdated(accessor);
- }
- public State getState() {
- return this.entityData.get(DATA_STATE_ID);
- }
- public void switchToState(State state) {
- this.entityData.set(DATA_STATE_ID, state);
- this.inStateTicks = 0L;
- }
- public boolean isInAnimationTransition() {
- return switch (this.getState()) {
- case START_FLOATING -> this.inStateTicks < State.START_FLOATING.animationDuration();
- case STOP_FLOATING -> this.inStateTicks < State.STOP_FLOATING.animationDuration();
- case SIT_DOWN -> this.inStateTicks < State.SIT_DOWN.animationDuration();
- case STAND_UP -> this.inStateTicks < State.STAND_UP.animationDuration();
- default -> false;
- };
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- public boolean isFloating() {
- return this.entityData.get(DATA_FLOATING_ID);
- }
- public void setFloating(boolean value) {
- this.entityData.set(DATA_FLOATING_ID, value);
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- public boolean isSitting() {
- return this.entityData.get(DATA_SITTING_ID);
- }
- public void setSitting(boolean value) {
- this.entityData.set(DATA_SITTING_ID, value);
- }
- public void sitDown() {
- if (!this.isSitting() && this.onGround() && !this.isInWater()) {
- this.switchToState(State.SIT_DOWN);
- this.setSitting(true);
- }
- }
- public void standUp() {
- if (this.isSitting()) {
- this.switchToState(State.STAND_UP);
- this.setSitting(false);
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- @Override
- public boolean canSleep() {
- return this.level().isNight() && this.isInWater() && this.isFloating();
- }
- @Override
- public boolean isSleeping() {
- return this.entityData.get(DATA_SLEEPING_ID);
- }
- @Override
- public void setSleeping(boolean sleeping) {
- this.entityData.set(DATA_SLEEPING_ID, sleeping);
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- public boolean wantsToSwim() {
- return this.ticksSinceLastSwam > 600;
- }
- public void resetTicksSinceLastSwam() {
- this.ticksSinceLastSwam = 0;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- public boolean needsToSurface() {
- return this.needsToSurface;
- }
- public void setNeedsToSurface(boolean value) {
- this.needsToSurface = value;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- @Nullable
- public BlockPos getSurfacePos() {
- return this.surfacePos;
- }
- public void setSurfacePos(BlockPos pos) {
- this.surfacePos = pos;
- }
- public boolean hasReachedSurface() {
- return this.getSurfacePos() != null && this.hasReachedTarget(this.getSurfacePos(), 0.5D);
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- public boolean isHoldingBaby() {
- return this.holdingBaby;
- }
- public void setHoldingBaby(boolean value) {
- this.holdingBaby = value;
- }
- public boolean isBeingHeld() {
- return this.beingHeld;
- }
- public void setBeingHeld(boolean value) {
- this.beingHeld = value;
- }
- @Override
- protected Vec3 getPassengerAttachmentPoint(Entity entity, EntityDimensions dimensions, float scale) {
- return super.getPassengerAttachmentPoint(entity, dimensions, scale).add(0, -0.3D, 0);
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- @Override
- protected PathNavigation createNavigation(Level level) {
- return new SeaOtter.SeaOtterPathNavigation(this, level);
- }
- @Override
- protected BodyRotationControl createBodyControl() {
- return new SeaOtter.SeaOtterBodyRotationControl(this);
- }
- @Override
- public void travel(Vec3 pos) {
- if (this.refuseToMove() && this.onGround()) {
- this.setDeltaMovement(this.getDeltaMovement().multiply(0.0, 1.0, 0.0));
- pos = pos.multiply(0.0, 1.0, 0.0);
- }
- super.travel(pos);
- }
- public void pathfindDirectlyTowards(BlockPos pos, double speed) {
- this.navigation.setMaxVisitedNodesMultiplier(10.0F);
- this.navigation.moveTo(pos.getX() + 0.5D, pos.getY(), pos.getZ() + 0.5D, speed);
- }
- public boolean refuseToMove() {
- return this.isSitting() || this.isInAnimationTransition();
- }
- public boolean wantsToMove() {
- return !this.getNavigation().isDone() || this.getTarget() != null || this.moveControl.hasWanted();
- }
- public boolean isCloserThan(BlockPos pos, double distance) {
- return pos.closerThan(this.blockPosition(), distance);
- }
- public boolean hasReachedTarget(BlockPos pos, double distance) {
- if (this.isCloserThan(pos, distance)) {
- return true;
- } else {
- Path path = this.navigation.getPath();
- return path != null && path.getTarget().equals(pos) && path.canReach() && path.isDone();
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- @Override
- public Vec3 getViewVector(float ticks) {
- Vec3 view = super.getViewVector(ticks);
- if (this.isFloating()) {
- return view.reverse();
- }
- return view;
- }
- @Override
- public int getMaxHeadYRot() {
- if (this.isFloating()) {
- return 2;
- } else if (this.isSitting()) {
- return 20;
- } else {
- return super.getMaxHeadYRot();
- }
- }
- @Override
- public int getHeadRotSpeed() {
- return this.isFloating() ? 5 : 10;
- }
- @Override
- public boolean isFood(ItemStack stack) {
- return stack.is(ItemTags.FISHES);
- }
- @Override
- public InteractionResult mobInteract(Player player, InteractionHand hand) {
- if (this.isBeingHeld()) {
- this.setBaby(true);
- }
- return super.mobInteract(player, hand);
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /** todo: SWIM TO SURFACE GOAL */
- public static class SwimToSurfaceGoal extends MoveToBlockGoal {
- private final SeaOtter seaOtter;
- private boolean reachedTarget;
- public SwimToSurfaceGoal(SeaOtter mob, double speed, int distance) {
- super(mob, speed, distance, distance);
- this.seaOtter = mob;
- }
- @Override
- public boolean canUse() {
- if (!this.seaOtter.isInWater()) {
- return false;
- } else if (this.seaOtter.isBaby()) {
- return false;
- }
- return this.seaOtter.needsToSurface() && !this.seaOtter.isFloating() && super.canUse();
- }
- @Override
- public boolean canContinueToUse() {
- return !this.isReachedTarget();
- }
- @Override
- public void start() {
- super.start();
- this.seaOtter.switchToState(State.SWIMMING);
- this.seaOtter.setSurfacePos(this.blockPos);
- System.out.println("swimming to surface at : " + this.seaOtter.getSurfacePos());
- }
- @Override
- public void stop() {
- this.seaOtter.stopInPlace();
- this.seaOtter.getNavigation().resetMaxVisitedNodesMultiplier();
- System.out.println("reached surface");
- }
- @Override
- public void tick() {
- BlockPos pos = this.getMoveToTarget();
- Vec3 otterPos = this.seaOtter.position();
- Vec3 centerPos = Vec3.atBottomCenterOf(pos);
- if (!pos.closerToCenterThan(otterPos, 0.7D)) {
- this.seaOtter.pathfindDirectlyTowards(pos,3.0D);
- this.reachedTarget = false;
- } else {
- this.reachedTarget = true;
- }
- }
- @Override
- protected BlockPos getMoveToTarget() {
- return this.blockPos;
- }
- @Override
- protected boolean isValidTarget(LevelReader level, BlockPos pos) {
- return level.getBlockState(pos.below()).is(Blocks.WATER) && level.getBlockState(pos).isAir();
- }
- @Override
- protected boolean isReachedTarget() {
- return this.reachedTarget;
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /** todo: FLOATING GOAL */
- public static class FloatingGoal extends Goal {
- private final SeaOtter seaOtter;
- private Phase phase = Phase.NONE;
- public FloatingGoal(SeaOtter mob) {
- this.seaOtter = mob;
- }
- @Override
- public boolean canUse() {
- if (!this.seaOtter.isInWater()) {
- return false;
- } else if (this.seaOtter.isBaby()) {
- return false;
- }
- return !this.seaOtter.isFloating() && this.seaOtter.hasReachedSurface();
- }
- @Override
- public boolean canContinueToUse() {
- return this.seaOtter.isInWater() && this.phase != Phase.NONE;
- }
- @Override
- public void start() {
- this.seaOtter.setFloating(true);
- this.seaOtter.switchToState(State.START_FLOATING);
- this.phase = Phase.START_FLOATING;
- System.out.println("started floating");
- }
- @Override
- public void stop() {
- this.seaOtter.setFloating(false);
- this.seaOtter.setSurfacePos(null);
- System.out.println("finished floating");
- }
- @Override
- public void tick() {
- switch (this.phase) {
- case START_FLOATING -> {
- if (this.seaOtter.inStateTicks >= State.START_FLOATING.animationDuration()) {
- this.seaOtter.switchToState(State.FLOATING);
- this.phase = Phase.FLOATING;
- }
- }
- case FLOATING -> {
- if (this.seaOtter.inStateTicks >= State.FLOATING.animationDuration() && this.wantsToBeDone()) {
- System.out.println("stopping floating");
- this.seaOtter.switchToState(State.STOP_FLOATING);
- this.phase = Phase.STOP_FLOATING;
- }
- }
- case STOP_FLOATING -> {
- if (this.seaOtter.inStateTicks >= State.STOP_FLOATING.animationDuration()) {
- this.seaOtter.switchToState(State.SWIMMING);
- this.phase = Phase.NONE;
- }
- }
- }
- }
- private boolean wantsToBeDone() {
- return this.seaOtter.wantsToSwim(); /// or attacked, or search for food, or distracted, etc.
- }
- enum Phase {
- NONE,
- START_FLOATING,
- FLOATING,
- STOP_FLOATING
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /** todo: SWIM AROUND GOAL */
- public static class SwimAroundGoal extends RandomSwimmingGoal {
- private final SeaOtter seaOtter;
- private int ticksSwimming;
- public SwimAroundGoal(SeaOtter mob, double speed, int interval) {
- super(mob, speed, interval);
- this.seaOtter = mob;
- }
- @Override
- public boolean canUse() {
- if (!this.seaOtter.isInWater()) {
- return false;
- } else if (this.seaOtter.isSleeping()) {
- return false;
- } else if (this.seaOtter.isHoldingBaby()) {
- return false;
- } else if (this.seaOtter.isBaby()) {
- return false;
- }
- return !this.seaOtter.isFloating() && this.seaOtter.wantsToSwim() && super.canUse();
- }
- @Override
- public boolean canContinueToUse() {
- return this.seaOtter.isInWater() && (!this.hasSwamLongEnough() || this.seaOtter.canSleep());
- }
- @Override
- public void start() {
- super.start();
- this.seaOtter.switchToState(State.SWIMMING);
- System.out.println("started swimming");
- }
- @Override
- public void stop() {
- super.stop();
- this.ticksSwimming = 0;
- this.seaOtter.resetTicksSinceLastSwam();
- this.seaOtter.setNeedsToSurface(true);
- System.out.println("stopped swimming");
- }
- @Override
- protected Vec3 getPosition() {
- return BehaviorUtils.getRandomSwimmablePos(this.mob, 10, 4);
- }
- @Override
- public void tick() {
- this.trigger();
- ++this.ticksSwimming;
- }
- private boolean hasSwamLongEnough() {
- return this.ticksSwimming > 600;
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- public static class HoldBabyGoal extends Goal {
- private final SeaOtter seaOtter;
- @Nullable
- private SeaOtter baby;
- public HoldBabyGoal(SeaOtter mob) {
- this.seaOtter = mob;
- }
- @Override
- public boolean canUse() {
- SeaOtter baby = null;
- for (SeaOtter seaOtter : this.seaOtter.level().getEntitiesOfClass(SeaOtter.class, this.seaOtter.getBoundingBox().inflate(8.0, 4.0, 8.0))) {
- if (seaOtter.isBaby()) {
- baby = seaOtter;
- }
- }
- if (!this.seaOtter.isFloating()) {
- return false;
- } else if (this.seaOtter.isHoldingBaby()) { /// cannot use because is already holding a babby.
- return false;
- } else if (baby == null) {
- return false;
- } else if (this.seaOtter.distanceToSqr(baby) < 9.0) {
- return false;
- } else {
- this.baby = baby;
- return true;
- }
- }
- @Override
- public boolean canContinueToUse() {
- return false;
- }
- @Override
- public void start() {
- if (this.baby != null) {
- this.baby.startRiding(this.seaOtter, true);
- this.baby.setBeingHeld(true);
- this.seaOtter.setHoldingBaby(true);
- }
- }
- @Override
- public void stop() {
- }
- @Override
- public void tick() {
- }
- }
- public static class BreedGoal extends Goal {
- private final SeaOtter seaOtter;
- public BreedGoal(SeaOtter mob) {
- this.seaOtter = mob;
- }
- @Override
- public boolean canUse() {
- return false;
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- public static class HoldHandsGoal extends Goal {
- private final SeaOtter seaOtter;
- public HoldHandsGoal(SeaOtter mob) {
- this.seaOtter = mob;
- }
- @Override
- public boolean canUse() {
- return false;
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- public static class DriftGoal extends Goal {
- private final SeaOtter seaOtter;
- public DriftGoal(SeaOtter mob) {
- this.seaOtter = mob;
- }
- @Override
- public boolean canUse() {
- return false;
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- public static class SeaOtterMoveControl extends MoveControl {
- private final SeaOtter seaOtter;
- public SeaOtterMoveControl(SeaOtter mob) {
- super(mob);
- this.seaOtter = mob;
- }
- @Override
- public void tick() {
- if (this.seaOtter.isSleeping()) {
- return;
- }
- if (this.seaOtter.isInWater() && !this.seaOtter.isFloating()) {
- this.seaOtter.setDeltaMovement(this.seaOtter.getDeltaMovement().add(this.seaOtter.getLookAngle().scale(this.seaOtter.isFloating() ? 0.002F : 0.005F)));
- if (this.operation == MoveControl.Operation.MOVE_TO && !this.seaOtter.getNavigation().isDone()) {
- double d0 = this.wantedX - this.seaOtter.getX();
- double d1 = this.wantedY - this.seaOtter.getY();
- double d2 = this.wantedZ - this.seaOtter.getZ();
- double d3 = d0 * d0 + d1 * d1 + d2 * d2;
- if (d3 < (double)2.5000003E-7F) {
- this.seaOtter.setZza(0.0F);
- } else {
- float f = (float)(Mth.atan2(d2, d0) * (double)(180F / (float)Math.PI)) - 90.0F;
- this.seaOtter.setYRot(this.rotlerp(this.seaOtter.getYRot(), f, (float)10));
- this.seaOtter.yBodyRot = this.seaOtter.getYRot();
- this.seaOtter.yHeadRot = this.seaOtter.getYRot();
- float speed = (float)(this.speedModifier * this.seaOtter.getAttributeValue(Attributes.MOVEMENT_SPEED));
- this.seaOtter.setSpeed(speed * 0.02F);
- double d4 = Math.sqrt(d0 * d0 + d2 * d2);
- if (Math.abs(d1) > (double)1.0E-5F || Math.abs(d4) > (double)1.0E-5F) {
- float f3 = -((float)(Mth.atan2(d1, d4) * (double)(180F / (float)Math.PI)));
- f3 = Mth.clamp(Mth.wrapDegrees(f3), (float)(-85), (float)85);
- this.seaOtter.setXRot(this.rotlerp(this.seaOtter.getXRot(), f3, 5.0F));
- }
- 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()) {
- this.seaOtter.getJumpControl().jump();
- this.seaOtter.setSpeed(speed);
- }
- float f6 = Mth.cos(this.seaOtter.getXRot() * ((float)Math.PI / 180F));
- float f4 = Mth.sin(this.seaOtter.getXRot() * ((float)Math.PI / 180F));
- this.seaOtter.zza = f6 * speed;
- this.seaOtter.yya = -f4 * speed;
- }
- } else {
- this.seaOtter.setSpeed(0.0F);
- this.seaOtter.setXxa(0.0F);
- this.seaOtter.setYya(0.0F);
- this.seaOtter.setZza(0.0F);
- }
- } else {
- if (this.hasWanted() && this.seaOtter.isSitting()) {
- this.seaOtter.standUp();
- }
- if (!this.seaOtter.isFloating()) {
- super.tick();
- }
- }
- }
- }
- public static class SeaOtterLookControl extends LookControl {
- private final SeaOtter seaOtter;
- public SeaOtterLookControl(SeaOtter mob) {
- super(mob);
- this.seaOtter = mob;
- }
- @Override
- protected Optional<Float> getXRotD() {
- if (this.seaOtter.isFloating() && super.getXRotD().isPresent()) {
- return Optional.of(-super.getXRotD().get());
- }
- return super.getXRotD();
- }
- @Override
- protected Optional<Float> getYRotD() {
- if (this.seaOtter.isFloating() && super.getYRotD().isPresent()) {
- return Optional.of(Mth.wrapDegrees(super.getYRotD().get() + 180.0F));
- }
- return super.getYRotD();
- }
- @Override
- protected boolean resetXRotOnTick() {
- boolean flag = this.seaOtter.getState() == State.START_FLOATING && this.seaOtter.inStateTicks <= State.START_FLOATING.animationDuration();
- boolean flag2 = this.seaOtter.getState() == State.STOP_FLOATING && this.seaOtter.inStateTicks <= State.STOP_FLOATING.animationDuration();
- return flag || flag2;
- }
- @Override
- public void tick() {
- if (this.resetXRotOnTick()) {
- this.mob.setXRot(0.0F);
- }
- if (this.seaOtter.isSleeping()) {
- return;
- }
- if (!this.seaOtter.isBaby() && this.seaOtter.isBeingHeld()) {
- 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())) {
- if (this.seaOtter.isInWater()) {
- if (this.lookAtCooldown > 0) {
- this.lookAtCooldown--;
- this.getYRotD().ifPresent(i -> this.seaOtter.yHeadRot = this.rotateTowards(this.seaOtter.yHeadRot, i + 20.0F, this.yMaxRotSpeed));
- this.getXRotD().ifPresent(i -> this.seaOtter.setXRot(this.rotateTowards(this.seaOtter.getXRot(), i + 10.0F, this.xMaxRotAngle)));
- } else {
- if (this.seaOtter.getNavigation().isDone()) {
- this.seaOtter.setXRot(this.rotateTowards(this.seaOtter.getXRot(), 0.0F, 5.0F));
- }
- this.seaOtter.yHeadRot = this.rotateTowards(this.seaOtter.yHeadRot, this.seaOtter.yBodyRot, this.yMaxRotSpeed);
- }
- float f = Mth.wrapDegrees(this.seaOtter.yHeadRot - this.seaOtter.yBodyRot);
- if (f < (float)(-10)) {
- this.seaOtter.yBodyRot -= 4.0F;
- } else if (f > (float)10) {
- this.seaOtter.yBodyRot += 4.0F;
- }
- }
- } else {
- super.tick();
- }
- }
- }
- }
- public class SeaOtterPathNavigation extends WaterBoundPathNavigation {
- public SeaOtterPathNavigation(Mob mob, Level level) {
- super(mob, level);
- }
- @Override
- protected PathFinder createPathFinder(int nodes) {
- this.nodeEvaluator = new AmphibiousNodeEvaluator(true);
- return new PathFinder(this.nodeEvaluator, nodes);
- }
- @Override
- protected boolean canUpdatePath() {
- return true;
- }
- @Override
- public boolean isStableDestination(BlockPos pos) {
- BlockState belowState = this.level.getBlockState(pos.below());
- if (SeaOtter.this.isInWater()) {
- return !(belowState.isAir() || belowState.getFluidState().is(FluidTags.WATER));
- } else {
- return !belowState.isAir();
- }
- }
- }
- public class SeaOtterBodyRotationControl extends BodyRotationControl {
- public SeaOtterBodyRotationControl(Mob mob) {
- super(mob);
- }
- @Override
- public void clientTick() {
- if (!SeaOtter.this.refuseToMove() && !SeaOtter.this.isFloating()) {
- super.clientTick();
- }
- }
- }
- public enum State implements StringRepresentable {
- NOTHING("nothing", 0, 0),
- IDLE_IN_WATER("idle_in_water", 1, 50),
- SWIMMING("swimming", 2, 40),
- GLIDE_WHILE_SWIMMING("glide_while_swimming", 3, 40),
- TWIRL_WHILE_SWIMMING("twirl_while_swimming", 4, 30),
- FLOATING("floating", 5, 50),
- START_FLOATING("start_floating", 6, 25, true),
- STOP_FLOATING("stop_floating", 7, 40, true),
- SWIMMING_WHILE_FLOATING("swimming_while_floating", 8, 50),
- TWIRL_WHILE_FLOATING("twirl_while_floating", 9, 55),
- SIT_DOWN("sit_down", 10, 30, true),
- SITTING("sitting", 11, 60),
- STAND_UP("stand_up", 12, 40, true),
- WALKING("walking", 13, 45);
- 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;
- private final boolean isTransition;
- State(final String name, final int id, final int animationDuration) {
- this(name, id, animationDuration, false);
- }
- State(final String name, final int id, final int animationDuration, boolean isTransition) {
- this.name = name;
- this.id = id;
- this.animationDuration = animationDuration;
- this.isTransition = isTransition;
- }
- public static SeaOtter.State fromName(String name) {
- return StringRepresentable.fromEnum(SeaOtter.State::values).byName(name, NOTHING);
- }
- @Override
- public String getSerializedName() {
- return this.name;
- }
- private int id() {
- return this.id;
- }
- public int animationDuration() {
- return this.animationDuration;
- }
- public boolean isTransition() {
- return this.isTransition;
- }
- }
- private enum Reason {
- NEEDS_AIR,
- WANTS_TO_FLOAT,
- IS_BEDTIME
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment