From b653e6a01271c05bdbd947ab7120d10d30ecee91 Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Tue, 21 Feb 2012 16:27:30 +0000 Subject: Removed cChunkPtrs from everywhere but internal cChunkMap usage. Now we should finally be threadsafe :) Also fixed a threading issue when a player connecting might have gotten stuck in "Downloading world" forever git-svn-id: http://mc-server.googlecode.com/svn/trunk@304 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/Bindings.cpp | 6 +- source/cChunk.cpp | 11 ++-- source/cChunk.h | 10 +++- source/cChunkMap.cpp | 143 ++++++++++++++++++++++++++++++++++++++++++++++- source/cChunkMap.h | 22 ++++++-- source/cClientHandle.cpp | 21 +++---- source/cPickup.cpp | 2 +- source/cSignEntity.cpp | 2 +- source/cWorld.cpp | 109 ++++++++++++------------------------ source/cWorld.h | 14 +++-- 10 files changed, 231 insertions(+), 109 deletions(-) diff --git a/source/Bindings.cpp b/source/Bindings.cpp index a8d99330f..21e6ecdb9 100644 --- a/source/Bindings.cpp +++ b/source/Bindings.cpp @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 02/16/12 18:16:16. +** Generated automatically by tolua++-1.0.92 on 02/21/12 17:01:49. */ #ifndef __cplusplus @@ -9508,7 +9508,7 @@ static int tolua_AllToLua_cWorld_GetHeight00(lua_State* tolua_S) if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetHeight'", NULL); #endif { - char tolua_ret = (char) self->GetHeight(a_X,a_Z); + int tolua_ret = (int) self->GetHeight(a_X,a_Z); tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); } } @@ -9984,7 +9984,7 @@ static int tolua_AllToLua_cWorld_GetBlockEntity00(lua_State* tolua_S) if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetBlockEntity'", NULL); #endif { - cBlockEntity* tolua_ret = (cBlockEntity*) self->GetBlockEntity(a_X,a_Y,a_Z); + OBSOLETE cBlockEntity* tolua_ret = (OBSOLETE cBlockEntity*) self->GetBlockEntity(a_X,a_Y,a_Z); tolua_pushusertype(tolua_S,(void*)tolua_ret,"cBlockEntity"); } } diff --git a/source/cChunk.cpp b/source/cChunk.cpp index a783e30b4..c8ba8ba4c 100644 --- a/source/cChunk.cpp +++ b/source/cChunk.cpp @@ -67,7 +67,7 @@ sSetBlock::sSetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockM /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cChunk: -cChunk::cChunk(int a_X, int a_Y, int a_Z, cWorld * a_World) +cChunk::cChunk(int a_X, int a_Y, int a_Z, cChunkMap * a_ChunkMap, cWorld * a_World) : m_bCalculateLighting( false ) , m_bCalculateHeightmap( false ) , m_PosX( a_X ) @@ -82,6 +82,7 @@ cChunk::cChunk(int a_X, int a_Y, int a_Z, cWorld * a_World) , m_BlockTickY( 0 ) , m_BlockTickZ( 0 ) , m_World( a_World ) + , m_ChunkMap(a_ChunkMap) , m_IsValid(false) , m_IsDirty(false) , m_IsSaving(false) @@ -700,8 +701,8 @@ void cChunk::SpreadLight(char* a_LightBuffer) bCalcLeft = bCalcRight = bCalcFront = bCalcBack = false; // Spread to neighbour chunks X-axis - cChunkPtr LeftChunk = m_World->GetChunkNoGen( m_PosX - 1, m_PosY, m_PosZ ); - cChunkPtr RightChunk = m_World->GetChunkNoGen( m_PosX + 1, m_PosY, m_PosZ ); + cChunkPtr LeftChunk = m_ChunkMap->GetChunkNoGen( m_PosX - 1, m_PosY, m_PosZ ); + cChunkPtr RightChunk = m_ChunkMap->GetChunkNoGen( m_PosX + 1, m_PosY, m_PosZ ); char * LeftSky = NULL, *RightSky = NULL; if (LeftChunk->IsValid()) { @@ -745,8 +746,8 @@ void cChunk::SpreadLight(char* a_LightBuffer) } // Spread to neighbour chunks Z-axis - cChunkPtr FrontChunk = m_World->GetChunkNoGen( m_PosX, m_PosY, m_PosZ - 1 ); - cChunkPtr BackChunk = m_World->GetChunkNoGen( m_PosX, m_PosY, m_PosZ + 1 ); + cChunkPtr FrontChunk = m_ChunkMap->GetChunkNoGen( m_PosX, m_PosY, m_PosZ - 1 ); + cChunkPtr BackChunk = m_ChunkMap->GetChunkNoGen( m_PosX, m_PosY, m_PosZ + 1 ); char * FrontSky = NULL, * BackSky = NULL; if (FrontChunk->IsValid()) { diff --git a/source/cChunk.h b/source/cChunk.h index bbeb2f1b4..2fec4bcbe 100644 --- a/source/cChunk.h +++ b/source/cChunk.h @@ -46,10 +46,15 @@ class cClientHandle; class cServer; class MTRand; class cPlayer; +class cChunkMap; typedef std::list cClientHandleList; typedef std::list cBlockEntityList; + + + + /** Interface class used for getting data out of a chunk using the GetAllData() function. Implementation must use the pointers immediately and NOT store any of them for later use */ @@ -108,7 +113,7 @@ public: static const int c_NumBlocks = 16 * 128 * 16; static const int c_BlockDataSize = c_NumBlocks * 2 + (c_NumBlocks/2); // 2.5 * numblocks - cChunk(int a_X, int a_Y, int a_Z, cWorld* a_World); + cChunk(int a_X, int a_Y, int a_Z, cChunkMap * a_ChunkMap, cWorld * a_World); ~cChunk(); bool IsValid(void) const {return m_IsValid; } // Returns true if the chunk is valid (loaded / generated) @@ -248,7 +253,8 @@ private: bool m_bCalculateHeightmap; int m_PosX, m_PosY, m_PosZ; - cWorld * m_World; + cWorld * m_World; + cChunkMap * m_ChunkMap; char m_BlockData[c_BlockDataSize]; // Chunk data ready to be compressed and sent char *m_BlockType; // Pointers to an element in m_BlockData diff --git a/source/cChunkMap.cpp b/source/cChunkMap.cpp index 2621e0793..21b99873f 100644 --- a/source/cChunkMap.cpp +++ b/source/cChunkMap.cpp @@ -2,11 +2,13 @@ #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "cChunkMap.h" -#include "cChunk.h" #include "cWorld.h" #include "cRoot.h" #include "cMakeDir.h" #include "cPlayer.h" +#include "BlockID.h" +#include "cItem.h" +#include "cPickup.h" #ifndef _WIN32 #include // abs @@ -19,6 +21,17 @@ +#define RECI_RAND_MAX (1.f/RAND_MAX) +inline float fRadRand( float a_Radius ) +{ + MTRand r1; + return ((float)r1.rand() * RECI_RAND_MAX)*a_Radius - a_Radius*0.5f; +} + + + + + //////////////////////////////////////////////////////////////////////////////// // cChunkMap: @@ -479,6 +492,88 @@ char cChunkMap::GetBlockMeta(int a_X, int a_Y, int a_Z) +void cChunkMap::SetBlockMeta(int a_X, int a_Y, int a_Z, char a_BlockMeta) +{ + int ChunkX, ChunkZ; + AbsoluteToRelative( a_X, a_Y, a_Z, ChunkX, ChunkZ ); + + cCSLock Lock(m_CSLayers); + cChunkPtr Chunk = GetChunk( ChunkX, ZERO_CHUNK_Y, ChunkZ ); + if ((Chunk != NULL) && Chunk->IsValid() ) + { + // Although it is called SetLight(), it actually sets meta when passed the Meta field + Chunk->SetLight( Chunk->pGetMeta(), a_X, a_Y, a_Z, a_BlockMeta ); + Chunk->SendBlockTo( a_X, a_Y, a_Z, NULL ); + } +} + + + + + +void cChunkMap::SetBlock(int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockMeta) +{ + int ChunkX, ChunkZ, X = a_X, Y = a_Y, Z = a_Z; + AbsoluteToRelative( X, Y, Z, ChunkX, ChunkZ ); + + cCSLock Lock(m_CSLayers); + cChunkPtr Chunk = GetChunk( ChunkX, ZERO_CHUNK_Y, ChunkZ ); + if ((Chunk != NULL) && Chunk->IsValid()) + { + Chunk->SetBlock(X, Y, Z, a_BlockType, a_BlockMeta ); + } +} + + + + + +bool cChunkMap::DigBlock(int a_X, int a_Y, int a_Z, cItem & a_PickupItem) +{ + int PosX = a_X, PosY = a_Y, PosZ = a_Z, ChunkX, ChunkZ; + + AbsoluteToRelative( PosX, PosY, PosZ, ChunkX, ChunkZ ); + + cCSLock Lock(m_CSLayers); + cChunkPtr DestChunk = GetChunk( ChunkX, ZERO_CHUNK_Y, ChunkZ ); + if ((DestChunk == NULL) || !DestChunk->IsValid()) + { + return false; + } + + DestChunk->SetBlock(PosX, PosY, PosZ, E_BLOCK_AIR, 0 ); + + m_World->GetSimulatorManager()->WakeUp(a_X, a_Y, a_Z); + + if ( !a_PickupItem.IsEmpty() ) + { + cPickup * Pickup = new cPickup( a_X * 32 + 16 + (int)fRadRand(16.f), a_Y * 32 + 16 + (int)fRadRand(16.f), a_Z * 32 + 16 + (int)fRadRand(16.f), a_PickupItem ); + Pickup->Initialize(m_World); + } + return true; +} + + + + + +void cChunkMap::SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player) +{ + int ChunkX, ChunkZ; + AbsoluteToRelative(a_X, a_Y, a_Z, ChunkX, ChunkZ); + + cCSLock Lock(m_CSLayers); + cChunkPtr Chunk = GetChunk(ChunkX, ZERO_CHUNK_Y, ChunkZ); + if (Chunk->IsValid()) + { + Chunk->SendBlockTo(a_X, a_Y, a_Z, a_Player->GetClientHandle()); + } +} + + + + + void cChunkMap::CompareChunkClients(int a_ChunkX1, int a_ChunkY1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkY2, int a_ChunkZ2, cClientDiffCallback & a_Callback) { cCSLock Lock(m_CSLayers); @@ -552,6 +647,21 @@ 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) +{ + cCSLock Lock(m_CSLayers); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ); + if (Chunk == NULL) + { + return; + } + Chunk->RemoveClient(a_Client); +} + + + + + void cChunkMap::RemoveClientFromChunks(cClientHandle * a_Client, const cChunkCoordsList & a_Chunks) { cCSLock Lock(m_CSLayers); @@ -569,7 +679,7 @@ void cChunkMap::RemoveClientFromChunks(cClientHandle * a_Client, const cChunkCoo bool cChunkMap::SendChunkTo(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ); + cChunkPtr Chunk = GetChunk(a_ChunkX, a_ChunkY, a_ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { return false; @@ -616,6 +726,33 @@ void cChunkMap::RemoveEntityFromChunk(cEntity * a_Entity, int a_ChunkX, int a_Ch +void cChunkMap::TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +{ + cCSLock Lock(m_CSLayers); + GetChunk(a_ChunkX, a_ChunkY, a_ChunkZ); +} + + + + + +void cChunkMap::UpdateSign(int a_X, int a_Y, int a_Z, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) +{ + cCSLock Lock(m_CSLayers); + int ChunkX, ChunkZ; + BlockToChunk(a_X, a_Y, a_Z, ChunkX, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + if ((Chunk == NULL) || !Chunk->IsValid()) + { + return; + } + Chunk->UpdateSign(a_X, a_Y, a_Z, a_Line1, a_Line2, a_Line3, a_Line4); +} + + + + + void cChunkMap::Tick( float a_Dt, MTRand & a_TickRandom ) { cCSLock Lock(m_CSLayers); @@ -687,7 +824,7 @@ cChunkPtr cChunkMap::cChunkLayer::GetChunk( int a_ChunkX, int a_ChunkY, int a_Ch int Index = LocalX + LocalZ * LAYER_SIZE; if (m_Chunks[Index].get() == NULL) { - m_Chunks[Index].reset(new cChunk(a_ChunkX, 0, a_ChunkZ, m_Parent->GetWorld())); + m_Chunks[Index].reset(new cChunk(a_ChunkX, 0, a_ChunkZ, m_Parent, m_Parent->GetWorld())); } return m_Chunks[Index]; } diff --git a/source/cChunkMap.h b/source/cChunkMap.h index 026594f11..98698cfe3 100644 --- a/source/cChunkMap.h +++ b/source/cChunkMap.h @@ -13,6 +13,7 @@ class cWorld; class cEntity; +class cItem; class MTRand; @@ -27,10 +28,6 @@ public: cChunkMap(cWorld* a_World ); ~cChunkMap(); - // TODO: Get rid of these (put into Private section) in favor of the direct action methods: - cChunkPtr GetChunk ( int a_ChunkX, int a_ChunkY, int a_ChunkZ ); // Also queues the chunk for loading / generating if not valid - cChunkPtr GetChunkNoGen( int a_ChunkX, int a_ChunkY, int a_ChunkZ ); // Also queues the chunk for loading if not valid; doesn't generate - // Direct action methods: /// Broadcast a_Packet to all clients in the chunk specified void BroadcastToChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cPacket & a_Packet, cClientHandle * a_Exclude = NULL); @@ -56,6 +53,10 @@ public: void CollectPickupsByPlayer(cPlayer * a_Player); char GetBlock (int a_X, int a_Y, int a_Z); char GetBlockMeta (int a_X, int a_Y, int a_Z); + void SetBlockMeta (int a_X, int a_Y, int a_Z, char a_BlockMeta); + void SetBlock (int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockMeta); + bool DigBlock (int a_X, int a_Y, int a_Z, cItem & a_PickupItem); + 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); @@ -63,6 +64,9 @@ public: /// 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); + /// Removes the client from the chunk + void RemoveChunkClient(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client); + /// Removes the client from all chunks specified void RemoveClientFromChunks(cClientHandle * a_Client, const cChunkCoordsList & a_Chunks); @@ -74,6 +78,11 @@ public: /// Removes the entity from the chunk specified void RemoveEntityFromChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkY, int a_ChunkZ); + + /// Touches the chunk, causing it to be loaded or generated + void TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + + void UpdateSign(int a_X, int a_Y, int a_Z, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4); void Tick( float a_Dt, MTRand & a_TickRand ); @@ -113,6 +122,8 @@ public: private: + friend class cChunk; // Temporary (until we have a separate Lighting thread), so that cChunk's lighting calc can ask for neighbor chunks + class cChunkLayer { public: @@ -153,6 +164,9 @@ private: cEvent m_evtChunkValid; // Set whenever any chunk becomes valid, via ChunkValidated() cWorld * m_World; + + cChunkPtr GetChunk ( int a_ChunkX, int a_ChunkY, int a_ChunkZ ); // Also queues the chunk for loading / generating if not valid + cChunkPtr GetChunkNoGen( int a_ChunkX, int a_ChunkY, int a_ChunkZ ); // Also queues the chunk for loading if not valid; doesn't generate }; diff --git a/source/cClientHandle.cpp b/source/cClientHandle.cpp index 6db6a2501..91ccb4005 100644 --- a/source/cClientHandle.cpp +++ b/source/cClientHandle.cpp @@ -343,7 +343,7 @@ void cClientHandle::StreamChunks(void) int RelZ = (*itr).m_ChunkZ - ChunkPosZ; if ((RelX > VIEWDISTANCE) || (RelX < -VIEWDISTANCE) || (RelZ > VIEWDISTANCE) || (RelZ < -VIEWDISTANCE)) { - World->GetChunk(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ)->RemoveClient(this); + World->RemoveChunkClient(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ, this); itr = m_LoadedChunks.erase(itr); } else @@ -389,13 +389,13 @@ void cClientHandle::StreamChunks(void) // For each distance touch chunks in a hollow square centered around current position: for (int i = -d; i <= d; ++i) { - World->GetChunk(ChunkPosX + d, ZERO_CHUNK_Y, ChunkPosZ + i); - World->GetChunk(ChunkPosX - d, ZERO_CHUNK_Y, ChunkPosZ + i); + World->TouchChunk(ChunkPosX + d, ZERO_CHUNK_Y, ChunkPosZ + i); + World->TouchChunk(ChunkPosX - d, ZERO_CHUNK_Y, ChunkPosZ + i); } // for i for (int i = -d + 1; i < d; ++i) { - World->GetChunk(ChunkPosX + i, ZERO_CHUNK_Y, ChunkPosZ + d); - World->GetChunk(ChunkPosX + i, ZERO_CHUNK_Y, ChunkPosZ - d); + World->TouchChunk(ChunkPosX + i, ZERO_CHUNK_Y, ChunkPosZ + d); + World->TouchChunk(ChunkPosX + i, ZERO_CHUNK_Y, ChunkPosZ - d); } // for i } // for d } @@ -1510,12 +1510,7 @@ void cClientHandle::HandleWindowClick(cPacket_WindowClick * a_Packet) void cClientHandle::HandleUpdateSign(cPacket_UpdateSign * a_Packet) { cWorld * World = m_Player->GetWorld(); - cChunkPtr Chunk = World->GetChunkOfBlock(a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ); - if ((Chunk == NULL) || !Chunk->IsValid()) - { - return; - } - Chunk->UpdateSign(a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ, a_Packet->m_Line1, a_Packet->m_Line2, a_Packet->m_Line3, a_Packet->m_Line4); + World->UpdateSign(a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ, a_Packet->m_Line1, a_Packet->m_Line2, a_Packet->m_Line3, a_Packet->m_Line4); } @@ -1664,8 +1659,10 @@ void cClientHandle::Tick(float a_Dt) // Only send up to 10 chunks per tick, otherwise we'd choke the tick thread break; } - CheckIfWorldDownloaded(); } // for itr - m_ChunksToSend[] + + // Check even if we didn't send anything - a chunk may have sent a notification that we'd miss otherwise + CheckIfWorldDownloaded(); } } diff --git a/source/cPickup.cpp b/source/cPickup.cpp index bba9ae518..49dc5b342 100644 --- a/source/cPickup.cpp +++ b/source/cPickup.cpp @@ -160,7 +160,7 @@ void cPickup::Tick(float a_Dt) m_bReplicated = true; m_bDirtyPosition = false; cPacket_TeleportEntity TeleportEntity( this ); - GetWorld()->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ )->Broadcast( &TeleportEntity ); + GetWorld()->BroadcastToChunk( m_ChunkX, m_ChunkY, m_ChunkZ, TeleportEntity ); } } diff --git a/source/cSignEntity.cpp b/source/cSignEntity.cpp index 618f5960e..c181deae2 100644 --- a/source/cSignEntity.cpp +++ b/source/cSignEntity.cpp @@ -98,7 +98,7 @@ void cSignEntity::SendTo( cClientHandle* a_Client ) } else // broadcast of a_Client == 0 { - m_World->GetChunkOfBlock(m_PosX, m_PosY, m_PosZ)->Broadcast( Sign ); + m_World->BroadcastToChunkOfBlock(m_PosX, m_PosY, m_PosZ, &Sign ); } } diff --git a/source/cWorld.cpp b/source/cWorld.cpp index 84f350495..1b719d031 100644 --- a/source/cWorld.cpp +++ b/source/cWorld.cpp @@ -80,17 +80,6 @@ bool g_BlockPistonBreakable[128]; -#define RECI_RAND_MAX (1.f/RAND_MAX) -inline float fRadRand( float a_Radius ) -{ - MTRand r1; - return ((float)r1.rand() * RECI_RAND_MAX)*a_Radius - a_Radius*0.5f; -} - - - - - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cWorldLoadProgress: @@ -443,7 +432,7 @@ void cWorld::InitializeSpawn() { for (int z = 0; z < ViewDist; z++) { - GetChunk( x + ChunkX-(ViewDist - 1) / 2, 0, z + ChunkZ-(ViewDist - 1) / 2 ); // Queue the chunk in the generator / loader + m_ChunkMap->TouchChunk( x + ChunkX-(ViewDist - 1) / 2, 0, z + ChunkZ-(ViewDist - 1) / 2 ); // Queue the chunk in the generator / loader } } @@ -812,29 +801,11 @@ void cWorld::GrowTree( int a_X, int a_Y, int a_Z ) -cChunkPtr cWorld::GetChunkOfBlock( int a_X, int a_Y, int a_Z ) -{ - int ChunkX, ChunkY, ChunkZ; - AbsoluteToRelative( a_X, a_Y, a_Z, ChunkX, ChunkY, ChunkZ ); - return GetChunk( ChunkX, ChunkY, ChunkZ ); -} - - - - - void cWorld::SetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockMeta ) { - int ChunkX, ChunkY, ChunkZ, X = a_X, Y = a_Y, Z = a_Z; - AbsoluteToRelative( X, Y, Z, ChunkX, ChunkY, ChunkZ ); + m_ChunkMap->SetBlock(a_X, a_Y, a_Z, a_BlockType, a_BlockMeta); - cChunkPtr Chunk = GetChunk( ChunkX, ChunkY, ChunkZ ); - if ( Chunk->IsValid() ) - { - Chunk->SetBlock(X, Y, Z, a_BlockType, a_BlockMeta ); - this->GetSimulatorManager()->WakeUp(a_X, a_Y, a_Z); - } - // The chunk is not yet initialized, so it's probably far away from all players, no need to store this Meta change + GetSimulatorManager()->WakeUp(a_X, a_Y, a_Z); } @@ -899,17 +870,7 @@ char cWorld::GetBlockMeta( int a_X, int a_Y, int a_Z ) void cWorld::SetBlockMeta( int a_X, int a_Y, int a_Z, char a_MetaData ) { - int ChunkX, ChunkY, ChunkZ; - - AbsoluteToRelative( a_X, a_Y, a_Z, ChunkX, ChunkY, ChunkZ ); - - cChunkPtr Chunk = GetChunk( ChunkX, ChunkY, ChunkZ ); - if ( Chunk->IsValid() ) - { - Chunk->SetLight( Chunk->pGetMeta(), a_X, a_Y, a_Z, a_MetaData ); - Chunk->SendBlockTo( a_X, a_Y, a_Z, NULL ); - } - // The chunk is not yet initialized, so it's probably far away from all players, no need to store this Meta change + m_ChunkMap->SetBlockMeta(a_X, a_Y, a_Z, a_MetaData); } @@ -918,24 +879,12 @@ void cWorld::SetBlockMeta( int a_X, int a_Y, int a_Z, char a_MetaData ) bool cWorld::DigBlock( int a_X, int a_Y, int a_Z, cItem & a_PickupItem ) { - int PosX = a_X, PosY = a_Y, PosZ = a_Z, ChunkX, ChunkY, ChunkZ; - - AbsoluteToRelative( PosX, PosY, PosZ, ChunkX, ChunkY, ChunkZ ); - - cChunkPtr DestChunk = GetChunk( ChunkX, ChunkY, ChunkZ ); - if (DestChunk->IsValid()) + bool res = m_ChunkMap->DigBlock(a_X, a_Y, a_Z, a_PickupItem); + if (res) { - DestChunk->SetBlock(PosX, PosY, PosZ, E_BLOCK_AIR, 0 ); - GetSimulatorManager()->WakeUp(a_X, a_Y, a_Z); - - if ( !a_PickupItem.IsEmpty() ) - { - cPickup * Pickup = new cPickup( a_X * 32 + 16 + (int)fRadRand(16.f), a_Y * 32 + 16 + (int)fRadRand(16.f), a_Z * 32 + 16 + (int)fRadRand(16.f), a_PickupItem ); - Pickup->Initialize( this ); - } } - return true; + return res; } @@ -944,13 +893,7 @@ bool cWorld::DigBlock( int a_X, int a_Y, int a_Z, cItem & a_PickupItem ) void cWorld::SendBlockTo( int a_X, int a_Y, int a_Z, cPlayer * a_Player ) { - int ChunkX, ChunkY, ChunkZ; - AbsoluteToRelative( a_X, a_Y, a_Z, ChunkX, ChunkY, ChunkZ ); - cChunkPtr Chunk = GetChunk( ChunkX, ChunkY, ChunkZ ); - if (Chunk->IsValid()) - { - Chunk->SendBlockTo( a_X, a_Y, a_Z, a_Player->GetClientHandle() ); - } + m_ChunkMap->SendBlockTo(a_X, a_Y, a_Z, a_Player); } @@ -960,15 +903,6 @@ void cWorld::SendBlockTo( int a_X, int a_Y, int a_Z, cPlayer * a_Player ) // TODO: This interface is dangerous! cBlockEntity * cWorld::GetBlockEntity( int a_X, int a_Y, int a_Z ) { - int PosX = a_X, PosY = a_Y, PosZ = a_Z, ChunkX, ChunkY, ChunkZ; - - AbsoluteToRelative( PosX, PosY, PosZ, ChunkX, ChunkY, ChunkZ ); - - cChunkPtr Chunk = GetChunk( ChunkX, ChunkY, ChunkZ ); - if (Chunk->IsValid()) - { - // TODO: return Chunk->GetBlockEntity( a_X, a_Y, a_Z ); - } return NULL; } @@ -1340,6 +1274,15 @@ bool cWorld::AddChunkClient(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHan +void cWorld::RemoveChunkClient(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client) +{ + m_ChunkMap->RemoveChunkClient(a_ChunkX, a_ChunkY, a_ChunkZ, a_Client); +} + + + + + void cWorld::RemoveClientFromChunks(cClientHandle * a_Client, const cChunkCoordsList & a_Chunks) { m_ChunkMap->RemoveClientFromChunks(a_Client, a_Chunks); @@ -1358,6 +1301,24 @@ bool cWorld::SendChunkTo(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle +void cWorld::TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +{ + m_ChunkMap->TouchChunk(a_ChunkX, a_ChunkY, a_ChunkZ); +} + + + + + +void cWorld::UpdateSign(int a_X, int a_Y, int a_Z, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) +{ + m_ChunkMap->UpdateSign(a_X, a_Y, a_Z, a_Line1, a_Line2, a_Line3, a_Line4); +} + + + + + void cWorld::SaveAllChunks() { LOG("Saving all chunks..."); diff --git a/source/cWorld.h b/source/cWorld.h index b181df365..2fc907b3a 100644 --- a/source/cWorld.h +++ b/source/cWorld.h @@ -57,9 +57,6 @@ public: void SetWorldTime(long long a_WorldTime) { m_WorldTime = a_WorldTime; } //tolua_export - cChunkPtr GetChunk ( int a_ChunkX, int a_ChunkY, int a_ChunkZ ) {return m_ChunkMap->GetChunk (a_ChunkX, a_ChunkY, a_ChunkZ); } - cChunkPtr GetChunkNoGen ( int a_ChunkX, int a_ChunkY, int a_ChunkZ ) {return m_ChunkMap->GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ); } - cChunkPtr GetChunkOfBlock( int a_X, int a_Y, int a_Z ); int GetHeight( int a_X, int a_Z ); //tolua_export //void AddClient( cClientHandle* a_Client ); @@ -124,11 +121,19 @@ public: /// 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); + /// Removes client from the chunk specified + void RemoveChunkClient(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client); + /// Removes the client from all chunks specified void RemoveClientFromChunks(cClientHandle * a_Client, const cChunkCoordsList & a_Chunks); /// Sends a chunk to client, returns true if successful, false if not sent bool SendChunkTo(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client); + + /// Touches the chunk, causing it to be loaded or generated + void TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + + void UpdateSign(int a_X, int a_Y, int a_Z, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4); // TODO: Export to Lua bool DoWithEntity( int a_UniqueID, cEntityCallback & a_Callback ); @@ -150,7 +155,8 @@ public: inline cLavaSimulator *GetLavaSimulator() { return m_LavaSimulator; } // TODO: This interface is dangerous! Export as a set of specific action functions for Lua: GetChestItem, GetFurnaceItem, SetFurnaceItem, SetSignLines etc. - cBlockEntity * GetBlockEntity( int a_X, int a_Y, int a_Z ); //tolua_export + // _X 2012_02_21: This function always returns NULL + OBSOLETE cBlockEntity * GetBlockEntity( int a_X, int a_Y, int a_Z ); //tolua_export /// a_Player is using block entity at [x, y, z], handle that: void UseBlockEntity(cPlayer * a_Player, int a_X, int a_Y, int a_Z) {m_ChunkMap->UseBlockEntity(a_Player, a_X, a_Y, a_Z); } -- cgit v1.2.3