From a439924489bd5b24de9e66e78f93f05c1caa47c0 Mon Sep 17 00:00:00 2001 From: Vos Date: Sun, 16 Nov 2025 20:21:52 -0600 Subject: [PATCH] Fren --- .../acesbs/models/item/fren_spawn_egg.json | 3 + .../com/acethewildfire/acesbs/AcesBS.java | 6 ++ .../acethewildfire/acesbs/AcesBSClient.java | 8 ++ .../java/com/acethewildfire/acesbs/TODO.txt | 2 +- .../acesbs/datagen/ModModelProvider.java | 5 ++ .../acesbs/datagen/ModRecipeProvider.java | 40 ++++++++- .../acesbs/entity/ModEntities.java | 22 +++++ .../acesbs/entity/client/FrenAnimations.java | 80 ++++++++++++++++++ .../acesbs/entity/client/FrenModel.java | 78 +++++++++++++++++ .../acesbs/entity/client/FrenRenderer.java | 32 +++++++ .../acesbs/entity/custom/FrenEntity.java | 79 +++++++++++++++++ .../acesbs/item/ModItemGroups.java | 1 + .../acethewildfire/acesbs/item/ModItems.java | 4 + .../acesbs/mixin/CreeperInteractMixin.java | 52 ++++++++++++ .../acesbs/mixin/CreeperTickMixin.java | 76 +++++++++++++++++ .../mixin/CreeperTransformStateMixin.java | 32 +++++++ .../acesbs/util/CreeperTransformAccess.java | 9 ++ src/main/resources/acesbs.mixins.json | 5 +- .../resources/assets/acesbs/lang/en_us.json | 6 +- .../acesbs/textures/entity/fren/fren.png | Bin 0 -> 3176 bytes 20 files changed, 535 insertions(+), 5 deletions(-) create mode 100644 src/main/generated/assets/acesbs/models/item/fren_spawn_egg.json create mode 100644 src/main/java/com/acethewildfire/acesbs/entity/ModEntities.java create mode 100644 src/main/java/com/acethewildfire/acesbs/entity/client/FrenAnimations.java create mode 100644 src/main/java/com/acethewildfire/acesbs/entity/client/FrenModel.java create mode 100644 src/main/java/com/acethewildfire/acesbs/entity/client/FrenRenderer.java create mode 100644 src/main/java/com/acethewildfire/acesbs/entity/custom/FrenEntity.java create mode 100644 src/main/java/com/acethewildfire/acesbs/mixin/CreeperInteractMixin.java create mode 100644 src/main/java/com/acethewildfire/acesbs/mixin/CreeperTickMixin.java create mode 100644 src/main/java/com/acethewildfire/acesbs/mixin/CreeperTransformStateMixin.java create mode 100644 src/main/java/com/acethewildfire/acesbs/util/CreeperTransformAccess.java create mode 100644 src/main/resources/assets/acesbs/textures/entity/fren/fren.png 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 0000000000000000000000000000000000000000..26e3a9cd8ff5c046797343802d4461fef76ad238 GIT binary patch literal 3176 zcmV-u443nXP)3Y3+2-#4*Zfw2>qjFaj!Z1r;=avI-PSQPjTIyr~a!&YYYxeDI+D-w*e#Tet45 z``qU~&;S3(7zcUfnZ6~d%XnDGU{r1((iO>{YW~dYt2R@v+mF>{<7dGeIUxOrAbSvl zXI-o-UQ4(l0;j>vl8j;r4={xB1~@vQy1I^Q-m82k`G#}qDx@Ac8o9XH%TDy81|(V! z8do3+qly=be?eKr0rdJ&^y)z#bc}0&kU26m3!v$IGa=3}9PK`KulkVV#?MGx6382A zThYoxunjoKPF%=G5$HN~-OP^H^Bp*zHbj&TieKvzzU`Go(y zrvDTn(op~V^F_~M3>ZN<$4+E&DDQm#9`N>2#WVnHrSFj zt;ViXuxr_W(C_JIcHnH{6tR3>{smnv!VtmA?Be2+QEDc!A{jYJ4<$=NR)9`Q!#HCH93lX8mp+@BPy| zNIU{{SHERv)lT|^J6LasWN5OLDcVUGZkh2VNT`=r;Tx2YAWLSFD~(I024Z94`Ma1R z6m~UJqGAaXLWv4jP@R9_zHR;o2$B#Vx9y$WJlpH56 z^^?R$Me^o??OZinU`%J^%9R^jJ#lp#_Ytz>N217PF*75wnUgmIx0t#sdyg`MO#Xc4 zV_KFp5}zB-FUy`IJ#!NA-c*haAEfTSZPGPAtsC(LrqpJaKG`R9K80URlbs(LL7pNLDw*4ukB~1 zCJVFIgjF!p@WsXdH*XhxSm1lV^aHv^Z;M)B8h`5j9YqN%8IzlcutuTt-r?}Mqio81 zo)d~gSbH2S3M=G>^b&((LzLwlzo)$5M^x?o;(zDhS4SDJ^%LsWU>kGM%yrZc3-r3X z#+`7{qAWHZ{yAL%t@JB97;W+L$CG;)Fm`iT_Ay6%2XQ)`bh$b?f4r5;!_9os|0#ij zmLZ#gdyO9%VB4qLm|K{}OFbCzC7>#> z5mq3h?%X9LKb);z!apo~lJi0>o`)@5aoxZvIBC_j^Y*lNxYziR0bX6diDA_ULAFrr zayv@7l7S{Y`VO)3gKyjki;DA5NCU8$op?eVs68seN23{Yj525$B*>>BNE(dEWTnTb zV|naSR>eHZ)R1Z1a(>UfhOF*Jjjzo12dp9&nJ4D`%({6b1;#VKC5ORg_R-oSsm%jmR-X;_f4=f)p=zc1U3z17L9J740(>90>{ zOc1IaU!(I4G0-uD*Y5In4%zew5dxv|PzD>Vqy(q(a8MSzul$9%i3MCb-Nb^JMYtRe znvOLwTs=z9AsrVgn%TeeFe;x)WS45OZm7l8CZ+$(FqtAvuBiToqSWOaJ^dyB81)u` zB9(Ru4v|OraEcYAp{g-H*#04c!$(@-baaj(CK{5`UB$lWY&EOGpWw~ve?cOX@NVu7 z4txGekTr-Wqkq92&mH!k{*1=ZM)IR`X|BJHOs?>!5TDzNc4hztV*k;qDr`+IO0rha zz4#h>kBP5upJn05T#VN(Y<=U`jF^Y1I8%jEq9(wn#AGuPk|`xd6iQ!R`-Hm{u*i=V?8AnJ%b8*L38-0^iW^|feZi)<8~T}@rzB|>eXOf+QC@lg!78IZ;* z&{(yU{idAWiXjq8BmM0YtJs!6YWuOvkp9@cdj0DMK z=#ikxil#|-9?vNsC$g*j3*{zc5j`!Ds-xdx5Oi$*&zCTFJJ9rsVrvYhKb_1Kg8|cs z)jxh(F^&m_gqF1!BNUDvo32hE=FWRj6HRlwvl>cr*=jh>h5y2x1DOdHUDu zh@2COGDd?}l-?taqAn73$kT@POdCk%mrreEqH)*vYr*chzM{p2{tcuABr_n^1uBk; zl_jm4()@fH9A_D;aj-y|w;&*oy2^TL z&YdP{St5@wUCY`jPfTbGxa-Mh{WjH?DV-wlshme)p$#^Z1^^ZM8Xkj4pmpwvwWE_$Cp}5sv zY=VukZX@@irhM1#6}(UD8