Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package com.mysticsbiomes.common.entity.animal.butterfly;
- import com.google.common.collect.Maps;
- import com.mysticsbiomes.common.block.entity.ButterflyNestBlockEntity;
- import com.mysticsbiomes.init.MysticBlocks;
- import com.mysticsbiomes.init.MysticPoiTypes;
- import com.mysticsbiomes.init.MysticSounds;
- import net.minecraft.core.BlockPos;
- import net.minecraft.core.particles.ParticleOptions;
- import net.minecraft.core.particles.ParticleTypes;
- import net.minecraft.nbt.CompoundTag;
- import net.minecraft.nbt.NbtUtils;
- import net.minecraft.network.syncher.EntityDataAccessor;
- import net.minecraft.network.syncher.EntityDataSerializers;
- import net.minecraft.network.syncher.SynchedEntityData;
- import net.minecraft.server.level.ServerLevel;
- import net.minecraft.sounds.SoundEvent;
- import net.minecraft.tags.BlockTags;
- 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.damagesource.DamageSource;
- 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.FlyingMoveControl;
- import net.minecraft.world.entity.ai.control.LookControl;
- import net.minecraft.world.entity.ai.goal.FloatGoal;
- import net.minecraft.world.entity.ai.goal.Goal;
- import net.minecraft.world.entity.ai.goal.TemptGoal;
- import net.minecraft.world.entity.ai.navigation.FlyingPathNavigation;
- import net.minecraft.world.entity.ai.navigation.PathNavigation;
- import net.minecraft.world.entity.ai.util.AirAndWaterRandomPos;
- import net.minecraft.world.entity.ai.util.AirRandomPos;
- import net.minecraft.world.entity.ai.util.HoverRandomPos;
- import net.minecraft.world.entity.ai.village.poi.PoiManager;
- import net.minecraft.world.entity.ai.village.poi.PoiRecord;
- import net.minecraft.world.entity.animal.Animal;
- import net.minecraft.world.entity.animal.FlyingAnimal;
- import net.minecraft.world.entity.player.Player;
- import net.minecraft.world.item.crafting.Ingredient;
- import net.minecraft.world.level.Level;
- import net.minecraft.world.level.LevelReader;
- import net.minecraft.world.level.ServerLevelAccessor;
- import net.minecraft.world.level.block.Block;
- import net.minecraft.world.level.block.Blocks;
- import net.minecraft.world.level.block.DoublePlantBlock;
- import net.minecraft.world.level.block.entity.BlockEntity;
- import net.minecraft.world.level.block.state.BlockState;
- import net.minecraft.world.level.block.state.properties.DoubleBlockHalf;
- import net.minecraft.world.level.gameevent.GameEvent;
- import net.minecraft.world.level.pathfinder.Path;
- import net.minecraft.world.phys.Vec3;
- import org.jetbrains.annotations.Nullable;
- import java.util.*;
- import java.util.function.Predicate;
- import java.util.stream.Collectors;
- import java.util.stream.Stream;
- /**
- * Butterflies are friendly ambient anthropoids, useful for growing flowers.
- */
- public class Butterfly extends Animal implements FlyingAnimal {
- private static final EntityDataAccessor<Integer> DATA_TYPE_ID = SynchedEntityData.defineId(Butterfly.class, EntityDataSerializers.INT);
- private boolean sleeping;
- private int ticksSinceLastSlept;
- private int remainingTicksBeforeLocatingNewNest;
- private int remainingCooldownBeforeCanPollinate; // 2400 ticks (2 minutes)
- private boolean hasNectar;
- private int nectarPoints;
- @Nullable
- private BlockPos nestPos;
- @Nullable
- private Block givenFlower;
- Butterfly.PollinateFlowerGoal pollinateGoal;
- private int underWaterTicks;
- public final AnimationState flyingAnimationState = new AnimationState();
- public Butterfly(EntityType<? extends Butterfly> entityType, Level level) {
- super(entityType, level);
- this.moveControl = new FlyingMoveControl(this, 20, true);
- this.lookControl = new ButterflyLookControl(this);
- }
- protected void defineSynchedData() {
- super.defineSynchedData();
- this.entityData.define(DATA_TYPE_ID, 0);
- }
- protected void registerGoals() {
- this.goalSelector.addGoal(0, new Butterfly.PlantFlowerGoal());
- this.pollinateGoal = new Butterfly.PollinateFlowerGoal();
- this.goalSelector.addGoal(1, this.pollinateGoal);
- this.goalSelector.addGoal(2, new Butterfly.EnterNestGoal());
- this.goalSelector.addGoal(3, new TemptGoal(this, 1.25D, Ingredient.of(ItemTags.FLOWERS), false));
- this.goalSelector.addGoal(4, new Butterfly.LocateNestGoal());
- this.goalSelector.addGoal(4, new Butterfly.GoToNestGoal());
- this.goalSelector.addGoal(5, new Butterfly.WanderGoal());
- this.goalSelector.addGoal(6, new FloatGoal(this));
- }
- public static AttributeSupplier.Builder createAttributes() {
- return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 10.0D).add(Attributes.FLYING_SPEED, 0.6F).add(Attributes.MOVEMENT_SPEED, 0.3F).add(Attributes.FOLLOW_RANGE, 28.0D);
- }
- @Override
- public void addAdditionalSaveData(CompoundTag tag) {
- super.addAdditionalSaveData(tag);
- tag.putString("Type", this.getVariant().getSerializedName());
- tag.putBoolean("IsSleeping", this.isSleeping());
- tag.putBoolean("HasNectar", this.hasNectar());
- tag.putInt("NectarPoints", this.nectarPoints);
- tag.putInt("TicksSinceLastSlept", this.ticksSinceLastSlept);
- tag.putInt("TicksBeforeCanPollinate", this.remainingCooldownBeforeCanPollinate);
- if (this.nestPos != null) {
- tag.put("NestPos", NbtUtils.writeBlockPos(this.nestPos));
- }
- }
- @Override
- public void readAdditionalSaveData(CompoundTag tag) {
- super.readAdditionalSaveData(tag);
- this.setVariant(Type.byName(tag.getString("Type")));
- this.sleeping = tag.getBoolean("IsSleeping");
- this.hasNectar = tag.contains("HasNectar");
- this.nectarPoints = tag.getInt("NectarPoints");
- this.ticksSinceLastSlept = tag.getInt("TicksSinceLastSlept");
- this.remainingCooldownBeforeCanPollinate = tag.getInt("TicksBeforeCanPollinate");
- this.nestPos = null;
- if (tag.contains("NestPos")) {
- this.nestPos = NbtUtils.readBlockPos(tag.getCompound("NestPos"));
- }
- }
- public AgeableMob getBreedOffspring(ServerLevel level, AgeableMob mob) {
- return null;
- }
- public MobType getMobType() {
- return MobType.ARTHROPOD;
- }
- public Type getVariant() {
- return Type.byId(this.entityData.get(DATA_TYPE_ID));
- }
- public void setVariant(Type type) {
- this.entityData.set(DATA_TYPE_ID, type.getId());
- }
- @Override
- public void tick() {
- super.tick();
- //if (this.level().isClientSide()) {
- //this.flyingAnimationState.animateWhen(this.isFlying(), this.tickCount);
- //}
- if (this.hasNectar() && this.random.nextFloat() < 0.05F) {
- for (int i = 0; i < this.random.nextInt(2) + 1; ++i) {
- this.level().addParticle(ParticleTypes.FALLING_NECTAR, Mth.lerp(this.level().random.nextDouble(), this.getX() - (double)0.3F, this.getX() + (double)0.3F), this.getY(0.5D), Mth.lerp(this.level().random.nextDouble(), this.getZ() - (double)0.3F, this.getZ() + (double)0.3F), 0.0D, 0.0D, 0.0D);
- }
- }
- }
- @Override
- public void aiStep() {
- super.aiStep();
- if (!this.level().isClientSide) {
- if (this.remainingTicksBeforeLocatingNewNest > 0) {
- --this.remainingTicksBeforeLocatingNewNest;
- }
- if (this.remainingCooldownBeforeCanPollinate > 0) {
- --this.remainingCooldownBeforeCanPollinate;
- }
- if (this.tickCount % 20 == 0 && !this.isNestValid()) {
- this.nestPos = null;
- }
- }
- }
- @Override
- protected void customServerAiStep() {
- super.customServerAiStep();
- if (this.isInWaterOrBubble()) {
- ++this.underWaterTicks;
- } else {
- this.underWaterTicks = 0;
- }
- if (this.underWaterTicks > 20) {
- this.hurt(this.damageSources().drown(), 1.0F);
- }
- if (!this.isSleeping()) {
- ++this.ticksSinceLastSlept;
- }
- }
- protected void addParticlesAroundSelf(ParticleOptions options) {
- for (int i = 0; i < 5; ++i) {
- double d0 = this.random.nextGaussian() * 0.02D;
- double d1 = this.random.nextGaussian() * 0.02D;
- double d2 = this.random.nextGaussian() * 0.02D;
- this.level().addParticle(options, this.getRandomX(1.0D), this.getRandomY() + 1.0D, this.getRandomZ(1.0D), d0, d1, d2);
- }
- }
- protected void playStepSound(BlockPos pos, BlockState state) {
- }
- protected float getSoundVolume() {
- return 0.4F;
- }
- protected SoundEvent getAmbientSound() {
- return MysticSounds.BUTTERFLY_AMBIENT.get();
- }
- protected SoundEvent getHurtSound(DamageSource source) {
- return MysticSounds.BUTTERFLY_HURT.get();
- }
- protected SoundEvent getDeathSound() {
- return MysticSounds.BUTTERFLY_DEATH.get();
- }
- protected PathNavigation createNavigation(Level level) {
- FlyingPathNavigation navigation = new FlyingPathNavigation(this, level) {
- public boolean isStableDestination(BlockPos p_27947_) {
- return !this.level.getBlockState(p_27947_.below()).isAir();
- }
- };
- navigation.setCanOpenDoors(false);
- navigation.setCanFloat(false);
- navigation.setCanPassDoors(true);
- return navigation;
- }
- protected void checkFallDamage(double distance, boolean b, BlockState state, BlockPos pos) {
- }
- protected float getStandingEyeHeight(Pose pose, EntityDimensions dimensions) {
- return dimensions.height * 0.5F;
- }
- public float getWalkTargetValue(BlockPos pos, LevelReader reader) {
- return reader.getBlockState(pos).isAir() ? 5.0F : 0.0F;
- }
- public boolean isFlying() {
- return !this.onGround();
- }
- public boolean isTired() {
- return this.ticksSinceLastSlept > 18000;
- }
- public boolean isSleeping() {
- return this.sleeping;
- }
- public void setIsSleeping(boolean sleeping) {
- this.sleeping = sleeping;
- }
- private boolean isNestValid() {
- if (this.nestPos == null) {
- return false;
- } else if (this.isTooFarAway(this.nestPos)) {
- return false;
- } else {
- BlockEntity blockEntity = this.level().getBlockEntity(this.nestPos);
- return blockEntity instanceof ButterflyNestBlockEntity;
- }
- }
- private boolean isNestNearFire() {
- if (this.nestPos == null) {
- return false;
- } else {
- BlockEntity blockEntity = this.level().getBlockEntity(this.nestPos);
- return blockEntity instanceof ButterflyNestBlockEntity && ((ButterflyNestBlockEntity)blockEntity).isFireNearby();
- }
- }
- private boolean doesNestHaveSpace(BlockPos pos) {
- BlockEntity blockEntity = this.level().getBlockEntity(pos);
- if (blockEntity instanceof ButterflyNestBlockEntity entity) {
- return !entity.isFull();
- } else {
- return false;
- }
- }
- private boolean wantsToEnterNest() {
- boolean flag = this.isTired() || this.level().isRaining() || this.level().isNight() || this.hasNectar();
- return flag && !this.isNestNearFire();
- }
- private boolean wasGivenFlower() {
- return this.givenFlower != null;
- }
- public boolean hasNectar() {
- return this.hasNectar;
- }
- public void setHasNectar(boolean hasNectar) {
- this.hasNectar = hasNectar;
- }
- public boolean canPollinate() {
- return this.remainingCooldownBeforeCanPollinate == 0;
- }
- /** determines when a butterfly wants to pollinate after their cooldown is over. */
- public boolean wantsToPollinate() {
- return this.canPollinate() && this.random.nextInt(120) == 0;
- }
- /**
- * @return if the butterfly has a home, is not tired, does not have nectar, and cooldown is at 0.
- */
- public boolean canSpreadFlowers() {
- boolean flag = !this.hasNectar || this.nestPos != null || !this.isTired();
- return flag && this.canPollinate();
- }
- @Override
- public InteractionResult mobInteract(Player player, InteractionHand hand) {
- if (player.getItemInHand(hand).is(ItemTags.SMALL_FLOWERS)) {
- if (this.canPollinate() && !Butterfly.this.hasNectar()) {
- this.givenFlower = Block.byItem(player.getItemInHand(hand).getItem());
- this.addParticlesAroundSelf(ParticleTypes.HAPPY_VILLAGER);
- return InteractionResult.SUCCESS;
- } else {
- this.addParticlesAroundSelf(ParticleTypes.ANGRY_VILLAGER);
- return InteractionResult.PASS;
- }
- } else {
- return super.mobInteract(player, hand);
- }
- }
- @Override
- public SpawnGroupData finalizeSpawn(ServerLevelAccessor accessor, DifficultyInstance instance, MobSpawnType type, @Nullable SpawnGroupData data, @Nullable CompoundTag tag) {
- data = super.finalizeSpawn(accessor, instance, type, data, tag);
- this.setVariant(Type.byId(random.nextInt(3)));
- return data;
- }
- private Optional<BlockPos> findNearestBlock(Predicate<BlockState> predicate, double distance) {
- BlockPos pos = Butterfly.this.blockPosition();
- BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos();
- for (int i = 0; (double)i <= distance; i = i > 0 ? -i : 1 - i) {
- for (int j = 0; (double)j < distance; ++j) {
- for (int k = 0; k <= j; k = k > 0 ? -k : 1 - k) {
- for (int l = k < j && k > -j ? j : 0; l <= j; l = l > 0 ? -l : 1 - l) {
- mutablePos.setWithOffset(pos, k, i - 1, l);
- if (pos.closerThan(mutablePos, distance) && predicate.test(Butterfly.this.level().getBlockState(mutablePos))) {
- return Optional.of(mutablePos);
- }
- }
- }
- }
- }
- return Optional.empty();
- }
- private void pathfindRandomlyTowards(BlockPos pos) {
- Vec3 vec3 = Vec3.atBottomCenterOf(pos);
- int i = 0;
- BlockPos pos1 = this.blockPosition();
- int j = (int)vec3.y - pos1.getY();
- if (j > 2) {
- i = 4;
- } else if (j < -2) {
- i = -4;
- }
- int k = 6;
- int l = 8;
- int i1 = pos1.distManhattan(pos);
- if (i1 < 15) {
- k = i1 / 2;
- l = i1 / 2;
- }
- Vec3 vec31 = AirRandomPos.getPosTowards(this, k, l, i, vec3, (float)Math.PI / 10F);
- if (vec31 != null) {
- this.navigation.setMaxVisitedNodesMultiplier(0.5F);
- this.navigation.moveTo(vec31.x, vec31.y, vec31.z, 1.0D);
- }
- }
- private boolean pathfindDirectlyTowards(BlockPos pos) {
- Butterfly.this.navigation.setMaxVisitedNodesMultiplier(10.0F);
- Butterfly.this.navigation.moveTo(pos.getX(), pos.getY(), pos.getZ(), 1.0D);
- return Butterfly.this.navigation.getPath() != null && Butterfly.this.navigation.getPath().canReach();
- }
- private boolean isCloserThan(BlockPos pos, int distance) {
- return pos.closerThan(this.blockPosition(), distance);
- }
- private boolean isTooFarAway(BlockPos pos) {
- return !this.isCloserThan(pos, 32);
- }
- private boolean hasReachedPosition(BlockPos pos) {
- if (this.isCloserThan(pos, 0)) {
- return true;
- } else {
- Path path = this.navigation.getPath();
- return path != null && path.getTarget().equals(pos) && path.canReach() && path.isDone();
- }
- }
- /**
- * Sets the butterflies home/nest position by scoping out an available one nearby.
- */
- class LocateNestGoal extends Goal {
- public boolean canUse() {
- return Butterfly.this.remainingTicksBeforeLocatingNewNest == 0 && Butterfly.this.nestPos == null && Butterfly.this.wantsToEnterNest();
- }
- public boolean canContinueToUse() {
- return false;
- }
- public void start() {
- Butterfly.this.remainingTicksBeforeLocatingNewNest = 200;
- List<BlockPos> list = this.findNearbyNestsWithSpace();
- if (!list.isEmpty()) {
- for (BlockPos pos : list) {
- Butterfly.this.nestPos = pos;
- return;
- }
- Butterfly.this.nestPos = list.get(0);
- }
- }
- private List<BlockPos> findNearbyNestsWithSpace() {
- BlockPos pos = Butterfly.this.blockPosition();
- PoiManager poiManager = ((ServerLevel)Butterfly.this.level()).getPoiManager();
- Stream<PoiRecord> stream = poiManager.getInRange((holder) -> holder.is(MysticPoiTypes.BUTTERFLY_NEST.getId()), pos, 20, PoiManager.Occupancy.ANY);
- return stream.map(PoiRecord::getPos).filter(Butterfly.this::doesNestHaveSpace).sorted(Comparator.comparingDouble((pos1) -> pos1.distSqr(pos))).collect(Collectors.toList());
- }
- }
- class GoToNestGoal extends Goal {
- @Nullable
- private Path lastPath;
- GoToNestGoal() {
- this.setFlags(EnumSet.of(Goal.Flag.MOVE));
- }
- public boolean canUse() {
- return Butterfly.this.nestPos != null && Butterfly.this.wantsToEnterNest() && !Butterfly.this.hasReachedPosition(Butterfly.this.nestPos) && Butterfly.this.level().getBlockState(Butterfly.this.nestPos).is(MysticBlocks.BUTTERFLY_NEST.get());
- }
- public boolean canContinueToUse() {
- return this.canUse();
- }
- public void stop() {
- Butterfly.this.navigation.stop();
- Butterfly.this.navigation.resetMaxVisitedNodesMultiplier();
- }
- public void tick() {
- if (Butterfly.this.nestPos != null) {
- if (!Butterfly.this.navigation.isInProgress()) {
- if (!Butterfly.this.isCloserThan(Butterfly.this.nestPos, 16)) {
- Butterfly.this.pathfindRandomlyTowards(Butterfly.this.nestPos);
- } else {
- boolean flag = Butterfly.this.pathfindDirectlyTowards(Butterfly.this.nestPos);
- if (flag) {
- if (this.lastPath != null && Butterfly.this.navigation.getPath() != null && !Butterfly.this.navigation.getPath().sameAs(this.lastPath)) {
- this.lastPath = Butterfly.this.navigation.getPath();
- }
- }
- }
- }
- }
- }
- }
- class EnterNestGoal extends Goal {
- public boolean canUse() {
- if (Butterfly.this.nestPos != null && Butterfly.this.wantsToEnterNest() && Butterfly.this.nestPos.closerToCenterThan(Butterfly.this.position(), 2.0D)) {
- BlockEntity blockEntity = Butterfly.this.level().getBlockEntity(Butterfly.this.nestPos);
- if (blockEntity instanceof ButterflyNestBlockEntity entity) {
- if (!entity.isFull()) {
- return true;
- }
- Butterfly.this.nestPos = null;
- }
- }
- return false;
- }
- public boolean canContinueToUse() {
- return false;
- }
- public void start() {
- Butterfly.this.sleeping = true;
- if (Butterfly.this.nestPos != null) {
- BlockEntity blockEntity = Butterfly.this.level().getBlockEntity(Butterfly.this.nestPos);
- if (blockEntity instanceof ButterflyNestBlockEntity entity) {
- entity.addOccupant(Butterfly.this, Butterfly.this.hasNectar());
- }
- }
- }
- public void stop() {
- Butterfly.this.ticksSinceLastSlept = 0;
- Butterfly.this.sleeping = false;
- }
- }
- /**
- * Either pollinates a random flower or locates and pollinates the same flower a player gave them.
- */
- class PollinateFlowerGoal extends Goal {
- private final Predicate<BlockState> VALID_POLLINATION_BLOCKS = (state) -> {
- if (state.is(BlockTags.FLOWERS)) {
- if (state.is(Blocks.SUNFLOWER)) {
- return state.getValue(DoublePlantBlock.HALF) == DoubleBlockHalf.UPPER;
- } else {
- return true;
- }
- } else {
- return false;
- }
- };
- private int pollinatingTicks;
- private boolean pollinating;
- @Nullable
- private BlockPos flowerPos;
- PollinateFlowerGoal() {
- this.setFlags(EnumSet.of(Goal.Flag.MOVE));
- }
- public boolean canUse() {
- if (Butterfly.this.level().isRaining()) {
- return false;
- } else {
- if (Butterfly.this.canPollinate()) {
- if (this.flowerPos != null) {
- return false;
- }
- return Butterfly.this.wasGivenFlower() ? Butterfly.this.canSpreadFlowers() : Butterfly.this.wantsToPollinate();
- } else {
- return false;
- }
- }
- }
- public boolean canContinueToUse() {
- if (Butterfly.this.level().isRaining()) {
- return false;
- } else {
- return this.pollinatingTicks < 600; // 30 seconds to pollinate
- }
- }
- public void start() {
- this.pollinatingTicks = 0;
- this.pollinating = true;
- Optional<BlockPos> optional = Butterfly.this.givenFlower != null ? Butterfly.this.findNearestBlock((block) -> block.is(Butterfly.this.givenFlower), 16.0D) : Butterfly.this.findNearestBlock(VALID_POLLINATION_BLOCKS, 4.0D);
- if (optional.isPresent() && this.flowerPos == null) {
- this.flowerPos = optional.get();
- }
- }
- public void stop() {
- this.pollinating = false;
- Butterfly.this.setHasNectar(true);
- Butterfly.this.nectarPoints += 2;
- if (!Butterfly.this.wasGivenFlower()) {
- this.flowerPos = null;
- Butterfly.this.navigation.stop();
- Butterfly.this.remainingCooldownBeforeCanPollinate = 3600; // 3 minute cooldown
- }
- }
- public boolean requiresUpdateEveryTick() {
- return true;
- }
- public void tick() {
- if (this.flowerPos != null) {
- if (Butterfly.this.hasReachedPosition(this.flowerPos)) {
- Vec3 hoverPos = Vec3.atBottomCenterOf(this.flowerPos).add(0.0D, 0.6F, 0.0D);
- Butterfly.this.getMoveControl().setWantedPosition(hoverPos.x(), hoverPos.y(), hoverPos.z(), 0.35F);
- Butterfly.this.navigation.stop();
- ++this.pollinatingTicks;
- } else {
- Butterfly.this.navigation.moveTo(this.flowerPos.getX() + 0.5D, this.flowerPos.getY() + 0.5D, this.flowerPos.getZ() + 0.5D, 0.85F);
- }
- }
- }
- boolean isPollinating() {
- return this.pollinating;
- }
- }
- /**
- * The main feature of butterflies; they plant 2 flowers for every 1 flower they collect nectar from.
- */
- class PlantFlowerGoal extends Goal {
- private int plantingTicks;
- @Nullable
- private BlockPos emptyPos;
- PlantFlowerGoal() {
- this.setFlags(EnumSet.of(Goal.Flag.MOVE));
- }
- public boolean canUse() {
- return Butterfly.this.wasGivenFlower() && Butterfly.this.hasNectar() && Butterfly.this.nectarPoints > 0;
- }
- public boolean canContinueToUse() {
- return this.plantingTicks < 1200; // 1 minute
- }
- public void start() {
- this.plantingTicks = 0;
- this.emptyPos = this.findRandomEmptyPos();
- }
- public void stop() {
- if (!Butterfly.this.level().isClientSide) {
- if (emptyPos != null) {
- int x = Mth.floor(this.emptyPos.getX());
- int y = Mth.floor(this.emptyPos.getY());
- int z = Mth.floor(this.emptyPos.getZ());
- BlockPos butterflyPos = new BlockPos(x, y, z);
- if (Butterfly.this.givenFlower != null) {
- BlockState flowerState = Butterfly.this.givenFlower.defaultBlockState();
- if (Butterfly.this.level().isEmptyBlock(butterflyPos) && flowerState.canSurvive(Butterfly.this.level(), butterflyPos)) {
- Butterfly.this.level().setBlockAndUpdate(butterflyPos, flowerState);
- Butterfly.this.level().gameEvent(GameEvent.BLOCK_PLACE, butterflyPos, GameEvent.Context.of(Butterfly.this, flowerState));
- }
- Butterfly.this.nectarPoints -= 1;
- this.emptyPos = null;
- }
- }
- }
- if (Butterfly.this.nectarPoints == 0) {
- Butterfly.this.givenFlower = null;
- Butterfly.this.pollinateGoal.flowerPos = null;
- Butterfly.this.setHasNectar(false);
- Butterfly.this.navigation.stop();
- Butterfly.this.remainingCooldownBeforeCanPollinate = 3600; // 3 minute cooldown
- }
- }
- public boolean requiresUpdateEveryTick() {
- return true;
- }
- public void tick() {
- if (this.emptyPos != null) {
- if (Butterfly.this.hasReachedPosition(this.emptyPos)) {
- Vec3 hoverPos = Vec3.atBottomCenterOf(this.emptyPos).add(0.0D, 0.6F, 0.0D);
- Butterfly.this.getMoveControl().setWantedPosition(hoverPos.x(), hoverPos.y(), hoverPos.z(), 0.35F);
- Butterfly.this.navigation.stop();
- ++this.plantingTicks;
- } else {
- Butterfly.this.navigation.moveTo(this.emptyPos.getX() + 0.5D, this.emptyPos.getY() + 0.5D, this.emptyPos.getZ() + 0.5D, 0.85F);
- }
- }
- }
- /**
- * @return a random empty space near the original flower pos a butterfly can plant a flower at.
- */
- private BlockPos findRandomEmptyPos() {
- Map<Integer, BlockPos> map = Maps.newHashMap();
- BlockPos flowerPos = Butterfly.this.pollinateGoal.flowerPos;
- BlockPos currentPos = flowerPos != null ? flowerPos : Butterfly.this.blockPosition();
- for (int i = 0; i <= 14; i++) {
- BlockPos pos;
- int x = Mth.floor(currentPos.getX() + (random.nextBoolean() ? random.nextInt(3) : -random.nextInt(3)));
- int y = Mth.floor(currentPos.getY());
- int z = Mth.floor(currentPos.getZ() + (random.nextBoolean() ? random.nextInt(3) : -random.nextInt(3)));
- pos = new BlockPos(x, y, z);
- if (Butterfly.this.level().getBlockState(pos).isAir() && Butterfly.this.level().getBlockState(pos.below()).is(Blocks.GRASS_BLOCK)) {
- map.put(i, pos);
- }
- }
- return map.get(0);
- }
- }
- class WanderGoal extends Goal {
- WanderGoal() {
- this.setFlags(EnumSet.of(Goal.Flag.MOVE));
- }
- public boolean canUse() {
- return Butterfly.this.navigation.isDone() && Butterfly.this.random.nextInt(10) == 0;
- }
- public boolean canContinueToUse() {
- return Butterfly.this.navigation.isInProgress();
- }
- public void start() {
- Vec3 vec3 = this.findPos();
- if (vec3 != null) {
- Butterfly.this.navigation.moveTo(Butterfly.this.navigation.createPath(BlockPos.containing(vec3), 1), 1.0D);
- }
- }
- @Nullable
- private Vec3 findPos() {
- Vec3 vec3;
- if (Butterfly.this.isNestValid() && Butterfly.this.nestPos != null && !Butterfly.this.isCloserThan(Butterfly.this.nestPos, 22)) {
- Vec3 vec31 = Vec3.atCenterOf(Butterfly.this.nestPos);
- vec3 = vec31.subtract(Butterfly.this.position()).normalize();
- } else {
- vec3 = Butterfly.this.getViewVector(0.0F);
- }
- Vec3 vec32 = HoverRandomPos.getPos(Butterfly.this, 8, 7, vec3.x, vec3.z, ((float)Math.PI / 2F), 3, 1);
- return vec32 != null ? vec32 : AirAndWaterRandomPos.getPos(Butterfly.this, 8, 4, -2, vec3.x, vec3.z, ((float)Math.PI / 2F));
- }
- }
- class ButterflyLookControl extends LookControl {
- ButterflyLookControl(Mob mob) {
- super(mob);
- }
- public void tick() {
- super.tick();
- }
- protected boolean resetXRotOnTick() {
- return !Butterfly.this.pollinateGoal.isPollinating();
- }
- }
- public enum Type implements StringRepresentable {
- APRICOT(0, "monarch");
- //CITRUS(1, "citrus"),
- //MYSTIC(2, "mystic"),
- //VALENTINE(3, "valentine"),
- //JELLY(4, "jelly"),
- //AUGUST(5, "august"),
- //MARSHMALLOW(6, "marshmallow");
- private final int id;
- private final String name;
- Type(int id, String name) {
- this.id = id;
- this.name = name;
- }
- public int getId() {
- return this.id;
- }
- public String getSerializedName() {
- return this.name;
- }
- public static Type byId(int id) {
- return ByIdMap.continuous(Type::getId, values(), ByIdMap.OutOfBoundsStrategy.ZERO).apply(id);
- }
- public static Type byName(String name) {
- return StringRepresentable.fromEnum(Type::values).byName(name, APRICOT);
- }
- }
- }
Add Comment
Please, Sign In to add comment