101 lines
4.0 KiB
C#
101 lines
4.0 KiB
C#
using NeonSprawl.Server.Game.Contracts;
|
|
using NeonSprawl.Server.Game.Factions;
|
|
|
|
namespace NeonSprawl.Server.Game.Rewards;
|
|
|
|
/// <summary>Id normalization and composite keys for reward delivery stores (NEO-126).</summary>
|
|
public static class RewardDeliveryIds
|
|
{
|
|
/// <summary>Trim + lowercase; empty when input is null/whitespace.</summary>
|
|
public static string NormalizePlayerId(string? playerId)
|
|
{
|
|
var trimmed = playerId?.Trim();
|
|
if (string.IsNullOrEmpty(trimmed))
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
return trimmed.ToLowerInvariant();
|
|
}
|
|
|
|
/// <summary>Trim + lowercase; empty when input is null/whitespace.</summary>
|
|
public static string NormalizeQuestId(string? questId) => NormalizePlayerId(questId);
|
|
|
|
/// <summary>Trim + lowercase; empty when input is null/whitespace.</summary>
|
|
public static string NormalizeContractInstanceId(string? contractInstanceId) =>
|
|
ContractInstanceIds.NormalizeContractInstanceId(contractInstanceId);
|
|
|
|
/// <summary>Stable idempotency key for quest completion delivery.</summary>
|
|
public static string MakeIdempotencyKey(string? playerId, string? questId)
|
|
{
|
|
var p = NormalizePlayerId(playerId);
|
|
var q = NormalizeQuestId(questId);
|
|
if (p.Length == 0 || q.Length == 0)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
return $"{p}:quest_complete:{q}";
|
|
}
|
|
|
|
/// <summary>Stable audit row id for one rep grant on a quest completion delivery (NEO-138).</summary>
|
|
public static string MakeReputationDeltaId(string idempotencyKey, string? factionId)
|
|
{
|
|
var faction = FactionStandingIds.NormalizeFactionId(factionId);
|
|
if (idempotencyKey.Length == 0 || faction.Length == 0)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
return $"{idempotencyKey}:rep:{faction}";
|
|
}
|
|
|
|
/// <summary>Rollback audit row id for compensating rep revert (NEO-138).</summary>
|
|
public static string MakeReputationRollbackDeltaId(string reputationDeltaId) =>
|
|
reputationDeltaId.Length == 0 ? string.Empty : $"{reputationDeltaId}:rollback";
|
|
|
|
/// <summary>Composite store key for quest completion delivery.</summary>
|
|
public static string MakeStoreKey(string? playerId, string? questId) =>
|
|
MakeStoreKey(playerId, RewardDeliverySourceKinds.QuestCompletion, questId);
|
|
|
|
/// <summary>Composite store key for <paramref name="playerId"/> + <paramref name="sourceKind"/> + source id.</summary>
|
|
public static string MakeStoreKey(string? playerId, string? sourceKind, string? sourceId)
|
|
{
|
|
var p = NormalizePlayerId(playerId);
|
|
var kind = NormalizeSourceKind(sourceKind);
|
|
var id = NormalizeSourceId(sourceKind, sourceId);
|
|
if (p.Length == 0 || kind.Length == 0 || id.Length == 0)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
return $"{p}\0{kind}\0{id}";
|
|
}
|
|
|
|
/// <summary>Resolves the source id field for a persisted delivery event.</summary>
|
|
public static string GetSourceId(in RewardDeliveryEvent deliveryEvent) =>
|
|
string.Equals(deliveryEvent.SourceKind, RewardDeliverySourceKinds.ContractCompletion, StringComparison.Ordinal)
|
|
? NormalizeContractInstanceId(deliveryEvent.ContractInstanceId)
|
|
: NormalizeQuestId(deliveryEvent.QuestId);
|
|
|
|
/// <summary>Composite store key for a persisted delivery event.</summary>
|
|
public static string MakeStoreKey(in RewardDeliveryEvent deliveryEvent) =>
|
|
MakeStoreKey(deliveryEvent.PlayerId, deliveryEvent.SourceKind, GetSourceId(deliveryEvent));
|
|
|
|
private static string NormalizeSourceKind(string? sourceKind)
|
|
{
|
|
var trimmed = sourceKind?.Trim();
|
|
if (string.IsNullOrEmpty(trimmed))
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
return trimmed.ToLowerInvariant();
|
|
}
|
|
|
|
private static string NormalizeSourceId(string? sourceKind, string? sourceId) =>
|
|
string.Equals(sourceKind, RewardDeliverySourceKinds.ContractCompletion, StringComparison.OrdinalIgnoreCase)
|
|
? NormalizeContractInstanceId(sourceId)
|
|
: NormalizeQuestId(sourceId);
|
|
}
|