fix(anim): Phase L.1b route motion commands
This commit is contained in:
parent
1c69670392
commit
460f95cb42
6 changed files with 218 additions and 53 deletions
97
src/AcDream.Core/Physics/AnimationCommandRouter.cs
Normal file
97
src/AcDream.Core/Physics/AnimationCommandRouter.cs
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
namespace AcDream.Core.Physics;
|
||||
|
||||
/// <summary>
|
||||
/// Central routing for full retail MotionCommand values after the wire's
|
||||
/// 16-bit command id has been reconstructed.
|
||||
///
|
||||
/// Retail/ACE split motion commands by class mask:
|
||||
/// - Action and ChatEmote commands play through link/action data.
|
||||
/// - Modifier commands play through modifier data.
|
||||
/// - SubState commands become the new cyclic state.
|
||||
/// - Style/UI/Toggle commands do not directly drive an animation overlay here.
|
||||
///
|
||||
/// References:
|
||||
/// CMotionTable::GetObjectSequence 0x00522860,
|
||||
/// CMotionInterp::DoInterpretedMotion 0x00528360,
|
||||
/// ACE MotionTable.GetObjectSequence, and
|
||||
/// docs/research/deepdives/r03-motion-animation.md section 3.
|
||||
/// </summary>
|
||||
public static class AnimationCommandRouter
|
||||
{
|
||||
private const uint ActionMask = 0x10000000u;
|
||||
private const uint ModifierMask = 0x20000000u;
|
||||
private const uint SubStateMask = 0x40000000u;
|
||||
private const uint ClassMask = 0xFF000000u;
|
||||
|
||||
/// <summary>
|
||||
/// Classifies a reconstructed full MotionCommand.
|
||||
/// </summary>
|
||||
public static AnimationCommandRouteKind Classify(uint fullCommand)
|
||||
{
|
||||
if (fullCommand == 0)
|
||||
return AnimationCommandRouteKind.None;
|
||||
|
||||
uint cls = fullCommand & ClassMask;
|
||||
if (cls == 0x12000000u || cls == 0x13000000u)
|
||||
return AnimationCommandRouteKind.ChatEmote;
|
||||
|
||||
if ((fullCommand & ModifierMask) != 0)
|
||||
return AnimationCommandRouteKind.Modifier;
|
||||
|
||||
if ((fullCommand & ActionMask) != 0)
|
||||
return AnimationCommandRouteKind.Action;
|
||||
|
||||
if ((fullCommand & SubStateMask) != 0)
|
||||
return AnimationCommandRouteKind.SubState;
|
||||
|
||||
return AnimationCommandRouteKind.Ignored;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reconstructs and routes a 16-bit wire command.
|
||||
/// </summary>
|
||||
public static AnimationCommandRouteKind RouteWireCommand(
|
||||
AnimationSequencer sequencer,
|
||||
uint currentStyle,
|
||||
ushort wireCommand,
|
||||
float speedMod = 1f)
|
||||
{
|
||||
uint fullCommand = MotionCommandResolver.ReconstructFullCommand(wireCommand);
|
||||
return RouteFullCommand(sequencer, currentStyle, fullCommand, speedMod);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Routes a full MotionCommand to the matching sequencer API.
|
||||
/// </summary>
|
||||
public static AnimationCommandRouteKind RouteFullCommand(
|
||||
AnimationSequencer sequencer,
|
||||
uint currentStyle,
|
||||
uint fullCommand,
|
||||
float speedMod = 1f)
|
||||
{
|
||||
var route = Classify(fullCommand);
|
||||
switch (route)
|
||||
{
|
||||
case AnimationCommandRouteKind.Action:
|
||||
case AnimationCommandRouteKind.Modifier:
|
||||
case AnimationCommandRouteKind.ChatEmote:
|
||||
sequencer.PlayAction(fullCommand, speedMod);
|
||||
break;
|
||||
case AnimationCommandRouteKind.SubState:
|
||||
sequencer.SetCycle(currentStyle, fullCommand, speedMod);
|
||||
break;
|
||||
}
|
||||
|
||||
return route;
|
||||
}
|
||||
}
|
||||
|
||||
public enum AnimationCommandRouteKind
|
||||
{
|
||||
None = 0,
|
||||
Action,
|
||||
Modifier,
|
||||
ChatEmote,
|
||||
SubState,
|
||||
Ignored,
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue