Files
SVSimServer/SVSim.BattleNode/Lifecycle/BattleSeeds.cs
2026-06-04 18:13:06 -04:00

42 lines
1.9 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
namespace SVSim.BattleNode.Lifecycle;
/// <summary>
/// Deterministic per-battle seed derivation. Given one random master seed (chosen once per battle
/// on <see cref="Sessions.Dispatch.BattleSessionState"/>), derives every RNG value the node hands
/// the clients: the shared effect seed (Matched.seed), each side's deck-shuffle RNG seed, and each
/// side's Ready.idxChangeSeed.
///
/// IMPORTANT: uses a fixed splitmix64-style bit-mix, NOT System.HashCode / string.GetHashCode
/// (those are randomized per process). Stability across process runs is what makes "same master
/// seed reproduces the same battle" — the foundation of replay — actually hold.
/// </summary>
internal static class BattleSeeds
{
/// <summary>Shared effect-RNG seed; identical for both sides (it seeds the synced stream).</summary>
public static int Stable(int master) => Derive(master, "stable");
/// <summary>Per-side Ready.idxChangeSeed (client XorShift for mid-battle card-into-deck).</summary>
public static int IdxChange(int master, long viewerId) => Derive(master, "idx", viewerId);
/// <summary>Per-side deck-shuffle RNG seed (node-side FisherYates).</summary>
public static int DeckShuffle(int master, long viewerId) => Derive(master, "deck", viewerId);
/// <summary>Derive a stable non-negative int from (master, tag, discriminator). Pure arithmetic
/// — reproducible across process runs and platforms.</summary>
public static int Derive(int master, string tag, long disc = 0)
{
ulong h = Mix((uint)master);
foreach (char c in tag) h = Mix(h ^ c);
h = Mix(h ^ (ulong)disc);
return (int)(h & 0x7FFFFFFFUL);
}
private static ulong Mix(ulong x)
{
x += 0x9E3779B97F4A7C15UL;
x = (x ^ (x >> 30)) * 0xBF58476D1CE4E5B9UL;
x = (x ^ (x >> 27)) * 0x94D049BB133111EBUL;
return x ^ (x >> 31);
}
}