Use a predictable RNG seed for random actor variations, so they are consistent between runs of the game.
This was SVN commit r9143.
This commit is contained in:
parent
97c934ad1c
commit
1a072a3f37
@ -27,9 +27,9 @@
|
||||
#include "ps/Filesystem.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "lib/timer.h"
|
||||
#include "lib/rand.h"
|
||||
#include "maths/MathUtil.h"
|
||||
|
||||
#include <boost/random/uniform_int.hpp>
|
||||
|
||||
CObjectBase::CObjectBase(CObjectManager& objectManager)
|
||||
: m_ObjectManager(objectManager)
|
||||
@ -411,7 +411,14 @@ const CObjectBase::Variation CObjectBase::BuildVariation(const std::vector<u8>&
|
||||
return variation;
|
||||
}
|
||||
|
||||
std::set<CStr> CObjectBase::CalculateRandomVariation(const std::set<CStr>& initialSelections)
|
||||
std::set<CStr> CObjectBase::CalculateRandomVariation(uint32_t seed, const std::set<CStr>& initialSelections)
|
||||
{
|
||||
rng_t rng;
|
||||
rng.seed(seed);
|
||||
return CalculateRandomVariation(rng, initialSelections);
|
||||
}
|
||||
|
||||
std::set<CStr> CObjectBase::CalculateRandomVariation(rng_t& rng, const std::set<CStr>& initialSelections)
|
||||
{
|
||||
std::set<CStr> selections = initialSelections;
|
||||
|
||||
@ -471,10 +478,8 @@ std::set<CStr> CObjectBase::CalculateRandomVariation(const std::set<CStr>& initi
|
||||
bool allZero = (totalFreq == 0);
|
||||
if (allZero) totalFreq = (int)grp->size();
|
||||
|
||||
// Choose a random number in the interval [0..totalFreq).
|
||||
// (It shouldn't be necessary to use a network-synchronised RNG,
|
||||
// since actors are meant to have purely visual manifestations.)
|
||||
int randNum = (int)rand(0, (size_t)totalFreq);
|
||||
// Choose a random number in the interval [0..totalFreq)
|
||||
int randNum = boost::uniform_int<>(0, totalFreq-1)(rng);
|
||||
|
||||
// and use that to choose one of the variants
|
||||
for (size_t i = 0; i < grp->size(); ++i)
|
||||
@ -518,7 +523,7 @@ std::set<CStr> CObjectBase::CalculateRandomVariation(const std::set<CStr>& initi
|
||||
CObjectBase* prop = m_ObjectManager.FindObjectBase(it->second);
|
||||
if (prop)
|
||||
{
|
||||
std::set<CStr> propSelections = prop->CalculateRandomVariation(selections);
|
||||
std::set<CStr> propSelections = prop->CalculateRandomVariation(rng, selections);
|
||||
// selections = union(propSelections, selections)
|
||||
std::set<CStr> newSelections;
|
||||
std::set_union(propSelections.begin(), propSelections.end(),
|
||||
|
@ -28,6 +28,8 @@ class CObjectManager;
|
||||
#include "lib/file/vfs/vfs_path.h"
|
||||
#include "ps/CStr.h"
|
||||
|
||||
#include <boost/random/mersenne_twister.hpp>
|
||||
|
||||
class CObjectBase
|
||||
{
|
||||
NONCOPYABLE(CObjectBase);
|
||||
@ -106,7 +108,7 @@ public:
|
||||
// Get a set of selection strings that are complete enough to specify an
|
||||
// exact variation of the actor, using the initial selections wherever possible
|
||||
// and choosing randomly where a choice is necessary.
|
||||
std::set<CStr> CalculateRandomVariation(const std::set<CStr>& initialSelections);
|
||||
std::set<CStr> CalculateRandomVariation(uint32_t seed, const std::set<CStr>& initialSelections);
|
||||
|
||||
// Get a list of variant groups for this object, plus for all possible
|
||||
// props. Duplicated groups are removed, if several props share the same
|
||||
@ -144,6 +146,13 @@ public:
|
||||
VfsPath m_Material;
|
||||
|
||||
private:
|
||||
// A low-quality RNG like rand48 causes visible non-random patterns (particularly
|
||||
// in large grids of the same actor with consecutive seeds, e.g. forests),
|
||||
// so use a better one that appears to avoid those patterns
|
||||
typedef boost::mt19937 rng_t;
|
||||
|
||||
std::set<CStr> CalculateRandomVariation(rng_t& rng, const std::set<CStr>& initialSelections);
|
||||
|
||||
std::vector< std::vector<Variant> > m_VariantGroups;
|
||||
CObjectManager& m_ObjectManager;
|
||||
};
|
||||
|
@ -44,14 +44,14 @@ CUnit::~CUnit()
|
||||
delete m_Model;
|
||||
}
|
||||
|
||||
CUnit* CUnit::Create(const CStrW& actorName, const std::set<CStr>& selections, CObjectManager& objectManager)
|
||||
CUnit* CUnit::Create(const CStrW& actorName, uint32_t seed, const std::set<CStr>& selections, CObjectManager& objectManager)
|
||||
{
|
||||
CObjectBase* base = objectManager.FindObjectBase(actorName);
|
||||
|
||||
if (! base)
|
||||
return NULL;
|
||||
|
||||
std::set<CStr> actorSelections = base->CalculateRandomVariation(selections);
|
||||
std::set<CStr> actorSelections = base->CalculateRandomVariation(seed, selections);
|
||||
|
||||
std::vector<std::set<CStr> > selectionsVec;
|
||||
selectionsVec.push_back(actorSelections);
|
||||
|
@ -42,9 +42,10 @@ private:
|
||||
|
||||
public:
|
||||
// Attempt to create a unit with the given actor, with a set of
|
||||
// suggested selections (with the rest being randomised).
|
||||
// suggested selections (with the rest being randomised using the
|
||||
// given random seed).
|
||||
// Returns NULL on failure.
|
||||
static CUnit* Create(const CStrW& actorName, const std::set<CStr>& selections, CObjectManager& objectManager);
|
||||
static CUnit* Create(const CStrW& actorName, uint32_t seed, const std::set<CStr>& selections, CObjectManager& objectManager);
|
||||
|
||||
// destructor
|
||||
~CUnit();
|
||||
|
@ -125,12 +125,12 @@ CUnit* CUnitManager::PickUnit(const CVector3D& origin, const CVector3D& dir) con
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CreateUnit: create a new unit and add it to the world
|
||||
CUnit* CUnitManager::CreateUnit(const CStrW& actorName, const std::set<CStr8>& selections)
|
||||
CUnit* CUnitManager::CreateUnit(const CStrW& actorName, uint32_t seed, const std::set<CStr8>& selections)
|
||||
{
|
||||
if (! m_ObjectManager)
|
||||
return NULL;
|
||||
|
||||
CUnit* unit = CUnit::Create(actorName, selections, *m_ObjectManager);
|
||||
CUnit* unit = CUnit::Create(actorName, seed, selections, *m_ObjectManager);
|
||||
if (unit)
|
||||
AddUnit(unit);
|
||||
return unit;
|
||||
|
@ -50,7 +50,7 @@ public:
|
||||
void DeleteAll();
|
||||
|
||||
// creates a new unit and adds it to the world
|
||||
CUnit* CreateUnit(const CStrW& actorName, const std::set<CStr8>& selections);
|
||||
CUnit* CreateUnit(const CStrW& actorName, uint32_t seed, const std::set<CStr8>& selections);
|
||||
|
||||
// return the units
|
||||
const std::vector<CUnit*>& GetUnits() const { return m_Units; }
|
||||
|
@ -57,6 +57,7 @@ public:
|
||||
|
||||
virtual void Init(const CParamNode& UNUSED(paramNode))
|
||||
{
|
||||
m_ActorSeed = 0;
|
||||
}
|
||||
|
||||
virtual void Deinit()
|
||||
@ -119,6 +120,8 @@ private:
|
||||
|
||||
std::vector<Projectile> m_Projectiles;
|
||||
|
||||
uint32_t m_ActorSeed;
|
||||
|
||||
void LaunchProjectile(entity_id_t source, CFixedVector3D targetPoint, entity_id_t targetEnt, fixed speed, fixed gravity);
|
||||
|
||||
void AdvanceProjectile(Projectile& projectile, float dt, float frameOffset);
|
||||
@ -151,7 +154,7 @@ void CCmpProjectileManager::LaunchProjectile(entity_id_t source, CFixedVector3D
|
||||
std::set<CStr> selections;
|
||||
|
||||
Projectile projectile;
|
||||
projectile.unit = GetSimContext().GetUnitManager().CreateUnit(name, selections);
|
||||
projectile.unit = GetSimContext().GetUnitManager().CreateUnit(name, m_ActorSeed++, selections);
|
||||
if (!projectile.unit)
|
||||
{
|
||||
// The error will have already been logged
|
||||
|
@ -117,7 +117,7 @@ public:
|
||||
m_R = m_G = m_B = fixed::FromInt(1);
|
||||
|
||||
std::set<CStr> selections;
|
||||
m_Unit = GetSimContext().GetUnitManager().CreateUnit(m_ActorName, selections);
|
||||
m_Unit = GetSimContext().GetUnitManager().CreateUnit(m_ActorName, GetActorSeed(), selections);
|
||||
if (!m_Unit)
|
||||
{
|
||||
// The error will have already been logged
|
||||
@ -336,7 +336,7 @@ public:
|
||||
return;
|
||||
|
||||
std::set<CStr> selections;
|
||||
CUnit* newUnit = GetSimContext().GetUnitManager().CreateUnit(m_ActorName, selections);
|
||||
CUnit* newUnit = GetSimContext().GetUnitManager().CreateUnit(m_ActorName, GetActorSeed(), selections);
|
||||
|
||||
if (!newUnit)
|
||||
return;
|
||||
@ -368,6 +368,11 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
int32_t GetActorSeed()
|
||||
{
|
||||
return GetEntityId();
|
||||
}
|
||||
|
||||
void Update(fixed turnLength);
|
||||
void Interpolate(float frameTime, float frameOffset);
|
||||
void RenderSubmit(SceneCollector& collector, const CFrustum& frustum, bool culling);
|
||||
|
Loading…
Reference in New Issue
Block a user