fix: complete retail parity stability pass
All checks were successful
CI / linux-portable (push) Successful in 3m41s
CI / windows-gate (push) Successful in 6m49s
CI / release (push) Successful in 3m22s

This commit is contained in:
Erik 2026-08-28 20:01:39 +02:00
parent d3df4cb20a
commit f7aa8e0eb7
131 changed files with 7765 additions and 1190 deletions

View file

@ -2,6 +2,7 @@ using AcDream.App.UI;
using AcDream.Core.Items;
using AcDream.Core.Net;
using AcDream.Core.Net.Messages;
using AcDream.Core.Selection;
namespace AcDream.App.World;
@ -26,6 +27,7 @@ internal sealed class InventoryWorldDropProjectionController : IDisposable
private readonly ClientObjectTable _objects;
private readonly LiveEntityRuntime _runtime;
private readonly LiveEntityHydrationController _hydration;
private readonly SelectionState _selection;
private readonly PendingSplitToWorldProjection _pending;
private readonly Func<double> _now;
private bool _disposed;
@ -35,6 +37,7 @@ internal sealed class InventoryWorldDropProjectionController : IDisposable
ClientObjectTable objects,
LiveEntityRuntime runtime,
LiveEntityHydrationController hydration,
SelectionState selection,
Func<double> now)
{
_interaction = interaction
@ -43,6 +46,7 @@ internal sealed class InventoryWorldDropProjectionController : IDisposable
_runtime = runtime ?? throw new ArgumentNullException(nameof(runtime));
_hydration = hydration
?? throw new ArgumentNullException(nameof(hydration));
_selection = selection ?? throw new ArgumentNullException(nameof(selection));
_now = now ?? throw new ArgumentNullException(nameof(now));
_pending = new PendingSplitToWorldProjection();
@ -64,7 +68,15 @@ internal sealed class InventoryWorldDropProjectionController : IDisposable
// Consume before the synchronous CreateObject graph runs. Re-entrant
// callbacks cannot bind the same split intent to a second GUID.
_hydration.OnCreate(spawn);
return _runtime.TryGetSnapshot(update.Guid, out _);
bool recovered = _runtime.TryGetSnapshot(update.Guid, out _);
if (recovered)
{
// ACCWeenieObject::DeclareValid @0x0058E481 transfers the one
// global selection to the recognized split result. This is an
// automatic system transition, not a synthetic inventory click.
_selection.Select(update.Guid, SelectionChangeSource.System);
}
return recovered;
}
public void Dispose()

View file

@ -1222,7 +1222,10 @@ public sealed class LiveEntityRuntime : ILiveEntityRadarSource
}
if (record.FullCellId != token.ExactCellId
|| record.Canonical.PlacementCommitVersion
!= token.PlacementCommitVersion)
!= token.PlacementCommitVersion
|| record.Canonical.PhysicsBody is not { } body
|| body.Position != projection.WorldPosition
|| body.Orientation != projection.Orientation)
{
// A newer move superseded this receipt's facts after the drain.
//
@ -1264,13 +1267,13 @@ public sealed class LiveEntityRuntime : ILiveEntityRadarSource
// That is a behaviour change in the wrong direction, not a
// restoration.
//
// The ONE supersession neither term covers is
// RuntimeRemotePlacementDriveController.StoreAcceptedDestinationPose:
// the far-snap Refused/Contention arm writes `body.Position` and
// `body.Orientation` with no placement commit and no cell move, so
// it can stale this receipt's pose silently. That is pre-existing
// (it predates C5b, which changed nothing about that arm) and is
// filed as docs/ISSUES.md #323 rather than papered over here.
// #323: compare the retained body's exact pose too. The receipt
// copied these floats directly from that body, so exact equality
// is the correct proof that its pose is still current. This
// catches StoreAcceptedDestinationPose's legitimate pose-only
// fallback without abusing PositionAuthorityVersion (which can
// advance while the receipt facts remain unchanged) or redefining
// PlacementCommitVersion for a store that committed no cell.
return true;
}