From 04aebd944bc988994d2eb2ad2945b1210faf9fb0 Mon Sep 17 00:00:00 2001 From: mgueydan Date: Sat, 7 Sep 2013 20:00:04 +0200 Subject: [PATCH 01/22] Adding Water and Lava as transparency blocks --- source/BlockID.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/BlockID.cpp b/source/BlockID.cpp index b53507f1..c1198dd3 100644 --- a/source/BlockID.cpp +++ b/source/BlockID.cpp @@ -598,6 +598,7 @@ public: g_BlockTransparent[E_BLOCK_GLASS] = true; g_BlockTransparent[E_BLOCK_ICE] = true; g_BlockTransparent[E_BLOCK_IRON_DOOR] = true; + g_BlockTransparent[E_BLOCK_LAVA] = true; g_BlockTransparent[E_BLOCK_LEAVES] = true; g_BlockTransparent[E_BLOCK_LEVER] = true; g_BlockTransparent[E_BLOCK_MELON_STEM] = true; @@ -610,11 +611,14 @@ public: g_BlockTransparent[E_BLOCK_RED_MUSHROOM] = true; g_BlockTransparent[E_BLOCK_RED_ROSE] = true; g_BlockTransparent[E_BLOCK_SIGN_POST] = true; + g_BlockTransparent[E_BLOCK_STATIONARY_LAVA] = true; + g_BlockTransparent[E_BLOCK_STATIONARY_WATER] = true; g_BlockTransparent[E_BLOCK_STONE_PRESSURE_PLATE] = true; g_BlockTransparent[E_BLOCK_SNOW] = true; g_BlockTransparent[E_BLOCK_TALL_GRASS] = true; g_BlockTransparent[E_BLOCK_TORCH] = true; g_BlockTransparent[E_BLOCK_VINES] = true; + g_BlockTransparent[E_BLOCK_WATER] = true; g_BlockTransparent[E_BLOCK_WALLSIGN] = true; g_BlockTransparent[E_BLOCK_WOODEN_DOOR] = true; g_BlockTransparent[E_BLOCK_WOODEN_PRESSURE_PLATE] = true; From 1e02e04d2ce528df037d1ca37314ea55e8806c52 Mon Sep 17 00:00:00 2001 From: mgueydan Date: Sat, 7 Sep 2013 20:02:50 +0200 Subject: [PATCH 02/22] Adding Family for monsters : Hostile/Passive/Water/Ambient --- source/Mobs/AggressiveMonster.cpp | 7 +++++++ source/Mobs/AggressiveMonster.h | 2 ++ source/Mobs/Bat.cpp | 19 +++++++++++++++++++ source/Mobs/Bat.h | 8 +++----- source/Mobs/Monster.h | 10 ++++++++++ source/Mobs/PassiveMonster.cpp | 7 +++++++ source/Mobs/PassiveMonster.h | 2 ++ source/Mobs/Squid.cpp | 5 ++++- source/Mobs/Squid.h | 2 ++ 9 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 source/Mobs/Bat.cpp diff --git a/source/Mobs/AggressiveMonster.cpp b/source/Mobs/AggressiveMonster.cpp index 2eae772d..d4852337 100644 --- a/source/Mobs/AggressiveMonster.cpp +++ b/source/Mobs/AggressiveMonster.cpp @@ -95,5 +95,12 @@ void cAggressiveMonster::Tick(float a_Dt, cChunk & a_Chunk) } +cMonster::eFamily cAggressiveMonster::GetMobFamily() const +{ + return mfHostile; +} + + + diff --git a/source/Mobs/AggressiveMonster.h b/source/Mobs/AggressiveMonster.h index 1eff1831..c1641954 100644 --- a/source/Mobs/AggressiveMonster.h +++ b/source/Mobs/AggressiveMonster.h @@ -19,6 +19,8 @@ public: virtual void InStateChasing(float a_Dt) override; virtual void EventSeePlayer(cEntity *) override; + + virtual eFamily GetMobFamily(void) const override; protected: float m_ChaseTime; diff --git a/source/Mobs/Bat.cpp b/source/Mobs/Bat.cpp new file mode 100644 index 00000000..ec7ce7bc --- /dev/null +++ b/source/Mobs/Bat.cpp @@ -0,0 +1,19 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "Bat.h" +#include "../Vector3d.h" +#include "../Chunk.h" + + +cBat::cBat(void) : + // TODO: The size is only a guesstimate, measure in vanilla and fix the size values here + super("Bat", 65, "mob.bat.hurt", "mob.bat.death", 0.7, 0.7) +{ +} + + +cMonster::eFamily cBat::GetMobFamily() const +{ + return mfWater; +} diff --git a/source/Mobs/Bat.h b/source/Mobs/Bat.h index 8e4cde29..e0afb574 100644 --- a/source/Mobs/Bat.h +++ b/source/Mobs/Bat.h @@ -13,13 +13,11 @@ class cBat : typedef cPassiveMonster super; public: - cBat(void) : - // TODO: The size is only a guesstimate, measure in vanilla and fix the size values here - super("Bat", 65, "mob.bat.hurt", "mob.bat.death", 0.7, 0.7) - { - } + cBat(void); CLASS_PROTODEF(cBat); + + virtual eFamily GetMobFamily(void) const override; } ; diff --git a/source/Mobs/Monster.h b/source/Mobs/Monster.h index 5f33d445..357e540b 100644 --- a/source/Mobs/Monster.h +++ b/source/Mobs/Monster.h @@ -55,6 +55,15 @@ public: mtIronGolem = E_META_SPAWN_EGG_IRON_GOLEM, mtVillager = E_META_SPAWN_EGG_VILLAGER, } ; + + enum eFamily + { + mfHostile = 0, // Spider, Zombies ... + mfPassive = 1, // Cows, Pigs + mfAmbient = 2, // Bats + mfWater = 3, // Squid + mfMaxplusone = 4, // Nothing + } ; // tolua_end @@ -81,6 +90,7 @@ public: virtual bool ReachedDestination(void); char GetMobType(void) const {return m_MobType; } + virtual eFamily GetMobFamily(void) const = 0; const char * GetState(); void SetState(const AString & str); diff --git a/source/Mobs/PassiveMonster.cpp b/source/Mobs/PassiveMonster.cpp index 7a6140c0..3d7b8c8a 100644 --- a/source/Mobs/PassiveMonster.cpp +++ b/source/Mobs/PassiveMonster.cpp @@ -55,4 +55,11 @@ void cPassiveMonster::Tick(float a_Dt, cChunk & a_Chunk) +cMonster::eFamily cPassiveMonster::GetMobFamily() const +{ + return mfPassive; +} + + + diff --git a/source/Mobs/PassiveMonster.h b/source/Mobs/PassiveMonster.h index ae0bea3f..9d355772 100644 --- a/source/Mobs/PassiveMonster.h +++ b/source/Mobs/PassiveMonster.h @@ -19,6 +19,8 @@ public: /// When hit by someone, run away virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override; + + virtual eFamily GetMobFamily(void) const override; } ; diff --git a/source/Mobs/Squid.cpp b/source/Mobs/Squid.cpp index cb796f5e..50265aea 100644 --- a/source/Mobs/Squid.cpp +++ b/source/Mobs/Squid.cpp @@ -54,4 +54,7 @@ void cSquid::Tick(float a_Dt, cChunk & a_Chunk) - +cMonster::eFamily cSquid::GetMobFamily() const +{ + return mfWater; +} diff --git a/source/Mobs/Squid.h b/source/Mobs/Squid.h index 35d7295b..d5f3a74d 100644 --- a/source/Mobs/Squid.h +++ b/source/Mobs/Squid.h @@ -20,6 +20,8 @@ public: CLASS_PROTODEF(cSquid); virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; + + virtual eFamily GetMobFamily(void) const override; } ; From 2361a5dc418a42092ed8040e6826b65b38e94fcb Mon Sep 17 00:00:00 2001 From: mgueydan Date: Sat, 7 Sep 2013 20:07:56 +0200 Subject: [PATCH 03/22] relockating mobs includes (they probably will end somewhere else in order not to recompile world each time you update a mob) --- source/Mobs/IncludeAllMonsters.h | 23 +++++++++++++++++++++++ source/World.cpp | 24 +----------------------- 2 files changed, 24 insertions(+), 23 deletions(-) create mode 100644 source/Mobs/IncludeAllMonsters.h diff --git a/source/Mobs/IncludeAllMonsters.h b/source/Mobs/IncludeAllMonsters.h new file mode 100644 index 00000000..d89a6c5b --- /dev/null +++ b/source/Mobs/IncludeAllMonsters.h @@ -0,0 +1,23 @@ +#include "Bat.h" +#include "Blaze.h" +#include "Cavespider.h" +#include "Chicken.h" +#include "Cow.h" +#include "Creeper.h" +#include "Enderman.h" +#include "Ghast.h" +#include "Magmacube.h" +#include "Mooshroom.h" +#include "Ocelot.h" +#include "Pig.h" +#include "Sheep.h" +#include "Silverfish.h" +#include "Skeleton.h" +#include "Slime.h" +#include "Spider.h" +#include "Squid.h" +#include "Villager.h" +#include "Witch.h" +#include "Wolf.h" +#include "Zombie.h" +#include "Zombiepigman.h" diff --git a/source/World.cpp b/source/World.cpp index ab783d7a..d0fa588b 100644 --- a/source/World.cpp +++ b/source/World.cpp @@ -28,29 +28,7 @@ #include "Simulator/VaporizeFluidSimulator.h" // Mobs: -#include "Mobs/Bat.h" -#include "Mobs/Blaze.h" -#include "Mobs/Cavespider.h" -#include "Mobs/Chicken.h" -#include "Mobs/Cow.h" -#include "Mobs/Creeper.h" -#include "Mobs/Enderman.h" -#include "Mobs/Ghast.h" -#include "Mobs/Magmacube.h" -#include "Mobs/Mooshroom.h" -#include "Mobs/Ocelot.h" -#include "Mobs/Pig.h" -#include "Mobs/Sheep.h" -#include "Mobs/Silverfish.h" -#include "Mobs/Skeleton.h" -#include "Mobs/Slime.h" -#include "Mobs/Spider.h" -#include "Mobs/Squid.h" -#include "Mobs/Villager.h" -#include "Mobs/Witch.h" -#include "Mobs/Wolf.h" -#include "Mobs/Zombie.h" -#include "Mobs/Zombiepigman.h" +#include "Mobs/IncludeAllMonsters.h" #include "OSSupport/MakeDir.h" #include "MersenneTwister.h" From e844612503e0d78723c76423e93165164505f7ac Mon Sep 17 00:00:00 2001 From: mgueydan Date: Sat, 7 Sep 2013 20:51:31 +0200 Subject: [PATCH 04/22] Adding a getType in Monster that return an enum instead of an int or char --- source/Mobs/Monster.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/Mobs/Monster.h b/source/Mobs/Monster.h index 357e540b..594914ca 100644 --- a/source/Mobs/Monster.h +++ b/source/Mobs/Monster.h @@ -89,7 +89,8 @@ public: virtual void MoveToPosition(const Vector3f & a_Position); virtual bool ReachedDestination(void); - char GetMobType(void) const {return m_MobType; } + char GetMobType(void) const {return m_MobType; } // MG TODO : see if we can delete this one. + eType GetMobTypeAsEnum(void) const {return (eType)m_MobType; } // MG TODO : see if we should store m_MobType as enum instead of char. virtual eFamily GetMobFamily(void) const = 0; const char * GetState(); From d2eb58f27780a3c65fedd0d21d152ee8866ebb86 Mon Sep 17 00:00:00 2001 From: mgueydan Date: Sat, 7 Sep 2013 22:19:56 +0200 Subject: [PATCH 05/22] Adding mob census (sorry this is a big commit as work was done before git integration i couldn't split it more) --- source/Chunk.cpp | 39 ++++++++++ source/Chunk.h | 4 + source/ChunkMap.cpp | 32 ++++++++ source/ChunkMap.h | 8 ++ source/MobCensus.cpp | 89 ++++++++++++++++++++++ source/MobCensus.h | 58 +++++++++++++++ source/MobFamilyCollecter.cpp | 33 +++++++++ source/MobFamilyCollecter.h | 40 ++++++++++ source/MobProximityCounter.cpp | 77 +++++++++++++++++++ source/MobProximityCounter.h | 65 +++++++++++++++++ source/MobTypesManager.cpp | 130 +++++++++++++++++++++++++++++++++ source/MobTypesManager.h | 41 +++++++++++ source/World.cpp | 5 ++ source/World.h | 1 + 14 files changed, 622 insertions(+) create mode 100644 source/MobCensus.cpp create mode 100644 source/MobCensus.h create mode 100644 source/MobFamilyCollecter.cpp create mode 100644 source/MobFamilyCollecter.h create mode 100644 source/MobProximityCounter.cpp create mode 100644 source/MobProximityCounter.h create mode 100644 source/MobTypesManager.cpp create mode 100644 source/MobTypesManager.h diff --git a/source/Chunk.cpp b/source/Chunk.cpp index db533f64..59a65a53 100644 --- a/source/Chunk.cpp +++ b/source/Chunk.cpp @@ -30,6 +30,8 @@ #include "PluginManager.h" #include "Blocks/BlockHandler.h" #include "Simulator/FluidSimulator.h" +#include "MobCensus.h" + #include @@ -429,6 +431,43 @@ void cChunk::Stay(bool a_Stay) +void cChunk::CollectMobCensus(cMobCensus& toFill) +{ + toFill.CollectSpawnableChunck(*this); + std::list 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_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) { diff --git a/source/Chunk.h b/source/Chunk.h index c979b792..5f2bba3d 100644 --- a/source/Chunk.h +++ b/source/Chunk.h @@ -49,6 +49,7 @@ class cPickup; class cChunkDataSerializer; class cBlockArea; class cFluidSimulatorData; +class cMobCensus; typedef std::list cClientHandleList; typedef cItemCallback cEntityCallback; @@ -124,6 +125,9 @@ public: /// Sets or resets the internal flag that prevents chunk from being unloaded 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); int GetPosX(void) const { return m_PosX; } diff --git a/source/ChunkMap.cpp b/source/ChunkMap.cpp index a15f3aed..610b293b 100644 --- a/source/ChunkMap.cpp +++ b/source/ChunkMap.cpp @@ -12,6 +12,7 @@ #include "BlockArea.h" #include "PluginManager.h" #include "Entities/TNTEntity.h" +#include "MobCensus.h" #ifndef _WIN32 #include // 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) { @@ -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) { diff --git a/source/ChunkMap.h b/source/ChunkMap.h index b0af0d77..c9d9abf7 100644 --- a/source/ChunkMap.h +++ b/source/ChunkMap.h @@ -26,6 +26,7 @@ class cPawn; class cPickup; class cChunkDataSerializer; class cBlockArea; +class cMobCensus; typedef std::list cClientHandleList; 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 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 UnloadUnusedChunks(void); @@ -309,6 +313,10 @@ private: void Save(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 RemoveClient(cClientHandle * a_Client); diff --git a/source/MobCensus.cpp b/source/MobCensus.cpp new file mode 100644 index 00000000..4984c53c --- /dev/null +++ b/source/MobCensus.cpp @@ -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 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 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)); +} diff --git a/source/MobCensus.h b/source/MobCensus.h new file mode 100644 index 00000000..32e60832 --- /dev/null +++ b/source/MobCensus.h @@ -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 tCapMultipliersMap; + static tCapMultipliersMap& m_CapMultipliers(); + + std::set 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 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(); +}; + diff --git a/source/MobFamilyCollecter.cpp b/source/MobFamilyCollecter.cpp new file mode 100644 index 00000000..2aa46599 --- /dev/null +++ b/source/MobFamilyCollecter.cpp @@ -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 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(); +} diff --git a/source/MobFamilyCollecter.h b/source/MobFamilyCollecter.h new file mode 100644 index 00000000..659d2b68 --- /dev/null +++ b/source/MobFamilyCollecter.h @@ -0,0 +1,40 @@ + +#pragma once + +#include +#include +#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 > 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 tMobFamilyList; + static tMobFamilyList& m_AllFamilies(); + +public : + typedef const std::map tMobSpawRate; + static tMobSpawRate& m_SpawnRate(); + +protected : + static tMobFamilyList initMobFamilyBeforeCx11(); + static tMobSpawRate initMobSpawnRateBeforeCx11(); +}; + diff --git a/source/MobProximityCounter.cpp b/source/MobProximityCounter.cpp new file mode 100644 index 00000000..59979fa1 --- /dev/null +++ b/source/MobProximityCounter.cpp @@ -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 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; +} diff --git a/source/MobProximityCounter.h b/source/MobProximityCounter.h new file mode 100644 index 00000000..d033f1b7 --- /dev/null +++ b/source/MobProximityCounter.h @@ -0,0 +1,65 @@ + +#pragma once + +#include + +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 tMonsterToDistance; + typedef std::multimap 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 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); + +}; diff --git a/source/MobTypesManager.cpp b/source/MobTypesManager.cpp new file mode 100644 index 00000000..d8606e61 --- /dev/null +++ b/source/MobTypesManager.cpp @@ -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* value = new std::map(MobTypes2NamesInitializerBeforeCx11()); + return *value; +} + +cMobTypesManager::tMobTypes2Names cMobTypesManager::MobTypes2NamesInitializerBeforeCx11() +{ + std::map toReturn; + typedef std::map::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::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::const_iterator itr = m_MobsTypes2Names().begin(); itr != m_MobsTypes2Names().end(); itr++) + { + if (itr->second == a_Name) + { + return itr->first; + } + } + throw new NotAMonsterException(); +} diff --git a/source/MobTypesManager.h b/source/MobTypesManager.h new file mode 100644 index 00000000..0e628899 --- /dev/null +++ b/source/MobTypesManager.h @@ -0,0 +1,41 @@ + +#pragma once + +#include +#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 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 + diff --git a/source/World.cpp b/source/World.cpp index d0fa588b..4bde20ed 100644 --- a/source/World.cpp +++ b/source/World.cpp @@ -29,6 +29,7 @@ // Mobs: #include "Mobs/IncludeAllMonsters.h" +#include "MobCensus.h" #include "OSSupport/MakeDir.h" #include "MersenneTwister.h" @@ -712,6 +713,10 @@ void cWorld::TickSpawnMobs(float a_Dt) { return; } + + cMobCensus MobCensus; + m_ChunkMap->CollectMobCensus(MobCensus); + MobCensus.logd(); m_LastSpawnMonster = m_WorldAge; Vector3d SpawnPos; diff --git a/source/World.h b/source/World.h index 1f82f4ef..6fb5c619 100644 --- a/source/World.h +++ b/source/World.h @@ -42,6 +42,7 @@ class cChunkGenerator; // The thread responsible for generating chunks class cChestEntity; class cDispenserEntity; class cFurnaceEntity; +class cMobCensus; typedef std::list< cPlayer * > cPlayerList; From bf1fb0aa3dbd5b6b793d920c4e301e4782fe0f0f Mon Sep 17 00:00:00 2001 From: mgueydan Date: Sun, 8 Sep 2013 00:11:38 +0200 Subject: [PATCH 06/22] Adding an Empty shell that would launch mob spawner - not called yet --- source/Chunk.cpp | 37 +++++++++++++++++++++++++++++++++++++ source/Chunk.h | 8 ++++++++ source/ChunkMap.cpp | 28 ++++++++++++++++++++++++++++ source/ChunkMap.h | 11 ++++++++--- source/MobSpawner.h | 28 ++++++++++++++++++++++++++++ 5 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 source/MobSpawner.h diff --git a/source/Chunk.cpp b/source/Chunk.cpp index 59a65a53..35e44363 100644 --- a/source/Chunk.cpp +++ b/source/Chunk.cpp @@ -31,6 +31,7 @@ #include "Blocks/BlockHandler.h" #include "Simulator/FluidSimulator.h" #include "MobCensus.h" +#include "MobSpawner.h" #include @@ -468,6 +469,42 @@ void cChunk::CollectMobCensus(cMobCensus& toFill) +void cChunk::getThreeRandomNumber(int& a_X, int& a_Y, int& a_Z,int a_MaxX, int a_MaxY, int a_MaxZ) +{ + assert(a_MaxX * a_MaxY * a_MaxZ * 8 < 0x00ffffff); + int Random = m_World->GetTickRandomNumber(0x00ffffff); + a_X = Random % (a_MaxX * 2); + a_Y = (Random / (a_MaxX * 2)) % (a_MaxY * 2); + a_Z = ((Random / (a_MaxX * 2)) / (a_MaxY * 2)) % (a_MaxZ * 2); + a_X /= 2; + a_Y /= 2; + a_Z /= 2; +} + + + + + +void cChunk::getRandomBlock(int& a_X, int& a_Y, int& a_Z) +{ + // MG TODO : check if this kind of optimization (only one random call) is still needed + // MG TODO : if so propagate it + + getThreeRandomNumber(a_X, a_Y, a_Z, Width, Height-2, Width); + a_Y++; +} + + + + + +void cChunk::SpawnMobs(cMobSpawner& a_MobSpawner) +{ +} + + + + void cChunk::Tick(float a_Dt) { diff --git a/source/Chunk.h b/source/Chunk.h index 5f2bba3d..69ecbfec 100644 --- a/source/Chunk.h +++ b/source/Chunk.h @@ -50,6 +50,7 @@ class cChunkDataSerializer; class cBlockArea; class cFluidSimulatorData; class cMobCensus; +class cMobSpawner; typedef std::list cClientHandleList; typedef cItemCallback cEntityCallback; @@ -128,6 +129,9 @@ public: /// Recence all mobs proximities to players in order to know what to do with them void CollectMobCensus(cMobCensus& toFill); + /// Try to Spawn Monsters inside chunk + void SpawnMobs(cMobSpawner& a_MobSpawner); + void Tick(float a_Dt); int GetPosX(void) const { return m_PosX; } @@ -389,6 +393,10 @@ private: cSandSimulatorChunkData m_SandSimulatorData; + // pick up a random block of this chunk + void getRandomBlock(int& a_X, int& a_Y, int& a_Z); + void getThreeRandomNumber(int& a_X, int& a_Y, int& a_Z,int a_MaxX, int a_MaxY, int a_MaxZ); + void RemoveBlockEntity(cBlockEntity * a_BlockEntity); void AddBlockEntity (cBlockEntity * a_BlockEntity); diff --git a/source/ChunkMap.cpp b/source/ChunkMap.cpp index 610b293b..f5cbacdc 100644 --- a/source/ChunkMap.cpp +++ b/source/ChunkMap.cpp @@ -13,6 +13,7 @@ #include "PluginManager.h" #include "Entities/TNTEntity.h" #include "MobCensus.h" +#include "MobSpawner.h" #ifndef _WIN32 #include // abs @@ -2167,6 +2168,19 @@ void cChunkMap::CollectMobCensus(cMobCensus& a_ToFill) +void cChunkMap::SpawnMobs(cMobSpawner& a_MobSpawner) +{ + cCSLock Lock(m_CSLayers); + for (cChunkLayerList::iterator itr = m_Layers.begin(); itr != m_Layers.end(); ++itr) + { + (*itr)->SpawnMobs(a_MobSpawner); + } // for itr - m_Layers +} + + + + + void cChunkMap::Tick(float a_Dt) { cCSLock Lock(m_CSLayers); @@ -2343,6 +2357,20 @@ void cChunkMap::cChunkLayer::CollectMobCensus(cMobCensus& a_ToFill) +void cChunkMap::cChunkLayer::SpawnMobs(cMobSpawner& a_MobSpawner) +{ + for (int i = 0; i < ARRAYCOUNT(m_Chunks); i++) + { + // We only spawn close to players + if ((m_Chunks[i] != NULL) && m_Chunks[i]->IsValid() && m_Chunks[i]->HasAnyClients()) + { + m_Chunks[i]->SpawnMobs(a_MobSpawner); + } + } // for i - m_Chunks[] +} + + + void cChunkMap::cChunkLayer::Tick(float a_Dt) { for (int i = 0; i < ARRAYCOUNT(m_Chunks); i++) diff --git a/source/ChunkMap.h b/source/ChunkMap.h index c9d9abf7..168f54b3 100644 --- a/source/ChunkMap.h +++ b/source/ChunkMap.h @@ -27,6 +27,7 @@ class cPickup; class cChunkDataSerializer; class cBlockArea; class cMobCensus; +class cMobSpawner; typedef std::list cClientHandleList; typedef cChunk * cChunkPtr; @@ -264,12 +265,15 @@ public: /// Grows a cactus present at the block specified by the amount of blocks specified, up to the max height specified in the config void GrowCactus(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow); - /// 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); /// Make a Mob census, of all mobs, their family, their chunk and theyr distance to closest player void CollectMobCensus(cMobCensus& a_ToFill); + /// Try to Spawn Monsters inside all Chunks + void SpawnMobs(cMobSpawner& a_MobSpawner); + void Tick(float a_Dt); void UnloadUnusedChunks(void); @@ -314,8 +318,9 @@ private: 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 CollectMobCensus(cMobCensus& a_ToFill); + /// Try to Spawn Monsters inside all Chunks + void SpawnMobs(cMobSpawner& a_MobSpawner); void Tick(float a_Dt); diff --git a/source/MobSpawner.h b/source/MobSpawner.h new file mode 100644 index 00000000..7498c567 --- /dev/null +++ b/source/MobSpawner.h @@ -0,0 +1,28 @@ + +#pragma once + +#include +#include "BlockID.h" +#include "ChunkDef.h" +#include "FastRandom.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; +class cEntity; + + +// This class is used to determine wich monster can be spawned on wich place +// it is essentially static (f.i. Squids spawn in water, Zombie spawn in dark places) +// but it also has dynamic part depending on the world.ini +class cMobSpawner +{ +public : + // constructor + // a_MobFamily is the mega type of mobs that this spawner will spawn + // a_AllowedTypes is the set of types allowed for mobs it will spawn. Empty set + // would result in no spawn at all + // Allowed mobs thah are not of the right Megatype will not be include (no warning) + cMobSpawner(cMonster::eFamily MobFamily, const std::set& a_AllowedTypes); + + +}; From caa54af54640d1c94c57bc84b6b1e4eb2e7a6f3c Mon Sep 17 00:00:00 2001 From: mgueydan Date: Sun, 8 Sep 2013 01:21:43 +0200 Subject: [PATCH 07/22] Implementing the MobSpawner (not used yet) that contains spawning rules --- source/MobSpawner.cpp | 277 +++++++++++++++++++++++++++++++++++++ source/MobSpawner.h | 50 ++++++- source/MobTypesManager.cpp | 50 ++++++- source/MobTypesManager.h | 11 +- source/Mobs/Monster.h | 5 +- 5 files changed, 384 insertions(+), 9 deletions(-) create mode 100644 source/MobSpawner.cpp diff --git a/source/MobSpawner.cpp b/source/MobSpawner.cpp new file mode 100644 index 00000000..19e3739c --- /dev/null +++ b/source/MobSpawner.cpp @@ -0,0 +1,277 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "MobSpawner.h" +#include "MobTypesManager.h" +#include "Mobs/Monster.h" +#include "Mobs/IncludeAllMonsters.h" + + +cMobSpawner::tMobTypes& cMobSpawner::m_MobTypes() +{ + static tMobTypes* value = new tMobTypes(initMobTypesBeforeCx11()); + return *value; +} + +cMobSpawner::tMobTypes cMobSpawner::initMobTypesBeforeCx11() +{ + std::set toReturn; + toReturn.insert(cMonster::mtCreeper); + toReturn.insert(cMonster::mtSkeleton); + toReturn.insert(cMonster::mtSpider); + toReturn.insert(cMonster::mtGiant); + toReturn.insert(cMonster::mtZombie); + toReturn.insert(cMonster::mtSlime); + toReturn.insert(cMonster::mtGhast); + toReturn.insert(cMonster::mtZombiePigman); + toReturn.insert(cMonster::mtEnderman); + toReturn.insert(cMonster::mtCaveSpider); + toReturn.insert(cMonster::mtSilverfish); + toReturn.insert(cMonster::mtBlaze); + toReturn.insert(cMonster::mtMagmaCube); + toReturn.insert(cMonster::mtEnderDragon); + toReturn.insert(cMonster::mtWither); + toReturn.insert(cMonster::mtBat); + toReturn.insert(cMonster::mtWitch); + toReturn.insert(cMonster::mtPig); + toReturn.insert(cMonster::mtSheep); + toReturn.insert(cMonster::mtCow); + toReturn.insert(cMonster::mtChicken); + toReturn.insert(cMonster::mtSquid); + toReturn.insert(cMonster::mtWolf); + toReturn.insert(cMonster::mtMooshroom); + toReturn.insert(cMonster::mtSnowGolem); + toReturn.insert(cMonster::mtOcelot); + toReturn.insert(cMonster::mtIronGolem); + toReturn.insert(cMonster::mtVillager); + return toReturn; +} + + +cMobSpawner::cMobSpawner(cMonster::eFamily a_MonsterFamily,const std::set& a_AllowedTypes) : + m_MonsterFamily(a_MonsterFamily), + m_NewPack(true), + m_MobType(cMonster::mtInvalidType) +{ + for (std::set::const_iterator itr = a_AllowedTypes.begin(); itr != a_AllowedTypes.end(); itr++) + { + if (cMobTypesManager::getFamilyFromType(*itr) == a_MonsterFamily) + { + m_AllowedTypes.insert(*itr); + } + } +} + +bool cMobSpawner::CheckPackCenter(BLOCKTYPE a_BlockType) +{ + // Packs of non-water mobs can only be centered on an air block + // Packs of water mobs can only be centered on a water block + if (m_MonsterFamily == cMonster::mfWater) + { + return IsBlockWater(a_BlockType); + } + else + { + return a_BlockType == E_BLOCK_AIR; + } +} + +void cMobSpawner::addIfAllowed(cMonster::eType toAdd, std::set& toAddIn) +{ + std::set::iterator itr = m_AllowedTypes.find(toAdd); + if (itr != m_AllowedTypes.end()) + { + toAddIn.insert(toAdd); + } +} + +cMonster::eType cMobSpawner::ChooseMobType(EMCSBiome a_Biome) +{ + std::set allowedMobs; + + if (a_Biome == biMushroomIsland || a_Biome == biMushroomShore) + { + addIfAllowed(cMonster::mtMooshroom, allowedMobs); + } + else if (a_Biome == biNether) + { + addIfAllowed(cMonster::mtGhast, allowedMobs); + addIfAllowed(cMonster::mtZombiePigman, allowedMobs); + addIfAllowed(cMonster::mtMagmaCube, allowedMobs); + } + /*else if (a_Biome == biEnder) MG TODO : figure out what are the biomes of the ender + { + addIfAllowed(cMonster::mtEnderman, allowedMobs); + }*/ + else + { + addIfAllowed(cMonster::mtBat, allowedMobs); + addIfAllowed(cMonster::mtSpider, allowedMobs); + addIfAllowed(cMonster::mtZombie, allowedMobs); + addIfAllowed(cMonster::mtSkeleton, allowedMobs); + addIfAllowed(cMonster::mtCreeper, allowedMobs); + addIfAllowed(cMonster::mtSquid, allowedMobs); + + if (a_Biome != biDesert && a_Biome != biBeach && a_Biome != biOcean) + { + addIfAllowed(cMonster::mtSheep, allowedMobs); + addIfAllowed(cMonster::mtPig, allowedMobs); + addIfAllowed(cMonster::mtCow, allowedMobs); + addIfAllowed(cMonster::mtChicken, allowedMobs); + addIfAllowed(cMonster::mtEnderman, allowedMobs); + addIfAllowed(cMonster::mtSlime, allowedMobs); // MG TODO : much more complicated rule + + if (a_Biome == biForest || a_Biome == biForestHills || a_Biome == biTaiga || a_Biome == biTaigaHills) + { + addIfAllowed(cMonster::mtWolf, allowedMobs); + } + else if (a_Biome == biJungle || a_Biome == biJungleHills) + { + addIfAllowed(cMonster::mtOcelot, allowedMobs); + } + } + } + + int allowedMobsSize = allowedMobs.size(); + if (allowedMobsSize > 0) + { + std::set::iterator itr = allowedMobs.begin(); + int iRandom = m_Random.NextInt(allowedMobsSize,a_Biome); + + for(int i = 0; i < iRandom; i++) + { + itr++; + } + + return *itr; + } + return cMonster::mtInvalidType; +} + + +bool cMobSpawner::CanSpawnHere(cMonster::eType a_MobType, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, BLOCKTYPE a_BlockType_below, NIBBLETYPE a_BlockMeta_below, BLOCKTYPE a_BlockType_above, NIBBLETYPE a_BlockMeta_above, EMCSBiome a_Biome, int a_Level) +{ + bool toReturn = false; + std::set::iterator itr = m_AllowedTypes.find(a_MobType); + if (itr != m_AllowedTypes.end()) + { + // MG TODO : find a nicer paging + if (a_MobType == cMonster::mtSquid) + { + toReturn = ( + IsBlockLiquid(a_BlockType) && + a_Level >= 45 && + a_Level <= 62 + ); + } + else if (a_MobType == cMonster::mtBat) + { + toReturn = a_Level <= 60; // MG TODO : find a real rule + } + else + { + if ( + a_BlockType == E_BLOCK_AIR && + a_BlockType_above == E_BLOCK_AIR && + ! (g_BlockTransparent[a_BlockType_below]) + ) + { + if (a_MobType == cMonster::mtChicken || a_MobType == cMonster::mtPig || a_MobType == cMonster::mtCow || a_MobType == cMonster::mtSheep) + { + LOGD("Trying to spawn an animal"); + toReturn = ( + a_BlockType_below == E_BLOCK_GRASS /*&& // MG TODO + a_LightLevel >= 9 */ + ); + } + else if (a_MobType == cMonster::mtOcelot) + { + toReturn = ( + a_Level >= 62 && + ( + a_BlockType_below == E_BLOCK_GRASS || + a_BlockType_below == E_BLOCK_LEAVES + ) && + m_Random.NextInt(3,a_Biome) != 0 + ); + } + else if (a_MobType == cMonster::mtCreeper || a_MobType == cMonster::mtSkeleton || a_MobType == cMonster::mtZombie || a_MobType == cMonster::mtSpider || a_MobType == cMonster::mtEnderman || a_MobType == cMonster::mtZombiePigman) + { + toReturn = true /*a_LightLevel <= 7 MG TODO*/; + /*if (a_SunLight) MG TODO + { + if (m_Random.NextInt(2,a_Biome) != 0) + { + toReturn = false; + } + }*/ + } + else if (a_MobType == cMonster::mtSlime) + { + toReturn = a_Level <= 40; + // MG TODO : much more complicated rules + } + else if (a_MobType == cMonster::mtGhast) + { + toReturn = m_Random.NextInt(20,a_Biome) == 0; + } + else + { + LOGD("MG TODO : check I've got a Rule to write for type %d",a_MobType); + toReturn = true; + } + } + } + } + return toReturn; +} + + +cMonster* cMobSpawner::TryToSpawnHere(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, BLOCKTYPE a_BlockType_below, NIBBLETYPE a_BlockMeta_below, BLOCKTYPE a_BlockType_above, NIBBLETYPE a_BlockMeta_above, EMCSBiome a_Biome, int a_Level, int& a_MaxPackSize) +{ + cMonster* toReturn = NULL; + if (m_NewPack) + { + m_MobType = ChooseMobType(a_Biome); + if (m_MobType == cMonster::mtInvalidType) + { + return toReturn; + } + if (m_MobType == cMonster::mtWolf) + { + a_MaxPackSize = 8; + } + else if (m_MobType == cMonster::mtGhast) + { + a_MaxPackSize = 1; + } + m_NewPack = false; + } + + + if (CanSpawnHere(m_MobType, a_BlockType, a_BlockMeta, a_BlockType_below, a_BlockMeta_below, a_BlockType_above, a_BlockMeta_above, a_Biome, a_Level)) + { + cMonster* newMob = cMobTypesManager::NewMonsterFromType(m_MobType); + if (newMob) + { + m_Spawned.insert(newMob); + } + toReturn = newMob; + } + return toReturn; +} + +void cMobSpawner::NewPack() +{ + m_NewPack = true; +} + +cMobSpawner::tSpawnedContainer& cMobSpawner::getSpawned() +{ + return m_Spawned; +} + +bool cMobSpawner::CanSpawnSomething() +{ + return m_AllowedTypes.size() > 0; +} diff --git a/source/MobSpawner.h b/source/MobSpawner.h index 7498c567..bb9e9517 100644 --- a/source/MobSpawner.h +++ b/source/MobSpawner.h @@ -8,7 +8,6 @@ #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; -class cEntity; // This class is used to determine wich monster can be spawned on wich place @@ -18,11 +17,56 @@ class cMobSpawner { public : // constructor - // a_MobFamily is the mega type of mobs that this spawner will spawn + // a_MobFamily is the Family of mobs that this spawner will spawn // a_AllowedTypes is the set of types allowed for mobs it will spawn. Empty set // would result in no spawn at all - // Allowed mobs thah are not of the right Megatype will not be include (no warning) + // Allowed mobs thah are not of the right Family will not be include (no warning) cMobSpawner(cMonster::eFamily MobFamily, const std::set& a_AllowedTypes); + // Check if specified block can be a Pack center for this spawner + bool CheckPackCenter(BLOCKTYPE a_BlockType); + + // Try to create a monster here + // if this is the first of a Pack : determine the type of monster + // BlockType & BlockMeta are use to know what kind of Mob can Spawn here + // MaxPackSize is set to the maximal size for a pack this type of mob + cMonster* TryToSpawnHere(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, BLOCKTYPE a_BlockType_below, NIBBLETYPE a_BlockMeta_below, BLOCKTYPE a_BlockType_above, NIBBLETYPE a_BlockMeta_above, EMCSBiome a_Biome, int a_Level, int& a_MaxPackSize); + + // mark the beginning of a new Pack + // all mobs of the same Pack are the same type + void NewPack(); + + // return true if there is at least one allowed type + bool CanSpawnSomething(); + + typedef const std::set tSpawnedContainer; + tSpawnedContainer& getSpawned(); + +protected : + // return true if specified type of mob can spawn on specified block + bool CanSpawnHere(cMonster::eType a_MobType, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, BLOCKTYPE a_BlockType_below, NIBBLETYPE a_BlockMeta_below, BLOCKTYPE a_BlockType_above, NIBBLETYPE a_BlockMeta_above, EMCSBiome a_Biome, int a_Level); + + // return a random type that can spawn on specified biome. + // returns E_ENTITY_TYPE_DONOTUSE if none is possible + cMonster::eType ChooseMobType(EMCSBiome a_Biome); + + // add toAdd inside toAddIn, if toAdd is in m_AllowedTypes + void addIfAllowed(cMonster::eType toAdd, std::set& toAddIn); + +protected : + cMonster::eFamily m_MonsterFamily; + std::set m_AllowedTypes; + bool m_NewPack; + cMonster::eType m_MobType; + std::set m_Spawned; + cFastRandom m_Random; + +public : + typedef const std::set tMobTypes; // MG TODO : maybe relocate all those statics set/maps in the same place ? + static tMobTypes& m_MobTypes(); + +protected : + static tMobTypes initMobTypesBeforeCx11(); + }; diff --git a/source/MobTypesManager.cpp b/source/MobTypesManager.cpp index d8606e61..0c13e5ae 100644 --- a/source/MobTypesManager.cpp +++ b/source/MobTypesManager.cpp @@ -44,6 +44,43 @@ cMobTypesManager::tMobTypes2Names cMobTypesManager::MobTypes2NamesInitializerBef return toReturn; } +cMobTypesManager::tMobType2Family& cMobTypesManager::m_MobsType2Family() +{ + static std::map* value = new std::map(MobType2FamilyInitializerBeforeCx11()); + return *value; +} + +cMobTypesManager::tMobType2Family cMobTypesManager::MobType2FamilyInitializerBeforeCx11() +{ + std::map toReturn; + typedef std::map::value_type ValueType; + toReturn.insert(ValueType(cMonster::mtBat,cMonster::mfAmbient)); + toReturn.insert(ValueType(cMonster::mtSquid,cMonster::mfWater)); + toReturn.insert(ValueType(cMonster::mtCow,cMonster::mfPassive)); + toReturn.insert(ValueType(cMonster::mtPig,cMonster::mfPassive)); + toReturn.insert(ValueType(cMonster::mtSheep,cMonster::mfPassive)); + toReturn.insert(ValueType(cMonster::mtChicken,cMonster::mfPassive)); + toReturn.insert(ValueType(cMonster::mtVillager,cMonster::mfPassive)); + toReturn.insert(ValueType(cMonster::mtMagmaCube,cMonster::mfHostile)); + toReturn.insert(ValueType(cMonster::mtSlime,cMonster::mfHostile)); + toReturn.insert(ValueType(cMonster::mtBlaze,cMonster::mfHostile)); + toReturn.insert(ValueType(cMonster::mtCaveSpider,cMonster::mfHostile)); + toReturn.insert(ValueType(cMonster::mtCreeper,cMonster::mfHostile)); + toReturn.insert(ValueType(cMonster::mtEnderman,cMonster::mfHostile)); + toReturn.insert(ValueType(cMonster::mtGhast,cMonster::mfHostile)); + toReturn.insert(ValueType(cMonster::mtMooshroom,cMonster::mfHostile)); + toReturn.insert(ValueType(cMonster::mtOcelot,cMonster::mfHostile)); + toReturn.insert(ValueType(cMonster::mtSilverfish,cMonster::mfHostile)); + toReturn.insert(ValueType(cMonster::mtSkeleton,cMonster::mfHostile)); + toReturn.insert(ValueType(cMonster::mtSpider,cMonster::mfHostile)); + toReturn.insert(ValueType(cMonster::mtWitch,cMonster::mfHostile)); + toReturn.insert(ValueType(cMonster::mtWolf,cMonster::mfHostile)); + toReturn.insert(ValueType(cMonster::mtZombie,cMonster::mfHostile)); + toReturn.insert(ValueType(cMonster::mtZombiePigman,cMonster::mfHostile)); + + return toReturn; +} + cFastRandom& cMobTypesManager::m_Random() { @@ -126,5 +163,16 @@ cMonster::eType cMobTypesManager::fromStringToMobType(const std::string& a_Name) return itr->first; } } - throw new NotAMonsterException(); + return cMonster::mtInvalidType; +} + +cMonster::eFamily cMobTypesManager::getFamilyFromType(cMonster::eType a_Type) +{ + cMonster::eFamily toReturn = cMonster::mfMaxplusone; + std::map::const_iterator itr = m_MobsType2Family().find(a_Type); + if (itr != m_MobsType2Family().end()) + { + toReturn = itr->second; + } + return toReturn; } diff --git a/source/MobTypesManager.h b/source/MobTypesManager.h index 0e628899..a1b2dfdd 100644 --- a/source/MobTypesManager.h +++ b/source/MobTypesManager.h @@ -10,20 +10,23 @@ class cFastRandom; // 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 +// - return mob family from providen type 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 + static cMonster::eType fromStringToMobType(const std::string& a_MobTypeName); + static cMonster::eFamily getFamilyFromType(cMonster::eType a_MobType); protected : typedef const std::map tMobTypes2Names; static tMobTypes2Names& m_MobsTypes2Names(); static tMobTypes2Names MobTypes2NamesInitializerBeforeCx11(); + typedef const std::map tMobType2Family; //MG TODO : this is redundancy with cMonster::getFamily() methods. But almost all the management of MobType is redundancy in this project. Maybe is it optimization, or just historical TODO : understand and do something about it. + static tMobType2Family& m_MobsType2Family(); + static tMobType2Family MobType2FamilyInitializerBeforeCx11(); + static cFastRandom& m_Random(); public : diff --git a/source/Mobs/Monster.h b/source/Mobs/Monster.h index 594914ca..ef7904e8 100644 --- a/source/Mobs/Monster.h +++ b/source/Mobs/Monster.h @@ -54,6 +54,8 @@ public: mtOcelot = E_META_SPAWN_EGG_OCELOT, mtIronGolem = E_META_SPAWN_EGG_IRON_GOLEM, mtVillager = E_META_SPAWN_EGG_VILLAGER, + + mtInvalidType, // MG TODO : be sure this is the way we do in this project. (needed inside cMobSpawner::ChooscMonster for instance if nothing can be spawned) } ; enum eFamily @@ -62,7 +64,8 @@ public: mfPassive = 1, // Cows, Pigs mfAmbient = 2, // Bats mfWater = 3, // Squid - mfMaxplusone = 4, // Nothing + + mfMaxplusone, // Nothing. Be sure this is the last and the others are in order } ; // tolua_end From 04151677d57905e35993eac4899e6bd72831ec6f Mon Sep 17 00:00:00 2001 From: mgueydan Date: Sun, 8 Sep 2013 01:43:55 +0200 Subject: [PATCH 08/22] Disabeling current mob spawning and tick --- source/Chunk.cpp | 8 ++++++-- source/World.cpp | 9 +++++---- source/World.h | 4 ++-- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/source/Chunk.cpp b/source/Chunk.cpp index 35e44363..1d649f3f 100644 --- a/source/Chunk.cpp +++ b/source/Chunk.cpp @@ -533,10 +533,14 @@ void cChunk::Tick(float a_Dt) m_IsDirty = (*itr)->Tick(a_Dt, *this) | m_IsDirty; } - // Tick all entities in this chunk: + // Tick all entities in this chunk (except mobs): for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr) { - (*itr)->Tick(a_Dt, *this); + // Mobs are tickes inside MobTick (as we don't have to tick them if they are far away from players) + if (!((*itr)->IsMob())) + { + (*itr)->Tick(a_Dt, *this); + } } // for itr - m_Entitites[] // Remove all entities that were scheduled for removal: diff --git a/source/World.cpp b/source/World.cpp index 4bde20ed..17c5ccb3 100644 --- a/source/World.cpp +++ b/source/World.cpp @@ -622,7 +622,7 @@ void cWorld::Tick(float a_Dt) UnloadUnusedChunks(); } - TickSpawnMobs(a_Dt); + TickMobs(a_Dt); std::vector m_RSList_copy(m_RSList); @@ -707,13 +707,13 @@ void cWorld::TickWeather(float a_Dt) -void cWorld::TickSpawnMobs(float a_Dt) +void cWorld::TickMobs(float a_Dt) { - if (!m_bAnimals || (m_WorldAge - m_LastSpawnMonster <= m_SpawnMonsterRate)) + if (!m_bAnimals) { return; } - +/* cMobCensus MobCensus; m_ChunkMap->CollectMobCensus(MobCensus); MobCensus.logd(); @@ -810,6 +810,7 @@ void cWorld::TickSpawnMobs(float a_Dt) // A proper mob type was selected, now spawn the mob: SpawnMob(SpawnPos.x, SpawnPos.y, SpawnPos.z, (cMonster::eType)MobType); } +*/ } diff --git a/source/World.h b/source/World.h index 6fb5c619..eb19dce4 100644 --- a/source/World.h +++ b/source/World.h @@ -711,8 +711,8 @@ private: /// Handles the weather in each tick void TickWeather(float a_Dt); - /// Handles the mob spawning each tick - void TickSpawnMobs(float a_Dt); + /// Handles the mob spawning/moving/destroying each tick + void TickMobs(float a_Dt); /// Executes all tasks queued onto the tick thread void TickQueuedTasks(void); From 7a5e3592ffcc80f8c768ed2391b0ad521c59b67e Mon Sep 17 00:00:00 2001 From: mgueydan Date: Sun, 8 Sep 2013 02:47:02 +0200 Subject: [PATCH 09/22] Adding glue to call everything done in last commits - now the mobs are spawning --- source/Chunk.cpp | 61 ++++++++++++++ source/World.cpp | 215 ++++++++++++++++------------------------------- source/World.h | 5 +- 3 files changed, 138 insertions(+), 143 deletions(-) diff --git a/source/Chunk.cpp b/source/Chunk.cpp index 1d649f3f..8c4c7725 100644 --- a/source/Chunk.cpp +++ b/source/Chunk.cpp @@ -500,6 +500,67 @@ void cChunk::getRandomBlock(int& a_X, int& a_Y, int& a_Z) void cChunk::SpawnMobs(cMobSpawner& a_MobSpawner) { + int Center_X,Center_Y,Center_Z; + getRandomBlock(Center_X,Center_Y,Center_Z); + + BLOCKTYPE PackCenterBlock = GetBlock(Center_X, Center_Y, Center_Z); + if (a_MobSpawner.CheckPackCenter(PackCenterBlock)) + { + a_MobSpawner.NewPack(); + int NumberOfTries = 0; + int NumberOfSuccess = 0; + int MaxNbOfSuccess = 4; // this can be changed during the process for Wolves and Ghass + while (NumberOfTries < 12 && NumberOfSuccess < MaxNbOfSuccess) + { + const int HorizontalRange = 20; // MG TODO : relocate + const int VerticalRange = 0; // MG TODO : relocate + int Try_X, Try_Y, Try_Z; + getThreeRandomNumber(Try_X, Try_Y, Try_Z, 2*HorizontalRange+1 , 2*VerticalRange+1 , 2*HorizontalRange+1); + Try_X -= HorizontalRange; + Try_Y -= VerticalRange; + Try_Z -= HorizontalRange; + Try_X += Center_X; + Try_Y += Center_Y; + Try_Z += Center_Z; + + assert(Try_Y > 0); + assert(Try_Y < cChunkDef::Height-1); + + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + BLOCKTYPE BlockType_below; + NIBBLETYPE BlockMeta_below; + BLOCKTYPE BlockType_above; + NIBBLETYPE BlockMeta_above; + if (UnboundedRelGetBlock(Try_X, Try_Y , Try_Z, BlockType, BlockMeta) && + UnboundedRelGetBlock(Try_X, Try_Y-1, Try_Z, BlockType_below, BlockMeta_below)&& + UnboundedRelGetBlock(Try_X, Try_Y+1, Try_Z, BlockType_above, BlockMeta_above) + ) + { + EMCSBiome Biome = m_ChunkMap->GetBiomeAt (Try_X, Try_Z); + // MG TODO : + // Moon cycle (for slime) + // check player and playerspawn presence < 24 blocks + // check mobs presence on the block + + // MG TODO: fix the "light" thing, I'm pretty sure that UnboundedRelGetBlock s not returning the right thing + + // MG TODO : check that "Level" really means Y + cEntity* newMob = a_MobSpawner.TryToSpawnHere(BlockType, BlockMeta, BlockType_below, BlockMeta_below, BlockType_above, BlockMeta_above, Biome, Try_Y, MaxNbOfSuccess); + if (newMob) + { + int WorldX, WorldY, WorldZ; + PositionToWorldPosition(Try_X, Try_Y, Try_Z, WorldX, WorldY, WorldZ); + newMob->SetPosition(WorldX, WorldY, WorldZ); + LOGD("Spawning %s #%i at %d,%d,%d",newMob->GetClass(),newMob->GetUniqueID(),WorldX, WorldY, WorldZ); + NumberOfSuccess++; + } + } + + NumberOfTries++; + } + } + } diff --git a/source/World.cpp b/source/World.cpp index 17c5ccb3..2e8f3084 100644 --- a/source/World.cpp +++ b/source/World.cpp @@ -30,6 +30,9 @@ // Mobs: #include "Mobs/IncludeAllMonsters.h" #include "MobCensus.h" +#include "MobSpawner.h" +#include "MobTypesManager.h" + #include "OSSupport/MakeDir.h" #include "MersenneTwister.h" @@ -226,7 +229,6 @@ cWorld::cWorld(const AString & a_WorldName) : m_WorldAge(0), m_TimeOfDay(0), m_LastTimeUpdate(0), - m_LastSpawnMonster(0), m_RSList(0), m_Weather(eWeather_Sunny), m_WeatherInterval(24000), // Guaranteed 1 day of sunshine at server start :) @@ -490,14 +492,13 @@ void cWorld::Start(void) m_GameMode = (eGameMode)IniFile.GetValueSetI("GameMode", "GameMode", m_GameMode); m_bAnimals = true; - m_SpawnMonsterRate = 200; // 1 mob each 10 seconds - cIniFile IniFile2("settings.ini"); - if (IniFile2.ReadFile()) - { - m_bAnimals = IniFile2.GetValueB("Monsters", "AnimalsOn", true); - m_SpawnMonsterRate = (Int64)(IniFile2.GetValueF("Monsters", "AnimalSpawnInterval", 10) * 20); // Convert from secs to ticks - - } + + m_AllowedMobs.insert(cMonster::mtCow); // MG TODO : temporary + m_AllowedMobs.insert(cMonster::mtZombie); + m_AllowedMobs.insert(cMonster::mtZombiePigman); + m_AllowedMobs.insert(cMonster::mtBat); + m_AllowedMobs.insert(cMonster::mtSpider); + m_AllowedMobs.insert(cMonster::mtGhast); m_ChunkMap = new cChunkMap(this); @@ -527,6 +528,13 @@ void cWorld::Start(void) m_ChunkSender.Start(this); m_TickThread.Start(); + // Init of the spawn monster time (as they are supposed to have different spawn rate) + m_LastSpawnMonster.insert(std::map::value_type(cMonster::mfHostile,0)); + m_LastSpawnMonster.insert(std::map::value_type(cMonster::mfPassive,0)); + m_LastSpawnMonster.insert(std::map::value_type(cMonster::mfAmbient,0)); + m_LastSpawnMonster.insert(std::map::value_type(cMonster::mfWater,0)); + + // Save any changes that the defaults may have done to the ini file: if (!IniFile.WriteFile()) { @@ -713,104 +721,52 @@ void cWorld::TickMobs(float a_Dt) { return; } -/* + + // before every Mob action, we have to "counts" them depending on the distance to players, on their megatype ... cMobCensus MobCensus; m_ChunkMap->CollectMobCensus(MobCensus); - MobCensus.logd(); - - m_LastSpawnMonster = m_WorldAge; - Vector3d SpawnPos; + + for(cMobFamilyCollecter::tMobFamilyList::const_iterator itr = cMobFamilyCollecter::m_AllFamilies().begin(); itr != cMobFamilyCollecter::m_AllFamilies().end(); itr++) { - cCSLock Lock(m_CSPlayers); - if (m_Players.size() <= 0) + cMobCensus::tMobSpawnRate::const_iterator spawnrate = cMobCensus::m_SpawnRate().find(*itr); + // hostile mobs are spawned more often + if (spawnrate != cMobCensus::m_SpawnRate().end() && m_LastSpawnMonster[*itr] < m_WorldAge - spawnrate->second) { - return; - } - int RandomPlayerIdx = m_TickRand.randInt() & m_Players.size(); - cPlayerList::iterator itr = m_Players.begin(); - for (int i = 1; i < RandomPlayerIdx; i++) - { - itr++; - } - SpawnPos = (*itr)->GetPosition(); - } - - int dayRand = (m_TickRand.randInt() / 7) % 6; - int nightRand = (m_TickRand.randInt() / 11) % 10; - - SpawnPos += Vector3d((double)(m_TickRand.randInt() % 64) - 32, (double)(m_TickRand.randInt() % 64) - 32, (double)(m_TickRand.randInt() % 64) - 32); - int Height = GetHeight((int)SpawnPos.x, (int)SpawnPos.z); - - int MobType = -1; - int Biome = GetBiomeAt((int)SpawnPos.x, (int)SpawnPos.z); - switch (Biome) - { - case biNether: - { - // Spawn nether mobs - switch (nightRand) + m_LastSpawnMonster[*itr] = m_WorldAge; + // each megatype of mob has it's own cap + if (!(MobCensus.isCaped(*itr))) { - case 5: MobType = cMonster::mtGhast; break; - case 6: MobType = cMonster::mtZombiePigman; break; - } - break; - } - - case biEnd: - { - // Only endermen spawn in the End - MobType = cMonster::mtEnderman; - break; - } - - case biMushroomIsland: - case biMushroomShore: - { - // Mushroom land gets only mooshrooms - MobType = cMonster::mtMooshroom; - break; - } - - default: - { - // Overworld biomes depend on whether it's night or day: - if (m_TimeOfDay >= 12000 + 1000) - { - // Night mobs: - switch (nightRand) - { - case 0: MobType = cMonster::mtSpider; break; - case 1: MobType = cMonster::mtZombie; break; - case 2: MobType = cMonster::mtEnderman; break; - case 3: MobType = cMonster::mtCreeper; break; - case 4: MobType = cMonster::mtCaveSpider; break; - case 7: MobType = cMonster::mtSlime; break; - case 8: MobType = cMonster::mtSilverfish; break; - case 9: MobType = cMonster::mtSkeleton; break; - } - } // if (night) - else - { - // During the day: - switch (dayRand) + if (m_bAnimals) { - case 0: MobType = cMonster::mtChicken; break; - case 1: MobType = cMonster::mtCow; break; - case 2: MobType = cMonster::mtPig; break; - case 3: MobType = cMonster::mtSheep; break; - case 4: MobType = cMonster::mtSquid; break; - case 5: MobType = cMonster::mtWolf; break; + cMobSpawner Spawner(*itr,m_AllowedMobs); + if (Spawner.CanSpawnSomething()) + { + m_ChunkMap->SpawnMobs(Spawner); + // do the spawn + + for(cMobSpawner::tSpawnedContainer::const_iterator itr2 = Spawner.getSpawned().begin(); itr2 != Spawner.getSpawned().end(); itr2++) + { + SpawnMobFinalize(*itr2); + } + } } - } // else (night) - } // case overworld biomes - } // switch (biome) - - if (MobType >= 0) - { - // A proper mob type was selected, now spawn the mob: - SpawnMob(SpawnPos.x, SpawnPos.y, SpawnPos.z, (cMonster::eType)MobType); + } + } + } + + // move close mobs + cMobProximityCounter::sIterablePair allCloseEnoughToMoveMobs = MobCensus.getProximityCounter().getMobWithinThosesDistances(-1,64*16);// MG TODO : deal with this magic number (the 16 is the size of a block) + for(cMobProximityCounter::tDistanceToMonster::const_iterator itr = allCloseEnoughToMoveMobs.m_Begin; itr != allCloseEnoughToMoveMobs.m_End; itr++) + { + itr->second.m_Monster.Tick(a_Dt,itr->second.m_Chunk); + } + + // remove too far mobs + cMobProximityCounter::sIterablePair allTooFarMobs = MobCensus.getProximityCounter().getMobWithinThosesDistances(128*16,-1);// MG TODO : deal with this magic number (the 16 is the size of a block) + for(cMobProximityCounter::tDistanceToMonster::const_iterator itr = allTooFarMobs.m_Begin; itr != allTooFarMobs.m_End; itr++) + { + itr->second.m_Monster.Destroy(true); } -*/ } @@ -2578,55 +2534,32 @@ int cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eTyp { cMonster * Monster = NULL; - int Size = GetTickRandomNumber(2) + 1; // 1 .. 3 - - switch (a_MonsterType) - { - case cMonster::mtBat: Monster = new cBat(); break; - case cMonster::mtBlaze: Monster = new cBlaze(); break; - case cMonster::mtCaveSpider: Monster = new cCavespider(); break; - case cMonster::mtChicken: Monster = new cChicken(); break; - case cMonster::mtCow: Monster = new cCow(); break; - case cMonster::mtCreeper: Monster = new cCreeper(); break; - case cMonster::mtEnderman: Monster = new cEnderman(); break; - case cMonster::mtGhast: Monster = new cGhast(); break; - case cMonster::mtMagmaCube: Monster = new cMagmacube(Size); break; - case cMonster::mtMooshroom: Monster = new cMooshroom(); break; - case cMonster::mtOcelot: Monster = new cOcelot(); break; - case cMonster::mtPig: Monster = new cPig(); break; - case cMonster::mtSheep: Monster = new cSheep(); break; - case cMonster::mtSilverfish: Monster = new cSilverfish(); break; - case cMonster::mtSkeleton: Monster = new cSkeleton(); break; - case cMonster::mtSlime: Monster = new cSlime(Size); break; - case cMonster::mtSpider: Monster = new cSpider(); break; - case cMonster::mtSquid: Monster = new cSquid(); break; - case cMonster::mtVillager: Monster = new cVillager(); break; - case cMonster::mtWitch: Monster = new cWitch(); break; - case cMonster::mtWolf: Monster = new cWolf(); break; - case cMonster::mtZombie: Monster = new cZombie(); break; - case cMonster::mtZombiePigman: Monster = new cZombiepigman(); break; - - default: - { - LOGWARNING("%s: Unhandled monster type: %d. Not spawning.", __FUNCTION__, a_MonsterType); - return -1; - } - } + cMobTypesManager::NewMonsterFromType(a_MonsterType); Monster->SetPosition(a_PosX, a_PosY, a_PosZ); - Monster->SetHealth(Monster->GetMaxHealth()); - if (cPluginManager::Get()->CallHookSpawningMonster(*this, *Monster)) + + return SpawnMobFinalize(Monster); +} + + + + +int cWorld::SpawnMobFinalize(cMonster* a_Monster) +{ + a_Monster->SetHealth(a_Monster->GetMaxHealth()); + if (cPluginManager::Get()->CallHookSpawningMonster(*this, *a_Monster)) { - delete Monster; + delete a_Monster; return -1; } - if (!Monster->Initialize(this)) + if (!a_Monster->Initialize(this)) { - delete Monster; + delete a_Monster; return -1; } - BroadcastSpawnEntity(*Monster); - cPluginManager::Get()->CallHookSpawnedMonster(*this, *Monster); - return Monster->GetUniqueID(); + BroadcastSpawnEntity(*a_Monster); + cPluginManager::Get()->CallHookSpawnedMonster(*this, *a_Monster); + + return a_Monster->GetUniqueID(); } diff --git a/source/World.h b/source/World.h index eb19dce4..4590fb9c 100644 --- a/source/World.h +++ b/source/World.h @@ -574,6 +574,7 @@ public: /// Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType); // tolua_export + int SpawnMobFinalize(cMonster* a_Monster); /// Creates a projectile of the specified type. Returns the projectile's EntityID if successful, <0 otherwise int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const Vector3d * a_Speed = NULL); // tolua_export @@ -626,7 +627,7 @@ private: Int64 m_LastTimeUpdate; // The tick in which the last time update has been sent. Int64 m_LastUnload; // The last WorldAge (in ticks) in which unloading was triggerred Int64 m_LastSave; // The last WorldAge (in ticks) in which save-all was triggerred - Int64 m_LastSpawnMonster; // The last WorldAge (in ticks) in which a monster was spawned + std::map m_LastSpawnMonster; // The last WorldAge (in ticks) in which a monster was spawned (for each megatype of monster) // MG TODO : find a way to optimize without creating unmaintenability (if mob IDs are becoming unrowed) eGameMode m_GameMode; bool m_bEnabledPVP; @@ -656,7 +657,7 @@ private: cChunkMap * m_ChunkMap; bool m_bAnimals; - Int64 m_SpawnMonsterRate; + std::set m_AllowedMobs; eWeather m_Weather; int m_WeatherInterval; From d67e8dcca5dda496480f3e983a0cf72c1d047bf7 Mon Sep 17 00:00:00 2001 From: mgueydan Date: Sun, 8 Sep 2013 03:30:09 +0200 Subject: [PATCH 10/22] Adding mobtype filter inside world.ini --- source/MobSpawner.cpp | 3 ++- source/World.cpp | 21 +++++++++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/source/MobSpawner.cpp b/source/MobSpawner.cpp index 19e3739c..38234ae6 100644 --- a/source/MobSpawner.cpp +++ b/source/MobSpawner.cpp @@ -6,6 +6,7 @@ #include "Mobs/Monster.h" #include "Mobs/IncludeAllMonsters.h" +#include cMobSpawner::tMobTypes& cMobSpawner::m_MobTypes() { @@ -178,7 +179,7 @@ bool cMobSpawner::CanSpawnHere(cMonster::eType a_MobType, BLOCKTYPE a_BlockType, { if (a_MobType == cMonster::mtChicken || a_MobType == cMonster::mtPig || a_MobType == cMonster::mtCow || a_MobType == cMonster::mtSheep) { - LOGD("Trying to spawn an animal"); + LOGD(oss.str().c_str()); toReturn = ( a_BlockType_below == E_BLOCK_GRASS /*&& // MG TODO a_LightLevel >= 9 */ diff --git a/source/World.cpp b/source/World.cpp index 2e8f3084..9ca432f5 100644 --- a/source/World.cpp +++ b/source/World.cpp @@ -491,14 +491,19 @@ void cWorld::Start(void) m_GameMode = (eGameMode)IniFile.GetValueSetI("GameMode", "GameMode", m_GameMode); - m_bAnimals = true; - - m_AllowedMobs.insert(cMonster::mtCow); // MG TODO : temporary - m_AllowedMobs.insert(cMonster::mtZombie); - m_AllowedMobs.insert(cMonster::mtZombiePigman); - m_AllowedMobs.insert(cMonster::mtBat); - m_AllowedMobs.insert(cMonster::mtSpider); - m_AllowedMobs.insert(cMonster::mtGhast); + m_bAnimals = IniFile.GetValueB("Monsters", "AnimalsOn", true); + AString sAllMonsters = IniFile.GetValue("Monsters", "Types"); + AStringVector SplitList = StringSplit(sAllMonsters, ","); + for (unsigned int i = 0; i < SplitList.size(); ++i) + { + cMonster::eType ToAdd = cMobTypesManager::fromStringToMobType(SplitList[i]); + if (ToAdd != cMonster::mtInvalidType) + { + m_AllowedMobs.insert(ToAdd); + LOGD("Allowed mob: %s",cMobTypesManager::fromMobTypeToString(ToAdd).c_str()); // a bit reverse working, but very few ressources wasted + } + }; + m_ChunkMap = new cChunkMap(this); From 1d987d4e902b03b823d83a55ff49e8ee777f5ed1 Mon Sep 17 00:00:00 2001 From: mgueydan Date: Sun, 8 Sep 2013 03:31:24 +0200 Subject: [PATCH 11/22] incrementing .gitignore : adding emacs stuff and world --- .gitignore | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.gitignore b/.gitignore index 7706ecc0..b0ad11d5 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,23 @@ cloc.xsl *.suo /EveryNight.cmd *.sublime-* + +# emacs stuff +*.*~ + +# world inside source +ChunkWorx.ini +groups.ini +items.ini +monsters.ini +settings.ini +terrain.ini +users.ini +webadmin.ini +world.ini +crafting.txt +motd.txt +logs +players +world +world_nether From 668b6edaa7390f87b0b7e7e28ddb49c9d3f66d2a Mon Sep 17 00:00:00 2001 From: mgueydan Date: Sun, 8 Sep 2013 11:48:48 +0200 Subject: [PATCH 12/22] renaming the cChunk::getRandomBlock method + removing a buggy working log --- source/Chunk.cpp | 4 ++-- source/Chunk.h | 2 +- source/MobSpawner.cpp | 3 --- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/source/Chunk.cpp b/source/Chunk.cpp index 8c4c7725..a77f1060 100644 --- a/source/Chunk.cpp +++ b/source/Chunk.cpp @@ -485,7 +485,7 @@ void cChunk::getThreeRandomNumber(int& a_X, int& a_Y, int& a_Z,int a_MaxX, int a -void cChunk::getRandomBlock(int& a_X, int& a_Y, int& a_Z) +void cChunk::getRandomBlockCoords(int& a_X, int& a_Y, int& a_Z) { // MG TODO : check if this kind of optimization (only one random call) is still needed // MG TODO : if so propagate it @@ -501,7 +501,7 @@ void cChunk::getRandomBlock(int& a_X, int& a_Y, int& a_Z) void cChunk::SpawnMobs(cMobSpawner& a_MobSpawner) { int Center_X,Center_Y,Center_Z; - getRandomBlock(Center_X,Center_Y,Center_Z); + getRandomBlockCoords(Center_X,Center_Y,Center_Z); BLOCKTYPE PackCenterBlock = GetBlock(Center_X, Center_Y, Center_Z); if (a_MobSpawner.CheckPackCenter(PackCenterBlock)) diff --git a/source/Chunk.h b/source/Chunk.h index 69ecbfec..aca180d1 100644 --- a/source/Chunk.h +++ b/source/Chunk.h @@ -394,7 +394,7 @@ private: // pick up a random block of this chunk - void getRandomBlock(int& a_X, int& a_Y, int& a_Z); + void getRandomBlockCoords(int& a_X, int& a_Y, int& a_Z); void getThreeRandomNumber(int& a_X, int& a_Y, int& a_Z,int a_MaxX, int a_MaxY, int a_MaxZ); void RemoveBlockEntity(cBlockEntity * a_BlockEntity); diff --git a/source/MobSpawner.cpp b/source/MobSpawner.cpp index 38234ae6..9bff8753 100644 --- a/source/MobSpawner.cpp +++ b/source/MobSpawner.cpp @@ -6,8 +6,6 @@ #include "Mobs/Monster.h" #include "Mobs/IncludeAllMonsters.h" -#include - cMobSpawner::tMobTypes& cMobSpawner::m_MobTypes() { static tMobTypes* value = new tMobTypes(initMobTypesBeforeCx11()); @@ -179,7 +177,6 @@ bool cMobSpawner::CanSpawnHere(cMonster::eType a_MobType, BLOCKTYPE a_BlockType, { if (a_MobType == cMonster::mtChicken || a_MobType == cMonster::mtPig || a_MobType == cMonster::mtCow || a_MobType == cMonster::mtSheep) { - LOGD(oss.str().c_str()); toReturn = ( a_BlockType_below == E_BLOCK_GRASS /*&& // MG TODO a_LightLevel >= 9 */ From e6e85168bc1462f66011096fb28f9899b9743d6b Mon Sep 17 00:00:00 2001 From: mgueydan Date: Sun, 8 Sep 2013 12:04:20 +0200 Subject: [PATCH 13/22] removing an assert + correcting a distance calculation bug --- source/MobProximityCounter.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/source/MobProximityCounter.cpp b/source/MobProximityCounter.cpp index 59979fa1..e0b7f34c 100644 --- a/source/MobProximityCounter.cpp +++ b/source/MobProximityCounter.cpp @@ -14,12 +14,18 @@ void cMobProximityCounter::CollectMob(cEntity& a_Monster, cChunk& a_Chunk, doubl { sDistanceAndChunk newDistanceAndChunck(a_Distance,a_Chunk); std::pair result = m_MonsterToDistance.insert(tMonsterToDistance::value_type(&a_Monster,newDistanceAndChunck)); - assert(result.second); + if (!result.second) + { + ASSERT("A collected Monster was not found inside distance map using find(), but insert() said there already is a key for it"); + } } else { - it->second.m_Distance = a_Distance; - it->second.m_Chunk = a_Chunk; + if (a_Distance < it->second.m_Distance) + { + it->second.m_Distance = a_Distance; + it->second.m_Chunk = a_Chunk; + } } m_EligibleForSpawnChunks.insert(&a_Chunk); From 5846be9400d26d198ddc3884a8e02c405748c6ad Mon Sep 17 00:00:00 2001 From: mgueydan Date: Sun, 8 Sep 2013 12:20:19 +0200 Subject: [PATCH 14/22] replacing asserts by ASSERTs --- source/Chunk.cpp | 6 +++--- source/MobProximityCounter.cpp | 2 +- source/MobTypesManager.cpp | 8 ++++++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/source/Chunk.cpp b/source/Chunk.cpp index a77f1060..01cb13c4 100644 --- a/source/Chunk.cpp +++ b/source/Chunk.cpp @@ -471,7 +471,7 @@ void cChunk::CollectMobCensus(cMobCensus& toFill) void cChunk::getThreeRandomNumber(int& a_X, int& a_Y, int& a_Z,int a_MaxX, int a_MaxY, int a_MaxZ) { - assert(a_MaxX * a_MaxY * a_MaxZ * 8 < 0x00ffffff); + ASSERT(a_MaxX * a_MaxY * a_MaxZ * 8 < 0x00ffffff); int Random = m_World->GetTickRandomNumber(0x00ffffff); a_X = Random % (a_MaxX * 2); a_Y = (Random / (a_MaxX * 2)) % (a_MaxY * 2); @@ -523,8 +523,8 @@ void cChunk::SpawnMobs(cMobSpawner& a_MobSpawner) Try_Y += Center_Y; Try_Z += Center_Z; - assert(Try_Y > 0); - assert(Try_Y < cChunkDef::Height-1); + ASSERT(Try_Y > 0); + ASSERT(Try_Y < cChunkDef::Height-1); BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; diff --git a/source/MobProximityCounter.cpp b/source/MobProximityCounter.cpp index e0b7f34c..3c5ec915 100644 --- a/source/MobProximityCounter.cpp +++ b/source/MobProximityCounter.cpp @@ -16,7 +16,7 @@ void cMobProximityCounter::CollectMob(cEntity& a_Monster, cChunk& a_Chunk, doubl std::pair result = m_MonsterToDistance.insert(tMonsterToDistance::value_type(&a_Monster,newDistanceAndChunck)); if (!result.second) { - ASSERT("A collected Monster was not found inside distance map using find(), but insert() said there already is a key for it"); + ASSERT(!"A collected Monster was not found inside distance map using find(), but insert() said there already is a key for it"); } } else diff --git a/source/MobTypesManager.cpp b/source/MobTypesManager.cpp index 0c13e5ae..2d24bd39 100644 --- a/source/MobTypesManager.cpp +++ b/source/MobTypesManager.cpp @@ -102,7 +102,11 @@ cMonster* cMobTypesManager::NewMonsterFromType(cMonster::eType a_MobType, int a_ { a_Size = m_Random().NextInt(2,a_MobType)+1; } - assert(a_Size > 0 && a_Size < 4); + if (a_Size <= 0 || a_Size >= 4) + { + ASSERT(!"Random for size was supposed to pick in [1..3] and picked outside"); + a_Size = 1; + } break; default : break; } @@ -135,7 +139,7 @@ cMonster* cMobTypesManager::NewMonsterFromType(cMonster::eType a_MobType, int a_ case cMonster::mtZombiePigman: toReturn = new cZombiepigman(); break; default: { - assert(false); + ASSERT(!"Unhandled Mob type"); } } return toReturn; From b4bb2553445d44dc8ca03bb33d801cf620f71898 Mon Sep 17 00:00:00 2001 From: mgueydan Date: Sun, 8 Sep 2013 12:25:07 +0200 Subject: [PATCH 15/22] Replacing chunCk by chunk --- source/Chunk.cpp | 2 +- source/MobCensus.cpp | 4 ++-- source/MobCensus.h | 8 ++++---- source/MobProximityCounter.cpp | 4 ++-- source/MobProximityCounter.h | 6 +++--- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/source/Chunk.cpp b/source/Chunk.cpp index 01cb13c4..0d6ce335 100644 --- a/source/Chunk.cpp +++ b/source/Chunk.cpp @@ -434,7 +434,7 @@ void cChunk::Stay(bool a_Stay) void cChunk::CollectMobCensus(cMobCensus& toFill) { - toFill.CollectSpawnableChunck(*this); + toFill.CollectSpawnableChunk(*this); std::list playerPositions; cPlayer* currentPlayer; for (cClientHandleList::iterator itr = m_LoadedByClient.begin(), end = m_LoadedByClient.end(); itr != end; ++itr) diff --git a/source/MobCensus.cpp b/source/MobCensus.cpp index 4984c53c..612f2591 100644 --- a/source/MobCensus.cpp +++ b/source/MobCensus.cpp @@ -50,7 +50,7 @@ void cMobCensus::CollectMob(cMonster& a_Monster, cChunk& a_Chunk, double a_Dista 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 + const int ratio = 319; // this should be 256 as we are only supposed to take account from chunks 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); @@ -64,7 +64,7 @@ bool cMobCensus::isCaped(cMonster::eFamily a_MobFamily) return toReturn; } -void cMobCensus::CollectSpawnableChunck(cChunk& a_Chunk) +void cMobCensus::CollectSpawnableChunk(cChunk& a_Chunk) { m_EligibleForSpawnChunks.insert(&a_Chunk); } diff --git a/source/MobCensus.h b/source/MobCensus.h index 32e60832..8aa8f3a6 100644 --- a/source/MobCensus.h +++ b/source/MobCensus.h @@ -11,7 +11,7 @@ class cMonster; // 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 : it also collect the chunks 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 { @@ -27,7 +27,7 @@ protected : std::set m_EligibleForSpawnChunks; - // count the chunks that are elligible to spawn (for now, the loaded valide not null chuncks) + // count the chunks that are elligible to spawn (for now, the loaded valide not null chunks) int getChunkNb(); public: @@ -39,8 +39,8 @@ public: 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); + // MG TODO : code the correct rule (not loaded chunk but short distant from players) + void CollectSpawnableChunk(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); diff --git a/source/MobProximityCounter.cpp b/source/MobProximityCounter.cpp index 3c5ec915..583a7157 100644 --- a/source/MobProximityCounter.cpp +++ b/source/MobProximityCounter.cpp @@ -12,8 +12,8 @@ void cMobProximityCounter::CollectMob(cEntity& a_Monster, cChunk& a_Chunk, doubl tMonsterToDistance::iterator it = m_MonsterToDistance.find(&a_Monster); if (it == m_MonsterToDistance.end()) { - sDistanceAndChunk newDistanceAndChunck(a_Distance,a_Chunk); - std::pair result = m_MonsterToDistance.insert(tMonsterToDistance::value_type(&a_Monster,newDistanceAndChunck)); + sDistanceAndChunk newDistanceAndChunk(a_Distance,a_Chunk); + std::pair result = m_MonsterToDistance.insert(tMonsterToDistance::value_type(&a_Monster,newDistanceAndChunk)); if (!result.second) { ASSERT(!"A collected Monster was not found inside distance map using find(), but insert() said there already is a key for it"); diff --git a/source/MobProximityCounter.h b/source/MobProximityCounter.h index d033f1b7..8a67139a 100644 --- a/source/MobProximityCounter.h +++ b/source/MobProximityCounter.h @@ -38,7 +38,7 @@ protected : // 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. + // this are the collected chunks. Used to determinate the number of elligible chunk for spawning. std::set m_EligibleForSpawnChunks; protected : @@ -47,9 +47,9 @@ protected : void convertMaps(); public : - // count a mob on a specified chunck with specified distance to an unkown player + // count a mob on a specified chunk 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) + // distance and the chunk 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 From ead953898d06faa75c6f5cffae6dd284c19db83a Mon Sep 17 00:00:00 2001 From: mgueydan Date: Sun, 8 Sep 2013 12:37:14 +0200 Subject: [PATCH 16/22] replacing C-style cast by dynamic_cast --- source/Chunk.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/Chunk.cpp b/source/Chunk.cpp index 0d6ce335..00010e80 100644 --- a/source/Chunk.cpp +++ b/source/Chunk.cpp @@ -451,7 +451,7 @@ void cChunk::CollectMobCensus(cMobCensus& toFill) { try { - cMonster& Monster = (cMonster&)(**itr); + cMonster& Monster = dynamic_cast(**itr); currentPosition = Monster.GetPosition(); for (std::list::const_iterator itr2 = playerPositions.begin(); itr2 != playerPositions.end(); itr2 ++) { From 59f46353091ef3a453193ea3d74dd712bb0acf38 Mon Sep 17 00:00:00 2001 From: mgueydan Date: Mon, 9 Sep 2013 18:45:39 +0200 Subject: [PATCH 17/22] replacing dynamic_cast by c-style cast --- source/Chunk.cpp | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/source/Chunk.cpp b/source/Chunk.cpp index 00010e80..21401163 100644 --- a/source/Chunk.cpp +++ b/source/Chunk.cpp @@ -449,18 +449,11 @@ void cChunk::CollectMobCensus(cMobCensus& toFill) //LOGD("Counting entity #%i (%s)", (*itr)->GetUniqueID(), (*itr)->GetClass()); if ((*itr)->IsMob()) { - try - { - cMonster& Monster = dynamic_cast(**itr); - currentPosition = Monster.GetPosition(); - for (std::list::const_iterator itr2 = playerPositions.begin(); itr2 != playerPositions.end(); itr2 ++) - { - toFill.CollectMob(Monster,*this,(currentPosition-**itr2).SqrLength()); - } - } - catch (std::bad_cast& e) + cMonster& Monster = (cMonster&)(**itr); + currentPosition = Monster.GetPosition(); + for (std::list::const_iterator itr2 = playerPositions.begin(); itr2 != playerPositions.end(); itr2 ++) { - LOGD("Something wrong happend I'm collecting an entity that respond 'true' to IsMob() but are not castable in cMonster - No Action"); + toFill.CollectMob(Monster,*this,(currentPosition-**itr2).SqrLength()); } } } // for itr - m_Entitites[] From bf4781d0ee04625bebac2239a336caaea41f51a3 Mon Sep 17 00:00:00 2001 From: mgueydan Date: Tue, 10 Sep 2013 14:26:27 +0200 Subject: [PATCH 18/22] Changing Bat to AMbiant creature --- source/Mobs/Bat.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/Mobs/Bat.cpp b/source/Mobs/Bat.cpp index ec7ce7bc..ff86f413 100644 --- a/source/Mobs/Bat.cpp +++ b/source/Mobs/Bat.cpp @@ -15,5 +15,5 @@ cBat::cBat(void) : cMonster::eFamily cBat::GetMobFamily() const { - return mfWater; + return mfAmbient; } From f12ac6b995f46acf76e61e7f83273ebfc18c090f Mon Sep 17 00:00:00 2001 From: mgueydan Date: Tue, 10 Sep 2013 15:09:45 +0200 Subject: [PATCH 19/22] Inside cMonster::getMobFamily() : replacing Polymorphism by Map, in order to remove redundancy --- source/MobTypesManager.h | 2 +- source/Mobs/AggressiveMonster.cpp | 9 --------- source/Mobs/AggressiveMonster.h | 1 - source/Mobs/Bat.cpp | 4 ---- source/Mobs/Bat.h | 1 - source/Mobs/Monster.cpp | 6 ++++++ source/Mobs/Monster.h | 3 ++- source/Mobs/PassiveMonster.cpp | 6 ------ source/Mobs/PassiveMonster.h | 1 - source/Mobs/Squid.cpp | 4 ---- source/Mobs/Squid.h | 1 - 11 files changed, 9 insertions(+), 29 deletions(-) diff --git a/source/MobTypesManager.h b/source/MobTypesManager.h index a1b2dfdd..941dac72 100644 --- a/source/MobTypesManager.h +++ b/source/MobTypesManager.h @@ -23,7 +23,7 @@ protected : static tMobTypes2Names& m_MobsTypes2Names(); static tMobTypes2Names MobTypes2NamesInitializerBeforeCx11(); - typedef const std::map tMobType2Family; //MG TODO : this is redundancy with cMonster::getFamily() methods. But almost all the management of MobType is redundancy in this project. Maybe is it optimization, or just historical TODO : understand and do something about it. + typedef const std::map tMobType2Family; static tMobType2Family& m_MobsType2Family(); static tMobType2Family MobType2FamilyInitializerBeforeCx11(); diff --git a/source/Mobs/AggressiveMonster.cpp b/source/Mobs/AggressiveMonster.cpp index d4852337..93dba6d7 100644 --- a/source/Mobs/AggressiveMonster.cpp +++ b/source/Mobs/AggressiveMonster.cpp @@ -95,12 +95,3 @@ void cAggressiveMonster::Tick(float a_Dt, cChunk & a_Chunk) } -cMonster::eFamily cAggressiveMonster::GetMobFamily() const -{ - return mfHostile; -} - - - - - diff --git a/source/Mobs/AggressiveMonster.h b/source/Mobs/AggressiveMonster.h index c1641954..f22ed5b8 100644 --- a/source/Mobs/AggressiveMonster.h +++ b/source/Mobs/AggressiveMonster.h @@ -20,7 +20,6 @@ public: virtual void EventSeePlayer(cEntity *) override; - virtual eFamily GetMobFamily(void) const override; protected: float m_ChaseTime; diff --git a/source/Mobs/Bat.cpp b/source/Mobs/Bat.cpp index ff86f413..715f2548 100644 --- a/source/Mobs/Bat.cpp +++ b/source/Mobs/Bat.cpp @@ -13,7 +13,3 @@ cBat::cBat(void) : } -cMonster::eFamily cBat::GetMobFamily() const -{ - return mfAmbient; -} diff --git a/source/Mobs/Bat.h b/source/Mobs/Bat.h index e0afb574..fd3e00a0 100644 --- a/source/Mobs/Bat.h +++ b/source/Mobs/Bat.h @@ -17,7 +17,6 @@ public: CLASS_PROTODEF(cBat); - virtual eFamily GetMobFamily(void) const override; } ; diff --git a/source/Mobs/Monster.cpp b/source/Mobs/Monster.cpp index a42ae30e..b378b2bc 100644 --- a/source/Mobs/Monster.cpp +++ b/source/Mobs/Monster.cpp @@ -9,6 +9,7 @@ #include "../Entities/Player.h" #include "../Defines.h" #include "../MonsterConfig.h" +#include "../MobTypesManager.h" #include "../MersenneTwister.h" #include "../Vector3f.h" @@ -17,6 +18,7 @@ #include "../Tracer.h" #include "../Chunk.h" + // #include "../../iniFile/iniFile.h" @@ -510,3 +512,7 @@ void cMonster::HandleDaylightBurning(cChunk & a_Chunk) +cMonster::eFamily cMonster::GetMobFamily(void) const +{ + return cMobTypesManager::getFamilyFromType(GetMobTypeAsEnum()); +} diff --git a/source/Mobs/Monster.h b/source/Mobs/Monster.h index ef7904e8..e08fd518 100644 --- a/source/Mobs/Monster.h +++ b/source/Mobs/Monster.h @@ -94,7 +94,8 @@ public: char GetMobType(void) const {return m_MobType; } // MG TODO : see if we can delete this one. eType GetMobTypeAsEnum(void) const {return (eType)m_MobType; } // MG TODO : see if we should store m_MobType as enum instead of char. - virtual eFamily GetMobFamily(void) const = 0; + eFamily GetMobFamily(void) const; + const char * GetState(); void SetState(const AString & str); diff --git a/source/Mobs/PassiveMonster.cpp b/source/Mobs/PassiveMonster.cpp index 3d7b8c8a..8c69c805 100644 --- a/source/Mobs/PassiveMonster.cpp +++ b/source/Mobs/PassiveMonster.cpp @@ -55,11 +55,5 @@ void cPassiveMonster::Tick(float a_Dt, cChunk & a_Chunk) -cMonster::eFamily cPassiveMonster::GetMobFamily() const -{ - return mfPassive; -} - - diff --git a/source/Mobs/PassiveMonster.h b/source/Mobs/PassiveMonster.h index 9d355772..908bb0ce 100644 --- a/source/Mobs/PassiveMonster.h +++ b/source/Mobs/PassiveMonster.h @@ -20,7 +20,6 @@ public: /// When hit by someone, run away virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override; - virtual eFamily GetMobFamily(void) const override; } ; diff --git a/source/Mobs/Squid.cpp b/source/Mobs/Squid.cpp index 50265aea..e6a44079 100644 --- a/source/Mobs/Squid.cpp +++ b/source/Mobs/Squid.cpp @@ -54,7 +54,3 @@ void cSquid::Tick(float a_Dt, cChunk & a_Chunk) -cMonster::eFamily cSquid::GetMobFamily() const -{ - return mfWater; -} diff --git a/source/Mobs/Squid.h b/source/Mobs/Squid.h index d5f3a74d..ad299b95 100644 --- a/source/Mobs/Squid.h +++ b/source/Mobs/Squid.h @@ -21,7 +21,6 @@ public: virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; - virtual eFamily GetMobFamily(void) const override; } ; From 369b4abff8ac9836536feff26e7e62bacec8bd97 Mon Sep 17 00:00:00 2001 From: Samuel Barney Date: Mon, 14 Oct 2013 08:12:23 -0600 Subject: [PATCH 20/22] Mobs no longer spawn up in the air. --- source/World.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/World.cpp b/source/World.cpp index 67b2738f..2b8fe54c 100644 --- a/source/World.cpp +++ b/source/World.cpp @@ -2632,6 +2632,8 @@ int cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eTyp return -1; } } + while(this->GetBlock(a_PosX, a_PosY - 1, a_PosZ) == E_BLOCK_AIR) + --a_PosY; Monster->SetPosition(a_PosX, a_PosY, a_PosZ); Monster->SetHealth(Monster->GetMaxHealth()); if (cPluginManager::Get()->CallHookSpawningMonster(*this, *Monster)) From 210cd4eb50bd9470611e772dfb1ae20997996710 Mon Sep 17 00:00:00 2001 From: Samuel Barney Date: Mon, 14 Oct 2013 11:12:12 -0600 Subject: [PATCH 21/22] General fixes to get the new Monster spawning code working. Also wrote in some code to use the default settings for monsters located in settings.ini --- source/World.cpp | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/source/World.cpp b/source/World.cpp index 7a9bf46a..3a4469c9 100644 --- a/source/World.cpp +++ b/source/World.cpp @@ -444,6 +444,12 @@ void cWorld::Start(void) m_SpawnY = cChunkDef::Height; m_SpawnZ = (double)((m_TickRand.randInt() % 1000) - 500); m_GameMode = eGameMode_Creative; + static AString SettingsName = "settings.ini"; + cIniFile Settings(SettingsName); + if (!Settings.ReadFile()) + { + LOGWARNING("Cannot read world settings from \"%s\", defaults will be used.", SettingsName.c_str()); + } cIniFile IniFile(m_IniFileName); if (!IniFile.ReadFile()) @@ -489,8 +495,11 @@ void cWorld::Start(void) m_GameMode = (eGameMode)IniFile.GetValueSetI("GameMode", "GameMode", m_GameMode); - m_bAnimals = IniFile.GetValueB("Monsters", "AnimalsOn", true); + m_bAnimals = Settings.GetValueB("Monsters", "AnimalsOn", true); + m_bAnimals = IniFile.GetValueB("Monsters", "AnimalsOn", m_bAnimals); AString sAllMonsters = IniFile.GetValue("Monsters", "Types"); + if (!sAllMonsters.size()) + sAllMonsters = Settings.GetValue("Monsters", "Types"); AStringVector SplitList = StringSplit(sAllMonsters, ","); for (unsigned int i = 0; i < SplitList.size(); ++i) { @@ -728,7 +737,6 @@ void cWorld::TickMobs(float a_Dt) // before every Mob action, we have to "counts" them depending on the distance to players, on their megatype ... cMobCensus MobCensus; m_ChunkMap->CollectMobCensus(MobCensus); - for(cMobFamilyCollecter::tMobFamilyList::const_iterator itr = cMobFamilyCollecter::m_AllFamilies().begin(); itr != cMobFamilyCollecter::m_AllFamilies().end(); itr++) { cMobCensus::tMobSpawnRate::const_iterator spawnrate = cMobCensus::m_SpawnRate().find(*itr); @@ -741,6 +749,7 @@ void cWorld::TickMobs(float a_Dt) { if (m_bAnimals) { + cMobSpawner Spawner(*itr,m_AllowedMobs); if (Spawner.CanSpawnSomething()) { @@ -2511,11 +2520,11 @@ int cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eTyp int SlSize = GetTickRandomNumber(2) + 1; // 1 .. 3 - Slime int ShColor = GetTickRandomNumber(15); // 0 .. 15 - Sheep - bool SkType = GetDimension() == biNether; // Skeleton - - cMobTypesManager::NewMonsterFromType(a_MonsterType); - Monster->SetPosition(a_PosX, a_PosY, a_PosZ); + bool SkType = GetDimension() == dimNether ; // Skeleton + Monster = cMobTypesManager::NewMonsterFromType(a_MonsterType); + if (Monster) + Monster->SetPosition(a_PosX, a_PosY, a_PosZ); return SpawnMobFinalize(Monster); } @@ -2524,6 +2533,8 @@ int cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eTyp int cWorld::SpawnMobFinalize(cMonster* a_Monster) { + if (!a_Monster) + return -1; a_Monster->SetHealth(a_Monster->GetMaxHealth()); if (cPluginManager::Get()->CallHookSpawningMonster(*this, *a_Monster)) { From 02baff662964303f080113e21c1e50d759ee9988 Mon Sep 17 00:00:00 2001 From: Samuel Barney Date: Mon, 14 Oct 2013 15:32:40 -0600 Subject: [PATCH 22/22] Removed reading default values from settings.ini for worlds. --- source/World.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/source/World.cpp b/source/World.cpp index 3a4469c9..967cd8f5 100644 --- a/source/World.cpp +++ b/source/World.cpp @@ -444,12 +444,6 @@ void cWorld::Start(void) m_SpawnY = cChunkDef::Height; m_SpawnZ = (double)((m_TickRand.randInt() % 1000) - 500); m_GameMode = eGameMode_Creative; - static AString SettingsName = "settings.ini"; - cIniFile Settings(SettingsName); - if (!Settings.ReadFile()) - { - LOGWARNING("Cannot read world settings from \"%s\", defaults will be used.", SettingsName.c_str()); - } cIniFile IniFile(m_IniFileName); if (!IniFile.ReadFile()) @@ -495,11 +489,8 @@ void cWorld::Start(void) m_GameMode = (eGameMode)IniFile.GetValueSetI("GameMode", "GameMode", m_GameMode); - m_bAnimals = Settings.GetValueB("Monsters", "AnimalsOn", true); - m_bAnimals = IniFile.GetValueB("Monsters", "AnimalsOn", m_bAnimals); + m_bAnimals = IniFile.GetValueB("Monsters", "AnimalsOn", true); AString sAllMonsters = IniFile.GetValue("Monsters", "Types"); - if (!sAllMonsters.size()) - sAllMonsters = Settings.GetValue("Monsters", "Types"); AStringVector SplitList = StringSplit(sAllMonsters, ","); for (unsigned int i = 0; i < SplitList.size(); ++i) {