🎲 Crafting — Random¶
The Random folder contains runtime implementations of IRandomProvider, used by the
Crafting system for all chance-based rolls.
This abstraction enables deterministic tests and replayable chance outcomes and allows custom RNG behaviour, while keeping Crafting decoupled from Unity’s global random state.
Truth-pass note: This README reflects behaviour implemented by the current runtime. Determinism depends on configuration and on the RNG call sequence remaining unchanged.
🎯 Purpose¶
Crafting supports probabilistic outputs (for example, a 10% chance of a rare drop).
To keep outcomes testable and replayable, all randomness flows through the
IRandomProvider abstraction rather than calling UnityEngine.Random directly.
This provides:
- No hidden coupling to Unity’s global RNG state (unless you choose to use it)
- Reproducible results when seeded and the RNG call sequence is unchanged
- A clean seam for multiplayer, replay, or test systems
The implementations in this folder are internal defaults. Custom RNG behaviour should be supplied by consumers via their own
IRandomProviderimplementations.
🧩 Implementations¶
UnityRandomProvider¶
- Uses
UnityEngine.Random.valuefor each roll. - Suitable for live gameplay where coupling to Unity’s global RNG is acceptable.
- Any system modifying
UnityEngine.Random.statewill influence Crafting outcomes.
SeededRandomProvider¶
- Lightweight XorShift-based RNG implementation.
- Deterministic per instance given the same seed and call sequence.
- Enforces a non-zero internal state even if
0is supplied as the seed. - Produces uniform floats in
[0,1)using the top 24 bits of the PRNG (~16 million discrete values).
Selected when:
deterministicRng == true, orCraftingServiceCore.UseDeterministicRng(seed)is called
Determinism applies to:
- Chance outputs (per-craft rolls)
- Per-craft rolls inside batches when using exact mode and a deterministic RNG
Note: Determinism is not bit-identical when binomial approximation is enabled for large batches (see below).
⚙️ RNG selection in CraftingServiceCore¶
The crafting service selects its RNG using this precedence:
-
Custom RNG component
IfrandomProviderComponentis assigned and implementsIRandomProvider, it is used during dependency resolution. -
Deterministic RNG
When deterministic mode is enabled, the service creates:SeededRandomProvider(seed). -
Unity RNG (default)
Otherwise the service falls back to:UnityRandomProvider().
You may switch RNGs at runtime:
// Deterministic (replay-safe when call order is unchanged)
craftingService.UseDeterministicRng(seed: 12345);
// Back to UnityEngine.Random
craftingService.UseUnityRng();
Assigning a custom IRandomProvider component takes priority during dependency resolution.
Calling UseDeterministicRng() or UseUnityRng() overrides the active RNG instance.
🔒 RNG contract¶
public interface IRandomProvider
{
float Value01(); // uniform value in [0,1)
}
Crafting calls Value01() for every probabilistic check.
Chance outputs are evaluated:
- At delivery time: one roll per craft (unless approximation is enabled)
- During space preflight: via policy-based space budgeting (no RNG calls)
No chance rolls occur at accept time in the current implementation.
📦 Batched crafts and RNG¶
Large batch crafts can optionally trade bit-identical determinism for performance.
Exact mode (default)¶
When:
enableBinomialApprox == false, orbatchCount < binomialApproxThreshold
Crafting performs one RNG roll per craft inside the batch.
This mode is deterministic when using SeededRandomProvider and an unchanged RNG call sequence.
Approximation mode (optional)¶
When:
enableBinomialApprox == true, andbatchCount >= binomialApproxThreshold(default:512)
Crafting performs a single approximate binomial draw instead of per-craft rolls.
- Significantly reduces RNG calls for very large batches
- Preserves statistical expectation
- Not bit-identical, even with deterministic RNG enabled
To guarantee deterministic replays, disable binomial approximation.
🧪 Usage tips¶
- RNG providers manage their own internal state; Crafting never mutates it directly.
- For deterministic tests or lockstep / rollback multiplayer, seed a deterministic provider explicitly.
- For unit testing, provide a stub RNG:
public sealed class AlwaysSuccess : IRandomProvider
{
// Very close to 1.0f, but still inside [0,1)
public float Value01() => 0.9999999f;
}
- To simulate guaranteed failure, return
0f. - For cryptographically secure randomness, implement your own
IRandomProvider.
These RNG abstractions ensure crafting chance outcomes remain reproducible, testable, and isolated from Unity’s global random state when desired.