jayhillx

butterflies (alpha)

Sep 6th, 2023
163
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 33.41 KB | None | 0 0
  1. package com.mysticsbiomes.common.entity.animal.butterfly;
  2.  
  3. import com.mysticsbiomes.common.block.entity.ButterflyNestBlockEntity;
  4. import com.mysticsbiomes.init.MysticBlocks;
  5. import com.mysticsbiomes.init.MysticPoiTypes;
  6. import com.mysticsbiomes.init.MysticSounds;
  7. import net.minecraft.core.BlockPos;
  8. import net.minecraft.core.particles.ParticleOptions;
  9. import net.minecraft.core.particles.ParticleTypes;
  10. import net.minecraft.core.registries.Registries;
  11. import net.minecraft.nbt.CompoundTag;
  12. import net.minecraft.nbt.NbtUtils;
  13. import net.minecraft.network.syncher.EntityDataAccessor;
  14. import net.minecraft.network.syncher.EntityDataSerializers;
  15. import net.minecraft.network.syncher.SynchedEntityData;
  16. import net.minecraft.server.level.ServerLevel;
  17. import net.minecraft.sounds.SoundEvent;
  18. import net.minecraft.tags.BlockTags;
  19. import net.minecraft.tags.ItemTags;
  20. import net.minecraft.util.ByIdMap;
  21. import net.minecraft.util.Mth;
  22. import net.minecraft.util.StringRepresentable;
  23. import net.minecraft.world.DifficultyInstance;
  24. import net.minecraft.world.InteractionHand;
  25. import net.minecraft.world.InteractionResult;
  26. import net.minecraft.world.damagesource.DamageSource;
  27. import net.minecraft.world.entity.*;
  28. import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
  29. import net.minecraft.world.entity.ai.attributes.Attributes;
  30. import net.minecraft.world.entity.ai.control.FlyingMoveControl;
  31. import net.minecraft.world.entity.ai.goal.FloatGoal;
  32. import net.minecraft.world.entity.ai.goal.Goal;
  33. import net.minecraft.world.entity.ai.goal.TemptGoal;
  34. import net.minecraft.world.entity.ai.navigation.FlyingPathNavigation;
  35. import net.minecraft.world.entity.ai.navigation.PathNavigation;
  36. import net.minecraft.world.entity.ai.util.AirAndWaterRandomPos;
  37. import net.minecraft.world.entity.ai.util.AirRandomPos;
  38. import net.minecraft.world.entity.ai.util.HoverRandomPos;
  39. import net.minecraft.world.entity.ai.village.poi.PoiManager;
  40. import net.minecraft.world.entity.ai.village.poi.PoiRecord;
  41. import net.minecraft.world.entity.animal.FlyingAnimal;
  42. import net.minecraft.world.entity.player.Player;
  43. import net.minecraft.world.item.crafting.Ingredient;
  44. import net.minecraft.world.level.Level;
  45. import net.minecraft.world.level.LevelReader;
  46. import net.minecraft.world.level.ServerLevelAccessor;
  47. import net.minecraft.world.level.block.Block;
  48. import net.minecraft.world.level.block.Blocks;
  49. import net.minecraft.world.level.block.entity.BlockEntity;
  50. import net.minecraft.world.level.block.state.BlockState;
  51. import net.minecraft.world.level.gameevent.GameEvent;
  52. import net.minecraft.world.level.pathfinder.BlockPathTypes;
  53. import net.minecraft.world.level.pathfinder.Path;
  54. import net.minecraft.world.phys.Vec3;
  55. import org.jetbrains.annotations.Nullable;
  56.  
  57. import java.util.*;
  58. import java.util.function.IntFunction;
  59. import java.util.function.Predicate;
  60. import java.util.stream.Collectors;
  61. import java.util.stream.Stream;
  62.  
  63. /**
  64.  * Butterflies are friendly ambient anthropoids, useful for growing flowers.
  65.  */
  66. public class Butterfly extends TamableAnimal implements FlyingAnimal {
  67.     private static final EntityDataAccessor<Integer> DATA_TYPE_ID = SynchedEntityData.defineId(Butterfly.class, EntityDataSerializers.INT);
  68.     private static final EntityDataAccessor<Byte> DATA_FLAGS_ID = SynchedEntityData.defineId(Butterfly.class, EntityDataSerializers.BYTE);
  69.     private int remainingTicksBeforeLocatingNewNest;
  70.     private int remainingTicksBeforeCanPollinate;
  71.     private int ticksSinceLastSleptInNest;
  72.     private boolean wasGivenFlower;
  73.     @Nullable
  74.     private BlockPos nestPos;
  75.     @Nullable
  76.     private Block givenFlower;
  77.     Butterfly.PollinateFlowerGoal pollinateFlowerGoal;
  78.     Butterfly.PlantFlowerGoal plantFlowerGoal;
  79.     private int underWaterTicks;
  80.  
  81.     public final AnimationState flyingAnimationState = new AnimationState();
  82.  
  83.     public Butterfly(EntityType<? extends Butterfly> entityType, Level level) {
  84.         super(entityType, level);
  85.         this.moveControl = new FlyingMoveControl(this, 20, true);
  86.         this.lookControl = new Butterfly.LookControl(this);
  87.         this.setPathfindingMalus(BlockPathTypes.DANGER_FIRE, -1.0F);
  88.         this.setPathfindingMalus(BlockPathTypes.WATER, -1.0F);
  89.         this.setPathfindingMalus(BlockPathTypes.FENCE, -1.0F);
  90.     }
  91.  
  92.     // DATA & TYPES
  93.  
  94.     protected void defineSynchedData() {
  95.         super.defineSynchedData();
  96.         this.entityData.define(DATA_TYPE_ID, 0);
  97.         this.entityData.define(DATA_FLAGS_ID, (byte)0);
  98.     }
  99.  
  100.     protected void registerGoals() {
  101.         this.pollinateFlowerGoal = new PollinateFlowerGoal();
  102.         this.goalSelector.addGoal(0, this.pollinateFlowerGoal);
  103.         this.plantFlowerGoal = new PlantFlowerGoal();
  104.         this.goalSelector.addGoal(0, this.plantFlowerGoal);
  105.         this.goalSelector.addGoal(1, new Butterfly.EnterNestGoal());
  106.         this.goalSelector.addGoal(2, new TemptGoal(this, 1.25D, Ingredient.of(ItemTags.FLOWERS), false));
  107.         this.goalSelector.addGoal(3, new Butterfly.LocateNestGoal());
  108.         this.goalSelector.addGoal(3, new Butterfly.GoToNestGoal());
  109.         this.goalSelector.addGoal(4, new Butterfly.WanderGoal());
  110.         this.goalSelector.addGoal(5, new FloatGoal(this));
  111.     }
  112.  
  113.     public static AttributeSupplier.Builder createAttributes() {
  114.         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);
  115.     }
  116.  
  117.     @Override
  118.     public void addAdditionalSaveData(CompoundTag tag) {
  119.         super.addAdditionalSaveData(tag);
  120.         if (this.nestPos != null) {
  121.             tag.put("NestPos", NbtUtils.writeBlockPos(this.nestPos));
  122.         }
  123.  
  124.         if (this.givenFlower != null) {
  125.             tag.putString("GivenFlower", this.givenFlower.getDescriptionId());
  126.         }
  127.  
  128.         tag.putString("Type", this.getVariant().name);
  129.         tag.putBoolean("HasNectar", this.hasNectar());
  130.         tag.putInt("TicksBeforeCanPollinate", this.remainingTicksBeforeCanPollinate);
  131.         tag.putInt("TicksSinceLastSlept", this.ticksSinceLastSleptInNest);
  132.     }
  133.  
  134.     @Override
  135.     public void readAdditionalSaveData(CompoundTag tag) {
  136.         super.readAdditionalSaveData(tag);
  137.  
  138.         this.nestPos = null;
  139.         if (tag.contains("NestPos")) {
  140.             this.nestPos = NbtUtils.readBlockPos(tag.getCompound("NestPos"));
  141.         }
  142.  
  143.         this.givenFlower = null;
  144.         if (tag.contains("GivenFlower")) {
  145.             this.givenFlower = NbtUtils.readBlockState(this.level().holderLookup(Registries.BLOCK), tag.getCompound("GivenFlower")).getBlock();
  146.         }
  147.  
  148.         this.setVariant(Type.byName(tag.getString("Type")));
  149.         this.setHasNectar(tag.getBoolean("HasNectar"));
  150.         this.remainingTicksBeforeCanPollinate = tag.getInt("TicksBeforeCanPollinate");
  151.         this.ticksSinceLastSleptInNest = tag.getInt("TicksSinceLastSlept");
  152.     }
  153.  
  154.     public AgeableMob getBreedOffspring(ServerLevel level, AgeableMob mob) {
  155.         return null;
  156.     }
  157.  
  158.     public MobType getMobType() {
  159.         return MobType.ARTHROPOD;
  160.     }
  161.  
  162.     public Type getVariant() {
  163.         return Type.byId(this.entityData.get(DATA_TYPE_ID));
  164.     }
  165.  
  166.     public void setVariant(Type type) {
  167.         this.entityData.set(DATA_TYPE_ID, type.id);
  168.     }
  169.  
  170.     ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  171.  
  172.     // TICKS & AI STEPS
  173.  
  174.     public void tick() {
  175.         super.tick();
  176.  
  177.         if (this.level().isClientSide()) {
  178.             this.flyingAnimationState.animateWhen(this.isFlying(), this.tickCount);
  179.         }
  180.  
  181.         if (this.hasNectar() && this.random.nextFloat() < 0.05F) {
  182.             for (int i = 0; i < this.random.nextInt(2) + 1; ++i) {
  183.                 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);
  184.             }
  185.         }
  186.     }
  187.  
  188.     public void aiStep() {
  189.         super.aiStep();
  190.  
  191.         if (!this.level().isClientSide) {
  192.             if (this.remainingTicksBeforeLocatingNewNest > 0) {
  193.                 --this.remainingTicksBeforeLocatingNewNest;
  194.             }
  195.  
  196.             if (this.remainingTicksBeforeCanPollinate > 0) {
  197.                 --this.remainingTicksBeforeCanPollinate;
  198.             }
  199.  
  200.             ++this.ticksSinceLastSleptInNest;
  201.  
  202.             if (this.tickCount % 20 == 0 && !this.isNestValid()) {
  203.                 this.nestPos = null;
  204.             }
  205.         }
  206.     }
  207.  
  208.     protected void customServerAiStep() {
  209.         if (this.isInWaterOrBubble()) {
  210.             ++this.underWaterTicks;
  211.         } else {
  212.             this.underWaterTicks = 0;
  213.         }
  214.  
  215.         if (this.underWaterTicks > 20) {
  216.             this.hurt(this.damageSources().drown(), 1.0F);
  217.         }
  218.     }
  219.  
  220.     ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  221.  
  222.     // PARTICLES
  223.  
  224.     protected void addParticlesAroundSelf(ParticleOptions options) {
  225.         for (int i = 0; i < 5; ++i) {
  226.             double d0 = this.random.nextGaussian() * 0.02D;
  227.             double d1 = this.random.nextGaussian() * 0.02D;
  228.             double d2 = this.random.nextGaussian() * 0.02D;
  229.             this.level().addParticle(options, this.getRandomX(1.0D), this.getRandomY() + 1.0D, this.getRandomZ(1.0D), d0, d1, d2);
  230.         }
  231.     }
  232.  
  233.     ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  234.  
  235.     // MOVEMENT
  236.  
  237.     protected PathNavigation createNavigation(Level level) {
  238.         FlyingPathNavigation navigation = new FlyingPathNavigation(this, level) {
  239.             public boolean isStableDestination(BlockPos pos) {
  240.                 return !this.level.getBlockState(pos.below()).isAir();
  241.             }
  242.  
  243.             public void tick() {
  244.                 super.tick();
  245.             }
  246.         };
  247.         navigation.setCanOpenDoors(false);
  248.         navigation.setCanFloat(false);
  249.         navigation.setCanPassDoors(true);
  250.         return navigation;
  251.     }
  252.  
  253.     protected void checkFallDamage(double distance, boolean b, BlockState state, BlockPos pos) {
  254.     }
  255.  
  256.     public float getWalkTargetValue(BlockPos pos, LevelReader reader) {
  257.         return reader.getBlockState(pos).isAir() ? 5.0F : 0.0F;
  258.     }
  259.  
  260.     public boolean isFlying() {
  261.         return !this.onGround();
  262.     }
  263.  
  264.     ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  265.  
  266.     // DISTANCE & PATHFINDING
  267.  
  268.     private Optional<BlockPos> findNearestBlock(Block block, double distance) {
  269.         return this.findNearestBlock((b) -> b.defaultBlockState().is(block), distance);
  270.     }
  271.  
  272.     private Optional<BlockPos> findNearestBlock(Predicate<Block> predicate, double distance) {
  273.         BlockPos pos = Butterfly.this.blockPosition();
  274.         BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos();
  275.  
  276.         for (int i = 0; (double)i <= distance; i = i > 0 ? -i : 1 - i) {
  277.             for (int j = 0; (double)j < distance; ++j) {
  278.                 for (int k = 0; k <= j; k = k > 0 ? -k : 1 - k) {
  279.                     for (int l = k < j && k > -j ? j : 0; l <= j; l = l > 0 ? -l : 1 - l) {
  280.                         mutablePos.setWithOffset(pos, k, i - 1, l);
  281.  
  282.                         if (pos.closerThan(mutablePos, distance) && predicate.test(Butterfly.this.level().getBlockState(mutablePos).getBlock())) {
  283.                             return Optional.of(mutablePos);
  284.                         }
  285.                     }
  286.                 }
  287.             }
  288.         }
  289.         return Optional.empty();
  290.     }
  291.  
  292.     private void pathfindRandomlyTowards(BlockPos pos) {
  293.         Vec3 vec3 = Vec3.atBottomCenterOf(pos);
  294.         int i = 0;
  295.         BlockPos pos1 = this.blockPosition();
  296.         int j = (int)vec3.y - pos1.getY();
  297.         if (j > 2) {
  298.             i = 4;
  299.         } else if (j < -2) {
  300.             i = -4;
  301.         }
  302.  
  303.         int k = 6;
  304.         int l = 8;
  305.         int i1 = pos1.distManhattan(pos);
  306.         if (i1 < 15) {
  307.             k = i1 / 2;
  308.             l = i1 / 2;
  309.         }
  310.  
  311.         Vec3 vec31 = AirRandomPos.getPosTowards(this, k, l, i, vec3, (float)Math.PI / 10F);
  312.         if (vec31 != null) {
  313.             this.navigation.setMaxVisitedNodesMultiplier(0.5F);
  314.             this.navigation.moveTo(vec31.x, vec31.y, vec31.z, 1.0D);
  315.         }
  316.     }
  317.  
  318.     private boolean pathfindDirectlyTowards(BlockPos pos) {
  319.         Butterfly.this.navigation.setMaxVisitedNodesMultiplier(10.0F);
  320.         Butterfly.this.navigation.moveTo(pos.getX(), pos.getY(), pos.getZ(), 1.0D);
  321.         return Butterfly.this.navigation.getPath() != null && Butterfly.this.navigation.getPath().canReach();
  322.     }
  323.  
  324.     private boolean hasReachedTarget(BlockPos pos) {
  325.         if (Butterfly.this.closerThan(pos, 0)) {
  326.             return Butterfly.this.blockPosition().equals(pos);
  327.         } else {
  328.             Path path = Butterfly.this.navigation.getPath();
  329.             return path != null && path.getTarget().equals(pos) && path.canReach() && path.isDone();
  330.         }
  331.     }
  332.  
  333.     private boolean isTooFarAway(BlockPos pos) {
  334.         return !this.closerThan(pos, 32);
  335.     }
  336.  
  337.     private boolean closerThan(BlockPos pos, int distance) {
  338.         return pos != null && pos.closerThan(this.blockPosition(), distance);
  339.     }
  340.  
  341.     ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  342.  
  343.     // POSITION
  344.  
  345.     @Nullable
  346.     private Vec3 hoverPos;
  347.  
  348.     private void setPollinatingPos(BlockPos pos) {
  349.         Vec3 vec3 = Vec3.atBottomCenterOf(pos).add(0.0D, 0.6F, 0.0D);
  350.  
  351.         if (vec3.distanceTo(Butterfly.this.position()) > 1.0D) {
  352.             this.hoverPos = vec3;
  353.             this.setWantedPos();
  354.         } else {
  355.             if (this.hoverPos == null) {
  356.                 this.hoverPos = vec3;
  357.             }
  358.  
  359.             boolean flag = Butterfly.this.position().distanceTo(this.hoverPos) <= 0.1D;
  360.             boolean flag1 = true;
  361.             if (flag) {
  362.                 boolean flag2 = Butterfly.this.random.nextInt(100) < 5;
  363.                 if (flag2) {
  364.                     this.hoverPos = new Vec3(vec3.x() + (double)this.getOffset(), vec3.y(), vec3.z() + (double)this.getOffset());
  365.                     Butterfly.this.navigation.stop();
  366.                 } else {
  367.                     flag1 = false;
  368.                 }
  369.                 Butterfly.this.getLookControl().setLookAt(vec3.x(), vec3.y(), vec3.z());
  370.             }
  371.  
  372.             if (flag1) {
  373.                 this.setWantedPos();
  374.             }
  375.         }
  376.     }
  377.  
  378.     private void setWantedPos() {
  379.         if (this.hoverPos != null) {
  380.             Butterfly.this.getMoveControl().setWantedPosition(this.hoverPos.x(), this.hoverPos.y(), this.hoverPos.z(), 0.35F);
  381.         }
  382.     }
  383.  
  384.     private float getOffset() {
  385.         return (Butterfly.this.random.nextFloat() * 2.0F - 1.0F) * 0.33333334F;
  386.     }
  387.  
  388.     ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  389.  
  390.     // NEST & SLEEP
  391.  
  392.     /**
  393.      * @return if a butterfly hasn't slept in over half a day, or has planted flowers.
  394.      */
  395.     private boolean isTired() {
  396.         return this.ticksSinceLastSleptInNest > 18000;
  397.     }
  398.  
  399.     private boolean isNestValid() {
  400.         if (this.nestPos == null) {
  401.             return false;
  402.         } else if (this.isTooFarAway(this.nestPos)) {
  403.             return false;
  404.         } else {
  405.             BlockEntity blockEntity = this.level().getBlockEntity(this.nestPos);
  406.             return blockEntity instanceof ButterflyNestBlockEntity;
  407.         }
  408.     }
  409.  
  410.     private boolean isNestNearFire() {
  411.         if (this.nestPos == null) {
  412.             return false;
  413.         } else {
  414.             BlockEntity blockEntity = this.level().getBlockEntity(this.nestPos);
  415.             return blockEntity instanceof ButterflyNestBlockEntity && ((ButterflyNestBlockEntity)blockEntity).isFireNearby();
  416.         }
  417.     }
  418.  
  419.     private boolean doesNestHaveSpace(BlockPos pos) {
  420.         BlockEntity blockEntity = this.level().getBlockEntity(pos);
  421.  
  422.         if (blockEntity instanceof ButterflyNestBlockEntity entity) {
  423.             return !entity.isFull();
  424.         } else {
  425.             return false;
  426.         }
  427.     }
  428.  
  429.     public boolean wantsToEnterNest() {
  430.         boolean flag = this.isTired() || this.level().isRaining() || this.level().isNight();
  431.         return flag && !this.isNestNearFire();
  432.     }
  433.  
  434.     ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  435.  
  436.     // BEFRIENDING
  437.  
  438.     ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  439.  
  440.     // FLOWER BREEDING
  441.  
  442.     public boolean isFlowerValid(BlockPos pos) {
  443.         return this.level().isLoaded(pos) && this.level().getBlockState(pos).is(BlockTags.FLOWERS);
  444.     }
  445.  
  446.     public boolean hasNectar() {
  447.         return this.getFlag();
  448.     }
  449.  
  450.     public void setHasNectar(boolean b) {
  451.         this.setFlag(b);
  452.     }
  453.  
  454.     private boolean canPollinateOrPlantFlowers() {
  455.         return this.remainingTicksBeforeCanPollinate == 0;
  456.     }
  457.  
  458.     @Override
  459.     public InteractionResult mobInteract(Player player, InteractionHand hand) {
  460.         Block block = Block.byItem(player.getItemInHand(hand).getItem());
  461.  
  462.         if (block.defaultBlockState().is(BlockTags.SMALL_FLOWERS)) {
  463.             if (this.canPollinateOrPlantFlowers()) {
  464.                 this.givenFlower = block;
  465.  
  466.                 this.wasGivenFlower = true;
  467.                 this.addParticlesAroundSelf(ParticleTypes.HAPPY_VILLAGER);
  468.                 return InteractionResult.SUCCESS;
  469.             } else {
  470.                 this.addParticlesAroundSelf(ParticleTypes.ANGRY_VILLAGER);
  471.                 return InteractionResult.FAIL;
  472.             }
  473.         }
  474.         return super.mobInteract(player, hand);
  475.     }
  476.  
  477.     ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  478.  
  479.     // OTHER
  480.  
  481.     public boolean hurt(DamageSource source, float amount) {
  482.         if (this.isInvulnerableTo(source)) {
  483.             return false;
  484.         } else {
  485.             if (!this.level().isClientSide) {
  486.                 this.pollinateFlowerGoal.stopPollinating();
  487.             }
  488.             return super.hurt(source, amount);
  489.         }
  490.     }
  491.  
  492.     private boolean getFlag() {
  493.         return (this.entityData.get(DATA_FLAGS_ID) & 8) != 0;
  494.     }
  495.  
  496.     private void setFlag(boolean b) {
  497.         if (b) {
  498.             this.entityData.set(DATA_FLAGS_ID, (byte)(this.entityData.get(DATA_FLAGS_ID) | 8));
  499.         } else {
  500.             this.entityData.set(DATA_FLAGS_ID, (byte)(this.entityData.get(DATA_FLAGS_ID) & ~8));
  501.         }
  502.     }
  503.  
  504.     protected void playStepSound(BlockPos pos, BlockState state) {
  505.     }
  506.  
  507.     protected float getSoundVolume() {
  508.         return 0.4F;
  509.     }
  510.  
  511.     protected SoundEvent getAmbientSound() {
  512.         return MysticSounds.BUTTERFLY_AMBIENT.get();
  513.     }
  514.  
  515.     protected SoundEvent getHurtSound(DamageSource source) {
  516.         return MysticSounds.BUTTERFLY_HURT.get();
  517.     }
  518.  
  519.     protected SoundEvent getDeathSound() {
  520.         return MysticSounds.BUTTERFLY_DEATH.get();
  521.     }
  522.  
  523.     @Override
  524.     public SpawnGroupData finalizeSpawn(ServerLevelAccessor accessor, DifficultyInstance instance, MobSpawnType type, @Nullable SpawnGroupData data, @Nullable CompoundTag tag) {
  525.         data = super.finalizeSpawn(accessor, instance, type, data, tag);
  526.         this.setVariant(Type.byId(random.nextInt(3)));
  527.         return data;
  528.     }
  529.  
  530.     ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  531.  
  532.     // GOALS
  533.  
  534.     /**
  535.      * Sets the butterflies home/nest position by scoping out an available one nearby.
  536.      */
  537.     class LocateNestGoal extends Goal {
  538.  
  539.         public boolean canUse() {
  540.             return Butterfly.this.remainingTicksBeforeLocatingNewNest == 0 && Butterfly.this.nestPos == null && Butterfly.this.wantsToEnterNest();
  541.         }
  542.  
  543.         public boolean canContinueToUse() {
  544.             return false;
  545.         }
  546.  
  547.         public void start() {
  548.             Butterfly.this.remainingTicksBeforeLocatingNewNest = 200;
  549.  
  550.             List<BlockPos> list = this.findNearbyNestsWithSpace();
  551.             if (!list.isEmpty()) {
  552.                 for (BlockPos pos : list) {
  553.                     Butterfly.this.nestPos = pos;
  554.                     return;
  555.                 }
  556.                 Butterfly.this.nestPos = list.get(0);
  557.             }
  558.         }
  559.  
  560.         private List<BlockPos> findNearbyNestsWithSpace() {
  561.             BlockPos pos = Butterfly.this.blockPosition();
  562.             PoiManager poiManager = ((ServerLevel)Butterfly.this.level()).getPoiManager();
  563.  
  564.             Stream<PoiRecord> stream = poiManager.getInRange((holder) -> holder.is(MysticPoiTypes.BUTTERFLY_NEST.getId()), pos, 20, PoiManager.Occupancy.ANY);
  565.             return stream.map(PoiRecord::getPos).filter(Butterfly.this::doesNestHaveSpace).sorted(Comparator.comparingDouble((pos1) -> pos1.distSqr(pos))).collect(Collectors.toList());
  566.         }
  567.     }
  568.  
  569.     class GoToNestGoal extends Goal {
  570.         @Nullable
  571.         private Path lastPath;
  572.  
  573.         GoToNestGoal() {
  574.             this.setFlags(EnumSet.of(Goal.Flag.MOVE));
  575.         }
  576.  
  577.         public boolean canUse() {
  578.             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());
  579.         }
  580.  
  581.         public boolean canContinueToUse() {
  582.             return this.canUse();
  583.         }
  584.  
  585.         public void stop() {
  586.             Butterfly.this.navigation.stop();
  587.             Butterfly.this.navigation.resetMaxVisitedNodesMultiplier();
  588.         }
  589.  
  590.         public void tick() {
  591.             if (Butterfly.this.nestPos != null) {
  592.  
  593.                 if (!Butterfly.this.navigation.isInProgress()) {
  594.                     if (!Butterfly.this.closerThan(Butterfly.this.nestPos, 16)) {
  595.                         Butterfly.this.pathfindRandomlyTowards(Butterfly.this.nestPos);
  596.                     } else {
  597.                         boolean flag = Butterfly.this.pathfindDirectlyTowards(Butterfly.this.nestPos);
  598.  
  599.                         if (flag) {
  600.                             if (this.lastPath != null && Butterfly.this.navigation.getPath() != null && !Butterfly.this.navigation.getPath().sameAs(this.lastPath)) {
  601.                                 this.lastPath = Butterfly.this.navigation.getPath();
  602.                             }
  603.                         }
  604.                     }
  605.                 }
  606.             }
  607.         }
  608.     }
  609.  
  610.     class EnterNestGoal extends Goal {
  611.  
  612.         public boolean canUse() {
  613.             if (Butterfly.this.nestPos != null && Butterfly.this.wantsToEnterNest() && Butterfly.this.nestPos.closerToCenterThan(Butterfly.this.position(), 2.0D)) {
  614.                 BlockEntity entity = Butterfly.this.level().getBlockEntity(Butterfly.this.nestPos);
  615.  
  616.                 if (entity instanceof ButterflyNestBlockEntity blockEntity) {
  617.                     return !blockEntity.isFull();
  618.                 }
  619.             }
  620.             return false;
  621.         }
  622.  
  623.         public boolean canContinueToUse() {
  624.             return false;
  625.         }
  626.  
  627.         public void start() {
  628.             if (Butterfly.this.nestPos != null) {
  629.                 BlockEntity entity = Butterfly.this.level().getBlockEntity(Butterfly.this.nestPos);
  630.  
  631.                 if (entity instanceof ButterflyNestBlockEntity blockEntity) {
  632.                     blockEntity.addOccupant(Butterfly.this);
  633.                 }
  634.             }
  635.         }
  636.  
  637.         public void stop() {
  638.             Butterfly.this.ticksSinceLastSleptInNest = 0;
  639.             Butterfly.this.setHasNectar(false);
  640.             super.stop();
  641.         }
  642.     }
  643.  
  644.     /**
  645.      * Either pollinates a random flower or locates and pollinates the same flower a player gave them.
  646.      */
  647.     class PollinateFlowerGoal extends Goal {
  648.         private int pollinatingTicks;
  649.         private boolean pollinating;
  650.         @Nullable
  651.         private BlockPos flowerPos;
  652.  
  653.         PollinateFlowerGoal() {
  654.             this.setFlags(EnumSet.of(Goal.Flag.MOVE));
  655.         }
  656.  
  657.         public boolean canUse() {
  658.             if (Butterfly.this.level().isRaining()) {
  659.                 return false;
  660.             } else if (!Butterfly.this.canPollinateOrPlantFlowers()) {
  661.                 return false;
  662.             } else {
  663.                 return Butterfly.this.wasGivenFlower && !Butterfly.this.hasNectar();
  664.             }
  665.         }
  666.  
  667.         public boolean canContinueToUse() {
  668.             if (Butterfly.this.level().isRaining()) {
  669.                 return false;
  670.             } else if (!Butterfly.this.isFlowerValid(this.flowerPos)) {
  671.                 this.flowerPos = null;
  672.                 return false;
  673.             } else {
  674.                 return !this.hasPollinatedLongEnough();
  675.             }
  676.         }
  677.  
  678.         public void start() {
  679.             this.pollinatingTicks = 0;
  680.             this.pollinating = true;
  681.  
  682.             Optional<BlockPos> optional = Butterfly.this.findNearestBlock(Butterfly.this.givenFlower, 16.0D);
  683.             if (optional.isPresent() && this.flowerPos == null) {
  684.                 this.flowerPos = optional.get();
  685.             }
  686.         }
  687.  
  688.         public void stop() {
  689.             if (this.hasPollinatedLongEnough()) {
  690.                 Butterfly.this.setHasNectar(true);
  691.             }
  692.  
  693.             this.pollinating = false;
  694.             this.flowerPos = null;
  695.         }
  696.  
  697.         public boolean requiresUpdateEveryTick() {
  698.             return true;
  699.         }
  700.  
  701.         public void tick() {
  702.             if (this.flowerPos != null) {
  703.                 if (Butterfly.this.hasReachedTarget(this.flowerPos)) {
  704.                     Butterfly.this.setPollinatingPos(this.flowerPos);
  705.  
  706.                     ++this.pollinatingTicks;
  707.                 } else {
  708.                     Butterfly.this.navigation.moveTo(this.flowerPos.getX() + 0.5D, this.flowerPos.getY() + 0.5D, this.flowerPos.getZ() + 0.5D, 0.85F);
  709.                 }
  710.             }
  711.         }
  712.  
  713.         public void stopPollinating() {
  714.             this.pollinating = false;
  715.         }
  716.  
  717.         public boolean isPollinating() {
  718.             return this.pollinating;
  719.         }
  720.  
  721.         private boolean hasPollinatedLongEnough() {
  722.             return this.pollinatingTicks > 400;
  723.         }
  724.     }
  725.  
  726.     /**
  727.      * Will start when the butterfly has a valid given flower from the player, and they have found and pollinated the same flower.
  728.      */
  729.     class PlantFlowerGoal extends Goal {
  730.         private int plantingFlowerTicks;
  731.         private int flowersPlanted;
  732.         @Nullable
  733.         private BlockPos emptyPos;
  734.  
  735.         PlantFlowerGoal() {
  736.             this.setFlags(EnumSet.of(Goal.Flag.MOVE));
  737.         }
  738.  
  739.         public boolean canUse() {
  740.             if (this.flowersPlanted < 2) {
  741.                 return Butterfly.this.wasGivenFlower && Butterfly.this.hasNectar();
  742.             } else {
  743.                 return false;
  744.             }
  745.         }
  746.  
  747.         public boolean canContinueToUse() {
  748.             return this.plantingFlowerTicks <= 100;
  749.         }
  750.  
  751.         public void start() {
  752.             this.plantingFlowerTicks = 0;
  753.  
  754.             BlockPos pos = null;
  755.             Optional<BlockPos> optional = Butterfly.this.findNearestBlock(Blocks.GRASS_BLOCK, 4.0D);
  756.             if (optional.isPresent()) {
  757.                 int x = Mth.floor(optional.get().getX() + (random.nextBoolean() ? random.nextInt(4) : -random.nextInt(4)));
  758.                 int y = Mth.floor(optional.get().above().getY());
  759.                 int z = Mth.floor(optional.get().getZ() + (random.nextBoolean() ? random.nextInt(4) : -random.nextInt(4)));
  760.  
  761.                 pos = new BlockPos(x, y, z);
  762.             }
  763.  
  764.             List<BlockPos> posList = new ArrayList<>(18);
  765.             for (int i = 0; i < 18; i++) {
  766.                 if (pos != null && Butterfly.this.level().getBlockState(pos).isAir()) {
  767.                     if (!posList.contains(pos)) {
  768.                         posList.add(pos);
  769.                     }
  770.                 }
  771.             }
  772.  
  773.             this.emptyPos = posList.get(0);
  774.         }
  775.  
  776.         public void stop() {
  777.             this.flowersPlanted = this.flowersPlanted + 1;
  778.             Butterfly.this.setHasNectar(false);
  779.  
  780.             if (this.flowersPlanted < 2) {
  781.                 if (!Butterfly.this.level().isClientSide) {
  782.                     int x = Mth.floor(Butterfly.this.getX());
  783.                     int y = Mth.floor(Butterfly.this.getY());
  784.                     int z = Mth.floor(Butterfly.this.getZ());
  785.                     BlockPos butterflyPos = new BlockPos(x, y, z);
  786.  
  787.                     if (Butterfly.this.givenFlower != null) {
  788.                         BlockState flowerState = Butterfly.this.givenFlower.defaultBlockState();
  789.  
  790.                         if (Butterfly.this.level().isEmptyBlock(butterflyPos) && flowerState.canSurvive(Butterfly.this.level(), butterflyPos)) {
  791.                             Butterfly.this.level().setBlockAndUpdate(butterflyPos, flowerState);
  792.                             Butterfly.this.level().gameEvent(GameEvent.BLOCK_PLACE, butterflyPos, GameEvent.Context.of(Butterfly.this, flowerState));
  793.                         }
  794.                     }
  795.                 }
  796.                 this.repeat();
  797.             } else {
  798.                 this.flowersPlanted = 0;
  799.                 Butterfly.this.wasGivenFlower = false;
  800.                 Butterfly.this.remainingTicksBeforeCanPollinate = 1600;
  801.                 Butterfly.this.navigation.stop();
  802.             }
  803.         }
  804.  
  805.         public boolean requiresUpdateEveryTick() {
  806.             return true;
  807.         }
  808.  
  809.         public void tick() {
  810.             if (this.emptyPos != null) {
  811.                 if (Butterfly.this.hasReachedTarget(this.emptyPos)) {
  812.                     Butterfly.this.setPollinatingPos(this.emptyPos);
  813.  
  814.                     ++this.plantingFlowerTicks;
  815.                 } else {
  816.                     Butterfly.this.navigation.moveTo(this.emptyPos.getX() + 0.5D, this.emptyPos.getY() + 0.5D, this.emptyPos.getZ() + 0.5D, 0.85F);
  817.                 }
  818.             }
  819.         }
  820.  
  821.         /**
  822.          * Repeat until butterfly has planted 2 flowers.
  823.          */
  824.         private void repeat() {
  825.             Butterfly.this.wasGivenFlower = true;
  826.         }
  827.     }
  828.  
  829.     class LookControl extends net.minecraft.world.entity.ai.control.LookControl {
  830.  
  831.         public LookControl(Mob mob) {
  832.             super(mob);
  833.         }
  834.  
  835.         protected boolean resetXRotOnTick() {
  836.             return !Butterfly.this.pollinateFlowerGoal.isPollinating();
  837.         }
  838.     }
  839.  
  840.     class WanderGoal extends Goal {
  841.  
  842.         WanderGoal() {
  843.             this.setFlags(EnumSet.of(Goal.Flag.MOVE));
  844.         }
  845.  
  846.         public boolean canUse() {
  847.             return Butterfly.this.navigation.isDone() && Butterfly.this.random.nextInt(10) == 0;
  848.         }
  849.  
  850.         public boolean canContinueToUse() {
  851.             return Butterfly.this.navigation.isInProgress();
  852.         }
  853.  
  854.         public void start() {
  855.             Vec3 vec3 = this.findPos();
  856.  
  857.             if (vec3 != null) {
  858.                 Butterfly.this.navigation.moveTo(Butterfly.this.navigation.createPath(BlockPos.containing(vec3), 1), 1.0D);
  859.             }
  860.         }
  861.  
  862.         @Nullable
  863.         private Vec3 findPos() {
  864.             Vec3 vec3;
  865.             if (Butterfly.this.isNestValid() && Butterfly.this.nestPos != null && !Butterfly.this.closerThan(Butterfly.this.nestPos, 22)) {
  866.                 Vec3 vec31 = Vec3.atCenterOf(Butterfly.this.nestPos);
  867.                 vec3 = vec31.subtract(Butterfly.this.position()).normalize();
  868.             } else {
  869.                 vec3 = Butterfly.this.getViewVector(0.0F);
  870.             }
  871.  
  872.             Vec3 vec32 = HoverRandomPos.getPos(Butterfly.this, 8, 7, vec3.x, vec3.z, ((float)Math.PI / 2F), 3, 1);
  873.             return vec32 != null ? vec32 : AirAndWaterRandomPos.getPos(Butterfly.this, 8, 4, -2, vec3.x, vec3.z, ((float)Math.PI / 2F));
  874.         }
  875.     }
  876.  
  877.     ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  878.  
  879.     // TYPES
  880.  
  881.     public enum Type implements StringRepresentable {
  882.         APRICOT(0, "apricot"),
  883.         CITRUS(1, "citrus"),
  884.         MYSTIC(2, "mystic"),
  885.         //plum
  886.         //valentine
  887.         //berry
  888.         //coral
  889.         JELLY(3, "jelly"),
  890.         AUGUST(4, "august");
  891.         //evergreen (lime)
  892.         //everest (dark green)
  893.         //ebony (black)
  894.  
  895.         @SuppressWarnings("deprecation")
  896.         public static final StringRepresentable.EnumCodec<Type> CODEC = StringRepresentable.fromEnum(Type::values);
  897.         private static final IntFunction<Type> BY_ID = ByIdMap.continuous(Type::getId, values(), ByIdMap.OutOfBoundsStrategy.ZERO);
  898.         private final int id;
  899.         private final String name;
  900.  
  901.         Type(int id, String name) {
  902.             this.id = id;
  903.             this.name = name;
  904.         }
  905.  
  906.         public String getSerializedName() {
  907.             return this.name;
  908.         }
  909.  
  910.         public int getId() {
  911.             return this.id;
  912.         }
  913.  
  914.         public static Type byName(String name) {
  915.             return CODEC.byName(name, APRICOT);
  916.         }
  917.  
  918.         public static Type byId(int id) {
  919.             return BY_ID.apply(id);
  920.         }
  921.     }
  922.  
  923. }
Add Comment
Please, Sign In to add comment