66 lines
2.4 KiB
C#
66 lines
2.4 KiB
C#
using System.Security.Cryptography;
|
|
using System.Text;
|
|
|
|
namespace NeonSprawl.Server.Game.Contracts;
|
|
|
|
/// <summary>Id normalization for contract instance stores (NEO-146).</summary>
|
|
public static class ContractInstanceIds
|
|
{
|
|
/// <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 NormalizeContractInstanceId(string? contractInstanceId) => NormalizePlayerId(contractInstanceId);
|
|
|
|
/// <summary>Trim + lowercase; empty when input is null/whitespace.</summary>
|
|
public static string NormalizeTemplateId(string? templateId) => NormalizePlayerId(templateId);
|
|
|
|
/// <summary>Trim; empty when input is null/whitespace (seed bucket casing preserved).</summary>
|
|
public static string NormalizeSeedBucket(string? seedBucket)
|
|
{
|
|
var trimmed = seedBucket?.Trim();
|
|
return string.IsNullOrEmpty(trimmed) ? string.Empty : trimmed;
|
|
}
|
|
|
|
/// <summary>Composite store key for <paramref name="playerId"/> + <paramref name="contractInstanceId"/>.</summary>
|
|
public static string MakeInstanceKey(string? playerId, string? contractInstanceId)
|
|
{
|
|
var p = NormalizePlayerId(playerId);
|
|
var i = NormalizeContractInstanceId(contractInstanceId);
|
|
if (p.Length == 0 || i.Length == 0)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
return $"{p}\0{i}";
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deterministic contract instance id from normalized seed inputs (NEO-147).
|
|
/// Format: <c>ci_{32 lowercase hex}</c> from SHA-256 of <c>{playerId}|{templateId}|{seedBucket}</c>.
|
|
/// </summary>
|
|
public static string MakeDeterministicInstanceId(string? playerId, string? templateId, string? seedBucket)
|
|
{
|
|
var p = NormalizePlayerId(playerId);
|
|
var t = NormalizeTemplateId(templateId);
|
|
var b = NormalizeSeedBucket(seedBucket);
|
|
if (p.Length == 0 || t.Length == 0 || b.Length == 0)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
var payload = $"{p}|{t}|{b}";
|
|
var hash = SHA256.HashData(Encoding.UTF8.GetBytes(payload));
|
|
return $"ci_{Convert.ToHexStringLower(hash.AsSpan(0, 16))}";
|
|
}
|
|
}
|