From a4a418a679f1ac760a8763edd856f0178cfc6dde Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Fri, 25 May 2012 07:18:52 +0000 Subject: Merged the composable_generator branch into the trunk git-svn-id: http://mc-server.googlecode.com/svn/trunk@504 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/cWorld.cpp | 492 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 258 insertions(+), 234 deletions(-) (limited to 'source/cWorld.cpp') diff --git a/source/cWorld.cpp b/source/cWorld.cpp index a2c651d44..9abfb963e 100644 --- a/source/cWorld.cpp +++ b/source/cWorld.cpp @@ -36,12 +36,11 @@ #include "cCavespider.h" //cavespider #include "cGhast.h" //Ghast #include "cZombiepigman.h" //Zombiepigman -#include "cGenSettings.h" #include "cMakeDir.h" #include "cChunkGenerator.h" #include "MersenneTwister.h" -#include "cWorldGenerator_Test.h" #include "cTracer.h" +#include "Trees.h" #include "packets/cPacket_TimeUpdate.h" @@ -71,12 +70,6 @@ const int MAX_LIGHTING_SPREAD_PER_TICK = 10; float cWorld::m_Time = 0.f; -char g_BlockLightValue[128]; -char g_BlockSpreadLightFalloff[128]; -bool g_BlockTransparent[128]; -bool g_BlockOneHitDig[128]; -bool g_BlockPistonBreakable[128]; - @@ -96,6 +89,12 @@ public: Start(); } + void Stop(void) + { + m_ShouldTerminate = true; + Wait(); + } + protected: cWorld * m_World; @@ -127,6 +126,53 @@ protected: +/// A simple thread that displays the progress of world lighting in cWorld::InitializeSpawn() +class cWorldLightingProgress : + public cIsThread +{ +public: + cWorldLightingProgress(cLightingThread * a_Lighting) : + cIsThread("cWorldLightingProgress"), + m_Lighting(a_Lighting) + { + Start(); + } + + void Stop(void) + { + m_ShouldTerminate = true; + Wait(); + } + +protected: + + cLightingThread * m_Lighting; + + virtual void Execute(void) override + { + for (;;) + { + LOG("%d chunks remaining to light", m_Lighting->GetQueueLength() + ); + + // Wait for 2 sec, but be "reasonably wakeable" when the thread is to finish + for (int i = 0; i < 20; i++) + { + cSleep::MilliSleep(100); + if (m_ShouldTerminate) + { + return; + } + } + } // for (-ever) + } + +} ; + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cWorld: @@ -182,21 +228,6 @@ cWorld::cWorld( const AString & a_WorldName ) , m_RSList ( 0 ) , m_Weather ( eWeather_Sunny ) { - /* - // DEBUG: - DWORD Tick = GetTickCount(); - for (int i = 0; i < 3000; i++) - { - BLOCKTYPE Playground[cChunkDef::NumBlocks / 2]; - for (int x = 0; x < 16; x++) for (int z = 0; z < 16; z++) for (int y = 0; y < 256; y++) - { - cChunkDef::SetNibble(Playground, x, y, z, x); - } // for x, y, z - } // for i - Tick = GetTickCount() - Tick; - LOGINFO("3000 chunkfulls of SetNibble() took %d ticks", Tick); - //*/ - LOG("cWorld::cWorld(%s)", a_WorldName.c_str()); m_WorldName = a_WorldName; m_IniFileName = m_WorldName + "/world.ini"; @@ -207,10 +238,8 @@ cWorld::cWorld( const AString & a_WorldName ) m_SpawnX = (double)((r1.randInt()%1000)-500); m_SpawnY = cChunkDef::Height; m_SpawnZ = (double)((r1.randInt()%1000)-500); - m_WorldSeed = r1.randInt(); m_GameMode = eGameMode_Creative; - AString GeneratorName; AString StorageSchema("Default"); cIniFile IniFile(m_IniFileName); @@ -219,9 +248,7 @@ cWorld::cWorld( const AString & a_WorldName ) m_SpawnX = IniFile.GetValueF("SpawnPosition", "X", m_SpawnX ); m_SpawnY = IniFile.GetValueF("SpawnPosition", "Y", m_SpawnY ); m_SpawnZ = IniFile.GetValueF("SpawnPosition", "Z", m_SpawnZ ); - m_WorldSeed = IniFile.GetValueI("Seed", "Seed", m_WorldSeed ); m_GameMode = (eGameMode)IniFile.GetValueI("GameMode", "GameMode", m_GameMode ); - GeneratorName = IniFile.GetValue("Generator", "GeneratorName", GeneratorName); StorageSchema = IniFile.GetValue("Storage", "Schema", StorageSchema); } else @@ -229,19 +256,17 @@ cWorld::cWorld( const AString & a_WorldName ) IniFile.SetValueF("SpawnPosition", "X", m_SpawnX ); IniFile.SetValueF("SpawnPosition", "Y", m_SpawnY ); IniFile.SetValueF("SpawnPosition", "Z", m_SpawnZ ); - IniFile.SetValueI("Seed", "Seed", m_WorldSeed ); IniFile.SetValueI("GameMode", "GameMode", m_GameMode ); - IniFile.SetValue("Generator", "GeneratorName", GeneratorName); IniFile.SetValue("Storage", "Schema", StorageSchema); if( !IniFile.WriteFile() ) { LOG("WARNING: Could not write to %s", m_IniFileName.c_str()); } } - LOGINFO("Seed: %i", m_WorldSeed ); - + + m_Lighting.Start(this); m_Storage.Start(this, StorageSchema); - m_Generator.Start(this, GeneratorName); + m_Generator.Start(this, IniFile); m_bAnimals = true; m_SpawnMonsterRate = 10; @@ -277,105 +302,6 @@ cWorld::cWorld( const AString & a_WorldName ) m_SimulatorManager->RegisterSimulator(m_SandSimulator, 1); m_SimulatorManager->RegisterSimulator(m_FireSimulator, 10); m_SimulatorManager->RegisterSimulator(m_RedstoneSimulator, 1); - - memset( g_BlockLightValue, 0x0, sizeof( g_BlockLightValue ) ); - memset( g_BlockSpreadLightFalloff, 0xf, sizeof( g_BlockSpreadLightFalloff ) ); // 0xf means total falloff - memset( g_BlockTransparent, 0x0, sizeof( g_BlockTransparent ) ); - memset( g_BlockOneHitDig, 0x0, sizeof( g_BlockOneHitDig ) ); - memset( g_BlockPistonBreakable, 0x0, sizeof( g_BlockPistonBreakable ) ); - - // Emissive blocks - g_BlockLightValue[ E_BLOCK_TORCH ] = 14; - g_BlockLightValue[ E_BLOCK_FIRE ] = 15; - g_BlockLightValue[ E_BLOCK_LAVA ] = 15; - g_BlockLightValue[ E_BLOCK_STATIONARY_LAVA ] = 15; - g_BlockLightValue[ E_BLOCK_GLOWSTONE ] = 15; - - // Spread blocks - g_BlockSpreadLightFalloff[ E_BLOCK_AIR ] = 1; - g_BlockSpreadLightFalloff[ E_BLOCK_TORCH ] = 1; - g_BlockSpreadLightFalloff[ E_BLOCK_FIRE ] = 1; - g_BlockSpreadLightFalloff[ E_BLOCK_LAVA ] = 1; - g_BlockSpreadLightFalloff[ E_BLOCK_STATIONARY_LAVA ] = 1; - g_BlockSpreadLightFalloff[ E_BLOCK_WATER ] = 4; // Light in water dissapears faster - g_BlockSpreadLightFalloff[ E_BLOCK_STATIONARY_WATER ] = 4; - g_BlockSpreadLightFalloff[ E_BLOCK_LEAVES ] = 1; - g_BlockSpreadLightFalloff[ E_BLOCK_GLASS ] = 1; - g_BlockSpreadLightFalloff[ E_BLOCK_GLOWSTONE ] = 1; - g_BlockSpreadLightFalloff[ E_BLOCK_SIGN_POST ] = 1; - g_BlockSpreadLightFalloff[ E_BLOCK_WALLSIGN ] = 1; - - // Transparent blocks - g_BlockTransparent[ E_BLOCK_AIR ] = true; - g_BlockTransparent[ E_BLOCK_GLASS ] = true; - g_BlockTransparent[ E_BLOCK_FIRE ] = true; - g_BlockTransparent[ E_BLOCK_ICE ] = true; - g_BlockTransparent[ E_BLOCK_TORCH ] = true; - g_BlockTransparent[ E_BLOCK_SIGN_POST ] = true; - g_BlockTransparent[ E_BLOCK_WALLSIGN ] = true; - g_BlockTransparent[ E_BLOCK_TALL_GRASS ] = true; - g_BlockTransparent[ E_BLOCK_YELLOW_FLOWER ] = true; - g_BlockTransparent[ E_BLOCK_RED_ROSE ] = true; - g_BlockTransparent[ E_BLOCK_RED_MUSHROOM ] = true; - g_BlockTransparent[ E_BLOCK_BROWN_MUSHROOM ] = true; - g_BlockTransparent[ E_BLOCK_SNOW ] = true; - - // TODO: Any other transparent blocks? - - // One hit break blocks - g_BlockOneHitDig[ E_BLOCK_SAPLING ] = true; - g_BlockOneHitDig[ E_BLOCK_YELLOW_FLOWER ] = true; - g_BlockOneHitDig[ E_BLOCK_RED_ROSE ] = true; - g_BlockOneHitDig[ E_BLOCK_BROWN_MUSHROOM ] = true; - g_BlockOneHitDig[ E_BLOCK_RED_MUSHROOM ] = true; - g_BlockOneHitDig[ E_BLOCK_TNT ] = true; - g_BlockOneHitDig[ E_BLOCK_TORCH ] = true; - g_BlockOneHitDig[ E_BLOCK_REDSTONE_WIRE ] = true; - g_BlockOneHitDig[ E_BLOCK_CROPS ] = true; - g_BlockOneHitDig[ E_BLOCK_REDSTONE_TORCH_OFF ] = true; - g_BlockOneHitDig[ E_BLOCK_REDSTONE_TORCH_ON ] = true; - g_BlockOneHitDig[ E_BLOCK_REEDS ] = true; - g_BlockOneHitDig[ E_BLOCK_REDSTONE_WIRE ] = true; - g_BlockOneHitDig[ E_BLOCK_REDSTONE_REPEATER_OFF ] = true; - g_BlockOneHitDig[ E_BLOCK_REDSTONE_REPEATER_ON ] = true; - g_BlockOneHitDig[ E_BLOCK_LOCKED_CHEST ] = true; - g_BlockOneHitDig [ E_BLOCK_FIRE ] = true; - - // Blocks that breaks when pushed by piston - g_BlockPistonBreakable[ E_BLOCK_AIR ] = true; - g_BlockPistonBreakable[ E_BLOCK_STATIONARY_WATER ] = false; //This gave pistons the ability to drop water :D - g_BlockPistonBreakable[ E_BLOCK_WATER ] = false; - g_BlockPistonBreakable[ E_BLOCK_STATIONARY_LAVA ] = false; - g_BlockPistonBreakable[ E_BLOCK_LAVA ] = false; - g_BlockPistonBreakable[ E_BLOCK_BED ] = true; - g_BlockPistonBreakable[ E_BLOCK_COBWEB ] = true; - g_BlockPistonBreakable[ E_BLOCK_TALL_GRASS ] = true; - g_BlockPistonBreakable[ E_BLOCK_YELLOW_FLOWER ] = true; - g_BlockPistonBreakable[ E_BLOCK_BROWN_MUSHROOM ] = true; - g_BlockPistonBreakable[ E_BLOCK_RED_ROSE ] = true; - g_BlockPistonBreakable[ E_BLOCK_RED_MUSHROOM ] = true; - g_BlockPistonBreakable[ E_BLOCK_DEAD_BUSH ] = true; - g_BlockPistonBreakable[ E_BLOCK_TORCH ] = true; - g_BlockPistonBreakable[ E_BLOCK_FIRE ] = true; - g_BlockPistonBreakable[ E_BLOCK_REDSTONE_WIRE ] = true; - g_BlockPistonBreakable[ E_BLOCK_CROPS ] = true; - g_BlockPistonBreakable[ E_BLOCK_LADDER ] = true; - g_BlockPistonBreakable[ E_BLOCK_WOODEN_DOOR ] = true; - g_BlockPistonBreakable[ E_BLOCK_IRON_DOOR ] = true; - g_BlockPistonBreakable[ E_BLOCK_LEVER ] = true; - g_BlockPistonBreakable[ E_BLOCK_STONE_BUTTON ] = true; - g_BlockPistonBreakable[ E_BLOCK_REDSTONE_TORCH_ON ] = true; - g_BlockPistonBreakable[ E_BLOCK_REDSTONE_TORCH_OFF ]= true; - g_BlockPistonBreakable[ E_BLOCK_SNOW ] = true; - g_BlockPistonBreakable[ E_BLOCK_REEDS ] = true; - g_BlockPistonBreakable[ E_BLOCK_PUMPKIN_STEM ] = true; - g_BlockPistonBreakable[ E_BLOCK_MELON_STEM ] = true; - g_BlockPistonBreakable[ E_BLOCK_MELON ] = true; - g_BlockPistonBreakable[ E_BLOCK_PUMPKIN ] = true; - g_BlockPistonBreakable[ E_BLOCK_JACK_O_LANTERN ] = true; - g_BlockPistonBreakable[ E_BLOCK_VINES ] = true; - g_BlockPistonBreakable[ E_BLOCK_STONE_PRESSURE_PLATE ] = true; - g_BlockPistonBreakable[ E_BLOCK_WOODEN_PRESSURE_PLATE ] = true; } @@ -434,7 +360,7 @@ void cWorld::CastThunderbolt ( int a_X, int a_Y, int a_Z ) -void cWorld::InitializeSpawn() +void cWorld::InitializeSpawn(void) { int ChunkX = 0, ChunkY = 0, ChunkZ = 0; BlockToChunk( (int)m_SpawnX, (int)m_SpawnY, (int)m_SpawnZ, ChunkX, ChunkY, ChunkZ ); @@ -446,24 +372,51 @@ void cWorld::InitializeSpawn() int ViewDist = 20; // Always prepare an area 20 chunks across, no matter what the actual cClientHandle::VIEWDISTANCE is #endif // _DEBUG - LOG("Preparing spawn area in world \"%s\"", m_WorldName.c_str()); + LOG("Preparing spawn area in world \"%s\"...", m_WorldName.c_str()); for (int x = 0; x < ViewDist; x++) { for (int z = 0; z < ViewDist; z++) { - m_ChunkMap->TouchChunk( x + ChunkX-(ViewDist - 1) / 2, 0, z + ChunkZ-(ViewDist - 1) / 2 ); // Queue the chunk in the generator / loader + m_ChunkMap->TouchChunk( x + ChunkX-(ViewDist - 1) / 2, ZERO_CHUNK_Y, z + ChunkZ-(ViewDist - 1) / 2 ); // Queue the chunk in the generator / loader } } - // Display progress during this process: - cWorldLoadProgress Progress(this); + { + // Display progress during this process: + cWorldLoadProgress Progress(this); + + // Wait for the loader to finish loading + m_Storage.WaitForQueuesEmpty(); + + // Wait for the generator to finish generating + m_Generator.WaitForQueueEmpty(); + + Progress.Stop(); + } - // Wait for the loader to finish loading - m_Storage.WaitForQueuesEmpty(); + // Light all chunks that have been newly generated: + LOG("Lighting spawn area in world \"%s\"...", m_WorldName.c_str()); - // Wait for the generator to finish generating - m_Generator.WaitForQueueEmpty(); + for (int x = 0; x < ViewDist; x++) + { + int ChX = x + ChunkX-(ViewDist - 1) / 2; + for (int z = 0; z < ViewDist; z++) + { + int ChZ = z + ChunkZ-(ViewDist - 1) / 2; + if (!m_ChunkMap->IsChunkLighted(ChX, ChZ)) + { + m_Lighting.QueueChunk(ChX, ChZ); // Queue the chunk in the lighting thread + } + } // for z + } // for x + { + cWorldLightingProgress Progress(&m_Lighting); + m_Lighting.WaitForQueueEmpty(); + Progress.Stop(); + } + + // TODO: Better spawn detection - move spawn out of the water if it isn't set in the INI already m_SpawnY = (double)GetHeight( (int)m_SpawnX, (int)m_SpawnZ ) + 1.6f; // +1.6f eye height } @@ -508,8 +461,6 @@ void cWorld::Tick(float a_Dt) } } - TickLighting(); - m_ChunkMap->Tick(a_Dt, m_TickRand); GetSimulatorManager()->Simulate(a_Dt); @@ -523,7 +474,7 @@ void cWorld::Tick(float a_Dt) std::swap(FastSetBlockQueueCopy, m_FastSetBlockQueue); } m_ChunkMap->FastSetBlocks(FastSetBlockQueueCopy); - if (FastSetBlockQueueCopy.size() > 0) + if (!FastSetBlockQueueCopy.empty()) { // Some blocks failed, store them for next tick: cCSLock Lock(m_CSFastSetBlock); @@ -716,30 +667,17 @@ void cWorld::TickSpawnMobs(float a_Dt) -void cWorld::TickLighting(void) +void cWorld::GrowTree( int a_X, int a_Y, int a_Z ) { - // To avoid a deadlock, we lock the spread queue only long enough to pick the chunk coords to spread - // The spreading itself will run unlocked - cChunkCoordsList SpreadQueue; + if (GetBlock(a_X, a_Y, a_Z) == E_BLOCK_SAPLING) { - cCSLock Lock(m_CSLighting); - if (m_SpreadQueue.size() == 0) - { - return; - } - if (m_SpreadQueue.size() >= MAX_LIGHTING_SPREAD_PER_TICK ) - { - LOGWARN("cWorld: Lots of lighting to do! Still %i chunks left!", m_SpreadQueue.size() ); - } - // Move up to MAX_LIGHTING_SPREAD_PER_TICK elements from m_SpreadQueue out into SpreadQueue: - cChunkCoordsList::iterator itr = m_SpreadQueue.begin(); - std::advance(itr, MIN(m_SpreadQueue.size(), MAX_LIGHTING_SPREAD_PER_TICK)); - SpreadQueue.splice(SpreadQueue.begin(), m_SpreadQueue, m_SpreadQueue.begin(), itr); + // There is a sapling here, grow a tree according to its type: + GrowTreeFromSapling(a_X, a_Y, a_Z, GetBlockMeta(a_X, a_Y, a_Z)); } - - for (cChunkCoordsList::iterator itr = SpreadQueue.begin(); itr != SpreadQueue.end(); ++itr) + else { - m_ChunkMap->SpreadChunkLighting(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ); + // There is nothing here, grow a tree based on the current biome here: + GrowTreeByBiome(a_X, a_Y, a_Z); } } @@ -747,73 +685,84 @@ void cWorld::TickLighting(void) -void cWorld::GrowTree( int a_X, int a_Y, int a_Z ) +void cWorld::GrowTreeFromSapling(int a_X, int a_Y, int a_Z, char a_SaplingMeta) { - // new tree code, looks much better - // with help from seanj - // converted from php to lua then lua to c++ - - // build trunk - MTRand r1; - int trunk = r1.randInt() % (7 - 5 + 1) + 5; - for (int i = 0; i < trunk; i++) + cNoise Noise(m_Generator.GetSeed()); + sSetBlockVector Blocks; + switch (a_SaplingMeta & 0x07) { - FastSetBlock( a_X, a_Y + i, a_Z, E_BLOCK_LOG, 0 ); + case E_META_SAPLING_APPLE: GetAppleTreeImage (a_X, a_Y, a_Z, Noise, (int)(m_WorldTime & 0xffffffff), Blocks); break; + case E_META_SAPLING_BIRCH: GetBirchTreeImage (a_X, a_Y, a_Z, Noise, (int)(m_WorldTime & 0xffffffff), Blocks); break; + case E_META_SAPLING_CONIFER: GetConiferTreeImage(a_X, a_Y, a_Z, Noise, (int)(m_WorldTime & 0xffffffff), Blocks); break; + case E_META_SAPLING_JUNGLE: GetJungleTreeImage (a_X, a_Y, a_Z, Noise, (int)(m_WorldTime & 0xffffffff), Blocks); break; } + + GrowTreeImage(Blocks); +} + + + + + +void cWorld::GrowTreeByBiome(int a_X, int a_Y, int a_Z) +{ + cNoise Noise(m_Generator.GetSeed()); + sSetBlockVector Blocks; + GetTreeImageByBiome(a_X, a_Y, a_Z, Noise, (int)(m_WorldTime & 0xffffffff), (EMCSBiome)GetBiomeAt(a_X, a_Z), Blocks); + GrowTreeImage(Blocks); +} - // build tree - for (int j = 0; j < trunk; j++) + + + + +void cWorld::GrowTreeImage(const sSetBlockVector & a_Blocks) +{ + // Check that the tree has place to grow + + // Make a copy of the log blocks: + sSetBlockVector b2; + for (sSetBlockVector::const_iterator itr = a_Blocks.begin(); itr != a_Blocks.end(); ++itr) { - int radius = trunk - j; - if (radius < 4) + if (itr->BlockType == E_BLOCK_LOG) { - if (radius > 2) - { - radius = 2; - } - for (int i = a_X - radius; i <= a_X + radius; i++) + b2.push_back(*itr); + } + } // for itr - a_Blocks[] + + // Query blocktypes and metas at those log blocks: + if (!GetBlocks(b2, false)) + { + return; + } + + // Check that at each log's coord there's an block allowed to be overwritten: + for (sSetBlockVector::const_iterator itr = b2.begin(); itr != b2.end(); ++itr) + { + switch (itr->BlockType) + { + CASE_TREE_ALLOWED_BLOCKS: { - for (int k = a_Z-radius; k <= a_Z + radius; k++) - { - // small chance to be missing a block to add a little random - if (k != a_Z || i != a_X && (r1.randInt() % 100 + 1) > 20) - { - if( GetBlock( i, a_Y + j, k ) == E_BLOCK_AIR ) - { - FastSetBlock(i, a_Y+j, k, E_BLOCK_LEAVES, 0 ); - } - } - else - { - //if( m_BlockType[ MakeIndex(i, TopY+j, k) ] == E_BLOCK_AIR ) - // m_BlockType[ MakeIndex(i, TopY+j, k) ] = E_BLOCK_LEAVES; - } - } + break; } - if (GetBlock( a_X, a_Y+j, a_Z ) == E_BLOCK_AIR ) + default: { - FastSetBlock( a_X, a_Y+j, a_Z, E_BLOCK_LOG, 0 ); + return; } } - } - - // do the top - if( GetBlock( a_X+1, a_Y+trunk, a_Z ) == E_BLOCK_AIR ) - FastSetBlock( a_X+1, a_Y+trunk, a_Z, E_BLOCK_LEAVES, 0 ); + } // for itr - b2[] + + // All ok, replace blocks with the tree image: + m_ChunkMap->ReplaceTreeBlocks(a_Blocks); +} - if( GetBlock( a_X-1, a_Y+trunk, a_Z ) == E_BLOCK_AIR ) - FastSetBlock( a_X-1, a_Y+trunk, a_Z, E_BLOCK_LEAVES, 0 ); - if( GetBlock( a_X, a_Y+trunk, a_Z+1 ) == E_BLOCK_AIR ) - FastSetBlock( a_X, a_Y+trunk, a_Z+1, E_BLOCK_LEAVES, 0 ); - if( GetBlock( a_X, a_Y+trunk, a_Z-1 ) == E_BLOCK_AIR ) - FastSetBlock( a_X, a_Y+trunk, a_Z-1, E_BLOCK_LEAVES, 0 ); - if( GetBlock( a_X, a_Y+trunk, a_Z ) == E_BLOCK_AIR ) - FastSetBlock( a_X, a_Y+trunk, a_Z, E_BLOCK_LEAVES, 0 ); - // end new tree code +int cWorld::GetBiomeAt (int a_BlockX, int a_BlockZ) +{ + return m_ChunkMap->GetBiomeAt(a_BlockX, a_BlockZ); } @@ -905,6 +854,24 @@ char cWorld::GetBlockSkyLight( int a_X, int a_Y, int a_Z ) +void cWorld::ReplaceBlocks(const sSetBlockVector & a_Blocks, BLOCKTYPE a_FilterBlockType) +{ + m_ChunkMap->ReplaceBlocks(a_Blocks, a_FilterBlockType); +} + + + + + +bool cWorld::GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure) +{ + return m_ChunkMap->GetBlocks(a_Blocks, a_ContinueOnFailure); +} + + + + + bool cWorld::DigBlock( int a_X, int a_Y, int a_Z, cItem & a_PickupItem ) { bool res = m_ChunkMap->DigBlock(a_X, a_Y, a_Z, a_PickupItem); @@ -1018,38 +985,58 @@ void cWorld::MarkChunkSaved (int a_ChunkX, int a_ChunkY, int a_ChunkZ) -void cWorld::ChunkDataLoaded( +void cWorld::SetChunkData( int a_ChunkX, int a_ChunkY, int a_ChunkZ, const BLOCKTYPE * a_BlockTypes, - const BLOCKTYPE * a_BlockMeta, - const BLOCKTYPE * a_BlockLight, - const BLOCKTYPE * a_BlockSkyLight, + const NIBBLETYPE * a_BlockMeta, + const NIBBLETYPE * a_BlockLight, + const NIBBLETYPE * a_BlockSkyLight, const cChunkDef::HeightMap * a_HeightMap, + const cChunkDef::BiomeMap * a_BiomeMap, cEntityList & a_Entities, - cBlockEntityList & a_BlockEntities + cBlockEntityList & a_BlockEntities, + bool a_MarkDirty ) { - m_ChunkMap->ChunkDataLoaded(a_ChunkX, a_ChunkY, a_ChunkZ, a_BlockTypes, a_BlockMeta, a_BlockLight, a_BlockSkyLight, a_HeightMap, a_Entities, a_BlockEntities); - m_ChunkSender.ChunkReady(a_ChunkX, a_ChunkY, a_ChunkZ); + // Validate biomes, if needed: + cChunkDef::BiomeMap BiomeMap; + const cChunkDef::BiomeMap * Biomes = a_BiomeMap; + if (a_BiomeMap == NULL) + { + // The biomes are not assigned, get them from the generator: + Biomes = &BiomeMap; + m_Generator.GenerateBiomes(a_ChunkX, a_ChunkZ, BiomeMap); + } + + m_ChunkMap->SetChunkData( + a_ChunkX, a_ChunkY, a_ChunkZ, + a_BlockTypes, a_BlockMeta, a_BlockLight, a_BlockSkyLight, + a_HeightMap, *Biomes, + a_Entities, a_BlockEntities, + a_MarkDirty + ); + + // If a client is requesting this chunk, send it to them: + if (m_ChunkMap->HasChunkAnyClients(a_ChunkX, a_ChunkY, a_ChunkZ)) + { + m_ChunkSender.ChunkReady(a_ChunkX, a_ChunkY, a_ChunkZ); + } + + // Notify the lighting thread that the chunk has become valid (in case it is a neighbor of a postponed chunk): + m_Lighting.ChunkReady(a_ChunkX, a_ChunkZ); } -void cWorld::ChunkDataGenerated( - int a_ChunkX, int a_ChunkY, int a_ChunkZ, - const BLOCKTYPE * a_BlockTypes, - const BLOCKTYPE * a_BlockMeta, - const BLOCKTYPE * a_BlockLight, - const BLOCKTYPE * a_BlockSkyLight, - const cChunkDef::HeightMap * a_HeightMap, - cEntityList & a_Entities, - cBlockEntityList & a_BlockEntities +void cWorld::ChunkLighted( + int a_ChunkX, int a_ChunkZ, + const cChunkDef::BlockNibbles & a_BlockLight, + const cChunkDef::BlockNibbles & a_SkyLight ) { - m_ChunkMap->ChunkDataGenerated(a_ChunkX, a_ChunkY, a_ChunkZ, a_BlockTypes, a_BlockMeta, a_BlockLight, a_BlockSkyLight, a_HeightMap, a_Entities, a_BlockEntities); - m_ChunkSender.ChunkReady(a_ChunkX, a_ChunkY, a_ChunkZ); + m_ChunkMap->ChunkLighted(a_ChunkX, a_ChunkZ, a_BlockLight, a_SkyLight); } @@ -1431,14 +1418,41 @@ void cWorld::RegenerateChunk(int a_ChunkX, int a_ChunkZ) m_ChunkMap->MarkChunkRegenerating(a_ChunkX, a_ChunkZ); // Trick: use Y=1 to force the chunk generation even though the chunk data is already present - m_Generator.GenerateChunk(a_ChunkX, 1, a_ChunkZ); + m_Generator.QueueGenerateChunk(a_ChunkX, 1, a_ChunkZ); +} + + + + + +void cWorld::GenerateChunk(int a_ChunkX, int a_ChunkZ) +{ + m_Generator.QueueGenerateChunk(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); +} + + + + + +void cWorld::QueueLightChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_Callback) +{ + m_Lighting.QueueChunk(a_ChunkX, a_ChunkZ, a_Callback); +} + + + + + +bool cWorld::IsChunkLighted(int a_ChunkX, int a_ChunkZ) +{ + return m_ChunkMap->IsChunkLighted(a_ChunkX, a_ChunkZ); } -void cWorld::SaveAllChunks() +void cWorld::SaveAllChunks(void) { LOG("Saving all chunks..."); m_LastSave = m_Time; @@ -1514,3 +1528,13 @@ int cWorld::GetNumChunks(void) const + +void cWorld::GetChunkStats(int & a_NumValid, int & a_NumDirty, int & a_NumInLightingQueue) +{ + m_ChunkMap->GetChunkStats(a_NumValid, a_NumDirty); + a_NumInLightingQueue = (int) m_Lighting.GetQueueLength(); +} + + + + -- cgit v1.2.3