diff --git a/src/main/generated/assets/acesbs/models/item/fren_spawn_egg.json b/src/main/generated/assets/acesbs/models/item/fren_spawn_egg.json new file mode 100644 index 0000000..d1aaa9d --- /dev/null +++ b/src/main/generated/assets/acesbs/models/item/fren_spawn_egg.json @@ -0,0 +1,3 @@ +{ + "parent": "minecraft:item/template_spawn_egg" +} \ No newline at end of file diff --git a/src/main/java/com/acethewildfire/acesbs/AcesBS.java b/src/main/java/com/acethewildfire/acesbs/AcesBS.java index 809056b..bd49671 100644 --- a/src/main/java/com/acethewildfire/acesbs/AcesBS.java +++ b/src/main/java/com/acethewildfire/acesbs/AcesBS.java @@ -4,6 +4,8 @@ import com.acethewildfire.acesbs.block.ModBlocks; import com.acethewildfire.acesbs.component.ModDataComponentTypes; import com.acethewildfire.acesbs.effect.ModEffects; import com.acethewildfire.acesbs.enchantment.ModEnchantmentEffects; +import com.acethewildfire.acesbs.entity.ModEntities; +import com.acethewildfire.acesbs.entity.custom.FrenEntity; import com.acethewildfire.acesbs.item.ModItemGroups; import com.acethewildfire.acesbs.item.ModItems; import com.acethewildfire.acesbs.potion.ModPotions; @@ -15,6 +17,7 @@ import com.acethewildfire.acesbs.world.gen.ModWorldGeneration; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.event.player.AttackEntityCallback; import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents; +import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry; import net.fabricmc.fabric.api.registry.CompostingChanceRegistry; import net.fabricmc.fabric.api.registry.FabricBrewingRecipeRegistryBuilder; import net.fabricmc.fabric.api.registry.FlammableBlockRegistry; @@ -48,6 +51,7 @@ public class AcesBS implements ModInitializer { ModPotions.registerPotions(); ModEnchantmentEffects.registerModEnchantments(); ModWorldGeneration.generateModWorldGen(); + ModEntities.registerModEntities(); ModDataComponentTypes.registerDataComponentsTypes(); @@ -77,5 +81,7 @@ public class AcesBS implements ModInitializer { FlammableBlockRegistry.getDefaultInstance().add(ModBlocks.LEMONWOOD_STAIRS, 5, 20); FlammableBlockRegistry.getDefaultInstance().add(ModBlocks.LEMONWOOD_LEAVES, 30, 60); + + FabricDefaultAttributeRegistry.register(ModEntities.FREN, FrenEntity.createAttributes()); } } \ No newline at end of file diff --git a/src/main/java/com/acethewildfire/acesbs/AcesBSClient.java b/src/main/java/com/acethewildfire/acesbs/AcesBSClient.java index fa601b6..5bde8e5 100644 --- a/src/main/java/com/acethewildfire/acesbs/AcesBSClient.java +++ b/src/main/java/com/acethewildfire/acesbs/AcesBSClient.java @@ -1,9 +1,14 @@ package com.acethewildfire.acesbs; import com.acethewildfire.acesbs.block.ModBlocks; +import com.acethewildfire.acesbs.entity.ModEntities; +import com.acethewildfire.acesbs.entity.client.FrenModel; +import com.acethewildfire.acesbs.entity.client.FrenRenderer; import com.acethewildfire.acesbs.util.ModModelPredicates; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap; +import net.fabricmc.fabric.api.client.rendering.v1.EntityModelLayerRegistry; +import net.fabricmc.fabric.api.client.rendering.v1.EntityRendererRegistry; import net.minecraft.client.render.RenderLayer; public class AcesBSClient implements ClientModInitializer { @@ -16,5 +21,8 @@ public class AcesBSClient implements ClientModInitializer { BlockRenderLayerMap.INSTANCE.putBlock(ModBlocks.POTTED_LEMONWOOD_SAPLING, RenderLayer.getCutout()); ModModelPredicates.registerModelPredicates(); + + EntityModelLayerRegistry.registerModelLayer(FrenModel.FREN, FrenModel::getTexturedModelData); + EntityRendererRegistry.register(ModEntities.FREN, FrenRenderer::new); } } diff --git a/src/main/java/com/acethewildfire/acesbs/TODO.txt b/src/main/java/com/acethewildfire/acesbs/TODO.txt index 09dd5ce..b18a2b8 100644 --- a/src/main/java/com/acethewildfire/acesbs/TODO.txt +++ b/src/main/java/com/acethewildfire/acesbs/TODO.txt @@ -77,7 +77,7 @@ Workstations - Entropic Entangler (For Metals and Stones) Mobs -- Fren (Stable Entropy on a Creeper) +X Fren (Stable Entropy on a Creeper) - Burning Wizard (Infernal Ashes on a Witch) - Wildfire Iskat (Infernal Ashes on a tamed cat) - Rat Bastard (Stable Entropy on a cat) diff --git a/src/main/java/com/acethewildfire/acesbs/datagen/ModModelProvider.java b/src/main/java/com/acethewildfire/acesbs/datagen/ModModelProvider.java index ea5a23f..78723b9 100644 --- a/src/main/java/com/acethewildfire/acesbs/datagen/ModModelProvider.java +++ b/src/main/java/com/acethewildfire/acesbs/datagen/ModModelProvider.java @@ -11,6 +11,8 @@ import net.minecraft.data.client.*; import net.minecraft.item.ArmorItem; import net.minecraft.util.Identifier; +import java.util.Optional; + public class ModModelProvider extends FabricModelProvider { public ModModelProvider(FabricDataOutput output) { @@ -90,5 +92,8 @@ public class ModModelProvider extends FabricModelProvider { itemModelGenerator.registerArmor((ArmorItem) ModItems.PRISMA_STEEL_BOOTS); itemModelGenerator.registerArmor((ArmorItem) ModItems.BERSERKERS_PAULDRON); + + itemModelGenerator.register(ModItems.FREN_SPAWN_EGG, + new Model(Optional.of(Identifier.of("item/template_spawn_egg")), Optional.empty())); } } diff --git a/src/main/java/com/acethewildfire/acesbs/datagen/ModRecipeProvider.java b/src/main/java/com/acethewildfire/acesbs/datagen/ModRecipeProvider.java index 4fe7b88..50bdb9f 100644 --- a/src/main/java/com/acethewildfire/acesbs/datagen/ModRecipeProvider.java +++ b/src/main/java/com/acethewildfire/acesbs/datagen/ModRecipeProvider.java @@ -60,12 +60,48 @@ public class ModRecipeProvider extends FabricRecipeProvider { .criterion(hasItem(ModBlocks.LIZARD_PLANKS), conditionsFromItem(ModBlocks.LIZARD_PLANKS)) .offerTo(recipeExporter); - ShapelessRecipeJsonBuilder.create(RecipeCategory.BUILDING_BLOCKS, ModBlocks.LEMONWOOD_PLANKS, 4) - .input(Blocks.BIRCH_PLANKS, 4) + ShapelessRecipeJsonBuilder.create(RecipeCategory.DECORATIONS, ModBlocks.LEMONWOOD_SAPLING, 1) + .input(Blocks.BIRCH_SAPLING, 1) .input(ModItems.LEMON, 1) .criterion(hasItem(ModItems.LEMON), conditionsFromItem(ModItems.LEMON)) .offerTo(recipeExporter); + ShapelessRecipeJsonBuilder.create(RecipeCategory.BUILDING_BLOCKS, ModBlocks.LEMONWOOD_PLANKS, 4) + .input(ModBlocks.LEMONWOOD_LOG, 1) + .criterion(hasItem(ModBlocks.LEMONWOOD_LOG), conditionsFromItem(ModBlocks.LEMONWOOD_LOG)) + .offerTo(recipeExporter, Identifier.of(AcesBS.MOD_ID, "lemonwood_planks_from_lemonwood_log")); + + ShapelessRecipeJsonBuilder.create(RecipeCategory.BUILDING_BLOCKS, ModBlocks.LEMONWOOD_PLANKS, 4) + .input(ModBlocks.STRIPPED_LEMONWOOD_LOG, 1) + .criterion(hasItem(ModBlocks.STRIPPED_LEMONWOOD_LOG), conditionsFromItem(ModBlocks.STRIPPED_LEMONWOOD_LOG)) + .offerTo(recipeExporter, Identifier.of(AcesBS.MOD_ID, "lemonwood_planks_from_stripped_lemonwood_log")); + + ShapelessRecipeJsonBuilder.create(RecipeCategory.BUILDING_BLOCKS, ModBlocks.LEMONWOOD_PLANKS, 4) + .input(ModBlocks.LEMONWOOD_WOOD, 1) + .criterion(hasItem(ModBlocks.LEMONWOOD_WOOD), conditionsFromItem(ModBlocks.LEMONWOOD_WOOD)) + .offerTo(recipeExporter, Identifier.of(AcesBS.MOD_ID, "lemonwood_planks_from_lemonwood_wood")); + + ShapelessRecipeJsonBuilder.create(RecipeCategory.BUILDING_BLOCKS, ModBlocks.LEMONWOOD_PLANKS, 4) + .input(ModBlocks.STRIPPED_LEMONWOOD_WOOD, 1) + .criterion(hasItem(ModBlocks.STRIPPED_LEMONWOOD_WOOD), conditionsFromItem(ModBlocks.STRIPPED_LEMONWOOD_WOOD)) + .offerTo(recipeExporter, Identifier.of(AcesBS.MOD_ID, "lemonwood_planks_from_stripped_lemonwood_wood")); + + ShapedRecipeJsonBuilder.create(RecipeCategory.BUILDING_BLOCKS, ModBlocks.LEMONWOOD_WOOD, 3) + .pattern("## ") + .pattern("## ") + .pattern(" ") + .input('#', ModBlocks.LEMONWOOD_LOG) + .criterion(hasItem(ModBlocks.LEMONWOOD_LOG), conditionsFromItem(ModBlocks.LEMONWOOD_LOG)) + .offerTo(recipeExporter); + + ShapedRecipeJsonBuilder.create(RecipeCategory.BUILDING_BLOCKS, ModBlocks.STRIPPED_LEMONWOOD_WOOD, 3) + .pattern("## ") + .pattern("## ") + .pattern(" ") + .input('#', ModBlocks.STRIPPED_LEMONWOOD_LOG) + .criterion(hasItem(ModBlocks.STRIPPED_LEMONWOOD_LOG), conditionsFromItem(ModBlocks.STRIPPED_LEMONWOOD_LOG)) + .offerTo(recipeExporter); + createStairsRecipe(ModBlocks.LEMONWOOD_STAIRS, Ingredient.ofItems(ModBlocks.LEMONWOOD_PLANKS)) .criterion(hasItem(ModBlocks.LEMONWOOD_PLANKS), conditionsFromItem(ModBlocks.LEMONWOOD_PLANKS)) .offerTo(recipeExporter); diff --git a/src/main/java/com/acethewildfire/acesbs/entity/ModEntities.java b/src/main/java/com/acethewildfire/acesbs/entity/ModEntities.java new file mode 100644 index 0000000..fac5d90 --- /dev/null +++ b/src/main/java/com/acethewildfire/acesbs/entity/ModEntities.java @@ -0,0 +1,22 @@ +package com.acethewildfire.acesbs.entity; + +import com.acethewildfire.acesbs.AcesBS; +import com.acethewildfire.acesbs.entity.custom.FrenEntity; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.SpawnGroup; +import net.minecraft.registry.Registries; +import net.minecraft.registry.Registry; +import net.minecraft.util.Identifier; + +public class ModEntities { + + public static final EntityType FREN = Registry.register(Registries.ENTITY_TYPE, + Identifier.of(AcesBS.MOD_ID, "fren"), + EntityType.Builder.create(FrenEntity::new, SpawnGroup.MONSTER) + .dimensions(0.6F, 1.7F).build()); + + + public static void registerModEntities() { + AcesBS.LOGGER.info("Registering Mod Entities for " + AcesBS.MOD_ID); + } +} diff --git a/src/main/java/com/acethewildfire/acesbs/entity/client/FrenAnimations.java b/src/main/java/com/acethewildfire/acesbs/entity/client/FrenAnimations.java new file mode 100644 index 0000000..03b7e5a --- /dev/null +++ b/src/main/java/com/acethewildfire/acesbs/entity/client/FrenAnimations.java @@ -0,0 +1,80 @@ +package com.acethewildfire.acesbs.entity.client; +// Save this class in your mod and generate all required imports + +import net.minecraft.client.render.entity.animation.Animation; +import net.minecraft.client.render.entity.animation.AnimationHelper; +import net.minecraft.client.render.entity.animation.Keyframe; +import net.minecraft.client.render.entity.animation.Transformation; + +/** + * Made with Blockbench 5.0.4 + * Exported for Minecraft version 1.19 or later with Yarn mappings + * @author Author + */ +public class FrenAnimations { + public static final Animation ANIM_FREN_WALK = Animation.Builder.create(1.0025F).looping() + .addBoneAnimation("head", new Transformation(Transformation.Targets.ROTATE, + new Keyframe(0.0F, AnimationHelper.createRotationalVector(0.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR), + new Keyframe(0.25F, AnimationHelper.createRotationalVector(0.0F, 0.0F, 5.0F), Transformation.Interpolations.LINEAR), + new Keyframe(0.5F, AnimationHelper.createRotationalVector(0.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR), + new Keyframe(0.75F, AnimationHelper.createRotationalVector(0.0F, 0.0F, -5.0F), Transformation.Interpolations.LINEAR), + new Keyframe(1.0F, AnimationHelper.createRotationalVector(0.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR) + )) + .addBoneAnimation("leg1", new Transformation(Transformation.Targets.ROTATE, + new Keyframe(0.0F, AnimationHelper.createRotationalVector(0.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR), + new Keyframe(0.25F, AnimationHelper.createRotationalVector(30.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR), + new Keyframe(0.5F, AnimationHelper.createRotationalVector(0.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR), + new Keyframe(0.75F, AnimationHelper.createRotationalVector(-30.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR), + new Keyframe(1.0F, AnimationHelper.createRotationalVector(0.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR) + )) + .addBoneAnimation("leg2", new Transformation(Transformation.Targets.ROTATE, + new Keyframe(0.0F, AnimationHelper.createRotationalVector(0.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR), + new Keyframe(0.25F, AnimationHelper.createRotationalVector(-30.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR), + new Keyframe(0.5F, AnimationHelper.createRotationalVector(0.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR), + new Keyframe(0.75F, AnimationHelper.createRotationalVector(30.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR), + new Keyframe(1.0F, AnimationHelper.createRotationalVector(0.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR) + )) + .addBoneAnimation("leg4", new Transformation(Transformation.Targets.ROTATE, + new Keyframe(0.0F, AnimationHelper.createRotationalVector(0.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR), + new Keyframe(0.25F, AnimationHelper.createRotationalVector(30.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR), + new Keyframe(0.5F, AnimationHelper.createRotationalVector(0.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR), + new Keyframe(0.75F, AnimationHelper.createRotationalVector(-30.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR), + new Keyframe(1.0F, AnimationHelper.createRotationalVector(0.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR) + )) + .addBoneAnimation("leg3", new Transformation(Transformation.Targets.ROTATE, + new Keyframe(0.0F, AnimationHelper.createRotationalVector(0.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR), + new Keyframe(0.25F, AnimationHelper.createRotationalVector(-30.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR), + new Keyframe(0.5F, AnimationHelper.createRotationalVector(0.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR), + new Keyframe(0.75F, AnimationHelper.createRotationalVector(30.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR), + new Keyframe(1.0F, AnimationHelper.createRotationalVector(0.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR) + )) + .build(); + + public static final Animation ANIM_FREN_IDLE = Animation.Builder.create(1.0F).looping() + .addBoneAnimation("head", new Transformation(Transformation.Targets.ROTATE, + new Keyframe(0.0F, AnimationHelper.createRotationalVector(0.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR), + new Keyframe(1.0F, AnimationHelper.createRotationalVector(0.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR) + )) + .addBoneAnimation("head", new Transformation(Transformation.Targets.TRANSLATE, + new Keyframe(0.0F, AnimationHelper.createTranslationalVector(0.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR), + new Keyframe(0.5F, AnimationHelper.createTranslationalVector(0.0F, -0.25F, 0.0F), Transformation.Interpolations.LINEAR), + new Keyframe(1.0F, AnimationHelper.createTranslationalVector(0.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR) + )) + .addBoneAnimation("leg1", new Transformation(Transformation.Targets.ROTATE, + new Keyframe(0.0F, AnimationHelper.createRotationalVector(0.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR), + new Keyframe(1.0F, AnimationHelper.createRotationalVector(0.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR) + )) + .addBoneAnimation("leg2", new Transformation(Transformation.Targets.ROTATE, + new Keyframe(0.0F, AnimationHelper.createRotationalVector(0.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR), + new Keyframe(1.0F, AnimationHelper.createRotationalVector(0.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR) + )) + .addBoneAnimation("leg4", new Transformation(Transformation.Targets.ROTATE, + new Keyframe(0.0F, AnimationHelper.createRotationalVector(0.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR), + new Keyframe(1.0F, AnimationHelper.createRotationalVector(0.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR) + )) + .addBoneAnimation("leg3", new Transformation(Transformation.Targets.ROTATE, + new Keyframe(0.0F, AnimationHelper.createRotationalVector(0.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR), + new Keyframe(1.0F, AnimationHelper.createRotationalVector(0.0F, 0.0F, 0.0F), Transformation.Interpolations.LINEAR) + )) + .build(); +} \ No newline at end of file diff --git a/src/main/java/com/acethewildfire/acesbs/entity/client/FrenModel.java b/src/main/java/com/acethewildfire/acesbs/entity/client/FrenModel.java new file mode 100644 index 0000000..4eaf203 --- /dev/null +++ b/src/main/java/com/acethewildfire/acesbs/entity/client/FrenModel.java @@ -0,0 +1,78 @@ +package com.acethewildfire.acesbs.entity.client; + +import com.acethewildfire.acesbs.AcesBS; +import com.acethewildfire.acesbs.entity.custom.FrenEntity; +import net.minecraft.client.model.*; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.entity.model.EntityModel; +import net.minecraft.client.render.entity.model.EntityModelLayer; +import net.minecraft.client.render.entity.model.SinglePartEntityModel; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.MathHelper; + +public class FrenModel extends SinglePartEntityModel { + public static final EntityModelLayer FREN = new EntityModelLayer(Identifier.of(AcesBS.MOD_ID, "fren"), "main"); + private final ModelPart root; + private final ModelPart leg3; + private final ModelPart leg4; + private final ModelPart leg2; + private final ModelPart leg1; + private final ModelPart head; + private final ModelPart body; + + public FrenModel(ModelPart root) { + this.root = root.getChild("root"); + this.leg3 = this.root.getChild("leg3"); + this.leg4 = this.root.getChild("leg4"); + this.leg2 = this.root.getChild("leg2"); + this.leg1 = this.root.getChild("leg1"); + this.head = this.root.getChild("head"); + this.body = this.root.getChild("body"); + } + public static TexturedModelData getTexturedModelData() { + ModelData modelData = new ModelData(); + ModelPartData modelPartData = modelData.getRoot(); + ModelPartData root = modelPartData.addChild("root", ModelPartBuilder.create(), ModelTransform.pivot(0.0F, 17.0F, 0.0F)); + + ModelPartData head = root.addChild("head", ModelPartBuilder.create().uv(0, 0).cuboid(-4.0F, -7.0F, -4.0F, 8.0F, 8.0F, 8.0F, new Dilation(0.0F)), ModelTransform.pivot(0.0F, -12.0F, 0.0F)); + + ModelPartData body = root.addChild("body", ModelPartBuilder.create().uv(16, 16).cuboid(-4.0F, -18.0F, -2.0F, 8.0F, 12.0F, 4.0F, new Dilation(0.0F)), ModelTransform.pivot(0.0F, 7.0F, 0.0F)); + + ModelPartData leg1 = root.addChild("leg1", ModelPartBuilder.create().uv(0, 16).cuboid(-2.0F, 0.0F, 0.0F, 4.0F, 6.0F, 4.0F, new Dilation(0.0F)), ModelTransform.pivot(-2.0F, 1.0F, 2.0F)); + + ModelPartData leg2 = root.addChild("leg2", ModelPartBuilder.create().uv(0, 16).cuboid(-2.0F, 0.0F, 0.0F, 4.0F, 6.0F, 4.0F, new Dilation(0.0F)), ModelTransform.pivot(2.0F, 1.0F, 2.0F)); + + ModelPartData leg4 = root.addChild("leg4", ModelPartBuilder.create().uv(0, 16).cuboid(-2.0F, 0.0F, -4.0F, 4.0F, 6.0F, 4.0F, new Dilation(0.0F)), ModelTransform.pivot(2.0F, 1.0F, -2.0F)); + + ModelPartData leg3 = root.addChild("leg3", ModelPartBuilder.create().uv(0, 16).cuboid(-2.0F, 0.0F, -4.0F, 4.0F, 6.0F, 4.0F, new Dilation(0.0F)), ModelTransform.pivot(-2.0F, 1.0F, -2.0F)); + return TexturedModelData.of(modelData, 64, 32); + } + + @Override + public void render(MatrixStack matrices, VertexConsumer vertexConsumer, int light, int overlay, int color) { + root.render(matrices, vertexConsumer, light, overlay, color); + } + + @Override + public ModelPart getPart() { + return root; + } + + @Override + public void setAngles(FrenEntity entity, float limbAngle, float limbDistance, float animationProgress, float headYaw, float headPitch) { + this.getPart().traverse().forEach(ModelPart::resetTransform); + this.setHeadAngles(headYaw, headPitch); + + this.animateMovement(FrenAnimations.ANIM_FREN_WALK, limbAngle, limbDistance, 2f, 2.5f); + this.updateAnimation(entity.idleAnimationState, FrenAnimations.ANIM_FREN_IDLE, animationProgress, 1f); + } + + private void setHeadAngles(float headYaw, float headPitch) { + headYaw = MathHelper.clamp(headYaw, -30.0F, 30.0F); + headPitch = MathHelper.clamp(headPitch, -25.0F, 45.0F); + + this.head.yaw = headYaw * 0.017453292F; + this.head.pitch = headPitch * 0.017453292F; + } +} diff --git a/src/main/java/com/acethewildfire/acesbs/entity/client/FrenRenderer.java b/src/main/java/com/acethewildfire/acesbs/entity/client/FrenRenderer.java new file mode 100644 index 0000000..99a78f4 --- /dev/null +++ b/src/main/java/com/acethewildfire/acesbs/entity/client/FrenRenderer.java @@ -0,0 +1,32 @@ +package com.acethewildfire.acesbs.entity.client; + +import com.acethewildfire.acesbs.AcesBS; +import com.acethewildfire.acesbs.entity.custom.FrenEntity; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.entity.EntityRendererFactory; +import net.minecraft.client.render.entity.MobEntityRenderer; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.Identifier; + +public class FrenRenderer extends MobEntityRenderer> { + public FrenRenderer(EntityRendererFactory.Context context) { + super(context, new FrenModel<>(context.getPart(FrenModel.FREN)), 0.75f); + } + + @Override + public Identifier getTexture(FrenEntity entity) { + return Identifier.of(AcesBS.MOD_ID, "textures/entity/fren/fren.png"); + } + + @Override + public void render(FrenEntity livingEntity, float f, float g, MatrixStack matrixStack, + VertexConsumerProvider vertexConsumerProvider, int i) { + if(livingEntity.isBaby()) { + matrixStack.scale(0.5f, 0.5f, 0.5f); + } else { + matrixStack.scale(1f, 1f, 1f); + } + + super.render(livingEntity, f, g, matrixStack, vertexConsumerProvider, i); + } +} \ No newline at end of file diff --git a/src/main/java/com/acethewildfire/acesbs/entity/custom/FrenEntity.java b/src/main/java/com/acethewildfire/acesbs/entity/custom/FrenEntity.java new file mode 100644 index 0000000..8181269 --- /dev/null +++ b/src/main/java/com/acethewildfire/acesbs/entity/custom/FrenEntity.java @@ -0,0 +1,79 @@ +package com.acethewildfire.acesbs.entity.custom; + +import com.acethewildfire.acesbs.entity.ModEntities; +import com.acethewildfire.acesbs.item.ModItems; +import net.minecraft.entity.AnimationState; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.ai.goal.*; +import net.minecraft.entity.attribute.DefaultAttributeContainer; +import net.minecraft.entity.attribute.EntityAttributes; +import net.minecraft.entity.mob.MobEntity; +import net.minecraft.entity.passive.AnimalEntity; +import net.minecraft.entity.passive.PassiveEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.recipe.Ingredient; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; + +public class FrenEntity extends AnimalEntity { + public final AnimationState idleAnimationState = new AnimationState(); + private int idleAnimationTimeout = 0; + + public FrenEntity(EntityType entityType, World world) { + super(entityType, world); + } + + @Override + protected void initGoals() { + this.goalSelector.add(0, new SwimGoal(this)); + + this.goalSelector.add(1, new AnimalMateGoal(this, 1.15D)); + this.goalSelector.add(2, new TemptGoal(this, 1.15D, Ingredient.ofItems(ModItems.LEMON), false)); + +// this.goalSelector.add(3, new MeleeAttackGoal(this, 1.0, false)); + + this.goalSelector.add(4, new WanderAroundFarGoal(this, 1.0D)); + this.goalSelector.add(5, new LookAtEntityGoal(this, PlayerEntity.class, 4.0F)); + this.goalSelector.add(6, new LookAroundGoal(this)); + + this.targetSelector.add(1, new ActiveTargetGoal<>(this, PlayerEntity.class, true)); + } + + public static DefaultAttributeContainer.Builder createAttributes() { + return MobEntity.createMobAttributes() + .add(EntityAttributes.GENERIC_MAX_HEALTH, 18) + .add(EntityAttributes.GENERIC_MOVEMENT_SPEED, 0.25) + .add(EntityAttributes.GENERIC_ATTACK_DAMAGE, 0) // No damage + .add(EntityAttributes.GENERIC_FOLLOW_RANGE, 20); + } + + private void setupAnimationStates() { + if (this.idleAnimationTimeout <= 0) { + this.idleAnimationTimeout = 20; + this.idleAnimationState.start(this.age); + } else { + --this.idleAnimationTimeout; + } + } + + @Override + public void tick() { + super.tick(); + + if (this.getWorld().isClient()) { + this.setupAnimationStates(); + } + } + + @Override + public @Nullable PassiveEntity createChild(ServerWorld world, PassiveEntity entity) { + return ModEntities.FREN.create(world); + } + + @Override + public boolean isBreedingItem(ItemStack stack) { + return stack.isOf(ModItems.LEMON); + } +} diff --git a/src/main/java/com/acethewildfire/acesbs/item/ModItemGroups.java b/src/main/java/com/acethewildfire/acesbs/item/ModItemGroups.java index b9d9f5f..a8a7fa1 100644 --- a/src/main/java/com/acethewildfire/acesbs/item/ModItemGroups.java +++ b/src/main/java/com/acethewildfire/acesbs/item/ModItemGroups.java @@ -29,6 +29,7 @@ public class ModItemGroups { entries.add(ModItems.CRAB_RAVE_MUSIC_DISC); entries.add(ModItems.TOBACCO_SEEDS); entries.add(ModItems.TOBACCO); + entries.add(ModItems.FREN_SPAWN_EGG); }) .build()); diff --git a/src/main/java/com/acethewildfire/acesbs/item/ModItems.java b/src/main/java/com/acethewildfire/acesbs/item/ModItems.java index d60b5ec..0603227 100644 --- a/src/main/java/com/acethewildfire/acesbs/item/ModItems.java +++ b/src/main/java/com/acethewildfire/acesbs/item/ModItems.java @@ -2,6 +2,7 @@ package com.acethewildfire.acesbs.item; import com.acethewildfire.acesbs.AcesBS; import com.acethewildfire.acesbs.block.ModBlocks; +import com.acethewildfire.acesbs.entity.ModEntities; import com.acethewildfire.acesbs.item.custom.HammerItem; import com.acethewildfire.acesbs.item.custom.ModArmorItem; import com.acethewildfire.acesbs.item.custom.OracleLemon; @@ -151,6 +152,9 @@ public class ModItems { public static final Item TOBACCO = registerItem("tobacco", new Item(new Item.Settings())); + public static final Item FREN_SPAWN_EGG = registerItem("fren_spawn_egg", + new SpawnEggItem(ModEntities.FREN, 894731, 0, new Item.Settings())); + private static Item registerItem(String name, Item item){ return Registry.register(Registries.ITEM, Identifier.of(AcesBS.MOD_ID, name), item); } diff --git a/src/main/java/com/acethewildfire/acesbs/mixin/CreeperInteractMixin.java b/src/main/java/com/acethewildfire/acesbs/mixin/CreeperInteractMixin.java new file mode 100644 index 0000000..f560c60 --- /dev/null +++ b/src/main/java/com/acethewildfire/acesbs/mixin/CreeperInteractMixin.java @@ -0,0 +1,52 @@ +package com.acethewildfire.acesbs.mixin; +import com.acethewildfire.acesbs.item.ModItems; +import com.acethewildfire.acesbs.util.CreeperTransformAccess; +import net.minecraft.entity.mob.CreeperEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.sound.SoundEvents; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(CreeperEntity.class) +public abstract class CreeperInteractMixin { + + @Inject(method = "interactMob", at = @At("HEAD"), cancellable = true) + private void onRightClick(PlayerEntity player, Hand hand, CallbackInfoReturnable cir) { + ItemStack itemStack = player.getStackInHand(hand); + + // === Here is the item check === + if (itemStack.isOf(ModItems.STABLE_ENTROPY)) { + CreeperEntity creeper = (CreeperEntity) (Object) this; + World world = creeper.getWorld(); + + if (!world.isClient) { + + CreeperTransformAccess access = (CreeperTransformAccess) creeper; + + access.aces_bravo_sierra_template_1_21$setTransforming(true); + access.aces_bravo_sierra_template_1_21$setTransformTimer(0); + + creeper.setAiDisabled(true); + creeper.setInvulnerable(true); + + world.playSound(null, creeper.getBlockPos(), SoundEvents.ENTITY_EVOKER_CAST_SPELL, + creeper.getSoundCategory(), 1.0f, 1.0f); + + + // Consume item unless in creative mode + if (!player.isCreative()) { + itemStack.decrement(1); + } + } + + // Stop vanilla behavior and return success + cir.setReturnValue(ActionResult.SUCCESS); + } + } +} diff --git a/src/main/java/com/acethewildfire/acesbs/mixin/CreeperTickMixin.java b/src/main/java/com/acethewildfire/acesbs/mixin/CreeperTickMixin.java new file mode 100644 index 0000000..44fe541 --- /dev/null +++ b/src/main/java/com/acethewildfire/acesbs/mixin/CreeperTickMixin.java @@ -0,0 +1,76 @@ +package com.acethewildfire.acesbs.mixin; + +import com.acethewildfire.acesbs.entity.ModEntities; +import com.acethewildfire.acesbs.util.CreeperTransformAccess; +import net.minecraft.entity.mob.CreeperEntity; +import net.minecraft.entity.mob.MobEntity; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.sound.SoundEvents; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(CreeperEntity.class) +public class CreeperTickMixin { + + @Inject(method = "tick", at = @At("HEAD")) + private void tick(CallbackInfo ci) { + CreeperEntity creeper = (CreeperEntity)(Object) this; + CreeperTransformAccess access = (CreeperTransformAccess) creeper; + + if (!access.aces_bravo_sierra_template_1_21$isTransforming()) return; + + World world = creeper.getWorld(); + + ((ServerWorld) world).spawnParticles( + ParticleTypes.ENCHANT, + creeper.getX(), + creeper.getY() + 1.0, + creeper.getZ(), + 5, // count + 0.2, // dx + 0.2, // dy + 0.2, // dz + 0.0 // speed + ); + + // timer + int t = access.aces_bravo_sierra_template_1_21$getTransformTimer() + 1; + access.aces_bravo_sierra_template_1_21$setTransformTimer(t); + + if (t >= 20 && !world.isClient) { + + world.playSound(null, creeper.getBlockPos(), + SoundEvents.ENTITY_ZOMBIE_VILLAGER_CURE, + creeper.getSoundCategory(), 1f, 1f); + + ((ServerWorld) world).spawnParticles( + ParticleTypes.EXPLOSION, + creeper.getX(), + creeper.getY() + 1.0, + creeper.getZ(), + 5, // count + 0.2, // dx + 0.2, // dy + 0.2, // dz + 0.0 // speed + ); + + // spawn new mob + MobEntity newMob = ModEntities.FREN.create(world); + if (newMob != null) { + Vec3d pos = creeper.getPos(); + newMob.refreshPositionAndAngles(pos.x, pos.y, pos.z, creeper.getYaw(), creeper.getPitch()); + world.spawnEntity(newMob); + newMob.refreshPositionAndAngles(pos.x, pos.y, pos.z, creeper.getYaw(), creeper.getPitch()); + } + + creeper.discard(); + } + } +} diff --git a/src/main/java/com/acethewildfire/acesbs/mixin/CreeperTransformStateMixin.java b/src/main/java/com/acethewildfire/acesbs/mixin/CreeperTransformStateMixin.java new file mode 100644 index 0000000..3af987c --- /dev/null +++ b/src/main/java/com/acethewildfire/acesbs/mixin/CreeperTransformStateMixin.java @@ -0,0 +1,32 @@ +package com.acethewildfire.acesbs.mixin; + +import com.acethewildfire.acesbs.util.CreeperTransformAccess; +import net.minecraft.entity.mob.CreeperEntity; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(CreeperEntity.class) +public class CreeperTransformStateMixin implements CreeperTransformAccess { + + private boolean isTransforming = false; + private int transformTimer = 0; + + @Override + public boolean aces_bravo_sierra_template_1_21$isTransforming() { + return isTransforming; + } + + @Override + public void aces_bravo_sierra_template_1_21$setTransforming(boolean value) { + this.isTransforming = value; + } + + @Override + public int aces_bravo_sierra_template_1_21$getTransformTimer() { + return transformTimer; + } + + @Override + public void aces_bravo_sierra_template_1_21$setTransformTimer(int value) { + this.transformTimer = value; + } +} diff --git a/src/main/java/com/acethewildfire/acesbs/util/CreeperTransformAccess.java b/src/main/java/com/acethewildfire/acesbs/util/CreeperTransformAccess.java new file mode 100644 index 0000000..bc36056 --- /dev/null +++ b/src/main/java/com/acethewildfire/acesbs/util/CreeperTransformAccess.java @@ -0,0 +1,9 @@ +package com.acethewildfire.acesbs.util; + +public interface CreeperTransformAccess { + boolean aces_bravo_sierra_template_1_21$isTransforming(); + void aces_bravo_sierra_template_1_21$setTransforming(boolean value); + + int aces_bravo_sierra_template_1_21$getTransformTimer(); + void aces_bravo_sierra_template_1_21$setTransformTimer(int value); +} diff --git a/src/main/resources/acesbs.mixins.json b/src/main/resources/acesbs.mixins.json index 3bfd8de..9811231 100644 --- a/src/main/resources/acesbs.mixins.json +++ b/src/main/resources/acesbs.mixins.json @@ -3,7 +3,10 @@ "package": "com.acethewildfire.acesbs.mixin", "compatibilityLevel": "JAVA_21", "mixins": [ - "ExampleMixin" + "CreeperInteractMixin", + "CreeperTickMixin", + "CreeperTransformStateMixin", + "ExampleMixin" ], "injectors": { "defaultRequire": 1 diff --git a/src/main/resources/assets/acesbs/lang/en_us.json b/src/main/resources/assets/acesbs/lang/en_us.json index afd9cd7..56d3cb1 100644 --- a/src/main/resources/assets/acesbs/lang/en_us.json +++ b/src/main/resources/assets/acesbs/lang/en_us.json @@ -43,6 +43,8 @@ "item.acesbs.tobacco_seeds": "Tobacco Seeds", "item.acesbs.tobacco": "Tobacco", + "item.acesbs.fren_spawn_egg": "Fren Spawn Egg", + "painting.acesbs.herald.title": "Herald's Banner", "painting.acesbs.herald.author": "AceTheWildfire", @@ -142,5 +144,7 @@ "sounds.acesbs.lizard": "Lizard!", "sounds.acesbs.crab_rave": "Jukebox plays Crab Rave", - "enchantment.acesbs.lightning_strike": "Lightning Strike" + "enchantment.acesbs.lightning_strike": "Lightning Strike", + + "entity.acesbs.fren": "Fren" } \ No newline at end of file diff --git a/src/main/resources/assets/acesbs/textures/entity/fren/fren.png b/src/main/resources/assets/acesbs/textures/entity/fren/fren.png new file mode 100644 index 0000000..26e3a9c Binary files /dev/null and b/src/main/resources/assets/acesbs/textures/entity/fren/fren.png differ