neon-sprawl/server/NeonSprawl.Server/Game/Factions/FactionStandingApi.cs

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(
statusCode: StatusCodes.Status500InternalServerError,
title: "Faction standing read failed",
detail: snapshotResult.ReasonCode),
_ => 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);
}