From 256313e32f17ef0c4f8358151f99137377e3b6ed Mon Sep 17 00:00:00 2001 From: ian1337 Date: Thu, 24 Sep 2026 20:13:36 +0200 Subject: [PATCH] [add] Shark --- gradle.properties | 2 +- .../6143fb1502ae754d8039ff811e28c49eaa7e6409 | 4 +- .../d1416cf72769a6a520cc2c44944968403e1a0de7 | 3 +- .../assets/masterwild/lang/en_us.json | 2 + .../models/item/shark_spawn_egg.json | 3 + .../ovh/glitchlabs/masterwild/Config.java | 50 ------ .../glitchlabs/masterwild/Item/ModItems.java | 3 + .../ovh/glitchlabs/masterwild/Masterwild.java | 4 +- .../datagen/ModItemModelProvider.java | 1 + .../datagen/ModLanguageProvider.java | 2 + .../masterwild/entity/ModEntities.java | 5 + .../entity/client/Shark/SharkAnimation.java | 165 ++++++++++++++++++ .../entity/client/Shark/SharkModel.java | 103 +++++++++++ .../entity/client/Shark/SharkRenderer.java | 21 +++ .../masterwild/entity/custom/SharkEntity.java | 110 ++++++++++++ .../masterwild/event/ModEventBusEvents.java | 4 + .../masterwild/textures/entity/shark.png | Bin 0 -> 7357 bytes 17 files changed, 426 insertions(+), 56 deletions(-) create mode 100644 src/generated/resources/assets/masterwild/models/item/shark_spawn_egg.json delete mode 100644 src/main/java/ovh/glitchlabs/masterwild/Config.java create mode 100755 src/main/java/ovh/glitchlabs/masterwild/entity/client/Shark/SharkAnimation.java create mode 100755 src/main/java/ovh/glitchlabs/masterwild/entity/client/Shark/SharkModel.java create mode 100644 src/main/java/ovh/glitchlabs/masterwild/entity/client/Shark/SharkRenderer.java create mode 100644 src/main/java/ovh/glitchlabs/masterwild/entity/custom/SharkEntity.java create mode 100755 src/main/resources/assets/masterwild/textures/entity/shark.png diff --git a/gradle.properties b/gradle.properties index 9468e4e..bd849be 100644 --- a/gradle.properties +++ b/gradle.properties @@ -29,7 +29,7 @@ mod_name=MasterWIld # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=All Rights Reserved # The mod version. See https://semver.org/ -mod_version=0.0.2 +mod_version=0.0.3 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/generated/resources/.cache/6143fb1502ae754d8039ff811e28c49eaa7e6409 b/src/generated/resources/.cache/6143fb1502ae754d8039ff811e28c49eaa7e6409 index 02dd52c..746dd74 100644 --- a/src/generated/resources/.cache/6143fb1502ae754d8039ff811e28c49eaa7e6409 +++ b/src/generated/resources/.cache/6143fb1502ae754d8039ff811e28c49eaa7e6409 @@ -1,2 +1,2 @@ -// 1.21.1 2026-09-24T18:18:13.079823188 Languages: en_us for mod: masterwild -57c760308c9f5032b784687dcf1070b4c3f3cc6d assets/masterwild/lang/en_us.json +// 1.21.1 2026-09-24T20:03:22.379929654 Languages: en_us for mod: masterwild +983f6e76a68757a3db42ee7909f23c5af0aa3833 assets/masterwild/lang/en_us.json diff --git a/src/generated/resources/.cache/d1416cf72769a6a520cc2c44944968403e1a0de7 b/src/generated/resources/.cache/d1416cf72769a6a520cc2c44944968403e1a0de7 index 1e91910..177f11a 100644 --- a/src/generated/resources/.cache/d1416cf72769a6a520cc2c44944968403e1a0de7 +++ b/src/generated/resources/.cache/d1416cf72769a6a520cc2c44944968403e1a0de7 @@ -1,4 +1,5 @@ -// 1.21.1 2026-09-24T17:08:07.016016258 Item Models: masterwild +// 1.21.1 2026-09-24T20:03:49.185849858 Item Models: masterwild 63ec6c618a3a23eab4cab9c52d7d3250de9b516e assets/masterwild/models/item/firefly_spawn_egg.json 63ec6c618a3a23eab4cab9c52d7d3250de9b516e assets/masterwild/models/item/pinguin_spawn_egg.json 63ec6c618a3a23eab4cab9c52d7d3250de9b516e assets/masterwild/models/item/rooster_spawn_egg.json +63ec6c618a3a23eab4cab9c52d7d3250de9b516e assets/masterwild/models/item/shark_spawn_egg.json diff --git a/src/generated/resources/assets/masterwild/lang/en_us.json b/src/generated/resources/assets/masterwild/lang/en_us.json index 89b4659..7930404 100644 --- a/src/generated/resources/assets/masterwild/lang/en_us.json +++ b/src/generated/resources/assets/masterwild/lang/en_us.json @@ -2,8 +2,10 @@ "entity.masterwild.firefly": "Firefly", "entity.masterwild.pinguin": "Pinguin", "entity.masterwild.rooster": "Rooster", + "entity.masterwild.shark": "Shark", "item.masterwild.firefly_spawn_egg": "Firefly Spawn Egg", "item.masterwild.pinguin_spawn_egg": "Pinguin Spawn Egg", "item.masterwild.rooster_spawn_egg": "Rooster Spawn Egg", + "item.masterwild.shark_spawn_egg": "Shark Spawn Egg", "subtitles.masterwild.rooster_crow": "Rooster crows" } \ No newline at end of file diff --git a/src/generated/resources/assets/masterwild/models/item/shark_spawn_egg.json b/src/generated/resources/assets/masterwild/models/item/shark_spawn_egg.json new file mode 100644 index 0000000..d1aaa9d --- /dev/null +++ b/src/generated/resources/assets/masterwild/models/item/shark_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/ovh/glitchlabs/masterwild/Config.java b/src/main/java/ovh/glitchlabs/masterwild/Config.java deleted file mode 100644 index 6ff740c..0000000 --- a/src/main/java/ovh/glitchlabs/masterwild/Config.java +++ /dev/null @@ -1,50 +0,0 @@ -package ovh.glitchlabs.masterwild; - -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.Item; -import net.neoforged.bus.api.SubscribeEvent; -import net.neoforged.fml.common.EventBusSubscriber; -import net.neoforged.fml.event.config.ModConfigEvent; -import net.neoforged.neoforge.common.ModConfigSpec; - -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -// An example config class. This is not required, but it's a good idea to have one to keep your config organized. -// Demonstrates how to use Neo's config APIs -@EventBusSubscriber(modid = Masterwild.MODID, bus = EventBusSubscriber.Bus.MOD) -public class Config { - private static final ModConfigSpec.Builder BUILDER = new ModConfigSpec.Builder(); - - private static final ModConfigSpec.BooleanValue LOG_DIRT_BLOCK = BUILDER.comment("Whether to log the dirt block on common setup").define("logDirtBlock", true); - - private static final ModConfigSpec.IntValue MAGIC_NUMBER = BUILDER.comment("A magic number").defineInRange("magicNumber", 42, 0, Integer.MAX_VALUE); - - public static final ModConfigSpec.ConfigValue MAGIC_NUMBER_INTRODUCTION = BUILDER.comment("What you want the introduction message to be for the magic number").define("magicNumberIntroduction", "The magic number is... "); - - // a list of strings that are treated as resource locations for items - private static final ModConfigSpec.ConfigValue> ITEM_STRINGS = BUILDER.comment("A list of items to log on common setup.").defineListAllowEmpty("items", List.of("minecraft:iron_ingot"), Config::validateItemName); - - static final ModConfigSpec SPEC = BUILDER.build(); - - public static boolean logDirtBlock; - public static int magicNumber; - public static String magicNumberIntroduction; - public static Set items; - - private static boolean validateItemName(final Object obj) { - return obj instanceof String itemName && BuiltInRegistries.ITEM.containsKey(ResourceLocation.parse(itemName)); - } - - @SubscribeEvent - static void onLoad(final ModConfigEvent event) { - logDirtBlock = LOG_DIRT_BLOCK.get(); - magicNumber = MAGIC_NUMBER.get(); - magicNumberIntroduction = MAGIC_NUMBER_INTRODUCTION.get(); - - // convert the list of strings into a set of items - items = ITEM_STRINGS.get().stream().map(itemName -> BuiltInRegistries.ITEM.get(ResourceLocation.parse(itemName))).collect(Collectors.toSet()); - } -} diff --git a/src/main/java/ovh/glitchlabs/masterwild/Item/ModItems.java b/src/main/java/ovh/glitchlabs/masterwild/Item/ModItems.java index 0ee3f22..c8b5daa 100644 --- a/src/main/java/ovh/glitchlabs/masterwild/Item/ModItems.java +++ b/src/main/java/ovh/glitchlabs/masterwild/Item/ModItems.java @@ -23,6 +23,9 @@ public class ModItems { public static final DeferredItem ROOSTER_SPAWN_EGG = ITEMS.register("rooster_spawn_egg", () -> new DeferredSpawnEggItem(ModEntities.ROOSTER, 0xc4551c, 0x4f5026, new Item.Properties())); + public static final DeferredItem SHARK_SPAWN_EGG = ITEMS.register("shark_spawn_egg", + () -> new DeferredSpawnEggItem(ModEntities.SHARK, 0x1d598b, 0x8daec4, + new Item.Properties())); public static void register(IEventBus eventBus) { ITEMS.register(eventBus); diff --git a/src/main/java/ovh/glitchlabs/masterwild/Masterwild.java b/src/main/java/ovh/glitchlabs/masterwild/Masterwild.java index 4c0c015..3ca06b7 100644 --- a/src/main/java/ovh/glitchlabs/masterwild/Masterwild.java +++ b/src/main/java/ovh/glitchlabs/masterwild/Masterwild.java @@ -20,6 +20,7 @@ import ovh.glitchlabs.masterwild.Sounds.ModSounds; 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.firefly.FireflyRenderer; // The value here should match an entry in the META-INF/neoforge.mods.toml file @@ -46,8 +47,6 @@ public class Masterwild { // Do not add this line if there are no @SubscribeEvent-annotated functions in this class, like onServerStarting() below. NeoForge.EVENT_BUS.register(this); - // Register our mod's ModConfigSpec so that FML can create and load the config file for us - modContainer.registerConfig(ModConfig.Type.COMMON, Config.SPEC); } private void commonSetup(final FMLCommonSetupEvent event) { @@ -71,6 +70,7 @@ public class Masterwild { EntityRenderers.register(ModEntities.PINGUIN.get(), PinguinRenderer::new); EntityRenderers.register(ModEntities.FIREFLY.get(), FireflyRenderer::new); EntityRenderers.register(ModEntities.ROOSTER.get(), RoosterRenderer::new); + EntityRenderers.register(ModEntities.SHARK.get(), SharkRenderer::new); } } } diff --git a/src/main/java/ovh/glitchlabs/masterwild/datagen/ModItemModelProvider.java b/src/main/java/ovh/glitchlabs/masterwild/datagen/ModItemModelProvider.java index 3bcd605..de25116 100644 --- a/src/main/java/ovh/glitchlabs/masterwild/datagen/ModItemModelProvider.java +++ b/src/main/java/ovh/glitchlabs/masterwild/datagen/ModItemModelProvider.java @@ -17,5 +17,6 @@ public class ModItemModelProvider extends ItemModelProvider { withExistingParent(ModItems.PINGUIN_SPAWN_EGG.getId().getPath(), mcLoc("item/template_spawn_egg")); withExistingParent(ModItems.FIREFLY_SPAWN_EGG.getId().getPath(), mcLoc("item/template_spawn_egg")); withExistingParent(ModItems.ROOSTER_SPAWN_EGG.getId().getPath(), mcLoc("item/template_spawn_egg")); + withExistingParent(ModItems.SHARK_SPAWN_EGG.getId().getPath(), mcLoc("item/template_spawn_egg")); } } \ No newline at end of file diff --git a/src/main/java/ovh/glitchlabs/masterwild/datagen/ModLanguageProvider.java b/src/main/java/ovh/glitchlabs/masterwild/datagen/ModLanguageProvider.java index fcc579e..34fcd55 100644 --- a/src/main/java/ovh/glitchlabs/masterwild/datagen/ModLanguageProvider.java +++ b/src/main/java/ovh/glitchlabs/masterwild/datagen/ModLanguageProvider.java @@ -17,10 +17,12 @@ public class ModLanguageProvider extends LanguageProvider { add(ModEntities.PINGUIN.get(), "Pinguin"); add(ModEntities.FIREFLY.get(), "Firefly"); add(ModEntities.ROOSTER.get(), "Rooster"); + add(ModEntities.SHARK.get(), "Shark"); add(ModItems.PINGUIN_SPAWN_EGG.get(), "Pinguin Spawn Egg"); add(ModItems.FIREFLY_SPAWN_EGG.get(), "Firefly Spawn Egg"); add(ModItems.ROOSTER_SPAWN_EGG.get(), "Rooster Spawn Egg"); + add(ModItems.SHARK_SPAWN_EGG.get(), "Shark Spawn Egg"); add("subtitles.masterwild.rooster_crow", "Rooster crows"); } diff --git a/src/main/java/ovh/glitchlabs/masterwild/entity/ModEntities.java b/src/main/java/ovh/glitchlabs/masterwild/entity/ModEntities.java index cf1eae4..2cdcc74 100644 --- a/src/main/java/ovh/glitchlabs/masterwild/entity/ModEntities.java +++ b/src/main/java/ovh/glitchlabs/masterwild/entity/ModEntities.java @@ -9,6 +9,7 @@ import ovh.glitchlabs.masterwild.Masterwild; import ovh.glitchlabs.masterwild.entity.custom.FireflyEntity; import ovh.glitchlabs.masterwild.entity.custom.PinguinEntity; import ovh.glitchlabs.masterwild.entity.custom.RoosterEntity; +import ovh.glitchlabs.masterwild.entity.custom.SharkEntity; import java.util.function.Supplier; @@ -28,6 +29,10 @@ public class ModEntities { ENTITY_TYPES.register("rooster", () -> EntityType.Builder.of(RoosterEntity::new, MobCategory.CREATURE) .sized(0.5f, 0.75f).build("rooster")); + public static final Supplier> SHARK = + ENTITY_TYPES.register("shark", () -> EntityType.Builder.of(SharkEntity::new, MobCategory.WATER_CREATURE) + .sized(1.6f, 0.8f).build("shark")); + public static void register(IEventBus eventBus) { ENTITY_TYPES.register(eventBus); diff --git a/src/main/java/ovh/glitchlabs/masterwild/entity/client/Shark/SharkAnimation.java b/src/main/java/ovh/glitchlabs/masterwild/entity/client/Shark/SharkAnimation.java new file mode 100755 index 0000000..4f57307 --- /dev/null +++ b/src/main/java/ovh/glitchlabs/masterwild/entity/client/Shark/SharkAnimation.java @@ -0,0 +1,165 @@ +package ovh.glitchlabs.masterwild.entity.client.Shark;// 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 SharkAnimation { + public static final AnimationDefinition shark_swim = AnimationDefinition.Builder.withLength(0.5F).looping() + .addAnimation("head", new AnimationChannel(AnimationChannel.Targets.ROTATION, + new Keyframe(0.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM), + new Keyframe(0.5F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("head", new AnimationChannel(AnimationChannel.Targets.POSITION, + new Keyframe(0.0F, KeyframeAnimations.posVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM), + new Keyframe(0.5F, KeyframeAnimations.posVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("head", new AnimationChannel(AnimationChannel.Targets.SCALE, + new Keyframe(0.0F, KeyframeAnimations.scaleVec(1.0F, 1.0F, 1.0F), AnimationChannel.Interpolations.CATMULLROM), + new Keyframe(0.5F, KeyframeAnimations.scaleVec(1.0F, 1.0F, 1.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("flos_L", new AnimationChannel(AnimationChannel.Targets.ROTATION, + new Keyframe(0.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("flos_L", new AnimationChannel(AnimationChannel.Targets.POSITION, + new Keyframe(0.0F, KeyframeAnimations.posVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("flos_L", new AnimationChannel(AnimationChannel.Targets.SCALE, + new Keyframe(0.0F, KeyframeAnimations.scaleVec(1.0F, 1.0F, 1.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("flos_R", new AnimationChannel(AnimationChannel.Targets.ROTATION, + new Keyframe(0.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("flos_R", new AnimationChannel(AnimationChannel.Targets.POSITION, + new Keyframe(0.0F, KeyframeAnimations.posVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("flos_R", new AnimationChannel(AnimationChannel.Targets.SCALE, + new Keyframe(0.0F, KeyframeAnimations.scaleVec(1.0F, 1.0F, 1.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("body1", new AnimationChannel(AnimationChannel.Targets.ROTATION, + new Keyframe(0.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM), + new Keyframe(0.1667F, KeyframeAnimations.degreeVec(0.0F, -5.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM), + new Keyframe(0.3333F, KeyframeAnimations.degreeVec(0.0F, 5.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM), + new Keyframe(0.5F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("body1", new AnimationChannel(AnimationChannel.Targets.POSITION, + new Keyframe(0.0F, KeyframeAnimations.posVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM), + new Keyframe(0.5F, KeyframeAnimations.posVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("body1", new AnimationChannel(AnimationChannel.Targets.SCALE, + new Keyframe(0.0F, KeyframeAnimations.scaleVec(1.0F, 1.0F, 1.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("body2", new AnimationChannel(AnimationChannel.Targets.ROTATION, + new Keyframe(0.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM), + new Keyframe(0.1667F, KeyframeAnimations.degreeVec(0.0F, 7.5F, 0.0F), AnimationChannel.Interpolations.CATMULLROM), + new Keyframe(0.3333F, KeyframeAnimations.degreeVec(0.0F, -7.5F, 0.0F), AnimationChannel.Interpolations.CATMULLROM), + new Keyframe(0.5F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("body2", new AnimationChannel(AnimationChannel.Targets.POSITION, + new Keyframe(0.0F, KeyframeAnimations.posVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("body2", new AnimationChannel(AnimationChannel.Targets.SCALE, + new Keyframe(0.0F, KeyframeAnimations.scaleVec(1.0F, 1.0F, 1.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("body3", new AnimationChannel(AnimationChannel.Targets.ROTATION, + new Keyframe(0.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM), + new Keyframe(0.1667F, KeyframeAnimations.degreeVec(0.0F, 17.5F, 0.0F), AnimationChannel.Interpolations.CATMULLROM), + new Keyframe(0.3333F, KeyframeAnimations.degreeVec(0.0F, -17.5F, 0.0F), AnimationChannel.Interpolations.CATMULLROM), + new Keyframe(0.5F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("body3", new AnimationChannel(AnimationChannel.Targets.POSITION, + new Keyframe(0.0F, KeyframeAnimations.posVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("body3", new AnimationChannel(AnimationChannel.Targets.SCALE, + new Keyframe(0.0F, KeyframeAnimations.scaleVec(1.0F, 1.0F, 1.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .build(); + + public static final AnimationDefinition shark_attack = AnimationDefinition.Builder.withLength(0.5F) + .addAnimation("head", new AnimationChannel(AnimationChannel.Targets.ROTATION, + new Keyframe(0.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.2083F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.LINEAR), + new Keyframe(0.3333F, KeyframeAnimations.degreeVec(-5.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM), + new Keyframe(0.5F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("head", new AnimationChannel(AnimationChannel.Targets.POSITION, + new Keyframe(0.0F, KeyframeAnimations.posVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("head", new AnimationChannel(AnimationChannel.Targets.SCALE, + new Keyframe(0.0F, KeyframeAnimations.scaleVec(1.0F, 1.0F, 1.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("flos_L", new AnimationChannel(AnimationChannel.Targets.ROTATION, + new Keyframe(0.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("flos_L", new AnimationChannel(AnimationChannel.Targets.POSITION, + new Keyframe(0.0F, KeyframeAnimations.posVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("flos_L", new AnimationChannel(AnimationChannel.Targets.SCALE, + new Keyframe(0.0F, KeyframeAnimations.scaleVec(1.0F, 1.0F, 1.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("flos_R", new AnimationChannel(AnimationChannel.Targets.ROTATION, + new Keyframe(0.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("flos_R", new AnimationChannel(AnimationChannel.Targets.POSITION, + new Keyframe(0.0F, KeyframeAnimations.posVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("flos_R", new AnimationChannel(AnimationChannel.Targets.SCALE, + new Keyframe(0.0F, KeyframeAnimations.scaleVec(1.0F, 1.0F, 1.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("body1", new AnimationChannel(AnimationChannel.Targets.ROTATION, + new Keyframe(0.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM), + new Keyframe(0.1667F, KeyframeAnimations.degreeVec(0.0F, 7.5F, 0.0F), AnimationChannel.Interpolations.CATMULLROM), + new Keyframe(0.25F, KeyframeAnimations.degreeVec(-10.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM), + new Keyframe(0.3333F, KeyframeAnimations.degreeVec(0.0F, -7.5F, 0.0F), AnimationChannel.Interpolations.CATMULLROM), + new Keyframe(0.5F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("body1", new AnimationChannel(AnimationChannel.Targets.POSITION, + new Keyframe(0.0F, KeyframeAnimations.posVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM), + new Keyframe(0.25F, KeyframeAnimations.posVec(0.0F, 0.0F, -3.0F), AnimationChannel.Interpolations.CATMULLROM), + new Keyframe(0.5F, KeyframeAnimations.posVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("body1", new AnimationChannel(AnimationChannel.Targets.SCALE, + new Keyframe(0.0F, KeyframeAnimations.scaleVec(1.0F, 1.0F, 1.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("body2", new AnimationChannel(AnimationChannel.Targets.ROTATION, + new Keyframe(0.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM), + new Keyframe(0.1667F, KeyframeAnimations.degreeVec(0.0F, -5.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM), + new Keyframe(0.3333F, KeyframeAnimations.degreeVec(0.0F, 5.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM), + new Keyframe(0.5F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("body2", new AnimationChannel(AnimationChannel.Targets.POSITION, + new Keyframe(0.0F, KeyframeAnimations.posVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("body2", new AnimationChannel(AnimationChannel.Targets.SCALE, + new Keyframe(0.0F, KeyframeAnimations.scaleVec(1.0F, 1.0F, 1.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("body3", new AnimationChannel(AnimationChannel.Targets.ROTATION, + new Keyframe(0.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM), + new Keyframe(0.1667F, KeyframeAnimations.degreeVec(0.0F, 17.5F, 0.0F), AnimationChannel.Interpolations.CATMULLROM), + new Keyframe(0.3333F, KeyframeAnimations.degreeVec(0.0F, -17.5F, 0.0F), AnimationChannel.Interpolations.CATMULLROM), + new Keyframe(0.5F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("body3", new AnimationChannel(AnimationChannel.Targets.POSITION, + new Keyframe(0.0F, KeyframeAnimations.posVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("body3", new AnimationChannel(AnimationChannel.Targets.SCALE, + new Keyframe(0.0F, KeyframeAnimations.scaleVec(1.0F, 1.0F, 1.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("head_down", new AnimationChannel(AnimationChannel.Targets.ROTATION, + new Keyframe(0.0F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM), + new Keyframe(0.25F, KeyframeAnimations.degreeVec(15.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM), + new Keyframe(0.5F, KeyframeAnimations.degreeVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("head_down", new AnimationChannel(AnimationChannel.Targets.POSITION, + new Keyframe(0.0F, KeyframeAnimations.posVec(0.0F, 0.0F, 0.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .addAnimation("head_down", new AnimationChannel(AnimationChannel.Targets.SCALE, + new Keyframe(0.0F, KeyframeAnimations.scaleVec(1.0F, 1.0F, 1.0F), AnimationChannel.Interpolations.CATMULLROM) + )) + .build(); +} \ No newline at end of file diff --git a/src/main/java/ovh/glitchlabs/masterwild/entity/client/Shark/SharkModel.java b/src/main/java/ovh/glitchlabs/masterwild/entity/client/Shark/SharkModel.java new file mode 100755 index 0000000..870a335 --- /dev/null +++ b/src/main/java/ovh/glitchlabs/masterwild/entity/client/Shark/SharkModel.java @@ -0,0 +1,103 @@ +package ovh.glitchlabs.masterwild.entity.client.Shark;// 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 ovh.glitchlabs.masterwild.Masterwild; +import ovh.glitchlabs.masterwild.entity.custom.SharkEntity; + +public class SharkModel extends HierarchicalModel { + // 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, "shark"), "main"); + private final ModelPart Shark; + private final ModelPart body; + private final ModelPart body1; + private final ModelPart flos_R; + private final ModelPart flos_L; + private final ModelPart head; + private final ModelPart head_down; + private final ModelPart body2; + private final ModelPart body3; + + public SharkModel(ModelPart root) { + this.Shark = root.getChild("Shark"); + this.body = this.Shark.getChild("body"); + this.body1 = this.body.getChild("body1"); + this.flos_R = this.body1.getChild("flos_R"); + this.flos_L = this.body1.getChild("flos_L"); + this.head = this.body1.getChild("head"); + this.head_down = this.head.getChild("head_down"); + this.body2 = this.body1.getChild("body2"); + this.body3 = this.body2.getChild("body3"); + } + + public static LayerDefinition createBodyLayer() { + MeshDefinition meshdefinition = new MeshDefinition(); + PartDefinition partdefinition = meshdefinition.getRoot(); + + PartDefinition Shark = partdefinition.addOrReplaceChild("Shark", CubeListBuilder.create(), PartPose.offset(0.0F, 19.0F, -9.0F)); + + PartDefinition body = Shark.addOrReplaceChild("body", CubeListBuilder.create(), PartPose.offset(0.0F, 5.0F, 9.0F)); + + PartDefinition body1 = body.addOrReplaceChild("body1", CubeListBuilder.create().texOffs(0, 0).addBox(-7.7143F, -4.18F, -9.6524F, 12.0F, 8.0F, 16.0F, new CubeDeformation(0.0F)), PartPose.offset(1.7143F, -3.82F, 1.6524F)); + + PartDefinition cube_r1 = body1.addOrReplaceChild("cube_r1", CubeListBuilder.create().texOffs(56, 6).addBox(-1.0F, -6.0F, -4.0F, 2.0F, 5.0F, 8.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-1.7143F, -2.68F, 1.3476F, 0.7854F, 0.0F, 0.0F)); + + PartDefinition flos_R = body1.addOrReplaceChild("flos_R", CubeListBuilder.create(), PartPose.offset(4.2857F, 3.32F, -3.6524F)); + + PartDefinition cube_r2 = flos_R.addOrReplaceChild("cube_r2", CubeListBuilder.create().texOffs(56, 0).addBox(-9.0F, -1.0F, -1.0F, 10.0F, 1.0F, 5.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-12.0F, 0.0F, 0.0F, 0.0F, 0.3927F, 0.0F)); + + PartDefinition flos_L = body1.addOrReplaceChild("flos_L", CubeListBuilder.create(), PartPose.offset(4.2857F, 3.32F, -3.6524F)); + + PartDefinition cube_r3 = flos_L.addOrReplaceChild("cube_r3", CubeListBuilder.create().texOffs(30, 53).addBox(-1.0F, -1.0F, -1.0F, 10.0F, 1.0F, 5.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0F, 0.0F, 0.0F, 0.0F, -0.3927F, 0.0F)); + + PartDefinition head = body1.addOrReplaceChild("head", CubeListBuilder.create().texOffs(0, 24).addBox(-5.0F, -2.0F, -9.0F, 10.0F, 4.0F, 10.0F, new CubeDeformation(0.0F)) + .texOffs(0, 50).addBox(-4.0F, 2.0F, -8.0F, 8.0F, 1.0F, 7.0F, new CubeDeformation(0.0F)), PartPose.offset(-1.7143F, -1.18F, -10.6524F)); + + PartDefinition head_down = head.addOrReplaceChild("head_down", CubeListBuilder.create(), PartPose.offset(0.0F, 2.0F, 1.0F)); + + PartDefinition cube_r4 = head_down.addOrReplaceChild("cube_r4", CubeListBuilder.create().texOffs(0, 38).addBox(-5.0F, -0.0872F, -9.9962F, 10.0F, 2.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0F, 0.0F, 0.5F, 0.0873F, 0.0F, 0.0F)); + + PartDefinition body2 = body1.addOrReplaceChild("body2", CubeListBuilder.create().texOffs(40, 24).addBox(-5.0F, -3.1893F, -1.0251F, 10.0F, 6.0F, 8.0F, new CubeDeformation(0.0F)), PartPose.offset(-1.7143F, 0.0094F, 6.3727F)); + + PartDefinition cube_r5 = body2.addOrReplaceChild("cube_r5", CubeListBuilder.create().texOffs(40, 59).addBox(-1.0F, -6.0F, -4.0F, 2.0F, 2.0F, 4.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0F, -1.6893F, 7.9749F, 0.7854F, 0.0F, 0.0F)); + + PartDefinition body3 = body2.addOrReplaceChild("body3", CubeListBuilder.create().texOffs(20, 59).addBox(-3.0F, -2.0453F, -2.0168F, 6.0F, 4.0F, 4.0F, new CubeDeformation(0.0F)), PartPose.offset(0.0F, -0.144F, 7.9916F)); + + PartDefinition cube_r6 = body3.addOrReplaceChild("cube_r6", CubeListBuilder.create().texOffs(0, 58).addBox(-1.0F, -5.0F, -8.0F, 2.0F, 3.0F, 8.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0F, 7.9547F, 3.9832F, -0.7854F, 0.0F, 0.0F)); + + PartDefinition cube_r7 = body3.addOrReplaceChild("cube_r7", CubeListBuilder.create().texOffs(40, 38).addBox(-1.0F, -6.0F, -8.0F, 2.0F, 4.0F, 11.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0F, -1.5453F, 9.9832F, 0.7854F, 0.0F, 0.0F)); + + return LayerDefinition.create(meshdefinition, 128, 128); + } + + @Override + public void setupAnim(T entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch) { + this.root().getAllParts().forEach(ModelPart::resetPose); + + this.Shark.xRot = headPitch * ((float) Math.PI / 180f); + + float swimSpeed = 0.5f + Math.min(limbSwingAmount * 2f, 1f); + this.animate(entity.swimAnimationState, SharkAnimation.shark_swim, ageInTicks, swimSpeed); + this.animate(entity.attackAnimationState, SharkAnimation.shark_attack, ageInTicks, 1f); + } + + @Override + public void renderToBuffer(PoseStack poseStack, VertexConsumer vertexConsumer, int packedLight, int packedOverlay, int color) { + Shark.render(poseStack, vertexConsumer, packedLight, packedOverlay, color); + } + + @Override + public ModelPart root() { + return Shark; + } +} \ No newline at end of file diff --git a/src/main/java/ovh/glitchlabs/masterwild/entity/client/Shark/SharkRenderer.java b/src/main/java/ovh/glitchlabs/masterwild/entity/client/Shark/SharkRenderer.java new file mode 100644 index 0000000..b203e6b --- /dev/null +++ b/src/main/java/ovh/glitchlabs/masterwild/entity/client/Shark/SharkRenderer.java @@ -0,0 +1,21 @@ +package ovh.glitchlabs.masterwild.entity.client.Shark; + +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.custom.SharkEntity; + +public class SharkRenderer extends MobRenderer> { + private static final ResourceLocation TEXTURE = + ResourceLocation.fromNamespaceAndPath(Masterwild.MODID, "textures/entity/shark.png"); + + public SharkRenderer(EntityRendererProvider.Context context) { + super(context, new SharkModel<>(context.bakeLayer(SharkModel.LAYER_LOCATION)), 0.8f); + } + + @Override + public ResourceLocation getTextureLocation(SharkEntity entity) { + return TEXTURE; + } +} \ No newline at end of file diff --git a/src/main/java/ovh/glitchlabs/masterwild/entity/custom/SharkEntity.java b/src/main/java/ovh/glitchlabs/masterwild/entity/custom/SharkEntity.java new file mode 100644 index 0000000..cc84c1f --- /dev/null +++ b/src/main/java/ovh/glitchlabs/masterwild/entity/custom/SharkEntity.java @@ -0,0 +1,110 @@ +package ovh.glitchlabs.masterwild.entity.custom; + +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.AnimationState; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.Mob; +import net.minecraft.world.entity.MoverType; +import net.minecraft.world.entity.ai.attributes.AttributeSupplier; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.entity.ai.control.SmoothSwimmingLookControl; +import net.minecraft.world.entity.ai.control.SmoothSwimmingMoveControl; +import net.minecraft.world.entity.ai.goal.MeleeAttackGoal; +import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal; +import net.minecraft.world.entity.ai.goal.RandomSwimmingGoal; +import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal; +import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal; +import net.minecraft.world.entity.ai.navigation.PathNavigation; +import net.minecraft.world.entity.ai.navigation.WaterBoundPathNavigation; +import net.minecraft.world.entity.animal.AbstractFish; +import net.minecraft.world.entity.animal.WaterAnimal; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; + +public class SharkEntity extends WaterAnimal { + public final AnimationState swimAnimationState = new AnimationState(); + public final AnimationState attackAnimationState = new AnimationState(); + + public SharkEntity(EntityType entityType, Level level) { + super(entityType, level); + this.xpReward = 10; + this.moveControl = new SmoothSwimmingMoveControl(this, 85, 10, 0.02F, 0.1F, true); + this.lookControl = new SmoothSwimmingLookControl(this, 10); + } + + public static AttributeSupplier.Builder createAttributes() { + return Mob.createMobAttributes() + .add(Attributes.MAX_HEALTH, 18) + .add(Attributes.MOVEMENT_SPEED, 1.2) + .add(Attributes.ATTACK_DAMAGE, 6) + .add(Attributes.FOLLOW_RANGE, 32) + .add(Attributes.KNOCKBACK_RESISTANCE, 0.3); + } + + @Override + protected PathNavigation createNavigation(Level level) { + return new WaterBoundPathNavigation(this, level); + } + + @Override + protected void registerGoals() { + this.goalSelector.addGoal(1, new MeleeAttackGoal(this, 1.2, true)); + this.goalSelector.addGoal(2, new RandomSwimmingGoal(this, 1.0, 10)); + this.goalSelector.addGoal(3, new RandomLookAroundGoal(this)); + + this.targetSelector.addGoal(1, new HurtByTargetGoal(this)); + this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); + this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractFish.class, true)); + } + + @Override + public void travel(Vec3 travelVector) { + if (this.isControlledByLocalInstance() && this.isInWater()) { + this.moveRelative(this.getSpeed(), travelVector); + this.move(MoverType.SELF, this.getDeltaMovement()); + this.setDeltaMovement(this.getDeltaMovement().scale(0.9)); + if (this.getTarget() == null) { + this.setDeltaMovement(this.getDeltaMovement().add(0.0, -0.005, 0.0)); + } + } else { + super.travel(travelVector); + } + } + + @Override + public boolean doHurtTarget(Entity target) { + this.level().broadcastEntityEvent(this, (byte) 4); + return super.doHurtTarget(target); + } + + @Override + public void handleEntityEvent(byte id) { + if (id == 4) { + this.attackAnimationState.start(this.tickCount); + } else { + super.handleEntityEvent(id); + } + } + + @Override + public void tick() { + super.tick(); + if (this.level().isClientSide()) { + this.swimAnimationState.startIfStopped(this.tickCount); + } + } + + @Override + protected SoundEvent getHurtSound(DamageSource source) { + return SoundEvents.DOLPHIN_HURT; + } + + @Override + protected SoundEvent getDeathSound() { + return SoundEvents.DOLPHIN_DEATH; + } +} \ No newline at end of file diff --git a/src/main/java/ovh/glitchlabs/masterwild/event/ModEventBusEvents.java b/src/main/java/ovh/glitchlabs/masterwild/event/ModEventBusEvents.java index b291dad..47681fe 100644 --- a/src/main/java/ovh/glitchlabs/masterwild/event/ModEventBusEvents.java +++ b/src/main/java/ovh/glitchlabs/masterwild/event/ModEventBusEvents.java @@ -8,10 +8,12 @@ import ovh.glitchlabs.masterwild.Masterwild; 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.firefly.FireflyModel; import ovh.glitchlabs.masterwild.entity.custom.FireflyEntity; import ovh.glitchlabs.masterwild.entity.custom.PinguinEntity; import ovh.glitchlabs.masterwild.entity.custom.RoosterEntity; +import ovh.glitchlabs.masterwild.entity.custom.SharkEntity; @EventBusSubscriber(modid = Masterwild.MODID, bus = EventBusSubscriber.Bus.MOD) public class ModEventBusEvents { @@ -20,6 +22,7 @@ public class ModEventBusEvents { event.registerLayerDefinition(PinguinModel.LAYER_LOCATION, PinguinModel::createBodyLayer); event.registerLayerDefinition(FireflyModel.LAYER_LOCATION, FireflyModel::createBodyLayer); event.registerLayerDefinition(RoosterModel.LAYER_LOCATION, RoosterModel::createBodyLayer); + event.registerLayerDefinition(SharkModel.LAYER_LOCATION, SharkModel::createBodyLayer); } @SubscribeEvent @@ -27,5 +30,6 @@ public class ModEventBusEvents { event.put(ModEntities.PINGUIN.get(), PinguinEntity.createAttributes().build()); event.put(ModEntities.FIREFLY.get(), FireflyEntity.createAttributes().build()); event.put(ModEntities.ROOSTER.get(), RoosterEntity.createAttributes().build()); + event.put(ModEntities.SHARK.get(), SharkEntity.createAttributes().build()); } } diff --git a/src/main/resources/assets/masterwild/textures/entity/shark.png b/src/main/resources/assets/masterwild/textures/entity/shark.png new file mode 100755 index 0000000000000000000000000000000000000000..4330b1771f36caecfc3c0b4b0eb25664c7f8dac2 GIT binary patch literal 7357 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 Ee`iTv?*IS* literal 0 HcmV?d00001