Sitelet https://github.com/o3de/o3de/pull/20176
Skip to content

Feature/emotionfx sockets - #20176

Open
Grimwarrior wants to merge 9 commits into
o3de:developmentfrom
Grimwarrior:feature/emotionfx-sockets
Open

Grimwarrior wants to merge 9 commits into
o3de:developmentfrom
Grimwarrior:feature/emotionfx-sockets

Conversation

@Grimwarrior

@Grimwarrior Grimwarrior commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds Unreal-style sockets to EMotionFX: named, joint-relative frames with a position and a forward direction (local +Y). They can be authored in the Animation Editor and read at runtime, for example to spawn a projectile along a socket's forward direction without computing an aim.

  • Data: a SocketSetup on Actor. It is saved to the source asset's manifest through a new SocketSetupRule (the same route as simulated objects), exported into the .actor as a new chunk, and read back on import. The chunk is skipped when an actor has no sockets, so existing actor files export unchanged.
  • Runtime API: ActorComponentRequestBus gets GetNumSockets, GetSocketName, GetSocketIndexByName, GetSocketTransform and GetSocketForward, plus by-name variants, reflected to behavior context for Lua and Script Canvas.
  • Commands: undoable AddSocket, RemoveSocket and AdjustSocket.
  • Editor:
    • A Sockets dock window with a socket list and fields for name, joint, position and rotation.
    • Move and rotate gizmos (with a Move/Rotate cluster) that show only for the selected socket. A drag previews the change and commits one undoable command on release.
    • A wireframe arrow drawn in the viewport, which can be hidden with the new "Sockets" entry in the Render Options menu.
    • Sockets are added from the skeleton outliner's right-click menu and from the "Add Property" popup, the same way as colliders and ragdolls.

Notes

  • The joint is stored by name and resolved to a skeleton index at load. A socket whose joint is missing shows red in the list and returns identity at runtime.
  • For the transform and forward calls, LocalSpace is the authored offset from the joint, not relative to the joint's parent.
  • The Sockets render flag is on by default only for fresh view settings; existing saved settings need it ticked once.
  • Not based on fix/viewport-ui-cluster-checked-highlight, so the Move/Rotate cluster's active-button highlight depends on that fix.

How was this PR tested?

Built and tried in the Animation Editor: adding, selecting and deselecting sockets, and the move and rotate gizmos.

  • Save and reload an actor with sockets, and check the .assetinfo and .actor round trip
  • Read a socket's world transform and forward from Lua at runtime
  • Undo and redo for add, remove and each adjust

@Grimwarrior
Grimwarrior requested review from a team as code owners October 4, 2026 13:36
Grimwarrior and others added 5 commits October 4, 2026 15:41
A socket is a named, joint-relative frame (local position and rotation,
with local +Y as its forward direction) stored on the actor in a new
SocketSetup, so every instance of a character shares the same sockets.

Sockets are authored into the source asset's manifest through a new
SocketSetupRule, the same route simulated objects and physics setups
take, exported into the .actor as a new chunk, and read back on import.
The chunk is skipped for actors without sockets, so existing actor files
export unchanged. The joint is stored by name and resolved to a skeleton
index when the actor is loaded.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: Grimwarrior <143121582+Grimwarrior@users.noreply.github.com>
Add GetNumSockets, GetSocketName, GetSocketIndexByName,
GetSocketTransform and GetSocketForward, plus by-name variants, and
reflect them to behavior context so Lua and Script Canvas can read a
socket's transform and forward direction, for example to spawn a
projectile along it.

For the transform and forward calls, LocalSpace is the authored offset
from the socket's joint, and ModelSpace and WorldSpace are the joint's
transform in that space times the offset.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: Grimwarrior <143121582+Grimwarrior@users.noreply.github.com>
Add AddSocket, RemoveSocket and AdjustSocket to the command system so
socket edits go through the command history. Adding makes a unique name
when the requested one is empty or taken and checks the parent joint
exists, removing remembers the socket's position so undo restores it in
place, and adjusting can change any combination of name, joint, position
and rotation and restores the previous values on undo.

CommandSocketHelpers builds the command strings for callers.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: Grimwarrior <143121582+Grimwarrior@users.noreply.github.com>
Add an ActorRenderFlags::Sockets flag and a Sockets entry in the
viewport's Render Options menu, so the socket visuals can be hidden.
The flag is on by default for fresh settings and counts as requiring
updated transforms.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: Grimwarrior <143121582+Grimwarrior@users.noreply.github.com>
Add a Sockets dock window to EMotionStudio for the selected actor: a
socket list with add and remove, and fields for the name, parent joint,
position and rotation, all applied through the socket commands so every
edit is undoable. Sockets are drawn in the viewport as a wireframe
arrow along their forward direction with the name beside it.

Selecting a socket shows move and rotate gizmos on it, with a Move and
Rotate cluster to switch between them. Dragging previews the new value
and commits one command on release, so undo restores the pre-drag
value. Nothing is selected by default and clicking an empty part of the
list deselects, so the gizmos only show for a selected socket.

Sockets are added the same way as colliders and ragdolls: a Socket
submenu in the skeleton outliner's right-click menu (add, and remove
when the joint has sockets) and an Add Socket row in the Inspector's
Add Property popup. Both add one socket per selected joint as a single
undo step and open the Sockets window if it is closed.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: Grimwarrior <143121582+Grimwarrior@users.noreply.github.com>
@Grimwarrior
Grimwarrior force-pushed the feature/emotionfx-sockets branch from d72d8cb to a8f99c1 Compare October 4, 2026 13:41
Grimwarrior and others added 4 commits October 4, 2026 21:07
GetSocketBindTransform reads the socket from the bind pose so server and
clients agree; GetSocketTransformFromEntity composes the animated
model-space socket with the entity's current world transform for use in
network input processing, which runs before the animation update.

Signed-off-by: Grimwarrior <143121582+Grimwarrior@users.noreply.github.com>
Socket queries move to ActorSocketQueries, shared by the runtime and
editor actor components, so level entities answer them outside game mode.
ActorComponentRequestBus is reflected with the Common scope so editor
Python can call it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Grimwarrior <143121582+Grimwarrior@users.noreply.github.com>
Command vectors need a decimal point in every component, so the "0,0,0"
and "0,0,0,1" defaults failed to parse and AddSocket without -position or
-rotation stored uninitialized values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Grimwarrior <143121582+Grimwarrior@users.noreply.github.com>
Gems that also build against engines without actor sockets can compile
their socket calls conditionally.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Grimwarrior <143121582+Grimwarrior@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant