1
0

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
This commit is contained in:
madmaxoft@gmail.com 2012-02-21 16:27:30 +00:00
parent f0145ee9fa
commit b653e6a012
10 changed files with 231 additions and 109 deletions

View File

@ -1,6 +1,6 @@
/* /*
** Lua binding: AllToLua ** 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 #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); if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetHeight'", NULL);
#endif #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); 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); if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetBlockEntity'", NULL);
#endif #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"); tolua_pushusertype(tolua_S,(void*)tolua_ret,"cBlockEntity");
} }
} }

View File

@ -67,7 +67,7 @@ sSetBlock::sSetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockM
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cChunk: // 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_bCalculateLighting( false )
, m_bCalculateHeightmap( false ) , m_bCalculateHeightmap( false )
, m_PosX( a_X ) , 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_BlockTickY( 0 )
, m_BlockTickZ( 0 ) , m_BlockTickZ( 0 )
, m_World( a_World ) , m_World( a_World )
, m_ChunkMap(a_ChunkMap)
, m_IsValid(false) , m_IsValid(false)
, m_IsDirty(false) , m_IsDirty(false)
, m_IsSaving(false) , m_IsSaving(false)
@ -700,8 +701,8 @@ void cChunk::SpreadLight(char* a_LightBuffer)
bCalcLeft = bCalcRight = bCalcFront = bCalcBack = false; bCalcLeft = bCalcRight = bCalcFront = bCalcBack = false;
// Spread to neighbour chunks X-axis // Spread to neighbour chunks X-axis
cChunkPtr LeftChunk = 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_World->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; char * LeftSky = NULL, *RightSky = NULL;
if (LeftChunk->IsValid()) if (LeftChunk->IsValid())
{ {
@ -745,8 +746,8 @@ void cChunk::SpreadLight(char* a_LightBuffer)
} }
// Spread to neighbour chunks Z-axis // Spread to neighbour chunks Z-axis
cChunkPtr FrontChunk = 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_World->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; char * FrontSky = NULL, * BackSky = NULL;
if (FrontChunk->IsValid()) if (FrontChunk->IsValid())
{ {

View File

@ -46,10 +46,15 @@ class cClientHandle;
class cServer; class cServer;
class MTRand; class MTRand;
class cPlayer; class cPlayer;
class cChunkMap;
typedef std::list<cClientHandle *> cClientHandleList; typedef std::list<cClientHandle *> cClientHandleList;
typedef std::list<cBlockEntity *> cBlockEntityList; typedef std::list<cBlockEntity *> cBlockEntityList;
/** Interface class used for getting data out of a chunk using the GetAllData() function. /** 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 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_NumBlocks = 16 * 128 * 16;
static const int c_BlockDataSize = c_NumBlocks * 2 + (c_NumBlocks/2); // 2.5 * numblocks 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(); ~cChunk();
bool IsValid(void) const {return m_IsValid; } // Returns true if the chunk is valid (loaded / generated) bool IsValid(void) const {return m_IsValid; } // Returns true if the chunk is valid (loaded / generated)
@ -249,6 +254,7 @@ private:
int m_PosX, m_PosY, m_PosZ; 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_BlockData[c_BlockDataSize]; // Chunk data ready to be compressed and sent
char *m_BlockType; // Pointers to an element in m_BlockData char *m_BlockType; // Pointers to an element in m_BlockData

View File

@ -2,11 +2,13 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "cChunkMap.h" #include "cChunkMap.h"
#include "cChunk.h"
#include "cWorld.h" #include "cWorld.h"
#include "cRoot.h" #include "cRoot.h"
#include "cMakeDir.h" #include "cMakeDir.h"
#include "cPlayer.h" #include "cPlayer.h"
#include "BlockID.h"
#include "cItem.h"
#include "cPickup.h"
#ifndef _WIN32 #ifndef _WIN32
#include <cstdlib> // abs #include <cstdlib> // 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: // 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) 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); 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) void cChunkMap::RemoveClientFromChunks(cClientHandle * a_Client, const cChunkCoordsList & a_Chunks)
{ {
cCSLock Lock(m_CSLayers); 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) bool cChunkMap::SendChunkTo(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client)
{ {
cCSLock Lock(m_CSLayers); 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()) if ((Chunk == NULL) || !Chunk->IsValid())
{ {
return false; 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 ) void cChunkMap::Tick( float a_Dt, MTRand & a_TickRandom )
{ {
cCSLock Lock(m_CSLayers); 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; int Index = LocalX + LocalZ * LAYER_SIZE;
if (m_Chunks[Index].get() == NULL) 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]; return m_Chunks[Index];
} }

View File

@ -13,6 +13,7 @@
class cWorld; class cWorld;
class cEntity; class cEntity;
class cItem;
class MTRand; class MTRand;
@ -27,10 +28,6 @@ public:
cChunkMap(cWorld* a_World ); cChunkMap(cWorld* a_World );
~cChunkMap(); ~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: // Direct action methods:
/// Broadcast a_Packet to all clients in the chunk specified /// 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); 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); void CollectPickupsByPlayer(cPlayer * a_Player);
char GetBlock (int a_X, int a_Y, int a_Z); char GetBlock (int a_X, int a_Y, int a_Z);
char GetBlockMeta (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 /// 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_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 /// 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_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 /// Removes the client from all chunks specified
void RemoveClientFromChunks(cClientHandle * a_Client, const cChunkCoordsList & a_Chunks); void RemoveClientFromChunks(cClientHandle * a_Client, const cChunkCoordsList & a_Chunks);
@ -75,6 +79,11 @@ public:
/// Removes the entity from the chunk specified /// 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_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 ); void Tick( float a_Dt, MTRand & a_TickRand );
void UnloadUnusedChunks(); void UnloadUnusedChunks();
@ -113,6 +122,8 @@ public:
private: 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 class cChunkLayer
{ {
public: public:
@ -153,6 +164,9 @@ private:
cEvent m_evtChunkValid; // Set whenever any chunk becomes valid, via ChunkValidated() cEvent m_evtChunkValid; // Set whenever any chunk becomes valid, via ChunkValidated()
cWorld * m_World; 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
}; };

View File

@ -343,7 +343,7 @@ void cClientHandle::StreamChunks(void)
int RelZ = (*itr).m_ChunkZ - ChunkPosZ; int RelZ = (*itr).m_ChunkZ - ChunkPosZ;
if ((RelX > VIEWDISTANCE) || (RelX < -VIEWDISTANCE) || (RelZ > VIEWDISTANCE) || (RelZ < -VIEWDISTANCE)) 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); itr = m_LoadedChunks.erase(itr);
} }
else else
@ -389,13 +389,13 @@ void cClientHandle::StreamChunks(void)
// For each distance touch chunks in a hollow square centered around current position: // For each distance touch chunks in a hollow square centered around current position:
for (int i = -d; i <= d; ++i) for (int i = -d; i <= d; ++i)
{ {
World->GetChunk(ChunkPosX + d, ZERO_CHUNK_Y, ChunkPosZ + i); World->TouchChunk(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);
} // for i } // for i
for (int i = -d + 1; i < d; ++i) for (int i = -d + 1; i < d; ++i)
{ {
World->GetChunk(ChunkPosX + i, ZERO_CHUNK_Y, ChunkPosZ + d); World->TouchChunk(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);
} // for i } // for i
} // for d } // for d
} }
@ -1510,12 +1510,7 @@ void cClientHandle::HandleWindowClick(cPacket_WindowClick * a_Packet)
void cClientHandle::HandleUpdateSign(cPacket_UpdateSign * a_Packet) void cClientHandle::HandleUpdateSign(cPacket_UpdateSign * a_Packet)
{ {
cWorld * World = m_Player->GetWorld(); cWorld * World = m_Player->GetWorld();
cChunkPtr Chunk = World->GetChunkOfBlock(a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ); 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);
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);
} }
@ -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 // Only send up to 10 chunks per tick, otherwise we'd choke the tick thread
break; break;
} }
CheckIfWorldDownloaded();
} // for itr - m_ChunksToSend[] } // 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();
} }
} }

View File

@ -160,7 +160,7 @@ void cPickup::Tick(float a_Dt)
m_bReplicated = true; m_bReplicated = true;
m_bDirtyPosition = false; m_bDirtyPosition = false;
cPacket_TeleportEntity TeleportEntity( this ); cPacket_TeleportEntity TeleportEntity( this );
GetWorld()->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ )->Broadcast( &TeleportEntity ); GetWorld()->BroadcastToChunk( m_ChunkX, m_ChunkY, m_ChunkZ, TeleportEntity );
} }
} }

View File

@ -98,7 +98,7 @@ void cSignEntity::SendTo( cClientHandle* a_Client )
} }
else // broadcast of a_Client == 0 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 );
} }
} }

View File

@ -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: // cWorldLoadProgress:
@ -443,7 +432,7 @@ void cWorld::InitializeSpawn()
{ {
for (int z = 0; z < ViewDist; z++) 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 ) 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; m_ChunkMap->SetBlock(a_X, a_Y, a_Z, a_BlockType, a_BlockMeta);
AbsoluteToRelative( X, Y, Z, ChunkX, ChunkY, ChunkZ );
cChunkPtr Chunk = GetChunk( ChunkX, ChunkY, ChunkZ ); GetSimulatorManager()->WakeUp(a_X, a_Y, a_Z);
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
} }
@ -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 ) void cWorld::SetBlockMeta( int a_X, int a_Y, int a_Z, char a_MetaData )
{ {
int ChunkX, ChunkY, ChunkZ; m_ChunkMap->SetBlockMeta(a_X, a_Y, a_Z, a_MetaData);
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
} }
@ -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 ) 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; bool res = m_ChunkMap->DigBlock(a_X, a_Y, a_Z, a_PickupItem);
if (res)
AbsoluteToRelative( PosX, PosY, PosZ, ChunkX, ChunkY, ChunkZ );
cChunkPtr DestChunk = GetChunk( ChunkX, ChunkY, ChunkZ );
if (DestChunk->IsValid())
{ {
DestChunk->SetBlock(PosX, PosY, PosZ, E_BLOCK_AIR, 0 );
GetSimulatorManager()->WakeUp(a_X, a_Y, a_Z); 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 res;
return true;
} }
@ -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 ) void cWorld::SendBlockTo( int a_X, int a_Y, int a_Z, cPlayer * a_Player )
{ {
int ChunkX, ChunkY, ChunkZ; m_ChunkMap->SendBlockTo(a_X, a_Y, a_Z, a_Player);
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() );
}
} }
@ -960,15 +903,6 @@ void cWorld::SendBlockTo( int a_X, int a_Y, int a_Z, cPlayer * a_Player )
// TODO: This interface is dangerous! // TODO: This interface is dangerous!
cBlockEntity * cWorld::GetBlockEntity( int a_X, int a_Y, int a_Z ) 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; 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) void cWorld::RemoveClientFromChunks(cClientHandle * a_Client, const cChunkCoordsList & a_Chunks)
{ {
m_ChunkMap->RemoveClientFromChunks(a_Client, 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() void cWorld::SaveAllChunks()
{ {
LOG("Saving all chunks..."); LOG("Saving all chunks...");

View File

@ -57,9 +57,6 @@ public:
void SetWorldTime(long long a_WorldTime) { m_WorldTime = a_WorldTime; } //tolua_export 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 int GetHeight( int a_X, int a_Z ); //tolua_export
//void AddClient( cClientHandle* a_Client ); //void AddClient( cClientHandle* a_Client );
@ -124,12 +121,20 @@ public:
/// Adds client to a chunk, if not already present; returns true if added, false if present /// 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_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 /// Removes the client from all chunks specified
void RemoveClientFromChunks(cClientHandle * a_Client, const cChunkCoordsList & a_Chunks); void RemoveClientFromChunks(cClientHandle * a_Client, const cChunkCoordsList & a_Chunks);
/// Sends a chunk to client, returns true if successful, false if not sent /// 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); 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 // TODO: Export to Lua
bool DoWithEntity( int a_UniqueID, cEntityCallback & a_Callback ); bool DoWithEntity( int a_UniqueID, cEntityCallback & a_Callback );
@ -150,7 +155,8 @@ public:
inline cLavaSimulator *GetLavaSimulator() { return m_LavaSimulator; } 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. // 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: /// 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); } 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); }