1
0
mirror of https://github.com/GeyserMC/Rainbow.git synced 2025-12-19 14:59:16 +00:00

Head animations, seems to work decently?

This commit is contained in:
Eclipse
2025-10-19 09:43:41 +00:00
parent 2724b4811f
commit f154eadc43
3 changed files with 21 additions and 4 deletions

View File

@@ -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");
}
}

View File

@@ -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) {
}

View File

@@ -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();
});