100 lines
3.6 KiB
C#
100 lines
3.6 KiB
C#
using NeonSprawl.Server.Game.PositionState;
|
|
|
|
namespace NeonSprawl.Server.Game.Factions;
|
|
|
|
/// <summary>Maps <c>GET /game/players/{{id}}/faction-standing</c> — read snapshot (NEO-139).</summary>
|
|
public static class FactionStandingApi
|
|
{
|
|
public static WebApplication MapFactionStandingApi(this WebApplication app)
|
|
{
|
|
app.MapGet(
|
|
"/game/players/{id}/faction-standing",
|
|
(string id, IPositionStateStore positions, IFactionDefinitionRegistry factionRegistry,
|
|
IFactionStandingStore standingStore) =>
|
|
{
|
|
var trimmedId = id.Trim();
|
|
if (trimmedId.Length == 0 || !positions.TryGetPosition(trimmedId, out _))
|
|
{
|
|
return Results.NotFound();
|
|
}
|
|
|
|
var snapshotResult = TryBuildSnapshot(trimmedId, factionRegistry, standingStore);
|
|
return snapshotResult.Kind switch
|
|
{
|
|
FactionStandingSnapshotBuildKind.Success => Results.Json(snapshotResult.Response),
|
|
FactionStandingSnapshotBuildKind.StoreReadFailed =>
|
|
Results.Problem(
|
|
detail: snapshotResult.ReasonCode,
|
|
statusCode: StatusCodes.Status500InternalServerError,
|
|
title: "Faction standing read failed"),
|
|
_ => throw new InvalidOperationException($"Unexpected build outcome: {snapshotResult.Kind}"),
|
|
};
|
|
});
|
|
|
|
return app;
|
|
}
|
|
|
|
internal static FactionStandingSnapshotResponse BuildSnapshot(
|
|
string playerId,
|
|
IFactionDefinitionRegistry factionRegistry,
|
|
IFactionStandingStore standingStore)
|
|
{
|
|
var result = TryBuildSnapshot(playerId, factionRegistry, standingStore);
|
|
if (result.Kind != FactionStandingSnapshotBuildKind.Success || result.Response is null)
|
|
{
|
|
throw new InvalidOperationException(
|
|
$"BuildSnapshot failed: {result.ReasonCode ?? result.Kind.ToString()}");
|
|
}
|
|
|
|
return result.Response;
|
|
}
|
|
|
|
private static FactionStandingSnapshotBuildResult TryBuildSnapshot(
|
|
string playerId,
|
|
IFactionDefinitionRegistry factionRegistry,
|
|
IFactionStandingStore standingStore)
|
|
{
|
|
var defs = factionRegistry.GetDefinitionsInIdOrder();
|
|
var factions = new List<FactionStandingRowJson>(defs.Count);
|
|
foreach (var definition in defs)
|
|
{
|
|
var outcome = standingStore.TryGetStanding(playerId, definition.Id);
|
|
if (!outcome.Success)
|
|
{
|
|
return new FactionStandingSnapshotBuildResult(
|
|
FactionStandingSnapshotBuildKind.StoreReadFailed,
|
|
null,
|
|
outcome.ReasonCode);
|
|
}
|
|
|
|
factions.Add(
|
|
new FactionStandingRowJson
|
|
{
|
|
Id = definition.Id,
|
|
Standing = outcome.Standing,
|
|
});
|
|
}
|
|
|
|
return new FactionStandingSnapshotBuildResult(
|
|
FactionStandingSnapshotBuildKind.Success,
|
|
new FactionStandingSnapshotResponse
|
|
{
|
|
PlayerId = playerId,
|
|
Factions = factions,
|
|
SchemaVersion = FactionStandingSnapshotResponse.CurrentSchemaVersion,
|
|
},
|
|
null);
|
|
}
|
|
|
|
private enum FactionStandingSnapshotBuildKind
|
|
{
|
|
Success,
|
|
StoreReadFailed,
|
|
}
|
|
|
|
private readonly record struct FactionStandingSnapshotBuildResult(
|
|
FactionStandingSnapshotBuildKind Kind,
|
|
FactionStandingSnapshotResponse? Response,
|
|
string? ReasonCode);
|
|
}
|