diff --git a/rainbow/src/main/java/org/geysermc/rainbow/mapping/animation/AnimationMapper.java b/rainbow/src/main/java/org/geysermc/rainbow/mapping/animation/AnimationMapper.java index 30a641d..2857e03 100644 --- a/rainbow/src/main/java/org/geysermc/rainbow/mapping/animation/AnimationMapper.java +++ b/rainbow/src/main/java/org/geysermc/rainbow/mapping/animation/AnimationMapper.java @@ -11,7 +11,7 @@ public class AnimationMapper { private static final Vector3fc FIRST_PERSON_POSITION_OFFSET = new Vector3f(-7.0F, 22.5F, -7.0F); private static final Vector3fc FIRST_PERSON_ROTATION_OFFSET = new Vector3f(-22.5F, 50.0F, -32.5F); - // These transformations perfect... but I spent over 3 hours trying to get these. It's good enough for me. + // These transformations aren't perfect... but I spent over 4 hours trying to get these. It's good enough for me. public static BedrockAnimationContext mapAnimation(String identifier, String bone, ItemTransforms transforms) { // I don't think it's possible to display separate animations for left- and right hands ItemTransform firstPerson = transforms.firstPersonRightHand(); @@ -26,6 +26,18 @@ public class AnimationMapper { Vector3f thirdPersonRotation = new Vector3f(-thirdPerson.rotation().x() + 90.0F, -thirdPerson.rotation().y(), 0.0F); Vector3f thirdPersonScale = new Vector3f(thirdPerson.scale()); + // Head translation + scale is scaled by around 0.655 (not perfect but close enough) + ItemTransform head = transforms.head(); + // Add a base translation of 20 on the Y axis as bedrock displays the item at the player's feet + // Translation is inverted on the X axis + Vector3f headPosition = head.translation().mul(-0.655F, 0.655F, 0.655F, new Vector3f()).add(0.0F, 20.0F, 0.0F); + // Rotation is inverted on the X and Y axis + Vector3f headRotation = new Vector3f(-head.rotation().x(), -head.rotation().y(), head.rotation().z()); + Vector3f headScale = head.scale().mul(0.655F, new Vector3f()); + + // Note that for items marked as equippable, the 3D model only shows up when having the item equipped on the head, and the icon is used when holding the item in hand + // Interestingly when an item is NOT marked equippable (so the player can't equip it normally), the 3D model does show up properly both in hand and on head + // I think this is a bedrock bug and not something we can fix return new BedrockAnimationContext(BedrockAnimation.builder() .withAnimation(identifier + ".hold_first_person", BedrockAnimation.animation() .withLoopMode(BedrockAnimation.LoopMode.LOOP) @@ -33,6 +45,9 @@ public class AnimationMapper { .withAnimation(identifier + ".hold_third_person", BedrockAnimation.animation() .withLoopMode(BedrockAnimation.LoopMode.LOOP) .withBone(bone, thirdPersonPosition, thirdPersonRotation, thirdPersonScale)) - .build(), "animation." + identifier + ".hold_first_person", "animation." + identifier + ".hold_third_person"); + .withAnimation(identifier + ".head", BedrockAnimation.animation() + .withLoopMode(BedrockAnimation.LoopMode.LOOP) + .withBone(bone, headPosition, headRotation, headScale)) + .build(), "animation." + identifier + ".hold_first_person", "animation." + identifier + ".hold_third_person", identifier + ".head"); } } diff --git a/rainbow/src/main/java/org/geysermc/rainbow/mapping/animation/BedrockAnimationContext.java b/rainbow/src/main/java/org/geysermc/rainbow/mapping/animation/BedrockAnimationContext.java index 553836c..e98fb3a 100644 --- a/rainbow/src/main/java/org/geysermc/rainbow/mapping/animation/BedrockAnimationContext.java +++ b/rainbow/src/main/java/org/geysermc/rainbow/mapping/animation/BedrockAnimationContext.java @@ -2,5 +2,5 @@ package org.geysermc.rainbow.mapping.animation; import org.geysermc.rainbow.pack.animation.BedrockAnimation; -public record BedrockAnimationContext(BedrockAnimation animation, String firstPerson, String thirdPerson) { +public record BedrockAnimationContext(BedrockAnimation animation, String firstPerson, String thirdPerson, String head) { } diff --git a/rainbow/src/main/java/org/geysermc/rainbow/mapping/attachable/AttachableMapper.java b/rainbow/src/main/java/org/geysermc/rainbow/mapping/attachable/AttachableMapper.java index adc493a..57f8ce7 100644 --- a/rainbow/src/main/java/org/geysermc/rainbow/mapping/attachable/AttachableMapper.java +++ b/rainbow/src/main/java/org/geysermc/rainbow/mapping/attachable/AttachableMapper.java @@ -41,8 +41,10 @@ public class AttachableMapper { geometryContext.animation().ifPresent(animation -> { attachable.withAnimation("first_person", animation.firstPerson()); attachable.withAnimation("third_person", animation.thirdPerson()); + attachable.withAnimation("head", animation.head()); attachable.withScript("animate", "first_person", "context.is_first_person == 1.0"); - attachable.withScript("animate", "third_person", "context.is_first_person == 0.0"); + attachable.withScript("animate", "third_person", "context.is_first_person == 0.0 && context.item_slot != 'head'"); + attachable.withScript("animate", "head", "context.is_first_person == 0.0 && context.item_slot == 'head'"); }); return attachable.build(); });