Adding mob census (sorry this is a big commit as work was done before git integration i couldn't split it more)
This commit is contained in:
parent
e844612503
commit
d2eb58f277
@ -30,6 +30,8 @@
|
|||||||
#include "PluginManager.h"
|
#include "PluginManager.h"
|
||||||
#include "Blocks/BlockHandler.h"
|
#include "Blocks/BlockHandler.h"
|
||||||
#include "Simulator/FluidSimulator.h"
|
#include "Simulator/FluidSimulator.h"
|
||||||
|
#include "MobCensus.h"
|
||||||
|
|
||||||
|
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
|
|
||||||
@ -429,6 +431,43 @@ void cChunk::Stay(bool a_Stay)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunk::CollectMobCensus(cMobCensus& toFill)
|
||||||
|
{
|
||||||
|
toFill.CollectSpawnableChunck(*this);
|
||||||
|
std::list<const Vector3d*> playerPositions;
|
||||||
|
cPlayer* currentPlayer;
|
||||||
|
for (cClientHandleList::iterator itr = m_LoadedByClient.begin(), end = m_LoadedByClient.end(); itr != end; ++itr)
|
||||||
|
{
|
||||||
|
currentPlayer = (*itr)->GetPlayer();
|
||||||
|
playerPositions.push_back(&(currentPlayer->GetPosition()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3d currentPosition;
|
||||||
|
for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr)
|
||||||
|
{
|
||||||
|
//LOGD("Counting entity #%i (%s)", (*itr)->GetUniqueID(), (*itr)->GetClass());
|
||||||
|
if ((*itr)->IsMob())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
cMonster& Monster = (cMonster&)(**itr);
|
||||||
|
currentPosition = Monster.GetPosition();
|
||||||
|
for (std::list<const Vector3d*>::const_iterator itr2 = playerPositions.begin(); itr2 != playerPositions.end(); itr2 ++)
|
||||||
|
{
|
||||||
|
toFill.CollectMob(Monster,*this,(currentPosition-**itr2).SqrLength());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::bad_cast& e)
|
||||||
|
{
|
||||||
|
LOGD("Something wrong happend I'm collecting an entity that respond 'true' to IsMob() but are not castable in cMonster - No Action");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // for itr - m_Entitites[]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cChunk::Tick(float a_Dt)
|
void cChunk::Tick(float a_Dt)
|
||||||
{
|
{
|
||||||
|
@ -49,6 +49,7 @@ class cPickup;
|
|||||||
class cChunkDataSerializer;
|
class cChunkDataSerializer;
|
||||||
class cBlockArea;
|
class cBlockArea;
|
||||||
class cFluidSimulatorData;
|
class cFluidSimulatorData;
|
||||||
|
class cMobCensus;
|
||||||
|
|
||||||
typedef std::list<cClientHandle *> cClientHandleList;
|
typedef std::list<cClientHandle *> cClientHandleList;
|
||||||
typedef cItemCallback<cEntity> cEntityCallback;
|
typedef cItemCallback<cEntity> cEntityCallback;
|
||||||
@ -124,6 +125,9 @@ public:
|
|||||||
/// Sets or resets the internal flag that prevents chunk from being unloaded
|
/// Sets or resets the internal flag that prevents chunk from being unloaded
|
||||||
void Stay(bool a_Stay = true);
|
void Stay(bool a_Stay = true);
|
||||||
|
|
||||||
|
/// Recence all mobs proximities to players in order to know what to do with them
|
||||||
|
void CollectMobCensus(cMobCensus& toFill);
|
||||||
|
|
||||||
void Tick(float a_Dt);
|
void Tick(float a_Dt);
|
||||||
|
|
||||||
int GetPosX(void) const { return m_PosX; }
|
int GetPosX(void) const { return m_PosX; }
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "BlockArea.h"
|
#include "BlockArea.h"
|
||||||
#include "PluginManager.h"
|
#include "PluginManager.h"
|
||||||
#include "Entities/TNTEntity.h"
|
#include "Entities/TNTEntity.h"
|
||||||
|
#include "MobCensus.h"
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <cstdlib> // abs
|
#include <cstdlib> // abs
|
||||||
@ -2152,6 +2153,19 @@ void cChunkMap::SetNextBlockTick(int a_BlockX, int a_BlockY, int a_BlockZ)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunkMap::CollectMobCensus(cMobCensus& a_ToFill)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSLayers);
|
||||||
|
for (cChunkLayerList::iterator itr = m_Layers.begin(); itr != m_Layers.end(); ++itr)
|
||||||
|
{
|
||||||
|
(*itr)->CollectMobCensus(a_ToFill);
|
||||||
|
} // for itr - m_Layers
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cChunkMap::Tick(float a_Dt)
|
void cChunkMap::Tick(float a_Dt)
|
||||||
{
|
{
|
||||||
@ -2310,6 +2324,24 @@ cChunk * cChunkMap::cChunkLayer::FindChunk(int a_ChunkX, int a_ChunkZ)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunkMap::cChunkLayer::CollectMobCensus(cMobCensus& a_ToFill)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < ARRAYCOUNT(m_Chunks); i++)
|
||||||
|
{
|
||||||
|
// We do count every Mobs in the world. But we are assuming that every chunk not loaded by any client
|
||||||
|
// doesn't affect us. Normally they should not have mobs because every "too far" mobs despawn
|
||||||
|
// If they have (f.i. when player disconnect) we assume we don't have to make them live or despawn
|
||||||
|
if ((m_Chunks[i] != NULL) && m_Chunks[i]->IsValid() && m_Chunks[i]->HasAnyClients())
|
||||||
|
{
|
||||||
|
m_Chunks[i]->CollectMobCensus(a_ToFill);
|
||||||
|
}
|
||||||
|
} // for i - m_Chunks[]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cChunkMap::cChunkLayer::Tick(float a_Dt)
|
void cChunkMap::cChunkLayer::Tick(float a_Dt)
|
||||||
{
|
{
|
||||||
|
@ -26,6 +26,7 @@ class cPawn;
|
|||||||
class cPickup;
|
class cPickup;
|
||||||
class cChunkDataSerializer;
|
class cChunkDataSerializer;
|
||||||
class cBlockArea;
|
class cBlockArea;
|
||||||
|
class cMobCensus;
|
||||||
|
|
||||||
typedef std::list<cClientHandle *> cClientHandleList;
|
typedef std::list<cClientHandle *> cClientHandleList;
|
||||||
typedef cChunk * cChunkPtr;
|
typedef cChunk * cChunkPtr;
|
||||||
@ -266,6 +267,9 @@ public:
|
|||||||
/// Sets the blockticking to start at the specified block. Only one blocktick per chunk may be set, second call overwrites the first call
|
/// Sets the blockticking to start at the specified block. Only one blocktick per chunk may be set, second call overwrites the first call
|
||||||
void SetNextBlockTick(int a_BlockX, int a_BlockY, int a_BlockZ);
|
void SetNextBlockTick(int a_BlockX, int a_BlockY, int a_BlockZ);
|
||||||
|
|
||||||
|
/// Make a Mob census, of all mobs, their family, their chunk and theyr distance to closest player
|
||||||
|
void CollectMobCensus(cMobCensus& a_ToFill);
|
||||||
|
|
||||||
void Tick(float a_Dt);
|
void Tick(float a_Dt);
|
||||||
|
|
||||||
void UnloadUnusedChunks(void);
|
void UnloadUnusedChunks(void);
|
||||||
@ -309,6 +313,10 @@ private:
|
|||||||
void Save(void);
|
void Save(void);
|
||||||
void UnloadUnusedChunks(void);
|
void UnloadUnusedChunks(void);
|
||||||
|
|
||||||
|
/// Collect a mob census, of all mobs, their megatype, their chunk and their distance o closest player
|
||||||
|
void CollectMobCensus(cMobCensus& a_ToFill);
|
||||||
|
|
||||||
|
|
||||||
void Tick(float a_Dt);
|
void Tick(float a_Dt);
|
||||||
|
|
||||||
void RemoveClient(cClientHandle * a_Client);
|
void RemoveClient(cClientHandle * a_Client);
|
||||||
|
89
source/MobCensus.cpp
Normal file
89
source/MobCensus.cpp
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
|
||||||
|
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||||
|
|
||||||
|
#include "MobCensus.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cMobCensus::tCapMultipliersMap cMobCensus::CapMultiplierInitializerBeforeCx11()
|
||||||
|
{
|
||||||
|
std::map<cMonster::eFamily,int> toReturn;
|
||||||
|
toReturn[cMonster::mfHostile] = 79;
|
||||||
|
toReturn[cMonster::mfPassive] = 11;
|
||||||
|
toReturn[cMonster::mfAmbient] = 16;
|
||||||
|
toReturn[cMonster::mfWater] = 5;
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
cMobCensus::tMobSpawnRate cMobCensus::MobSpawnRateInitializerBeforeCx11()
|
||||||
|
{
|
||||||
|
std::map<cMonster::eFamily,int> toReturn;
|
||||||
|
toReturn[cMonster::mfHostile] = 1;
|
||||||
|
toReturn[cMonster::mfPassive] = 400;
|
||||||
|
toReturn[cMonster::mfAmbient] = 400;
|
||||||
|
toReturn[cMonster::mfWater] = 400;
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
cMobCensus::tCapMultipliersMap& cMobCensus::m_CapMultipliers()
|
||||||
|
{
|
||||||
|
static tCapMultipliersMap* value = new tCapMultipliersMap(CapMultiplierInitializerBeforeCx11());
|
||||||
|
return *value;
|
||||||
|
}
|
||||||
|
|
||||||
|
cMobCensus::tMobSpawnRate& cMobCensus::m_SpawnRate()
|
||||||
|
{
|
||||||
|
static tMobSpawnRate* value = new tMobSpawnRate(MobSpawnRateInitializerBeforeCx11());
|
||||||
|
return *value;
|
||||||
|
}
|
||||||
|
|
||||||
|
cMobCensus::cMobCensus()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void cMobCensus::CollectMob(cMonster& a_Monster, cChunk& a_Chunk, double a_Distance)
|
||||||
|
{
|
||||||
|
m_ProximityCounter.CollectMob(a_Monster,a_Chunk,a_Distance);
|
||||||
|
m_MobFamilyCollecter.CollectMob(a_Monster);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cMobCensus::isCaped(cMonster::eFamily a_MobFamily)
|
||||||
|
{
|
||||||
|
bool toReturn = true;
|
||||||
|
const int ratio = 319; // this should be 256 as we are only supposed to take account from chuncks that are in 17x17 from a player
|
||||||
|
// but for now, we use all chunks loaded by players. that means 19 x 19 chucks. That's why we use 256 * (19*19) / (17*17) = 319
|
||||||
|
// MG TODO : code the correct count
|
||||||
|
tCapMultipliersMap::const_iterator capMultiplier = m_CapMultipliers().find(a_MobFamily);
|
||||||
|
if (
|
||||||
|
(capMultiplier != m_CapMultipliers().end()) &&
|
||||||
|
(capMultiplier->second * getChunkNb()) / ratio >= m_MobFamilyCollecter.getNumberOfCollectedMobs(a_MobFamily)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
toReturn = false;
|
||||||
|
}
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cMobCensus::CollectSpawnableChunck(cChunk& a_Chunk)
|
||||||
|
{
|
||||||
|
m_EligibleForSpawnChunks.insert(&a_Chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cMobCensus::getChunkNb()
|
||||||
|
{
|
||||||
|
return m_EligibleForSpawnChunks.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
cMobProximityCounter& cMobCensus::getProximityCounter()
|
||||||
|
{
|
||||||
|
return m_ProximityCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void cMobCensus::logd()
|
||||||
|
{
|
||||||
|
LOGD((std::string("Hostile mobs : %d") + (isCaped(cMonster::mfHostile)?"(capped)":"")).c_str(),m_MobFamilyCollecter.getNumberOfCollectedMobs(cMonster::mfHostile));
|
||||||
|
LOGD((std::string("Ambiant mobs : %d") + (isCaped(cMonster::mfAmbient)?"(capped)":"")).c_str(),m_MobFamilyCollecter.getNumberOfCollectedMobs(cMonster::mfAmbient));
|
||||||
|
LOGD((std::string("Water mobs : %d") + (isCaped(cMonster::mfWater)? "(capped)":"")).c_str(),m_MobFamilyCollecter.getNumberOfCollectedMobs(cMonster::mfWater));
|
||||||
|
LOGD((std::string("Passive mobs : %d") + (isCaped(cMonster::mfPassive)?"(capped)":"")).c_str(),m_MobFamilyCollecter.getNumberOfCollectedMobs(cMonster::mfPassive));
|
||||||
|
}
|
58
source/MobCensus.h
Normal file
58
source/MobCensus.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "MobProximityCounter.h"
|
||||||
|
#include "MobFamilyCollecter.h"
|
||||||
|
|
||||||
|
class cChunk;
|
||||||
|
class cMonster;
|
||||||
|
|
||||||
|
// This class is used to collect, for each Mob, what is the distance of the closest player
|
||||||
|
// it was first being designed in order to make mobs spawn / despawn / act
|
||||||
|
// as the behaviour and even life of mobs depends on the distance to closest player
|
||||||
|
//
|
||||||
|
// as side effect : it also collect the chuncks that are elligible for spawning
|
||||||
|
// as side effect 2 : it also know the caps for mobs number and can compare census to this numbers
|
||||||
|
class cMobCensus
|
||||||
|
{
|
||||||
|
public :
|
||||||
|
cMobCensus();
|
||||||
|
|
||||||
|
protected :
|
||||||
|
cMobProximityCounter m_ProximityCounter;
|
||||||
|
cMobFamilyCollecter m_MobFamilyCollecter;
|
||||||
|
|
||||||
|
typedef const std::map<cMonster::eFamily,int> tCapMultipliersMap;
|
||||||
|
static tCapMultipliersMap& m_CapMultipliers();
|
||||||
|
|
||||||
|
std::set<cChunk*> m_EligibleForSpawnChunks;
|
||||||
|
|
||||||
|
// count the chunks that are elligible to spawn (for now, the loaded valide not null chuncks)
|
||||||
|
int getChunkNb();
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef const std::map<cMonster::eFamily,int> tMobSpawnRate;
|
||||||
|
static tMobSpawnRate& m_SpawnRate();
|
||||||
|
|
||||||
|
// return the nested proximity counter
|
||||||
|
cMobProximityCounter& getProximityCounter();
|
||||||
|
|
||||||
|
public :
|
||||||
|
// collect an elligible Chunk for Mob Spawning
|
||||||
|
// MG TODO : code the correct rule (not loaded chunck but short distant from players)
|
||||||
|
void CollectSpawnableChunck(cChunk& a_Chunk);
|
||||||
|
|
||||||
|
// collect a mob - it's distance to player, it's family ...
|
||||||
|
void CollectMob(cMonster& a_Monster, cChunk& a_Chunk, double a_Distance);
|
||||||
|
|
||||||
|
// return true if the family is caped (i.e. there is more mobs of this family than max)
|
||||||
|
bool isCaped(cMonster::eFamily a_MobFamily);
|
||||||
|
|
||||||
|
// log the results of census
|
||||||
|
void logd();
|
||||||
|
|
||||||
|
protected :
|
||||||
|
static tCapMultipliersMap CapMultiplierInitializerBeforeCx11();
|
||||||
|
static tCapMultipliersMap MobSpawnRateInitializerBeforeCx11();
|
||||||
|
};
|
||||||
|
|
33
source/MobFamilyCollecter.cpp
Normal file
33
source/MobFamilyCollecter.cpp
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
|
||||||
|
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||||
|
|
||||||
|
#include "MobFamilyCollecter.h"
|
||||||
|
#include "Mobs/Monster.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cMobFamilyCollecter::tMobFamilyList cMobFamilyCollecter::initMobFamilyBeforeCx11()
|
||||||
|
{
|
||||||
|
std::set<cMonster::eFamily> toReturn;
|
||||||
|
toReturn.insert(cMonster::mfHostile);
|
||||||
|
toReturn.insert(cMonster::mfPassive);
|
||||||
|
toReturn.insert(cMonster::mfAmbient);
|
||||||
|
toReturn.insert(cMonster::mfWater);
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
cMobFamilyCollecter::tMobFamilyList& cMobFamilyCollecter::m_AllFamilies()
|
||||||
|
{
|
||||||
|
static tMobFamilyList* AllFamilies = new tMobFamilyList(initMobFamilyBeforeCx11());
|
||||||
|
return *AllFamilies;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cMobFamilyCollecter::CollectMob(cMonster& a_Monster)
|
||||||
|
{
|
||||||
|
cMonster::eFamily MobFamily = a_Monster.GetMobFamily();
|
||||||
|
m_Mobs[MobFamily].insert(&a_Monster);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cMobFamilyCollecter::getNumberOfCollectedMobs(cMonster::eFamily a_Family)
|
||||||
|
{
|
||||||
|
return m_Mobs[a_Family].size();
|
||||||
|
}
|
40
source/MobFamilyCollecter.h
Normal file
40
source/MobFamilyCollecter.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#include "BlockID.h"
|
||||||
|
#include "Mobs/Monster.h" //this is a side-effect of keeping Mobfamily inside Monster class. I'd prefer to keep both (Mobfamily and Monster) inside a "Monster" namespace MG TODO : do it
|
||||||
|
|
||||||
|
class cChunk;
|
||||||
|
|
||||||
|
|
||||||
|
// This class is used to collect, for each Mob, what is it's family. It was first
|
||||||
|
// being designed to check the caps of the mobs (no more than ... hostile mob in the world)
|
||||||
|
//
|
||||||
|
// as side effects : it also know what is the spawnrate of each family : MG TODO relocate
|
||||||
|
class cMobFamilyCollecter
|
||||||
|
{
|
||||||
|
protected :
|
||||||
|
std::map<cMonster::eFamily,std::set<cMonster*> > m_Mobs;
|
||||||
|
|
||||||
|
public :
|
||||||
|
// collect a mob
|
||||||
|
void CollectMob(cMonster& a_Monster);
|
||||||
|
|
||||||
|
// return the number of mobs for this family
|
||||||
|
int getNumberOfCollectedMobs(cMonster::eFamily a_Family);
|
||||||
|
|
||||||
|
public :
|
||||||
|
typedef const std::set<cMonster::eFamily> tMobFamilyList;
|
||||||
|
static tMobFamilyList& m_AllFamilies();
|
||||||
|
|
||||||
|
public :
|
||||||
|
typedef const std::map<cMonster::eFamily,int> tMobSpawRate;
|
||||||
|
static tMobSpawRate& m_SpawnRate();
|
||||||
|
|
||||||
|
protected :
|
||||||
|
static tMobFamilyList initMobFamilyBeforeCx11();
|
||||||
|
static tMobSpawRate initMobSpawnRateBeforeCx11();
|
||||||
|
};
|
||||||
|
|
77
source/MobProximityCounter.cpp
Normal file
77
source/MobProximityCounter.cpp
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
|
||||||
|
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||||
|
|
||||||
|
#include "MobProximityCounter.h"
|
||||||
|
|
||||||
|
#include "Entities/Entity.h"
|
||||||
|
#include "Chunk.h"
|
||||||
|
|
||||||
|
void cMobProximityCounter::CollectMob(cEntity& a_Monster, cChunk& a_Chunk, double a_Distance)
|
||||||
|
{
|
||||||
|
// LOGD("Collecting monster %s, with distance %f",a_Monster->GetClass(),a_Distance);
|
||||||
|
tMonsterToDistance::iterator it = m_MonsterToDistance.find(&a_Monster);
|
||||||
|
if (it == m_MonsterToDistance.end())
|
||||||
|
{
|
||||||
|
sDistanceAndChunk newDistanceAndChunck(a_Distance,a_Chunk);
|
||||||
|
std::pair<tMonsterToDistance::iterator,bool> result = m_MonsterToDistance.insert(tMonsterToDistance::value_type(&a_Monster,newDistanceAndChunck));
|
||||||
|
assert(result.second);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
it->second.m_Distance = a_Distance;
|
||||||
|
it->second.m_Chunk = a_Chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_EligibleForSpawnChunks.insert(&a_Chunk);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void cMobProximityCounter::convertMaps()
|
||||||
|
{
|
||||||
|
for(tMonsterToDistance::const_iterator itr = m_MonsterToDistance.begin(); itr != m_MonsterToDistance.end(); itr++)
|
||||||
|
{
|
||||||
|
m_DistanceToMonster.insert(tDistanceToMonster::value_type(itr->second.m_Distance,sMonsterAndChunk(*itr->first,itr->second.m_Chunk)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cMobProximityCounter::sIterablePair cMobProximityCounter::getMobWithinThosesDistances(double a_DistanceMin, double a_DistanceMax)
|
||||||
|
{
|
||||||
|
sIterablePair toReturn;
|
||||||
|
toReturn.m_Count = 0;
|
||||||
|
toReturn.m_Begin = m_DistanceToMonster.end();
|
||||||
|
toReturn.m_End = m_DistanceToMonster.end();
|
||||||
|
|
||||||
|
a_DistanceMin *= a_DistanceMin;// this is because is use square distance
|
||||||
|
a_DistanceMax *= a_DistanceMax;
|
||||||
|
|
||||||
|
if (m_DistanceToMonster.size() <= 0)
|
||||||
|
{
|
||||||
|
convertMaps();
|
||||||
|
}
|
||||||
|
|
||||||
|
for(tDistanceToMonster::const_iterator itr = m_DistanceToMonster.begin(); itr != m_DistanceToMonster.end(); itr++)
|
||||||
|
{
|
||||||
|
if (toReturn.m_Begin == m_DistanceToMonster.end())
|
||||||
|
{
|
||||||
|
if (a_DistanceMin == -1 || itr->first > a_DistanceMin)
|
||||||
|
{
|
||||||
|
toReturn.m_Begin = itr; // this is the first one with distance > a_DistanceMin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toReturn.m_Begin != m_DistanceToMonster.end())
|
||||||
|
{
|
||||||
|
if (a_DistanceMax != -1 && itr->first > a_DistanceMax)
|
||||||
|
{
|
||||||
|
toReturn.m_End = itr; // this is just after the last one with distance < a_DistanceMax
|
||||||
|
// Note : if we are not going through this, it's ok, toReturn.m_End will be end();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
toReturn.m_Count ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return toReturn;
|
||||||
|
}
|
65
source/MobProximityCounter.h
Normal file
65
source/MobProximityCounter.h
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
class cChunk;
|
||||||
|
class cEntity;
|
||||||
|
|
||||||
|
|
||||||
|
// This class is used to collect, for each Mob, what is the distance of the closest player
|
||||||
|
// it was first being designed in order to make mobs spawn / despawn / act
|
||||||
|
// as the behaviour and even life of mobs depends on the distance to closest player
|
||||||
|
class cMobProximityCounter
|
||||||
|
{
|
||||||
|
protected :
|
||||||
|
// structs used for later maps (see m_MonsterToDistance and m_DistanceToMonster)
|
||||||
|
struct sDistanceAndChunk
|
||||||
|
{
|
||||||
|
sDistanceAndChunk(double a_Distance, cChunk& a_Chunk) : m_Distance(a_Distance), m_Chunk(a_Chunk) {}
|
||||||
|
double m_Distance;
|
||||||
|
cChunk& m_Chunk;
|
||||||
|
};
|
||||||
|
struct sMonsterAndChunk
|
||||||
|
{
|
||||||
|
sMonsterAndChunk(cEntity& a_Monster, cChunk& a_Chunk) : m_Monster(a_Monster), m_Chunk(a_Chunk) {}
|
||||||
|
cEntity& m_Monster;
|
||||||
|
cChunk& m_Chunk;
|
||||||
|
};
|
||||||
|
|
||||||
|
public :
|
||||||
|
typedef std::map<cEntity*,sDistanceAndChunk> tMonsterToDistance;
|
||||||
|
typedef std::multimap<double,sMonsterAndChunk> tDistanceToMonster;
|
||||||
|
|
||||||
|
protected :
|
||||||
|
// this map is filled during collection phase, it will be later transformed into DistanceToMonster
|
||||||
|
tMonsterToDistance m_MonsterToDistance;
|
||||||
|
|
||||||
|
// this map is generated after collection phase, in order to access monster by distance to player
|
||||||
|
tDistanceToMonster m_DistanceToMonster;
|
||||||
|
|
||||||
|
// this are the collected chuncks. Used to determinate the number of elligible chunck for spawning.
|
||||||
|
std::set<cChunk*> m_EligibleForSpawnChunks;
|
||||||
|
|
||||||
|
protected :
|
||||||
|
// transform monsterToDistance map (that was usefull for collecting) into distanceToMonster
|
||||||
|
// that will be usefull for picking up.
|
||||||
|
void convertMaps();
|
||||||
|
|
||||||
|
public :
|
||||||
|
// count a mob on a specified chunck with specified distance to an unkown player
|
||||||
|
// if the distance is shortest than the one collected, this become the new closest
|
||||||
|
// distance and the chunck become the "hosting" chunk (that is the one that will perform the action)
|
||||||
|
void CollectMob(cEntity& a_Monster, cChunk& a_Chunk, double a_Distance);
|
||||||
|
|
||||||
|
// return the mobs that are within the range of distance of the closest player they are
|
||||||
|
// that means that if a mob is 30 m from a player and 150 m from another one. It will be
|
||||||
|
// in the range [0..50] but not in [100..200]
|
||||||
|
struct sIterablePair{
|
||||||
|
tDistanceToMonster::const_iterator m_Begin;
|
||||||
|
tDistanceToMonster::const_iterator m_End;
|
||||||
|
int m_Count;
|
||||||
|
};
|
||||||
|
sIterablePair getMobWithinThosesDistances(double a_DistanceMin, double a_DistanceMax);
|
||||||
|
|
||||||
|
};
|
130
source/MobTypesManager.cpp
Normal file
130
source/MobTypesManager.cpp
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
|
||||||
|
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||||
|
|
||||||
|
#include "MobTypesManager.h"
|
||||||
|
#include "MersenneTwister.h"
|
||||||
|
#include "Mobs/Monster.h"
|
||||||
|
#include "Mobs/IncludeAllMonsters.h"
|
||||||
|
#include "FastRandom.h"
|
||||||
|
|
||||||
|
|
||||||
|
cMobTypesManager::tMobTypes2Names& cMobTypesManager::m_MobsTypes2Names()
|
||||||
|
{
|
||||||
|
static std::map<cMonster::eType,std::string>* value = new std::map<cMonster::eType,std::string>(MobTypes2NamesInitializerBeforeCx11());
|
||||||
|
return *value;
|
||||||
|
}
|
||||||
|
|
||||||
|
cMobTypesManager::tMobTypes2Names cMobTypesManager::MobTypes2NamesInitializerBeforeCx11()
|
||||||
|
{
|
||||||
|
std::map<cMonster::eType,std::string> toReturn;
|
||||||
|
typedef std::map<cMonster::eType,std::string>::value_type ValueType;
|
||||||
|
toReturn.insert(ValueType(cMonster::mtMagmaCube,"Magmacube"));
|
||||||
|
toReturn.insert(ValueType(cMonster::mtSlime,"Slime"));
|
||||||
|
toReturn.insert(ValueType(cMonster::mtBat,"Bat"));
|
||||||
|
toReturn.insert(ValueType(cMonster::mtBlaze,"Blaze"));
|
||||||
|
toReturn.insert(ValueType(cMonster::mtCaveSpider,"Cavespider"));
|
||||||
|
toReturn.insert(ValueType(cMonster::mtChicken,"Chicken"));
|
||||||
|
toReturn.insert(ValueType(cMonster::mtCow,"Cow"));
|
||||||
|
toReturn.insert(ValueType(cMonster::mtCreeper,"Creeper"));
|
||||||
|
toReturn.insert(ValueType(cMonster::mtEnderman,"Enderman"));
|
||||||
|
toReturn.insert(ValueType(cMonster::mtGhast,"Ghast"));
|
||||||
|
toReturn.insert(ValueType(cMonster::mtMooshroom,"Mooshroom"));
|
||||||
|
toReturn.insert(ValueType(cMonster::mtOcelot,"Ocelot"));
|
||||||
|
toReturn.insert(ValueType(cMonster::mtPig,"Pig"));
|
||||||
|
toReturn.insert(ValueType(cMonster::mtSheep,"Sheep"));
|
||||||
|
toReturn.insert(ValueType(cMonster::mtSilverfish,"Silverfish"));
|
||||||
|
toReturn.insert(ValueType(cMonster::mtSkeleton,"Skeleton"));
|
||||||
|
toReturn.insert(ValueType(cMonster::mtSpider,"Spider"));
|
||||||
|
toReturn.insert(ValueType(cMonster::mtSquid,"Squid"));
|
||||||
|
toReturn.insert(ValueType(cMonster::mtVillager,"Villager"));
|
||||||
|
toReturn.insert(ValueType(cMonster::mtWitch,"Witch"));
|
||||||
|
toReturn.insert(ValueType(cMonster::mtWolf,"Wolf"));
|
||||||
|
toReturn.insert(ValueType(cMonster::mtZombie,"Zombie"));
|
||||||
|
toReturn.insert(ValueType(cMonster::mtZombiePigman,"Zombiepigman"));
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cFastRandom& cMobTypesManager::m_Random()
|
||||||
|
{
|
||||||
|
static cFastRandom* value = new cFastRandom();
|
||||||
|
return *value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cMonster* cMobTypesManager::NewMonsterFromType(cMonster::eType a_MobType, int a_Size)
|
||||||
|
{
|
||||||
|
cMonster * toReturn = NULL;
|
||||||
|
|
||||||
|
// unspecified size get rand[1,3] for Monsters that need size
|
||||||
|
switch (a_MobType)
|
||||||
|
{
|
||||||
|
case cMonster::mtMagmaCube:
|
||||||
|
case cMonster::mtSlime:
|
||||||
|
if (a_Size == -1)
|
||||||
|
{
|
||||||
|
a_Size = m_Random().NextInt(2,a_MobType)+1;
|
||||||
|
}
|
||||||
|
assert(a_Size > 0 && a_Size < 4);
|
||||||
|
break;
|
||||||
|
default : break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the big switch
|
||||||
|
switch (a_MobType)
|
||||||
|
{
|
||||||
|
case cMonster::mtMagmaCube: toReturn = new cMagmacube(a_Size); break;
|
||||||
|
case cMonster::mtSlime: toReturn = new cSlime(a_Size); break;
|
||||||
|
case cMonster::mtBat: toReturn = new cBat(); break;
|
||||||
|
case cMonster::mtBlaze: toReturn = new cBlaze(); break;
|
||||||
|
case cMonster::mtCaveSpider: toReturn = new cCavespider(); break;
|
||||||
|
case cMonster::mtChicken: toReturn = new cChicken(); break;
|
||||||
|
case cMonster::mtCow: toReturn = new cCow(); break;
|
||||||
|
case cMonster::mtCreeper: toReturn = new cCreeper(); break;
|
||||||
|
case cMonster::mtEnderman: toReturn = new cEnderman(); break;
|
||||||
|
case cMonster::mtGhast: toReturn = new cGhast(); break;
|
||||||
|
case cMonster::mtMooshroom: toReturn = new cMooshroom(); break;
|
||||||
|
case cMonster::mtOcelot: toReturn = new cOcelot(); break;
|
||||||
|
case cMonster::mtPig: toReturn = new cPig(); break;
|
||||||
|
case cMonster::mtSheep: toReturn = new cSheep(); break;
|
||||||
|
case cMonster::mtSilverfish: toReturn = new cSilverfish(); break;
|
||||||
|
case cMonster::mtSkeleton: toReturn = new cSkeleton(); break;
|
||||||
|
case cMonster::mtSpider: toReturn = new cSpider(); break;
|
||||||
|
case cMonster::mtSquid: toReturn = new cSquid(); break;
|
||||||
|
case cMonster::mtVillager: toReturn = new cVillager(); break;
|
||||||
|
case cMonster::mtWitch: toReturn = new cWitch(); break;
|
||||||
|
case cMonster::mtWolf: toReturn = new cWolf(); break;
|
||||||
|
case cMonster::mtZombie: toReturn = new cZombie(); break;
|
||||||
|
case cMonster::mtZombiePigman: toReturn = new cZombiepigman(); break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const std::string& cMobTypesManager::fromMobTypeToString(cMonster::eType a_MobType)
|
||||||
|
{
|
||||||
|
static std::string toReturnDefault = "";
|
||||||
|
std::string& toReturn = toReturnDefault;
|
||||||
|
std::map<cMonster::eType,std::string>::const_iterator itr = m_MobsTypes2Names().find(a_MobType);
|
||||||
|
if (itr != m_MobsTypes2Names().end())
|
||||||
|
{
|
||||||
|
toReturn = itr->second;
|
||||||
|
}
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
cMonster::eType cMobTypesManager::fromStringToMobType(const std::string& a_Name)
|
||||||
|
{
|
||||||
|
for(std::map<cMonster::eType,std::string>::const_iterator itr = m_MobsTypes2Names().begin(); itr != m_MobsTypes2Names().end(); itr++)
|
||||||
|
{
|
||||||
|
if (itr->second == a_Name)
|
||||||
|
{
|
||||||
|
return itr->first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new NotAMonsterException();
|
||||||
|
}
|
41
source/MobTypesManager.h
Normal file
41
source/MobTypesManager.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include "Mobs/Monster.h" // this is a side effect of declaring cMonster::eType inside cMonster MG TODO : make a namespace
|
||||||
|
|
||||||
|
class cFastRandom;
|
||||||
|
|
||||||
|
// this aggregate static functionnalities about mob types (some could call it helper)
|
||||||
|
// functionnalities are (in the first version) :
|
||||||
|
// - create a mob from its type (as enum) (in that way it is a compiler-proxy for mobs)
|
||||||
|
// - can transform MobTypes from enums to string and reciprocal
|
||||||
|
class cMobTypesManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const std::string& fromMobTypeToString(cMonster::eType a_MobType);
|
||||||
|
static cMonster::eType fromStringToMobType(const std::string&);
|
||||||
|
|
||||||
|
public:
|
||||||
|
class NotAMonsterException : public std::exception {}; //MG TODO : check if this is this project way to do it
|
||||||
|
|
||||||
|
protected :
|
||||||
|
typedef const std::map<cMonster::eType,std::string> tMobTypes2Names;
|
||||||
|
static tMobTypes2Names& m_MobsTypes2Names();
|
||||||
|
static tMobTypes2Names MobTypes2NamesInitializerBeforeCx11();
|
||||||
|
|
||||||
|
static cFastRandom& m_Random();
|
||||||
|
|
||||||
|
public :
|
||||||
|
/** create a new object of the specified mob.
|
||||||
|
Warning, new without delete here;
|
||||||
|
a_MobType is the type of the mob to be created
|
||||||
|
a_Size is the size (for mobs with size)
|
||||||
|
if a_Size is let to -1 for entities that need size, size will be random
|
||||||
|
assert or return null if mob type is not specified
|
||||||
|
assert if size < 1 or > 3 for entities that need size
|
||||||
|
*/
|
||||||
|
static cMonster* NewMonsterFromType(cMonster::eType a_MobType, int a_Size=-1);
|
||||||
|
|
||||||
|
}; // tolua_export
|
||||||
|
|
@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
// Mobs:
|
// Mobs:
|
||||||
#include "Mobs/IncludeAllMonsters.h"
|
#include "Mobs/IncludeAllMonsters.h"
|
||||||
|
#include "MobCensus.h"
|
||||||
|
|
||||||
#include "OSSupport/MakeDir.h"
|
#include "OSSupport/MakeDir.h"
|
||||||
#include "MersenneTwister.h"
|
#include "MersenneTwister.h"
|
||||||
@ -713,6 +714,10 @@ void cWorld::TickSpawnMobs(float a_Dt)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cMobCensus MobCensus;
|
||||||
|
m_ChunkMap->CollectMobCensus(MobCensus);
|
||||||
|
MobCensus.logd();
|
||||||
|
|
||||||
m_LastSpawnMonster = m_WorldAge;
|
m_LastSpawnMonster = m_WorldAge;
|
||||||
Vector3d SpawnPos;
|
Vector3d SpawnPos;
|
||||||
{
|
{
|
||||||
|
@ -42,6 +42,7 @@ class cChunkGenerator; // The thread responsible for generating chunks
|
|||||||
class cChestEntity;
|
class cChestEntity;
|
||||||
class cDispenserEntity;
|
class cDispenserEntity;
|
||||||
class cFurnaceEntity;
|
class cFurnaceEntity;
|
||||||
|
class cMobCensus;
|
||||||
|
|
||||||
typedef std::list< cPlayer * > cPlayerList;
|
typedef std::list< cPlayer * > cPlayerList;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user