feat(animation): add FullHead convention — opt-in head animation in Full animations

FullStruggle, FullWalk etc. animate body+legs but preserve head tracking.
FullHeadStruggle, FullHeadWalk etc. also animate the head.
The 'Head' keyword in the animation name is the opt-in signal.
This commit is contained in:
NotEvil
2026-04-17 03:01:43 +02:00
parent 3d57d83a5b
commit 806a1e732d

View File

@@ -584,6 +584,10 @@ public final class GltfPoseConverter {
// The "gltf_" prefix is added by convertClipSelective, so check for "gltf_Full"
boolean isFullBodyAnimation = animName != null &&
animName.startsWith("gltf_Full");
// Head is protected by default — only enabled as a free bone when the animation
// name contains "Head" (e.g., FullHeadStruggle, FullHeadIdle).
// This lets artists opt-in per animation without affecting the item's regions.
boolean allowFreeHead = isFullBodyAnimation && animName.contains("Head");
String[] allParts = {
"head",
@@ -606,14 +610,14 @@ public final class GltfPoseConverter {
isFullBodyAnimation &&
enabledParts.contains(partName) &&
partsWithKeyframes.contains(partName) &&
!"head".equals(partName)
(!"head".equals(partName) || allowFreeHead)
) {
// Full-body animation: free part WITH keyframes — enable.
// The "Full" prefix is the artist's explicit opt-in to animate
// bones outside their declared regions.
// EXCEPTION: head is never enabled as a free bone — vanilla head
// tracking (mouse look) is always preserved unless the item
// explicitly owns a head region (HEAD, EYES, EARS, MOUTH).
// Head is protected by default (preserves vanilla head tracking).
// Use "Head" in the animation name (e.g., FullHeadStruggle) to
// explicitly opt-in to head control for that animation.
part.fullyEnablePart(false);
} else {
// Non-Full animation, other item's part, or free part without keyframes.