1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-03-01 07:09:41 +00:00

Separate global vs world rng functions and use custom prng

This commit is contained in:
ζeh Matt 2022-03-07 12:03:13 +02:00
parent 08fae7be6e
commit 151770ccf1
No known key found for this signature in database
GPG key ID: 18CE582C71A225B0
3 changed files with 81 additions and 20 deletions

View file

@ -338,6 +338,10 @@ namespace MWWorld
void World::write (ESM::ESMWriter& writer, Loading::Listener& progress) const 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 // Active cells could have a dirty fog of war, sync it to the CellStore first
for (CellStore* cellstore : mWorldScene->getActiveCells()) for (CellStore* cellstore : mWorldScene->getActiveCells())
{ {
@ -359,12 +363,6 @@ namespace MWWorld
writer.writeHNT("LEVT", mLevitationEnabled); writer.writeHNT("LEVT", mLevitationEnabled);
writer.endRecord(ESM::REC_ENAB); 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.startRecord(ESM::REC_CAM_);
writer.writeHNT("FIRS", isFirstPerson()); writer.writeHNT("FIRS", isFirstPerson());
writer.endRecord(ESM::REC_CAM_); writer.endRecord(ESM::REC_CAM_);
@ -384,10 +382,11 @@ namespace MWWorld
return; return;
case ESM::REC_RAND: case ESM::REC_RAND:
{ {
std::stringstream ssPrng; Misc::Rng::Generator::result_type seed{};
ssPrng << reader.getHString(); reader.getHNT(seed, "RAND");
ssPrng.seekg(0); Log(Debug::Info) << "---- World random state: " << seed << " ----";
ssPrng >> mPrng; mPrng.seed(seed);
Misc::Rng::getGenerator().seed(seed);
} }
break; break;
case ESM::REC_PLAY: case ESM::REC_PLAY:
@ -3723,9 +3722,10 @@ namespace MWWorld
static int iNumberCreatures = mStore.get<ESM::GameSetting>().find("iNumberCreatures")->mValue.getInteger(); static int iNumberCreatures = mStore.get<ESM::GameSetting>().find("iNumberCreatures")->mValue.getInteger();
int numCreatures = 1 + Misc::Rng::rollDice(iNumberCreatures); // [1, iNumberCreatures] int numCreatures = 1 + Misc::Rng::rollDice(iNumberCreatures); // [1, iNumberCreatures]
auto& prng = MWBase::Environment::get().getWorld()->getPrng();
for (int i=0; i<numCreatures; ++i) for (int i=0; i<numCreatures; ++i)
{ {
std::string selectedCreature = MWMechanics::getLevelledItem(list, true); std::string selectedCreature = MWMechanics::getLevelledItem(list, true, prng);
if (selectedCreature.empty()) if (selectedCreature.empty())
continue; continue;

View file

@ -3,6 +3,8 @@
#include <chrono> #include <chrono>
#include <random> #include <random>
#include <components/debug/debuglog.hpp>
namespace Misc::Rng namespace Misc::Rng
{ {
static Generator sGenerator; static Generator sGenerator;
@ -12,29 +14,51 @@ namespace Misc::Rng
return sGenerator; return sGenerator;
} }
unsigned int generateDefaultSeed()
{
auto res = static_cast<unsigned int>(std::chrono::high_resolution_clock::now().time_since_epoch().count());
Log(Debug::Info) << __FUNCTION__ << ": " << res;
return res;
}
void init(unsigned int seed) void init(unsigned int seed)
{ {
sGenerator.seed(seed); sGenerator.seed(seed);
} }
float rollProbability()
{
return std::uniform_real_distribution<float>(0, 1 - std::numeric_limits<float>::epsilon())(getGenerator());
}
float rollProbability(Generator& prng) float rollProbability(Generator& prng)
{ {
return std::uniform_real_distribution<float>(0, 1 - std::numeric_limits<float>::epsilon())(prng); return std::uniform_real_distribution<float>(0, 1 - std::numeric_limits<float>::epsilon())(prng);
} }
float rollClosedProbability()
{
return std::uniform_real_distribution<float>(0, 1)(getGenerator());
}
float rollClosedProbability(Generator& prng) float rollClosedProbability(Generator& prng)
{ {
return std::uniform_real_distribution<float>(0, 1)(prng); return std::uniform_real_distribution<float>(0, 1)(prng);
} }
int rollDice(int max)
{
return max > 0 ? std::uniform_int_distribution<int>(0, max - 1)(getGenerator()) : 0;
}
int rollDice(int max, Generator& prng) int rollDice(int max, Generator& prng)
{ {
return max > 0 ? std::uniform_int_distribution<int>(0, max - 1)(prng) : 0; return max > 0 ? std::uniform_int_distribution<int>(0, max - 1)(prng) : 0;
} }
unsigned int generateDefaultSeed() float deviate(float mean, float deviation)
{ {
return static_cast<unsigned int>(std::chrono::high_resolution_clock::now().time_since_epoch().count()); return std::uniform_real_distribution<float>(mean - deviation, mean + deviation)(getGenerator());
} }
float deviate(float mean, float deviation, Generator& prng) float deviate(float mean, float deviation, Generator& prng)

View file

@ -9,8 +9,41 @@
*/ */
namespace Misc::Rng 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(); Generator& getGenerator();
@ -21,19 +54,23 @@ namespace Misc::Rng
void init(unsigned int seed = generateDefaultSeed()); void init(unsigned int seed = generateDefaultSeed());
/// return value in range [0.0f, 1.0f) <- note open upper range. /// 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. /// 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. /// 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] /// return value in range [0, 99]
inline int roll0to99(Generator& prng = getGenerator()) { return rollDice(100, prng); } inline int roll0to99(Generator& prng) { return rollDice(100, prng); }
inline int roll0to99() { return rollDice(100); }
float deviate(float mean, float deviation, Generator& prng = getGenerator());
float deviate(float mean, float deviation);
float deviate(float mean, float deviation, Generator& prng);
} }
#endif #endif