Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package com.mysticsbiomes.common.entity.animal.butterfly;
- 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.core.registries.Registries;
- 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.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.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.entity.BlockEntity;
- import net.minecraft.world.level.block.state.BlockState;
- import net.minecraft.world.level.gameevent.GameEvent;
- import net.minecraft.world.level.pathfinder.BlockPathTypes;
- 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.IntFunction;
- 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 TamableAnimal implements FlyingAnimal {
- private static final EntityDataAccessor<Integer> DATA_TYPE_ID = SynchedEntityData.defineId(Butterfly.class, EntityDataSerializers.INT);
- private static final EntityDataAccessor<Byte> DATA_FLAGS_ID = SynchedEntityData.defineId(Butterfly.class, EntityDataSerializers.BYTE);
- private int remainingTicksBeforeLocatingNewNest;
- private int remainingTicksBeforeCanPollinate;
- private int ticksSinceLastSleptInNest;
- private boolean wasGivenFlower;
- @Nullable
- private BlockPos nestPos;
- @Nullable
- private Block givenFlower;
- Butterfly.PollinateFlowerGoal pollinateFlowerGoal;
- Butterfly.PlantFlowerGoal plantFlowerGoal;
- 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 Butterfly.LookControl(this);
- this.setPathfindingMalus(BlockPathTypes.DANGER_FIRE, -1.0F);
- this.setPathfindingMalus(BlockPathTypes.WATER, -1.0F);
- this.setPathfindingMalus(BlockPathTypes.FENCE, -1.0F);
- }
- // DATA & TYPES
- protected void defineSynchedData() {
- super.defineSynchedData();
- this.entityData.define(DATA_TYPE_ID, 0);
- this.entityData.define(DATA_FLAGS_ID, (byte)0);
- }
- protected void registerGoals() {
- this.pollinateFlowerGoal = new PollinateFlowerGoal();
- this.goalSelector.addGoal(0, this.pollinateFlowerGoal);
- this.plantFlowerGoal = new PlantFlowerGoal();
- this.goalSelector.addGoal(0, this.plantFlowerGoal);
- this.goalSelector.addGoal(1, new Butterfly.EnterNestGoal());
- this.goalSelector.addGoal(2, new TemptGoal(this, 1.25D, Ingredient.of(ItemTags.FLOWERS), false));
- this.goalSelector.addGoal(3, new Butterfly.LocateNestGoal());
- this.goalSelector.addGoal(3, new Butterfly.GoToNestGoal());
- this.goalSelector.addGoal(4, new Butterfly.WanderGoal());
- this.goalSelector.addGoal(5, 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, 48.0D);
- }
- @Override
- public void addAdditionalSaveData(CompoundTag tag) {
- super.addAdditionalSaveData(tag);
- if (this.nestPos != null) {
- tag.put("NestPos", NbtUtils.writeBlockPos(this.nestPos));
- }
- if (this.givenFlower != null) {
- tag.putString("GivenFlower", this.givenFlower.getDescriptionId());
- }
- tag.putString("Type", this.getVariant().name);
- tag.putBoolean("HasNectar", this.hasNectar());
- tag.putInt("TicksBeforeCanPollinate", this.remainingTicksBeforeCanPollinate);
- tag.putInt("TicksSinceLastSlept", this.ticksSinceLastSleptInNest);
- }
- @Override
- public void readAdditionalSaveData(CompoundTag tag) {
- super.readAdditionalSaveData(tag);
- this.nestPos = null;
- if (tag.contains("NestPos")) {
- this.nestPos = NbtUtils.readBlockPos(tag.getCompound("NestPos"));
- }
- this.givenFlower = null;
- if (tag.contains("GivenFlower")) {
- this.givenFlower = NbtUtils.readBlockState(this.level().holderLookup(Registries.BLOCK), tag.getCompound("GivenFlower")).getBlock();
- }
- this.setVariant(Type.byName(tag.getString("Type")));
- this.setHasNectar(tag.getBoolean("HasNectar"));
- this.remainingTicksBeforeCanPollinate = tag.getInt("TicksBeforeCanPollinate");
- this.ticksSinceLastSleptInNest = tag.getInt("TicksSinceLastSlept");
- }
- 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.id);
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // TICKS & AI STEPS
- 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);
- }
- }
- }
- public void aiStep() {
- super.aiStep();
- if (!this.level().isClientSide) {
- if (this.remainingTicksBeforeLocatingNewNest > 0) {
- --this.remainingTicksBeforeLocatingNewNest;
- }
- if (this.remainingTicksBeforeCanPollinate > 0) {
- --this.remainingTicksBeforeCanPollinate;
- }
- ++this.ticksSinceLastSleptInNest;
- if (this.tickCount % 20 == 0 && !this.isNestValid()) {
- this.nestPos = null;
- }
- }
- }
- protected void customServerAiStep() {
- if (this.isInWaterOrBubble()) {
- ++this.underWaterTicks;
- } else {
- this.underWaterTicks = 0;
- }
- if (this.underWaterTicks > 20) {
- this.hurt(this.damageSources().drown(), 1.0F);
- }
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // PARTICLES
- 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);
- }
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // MOVEMENT
- protected PathNavigation createNavigation(Level level) {
- FlyingPathNavigation navigation = new FlyingPathNavigation(this, level) {
- public boolean isStableDestination(BlockPos pos) {
- return !this.level.getBlockState(pos.below()).isAir();
- }
- public void tick() {
- super.tick();
- }
- };
- navigation.setCanOpenDoors(false);
- navigation.setCanFloat(false);
- navigation.setCanPassDoors(true);
- return navigation;
- }
- protected void checkFallDamage(double distance, boolean b, BlockState state, BlockPos pos) {
- }
- public float getWalkTargetValue(BlockPos pos, LevelReader reader) {
- return reader.getBlockState(pos).isAir() ? 5.0F : 0.0F;
- }
- public boolean isFlying() {
- return !this.onGround();
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // DISTANCE & PATHFINDING
- private Optional<BlockPos> findNearestBlock(Block block, double distance) {
- return this.findNearestBlock((b) -> b.defaultBlockState().is(block), distance);
- }
- private Optional<BlockPos> findNearestBlock(Predicate<Block> 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).getBlock())) {
- 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 hasReachedTarget(BlockPos pos) {
- if (Butterfly.this.closerThan(pos, 0)) {
- return Butterfly.this.blockPosition().equals(pos);
- } else {
- Path path = Butterfly.this.navigation.getPath();
- return path != null && path.getTarget().equals(pos) && path.canReach() && path.isDone();
- }
- }
- private boolean isTooFarAway(BlockPos pos) {
- return !this.closerThan(pos, 32);
- }
- private boolean closerThan(BlockPos pos, int distance) {
- return pos != null && pos.closerThan(this.blockPosition(), distance);
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // POSITION
- @Nullable
- private Vec3 hoverPos;
- private void setPollinatingPos(BlockPos pos) {
- Vec3 vec3 = Vec3.atBottomCenterOf(pos).add(0.0D, 0.6F, 0.0D);
- if (vec3.distanceTo(Butterfly.this.position()) > 1.0D) {
- this.hoverPos = vec3;
- this.setWantedPos();
- } else {
- if (this.hoverPos == null) {
- this.hoverPos = vec3;
- }
- boolean flag = Butterfly.this.position().distanceTo(this.hoverPos) <= 0.1D;
- boolean flag1 = true;
- if (flag) {
- boolean flag2 = Butterfly.this.random.nextInt(100) < 5;
- if (flag2) {
- this.hoverPos = new Vec3(vec3.x() + (double)this.getOffset(), vec3.y(), vec3.z() + (double)this.getOffset());
- Butterfly.this.navigation.stop();
- } else {
- flag1 = false;
- }
- Butterfly.this.getLookControl().setLookAt(vec3.x(), vec3.y(), vec3.z());
- }
- if (flag1) {
- this.setWantedPos();
- }
- }
- }
- private void setWantedPos() {
- if (this.hoverPos != null) {
- Butterfly.this.getMoveControl().setWantedPosition(this.hoverPos.x(), this.hoverPos.y(), this.hoverPos.z(), 0.35F);
- }
- }
- private float getOffset() {
- return (Butterfly.this.random.nextFloat() * 2.0F - 1.0F) * 0.33333334F;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // NEST & SLEEP
- /**
- * @return if a butterfly hasn't slept in over half a day, or has planted flowers.
- */
- private boolean isTired() {
- return this.ticksSinceLastSleptInNest > 18000;
- }
- 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;
- }
- }
- public boolean wantsToEnterNest() {
- boolean flag = this.isTired() || this.level().isRaining() || this.level().isNight();
- return flag && !this.isNestNearFire();
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // BEFRIENDING
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // FLOWER BREEDING
- public boolean isFlowerValid(BlockPos pos) {
- return this.level().isLoaded(pos) && this.level().getBlockState(pos).is(BlockTags.FLOWERS);
- }
- public boolean hasNectar() {
- return this.getFlag();
- }
- public void setHasNectar(boolean b) {
- this.setFlag(b);
- }
- private boolean canPollinateOrPlantFlowers() {
- return this.remainingTicksBeforeCanPollinate == 0;
- }
- @Override
- public InteractionResult mobInteract(Player player, InteractionHand hand) {
- Block block = Block.byItem(player.getItemInHand(hand).getItem());
- if (block.defaultBlockState().is(BlockTags.SMALL_FLOWERS)) {
- if (this.canPollinateOrPlantFlowers()) {
- this.givenFlower = block;
- this.wasGivenFlower = true;
- this.addParticlesAroundSelf(ParticleTypes.HAPPY_VILLAGER);
- return InteractionResult.SUCCESS;
- } else {
- this.addParticlesAroundSelf(ParticleTypes.ANGRY_VILLAGER);
- return InteractionResult.FAIL;
- }
- }
- return super.mobInteract(player, hand);
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // OTHER
- public boolean hurt(DamageSource source, float amount) {
- if (this.isInvulnerableTo(source)) {
- return false;
- } else {
- if (!this.level().isClientSide) {
- this.pollinateFlowerGoal.stopPollinating();
- }
- return super.hurt(source, amount);
- }
- }
- private boolean getFlag() {
- return (this.entityData.get(DATA_FLAGS_ID) & 8) != 0;
- }
- private void setFlag(boolean b) {
- if (b) {
- this.entityData.set(DATA_FLAGS_ID, (byte)(this.entityData.get(DATA_FLAGS_ID) | 8));
- } else {
- this.entityData.set(DATA_FLAGS_ID, (byte)(this.entityData.get(DATA_FLAGS_ID) & ~8));
- }
- }
- 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();
- }
- @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;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // GOALS
- /**
- * 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.hasReachedTarget(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.closerThan(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 entity = Butterfly.this.level().getBlockEntity(Butterfly.this.nestPos);
- if (entity instanceof ButterflyNestBlockEntity blockEntity) {
- return !blockEntity.isFull();
- }
- }
- return false;
- }
- public boolean canContinueToUse() {
- return false;
- }
- public void start() {
- if (Butterfly.this.nestPos != null) {
- BlockEntity entity = Butterfly.this.level().getBlockEntity(Butterfly.this.nestPos);
- if (entity instanceof ButterflyNestBlockEntity blockEntity) {
- blockEntity.addOccupant(Butterfly.this);
- }
- }
- }
- public void stop() {
- Butterfly.this.ticksSinceLastSleptInNest = 0;
- Butterfly.this.setHasNectar(false);
- super.stop();
- }
- }
- /**
- * Either pollinates a random flower or locates and pollinates the same flower a player gave them.
- */
- class PollinateFlowerGoal extends Goal {
- 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.canPollinateOrPlantFlowers()) {
- return false;
- } else {
- return Butterfly.this.wasGivenFlower && !Butterfly.this.hasNectar();
- }
- }
- public boolean canContinueToUse() {
- if (Butterfly.this.level().isRaining()) {
- return false;
- } else if (!Butterfly.this.isFlowerValid(this.flowerPos)) {
- this.flowerPos = null;
- return false;
- } else {
- return !this.hasPollinatedLongEnough();
- }
- }
- public void start() {
- this.pollinatingTicks = 0;
- this.pollinating = true;
- Optional<BlockPos> optional = Butterfly.this.findNearestBlock(Butterfly.this.givenFlower, 16.0D);
- if (optional.isPresent() && this.flowerPos == null) {
- this.flowerPos = optional.get();
- }
- }
- public void stop() {
- if (this.hasPollinatedLongEnough()) {
- Butterfly.this.setHasNectar(true);
- }
- this.pollinating = false;
- this.flowerPos = null;
- }
- public boolean requiresUpdateEveryTick() {
- return true;
- }
- public void tick() {
- if (this.flowerPos != null) {
- if (Butterfly.this.hasReachedTarget(this.flowerPos)) {
- Butterfly.this.setPollinatingPos(this.flowerPos);
- ++this.pollinatingTicks;
- } else {
- Butterfly.this.navigation.moveTo(this.flowerPos.getX() + 0.5D, this.flowerPos.getY() + 0.5D, this.flowerPos.getZ() + 0.5D, 0.85F);
- }
- }
- }
- public void stopPollinating() {
- this.pollinating = false;
- }
- public boolean isPollinating() {
- return this.pollinating;
- }
- private boolean hasPollinatedLongEnough() {
- return this.pollinatingTicks > 400;
- }
- }
- /**
- * Will start when the butterfly has a valid given flower from the player, and they have found and pollinated the same flower.
- */
- class PlantFlowerGoal extends Goal {
- private int plantingFlowerTicks;
- private int flowersPlanted;
- @Nullable
- private BlockPos emptyPos;
- PlantFlowerGoal() {
- this.setFlags(EnumSet.of(Goal.Flag.MOVE));
- }
- public boolean canUse() {
- if (this.flowersPlanted < 2) {
- return Butterfly.this.wasGivenFlower && Butterfly.this.hasNectar();
- } else {
- return false;
- }
- }
- public boolean canContinueToUse() {
- return this.plantingFlowerTicks <= 100;
- }
- public void start() {
- this.plantingFlowerTicks = 0;
- BlockPos pos = null;
- Optional<BlockPos> optional = Butterfly.this.findNearestBlock(Blocks.GRASS_BLOCK, 4.0D);
- if (optional.isPresent()) {
- int x = Mth.floor(optional.get().getX() + (random.nextBoolean() ? random.nextInt(4) : -random.nextInt(4)));
- int y = Mth.floor(optional.get().above().getY());
- int z = Mth.floor(optional.get().getZ() + (random.nextBoolean() ? random.nextInt(4) : -random.nextInt(4)));
- pos = new BlockPos(x, y, z);
- }
- List<BlockPos> posList = new ArrayList<>(18);
- for (int i = 0; i < 18; i++) {
- if (pos != null && Butterfly.this.level().getBlockState(pos).isAir()) {
- if (!posList.contains(pos)) {
- posList.add(pos);
- }
- }
- }
- this.emptyPos = posList.get(0);
- }
- public void stop() {
- this.flowersPlanted = this.flowersPlanted + 1;
- Butterfly.this.setHasNectar(false);
- if (this.flowersPlanted < 2) {
- if (!Butterfly.this.level().isClientSide) {
- int x = Mth.floor(Butterfly.this.getX());
- int y = Mth.floor(Butterfly.this.getY());
- int z = Mth.floor(Butterfly.this.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));
- }
- }
- }
- this.repeat();
- } else {
- this.flowersPlanted = 0;
- Butterfly.this.wasGivenFlower = false;
- Butterfly.this.remainingTicksBeforeCanPollinate = 1600;
- Butterfly.this.navigation.stop();
- }
- }
- public boolean requiresUpdateEveryTick() {
- return true;
- }
- public void tick() {
- if (this.emptyPos != null) {
- if (Butterfly.this.hasReachedTarget(this.emptyPos)) {
- Butterfly.this.setPollinatingPos(this.emptyPos);
- ++this.plantingFlowerTicks;
- } else {
- Butterfly.this.navigation.moveTo(this.emptyPos.getX() + 0.5D, this.emptyPos.getY() + 0.5D, this.emptyPos.getZ() + 0.5D, 0.85F);
- }
- }
- }
- /**
- * Repeat until butterfly has planted 2 flowers.
- */
- private void repeat() {
- Butterfly.this.wasGivenFlower = true;
- }
- }
- class LookControl extends net.minecraft.world.entity.ai.control.LookControl {
- public LookControl(Mob mob) {
- super(mob);
- }
- protected boolean resetXRotOnTick() {
- return !Butterfly.this.pollinateFlowerGoal.isPollinating();
- }
- }
- 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.closerThan(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));
- }
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // TYPES
- public enum Type implements StringRepresentable {
- APRICOT(0, "apricot"),
- CITRUS(1, "citrus"),
- MYSTIC(2, "mystic"),
- //plum
- //valentine
- //berry
- //coral
- JELLY(3, "jelly"),
- AUGUST(4, "august");
- //evergreen (lime)
- //everest (dark green)
- //ebony (black)
- @SuppressWarnings("deprecation")
- public static final StringRepresentable.EnumCodec<Type> CODEC = StringRepresentable.fromEnum(Type::values);
- private static final IntFunction<Type> BY_ID = ByIdMap.continuous(Type::getId, values(), ByIdMap.OutOfBoundsStrategy.ZERO);
- private final int id;
- private final String name;
- Type(int id, String name) {
- this.id = id;
- this.name = name;
- }
- public String getSerializedName() {
- return this.name;
- }
- public int getId() {
- return this.id;
- }
- public static Type byName(String name) {
- return CODEC.byName(name, APRICOT);
- }
- public static Type byId(int id) {
- return BY_ID.apply(id);
- }
- }
- }
Add Comment
Please, Sign In to add comment