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

65 lines
2.5 KiB
C#

using NeonSprawl.Server.Game.Quests;
namespace NeonSprawl.Server.Game.Factions;
/// <summary>
/// Evaluates <see cref="FactionGateRuleRow"/> minimum-standing gates (NEO-137).
/// Quest accept wiring: <see cref="QuestStateOperations.TryAccept"/>.
/// NEO-141 telemetry hook site: deny return path below.
/// </summary>
public static class FactionGateOperations
{
/// <summary>
/// All rules must pass (AND). Empty rules succeed immediately.
/// Compares player standing vs <see cref="FactionGateRuleRow.MinStanding"/> with <c>standing &gt;= minStanding</c>.
/// </summary>
public static FactionGateEvaluateOutcome TryEvaluate(
string playerId,
IReadOnlyList<FactionGateRuleRow> rules,
IFactionStandingStore standingStore)
{
var normalizedPlayerId = FactionStandingIds.NormalizePlayerId(playerId);
if (rules.Count == 0)
{
return Success();
}
foreach (var rule in rules)
{
var factionId = FactionStandingIds.NormalizeFactionId(rule.FactionId);
var read = standingStore.TryGetStanding(normalizedPlayerId, factionId);
if (!read.Success)
{
// --- Telemetry hook site (NEO-141): future E9.M1 catalog event `faction_gate_blocked` ---
// TODO(E9.M1): catalog emit — ops reasonCode (e.g. unknown_faction), playerId, factionId, minStanding, currentStanding (null).
// No ingest or ILogger here (comments-only).
return Deny(read.ReasonCode, factionId, rule.MinStanding, null);
}
if (read.Standing < rule.MinStanding)
{
// --- Telemetry hook site (NEO-141): future E9.M1 catalog event `faction_gate_blocked` ---
// TODO(E9.M1): catalog emit — ops reasonCode (gate_blocked), playerId, factionId, minStanding, currentStanding.
// No ingest or ILogger here (comments-only).
return Deny(
FactionGateEvaluateReasonCodes.GateBlocked,
factionId,
rule.MinStanding,
read.Standing);
}
}
return Success();
}
private static FactionGateEvaluateOutcome Success() =>
new(true, null, null, null, null);
private static FactionGateEvaluateOutcome Deny(
string? reasonCode,
string factionId,
int minStanding,
int? currentStanding) =>
new(false, reasonCode, factionId, minStanding, currentStanding);
}