[add] Butterfly

This commit is contained in:
2026-09-27 17:17:30 +02:00
parent 3831a0854d
commit 7a78ce7934
22 changed files with 344 additions and 4 deletions
@@ -28,6 +28,7 @@ public class ModCreativeModeTabs {
output.accept(ModItems.SHARK_SPAWN_EGG);
output.accept(ModItems.HEDGEHOG_SPAWN_EGG);
output.accept(ModItems.RED_PANDA_SPAWN_EGG);
output.accept(ModItems.BUTTERFLY_SPAWN_EGG);
}).build());
@@ -43,6 +43,9 @@ public class ModItems {
public static final DeferredItem<Item> RED_PANDA_SPAWN_EGG = ITEMS.register("red-panda_spawn_egg",
() -> new DeferredSpawnEggItem(ModEntities.RED_PANDA, 0x923918, 0x211b1b,
new Item.Properties()));
public static final DeferredItem<Item> BUTTERFLY_SPAWN_EGG = ITEMS.register("butterfly_spawn_egg",
() -> new DeferredSpawnEggItem(ModEntities.BUTTERFLY, 0x923918, 0x0b0b17,
new Item.Properties()));
public static void register(IEventBus eventBus) {
ITEMS.register(eventBus);
@@ -22,6 +22,7 @@ import ovh.glitchlabs.masterwild.entity.ModEntities;
import ovh.glitchlabs.masterwild.entity.client.Pinguin.PinguinRenderer;
import ovh.glitchlabs.masterwild.entity.client.Rooster.RoosterRenderer;
import ovh.glitchlabs.masterwild.entity.client.Shark.SharkRenderer;
import ovh.glitchlabs.masterwild.entity.client.butterfly.ButterflyRenderer;
import ovh.glitchlabs.masterwild.entity.client.firefly.FireflyRenderer;
import ovh.glitchlabs.masterwild.entity.client.hedgehog.HedgehogRenderer;
import ovh.glitchlabs.masterwild.entity.client.red_panda.Red_PandaRenderer;
@@ -78,6 +79,7 @@ public class Masterwild {
EntityRenderers.register(ModEntities.SHARK.get(), SharkRenderer::new);
EntityRenderers.register(ModEntities.HEDGEHOG.get(), HedgehogRenderer::new);
EntityRenderers.register(ModEntities.RED_PANDA.get(), Red_PandaRenderer::new);
EntityRenderers.register(ModEntities.BUTTERFLY.get(), ButterflyRenderer::new);
}
}
}
@@ -27,5 +27,6 @@ public class ModItemModelProvider extends ItemModelProvider {
withExistingParent(ModItems.SHARK_SPAWN_EGG.getId().getPath(), mcLoc("item/template_spawn_egg"));
withExistingParent(ModItems.HEDGEHOG_SPAWN_EGG.getId().getPath(), mcLoc("item/template_spawn_egg"));
withExistingParent(ModItems.RED_PANDA_SPAWN_EGG.getId().getPath(), mcLoc("item/template_spawn_egg"));
withExistingParent(ModItems.BUTTERFLY_SPAWN_EGG.getId().getPath(), mcLoc("item/template_spawn_egg"));
}
}
@@ -23,6 +23,7 @@ public class ModLanguageProvider extends LanguageProvider {
add(ModEntities.SHARK.get(), "Shark");
add(ModEntities.HEDGEHOG.get(), "Hedgehog");
add(ModEntities.RED_PANDA.get(), "Red Panda");
add(ModEntities.BUTTERFLY.get(), "Butterfly");
add(ModItems.PINGUIN_SPAWN_EGG.get(), "Pinguin Spawn Egg");
add(ModItems.FIREFLY_SPAWN_EGG.get(), "Firefly Spawn Egg");
@@ -30,6 +31,7 @@ public class ModLanguageProvider extends LanguageProvider {
add(ModItems.SHARK_SPAWN_EGG.get(), "Shark Spawn Egg");
add(ModItems.HEDGEHOG_SPAWN_EGG.get(), "Hedgehog Spawn Egg");
add(ModItems.RED_PANDA_SPAWN_EGG.get(), "Red Panda Spawn Egg");
add(ModItems.BUTTERFLY_SPAWN_EGG.get(), "Butterfly Spawn Egg");
add("creativetab.masterwild.masterwild", "MasterWild");
add("subtitles.masterwild.rooster_crow", "Rooster crows");
@@ -0,0 +1,30 @@
package ovh.glitchlabs.masterwild.entity;
import java.util.Arrays;
import java.util.Comparator;
public enum ButterflyVariants {
PURLE(0),
BLUE(1),
RED(2),
ORANGE(3),
GREEN(4),
;
private static final ButterflyVariants[] BY_ID = Arrays.stream(values()).sorted(
Comparator.comparingInt(ButterflyVariants::getId)).toArray(ButterflyVariants[]::new);
private final int id;
ButterflyVariants(int id) {
this.id = id;
}
public int getId() {
return id;
}
public static ButterflyVariants byId(int id) {
return BY_ID[id % BY_ID.length];
}
}
@@ -38,6 +38,10 @@ public class ModEntities {
ENTITY_TYPES.register("red_panda", () -> EntityType.Builder.of(Red_PandaEntity::new, MobCategory.CREATURE)
.sized(0.6f, 0.7f).build("red_panda"));
public static final Supplier<EntityType<ButterflyEntity>> BUTTERFLY =
ENTITY_TYPES.register("butterfly", () -> EntityType.Builder.of(ButterflyEntity::new, MobCategory.AMBIENT)
.sized(0.6f, 0.7f).build("butterfly"));
public static void register(IEventBus eventBus) {
ENTITY_TYPES.register(eventBus);
@@ -0,0 +1,25 @@
package ovh.glitchlabs.masterwild.entity.client.butterfly;// Save this class in your mod and generate all required imports
import net.minecraft.client.animation.AnimationChannel;
import net.minecraft.client.animation.AnimationDefinition;
import net.minecraft.client.animation.Keyframe;
import net.minecraft.client.animation.KeyframeAnimations;
/**
* Made with Blockbench 5.2.0
* Exported for Minecraft version 1.19 or later with Mojang mappings
* @author Author
*/
public class ButterflyAnimation {
public static final AnimationDefinition Butterfly_flaps = AnimationDefinition.Builder.withLength(0.25F).looping()
.addAnimation("L_wings", new AnimationChannel(AnimationChannel.Targets.ROTATION,
new Keyframe(0.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, -45.0F), AnimationChannel.Interpolations.CATMULLROM),
new Keyframe(0.125F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 45.0F), AnimationChannel.Interpolations.CATMULLROM),
new Keyframe(0.25F, KeyframeAnimations.degreeVec(0.0F, 0.0F, -45.0F), AnimationChannel.Interpolations.CATMULLROM)
))
.addAnimation("R_wings", new AnimationChannel(AnimationChannel.Targets.ROTATION,
new Keyframe(0.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 45.0F), AnimationChannel.Interpolations.CATMULLROM),
new Keyframe(0.125F, KeyframeAnimations.degreeVec(0.0F, 0.0F, -45.0F), AnimationChannel.Interpolations.CATMULLROM),
new Keyframe(0.25F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 45.0F), AnimationChannel.Interpolations.CATMULLROM)
))
.build();
}
@@ -0,0 +1,68 @@
package ovh.glitchlabs.masterwild.entity.client.butterfly;// Made with Blockbench 5.2.0
// Exported for Minecraft version 1.17 or later with Mojang mappings
// Paste this class into your mod and generate all required imports
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.client.model.EntityModel;
import net.minecraft.client.model.HierarchicalModel;
import net.minecraft.client.model.geom.ModelLayerLocation;
import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.client.model.geom.PartPose;
import net.minecraft.client.model.geom.builders.*;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.AnimationState;
import ovh.glitchlabs.masterwild.Masterwild;
import ovh.glitchlabs.masterwild.entity.custom.ButterflyEntity;
public class ButterflyModel<T extends ButterflyEntity> extends HierarchicalModel<T> {
// This layer location should be baked with EntityRendererProvider.Context in the entity renderer and passed into this model's constructor
public static final ModelLayerLocation LAYER_LOCATION = new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath(Masterwild.MODID, "butterfly"), "main");
private final ModelPart Butterfly;
private final ModelPart body;
private final ModelPart L_wings;
private final ModelPart R_wings;
public ButterflyModel(ModelPart root) {
this.Butterfly = root.getChild("Butterfly");
this.body = this.Butterfly.getChild("body");
this.L_wings = this.Butterfly.getChild("L_wings");
this.R_wings = this.Butterfly.getChild("R_wings");
}
public static LayerDefinition createBodyLayer() {
MeshDefinition meshdefinition = new MeshDefinition();
PartDefinition partdefinition = meshdefinition.getRoot();
PartDefinition Butterfly = partdefinition.addOrReplaceChild("Butterfly", CubeListBuilder.create(), PartPose.offset(0.0F, 24.0F, 0.0F));
PartDefinition body = Butterfly.addOrReplaceChild("body", CubeListBuilder.create().texOffs(-5, 27).addBox(-1.5F, -2.0F, -4.5F, 3.0F, 0.0F, 13.0F, new CubeDeformation(0.0F)), PartPose.offset(0.0F, 0.0F, 0.0F));
PartDefinition cube_r1 = body.addOrReplaceChild("cube_r1", CubeListBuilder.create().texOffs(26, 32).addBox(-1.0F, -2.0F, -1.0F, 0.0F, 1.0F, 2.0F, new CubeDeformation(0.0F))
.texOffs(22, 32).addBox(-3.0F, -2.0F, -1.0F, 0.0F, 1.0F, 2.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(2.0F, -1.0F, -5.0F, -0.3927F, 0.0F, 0.0F));
PartDefinition L_wings = Butterfly.addOrReplaceChild("L_wings", CubeListBuilder.create().texOffs(0, 16).addBox(0.0F, 0.0F, -8.0F, 14.0F, 0.0F, 16.0F, new CubeDeformation(0.0F)), PartPose.offset(0.5F, -2.0F, 0.0F));
PartDefinition R_wings = Butterfly.addOrReplaceChild("R_wings", CubeListBuilder.create().texOffs(0, 0).addBox(-14.0F, 0.0F, -8.0F, 14.0F, 0.0F, 16.0F, new CubeDeformation(0.0F)), PartPose.offset(-0.5F, -2.0F, 0.0F));
return LayerDefinition.create(meshdefinition, 64, 64);
}
@Override
public void setupAnim(ButterflyEntity entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch) {
this.root().getAllParts();
this.animate(entity.idleAnimationState, ButterflyAnimation.Butterfly_flaps, ageInTicks, 0.4f);
}
@Override
public void renderToBuffer(PoseStack poseStack, VertexConsumer vertexConsumer, int packedLight, int packedOverlay, int color) {
Butterfly.render(poseStack, vertexConsumer, packedLight, packedOverlay, color);
}
@Override
public ModelPart root() {
return Butterfly;
}
}
@@ -0,0 +1,38 @@
package ovh.glitchlabs.masterwild.entity.client.butterfly;
import com.google.common.collect.Maps;
import net.minecraft.Util;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import net.minecraft.client.renderer.entity.MobRenderer;
import net.minecraft.resources.ResourceLocation;
import ovh.glitchlabs.masterwild.Masterwild;
import ovh.glitchlabs.masterwild.entity.ButterflyVariants;
import ovh.glitchlabs.masterwild.entity.custom.ButterflyEntity;
import java.util.Map;
public class ButterflyRenderer extends MobRenderer<ButterflyEntity, ButterflyModel<ButterflyEntity>> {
public static final Map<ButterflyVariants, ResourceLocation> LOCATION_BY_VARIANT =
Util.make(Maps.newEnumMap(ButterflyVariants.class), map -> {
map.put(ButterflyVariants.PURLE,
ResourceLocation.fromNamespaceAndPath(Masterwild.MODID, "textures/entity/butterfly/butterfly_purple.png"));
map.put(ButterflyVariants.BLUE,
ResourceLocation.fromNamespaceAndPath(Masterwild.MODID, "textures/entity/butterfly/butterfly_blue.png"));
map.put(ButterflyVariants.RED,
ResourceLocation.fromNamespaceAndPath(Masterwild.MODID, "textures/entity/butterfly/butterfly_red.png"));
map.put(ButterflyVariants.ORANGE,
ResourceLocation.fromNamespaceAndPath(Masterwild.MODID, "textures/entity/butterfly/butterfly_orange.png"));
map.put(ButterflyVariants.GREEN,
ResourceLocation.fromNamespaceAndPath(Masterwild.MODID, "textures/entity/butterfly/butterfly_green.png"));
});
public ButterflyRenderer(EntityRendererProvider.Context context) {
super(context, new ButterflyModel<>(context.bakeLayer(ButterflyModel.LAYER_LOCATION)), 0.1f);
}
@Override
public ResourceLocation getTextureLocation(ButterflyEntity entity) {
return LOCATION_BY_VARIANT.get(entity.getVariant());
}
}
@@ -0,0 +1,157 @@
package ovh.glitchlabs.masterwild.entity.custom;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
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.util.Mth;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.AgeableMob;
import net.minecraft.world.entity.AnimationState;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.MobSpawnType;
import net.minecraft.world.entity.SpawnGroupData;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.animal.Animal;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.ServerLevelAccessor;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable;
import ovh.glitchlabs.masterwild.entity.ButterflyVariants;
public class ButterflyEntity extends Animal {
private static final EntityDataAccessor<Integer> VARIANT =
SynchedEntityData.defineId(ButterflyEntity.class, EntityDataSerializers.INT);
public final AnimationState idleAnimationState = new AnimationState();
private BlockPos targetPosition;
public ButterflyEntity(EntityType<? extends Animal> entityType, Level level) {
super(entityType, level);
}
public static AttributeSupplier.Builder createAttributes() {
return Mob.createMobAttributes()
.add(Attributes.MOVEMENT_SPEED, 0.4)
.add(Attributes.MAX_HEALTH, 4)
.add(Attributes.ARMOR, 0)
.add(Attributes.ATTACK_DAMAGE, 0)
.add(Attributes.FOLLOW_RANGE, 4)
.add(Attributes.FLYING_SPEED, 0.3);
}
@Override
protected void customServerAiStep() {
super.customServerAiStep();
if (this.targetPosition != null && (!this.level().isEmptyBlock(this.targetPosition)
|| this.targetPosition.getY() <= this.level().getMinBuildHeight())) {
this.targetPosition = null;
}
if (this.targetPosition == null || this.random.nextInt(30) == 0
|| this.targetPosition.closerToCenterThan(this.position(), 2.0)) {
this.targetPosition = BlockPos.containing(
this.getX() + this.random.nextInt(7) - this.random.nextInt(7),
this.getY() + this.random.nextInt(6) - 2.0,
this.getZ() + this.random.nextInt(7) - this.random.nextInt(7));
}
double dx = this.targetPosition.getX() + 0.5 - this.getX();
double dy = this.targetPosition.getY() + 0.1 - this.getY();
double dz = this.targetPosition.getZ() + 0.5 - this.getZ();
Vec3 motion = this.getDeltaMovement();
Vec3 newMotion = motion.add(
(Math.signum(dx) * 0.25 - motion.x) * 0.1,
(Math.signum(dy) * 0.35 - motion.y) * 0.1,
(Math.signum(dz) * 0.25 - motion.z) * 0.1);
this.setDeltaMovement(newMotion);
float targetYaw = (float) (Mth.atan2(newMotion.z, newMotion.x) * 180.0 / Math.PI) - 90.0F;
this.zza = 0.5F;
this.setYRot(this.getYRot() + Mth.wrapDegrees(targetYaw - this.getYRot()));
}
@Override
public boolean isNoGravity() {
return true;
}
@Override
public boolean isPushable() {
return false;
}
@Override
public boolean causeFallDamage(float fallDistance, float multiplier, DamageSource source) {
return false;
}
@Override
protected void checkFallDamage(double y, boolean onGround, BlockState state, BlockPos pos) {
}
@Override
public boolean isFood(ItemStack itemStack) {
return false;
}
@Override
public @Nullable AgeableMob getBreedOffspring(ServerLevel serverLevel, AgeableMob ageableMob) {
return null;
}
@Override
public void tick() {
super.tick();
if (this.level().isClientSide()) {
this.idleAnimationState.startIfStopped(this.tickCount);
}
}
@Override
protected void defineSynchedData(SynchedEntityData.Builder builder) {
super.defineSynchedData(builder);
builder.define(VARIANT, 0);
}
private int getTypeVariant() {
return this.entityData.get(VARIANT);
}
public ButterflyVariants getVariant() {
return ButterflyVariants.byId(this.getTypeVariant() & 255);
}
private void setVariant(ButterflyVariants variant) {
this.entityData.set(VARIANT, variant.getId() & 255);
}
@Override
public void addAdditionalSaveData(CompoundTag compound) {
super.addAdditionalSaveData(compound);
compound.putInt("Variant", this.getTypeVariant());
}
@Override
public void readAdditionalSaveData(CompoundTag compound) {
super.readAdditionalSaveData(compound);
this.entityData.set(VARIANT, compound.getInt("Variant"));
}
@Override
public SpawnGroupData finalizeSpawn(ServerLevelAccessor level, DifficultyInstance difficulty,
MobSpawnType spawnType, @Nullable SpawnGroupData spawnGroupData) {
ButterflyVariants[] variants = ButterflyVariants.values();
this.setVariant(variants[this.random.nextInt(variants.length)]);
return super.finalizeSpawn(level, difficulty, spawnType, spawnGroupData);
}
}
@@ -9,6 +9,7 @@ import ovh.glitchlabs.masterwild.entity.ModEntities;
import ovh.glitchlabs.masterwild.entity.client.Pinguin.PinguinModel;
import ovh.glitchlabs.masterwild.entity.client.Rooster.RoosterModel;
import ovh.glitchlabs.masterwild.entity.client.Shark.SharkModel;
import ovh.glitchlabs.masterwild.entity.client.butterfly.ButterflyModel;
import ovh.glitchlabs.masterwild.entity.client.firefly.FireflyModel;
import ovh.glitchlabs.masterwild.entity.client.hedgehog.HedgehogModel;
import ovh.glitchlabs.masterwild.entity.client.red_panda.Red_PandaModel;
@@ -24,6 +25,7 @@ public class ModEventBusEvents {
event.registerLayerDefinition(SharkModel.LAYER_LOCATION, SharkModel::createBodyLayer);
event.registerLayerDefinition(HedgehogModel.LAYER_LOCATION, HedgehogModel::createBodyLayer);
event.registerLayerDefinition(Red_PandaModel.LAYER_LOCATION, Red_PandaModel::createBodyLayer);
event.registerLayerDefinition(ButterflyModel.LAYER_LOCATION, ButterflyModel::createBodyLayer);
}
@SubscribeEvent
@@ -34,5 +36,6 @@ public class ModEventBusEvents {
event.put(ModEntities.SHARK.get(), SharkEntity.createAttributes().build());
event.put(ModEntities.HEDGEHOG.get(), HedgehogEntity.createAttributes().build());
event.put(ModEntities.RED_PANDA.get(), Red_PandaEntity.createAttributes().build());
event.put(ModEntities.BUTTERFLY.get(), ButterflyEntity.createAttributes().build());
}
}