#pragma once #include namespace bs { // Small deterministic PRNG (SplitMix64 seeding + xoshiro128**). Unlike // distributions its output is identical on every platform, so the server and // all clients generate the same zone from the same seed. class Rng { public: explicit Rng(uint64_t seed = 1) { reseed(seed); } void reseed(uint64_t seed) { for (uint32_t& s : s_) { seed += 0x9E3779B97F4A7C15ull; uint64_t z = seed; z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9ull; z = (z ^ (z >> 27)) * 0x94D049BB133111EBull; s = uint32_t(z ^ (z >> 31)) | 1u; } } uint32_t next() { const uint32_t result = rotl(s_[1] * 5, 7) * 9; const uint32_t t = s_[1] << 9; s_[2] ^= s_[0]; s_[3] ^= s_[1]; s_[1] ^= s_[2]; s_[0] ^= s_[3]; s_[2] ^= t; s_[3] = rotl(s_[3], 11); return result; } float uniform() { return float(next() >> 8) * (1.0f / 16777216.0f); } // [0, 1) float range(float a, float b) { return a + (b - a) * uniform(); } int range(int a, int bInclusive) { return a + int(next() % uint32_t(bInclusive - a + 1)); } bool chance(float p) { return uniform() < p; } private: static uint32_t rotl(uint32_t x, int k) { return (x << k) | (x >> (32 - k)); } uint32_t s_[4]; }; // Stable 32-bit hash for strings/ids (FNV-1a). inline uint32_t hash32(const char* s) { uint32_t h = 2166136261u; for (; *s; ++s) h = (h ^ uint8_t(*s)) * 16777619u; return h; } } // namespace bs