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:
commit
8a182c130a
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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};
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user