77 lines
3.1 KiB
C#
77 lines
3.1 KiB
C#
using System.Text.Json.Serialization;
|
|
using NeonSprawl.Server.Game.PositionState;
|
|
|
|
namespace NeonSprawl.Server.Game.Targeting;
|
|
|
|
/// <summary>JSON body for <c>GET /game/players/{{id}}/target</c> and nested <c>targetState</c> on select (NEO-23).</summary>
|
|
public sealed class PlayerTargetStateResponse
|
|
{
|
|
public const int CurrentSchemaVersion = 1;
|
|
|
|
[JsonPropertyName("schemaVersion")]
|
|
public int SchemaVersion { get; init; } = CurrentSchemaVersion;
|
|
|
|
[JsonPropertyName("playerId")]
|
|
public required string PlayerId { get; init; }
|
|
|
|
/// <summary>Lowercase registry id when locked; JSON <c>null</c> when no lock (key always serialized).</summary>
|
|
[JsonPropertyName("lockedTargetId")]
|
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
|
public string? LockedTargetId { get; init; }
|
|
|
|
/// <summary>One of <see cref="TargetValidity"/> string constants.</summary>
|
|
[JsonPropertyName("validity")]
|
|
public required string Validity { get; init; }
|
|
|
|
[JsonPropertyName("sequence")]
|
|
public int Sequence { get; init; }
|
|
}
|
|
|
|
/// <summary>POST body for <c>POST /game/players/{{id}}/target/select</c> (NEO-23).</summary>
|
|
/// <remarks>
|
|
/// Omit <c>targetId</c> or send JSON <c>null</c> to clear the lock. Whitespace-only after trim → HTTP 400.
|
|
/// </remarks>
|
|
public sealed class TargetSelectRequest
|
|
{
|
|
public const int CurrentSchemaVersion = 1;
|
|
|
|
[JsonPropertyName("schemaVersion")]
|
|
public int SchemaVersion { get; init; }
|
|
|
|
/// <summary>Registry key after trim + case-insensitive lookup; <c>null</c> or omitted ⇒ clear intent.</summary>
|
|
[JsonPropertyName("targetId")]
|
|
public string? TargetId { get; init; }
|
|
|
|
/// <summary>
|
|
/// Optional client-reported current position. When present the server uses these coordinates
|
|
/// for the range check instead of the stored <c>PositionState</c> snapshot, eliminating the
|
|
/// race between <c>move-stream</c> and <c>target/select</c> POSTs (NEO-24 follow-up #5). Purely
|
|
/// advisory: it does <em>not</em> write to the position store (<c>move-stream</c> remains the
|
|
/// only write path). Real combat (E5.M1) will bound the hint against the stored snap / movement
|
|
/// budget so this cannot be used to "teleport" the radius check — prototype does not yet.
|
|
/// </summary>
|
|
[JsonPropertyName("positionHint")]
|
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
|
public PositionVector? PositionHint { get; init; }
|
|
}
|
|
|
|
/// <summary>POST response for target selection (NEO-23).</summary>
|
|
public sealed class TargetSelectResponse
|
|
{
|
|
public const int CurrentSchemaVersion = 1;
|
|
|
|
[JsonPropertyName("schemaVersion")]
|
|
public int SchemaVersion { get; init; } = CurrentSchemaVersion;
|
|
|
|
[JsonPropertyName("selectionApplied")]
|
|
public bool SelectionApplied { get; init; }
|
|
|
|
[JsonPropertyName("targetState")]
|
|
public required PlayerTargetStateResponse TargetState { get; init; }
|
|
|
|
/// <summary>Required when <see cref="SelectionApplied"/> is <c>false</c>; omitted on success.</summary>
|
|
[JsonPropertyName("reasonCode")]
|
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
|
public string? ReasonCode { get; init; }
|
|
}
|