Skip to content

client: runtime-spawned actors bind the animated roster setup (T-pose fix, #1601)#1616

Merged
100yenadmin merged 2 commits into
mainfrom
tpose-fix
Jul 16, 2026
Merged

client: runtime-spawned actors bind the animated roster setup (T-pose fix, #1601)#1616
100yenadmin merged 2 commits into
mainfrom
tpose-fix

Conversation

@100yenadmin

Copy link
Copy Markdown
Member

Fixes the runtime-spawn T-pose (#1601). Runtime-spawned player actors — 'Gauge' the rogue (shop sandbox) and 'Sable' the rogue (dwing sandbox) — rendered a sideways T-pose (frozen, gliding) while the baked PC 'Aldric' animated on the same client code.

Root cause

A runtime actor is resolved by its in-game NAME (slugified): SpawnActor(t.id, t.name, ...)ResolveAsset(Slugify(name), "character"). A rogue's name (gauge/sable) matches no registry asset or alias, so it falls through to defaults.character = template_human = Assets/painterly/models/hero.fbx.

hero.fbx is the one character model flagged humanoid:false / needs_remodel (avatar isHuman=false) with no resolvable idle clip:

  • it fails the humanoid-controller gate (CombatSurfaceClient.cs:1476), and
  • PlayIdleGraph gets a null clip (ResolveIdleClipCombatSurfaceClient.cs:1876 finds nothing, and the donor-idle retarget needs isHuman), and
  • its non-skinned import takes the -90 pitch stand-up (CombatSurfaceClient.cs:1441) → frozen, lying sideways.

'Aldric' works because aldric aliases to the Humanoid fighter.

Fix — a T-pose is impossible at the character floor

Reuses an existing animated asset (patron_commoner, the generic rigged humanoid the tavern/camp cast already spawn correctly) instead of adding a code branch — the same idiom as the #1423 wren/camp-scout alias fix.

  • data/asset-registry/registry.json — re-point template_human off hero.fbx onto patron_commoner (meshy 9-clip idle in anim_idle.fbx). Every character miss (and __any__) now animates via the per-frame idle-graph fallback every Generic-import character already uses. asset_id stays template_human (no resolver-semantics change).
  • CombatSurfaceClient.cs — the in-code character floor (registry-absent path) now returns patron_commoner + its idle moveset instead of hero.fbx, so even a registry-less build floors to an animated humanoid.
  • asset_registry.py / AssetRegistry.cs — the hardcoded floors in both twins moved off hero.fbx for parity.

Tests

viewer/tests/test_asset_registry.py: 16 pass (11 existing + 5 new anti-T-pose invariants — the Gauge/Sable repros, arbitrary character names, the __any__ and in-code floors, and a default/alias-target + model_ref completeness lint). Run: python3 -m pytest viewer/tests/test_asset_registry.py -q -p no:xdist.

Box-side follow-up (no new assets required)

patron_commoner's rigged.fbx/albedo.jpg/anim_idle.fbx are already registry-referenced, so they are already baked into the worldos_actors bundle — nothing to generate. To ship the fix the box operator must:

  1. Sync this repo's data/asset-registry/registry.json → the Unity project root registry.json (the file BuildMacOSPlayer.EnsurePackaged reads, BuildMacOSPlayer.cs:63,68).
  2. Run BuildMacOSPlayer.PackageOnly() (EnsurePackaged) to re-copy registry.json into StreamingAssets/ and rebuild the recompiled client, then rebuild the player.

Runtime visual verification (rogue stands + idles + walks, no T-pose) to happen upstream in the sandbox.

Do not merge — orchestrator review.

… fix, #1601)

Runtime-spawned player actors (the rogues 'Gauge' in the shop sandbox and
'Sable' in the dwing sandbox) rendered a sideways T-pose while the baked PC
'Aldric' animated on the same client code.

Root cause: a runtime actor is resolved by its in-game NAME (slugified), so a
rogue's name matches no registry asset or alias and falls to
defaults.character = template_human = Assets/painterly/models/hero.fbx. hero.fbx
is the one character model flagged humanoid:false / needs_remodel (avatar
isHuman=false) with no resolvable idle clip: it fails the humanoid-controller
gate AND PlayIdleGraph gets a null clip, and its non-skinned import takes the
-90 pitch stand-up -> a frozen, sideways T-pose. 'Aldric' works because
'aldric' aliases to the Humanoid 'fighter'.

Fix (make a T-pose impossible at the character floor, reusing an existing
animated asset rather than a new code branch):
- data/asset-registry/registry.json: re-point template_human off hero.fbx onto
  patron_commoner -- the generic rigged humanoid the tavern/camp cast already
  spawn correctly (meshy 9-clip idle in anim_idle.fbx). Every character miss
  (and __any__) now animates via the same per-frame idle-graph fallback.
- CombatSurfaceClient.cs: the in-code character floor (registry-absent path) now
  returns patron_commoner + its idle moveset instead of hero.fbx, so even a
  registry-less build floors to an animated humanoid.
- asset_registry.py / AssetRegistry.cs: the hardcoded floors in both twins moved
  off hero.fbx for parity.
- viewer/tests/test_asset_registry.py: +5 anti-T-pose invariant tests (the Gauge
  /Sable repros, arbitrary character names, the __any__ and in-code floors, and
  a default/alias-target + model_ref completeness lint).
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 45 seconds

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1d177b9a-d205-4b0c-a85e-9a5f121cac10

📥 Commits

Reviewing files that changed from the base of the PR and between 0b5cc68 and b15719d.

📒 Files selected for processing (6)
  • data/asset-registry/registry.json
  • extensions/renderers/unity/scripts/AssetRegistry.cs
  • extensions/renderers/unity/scripts/CombatSurfaceClient.cs
  • extensions/renderers/unity/scripts/paint_combat_v1.cs
  • viewer/asset_registry.py
  • viewer/tests/test_asset_registry.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch tpose-fix

Comment @coderabbitai help to get the list of available commands.

@evaos-code-review-bot

evaos-code-review-bot Bot commented Jul 16, 2026

Copy link
Copy Markdown

evaOS review status: completed

PR: #1616 - client: runtime-spawned actors bind the animated roster setup (T-pose fix, #1601)
Head: d36c8584da61829188314e65de93819ca8b47e03
Updated: 2026-07-16T07:22:22.367Z

evaOS review completed for this PR head.

Automation note: agents should wait for this comment to reach completed, stale_head, closed_or_merged_before_review, skipped, or failed before treating evaOS review as settled for this head. provider_deferred means evaOS still intends to retry.

PR URL: #1616

Review URL: #1616 (review)

@evaos-code-review-bot evaos-code-review-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Walkthrough

PR: #1616 - client: runtime-spawned actors bind the animated roster setup (T-pose fix, #1601)
Head: d36c8584da61829188314e65de93819ca8b47e03 into main. Review event: COMMENT.
Provider: GLM/Z.ai through ZCode (zcode-glm, zcode, model GLM-5.2).

Estimated review effort: 1/5 (~14 min)

Changed Files

File Status Churn Purpose Risk
extensions/renderers/unity/scripts/AssetRegistry.cs modified +8/-3 Unity/gameplay state Moderate: validated P3 finding
extensions/renderers/unity/scripts/CombatSurfaceClient.cs modified +16/-8 Unity/gameplay state Moderate: validated P2 finding

Review Signal

Validated inline findings: 2 (P0: 0, P1: 0, P2: 1, P3: 1).
Dropped findings before posting: 1. High-severity findings: 0.

Risk Taxonomy

  • Release regression: 1
  • Unity scene/prefab: 1

Validation and Proof

1 required validation/proof recommendation(s) selected from changed files.

  • required: Unity editor or Play Mode smoke - Unity asset/script/project files changed. Proof: Unity editor smoke; Play Mode log; scene/prefab screenshot or recording.
    Proof status: missing - 1 required validation/proof recommendation(s) missing from PR metadata.
    Profile validation hints: Prefer correctness, persistence, CI, release, and regression findings over style-only feedback.
    Profile proof expectations: Look for Unity editor, play-mode, fixture, or focused smoke evidence when runtime behavior changes.

Related Context

Related issues/PRs: #1601, #1423.
Suggested labels: unity.
Suggested reviewers: none from current metadata.

Review Settings Preview

  • Profile: assertive
  • Enabled sections: Review summary (inline_review); Walkthrough (inline_review); Changed-files table (walkthrough); Effort estimate (walkthrough); Related issues/PRs (walkthrough); Suggested labels (suggestion_only); Review status comment (sticky_status)
  • Path instructions: Assets/** - Prioritize scene, prefab, save-state, asset-reference, and gameplay regressions.
  • Path instructions: ProjectSettings/** - Treat build, platform, input, graphics, and release behavior changes as high risk.
  • Label suggestions: unity, gameplay, regression-hardening
  • Reviewer suggestions: none
  • Suggestion behavior: suggestions only; labels and reviewers are not auto-applied.
  • Roadmap-only settings: auto-apply labels; auto-request reviewers; required status checks

Pre-merge checklist

  • Inline comments target current RIGHT-side diff lines.
  • No secret-like content survived into posted inline comments.
  • REQUEST_CHANGES is only used when eligible P0/P1 findings survive validation.
  • Required behavior proof is present or not applicable.
  • Labels and reviewers are suggestions only; the bot did not auto-apply them.

}
}
return new[] { fbxDef, albDef, "" };
return new[] { fbxDef, albDef, animDef };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: #1601 T-pose fix not applied to its documented mirror paint_combat_v1.cs::resolveAsset, which still floors characters to the clipless hero.fbx

ResolveAsset's new comment (lines 1252-1262) says it 'Mirrors paint_combat_v1.cs resolveAsset' and frames the patron_commoner character floor as the correct #1601 behavior. But the original mirror at extensions/renderers/unity/scripts/paint_combat_v1.cs:330-346 was NOT updated in this PR: it still sets fbxDef = ... : "Assets/painterly/models/hero.fbx", albDef = ... : "Assets/painterly/models/hero_albedo.png", and returns empty anim_ref for the character floor (lines 331-333, 346) — exactly the sideways-T-pose root cause #1601 fixes in the two edited files. paint_combat_v1.cs is still a live canonical path: M15SpendGateProbe.cs:46 calls 'paint_combat_v1.cs SaveScene the canonical scene after every render', and BuildMacOSPlayer.cs:31 describes the build as consuming '/combat-surface via paint_combat_v1.cs engine-driven actor placement'. So any runtime-spawned rogue whose slug matches no asset/alias and renders through paint_combat_v1 (or a future regression that re-points CombatSurfaceClient back at its stated mirror) will still T-pose. The fix is incomplete: either apply the identical patron_commoner floor + anim_idle.fbx anim_ref to paint_combat_v1.cs::resolveAsset, or add a comment there explicitly documenting the intentional divergence and that paint_combat_v1 is superseded by CombatSurfaceClient for runtime-spawned actors.

Category: Release regression

Why this matters: The PR's stated root-cause fix (kill the T-pose at the character floor) is only applied to 2 of the 3 resolveAsset copies. The third is the documented mirror and is still live, so the bug class survives in that path and the three implementations now silently diverge, which defeats the 'kill it at the floor rather than adding a code branch' design stated in the registry's template_human gen_recipe.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adopted — paint_combat_v1.cs::resolveAsset now carries the identical patron_commoner floor (model+albedo+anim) with the same template-vs-real anim_ref split as CombatSurfaceClient; all three twins agree and the only remaining hero.fbx mentions anywhere are comments.
🤖 Addressed by Claude Code

animRef = "Assets/painterly/models/hero@moveset.fbx",
modelRef = "Assets/chars_v2/patron_commoner/rigged.fbx",
albedoRef = "Assets/chars_v2/patron_commoner/albedo.jpg",
animRef = "Assets/chars_v2/patron_commoner/anim_idle.fbx",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: No C# test pins the Unity in-code floor away from hero.fbx (Python twin has one)

The Python twin viewer/asset_registry.py has test_in_code_floor_is_animatable (viewer/tests/test_asset_registry.py:187-192) that asserts _HARDCODED_FLOOR is NOT hero.fbx, and _assert_animatable_character covers the anim_ref. The two C# twins edited here — AssetRegistry.HardcodedFloor and CombatSurfaceClient.ResolveAsset — have no equivalent test (no C# test references HardcodedFloor/ResolveAsset/patron_commoner/T-pose; only PathingTestDriver.cs exists under the unity test path). #1601 is a visual regression fix with no committed Unity editor/play-mode or fixture evidence in the diff. A future refactor could revert either C# floor back to hero.fbx with nothing failing. Recommend an edit-mode test asserting HardcodedFloor('character').modelRef != hero.fbx and that animRef is non-empty for the character kind, mirroring the Python guard.

Category: Unity scene/prefab

Why this matters: Runtime-animation behavior changed with no automated regression guard on the Unity side; the only protection is a test on the Python twin, which does not exercise the C# resolve path the renderer actually calls.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adopted in the honest form available: the twins have no C# edit-mode rig in this repo, so the invariant is pinned as a source-level lint in viewer/tests/test_asset_registry.py — comments-stripped CombatSurfaceClient.cs / paint_combat_v1.cs / AssetRegistry.cs must contain NO hero.fbx code literal (a reappearance = a floor regression). Runs in the same CI as the Python-twin guards; a real Play-Mode smoke rides the next box build per the PR's box recipe.
🤖 Addressed by Claude Code

… + source-lint guard (evaOS P2/P3)

paint_combat_v1.cs::resolveAsset (the documented mirror, still live via M15SpendGateProbe +
BuildMacOSPlayer) still floored characters to the clipless hero.fbx. Same floor + template-vs-real
anim_ref split as CombatSurfaceClient (a REAL asset row with no anim_ref keeps mesh-as-poseClip;
a template fall-through takes the animated floor's idle). The Unity twins have no C# test rig, so
the anti-T-pose invariant is pinned at source level: comments-stripped .cs must not mention
hero.fbx in code (17/17).
@evaos-code-review-bot

evaos-code-review-bot Bot commented Jul 16, 2026

Copy link
Copy Markdown

evaOS review status: completed

PR: #1616 - client: runtime-spawned actors bind the animated roster setup (T-pose fix, #1601)
Head: b15719de7664208cd570a1571dc5ab9366cd9959
Updated: 2026-07-16T09:15:13.651Z

evaOS review completed for this PR head.

Automation note: agents should wait for this comment to reach completed, stale_head, closed_or_merged_before_review, skipped, or failed before treating evaOS review as settled for this head. provider_deferred means evaOS still intends to retry.

PR URL: #1616

Review URL: #1616 (review)

@100yenadmin
100yenadmin enabled auto-merge (squash) July 16, 2026 09:08

@evaos-code-review-bot evaos-code-review-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Walkthrough

PR: #1616 - client: runtime-spawned actors bind the animated roster setup (T-pose fix, #1601)
Head: b15719de7664208cd570a1571dc5ab9366cd9959 into main. Review event: COMMENT.
Provider: GLM/Z.ai through ZCode (zcode-glm, zcode, model GLM-5.2).

Estimated review effort: 1/5 (~16 min)

Changed Files

File Status Churn Purpose Risk
extensions/renderers/unity/scripts/AssetRegistry.cs modified +8/-3 Unity/gameplay state Moderate: runtime path
extensions/renderers/unity/scripts/CombatSurfaceClient.cs modified +16/-8 Unity/gameplay state Moderate: validated P3 finding
extensions/renderers/unity/scripts/paint_combat_v1.cs modified +14/-5 Unity/gameplay state Moderate: validated P3 finding

Review Signal

Validated inline findings: 2 (P0: 0, P1: 0, P2: 0, P3: 2).
Dropped findings before posting: 0. High-severity findings: 0.

Risk Taxonomy

  • Unity scene/prefab: 2

Validation and Proof

1 required validation/proof recommendation(s) selected from changed files.

  • required: Unity editor or Play Mode smoke - Unity asset/script/project files changed. Proof: Unity editor smoke; Play Mode log; scene/prefab screenshot or recording.
    Proof status: missing - 1 required validation/proof recommendation(s) missing from PR metadata.
    Profile validation hints: Prefer correctness, persistence, CI, release, and regression findings over style-only feedback.
    Profile proof expectations: Look for Unity editor, play-mode, fixture, or focused smoke evidence when runtime behavior changes.

Related Context

Related issues/PRs: #1601, #1423.
Suggested labels: unity.
Suggested reviewers: none from current metadata.

Review Settings Preview

  • Profile: assertive
  • Enabled sections: Review summary (inline_review); Walkthrough (inline_review); Changed-files table (walkthrough); Effort estimate (walkthrough); Related issues/PRs (walkthrough); Suggested labels (suggestion_only); Review status comment (sticky_status)
  • Path instructions: Assets/** - Prioritize scene, prefab, save-state, asset-reference, and gameplay regressions.
  • Path instructions: ProjectSettings/** - Treat build, platform, input, graphics, and release behavior changes as high risk.
  • Label suggestions: unity, gameplay, regression-hardening
  • Reviewer suggestions: none
  • Suggestion behavior: suggestions only; labels and reviewers are not auto-applied.
  • Roadmap-only settings: auto-apply labels; auto-request reviewers; required status checks

Pre-merge checklist

  • Inline comments target current RIGHT-side diff lines.
  • No secret-like content survived into posted inline comments.
  • REQUEST_CHANGES is only used when eligible P0/P1 findings survive validation.
  • Required behavior proof is present or not applicable.
  • Labels and reviewers are suggestions only; the bot did not auto-apply them.

// silently diverge — evaOS #1616 P2 caught this copy still flooring to hero.fbx).
string fbxDef=kind=="monster"?"Assets/chars_v2/goblin/goblin.fbx":"Assets/chars_v2/patron_commoner/rigged.fbx";
string albDef=kind=="monster"?"Assets/chars_v2/goblin/albedo.png":"Assets/chars_v2/patron_commoner/albedo.jpg";
string animDef=kind=="monster"?"":"Assets/chars_v2/patron_commoner/anim_idle.fbx";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Floor paths duplicated across 3 files with no shared constant or test guard

The patron_commoner floor (model/albedo/anim refs) is now copy-pasted in three places that the comments explicitly say 'must not silently diverge': AssetRegistry.cs:80-82, CombatSurfaceClient.cs:1267-1268, and paint_combat_v1.cs:335-337. The PR's own comment at paint_combat_v1.cs:334 acknowledges 'evaOS #1616 P2 caught this copy still flooring to hero.fbx' — i.e. this exact divergence was caught by human review, not by any automated check. There is still no source-lint/test asserting the three floors (and the Python twin viewer/asset_registry.py:47-49, plus registry.json's template_human/patron_commoner rows) stay byte-identical. A fourth silent divergence on the next floor change is likely. Consider a single shared constant or a qa fixture that asserts all four sources resolve to the same model/albedo/anim triple.

Category: Unity scene/prefab

Why this matters: A future floor repoint that touches only some copies reintroduces the T-pose regression this PR exists to fix, and review is the only current safety net.

}
}
return new[] { fbxDef, albDef, "" };
return new[] { fbxDef, albDef, animDef };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: No editor/play-mode or fixture evidence in diff for the T-pose fix

This PR changes runtime actor-spawn behavior (the in-code character floor across both the live client SpawnActor path at CombatSurfaceClient.cs:1430-1494 and the capture paint path at paint_combat_v1.cs:330-355), which is exactly the runtime-behavior class the repo profile asks for Unity editor/play-mode/fixture smoke evidence on. The diff contains comments describing the measured T-pose/sideways symptom but no committed test, fixture, or captured evidence proving a runtime-spawned rogue (e.g. 'Gauge'/'Sable' named in the registry.json template_human gen_recipe) now renders an animated idle on the patron_commoner floor. The behavioral reasoning is sound on inspection (rest mode: anim_idle.fbx sampled at paint_combat_v1.cs:388,212; live client: ResolveIdleClip finds the moveset idle via _animOf at CombatSurfaceClient.cs:1439,1494), but it is unverified by any committed artifact. Add a focused smoke/fixture or link build-SHA capture evidence.

Category: Unity scene/prefab

Why this matters: The fix is correct-by-reasoning but the T-pose class has repeatedly regressed (#1408, this PR's own P2 catch); without committed proof the next refactor can reintroduce it unnoticed.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b15719de76

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

literal means a floor regressed to the clipless non-humanoid model."""
import re
root = Path(__file__).resolve().parents[2] / "extensions" / "renderers" / "unity" / "scripts"
for name in ("CombatSurfaceClient.cs", "paint_combat_v1.cs", "AssetRegistry.cs"):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include the replay resolver in the T-pose guard

This new source guard skips paint_combat_replay_v1.cs, but that action-replay renderer still has the same inline resolver and still returns Assets/painterly/models/hero.fbx when /home/unity/worldos-unity/registry.json is missing or unreadable (paint_combat_replay_v1.cs:227-243). In registry-absent replay/evidence runs, unknown character names such as Gauge/Sable can therefore still hit the clipless hero floor even though this patch updates the other registry-absent floors. Please include/update the replay file as well so the anti-T-pose fix covers the replay lane.

Useful? React with 👍 / 👎.

@100yenadmin
100yenadmin merged commit 1743839 into main Jul 16, 2026
30 of 36 checks passed
@100yenadmin
100yenadmin deleted the tpose-fix branch July 16, 2026 09:16
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