Re-added butterflies
|
@ -1,9 +1,11 @@
|
|||
package com.minelittlepony.unicopia;
|
||||
|
||||
import com.minelittlepony.unicopia.entity.ButterflyEntity;
|
||||
import com.minelittlepony.unicopia.entity.CastSpellEntity;
|
||||
import com.minelittlepony.unicopia.entity.FloatingArtefactEntity;
|
||||
import com.minelittlepony.unicopia.projectile.MagicProjectileEntity;
|
||||
|
||||
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry;
|
||||
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricEntityTypeBuilder;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityDimensions;
|
||||
|
@ -14,6 +16,8 @@ import net.minecraft.util.registry.Registry;
|
|||
|
||||
public interface UEntities {
|
||||
|
||||
EntityType<ButterflyEntity> BUTTERFLY = register("butterfly", FabricEntityTypeBuilder.create(SpawnGroup.AMBIENT, ButterflyEntity::new)
|
||||
.dimensions(EntityDimensions.fixed(0.25F, 0.25F)));
|
||||
EntityType<MagicProjectileEntity> THROWN_ITEM = register("thrown_item", FabricEntityTypeBuilder.<MagicProjectileEntity>create(SpawnGroup.MISC, MagicProjectileEntity::new)
|
||||
.trackRangeBlocks(100)
|
||||
.trackedUpdateRate(2)
|
||||
|
@ -30,5 +34,7 @@ public interface UEntities {
|
|||
return Registry.register(Registry.ENTITY_TYPE, new Identifier("unicopia", name), type);
|
||||
}
|
||||
|
||||
static void bootstrap() {}
|
||||
static void bootstrap() {
|
||||
FabricDefaultAttributeRegistry.register(BUTTERFLY, ButterflyEntity.createButterflyAttributes());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ public class Unicopia implements ModInitializer {
|
|||
Channel.bootstrap();
|
||||
UTags.bootstrap();
|
||||
UCriteria.bootstrap();
|
||||
UEntities.bootstrap();
|
||||
Commands.bootstrap();
|
||||
|
||||
ServerTickEvents.END_WORLD_TICK.register(w -> {
|
||||
|
|
|
@ -16,6 +16,7 @@ import com.minelittlepony.unicopia.client.render.AccessoryFeatureRenderer;
|
|||
import com.minelittlepony.unicopia.client.render.AmuletFeatureRenderer;
|
||||
import com.minelittlepony.unicopia.client.render.BatWingsFeatureRenderer;
|
||||
import com.minelittlepony.unicopia.client.render.BraceletFeatureRenderer;
|
||||
import com.minelittlepony.unicopia.client.render.ButterflyEntityRenderer;
|
||||
import com.minelittlepony.unicopia.client.render.CastSpellEntityRenderer;
|
||||
import com.minelittlepony.unicopia.client.render.FloatingArtefactEntityRenderer;
|
||||
import com.minelittlepony.unicopia.client.render.IcarusWingsFeatureRenderer;
|
||||
|
@ -65,6 +66,7 @@ public interface URenderers {
|
|||
AccessoryFeatureRenderer.register(BatWingsFeatureRenderer::new);
|
||||
|
||||
EntityRendererRegistry.INSTANCE.register(UEntities.THROWN_ITEM, FlyingItemEntityRenderer::new);
|
||||
EntityRendererRegistry.INSTANCE.register(UEntities.BUTTERFLY, ButterflyEntityRenderer::new);
|
||||
EntityRendererRegistry.INSTANCE.register(UEntities.FLOATING_ARTEFACT, FloatingArtefactEntityRenderer::new);
|
||||
EntityRendererRegistry.INSTANCE.register(UEntities.CAST_SPELL, CastSpellEntityRenderer::new);
|
||||
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
package com.minelittlepony.unicopia.client.render;
|
||||
|
||||
import com.minelittlepony.unicopia.entity.ButterflyEntity;
|
||||
|
||||
import net.minecraft.client.model.ModelData;
|
||||
import net.minecraft.client.model.ModelPart;
|
||||
import net.minecraft.client.model.ModelPartBuilder;
|
||||
import net.minecraft.client.model.ModelPartData;
|
||||
import net.minecraft.client.model.ModelTransform;
|
||||
import net.minecraft.client.model.TexturedModelData;
|
||||
import net.minecraft.client.render.VertexConsumer;
|
||||
import net.minecraft.client.render.entity.EntityRendererFactory;
|
||||
import net.minecraft.client.render.entity.MobEntityRenderer;
|
||||
import net.minecraft.client.render.entity.model.EntityModel;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
|
||||
public class ButterflyEntityRenderer extends MobEntityRenderer<ButterflyEntity, ButterflyEntityRenderer.ButterflyEntityModel> {
|
||||
public ButterflyEntityRenderer(EntityRendererFactory.Context context) {
|
||||
super(context, new ButterflyEntityModel(ButterflyEntityModel.getData().createModel()), 0.25F);
|
||||
shadowRadius = 0.2F;
|
||||
shadowOpacity = 0.3F;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier getTexture(ButterflyEntity entity) {
|
||||
return entity.getVariant().getSkin();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void scale(ButterflyEntity entity, MatrixStack matrices, float ticks) {
|
||||
matrices.scale(0.35F, 0.35F, 0.35F);
|
||||
matrices.translate(0.5F, 0, -0.5F);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupTransforms(ButterflyEntity entity, MatrixStack matrices, float age, float yaw, float ticks) {
|
||||
|
||||
if (!entity.isResting()) {
|
||||
matrices.translate(0, MathHelper.cos(age / 3F) / 10F, 0);
|
||||
}
|
||||
|
||||
super.setupTransforms(entity, matrices, age, yaw, ticks);
|
||||
}
|
||||
|
||||
public static class ButterflyEntityModel extends EntityModel<ButterflyEntity> {
|
||||
private final ModelPart body;
|
||||
private final ModelPart leftWing;
|
||||
private final ModelPart rightWing;
|
||||
|
||||
public ButterflyEntityModel(ModelPart tree) {
|
||||
super(RenderLayers::getEntityAlpha);
|
||||
body = tree;
|
||||
body.pivotX = -10;
|
||||
body.pivotY = 12;
|
||||
leftWing = tree.getChild("left_wing");
|
||||
rightWing = tree.getChild("right_wing");
|
||||
}
|
||||
|
||||
static TexturedModelData getData() {
|
||||
ModelData data = new ModelData();
|
||||
ModelPartData tree = data.getRoot();
|
||||
|
||||
tree.addChild("right_wing", ModelPartBuilder.create().uv(42, 0).cuboid(-13, -5, 0, 10, 19, 1), ModelTransform.rotation(0, 0, -0.2F))
|
||||
.addChild("right_wing_outer", ModelPartBuilder.create().uv(24, 16).cuboid(0, 0, 0, 10, 12, 1), ModelTransform.of(-13, 10, 0.1F, 0, 0, -0.2F));
|
||||
|
||||
tree.addChild("left_wing", ModelPartBuilder.create().uv(42, 0).mirrored().cuboid(2, -5, 0, 10, 19, 1), ModelTransform.rotation(0, 0, 0.2F))
|
||||
.addChild("left_wing_outer", ModelPartBuilder.create().uv(24, 16).cuboid(0, 0, 0, 10, 12, 1), ModelTransform.of(2, 10, 0.1F, 0, 0, 0.2F));
|
||||
|
||||
return TexturedModelData.of(data, 64, 64);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(MatrixStack matrices, VertexConsumer vertexConsumer, int light, int overlay, float red, float green, float blue, float alpha) {
|
||||
body.render(matrices, vertexConsumer, light, overlay, red, green, blue, alpha);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAngles(ButterflyEntity entity, float limbSwing, float limbSwingAmount, float ageInTicks, float headYaw, float headPitch) {
|
||||
|
||||
float flap = MathHelper.cos(ageInTicks) * (float)Math.PI / 4;
|
||||
|
||||
if (entity.isResting()) {
|
||||
body.pitch = 0.8F;
|
||||
flap = MathHelper.cos((ageInTicks + (1 + entity.getId()) % 2) / 20) * (float)Math.PI / 6 + 0.7F;
|
||||
} else {
|
||||
body.pitch = ((float)Math.PI / 4) + MathHelper.cos(ageInTicks * 0.1F) * 0.15F;
|
||||
}
|
||||
|
||||
leftWing.yaw = -flap;
|
||||
rightWing.yaw = flap;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,226 @@
|
|||
package com.minelittlepony.unicopia.entity;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityPose;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.SpawnReason;
|
||||
import net.minecraft.entity.attribute.DefaultAttributeContainer;
|
||||
import net.minecraft.entity.attribute.EntityAttributes;
|
||||
import net.minecraft.entity.damage.DamageSource;
|
||||
import net.minecraft.entity.data.DataTracker;
|
||||
import net.minecraft.entity.data.TrackedData;
|
||||
import net.minecraft.entity.data.TrackedDataHandlerRegistry;
|
||||
import net.minecraft.entity.mob.AmbientEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.predicate.entity.EntityPredicates;
|
||||
import net.minecraft.sound.SoundEvent;
|
||||
import net.minecraft.sound.SoundEvents;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldAccess;
|
||||
|
||||
public class ButterflyEntity extends AmbientEntity {
|
||||
private static final TrackedData<Boolean> RESTING = DataTracker.registerData(ButterflyEntity.class, TrackedDataHandlerRegistry.BOOLEAN);
|
||||
private static final TrackedData<Integer> VARIANT = DataTracker.registerData(ButterflyEntity.class, TrackedDataHandlerRegistry.INTEGER);
|
||||
|
||||
private BlockPos hoveringPosition;
|
||||
|
||||
public ButterflyEntity(EntityType<ButterflyEntity> type, World world) {
|
||||
super(type, world);
|
||||
setVariant(Variant.random(world.random));
|
||||
setResting(true);
|
||||
}
|
||||
|
||||
public static DefaultAttributeContainer.Builder createButterflyAttributes() {
|
||||
return createMobAttributes().add(EntityAttributes.GENERIC_MAX_HEALTH, 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getSoundPitch() {
|
||||
return super.getSoundPitch() * 0.95F;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected SoundEvent getHurtSound(DamageSource damageSourceIn) {
|
||||
return SoundEvents.ENTITY_BAT_HURT;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected SoundEvent getDeathSound() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initDataTracker() {
|
||||
super.initDataTracker();
|
||||
getDataTracker().startTracking(VARIANT, Variant.BUTTERFLY.ordinal());
|
||||
getDataTracker().startTracking(RESTING, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPushable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean collides() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
Vec3d vel = getVelocity();
|
||||
setVelocity(vel.x, vel.y * 0.6 + 0.02F, vel.z);
|
||||
}
|
||||
|
||||
public boolean isResting() {
|
||||
return getDataTracker().get(RESTING);
|
||||
}
|
||||
|
||||
public void setResting(boolean resting) {
|
||||
getDataTracker().set(RESTING, resting);
|
||||
}
|
||||
|
||||
public Variant getVariant() {
|
||||
Variant[] values = Variant.values();
|
||||
return values[getDataTracker().get(VARIANT) % values.length];
|
||||
}
|
||||
|
||||
public void setVariant(Variant variant) {
|
||||
getDataTracker().set(VARIANT, variant.ordinal());
|
||||
}
|
||||
|
||||
protected boolean isAggressor(Entity e) {
|
||||
if (e instanceof ButterflyEntity) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (e instanceof PlayerEntity) {
|
||||
PlayerEntity player = (PlayerEntity)e;
|
||||
|
||||
if (player.isCreative() || player.isSpectator()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (player.isSprinting() || player.handSwinging || player.forwardSpeed > 0 || player.sidewaysSpeed > 0) {
|
||||
return true;
|
||||
}
|
||||
} else if (!EntityPredicates.EXCEPT_CREATIVE_OR_SPECTATOR.test(e)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return e.getVelocity().x != 0 || e.getVelocity().z != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tickMovement() {
|
||||
super.tickMovement();
|
||||
|
||||
BlockPos pos = getBlockPos();
|
||||
BlockPos below = pos.down();
|
||||
|
||||
if (isResting()) {
|
||||
if (world.getBlockState(below).isOpaque()) {
|
||||
if (!world.getOtherEntities(this, getBoundingBox().expand(7), this::isAggressor).isEmpty()) {
|
||||
setResting(false);
|
||||
}
|
||||
} else {
|
||||
setResting(false);
|
||||
}
|
||||
} else {
|
||||
|
||||
// invalidate the hovering position
|
||||
if (hoveringPosition != null && (!world.isAir(hoveringPosition) || hoveringPosition.getY() < 1)) {
|
||||
hoveringPosition = null;
|
||||
}
|
||||
|
||||
// select a new hovering position
|
||||
if (hoveringPosition == null || random.nextInt(30) == 0 || hoveringPosition.getSquaredDistance(pos) < 4) {
|
||||
hoveringPosition = new BlockPos(
|
||||
getX() + random.nextInt(7) - random.nextInt(7),
|
||||
getY() + random.nextInt(6) - 2,
|
||||
getZ() + random.nextInt(7) - random.nextInt(7)
|
||||
);
|
||||
}
|
||||
|
||||
// hover casually towards the chosen position
|
||||
Vec3d motion = Vec3d.ofCenter(hoveringPosition, 0.1).subtract(getPos());
|
||||
Vec3d vel = getVelocity();
|
||||
|
||||
addVelocity(
|
||||
(Math.signum(motion.getX()) * 0.5 - vel.x) * 0.1,
|
||||
(Math.signum(motion.getY()) * 0.7 - vel.y) * 0.1,
|
||||
(Math.signum(motion.getZ()) * 0.5 - vel.z) * 0.1
|
||||
);
|
||||
|
||||
float direction = (float)(MathHelper.atan2(vel.z, vel.x) * (180 / Math.PI)) - 90;
|
||||
|
||||
forwardSpeed = 0.5F;
|
||||
headYaw += MathHelper.wrapDegrees(direction - headYaw);
|
||||
|
||||
if (random.nextInt(100) == 0 && world.getBlockState(below).isOpaque()) {
|
||||
setResting(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleFallDamage(float distance, float damageMultiplier, DamageSource cause) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fall(double y, boolean onGroundIn, BlockState state, BlockPos pos) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSpawn(WorldAccess world, SpawnReason reason) {
|
||||
return reason != SpawnReason.NATURAL || (getY() < world.getSeaLevel() && world.getLightLevel(getBlockPos()) > 7);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getEyeHeight(EntityPose pose) {
|
||||
return getHeight() / 2;
|
||||
}
|
||||
|
||||
public enum Variant {
|
||||
BUTTERFLY,
|
||||
YELLOW,
|
||||
LIME,
|
||||
RED,
|
||||
GREEN,
|
||||
BLUE,
|
||||
PURPLE,
|
||||
MAGENTA,
|
||||
PINK,
|
||||
HEDYLIDAE,
|
||||
LYCAENIDAE,
|
||||
NYMPHALIDAE,
|
||||
MONARCH,
|
||||
WHITE_MONARCH,
|
||||
BRIMSTONE;
|
||||
|
||||
private final Identifier skin = new Identifier("unicopia", "textures/entity/butterfly/" + name().toLowerCase() + ".png");
|
||||
|
||||
public Identifier getSkin() {
|
||||
return skin;
|
||||
}
|
||||
|
||||
static Variant random(Random rand) {
|
||||
Variant[] values = values();
|
||||
return values[rand.nextInt(values.length)];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ package com.minelittlepony.unicopia.item;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.minelittlepony.unicopia.UEntities;
|
||||
import com.minelittlepony.unicopia.USounds;
|
||||
import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
|
||||
import com.minelittlepony.unicopia.item.toxin.UFoodComponents;
|
||||
|
@ -15,6 +16,7 @@ import net.fabricmc.fabric.api.item.v1.FabricItemSettings;
|
|||
import net.minecraft.item.BlockItem;
|
||||
import net.minecraft.item.FoodComponents;
|
||||
import net.minecraft.item.MusicDiscItem;
|
||||
import net.minecraft.item.SpawnEggItem;
|
||||
import net.minecraft.sound.SoundEvent;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.Rarity;
|
||||
|
@ -72,6 +74,8 @@ public interface UItems {
|
|||
Item GOLDEN_FEATHER = register("golden_feather", new Item(new Item.Settings().rarity(Rarity.UNCOMMON).group(ItemGroup.MATERIALS)));
|
||||
Item GOLDEN_WING = register("golden_wing", new Item(new Item.Settings().rarity(Rarity.UNCOMMON).group(ItemGroup.MATERIALS)));
|
||||
|
||||
Item BUTTERFLY_SPAWN_EGG = register("butterfly_spawn_egg", new SpawnEggItem(UEntities.BUTTERFLY, 0x222200, 0xaaeeff, new Item.Settings().group(ItemGroup.MISC)));
|
||||
|
||||
AmuletItem PEGASUS_AMULET = register("pegasus_amulet", new AmuletItem(new FabricItemSettings()
|
||||
.maxCount(1)
|
||||
.maxDamage(890)
|
||||
|
|
|
@ -66,6 +66,7 @@
|
|||
"item.unicopia.music_disc_funk": "Music Disc",
|
||||
"item.unicopia.music_disc_funk.desc": "funk, just funk",
|
||||
|
||||
"entity.unicopia.butterfly": "Butterfly",
|
||||
"entity.unicopia.cast_spell": "Cast Spell",
|
||||
"entity.unicopia.cast_spell.by": "a spell cast by %s",
|
||||
|
||||
|
|
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 2.9 KiB |