using NeonSprawl.Server.Game.PositionState; using NeonSprawl.Server.Game.World; namespace NeonSprawl.Server.Game.Targeting; /// Computes from authoritative position + persisted lock (NEO-23). public static class PlayerTargetStateReader { public static string ComputeValidity(string? lockIdLowercase, in PositionSnapshot snap) { if (string.IsNullOrEmpty(lockIdLowercase)) { return TargetValidity.None; } if (!PrototypeTargetRegistry.TryGet(lockIdLowercase, out var entry)) { return TargetValidity.InvalidTarget; } if (!HorizontalReach.IsWithinHorizontalRadius(snap.X, snap.Z, entry.X, entry.Z, entry.LockRadius)) { return TargetValidity.OutOfRange; } return TargetValidity.Ok; } public static PlayerTargetStateResponse Build(string routePlayerId, string? lockIdLowercase, int sequence, in PositionSnapshot snap) => new() { SchemaVersion = PlayerTargetStateResponse.CurrentSchemaVersion, PlayerId = routePlayerId, LockedTargetId = lockIdLowercase, Validity = ComputeValidity(lockIdLowercase, in snap), Sequence = sequence, }; }