1
0

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
This commit is contained in:
madmaxoft@gmail.com 2012-03-05 16:41:57 +00:00
parent a655d7fdae
commit 4d65ffffc0
21 changed files with 473 additions and 237 deletions

View File

@ -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"
>
</File>
<File
RelativePath="..\source\ChunkSender.cpp"
>
</File>
<File
RelativePath="..\source\ChunkSender.h"
>
</File>
<File
RelativePath="..\source\cInventory.cpp"
>

View File

@ -329,6 +329,7 @@
<ClCompile Include="..\Source\cGroup.cpp" />
<ClCompile Include="..\Source\cGroupManager.cpp" />
<ClCompile Include="..\Source\cHeartBeat.cpp" />
<ClCompile Include="..\source\ChunkSender.cpp" />
<ClCompile Include="..\source\cIsThread.cpp" />
<ClCompile Include="..\source\cItem.cpp" />
<ClCompile Include="..\source\cLavaSimulator.cpp" />
@ -513,6 +514,7 @@
<ClInclude Include="..\Source\cGroup.h" />
<ClInclude Include="..\Source\cGroupManager.h" />
<ClInclude Include="..\Source\cHeartBeat.h" />
<ClInclude Include="..\source\ChunkSender.h" />
<ClInclude Include="..\source\cIsThread.h" />
<ClInclude Include="..\Source\cLadder.h" />
<ClInclude Include="..\source\cLavaSimulator.h" />

View File

@ -918,6 +918,7 @@
<ClCompile Include="..\source\cRedstoneSimulator.cpp">
<Filter>Simulator\cSimulator\cRedstoneSimulator</Filter>
</ClCompile>
<ClCompile Include="..\source\ChunkSender.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\source\cServer.h">
@ -1417,6 +1418,7 @@
<ClInclude Include="..\source\cRedstoneSimulator.h">
<Filter>Simulator\cSimulator\cRedstoneSimulator</Filter>
</ClInclude>
<ClInclude Include="..\source\ChunkSender.h" />
</ItemGroup>
<ItemGroup>
<None Include="..\source\AllToLua.pkg">

133
source/ChunkSender.cpp Normal file
View File

@ -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 ;)
}

63
source/ChunkSender.h Normal file
View File

@ -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;
} ;

View File

@ -144,4 +144,11 @@ public:
#define MINECRAFT_1_2_2 (1)
// 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

View File

@ -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<cPacket> 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

View File

@ -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;

View File

@ -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 );

View File

@ -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();
}

View File

@ -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);

View File

@ -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);

View File

@ -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)
{

View File

@ -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);

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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:

View File

@ -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);

View File

@ -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;

View File

@ -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<char> 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;

View File

@ -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
};