From 4d65ffffc0b6f35ac84e310fd4bc9739ea7e0c0a Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Mon, 5 Mar 2012 16:41:57 +0000 Subject: [PATCH] ChunkSender: Chunks are now compressed and sent to clients from a separate threads, proper passive waiting between threads. Not much tested, just appears to work :) git-svn-id: http://mc-server.googlecode.com/svn/trunk@365 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- VC2008/MCServer.vcproj | 10 ++- VC2010/MCServer.vcxproj | 2 + VC2010/MCServer.vcxproj.filters | 2 + source/ChunkSender.cpp | 133 ++++++++++++++++++++++++++++ source/ChunkSender.h | 63 +++++++++++++ source/Globals.h | 9 +- source/cBlockEntity.h | 30 ++++++- source/cChunk.cpp | 115 +++++++++++------------- source/cChunk.h | 15 ++-- source/cChunk.inl.h | 46 +++++----- source/cChunkMap.cpp | 51 ++++++----- source/cChunkMap.h | 9 +- source/cClientHandle.cpp | 59 +++++------- source/cClientHandle.h | 2 + source/cPlayer.cpp | 8 +- source/cSignEntity.cpp | 28 +++--- source/cSignEntity.h | 3 +- source/cWorld.cpp | 22 +++-- source/cWorld.h | 12 ++- source/packets/cPacket_MapChunk.cpp | 78 ++++++++-------- source/packets/cPacket_MapChunk.h | 13 +-- 21 files changed, 473 insertions(+), 237 deletions(-) create mode 100644 source/ChunkSender.cpp create mode 100644 source/ChunkSender.h diff --git a/VC2008/MCServer.vcproj b/VC2008/MCServer.vcproj index 0d2168c6e..c647ec267 100644 --- a/VC2008/MCServer.vcproj +++ b/VC2008/MCServer.vcproj @@ -42,7 +42,7 @@ AdditionalOptions="/MP" Optimization="0" AdditionalIncludeDirectories="../zlib-1.2.5;../jsoncpp-src-0.5.0/include;../lua-5.1.4/src;../tolua++-1.0.93/include" - PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;" + PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;MINECRAFT_1_2_2=1" MinimalRebuild="false" BasicRuntimeChecks="3" RuntimeLibrary="3" @@ -289,6 +289,14 @@ RelativePath="..\source\cHeartBeat.h" > + + + + diff --git a/VC2010/MCServer.vcxproj b/VC2010/MCServer.vcxproj index aece29df4..89662dba8 100644 --- a/VC2010/MCServer.vcxproj +++ b/VC2010/MCServer.vcxproj @@ -329,6 +329,7 @@ + @@ -513,6 +514,7 @@ + diff --git a/VC2010/MCServer.vcxproj.filters b/VC2010/MCServer.vcxproj.filters index 76d6862fe..4640ff5de 100644 --- a/VC2010/MCServer.vcxproj.filters +++ b/VC2010/MCServer.vcxproj.filters @@ -918,6 +918,7 @@ Simulator\cSimulator\cRedstoneSimulator + @@ -1417,6 +1418,7 @@ Simulator\cSimulator\cRedstoneSimulator + diff --git a/source/ChunkSender.cpp b/source/ChunkSender.cpp new file mode 100644 index 000000000..527db4543 --- /dev/null +++ b/source/ChunkSender.cpp @@ -0,0 +1,133 @@ + +// ChunkSender.cpp + +// Interfaces to the cChunkSender class representing the thread that waits for chunks becoming ready (loaded / generated) and sends them to clients + + + + + +#include "Globals.h" +#include "ChunkSender.h" +#include "cWorld.h" +#include "packets/cPacket_MapChunk.h" +#include "packets/cPacket_PreChunk.h" +#include "cBlockEntity.h" + + + + + +cChunkSender::cChunkSender(void) : + super("ChunkSender"), + m_World(NULL) +{ +} + + + + + +cChunkSender::~cChunkSender() +{ + mShouldTerminate = true; + m_Event.Set(); +} + + + + + +bool cChunkSender::Start(cWorld * a_World) +{ + m_World = a_World; + return super::Start(); +} + + + + + +void cChunkSender::ChunkReady(int a_ChunkX, int a_ChunkY, 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_Event.Set(); +} + + + + + +void cChunkSender::Execute(void) +{ + while (!mShouldTerminate) + { + cCSLock Lock(m_CS); + while (m_ChunksReady.empty()) + { + cCSUnlock Unlock(Lock); + m_Event.Wait(); + if (mShouldTerminate) + { + return; + } + } // while (empty) + + // Take one from the queue: + cChunkCoords Coords(m_ChunksReady.front()); + m_ChunksReady.pop_front(); + Lock.Unlock(); + + ASSERT(m_World != NULL); + + // Send it to anyone waiting: + m_World->GetChunkData(Coords.m_ChunkX, Coords.m_ChunkY, Coords.m_ChunkZ, this); + cPacket_PreChunk PreChunk(Coords.m_ChunkX, Coords.m_ChunkZ, true); + cPacket_MapChunk MapChunk(Coords.m_ChunkX, Coords.m_ChunkY, Coords.m_ChunkZ, m_BlockData); + m_World->BroadcastToChunk(Coords.m_ChunkX, Coords.m_ChunkY, Coords.m_ChunkZ, PreChunk); + m_World->BroadcastToChunk(Coords.m_ChunkX, Coords.m_ChunkY, Coords.m_ChunkZ, MapChunk); + + // Send entity creation packets: + for (PacketList::iterator itr = m_Packets.begin(); itr != m_Packets.end(); ++itr) + { + m_World->BroadcastToChunk(Coords.m_ChunkX, Coords.m_ChunkY, Coords.m_ChunkZ, **itr); + delete *itr; + } // for itr - m_Packets + m_Packets.clear(); + + } // while (!mShouldTerminate) +} + + + + + +void cChunkSender::BlockData(const char * a_Data) +{ + memcpy(m_BlockData, a_Data, cChunk::c_BlockDataSize); +} + + + + + +void cChunkSender::BlockEntity(cBlockEntity * a_Entity) +{ + m_Packets.push_back(a_Entity->GetPacket()); +} + + + + +void cChunkSender::Entity(cEntity * a_Entity) +{ + // Nothing needed yet, perhaps in the future when we save entities into chunks we'd like to send them upon load, too ;) +} + + + + diff --git a/source/ChunkSender.h b/source/ChunkSender.h new file mode 100644 index 000000000..a56e797da --- /dev/null +++ b/source/ChunkSender.h @@ -0,0 +1,63 @@ + +// ChunkSender.h + +// Interfaces to the cChunkSender class representing the thread that waits for chunks becoming ready (loaded / generated) and sends them to clients + + + + + +#pragma once + +#include "cIsThread.h" +#include "cChunk.h" +#include "packets/cPacket.h" + + + + + +class cWorld; + + + + + +class cChunkSender: + public cIsThread, + public cChunkDataCallback +{ + typedef cIsThread super; +public: + cChunkSender(void); + ~cChunkSender(); + + bool Start(cWorld * a_World); + + void ChunkReady(int a_ChunkX, int a_ChunkY, int a_ChunkZ); + +protected: + + cWorld * m_World; + + cCriticalSection m_CS; + cChunkCoordsList m_ChunksReady; + cEvent m_Event; // Set when anything is added to m_ChunksReady + + // Data about the chunk that is being sent: + char m_BlockData[cChunk::c_BlockDataSize]; + PacketList m_Packets; // Accumulator for the entity-packets to send + + // cIsThread override: + virtual void Execute(void) override; + + // cChunkDataCallback overrides: + virtual void BlockData(const char * a_Data) override; + virtual void Entity(cEntity * a_Entity) override; + virtual void BlockEntity(cBlockEntity * a_Entity) override; + +} ; + + + + diff --git a/source/Globals.h b/source/Globals.h index ce122528c..419d5f5a7 100644 --- a/source/Globals.h +++ b/source/Globals.h @@ -144,4 +144,11 @@ public: -#define MINECRAFT_1_2_2 (1) \ No newline at end of file +// TODO: Remove this when 1.2 is the major version out there and we're fully compatible +#ifndef MINECRAFT_1_2_2 + #define MINECRAFT_1_2_2 (1) +#endif + + + + diff --git a/source/cBlockEntity.h b/source/cBlockEntity.h index ad1cf14ba..ab0a6c6ca 100644 --- a/source/cBlockEntity.h +++ b/source/cBlockEntity.h @@ -1,6 +1,13 @@ #pragma once +#include "cClientHandle.h" +#include "cWorld.h" + + + + + #ifndef _WIN32 #include "BlockID.h" #else @@ -16,9 +23,9 @@ namespace Json class Value; }; -class cClientHandle; class cPlayer; class cWorld; +class cPacket; @@ -49,7 +56,26 @@ public: virtual void SaveToJson (Json::Value & a_Value ) = 0; virtual void UsedBy( cPlayer * a_Player ) = 0; - virtual void SendTo( cClientHandle* a_Client ) { (void)a_Client; } + + void SendTo( cClientHandle* a_Client ) + { + std::auto_ptr Packet(GetPacket()); + if (Packet.get() == NULL) + { + return; + } + if ( a_Client != NULL ) + { + a_Client->Send(Packet.get()); + } + else // broadcast to all chunk clients + { + m_World->BroadcastToChunkOfBlock(m_PosX, m_PosY, m_PosZ, Packet.get()); + } + } + + /// Returns the packet to send to clients to represent this entity; NULL if no packet needed; caller is supposed to delete the packet + virtual cPacket * GetPacket(void) {return NULL; } protected: int m_PosX; // Position in block coordinates diff --git a/source/cChunk.cpp b/source/cChunk.cpp index fc26b380d..48d2bc086 100644 --- a/source/cChunk.cpp +++ b/source/cChunk.cpp @@ -294,6 +294,16 @@ void cChunk::GetBlocks(char * a_Blocks) +/// Copies m_BlockData into a_Blocks, only the block types +void cChunk::GetBlockData(char * a_BlockData) +{ + memcpy(a_BlockData, m_BlockData, cChunk::c_BlockDataSize); +} + + + + + /// Returns true if there is a block entity at the coords specified bool cChunk::HasBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ) { @@ -359,13 +369,13 @@ void cChunk::Tick(float a_Dt, MTRand & a_TickRandom) #if (MINECRAFT_1_2_2 == 1) unsigned int Coords = Y | Z << 8 | X << 12; - unsigned int Blocks = GetLight( m_BlockMeta, index ) | (m_BlockType[index]<<4); + unsigned int Blocks = GetNibble( m_BlockMeta, index ) | (m_BlockType[index]<<4); MultiBlock.m_Data[i].Data = Coords << 16 | Blocks; #else MultiBlock.m_BlockCoordinates[i] = (Z&0xf) | (X&0xf)<<4 | (Y&0xff)<<8; //LOG("X: %i Y: %i Z: %i Combo: 0x%04x", X, Y, Z, MultiBlock.m_BlockCoordinates[i] ); MultiBlock.m_BlockTypes[i] = m_BlockType[index]; - MultiBlock.m_BlockMetas[i] = GetLight( m_BlockMeta, index ); + MultiBlock.m_BlockMetas[i] = GetNibble( m_BlockMeta, index ); #endif } m_PendingSendBlocks.clear(); @@ -386,7 +396,7 @@ void cChunk::Tick(float a_Dt, MTRand & a_TickRandom) BlockChange.m_PosY = (char)(Y + m_PosY*c_ChunkHeight); BlockChange.m_PosZ = Z + m_PosZ*c_ChunkWidth; BlockChange.m_BlockType = m_BlockType[index]; - BlockChange.m_BlockMeta = GetLight( m_BlockMeta, index ); + BlockChange.m_BlockMeta = GetNibble( m_BlockMeta, index ); Broadcast( BlockChange ); } m_PendingSendBlocks.clear(); @@ -466,7 +476,7 @@ void cChunk::Tick(float a_Dt, MTRand & a_TickRandom) isRedstone = true; case E_BLOCK_TORCH: { - char Dir = cTorch::MetaDataToDirection( GetLight( m_BlockMeta, X, Y, Z ) ); + char Dir = cTorch::MetaDataToDirection( GetNibble( m_BlockMeta, X, Y, Z ) ); LOG("MetaData: %i", Dir ); int XX = X + m_PosX*c_ChunkWidth; int YY = Y + m_PosY*c_ChunkHeight; @@ -490,7 +500,7 @@ void cChunk::Tick(float a_Dt, MTRand & a_TickRandom) break; case E_BLOCK_LADDER: { - char Dir = cLadder::MetaDataToDirection( GetLight( m_BlockMeta, X, Y, Z ) ); + char Dir = cLadder::MetaDataToDirection( GetNibble( m_BlockMeta, X, Y, Z ) ); int XX = X + m_PosX*c_ChunkWidth; int YY = Y + m_PosY*c_ChunkHeight; int ZZ = Z + m_PosZ*c_ChunkWidth; @@ -534,13 +544,13 @@ void cChunk::Tick(float a_Dt, MTRand & a_TickRandom) case E_BLOCK_DIRT: { char AboveBlock = GetBlock( Index+1 ); - if ( (AboveBlock == 0) && GetLight( m_BlockSkyLight, Index ) > 0xf/2 ) // Half lit //changed to not allow grass if any one hit object is on top + if ( (AboveBlock == 0) && GetNibble( m_BlockSkyLight, Index ) > 0xf/2 ) // Half lit //changed to not allow grass if any one hit object is on top { - FastSetBlock( m_BlockTickX, m_BlockTickY, m_BlockTickZ, E_BLOCK_GRASS, GetLight( m_BlockMeta, Index ) ); + FastSetBlock( m_BlockTickX, m_BlockTickY, m_BlockTickZ, E_BLOCK_GRASS, GetNibble( m_BlockMeta, Index ) ); } - if ( (g_BlockOneHitDig[AboveBlock]) && GetLight( m_BlockSkyLight, Index+1 ) > 0xf/2 ) // Half lit //ch$ + if ( (g_BlockOneHitDig[AboveBlock]) && GetNibble( m_BlockSkyLight, Index+1 ) > 0xf/2 ) // Half lit //ch$ { - FastSetBlock( m_BlockTickX, m_BlockTickY, m_BlockTickZ, E_BLOCK_GRASS, GetLight( m_BlockMeta, Index ) ); + FastSetBlock( m_BlockTickX, m_BlockTickY, m_BlockTickZ, E_BLOCK_GRASS, GetNibble( m_BlockMeta, Index ) ); } break; @@ -552,13 +562,13 @@ void cChunk::Tick(float a_Dt, MTRand & a_TickRandom) char AboveBlock = GetBlock( Index+1 ); if (!( (AboveBlock == 0) || (g_BlockOneHitDig[AboveBlock]) || (g_BlockTransparent[AboveBlock]) ) ) //changed to not allow grass if any one hit object is on top { - FastSetBlock( m_BlockTickX, m_BlockTickY, m_BlockTickZ, E_BLOCK_DIRT, GetLight( m_BlockMeta, Index ) ); + FastSetBlock( m_BlockTickX, m_BlockTickY, m_BlockTickZ, E_BLOCK_DIRT, GetNibble( m_BlockMeta, Index ) ); } } break; case E_BLOCK_SAPLING: //todo: check meta of sapling. change m_World->GrowTree to look change trunk and leaves based on meta of sapling { - FastSetBlock( m_BlockTickX, m_BlockTickY, m_BlockTickZ, E_BLOCK_AIR, GetLight( m_BlockMeta, Index ) ); + FastSetBlock( m_BlockTickX, m_BlockTickY, m_BlockTickZ, E_BLOCK_AIR, GetNibble( m_BlockMeta, Index ) ); m_World->GrowTree( m_BlockTickX + m_PosX*c_ChunkWidth, m_BlockTickY, m_BlockTickZ + m_PosZ*c_ChunkWidth ); } break; @@ -675,12 +685,12 @@ void cChunk::CalculateLighting() { // Calculate sunlight memset(m_BlockSkyLight, 0xff, c_NumBlocks / 2 ); // Set all to fully lit, so everything above HeightMap is lit - for(int x = 0; x < c_ChunkWidth; x++) + for (int x = 0; x < c_ChunkWidth; x++) { - for(int z = 0; z < c_ChunkWidth; z++) + for (int z = 0; z < c_ChunkWidth; z++) { char sunlight = 0xf; - for(int y = m_HeightMap[x + z*c_ChunkWidth]; y > -1; y--) + for (int y = m_HeightMap[x + z*c_ChunkWidth]; y > -1; y--) { int index = y + (z * c_ChunkHeight) + (x * c_ChunkHeight * c_ChunkWidth); @@ -688,21 +698,21 @@ void cChunk::CalculateLighting() { sunlight = 0x0; } - SetLight( m_BlockSkyLight, x, y, z, sunlight ); + SetNibble( m_BlockSkyLight, x, y, z, sunlight ); } } } // Calculate blocklights - for(int x = 0; x < c_ChunkWidth; x++) + for (int x = 0; x < c_ChunkWidth; x++) { - for(int z = 0; z < c_ChunkWidth; z++) + for (int z = 0; z < c_ChunkWidth; z++) { int MaxHeight = m_HeightMap[x + z*c_ChunkWidth]; - for(int y = 0; y < MaxHeight; y++) + for (int y = 0; y < MaxHeight; y++) { char BlockID = GetBlock(x, y, z); - SetLight( m_BlockLight, x, y, z, g_BlockLightValue[(int)BlockID] ); + SetNibble( m_BlockLight, x, y, z, g_BlockLightValue[(int)BlockID] ); } } } @@ -710,6 +720,8 @@ void cChunk::CalculateLighting() SpreadLight(m_BlockSkyLight); SpreadLight(m_BlockLight); + MarkDirty(); + // Stop it from calculating again :P m_bCalculateLighting = false; } @@ -762,11 +774,11 @@ void cChunk::SpreadLight(char* a_LightBuffer) int index = y + (z * c_ChunkHeight) + (0 * c_ChunkHeight * c_ChunkWidth); if( g_BlockSpreadLightFalloff[ m_BlockData[index] ] > 0 ) { - char CurrentLight = GetLight( a_LightBuffer, 0, y, z ); - char LeftLight = GetLight( LeftSky, c_ChunkWidth-1, y, z ); + char CurrentLight = GetNibble( a_LightBuffer, 0, y, z ); + char LeftLight = GetNibble( LeftSky, c_ChunkWidth-1, y, z ); if( LeftLight < CurrentLight-g_BlockSpreadLightFalloff[ m_BlockData[index] ] ) { - SetLight( LeftSky, c_ChunkWidth-1, y, z, MAX(0, CurrentLight-g_BlockSpreadLightFalloff[ m_BlockData[index] ]) ); + SetNibble( LeftSky, c_ChunkWidth - 1, y, z, MAX(0, CurrentLight-g_BlockSpreadLightFalloff[ m_BlockData[index] ]) ); bCalcLeft = true; } } @@ -776,11 +788,11 @@ void cChunk::SpreadLight(char* a_LightBuffer) int index = y + (z * c_ChunkHeight) + ((c_ChunkWidth-1) * c_ChunkHeight * c_ChunkWidth); if( g_BlockSpreadLightFalloff[ m_BlockData[index] ] > 0 ) { - char CurrentLight = GetLight( a_LightBuffer, c_ChunkWidth-1, y, z ); - char RightLight = GetLight( RightSky, 0, y, z ); + char CurrentLight = GetNibble( a_LightBuffer, c_ChunkWidth-1, y, z ); + char RightLight = GetNibble( RightSky, 0, y, z ); if( RightLight < CurrentLight-g_BlockSpreadLightFalloff[ m_BlockData[index] ] ) { - SetLight( RightSky, 0, y, z, MAX(0, CurrentLight-g_BlockSpreadLightFalloff[ m_BlockData[index] ]) ); + SetNibble( RightSky, 0, y, z, MAX(0, CurrentLight-g_BlockSpreadLightFalloff[ m_BlockData[index] ]) ); bCalcRight = true; } } @@ -806,11 +818,11 @@ void cChunk::SpreadLight(char* a_LightBuffer) int index = y + (0 * c_ChunkHeight) + (x * c_ChunkHeight * c_ChunkWidth); if( g_BlockSpreadLightFalloff[ m_BlockData[index] ] > 0 ) { - char CurrentLight = GetLight( a_LightBuffer, x, y, 0 ); - char FrontLight = GetLight( FrontSky, x, y, c_ChunkWidth-1 ); + char CurrentLight = GetNibble( a_LightBuffer, x, y, 0 ); + char FrontLight = GetNibble( FrontSky, x, y, c_ChunkWidth-1 ); if( FrontLight < CurrentLight-g_BlockSpreadLightFalloff[ m_BlockData[index] ] ) { - SetLight( FrontSky, x, y, c_ChunkWidth-1, MAX(0, CurrentLight-g_BlockSpreadLightFalloff[ m_BlockData[index] ]) ); + SetNibble( FrontSky, x, y, c_ChunkWidth-1, MAX(0, CurrentLight-g_BlockSpreadLightFalloff[ m_BlockData[index] ]) ); bCalcFront = true; } } @@ -820,41 +832,22 @@ void cChunk::SpreadLight(char* a_LightBuffer) int index = y + ((c_ChunkWidth-1) * c_ChunkHeight) + (x * c_ChunkHeight * c_ChunkWidth); if( g_BlockSpreadLightFalloff[ m_BlockData[index] ] > 0 ) { - char CurrentLight = GetLight( a_LightBuffer, x, y, c_ChunkWidth-1 ); - char BackLight = GetLight( BackSky, x, y, 0 ); + char CurrentLight = GetNibble( a_LightBuffer, x, y, c_ChunkWidth-1 ); + char BackLight = GetNibble( BackSky, x, y, 0 ); if ( BackLight < CurrentLight-g_BlockSpreadLightFalloff[ m_BlockData[index] ] ) { - SetLight( BackSky, x, y, 0, MAX(0, CurrentLight-g_BlockSpreadLightFalloff[ m_BlockData[index] ]) ); + SetNibble( BackSky, x, y, 0, MAX(0, CurrentLight-g_BlockSpreadLightFalloff[ m_BlockData[index] ]) ); bCalcBack = true; } } } } - if( bCalcLeft ) m_World->ReSpreadLighting( m_PosX - 1, m_PosY, m_PosZ ); - if( bCalcRight ) m_World->ReSpreadLighting( m_PosX + 1, m_PosY, m_PosZ ); - if( bCalcFront ) m_World->ReSpreadLighting( m_PosX, m_PosY, m_PosZ - 1 ); - if( bCalcBack ) m_World->ReSpreadLighting( m_PosX, m_PosY, m_PosZ + 1 ); -} - - - - - -void cChunk::SendTo(cClientHandle* a_Client) -{ - cPacket_PreChunk PreChunk; - PreChunk.m_PosX = m_PosX; - PreChunk.m_PosZ = m_PosZ; - PreChunk.m_bLoad = true; - a_Client->Send( PreChunk ); - a_Client->Send( cPacket_MapChunk( this ) ); - - cCSLock Lock(m_CSBlockLists); - for (cBlockEntityList::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr ) - { - (*itr)->SendTo( a_Client ); - } + if ( bCalcLeft ) m_World->ReSpreadLighting( m_PosX - 1, m_PosY, m_PosZ ); + if ( bCalcRight ) m_World->ReSpreadLighting( m_PosX + 1, m_PosY, m_PosZ ); + if ( bCalcFront ) m_World->ReSpreadLighting( m_PosX, m_PosY, m_PosZ - 1 ); + if ( bCalcBack ) m_World->ReSpreadLighting( m_PosX, m_PosY, m_PosZ + 1 ); + // No need to set those neighbors dirty, they will recalc their light anyway so they'll get marked dirty there } @@ -871,12 +864,11 @@ void cChunk::SetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_Block ASSERT(IsValid()); // Is this chunk loaded / generated? int index = a_Y + (a_Z * c_ChunkHeight) + (a_X * c_ChunkHeight * c_ChunkWidth); - char OldBlockMeta = GetLight( m_BlockMeta, index ); + char OldBlockMeta = GetNibble( m_BlockMeta, index ); char OldBlockType = m_BlockType[index]; m_BlockType[index] = a_BlockType; - // It's called SetLight(), but it sets the Meta when passed the BlockMeta workspace - SetLight( m_BlockMeta, index, a_BlockMeta ); + SetNibble( m_BlockMeta, index, a_BlockMeta ); if ((OldBlockType == a_BlockType) && (OldBlockMeta == a_BlockMeta)) { @@ -968,7 +960,7 @@ void cChunk::FastSetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_B const int index = a_Y + (a_Z * c_ChunkHeight) + (a_X * c_ChunkHeight * c_ChunkWidth); const char OldBlock = m_BlockType[index]; - const char OldBlockMeta = GetLight( m_BlockMeta, index ); + const char OldBlockMeta = GetNibble( m_BlockMeta, index ); if (OldBlock == a_BlockType && OldBlockMeta == a_BlockMeta) { return; @@ -983,8 +975,7 @@ void cChunk::FastSetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_B m_PendingSendBlocks.push_back( index ); } - // It's called SetLight(), but it sets the Meta when passed the BlockMeta workspace - SetLight( m_BlockMeta, index, a_BlockMeta ); + SetNibble( m_BlockMeta, index, a_BlockMeta ); // ONLY recalculate lighting if it's necessary! if( @@ -1046,7 +1037,7 @@ void cChunk::SendBlockTo( int a_X, int a_Y, int a_Z, cClientHandle* a_Client ) if( index != INDEX_OUT_OF_RANGE ) { BlockChange.m_BlockType = m_BlockType[ index ]; - BlockChange.m_BlockMeta = GetLight( m_BlockMeta, index ); + BlockChange.m_BlockMeta = GetNibble( m_BlockMeta, index ); } // else it's both 0 a_Client->Send( BlockChange ); break; diff --git a/source/cChunk.h b/source/cChunk.h index dfbbd0c98..aad652c40 100644 --- a/source/cChunk.h +++ b/source/cChunk.h @@ -145,7 +145,10 @@ public: void SetAllData(const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities); /// Copies m_BlockData into a_Blocks, only the block types - void GetBlocks(char a_Blocks[cChunk::c_NumBlocks]); + void GetBlocks(char * a_Blocks); + + /// Copies m_BlockData into a_Blocks, the entire array + void GetBlockData(char * a_BlockData); /// Returns true if there is a block entity at the coords specified bool HasBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ); @@ -160,7 +163,7 @@ public: int GetPosZ() { return m_PosZ; } cWorld * GetWorld() { return m_World; } - void SendTo( cClientHandle * a_Client ); + // OBSOLETE void SendTo( cClientHandle * a_Client ); void SetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockMeta ); void FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, char a_BlockType, char a_BlockMeta ); // Doesn't force block updates on neighbors, use for simple changes such as grass growing etc. @@ -206,10 +209,10 @@ public: void CopyBlockDataFrom(const char * a_NewBlockData); // Copies all blockdata, recalculates heightmap (used by chunk loaders) - char GetLight(char* a_Buffer, int a_BlockIdx); - char GetLight(char* a_Buffer, int x, int y, int z); - void SetLight(char* a_Buffer, int a_BlockIdx, char a_Light); - void SetLight(char* a_Buffer, int x, int y, int z, char light); + static char GetNibble(char * a_Buffer, int a_BlockIdx); + static char GetNibble(char * a_Buffer, int x, int y, int z); + static void SetNibble(char * a_Buffer, int a_BlockIdx, char a_Light); + static void SetNibble(char * a_Buffer, int x, int y, int z, char light); void PositionToWorldPosition(int a_ChunkX, int a_ChunkY, int a_ChunkZ, int & a_X, int & a_Y, int & a_Z); Vector3i PositionToWorldPosition( const Vector3i & a_InChunkPos ); diff --git a/source/cChunk.inl.h b/source/cChunk.inl.h index 36643a87c..16d1855dd 100644 --- a/source/cChunk.inl.h +++ b/source/cChunk.inl.h @@ -11,7 +11,7 @@ __C_CHUNK_INLINE__ -char cChunk::GetLight(char* a_Buffer, int a_BlockIdx) +char cChunk::GetNibble(char* a_Buffer, int a_BlockIdx) { if( a_BlockIdx > -1 && a_BlockIdx < c_NumBlocks ) { @@ -33,7 +33,7 @@ char cChunk::GetLight(char* a_Buffer, int a_BlockIdx) __C_CHUNK_INLINE__ -char cChunk::GetLight(char* a_Buffer, int x, int y, int z) +char cChunk::GetNibble(char* a_Buffer, int x, int y, int z) { if( x < c_ChunkWidth && x > -1 && y < c_ChunkHeight && y > -1 && z < c_ChunkWidth && z > -1 ) { @@ -55,7 +55,7 @@ char cChunk::GetLight(char* a_Buffer, int x, int y, int z) __C_CHUNK_INLINE__ -void cChunk::SetLight(char* a_Buffer, int a_BlockIdx, char a_Light) +void cChunk::SetNibble(char* a_Buffer, int a_BlockIdx, char a_Light) { if( a_BlockIdx > -1 && a_BlockIdx < c_NumBlocks ) { @@ -70,7 +70,6 @@ void cChunk::SetLight(char* a_Buffer, int a_BlockIdx, char a_Light) a_Buffer[cindex] &= 0x0f; // Set second half to 0 a_Buffer[cindex] |= (a_Light << 4) & 0xf0; } - MarkDirty(); } } @@ -79,7 +78,7 @@ void cChunk::SetLight(char* a_Buffer, int a_BlockIdx, char a_Light) __C_CHUNK_INLINE__ -void cChunk::SetLight(char* a_Buffer, int x, int y, int z, char light) +void cChunk::SetNibble(char* a_Buffer, int x, int y, int z, char light) { if( x < c_ChunkWidth && x > -1 && y < c_ChunkHeight && y > -1 && z < c_ChunkWidth && z > -1 ) { @@ -94,7 +93,6 @@ void cChunk::SetLight(char* a_Buffer, int x, int y, int z, char light) a_Buffer[cindex] &= 0x0f; // Set second half to 0 a_Buffer[cindex] |= (light << 4) & 0xf0; } - MarkDirty(); } } @@ -105,13 +103,14 @@ void cChunk::SetLight(char* a_Buffer, int x, int y, int z, char light) __C_CHUNK_INLINE__ void cChunk::SpreadLightOfBlock(char* a_LightBuffer, int a_X, int a_Y, int a_Z, char a_Falloff) { - unsigned char CurrentLight = GetLight( a_LightBuffer, a_X, a_Y, a_Z ); - SetLight( a_LightBuffer, a_X-1, a_Y, a_Z, MAX(GetLight( a_LightBuffer, a_X-1, a_Y, a_Z ), MAX(0,CurrentLight-a_Falloff) ) ); - SetLight( a_LightBuffer, a_X+1, a_Y, a_Z, MAX(GetLight( a_LightBuffer, a_X+1, a_Y, a_Z ), MAX(0,CurrentLight-a_Falloff) ) ); - SetLight( a_LightBuffer, a_X, a_Y-1, a_Z, MAX(GetLight( a_LightBuffer, a_X, a_Y-1, a_Z ), MAX(0,CurrentLight-a_Falloff) ) ); - SetLight( a_LightBuffer, a_X, a_Y+1, a_Z, MAX(GetLight( a_LightBuffer, a_X, a_Y+1, a_Z ), MAX(0,CurrentLight-a_Falloff) ) ); - SetLight( a_LightBuffer, a_X, a_Y, a_Z-1, MAX(GetLight( a_LightBuffer, a_X, a_Y, a_Z-1 ), MAX(0,CurrentLight-a_Falloff) ) ); - SetLight( a_LightBuffer, a_X, a_Y, a_Z+1, MAX(GetLight( a_LightBuffer, a_X, a_Y, a_Z+1 ), MAX(0,CurrentLight-a_Falloff) ) ); + unsigned char CurrentLight = GetNibble( a_LightBuffer, a_X, a_Y, a_Z ); + SetNibble( a_LightBuffer, a_X-1, a_Y, a_Z, MAX(GetNibble( a_LightBuffer, a_X-1, a_Y, a_Z ), MAX(0,CurrentLight-a_Falloff) ) ); + SetNibble( a_LightBuffer, a_X+1, a_Y, a_Z, MAX(GetNibble( a_LightBuffer, a_X+1, a_Y, a_Z ), MAX(0,CurrentLight-a_Falloff) ) ); + SetNibble( a_LightBuffer, a_X, a_Y-1, a_Z, MAX(GetNibble( a_LightBuffer, a_X, a_Y-1, a_Z ), MAX(0,CurrentLight-a_Falloff) ) ); + SetNibble( a_LightBuffer, a_X, a_Y+1, a_Z, MAX(GetNibble( a_LightBuffer, a_X, a_Y+1, a_Z ), MAX(0,CurrentLight-a_Falloff) ) ); + SetNibble( a_LightBuffer, a_X, a_Y, a_Z-1, MAX(GetNibble( a_LightBuffer, a_X, a_Y, a_Z-1 ), MAX(0,CurrentLight-a_Falloff) ) ); + SetNibble( a_LightBuffer, a_X, a_Y, a_Z+1, MAX(GetNibble( a_LightBuffer, a_X, a_Y, a_Z+1 ), MAX(0,CurrentLight-a_Falloff) ) ); + MarkDirty(); } @@ -121,9 +120,10 @@ void cChunk::SpreadLightOfBlock(char* a_LightBuffer, int a_X, int a_Y, int a_Z, __C_CHUNK_INLINE__ void cChunk::SpreadLightOfBlockX(char* a_LightBuffer, int a_X, int a_Y, int a_Z) { - unsigned char CurrentLight = GetLight( a_LightBuffer, a_X, a_Y, a_Z ); - SetLight( a_LightBuffer, a_X-1, a_Y, a_Z, MAX(GetLight( a_LightBuffer, a_X-1, a_Y, a_Z ), CurrentLight-1) ); - SetLight( a_LightBuffer, a_X+1, a_Y, a_Z, MAX(GetLight( a_LightBuffer, a_X+1, a_Y, a_Z ), CurrentLight-1) ); + unsigned char CurrentLight = GetNibble( a_LightBuffer, a_X, a_Y, a_Z ); + SetNibble( a_LightBuffer, a_X-1, a_Y, a_Z, MAX(GetNibble( a_LightBuffer, a_X-1, a_Y, a_Z ), CurrentLight-1) ); + SetNibble( a_LightBuffer, a_X+1, a_Y, a_Z, MAX(GetNibble( a_LightBuffer, a_X+1, a_Y, a_Z ), CurrentLight-1) ); + MarkDirty(); } @@ -133,9 +133,10 @@ void cChunk::SpreadLightOfBlockX(char* a_LightBuffer, int a_X, int a_Y, int a_Z) __C_CHUNK_INLINE__ void cChunk::SpreadLightOfBlockY(char* a_LightBuffer, int a_X, int a_Y, int a_Z) { - unsigned char CurrentLight = GetLight( a_LightBuffer, a_X, a_Y, a_Z ); - SetLight( a_LightBuffer, a_X, a_Y-1, a_Z, MAX(GetLight( a_LightBuffer, a_X, a_Y-1, a_Z ), CurrentLight-1) ); - SetLight( a_LightBuffer, a_X, a_Y+1, a_Z, MAX(GetLight( a_LightBuffer, a_X, a_Y+1, a_Z ), CurrentLight-1) ); + unsigned char CurrentLight = GetNibble( a_LightBuffer, a_X, a_Y, a_Z ); + SetNibble( a_LightBuffer, a_X, a_Y-1, a_Z, MAX(GetNibble( a_LightBuffer, a_X, a_Y-1, a_Z ), CurrentLight-1) ); + SetNibble( a_LightBuffer, a_X, a_Y+1, a_Z, MAX(GetNibble( a_LightBuffer, a_X, a_Y+1, a_Z ), CurrentLight-1) ); + MarkDirty(); } @@ -145,9 +146,10 @@ void cChunk::SpreadLightOfBlockY(char* a_LightBuffer, int a_X, int a_Y, int a_Z) __C_CHUNK_INLINE__ void cChunk::SpreadLightOfBlockZ(char* a_LightBuffer, int a_X, int a_Y, int a_Z) { - unsigned char CurrentLight = GetLight( a_LightBuffer, a_X, a_Y, a_Z ); - SetLight( a_LightBuffer, a_X, a_Y, a_Z-1, MAX(GetLight( a_LightBuffer, a_X, a_Y, a_Z-1 ), CurrentLight-1) ); - SetLight( a_LightBuffer, a_X, a_Y, a_Z+1, MAX(GetLight( a_LightBuffer, a_X, a_Y, a_Z+1 ), CurrentLight-1) ); + unsigned char CurrentLight = GetNibble( a_LightBuffer, a_X, a_Y, a_Z ); + SetNibble( a_LightBuffer, a_X, a_Y, a_Z-1, MAX(GetNibble( a_LightBuffer, a_X, a_Y, a_Z-1 ), CurrentLight-1) ); + SetNibble( a_LightBuffer, a_X, a_Y, a_Z+1, MAX(GetNibble( a_LightBuffer, a_X, a_Y, a_Z+1 ), CurrentLight-1) ); + MarkDirty(); } diff --git a/source/cChunkMap.cpp b/source/cChunkMap.cpp index 0f0cc03a4..beccaefb1 100644 --- a/source/cChunkMap.cpp +++ b/source/cChunkMap.cpp @@ -343,6 +343,22 @@ bool cChunkMap::GetChunkBlocks(int a_ChunkX, int a_ChunkY, int a_ChunkZ, char * +bool cChunkMap::GetChunkBlockData(int a_ChunkX, int a_ChunkY, int a_ChunkZ, char * a_BlockData) +{ + cCSLock Lock(m_CSLayers); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ); + if ((Chunk == NULL) || !Chunk->IsValid()) + { + return false; + } + Chunk->GetBlockData(a_BlockData); + return true; +} + + + + + bool cChunkMap::IsChunkValid(int a_ChunkX, int a_ChunkY, int a_ChunkZ) { cCSLock Lock(m_CSLayers); @@ -469,14 +485,17 @@ void cChunkMap::CollectPickupsByPlayer(cPlayer * a_Player) int OtherChunkX = ChunkX + ((BlockX > 8) ? 1 : -1); int OtherChunkZ = ChunkZ + ((BlockZ > 8) ? 1 : -1); + // We suppose that each player keeps their chunks in memory, therefore it makes little sense to try to re-load or even generate them. + // The only time the chunks are not valid is when the player is downloading the initial world and they should not call this at that moment + cCSLock Lock(m_CSLayers); - GetChunkNoGen(ChunkX, ChunkY, ChunkZ)->CollectPickupsByPlayer(a_Player); + GetChunkNoLoad(ChunkX, ChunkY, ChunkZ)->CollectPickupsByPlayer(a_Player); // Check the neighboring chunks as well: - GetChunkNoGen(OtherChunkX, ChunkY, ChunkZ )->CollectPickupsByPlayer(a_Player); - GetChunkNoGen(OtherChunkX, ChunkY, OtherChunkZ)->CollectPickupsByPlayer(a_Player); - GetChunkNoGen(ChunkX, ChunkY, ChunkZ )->CollectPickupsByPlayer(a_Player); - GetChunkNoGen(ChunkX, ChunkY, OtherChunkZ)->CollectPickupsByPlayer(a_Player); + GetChunkNoLoad(OtherChunkX, ChunkY, ChunkZ )->CollectPickupsByPlayer(a_Player); + GetChunkNoLoad(OtherChunkX, ChunkY, OtherChunkZ)->CollectPickupsByPlayer(a_Player); + GetChunkNoLoad(ChunkX, ChunkY, ChunkZ )->CollectPickupsByPlayer(a_Player); + GetChunkNoLoad(ChunkX, ChunkY, OtherChunkZ)->CollectPickupsByPlayer(a_Player); } @@ -511,7 +530,7 @@ char cChunkMap::GetBlockMeta(int a_X, int a_Y, int a_Z) if ((Chunk != NULL) && Chunk->IsValid() ) { // Although it is called GetLight(), it actually gets meta when passed the Meta field - return Chunk->GetLight( Chunk->pGetMeta(), a_X, a_Y, a_Z ); + return cChunk::GetNibble( Chunk->pGetMeta(), a_X, a_Y, a_Z ); } return 0; } @@ -529,8 +548,8 @@ void cChunkMap::SetBlockMeta(int a_X, int a_Y, int a_Z, char a_BlockMeta) 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 ); + cChunk::SetNibble( Chunk->pGetMeta(), a_X, a_Y, a_Z, a_BlockMeta ); + Chunk->MarkDirty(); Chunk->SendBlockTo( a_X, a_Y, a_Z, NULL ); } } @@ -706,22 +725,6 @@ 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); - if ((Chunk == NULL) || !Chunk->IsValid()) - { - return false; - } - Chunk->SendTo(a_Client); - return true; -} - - - - - void cChunkMap::MoveEntityToChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkY, int a_ChunkZ) { cCSLock Lock(m_CSLayers); diff --git a/source/cChunkMap.h b/source/cChunkMap.h index 32ae4da6e..f5a750f87 100644 --- a/source/cChunkMap.h +++ b/source/cChunkMap.h @@ -45,7 +45,13 @@ public: void ChunkDataLoaded (int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities); void ChunkDataGenerated (int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities); void GetChunkData (int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkDataCallback * a_Callback); + + /// Gets the chunk's blocks, only the block types bool GetChunkBlocks (int a_ChunkX, int a_ChunkY, int a_ChunkZ, char * a_Blocks); + + /// Gets the chunk's blockdata, the entire array + bool GetChunkBlockData (int a_ChunkX, int a_ChunkY, int a_ChunkZ, char * a_BlockData); + bool IsChunkValid (int a_ChunkX, int a_ChunkY, int a_ChunkZ); bool HasChunkAnyClients (int a_ChunkX, int a_ChunkY, int a_ChunkZ); void SpreadChunkLighting(int a_ChunkX, int a_ChunkY, int a_ChunkZ); @@ -71,9 +77,6 @@ public: /// 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); - /// 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); diff --git a/source/cClientHandle.cpp b/source/cClientHandle.cpp index f27ca9e61..9ea063f11 100644 --- a/source/cClientHandle.cpp +++ b/source/cClientHandle.cpp @@ -1681,35 +1681,6 @@ void cClientHandle::Tick(float a_Dt) Send(Ping); m_LastPingTime = m_PingStartTime; } - - if (m_State >= csDownloadingWorld) - { - cWorld * World = m_Player->GetWorld(); - - cCSLock Lock(m_CSChunkLists); - - // Send the chunks: - int NumSent = 0; - for (cChunkCoordsList::iterator itr = m_ChunksToSend.begin(); itr != m_ChunksToSend.end();) - { - if (!World->SendChunkTo(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ, this)) - { - ++itr; - continue; - } - itr = m_ChunksToSend.erase(itr); - NumSent++; - if (NumSent > 10) - { - // Only send up to 10 chunks per tick, otherwise we'd choke the tick thread - break; - } - } // for itr - m_ChunksToSend[] - Lock.Unlock(); - - // Check even if we didn't send anything - a chunk may have sent a notification that we'd miss otherwise - CheckIfWorldDownloaded(); - } } @@ -1737,20 +1708,38 @@ void cClientHandle::Send(const cPacket * a_Packet, ENUM_PRIORITY a_Priority /* = case E_PLAYERMOVELOOK: case E_KEEP_ALIVE: case E_PRE_CHUNK: + case E_MAP_CHUNK: { // Allow break; } - case E_MAP_CHUNK: - { - CheckIfWorldDownloaded(); - break; - } - default: return; } } + // Check chunks being sent, erase them from m_ChunksToSend: + if (a_Packet->m_PacketID == E_MAP_CHUNK) + { + #if (MINECRAFT_1_2_2 == 1) + int ChunkX = ((cPacket_MapChunk *)a_Packet)->m_PosX; + int ChunkZ = ((cPacket_MapChunk *)a_Packet)->m_PosZ; + #else + int ChunkX = ((cPacket_MapChunk *)a_Packet)->m_PosX / cChunk::c_ChunkWidth; + int ChunkZ = ((cPacket_MapChunk *)a_Packet)->m_PosZ / cChunk::c_ChunkWidth; + #endif + cCSLock Lock(m_CSChunkLists); + for (cChunkCoordsList::iterator itr = m_ChunksToSend.begin(); itr != m_ChunksToSend.end(); ++itr) + { + if ((itr->m_ChunkX == ChunkX) && (itr->m_ChunkZ == ChunkZ)) + { + m_ChunksToSend.erase(itr); + CheckIfWorldDownloaded(); + break; + } + } // for itr - m_ChunksToSend[] + } + + // Optimize away multiple queued RelativeEntityMoveLook packets: cCSLock Lock(m_CSPackets); if (a_Priority == E_PRIORITY_NORMAL) { diff --git a/source/cClientHandle.h b/source/cClientHandle.h index 3fcfef716..6ac6e07b8 100644 --- a/source/cClientHandle.h +++ b/source/cClientHandle.h @@ -94,6 +94,8 @@ public: bool IsDestroyed() { return m_bDestroyed; } void Destroy(); + + bool IsPlaying(void) const {return (m_State == csPlaying); } void Send(const cPacket & a_Packet, ENUM_PRIORITY a_Priority = E_PRIORITY_NORMAL) { Send(&a_Packet, a_Priority); } void Send(const cPacket * a_Packet, ENUM_PRIORITY a_Priority = E_PRIORITY_NORMAL); diff --git a/source/cPlayer.cpp b/source/cPlayer.cpp index f013465de..673d0b41a 100644 --- a/source/cPlayer.cpp +++ b/source/cPlayer.cpp @@ -177,6 +177,12 @@ cPacket * cPlayer::GetSpawnPacket(void) const void cPlayer::Tick(float a_Dt) { + if (!m_ClientHandle->IsPlaying()) + { + // We're not yet in the game, ignore everything + return; + } + cPawn::Tick(a_Dt); if (m_bDirtyOrientation && !m_bDirtyPosition) @@ -233,7 +239,7 @@ void cPlayer::Tick(float a_Dt) m_ClientHandle->StreamChunks(); } - if ( m_Health > 0 ) // make sure player is alive + if (m_Health > 0) // make sure player is alive { m_World->CollectPickupsByPlayer(this); } diff --git a/source/cSignEntity.cpp b/source/cSignEntity.cpp index c181deae2..3f0befc3f 100644 --- a/source/cSignEntity.cpp +++ b/source/cSignEntity.cpp @@ -81,25 +81,17 @@ AString cSignEntity::GetLine( int a_Index ) const -void cSignEntity::SendTo( cClientHandle* a_Client ) +cPacket * cSignEntity::GetPacket(void) { - cPacket_UpdateSign Sign; - Sign.m_PosX = m_PosX; - Sign.m_PosY = (short)m_PosY; - Sign.m_PosZ = m_PosZ; - Sign.m_Line1 = m_Line[0]; - Sign.m_Line2 = m_Line[1]; - Sign.m_Line3 = m_Line[2]; - Sign.m_Line4 = m_Line[3]; - - if ( a_Client != NULL ) - { - a_Client->Send( Sign ); - } - else // broadcast of a_Client == 0 - { - m_World->BroadcastToChunkOfBlock(m_PosX, m_PosY, m_PosZ, &Sign ); - } + cPacket_UpdateSign * Sign = new cPacket_UpdateSign; + Sign->m_PosX = m_PosX; + Sign->m_PosY = (short)m_PosY; + Sign->m_PosZ = m_PosZ; + Sign->m_Line1 = m_Line[0]; + Sign->m_Line2 = m_Line[1]; + Sign->m_Line3 = m_Line[2]; + Sign->m_Line4 = m_Line[3]; + return Sign; } diff --git a/source/cSignEntity.h b/source/cSignEntity.h index bc45e5ff4..5d9d11a9c 100644 --- a/source/cSignEntity.h +++ b/source/cSignEntity.h @@ -34,7 +34,8 @@ public: AString GetLine( int a_Index ) const; virtual void UsedBy( cPlayer * a_Player ) override; - virtual void SendTo( cClientHandle* a_Client ) override; + + virtual cPacket * GetPacket(void) override; private: diff --git a/source/cWorld.cpp b/source/cWorld.cpp index 2b0f4ab2b..daf34d8f1 100644 --- a/source/cWorld.cpp +++ b/source/cWorld.cpp @@ -238,6 +238,8 @@ cWorld::cWorld( const AString & a_WorldName ) } m_ChunkMap = new cChunkMap(this ); + + m_ChunkSender.Start(this); m_Time = 0; m_WorldTimeFraction = 0.f; @@ -975,6 +977,7 @@ void cWorld::MarkChunkSaved (int a_ChunkX, int a_ChunkY, int a_ChunkZ) void cWorld::ChunkDataLoaded(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities) { m_ChunkMap->ChunkDataLoaded(a_ChunkX, a_ChunkY, a_ChunkZ, a_BlockData, a_Entities, a_BlockEntities); + m_ChunkSender.ChunkReady(a_ChunkX, a_ChunkY, a_ChunkZ); } @@ -984,6 +987,7 @@ void cWorld::ChunkDataLoaded(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const cha void cWorld::ChunkDataGenerated(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities) { m_ChunkMap->ChunkDataGenerated(a_ChunkX, a_ChunkY, a_ChunkZ, a_BlockData, a_Entities, a_BlockEntities); + m_ChunkSender.ChunkReady(a_ChunkX, a_ChunkY, a_ChunkZ); } @@ -1008,6 +1012,15 @@ bool cWorld::GetChunkBlocks(int a_ChunkX, int a_ChunkY, int a_ChunkZ, char * a_B +bool cWorld::GetChunkBlockData(int a_ChunkX, int a_ChunkY, int a_ChunkZ, char * a_BlockData) +{ + return m_ChunkMap->GetChunkBlockData(a_ChunkX, a_ChunkY, a_ChunkZ, a_BlockData); +} + + + + + bool cWorld::IsChunkValid(int a_ChunkX, int a_ChunkY, int a_ChunkZ) const { return m_ChunkMap->IsChunkValid(a_ChunkX, a_ChunkY, a_ChunkZ); @@ -1279,15 +1292,6 @@ void cWorld::RemoveClientFromChunks(cClientHandle * a_Client, const cChunkCoords -bool cWorld::SendChunkTo(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client) -{ - return m_ChunkMap->SendChunkTo(a_ChunkX, a_ChunkY, a_ChunkZ, a_Client); -} - - - - - void cWorld::TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) { m_ChunkMap->TouchChunk(a_ChunkX, a_ChunkY, a_ChunkZ); diff --git a/source/cWorld.h b/source/cWorld.h index 60b393ab8..e4fac9d90 100644 --- a/source/cWorld.h +++ b/source/cWorld.h @@ -15,6 +15,7 @@ #include "WorldStorage.h" #include "cChunkGenerator.h" #include "Vector3i.h" +#include "ChunkSender.h" @@ -71,7 +72,13 @@ public: void ChunkDataLoaded (int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities); void ChunkDataGenerated(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities); void GetChunkData (int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkDataCallback * a_Callback); + + /// Gets the chunk's blocks, only the block types bool GetChunkBlocks (int a_ChunkX, int a_ChunkY, int a_ChunkZ, char * a_Blocks); + + /// Gets the chunk's blockdata, the entire array + bool GetChunkBlockData (int a_ChunkX, int a_ChunkY, int a_ChunkZ, char * a_BlockData); + bool IsChunkValid (int a_ChunkX, int a_ChunkY, int a_ChunkZ) const; bool HasChunkAnyClients(int a_ChunkX, int a_ChunkY, int a_ChunkZ) const; void UnloadUnusedChunks(void); @@ -123,9 +130,6 @@ public: /// 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); @@ -284,6 +288,8 @@ private: sSetBlockList m_FastSetBlockQueue; cChunkGenerator m_Generator; + + cChunkSender m_ChunkSender; AString m_WorldName; diff --git a/source/packets/cPacket_MapChunk.cpp b/source/packets/cPacket_MapChunk.cpp index d602007e3..6fdd73f12 100644 --- a/source/packets/cPacket_MapChunk.cpp +++ b/source/packets/cPacket_MapChunk.cpp @@ -19,16 +19,15 @@ cPacket_MapChunk::~cPacket_MapChunk() -cPacket_MapChunk::cPacket_MapChunk(cChunk * a_Chunk) +cPacket_MapChunk::cPacket_MapChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, char * a_BlockData) { - ASSERT(a_Chunk->IsValid()); m_PacketID = E_MAP_CHUNK; #if (MINECRAFT_1_2_2 == 1 ) // ... - m_PosX = a_Chunk->GetPosX(); // Chunk coordinates now, instead of block coordinates - m_PosZ = a_Chunk->GetPosZ(); + m_PosX = a_ChunkX; // Chunk coordinates now, instead of block coordinates + m_PosZ = a_ChunkZ; m_bContiguous = false; m_BitMap1 = 0; @@ -37,52 +36,59 @@ cPacket_MapChunk::cPacket_MapChunk(cChunk * a_Chunk) m_UnusedInt = 0; - unsigned int DataSize = (cChunk::c_ChunkHeight/16) * (4096 + 2048 + 2048 + 2048); - char* AllData = new char[ DataSize ]; - memset( AllData, 0, DataSize ); + unsigned int DataSize = (cChunk::c_ChunkHeight / 16) * (4096 + 2048 + 2048 + 2048); + std::auto_ptr AllData(new char[ DataSize ]); + memset( AllData.get(), 0, DataSize ); unsigned int iterator = 0; - for( int i = 0; i < (cChunk::c_ChunkHeight/16); ++i ) // Old world is only 8*16 high (should be 16*16) + for ( int i = 0; i < (cChunk::c_ChunkHeight / 16); ++i ) { m_BitMap1 |= (1 << i); // This tells what chunks are sent. Use this to NOT send air only chunks (right now everything is sent) - for( int y = 0; y < 16; ++y ) for( int z = 0; z < 16; ++z ) for( int x = 0; x < 16; ++x ) + for ( int y = 0; y < 16; ++y ) for( int z = 0; z < 16; ++z ) for( int x = 0; x < 16; ++x ) { - AllData[iterator] = a_Chunk->GetBlock( x, y+i*16, z ); + int idx = cChunk::MakeIndex(x, y + i * 16, z); + AllData.get()[iterator] = a_BlockData[idx]; ++iterator; - } + } // for y, z, x } - //Send block metadata - for( int i = 0; i < (cChunk::c_ChunkHeight/16); ++i ) + + // Send block metadata: + char * Meta = a_BlockData + cChunk::c_NumBlocks; + for ( int i = 0; i < (cChunk::c_ChunkHeight / 16); ++i ) { - for( int y = 0; y < 16; ++y ) for( int z = 0; z < 16; ++z ) + for ( int y = 0; y < 16; ++y ) for( int z = 0; z < 16; ++z ) { - for( int x = 0; x < 8; ++x ) + for ( int x = 0; x < 8; ++x ) { - AllData[iterator] = a_Chunk->GetLight( a_Chunk->pGetMeta(), x*2+0, y+i*16, z ) | a_Chunk->GetLight( a_Chunk->pGetMeta(), x*2+1, y+i*16, z ) << 4; + AllData.get()[iterator] = cChunk::GetNibble(Meta, x * 2 + 0, y + i * 16, z) | (cChunk::GetNibble(Meta, x * 2 + 1, y + i * 16, z ) << 4); + ++iterator; + } // for x + } // for y, z + } + + // Send block light: + char * Light = Meta + cChunk::c_NumBlocks / 2; + for ( int i = 0; i < (cChunk::c_ChunkHeight / 16); ++i ) + { + for ( int y = 0; y < 16; ++y ) for( int z = 0; z < 16; ++z ) + { + for ( int x = 0; x < 8; ++x ) + { + AllData.get()[iterator] = cChunk::GetNibble(Light, x * 2 + 0, y + i * 16, z ) | (cChunk::GetNibble(Light, x * 2 + 1, y + i * 16, z ) << 4); ++iterator; } } } - //Send block light + + // Send sky light: + char * SkyLight = Light + cChunk::c_NumBlocks / 2; for( int i = 0; i < (cChunk::c_ChunkHeight/16); ++i ) { for( int y = 0; y < 16; ++y ) for( int z = 0; z < 16; ++z ) { for( int x = 0; x < 8; ++x ) { - AllData[iterator] = a_Chunk->GetLight( a_Chunk->pGetLight(), x*2+0, y+i*16, z ) | a_Chunk->GetLight( a_Chunk->pGetLight(), x*2+1, y+i*16, z ) << 4; - ++iterator; - } - } - } - //Send sky light - for( int i = 0; i < (cChunk::c_ChunkHeight/16); ++i ) - { - for( int y = 0; y < 16; ++y ) for( int z = 0; z < 16; ++z ) - { - for( int x = 0; x < 8; ++x ) - { - AllData[iterator] = a_Chunk->GetLight( a_Chunk->pGetSkyLight(), x*2+0, y+i*16, z ) | a_Chunk->GetLight( a_Chunk->pGetSkyLight(), x*2+1, y+i*16, z ) << 4; + AllData.get()[iterator] = cChunk::GetNibble(SkyLight, x * 2 + 0, y + i * 16, z ) | (cChunk::GetNibble(SkyLight, x * 2 + 1, y + i * 16, z ) << 4); ++iterator; } } @@ -91,17 +97,15 @@ cPacket_MapChunk::cPacket_MapChunk(cChunk * a_Chunk) uLongf CompressedSize = compressBound( DataSize ); char * CompressedBlockData = new char[CompressedSize]; - compress2( (Bytef*)CompressedBlockData, &CompressedSize, (const Bytef*)AllData, DataSize, Z_DEFAULT_COMPRESSION); - - delete [] AllData; + compress2( (Bytef*)CompressedBlockData, &CompressedSize, (const Bytef*)AllData.get(), DataSize, Z_DEFAULT_COMPRESSION); m_CompressedData = CompressedBlockData; m_CompressedSize = CompressedSize; #else - m_PosX = a_Chunk->GetPosX() * cChunk::c_ChunkWidth; // It has to be block coordinates - m_PosY = (short)(a_Chunk->GetPosY() * cChunk::c_ChunkHeight); - m_PosZ = a_Chunk->GetPosZ() * cChunk::c_ChunkWidth; + m_PosX = a_ChunkX * cChunk::c_ChunkWidth; // It has to be block coordinates + m_PosY = (short)(a_ChunkY * cChunk::c_ChunkHeight); + m_PosZ = a_ChunkZ * cChunk::c_ChunkWidth; m_SizeX = 15; m_SizeY = 127; @@ -110,7 +114,7 @@ cPacket_MapChunk::cPacket_MapChunk(cChunk * a_Chunk) uLongf CompressedSize = compressBound( cChunk::c_BlockDataSize ); char * CompressedBlockData = new char[CompressedSize]; - compress2( (Bytef*)CompressedBlockData, &CompressedSize, (const Bytef*)a_Chunk->pGetBlockData(), cChunk::c_BlockDataSize, Z_DEFAULT_COMPRESSION); + compress2( (Bytef*)CompressedBlockData, &CompressedSize, (const Bytef*)a_BlockData, cChunk::c_BlockDataSize, Z_DEFAULT_COMPRESSION); m_CompressedData = CompressedBlockData; m_CompressedSize = CompressedSize; diff --git a/source/packets/cPacket_MapChunk.h b/source/packets/cPacket_MapChunk.h index 72cef7d25..db4192457 100644 --- a/source/packets/cPacket_MapChunk.h +++ b/source/packets/cPacket_MapChunk.h @@ -7,12 +7,6 @@ -class cChunk; - - - - - class cPacket_MapChunk : public cPacket { @@ -39,6 +33,7 @@ public: { m_PacketID = E_MAP_CHUNK; m_CompressedData = 0; } cPacket_MapChunk( const cPacket_MapChunk & a_Copy ); + cPacket_MapChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, char * a_BlockData); ~cPacket_MapChunk(); virtual cPacket* Clone() const { return new cPacket_MapChunk(*this); } @@ -66,12 +61,6 @@ public: char * m_CompressedData; - -protected: - friend class cChunk; - - cPacket_MapChunk(cChunk * a_Chunk); // Called only from within cChunk, therefore it CAN receive a direct pointer - };