Part 1 deleted probes whose owning issues were closed. These 14 named no issue at all, so each was traced to its introducing commit (git log -S) instead of guessed at. Attribution split them three ways: DELETED (7, investigations closed): ACDREAM_A8_DUMP_PV and ACDREAM_DUMP_LIVE_SPAWNS (Phase A8), ACDREAM_DUMP_CLOTHING (#37), ACDREAM_DUMP_EDGE_SLIDE (#32), ACDREAM_DUMP_STEPUP (L.2.3d-f), ACDREAM_DUMP_VENDOR (the vendor campaign, 25 call sites across 8 files), ACDREAM_DUMP_VITALS (#5, four independent read sites). VendorDiagnostics.cs went entirely. RECLASSIFIED (8, tools misfiled as probes): the DUMP_CELLS/DUMP_GFXOBJS fixture-extraction family (replay-harness tooling with a roundtrip test), PROBE_CELL (standing cell-transit tracer, pair of the permanent PROBE_RESOLVE), DUMP_SKY and HIDE_PART (generic isolation tools), and DUMP_STEEP_ROOF — which looked like an L.4 relic but observes LIVE divergence-register row AD-56; deleting it would have removed the only runtime lens on an active divergence. All moved to Permanent diagnostics with their attribution recorded. RESTORED (1): ACDREAM_DUMP_MOVE_TRUTH was deleted and un-deleted the same day. It is not a probe — the canonical nine-stop soak (run-connected-r6-soak.ps1) hard-fails every destination without its 'move-truth OUT' records, with a message that would misdirect the next operator. Under the no-workarounds rule the gate's mechanism is restored, not left broken with an IOU (#437, closed). Process lesson recorded on both issues: a closed owning issue is NOT sufficient to delete a probe — grep tools/ and the contract tests for consumers first. Also lands the owner-requested default-off invariant: every diagnostic in the codebase is inert until its env var is explicitly set. Exactly four flags default ON and none is a diagnostic — RETAIL_CHASE, CAMERA_COLLIDE, CAMERA_ALIGN_SLOPE, RETAIL_CLOSE_DEGRADES are retail behaviors wearing an A/B off-switch. That set is now FROZEN by LaunchOptionsDocumentationTests.OnlyTheFourRetailBehaviorFlagsDefaultOn; docs/launch-options.md's Conventions and CLAUDE.md state the rule, and CLAUDE.md now binds future probes to a documented row in the same commit. The client reads 137 environment variables (161 at audit start); 40 temporary probes remain, every one attributed. Full hermetic suite 15,322 passed / 0 failed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
78 lines
3.1 KiB
C#
78 lines
3.1 KiB
C#
using AcDream.App.Input;
|
|
using AcDream.Core.Items;
|
|
using AcDream.Core.Physics;
|
|
using AcDream.Core.Physics.Motion;
|
|
|
|
namespace AcDream.App.Interaction;
|
|
|
|
internal interface IPlayerInteractionMovementSink
|
|
{
|
|
/// <summary>
|
|
/// Cancels any preceding MoveTo, invokes <paramref name="armAfterCancel"/>,
|
|
/// then installs the new movement. The callback boundary lets the intent
|
|
/// owner arm completion state before an already-facing TurnTo can finish
|
|
/// synchronously, without letting the preceding cancellation clear it.
|
|
/// </summary>
|
|
bool BeginApproach(
|
|
InteractionApproach approach,
|
|
Action<PlayerApproachToken>? armAfterCancel = null);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Installs retail's client-side TurnToObject/MoveToObject prediction through
|
|
/// the same MovementManager used by authoritative movement packets.
|
|
/// </summary>
|
|
internal sealed class PlayerInteractionMovementSink(
|
|
Func<PlayerMovementController?> player,
|
|
IPlayerApproachTokenSource approachTokens)
|
|
: IPlayerInteractionMovementSink
|
|
{
|
|
private readonly Func<PlayerMovementController?> _player = player
|
|
?? throw new ArgumentNullException(nameof(player));
|
|
private readonly IPlayerApproachTokenSource _approachTokens = approachTokens
|
|
?? throw new ArgumentNullException(nameof(approachTokens));
|
|
|
|
public bool BeginApproach(
|
|
InteractionApproach approach,
|
|
Action<PlayerApproachToken>? armAfterCancel = null)
|
|
{
|
|
PlayerMovementController? controller = _player();
|
|
if (controller?.MoveTo is null)
|
|
return false;
|
|
|
|
var parameters = new MovementParameters
|
|
{
|
|
DistanceToObject = approach.UseRadius,
|
|
CanCharge = approach.CanCharge,
|
|
};
|
|
var movement = new MovementStruct
|
|
{
|
|
ObjectId = approach.Target.ServerGuid,
|
|
TopLevelId = approach.Target.ServerGuid,
|
|
Pos = new Position(
|
|
approach.Player.CellId,
|
|
approach.Target.Entity.Position,
|
|
System.Numerics.Quaternion.Identity),
|
|
Params = parameters,
|
|
Type = approach.IsCloseRange
|
|
? MovementType.TurnToObject
|
|
: MovementType.MoveToObject,
|
|
Radius = approach.TargetRadius,
|
|
Height = approach.TargetHeight,
|
|
};
|
|
|
|
// PerformMovement cancels at its head. Do it explicitly before the
|
|
// intent is armed so cancellation of the preceding move cannot clear
|
|
// the new request; the internal second call is then a retail no-op.
|
|
controller.Movement.CancelMoveTo(WeenieError.ActionCancelled);
|
|
if (!_approachTokens.TryBeginApproach(out PlayerApproachToken token))
|
|
return false;
|
|
armAfterCancel?.Invoke(token);
|
|
|
|
// P1's wire MoveToObject store marks the command non-autonomous.
|
|
// The speculative local install must do the same or the next raw-input
|
|
// pump overwrites it before ACE's authoritative movement arrives.
|
|
controller.SetLastMoveWasAutonomous(false);
|
|
return controller.Movement.PerformMovement(movement) == WeenieError.None;
|
|
}
|
|
}
|