Advertisement
jayhillx

Butterfly 3

Aug 23rd, 2023
1,244
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 21.33 KB | None | 0 0
  1. package com.mysticsbiomes.common.entity.animal;
  2.  
  3. import com.google.common.collect.Maps;
  4. import com.mysticsbiomes.MysticsBiomes;
  5. import com.mysticsbiomes.common.block.entity.ButterflyNestBlockEntity;
  6. import com.mysticsbiomes.init.MysticPoiTypes;
  7. import net.minecraft.Util;
  8. import net.minecraft.core.BlockPos;
  9. import net.minecraft.nbt.CompoundTag;
  10. import net.minecraft.nbt.NbtUtils;
  11. import net.minecraft.network.syncher.EntityDataAccessor;
  12. import net.minecraft.network.syncher.EntityDataSerializers;
  13. import net.minecraft.network.syncher.SynchedEntityData;
  14. import net.minecraft.resources.ResourceLocation;
  15. import net.minecraft.server.level.ServerLevel;
  16. import net.minecraft.tags.ItemTags;
  17. import net.minecraft.util.ByIdMap;
  18. import net.minecraft.util.Mth;
  19. import net.minecraft.util.RandomSource;
  20. import net.minecraft.util.StringRepresentable;
  21. import net.minecraft.world.DifficultyInstance;
  22. import net.minecraft.world.InteractionHand;
  23. import net.minecraft.world.InteractionResult;
  24. import net.minecraft.world.entity.*;
  25. import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
  26. import net.minecraft.world.entity.ai.attributes.Attributes;
  27. import net.minecraft.world.entity.ai.control.FlyingMoveControl;
  28. import net.minecraft.world.entity.ai.control.LookControl;
  29. import net.minecraft.world.entity.ai.goal.BreedGoal;
  30. import net.minecraft.world.entity.ai.goal.FloatGoal;
  31. import net.minecraft.world.entity.ai.goal.Goal;
  32. import net.minecraft.world.entity.ai.goal.TemptGoal;
  33. import net.minecraft.world.entity.ai.navigation.FlyingPathNavigation;
  34. import net.minecraft.world.entity.ai.navigation.PathNavigation;
  35. import net.minecraft.world.entity.ai.util.AirAndWaterRandomPos;
  36. import net.minecraft.world.entity.ai.util.AirRandomPos;
  37. import net.minecraft.world.entity.ai.util.HoverRandomPos;
  38. import net.minecraft.world.entity.ai.village.poi.PoiManager;
  39. import net.minecraft.world.entity.ai.village.poi.PoiRecord;
  40. import net.minecraft.world.entity.animal.Animal;
  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.entity.BlockEntity;
  48. import net.minecraft.world.level.block.state.BlockState;
  49. import net.minecraft.world.level.pathfinder.Path;
  50. import net.minecraft.world.phys.Vec3;
  51.  
  52. import javax.annotation.Nullable;
  53. import java.util.*;
  54. import java.util.function.IntFunction;
  55. import java.util.function.Predicate;
  56. import java.util.stream.Collectors;
  57. import java.util.stream.Stream;
  58.  
  59. /**
  60.  * Butterflies are friendly ambient anthropoids, useful for growing flowers.
  61.  *
  62.  * When a butterfly is given a flower, they will save it and will look for that same flower in the world.
  63.  * Under specific circumstances
  64.  *      the butterfly has been out of their nest for more than x ticks.
  65.  *      it has pollinated at least one flower beforehand.
  66.  */
  67. public class Butterfly extends Animal implements FlyingAnimal {
  68.     public static final Map<Integer, Map<Integer, ResourceLocation>> TEXTURE_BY_TYPE = Util.make(Maps.newHashMap(), (map) -> {
  69.         for (Type type : Type.values()) {
  70.             map.put(type.getId(), addButterflyVariants(type.getSerializedName()));
  71.         }
  72.     });
  73.     private static final EntityDataAccessor<Integer> DATA_TYPE_ID = SynchedEntityData.defineId(Butterfly.class, EntityDataSerializers.INT);
  74.     private static final int TICKS_PER_FLAP = Mth.ceil(1.4959966F);
  75.     private boolean wantsToEnterNest;
  76.     private int stayOutOfNestCountdown;
  77.     int remainingCooldownBeforeLocatingNewNest;
  78.     @Nullable
  79.     BlockPos nestPos;
  80.     Butterfly.GoToNestGoal goToNestGoal;
  81.     public final AnimationState flyingAnimation = new AnimationState();
  82.  
  83.     public Butterfly(EntityType<? extends Butterfly> type, Level level) {
  84.         super(type, level);
  85.         this.moveControl = new FlyingMoveControl(this, 20, true);
  86.         this.lookControl = new LookControl(this);
  87.     }
  88.  
  89.     public static AttributeSupplier.Builder createAttributes() {
  90.         return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 6.0D).add(Attributes.FLYING_SPEED, 1.0D).add(Attributes.FOLLOW_RANGE, 16.0D);
  91.     }
  92.  
  93.     protected void registerGoals() {
  94.         this.goalSelector.addGoal(1, new EnterNestGoal());
  95.         this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D));
  96.         this.goalSelector.addGoal(3, new TemptGoal(this, 1.25D, Ingredient.of(ItemTags.FLOWERS), false));
  97.         this.goalSelector.addGoal(5, new LocateNestGoal());
  98.         this.goToNestGoal = new GoToNestGoal();
  99.         this.goalSelector.addGoal(8, new WanderGoal());
  100.         this.goalSelector.addGoal(9, new FloatGoal(this));
  101.     }
  102.  
  103.     protected void defineSynchedData() {
  104.         super.defineSynchedData();
  105.         this.entityData.define(DATA_TYPE_ID, this.random.nextInt(1, 2));
  106.     }
  107.  
  108.     @Override
  109.     public void addAdditionalSaveData(CompoundTag tag) {
  110.         super.addAdditionalSaveData(tag);
  111.  
  112.         if (this.nestPos != null) {
  113.             tag.put("NestPos", NbtUtils.writeBlockPos(this.nestPos));
  114.         }
  115.  
  116.         tag.putString("Type", this.getVariant().name);
  117.         tag.putInt("CannotEnterNestTicks", this.stayOutOfNestCountdown);
  118.     }
  119.  
  120.     @Override
  121.     public void readAdditionalSaveData(CompoundTag tag) {
  122.         this.nestPos = null;
  123.         if (tag.contains("NestPos")) {
  124.             this.nestPos = NbtUtils.readBlockPos(tag.getCompound("NestPos"));
  125.         }
  126.  
  127.         super.readAdditionalSaveData(tag);
  128.         this.setVariant(Type.byName(tag.getString("Type")));
  129.         this.stayOutOfNestCountdown = tag.getInt("CannotEnterNestTicks");
  130.     }
  131.  
  132.     @Nullable
  133.     @Override
  134.     public AgeableMob getBreedOffspring(ServerLevel level, AgeableMob mob) {
  135.         return null;
  136.     }
  137.  
  138.     @Override
  139.     public MobType getMobType() {
  140.         return MobType.ARTHROPOD;
  141.     }
  142.  
  143.     public Type getVariant() {
  144.         return Type.byId(this.entityData.get(DATA_TYPE_ID));
  145.     }
  146.  
  147.     public void setVariant(Type type) {
  148.         this.entityData.set(DATA_TYPE_ID, type.getId());
  149.     }
  150.  
  151.     public static Map<Integer, ResourceLocation> addButterflyVariants(String type) {
  152.         Map<Integer, ResourceLocation> map = Maps.newHashMap();
  153.         map.put(1, MysticsBiomes.modLoc("textures/entity/butterfly/" + type + ".png"));
  154.         map.put(2, MysticsBiomes.modLoc("textures/entity/butterfly/" + type + "_still.png"));
  155.         return map;
  156.     }
  157.  
  158.     @Nullable
  159.     @Override
  160.     public SpawnGroupData finalizeSpawn(ServerLevelAccessor accessor, DifficultyInstance instance, MobSpawnType spawnType, @Nullable SpawnGroupData spawnData, @Nullable CompoundTag tag) {
  161.         RandomSource source = accessor.getRandom();
  162.  
  163.         Butterfly.Type type;
  164.         if (spawnData instanceof Butterfly.GroupData) {
  165.             type = ((GroupData)spawnData).type;
  166.         } else {
  167.             type = Util.getRandom(Butterfly.Type.values(), source);
  168.             spawnData = new Butterfly.GroupData(type);
  169.         }
  170.  
  171.         this.setVariant(type);
  172.         return super.finalizeSpawn(accessor, instance, spawnType, spawnData, tag);
  173.     }
  174.  
  175.     //////////////////////////////////////////////////////////////////
  176.  
  177.     public void tick() {
  178.         if (this.level().isClientSide()) {
  179.             this.flyingAnimation.animateWhen(this.walkAnimation.isMoving(), this.tickCount);
  180.         }
  181.         super.tick();
  182.     }
  183.  
  184.     public void aiStep() {
  185.         super.aiStep();
  186.         if (!this.level().isClientSide) {
  187.             if (this.stayOutOfNestCountdown > 0) {
  188.                 --this.stayOutOfNestCountdown;
  189.             }
  190.  
  191.             if (this.remainingCooldownBeforeLocatingNewNest > 0) {
  192.                 --this.remainingCooldownBeforeLocatingNewNest;
  193.             }
  194.  
  195.             if (this.tickCount % 20 == 0 && !this.isNestValid()) {
  196.                 this.nestPos = null;
  197.             }
  198.         }
  199.     }
  200.  
  201.     protected void customServerAiStep() {
  202.  
  203.     }
  204.  
  205.     //////////////////////////////////////////////////////////////////
  206.  
  207.     protected void updateWalkAnimation(float f) {
  208.         this.walkAnimation.update(Math.min(f * 25.0F, 1.0F), 0.4F);
  209.     }
  210.  
  211.     //////////////////////////////////////////////////////////////////
  212.  
  213.     public float getWalkTargetValue(BlockPos pos, LevelReader reader) {
  214.         return reader.getBlockState(pos).isAir() ? 6.0F : 0.0F;
  215.     }
  216.  
  217.     protected void checkFallDamage(double distance, boolean b, BlockState state, BlockPos pos) {
  218.     }
  219.  
  220.     protected PathNavigation createNavigation(Level level) {
  221.         FlyingPathNavigation navigation = new FlyingPathNavigation(this, level) {
  222.             public boolean isStableDestination(BlockPos pos) {
  223.                 return !this.level.getBlockState(pos.below()).isAir();
  224.             }
  225.         };
  226.         navigation.setCanOpenDoors(false);
  227.         navigation.setCanFloat(false);
  228.         navigation.setCanPassDoors(true);
  229.         return navigation;
  230.     }
  231.  
  232.     private Optional<BlockPos> findNearbyFlower() {
  233.         return Butterfly.this.findNearestBlock(null, 5.0D);
  234.     }
  235.  
  236.     private Optional<BlockPos> findNearestBlock(Predicate<BlockState> predicate, double distance) {
  237.         BlockPos pos = Butterfly.this.blockPosition();
  238.         BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos();
  239.  
  240.         for (int i = 0; (double)i <= distance; i = i > 0 ? -i : 1 - i) {
  241.             for (int j = 0; (double)j < distance; ++j) {
  242.                 for (int k = 0; k <= j; k = k > 0 ? -k : 1 - k) {
  243.                     for (int l = k < j && k > -j ? j : 0; l <= j; l = l > 0 ? -l : 1 - l) {
  244.                         mutablePos.setWithOffset(pos, k, i - 1, l);
  245.                         if (pos.closerThan(mutablePos, distance) && predicate.test(Butterfly.this.level().getBlockState(mutablePos))) {
  246.                             return Optional.of(mutablePos);
  247.                         }
  248.                     }
  249.                 }
  250.             }
  251.         }
  252.         return Optional.empty();
  253.     }
  254.  
  255.     private void pathfindRandomlyTowards(BlockPos pos) {
  256.         Vec3 vec3 = Vec3.atBottomCenterOf(pos);
  257.         int i = 0;
  258.         BlockPos pos1 = this.blockPosition();
  259.         int j = (int)vec3.y - pos1.getY();
  260.         if (j > 2) {
  261.             i = 4;
  262.         } else if (j < -2) {
  263.             i = -4;
  264.         }
  265.  
  266.         int k = 6;
  267.         int l = 8;
  268.         int i1 = pos1.distManhattan(pos);
  269.         if (i1 < 15) {
  270.             k = i1 / 2;
  271.             l = i1 / 2;
  272.         }
  273.  
  274.         Vec3 vec31 = AirRandomPos.getPosTowards(this, k, l, i, vec3, ((float)Math.PI / 10F));
  275.         if (vec31 != null) {
  276.             this.navigation.setMaxVisitedNodesMultiplier(0.5F);
  277.             this.navigation.moveTo(vec31.x, vec31.y, vec31.z, 1.0D);
  278.         }
  279.     }
  280.  
  281.     private boolean pathfindDirectlyTowards(BlockPos pos) {
  282.         Butterfly.this.navigation.setMaxVisitedNodesMultiplier(10.0F);
  283.         Butterfly.this.navigation.moveTo(pos.getX(), pos.getY(), pos.getZ(), 1.0D);
  284.         return Butterfly.this.navigation.getPath() != null && Butterfly.this.navigation.getPath().canReach();
  285.     }
  286.  
  287.     private boolean closerThan(BlockPos pos, int distance) {
  288.         return pos.closerThan(this.blockPosition(), distance);
  289.     }
  290.  
  291.     private boolean isTooFarAway(BlockPos pos) {
  292.         return !this.closerThan(pos, 32);
  293.     }
  294.  
  295.     public boolean isFlying() {
  296.         return !this.level().isNight() || !this.isInWaterRainOrBubble();
  297.     }
  298.  
  299.     public boolean isFlapping() {
  300.         return this.isFlying() && this.tickCount % TICKS_PER_FLAP == 0;
  301.     }
  302.  
  303.     //////////////////////////////////////////////////////////////////
  304.  
  305.     public void setStayOutOfNestCountdown(int ticks) {
  306.         this.stayOutOfNestCountdown = ticks;
  307.     }
  308.  
  309.     public boolean isNestValid() {
  310.         if (this.nestPos != null) {
  311.             if (this.isTooFarAway(this.nestPos)) {
  312.                 return false;
  313.             } else {
  314.                 BlockEntity blockEntity = this.level().getBlockEntity(this.nestPos);
  315.                 return blockEntity instanceof ButterflyNestBlockEntity;
  316.             }
  317.         } else {
  318.             return false;
  319.         }
  320.     }
  321.  
  322.     /** @return true if it's raining, night or their nest is on fire. */
  323.     public boolean wantsToEnterNest() {
  324.         if (this.stayOutOfNestCountdown <= 0) {
  325.             return this.wantsToEnterNest || this.level().isRaining() || this.level().isNight() && !this.isNestNearFire();
  326.         } else {
  327.             return false;
  328.         }
  329.     }
  330.  
  331.     private boolean doesNestHaveSpace(BlockPos pos) {
  332.         BlockEntity blockEntity = this.level().getBlockEntity(pos);
  333.  
  334.         if (blockEntity instanceof ButterflyNestBlockEntity entity) {
  335.             return !entity.isFull();
  336.         } else {
  337.             return false;
  338.         }
  339.     }
  340.  
  341.     private boolean isNestNearFire() {
  342.         if (this.nestPos == null) {
  343.             return false;
  344.         } else {
  345.             BlockEntity blockEntity = this.level().getBlockEntity(this.nestPos);
  346.             return blockEntity instanceof ButterflyNestBlockEntity && ((ButterflyNestBlockEntity)blockEntity).isFireNearby();
  347.         }
  348.     }
  349.  
  350.     //////////////////////////////////////////////////////////////////
  351.  
  352.     @Override
  353.     public InteractionResult mobInteract(Player player, InteractionHand hand) {
  354.         if (player.isCreative()) {
  355.             this.remainingCooldownBeforeLocatingNewNest = 0;
  356.             this.stayOutOfNestCountdown = 0;
  357.             return InteractionResult.SUCCESS;
  358.         }
  359.         return super.mobInteract(player, hand);
  360.     }
  361.  
  362.     //////////////////////////////////////////////////////////////////
  363.  
  364.     class LocateNestGoal extends Goal {
  365.  
  366.         public boolean canUse() {
  367.             return Butterfly.this.remainingCooldownBeforeLocatingNewNest == 0 && Butterfly.this.nestPos != null && Butterfly.this.wantsToEnterNest();
  368.         }
  369.  
  370.         public boolean canContinueToUse() {
  371.             return false;
  372.         }
  373.  
  374.         public void start() {
  375.             Butterfly.this.remainingCooldownBeforeLocatingNewNest = 200;
  376.  
  377.             List<BlockPos> list = this.findNearbyNestWithSpace();
  378.             if (!list.isEmpty()) {
  379.                 for (BlockPos pos : list) {
  380.                     Butterfly.this.nestPos = pos;
  381.                     return;
  382.                 }
  383.                 Butterfly.this.nestPos = list.get(0);
  384.             }
  385.         }
  386.  
  387.         private List<BlockPos> findNearbyNestWithSpace() {
  388.             BlockPos pos = Butterfly.this.blockPosition();
  389.             PoiManager manager = ((ServerLevel)Butterfly.this.level()).getPoiManager();
  390.  
  391.             Stream<PoiRecord> stream = manager.getInRange((holder) -> holder.is(MysticPoiTypes.BUTTERFLY_NEST.getId()), pos, 26, PoiManager.Occupancy.ANY);
  392.             return stream.map(PoiRecord::getPos).filter(Butterfly.this::doesNestHaveSpace).sorted(Comparator.comparingDouble((pos1) -> pos1.distSqr(pos))).collect(Collectors.toList());
  393.         }
  394.     }
  395.  
  396.     public class GoToNestGoal extends Goal {
  397.         int travellingTicks = Butterfly.this.level().random.nextInt(10);
  398.         @Nullable
  399.         private Path lastPath;
  400.  
  401.         GoToNestGoal() {
  402.             this.setFlags(EnumSet.of(Goal.Flag.MOVE));
  403.         }
  404.  
  405.         public boolean canUse() {
  406.             return Butterfly.this.nestPos != null && !Butterfly.this.hasRestriction() && Butterfly.this.wantsToEnterNest() && !this.hasReachedTarget(Butterfly.this.nestPos);
  407.         }
  408.  
  409.         public boolean canContinueToUse() {
  410.             return this.canUse();
  411.         }
  412.  
  413.         public void start() {
  414.             this.travellingTicks = 0;
  415.             super.start();
  416.         }
  417.  
  418.         public void stop() {
  419.             this.travellingTicks = 0;
  420.             Butterfly.this.navigation.stop();
  421.             Butterfly.this.navigation.resetMaxVisitedNodesMultiplier();
  422.         }
  423.  
  424.         public void tick() {
  425.             if (Butterfly.this.nestPos != null) {
  426.                 ++this.travellingTicks;
  427.  
  428.                 if (!Butterfly.this.navigation.isInProgress()) {
  429.                     if (!Butterfly.this.closerThan(Butterfly.this.nestPos, 16)) {
  430.                         if (!Butterfly.this.isTooFarAway(Butterfly.this.nestPos)) {
  431.                             Butterfly.this.pathfindRandomlyTowards(Butterfly.this.nestPos);
  432.                         }
  433.                     } else {
  434.                         boolean flag = Butterfly.this.pathfindDirectlyTowards(Butterfly.this.nestPos);
  435.  
  436.                         if (flag && this.lastPath != null) {
  437.                             this.lastPath = Butterfly.this.navigation.getPath();
  438.                         }
  439.                     }
  440.                 }
  441.             }
  442.         }
  443.  
  444.         private boolean hasReachedTarget(BlockPos pos) {
  445.             if (Butterfly.this.closerThan(pos, 2)) {
  446.                 return true;
  447.             } else {
  448.                 Path path = Butterfly.this.navigation.getPath();
  449.                 return path != null && path.getTarget().equals(pos) && path.canReach() && path.isDone();
  450.             }
  451.         }
  452.     }
  453.  
  454.     class EnterNestGoal extends Goal {
  455.  
  456.         public boolean canUse() {
  457.             if (Butterfly.this.nestPos != null && Butterfly.this.wantsToEnterNest() && Butterfly.this.nestPos.closerToCenterThan(Butterfly.this.position(), 2.0D)) {
  458.                 BlockEntity blockEntity = Butterfly.this.level().getBlockEntity(Butterfly.this.nestPos);
  459.  
  460.                 if (blockEntity instanceof ButterflyNestBlockEntity entity) {
  461.                     if (!entity.isFull()) {
  462.                         return true;
  463.                     }
  464.                     Butterfly.this.nestPos = null;
  465.                 }
  466.             }
  467.             return false;
  468.         }
  469.  
  470.         public boolean canContinueToUse() {
  471.             return false;
  472.         }
  473.  
  474.         public void start() {
  475.             if (Butterfly.this.nestPos != null) {
  476.                 BlockEntity blockEntity = Butterfly.this.level().getBlockEntity(Butterfly.this.nestPos);
  477.  
  478.                 if (blockEntity instanceof ButterflyNestBlockEntity entity) {
  479.                     entity.addOccupant(Butterfly.this);
  480.                 }
  481.             }
  482.         }
  483.  
  484.         public void stop() {
  485.             Butterfly.this.wantsToEnterNest = false;
  486.         }
  487.     }
  488.  
  489.     class WanderGoal extends Goal {
  490.  
  491.         WanderGoal() {
  492.             this.setFlags(EnumSet.of(Goal.Flag.MOVE));
  493.         }
  494.  
  495.         public boolean canUse() {
  496.             return Butterfly.this.navigation.isDone() && Butterfly.this.random.nextInt(10) == 0;
  497.         }
  498.  
  499.         public boolean canContinueToUse() {
  500.             return Butterfly.this.navigation.isInProgress();
  501.         }
  502.  
  503.         public void start() {
  504.             Vec3 vec3 = this.findPos();
  505.  
  506.             if (vec3 != null) {
  507.                 Butterfly.this.navigation.moveTo(Butterfly.this.navigation.createPath(BlockPos.containing(vec3), 1), 1.0D);
  508.             }
  509.         }
  510.  
  511.         private Vec3 findPos() {
  512.             Vec3 vec3;
  513.             if (Butterfly.this.nestPos != null && !Butterfly.this.closerThan(Butterfly.this.nestPos, 22)) {
  514.                 Vec3 vec31 = Vec3.atCenterOf(Butterfly.this.nestPos);
  515.                 vec3 = vec31.subtract(Butterfly.this.position()).normalize();
  516.             } else {
  517.                 vec3 = Butterfly.this.getViewVector(0.0F);
  518.             }
  519.  
  520.             Vec3 vec32 = HoverRandomPos.getPos(Butterfly.this, 8, 7, vec3.x, vec3.z, ((float)Math.PI / 2F), 3, 1);
  521.             return vec32 != null ? vec32 : AirAndWaterRandomPos.getPos(Butterfly.this, 8, 4, -2, vec3.x, vec3.z, ((float)Math.PI / 2F));
  522.         }
  523.     }
  524.  
  525.     public static class GroupData extends AgeableMob.AgeableMobGroupData {
  526.         public final Butterfly.Type type;
  527.  
  528.         GroupData(Butterfly.Type type) {
  529.             super(true);
  530.             this.type = type;
  531.         }
  532.     }
  533.  
  534.     public enum Type implements StringRepresentable {
  535.         MONARCH(0, "monarch"),
  536.         MORPHO(1, "morpho");
  537.  
  538.         public static final StringRepresentable.EnumCodec<Type> CODEC = StringRepresentable.fromEnum(Type::values);
  539.         private static final IntFunction<Type> BY_ID = ByIdMap.continuous(Type::getId, values(), ByIdMap.OutOfBoundsStrategy.ZERO);
  540.         private final int id;
  541.         private final String name;
  542.  
  543.         Type(int id, String name) {
  544.             this.id = id;
  545.             this.name = name;
  546.         }
  547.  
  548.         public String getSerializedName() {
  549.             return this.name;
  550.         }
  551.  
  552.         public int getId() {
  553.             return this.id;
  554.         }
  555.  
  556.         public static Type byName(String name) {
  557.             return CODEC.byName(name, MONARCH);
  558.         }
  559.  
  560.         public static Type byId(int id) {
  561.             return BY_ID.apply(id);
  562.         }
  563.     }
  564.  
  565.     /**
  566.      * TODO:
  567.      *
  568.      */
  569.     static class Butterfly2 extends Animal implements FlyingAnimal {
  570.  
  571.         public Butterfly2(EntityType<? extends Butterfly2> type, Level level) {
  572.             super(type, level);
  573.         }
  574.  
  575.         public static AttributeSupplier.Builder createAttributes() {
  576.             return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 6.0D).add(Attributes.FLYING_SPEED, 1.0D).add(Attributes.FOLLOW_RANGE, 16.0D);
  577.         }
  578.        
  579.         @Override
  580.         public AgeableMob getBreedOffspring(ServerLevel level, AgeableMob mob) {
  581.             return null;
  582.         }
  583.  
  584.         @Override
  585.         public boolean isFlying() {
  586.             return false;
  587.         }
  588.     }
  589.  
  590. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement