Skip to content

VR: other players' worn armor is not drawn when they wear no torso armor - #14

Draft
cec339 wants to merge 1 commit into
vr-supportfrom
fix/vr-remote-gear-redraw
Draft

cec339 wants to merge 1 commit into
vr-supportfrom
fix/vr-remote-gear-redraw

Conversation

@cec339

@cec339 cec339 commented Oct 4, 2026

Copy link
Copy Markdown
Collaborator

For humans

In VR, when another player wears no chest armor (only hood, boots, gloves...), their copy can appear after a door or spawn with none of that armor drawn: no hood, and feet and hands disappear with the boots and gloves.

Changing any armor piece fixed it by hand. Now (VR only) the copy's worn armor is taken off after 0.5 s and put back 0.25 s later, which redraws it.

Equipment changes by the owner are kept. Weapons are not touched. Independent of #11.

Tested: two people, two headsets, both directions: hood + boots through doors now shows them; chest armor still fine. Armor can blink once during the redraw.


For LLMs / agents (detailed)

Commit (base 5ab99be4 = vr-support)

260f9ed5 fix: vr remote player bodies draw their worn armor without a torso piece. 5 files, +487: Code/client/Services/GearRedraw.h (new, engine-free schedule), Code/client/Services/CharacterService.h, Code/client/Services/Generic/CharacterService.cpp, Code/client/Services/Generic/InventoryService.cpp (one hook), Code/tests/gear_redraw.cpp (new). The runtime integration is under #if TP_SKYRIMVR and runs only for IsRemotePlayer() copies; the pure scheduler header and its host tests are unguarded. Both changed client units compile for SE (TP_SKYRIMVR=0 / TP_SKYRIMSE=1); SE was not linked or run.

The defect (reproduced on demand, both directions)

  • Trigger: the owner wears no torso-slot armor (e.g. EnchClothesRobesMageHoodNovice 10DD3A + ArmorImperialLightBoots 13ED7), and the watching client creates or rebuilds the copy (door crossing, reconnect, first spawn).
  • The copy's worn list is right (Applied 3D for actor ... now wearing 2 armor pieces), and the owner's own game shows the items equipped, but none of them is drawn. With a torso piece (robes, tunic, cuirass) everything draws.
  • Any ARMOR equip/unequip by the owner (NotifyEquipmentChanges) redraws the whole copy, including pieces that did not change; a weapon change does not.
  • Mechanism, not verified: SetActorInventory -> TESObjectREFR::SetInventory -> AddOrRemoveItem copies the sender's worn flags onto the item's extra list before AddObjectToContainer, then calls EquipManager::Equip(actor, item, nullptr, ...). GetWornArmor reads those flags, not attached geometry, so the list looks right. A biped refresh triggered only by a torso-slot change is a hypothesis. The VR equip entry rejects an explicitly supplied already-worn list, but this path passes nullptr, so that does not establish the cause.

The change

  • After SetActorInventory in the WaitingFor3D block, and after a retained body's equipment is restored in ProcessNewEntity, QueueGearRedraw schedules one redraw per copy (bound to entity, form id and ownership epoch; a repeat for the same body restarts nothing).
  • RunGearRedraws (after ApplyCachedWeaponDraws in OnUpdate): at 0.5 s it takes every worn armor piece off (UnEquip(actor, armor, nullptr, 1, nullptr, false, true, false, false, nullptr)), and at least 0.25 s later, on a later update, puts them back (Equip(actor, armor, nullptr, 1, nullptr, false, true, false, false)): the same arguments as OnNotifyEquipmentChanges, in separate updates because an unequip and an equip in one drain cancel (see ReattachHandItems).
  • Owner changes in between win: InventoryService::OnNotifyEquipmentChanges calls OnRemoteEquipmentChange, which drops that item from the restore set; a stripped piece whose biped slots (TESObjectARMO::slotType) the owner has since filled is not put back.
  • The hand-item passes (DetachHandItems/ReattachHandItems, 2.25/2.75 s) wait while the armor is off, without restarting their counter.
  • A body removed while its armor is off: if it is kept through a 3D rebuild (PendingEquipmentComponent), the stripped pieces are saved as worn (minus any whose slot the owner filled). The redraw is dropped if the body is gone, changed owner, or has no 3D before the strip; the restore runs without 3D.
  • Weapons are not equipped by this change.

Log lines (client tp_client.log)

  • Gear redraw queued for remote body X: received N worn armor and M worn weapons, worn now [ids], right hand R, left hand L
  • Gear redraw took N armor pieces off remote body X: [ids]. They go back next pass.
  • Gear redraw put [ids] back on remote body X (left off, slot since filled by the owner: [ids]); worn now [ids], right hand R, left hand L
  • Gear redraw skipped ... no worn armor, Gear redraw dropped ..., Gear redraw cancelled for remote body X with its armor off; kept as worn N, left off ... M

Testing done

Not fixed here (upstream, related)

  • A sheathed weapon is missing at the hip on remote copies in our tests. DetachHandItems skips drawn spawn requests and bodies with no equipped weapon or shield, without logging; whether that is the cause is unproven.
  • The VR inventory sometimes stays open after its panel closes (floating rotating item preview; the game still reports the menu open). Reopening and closing it clears it.

Review provenance

Codex (gpt-6-astra, high): spec review REVISE (armor-only design adopted), diff review REVISE (2 High: stale restore after removal, armor replacement), recheck REVISE (1 High: replacement plus removal, 1 Low: log count), second recheck ACCEPT. Every finding verified against code and logs before fixing.

🤖 Generated with Claude Code

https://claude.ai/code/session_014b5v4UAeR2a8gR537GMuvi

A remote player body built while its owner wears no torso armor drew none
of its worn armor: hood, boots and gauntlets were in its worn list and the
owner had them equipped, but nothing showed, so its feet and hands
vanished with the boots and gauntlets. A torso piece hid the problem, and
any armor change by the owner repaired it, since that redraws the body.

After a remote player body gets its inventory, VR only, its worn armor is
now taken off at 0.5 s and put back at least 0.25 s later on a later
update, the same shape as the owner's own fix. Anything the owner changes
in between is left as they set it: a piece they changed, or one whose slot
they filled, is not put back. The hand item passes wait while the armor is
off. A body that changes owner drops the redraw; one kept through a 3D
rebuild while its armor is off saves that armor as worn. Weapons are not
touched. Each step logs what it did, with the received worn armor and
weapons and the hand slots, so a missing weapon can be traced.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014b5v4UAeR2a8gR537GMuvi
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