From 151770ccf145495de5a0b04f4e04e10eda8909c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=B6eh=20Matt?= <5415177+ZehMatt@users.noreply.github.com> Date: Mon, 7 Mar 2022 12:03:13 +0200 Subject: [PATCH] Separate global vs world rng functions and use custom prng --- apps/openmw/mwworld/worldimp.cpp | 22 +++++++------- components/misc/rng.cpp | 28 ++++++++++++++++-- components/misc/rng.hpp | 51 +++++++++++++++++++++++++++----- 3 files changed, 81 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index afb248bf08..16eb5f3b9b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -338,6 +338,10 @@ namespace MWWorld void World::write (ESM::ESMWriter& writer, Loading::Listener& progress) const { + writer.startRecord(ESM::REC_RAND); + writer.writeHNT("RAND", mPrng.getSeed()); + writer.endRecord(ESM::REC_RAND); + // Active cells could have a dirty fog of war, sync it to the CellStore first for (CellStore* cellstore : mWorldScene->getActiveCells()) { @@ -359,12 +363,6 @@ namespace MWWorld writer.writeHNT("LEVT", mLevitationEnabled); writer.endRecord(ESM::REC_ENAB); - std::stringstream ssPrng; - ssPrng << mPrng; - writer.startRecord(ESM::REC_RAND); - writer.writeHString(ssPrng.str()); - writer.endRecord(ESM::REC_RAND); - writer.startRecord(ESM::REC_CAM_); writer.writeHNT("FIRS", isFirstPerson()); writer.endRecord(ESM::REC_CAM_); @@ -384,10 +382,11 @@ namespace MWWorld return; case ESM::REC_RAND: { - std::stringstream ssPrng; - ssPrng << reader.getHString(); - ssPrng.seekg(0); - ssPrng >> mPrng; + Misc::Rng::Generator::result_type seed{}; + reader.getHNT(seed, "RAND"); + Log(Debug::Info) << "---- World random state: " << seed << " ----"; + mPrng.seed(seed); + Misc::Rng::getGenerator().seed(seed); } break; case ESM::REC_PLAY: @@ -3723,9 +3722,10 @@ namespace MWWorld static int iNumberCreatures = mStore.get().find("iNumberCreatures")->mValue.getInteger(); int numCreatures = 1 + Misc::Rng::rollDice(iNumberCreatures); // [1, iNumberCreatures] + auto& prng = MWBase::Environment::get().getWorld()->getPrng(); for (int i=0; i #include +#include + namespace Misc::Rng { static Generator sGenerator; @@ -12,29 +14,51 @@ namespace Misc::Rng return sGenerator; } + unsigned int generateDefaultSeed() + { + auto res = static_cast(std::chrono::high_resolution_clock::now().time_since_epoch().count()); + Log(Debug::Info) << __FUNCTION__ << ": " << res; + return res; + } + void init(unsigned int seed) { sGenerator.seed(seed); } + float rollProbability() + { + return std::uniform_real_distribution(0, 1 - std::numeric_limits::epsilon())(getGenerator()); + } + float rollProbability(Generator& prng) { return std::uniform_real_distribution(0, 1 - std::numeric_limits::epsilon())(prng); } + float rollClosedProbability() + { + return std::uniform_real_distribution(0, 1)(getGenerator()); + } + float rollClosedProbability(Generator& prng) { return std::uniform_real_distribution(0, 1)(prng); } + int rollDice(int max) + { + return max > 0 ? std::uniform_int_distribution(0, max - 1)(getGenerator()) : 0; + } + int rollDice(int max, Generator& prng) { return max > 0 ? std::uniform_int_distribution(0, max - 1)(prng) : 0; } - unsigned int generateDefaultSeed() + float deviate(float mean, float deviation) { - return static_cast(std::chrono::high_resolution_clock::now().time_since_epoch().count()); + return std::uniform_real_distribution(mean - deviation, mean + deviation)(getGenerator()); } float deviate(float mean, float deviation, Generator& prng) diff --git a/components/misc/rng.hpp b/components/misc/rng.hpp index 8d300f0913..1b7831e3c6 100644 --- a/components/misc/rng.hpp +++ b/components/misc/rng.hpp @@ -9,8 +9,41 @@ */ namespace Misc::Rng { + class Generator + { + uint32_t mState{}; - using Generator = std::mt19937; + public: + using result_type = uint32_t; + + constexpr Generator() = default; + constexpr Generator(result_type seed) : mState{ seed } {} + constexpr result_type operator()() noexcept + { + mState = (214013 * mState + 2531011); + return (mState >> 16) & max(); + } + + static constexpr result_type min() noexcept + { + return 0u; + } + + static constexpr result_type max() noexcept + { + return 0x7FFFu; + } + + void seed(result_type val) noexcept + { + mState = val; + } + + uint32_t getSeed() const noexcept + { + return mState; + } + }; Generator& getGenerator(); @@ -21,19 +54,23 @@ namespace Misc::Rng void init(unsigned int seed = generateDefaultSeed()); /// return value in range [0.0f, 1.0f) <- note open upper range. - float rollProbability(Generator& prng = getGenerator()); + float rollProbability(); + float rollProbability(Generator& prng); /// return value in range [0.0f, 1.0f] <- note closed upper range. - float rollClosedProbability(Generator& prng = getGenerator()); + float rollClosedProbability(); + float rollClosedProbability(Generator& prng); /// return value in range [0, max) <- note open upper range. - int rollDice(int max, Generator& prng = getGenerator()); + int rollDice(int max); + int rollDice(int max, Generator& prng); /// return value in range [0, 99] - inline int roll0to99(Generator& prng = getGenerator()) { return rollDice(100, prng); } - - float deviate(float mean, float deviation, Generator& prng = getGenerator()); + inline int roll0to99(Generator& prng) { return rollDice(100, prng); } + inline int roll0to99() { return rollDice(100); } + float deviate(float mean, float deviation); + float deviate(float mean, float deviation, Generator& prng); } #endif