fix(vendor): evidence-based pass — max-first stack ceiling; the local player resolves never-animated MoveTo targets
Some checks are pending
Headless portability / portable-headless (ubuntu-latest) (push) Waiting to run
Headless portability / portable-headless (windows-latest) (push) Waiting to run
Headless portability / linux-graphical (push) Waiting to run
Headless portability / linux-vulkan (push) Waiting to run
Some checks are pending
Headless portability / portable-headless (ubuntu-latest) (push) Waiting to run
Headless portability / portable-headless (windows-latest) (push) Waiting to run
Headless portability / linux-graphical (push) Waiting to run
Headless portability / linux-vulkan (push) Waiting to run
Both chains pinned by the live [vendor-diag] run (vendor-diag.log) after three code-reading rounds each failed: The split bar: ACE serializes descStackSize=1 for EVERY browse row (live wire, log 343-348) — the R1-era "ACE never populates desc" claim is retracted with the line quoted. Retail's vendor sites read pwd._maxStackSize directly (four sites, incl. UpdateItemsList @0x004c1ea0 stamping min(remaining, _maxStackSize)); ResolveAuthoredStackSize flips to max-first for its vendor-only consumers. Taper ceiling 1000, scarab 100, seed 1 for exempt. Pricing still reads the desc (per-1 values on ACE). Walk-to-use: the local player's getObjectA seam was bound to TryGetPhysicsHost, which resolves only INSTALLED physics hosts — a never-animated vendor has none, so TargetManager.SetTarget got null, the MoveToObject armed with zero nodes, and UseTime never dispatched. The log's natural=False completions were the user's own movement keys (retail-correct input-edge cancels); attempt 4 worked because the greeting animation had installed a host. RuntimePhysicsState gains the retail CObjectMaint::GetObjectA seam (bound canonical resolver with installed-host fallback); the graphical host binds the SAME lazy-minimal-host resolver every remote already uses — whose own doc comment names this exact never-animated hazard. The reservation release was already correct (2b premise refuted with evidence); the production-wiring invariants are now pinned by four new tests including the pre-fix pathology as a permanent sabotage control. AP-169 rewritten a second time, honestly. The [vendor-diag] probe family (ACDREAM_DUMP_VENDOR) lands env-gated for future live triage. Clean-room complete solution: 11,536 passed / 4 skipped / 0 failed. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
d003449bb4
commit
02b735ba4a
21 changed files with 1139 additions and 102 deletions
|
|
@ -1240,6 +1240,57 @@ public sealed class RuntimePhysicsState : IDisposable
|
|||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The host-installed retail <c>CObjectMaint::GetObjectA</c> stand-in
|
||||
/// consumed by <see cref="ResolveObjectTableHost"/>. Retail resolves ANY
|
||||
/// in-world object here — every <c>CPhysicsObj</c> can answer
|
||||
/// <c>add_voyeur</c>, so a moveto/sticky can target a never-animated
|
||||
/// static object and still receive the immediate initial target snapshot
|
||||
/// (<c>TargetManager::AddVoyeur</c> → <c>SendVoyeurUpdate(Ok)</c>). This
|
||||
/// state's own <see cref="TryGetPhysicsHost"/> is narrower: it answers
|
||||
/// only entities whose incarnation-stable host is ALREADY installed
|
||||
/// (remote-motion-bound movers, prior resolve targets), so a moveto
|
||||
/// bound to it alone arms but never initializes against a host-less
|
||||
/// target — the 2026-08-08 vendor-approach root cause. The graphical
|
||||
/// host binds its canonical lazy-resolving object-table lookup
|
||||
/// (<c>LiveEntityMotionRuntimeController.ResolvePhysicsHost</c>, the
|
||||
/// SAME resolver every remote host's <c>GetObjectA</c> already uses,
|
||||
/// including the TS-49 Hidden withholding), which installs a minimal
|
||||
/// position-only host into this state's canonical ownership on first
|
||||
/// resolve. Host-scoped, not session-scoped: the binding survives
|
||||
/// session resets (the bound resolver reads its own live session state
|
||||
/// per call); last bind wins so a host can rebind across routes.
|
||||
/// A no-window host that never binds keeps the exact-installed-host
|
||||
/// behavior via the fallback below.
|
||||
/// </summary>
|
||||
private Func<uint, AcDream.Core.Physics.Motion.IPhysicsObjHost?>?
|
||||
_objectTableHostResolver;
|
||||
|
||||
/// <summary>Binds (or replaces) the canonical object-table host
|
||||
/// resolver — see <see cref="ResolveObjectTableHost"/>. Pass null to
|
||||
/// clear back to the exact-installed-host fallback.</summary>
|
||||
public void BindObjectTableHostResolver(
|
||||
Func<uint, AcDream.Core.Physics.Motion.IPhysicsObjHost?>? resolver)
|
||||
{
|
||||
EnsureNotDisposed();
|
||||
_objectTableHostResolver = resolver;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retail <c>CObjectMaint::GetObjectA(id)</c> for consumers composed
|
||||
/// inside Runtime (the local player's publication-chain host): the bound
|
||||
/// canonical resolver when the host installed one, else the exact
|
||||
/// installed-host lookup (<see cref="TryGetPhysicsHost"/>).
|
||||
/// </summary>
|
||||
public AcDream.Core.Physics.Motion.IPhysicsObjHost? ResolveObjectTableHost(
|
||||
uint serverGuid)
|
||||
{
|
||||
EnsureNotDisposed();
|
||||
if (_objectTableHostResolver is { } resolver)
|
||||
return resolver(serverGuid);
|
||||
return TryGetPhysicsHost(serverGuid, out var host) ? host : null;
|
||||
}
|
||||
|
||||
public bool ClearRemoteMotion(RuntimeEntityRecord record)
|
||||
{
|
||||
EnsureNotDisposed();
|
||||
|
|
@ -2120,6 +2171,7 @@ public sealed class RuntimePhysicsState : IDisposable
|
|||
_localPlayerCreateObserved = false;
|
||||
CellCommitted = null;
|
||||
_collisionGenerationCommittedObservers.Clear();
|
||||
_objectTableHostResolver = null;
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue