From a49c004278b0e300521e9cedf44a46ac843a958b Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Sat, 13 Apr 2013 21:02:10 +0000 Subject: Rewritten entities so that they are owned by individual chunks and ticked within their chunk's Tick() git-svn-id: http://mc-server.googlecode.com/svn/trunk@1385 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/Bindings.cpp | 35 +---- source/Bindings.h | 2 +- source/ChestEntity.cpp | 4 +- source/Chunk.cpp | 142 +++++++++++++++--- source/Chunk.h | 17 ++- source/ChunkMap.cpp | 280 +++++++++++++++++++++++++++-------- source/ChunkMap.h | 64 +++++--- source/ChunkSender.cpp | 18 +-- source/ChunkSender.h | 4 +- source/ClientHandle.cpp | 30 ++-- source/ClientHandle.h | 4 +- source/Entity.cpp | 140 ++++-------------- source/Entity.h | 36 ++--- source/FallingBlock.cpp | 44 +++--- source/FallingBlock.h | 2 +- source/Generating/ChunkGenerator.cpp | 8 +- source/LightingThread.cpp | 2 +- source/Minecart.cpp | 2 +- source/Minecart.h | 2 +- source/Mobs/AggressiveMonster.cpp | 18 +-- source/Mobs/AggressiveMonster.h | 6 +- source/Mobs/Cavespider.cpp | 6 +- source/Mobs/Cavespider.h | 2 +- source/Mobs/Enderman.cpp | 15 -- source/Mobs/Enderman.h | 1 - source/Mobs/Monster.cpp | 51 +++---- source/Mobs/Monster.h | 16 +- source/Mobs/PassiveMonster.cpp | 8 +- source/Mobs/PassiveMonster.h | 2 +- source/Mobs/Skeleton.cpp | 6 +- source/Mobs/Skeleton.h | 2 +- source/Mobs/Squid.cpp | 7 +- source/Mobs/Squid.h | 2 +- source/Mobs/Zombie.cpp | 6 +- source/Mobs/Zombie.h | 2 +- source/Mobs/Zombiepigman.cpp | 6 +- source/Mobs/Zombiepigman.h | 2 +- source/Pawn.cpp | 10 +- source/Pawn.h | 6 +- source/Pickup.cpp | 9 +- source/Pickup.h | 4 +- source/Player.cpp | 15 +- source/Player.h | 4 +- source/Simulator/FireSimulator.h | 4 +- source/World.cpp | 157 +++++++------------- source/World.h | 44 +++--- source/WorldStorage/WSSAnvil.cpp | 8 +- source/WorldStorage/WSSCompact.cpp | 4 +- source/WorldStorage/WorldStorage.cpp | 12 +- 49 files changed, 690 insertions(+), 581 deletions(-) diff --git a/source/Bindings.cpp b/source/Bindings.cpp index f459f57e2..be95a05b3 100644 --- a/source/Bindings.cpp +++ b/source/Bindings.cpp @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 04/11/13 11:57:58. +** Generated automatically by tolua++-1.0.92 on 04/13/13 22:59:55. */ #ifndef __cplusplus @@ -4717,38 +4717,6 @@ static int tolua_AllToLua_cEntity_GetChunkX00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE -/* method: GetChunkY of class cEntity */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cEntity_GetChunkY00 -static int tolua_AllToLua_cEntity_GetChunkY00(lua_State* tolua_S) -{ -#ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if ( - !tolua_isusertype(tolua_S,1,"const cEntity",0,&tolua_err) || - !tolua_isnoobj(tolua_S,2,&tolua_err) - ) - goto tolua_lerror; - else -#endif - { - const cEntity* self = (const cEntity*) tolua_tousertype(tolua_S,1,0); -#ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetChunkY'", NULL); -#endif - { - int tolua_ret = (int) self->GetChunkY(); - tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); - } - } - return 1; -#ifndef TOLUA_RELEASE - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'GetChunkY'.",&tolua_err); - return 0; -#endif -} -#endif //#ifndef TOLUA_DISABLE - /* method: GetChunkZ of class cEntity */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cEntity_GetChunkZ00 static int tolua_AllToLua_cEntity_GetChunkZ00(lua_State* tolua_S) @@ -24470,7 +24438,6 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"GetSpeedY",tolua_AllToLua_cEntity_GetSpeedY00); tolua_function(tolua_S,"GetSpeedZ",tolua_AllToLua_cEntity_GetSpeedZ00); tolua_function(tolua_S,"GetChunkX",tolua_AllToLua_cEntity_GetChunkX00); - tolua_function(tolua_S,"GetChunkY",tolua_AllToLua_cEntity_GetChunkY00); tolua_function(tolua_S,"GetChunkZ",tolua_AllToLua_cEntity_GetChunkZ00); tolua_function(tolua_S,"SetHeadYaw",tolua_AllToLua_cEntity_SetHeadYaw00); tolua_function(tolua_S,"SetPosX",tolua_AllToLua_cEntity_SetPosX00); diff --git a/source/Bindings.h b/source/Bindings.h index b12285553..76098c6e4 100644 --- a/source/Bindings.h +++ b/source/Bindings.h @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 04/11/13 11:57:59. +** Generated automatically by tolua++-1.0.92 on 04/13/13 22:59:55. */ /* Exported function */ diff --git a/source/ChestEntity.cpp b/source/ChestEntity.cpp index dbd7f6ef2..e0f818de0 100644 --- a/source/ChestEntity.cpp +++ b/source/ChestEntity.cpp @@ -144,9 +144,9 @@ void cChestEntity::UsedBy(cPlayer * a_Player) // Instead of marking the chunk as dirty upon chest contents change, we mark it dirty now // We cannot properly detect contents change, but such a change doesn't happen without a player opening the chest first. // The few false positives aren't much to worry about - int ChunkX, ChunkY = 0, ChunkZ; + int ChunkX, ChunkZ; cChunkDef::BlockToChunk(m_PosX, m_PosY, m_PosZ, ChunkX, ChunkZ); - m_World->MarkChunkDirty(ChunkX, ChunkY, ChunkZ); + m_World->MarkChunkDirty(ChunkX, ChunkZ); } diff --git a/source/Chunk.cpp b/source/Chunk.cpp index 4feb45dc8..802cb358c 100644 --- a/source/Chunk.cpp +++ b/source/Chunk.cpp @@ -118,19 +118,15 @@ cChunk::~cChunk() // Remove and destroy all entities that are not players: cEntityList Entities; - for (cEntityList::const_iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr) + std::swap(Entities, m_Entities); // Need another list because cEntity destructors check if they've been removed from chunk + for (cEntityList::const_iterator itr = Entities.begin(); itr != Entities.end(); ++itr) { if (!(*itr)->IsPlayer()) { - Entities.push_back(*itr); + (*itr)->Destroy(); + delete *itr; } } - for (cEntityList::iterator itr = Entities.begin(); itr != Entities.end(); ++itr) - { - (*itr)->RemoveFromChunk(); - (*itr)->Destroy(); - } - m_Entities.clear(); if (m_NeighborXM != NULL) { @@ -267,7 +263,6 @@ void cChunk::SetAllData( const NIBBLETYPE * a_BlockSkyLight, const HeightMap * a_HeightMap, const BiomeMap & a_BiomeMap, - cEntityList & a_Entities, cBlockEntityList & a_BlockEntities ) { @@ -296,9 +291,6 @@ void cChunk::SetAllData( CalculateHeightmap(); } - // Append entities to current entity list: - m_Entities.insert(m_Entities.end(), a_Entities.begin(), a_Entities.end()); - // Clear the block entities present - either the loader / saver has better, or we'll create empty ones: for (cBlockEntityList::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr) { @@ -438,7 +430,7 @@ void cChunk::Stay(bool a_Stay) -void cChunk::Tick(float a_Dt, MTRand & a_TickRandom) +void cChunk::Tick(float a_Dt) { BroadcastPendingBlockChanges(); @@ -454,7 +446,7 @@ void cChunk::Tick(float a_Dt, MTRand & a_TickRandom) // Tick simulators: m_World->GetSimulatorManager()->SimulateChunk(a_Dt, m_PosX, m_PosZ, this); - TickBlocks(a_TickRandom); + TickBlocks(); // Tick all block entities in this chunk: for (cBlockEntityList::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr) @@ -462,6 +454,43 @@ void cChunk::Tick(float a_Dt, MTRand & a_TickRandom) m_IsDirty = (*itr)->Tick(a_Dt) | m_IsDirty; } + // Tick all entities in this chunk: + for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr) + { + (*itr)->Tick(a_Dt, *this); + } // for itr - m_Entitites[] + + // Remove all entities that were scheduled for removal: + for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end();) + { + if ((*itr)->IsDestroyed()) + { + LOGD("Destroying entity #%i (%s)", (*itr)->GetUniqueID(), (*itr)->GetClass()); + cEntity * ToDelete = *itr; + itr = m_Entities.erase(itr); + delete ToDelete; + continue; + } + itr++; + } // for itr - m_Entitites[] + + // If any entity moved out of the chunk, move it to the neighbor: + for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end();) + { + if ( + ((*itr)->GetChunkX() != m_PosX) || + ((*itr)->GetChunkZ() != m_PosZ) + ) + { + MoveEntityToNewChunk(*itr); + itr = m_Entities.erase(itr); + } + else + { + ++itr; + } + } + ApplyWeatherToTop(); } @@ -469,6 +498,46 @@ void cChunk::Tick(float a_Dt, MTRand & a_TickRandom) +void cChunk::MoveEntityToNewChunk(cEntity * a_Entity) +{ + cChunk * Neighbor = GetNeighborChunk((int)a_Entity->GetPosX(), (int)a_Entity->GetPosZ()); + if (Neighbor == NULL) + { + // TODO: What to do with this? + LOGWARNING("%s: Failed to move entity, destination chunk unreachable. Entity lost", __FUNCTION__); + return; + } + + Neighbor->AddEntity(a_Entity); + + class cMover : + public cClientDiffCallback + { + virtual void Removed(cClientHandle * a_Client) override + { + a_Client->SendDestroyEntity(*m_Entity); + } + + virtual void Added(cClientHandle * a_Client) override + { + m_Entity->SpawnOn(*a_Client); + } + + cEntity * m_Entity; + + public: + cMover(cEntity * a_Entity) : + m_Entity(a_Entity) + {} + } Mover(a_Entity); + + m_ChunkMap->CompareChunkClients(this, Neighbor, Mover); +} + + + + + void cChunk::BroadcastPendingBlockChanges(void) { sSetBlockVector Changes; @@ -516,13 +585,13 @@ void cChunk::CheckBlocks(void) -void cChunk::TickBlocks(MTRand & a_TickRandom) +void cChunk::TickBlocks(void) { // Tick dem blocks // _X: We must limit the random number or else we get a nasty int overflow bug ( http://forum.mc-server.org/showthread.php?tid=457 ) - int RandomX = a_TickRandom.randInt(0x00ffffff); - int RandomY = a_TickRandom.randInt(0x00ffffff); - int RandomZ = a_TickRandom.randInt(0x00ffffff); + int RandomX = m_World->GetTickRandomNumber(0x00ffffff); + int RandomY = m_World->GetTickRandomNumber(0x00ffffff); + int RandomZ = m_World->GetTickRandomNumber(0x00ffffff); int TickX = m_BlockTickX; int TickY = m_BlockTickY; int TickZ = m_BlockTickZ; @@ -1609,6 +1678,9 @@ void cChunk::AddEntity(cEntity * a_Entity) { MarkDirty(); } + + ASSERT(std::find(m_Entities.begin(), m_Entities.end(), a_Entity) == m_Entities.end()); // Not there already + m_Entities.push_back(a_Entity); } @@ -1636,6 +1708,22 @@ void cChunk::RemoveEntity(cEntity * a_Entity) +bool cChunk::HasEntity(int a_EntityID) +{ + for (cEntityList::const_iterator itr = m_Entities.begin(), end = m_Entities.end(); itr != end; ++itr) + { + if ((*itr)->GetUniqueID() == a_EntityID) + { + return true; + } + } // for itr - m_Entities[] + return false; +} + + + + + bool cChunk::ForEachEntity(cEntityCallback & a_Callback) { // The entity list is locked by the parent chunkmap's CS @@ -1654,6 +1742,24 @@ bool cChunk::ForEachEntity(cEntityCallback & a_Callback) +bool cChunk::DoWithEntityByID(int a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackResult) +{ + // The entity list is locked by the parent chunkmap's CS + for (cEntityList::iterator itr = m_Entities.begin(), end = m_Entities.end(); itr != end; ++itr) + { + if ((*itr)->GetUniqueID() == a_EntityID) + { + a_CallbackResult = a_Callback.Item(*itr); + return true; + } + } // for itr - m_Entitites[] + return false; +} + + + + + bool cChunk::ForEachChest(cChestCallback & a_Callback) { // The blockentity list is locked by the parent chunkmap's CS diff --git a/source/Chunk.h b/source/Chunk.h index a15a19466..09536f099 100644 --- a/source/Chunk.h +++ b/source/Chunk.h @@ -104,7 +104,6 @@ public: const NIBBLETYPE * a_BlockSkyLight, const cChunkDef::HeightMap * a_HeightMap, const cChunkDef::BiomeMap & a_BiomeMap, - cEntityList & a_Entities, cBlockEntityList & a_BlockEntities ); @@ -125,7 +124,7 @@ public: /// Sets or resets the internal flag that prevents chunk from being unloaded void Stay(bool a_Stay = true); - void Tick(float a_Dt, MTRand & a_TickRandom); + void Tick(float a_Dt); int GetPosX(void) const { return m_PosX; } int GetPosY(void) const { return m_PosY; } @@ -176,12 +175,16 @@ public: bool HasClient (cClientHandle* a_Client ); bool HasAnyClients(void); // Returns true if theres any client in the chunk; false otherwise - void AddEntity( cEntity * a_Entity); - void RemoveEntity( cEntity * a_Entity); + void AddEntity(cEntity * a_Entity); + void RemoveEntity(cEntity * a_Entity); + bool HasEntity(int a_EntityID); /// Calls the callback for each entity; returns true if all entities processed, false if the callback aborted by returning true bool ForEachEntity(cEntityCallback & a_Callback); // Lua-accessible + /// Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found. + bool DoWithEntityByID(int a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackResult); // Lua-accessible + /// Calls the callback for each chest; returns true if all chests processed, false if the callback aborted by returning true bool ForEachChest(cChestCallback & a_Callback); // Lua-accessible @@ -352,7 +355,8 @@ private: /// Checks the block scheduled for checking in m_ToTickBlocks[] void CheckBlocks(void); - void TickBlocks (MTRand & a_TickRandom); + /// Ticks several random blocks in the chunk + void TickBlocks(void); /// Adds snow to the top of snowy biomes and hydrates farmland / fills cauldrons in rainy biomes void ApplyWeatherToTop(void); @@ -368,6 +372,9 @@ private: /// Checks if a leaves block at the specified coords has a log up to 4 blocks away connected by other leaves blocks (false if no log) bool HasNearLog(cBlockArea & a_Area, int a_BlockX, int a_BlockY, int a_BlockZ); + + /// Called by Tick() when an entity moves out of this chunk into a neighbor; moves the entity and sends spawn / despawn packet to clients + void MoveEntityToNewChunk(cEntity * a_Entity); }; typedef cChunk * cChunkPtr; diff --git a/source/ChunkMap.cpp b/source/ChunkMap.cpp index c7a341af2..76835ee74 100644 --- a/source/ChunkMap.cpp +++ b/source/ChunkMap.cpp @@ -277,7 +277,7 @@ cChunk * cChunkMap::FindChunk(int a_ChunkX, int a_ChunkZ) void cChunkMap::BroadcastAttachEntity(const cEntity & a_Entity, const cEntity * a_Vehicle) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkY(), a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -292,7 +292,7 @@ void cChunkMap::BroadcastAttachEntity(const cEntity & a_Entity, const cEntity * void cChunkMap::BroadcastPlayerAnimation(const cPlayer & a_Player, char a_Animation, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Player.GetChunkX(), a_Player.GetChunkY(), a_Player.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Player.GetChunkX(), ZERO_CHUNK_Y, a_Player.GetChunkZ()); if (Chunk == NULL) { return; @@ -308,7 +308,7 @@ void cChunkMap::BroadcastPlayerAnimation(const cPlayer & a_Player, char a_Animat void cChunkMap::BroadcastEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkY(), a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -325,7 +325,7 @@ void cChunkMap::BroadcastEntityEquipment(const cEntity & a_Entity, short a_SlotN void cChunkMap::BroadcastEntVelocity(const cEntity & a_Entity, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkY(), a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -341,7 +341,7 @@ void cChunkMap::BroadcastEntVelocity(const cEntity & a_Entity, const cClientHand void cChunkMap::BroadcastEntRelMoveLook(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkY(), a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -358,7 +358,7 @@ void cChunkMap::BroadcastEntRelMoveLook(const cEntity & a_Entity, char a_RelX, c void cChunkMap::BroadcastEntRelMove(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkY(), a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -375,7 +375,7 @@ void cChunkMap::BroadcastEntRelMove(const cEntity & a_Entity, char a_RelX, char void cChunkMap::BroadcastEntLook(const cEntity & a_Entity, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkY(), a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -392,7 +392,7 @@ void cChunkMap::BroadcastEntLook(const cEntity & a_Entity, const cClientHandle * void cChunkMap::BroadcastEntHeadLook(const cEntity & a_Entity, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkY(), a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -431,7 +431,7 @@ void cChunkMap::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, c void cChunkMap::BroadcastDestroyEntity(const cEntity & a_Entity, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkY(), a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -448,7 +448,7 @@ void cChunkMap::BroadcastDestroyEntity(const cEntity & a_Entity, const cClientHa void cChunkMap::BroadcastEntityStatus(const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkY(), a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -465,7 +465,7 @@ void cChunkMap::BroadcastEntityStatus(const cEntity & a_Entity, char a_Status, c void cChunkMap::BroadcastMetadata(const cPawn & a_Pawn, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Pawn.GetChunkX(), a_Pawn.GetChunkY(), a_Pawn.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Pawn.GetChunkX(), ZERO_CHUNK_Y, a_Pawn.GetChunkZ()); if (Chunk == NULL) { return; @@ -481,7 +481,7 @@ void cChunkMap::BroadcastMetadata(const cPawn & a_Pawn, const cClientHandle * a_ void cChunkMap::BroadcastSpawn(cEntity & a_Entity, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkY(), a_Entity.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); if (Chunk == NULL) { return; @@ -497,7 +497,7 @@ void cChunkMap::BroadcastSpawn(cEntity & a_Entity, const cClientHandle * a_Exclu void cChunkMap::BroadcastCollectPickup(const cPickup & a_Pickup, const cPlayer & a_Player, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Pickup.GetChunkX(), a_Pickup.GetChunkY(), a_Pickup.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Pickup.GetChunkX(), ZERO_CHUNK_Y, a_Pickup.GetChunkZ()); if (Chunk == NULL) { return; @@ -689,10 +689,10 @@ void cChunkMap::WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ) -void cChunkMap::MarkChunkDirty (int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cChunkMap::MarkChunkDirty (int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return; @@ -704,10 +704,10 @@ void cChunkMap::MarkChunkDirty (int a_ChunkX, int a_ChunkY, int a_ChunkZ) -void cChunkMap::MarkChunkSaving(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cChunkMap::MarkChunkSaving(int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return; @@ -719,10 +719,10 @@ void cChunkMap::MarkChunkSaving(int a_ChunkX, int a_ChunkY, int a_ChunkZ) -void cChunkMap::MarkChunkSaved (int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cChunkMap::MarkChunkSaved (int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return; @@ -735,25 +735,24 @@ void cChunkMap::MarkChunkSaved (int a_ChunkX, int a_ChunkY, int a_ChunkZ) void cChunkMap::SetChunkData( - int a_ChunkX, int a_ChunkY, int a_ChunkZ, + int a_ChunkX, int a_ChunkZ, const BLOCKTYPE * a_BlockTypes, const NIBBLETYPE * a_BlockMeta, const NIBBLETYPE * a_BlockLight, const NIBBLETYPE * a_BlockSkyLight, const cChunkDef::HeightMap * a_HeightMap, const cChunkDef::BiomeMap & a_BiomeMap, - cEntityList & a_Entities, cBlockEntityList & a_BlockEntities, bool a_MarkDirty ) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkY, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); if (Chunk == NULL) { return; } - Chunk->SetAllData(a_BlockTypes, a_BlockMeta, a_BlockLight, a_BlockSkyLight, a_HeightMap, a_BiomeMap, a_Entities, a_BlockEntities); + Chunk->SetAllData(a_BlockTypes, a_BlockMeta, a_BlockLight, a_BlockSkyLight, a_HeightMap, a_BiomeMap, a_BlockEntities); if (a_MarkDirty) { @@ -788,10 +787,10 @@ void cChunkMap::ChunkLighted( -bool cChunkMap::GetChunkData(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkDataCallback & a_Callback) +bool cChunkMap::GetChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataCallback & a_Callback) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -804,10 +803,10 @@ bool cChunkMap::GetChunkData(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkDat -bool cChunkMap::GetChunkBlockTypes(int a_ChunkX, int a_ChunkY, int a_ChunkZ, BLOCKTYPE * a_BlockTypes) +bool cChunkMap::GetChunkBlockTypes(int a_ChunkX, int a_ChunkZ, BLOCKTYPE * a_BlockTypes) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -820,10 +819,10 @@ bool cChunkMap::GetChunkBlockTypes(int a_ChunkX, int a_ChunkY, int a_ChunkZ, BLO -bool cChunkMap::IsChunkValid(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +bool cChunkMap::IsChunkValid(int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkY, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); return (Chunk != NULL) && Chunk->IsValid(); } @@ -831,10 +830,10 @@ bool cChunkMap::IsChunkValid(int a_ChunkX, int a_ChunkY, int a_ChunkZ) -bool cChunkMap::HasChunkAnyClients(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +bool cChunkMap::HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); return (Chunk != NULL) && Chunk->HasAnyClients(); } @@ -844,24 +843,45 @@ bool cChunkMap::HasChunkAnyClients(int a_ChunkX, int a_ChunkY, int a_ChunkZ) int cChunkMap::GetHeight(int a_BlockX, int a_BlockZ) { + while (true) + { + cCSLock Lock(m_CSLayers); + int ChunkX, ChunkZ, BlockY = 0; + cChunkDef::AbsoluteToRelative(a_BlockX, BlockY, a_BlockZ, ChunkX, ChunkZ); + cChunkPtr Chunk = GetChunk(ChunkX, ZERO_CHUNK_Y, ChunkZ); + if (Chunk == NULL) + { + return 0; + } + + if (Chunk->IsValid()) + { + return Chunk->GetHeight(a_BlockX, a_BlockZ); + } + + // The chunk is not valid, wait for it to become valid: + cCSUnlock Unlock(Lock); + m_evtChunkValid.Wait(); + } // while (true) +} + + + + + +bool cChunkMap::TryGetHeight(int a_BlockX, int a_BlockZ, int & a_Height) +{ + // Returns false if chunk not loaded / generated cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ, BlockY = 0; cChunkDef::AbsoluteToRelative(a_BlockX, BlockY, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunk(ChunkX, ZERO_CHUNK_Y, ChunkZ); - if (Chunk == NULL) - { - return 0; - } - - // Wait for the chunk to become valid: - while (!Chunk->IsValid()) + cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ); + if ((Chunk == NULL) || !Chunk->IsValid()) { - GetChunk(ChunkX, ZERO_CHUNK_Y, ChunkZ); // Re-queue (in case it managed to get unloaded before we caught it - cCSUnlock Unlock(Lock); - m_evtChunkValid.Wait(); + return false; } - - return Chunk->GetHeight(a_BlockX, a_BlockZ); + a_Height = Chunk->GetHeight(a_BlockX, a_BlockZ); + return true; } @@ -1239,22 +1259,31 @@ void cChunkMap::SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player) -void cChunkMap::CompareChunkClients(int a_ChunkX1, int a_ChunkY1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkY2, int a_ChunkZ2, cClientDiffCallback & a_Callback) +void cChunkMap::CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkZ2, cClientDiffCallback & a_Callback) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk1 = GetChunkNoGen(a_ChunkX1, a_ChunkY1, a_ChunkZ1); + cChunkPtr Chunk1 = GetChunkNoGen(a_ChunkX1, ZERO_CHUNK_Y, a_ChunkZ1); if (Chunk1 == NULL) { return; } - cChunkPtr Chunk2 = GetChunkNoGen(a_ChunkX2, a_ChunkY2, a_ChunkZ2); + cChunkPtr Chunk2 = GetChunkNoGen(a_ChunkX2, ZERO_CHUNK_Y, a_ChunkZ2); if (Chunk2 == NULL) { return; } + + CompareChunkClients(Chunk1, Chunk2, a_Callback); +} - cClientHandleList Clients1(Chunk1->GetAllClients()); - cClientHandleList Clients2(Chunk2->GetAllClients()); + + + + +void cChunkMap::CompareChunkClients(cChunk * a_Chunk1, cChunk * a_Chunk2, cClientDiffCallback & a_Callback) +{ + cClientHandleList Clients1(a_Chunk1->GetAllClients()); + cClientHandleList Clients2(a_Chunk2->GetAllClients()); // Find "removed" clients: for (cClientHandleList::iterator itr1 = Clients1.begin(); itr1 != Clients1.end(); ++itr1) @@ -1297,10 +1326,10 @@ void cChunkMap::CompareChunkClients(int a_ChunkX1, int a_ChunkY1, int a_ChunkZ1, -bool cChunkMap::AddChunkClient(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client) +bool cChunkMap::AddChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunk(a_ChunkX, a_ChunkY, a_ChunkZ); + cChunkPtr Chunk = GetChunk(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); if (Chunk == NULL) { return false; @@ -1312,10 +1341,10 @@ bool cChunkMap::AddChunkClient(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClient -void cChunkMap::RemoveChunkClient(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client) +void cChunkMap::RemoveChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); if (Chunk == NULL) { return; @@ -1341,15 +1370,16 @@ void cChunkMap::RemoveClientFromChunks(cClientHandle * a_Client) -void cChunkMap::MoveEntityToChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkY, int a_ChunkZ) +// TODO: This function should not be needed, remove? +void cChunkMap::MoveEntityToChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); - cChunkPtr OldChunk = GetChunkNoGen(a_Entity->GetChunkX(), a_Entity->GetChunkY(), a_Entity->GetChunkZ()); + cChunkPtr OldChunk = GetChunkNoGen(a_Entity->GetChunkX(), ZERO_CHUNK_Y, a_Entity->GetChunkZ()); if (OldChunk != NULL) { OldChunk->RemoveEntity(a_Entity); } - cChunkPtr NewChunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ); + cChunkPtr NewChunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); if (NewChunk != NULL) { NewChunk->AddEntity(a_Entity); @@ -1360,10 +1390,10 @@ void cChunkMap::MoveEntityToChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkY -void cChunkMap::RemoveEntityFromChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cChunkMap::RemoveEntityFromChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); if ((Chunk == NULL) && !Chunk->IsValid()) { return; @@ -1375,6 +1405,55 @@ void cChunkMap::RemoveEntityFromChunk(cEntity * a_Entity, int a_ChunkX, int a_Ch +void cChunkMap::AddEntity(cEntity * a_Entity) +{ + cCSLock Lock(m_CSLayers); + cChunkPtr Chunk = GetChunkNoGen(a_Entity->GetChunkX(), ZERO_CHUNK_Y, a_Entity->GetChunkZ()); + if ((Chunk == NULL) && !Chunk->IsValid()) + { + return; + } + Chunk->AddEntity(a_Entity); +} + + + + + +bool cChunkMap::HasEntity(int a_UniqueID) +{ + cCSLock Lock(m_CSLayers); + for (cChunkLayerList::const_iterator itr = m_Layers.begin(); itr != m_Layers.end(); ++itr) + { + if ((*itr)->HasEntity(a_UniqueID)) + { + return true; + } + } + return false; +} + + + + + +bool cChunkMap::ForEachEntity(cEntityCallback & a_Callback) +{ + cCSLock Lock(m_CSLayers); + for (cChunkLayerList::const_iterator itr = m_Layers.begin(); itr != m_Layers.end(); ++itr) + { + if ((*itr)->ForEachEntity(a_Callback)) + { + return false; + } + } + return true; +} + + + + + bool cChunkMap::ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback) { cCSLock Lock(m_CSLayers); @@ -1390,6 +1469,24 @@ bool cChunkMap::ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback +bool cChunkMap::DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback) +{ + cCSLock Lock(m_CSLayers); + bool res = false; + for (cChunkLayerList::const_iterator itr = m_Layers.begin(); itr != m_Layers.end(); ++itr) + { + if ((*itr)->DoWithEntityByID(a_UniqueID, a_Callback, res)) + { + return res; + } + } + return false; +} + + + + + bool cChunkMap::ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback) { cCSLock Lock(m_CSLayers); @@ -1794,12 +1891,12 @@ void cChunkMap::SetNextBlockTick(int a_BlockX, int a_BlockY, int a_BlockZ) -void cChunkMap::Tick( float a_Dt, MTRand & a_TickRandom ) +void cChunkMap::Tick(float a_Dt) { cCSLock Lock(m_CSLayers); for (cChunkLayerList::iterator itr = m_Layers.begin(); itr != m_Layers.end(); ++itr) { - (*itr)->Tick(a_Dt, a_TickRandom); + (*itr)->Tick(a_Dt); } // for itr - m_Layers } @@ -1951,14 +2048,14 @@ cChunk * cChunkMap::cChunkLayer::FindChunk(int a_ChunkX, int a_ChunkZ) -void cChunkMap::cChunkLayer::Tick(float a_Dt, MTRand & a_TickRand) +void cChunkMap::cChunkLayer::Tick(float a_Dt) { for (int i = 0; i < ARRAYCOUNT(m_Chunks); i++) { // Only tick chunks that are valid and have clients: if ((m_Chunks[i] != NULL) && m_Chunks[i]->IsValid() && m_Chunks[i]->HasAnyClients()) { - m_Chunks[i]->Tick(a_Dt, a_TickRand); + m_Chunks[i]->Tick(a_Dt); } } // for i - m_Chunks[] } @@ -1982,6 +2079,65 @@ void cChunkMap::cChunkLayer::RemoveClient(cClientHandle * a_Client) +bool cChunkMap::cChunkLayer::ForEachEntity(cEntityCallback & a_Callback) +{ + // Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true + for (int i = 0; i < ARRAYCOUNT(m_Chunks); i++) + { + if ((m_Chunks[i] != NULL) && m_Chunks[i]->IsValid()) + { + if (!m_Chunks[i]->ForEachEntity(a_Callback)) + { + return false; + } + } + } + return true; +} + + + + + +bool cChunkMap::cChunkLayer::DoWithEntityByID(int a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackReturn) +{ + // Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found. + for (int i = 0; i < ARRAYCOUNT(m_Chunks); i++) + { + if ((m_Chunks[i] != NULL) && m_Chunks[i]->IsValid()) + { + if (m_Chunks[i]->DoWithEntityByID(a_EntityID, a_Callback, a_CallbackReturn)) + { + return true; + } + } + } + return false; +} + + + + + +bool cChunkMap::cChunkLayer::HasEntity(int a_EntityID) +{ + for (int i = 0; i < ARRAYCOUNT(m_Chunks); i++) + { + if ((m_Chunks[i] != NULL) && m_Chunks[i]->IsValid()) + { + if (m_Chunks[i]->HasEntity(a_EntityID)) + { + return true; + } + } + } + return false; +} + + + + + int cChunkMap::cChunkLayer::GetNumChunksLoaded(void) const { int NumChunks = 0; diff --git a/source/ChunkMap.h b/source/ChunkMap.h index 809c735a9..d52b2f263 100644 --- a/source/ChunkMap.h +++ b/source/ChunkMap.h @@ -105,9 +105,9 @@ public: /// Wakes up simulators for the specified block void WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ); - void MarkChunkDirty (int a_ChunkX, int a_ChunkY, int a_ChunkZ); - void MarkChunkSaving (int a_ChunkX, int a_ChunkY, int a_ChunkZ); - void MarkChunkSaved (int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void MarkChunkDirty (int a_ChunkX, int a_ChunkZ); + void MarkChunkSaving (int a_ChunkX, int a_ChunkZ); + void MarkChunkSaved (int a_ChunkX, int a_ChunkZ); /** Sets the chunk data as either loaded from the storage or generated. a_BlockLight and a_BlockSkyLight are optional, if not present, chunk will be marked as unlighted. @@ -116,14 +116,13 @@ public: If a_MarkDirty is set, the chunk is set as dirty (used after generating) */ void SetChunkData( - int a_ChunkX, int a_ChunkY, int a_ChunkZ, + int a_ChunkX, int a_ChunkZ, const BLOCKTYPE * a_BlockTypes, const NIBBLETYPE * a_BlockMeta, const NIBBLETYPE * a_BlockLight, const NIBBLETYPE * a_BlockSkyLight, const cChunkDef::HeightMap * a_HeightMap, const cChunkDef::BiomeMap & a_BiomeMap, - cEntityList & a_Entities, cBlockEntityList & a_BlockEntities, bool a_MarkDirty ); @@ -134,14 +133,15 @@ public: const cChunkDef::BlockNibbles & a_SkyLight ); - bool GetChunkData (int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkDataCallback & a_Callback); + bool GetChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataCallback & a_Callback); /// Copies the chunk's blocktypes into a_Blocks; returns true if successful - bool GetChunkBlockTypes (int a_ChunkX, int a_ChunkY, int a_ChunkZ, BLOCKTYPE * a_Blocks); + bool GetChunkBlockTypes (int a_ChunkX, int a_ChunkZ, BLOCKTYPE * a_Blocks); - bool IsChunkValid (int a_ChunkX, int a_ChunkY, int a_ChunkZ); - bool HasChunkAnyClients (int a_ChunkX, int a_ChunkY, int a_ChunkZ); - int GetHeight (int a_BlockX, int a_BlockZ); + bool IsChunkValid (int a_ChunkX, int a_ChunkZ); + bool HasChunkAnyClients (int a_ChunkX, int a_ChunkZ); + int GetHeight (int a_BlockX, int a_BlockZ); // Waits for the chunk to get loaded / generated + bool TryGetHeight (int a_BlockX, int a_BlockZ, int & a_Height); // Returns false if chunk not loaded / generated void FastSetBlocks (sSetBlockList & a_BlockList); void CollectPickupsByPlayer(cPlayer * a_Player); @@ -169,25 +169,40 @@ public: void SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player); /// Compares clients of two chunks, calls the callback accordingly - void CompareChunkClients(int a_ChunkX1, int a_ChunkY1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkY2, int a_ChunkZ2, cClientDiffCallback & a_Callback); + void CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkZ2, cClientDiffCallback & a_Callback); + /// Compares clients of two chunks, calls the callback accordingly + void CompareChunkClients(cChunk * a_Chunk1, cChunk * a_Chunk2, cClientDiffCallback & a_Callback); + /// Adds client to a chunk, if not already present; returns true if added, false if present - bool AddChunkClient(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client); + bool AddChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client); /// Removes the client from the chunk - void RemoveChunkClient(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client); + void RemoveChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client); /// Removes the client from all chunks it is present in void RemoveClientFromChunks(cClientHandle * a_Client); /// Moves the entity from its current chunk to the new chunk specified - void MoveEntityToChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void MoveEntityToChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkZ); /// Removes the entity from the chunk specified - void RemoveEntityFromChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void RemoveEntityFromChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkZ); + + /// Adds the entity to its appropriate chunk, takes ownership of the entity pointer + void AddEntity(cEntity * a_Entity); + /// Returns true if the entity with specified ID is present in the chunks + bool HasEntity(int a_EntityID); + + /// Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true + bool ForEachEntity(cEntityCallback & a_Callback); // Lua-accessible + /// Calls the callback for each entity in the specified chunk; returns true if all entities processed, false if the callback aborted by returning true bool ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback); // Lua-accessible + + /// Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found and callback returned false. + bool DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback); // Lua-accessible /// Calls the callback for each chest in the specified chunk; returns true if all chests processed, false if the callback aborted by returning true bool ForEachChestInChunk (int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback); // Lua-accessible @@ -253,12 +268,12 @@ 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); - void Tick( float a_Dt, MTRand & a_TickRand ); + void Tick(float a_Dt); - void UnloadUnusedChunks(); - void SaveAllChunks(); + void UnloadUnusedChunks(void); + void SaveAllChunks(void); - cWorld * GetWorld() { return m_World; } + cWorld * GetWorld(void) { return m_World; } int GetNumChunks(void); @@ -293,10 +308,19 @@ private: void Save(void); void UnloadUnusedChunks(void); - void Tick( float a_Dt, MTRand & a_TickRand ); + void Tick(float a_Dt); void RemoveClient(cClientHandle * a_Client); + /// Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true + bool ForEachEntity(cEntityCallback & a_Callback); // Lua-accessible + + /// Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found. + bool DoWithEntityByID(int a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackReturn); // Lua-accessible + + /// Returns true if there is an entity with the specified ID within this layer's chunks + bool HasEntity(int a_EntityID); + protected: cChunkPtr m_Chunks[LAYER_SIZE * LAYER_SIZE]; diff --git a/source/ChunkSender.cpp b/source/ChunkSender.cpp index b49561371..6282a605c 100644 --- a/source/ChunkSender.cpp +++ b/source/ChunkSender.cpp @@ -22,7 +22,7 @@ void cNotifyChunkSender::Call(int a_ChunkX, int a_ChunkZ) { - m_ChunkSender->ChunkReady(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + m_ChunkSender->ChunkReady(a_ChunkX, a_ChunkZ); } @@ -76,12 +76,12 @@ void cChunkSender::Stop(void) -void cChunkSender::ChunkReady(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cChunkSender::ChunkReady(int a_ChunkX, int a_ChunkZ) { // This is probably never gonna be called twice for the same chunk, and if it is, we don't mind, so we don't check { cCSLock Lock(m_CS); - m_ChunksReady.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ)); + m_ChunksReady.push_back(cChunkCoords(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ)); } m_evtQueue.Set(); } @@ -90,17 +90,17 @@ void cChunkSender::ChunkReady(int a_ChunkX, int a_ChunkY, int a_ChunkZ) -void cChunkSender::QueueSendChunkTo(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client) +void cChunkSender::QueueSendChunkTo(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client) { ASSERT(a_Client != NULL); { cCSLock Lock(m_CS); - if (std::find(m_SendChunks.begin(), m_SendChunks.end(), sSendChunk(a_ChunkX, a_ChunkY, a_ChunkZ, a_Client)) != m_SendChunks.end()) + if (std::find(m_SendChunks.begin(), m_SendChunks.end(), sSendChunk(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ, a_Client)) != m_SendChunks.end()) { // Already queued, bail out return; } - m_SendChunks.push_back(sSendChunk(a_ChunkX, a_ChunkY, a_ChunkZ, a_Client)); + m_SendChunks.push_back(sSendChunk(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ, a_Client)); } m_evtQueue.Set(); } @@ -200,13 +200,13 @@ void cChunkSender::SendChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHa } // If the chunk has no clients, no need to packetize it: - if (!m_World->HasChunkAnyClients(a_ChunkX, a_ChunkY, a_ChunkZ)) + if (!m_World->HasChunkAnyClients(a_ChunkX, a_ChunkZ)) { return; } // If the chunk is not valid, do nothing - whoever needs it has queued it for loading / generating - if (!m_World->IsChunkValid(a_ChunkX, a_ChunkY, a_ChunkZ)) + if (!m_World->IsChunkValid(a_ChunkX, a_ChunkZ)) { return; } @@ -219,7 +219,7 @@ void cChunkSender::SendChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHa } // Query and prepare chunk data: - if( !m_World->GetChunkData(a_ChunkX, a_ChunkY, a_ChunkZ, *this) ) + if (!m_World->GetChunkData(a_ChunkX, a_ChunkZ, *this)) { return; } diff --git a/source/ChunkSender.h b/source/ChunkSender.h index e5f2f7556..a26f764a7 100644 --- a/source/ChunkSender.h +++ b/source/ChunkSender.h @@ -80,10 +80,10 @@ public: void Stop(void); /// Notifies that a chunk has become ready and it should be sent to all its clients - void ChunkReady(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void ChunkReady(int a_ChunkX, int a_ChunkZ); /// Queues a chunk to be sent to a specific client - void QueueSendChunkTo(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client); + void QueueSendChunkTo(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client); /// Removes the a_Client from all waiting chunk send operations void RemoveClient(cClientHandle * a_Client); diff --git a/source/ClientHandle.cpp b/source/ClientHandle.cpp index c1b696630..497639649 100644 --- a/source/ClientHandle.cpp +++ b/source/ClientHandle.cpp @@ -137,7 +137,10 @@ cClientHandle::~cClientHandle() if (World != NULL) { World->RemovePlayer(m_Player); + m_Player->Destroy(); } + delete m_Player; + m_Player = NULL; } if (!m_HasSentDC) @@ -145,12 +148,6 @@ cClientHandle::~cClientHandle() SendDisconnect("Server shut down? Kthnxbai"); } - if (m_Player != NULL) - { - m_Player->Destroy(); - m_Player = NULL; - } - // Queue all remaining outgoing packets to cSocketThreads: { cCSLock Lock(m_CSOutgoingData); @@ -325,7 +322,7 @@ void cClientHandle::StreamChunks(void) } for (cChunkCoordsList::iterator itr = RemoveChunks.begin(); itr != RemoveChunks.end(); ++itr) { - World->RemoveChunkClient(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ, this); + World->RemoveChunkClient(itr->m_ChunkX, itr->m_ChunkZ, this); m_Protocol->SendUnloadChunk(itr->m_ChunkX, itr->m_ChunkZ); } // for itr - RemoveChunks[] @@ -336,13 +333,13 @@ void cClientHandle::StreamChunks(void) // For each distance add chunks in a hollow square centered around current position: for (int i = -d; i <= d; ++i) { - StreamChunk(ChunkPosX + d, ZERO_CHUNK_Y, ChunkPosZ + i); - StreamChunk(ChunkPosX - d, ZERO_CHUNK_Y, ChunkPosZ + i); + StreamChunk(ChunkPosX + d, ChunkPosZ + i); + StreamChunk(ChunkPosX - d, ChunkPosZ + i); } // for i for (int i = -d + 1; i < d; ++i) { - StreamChunk(ChunkPosX + i, ZERO_CHUNK_Y, ChunkPosZ + d); - StreamChunk(ChunkPosX + i, ZERO_CHUNK_Y, ChunkPosZ - d); + StreamChunk(ChunkPosX + i, ChunkPosZ + d); + StreamChunk(ChunkPosX + i, ChunkPosZ - d); } // for i } // for d @@ -366,7 +363,7 @@ void cClientHandle::StreamChunks(void) -void cClientHandle::StreamChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cClientHandle::StreamChunk(int a_ChunkX, int a_ChunkZ) { if (m_State >= csDestroying) { @@ -377,14 +374,14 @@ void cClientHandle::StreamChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) cWorld * World = m_Player->GetWorld(); ASSERT(World != NULL); - if (World->AddChunkClient(a_ChunkX, a_ChunkY, a_ChunkZ, this)) + if (World->AddChunkClient(a_ChunkX, a_ChunkZ, this)) { { cCSLock Lock(m_CSChunkLists); - m_LoadedChunks.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ)); - m_ChunksToSend.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ)); + m_LoadedChunks.push_back(cChunkCoords(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ)); + m_ChunksToSend.push_back(cChunkCoords(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ)); } - World->SendChunkTo(a_ChunkX, a_ChunkY, a_ChunkZ, this); + World->SendChunkTo(a_ChunkX, a_ChunkZ, this); } } @@ -1128,6 +1125,7 @@ void cClientHandle::HandleDisconnect(const AString & a_Reason) Printf(DisconnectMessage, "%s disconnected: %s", m_Username.c_str(), a_Reason.c_str()); m_Player->GetWorld()->BroadcastChat(DisconnectMessage, this); } + m_HasSentDC = true; Destroy(); } diff --git a/source/ClientHandle.h b/source/ClientHandle.h index 362e2b352..a43b0ca9b 100644 --- a/source/ClientHandle.h +++ b/source/ClientHandle.h @@ -209,7 +209,7 @@ private: cPlayer * m_Player; - bool m_HasSentDC; + bool m_HasSentDC; ///< True if a D/C packet has been sent in either direction // Chunk position when the last StreamChunks() was called; used to avoid re-streaming while in the same chunk int m_LastStreamedChunkX; @@ -267,7 +267,7 @@ private: void SendConfirmPosition(void); /// Adds a single chunk to be streamed to the client; used by StreamChunks() - void StreamChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void StreamChunk(int a_ChunkX, int a_ChunkZ); /// Handles the DIG_STARTED dig packet: void HandleBlockDigStarted (int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_OldBlock, NIBBLETYPE a_OldMeta); diff --git a/source/Entity.cpp b/source/Entity.cpp index d2404373b..59d07e33f 100644 --- a/source/Entity.cpp +++ b/source/Entity.cpp @@ -27,16 +27,13 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z) , m_Attachee(NULL) , m_Referencers(new cReferenceManager(cReferenceManager::RFMNGR_REFERENCERS)) , m_References(new cReferenceManager(cReferenceManager::RFMNGR_REFERENCES)) - , m_ChunkX(0) - , m_ChunkY(0) - , m_ChunkZ(0) , m_HeadYaw( 0.0 ) , m_Pos(a_X, a_Y, a_Z) , m_bDirtyHead(true) , m_bDirtyOrientation(true) , m_bDirtyPosition(true) , m_bDirtySpeed(true) - , m_bDestroyed(true) + , m_IsInitialized(false) , m_LastPosX( 0.0 ) , m_LastPosY( 0.0 ) , m_LastPosZ( 0.0 ) @@ -45,7 +42,6 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z) , m_TimeLastSpeedPacket(0) , m_EntityType(a_EntityType) , m_World(NULL) - , m_bRemovedFromChunk(true) , m_FireDamageInterval(0.f) , m_BurnPeriod(0.f) { @@ -60,6 +56,8 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z) cEntity::~cEntity() { + ASSERT(!m_World->HasEntity(m_UniqueID)); // Before deleting, the entity needs to have been removed from the world + LOGD("Deleting entity %d at pos {%.2f, %.2f, %.2f} ~ [%d, %d]; ptr %p", m_UniqueID, m_Pos.x, m_Pos.y, m_Pos.z, @@ -76,9 +74,9 @@ cEntity::~cEntity() m_Attachee->Detach(); } - if (!m_bDestroyed || !m_bRemovedFromChunk) + if (m_IsInitialized) { - LOGERROR("ERROR: Entity deallocated without being destroyed %i or unlinked %i", m_bDestroyed, m_bRemovedFromChunk); + LOGWARNING("ERROR: Entity deallocated without being destroyed"); ASSERT(!"Entity deallocated without being destroyed or unlinked"); } delete m_Referencers; @@ -118,41 +116,43 @@ const char * cEntity::GetParentClass(void) const void cEntity::Initialize(cWorld * a_World) { - m_bDestroyed = false; - m_bRemovedFromChunk = false; - + LOGD("Initializing entity #%d (%s) at {%.02f, %.02f, %.02f}", + m_UniqueID, GetClass(), m_Pos.x, m_Pos.y, m_Pos.z + ); + m_IsInitialized = true; m_World = a_World; m_World->AddEntity(this); - - MoveToCorrectChunk(true); } -void cEntity::WrapHeadYaw() +void cEntity::WrapHeadYaw(void) { - while (m_HeadYaw > 180.f) m_HeadYaw -=360.f; // Wrap it - while (m_HeadYaw < -180.f) m_HeadYaw +=360.f; + while (m_HeadYaw > 180.f) m_HeadYaw -= 360.f; // Wrap it + while (m_HeadYaw < -180.f) m_HeadYaw += 360.f; } -void cEntity::WrapRotation() +void cEntity::WrapRotation(void) { - while (m_Rot.x > 180.f) m_Rot.x-=360.f; // Wrap it - while (m_Rot.x < -180.f) m_Rot.x+=360.f; - while (m_Rot.y > 180.f) m_Rot.y-=360.f; - while (m_Rot.y < -180.f) m_Rot.y+=360.f; + while (m_Rot.x > 180.f) m_Rot.x -= 360.f; // Wrap it + while (m_Rot.x < -180.f) m_Rot.x += 360.f; + while (m_Rot.y > 180.f) m_Rot.y -= 360.f; + while (m_Rot.y < -180.f) m_Rot.y += 360.f; } -void cEntity::WrapSpeed() + + + +void cEntity::WrapSpeed(void) { - //There shoudn't be a need for flipping the flag on because this function is called - //after any update, so the flag is already turned on + // There shoudn't be a need for flipping the flag on because this function is called + // after any update, so the flag is already turned on if (m_Speed.x > 20.0f) m_Speed.x = 20.0f; else if (m_Speed.x < -20.0f) m_Speed.x = -20.0f; if (m_Speed.y > 20.0f) m_Speed.y = 20.0f; @@ -165,74 +165,15 @@ void cEntity::WrapSpeed() -void cEntity::MoveToCorrectChunk(bool a_bIgnoreOldChunk) -{ - if (!m_World) - { - // This is normal for entities being currently loaded - return; - } - - int ChunkX = 0, ChunkY = 0, ChunkZ = 0; - cWorld::BlockToChunk((int)m_Pos.x, (int)m_Pos.y, (int)m_Pos.z, ChunkX, ChunkY, ChunkZ); - if (!a_bIgnoreOldChunk && (m_ChunkX == ChunkX) && (m_ChunkY == ChunkY) && (m_ChunkZ == ChunkZ)) - { - return; - } - - class cMover : - public cClientDiffCallback - { - virtual void Removed(cClientHandle * a_Client) override - { - if (m_IgnoreOldChunk) - { - return; - } - a_Client->SendDestroyEntity(*m_Entity); - } - - virtual void Added(cClientHandle * a_Client) override - { - m_Entity->SpawnOn(*a_Client); - } - - bool m_IgnoreOldChunk; - cEntity * m_Entity; - - public: - cMover(cEntity * a_Entity, bool a_IgnoreOldChunk) : - m_IgnoreOldChunk(a_IgnoreOldChunk), - m_Entity(a_Entity) - {} - } Mover(this, a_bIgnoreOldChunk); - - m_World->CompareChunkClients(m_ChunkX, m_ChunkY, m_ChunkZ, ChunkX, ChunkY, ChunkZ, Mover); - m_World->MoveEntityToChunk(this, ChunkX, ChunkY, ChunkZ); - - m_ChunkX = ChunkX; - m_ChunkY = ChunkY; - m_ChunkZ = ChunkZ; -} - - - - - -void cEntity::Destroy() +void cEntity::Destroy(void) { - if (m_bDestroyed) + if (!m_IsInitialized) { return; } - if (!m_bRemovedFromChunk) - { - RemoveFromChunk(); - } - m_World->BroadcastDestroyEntity(*this); - m_bDestroyed = true; + m_IsInitialized = false; Destroyed(); } @@ -241,25 +182,8 @@ void cEntity::Destroy() -void cEntity::RemoveFromChunk(void) +void cEntity::Tick(float a_Dt, cChunk & a_Chunk) { - if (m_World == NULL) - { - return; - } - - m_World->RemoveEntityFromChunk(this, m_ChunkX, m_ChunkY, m_ChunkZ); - m_bRemovedFromChunk = true; -} - - - - - -void cEntity::Tick(float a_Dt, MTRand & a_TickRandom) -{ - UNUSED(a_TickRandom); - if (m_AttachedTo != NULL) { if ((m_Pos - m_AttachedTo->GetPosition()).Length() > 0.5) @@ -269,7 +193,7 @@ void cEntity::Tick(float a_Dt, MTRand & a_TickRandom) } else { - HandlePhysics(a_Dt); + HandlePhysics(a_Dt, a_Chunk); } } @@ -496,7 +420,6 @@ void cEntity::SetSpeedZ(double a_SpeedZ) void cEntity::AddPosX(double a_AddPosX) { m_Pos.x += a_AddPosX; - MoveToCorrectChunk(); m_bDirtyPosition = true; } @@ -506,7 +429,6 @@ void cEntity::AddPosX(double a_AddPosX) void cEntity::AddPosY(double a_AddPosY) { m_Pos.y += a_AddPosY; - MoveToCorrectChunk(); m_bDirtyPosition = true; } @@ -516,7 +438,6 @@ void cEntity::AddPosY(double a_AddPosY) void cEntity::AddPosZ(double a_AddPosZ) { m_Pos.z += a_AddPosZ; - MoveToCorrectChunk(); m_bDirtyPosition = true; } @@ -528,7 +449,6 @@ void cEntity::AddPosition(double a_AddPosX, double a_AddPosY, double a_AddPosZ) m_Pos.x += a_AddPosX; m_Pos.y += a_AddPosY; m_Pos.z += a_AddPosZ; - MoveToCorrectChunk(); m_bDirtyPosition = true; } @@ -600,7 +520,6 @@ Vector3d cEntity::GetLookVector(void) const void cEntity::SetPosition(double a_PosX, double a_PosY, double a_PosZ) { m_Pos.Set(a_PosX, a_PosY, a_PosZ); - MoveToCorrectChunk(); m_bDirtyPosition = true; } @@ -611,7 +530,6 @@ void cEntity::SetPosition(double a_PosX, double a_PosY, double a_PosZ) void cEntity::SetPosX(double a_PosX) { m_Pos.x = a_PosX; - MoveToCorrectChunk(); m_bDirtyPosition = true; } @@ -622,7 +540,6 @@ void cEntity::SetPosX(double a_PosX) void cEntity::SetPosY(double a_PosY) { m_Pos.y = a_PosY; - MoveToCorrectChunk(); m_bDirtyPosition = true; } @@ -633,7 +550,6 @@ void cEntity::SetPosY(double a_PosY) void cEntity::SetPosZ(double a_PosZ) { m_Pos.z = a_PosZ; - MoveToCorrectChunk(); m_bDirtyPosition = true; } diff --git a/source/Entity.h b/source/Entity.h index 80c399a92..3d4d1244e 100644 --- a/source/Entity.h +++ b/source/Entity.h @@ -38,7 +38,7 @@ class cWorld; class cReferenceManager; class cClientHandle; class cPlayer; -class MTRand; +class cChunk; @@ -120,9 +120,8 @@ public: double GetSpeedY (void) const { return m_Speed.y; } double GetSpeedZ (void) const { return m_Speed.z; } - int GetChunkX(void) const {return m_ChunkX; } - int GetChunkY(void) const {return m_ChunkY; } - int GetChunkZ(void) const {return m_ChunkZ; } + int GetChunkX(void) const {return FAST_FLOOR_DIV(((int)m_Pos.x), cChunkDef::Width); } + int GetChunkZ(void) const {return FAST_FLOOR_DIV(((int)m_Pos.z), cChunkDef::Width); } void SetHeadYaw (double a_HeadYaw); void SetPosX (double a_PosX); @@ -135,7 +134,7 @@ public: void SetPitch (double a_Pitch); void SetRoll (double a_Roll); void SetSpeed (double a_SpeedX, double a_SpeedY, double a_SpeedZ); - void SetSpeed (const Vector3d & a_Speed) { SetSpeed(a_Speed.x,a_Speed.y,a_Speed.z); } + void SetSpeed (const Vector3d & a_Speed) { SetSpeed(a_Speed.x, a_Speed.y, a_Speed.z); } void SetSpeedX (double a_SpeedX); void SetSpeedY (double a_SpeedY); void SetSpeedZ (double a_SpeedZ); @@ -151,16 +150,15 @@ public: void AddSpeedY (double a_AddSpeedY); void AddSpeedZ (double a_AddSpeedZ); - // tolua_end + inline int GetUniqueID(void) const { return m_UniqueID; } + inline bool IsDestroyed(void) const { return !m_IsInitialized; } - inline int GetUniqueID(void) const { return m_UniqueID; } // tolua_export - inline bool IsDestroyed(void) const { return m_bDestroyed; } // tolua_export + void Destroy(void); - void Destroy(); // tolua_export - void RemoveFromChunk(void); // for internal use in cChunk + // tolua_end - virtual void Tick(float a_Dt, MTRand & a_TickRandom); - virtual void HandlePhysics(float a_Dt) {} + virtual void Tick(float a_Dt, cChunk & a_Chunk); + virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) {} /** Descendants override this function to send a command to the specified client to spawn the entity on the client. To spawn on all eligible clients, use cChunkMap::BroadcastSpawnEntity() @@ -215,22 +213,19 @@ protected: cReferenceManager* m_Referencers; cReferenceManager* m_References; - int m_ChunkX, m_ChunkY, m_ChunkZ; - - //Flags that signal that we haven't updated the clients with the latest. + // Flags that signal that we haven't updated the clients with the latest. bool m_bDirtyHead; bool m_bDirtyOrientation; bool m_bDirtyPosition; bool m_bDirtySpeed; - //Last Position. + // Last Position. double m_LastPosX, m_LastPosY, m_LastPosZ; - //This variables keep track of the last time a packet was sent + // This variables keep track of the last time a packet was sent Int64 m_TimeLastTeleportPacket,m_TimeLastMoveReltPacket,m_TimeLastSpeedPacket; // In ticks - bool m_bDestroyed; - bool m_bRemovedFromChunk; + bool m_IsInitialized; // Is set to true when it's initialized, until it's destroyed (Initialize() till Destroy() ) eEntityType m_EntityType; @@ -242,8 +237,7 @@ protected: virtual void Destroyed(void) {} // Called after the entity has been destroyed void SetWorld(cWorld * a_World) { m_World = a_World; } - void MoveToCorrectChunk(bool a_bIgnoreOldChunk = false); - + friend class cReferenceManager; void AddReference( cEntity*& a_EntityPtr ); void ReferencedBy( cEntity*& a_EntityPtr ); diff --git a/source/FallingBlock.cpp b/source/FallingBlock.cpp index 5edae6283..db5679454 100644 --- a/source/FallingBlock.cpp +++ b/source/FallingBlock.cpp @@ -4,6 +4,7 @@ #include "World.h" #include "ClientHandle.h" #include "Simulator/SandSimulator.h" +#include "Chunk.h" @@ -40,7 +41,7 @@ void cFallingBlock::SpawnOn(cClientHandle & a_ClientHandle) -void cFallingBlock::Tick(float a_Dt, MTRand & a_TickRandom) +void cFallingBlock::Tick(float a_Dt, cChunk & a_Chunk) { float MilliDt = a_Dt * 0.001f; AddSpeedY(MilliDt * -9.8f); @@ -62,26 +63,29 @@ void cFallingBlock::Tick(float a_Dt, MTRand & a_TickRandom) return; } - if (BlockY < cChunkDef::Height - 1) + if (BlockY >= cChunkDef::Height) { - BLOCKTYPE BlockBelow; - NIBBLETYPE BelowMeta; - GetWorld()->GetBlockTypeMeta(BlockX, BlockY, BlockZ, BlockBelow, BelowMeta); - if (cSandSimulator::DoesBreakFallingThrough(BlockBelow, BelowMeta)) - { - // Fallen onto a block that breaks this into pickups (e. g. half-slab) - // Must finish the fall with coords one below the block: - cSandSimulator::FinishFalling(m_World, BlockX, BlockY, BlockZ, m_BlockType, m_BlockMeta); - Destroy(); - return; - } - else if (!cSandSimulator::CanContinueFallThrough(BlockBelow)) - { - // Fallen onto a solid block - cSandSimulator::FinishFalling(m_World, BlockX, BlockY + 1, BlockZ, m_BlockType, m_BlockMeta); - Destroy(); - return; - } + // Above the world, just wait for it to fall back down + return; + } + + int idx = a_Chunk.MakeIndexNoCheck(BlockX - a_Chunk.GetPosX() * cChunkDef::Width, BlockY, BlockZ - a_Chunk.GetPosZ() * cChunkDef::Width); + BLOCKTYPE BlockBelow = a_Chunk.GetBlock(idx); + NIBBLETYPE BelowMeta = a_Chunk.GetMeta(idx); + if (cSandSimulator::DoesBreakFallingThrough(BlockBelow, BelowMeta)) + { + // Fallen onto a block that breaks this into pickups (e. g. half-slab) + // Must finish the fall with coords one below the block: + cSandSimulator::FinishFalling(m_World, BlockX, BlockY, BlockZ, m_BlockType, m_BlockMeta); + Destroy(); + return; + } + else if (!cSandSimulator::CanContinueFallThrough(BlockBelow)) + { + // Fallen onto a solid block + cSandSimulator::FinishFalling(m_World, BlockX, BlockY + 1, BlockZ, m_BlockType, m_BlockMeta); + Destroy(); + return; } } diff --git a/source/FallingBlock.h b/source/FallingBlock.h index 37fb4c4cc..dd70eb1d1 100644 --- a/source/FallingBlock.h +++ b/source/FallingBlock.h @@ -31,7 +31,7 @@ public: // cEntity overrides: virtual void Initialize(cWorld * a_World) override; virtual void SpawnOn(cClientHandle & a_ClientHandle) override; - virtual void Tick(float a_Dt, MTRand & a_TickRandom) override; + virtual void Tick(float a_Dt, cChunk & a_Chunk) override; private: BLOCKTYPE m_BlockType; diff --git a/source/Generating/ChunkGenerator.cpp b/source/Generating/ChunkGenerator.cpp index b3c25cf46..7da7af69d 100644 --- a/source/Generating/ChunkGenerator.cpp +++ b/source/Generating/ChunkGenerator.cpp @@ -238,16 +238,16 @@ void cChunkGenerator::Execute(void) } // Hack for regenerating chunks: if Y != 0, the chunk is considered invalid, even if it has its data set - if ((coords.m_ChunkY == 0) && m_World->IsChunkValid(coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ)) + if ((coords.m_ChunkY == 0) && m_World->IsChunkValid(coords.m_ChunkX, coords.m_ChunkZ)) { LOGD("Chunk [%d, %d] already generated, skipping generation", coords.m_ChunkX, coords.m_ChunkZ); // Already generated, ignore request continue; } - if (SkipEnabled && !m_World->HasChunkAnyClients(coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ)) + if (SkipEnabled && !m_World->HasChunkAnyClients(coords.m_ChunkX, coords.m_ChunkZ)) { - LOGWARNING("Chunk generator overloaded, skipping chunk [%d, %d, %d]", coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ); + LOGWARNING("Chunk generator overloaded, skipping chunk [%d, %d]", coords.m_ChunkX, coords.m_ChunkZ); continue; } @@ -275,7 +275,7 @@ void cChunkGenerator::DoGenerate(int a_ChunkX, int a_ChunkY, int a_ChunkZ) ChunkDesc.CompressBlockMetas(BlockMetas); m_World->SetChunkData( - a_ChunkX, a_ChunkY, a_ChunkZ, + a_ChunkX, a_ChunkZ, ChunkDesc.GetBlockTypes(), BlockMetas, NULL, NULL, // We don't have lighting, chunk will be lighted when needed &ChunkDesc.GetHeightMap(), &ChunkDesc.GetBiomeMap(), diff --git a/source/LightingThread.cpp b/source/LightingThread.cpp index 5172887ba..d50cc28e2 100644 --- a/source/LightingThread.cpp +++ b/source/LightingThread.cpp @@ -338,7 +338,7 @@ bool cLightingThread::ReadChunks(int a_ChunkX, int a_ChunkZ) for (int x = 0; x < 3; x++) { Reader.m_ReadingChunkX = x; - if (!m_World->GetChunkData(a_ChunkX + x - 1, ZERO_CHUNK_Y, a_ChunkZ + z - 1, Reader)) + if (!m_World->GetChunkData(a_ChunkX + x - 1, a_ChunkZ + z - 1, Reader)) { return false; } diff --git a/source/Minecart.cpp b/source/Minecart.cpp index 359ea5402..c8d1946e5 100644 --- a/source/Minecart.cpp +++ b/source/Minecart.cpp @@ -53,7 +53,7 @@ void cMinecart::SpawnOn(cClientHandle & a_ClientHandle) -void cMinecart::Tick(float a_Dt, MTRand & a_TickRandom) +void cMinecart::Tick(float a_Dt, cChunk & a_Chunk) { // TODO: the physics } diff --git a/source/Minecart.h b/source/Minecart.h index d3ca22f4b..db61997d8 100644 --- a/source/Minecart.h +++ b/source/Minecart.h @@ -35,7 +35,7 @@ public: // cEntity overrides: virtual void Initialize(cWorld * a_World) override; virtual void SpawnOn(cClientHandle & a_ClientHandle) override; - virtual void Tick(float a_Dt, MTRand & a_TickRandom) override; + virtual void Tick(float a_Dt, cChunk & a_Chunk) override; ePayload GetPayload(void) const { return m_Payload; } diff --git a/source/Mobs/AggressiveMonster.cpp b/source/Mobs/AggressiveMonster.cpp index 0a5461837..de73e6123 100644 --- a/source/Mobs/AggressiveMonster.cpp +++ b/source/Mobs/AggressiveMonster.cpp @@ -23,9 +23,9 @@ cAggressiveMonster::cAggressiveMonster(const AString & a_ConfigName, char a_Prot // What to do if in Chasing State -void cAggressiveMonster::InStateChasing(float a_Dt, MTRand & a_TickRandom) +void cAggressiveMonster::InStateChasing(float a_Dt) { - super::InStateChasing(a_Dt, a_TickRandom); + super::InStateChasing(a_Dt); m_ChaseTime += a_Dt; if (m_Target != NULL) { @@ -58,9 +58,9 @@ void cAggressiveMonster::InStateChasing(float a_Dt, MTRand & a_TickRandom) -void cAggressiveMonster::EventSeePlayer(cEntity * a_Entity, MTRand & a_TickRandom) +void cAggressiveMonster::EventSeePlayer(cEntity * a_Entity) { - super::EventSeePlayer(a_Entity, a_TickRandom); + super::EventSeePlayer(a_Entity); m_EMState = CHASING; } @@ -68,26 +68,26 @@ void cAggressiveMonster::EventSeePlayer(cEntity * a_Entity, MTRand & a_TickRando -void cAggressiveMonster::Tick(float a_Dt, MTRand & a_TickRandom) +void cAggressiveMonster::Tick(float a_Dt, cChunk & a_Chunk) { - super::Tick(a_Dt, a_TickRandom); + super::Tick(a_Dt, a_Chunk); m_SeePlayerInterval += a_Dt; if (m_SeePlayerInterval > 1) { - int rem = a_TickRandom.randInt() % 3 + 1; // Check most of the time but miss occasionally + int rem = m_World->GetTickRandomNumber(3) + 1; // Check most of the time but miss occasionally m_SeePlayerInterval = 0.0; if (rem >= 2) { if (m_EMState == CHASING) { - CheckEventLostPlayer(a_TickRandom); + CheckEventLostPlayer(); } else { - CheckEventSeePlayer(a_TickRandom); + CheckEventSeePlayer(); } } } diff --git a/source/Mobs/AggressiveMonster.h b/source/Mobs/AggressiveMonster.h index a9303a975..ed21c6344 100644 --- a/source/Mobs/AggressiveMonster.h +++ b/source/Mobs/AggressiveMonster.h @@ -15,10 +15,10 @@ class cAggressiveMonster : public: cAggressiveMonster(const AString & a_ConfigName, char a_ProtocolMobType, const AString & a_SoundHurt, const AString & a_SoundDeath); - virtual void Tick (float a_Dt, MTRand & a_TickRandom) override; - virtual void InStateChasing(float a_Dt, MTRand & a_TickRandom) override; + virtual void Tick (float a_Dt, cChunk & a_Chunk) override; + virtual void InStateChasing(float a_Dt) override; - virtual void EventSeePlayer(cEntity *, MTRand & a_TickRandom) override; + virtual void EventSeePlayer(cEntity *) override; protected: float m_ChaseTime; diff --git a/source/Mobs/Cavespider.cpp b/source/Mobs/Cavespider.cpp index b63e28f1a..e4030af57 100644 --- a/source/Mobs/Cavespider.cpp +++ b/source/Mobs/Cavespider.cpp @@ -16,11 +16,11 @@ cCavespider::cCavespider(void) : -void cCavespider::Tick(float a_Dt, MTRand & a_TickRandom) +void cCavespider::Tick(float a_Dt, cChunk & a_Chunk) { - super::Tick(a_Dt, a_TickRandom); + super::Tick(a_Dt, a_Chunk); - // TODO: Check vanilla if cavespiders really get passive during the day + // TODO: Check vanilla if cavespiders really get passive during the day / in daylight m_EMPersonality = (GetWorld()->GetTimeOfDay() < (12000 + 1000)) ? PASSIVE : AGGRESSIVE; } diff --git a/source/Mobs/Cavespider.h b/source/Mobs/Cavespider.h index b02318a0f..00a4e16df 100644 --- a/source/Mobs/Cavespider.h +++ b/source/Mobs/Cavespider.h @@ -17,7 +17,7 @@ public: CLASS_PROTODEF(cCaveSpider); - virtual void Tick(float a_Dt, MTRand & a_TickRandom) override; + virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void GetDrops(cItems & a_Drops, cPawn * a_Killer = NULL) override; } ; diff --git a/source/Mobs/Enderman.cpp b/source/Mobs/Enderman.cpp index d7bbaa144..356815be0 100644 --- a/source/Mobs/Enderman.cpp +++ b/source/Mobs/Enderman.cpp @@ -16,21 +16,6 @@ cEnderman::cEnderman(void) : -void cEnderman::Tick(float a_Dt, MTRand & a_TickRandom) -{ - cMonster::Tick(a_Dt, a_TickRandom); - - // TODO Same as stated in cSkeleton - if ((GetWorld()->GetTimeOfDay() < (12000 + 1000)) && (GetMetaData() != BURNING)) - { - SetMetaData(BURNING); // BURN, BABY, BURN! >:D - } -} - - - - - void cEnderman::GetDrops(cItems & a_Drops, cPawn * a_Killer) { AddRandomDropItem(a_Drops, 0, 1, E_ITEM_ENDER_PEARL); diff --git a/source/Mobs/Enderman.h b/source/Mobs/Enderman.h index 0703ca25e..44719ea5a 100644 --- a/source/Mobs/Enderman.h +++ b/source/Mobs/Enderman.h @@ -17,7 +17,6 @@ public: CLASS_PROTODEF(cEnderman); - virtual void Tick(float a_Dt, MTRand & a_TickRandom) override; virtual void GetDrops(cItems & a_Drops, cPawn * a_Killer = NULL) override; } ; diff --git a/source/Mobs/Monster.cpp b/source/Mobs/Monster.cpp index 77bad8f51..8781858a6 100644 --- a/source/Mobs/Monster.cpp +++ b/source/Mobs/Monster.cpp @@ -87,9 +87,9 @@ bool cMonster::ReachedDestination() -void cMonster::Tick(float a_Dt, MTRand & a_TickRandom) +void cMonster::Tick(float a_Dt, cChunk & a_Chunk) { - super::Tick(a_Dt, a_TickRandom); + super::Tick(a_Dt, a_Chunk); if (m_Health <= 0) { @@ -145,7 +145,6 @@ void cMonster::Tick(float a_Dt, MTRand & a_TickRandom) HandlePhysics(a_Dt); BroadcastMovementUpdate(); - MoveToCorrectChunk(); Vector3d Distance = m_Destination - GetPosition(); if (Distance.SqrLength() > 0.1f) @@ -163,20 +162,20 @@ void cMonster::Tick(float a_Dt, MTRand & a_TickRandom) case IDLE: { // If enemy passive we ignore checks for player visibility - InStateIdle(a_Dt, a_TickRandom); + InStateIdle(a_Dt); break; } case CHASING: { // If we do not see a player anymore skip chasing action - InStateChasing(a_Dt, a_TickRandom); + InStateChasing(a_Dt); break; } case ESCAPING: { - InStateEscaping(a_Dt, a_TickRandom); + InStateEscaping(a_Dt); break; } } // switch (m_EMState) @@ -227,8 +226,6 @@ void cMonster::ReplicateMovement() m_LastPosZ = GetPosZ(); m_bDirtyPosition = false; } - - MoveToCorrectChunk(); } @@ -374,14 +371,14 @@ void cMonster::SetState(const AString & a_State) //Checks to see if EventSeePlayer should be fired //monster sez: Do I see the player -void cMonster::CheckEventSeePlayer(MTRand & a_TickRandom) +void cMonster::CheckEventSeePlayer(void) { // TODO: Rewrite this to use cWorld's DoWithPlayers() cPlayer * Closest = FindClosestPlayer(); if (Closest != NULL) { - EventSeePlayer(Closest, a_TickRandom); + EventSeePlayer(Closest); } } @@ -389,10 +386,8 @@ void cMonster::CheckEventSeePlayer(MTRand & a_TickRandom) -void cMonster::CheckEventLostPlayer(MTRand & a_TickRandom) +void cMonster::CheckEventLostPlayer(void) { - UNUSED(a_TickRandom); - Vector3f pos; cTracer LineOfSight(GetWorld()); @@ -416,12 +411,10 @@ void cMonster::CheckEventLostPlayer(MTRand & a_TickRandom) // What to do if player is seen // default to change state to chasing -void cMonster::EventSeePlayer(cEntity * a_SeenPlayer, MTRand & a_TickRandom) +void cMonster::EventSeePlayer(cEntity * a_SeenPlayer) { - UNUSED(a_TickRandom); - m_Target = a_SeenPlayer; - AddReference( m_Target ); + AddReference(m_Target); } @@ -431,7 +424,7 @@ void cMonster::EventSeePlayer(cEntity * a_SeenPlayer, MTRand & a_TickRandom) void cMonster::EventLosePlayer(void) { Dereference(m_Target); - m_Target = 0; + m_Target = NULL; m_EMState = IDLE; } @@ -440,24 +433,28 @@ void cMonster::EventLosePlayer(void) // What to do if in Idle State -void cMonster::InStateIdle(float a_Dt, MTRand & a_TickRandom) +void cMonster::InStateIdle(float a_Dt) { idle_interval += a_Dt; if (idle_interval > 1) { // at this interval the results are predictable - int rem = (a_TickRandom.randInt() % 6) + 1; + int rem = m_World->GetTickRandomNumber(6) + 1; // LOGD("Moving: int: %3.3f rem: %i",idle_interval,rem); idle_interval -= 1; // So nothing gets dropped when the server hangs for a few seconds Vector3f Dist; - Dist.x = (float)((a_TickRandom.randInt() % 11) - 5); - Dist.z = (float)((a_TickRandom.randInt() % 11) - 5); + Dist.x = (float)(m_World->GetTickRandomNumber(10) - 5); + Dist.z = (float)(m_World->GetTickRandomNumber(10) - 5); if ((Dist.SqrLength() > 2) && (rem >= 3)) { m_Destination.x = (float)(GetPosX() + Dist.x); m_Destination.z = (float)(GetPosZ() + Dist.z); - m_Destination.y = (float)GetWorld()->GetHeight((int)m_Destination.x, (int)m_Destination.z) + 1.2f; - MoveToPosition(m_Destination); + int PosY; + if (m_World->TryGetHeight((int)m_Destination.x, (int)m_Destination.z, PosY)) + { + m_Destination.y = (float)PosY + 1.2f; + MoveToPosition(m_Destination); + } } } } @@ -468,10 +465,9 @@ void cMonster::InStateIdle(float a_Dt, MTRand & a_TickRandom) // What to do if in Chasing State // This state should always be defined in each child class -void cMonster::InStateChasing(float a_Dt, MTRand & a_TickRandom) +void cMonster::InStateChasing(float a_Dt) { UNUSED(a_Dt); - UNUSED(a_TickRandom); } @@ -479,10 +475,9 @@ void cMonster::InStateChasing(float a_Dt, MTRand & a_TickRandom) // What to do if in Escaping State -void cMonster::InStateEscaping(float a_Dt, MTRand & a_TickRandom) +void cMonster::InStateEscaping(float a_Dt) { UNUSED(a_Dt); - UNUSED(a_TickRandom); if (m_Target != NULL) { diff --git a/source/Mobs/Monster.h b/source/Mobs/Monster.h index 5f30168f9..c7abeb243 100644 --- a/source/Mobs/Monster.h +++ b/source/Mobs/Monster.h @@ -24,6 +24,7 @@ class cMonster : typedef cPawn super; public: // tolua_end + float m_SightDistance; /** Creates the mob object. * If a_ConfigName is not empty, the configuration is loaded using GetMonsterConfig() @@ -36,7 +37,7 @@ public: virtual void SpawnOn(cClientHandle & a_ClientHandle) override; - virtual void Tick(float a_Dt, MTRand & a_TickRandom) override; + virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void HandlePhysics(float a_Dt); virtual void ReplicateMovement(void); @@ -53,20 +54,19 @@ public: const char * GetState(); void SetState(const AString & str); - virtual void CheckEventSeePlayer(MTRand & a_TickRandom); - virtual void EventSeePlayer(cEntity *, MTRand & a_TickRandom); - float m_SightDistance; + virtual void CheckEventSeePlayer(void); + virtual void EventSeePlayer(cEntity * a_Player); virtual cPlayer * FindClosestPlayer(); // non static is easier. also virtual so other mobs can implement their own searching algo /// Reads the monster configuration for the specified monster name and assigns it to this object. void GetMonsterConfig(const AString & a_Name); virtual void EventLosePlayer(void); - virtual void CheckEventLostPlayer(MTRand & a_TickRandom); + virtual void CheckEventLostPlayer(void); - virtual void InStateIdle (float a_Dt, MTRand & a_TickRandom); - virtual void InStateChasing (float a_Dt, MTRand & a_TickRandom); - virtual void InStateEscaping(float a_Dt, MTRand & a_TickRandom); + virtual void InStateIdle (float a_Dt); + virtual void InStateChasing (float a_Dt); + virtual void InStateEscaping(float a_Dt); virtual void Attack(float a_Dt); int GetMobType() {return m_MobType;} diff --git a/source/Mobs/PassiveMonster.cpp b/source/Mobs/PassiveMonster.cpp index aa2e6c118..22bc17f6f 100644 --- a/source/Mobs/PassiveMonster.cpp +++ b/source/Mobs/PassiveMonster.cpp @@ -31,22 +31,22 @@ void cPassiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI) -void cPassiveMonster::Tick(float a_Dt, MTRand & a_TickRandom) +void cPassiveMonster::Tick(float a_Dt, cChunk & a_Chunk) { - super::Tick(a_Dt, a_TickRandom); + super::Tick(a_Dt, a_Chunk); m_SeePlayerInterval += a_Dt; if (m_SeePlayerInterval > 1) // Check every second { - int rem = a_TickRandom.randInt() % 3 + 1; // Check most of the time but miss occasionally + int rem = m_World->GetTickRandomNumber(3) + 1; // Check most of the time but miss occasionally m_SeePlayerInterval = 0.0; if (rem >= 2) { if (m_EMState == ESCAPING) { - CheckEventLostPlayer(a_TickRandom); + CheckEventLostPlayer(); } } } diff --git a/source/Mobs/PassiveMonster.h b/source/Mobs/PassiveMonster.h index 66e718ec3..8abbd8687 100644 --- a/source/Mobs/PassiveMonster.h +++ b/source/Mobs/PassiveMonster.h @@ -15,7 +15,7 @@ class cPassiveMonster : public: cPassiveMonster(const AString & a_ConfigName, char a_ProtocolMobType, const AString & a_SoundHurt, const AString & a_SoundDeath); - virtual void Tick(float a_Dt, MTRand & a_TickRandom) override; + virtual void Tick(float a_Dt, cChunk & a_Chunk) override; /// When hit by someone, run away virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override; diff --git a/source/Mobs/Skeleton.cpp b/source/Mobs/Skeleton.cpp index 785584fcd..b2b0c325d 100644 --- a/source/Mobs/Skeleton.cpp +++ b/source/Mobs/Skeleton.cpp @@ -16,13 +16,13 @@ cSkeleton::cSkeleton(void) : -void cSkeleton::Tick(float a_Dt, MTRand & a_TickRandom) +void cSkeleton::Tick(float a_Dt, cChunk & a_Chunk) { - cMonster::Tick(a_Dt, a_TickRandom); + cMonster::Tick(a_Dt, a_Chunk); // TODO Outsource // TODO should do SkyLight check, mobs in the dark donīt burn - if ((GetWorld()->GetTimeOfDay() < (12000 + 1000)) && (GetMetaData() != BURNING)) + if ((GetWorld()->GetTimeOfDay() < (12000 + 1000)) && !IsBurning()) { SetMetaData(BURNING); // BURN, BABY, BURN! >:D } diff --git a/source/Mobs/Skeleton.h b/source/Mobs/Skeleton.h index a02d1b5a6..e0b537cc8 100644 --- a/source/Mobs/Skeleton.h +++ b/source/Mobs/Skeleton.h @@ -17,7 +17,7 @@ public: CLASS_PROTODEF(cSkeleton); - virtual void Tick(float a_Dt, MTRand & a_TickRandom) override; + virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void GetDrops(cItems & a_Drops, cPawn * a_Killer = NULL) override; } ; diff --git a/source/Mobs/Squid.cpp b/source/Mobs/Squid.cpp index 808bd359e..78dd37393 100644 --- a/source/Mobs/Squid.cpp +++ b/source/Mobs/Squid.cpp @@ -27,14 +27,15 @@ void cSquid::GetDrops(cItems & a_Drops, cPawn * a_Killer) -void cSquid::Tick(float a_Dt, MTRand & a_TickRandom) +void cSquid::Tick(float a_Dt, cChunk & a_Chunk) { - super::Tick(a_Dt, a_TickRandom); + // TODO: Rewrite this function to use a_Chunk instead of m_World + super::Tick(a_Dt, a_Chunk); Vector3d Pos = GetPosition(); // TODO: Not a real behavior, but cool :D - if (!IsBlockWater(GetWorld()->GetBlock((int) Pos.x, (int) Pos.y, (int) Pos.z)) && GetMetaData() != BURNING) + if (!IsBlockWater(GetWorld()->GetBlock((int) Pos.x, (int) Pos.y, (int) Pos.z)) && !IsBurning()) { SetMetaData(BURNING); } diff --git a/source/Mobs/Squid.h b/source/Mobs/Squid.h index 158fbea4a..de205f397 100644 --- a/source/Mobs/Squid.h +++ b/source/Mobs/Squid.h @@ -15,7 +15,7 @@ class cSquid : public: cSquid(); - virtual void Tick(float a_Dt, MTRand & a_TickRandom) override; + virtual void Tick(float a_Dt, cChunk & a_Chunk) override; CLASS_PROTODEF(cSquid); diff --git a/source/Mobs/Zombie.cpp b/source/Mobs/Zombie.cpp index 8038c51f6..cf0391b4c 100644 --- a/source/Mobs/Zombie.cpp +++ b/source/Mobs/Zombie.cpp @@ -16,12 +16,12 @@ cZombie::cZombie(void) : -void cZombie::Tick(float a_Dt, MTRand & a_TickRandom) +void cZombie::Tick(float a_Dt, cChunk & a_Chunk) { - super::Tick(a_Dt, a_TickRandom); + super::Tick(a_Dt, a_Chunk); // TODO Same as in cSkeleton :D - if ((GetWorld()->GetTimeOfDay() < (12000 + 1000)) && (GetMetaData() != BURNING)) + if ((GetWorld()->GetTimeOfDay() < (12000 + 1000)) && !IsBurning()) { SetMetaData(BURNING); // BURN, BABY, BURN! >:D } diff --git a/source/Mobs/Zombie.h b/source/Mobs/Zombie.h index c4988af72..5813a900b 100644 --- a/source/Mobs/Zombie.h +++ b/source/Mobs/Zombie.h @@ -16,7 +16,7 @@ public: CLASS_PROTODEF(cZombie); - virtual void Tick(float a_Dt, MTRand & a_TickRandom) override; + virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void GetDrops(cItems & a_Drops, cPawn * a_Killer = NULL) override; } ; diff --git a/source/Mobs/Zombiepigman.cpp b/source/Mobs/Zombiepigman.cpp index a542723c4..40fb0a593 100644 --- a/source/Mobs/Zombiepigman.cpp +++ b/source/Mobs/Zombiepigman.cpp @@ -16,12 +16,12 @@ cZombiepigman::cZombiepigman(void) : -void cZombiepigman::Tick(float a_Dt, MTRand & a_TickRandom) +void cZombiepigman::Tick(float a_Dt, cChunk & a_Chunk) { - super::Tick(a_Dt, a_TickRandom); + super::Tick(a_Dt, a_Chunk); // TODO Same as noticed in cSkeleton AND Do they really burn by sun?? :D In the neather is no sun :D - if ((GetWorld()->GetTimeOfDay() < (12000 + 1000)) && (GetMetaData() != BURNING)) + if ((GetWorld()->GetTimeOfDay() < (12000 + 1000)) && !IsBurning()) { SetMetaData(BURNING); // BURN, BABY, BURN! >:D } diff --git a/source/Mobs/Zombiepigman.h b/source/Mobs/Zombiepigman.h index 201416dbd..a8c2e429d 100644 --- a/source/Mobs/Zombiepigman.h +++ b/source/Mobs/Zombiepigman.h @@ -17,7 +17,7 @@ public: CLASS_PROTODEF(cZombiepigman); - virtual void Tick(float a_Dt, MTRand & a_TickRandom) override; + virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void GetDrops(cItems & a_Drops, cPawn * a_Killer = NULL) override; virtual void KilledBy(cPawn * a_Killer) override; } ; diff --git a/source/Pawn.cpp b/source/Pawn.cpp index 960f95de3..b3cba7ab0 100644 --- a/source/Pawn.cpp +++ b/source/Pawn.cpp @@ -288,11 +288,11 @@ void cPawn::TeleportTo(double a_PosX, double a_PosY, double a_PosZ) -void cPawn::Tick(float a_Dt, MTRand & a_TickRandom) +void cPawn::Tick(float a_Dt, cChunk & a_Chunk) { - CheckMetaDataBurn(); // Check to see if pawn should burn based on block they are on + CheckMetaDataBurn(a_Chunk); // Check to see if pawn should burn based on block they are on - if (GetMetaData() == BURNING) + if (IsBurning()) { InStateBurning(a_Dt); } @@ -315,8 +315,10 @@ void cPawn::SetMetaData(MetaData a_MetaData) //----Change Entity MetaData -void cPawn::CheckMetaDataBurn(void) +void cPawn::CheckMetaDataBurn(cChunk & a_Chunk) { + // TODO: Rewrite this function to use a_Chunk instead of m_World + if ((GetPosY() < 1) || (GetPosY() >= 254)) { // Y coord out of range diff --git a/source/Pawn.h b/source/Pawn.h index 9ddc61296..dddb98699 100644 --- a/source/Pawn.h +++ b/source/Pawn.h @@ -83,7 +83,7 @@ public: cPawn(eEntityType a_EntityType); - virtual void Tick(float a_Dt, MTRand & a_TickRandom) override; + virtual void Tick(float a_Dt, cChunk & a_Chunk) override; // tolua_begin @@ -150,10 +150,12 @@ public: virtual void InStateBurning(float a_Dt); - virtual void CheckMetaDataBurn(void); + virtual void CheckMetaDataBurn(cChunk & a_Chunk); virtual void SetMaxHealth(short a_MaxHealth); virtual short GetMaxHealth() { return m_MaxHealth; } + + bool IsBurning(void) const { return (m_MetaData == BURNING); } protected: short m_Health; diff --git a/source/Pickup.cpp b/source/Pickup.cpp index 16e68b3ee..7cee53cb7 100644 --- a/source/Pickup.cpp +++ b/source/Pickup.cpp @@ -59,9 +59,9 @@ void cPickup::SpawnOn(cClientHandle & a_Client) -void cPickup::Tick(float a_Dt, MTRand & a_TickRandom) +void cPickup::Tick(float a_Dt, cChunk & a_Chunk) { - super::Tick(a_Dt, a_TickRandom); + super::Tick(a_Dt, a_Chunk); m_Timer += a_Dt; a_Dt = a_Dt / 1000.f; @@ -88,7 +88,6 @@ void cPickup::Tick(float a_Dt, MTRand & a_TickRandom) if (!m_bReplicated || m_bDirtyPosition) { - MoveToCorrectChunk(); m_bReplicated = true; m_bDirtyPosition = false; GetWorld()->BroadcastTeleportEntity(*this); @@ -99,8 +98,10 @@ void cPickup::Tick(float a_Dt, MTRand & a_TickRandom) -void cPickup::HandlePhysics(float a_Dt) +void cPickup::HandlePhysics(float a_Dt, cChunk & a_Chunk) { + // TODO: Rewrite this function to use a_Chunk instead of m_World + m_ResultingSpeed.Set(0.f, 0.f, 0.f); cWorld * World = GetWorld(); diff --git a/source/Pickup.h b/source/Pickup.h index b294b4e45..b6a8130da 100644 --- a/source/Pickup.h +++ b/source/Pickup.h @@ -35,8 +35,8 @@ public: virtual bool CollectedBy(cPlayer * a_Dest); // tolua_export - virtual void Tick(float a_Dt, MTRand & a_TickRandom) override; - virtual void HandlePhysics(float a_Dt) override; + virtual void Tick(float a_Dt, cChunk & a_Chunk) override; + virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override; short GetHealth(void) const { return m_Health; } diff --git a/source/Player.cpp b/source/Player.cpp index af2e00570..cfbf5cdff 100644 --- a/source/Player.cpp +++ b/source/Player.cpp @@ -99,7 +99,7 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) cPlayer::~cPlayer(void) { - LOG("Deleting cPlayer \"%s\" at %p, ID %d; inv win %p", m_PlayerName.c_str(), this, GetUniqueID(), m_InventoryWindow); + LOG("Deleting cPlayer \"%s\" at %p, ID %d", m_PlayerName.c_str(), this, GetUniqueID()); SaveToDisk(); @@ -109,7 +109,7 @@ cPlayer::~cPlayer(void) delete m_InventoryWindow; - LOG("Player %p deleted", this); + LOGD("Player %p deleted", this); } @@ -119,7 +119,7 @@ cPlayer::~cPlayer(void) void cPlayer::Initialize( cWorld* a_World ) { cPawn::Initialize( a_World ); - GetWorld()->AddPlayer( this ); + GetWorld()->AddPlayer(this); } @@ -156,7 +156,7 @@ void cPlayer::SpawnOn(cClientHandle & a_Client) -void cPlayer::Tick(float a_Dt, MTRand & a_TickRandom) +void cPlayer::Tick(float a_Dt, cChunk & a_Chunk) { if (!m_ClientHandle->IsPlaying()) { @@ -164,7 +164,7 @@ void cPlayer::Tick(float a_Dt, MTRand & a_TickRandom) return; } - super::Tick(a_Dt, a_TickRandom); + super::Tick(a_Dt, a_Chunk); //TODO: Change this to use the BroadcastMovementUpdate function if (m_bDirtyOrientation && !m_bDirtyPosition) { @@ -853,12 +853,11 @@ bool cPlayer::MoveToWorld( const char* a_WorldName ) /* Remove all links to the old world */ m_World->RemovePlayer( this ); m_ClientHandle->RemoveFromAllChunks(); - m_World->RemoveEntityFromChunk(this, m_ChunkX, m_ChunkY, m_ChunkZ); + m_World->RemoveEntityFromChunk(this, GetChunkX(), GetChunkZ()); /* Add player to all the necessary parts of the new world */ SetWorld( World ); - GetWorld()->AddPlayer( this ); - MoveToCorrectChunk(true); + GetWorld()->AddPlayer(this); GetClientHandle()->StreamChunks(); return true; diff --git a/source/Player.h b/source/Player.h index 7d825eec4..d64cc7581 100644 --- a/source/Player.h +++ b/source/Player.h @@ -35,11 +35,11 @@ public: cPlayer(cClientHandle * a_Client, const AString & a_PlayerName); virtual ~cPlayer(); - virtual void Initialize( cWorld* a_World ); // tolua_export + virtual void Initialize(cWorld * a_World); // tolua_export virtual void SpawnOn(cClientHandle & a_Client) override; - virtual void Tick(float a_Dt, MTRand & a_TickRandom) override; + virtual void Tick(float a_Dt, cChunk & a_Chunk) override; /// Returns the curently equipped weapon; empty item if none virtual cItem GetEquippedWeapon(void) const override { return m_Inventory.GetEquippedItem(); } diff --git a/source/Simulator/FireSimulator.h b/source/Simulator/FireSimulator.h index 877075e73..3031cdba5 100644 --- a/source/Simulator/FireSimulator.h +++ b/source/Simulator/FireSimulator.h @@ -38,10 +38,10 @@ protected: unsigned m_BurnStepTimeNonfuel; /// Chance [0..100000] of an adjacent fuel to catch fire on each tick - unsigned m_Flammability; + int m_Flammability; /// Chance [0..100000] of a fuel burning out being replaced by a new fire block instead of an air block - unsigned m_ReplaceFuelChance; + int m_ReplaceFuelChance; virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override; diff --git a/source/World.cpp b/source/World.cpp index adea59c24..6e321d63a 100644 --- a/source/World.cpp +++ b/source/World.cpp @@ -294,20 +294,6 @@ cWorld::cWorld(const AString & a_WorldName) : cWorld::~cWorld() { - { - cCSLock Lock(m_CSEntities); - while (m_AllEntities.begin() != m_AllEntities.end()) - { - cEntity* Entity = *m_AllEntities.begin(); - m_AllEntities.remove(Entity); - if (!Entity->IsDestroyed()) - { - Entity->Destroy(); - } - delete Entity; - } - } - delete m_SimulatorManager; delete m_SandSimulator; delete m_WaterSimulator; @@ -480,25 +466,7 @@ void cWorld::Tick(float a_Dt) m_LastTimeUpdate = m_WorldAge; } - // Remove entities scheduled for removal: - { - cCSLock Lock(m_CSEntities); - for (cEntityList::iterator itr = m_AllEntities.begin(); itr != m_AllEntities.end();) - { - if ((*itr)->IsDestroyed()) - { - LOGD("Destroying entity #%i", (*itr)->GetUniqueID()); - cEntity * RemoveMe = *itr; - itr = m_AllEntities.erase(itr); - m_RemoveEntityQueue.push_back(RemoveMe); - continue; - } - (*itr)->Tick(a_Dt, m_TickRand); - itr++; - } - } - - m_ChunkMap->Tick(a_Dt, m_TickRand); + m_ChunkMap->Tick(a_Dt); TickQueuedBlocks(a_Dt); @@ -530,13 +498,6 @@ void cWorld::Tick(float a_Dt) UnloadUnusedChunks(); } - // Delete entities queued for removal: - for (cEntityList::iterator itr = m_RemoveEntityQueue.begin(); itr != m_RemoveEntityQueue.end(); ++itr) - { - delete *itr; - } - m_RemoveEntityQueue.clear(); - TickSpawnMobs(a_Dt); std::vector m_RSList_copy(m_RSList); @@ -1290,6 +1251,15 @@ int cWorld::GetHeight(int a_X, int a_Z) +bool cWorld::TryGetHeight(int a_BlockX, int a_BlockZ, int & a_Height) +{ + return m_ChunkMap->TryGetHeight(a_BlockX, a_BlockZ, a_Height); +} + + + + + void cWorld::BroadcastAttachEntity(const cEntity & a_Entity, const cEntity * a_Vehicle) { return m_ChunkMap->BroadcastAttachEntity(a_Entity, a_Vehicle); @@ -1577,27 +1547,27 @@ void cWorld::SendBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cClientHa -void cWorld::MarkChunkDirty (int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cWorld::MarkChunkDirty (int a_ChunkX, int a_ChunkZ) { - m_ChunkMap->MarkChunkDirty (a_ChunkX, a_ChunkY, a_ChunkZ); + m_ChunkMap->MarkChunkDirty (a_ChunkX, a_ChunkZ); } -void cWorld::MarkChunkSaving(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cWorld::MarkChunkSaving(int a_ChunkX, int a_ChunkZ) { - m_ChunkMap->MarkChunkSaving(a_ChunkX, a_ChunkY, a_ChunkZ); + m_ChunkMap->MarkChunkSaving(a_ChunkX, a_ChunkZ); } -void cWorld::MarkChunkSaved (int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cWorld::MarkChunkSaved (int a_ChunkX, int a_ChunkZ) { - m_ChunkMap->MarkChunkSaved (a_ChunkX, a_ChunkY, a_ChunkZ); + m_ChunkMap->MarkChunkSaved (a_ChunkX, a_ChunkZ); } @@ -1605,7 +1575,7 @@ void cWorld::MarkChunkSaved (int a_ChunkX, int a_ChunkY, int a_ChunkZ) void cWorld::SetChunkData( - int a_ChunkX, int a_ChunkY, int a_ChunkZ, + int a_ChunkX, int a_ChunkZ, const BLOCKTYPE * a_BlockTypes, const NIBBLETYPE * a_BlockMeta, const NIBBLETYPE * a_BlockLight, @@ -1628,10 +1598,10 @@ void cWorld::SetChunkData( } m_ChunkMap->SetChunkData( - a_ChunkX, a_ChunkY, a_ChunkZ, + a_ChunkX, a_ChunkZ, a_BlockTypes, a_BlockMeta, a_BlockLight, a_BlockSkyLight, a_HeightMap, *Biomes, - a_Entities, a_BlockEntities, + a_BlockEntities, a_MarkDirty ); @@ -1642,9 +1612,9 @@ void cWorld::SetChunkData( } // If a client is requesting this chunk, send it to them: - if (m_ChunkMap->HasChunkAnyClients(a_ChunkX, a_ChunkY, a_ChunkZ)) + if (m_ChunkMap->HasChunkAnyClients(a_ChunkX, a_ChunkZ)) { - m_ChunkSender.ChunkReady(a_ChunkX, a_ChunkY, a_ChunkZ); + m_ChunkSender.ChunkReady(a_ChunkX, a_ChunkZ); } // Notify the lighting thread that the chunk has become valid (in case it is a neighbor of a postponed chunk): @@ -1668,36 +1638,36 @@ void cWorld::ChunkLighted( -bool cWorld::GetChunkData(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkDataCallback & a_Callback) +bool cWorld::GetChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataCallback & a_Callback) { - return m_ChunkMap->GetChunkData(a_ChunkX, a_ChunkY, a_ChunkZ, a_Callback); + return m_ChunkMap->GetChunkData(a_ChunkX, a_ChunkZ, a_Callback); } -bool cWorld::GetChunkBlockTypes(int a_ChunkX, int a_ChunkY, int a_ChunkZ, BLOCKTYPE * a_BlockTypes) +bool cWorld::GetChunkBlockTypes(int a_ChunkX, int a_ChunkZ, BLOCKTYPE * a_BlockTypes) { - return m_ChunkMap->GetChunkBlockTypes(a_ChunkX, a_ChunkY, a_ChunkZ, a_BlockTypes); + return m_ChunkMap->GetChunkBlockTypes(a_ChunkX, a_ChunkZ, a_BlockTypes); } -bool cWorld::IsChunkValid(int a_ChunkX, int a_ChunkY, int a_ChunkZ) const +bool cWorld::IsChunkValid(int a_ChunkX, int a_ChunkZ) const { - return m_ChunkMap->IsChunkValid(a_ChunkX, a_ChunkY, a_ChunkZ); + return m_ChunkMap->IsChunkValid(a_ChunkX, a_ChunkZ); } -bool cWorld::HasChunkAnyClients(int a_ChunkX, int a_ChunkY, int a_ChunkZ) const +bool cWorld::HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) const { - return m_ChunkMap->HasChunkAnyClients(a_ChunkX, a_ChunkY, a_ChunkZ); + return m_ChunkMap->HasChunkAnyClients(a_ChunkX, a_ChunkZ); } @@ -1736,7 +1706,7 @@ void cWorld::SetMaxPlayers(int iMax) -void cWorld::AddPlayer(cPlayer* a_Player) +void cWorld::AddPlayer(cPlayer * a_Player) { cCSLock Lock(m_CSPlayers); @@ -1750,8 +1720,9 @@ void cWorld::AddPlayer(cPlayer* a_Player) -void cWorld::RemovePlayer(cPlayer* a_Player) +void cWorld::RemovePlayer(cPlayer * a_Player) { + m_ChunkMap->RemoveEntityFromChunk(a_Player, a_Player->GetChunkX(), a_Player->GetChunkZ()); cCSLock Lock(m_CSPlayers); m_Players.remove(a_Player); } @@ -1882,18 +1853,9 @@ void cWorld::SendPlayerList(cPlayer * a_DestPlayer) -void cWorld::RemoveEntityFromChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkY, int a_ChunkZ) +void cWorld::RemoveEntityFromChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkZ) { - m_ChunkMap->RemoveEntityFromChunk(a_Entity, a_ChunkX, a_ChunkY, a_ChunkZ); -} - - - - - -void cWorld::MoveEntityToChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkY, int a_ChunkZ) -{ - m_ChunkMap->MoveEntityToChunk(a_Entity, a_ChunkX, a_ChunkY, a_ChunkZ); + m_ChunkMap->RemoveEntityFromChunk(a_Entity, a_ChunkX, a_ChunkZ); } @@ -1902,16 +1864,7 @@ void cWorld::MoveEntityToChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkY, i bool cWorld::ForEachEntity(cEntityCallback & a_Callback) { - cCSLock Lock(m_CSEntities); - for (cEntityList::iterator itr = m_AllEntities.begin(), itr2 = itr; itr != m_AllEntities.end(); itr = itr2) - { - ++itr2; - if (a_Callback.Item(*itr)) - { - return false; - } - } // for itr - m_AllEntities[] - return false; + return m_ChunkMap->ForEachEntity(a_Callback); } @@ -1929,42 +1882,34 @@ bool cWorld::ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & bool cWorld::DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback) { - cCSLock Lock(m_CSEntities); - for (cEntityList::iterator itr = m_AllEntities.begin(), end = m_AllEntities.end(); itr != end; ++itr) - { - if ((*itr)->GetUniqueID() == a_UniqueID) - { - return a_Callback.Item(*itr); - } - } // for itr - m_AllEntities[] - return false; + return m_ChunkMap->DoWithEntityByID(a_UniqueID, a_Callback); } -void cWorld::CompareChunkClients(int a_ChunkX1, int a_ChunkY1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkY2, int a_ChunkZ2, cClientDiffCallback & a_Callback) +void cWorld::CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkZ2, cClientDiffCallback & a_Callback) { - m_ChunkMap->CompareChunkClients(a_ChunkX1, a_ChunkY1, a_ChunkZ1, a_ChunkX2, a_ChunkY2, a_ChunkZ2, a_Callback); + m_ChunkMap->CompareChunkClients(a_ChunkX1, a_ChunkZ1, a_ChunkX2, a_ChunkZ2, a_Callback); } -bool cWorld::AddChunkClient(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client) +bool cWorld::AddChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client) { - return m_ChunkMap->AddChunkClient(a_ChunkX, a_ChunkY, a_ChunkZ, a_Client); + return m_ChunkMap->AddChunkClient(a_ChunkX, a_ChunkZ, a_Client); } -void cWorld::RemoveChunkClient(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client) +void cWorld::RemoveChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client) { - m_ChunkMap->RemoveChunkClient(a_ChunkX, a_ChunkY, a_ChunkZ, a_Client); + m_ChunkMap->RemoveChunkClient(a_ChunkX, a_ChunkZ, a_Client); } @@ -1980,9 +1925,9 @@ void cWorld::RemoveClientFromChunks(cClientHandle * a_Client) -void cWorld::SendChunkTo(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client) +void cWorld::SendChunkTo(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client) { - m_ChunkSender.QueueSendChunkTo(a_ChunkX, a_ChunkY, a_ChunkZ, a_Client); + m_ChunkSender.QueueSendChunkTo(a_ChunkX, a_ChunkZ, a_Client); } @@ -2123,8 +2068,16 @@ void cWorld::SaveAllChunks(void) void cWorld::AddEntity(cEntity * a_Entity) { - cCSLock Lock(m_CSEntities); - m_AllEntities.push_back(a_Entity); + m_ChunkMap->AddEntity(a_Entity); +} + + + + + +bool cWorld::HasEntity(int a_UniqueID) +{ + return m_ChunkMap->HasEntity(a_UniqueID); } @@ -2254,8 +2207,8 @@ int cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, int a_EntityTy return -1; } } + Monster->SetPosition(a_PosX, a_PosY, a_PosZ); Monster->Initialize(this); - Monster->TeleportTo(a_PosX, a_PosY, a_PosZ); BroadcastSpawn(*Monster); return Monster->GetUniqueID(); } diff --git a/source/World.h b/source/World.h index 74dc3b9e8..38506d1a0 100644 --- a/source/World.h +++ b/source/World.h @@ -100,10 +100,14 @@ public: eDimension GetDimension(void) const { return m_Dimension; } + /// Returns the world height at the specified coords; waits for the chunk to get loaded / generated int GetHeight(int a_BlockX, int a_BlockZ); // tolua_end + /// Retrieves the world height at the specified coords; returns false if chunk not loaded / generated + bool TryGetHeight(int a_BlockX, int a_BlockZ, int & a_Height); // TODO: Export in ManualBindings.cpp + void BroadcastAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle); void BroadcastChat (const AString & a_Message, const cClientHandle * a_Exclude = NULL); void BroadcastPlayerAnimation (const cPlayer & a_Player, char a_Animation, const cClientHandle * a_Exclude = NULL); @@ -136,9 +140,9 @@ public: /// If there is a block entity at the specified coords, sends it to the client specified void SendBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cClientHandle & a_Client); - void MarkChunkDirty (int a_ChunkX, int a_ChunkY, int a_ChunkZ); - void MarkChunkSaving(int a_ChunkX, int a_ChunkY, int a_ChunkZ); - void MarkChunkSaved (int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void MarkChunkDirty (int a_ChunkX, int a_ChunkZ); + void MarkChunkSaving(int a_ChunkX, int a_ChunkZ); + void MarkChunkSaved (int a_ChunkX, int a_ChunkZ); /** Sets the chunk data as either loaded from the storage or generated. a_BlockLight and a_BlockSkyLight are optional, if not present, chunk will be marked as unlighted. @@ -147,7 +151,7 @@ public: If a_MarkDirty is set, the chunk is set as dirty (used after generating) */ void SetChunkData( - int a_ChunkX, int a_ChunkY, int a_ChunkZ, + int a_ChunkX, int a_ChunkZ, const BLOCKTYPE * a_BlockTypes, const NIBBLETYPE * a_BlockMeta, const NIBBLETYPE * a_BlockLight, @@ -165,13 +169,13 @@ public: const cChunkDef::BlockNibbles & a_SkyLight ); - bool GetChunkData (int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkDataCallback & a_Callback); + bool GetChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataCallback & a_Callback); /// Gets the chunk's blocks, only the block types - bool GetChunkBlockTypes(int a_ChunkX, int a_ChunkY, int a_ChunkZ, BLOCKTYPE * a_BlockTypes); + bool GetChunkBlockTypes(int a_ChunkX, int a_ChunkZ, BLOCKTYPE * a_BlockTypes); - bool IsChunkValid (int a_ChunkX, int a_ChunkY, int a_ChunkZ) const; - bool HasChunkAnyClients(int a_ChunkX, int a_ChunkY, int a_ChunkZ) const; + bool IsChunkValid (int a_ChunkX, int a_ChunkZ) const; + bool HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) const; void UnloadUnusedChunks(void); // tolua_export @@ -203,13 +207,12 @@ public: void SendPlayerList(cPlayer * a_DestPlayer); // Sends playerlist to the player - void AddEntity( cEntity* a_Entity ); + void AddEntity(cEntity * a_Entity); - /// Removes the entity from the chunk specified - void RemoveEntityFromChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkY, int a_ChunkZ); + bool HasEntity(int a_UniqueID); - /// Moves the entity from its current chunk to the new chunk specified - void MoveEntityToChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkY, int a_ChunkZ); + /// Removes the entity from the chunk specified + void RemoveEntityFromChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkZ); /// Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true bool ForEachEntity(cEntityCallback & a_Callback); // Exported in ManualBindings.cpp @@ -217,23 +220,23 @@ public: /// Calls the callback for each entity in the specified chunk; returns true if all entities processed, false if the callback aborted by returning true bool ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp - /// Calls the callback if the entity with the specified ID is found, with the entity object as the callback param + /// Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found and callback returned false. bool DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback); // TODO: Exported in ManualBindings.cpp /// Compares clients of two chunks, calls the callback accordingly - void CompareChunkClients(int a_ChunkX1, int a_ChunkY1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkY2, int a_ChunkZ2, cClientDiffCallback & a_Callback); + void CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkZ2, cClientDiffCallback & a_Callback); /// Adds client to a chunk, if not already present; returns true if added, false if present - bool AddChunkClient(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client); + bool AddChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client); /// Removes client from the chunk specified - void RemoveChunkClient(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client); + void RemoveChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client); /// Removes the client from all chunks it is present in void RemoveClientFromChunks(cClientHandle * a_Client); /// Sends the chunk to the client specified, if the chunk is valid. If not valid, the request is postponed (ChunkSender will send that chunk when it becomes valid+lighted) - void SendChunkTo(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client); + void SendChunkTo(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client); /// Removes client from ChunkSender's queue of chunks to be sent void RemoveClientFromChunkSender(cClientHandle * a_Client); @@ -461,7 +464,7 @@ public: int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, int a_EntityType); // tolua_export /// Returns a random number from the m_TickRand in range [0 .. a_Range]. To be used only in the tick thread! - unsigned GetTickRandomNumber(unsigned a_Range) { return m_TickRand.randInt(a_Range); } + int GetTickRandomNumber(unsigned a_Range) { return (int)(m_TickRand.randInt(a_Range)); } private: @@ -505,7 +508,6 @@ private: cRedstoneSimulator * m_RedstoneSimulator; cCriticalSection m_CSClients; - cCriticalSection m_CSEntities; cCriticalSection m_CSPlayers; cWorldStorage m_Storage; @@ -536,8 +538,6 @@ private: bool m_IsSaplingBonemealable; bool m_IsSugarcaneBonemealable; - cEntityList m_RemoveEntityQueue; - cEntityList m_AllEntities; cClientHandleList m_Clients; cPlayerList m_Players; diff --git a/source/WorldStorage/WSSAnvil.cpp b/source/WorldStorage/WSSAnvil.cpp index f14d4918b..234ddbd20 100644 --- a/source/WorldStorage/WSSAnvil.cpp +++ b/source/WorldStorage/WSSAnvil.cpp @@ -113,10 +113,12 @@ bool cWSSAnvil::SaveChunk(const cChunkCoords & a_Chunk) AString ChunkData; if (!SaveChunkToData(a_Chunk, ChunkData)) { + LOGWARNING("Cannot serialize chunk [%d, %d] into data", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); return false; } if (!SetChunkData(a_Chunk, ChunkData)) { + LOGWARNING("Cannot store chunk [%d, %d] data", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); return false; } @@ -252,6 +254,7 @@ bool cWSSAnvil::SaveChunkToData(const cChunkCoords & a_Chunk, AString & a_Data) cFastNBTWriter Writer; if (!SaveChunkToNBT(a_Chunk, Writer)) { + LOGWARNING("Cannot save chunk [%d, %d] to NBT", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); return false; } Writer.Finish(); @@ -360,7 +363,7 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT //*/ m_World->SetChunkData( - a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ, + a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, BlockTypes, MetaData, IsLightValid ? BlockLight : NULL, IsLightValid ? SkyLight : NULL, @@ -393,8 +396,9 @@ bool cWSSAnvil::SaveChunkToNBT(const cChunkCoords & a_Chunk, cFastNBTWriter & a_ a_Writer.AddInt("xPos", a_Chunk.m_ChunkX); a_Writer.AddInt("zPos", a_Chunk.m_ChunkZ); cNBTChunkSerializer Serializer(a_Writer); - if (!m_World->GetChunkData(a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ, Serializer)) + if (!m_World->GetChunkData(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, Serializer)) { + LOGWARNING("Cannot get chunk [%d, %d] data for NBT saving", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); return false; } Serializer.Finish(); // Close NBT tags diff --git a/source/WorldStorage/WSSCompact.cpp b/source/WorldStorage/WSSCompact.cpp index 1d873add6..a4acd0b93 100644 --- a/source/WorldStorage/WSSCompact.cpp +++ b/source/WorldStorage/WSSCompact.cpp @@ -875,7 +875,7 @@ bool cWSSCompact::LoadChunkFromData(const cChunkCoords & a_Chunk, int & a_Uncomp NIBBLETYPE * SkyLight = (NIBBLETYPE *)(BlockData + cChunkDef::SkyLightOffset); a_World->SetChunkData( - a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ, + a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, BlockData, MetaData, IsLightValid ? BlockLight : NULL, IsLightValid ? SkyLight : NULL, @@ -919,7 +919,7 @@ bool cWSSCompact::cPAKFile::SaveChunkToData(const cChunkCoords & a_Chunk, cWorld { // Serialize the chunk: cJsonChunkSerializer Serializer; - if (!a_World->GetChunkData(a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ, Serializer)) + if (!a_World->GetChunkData(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, Serializer)) { // Chunk not valid LOG("cWSSCompact: Trying to save chunk [%d, %d, %d] that has no data, ignoring request.", a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ); diff --git a/source/WorldStorage/WorldStorage.cpp b/source/WorldStorage/WorldStorage.cpp index 536dc05d8..1193a7128 100644 --- a/source/WorldStorage/WorldStorage.cpp +++ b/source/WorldStorage/WorldStorage.cpp @@ -349,16 +349,12 @@ bool cWorldStorage::SaveOneChunk(void) LOGINFO("Saved all chunks in world %s", m_World->GetName().c_str()); return HasMore; } - if (ShouldSave && m_World->IsChunkValid(Save.m_ChunkX, Save.m_ChunkY, Save.m_ChunkZ)) + if (ShouldSave && m_World->IsChunkValid(Save.m_ChunkX, Save.m_ChunkZ)) { - m_World->MarkChunkSaving(Save.m_ChunkX, Save.m_ChunkY, Save.m_ChunkZ); + m_World->MarkChunkSaving(Save.m_ChunkX, Save.m_ChunkZ); if (m_SaveSchema->SaveChunk(Save)) { - m_World->MarkChunkSaved(Save.m_ChunkX, Save.m_ChunkY, Save.m_ChunkZ); - } - else - { - LOGWARNING("Cannot save chunk [%d, %d, %d]", Save.m_ChunkX, Save.m_ChunkY, Save.m_ChunkZ); + m_World->MarkChunkSaved(Save.m_ChunkX, Save.m_ChunkZ); } } return HasMore; @@ -370,7 +366,7 @@ bool cWorldStorage::SaveOneChunk(void) bool cWorldStorage::LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) { - if (m_World->IsChunkValid(a_ChunkX, a_ChunkY, a_ChunkZ)) + if (m_World->IsChunkValid(a_ChunkX, a_ChunkZ)) { // Already loaded (can happen, since the queue is async) return true; -- cgit v1.2.3