diff --git a/VC2010/JsonCpp.vcxproj b/VC2010/JsonCpp.vcxproj index 7e92d3e51..b467336f2 100644 --- a/VC2010/JsonCpp.vcxproj +++ b/VC2010/JsonCpp.vcxproj @@ -18,13 +18,11 @@ StaticLibrary true - MultiByte StaticLibrary false true - MultiByte @@ -36,12 +34,18 @@ - + + $(Configuration)\$(ProjectName)\ + + + $(Configuration)\$(ProjectName)\ + Level3 Disabled ..\jsoncpp-src-0.5.0\include;%(AdditionalIncludeDirectories) + true true @@ -56,6 +60,7 @@ ..\jsoncpp-src-0.5.0\include;%(AdditionalIncludeDirectories) MultiThreaded Speed + true true diff --git a/VC2010/MCServer.vcxproj b/VC2010/MCServer.vcxproj index e36f5eaa8..a7728ea4f 100644 --- a/VC2010/MCServer.vcxproj +++ b/VC2010/MCServer.vcxproj @@ -27,8 +27,7 @@ Application - NotSet - false + true Application @@ -37,7 +36,6 @@ Application - NotSet Application @@ -63,13 +61,13 @@ <_ProjectFileVersion>10.0.30319.1 $(SolutionDir)..\ $(SolutionDir)..\ - $(Configuration)\ + $(Configuration)\$(ProjectName)\ $(Configuration)\ true true $(SolutionDir)..\ $(SolutionDir)..\ - $(Configuration)\ + $(Configuration)\$(ProjectName)\ $(Configuration)\ false false @@ -80,21 +78,18 @@ Disabled ..\tolua++-1.0.93\include;..\lua-5.1.4\src;..\zlib-1.2.5;..\mysql-connector\include;..\source\;..\pdcurs34\;..\jsoncpp-src-0.5.0\include;..\squirrel_3_0_1_stable\include;..\squirrel_3_0_1_stable;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - false + true Sync EnableFastChecks MultiThreadedDebugDLL true - StreamingSIMDExtensions2 - Fast - - Level3 - ProgramDatabase + EditAndContinue + true /IGNORE:4078 %(AdditionalOptions) - winmm.lib;ws2_32.lib;Psapi.lib;ZLib.lib;tolua++-1.0.93.lib;lua-5.1.4.lib;WebServer.lib;JsonCpp.lib;squirrel_3_0_1_stable.lib;%(AdditionalDependencies) + winmm.lib;ws2_32.lib;Psapi.lib;%(AdditionalDependencies) ../$(ProjectName)_debug.exe VLD;./Debug/;%(AdditionalLibraryDirectories) %(IgnoreSpecificDefaultLibraries) @@ -159,10 +154,11 @@ true + true /IGNORE:4078 %(AdditionalOptions) - winmm.lib;ws2_32.lib;Psapi.lib;ZLib.lib;tolua++-1.0.93.lib;lua-5.1.4.lib;WebServer.lib;JsonCpp.lib;squirrel_3_0_1_stable.lib;LIBCMT.LIB;%(AdditionalDependencies) + winmm.lib;ws2_32.lib;Psapi.lib;LIBCMT.LIB;%(AdditionalDependencies) ../$(ProjectName).exe ./Release/;%(AdditionalLibraryDirectories) LIBCMT;%(IgnoreSpecificDefaultLibraries) @@ -170,8 +166,7 @@ Console false true - - + UseLinkTimeCodeGeneration false @@ -223,6 +218,7 @@ + @@ -360,6 +356,7 @@ + @@ -510,26 +507,25 @@ + + {adbf25b9-7192-4e54-b35e-8ec47ca5ef86} + {5e511191-6f1f-4d0d-940a-b850780963d2} - false + + + {4571ce2d-9e18-452f-90d6-94ae8e2406f4} {67b50249-6cec-444e-a87a-d476112590ed} - false + + + {2b4bd5c6-91c0-4a74-939f-b28737fb0dc6} {f6f43a78-816d-4c37-a07b-68bed529273a} - false - - - - - - - diff --git a/VC2010/MCServer.vcxproj.filters b/VC2010/MCServer.vcxproj.filters index d817d7679..a6e3af736 100644 --- a/VC2010/MCServer.vcxproj.filters +++ b/VC2010/MCServer.vcxproj.filters @@ -400,6 +400,9 @@ {fcc08e08-8dba-47b4-89b0-5dc255bb9b8a} + + {0d6f822b-71eb-406f-b17a-d188c4924283} + @@ -802,6 +805,9 @@ Packets\cPacket_ItemData + + cChunkGenerator + @@ -1239,6 +1245,9 @@ Packets\cPacket_ItemData + + cChunkGenerator + diff --git a/VC2010/WebServer.vcxproj b/VC2010/WebServer.vcxproj index 934c3803d..03c84d620 100644 --- a/VC2010/WebServer.vcxproj +++ b/VC2010/WebServer.vcxproj @@ -26,7 +26,6 @@ StaticLibrary true - MultiByte StaticLibrary @@ -37,7 +36,6 @@ StaticLibrary false true - MultiByte StaticLibrary @@ -61,11 +59,15 @@ - + + $(Configuration)\$(ProjectName)\ + $(SolutionDir) - + + $(Configuration)\$(ProjectName)\ + $(SolutionDir) @@ -73,6 +75,7 @@ Level3 Disabled + true true @@ -99,6 +102,7 @@ true MultiThreaded Speed + true true diff --git a/VC2010/ZLib.vcxproj b/VC2010/ZLib.vcxproj index fcc0538e1..f71a9eed5 100644 --- a/VC2010/ZLib.vcxproj +++ b/VC2010/ZLib.vcxproj @@ -25,7 +25,6 @@ StaticLibrary - MultiByte true @@ -35,7 +34,6 @@ StaticLibrary - MultiByte StaticLibrary @@ -63,6 +61,8 @@ $(Configuration)\ $(SolutionDir) $(Configuration)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ @@ -70,7 +70,9 @@ true EnableFastChecks MultiThreadedDebugDLL - Level3 + TurnOffAllWarnings + EditAndContinue + true @@ -92,8 +94,9 @@ true MultiThreaded true - Level3 + TurnOffAllWarnings Speed + true true @@ -114,7 +117,6 @@ - @@ -123,7 +125,6 @@ - diff --git a/VC2010/ZLib.vcxproj.filters b/VC2010/ZLib.vcxproj.filters index 7e5dc46b8..b79ce5cce 100644 --- a/VC2010/ZLib.vcxproj.filters +++ b/VC2010/ZLib.vcxproj.filters @@ -27,9 +27,6 @@ Source Files - - Source Files - Source Files @@ -54,9 +51,6 @@ Source Files - - Source Files - Source Files diff --git a/VC2010/clean.bat b/VC2010/clean.bat index c481e1d03..dfc7a6777 100644 --- a/VC2010/clean.bat +++ b/VC2010/clean.bat @@ -16,11 +16,10 @@ del release\*.* /Q del x64\*.* /Q del "My Inspector Results"\*.* /Q del ipch\*.* /Q -rd release /Q -rd debug /Q -rd ipch /Q +rd release /S /Q +rd debug /S /Q +rd ipch /S /Q rd x64 /Q rd "My Inspector Results" /Q -rd ipch /Q pause \ No newline at end of file diff --git a/VC2010/lua-5.1.4.vcxproj b/VC2010/lua-5.1.4.vcxproj index 503345c0e..d0aa832bf 100644 --- a/VC2010/lua-5.1.4.vcxproj +++ b/VC2010/lua-5.1.4.vcxproj @@ -25,7 +25,6 @@ StaticLibrary - MultiByte true @@ -35,7 +34,6 @@ StaticLibrary - MultiByte StaticLibrary @@ -63,15 +61,18 @@ $(Configuration)\ $(SolutionDir) $(Configuration)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ Disabled - true EnableFastChecks - Level3 + TurnOffAllWarnings EditAndContinue MultiThreadedDebugDLL + true + true @@ -93,9 +94,10 @@ true MultiThreaded true - Level3 + TurnOffAllWarnings ProgramDatabase Speed + true true diff --git a/VC2010/squirrel_3_0_1_stable.vcxproj b/VC2010/squirrel_3_0_1_stable.vcxproj index a9c919c03..92b9cc05b 100644 --- a/VC2010/squirrel_3_0_1_stable.vcxproj +++ b/VC2010/squirrel_3_0_1_stable.vcxproj @@ -18,13 +18,11 @@ StaticLibrary true - MultiByte StaticLibrary false true - MultiByte @@ -36,12 +34,18 @@ - + + $(Configuration)\$(ProjectName)\ + + + $(Configuration)\$(ProjectName)\ + - Level3 + TurnOffAllWarnings Disabled ../squirrel_3_0_1_stable/include + true true @@ -49,13 +53,14 @@ - Level3 + TurnOffAllWarnings MaxSpeed true true ../squirrel_3_0_1_stable/include Speed MultiThreaded + true true diff --git a/VC2010/tolua++-1.0.93.vcxproj b/VC2010/tolua++-1.0.93.vcxproj index 9fbec5d5d..3cac62db7 100644 --- a/VC2010/tolua++-1.0.93.vcxproj +++ b/VC2010/tolua++-1.0.93.vcxproj @@ -25,7 +25,6 @@ StaticLibrary - MultiByte true @@ -35,7 +34,6 @@ StaticLibrary - MultiByte StaticLibrary @@ -63,6 +61,8 @@ $(Configuration)\ $(SolutionDir) $(Configuration)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ @@ -71,8 +71,9 @@ true EnableFastChecks MultiThreadedDebugDLL - Level3 + TurnOffAllWarnings EditAndContinue + true @@ -96,9 +97,10 @@ ..\lua-5.1.4\src;..\tolua++-1.0.93\include;%(AdditionalIncludeDirectories) MultiThreaded true - Level3 + TurnOffAllWarnings ProgramDatabase Speed + true true diff --git a/source/cBlockToPickup.cpp b/source/cBlockToPickup.cpp index c653f5409..6e59e6573 100644 --- a/source/cBlockToPickup.cpp +++ b/source/cBlockToPickup.cpp @@ -24,9 +24,8 @@ ENUM_ITEM_ID cBlockToPickup::ToPickup( unsigned char a_BlockID, ENUM_ITEM_ID a_U if( a_UsedItemID == E_ITEM_SHEARS ) return E_ITEM_LEAVES; else - if(rand() % 5 == 0) - return E_ITEM_SAPLING; - return E_ITEM_EMPTY; + if(rand() % 5 == 0) return E_ITEM_SAPLING; + return E_ITEM_EMPTY; case E_BLOCK_COAL_ORE: return E_ITEM_COAL; case E_BLOCK_LAPIS_ORE: diff --git a/source/cChunk.cpp b/source/cChunk.cpp index 0fe192c0b..86107e1ef 100644 --- a/source/cChunk.cpp +++ b/source/cChunk.cpp @@ -69,6 +69,11 @@ struct cChunk::sChunkState cChunk::~cChunk() { //LOG("~cChunk() %i %i %i", m_PosX, m_PosY, m_PosZ ); + if( !m_pState->m_LoadedByClient.empty() ) + { + LOGWARN("WARNING: Deleting cChunk while it contains %i clients!", m_pState->m_LoadedByClient.size() ); + } + for( std::list::iterator itr = m_pState->m_BlockEntities.begin(); itr != m_pState->m_BlockEntities.end(); ++itr) { delete *itr; @@ -128,23 +133,17 @@ void cChunk::Initialize() // Clear memory memset( m_BlockData, 0x00, c_BlockDataSize ); -// LARGE_INTEGER TicksPerSecond; -// QueryPerformanceFrequency( &TicksPerSecond ); - GenerateTerrain(); - -// LARGE_INTEGER start; -// QueryPerformanceCounter( &start ); + GenerateFoliage(); CalculateHeightmap(); CalculateLighting(); -// LARGE_INTEGER end; -// QueryPerformanceCounter( &end ); -// double Time = double( end.QuadPart - start.QuadPart ) / double( TicksPerSecond.QuadPart / 1000 ); -// LOG("Calculated light in %f ms", Time ); - CreateBlockEntities(); + + // During generation, some blocks might have been set by using (Fast)SetBlock() causing this list to fill. + // This chunk has not been sent to anybody yet, so there is no need for separately sending block changes when you can send an entire chunk + m_pState->m_PendingSendBlocks.clear(); } else { @@ -218,7 +217,7 @@ void cChunk::Tick(float a_Dt) } std::map< unsigned int, int > ToTickBlocks = m_pState->m_ToTickBlocks; - unsigned int NumTickBlocks = ToTickBlocks.size(); + //unsigned int NumTickBlocks = ToTickBlocks.size(); //if( NumTickBlocks > 0 ) LOG("To tick: %i", NumTickBlocks ); m_pState->m_ToTickBlocks.clear(); bool isRedstone = false; @@ -740,7 +739,7 @@ float GetNoise( float x, float y, cNoise & a_Noise ) return (oct1 + oct2 + oct3) * flatness + height; } -#define PI_2 (1.57079633) +#define PI_2 (1.57079633f) float GetMarbleNoise( float x, float y, float z, cNoise & a_Noise ) { float oct1 = (a_Noise.CubicNoise3D( x*0.1f, y*0.1f, z*0.1f ))*4; @@ -769,7 +768,7 @@ void cChunk::GenerateTerrain() { - const ENUM_BLOCK_ID GrassID = E_BLOCK_GRASS; + //const ENUM_BLOCK_ID GrassID = E_BLOCK_GRASS; const ENUM_BLOCK_ID DirtID = E_BLOCK_DIRT; const ENUM_BLOCK_ID StoneID = E_BLOCK_STONE; const ENUM_BLOCK_ID SandID = E_BLOCK_SAND; @@ -859,6 +858,17 @@ void cChunk::GenerateTerrain() } } } +} + +void cChunk::GenerateFoliage() +{ + const ENUM_BLOCK_ID GrassID = E_BLOCK_GRASS; + const ENUM_BLOCK_ID DirtID = E_BLOCK_DIRT; + const ENUM_BLOCK_ID SandID = E_BLOCK_SAND; + const ENUM_BLOCK_ID SandStoneID = E_BLOCK_SANDSTONE; + const ENUM_BLOCK_ID CaveID = E_BLOCK_AIR; + + cNoise m_Noise( m_World->GetWorldSeed() ); for(int z = 0; z < 16; z++) for(int x = 0; x < 16; x++) { @@ -882,7 +892,7 @@ void cChunk::GenerateTerrain() int index3 = MakeIndex( x, TopY-3, z ); int index4 = MakeIndex( x, TopY-4, z ); int index5 = MakeIndex( x, TopY-5, z ); - + if( m_BlockType[index] == SandID ) { if( m_BlockType[index1] == CaveID ) { @@ -898,19 +908,19 @@ void cChunk::GenerateTerrain() } } - + if( m_BlockType[index] == DirtID ) { m_BlockType[ index ] = (char)GrassID; } - + // Plant sum trees { int xx = x + m_PosX*16; -// int yy = TopY; + // int yy = TopY; int zz = z + m_PosZ*16; - + float val1 = m_Noise.CubicNoise2D( xx*0.1f, zz*0.1f ); float val2 = m_Noise.CubicNoise2D( xx*0.01f, zz*0.01f ); if( m_BlockType[index] == SandID ) @@ -941,7 +951,7 @@ void cChunk::GenerateTerrain() m_BlockType[ MakeIndex(x, TopY+1, z) ] = E_BLOCK_BROWN_MUSHROOM; } } - + } } } @@ -1038,7 +1048,7 @@ void cChunk::FastSetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_B m_pState->m_PendingSendBlocks.push_back( index ); SetLight( m_BlockMeta, index, a_BlockMeta ); - // ONLY recalculate lighting if it's nessesary! + // ONLY recalculate lighting if it's necessary! if( g_BlockLightValue[ OldBlock ] != g_BlockLightValue[ a_BlockType ] || g_BlockSpreadLightFalloff[ OldBlock ] != g_BlockSpreadLightFalloff[ a_BlockType ] || g_BlockTransparent[ OldBlock ] != g_BlockTransparent[ a_BlockType ] ) diff --git a/source/cChunk.h b/source/cChunk.h index 9e117bb94..0145908f5 100644 --- a/source/cChunk.h +++ b/source/cChunk.h @@ -101,6 +101,7 @@ private: void SaveToJson( Json::Value & a_Value ); void GenerateTerrain(); + void GenerateFoliage(); void CalculateLighting(); // Recalculate right now void CalculateHeightmap(); void SpreadLightOfBlock(char* a_LightBuffer, int a_X, int a_Y, int a_Z, char a_Falloff); diff --git a/source/cChunkMap.cpp b/source/cChunkMap.cpp index 855318159..2f8339176 100644 --- a/source/cChunkMap.cpp +++ b/source/cChunkMap.cpp @@ -208,6 +208,8 @@ void cChunkMap::AddChunk( cChunk* a_Chunk ) const int LocalZ = a_Chunk->GetPosZ() - LayerZ * LAYER_SIZE; if( FoundLayer->m_Chunks[ LocalX + LocalZ * LAYER_SIZE ].m_LiveChunk ) LOGWARN("WARNING: Added chunk to layer while it was already loaded!"); + if( FoundLayer->m_Chunks[ LocalX + LocalZ * LAYER_SIZE ].m_Compressed ) + LOGWARN("WARNING: Added chunk to layer while a compressed version exists!"); FoundLayer->m_Chunks[ LocalX + LocalZ * LAYER_SIZE ].m_LiveChunk = a_Chunk; FoundLayer->m_NumChunksLoaded++; } diff --git a/source/cChunkMap.h b/source/cChunkMap.h index d1a289a7d..c728514e1 100644 --- a/source/cChunkMap.h +++ b/source/cChunkMap.h @@ -20,6 +20,8 @@ public: void UnloadUnusedChunks(); bool RemoveEntityFromChunk( cEntity & a_Entity, cChunk* a_CalledFrom = 0 ); void SaveAllChunks(); + + cWorld* GetWorld() { return m_World; } private: class cChunkData { diff --git a/source/cClientHandle.cpp b/source/cClientHandle.cpp index 548dafeb6..6725a2156 100644 --- a/source/cClientHandle.cpp +++ b/source/cClientHandle.cpp @@ -249,12 +249,19 @@ void cClientHandle::StreamChunks() int ChunkPosX = (int)floor(m_Player->GetPosX() / 16); int ChunkPosZ = (int)floor(m_Player->GetPosZ() / 16); - cChunk* NeededChunks[VIEWDISTANCE*VIEWDISTANCE]; - for(int x = 0; x < VIEWDISTANCE; x++) + cWorld* World = m_Player->GetWorld(); + + cChunk* NeededChunks[VIEWDISTANCE*VIEWDISTANCE] = { 0 }; + const int MaxDist = VIEWDISTANCE+GENERATEDISTANCE*2; + for(int x = 0; x < MaxDist; x++) { - for(int z = 0; z < VIEWDISTANCE; z++) + for(int z = 0; z < MaxDist; z++) { - NeededChunks[x + z*VIEWDISTANCE] = m_Player->GetWorld()->GetChunk( x + ChunkPosX-(VIEWDISTANCE-1)/2, 0, z + ChunkPosZ-(VIEWDISTANCE-1)/2 ); + int RelX = x - (MaxDist-1)/2; + int RelZ = z - (MaxDist-1)/2; + cChunk* Chunk = World->GetChunk( ChunkPosX + RelX, 0, ChunkPosZ + RelZ ); // Touch all chunks in wide range, so they get generated + if( x >= GENERATEDISTANCE && x < VIEWDISTANCE+GENERATEDISTANCE && z >= GENERATEDISTANCE && z < VIEWDISTANCE+GENERATEDISTANCE ) // but player only needs chunks in view distance + NeededChunks[(x-GENERATEDISTANCE) + (z-GENERATEDISTANCE)*VIEWDISTANCE] = Chunk; } } @@ -263,6 +270,9 @@ void cClientHandle::StreamChunks() unsigned int MissIndex = 0; for(int i = 0; i < VIEWDISTANCE*VIEWDISTANCE; i++) // Handshake loop - touch each chunk once { + if( NeededChunks[i] == 0 ) continue; // Chunk is not yet loaded, so ignore + // This can cause MissIndex to be 0 and thus chunks will not be unloaded while they are actually out of range, + // which might actually be a good thing, otherwise it would keep trying to unload chunks until the new chunks are fully loaded bool bChunkMissing = true; for(int j = 0; j < VIEWDISTANCE*VIEWDISTANCE; j++) { @@ -280,7 +290,7 @@ void cClientHandle::StreamChunks() } if( MissIndex > 0 ) - { // Chunks are gonna be streamed in, so chunks probably also need to be streamed out + { // Chunks are gonna be streamed in, so chunks probably also need to be streamed out <- optimization for(int x = 0; x < VIEWDISTANCE; x++) { for(int z = 0; z < VIEWDISTANCE; z++) @@ -294,7 +304,10 @@ void cClientHandle::StreamChunks() || Chunk->GetPosZ() > ChunkPosZ+(VIEWDISTANCE-1)/2 ) { Chunk->RemoveClient( this ); - Chunk->AsyncUnload( this ); + Chunk->AsyncUnload( this ); // TODO - I think it's possible to unload the chunk immediately instead of next tick + // I forgot why I made it happen next tick + + m_LoadedChunks[x + z*VIEWDISTANCE] = 0; } } } @@ -306,6 +319,7 @@ void cClientHandle::StreamChunks() } } +// Sends chunks to the player from the player position outward void cClientHandle::StreamChunksSmart( cChunk** a_Chunks, unsigned int a_NumChunks ) { int X = (int)floor(m_Player->GetPosX() / 16); @@ -392,7 +406,7 @@ void cClientHandle::HandlePacket( cPacket* a_Packet ) LOGINFO("Got Create Inventory Action packet"); } break; - case E_PING: // Somebody tries to retreive information about the server + case E_PING: // Somebody tries to retrieve information about the server { LOGINFO("Got ping"); char NumPlayers[8], cMaxPlayers[8]; diff --git a/source/cClientHandle.h b/source/cClientHandle.h index 5025f03d2..048e46389 100644 --- a/source/cClientHandle.h +++ b/source/cClientHandle.h @@ -20,7 +20,8 @@ public: cClientHandle(const cSocket & a_Socket); ~cClientHandle(); - static const int VIEWDISTANCE = 13; + static const int VIEWDISTANCE = 13; // MUST be odd number or CRASH! + static const int GENERATEDISTANCE = 2; // Server generates this many chunks AHEAD of player sight. const cSocket & GetSocket(); cPlayer* GetPlayer() { return m_Player; } // tolua_export diff --git a/source/cPlayer.cpp b/source/cPlayer.cpp index 2087f7927..5a005005d 100644 --- a/source/cPlayer.cpp +++ b/source/cPlayer.cpp @@ -147,6 +147,8 @@ void cPlayer::SpawnOn( cClientHandle* a_Target ) void cPlayer::Tick(float a_Dt) { cChunk* InChunk = GetWorld()->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ ); + if( !InChunk ) return; + if(m_bDirtyOrientation && !m_bDirtyPosition) { cPacket_EntityLook EntityLook( this ); diff --git a/source/cWorld.cpp b/source/cWorld.cpp index 2f5ed1c2b..1dc4de6ac 100644 --- a/source/cWorld.cpp +++ b/source/cWorld.cpp @@ -33,6 +33,7 @@ #include "cZombiepigman.h" //Zombiepigman #include "cGenSettings.h" #include "cMakeDir.h" +#include "cChunkGenerator.h" #include "packets/cPacket_TimeUpdate.h" @@ -67,17 +68,33 @@ inline float fRadRand( float a_Radius ) return ((float)rand() * RECI_RAND_MAX)*a_Radius - a_Radius*0.5f; } +struct sSetBlockData +{ + sSetBlockData( int a_X, int a_Y, int a_Z, char a_BlockID, char a_BlockMeta ) + : x( a_X ) + , y( a_Y ) + , z( a_Z ) + , BlockID( a_BlockID ) + , BlockMeta( a_BlockMeta ) + {} + int x, y, z; + char BlockID, BlockMeta; +}; + +typedef std::list< sSetBlockData > FastSetBlockList; + struct cWorld::sWorldState { - cWorld::EntityList m_RemoveEntityQueue; - cWorld::EntityList m_AllEntities; - cWorld::ClientList m_Clients; - cWorld::PlayerList m_Players; + cWorld::EntityList RemoveEntityQueue; + cWorld::EntityList AllEntities; + cWorld::ClientList Clients; + cWorld::PlayerList Players; - static const unsigned int CHUNKBUFFER_SIZE = 5; - std::vector< unsigned int > m_ChunkBuffer; + cWorld::ChunkList SpreadQueue; - cWorld::ChunkList m_SpreadQueue; + FastSetBlockList FastSetBlockQueue; + + cChunkGenerator* pChunkGenerator; std::string WorldName; }; @@ -91,10 +108,10 @@ cWorld* cWorld::GetWorld() cWorld::~cWorld() { LockEntities(); - while( m_pState->m_AllEntities.begin() != m_pState->m_AllEntities.end() ) + while( m_pState->AllEntities.begin() != m_pState->AllEntities.end() ) { - cEntity* Entity = *m_pState->m_AllEntities.begin(); - m_pState->m_AllEntities.remove( Entity ); + cEntity* Entity = *m_pState->AllEntities.begin(); + m_pState->AllEntities.remove( Entity ); if( !Entity->IsDestroyed() ) Entity->Destroy(); RemoveEntity( Entity ); } @@ -104,6 +121,7 @@ cWorld::~cWorld() delete m_LavaSimulator; UnloadUnusedChunks(); + delete m_pState->pChunkGenerator; delete m_ChunkMap; delete m_ClientHandleCriticalSection; m_ClientHandleCriticalSection = 0; @@ -188,6 +206,7 @@ cWorld::cWorld( const char* a_WorldName ) } m_ChunkMap = new cChunkMap( 32, 32, this ); + m_pState->pChunkGenerator = new cChunkGenerator( m_ChunkMap ); m_Time = 0; m_WorldTimeFraction = 0.f; @@ -376,13 +395,13 @@ void cWorld::Tick(float a_Dt) LockChunks(); - while( !m_pState->m_SpreadQueue.empty() ) + while( !m_pState->SpreadQueue.empty() ) { - cChunk* Chunk = (*m_pState->m_SpreadQueue.begin()); + cChunk* Chunk = (*m_pState->SpreadQueue.begin()); //LOG("Spreading: %p", Chunk ); Chunk->SpreadLight( Chunk->pGetSkyLight() ); Chunk->SpreadLight( Chunk->pGetLight() ); - m_pState->m_SpreadQueue.remove( &*Chunk ); + m_pState->SpreadQueue.remove( &*Chunk ); } m_ChunkMap->Tick(a_Dt); @@ -427,6 +446,16 @@ void cWorld::Tick(float a_Dt) } ////////////////Weather/////////////////////// + // Asynchronously set blocks + FastSetBlockList FastSetBlockQueueCopy = m_pState->FastSetBlockQueue; + m_pState->FastSetBlockQueue.clear(); + for( FastSetBlockList::iterator itr = FastSetBlockQueueCopy.begin(); itr != FastSetBlockQueueCopy.end(); ++itr ) + { + sSetBlockData & SetBlockData = *itr; + FastSetBlock( SetBlockData.x, SetBlockData.y, SetBlockData.z, SetBlockData.BlockID, SetBlockData.BlockMeta ); // If unable to set block, it's added to FastSetBlockQueue again + } + if( FastSetBlockQueueCopy.size() != m_pState->FastSetBlockQueue.size() ) + LOG(" Before: %i, after %i" , FastSetBlockQueueCopy.size(), m_pState->FastSetBlockQueue.size() ); if( m_Time - m_LastSave > 60*5 ) // Save each 5 minutes { @@ -438,15 +467,15 @@ void cWorld::Tick(float a_Dt) UnloadUnusedChunks(); } - while( !m_pState->m_RemoveEntityQueue.empty() ) + while( !m_pState->RemoveEntityQueue.empty() ) { - RemoveEntity( *m_pState->m_RemoveEntityQueue.begin() ); + RemoveEntity( *m_pState->RemoveEntityQueue.begin() ); } if( m_bAnimals && ( m_Time - m_SpawnMonsterTime > m_SpawnMonsterRate ) ) // 10 seconds { m_SpawnMonsterTime = m_Time; - if( m_pState->m_Players.size() > 0 ) + if( m_pState->Players.size() > 0 ) { cMonster *Monster = 0; @@ -454,8 +483,8 @@ void cWorld::Tick(float a_Dt) int dayRand = rand() % 6; //added mob code int nightRand = rand() % 10; //added mob code - int RandomPlayerIdx = rand() & m_pState->m_Players.size(); - PlayerList::iterator itr = m_pState->m_Players.begin(); + int RandomPlayerIdx = rand() & m_pState->Players.size(); + PlayerList::iterator itr = m_pState->Players.begin(); for( int i = 1; i < RandomPlayerIdx; i++ ) itr++; @@ -516,12 +545,12 @@ void cWorld::Tick(float a_Dt) std::vector m_RSList_copy(m_RSList); //copy(m_RSList.begin(), m_RSList.end(), m_RSList_copy.begin()); m_RSList.erase(m_RSList.begin(),m_RSList.end()); - int tempX; + int tempX; // FIXME - Keep the scope in mind, these variables are not used in this scope at all, move them down into the for loop int tempY; int tempZ; int state; - std::vector::const_iterator cii; + std::vector::const_iterator cii; // FIXME - Please rename this variable, WTF is cii??? Use human readable variable names or common abbreviations (i, idx, itr, iter) for(cii=m_RSList_copy.begin(); cii!=m_RSList_copy.end();) { tempX = *cii;cii++; @@ -612,7 +641,7 @@ void cWorld::UnloadUnusedChunks() UnlockChunks(); } -cChunk* cWorld::GetChunk( int a_X, int a_Y, int a_Z ) +cChunk* cWorld::GetChunkReliable( int a_X, int a_Y, int a_Z ) // TODO - FIXME - WARNING - This can cause a duplicate chunk to be generated!! { cChunk* Chunk = GetChunkUnreliable( a_X, a_Y, a_Z ); if( Chunk ) @@ -632,7 +661,20 @@ cChunk* cWorld::GetChunk( int a_X, int a_Y, int a_Z ) return Chunk; } - // This should never happen, but yeah + // This should never happen since it's reliable, but yeah + return 0; +} + +cChunk* cWorld::GetChunk( int a_X, int a_Y, int a_Z ) +{ + // Get chunk from memory + cChunk* Chunk = GetChunkUnreliable( a_X, a_Y, a_Z ); + if( Chunk ) return Chunk; + + // Generate new chunk asynchronously + m_pState->pChunkGenerator->GenerateChunk( a_X, a_Z ); + + // Could not find chunk, it's being generated, so return 0 return 0; } @@ -660,16 +702,37 @@ void cWorld::SetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_Block int ChunkX, ChunkY, ChunkZ; AbsoluteToRelative( a_X, a_Y, a_Z, ChunkX, ChunkY, ChunkZ ); - GetChunk( ChunkX, ChunkY, ChunkZ )->SetBlock(a_X, a_Y, a_Z, a_BlockType, a_BlockMeta ); + cChunk* Chunk = GetChunk( ChunkX, ChunkY, ChunkZ ); + if( Chunk ) Chunk->SetBlock(a_X, a_Y, a_Z, a_BlockType, a_BlockMeta ); } void cWorld::FastSetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockMeta ) { - int ChunkX, ChunkY, ChunkZ; + int ChunkX, ChunkY, ChunkZ, X = a_X, Y = a_Y, Z = a_Z; - AbsoluteToRelative( a_X, a_Y, a_Z, ChunkX, ChunkY, ChunkZ ); + AbsoluteToRelative( X, Y, Z, ChunkX, ChunkY, ChunkZ ); - GetChunk( ChunkX, ChunkY, ChunkZ )->FastSetBlock(a_X, a_Y, a_Z, a_BlockType, a_BlockMeta ); + cChunk* Chunk = GetChunk( ChunkX, ChunkY, ChunkZ ); + if( Chunk ) + { + Chunk->FastSetBlock(X, Y, Z, a_BlockType, a_BlockMeta ); + return; + } + + // Could not find chunk, so it has been pushed into the generate chunks queue + // Check if currently generating the target chunk + m_pState->pChunkGenerator->Lock(); + Chunk = m_pState->pChunkGenerator->GetCurrentlyGenerating(); + if( Chunk && Chunk->GetPosX() == ChunkX && Chunk->GetPosZ() == ChunkZ ) + { + Chunk->FastSetBlock(X, Y, Z, a_BlockType, a_BlockMeta ); + m_pState->pChunkGenerator->Unlock(); + return; + } + m_pState->pChunkGenerator->Unlock(); + + // Unable to set block right now, try again later + m_pState->FastSetBlockQueue.push_back( sSetBlockData( a_X, a_Y, a_Z, a_BlockType, a_BlockMeta ) ); } char cWorld::GetBlock( int a_X, int a_Y, int a_Z ) @@ -678,7 +741,9 @@ char cWorld::GetBlock( int a_X, int a_Y, int a_Z ) AbsoluteToRelative( a_X, a_Y, a_Z, ChunkX, ChunkY, ChunkZ ); - return GetChunk( ChunkX, ChunkY, ChunkZ )->GetBlock(a_X, a_Y, a_Z); + cChunk* Chunk = GetChunk( ChunkX, ChunkY, ChunkZ ); + if( Chunk ) return Chunk->GetBlock(a_X, a_Y, a_Z); + return 0; } char cWorld::GetBlockMeta( int a_X, int a_Y, int a_Z ) @@ -688,7 +753,8 @@ char cWorld::GetBlockMeta( int a_X, int a_Y, int a_Z ) AbsoluteToRelative( a_X, a_Y, a_Z, ChunkX, ChunkY, ChunkZ ); cChunk* Chunk = GetChunk( ChunkX, ChunkY, ChunkZ ); - return Chunk->GetLight( Chunk->pGetMeta(), a_X, a_Y, a_Z ); + if( Chunk ) return Chunk->GetLight( Chunk->pGetMeta(), a_X, a_Y, a_Z ); + return 0; } void cWorld::SetBlockMeta( int a_X, int a_Y, int a_Z, char a_MetaData ) @@ -698,8 +764,11 @@ void cWorld::SetBlockMeta( int a_X, int a_Y, int a_Z, char a_MetaData ) AbsoluteToRelative( a_X, a_Y, a_Z, ChunkX, ChunkY, ChunkZ ); cChunk* Chunk = GetChunk( ChunkX, ChunkY, ChunkZ ); - Chunk->SetLight( Chunk->pGetMeta(), a_X, a_Y, a_Z, a_MetaData ); - Chunk->SendBlockTo( a_X, a_Y, a_Z, 0 ); + if( Chunk ) + { + Chunk->SetLight( Chunk->pGetMeta(), a_X, a_Y, a_Z, a_MetaData ); + Chunk->SendBlockTo( a_X, a_Y, a_Z, 0 ); + } } bool cWorld::DigBlock( int a_X, int a_Y, int a_Z, cItem & a_PickupItem ) @@ -750,7 +819,8 @@ char cWorld::GetHeight( int a_X, int a_Z ) int PosX = a_X, PosY = 0, PosZ = a_Z, ChunkX, ChunkY, ChunkZ; AbsoluteToRelative( PosX, PosY, PosZ, ChunkX, ChunkY, ChunkZ ); cChunk* Chunk = GetChunk( ChunkX, ChunkY, ChunkZ ); - return Chunk->GetHeight( PosX, PosZ ); + if( Chunk ) return Chunk->GetHeight( PosX, PosZ ); + return 0; } const double & cWorld::GetSpawnY() @@ -761,7 +831,7 @@ const double & cWorld::GetSpawnY() void cWorld::Broadcast( const cPacket & a_Packet, cClientHandle* a_Exclude /* = 0 */ ) { - for( PlayerList::iterator itr = m_pState->m_Players.begin(); itr != m_pState->m_Players.end(); ++itr) + for( PlayerList::iterator itr = m_pState->Players.begin(); itr != m_pState->Players.end(); ++itr) { if( (*itr)->GetClientHandle() == a_Exclude || !(*itr)->GetClientHandle()->IsLoggedIn() ) continue; (*itr)->GetClientHandle()->Send( a_Packet ); @@ -789,22 +859,22 @@ void cWorld::SetMaxPlayers(int iMax) void cWorld::AddPlayer( cPlayer* a_Player ) { - m_pState->m_Players.remove( a_Player ); - m_pState->m_Players.push_back( a_Player ); + m_pState->Players.remove( a_Player ); + m_pState->Players.push_back( a_Player ); } void cWorld::RemovePlayer( cPlayer* a_Player ) { - m_pState->m_Players.remove( a_Player ); + m_pState->Players.remove( a_Player ); } void cWorld::GetAllPlayers( lua_State* L ) { - lua_createtable(L, m_pState->m_Players.size(), 0); + lua_createtable(L, m_pState->Players.size(), 0); int newTable = lua_gettop(L); int index = 1; - PlayerList::const_iterator iter = m_pState->m_Players.begin(); - while(iter != m_pState->m_Players.end()) { + PlayerList::const_iterator iter = m_pState->Players.begin(); + while(iter != m_pState->Players.end()) { tolua_pushusertype( L, (*iter), "cPlayer" ); lua_rawseti(L, newTable, index); ++iter; @@ -820,7 +890,7 @@ cPlayer* cWorld::GetPlayer( const char* a_PlayerName ) bool bPerfectMatch = false; unsigned int NameLength = strlen( a_PlayerName ); - for( PlayerList::iterator itr = m_pState->m_Players.begin(); itr != m_pState->m_Players.end(); itr++ ) + for( PlayerList::iterator itr = m_pState->Players.begin(); itr != m_pState->Players.end(); itr++ ) { std::string Name = (*itr)->GetName(); if( NameLength > Name.length() ) continue; // Definitely not a match @@ -864,7 +934,7 @@ cPlayer* cWorld::GetPlayer( const char* a_PlayerName ) cEntity* cWorld::GetEntity( int a_UniqueID ) { - for( EntityList::iterator itr = m_pState->m_AllEntities.begin(); itr != m_pState->m_AllEntities.end(); ++itr ) + for( EntityList::iterator itr = m_pState->AllEntities.begin(); itr != m_pState->AllEntities.end(); ++itr ) { if( (*itr)->GetUniqueID() == a_UniqueID ) return *itr; @@ -884,7 +954,7 @@ cEntity* cWorld::GetEntity( int a_UniqueID ) void cWorld::RemoveEntity( cEntity* a_Entity ) { - m_pState->m_RemoveEntityQueue.remove( a_Entity ); + m_pState->RemoveEntityQueue.remove( a_Entity ); if( a_Entity ) { delete a_Entity; @@ -943,15 +1013,15 @@ void cWorld::UnlockChunks() void cWorld::ReSpreadLighting( cChunk* a_Chunk ) { LockChunks(); - m_pState->m_SpreadQueue.remove( a_Chunk ); - m_pState->m_SpreadQueue.push_back( a_Chunk ); + m_pState->SpreadQueue.remove( a_Chunk ); + m_pState->SpreadQueue.push_back( a_Chunk ); UnlockChunks(); } void cWorld::RemoveSpread( cChunk* a_Chunk ) { LockChunks(); - m_pState->m_SpreadQueue.remove( a_Chunk ); + m_pState->SpreadQueue.remove( a_Chunk ); UnlockChunks(); } @@ -969,24 +1039,24 @@ void cWorld::RemoveSpread( cChunk* a_Chunk ) // } cWorld::EntityList & cWorld::GetEntities() { - return m_pState->m_AllEntities; + return m_pState->AllEntities; } void cWorld::AddEntity( cEntity* a_Entity ) { - m_pState->m_AllEntities.push_back( a_Entity ); + m_pState->AllEntities.push_back( a_Entity ); } cWorld::PlayerList & cWorld::GetAllPlayers() { - return m_pState->m_Players; + return m_pState->Players; } unsigned int cWorld::GetNumPlayers() { - return m_pState->m_Players.size(); + return m_pState->Players.size(); } void cWorld::AddToRemoveEntityQueue( cEntity & a_Entity ) { - m_pState->m_AllEntities.remove( &a_Entity); - m_pState->m_RemoveEntityQueue.push_back( &a_Entity ); + m_pState->AllEntities.remove( &a_Entity); + m_pState->RemoveEntityQueue.push_back( &a_Entity ); } const char* cWorld::GetName() { diff --git a/source/cWorld.h b/source/cWorld.h index 83a9bcf66..1e3e1b5a2 100644 --- a/source/cWorld.h +++ b/source/cWorld.h @@ -47,6 +47,7 @@ public: void SetWorldTime(long long a_WorldTime) { m_WorldTime = a_WorldTime; } //tolua_export cChunk* GetChunk( int a_X, int a_Y, int a_Z ); + cChunk* GetChunkReliable( int a_X, int a_Y, int a_Z ); cChunk* GetChunkUnreliable( int a_X, int a_Y, int a_Z ); cChunk* GetChunkOfBlock( int a_X, int a_Y, int a_Z ); char GetHeight( int a_X, int a_Z ); //tolua_export