// MIT License - Copyright (c) 2025 wallstop
// Full license text: https://github.com/wallstop/unity-helpers/blob/main/LICENSE
namespace WallstopStudios.UnityHelpers.Core.Random
{
using System;
using System.Runtime.Serialization;
using System.Text.Json.Serialization;
using ProtoBuf;
///
/// WaveSplat: a one-word chaotic generator that increments by a fixed large constant and emits rotated high bits.
///
///
///
/// Reference: Will Stafford Parsons (wileylooper/wavesplat, repository offline). The generator maintains a single 64-bit state, adds a
/// Weyl-style increment of 11,111,111,111,111,111 each step, and returns bits shifted by a dynamic amount
/// derived from the low nibble of the state.
///
/// Pros:
///
/// - Tiny state footprint (one 64-bit word) with excellent cache locality.
/// - Deterministic and serializable via .
///
/// Cons:
///
/// - Not a statistically rigorous generator; treat as a fun chaotic mixer.
/// - Not cryptographically secure.
///
/// When to use:
///
/// - Quick procedural effects where minimal overhead matters.
///
/// When not to use:
///
/// - Simulation-grade workloads or anything security sensitive.
///
///
///
///
/// using WallstopStudios.UnityHelpers.Core.Random;
///
/// WaveSplatRandom rng = new WaveSplatRandom(seed: 0xCAFEBABEUL);
/// uint value = rng.NextUint();
/// float normalized = rng.NextFloat();
///
///
[RandomGeneratorMetadata(
RandomQuality.Experimental,
"Single-word chaotic generator; author notes period 2^64 but provides no formal test results—treat as experimental.",
"Will Stafford Parsons",
"" // Original repository wileylooper/wavesplat is offline
)]
[Serializable]
[DataContract]
[ProtoContract]
public sealed class WaveSplatRandom : AbstractRandom
{
private const ulong Increment = 11_111_111_111_111_111UL;
private const ulong DefaultGuidSeed = 0x9E3779B97F4A7C15UL;
private const int ShiftMask = 15;
private const int ShiftBase = 16;
public static WaveSplatRandom Instance => ThreadLocalRandom.Instance;
public override RandomState InternalState => BuildState(_state);
[ProtoMember(6)]
private ulong _state;
public WaveSplatRandom()
: this(Guid.NewGuid()) { }
public WaveSplatRandom(Guid guid)
{
InitializeFromGuid(guid);
}
public WaveSplatRandom(ulong seed)
{
_state = seed;
}
public WaveSplatRandom(uint seed)
: this((ulong)seed) { }
[JsonConstructor]
public WaveSplatRandom(RandomState internalState)
{
_state = internalState.State1;
RestoreCommonState(internalState);
}
public override uint NextUint()
{
unchecked
{
_state += Increment;
int shift = (int)((_state & ShiftMask) + ShiftBase);
ulong value = _state >> shift;
return (uint)value;
}
}
public override IRandom Copy()
{
return new WaveSplatRandom(InternalState);
}
private void InitializeFromGuid(Guid guid)
{
(ulong seedA, ulong seedB) = RandomUtilities.GuidToUInt64Pair(guid);
ulong combined = seedA ^ seedB;
if (combined == 0UL)
{
combined = seedA != 0UL ? seedA : DefaultGuidSeed;
}
_state = combined;
}
}
}