From 9e22f46b15d4c92bfbfdd5fb23d7530348f1d534 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Thu, 10 Jul 2014 18:18:32 +0200 Subject: [PATCH] Implemented support for forced chunk ticking. Fixes #1160. --- src/Chunk.cpp | 30 ++++++++++++++++++++++++++++-- src/Chunk.h | 30 ++++++++++++++++++++++++++---- src/ChunkMap.cpp | 20 ++++++++++++++++++-- src/ChunkMap.h | 7 +++++++ src/World.cpp | 9 +++++++++ src/World.h | 7 +++++++ 6 files changed, 95 insertions(+), 8 deletions(-) diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 0fee40cac..3f5165b7b 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -87,7 +87,8 @@ cChunk::cChunk( m_NeighborZM(a_NeighborZM), m_NeighborZP(a_NeighborZP), m_WaterSimulatorData(a_World->GetWaterSimulator()->CreateChunkData()), - m_LavaSimulatorData (a_World->GetLavaSimulator ()->CreateChunkData()) + m_LavaSimulatorData (a_World->GetLavaSimulator ()->CreateChunkData()), + m_AlwaysTicked(0) { if (a_NeighborXM != NULL) { @@ -1641,6 +1642,31 @@ cBlockEntity * cChunk::GetBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ) +bool cChunk::ShouldBeTicked(void) const +{ + return (HasAnyClients() || (m_AlwaysTicked > 0)); +} + + + + + +void cChunk::SetAlwaysTicked(bool a_AlwaysTicked) +{ + if (a_AlwaysTicked) + { + m_AlwaysTicked += 1; + } + else + { + m_AlwaysTicked -= 1; + } +} + + + + + void cChunk::UseBlockEntity(cPlayer * a_Player, int a_X, int a_Y, int a_Z) { cBlockEntity * be = GetBlockEntity(a_X, a_Y, a_Z); @@ -1852,7 +1878,7 @@ bool cChunk::HasClient( cClientHandle* a_Client ) -bool cChunk::HasAnyClients(void) +bool cChunk::HasAnyClients(void) const { return !m_LoadedByClient.empty(); } diff --git a/src/Chunk.h b/src/Chunk.h index e9d964e05..ededf62cd 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -200,11 +200,16 @@ public: void SendBlockTo(int a_RelX, int a_RelY, int a_RelZ, cClientHandle * a_Client); /** Adds a client to the chunk; returns true if added, false if already there */ - bool AddClient (cClientHandle* a_Client ); + bool AddClient(cClientHandle * a_Client); - void RemoveClient (cClientHandle* a_Client ); - bool HasClient (cClientHandle* a_Client ); - bool HasAnyClients(void); // Returns true if theres any client in the chunk; false otherwise + /** Removes the specified client from the chunk; ignored if client not in chunk. */ + void RemoveClient(cClientHandle * a_Client); + + /** Returns true if the specified client is present in this chunk. */ + bool HasClient(cClientHandle * a_Client); + + /** Returns true if theres any client in the chunk; false otherwise */ + bool HasAnyClients(void) const; void AddEntity(cEntity * a_Entity); void RemoveEntity(cEntity * a_Entity); @@ -390,6 +395,17 @@ public: cBlockEntity * GetBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ); cBlockEntity * GetBlockEntity(const Vector3i & a_BlockPos) { return GetBlockEntity(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z); } + + /** Returns true if the chunk should be ticked in the tick-thread. + Checks if there are any clients and if the always-tick flag is set */ + bool ShouldBeTicked(void) const; + + /** Increments (a_AlwaysTicked == true) or decrements (false) the m_AlwaysTicked counter. + If the m_AlwaysTicked counter is greater than zero, the chunk is ticked in the tick-thread regardless of + whether it has any clients or not. + This function allows nesting and task-concurrency (multiple separate tasks can request ticking and as long + as at least one requests is active the chunk will be ticked). */ + void SetAlwaysTicked(bool a_AlwaysTicked); private: @@ -462,6 +478,12 @@ private: /** Indicates if simulate-once blocks should be updated by the redstone simulator */ bool m_IsRedstoneDirty; + + /** If greater than zero, the chunk is ticked even if it has no clients. + Manipulated by the SetAlwaysTicked() function, allows for nested calls of the function. + This is the support for plugin-accessible chunk tick forcing. */ + int m_AlwaysTicked; + // Pick up a random block of this chunk void getRandomBlockCoords(int& a_X, int& a_Y, int& a_Z); diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index c9fb0b59e..687c0824f 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -2674,6 +2674,20 @@ void cChunkMap::QueueTickBlock(int a_BlockX, int a_BlockY, int a_BlockZ) +void cChunkMap::SetChunkAlwaysTicked(int a_ChunkX, int a_ChunkZ, bool a_AlwaysTicked) +{ + cCSLock Lock(m_CSLayers); + cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + if (Chunk != NULL) + { + Chunk->SetAlwaysTicked(a_AlwaysTicked); + } +} + + + + + //////////////////////////////////////////////////////////////////////////////// // cChunkMap::cChunkLayer: @@ -2788,12 +2802,14 @@ void cChunkMap::cChunkLayer::SpawnMobs(cMobSpawner& a_MobSpawner) + + void cChunkMap::cChunkLayer::Tick(float a_Dt) { for (size_t 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()) + // Only tick chunks that are valid and should be ticked: + if ((m_Chunks[i] != NULL) && m_Chunks[i]->IsValid() && m_Chunks[i]->ShouldBeTicked()) { m_Chunks[i]->Tick(a_Dt); } diff --git a/src/ChunkMap.h b/src/ChunkMap.h index 433516490..b8870dfca 100644 --- a/src/ChunkMap.h +++ b/src/ChunkMap.h @@ -339,6 +339,13 @@ public: /** Returns the CS for locking the chunkmap; only cWorld::cLock may use this function! */ cCriticalSection & GetCS(void) { return m_CSLayers; } + + /** Increments (a_AlwaysTicked == true) or decrements (false) the m_AlwaysTicked counter for the specified chunk. + If the m_AlwaysTicked counter is greater than zero, the chunk is ticked in the tick-thread regardless of + whether it has any clients or not. + This function allows nesting and task-concurrency (multiple separate tasks can request ticking and as long + as at least one requests is active the chunk will be ticked). */ + void SetChunkAlwaysTicked(int a_ChunkX, int a_ChunkZ, bool a_AlwaysTicked); private: diff --git a/src/World.cpp b/src/World.cpp index a6607de12..f91a15260 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -3033,6 +3033,15 @@ void cWorld::TabCompleteUserName(const AString & a_Text, AStringVector & a_Resul +void cWorld::SetChunkAlwaysTicked(int a_ChunkX, int a_ChunkZ, bool a_AlwaysTicked) +{ + m_ChunkMap->SetChunkAlwaysTicked(a_ChunkX, a_ChunkZ, a_AlwaysTicked); +} + + + + + cRedstoneSimulator * cWorld::InitializeRedstoneSimulator(cIniFile & a_IniFile) { AString SimulatorName = a_IniFile.GetValueSet("Physics", "RedstoneSimulator", ""); diff --git a/src/World.h b/src/World.h index 476a49739..f903ff5be 100644 --- a/src/World.h +++ b/src/World.h @@ -772,6 +772,13 @@ public: /** Get the current darkness level based on the time */ NIBBLETYPE GetSkyDarkness() { return m_SkyDarkness; } + + /** Increments (a_AlwaysTicked == true) or decrements (false) the m_AlwaysTicked counter for the specified chunk. + If the m_AlwaysTicked counter is greater than zero, the chunk is ticked in the tick-thread regardless of + whether it has any clients or not. + This function allows nesting and task-concurrency (multiple separate tasks can request ticking and as long + as at least one requests is active the chunk will be ticked). */ + void SetChunkAlwaysTicked(int a_ChunkX, int a_ChunkZ, bool a_AlwaysTicked = true); // tolua_export private: