1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-03-17 10:21:11 +00:00

Merge branch 'refactor/prng' into 'master'

Refactor and rename some things around Misc::Rng

See merge request OpenMW/openmw!1710
This commit is contained in:
jvoisin 2022-03-07 10:19:41 +00:00
commit 8a182c130a
5 changed files with 57 additions and 77 deletions

View File

@ -19,14 +19,14 @@ namespace MWMechanics
{ {
/// @return ID of resulting item, or empty if none /// @return ID of resulting item, or empty if none
inline std::string getLevelledItem (const ESM::LevelledListBase* levItem, bool creature, Misc::Rng::Seed& seed = Misc::Rng::getSeed()) inline std::string getLevelledItem (const ESM::LevelledListBase* levItem, bool creature, Misc::Rng::Generator& prng = Misc::Rng::getGenerator())
{ {
const std::vector<ESM::LevelledListBase::LevelItem>& items = levItem->mList; const std::vector<ESM::LevelledListBase::LevelItem>& items = levItem->mList;
const MWWorld::Ptr& player = getPlayer(); const MWWorld::Ptr& player = getPlayer();
int playerLevel = player.getClass().getCreatureStats(player).getLevel(); int playerLevel = player.getClass().getCreatureStats(player).getLevel();
if (Misc::Rng::roll0to99(seed) < levItem->mChanceNone) if (Misc::Rng::roll0to99(prng) < levItem->mChanceNone)
return std::string(); return std::string();
std::vector<std::string> candidates; std::vector<std::string> candidates;
@ -55,7 +55,7 @@ namespace MWMechanics
} }
if (candidates.empty()) if (candidates.empty())
return std::string(); return std::string();
std::string item = candidates[Misc::Rng::rollDice(candidates.size(), seed)]; std::string item = candidates[Misc::Rng::rollDice(candidates.size(), prng)];
// Vanilla doesn't fail on nonexistent items in levelled lists // Vanilla doesn't fail on nonexistent items in levelled lists
if (!MWBase::Environment::get().getWorld()->getStore().find(Misc::StringUtils::lowerCase(item))) if (!MWBase::Environment::get().getWorld()->getStore().find(Misc::StringUtils::lowerCase(item)))
@ -74,9 +74,9 @@ namespace MWMechanics
else else
{ {
if (ref.getPtr().getType() == ESM::ItemLevList::sRecordId) if (ref.getPtr().getType() == ESM::ItemLevList::sRecordId)
return getLevelledItem(ref.getPtr().get<ESM::ItemLevList>()->mBase, false, seed); return getLevelledItem(ref.getPtr().get<ESM::ItemLevList>()->mBase, false, prng);
else else
return getLevelledItem(ref.getPtr().get<ESM::CreatureLevList>()->mBase, true, seed); return getLevelledItem(ref.getPtr().get<ESM::CreatureLevList>()->mBase, true, prng);
} }
} }

View File

@ -514,12 +514,12 @@ int MWWorld::ContainerStore::remove(const Ptr& item, int count, const Ptr& actor
return count - toRemove; return count - toRemove;
} }
void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std::string& owner, Misc::Rng::Seed& seed) void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std::string& owner, Misc::Rng::Generator& prng)
{ {
for (const ESM::ContItem& iter : items.mList) for (const ESM::ContItem& iter : items.mList)
{ {
std::string id = Misc::StringUtils::lowerCase(iter.mItem); std::string id = Misc::StringUtils::lowerCase(iter.mItem);
addInitialItem(id, owner, iter.mCount, &seed); addInitialItem(id, owner, iter.mCount, &prng);
} }
flagAsModified(); flagAsModified();
@ -540,7 +540,7 @@ void MWWorld::ContainerStore::fillNonRandom (const ESM::InventoryList& items, co
} }
void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner, int count, void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner, int count,
Misc::Rng::Seed* seed, bool topLevel) Misc::Rng::Generator* prng, bool topLevel)
{ {
if (count == 0) return; //Don't restock with nothing. if (count == 0) return; //Don't restock with nothing.
try try
@ -548,13 +548,13 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::
ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count); ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count);
if (ref.getPtr().getClass().getScript(ref.getPtr()).empty()) if (ref.getPtr().getClass().getScript(ref.getPtr()).empty())
{ {
addInitialItemImp(ref.getPtr(), owner, count, seed, topLevel); addInitialItemImp(ref.getPtr(), owner, count, prng, topLevel);
} }
else else
{ {
// Adding just one item per time to make sure there isn't a stack of scripted items // Adding just one item per time to make sure there isn't a stack of scripted items
for (int i = 0; i < std::abs(count); i++) for (int i = 0; i < std::abs(count); i++)
addInitialItemImp(ref.getPtr(), owner, count < 0 ? -1 : 1, seed, topLevel); addInitialItemImp(ref.getPtr(), owner, count < 0 ? -1 : 1, prng, topLevel);
} }
} }
catch (const std::exception& e) catch (const std::exception& e)
@ -564,26 +564,26 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::
} }
void MWWorld::ContainerStore::addInitialItemImp(const MWWorld::Ptr& ptr, const std::string& owner, int count, void MWWorld::ContainerStore::addInitialItemImp(const MWWorld::Ptr& ptr, const std::string& owner, int count,
Misc::Rng::Seed* seed, bool topLevel) Misc::Rng::Generator* prng, bool topLevel)
{ {
if (ptr.getType()==ESM::ItemLevList::sRecordId) if (ptr.getType()==ESM::ItemLevList::sRecordId)
{ {
if(!seed) if(!prng)
return; return;
const ESM::ItemLevList* levItemList = ptr.get<ESM::ItemLevList>()->mBase; const ESM::ItemLevList* levItemList = ptr.get<ESM::ItemLevList>()->mBase;
if (topLevel && std::abs(count) > 1 && levItemList->mFlags & ESM::ItemLevList::Each) if (topLevel && std::abs(count) > 1 && levItemList->mFlags & ESM::ItemLevList::Each)
{ {
for (int i=0; i<std::abs(count); ++i) for (int i=0; i<std::abs(count); ++i)
addInitialItem(ptr.getCellRef().getRefId(), owner, count > 0 ? 1 : -1, seed, true); addInitialItem(ptr.getCellRef().getRefId(), owner, count > 0 ? 1 : -1, prng, true);
return; return;
} }
else else
{ {
std::string itemId = MWMechanics::getLevelledItem(ptr.get<ESM::ItemLevList>()->mBase, false, *seed); std::string itemId = MWMechanics::getLevelledItem(ptr.get<ESM::ItemLevList>()->mBase, false, *prng);
if (itemId.empty()) if (itemId.empty())
return; return;
addInitialItem(itemId, owner, count, seed, false); addInitialItem(itemId, owner, count, prng, false);
} }
} }
else else
@ -619,8 +619,8 @@ void MWWorld::ContainerStore::resolve()
{ {
for(const auto&& ptr : *this) for(const auto&& ptr : *this)
ptr.getRefData().setCount(0); ptr.getRefData().setCount(0);
Misc::Rng::Seed seed{mSeed}; Misc::Rng::Generator prng{mSeed};
fill(mPtr.get<ESM::Container>()->mBase->mInventory, "", seed); fill(mPtr.get<ESM::Container>()->mBase->mInventory, "", prng);
addScripts(*this, mPtr.mCell); addScripts(*this, mPtr.mCell);
} }
mModified = true; mModified = true;
@ -640,8 +640,8 @@ MWWorld::ResolutionHandle MWWorld::ContainerStore::resolveTemporarily()
{ {
for(const auto&& ptr : *this) for(const auto&& ptr : *this)
ptr.getRefData().setCount(0); ptr.getRefData().setCount(0);
Misc::Rng::Seed seed{mSeed}; Misc::Rng::Generator prng{mSeed};
fill(mPtr.get<ESM::Container>()->mBase->mInventory, "", seed); fill(mPtr.get<ESM::Container>()->mBase->mInventory, "", prng);
addScripts(*this, mPtr.mCell); addScripts(*this, mPtr.mCell);
} }
return {listener}; return {listener};

View File

@ -126,8 +126,8 @@ namespace MWWorld
std::weak_ptr<ResolutionListener> mResolutionListener; std::weak_ptr<ResolutionListener> mResolutionListener;
ContainerStoreIterator addImp (const Ptr& ptr, int count, bool markModified = true); ContainerStoreIterator addImp (const Ptr& ptr, int count, bool markModified = true);
void addInitialItem (const std::string& id, const std::string& owner, int count, Misc::Rng::Seed* seed, bool topLevel=true); void addInitialItem (const std::string& id, const std::string& owner, int count, Misc::Rng::Generator* prng, bool topLevel=true);
void addInitialItemImp (const MWWorld::Ptr& ptr, const std::string& owner, int count, Misc::Rng::Seed* seed, bool topLevel=true); void addInitialItemImp (const MWWorld::Ptr& ptr, const std::string& owner, int count, Misc::Rng::Generator* prng, bool topLevel=true);
template<typename T> template<typename T>
ContainerStoreIterator getState (CellRefList<T>& collection, ContainerStoreIterator getState (CellRefList<T>& collection,
@ -221,7 +221,7 @@ namespace MWWorld
virtual bool stacks (const ConstPtr& ptr1, const ConstPtr& ptr2) const; virtual bool stacks (const ConstPtr& ptr1, const ConstPtr& ptr2) const;
///< @return true if the two specified objects can stack with each other ///< @return true if the two specified objects can stack with each other
void fill (const ESM::InventoryList& items, const std::string& owner, Misc::Rng::Seed& seed = Misc::Rng::getSeed()); void fill (const ESM::InventoryList& items, const std::string& owner, Misc::Rng::Generator& seed = Misc::Rng::getGenerator());
///< Insert items into *this. ///< Insert items into *this.
void fillNonRandom (const ESM::InventoryList& items, const std::string& owner, unsigned int seed); void fillNonRandom (const ESM::InventoryList& items, const std::string& owner, unsigned int seed);

View File

@ -3,50 +3,42 @@
#include <chrono> #include <chrono>
#include <random> #include <random>
namespace namespace Misc::Rng
{ {
Misc::Rng::Seed sSeed; static Generator sGenerator;
}
namespace Misc Generator& getGenerator()
{
Rng::Seed::Seed(unsigned int seed)
{ {
mGenerator.seed(seed); return sGenerator;
} }
Rng::Seed& Rng::getSeed() void init(unsigned int seed)
{ {
return sSeed; sGenerator.seed(seed);
} }
void Rng::init(unsigned int seed) float rollProbability(Generator& prng)
{ {
sSeed.mGenerator.seed(seed); return std::uniform_real_distribution<float>(0, 1 - std::numeric_limits<float>::epsilon())(prng);
} }
float Rng::rollProbability(Seed& seed) float rollClosedProbability(Generator& prng)
{ {
return std::uniform_real_distribution<float>(0, 1 - std::numeric_limits<float>::epsilon())(seed.mGenerator); return std::uniform_real_distribution<float>(0, 1)(prng);
} }
float Rng::rollClosedProbability(Seed& seed) int rollDice(int max, Generator& prng)
{ {
return std::uniform_real_distribution<float>(0, 1)(seed.mGenerator); return max > 0 ? std::uniform_int_distribution<int>(0, max - 1)(prng) : 0;
} }
int Rng::rollDice(int max, Seed& seed) unsigned int generateDefaultSeed()
{
return max > 0 ? std::uniform_int_distribution<int>(0, max - 1)(seed.mGenerator) : 0;
}
unsigned int Rng::generateDefaultSeed()
{ {
return static_cast<unsigned int>(std::chrono::high_resolution_clock::now().time_since_epoch().count()); return static_cast<unsigned int>(std::chrono::high_resolution_clock::now().time_since_epoch().count());
} }
float Rng::deviate(float mean, float deviation, Seed& seed) float deviate(float mean, float deviation, Generator& prng)
{ {
return std::uniform_real_distribution<float>(mean - deviation, mean + deviation)(seed.mGenerator); return std::uniform_real_distribution<float>(mean - deviation, mean + deviation)(prng);
} }
} }

View File

@ -4,47 +4,35 @@
#include <cassert> #include <cassert>
#include <random> #include <random>
namespace Misc
{
/* /*
Provides central implementation of the RNG logic Provides central implementation of the RNG logic
*/ */
class Rng namespace Misc::Rng
{ {
public:
class Seed
{
std::mt19937 mGenerator;
public:
Seed() = default;
Seed(const Seed&) = delete;
Seed(unsigned int seed);
friend class Rng;
};
static Seed& getSeed(); using Generator = std::mt19937;
/// seed the RNG Generator& getGenerator();
static void init(unsigned int seed = generateDefaultSeed());
/// return value in range [0.0f, 1.0f) <- note open upper range.
static float rollProbability(Seed& seed = getSeed());
/// return value in range [0.0f, 1.0f] <- note closed upper range.
static float rollClosedProbability(Seed& seed = getSeed());
/// return value in range [0, max) <- note open upper range.
static int rollDice(int max, Seed& seed = getSeed());
/// return value in range [0, 99]
static int roll0to99(Seed& seed = getSeed()) { return rollDice(100, seed); }
/// returns default seed for RNG /// returns default seed for RNG
static unsigned int generateDefaultSeed(); unsigned int generateDefaultSeed();
static float deviate(float mean, float deviation, Seed& seed = getSeed()); /// seed the RNG
}; void init(unsigned int seed = generateDefaultSeed());
/// return value in range [0.0f, 1.0f) <- note open upper range.
float rollProbability(Generator& prng = getGenerator());
/// return value in range [0.0f, 1.0f] <- note closed upper range.
float rollClosedProbability(Generator& prng = getGenerator());
/// return value in range [0, max) <- note open upper range.
int rollDice(int max, Generator& prng = getGenerator());
/// 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());
} }