Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package com.mysticsbiomes.client.entity;
- import com.google.common.collect.Maps;
- import com.mysticsbiomes.core.init.MysticPoiTypes;
- import com.mysticsbiomes.common.block.entity.ButterflyNestBlockEntity;
- import com.mysticsbiomes.core.MysticsBiomes;
- import com.mysticsbiomes.core.init.MysticBlocks;
- import net.minecraft.Util;
- import net.minecraft.core.BlockPos;
- 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.resources.ResourceLocation;
- import net.minecraft.server.level.ServerLevel;
- import net.minecraft.tags.ItemTags;
- import net.minecraft.util.Mth;
- 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.BreedGoal;
- 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.item.crafting.Ingredient;
- import net.minecraft.world.level.Level;
- import net.minecraft.world.level.LevelReader;
- import net.minecraft.world.level.block.entity.BlockEntity;
- import net.minecraft.world.level.pathfinder.Path;
- import net.minecraft.world.phys.Vec3;
- import javax.annotation.Nullable;
- import java.util.Comparator;
- import java.util.EnumSet;
- import java.util.List;
- import java.util.Map;
- import java.util.stream.Collectors;
- import java.util.stream.Stream;
- /**
- * Butterflies flutter around and spread flowers!
- *
- * Enter Nest
- * Locate Nest
- * Sleep
- * Pollinate
- * Locate Flowers
- * Spread Flowers
- *
- * Bees and Butterflies work together, as butterflies collect the pollen, and bees
- * turn it into honey.
- *
- * When they are given a flower, they will search around the area for that flower in the world.
- * If they have nectar and locate that flower, they will begin to pollinate it, collecting its
- * data, and duplicate the flower based on the amount of nectar they have at that time.
- *
- * If a butterfly has 6 pollen, they will spread out 6 flowers.
- *
- * If they cannot find the flower they are given, they will emmit a particle, and continue with
- * their day. They will have the flower saved in their nbt. If they find the flower,
- * they will start the spreading process.
- *
- *
- * Butterflies are ambient friendly bugs, who's main feature is to spread flowers.
- *
- * // DAILY LIFE
- * - Butterflies flutter around in groups of 4.
- * - They will randomly decide to pollinate nearby flowers.
- * - If there are different flowers nearby, they will choose those over a flower they just pollinated.
- * - When they
- * - If butterflies do not pollinate in 2 days, they will die.
- * - Butterflies save the location of every last flower they pollinated.
- *
- *
- * pollinates a few times through the day
- * they flutter around
- * they drop off the nectar they collected at their nest
- * overtime the nest will have an abundance of nectar, nearby bees will try to steal some.
- *
- */
- public class Butterfly extends Animal implements FlyingAnimal {
- private static final EntityDataAccessor<Integer> DATA_TYPE_ID = SynchedEntityData.defineId(Butterfly.class, EntityDataSerializers.INT);
- public static final int TICKS_PER_FLAP = Mth.ceil(1.4959966F);
- public static final Map<Integer, ResourceLocation> TEXTURE_BY_TYPE = Util.make(Maps.newHashMap(), (map) -> {
- map.put(1, MysticsBiomes.modLoc("textures/entity/butterfly/orange.png"));
- map.put(2, MysticsBiomes.modLoc("textures/entity/butterfly/peach.png"));
- map.put(3, MysticsBiomes.modLoc("textures/entity/butterfly/lilac.png"));
- map.put(4, MysticsBiomes.modLoc("textures/entity/butterfly/blue.png"));
- map.put(5, MysticsBiomes.modLoc("textures/entity/butterfly/white.png"));
- map.put(6, MysticsBiomes.modLoc("textures/entity/butterfly/black.png"));
- });
- private int stayOutOfNestCountdown;
- int remainingCooldownBeforeLocatingNewNest;
- int remainingCooldownBeforeLocatingNewFlower = Mth.nextInt(this.random, 20, 60);
- private int underWaterTicks;
- @Nullable
- BlockPos nestPos;
- @Nullable
- BlockPos savedFlowerPos;
- Butterfly.GoToNestGoal goToNestGoal;
- public Butterfly(EntityType<? extends Animal> type, Level level) {
- super(type, level);
- this.moveControl = new FlyingMoveControl(this, 20, true);
- this.lookControl = new LookControl(this);
- }
- protected void defineSynchedData() {
- super.defineSynchedData();
- this.entityData.define(DATA_TYPE_ID, this.random.nextInt(1, 7));
- }
- protected void registerGoals() {
- this.goalSelector.addGoal(1, new Butterfly.EnterNestGoal());
- this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D));
- this.goalSelector.addGoal(3, new TemptGoal(this, 1.25D, Ingredient.of(ItemTags.FLOWERS), false));
- this.goalSelector.addGoal(5, new Butterfly.LocateNestGoal());
- this.goToNestGoal = new Butterfly.GoToNestGoal();
- this.goalSelector.addGoal(5, this.goToNestGoal);
- this.goalSelector.addGoal(8, new Butterfly.WanderGoal());
- this.goalSelector.addGoal(9, 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);
- }
- public void addAdditionalSaveData(CompoundTag tag) {
- super.addAdditionalSaveData(tag);
- tag.putInt("Type", this.getButterflyType());
- tag.putInt("CannotEnterNestTicks", this.stayOutOfNestCountdown);
- if (this.hasNest()) {
- tag.put("NestPos", NbtUtils.writeBlockPos(this.getNestPos()));
- }
- }
- public void readAdditionalSaveData(CompoundTag tag) {
- super.readAdditionalSaveData(tag);
- this.setButterflyType(tag.getInt("Type"));
- this.stayOutOfNestCountdown = tag.getInt("CannotEnterNestTicks");
- this.nestPos = null;
- if (tag.contains("NestPos")) {
- this.nestPos = NbtUtils.readBlockPos(tag.getCompound("NestPos"));
- }
- }
- public int getButterflyType() {
- return this.entityData.get(DATA_TYPE_ID);
- }
- public void setButterflyType(int value) {
- if (value <= 1 || value >= 6) {
- value = this.random.nextInt(6);
- }
- this.entityData.set(DATA_TYPE_ID, value);
- }
- public AgeableMob getBreedOffspring(ServerLevel level, AgeableMob mob) {
- return null;
- }
- ///////////////////////////////////////////////////////////////////////////////////////
- public void tick() {
- super.tick();
- }
- protected void customServerAiStep() {
- if (this.isInWaterOrBubble()) {
- ++this.underWaterTicks;
- } else {
- this.underWaterTicks = 0;
- }
- if (this.underWaterTicks > 20) {
- this.hurt(DamageSource.DROWN, 1.0F);
- }
- }
- public void aiStep() {
- super.aiStep();
- if (!this.level.isClientSide) {
- if (this.stayOutOfNestCountdown > 0) {
- --this.stayOutOfNestCountdown;
- }
- if (this.remainingCooldownBeforeLocatingNewNest > 0) {
- --this.remainingCooldownBeforeLocatingNewNest;
- }
- if (this.remainingCooldownBeforeLocatingNewFlower > 0) {
- --this.remainingCooldownBeforeLocatingNewFlower;
- }
- if (this.tickCount % 20 == 0 && !this.isNestValid()) {
- this.nestPos = null;
- }
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////
- /**
- * Butterflies cannot fly if they're wet.
- */
- public boolean isFlying() {
- return !this.onGround || !this.isInWaterRainOrBubble();
- }
- public boolean isFlapping() {
- return this.isFlying() && this.tickCount % TICKS_PER_FLAP == 0;
- }
- public boolean causeFallDamage(float amount, float height, DamageSource source) {
- return false;
- }
- public float getWalkTargetValue(BlockPos pos, LevelReader reader) {
- return reader.getBlockState(pos).isAir() ? 10.0F : 0.0F;
- }
- protected PathNavigation createNavigation(Level level) {
- FlyingPathNavigation navigation = new FlyingPathNavigation(this, level) {
- public boolean isStableDestination(BlockPos blockPos) {
- return !this.level.getBlockState(blockPos.below()).isAir();
- }
- public void tick() {
- super.tick();
- }
- };
- navigation.setCanOpenDoors(false);
- navigation.setCanFloat(false);
- navigation.setCanPassDoors(true);
- return navigation;
- }
- protected void pathfindRandomlyTowards(BlockPos blockPos) {
- Vec3 vec3 = Vec3.atBottomCenterOf(blockPos);
- int i = 0;
- BlockPos pos = this.blockPosition();
- int j = (int)vec3.y - pos.getY();
- if (j > 2) {
- i = 4;
- } else if (j < -2) {
- i = -4;
- }
- int k = 6;
- int l = 8;
- int i1 = pos.distManhattan(blockPos);
- 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);
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////
- @Nullable
- public BlockPos getNestPos() {
- return this.nestPos;
- }
- public boolean hasNest() {
- return this.nestPos != null;
- }
- private boolean isNestValid() {
- if (!this.hasNest()) {
- return false;
- } else {
- BlockEntity entity = this.level.getBlockEntity(this.nestPos);
- return entity instanceof ButterflyNestBlockEntity;
- }
- }
- private boolean isNestNearFire() {
- if (this.nestPos == null) {
- return false;
- } else {
- BlockEntity entity = this.level.getBlockEntity(this.nestPos);
- return entity instanceof ButterflyNestBlockEntity && ((ButterflyNestBlockEntity)entity).isFireNearby();
- }
- }
- private boolean doesNestHaveSpace(BlockPos pos) {
- BlockEntity entity = this.level.getBlockEntity(pos);
- if (entity instanceof ButterflyNestBlockEntity) {
- return !((ButterflyNestBlockEntity)entity).isFull();
- } else {
- return false;
- }
- }
- private boolean wantsToEnterNest() {
- return this.level.isRaining() || this.level.isNight() && !this.isNestNearFire();
- }
- public void setStayOutOfNestCountdown(int ticks) {
- this.stayOutOfNestCountdown = ticks;
- }
- ///////////////////////////////////////////////////////////////////////////////////////
- @Nullable
- public BlockPos getSavedFlowerPos() {
- return this.savedFlowerPos;
- }
- public boolean hasSavedFlowerPos() {
- return this.savedFlowerPos != null;
- }
- public void setSavedFlowerPos(BlockPos pos) {
- this.savedFlowerPos = pos;
- }
- ///////////////////////////////////////////////////////////////////////////////////////
- private boolean closerThan(BlockPos pos, int distance) {
- return pos.closerThan(this.blockPosition(), distance);
- }
- private boolean isTooFarAway(BlockPos pos) {
- return !this.closerThan(pos, 32);
- }
- ///////////////////////////////////////////////////////////////////////////////////////
- /**
- * TODO:
- * Enter nest goal
- * Locate flower goal
- * Pollinate goal
- * Spread flowers goal
- */
- private class LocateNestGoal extends Goal {
- public boolean canUse() {
- return Butterfly.this.remainingCooldownBeforeLocatingNewNest == 0 && !Butterfly.this.hasNest() && Butterfly.this.wantsToEnterNest();
- }
- public boolean canContinueToUse() {
- return false;
- }
- public void start() {
- Butterfly.this.remainingCooldownBeforeLocatingNewNest = 200;
- List<BlockPos> list = this.findNearbyNestsWithSpace();
- if (!list.isEmpty()) {
- for (BlockPos blockPos : list) {
- Butterfly.this.nestPos = blockPos;
- return;
- }
- Butterfly.this.nestPos = list.get(0);
- }
- }
- private List<BlockPos> findNearbyNestsWithSpace() {
- BlockPos blockPos = Butterfly.this.blockPosition();
- PoiManager poi = ((ServerLevel)Butterfly.this.level).getPoiManager();
- Stream<PoiRecord> stream = poi.getInRange((type) -> type == MysticPoiTypes.BUTTERFLY_NEST.get(), blockPos, 20, PoiManager.Occupancy.ANY);
- return stream.map(PoiRecord::getPos).filter(Butterfly.this::doesNestHaveSpace).sorted(Comparator.comparingDouble((pos) -> pos.distSqr(blockPos))).collect(Collectors.toList());
- }
- }
- public class GoToNestGoal extends Goal {
- int travellingTicks = Butterfly.this.level.random.nextInt(10);
- @Nullable
- private Path lastPath;
- private int ticksStuck;
- GoToNestGoal() {
- this.setFlags(EnumSet.of(Goal.Flag.MOVE));
- }
- public boolean canUse() {
- return Butterfly.this.nestPos != null && !Butterfly.this.hasRestriction() && Butterfly.this.wantsToEnterNest() && !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 start() {
- this.travellingTicks = 0;
- this.ticksStuck = 0;
- super.start();
- }
- public void stop() {
- this.travellingTicks = 0;
- this.ticksStuck = 0;
- Butterfly.this.navigation.stop();
- Butterfly.this.navigation.resetMaxVisitedNodesMultiplier();
- }
- public void tick() {
- if (Butterfly.this.nestPos != null) {
- ++this.travellingTicks;
- if (!Butterfly.this.navigation.isInProgress()) {
- if (!Butterfly.this.closerThan(Butterfly.this.nestPos, 16)) {
- if (!Butterfly.this.isTooFarAway(Butterfly.this.nestPos)) {
- Butterfly.this.pathfindRandomlyTowards(Butterfly.this.nestPos);
- }
- } else {
- boolean flag = this.pathfindDirectlyTowards(Butterfly.this.nestPos);
- if (flag && this.lastPath != null && Butterfly.this.navigation.getPath().sameAs(this.lastPath)) {
- ++this.ticksStuck;
- if (this.ticksStuck > 60) {
- this.ticksStuck = 0;
- }
- } else {
- this.lastPath = Butterfly.this.navigation.getPath();
- }
- }
- }
- }
- }
- private boolean pathfindDirectlyTowards(BlockPos blockPos) {
- Butterfly.this.navigation.setMaxVisitedNodesMultiplier(10.0F);
- Butterfly.this.navigation.moveTo(blockPos.getX(), blockPos.getY(), blockPos.getZ(), 1.0D);
- return Butterfly.this.navigation.getPath() != null && Butterfly.this.navigation.getPath().canReach();
- }
- private boolean hasReachedTarget(BlockPos blockPos) {
- if (Butterfly.this.closerThan(blockPos, 2)) {
- return true;
- } else {
- Path path = Butterfly.this.navigation.getPath();
- return path != null && path.getTarget().equals(blockPos) && path.canReach() && path.isDone();
- }
- }
- }
- private class EnterNestGoal extends Goal {
- public boolean canUse() {
- if (Butterfly.this.hasNest() && 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() {
- BlockEntity blockEntity = Butterfly.this.level.getBlockEntity(Butterfly.this.nestPos);
- if (blockEntity instanceof ButterflyNestBlockEntity entity) {
- entity.addOccupant(Butterfly.this, Butterfly.this.hasNest());
- }
- }
- }
- private 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(new BlockPos(vec3), 1), 1.0D);
- }
- }
- private Vec3 findPos() {
- Vec3 vec3;
- if (Butterfly.this.isNestValid() && !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));
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement