From 05e1cf1da625d68625b91625d4db245b40febdd8 Mon Sep 17 00:00:00 2001 From: crispytwig <48872606+crispytwig@users.noreply.github.com> Date: Wed, 23 Oct 2024 23:56:49 -0500 Subject: [PATCH] Hamster progress --- .../hamsters/HamstersVanillaIntegration.java | 8 +- .../hamsters/client/model/HamsterModel.java | 70 +++- .../client/model/HamsterNewModel.java | 31 +- .../shoulder/LeftSittingHamsterModel.java | 111 ++++++ .../shoulder/RightSittingHamsterModel.java | 111 ++++++ .../client/renderer/HamsterNewRenderer.java | 2 +- .../PlayerHamsterOnLeftShoulderLayer.java | 52 +++ .../PlayerHamsterOnRightShoulderLayer.java | 52 +++ .../hamsters/entity/Hamster.java | 1 + .../hamsters/entity/HamsterNew.java | 365 ++++++++++++++++-- .../hamsters/mixin/PlayerRendererMixin.java | 26 ++ .../registry/HamstersSoundEvents.java | 1 + .../hamsters/geo/entity/hamster.geo.json | 22 +- .../resources/assets/hamsters/lang/en_us.json | 1 + .../resources/assets/hamsters/sounds.json | 6 + .../resources/assets/hamsters/sounds/yay.ogg | Bin 0 -> 47249 bytes .../hamsters/textures/entity/hamster/wild.png | Bin 0 -> 813 bytes src/main/resources/hamsters.mixins.json | 5 +- 18 files changed, 792 insertions(+), 72 deletions(-) create mode 100644 src/main/java/com/starfish_studios/hamsters/client/model/shoulder/LeftSittingHamsterModel.java create mode 100644 src/main/java/com/starfish_studios/hamsters/client/model/shoulder/RightSittingHamsterModel.java create mode 100644 src/main/java/com/starfish_studios/hamsters/client/renderer/layers/player/PlayerHamsterOnLeftShoulderLayer.java create mode 100644 src/main/java/com/starfish_studios/hamsters/client/renderer/layers/player/PlayerHamsterOnRightShoulderLayer.java create mode 100644 src/main/java/com/starfish_studios/hamsters/mixin/PlayerRendererMixin.java create mode 100644 src/main/resources/assets/hamsters/sounds/yay.ogg create mode 100644 src/main/resources/assets/hamsters/textures/entity/hamster/wild.png diff --git a/src/main/java/com/starfish_studios/hamsters/HamstersVanillaIntegration.java b/src/main/java/com/starfish_studios/hamsters/HamstersVanillaIntegration.java index c6feb56..75ef361 100644 --- a/src/main/java/com/starfish_studios/hamsters/HamstersVanillaIntegration.java +++ b/src/main/java/com/starfish_studios/hamsters/HamstersVanillaIntegration.java @@ -1,21 +1,25 @@ package com.starfish_studios.hamsters; -import com.starfish_studios.hamsters.block.CagePanelBlock; +import com.starfish_studios.hamsters.client.model.shoulder.LeftSittingHamsterModel; import com.starfish_studios.hamsters.client.renderer.*; import com.starfish_studios.hamsters.registry.HamstersBlocks; import com.starfish_studios.hamsters.registry.HamstersEntityType; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; 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.model.geom.ModelLayerLocation; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import java.util.function.Supplier; public class HamstersVanillaIntegration { + public static final ModelLayerLocation HAMSTER_LAYER = new ModelLayerLocation(new ResourceLocation(Hamsters.MOD_ID, "sitting_hamster"), "main"); public static void serverInit() { @@ -38,6 +42,8 @@ private static void registerModelLayers() { EntityRendererRegistry.register(HamstersEntityType.HAMSTER, HamsterRenderer::new); EntityRendererRegistry.register(HamstersEntityType.HAMSTER_NEW, HamsterNewRenderer::new); EntityRendererRegistry.register(HamstersEntityType.HAMSTER_BALL, HamsterBallRenderer::new); + + EntityModelLayerRegistry.registerModelLayer(HAMSTER_LAYER, LeftSittingHamsterModel::createBodyLayer); } private static void registerBlockRenderLayers() { diff --git a/src/main/java/com/starfish_studios/hamsters/client/model/HamsterModel.java b/src/main/java/com/starfish_studios/hamsters/client/model/HamsterModel.java index 7789835..5c7851f 100644 --- a/src/main/java/com/starfish_studios/hamsters/client/model/HamsterModel.java +++ b/src/main/java/com/starfish_studios/hamsters/client/model/HamsterModel.java @@ -1,19 +1,13 @@ package com.starfish_studios.hamsters.client.model; -import com.google.common.collect.Maps; -import com.starfish_studios.hamsters.Hamsters; -import com.starfish_studios.hamsters.block.entity.HamsterWheelBlockEntity; import com.starfish_studios.hamsters.entity.Hamster; -import net.minecraft.Util; +import com.starfish_studios.hamsters.entity.HamsterNew; import net.minecraft.client.renderer.RenderType; import net.minecraft.resources.ResourceLocation; -import org.apache.logging.log4j.core.appender.ScriptAppenderSelector; import software.bernie.geckolib.core.animatable.model.CoreGeoBone; import software.bernie.geckolib.core.animation.AnimationState; import software.bernie.geckolib.model.DefaultedEntityGeoModel; -import java.util.Map; - import static com.starfish_studios.hamsters.Hamsters.MOD_ID; public class HamsterModel extends DefaultedEntityGeoModel { @@ -24,7 +18,47 @@ public HamsterModel() { @Override public ResourceLocation getModelResource(Hamster animatable) { - return animatable.isBaby() ? new ResourceLocation(MOD_ID, "geo/entity/pinkie.geo.json") : new ResourceLocation(MOD_ID, "geo/entity/hamster.geo.json"); +// return animatable.isBaby() ? new ResourceLocation(MOD_ID, "geo/entity/pinkie.geo.json") : new ResourceLocation(MOD_ID, "geo/entity/hamster.geo.json"); + return new ResourceLocation(MOD_ID, "geo/entity/hamster.geo.json"); + } + + public static ResourceLocation getVariantTexture2(HamsterNew.Variant variant) { + ResourceLocation resourceLocation; + switch (variant) { + case WHITE -> resourceLocation = new ResourceLocation(MOD_ID, "textures/entity/hamster/white.png"); + case CREAM -> resourceLocation = new ResourceLocation(MOD_ID, "textures/entity/hamster/cream.png"); + case CHAMPAGNE -> resourceLocation = new ResourceLocation(MOD_ID, "textures/entity/hamster/champagne.png"); + case SILVER_DOVE -> resourceLocation = new ResourceLocation(MOD_ID, "textures/entity/hamster/silver_dove.png"); + case DOVE -> resourceLocation = new ResourceLocation(MOD_ID, "textures/entity/hamster/dove.png"); + case CHOCOLATE -> resourceLocation = new ResourceLocation(MOD_ID, "textures/entity/hamster/chocolate.png"); + case BLACK -> resourceLocation = new ResourceLocation(MOD_ID, "textures/entity/hamster/black.png"); + case WILD -> resourceLocation = new ResourceLocation(MOD_ID, "textures/entity/hamster/wild.png"); + default -> throw new IllegalStateException("Unexpected value: " + variant); + } + return resourceLocation; + } + + public static ResourceLocation getVariantTexture(HamsterNew.Variant variant, HamsterNew.Marking marking) { + ResourceLocation resourceLocation; + switch (variant) { + case WHITE -> resourceLocation = new ResourceLocation(MOD_ID, "textures/entity/hamster/white.png"); + case CREAM -> resourceLocation = new ResourceLocation(MOD_ID, "textures/entity/hamster/cream.png"); + case CHAMPAGNE -> resourceLocation = new ResourceLocation(MOD_ID, "textures/entity/hamster/champagne.png"); + case SILVER_DOVE -> resourceLocation = new ResourceLocation(MOD_ID, "textures/entity/hamster/silver_dove.png"); + case DOVE -> resourceLocation = new ResourceLocation(MOD_ID, "textures/entity/hamster/dove.png"); + case CHOCOLATE -> resourceLocation = new ResourceLocation(MOD_ID, "textures/entity/hamster/chocolate.png"); + case BLACK -> resourceLocation = new ResourceLocation(MOD_ID, "textures/entity/hamster/black.png"); + case WILD -> resourceLocation = new ResourceLocation(MOD_ID, "textures/entity/hamster/wild.png"); + default -> throw new IllegalStateException("Unexpected value: " + variant); + } + switch (marking) { + case BLANK -> resourceLocation = new ResourceLocation(MOD_ID, "textures/entity/hamster/blank.png"); + case BANDED -> resourceLocation = new ResourceLocation(MOD_ID, "textures/entity/hamster/banded.png"); + case DOMINANT_SPOTS -> resourceLocation = new ResourceLocation(MOD_ID, "textures/entity/hamster/dominant_spots.png"); + case ROAN -> resourceLocation = new ResourceLocation(MOD_ID, "textures/entity/hamster/roan.png"); + case BELLY -> resourceLocation = new ResourceLocation(MOD_ID, "textures/entity/hamster/belly.png"); + } + return resourceLocation; } @Override @@ -32,15 +66,15 @@ public ResourceLocation getTextureResource(Hamster animatable) { if (animatable.isBaby()) { return new ResourceLocation(MOD_ID, "textures/entity/hamster/pinkie.png"); } - return switch (animatable.getVariant()) { - case 0 -> new ResourceLocation(MOD_ID, "textures/entity/hamster/white.png"); - case 1 -> new ResourceLocation(MOD_ID, "textures/entity/hamster/cream.png"); - case 2 -> new ResourceLocation(MOD_ID, "textures/entity/hamster/champagne.png"); - case 3 -> new ResourceLocation(MOD_ID, "textures/entity/hamster/silver_dove.png"); - case 4 -> new ResourceLocation(MOD_ID, "textures/entity/hamster/dove.png"); - case 5 -> new ResourceLocation(MOD_ID, "textures/entity/hamster/chocolate.png"); - case 6 -> new ResourceLocation(MOD_ID, "textures/entity/hamster/black.png"); - default -> throw new IllegalStateException("Unexpected value: " + animatable.getVariant()); + return switch (HamsterNew.Variant.getTypeById(animatable.getVariant())) { + case WHITE -> new ResourceLocation(MOD_ID, "textures/entity/hamster/white.png"); + case CREAM -> new ResourceLocation(MOD_ID, "textures/entity/hamster/cream.png"); + case CHAMPAGNE -> new ResourceLocation(MOD_ID, "textures/entity/hamster/champagne.png"); + case SILVER_DOVE -> new ResourceLocation(MOD_ID, "textures/entity/hamster/silver_dove.png"); + case DOVE -> new ResourceLocation(MOD_ID, "textures/entity/hamster/dove.png"); + case CHOCOLATE -> new ResourceLocation(MOD_ID, "textures/entity/hamster/chocolate.png"); + case BLACK -> new ResourceLocation(MOD_ID, "textures/entity/hamster/black.png"); + default -> new ResourceLocation(MOD_ID, "textures/entity/hamster/wild.png"); }; } @@ -51,7 +85,7 @@ public ResourceLocation getAnimationResource(Hamster animatable) { @Override public RenderType getRenderType(Hamster animatable, ResourceLocation texture) { - return RenderType.entitySolid(texture); + return RenderType.entityCutoutNoCull(texture); } @Override diff --git a/src/main/java/com/starfish_studios/hamsters/client/model/HamsterNewModel.java b/src/main/java/com/starfish_studios/hamsters/client/model/HamsterNewModel.java index 0261665..445d579 100644 --- a/src/main/java/com/starfish_studios/hamsters/client/model/HamsterNewModel.java +++ b/src/main/java/com/starfish_studios/hamsters/client/model/HamsterNewModel.java @@ -3,6 +3,7 @@ import com.starfish_studios.hamsters.entity.HamsterNew; import net.minecraft.client.renderer.RenderType; import net.minecraft.resources.ResourceLocation; +import org.apache.logging.log4j.core.appender.ScriptAppenderSelector; import software.bernie.geckolib.core.animatable.model.CoreGeoBone; import software.bernie.geckolib.core.animation.AnimationState; import software.bernie.geckolib.model.DefaultedEntityGeoModel; @@ -17,14 +18,15 @@ public HamsterNewModel() { @Override public ResourceLocation getModelResource(HamsterNew animatable) { - return animatable.isBaby() ? new ResourceLocation(MOD_ID, "geo/entity/pinkie.geo.json") : new ResourceLocation(MOD_ID, "geo/entity/hamster.geo.json"); +// return animatable.isBaby() ? new ResourceLocation(MOD_ID, "geo/entity/pinkie.geo.json") : new ResourceLocation(MOD_ID, "geo/entity/hamster.geo.json"); + return new ResourceLocation(MOD_ID, "geo/entity/hamster.geo.json"); } @Override public ResourceLocation getTextureResource(HamsterNew animatable) { - if (animatable.isBaby()) { - return new ResourceLocation(MOD_ID, "textures/entity/hamster/pinkie.png"); - } +// if (animatable.isBaby()) { +// return new ResourceLocation(MOD_ID, "textures/entity/hamster/pinkie.png"); +// } return switch (animatable.getVariant()) { case 0 -> new ResourceLocation(MOD_ID, "textures/entity/hamster/white.png"); case 1 -> new ResourceLocation(MOD_ID, "textures/entity/hamster/cream.png"); @@ -33,6 +35,7 @@ public ResourceLocation getTextureResource(HamsterNew animatable) { case 4 -> new ResourceLocation(MOD_ID, "textures/entity/hamster/dove.png"); case 5 -> new ResourceLocation(MOD_ID, "textures/entity/hamster/chocolate.png"); case 6 -> new ResourceLocation(MOD_ID, "textures/entity/hamster/black.png"); + case 7 -> new ResourceLocation(MOD_ID, "textures/entity/hamster/wild.png"); default -> throw new IllegalStateException("Unexpected value: " + animatable.getVariant()); }; } @@ -44,7 +47,7 @@ public ResourceLocation getAnimationResource(HamsterNew animatable) { @Override public RenderType getRenderType(HamsterNew animatable, ResourceLocation texture) { - return RenderType.entitySolid(texture); + return RenderType.entityCutoutNoCull(texture); } @Override @@ -52,12 +55,30 @@ public void setCustomAnimations(HamsterNew animatable, long instanceId, Animatio super.setCustomAnimations(animatable, instanceId, animationState); if (animationState == null) return; + CoreGeoBone root = this.getAnimationProcessor().getBone("root"); CoreGeoBone head = this.getAnimationProcessor().getBone("head"); CoreGeoBone sleep = this.getAnimationProcessor().getBone("sleep"); CoreGeoBone cheeks = this.getAnimationProcessor().getBone("cheeks"); + CoreGeoBone leftCheek = this.getAnimationProcessor().getBone("leftCheek"); + CoreGeoBone rightCheek = this.getAnimationProcessor().getBone("rightCheek"); cheeks.setHidden(animatable.getMainHandItem().isEmpty()); + if (animatable.getCheekLevel() > 0) { + cheeks.setHidden(false); + leftCheek.setScaleX(1.0F + (animatable.getCheekLevel() * 0.2F)); leftCheek.setScaleY(1.0F + (animatable.getCheekLevel() * 0.2F)); leftCheek.setScaleZ(1.0F + (animatable.getCheekLevel() * 0.2F)); + rightCheek.setScaleX(1.0F + (animatable.getCheekLevel() * 0.2F)); rightCheek.setScaleY(1.0F + (animatable.getCheekLevel() * 0.2F)); rightCheek.setScaleZ(1.0F + (animatable.getCheekLevel() * 0.2F)); + } else { + cheeks.setScaleX(1.0F); + cheeks.setScaleY(1.0F); + cheeks.setScaleZ(1.0F); + } + + if (animatable.getCheekLevel() > 1) { + root.setRotZ((float) Math.sin(System.currentTimeMillis() * 0.05) * 0.1F * (animatable.getCheekLevel() * 0.05F)); + + } + // Ensures there are no strange eye glitches when the hamster is sleeping or awake. if (animatable.isSleeping() && !animatable.isBaby()) { diff --git a/src/main/java/com/starfish_studios/hamsters/client/model/shoulder/LeftSittingHamsterModel.java b/src/main/java/com/starfish_studios/hamsters/client/model/shoulder/LeftSittingHamsterModel.java new file mode 100644 index 0000000..853e927 --- /dev/null +++ b/src/main/java/com/starfish_studios/hamsters/client/model/shoulder/LeftSittingHamsterModel.java @@ -0,0 +1,111 @@ +package com.starfish_studios.hamsters.client.model.shoulder; + + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.starfish_studios.hamsters.entity.HamsterNew; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.model.EntityModel; +import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.client.model.geom.PartPose; +import net.minecraft.client.model.geom.builders.*; + +public class LeftSittingHamsterModel extends EntityModel { + private final ModelPart root; + private final ModelPart body; + private final ModelPart headRot; + private final ModelPart head; + private final ModelPart armorBipedHead; + private final ModelPart rightEar; + private final ModelPart leftEar; + private final ModelPart cheeks; + private final ModelPart sleep; + private final ModelPart tail; + private final ModelPart rightHand; + private final ModelPart leftHand; + private final ModelPart legs; + private final ModelPart leftFoot; + private final ModelPart rightFoot; + + public LeftSittingHamsterModel(ModelPart modelPart) { + this.root = modelPart; + this.body = modelPart.getChild("body"); + this.headRot = this.body.getChild("headRot"); + this.head = this.headRot.getChild("head"); + this.armorBipedHead = this.head.getChild("armorBipedHead"); + this.rightEar = this.head.getChild("rightEar"); + this.leftEar = this.head.getChild("leftEar"); + this.cheeks = this.head.getChild("cheeks"); + this.sleep = this.head.getChild("sleep"); + this.tail = this.body.getChild("tail"); + this.rightHand = this.body.getChild("rightHand"); + this.leftHand = this.body.getChild("leftHand"); + this.legs = modelPart.getChild("legs"); + this.leftFoot = this.legs.getChild("leftFoot"); + this.rightFoot = this.legs.getChild("rightFoot"); + } + + public static LayerDefinition createBodyLayer() { + MeshDefinition meshdefinition = new MeshDefinition(); + PartDefinition partdefinition = meshdefinition.getRoot(); + + PartDefinition root = partdefinition.addOrReplaceChild("root", CubeListBuilder.create(), PartPose.offset(0.0F, 24.0F, -2.0F)); + + PartDefinition body = root.addOrReplaceChild("body", CubeListBuilder.create().texOffs(0, 0).addBox(-3.0F, -3.0F, -5.0F, 6.0F, 4.0F, 6.0F, new CubeDeformation(0.01F)), PartPose.offsetAndRotation(0.0F, -0.5F, 3.0F, -0.9599F, 0.0F, 0.0F)); + + PartDefinition headRot = body.addOrReplaceChild("headRot", CubeListBuilder.create(), PartPose.offsetAndRotation(-0.5F, -2.0F, -4.5F, 0.9599F, 0.0F, 0.0F)); + + PartDefinition head = headRot.addOrReplaceChild("head", CubeListBuilder.create(), PartPose.offset(0.0F, 0.0F, 0.0F)); + + PartDefinition armorBipedHead = head.addOrReplaceChild("armorBipedHead", CubeListBuilder.create().texOffs(1, 11).addBox(-2.5F, -4.0F, -2.0F, 5.0F, 4.0F, 4.0F, new CubeDeformation(0.0F)), PartPose.offset(0.5F, 1.5F, -2.0F)); + + PartDefinition rightEar = head.addOrReplaceChild("rightEar", CubeListBuilder.create().texOffs(0, 11).mirror().addBox(-2.0F, -2.0F, 0.0F, 2.0F, 2.0F, 0.0F, new CubeDeformation(0.01F)).mirror(false), PartPose.offset(-1.0F, -1.5F, -2.0F)); + + PartDefinition leftEar = head.addOrReplaceChild("leftEar", CubeListBuilder.create().texOffs(0, 11).addBox(0.0F, -2.0F, 0.0F, 2.0F, 2.0F, 0.0F, new CubeDeformation(0.01F)), PartPose.offset(2.0F, -1.5F, -2.0F)); + + PartDefinition cheeks = head.addOrReplaceChild("cheeks", CubeListBuilder.create().texOffs(20, 13).addBox(7.0F, -1.5F, -2.0F, 2.0F, 3.0F, 3.0F, new CubeDeformation(0.0F)) + .texOffs(20, 13).mirror().addBox(0.0F, -1.5F, -2.0F, 2.0F, 3.0F, 3.0F, new CubeDeformation(0.0F)).mirror(false), PartPose.offset(-4.0F, 0.0F, -2.0F)); + + PartDefinition sleep = head.addOrReplaceChild("sleep", CubeListBuilder.create(), PartPose.offset(0.5F, 2.5F, 0.0F)); + + PartDefinition tail = body.addOrReplaceChild("tail", CubeListBuilder.create().texOffs(19, 0).addBox(-1.0F, 0.0F, 0.0F, 2.0F, 1.0F, 1.0F, new CubeDeformation(0.0F)), PartPose.offset(0.0F, -3.0F, 1.0F)); + + PartDefinition rightHand = body.addOrReplaceChild("rightHand", CubeListBuilder.create().texOffs(24, 2).mirror().addBox(-1.0F, 0.0F, -1.0F, 2.0F, 1.0F, 2.0F, new CubeDeformation(0.0F)).mirror(false), PartPose.offsetAndRotation(-1.5F, 1.5F, -3.5F, 2.3126F, 0.2618F, 0.0565F)); + + PartDefinition leftHand = body.addOrReplaceChild("leftHand", CubeListBuilder.create().texOffs(24, 2).addBox(-1.0F, 0.0F, -1.0F, 2.0F, 1.0F, 2.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(1.5F, 1.5F, -3.5F, 2.3126F, -0.2618F, -0.0698F)); + + PartDefinition legs = root.addOrReplaceChild("legs", CubeListBuilder.create(), PartPose.offset(1.5F, -1.0F, -1.0F)); + + PartDefinition leftFoot = legs.addOrReplaceChild("leftFoot", CubeListBuilder.create().texOffs(24, 2).addBox(-1.0F, 0.0F, -1.0F, 2.0F, 1.0F, 2.0F, new CubeDeformation(0.0F)), PartPose.offset(0.0F, 0.0F, 3.0F)); + + PartDefinition rightFoot = legs.addOrReplaceChild("rightFoot", CubeListBuilder.create().texOffs(24, 2).mirror().addBox(-1.0F, 0.0F, -1.0F, 2.0F, 1.0F, 2.0F, new CubeDeformation(0.0F)).mirror(false), PartPose.offset(-3.0F, 0.0F, 3.0F)); + + return LayerDefinition.create(meshdefinition, 32, 32); + } + + public void renderOnShoulder(PoseStack poseStack, VertexConsumer vertexConsumer, int i, int j, float f, float g, float h, float k, int l) { + this.setupAnim(State.ON_SHOULDER, l, f, g, 0.0F, h, k); + this.root.render(poseStack, vertexConsumer, i, j); + } + + private void setupAnim(State state, int i, float f, float g, float h, float j, float k) { + this.head.xRot = k * 0.017453292F; + this.head.yRot = j * 0.017453292F; + } + + @Override + public void renderToBuffer(PoseStack poseStack, VertexConsumer vertexConsumer, int packedLight, int packedOverlay, float red, float green, float blue, float alpha) { + root.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha); + } + + @Override + public void setupAnim(T entity, float f, float g, float h, float i, float j) { + this.setupAnim(State.ON_SHOULDER, entity.tickCount, f, g, h, i, j); + } + + @Environment(EnvType.CLIENT) + public enum State { + ON_SHOULDER; + } +} \ No newline at end of file diff --git a/src/main/java/com/starfish_studios/hamsters/client/model/shoulder/RightSittingHamsterModel.java b/src/main/java/com/starfish_studios/hamsters/client/model/shoulder/RightSittingHamsterModel.java new file mode 100644 index 0000000..22b5116 --- /dev/null +++ b/src/main/java/com/starfish_studios/hamsters/client/model/shoulder/RightSittingHamsterModel.java @@ -0,0 +1,111 @@ +package com.starfish_studios.hamsters.client.model.shoulder; + + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.starfish_studios.hamsters.entity.HamsterNew; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.model.EntityModel; +import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.client.model.geom.PartPose; +import net.minecraft.client.model.geom.builders.*; + +public class RightSittingHamsterModel extends EntityModel { + private final ModelPart root; + private final ModelPart body; + private final ModelPart headRot; + private final ModelPart head; + private final ModelPart armorBipedHead; + private final ModelPart rightEar; + private final ModelPart leftEar; + private final ModelPart cheeks; + private final ModelPart sleep; + private final ModelPart tail; + private final ModelPart rightHand; + private final ModelPart leftHand; + private final ModelPart legs; + private final ModelPart leftFoot; + private final ModelPart rightFoot; + + public RightSittingHamsterModel(ModelPart modelPart) { + this.root = modelPart; + this.body = modelPart.getChild("body"); + this.headRot = this.body.getChild("headRot"); + this.head = this.headRot.getChild("head"); + this.armorBipedHead = this.head.getChild("armorBipedHead"); + this.rightEar = this.head.getChild("rightEar"); + this.leftEar = this.head.getChild("leftEar"); + this.cheeks = this.head.getChild("cheeks"); + this.sleep = this.head.getChild("sleep"); + this.tail = this.body.getChild("tail"); + this.rightHand = this.body.getChild("rightHand"); + this.leftHand = this.body.getChild("leftHand"); + this.legs = modelPart.getChild("legs"); + this.leftFoot = this.legs.getChild("leftFoot"); + this.rightFoot = this.legs.getChild("rightFoot"); + } + + public static LayerDefinition createBodyLayer() { + MeshDefinition meshdefinition = new MeshDefinition(); + PartDefinition partdefinition = meshdefinition.getRoot(); + + PartDefinition root = partdefinition.addOrReplaceChild("root", CubeListBuilder.create(), PartPose.offset(0.0F, 24.0F, -2.0F)); + + PartDefinition body = root.addOrReplaceChild("body", CubeListBuilder.create().texOffs(0, 0).addBox(-3.0F, -3.0F, -5.0F, 6.0F, 4.0F, 6.0F, new CubeDeformation(0.01F)), PartPose.offsetAndRotation(0.0F, -0.5F, 3.0F, -0.9599F, 0.0F, 0.0F)); + + PartDefinition headRot = body.addOrReplaceChild("headRot", CubeListBuilder.create(), PartPose.offsetAndRotation(-0.5F, -2.0F, -4.5F, 0.9599F, 0.0F, 0.0F)); + + PartDefinition head = headRot.addOrReplaceChild("head", CubeListBuilder.create(), PartPose.offset(0.0F, 0.0F, 0.0F)); + + PartDefinition armorBipedHead = head.addOrReplaceChild("armorBipedHead", CubeListBuilder.create().texOffs(1, 11).addBox(-2.5F, -4.0F, -2.0F, 5.0F, 4.0F, 4.0F, new CubeDeformation(0.0F)), PartPose.offset(0.5F, 1.5F, -2.0F)); + + PartDefinition rightEar = head.addOrReplaceChild("rightEar", CubeListBuilder.create().texOffs(0, 11).mirror().addBox(-2.0F, -2.0F, 0.0F, 2.0F, 2.0F, 0.0F, new CubeDeformation(0.01F)).mirror(false), PartPose.offset(-1.0F, -1.5F, -2.0F)); + + PartDefinition leftEar = head.addOrReplaceChild("leftEar", CubeListBuilder.create().texOffs(0, 11).addBox(0.0F, -2.0F, 0.0F, 2.0F, 2.0F, 0.0F, new CubeDeformation(0.01F)), PartPose.offset(2.0F, -1.5F, -2.0F)); + + PartDefinition cheeks = head.addOrReplaceChild("cheeks", CubeListBuilder.create().texOffs(20, 13).addBox(7.0F, -1.5F, -2.0F, 2.0F, 3.0F, 3.0F, new CubeDeformation(0.0F)) + .texOffs(20, 13).mirror().addBox(0.0F, -1.5F, -2.0F, 2.0F, 3.0F, 3.0F, new CubeDeformation(0.0F)).mirror(false), PartPose.offset(-4.0F, 0.0F, -2.0F)); + + PartDefinition sleep = head.addOrReplaceChild("sleep", CubeListBuilder.create(), PartPose.offset(0.5F, 2.5F, 0.0F)); + + PartDefinition tail = body.addOrReplaceChild("tail", CubeListBuilder.create().texOffs(19, 0).addBox(-1.0F, 0.0F, 0.0F, 2.0F, 1.0F, 1.0F, new CubeDeformation(0.0F)), PartPose.offset(0.0F, -3.0F, 1.0F)); + + PartDefinition rightHand = body.addOrReplaceChild("rightHand", CubeListBuilder.create().texOffs(24, 2).mirror().addBox(-1.0F, 0.0F, -1.0F, 2.0F, 1.0F, 2.0F, new CubeDeformation(0.0F)).mirror(false), PartPose.offsetAndRotation(-1.5F, 1.5F, -3.5F, 2.3126F, 0.2618F, 0.0565F)); + + PartDefinition leftHand = body.addOrReplaceChild("leftHand", CubeListBuilder.create().texOffs(24, 2).addBox(-1.0F, 0.0F, -1.0F, 2.0F, 1.0F, 2.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(1.5F, 1.5F, -3.5F, 2.3126F, -0.2618F, -0.0698F)); + + PartDefinition legs = root.addOrReplaceChild("legs", CubeListBuilder.create(), PartPose.offset(1.5F, -1.0F, -1.0F)); + + PartDefinition leftFoot = legs.addOrReplaceChild("leftFoot", CubeListBuilder.create().texOffs(24, 2).addBox(-1.0F, 0.0F, -1.0F, 2.0F, 1.0F, 2.0F, new CubeDeformation(0.0F)), PartPose.offset(0.0F, 0.0F, 3.0F)); + + PartDefinition rightFoot = legs.addOrReplaceChild("rightFoot", CubeListBuilder.create().texOffs(24, 2).mirror().addBox(-1.0F, 0.0F, -1.0F, 2.0F, 1.0F, 2.0F, new CubeDeformation(0.0F)).mirror(false), PartPose.offset(-3.0F, 0.0F, 3.0F)); + + return LayerDefinition.create(meshdefinition, 32, 32); + } + + public void renderOnShoulder(PoseStack poseStack, VertexConsumer vertexConsumer, int i, int j, float f, float g, float h, float k, int l) { + this.setupAnim(State.ON_SHOULDER, l, f, g, 0.0F, h, k); + this.root.render(poseStack, vertexConsumer, i, j); + } + + private void setupAnim(State state, int i, float f, float g, float h, float j, float k) { + this.head.xRot = k * 0.017453292F; + this.head.yRot = j * 0.017453292F; + } + + @Override + public void renderToBuffer(PoseStack poseStack, VertexConsumer vertexConsumer, int packedLight, int packedOverlay, float red, float green, float blue, float alpha) { + root.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha); + } + + @Override + public void setupAnim(T entity, float f, float g, float h, float i, float j) { + this.setupAnim(State.ON_SHOULDER, entity.tickCount, f, g, h, i, j); + } + + @Environment(EnvType.CLIENT) + public enum State { + ON_SHOULDER; + } +} \ No newline at end of file diff --git a/src/main/java/com/starfish_studios/hamsters/client/renderer/HamsterNewRenderer.java b/src/main/java/com/starfish_studios/hamsters/client/renderer/HamsterNewRenderer.java index fa66473..fda61aa 100644 --- a/src/main/java/com/starfish_studios/hamsters/client/renderer/HamsterNewRenderer.java +++ b/src/main/java/com/starfish_studios/hamsters/client/renderer/HamsterNewRenderer.java @@ -81,7 +81,7 @@ public float getMotionAnimThreshold(HamsterNew animatable) { @Override public void render(HamsterNew animatable, float entityYaw, float partialTick, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight) { if (animatable.isBaby()) { - poseStack.scale(1F, 1F, 1F); + poseStack.scale(0.6F, 0.6F, 0.6F); } else { poseStack.scale(1F, 1F, 1F); } diff --git a/src/main/java/com/starfish_studios/hamsters/client/renderer/layers/player/PlayerHamsterOnLeftShoulderLayer.java b/src/main/java/com/starfish_studios/hamsters/client/renderer/layers/player/PlayerHamsterOnLeftShoulderLayer.java new file mode 100644 index 0000000..f9f2395 --- /dev/null +++ b/src/main/java/com/starfish_studios/hamsters/client/renderer/layers/player/PlayerHamsterOnLeftShoulderLayer.java @@ -0,0 +1,52 @@ +package com.starfish_studios.hamsters.client.renderer.layers.player; + + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.starfish_studios.hamsters.Hamsters; +import com.starfish_studios.hamsters.client.model.HamsterModel; +import com.starfish_studios.hamsters.client.model.shoulder.LeftSittingHamsterModel; +import com.starfish_studios.hamsters.entity.HamsterNew; +import com.starfish_studios.hamsters.registry.HamstersEntityType; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.model.PlayerModel; +import net.minecraft.client.model.geom.EntityModelSet; +import net.minecraft.client.model.geom.ModelLayerLocation; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.entity.RenderLayerParent; +import net.minecraft.client.renderer.entity.layers.RenderLayer; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.player.Player; + +@Environment(EnvType.CLIENT) +public class PlayerHamsterOnLeftShoulderLayer extends RenderLayer> { + private final LeftSittingHamsterModel model; + public static final ModelLayerLocation HAMSTER_LAYER = new ModelLayerLocation(new ResourceLocation(Hamsters.MOD_ID, "left_sitting_hamster"), "main"); + + public PlayerHamsterOnLeftShoulderLayer(RenderLayerParent> renderLayerParent, EntityModelSet entityModelSet) { + super(renderLayerParent); + this.model = new LeftSittingHamsterModel<>(entityModelSet.bakeLayer(HAMSTER_LAYER)); + } + + public void render(PoseStack poseStack, MultiBufferSource multiBufferSource, int i, T player, float f, float g, float h, float j, float k, float l) { + this.render(poseStack, multiBufferSource, i, player, f, g, k, l, true); + } + + private void render(PoseStack poseStack, MultiBufferSource multiBufferSource, int i, T player, float f, float g, float h, float j, boolean bl) { + CompoundTag compoundTag = bl ? player.getShoulderEntityLeft() : player.getShoulderEntityRight(); + EntityType.byString(compoundTag.getString("id")).filter((entityType) -> entityType == HamstersEntityType.HAMSTER).ifPresent((entityType) -> { + poseStack.pushPose(); + poseStack.scale(bl ? 1.0F : -1.0F, 1.0F, 1.0F); + poseStack.translate(0.425F, player.isCrouching() ? 0.2F : 0.0F, 0.25F); + HamsterNew.Variant variant = HamsterNew.Variant.getTypeById(compoundTag.getInt("Variant")); +// HamsterNew.Marking marking = HamsterNew.Marking.byId(compoundTag.getInt("Marking")); + VertexConsumer vertexConsumer = multiBufferSource.getBuffer(this.model.renderType(HamsterModel.getVariantTexture2(variant))); + this.model.renderOnShoulder(poseStack, vertexConsumer, i, OverlayTexture.NO_OVERLAY, f, g, h, j, player.tickCount); + poseStack.popPose(); + }); + } +} diff --git a/src/main/java/com/starfish_studios/hamsters/client/renderer/layers/player/PlayerHamsterOnRightShoulderLayer.java b/src/main/java/com/starfish_studios/hamsters/client/renderer/layers/player/PlayerHamsterOnRightShoulderLayer.java new file mode 100644 index 0000000..bb4dcbb --- /dev/null +++ b/src/main/java/com/starfish_studios/hamsters/client/renderer/layers/player/PlayerHamsterOnRightShoulderLayer.java @@ -0,0 +1,52 @@ +package com.starfish_studios.hamsters.client.renderer.layers.player; + + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.starfish_studios.hamsters.Hamsters; +import com.starfish_studios.hamsters.client.model.HamsterModel; +import com.starfish_studios.hamsters.client.model.shoulder.LeftSittingHamsterModel; +import com.starfish_studios.hamsters.entity.HamsterNew; +import com.starfish_studios.hamsters.registry.HamstersEntityType; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.model.PlayerModel; +import net.minecraft.client.model.geom.EntityModelSet; +import net.minecraft.client.model.geom.ModelLayerLocation; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.entity.RenderLayerParent; +import net.minecraft.client.renderer.entity.layers.RenderLayer; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.player.Player; + +@Environment(EnvType.CLIENT) +public class PlayerHamsterOnRightShoulderLayer extends RenderLayer> { + private final LeftSittingHamsterModel model; + public static final ModelLayerLocation HAMSTER_LAYER = new ModelLayerLocation(new ResourceLocation(Hamsters.MOD_ID, "left_sitting_hamster"), "main"); + + public PlayerHamsterOnRightShoulderLayer(RenderLayerParent> renderLayerParent, EntityModelSet entityModelSet) { + super(renderLayerParent); + this.model = new LeftSittingHamsterModel<>(entityModelSet.bakeLayer(HAMSTER_LAYER)); + } + + public void render(PoseStack poseStack, MultiBufferSource multiBufferSource, int i, T player, float f, float g, float h, float j, float k, float l) { + this.render(poseStack, multiBufferSource, i, player, f, g, k, l, true); + } + + private void render(PoseStack poseStack, MultiBufferSource multiBufferSource, int i, T player, float f, float g, float h, float j, boolean bl) { + CompoundTag compoundTag = bl ? player.getShoulderEntityLeft() : player.getShoulderEntityRight(); + EntityType.byString(compoundTag.getString("id")).filter((entityType) -> entityType == HamstersEntityType.HAMSTER).ifPresent((entityType) -> { + poseStack.pushPose(); + poseStack.scale(1.0F, 1.0F, 1.0F); + poseStack.translate(-0.425F, player.isCrouching() ? 0.2F : 0.0F, 0.25F); + HamsterNew.Variant variant = HamsterNew.Variant.getTypeById(compoundTag.getInt("Variant")); +// HamsterNew.Marking marking = HamsterNew.Marking.byId(compoundTag.getInt("Marking")); + VertexConsumer vertexConsumer = multiBufferSource.getBuffer(this.model.renderType(HamsterModel.getVariantTexture2(variant))); + this.model.renderOnShoulder(poseStack, vertexConsumer, i, OverlayTexture.NO_OVERLAY, f, g, h, j, player.tickCount); + poseStack.popPose(); + }); + } +} diff --git a/src/main/java/com/starfish_studios/hamsters/entity/Hamster.java b/src/main/java/com/starfish_studios/hamsters/entity/Hamster.java index 5d2d3db..9ef9539 100644 --- a/src/main/java/com/starfish_studios/hamsters/entity/Hamster.java +++ b/src/main/java/com/starfish_studios/hamsters/entity/Hamster.java @@ -402,6 +402,7 @@ public String getName() { } + public enum Variant { WHITE (0, "white"), CREAM (1, "cream"), diff --git a/src/main/java/com/starfish_studios/hamsters/entity/HamsterNew.java b/src/main/java/com/starfish_studios/hamsters/entity/HamsterNew.java index 6a19c59..6bfcd98 100644 --- a/src/main/java/com/starfish_studios/hamsters/entity/HamsterNew.java +++ b/src/main/java/com/starfish_studios/hamsters/entity/HamsterNew.java @@ -1,46 +1,44 @@ package com.starfish_studios.hamsters.entity; import com.google.common.collect.Lists; -import com.starfish_studios.hamsters.block.HamsterWheelBlock; -import com.starfish_studios.hamsters.block.entity.HamsterWheelBlockEntity; import com.starfish_studios.hamsters.entity.common.MMPathNavigatorGround; -import com.starfish_studios.hamsters.entity.common.SearchForItemsGoal; import com.starfish_studios.hamsters.entity.common.SmartBodyHelper; import com.starfish_studios.hamsters.registry.HamstersEntityType; -import com.starfish_studios.hamsters.registry.HamstersPoiTypes; +import com.starfish_studios.hamsters.registry.HamstersSoundEvents; import com.starfish_studios.hamsters.registry.HamstersTags; +import net.minecraft.Util; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.particle.FireworkParticles; import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.ParticleTypes; import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtUtils; +import net.minecraft.nbt.ListTag; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.server.level.ServerLevel; -import net.minecraft.tags.BlockTags; -import net.minecraft.tags.ItemTags; -import net.minecraft.tags.PoiTypeTags; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; import net.minecraft.util.ByIdMap; import net.minecraft.util.RandomSource; -import net.minecraft.util.VisibleForDebug; import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.*; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.ai.control.BodyRotationControl; import net.minecraft.world.entity.ai.goal.*; import net.minecraft.world.entity.ai.navigation.PathNavigation; -import net.minecraft.world.entity.ai.util.AirRandomPos; -import net.minecraft.world.entity.ai.village.poi.PoiManager; -import net.minecraft.world.entity.ai.village.poi.PoiRecord; -import net.minecraft.world.entity.animal.Bee; +import net.minecraft.world.entity.animal.ShoulderRidingEntity; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; +import net.minecraft.world.entity.projectile.FireworkRocketEntity; +import net.minecraft.world.item.*; +import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BeehiveBlockEntity; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.pathfinder.Path; import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -55,24 +53,31 @@ import java.util.*; import java.util.function.IntFunction; -import java.util.stream.Collectors; -import java.util.stream.Stream; -public class HamsterNew extends TamableAnimal implements GeoEntity { +public class HamsterNew extends ShoulderRidingEntity implements GeoEntity { + // region VARIABLES private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this); protected static final RawAnimation IDLE = RawAnimation.begin().thenLoop("animation.sf_nba.hamster.idle"); protected static final RawAnimation WALK = RawAnimation.begin().thenLoop("animation.sf_nba.hamster.walk"); + protected static final RawAnimation PINKIE_WALK = RawAnimation.begin().thenLoop("animation.sf_nba.hamster.pinkie_walk"); protected static final RawAnimation RUN = RawAnimation.begin().thenLoop("animation.sf_nba.hamster.run"); protected static final RawAnimation SLEEP = RawAnimation.begin().thenLoop("animation.sf_nba.hamster.sleep"); protected static final RawAnimation STANDING = RawAnimation.begin().thenLoop("animation.sf_nba.hamster.standing"); private static final EntityDataAccessor VARIANT = SynchedEntityData.defineId(HamsterNew.class, EntityDataSerializers.INT); private static final EntityDataAccessor MARKING = SynchedEntityData.defineId(HamsterNew.class, EntityDataSerializers.INT); + private static final EntityDataAccessor DATA_BOW_COLOR = SynchedEntityData.defineId(HamsterNew.class, EntityDataSerializers.INT); + private static final EntityDataAccessor CHEEK_LEVEL = SynchedEntityData.defineId(HamsterNew.class, EntityDataSerializers.INT); - public HamsterNew(EntityType entityType, Level level) { + private static final Ingredient FOOD_ITEMS = Ingredient.of(HamstersTags.HAMSTER_FOOD); + + + // endregion + + public HamsterNew(EntityType entityType, Level level) { super(entityType, level); } - + @Override protected @NotNull PathNavigation createNavigation(@NotNull Level level) { return new MMPathNavigatorGround(this, level); @@ -88,12 +93,12 @@ protected void registerGoals() { this.goalSelector.addGoal(1, new PanicGoal(this, 1.3)); this.goalSelector.addGoal(2, new SitWhenOrderedToGoal(this)); this.goalSelector.addGoal(3, new BreedGoal(this, 1.0)); -// this.goalSelector.addGoal(4, new HamsterEnterWheelGoal()); -// this.goalSelector.addGoal(5, new HamsterLocateWheelGoal()); -// this.goalSelector.addGoal(5, new HamsterGoToWheelGoal()); + this.goalSelector.addGoal(5, new TemptGoal(this, 1.0, FOOD_ITEMS, false)); this.goalSelector.addGoal(6, new WaterAvoidingRandomStrollGoal(this, 1.0)); this.goalSelector.addGoal(7, new LookAtPlayerGoal(this, Player.class, 6.0F)); this.goalSelector.addGoal(9, new RandomLookAroundGoal(this)); + this.goalSelector.addGoal(10, new GetOnOwnersShoulderGoal(this)); + } public static AttributeSupplier.Builder createAttributes() { @@ -102,22 +107,237 @@ public static AttributeSupplier.Builder createAttributes() { .add(Attributes.MOVEMENT_SPEED, 0.25D); } + public boolean isFood(ItemStack itemStack) { + return itemStack.is(HamstersTags.HAMSTER_FOOD); + } + @Override + public void aiStep() { + super.aiStep(); + + if (this.level().isClientSide) { + if (this.getCheekLevel() == 2) { + if (this.tickCount % 10 == 0) { + this.level().addParticle(ParticleTypes.SPLASH, this.getX(), this.getY(1.2), this.getZ(), 0.0D, 0.2D, 0.0D); + this.playSound(HamstersSoundEvents.HAMSTER_BEG, 1.0F, 1.0F); + } + } else if (this.getCheekLevel() == 3) { + if (this.tickCount % 5 == 0) { + this.level().addParticle(ParticleTypes.SPLASH, this.getX(), this.getY(1.2), this.getZ(), 0.0D, 0.2D, 0.0D); + } + } + } + + if (!this.level().isClientSide && this.isAlive() && this.getCheekLevel() >= 2 && this.tickCount % (80 - (this.getCheekLevel() * 10)) == 0) { + this.playSound(HamstersSoundEvents.HAMSTER_BEG, 1.0F, 1.0F); + } + } + + private ItemStack getFirework(DyeColor dyeColor, int i) { + ItemStack itemStack = new ItemStack(Items.FIREWORK_ROCKET, 1); + ItemStack itemStack2 = new ItemStack(Items.FIREWORK_STAR); + CompoundTag compoundTag = itemStack2.getOrCreateTagElement("Explosion"); + List list = Lists.newArrayList(); + // Red + list.add(16711680); + // Orange + list.add(16753920); + // Yellow + list.add(16776960); + // Green + list.add(65280); + // Blue + list.add(255); + // Purple + list.add(16711935); + compoundTag.putIntArray("Colors", list); + compoundTag.putByte("Type", (byte) FireworkRocketItem.Shape.SMALL_BALL.getId()); + CompoundTag compoundTag2 = itemStack.getOrCreateTagElement("Fireworks"); + ListTag listTag = new ListTag(); + CompoundTag compoundTag3 = itemStack2.getTagElement("Explosion"); + if (compoundTag3 != null) { + listTag.add(compoundTag3); + } + CompoundTag compoundTag4 = itemStack2.getOrCreateTagElement("LifeTime"); + compoundTag4.putInt("LifeTime", 0); + + compoundTag2.putInt("Flight", -128); + if (!listTag.isEmpty()) { + compoundTag2.put("Explosions", listTag); + compoundTag4.putInt("LifeTime", 0); + } + return itemStack; + } + + + public InteractionResult mobInteract(Player player, InteractionHand interactionHand) { + ItemStack itemStack = player.getItemInHand(interactionHand); + Item item = itemStack.getItem(); + + RandomSource randomSource = this.getRandom(); + + if (this.level().isClientSide) { + boolean bl = this.isOwnedBy(player) || this.isTame() || itemStack.is(Items.BONE) && !this.isTame(); + return bl ? InteractionResult.CONSUME : InteractionResult.PASS; + } else { + if (this.isFood(itemStack)) { + if (this.getCheekLevel() < 3) { + if (player.getCooldowns().isOnCooldown(itemStack.getItem())) { + return InteractionResult.FAIL; + } + this.setCheekLevel(this.getCheekLevel() + 1); + this.level().playSound(null, this.getX(), this.getY(), this.getZ(), SoundEvents.PARROT_EAT, SoundSource.NEUTRAL, 1.0F, 1.0F); + player.getCooldowns().addCooldown(itemStack.getItem(), 20); + } else if (this.getCheekLevel() >= 3) { + if (player.getCooldowns().isOnCooldown(itemStack.getItem())) { + return InteractionResult.FAIL; + } + this.remove(RemovalReason.KILLED); + this.playSound(HamstersSoundEvents.HAMSTER_ExPLODE, 1.0F, 1.0F); + + DyeColor dyeColor = Util.getRandom(DyeColor.values(), randomSource); + int i = randomSource.nextInt(3); + ItemStack fireworkStack = this.getFirework(dyeColor, i); + FireworkRocketEntity fireworkRocketEntity = new FireworkRocketEntity(this.level(), this, this.getX(), this.getEyeY(), this.getZ(), fireworkStack); + fireworkRocketEntity.setSilent(true); + fireworkRocketEntity.setInvisible(true); + this.level().addFreshEntity(fireworkRocketEntity); + + fireworkRocketEntity.setDeltaMovement(0, 0, 0); + + + + + if (this.level() instanceof ServerLevel serverLevel) { +// serverLevel.sendParticles(ParticleTypes.EXPLOSION, this.getX(), this.getY(), this.getZ(), 1, 0.0D, 0.0D, 0.0D, 0.0D); + } + this.level().playSound(null, this.getX(), this.getY(), this.getZ(), SoundEvents.FIREWORK_ROCKET_BLAST, SoundSource.NEUTRAL, 1.0F, 1.0F); + } + return InteractionResult.SUCCESS; + } + + label90: { + if (this.isTame()) { + if (this.isFood(itemStack) && this.getHealth() < this.getMaxHealth()) { + if (!player.getAbilities().instabuild) { + itemStack.shrink(1); + } + + this.heal((float)item.getFoodProperties().getNutrition()); + return InteractionResult.SUCCESS; + } + + if (!(item instanceof DyeItem)) { + break label90; + } + + DyeItem dyeItem = (DyeItem)item; + if (!this.isOwnedBy(player)) { + break label90; + } + + DyeColor dyeColor = dyeItem.getDyeColor(); + if (dyeColor != this.getCollarColor()) { + this.setCollarColor(dyeColor); + if (!player.getAbilities().instabuild) { + itemStack.shrink(1); + } + + return InteractionResult.SUCCESS; + } + } else if (itemStack.is(Items.BONE)) { + if (!player.getAbilities().instabuild) { + itemStack.shrink(1); + } + + if (this.random.nextInt(3) == 0) { + this.tame(player); + this.navigation.stop(); + this.setTarget(null); + this.setOrderedToSit(true); + this.level().broadcastEntityEvent(this, (byte)7); + } else { + this.level().broadcastEntityEvent(this, (byte)6); + } + + return InteractionResult.SUCCESS; + } + + return super.mobInteract(player, interactionHand); + } + + InteractionResult interactionResult = super.mobInteract(player, interactionHand); + if ((!interactionResult.consumesAction() || this.isBaby()) && this.isOwnedBy(player)) { + this.setOrderedToSit(!this.isOrderedToSit()); + this.jumping = false; + this.navigation.stop(); + this.setTarget(null); + return InteractionResult.SUCCESS; + } else { + return interactionResult; + } + } + } + + + // Spawns a "Wild" HamsterNew with no markings. These cannot be obtained from breeding. @Override public SpawnGroupData finalizeSpawn(ServerLevelAccessor pLevel, DifficultyInstance pDifficulty, MobSpawnType pReason, @Nullable SpawnGroupData pSpawnData, @Nullable CompoundTag pDataTag) { this.populateDefaultEquipmentSlots(random, pDifficulty); if (pSpawnData == null) { - RandomSource randomSource = pLevel.getRandom(); - this.setVariant(HamsterNew.Variant.values()[randomSource.nextInt(HamsterNew.Variant.values().length)]); - this.setMarking(HamsterNew.Marking.values()[randomSource.nextInt(HamsterNew.Marking.values().length)].getId()); +// this.setVariant(HamsterNew.Variant.WILD); +// this.setMarking(HamsterNew.Marking.BLANK.getId()); + // Make them have any variant except for wild + this.setVariant(Variant.BY_ID[this.random.nextInt(Variant.BY_ID.length - 1)]); + // Give them random variants + this.setMarking(this.random.nextInt(Marking.values().length)); } return pSpawnData; } - @Nullable @Override public AgeableMob getBreedOffspring(@NotNull ServerLevel serverLevel, @NotNull AgeableMob ageableMob) { - return new HamsterNew(HamstersEntityType.HAMSTER, serverLevel); + HamsterNew hamster = HamstersEntityType.HAMSTER_NEW.create(serverLevel); + assert hamster != null; + // If both parents are Wild variant with no markings, the offspring will have a random color and marking. + if (ageableMob instanceof HamsterNew hamsterParent && hamsterParent.getVariant() == Variant.WILD.getId() && hamsterParent.getMarking() == Marking.BLANK.getId()) { + hamster.setVariant(Variant.BY_ID[this.random.nextInt(Variant.BY_ID.length)]); + hamster.setMarking(Marking.byId(this.random.nextInt(Marking.values().length)).getId()); + } + + // If one parent is Wild, and one parent has color/marking, the offspring will have a 50% chance + // of a random color/marking or will have the same as the parent with color/marking. + else if (ageableMob instanceof HamsterNew hamsterParent) { + if (hamsterParent.getVariant() == Variant.WILD.getId() && hamsterParent.getMarking() == Marking.BLANK.getId()) { + hamster.setVariant(Variant.BY_ID[this.random.nextInt(Variant.BY_ID.length)]); + hamster.setMarking(Marking.byId(this.random.nextInt(Marking.values().length)).getId()); + } else { + hamster.setVariant(Variant.getTypeById(hamsterParent.getVariant())); + hamster.setMarking(hamsterParent.getMarking()); + } + } + + // If neither parent is Wild, and they have their own color and marking, the offspring will pick a color + // and marking from one of the parents. + else if (ageableMob instanceof HamsterNew hamsterParent) { + hamster.setVariant(this.getOffspringVariant(this, hamsterParent)); + hamster.setMarking(this.getOffspringPattern(this, hamsterParent).getId()); + } + return hamster; + } + + private Marking getOffspringPattern(HamsterNew hamster, HamsterNew otherParent) { + Marking marking = Marking.byId(hamster.getMarking()); + Marking otherMarking = Marking.byId(otherParent.getMarking()); + + return this.random.nextBoolean() ? marking : otherMarking; + } + + private Variant getOffspringVariant(HamsterNew hamster, HamsterNew otherParent) { + Variant variant = Variant.getTypeById(hamster.getVariant()); + Variant otherVariant = Variant.getTypeById(otherParent.getVariant()); + + return this.random.nextBoolean() ? variant : otherVariant; } void pathfindTowards(BlockPos blockPos) { @@ -133,13 +353,16 @@ protected void defineSynchedData() { super.defineSynchedData(); this.entityData.define(VARIANT, 2); this.entityData.define(MARKING, 0); + this.entityData.define(DATA_BOW_COLOR, 0); + this.entityData.define(CHEEK_LEVEL, 0); } @Override public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { super.readAdditionalSaveData(compoundTag); - this.setVariant(HamsterNew.Variant.BY_ID[compoundTag.getInt("Variant")]); + this.setVariant(Variant.BY_ID[compoundTag.getInt("Variant")]); this.setMarking(compoundTag.getInt("Marking")); + this.setCheekLevel(compoundTag.getInt("CheekLevel")); } @Override @@ -147,6 +370,16 @@ public void addAdditionalSaveData(@NotNull CompoundTag compoundTag) { super.addAdditionalSaveData(compoundTag); compoundTag.putInt("Variant", this.getVariant()); compoundTag.putInt("Marking", this.getMarking()); + compoundTag.putInt("CheekLevel", this.getCheekLevel()); + } + + + public DyeColor getCollarColor() { + return DyeColor.byId(this.entityData.get(DATA_BOW_COLOR)); + } + + public void setCollarColor(DyeColor dyeColor) { + this.entityData.set(DATA_BOW_COLOR, dyeColor.getId()); } boolean closerThan(BlockPos blockPos, int i) { @@ -170,10 +403,18 @@ public int getVariant() { return this.entityData.get(VARIANT); } - public void setVariant(HamsterNew.Variant variant) { + public void setVariant(Variant variant) { this.entityData.set(VARIANT, variant.getId()); } + public int getCheekLevel() { + return this.entityData.get(CHEEK_LEVEL); + } + + public void setCheekLevel(int cheekLevel) { + this.entityData.set(CHEEK_LEVEL, cheekLevel); + } + public enum Marking { BLANK (0, "blank"), BANDED (1, "banded"), @@ -181,7 +422,7 @@ public enum Marking { ROAN (3, "roan"), BELLY (4, "belly"); - private static final IntFunction BY_ID = ByIdMap.continuous(HamsterNew.Marking::getId, values(), ByIdMap.OutOfBoundsStrategy.ZERO); + private static final IntFunction BY_ID = ByIdMap.continuous(Marking::getId, values(), ByIdMap.OutOfBoundsStrategy.ZERO); private final int id; private final String name; @@ -195,7 +436,7 @@ public int getId() { return this.id; } - public static HamsterNew.Marking byId(int i) { + public static Marking byId(int i) { return BY_ID.apply(i); } @@ -212,9 +453,10 @@ public enum Variant { SILVER_DOVE (3, "silver_dove"), DOVE (4, "dove"), CHOCOLATE (5, "chocolate"), - BLACK (6, "black"); + BLACK (6, "black"), + WILD (7, "wild"); - public static final HamsterNew.Variant[] BY_ID = Arrays.stream(values()).sorted(Comparator.comparingInt(HamsterNew.Variant::getId)).toArray(HamsterNew.Variant[]::new); + public static final Variant[] BY_ID = Arrays.stream(values()).sorted(Comparator.comparingInt(Variant::getId)).toArray(Variant[]::new); private final int id; private final String name; @@ -231,11 +473,11 @@ public String getName() { return this.name; } - public static HamsterNew.Variant getTypeById(int id) { - for (HamsterNew.Variant type : values()) { + public static Variant getTypeById(int id) { + for (Variant type : values()) { if (type.id == id) return type; } - return HamsterNew.Variant.CHAMPAGNE; + return Variant.CHAMPAGNE; } } @@ -258,8 +500,13 @@ protected PlayState animController(final AnimationState> { + public PlayerRendererMixin(EntityRendererProvider.Context context, PlayerModel entityModel, float f) { + super(context, entityModel, f); + } + + @Inject(method = "", at = @At("RETURN")) + private void onInit(EntityRendererProvider.Context context, boolean bl, CallbackInfo ci) { + this.addLayer(new PlayerHamsterOnLeftShoulderLayer<>(this, context.getModelSet())); + this.addLayer(new PlayerHamsterOnRightShoulderLayer<>(this, context.getModelSet())); + } +} \ No newline at end of file diff --git a/src/main/java/com/starfish_studios/hamsters/registry/HamstersSoundEvents.java b/src/main/java/com/starfish_studios/hamsters/registry/HamstersSoundEvents.java index c2348c0..eed5de7 100644 --- a/src/main/java/com/starfish_studios/hamsters/registry/HamstersSoundEvents.java +++ b/src/main/java/com/starfish_studios/hamsters/registry/HamstersSoundEvents.java @@ -17,6 +17,7 @@ public interface HamstersSoundEvents { SoundEvent HAMSTER_BEG = register("entity.hamster.beg"); SoundEvent HAMSTER_SLEEP = register("entity.hamster.sleep"); + SoundEvent HAMSTER_ExPLODE = register("entity.hamster.explode"); private static SoundType register(String name, float volume, float pitch) { return new SoundType(volume, pitch, register("block." + name + ".break"), register("block." + name + ".step"), register("block." + name + ".place"), register("block." + name + ".hit"), register("block." + name + ".fall")); diff --git a/src/main/resources/assets/hamsters/geo/entity/hamster.geo.json b/src/main/resources/assets/hamsters/geo/entity/hamster.geo.json index 1147dce..4aa9173 100644 --- a/src/main/resources/assets/hamsters/geo/entity/hamster.geo.json +++ b/src/main/resources/assets/hamsters/geo/entity/hamster.geo.json @@ -20,7 +20,8 @@ "parent": "root", "pivot": [0, 1.5, 3], "cubes": [ - {"origin": [-3, 0.5, -2], "size": [6, 4, 6], "inflate": 0.01, "uv": [0, 0]} + {"origin": [-3, 0.5, -2], "size": [6, 4, 6], "inflate": 0.01, "uv": [0, 0]}, + {"origin": [-4, 0.5, 2], "size": [8, 5, 0], "inflate": 0.01, "uv": [2, 26]} ] }, { @@ -41,7 +42,8 @@ "parent": "head", "pivot": [0, 2, -2], "cubes": [ - {"origin": [-2.5, 2, -4], "size": [5, 4, 4], "uv": [1, 11]} + {"origin": [-2.5, 2, -4], "size": [5, 4, 4], "uv": [1, 11]}, + {"origin": [0, 5, -5], "size": [0, 4, 4], "uv": [23, 16]} ] }, { @@ -63,9 +65,21 @@ { "name": "cheeks", "parent": "head", - "pivot": [-4.5, 3.5, -2], + "pivot": [0, 3.5, -2.5] + }, + { + "name": "leftCheek", + "parent": "cheeks", + "pivot": [2.5, 3.5, -2.5], + "cubes": [ + {"origin": [2.5, 2, -4], "size": [2, 3, 3], "uv": [20, 13]} + ] + }, + { + "name": "rightCheek", + "parent": "cheeks", + "pivot": [-2.5, 3.5, -2.5], "cubes": [ - {"origin": [2.5, 2, -4], "size": [2, 3, 3], "uv": [20, 13]}, {"origin": [-4.5, 2, -4], "size": [2, 3, 3], "uv": [20, 13], "mirror": true} ] }, diff --git a/src/main/resources/assets/hamsters/lang/en_us.json b/src/main/resources/assets/hamsters/lang/en_us.json index b48bd04..315f64e 100644 --- a/src/main/resources/assets/hamsters/lang/en_us.json +++ b/src/main/resources/assets/hamsters/lang/en_us.json @@ -86,6 +86,7 @@ "hamsters.subtitles.hamster.hurt": "Hamster hurts", "hamsters.subtitles.hamster.death": "Hamster dies", "hamsters.subtitles.hamster.beg": "Hamster begs", + "hamsters.subtitles.hamster.explode": "Hamster explodes", "tooltip.hamsters.white": "White", "tooltip.hamsters.peaches_and_cream": "Peaches and Cream", diff --git a/src/main/resources/assets/hamsters/sounds.json b/src/main/resources/assets/hamsters/sounds.json index 38de299..33ce9a5 100644 --- a/src/main/resources/assets/hamsters/sounds.json +++ b/src/main/resources/assets/hamsters/sounds.json @@ -46,5 +46,11 @@ "hamsters:entity/hamster/standing4" ], "subtitle": "hamsters.subtitles.hamster.beg" + }, + "entity.hamster.explode": { + "sounds": [ + "hamsters:yay" + ], + "subtitle": "hamsters.subtitles.hamster.explode" } } \ No newline at end of file diff --git a/src/main/resources/assets/hamsters/sounds/yay.ogg b/src/main/resources/assets/hamsters/sounds/yay.ogg new file mode 100644 index 0000000000000000000000000000000000000000..82c8a22449b8c6b96aa24be93bb8f77c0bff69eb GIT binary patch literal 47249 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

X|kmzVeAXC=k2>>b#r3YP~|(T`VJB7WLGAz|bj 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


F|amq>sq9{##;k9-4imLWw7LFFcLp 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/hamsters/textures/entity/hamster/wild.png b/src/main/resources/assets/hamsters/textures/entity/hamster/wild.png new file mode 100644 index 0000000000000000000000000000000000000000..2c7119a86dadcf7126972e1798cc01896907fd2e GIT binary patch literal 813 zcmV+|1JeA7P)Px%=Sf6CR9J=WmcdIKQ4q#|D=9V5B1jjJ)<{8;Xo$9{H$jS?B)JvDLj4bVC=@KT zheE-Ff?&aaptPW;LLnhHDWScUfZCX(B!*_xJj6Yq|y!Lf?IdhdJ%Nc{^ zj6tr_wDx$*xSP!mJsd?3N7>oir~lSX)9!QI;MDW8bl`-{(u~l< zQS&}JJ&94+GPUALfL3W`b|Kw=?%RVd@yR`Qd%4;$r^5|C zbz?ez%(I6vhNX9X(cLUeyrW+8=zK73V_WI@4)3?a#hc175tWJ^oB;v^+9pNJ2jx| zMxTvzJ7EnVJ{lC*O0UkaI!@}x$*vRofh1}h0-*3Y3BX|dMOy{T!$|g727dfDYq`eJQq)RGp&rpb8C(XQoOwWRXoTml z;VAu)M=xJNtK>#utMy!iT&3xFJ{W~9^l;Q{QEzC3`r)qWx3|u697}P@hptcEx7@2j zbea^EggxLval>4z{{Oge$O)T^4+;54SK7QFT0i^x+!*NZ6KcTtXiyCF_x<$y{^R0d r@7JXTmI^(u@9%+Exi7U9{~W#pI{Q^Zs%;8Y00000NkvXXu0mjfH|&dD literal 0 HcmV?d00001 diff --git a/src/main/resources/hamsters.mixins.json b/src/main/resources/hamsters.mixins.json index 354fff3..beab755 100644 --- a/src/main/resources/hamsters.mixins.json +++ b/src/main/resources/hamsters.mixins.json @@ -7,5 +7,8 @@ ], "injectors": { "defaultRequire": 1 - } + }, + "client": [ + "PlayerRendererMixin" + ] } \ No newline at end of file