summaryrefslogtreecommitdiffstats
path: root/source/cWorld.cpp
diff options
context:
space:
mode:
authormadmaxoft@gmail.com <madmaxoft@gmail.com@0a769ca7-a7f5-676a-18bf-c427514a06d6>2012-02-13 22:47:03 +0100
committermadmaxoft@gmail.com <madmaxoft@gmail.com@0a769ca7-a7f5-676a-18bf-c427514a06d6>2012-02-13 22:47:03 +0100
commit4f17362aeb80e5339c58a5d3b0fbaeb88d9e701c (patch)
treefebea3ecd89c0d4aa83924e430bf11366d754733 /source/cWorld.cpp
parentNew makefile with automatic *.cpp sourcefile import, automatic header file dependencies and switchable debug / release configuration. gnumake-specific :( (diff)
downloadcuberite-4f17362aeb80e5339c58a5d3b0fbaeb88d9e701c.tar
cuberite-4f17362aeb80e5339c58a5d3b0fbaeb88d9e701c.tar.gz
cuberite-4f17362aeb80e5339c58a5d3b0fbaeb88d9e701c.tar.bz2
cuberite-4f17362aeb80e5339c58a5d3b0fbaeb88d9e701c.tar.lz
cuberite-4f17362aeb80e5339c58a5d3b0fbaeb88d9e701c.tar.xz
cuberite-4f17362aeb80e5339c58a5d3b0fbaeb88d9e701c.tar.zst
cuberite-4f17362aeb80e5339c58a5d3b0fbaeb88d9e701c.zip
Diffstat (limited to '')
-rw-r--r--source/cWorld.cpp855
1 files changed, 404 insertions, 451 deletions
diff --git a/source/cWorld.cpp b/source/cWorld.cpp
index 00dcbd80e..c007070c6 100644
--- a/source/cWorld.cpp
+++ b/source/cWorld.cpp
@@ -40,14 +40,13 @@
#include "cChunkGenerator.h"
#include "MersenneTwister.h"
#include "cWorldGenerator_Test.h"
+#include "cTracer.h"
#include "packets/cPacket_TimeUpdate.h"
#include "packets/cPacket_NewInvalidState.h"
#include "packets/cPacket_Thunderbolt.h"
-#include "ptr_cChunk.h"
-
#include "Vector3d.h"
#include <time.h>
@@ -62,6 +61,13 @@
+/// Up to this many m_SpreadQueue elements are handled each world tick
+const int MAX_LIGHTING_SPREAD_PER_TICK = 10;
+
+
+
+
+
float cWorld::m_Time = 0.f;
char g_BlockLightValue[128];
@@ -70,6 +76,10 @@ bool g_BlockTransparent[128];
bool g_BlockOneHitDig[128];
bool g_BlockPistonBreakable[128];
+
+
+
+
#define RECI_RAND_MAX (1.f/RAND_MAX)
inline float fRadRand( float a_Radius )
{
@@ -77,36 +87,9 @@ inline float fRadRand( float a_Radius )
return ((float)r1.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 RemoveEntityQueue;
- cWorld::EntityList AllEntities;
- cWorld::ClientList Clients;
- cWorld::PlayerList Players;
- cWorld::ChunkList SpreadQueue;
- FastSetBlockList FastSetBlockQueue;
- cChunkGenerator* pChunkGenerator;
-
- std::string WorldName;
-};
cWorld* cWorld::GetWorld()
{
@@ -120,15 +103,19 @@ cWorld* cWorld::GetWorld()
cWorld::~cWorld()
{
- LockEntities();
- while( m_pState->AllEntities.begin() != m_pState->AllEntities.end() )
{
- cEntity* Entity = *m_pState->AllEntities.begin();
- m_pState->AllEntities.remove( Entity );
- if( !Entity->IsDestroyed() ) Entity->Destroy();
- RemoveEntity( Entity );
+ cCSLock Lock(m_CSEntities);
+ while( m_AllEntities.begin() != m_AllEntities.end() )
+ {
+ cEntity* Entity = *m_AllEntities.begin();
+ m_AllEntities.remove( Entity );
+ if ( !Entity->IsDestroyed() )
+ {
+ Entity->Destroy();
+ }
+ delete Entity;
+ }
}
- UnlockEntities();
delete m_SimulatorManager;
delete m_SandSimulator;
@@ -136,33 +123,28 @@ cWorld::~cWorld()
delete m_LavaSimulator;
delete m_FireSimulator;
- UnloadUnusedChunks();
- delete m_pState->pChunkGenerator;
- delete m_ChunkMap;
+ m_Generator.Stop();
- delete m_ClientHandleCriticalSection; m_ClientHandleCriticalSection = 0;
- delete m_EntitiesCriticalSection; m_EntitiesCriticalSection = 0;
- delete m_ChunksCriticalSection; m_ChunksCriticalSection = 0;
- delete m_pState;
+ UnloadUnusedChunks();
+
+ m_Storage.WaitForFinish();
- delete m_WorldGenerator;
+ delete m_ChunkMap;
}
-cWorld::cWorld( const char* a_WorldName )
- : m_pState( new sWorldState )
- , m_SpawnMonsterTime( 0.f )
+cWorld::cWorld( const AString & a_WorldName )
+ : m_SpawnMonsterTime( 0.f )
, m_RSList ( 0 )
, m_Weather ( 0 )
- , m_WorldGenerator( 0 )
{
- LOG("cWorld::cWorld(%s)", a_WorldName);
- m_pState->WorldName = a_WorldName;
+ LOG("cWorld::cWorld(%s)", a_WorldName.c_str());
+ m_WorldName = a_WorldName;
- cMakeDir::MakeDir(m_pState->WorldName.c_str());
+ cMakeDir::MakeDir(m_WorldName.c_str());
MTRand r1;
m_SpawnX = (double)((r1.randInt()%1000)-500);
@@ -171,9 +153,10 @@ cWorld::cWorld( const char* a_WorldName )
m_WorldSeed = r1.randInt();
m_GameMode = 0;
- std::string WorldGeneratorName;
+ AString GeneratorName;
+ AString StorageSchema;
- cIniFile IniFile( m_pState->WorldName + "/world.ini");
+ cIniFile IniFile( m_WorldName + "/world.ini");
if( IniFile.ReadFile() )
{
m_SpawnX = IniFile.GetValueF("SpawnPosition", "X", m_SpawnX );
@@ -181,7 +164,8 @@ cWorld::cWorld( const char* a_WorldName )
m_SpawnZ = IniFile.GetValueF("SpawnPosition", "Z", m_SpawnZ );
m_WorldSeed = IniFile.GetValueI("Seed", "Seed", m_WorldSeed );
m_GameMode = IniFile.GetValueI("GameMode", "GameMode", m_GameMode );
- WorldGeneratorName = IniFile.GetValue("Generator", "GeneratorName", "Default");
+ GeneratorName = IniFile.GetValue("Generator", "GeneratorName", "Default");
+ StorageSchema = IniFile.GetValue("Storage", "Schema", "Default");
}
else
{
@@ -198,11 +182,8 @@ cWorld::cWorld( const char* a_WorldName )
}
LOGINFO("Seed: %i", m_WorldSeed );
- if( WorldGeneratorName.compare("Test") == 0 )
- m_WorldGenerator = new cWorldGenerator_Test();
- else // Default
- m_WorldGenerator = new cWorldGenerator();
-
+ m_Storage.Start(this, StorageSchema);
+ m_Generator.Start(this, GeneratorName);
cIniFile GenSettings("terrain.ini");
if( GenSettings.ReadFile() )
{
@@ -238,16 +219,12 @@ cWorld::cWorld( const char* a_WorldName )
}
m_ChunkMap = new cChunkMap(this );
- m_pState->pChunkGenerator = new cChunkGenerator( m_ChunkMap );
m_Time = 0;
m_WorldTimeFraction = 0.f;
m_WorldTime = 0;
m_LastSave = 0;
m_LastUnload = 0;
- m_ClientHandleCriticalSection = new cCriticalSection();
- m_EntitiesCriticalSection = new cCriticalSection();
- m_ChunksCriticalSection = new cCriticalSection();
//Simulators:
m_WaterSimulator = new cWaterSimulator( this );
@@ -380,7 +357,12 @@ void cWorld::SetWeather( int Weather )
}
}
-void cWorld::CastThunderbolt ( int X, int Y, int Z ) {
+
+
+
+
+void cWorld::CastThunderbolt ( int X, int Y, int Z )
+{
cPacket_Thunderbolt ThunderboltPacket;
ThunderboltPacket.m_xLBPos = X;
ThunderboltPacket.m_yLBPos = Y;
@@ -396,16 +378,18 @@ void cWorld::InitializeSpawn()
{
int ChunkX = 0, ChunkY = 0, ChunkZ = 0;
BlockToChunk( (int)m_SpawnX, (int)m_SpawnY, (int)m_SpawnZ, ChunkX, ChunkY, ChunkZ );
- int ViewDist = cClientHandle::VIEWDISTANCE;
- LOG("Loading spawn area");
- for(int x = 0; x < ViewDist; x++)
+ int ViewDist = 20; // Always prepare an area 20 chunks across, no matter what the actual cClientHandle::VIEWDISTANCE is
+ 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++)
+ for (int z = 0; z < ViewDist; z++)
{
- GetChunk( x + ChunkX-(ViewDist-1)/2, 0, z + ChunkZ-(ViewDist-1)/2 );
+ GetChunk( x + ChunkX-(ViewDist - 1) / 2, 0, z + ChunkZ-(ViewDist - 1) / 2 ); // Queue the chunk in the generator / loader
}
- LOG("Loaded %0.2f", ((float)x / (float)ViewDist)*100 );
+ LOG("Queued %0.2f %% of spawn area", ((float)x / (float)ViewDist) * 100 );
}
+
+ // TODO: Wait for the generator to finish generating these chunks
}
@@ -415,188 +399,123 @@ void cWorld::InitializeSpawn()
void cWorld::Tick(float a_Dt)
{
int randWeather = 0;
- m_Time+=a_Dt/1000.f;
+ m_Time += a_Dt / 1000.f;
CurrentTick++;
bool bSendTime = false;
- m_WorldTimeFraction+=a_Dt/1000.f;
- while( m_WorldTimeFraction > 1.f )
+ m_WorldTimeFraction += a_Dt / 1000.f;
+ while ( m_WorldTimeFraction > 1.f )
{
- m_WorldTimeFraction-=1.f;
- m_WorldTime+=20;
- m_WorldTime %= 24000; // 24000 units in a day
+ m_WorldTimeFraction -= 1.f;
+ m_WorldTime += 20;
bSendTime = true;
}
- if( bSendTime ) Broadcast( cPacket_TimeUpdate( (m_WorldTime) ) );
+ m_WorldTime %= 24000; // 24000 units in a day
+ if ( bSendTime )
+ {
+ Broadcast( cPacket_TimeUpdate( (m_WorldTime) ) );
+ }
- LockEntities();
- for( cWorld::EntityList::iterator itr = GetEntities().begin(); itr != GetEntities().end();)
{
- if( (*itr)->IsDestroyed() )
+ cCSLock Lock(m_CSEntities);
+ for (cEntityList::iterator itr = m_AllEntities.begin(); itr != m_AllEntities.end();)
{
- LOG("Destroy that entity! %i", (*itr)->GetUniqueID() );
- cEntity* RemoveMe = *itr;
- itr = m_pState->AllEntities.erase( itr );
- m_pState->RemoveEntityQueue.push_back( RemoveMe );
- continue;
+ if ((*itr)->IsDestroyed())
+ {
+ LOG("Destroying entity #%i", (*itr)->GetUniqueID());
+ cEntity * RemoveMe = *itr;
+ itr = m_AllEntities.erase( itr );
+ m_RemoveEntityQueue.push_back( RemoveMe );
+ continue;
+ }
+ (*itr)->Tick(a_Dt);
+ itr++;
}
- (*itr)->Tick(a_Dt);
- itr++;
}
- UnlockEntities();
-
- LockChunks();
-
- int TimesSpreaded = 0;
- while( !m_pState->SpreadQueue.empty() && TimesSpreaded < 50 ) // Spread a max of 50 times each tick, otherwise server will hang
{
- ptr_cChunk& Chunk = *m_pState->SpreadQueue.begin();
- //LOG("Spreading: %p", Chunk );
- Chunk->SpreadLight( Chunk->pGetSkyLight() );
- Chunk->SpreadLight( Chunk->pGetLight() );
- m_pState->SpreadQueue.remove( Chunk );
- TimesSpreaded++;
- }
- if( TimesSpreaded >= 50 )
- {
- LOGWARN("Lots of lighting to do! At least %i chunks left!", m_pState->SpreadQueue.size() );
+ cCSLock Lock(m_CSLighting);
+ if (m_SpreadQueue.size() >= 50 )
+ {
+ LOGWARN("cWorld: Lots of lighting to do! Still %i chunks left!", m_SpreadQueue.size() );
+ }
+ int TimesSpreaded = 0;
+ while ( !m_SpreadQueue.empty() && TimesSpreaded < MAX_LIGHTING_SPREAD_PER_TICK ) // Do not choke the tick thread
+ {
+ cChunkPtr & Chunk = *m_SpreadQueue.begin();
+ //LOG("Spreading: %p", Chunk );
+ Chunk->SpreadLight( Chunk->pGetSkyLight() );
+ Chunk->SpreadLight( Chunk->pGetLight() );
+ m_SpreadQueue.pop_front();
+ TimesSpreaded++;
+ }
}
m_ChunkMap->Tick(a_Dt, m_TickRand);
GetSimulatorManager()->Simulate(a_Dt);
- UnlockChunks();
-
TickWeather(a_Dt);
// Asynchronously set blocks
- FastSetBlockList FastSetBlockQueueCopy = m_pState->FastSetBlockQueue;
- m_pState->FastSetBlockQueue.clear();
- for( FastSetBlockList::iterator itr = FastSetBlockQueueCopy.begin(); itr != FastSetBlockQueueCopy.end(); ++itr )
+ FastSetBlockList FastSetBlockQueueCopy;
+ {
+ cCSLock Lock(m_CSFastSetBlock);
+ FastSetBlockQueueCopy = m_FastSetBlockQueue;
+ m_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
+ if( m_Time - m_LastSave > 60 * 5 ) // Save each 5 minutes
{
SaveAllChunks();
}
- if( m_Time - m_LastUnload > 10 ) // Unload each minute
+ if( m_Time - m_LastUnload > 10 ) // Unload every 10 seconds
{
UnloadUnusedChunks();
}
- while( !m_pState->RemoveEntityQueue.empty() )
+ // Delete entities queued for removal:
+ for (cEntityList::iterator itr = m_RemoveEntityQueue.begin(); itr != m_RemoveEntityQueue.end(); ++itr)
{
- RemoveEntity( *m_pState->RemoveEntityQueue.begin() );
- }
-
- if( m_bAnimals && ( m_Time - m_SpawnMonsterTime > m_SpawnMonsterRate ) ) // 10 seconds
- {
- m_SpawnMonsterTime = m_Time;
- if( m_pState->Players.size() > 0 )
- {
- cMonster *Monster = 0;
-
- //srand ( time(NULL) ); // Only seed random ONCE! Is already done in the cWorld constructor
- int dayRand = m_TickRand.randInt() % 6; //added mob code
- int nightRand = m_TickRand.randInt() % 10; //added mob code
-
- int RandomPlayerIdx = m_TickRand.randInt() & m_pState->Players.size();
- PlayerList::iterator itr = m_pState->Players.begin();
- for( int i = 1; i < RandomPlayerIdx; i++ )
- itr++;
-
- cPlayer* Player = *itr;
- Vector3d SpawnPos = Player->GetPosition();
- SpawnPos += Vector3d( (double)(m_TickRand.randInt()%64)-32, (double)(m_TickRand.randInt()%64)-32, (double)(m_TickRand.randInt()%64)-32 );
- char Height = GetHeight( (int)SpawnPos.x, (int)SpawnPos.z );
-
- if(m_WorldTime >= 12000 + 1000) {
- if (nightRand == 0) //random percent to spawn for night
- Monster = new cSpider();
- else if (nightRand == 1)
- Monster = new cZombie();
- else if (nightRand == 2)
- Monster = new cEnderman();
- else if (nightRand == 3)
- Monster = new cCreeper();
- else if (nightRand == 4)
- Monster = new cCavespider();
- else if (nightRand == 5)
- Monster = new cGhast();
- else if (nightRand == 6)
- Monster = new cZombiepigman();
- else if (nightRand == 7)
- Monster = new cSlime();
- else if (nightRand == 8)
- Monster = new cSilverfish();
- else if (nightRand == 9)
- Monster = new cSkeleton();
- //end random percent to spawn for night
- } else {
- if (dayRand == 0) //random percent to spawn for day
- Monster = new cChicken();
- else if (dayRand == 1)
- Monster = new cCow();
- else if (dayRand == 2)
- Monster = new cPig();
- else if (dayRand == 3)
- Monster = new cSheep();
- else if (dayRand == 4)
- Monster = new cSquid();
- else if (dayRand == 5)
- Monster = new cWolf();
- //end random percent to spawn for day
- }
-
- if( Monster )
- {
- Monster->Initialize( this );
- Monster->TeleportTo( SpawnPos.x, (double)(Height)+2, SpawnPos.z );
- Monster->SpawnOn( 0 );
- }
- }
+ delete *itr;
}
+ m_RemoveEntityQueue.clear();
+ TickSpawnMobs(a_Dt);
std::vector<int> 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; // 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;
+
+ m_RSList.clear();
std::vector<int>::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++;
- tempY = *cii;cii++;
- tempZ = *cii;cii++;
- state = *cii;cii++;
+ int tempX = *cii;cii++;
+ int tempY = *cii;cii++;
+ int tempZ = *cii;cii++;
+ int state = *cii;cii++;
- //printf ("%i, %i, %i, %i\n",tempX,tempY,tempZ,state) ;
- if ( (state == 11111) && ( (int)GetBlock( tempX, tempY, tempZ ) == E_BLOCK_REDSTONE_TORCH_OFF ) ) {
+ if ( (state == 11111) && ( (int)GetBlock( tempX, tempY, tempZ ) == E_BLOCK_REDSTONE_TORCH_OFF ) )
+ {
FastSetBlock( tempX, tempY, tempZ, E_BLOCK_REDSTONE_TORCH_ON, (int)GetBlockMeta( tempX, tempY, tempZ ) );
cRedstone Redstone(this);
Redstone.ChangeRedstone( tempX, tempY, tempZ, true );
- } else if ( (state == 00000) && ( (int)GetBlock( tempX, tempY, tempZ ) == E_BLOCK_REDSTONE_TORCH_ON ) ) {
+ }
+ else if ( (state == 00000) && ( (int)GetBlock( tempX, tempY, tempZ ) == E_BLOCK_REDSTONE_TORCH_ON ) )
+ {
FastSetBlock( tempX, tempY, tempZ, E_BLOCK_REDSTONE_TORCH_OFF, (int)GetBlockMeta( tempX, tempY, tempZ ) );
cRedstone Redstone(this);
Redstone.ChangeRedstone( tempX, tempY, tempZ, false );
}
-
}
m_RSList_copy.erase(m_RSList_copy.begin(),m_RSList_copy.end());
-
}
@@ -605,7 +524,6 @@ void cWorld::Tick(float a_Dt)
void cWorld::TickWeather(float a_Dt)
{
- ////////////////Weather///////////////////////
if ( GetWeather() == 0 ) // if sunny
{
if( CurrentTick % 19 == 0 ) //every 20 ticks random weather
@@ -655,6 +573,90 @@ void cWorld::TickWeather(float a_Dt)
+void cWorld::TickSpawnMobs(float a_Dt)
+{
+ if (!m_bAnimals || (m_Time - m_SpawnMonsterTime <= m_SpawnMonsterRate))
+ {
+ return;
+ }
+
+ m_SpawnMonsterTime = m_Time;
+ Vector3d SpawnPos;
+ {
+ cCSLock Lock(m_CSPlayers);
+ if ( m_Players.size() <= 0)
+ {
+ return;
+ }
+ int RandomPlayerIdx = m_TickRand.randInt() & m_Players.size();
+ cPlayerList::iterator itr = m_Players.begin();
+ for( int i = 1; i < RandomPlayerIdx; i++ )
+ {
+ itr++;
+ }
+ SpawnPos = (*itr)->GetPosition();
+ }
+
+ cMonster * Monster = NULL;
+ int dayRand = m_TickRand.randInt() % 6;
+ int nightRand = m_TickRand.randInt() % 10;
+
+ SpawnPos += Vector3d( (double)(m_TickRand.randInt() % 64) - 32, (double)(m_TickRand.randInt() % 64) - 32, (double)(m_TickRand.randInt() % 64) - 32 );
+ char Height = GetHeight( (int)SpawnPos.x, (int)SpawnPos.z );
+
+ if (m_WorldTime >= 12000 + 1000)
+ {
+ if (nightRand == 0) //random percent to spawn for night
+ Monster = new cSpider();
+ else if (nightRand == 1)
+ Monster = new cZombie();
+ else if (nightRand == 2)
+ Monster = new cEnderman();
+ else if (nightRand == 3)
+ Monster = new cCreeper();
+ else if (nightRand == 4)
+ Monster = new cCavespider();
+ else if (nightRand == 5)
+ Monster = new cGhast();
+ else if (nightRand == 6)
+ Monster = new cZombiepigman();
+ else if (nightRand == 7)
+ Monster = new cSlime();
+ else if (nightRand == 8)
+ Monster = new cSilverfish();
+ else if (nightRand == 9)
+ Monster = new cSkeleton();
+ //end random percent to spawn for night
+ }
+ else
+ {
+ if (dayRand == 0) //random percent to spawn for day
+ Monster = new cChicken();
+ else if (dayRand == 1)
+ Monster = new cCow();
+ else if (dayRand == 2)
+ Monster = new cPig();
+ else if (dayRand == 3)
+ Monster = new cSheep();
+ else if (dayRand == 4)
+ Monster = new cSquid();
+ else if (dayRand == 5)
+ Monster = new cWolf();
+ //end random percent to spawn for day
+ }
+
+ if( Monster )
+ {
+ Monster->Initialize( this );
+ Monster->TeleportTo( SpawnPos.x, (double)(Height) + 2, SpawnPos.z );
+ Monster->SpawnOn(0);
+ }
+}
+
+
+
+
+
void cWorld::GrowTree( int a_X, int a_Y, int a_Z )
{
// new tree code, looks much better
@@ -714,234 +716,234 @@ void cWorld::GrowTree( int a_X, int a_Y, int a_Z )
// end new tree code
}
-void cWorld::UnloadUnusedChunks()
-{
- m_LastUnload = m_Time;
-
- LockChunks();
- LOGINFO("Unloading unused chunks");
- m_ChunkMap->UnloadUnusedChunks();
- UnlockChunks();
-}
-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 )
- {
- return Chunk;
- }
- // Found nothing, create a chunk
- Chunk = new cChunk( a_X, a_Y, a_Z, this );
- if(Chunk)
- {
- LOGWARN("Created new chunk! %i %i", a_X, a_Z);
- LockChunks();
- m_ChunkMap->AddChunk( Chunk );
- UnlockChunks();
- Chunk->Initialize();
- return Chunk;
- }
- // This should never happen since it's reliable, but yeah
- return 0;
-}
-cChunk* cWorld::GetChunk( int a_X, int a_Y, int a_Z )
+void cWorld::UnloadUnusedChunks()
{
- // Get chunk from memory
- cChunk* Chunk = GetChunkUnreliable( a_X, a_Y, a_Z );
- if( Chunk ) return Chunk;
-
-#if 1 // Current thread chunk generation
+ m_LastUnload = m_Time;
+ m_ChunkMap->UnloadUnusedChunks();
+}
- // Found nothing, create a chunk
- Chunk = new cChunk( a_X, a_Y, a_Z, this );
- if(Chunk)
- {
- LOGWARN("Created new chunk! %i %i", a_X, a_Z);
- LockChunks();
- m_ChunkMap->AddChunk( Chunk );
- UnlockChunks();
- Chunk->Initialize();
- return Chunk;
- }
- return 0;
-#else // Async thread generation
- // 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;
-#endif
-}
-ptr_cChunk cWorld::GetChunkUnreliable( int a_X, int a_Y, int a_Z )
-{
- LockChunks();
- ptr_cChunk Chunk( m_ChunkMap->GetChunk( a_X, a_Y, a_Z ) );
- UnlockChunks();
- return Chunk;
-}
-cChunk* cWorld::GetChunkOfBlock( int a_X, int a_Y, int a_Z )
+cChunkPtr cWorld::GetChunkOfBlock( int a_X, int a_Y, int a_Z )
{
int ChunkX, ChunkY, ChunkZ;
AbsoluteToRelative( a_X, a_Y, a_Z, ChunkX, ChunkY, ChunkZ );
return GetChunk( ChunkX, ChunkY, ChunkZ );
}
+
+
+
+
void cWorld::SetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockMeta )
{
int ChunkX, ChunkY, ChunkZ, X = a_X, Y = a_Y, Z = a_Z;
AbsoluteToRelative( X, Y, Z, ChunkX, ChunkY, ChunkZ );
- cChunk* Chunk = GetChunk( ChunkX, ChunkY, ChunkZ );
- if( Chunk )
+ cChunkPtr Chunk = GetChunk( ChunkX, ChunkY, ChunkZ );
+ if ( Chunk->IsValid() )
{
Chunk->SetBlock(X, Y, Z, a_BlockType, a_BlockMeta );
this->GetSimulatorManager()->WakeUp(a_X, a_Y, a_Z);
}
+ // The chunk is not yet initialized, so it's probably far away from all players, no need to store this Meta change
}
+
+
+
+
void cWorld::FastSetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockMeta )
{
int ChunkX, ChunkY, ChunkZ, X = a_X, Y = a_Y, Z = a_Z;
AbsoluteToRelative( X, Y, Z, ChunkX, ChunkY, ChunkZ );
- cChunk* Chunk = GetChunk( ChunkX, ChunkY, ChunkZ );
- if( Chunk )
+ cChunkPtr Chunk = GetChunkNoGen( ChunkX, ChunkY, ChunkZ );
+ if (Chunk->IsValid())
{
Chunk->FastSetBlock(X, Y, Z, a_BlockType, a_BlockMeta );
return;
}
// 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 ) );
+ cCSLock Lock(m_CSFastSetBlock);
+ m_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 )
+
+
+
+
+char cWorld::GetBlock(int a_X, int a_Y, int a_Z)
{
int ChunkX, ChunkY, ChunkZ;
AbsoluteToRelative( a_X, a_Y, a_Z, ChunkX, ChunkY, ChunkZ );
- cChunk* Chunk = GetChunk( ChunkX, ChunkY, ChunkZ );
- if( Chunk ) return Chunk->GetBlock(a_X, a_Y, a_Z);
+ cChunkPtr Chunk = GetChunk( ChunkX, ChunkY, ChunkZ );
+ if ( Chunk->IsValid() )
+ {
+ return Chunk->GetBlock(a_X, a_Y, a_Z);
+ }
return 0;
}
+
+
+
+
char cWorld::GetBlockMeta( int a_X, int a_Y, int a_Z )
{
int ChunkX, ChunkY, ChunkZ;
AbsoluteToRelative( a_X, a_Y, a_Z, ChunkX, ChunkY, ChunkZ );
- cChunk* Chunk = GetChunk( ChunkX, ChunkY, ChunkZ );
- if( Chunk ) return Chunk->GetLight( Chunk->pGetMeta(), a_X, a_Y, a_Z );
+ cChunkPtr Chunk = GetChunk( ChunkX, ChunkY, ChunkZ );
+ if ( Chunk->IsValid() )
+ {
+ 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 )
{
int ChunkX, ChunkY, ChunkZ;
AbsoluteToRelative( a_X, a_Y, a_Z, ChunkX, ChunkY, ChunkZ );
- cChunk* Chunk = GetChunk( ChunkX, ChunkY, ChunkZ );
- if( Chunk )
+ cChunkPtr Chunk = GetChunk( ChunkX, ChunkY, ChunkZ );
+ if ( Chunk->IsValid() )
{
Chunk->SetLight( Chunk->pGetMeta(), a_X, a_Y, a_Z, a_MetaData );
- Chunk->SendBlockTo( a_X, a_Y, a_Z, 0 );
+ Chunk->SendBlockTo( a_X, a_Y, a_Z, NULL );
}
+ // The chunk is not yet initialized, so it's probably far away from all players, no need to store this Meta change
}
+
+
+
+
bool cWorld::DigBlock( int a_X, int a_Y, int a_Z, cItem & a_PickupItem )
{
int PosX = a_X, PosY = a_Y, PosZ = a_Z, ChunkX, ChunkY, ChunkZ;
AbsoluteToRelative( PosX, PosY, PosZ, ChunkX, ChunkY, ChunkZ );
- cChunk* DestChunk = GetChunk( ChunkX, ChunkY, ChunkZ );
- if(DestChunk)
+ cChunkPtr DestChunk = GetChunk( ChunkX, ChunkY, ChunkZ );
+ if (DestChunk->IsValid())
{
DestChunk->SetBlock(PosX, PosY, PosZ, E_BLOCK_AIR, 0 );
GetSimulatorManager()->WakeUp(a_X, a_Y, a_Z);
- if( !a_PickupItem.IsEmpty() )
+ if ( !a_PickupItem.IsEmpty() )
{
- cPickup* Pickup = new cPickup( a_X*32 + 16 + (int)fRadRand(16.f), a_Y*32 + 16 + (int)fRadRand(16.f), a_Z*32 + 16 + (int)fRadRand(16.f), a_PickupItem );
+ cPickup * Pickup = new cPickup( a_X * 32 + 16 + (int)fRadRand(16.f), a_Y * 32 + 16 + (int)fRadRand(16.f), a_Z * 32 + 16 + (int)fRadRand(16.f), a_PickupItem );
Pickup->Initialize( this );
}
}
-
return true;
}
-void cWorld::SendBlockTo( int a_X, int a_Y, int a_Z, cPlayer* a_Player )
+
+
+
+
+void cWorld::SendBlockTo( int a_X, int a_Y, int a_Z, cPlayer * a_Player )
{
int ChunkX, ChunkY, ChunkZ;
AbsoluteToRelative( a_X, a_Y, a_Z, ChunkX, ChunkY, ChunkZ );
- cChunk* Chunk = GetChunk( ChunkX, ChunkY, ChunkZ );
- Chunk->SendBlockTo( a_X, a_Y, a_Z, a_Player->GetClientHandle() );
+ cChunkPtr Chunk = GetChunk( ChunkX, ChunkY, ChunkZ );
+ if (Chunk->IsValid())
+ {
+ Chunk->SendBlockTo( a_X, a_Y, a_Z, a_Player->GetClientHandle() );
+ }
}
-cBlockEntity* cWorld::GetBlockEntity( int a_X, int a_Y, int a_Z )
+
+
+
+
+// TODO: This interface is dangerous!
+cBlockEntity * cWorld::GetBlockEntity( int a_X, int a_Y, int a_Z )
{
int PosX = a_X, PosY = a_Y, PosZ = a_Z, ChunkX, ChunkY, ChunkZ;
AbsoluteToRelative( PosX, PosY, PosZ, ChunkX, ChunkY, ChunkZ );
- cChunk* Chunk = GetChunk( ChunkX, ChunkY, ChunkZ );
- if( !Chunk ) return 0;
-
- return Chunk->GetBlockEntity( a_X, a_Y, a_Z );
+ cChunkPtr Chunk = GetChunk( ChunkX, ChunkY, ChunkZ );
+ if (Chunk->IsValid())
+ {
+ // TODO: return Chunk->GetBlockEntity( a_X, a_Y, a_Z );
+ }
+ return NULL;
}
+
+
+
+
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 );
- if( Chunk ) return Chunk->GetHeight( PosX, PosZ );
+ cChunkPtr Chunk = GetChunk( ChunkX, ChunkY, ChunkZ );
+ if ( Chunk->IsValid())
+ {
+ return Chunk->GetHeight( PosX, PosZ );
+ }
return 0;
}
-const double & cWorld::GetSpawnY()
+
+
+
+
+const double & cWorld::GetSpawnY(void)
{
m_SpawnY = (double)GetHeight( (int)m_SpawnX, (int)m_SpawnZ ) + 1.6f; // +1.6f eye height
return m_SpawnY;
}
-void cWorld::Broadcast( const cPacket & a_Packet, cClientHandle* a_Exclude /* = 0 */ )
+
+
+
+void cWorld::Broadcast( const cPacket & a_Packet, cClientHandle* a_Exclude)
{
- for( PlayerList::iterator itr = m_pState->Players.begin(); itr != m_pState->Players.end(); ++itr)
+ cCSLock Lock(m_CSPlayers);
+ for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{
- if( (*itr)->GetClientHandle() == a_Exclude || !(*itr)->GetClientHandle()->IsLoggedIn() ) continue;
+ if (((*itr)->GetClientHandle() == a_Exclude) || !(*itr)->GetClientHandle()->IsLoggedIn() )
+ {
+ continue;
+ }
(*itr)->GetClientHandle()->Send( a_Packet );
}
}
-std::string cWorld::GetDescription()
-{
- return this->m_Description;
-}
-unsigned int cWorld::GetMaxPlayers()
-{
- return this->m_MaxPlayers;
-}
+
+
void cWorld::SetMaxPlayers(int iMax)
{
- this->m_MaxPlayers = MAX_PLAYERS;
+ m_MaxPlayers = MAX_PLAYERS;
if (iMax > 0 && iMax < MAX_PLAYERS)
{
- this->m_MaxPlayers = iMax;
+ m_MaxPlayers = iMax;
}
}
@@ -951,8 +953,9 @@ void cWorld::SetMaxPlayers(int iMax)
void cWorld::AddPlayer( cPlayer* a_Player )
{
- m_pState->Players.remove( a_Player );
- m_pState->Players.push_back( a_Player );
+ cCSLock Lock(m_CSPlayers);
+ m_Players.remove( a_Player ); // Make sure the player is registered only once
+ m_Players.push_back( a_Player );
}
@@ -961,7 +964,26 @@ void cWorld::AddPlayer( cPlayer* a_Player )
void cWorld::RemovePlayer( cPlayer* a_Player )
{
- m_pState->Players.remove( a_Player );
+ cCSLock Lock(m_CSPlayers);
+ m_Players.remove( a_Player );
+}
+
+
+
+
+
+bool cWorld::ForEachPlayer(cPlayerListCallback * a_Callback)
+{
+ // Calls the callback for each player in the list
+ cCSLock Lock(m_CSPlayers);
+ for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
+ {
+ if (a_Callback->Item(*itr))
+ {
+ return false;
+ }
+ } // for itr - m_Players[]
+ return true;
}
@@ -970,11 +992,12 @@ void cWorld::RemovePlayer( cPlayer* a_Player )
void cWorld::GetAllPlayers( lua_State* L )
{
- lua_createtable(L, m_pState->Players.size(), 0);
+ lua_createtable(L, m_Players.size(), 0);
int newTable = lua_gettop(L);
int index = 1;
- PlayerList::const_iterator iter = m_pState->Players.begin();
- while(iter != m_pState->Players.end()) {
+ cPlayerList::const_iterator iter = m_Players.begin();
+ while(iter != m_Players.end())
+ {
tolua_pushusertype( L, (*iter), "cPlayer" );
lua_rawseti(L, newTable, index);
++iter;
@@ -986,6 +1009,7 @@ void cWorld::GetAllPlayers( lua_State* L )
+// TODO: This interface is dangerous!
cPlayer* cWorld::GetPlayer( const char* a_PlayerName )
{
cPlayer* BestMatch = 0;
@@ -994,12 +1018,13 @@ cPlayer* cWorld::GetPlayer( const char* a_PlayerName )
bool bPerfectMatch = false;
unsigned int NameLength = strlen( a_PlayerName );
- for( PlayerList::iterator itr = m_pState->Players.begin(); itr != m_pState->Players.end(); itr++ )
+ cCSLock Lock(m_CSPlayers);
+ for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); itr++ )
{
std::string Name = (*itr)->GetName();
if( NameLength > Name.length() ) continue; // Definitely not a match
- for(unsigned int i = 0; i < NameLength; i++)
+ for (unsigned int i = 0; i < NameLength; i++)
{
char c1 = (char)toupper( a_PlayerName[i] );
char c2 = (char)toupper( Name[i] );
@@ -1029,65 +1054,91 @@ cPlayer* cWorld::GetPlayer( const char* a_PlayerName )
break;
}
}
- if( NumMatches == 1 )
+ if ( NumMatches == 1 )
+ {
return BestMatch;
+ }
- // More than one matches, so it's undefined. Return 0 instead
- return 0;
+ // More than one matches, so it's undefined. Return NULL instead
+ return NULL;
}
-cEntity* cWorld::GetEntity( int a_UniqueID )
+cPlayer * cWorld::FindClosestPlayer(const Vector3f & a_Pos, float a_SightLimit)
{
- for( EntityList::iterator itr = m_pState->AllEntities.begin(); itr != m_pState->AllEntities.end(); ++itr )
+ cTracer LineOfSight(this);
+
+ float ClosestDistance = a_SightLimit;
+ cPlayer* ClosestPlayer = NULL;
+
+ cCSLock Lock(m_CSPlayers);
+ for (cPlayerList::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{
- if( (*itr)->GetUniqueID() == a_UniqueID )
- return *itr;
+ Vector3f Pos = (*itr)->GetPosition();
+ float Distance = (Pos - a_Pos).Length();
+
+ if (Distance <= a_SightLimit)
+ {
+ if (!LineOfSight.Trace(a_Pos,(Pos - a_Pos),(int)(Pos - a_Pos).Length()))
+ {
+ if (Distance < ClosestDistance)
+ {
+ ClosestDistance = Distance;
+ ClosestPlayer = *itr;
+ }
+ }
+ }
}
- return 0;
+ return ClosestPlayer;
}
-// void cWorld::RemoveClient( cClientHandle* a_Client )
-// {
-// m_pState->m_Clients.remove( a_Client );
-// if( a_Client )
-// {
-// delete a_Client;
-// a_Client = 0;
-// }
-// }
+void cWorld::SendPlayerList(cPlayer * a_DestPlayer)
+{
+ // Sends the playerlist to a_DestPlayer
+ cCSLock Lock(m_CSPlayers);
+ for ( cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
+ {
+ if (((*itr)->GetClientHandle() != NULL) && !((*itr)->GetClientHandle()->IsDestroyed()))
+ {
+ cPacket_PlayerListItem PlayerListItem((*itr)->GetColor() + (*itr)->GetName(), true, (*itr)->GetClientHandle()->GetPing());
+ a_DestPlayer->GetClientHandle()->Send( PlayerListItem );
+ }
+ }
+}
-void cWorld::RemoveEntity( cEntity* a_Entity )
+// TODO: This interface is dangerous!
+cEntity * cWorld::GetEntity( int a_UniqueID )
{
- m_pState->RemoveEntityQueue.remove( a_Entity );
- if( a_Entity )
+ cCSLock Lock(m_CSEntities);
+ for (cEntityList::iterator itr = m_AllEntities.begin(); itr != m_AllEntities.end(); ++itr )
{
- delete a_Entity;
- a_Entity = 0;
+ if( (*itr)->GetUniqueID() == a_UniqueID )
+ {
+ return *itr;
+ }
}
+ return NULL;
}
-bool cWorld::RemoveEntityFromChunk( cEntity & a_Entity, cChunk* a_CalledFrom /* = 0 */ )
+void cWorld::RemoveEntityFromChunk(cEntity * a_Entity)
{
- LockChunks();
- bool retVal = m_ChunkMap->RemoveEntityFromChunk( a_Entity, a_CalledFrom );
- UnlockChunks();
- return retVal;
+ cChunkPtr Chunk = GetChunkOfBlock((int)(a_Entity->GetPosX()), (int)(a_Entity->GetPosY()), (int)(a_Entity->GetPosZ()));
+ Chunk->RemoveEntity(a_Entity);
}
@@ -1098,9 +1149,7 @@ void cWorld::SaveAllChunks()
{
LOG("Saving all chunks...");
m_LastSave = m_Time;
- LockChunks();
m_ChunkMap->SaveAllChunks();
- UnlockChunks();
LOG("Done saving chunks");
}
@@ -1108,79 +1157,21 @@ void cWorld::SaveAllChunks()
-void cWorld::LockClientHandle()
-{
- m_ClientHandleCriticalSection->Lock();
-}
-
-
-
-
-
-void cWorld::UnlockClientHandle()
-{
- m_ClientHandleCriticalSection->Unlock();
-}
-
-
-
-
-
-void cWorld::LockEntities()
-{
- m_EntitiesCriticalSection->Lock();
-}
-
-
-
-
-
-void cWorld::UnlockEntities()
-{
- m_EntitiesCriticalSection->Unlock();
-}
-
-
-
-
-
-void cWorld::LockChunks()
-{
- m_ChunksCriticalSection->Lock();
-}
-
-
-
-
-
-void cWorld::UnlockChunks()
+void cWorld::ReSpreadLighting( const cChunkPtr & a_Chunk )
{
- m_ChunksCriticalSection->Unlock();
+ cCSLock Lock(m_CSLighting);
+ m_SpreadQueue.remove( a_Chunk );
+ m_SpreadQueue.push_back( a_Chunk );
}
-void cWorld::ReSpreadLighting( const ptr_cChunk& a_Chunk )
+void cWorld::RemoveSpread( const cChunkPtr & a_Chunk )
{
- LockChunks();
- m_pState->SpreadQueue.remove( a_Chunk );
- m_pState->SpreadQueue.push_back( a_Chunk );
- //#define STRINGIZE(x) #x
- //a_Chunk->AddReference( __FILE__ ": " STRINGIZE(__LINE__) );
- UnlockChunks();
-}
-
-
-
-
-
-void cWorld::RemoveSpread( const ptr_cChunk& a_Chunk )
-{
- LockChunks();
- m_pState->SpreadQueue.remove( a_Chunk );
- UnlockChunks();
+ cCSLock Lock(m_CSLighting);
+ m_SpreadQueue.remove( a_Chunk );
}
@@ -1192,38 +1183,21 @@ void cWorld::RemoveSpread( const ptr_cChunk& a_Chunk )
/************************************************************************/
// void cWorld::AddClient( cClientHandle* a_Client )
// {
-// m_pState->m_Clients.push_back( a_Client );
+// m_m_Clients.push_back( a_Client );
// }
// cWorld::ClientList & cWorld::GetClients()
// {
-// return m_pState->m_Clients;
+// return m_m_Clients;
// }
-cWorld::EntityList & cWorld::GetEntities()
-{
- return m_pState->AllEntities;
-}
-
-
-
-
-
void cWorld::AddEntity( cEntity* a_Entity )
{
- m_pState->AllEntities.push_back( a_Entity );
-}
-
-
-
-
-
-cWorld::PlayerList & cWorld::GetAllPlayers()
-{
- return m_pState->Players;
+ cCSLock Lock(m_CSEntities);
+ m_AllEntities.push_back( a_Entity );
}
@@ -1232,38 +1206,17 @@ cWorld::PlayerList & cWorld::GetAllPlayers()
unsigned int cWorld::GetNumPlayers()
{
- return m_pState->Players.size();
-}
-
-
-
-
-
-void cWorld::AddToRemoveEntityQueue( cEntity & a_Entity )
-{
- m_pState->AllEntities.remove( &a_Entity);
- m_pState->RemoveEntityQueue.push_back( &a_Entity );
-}
-
-
-
-
-
-const char* cWorld::GetName()
-{
- return m_pState->WorldName.c_str();
+ cCSLock Lock(m_CSPlayers);
+ return m_Players.size();
}
-int cWorld::GetNumChunks(void)
+int cWorld::GetNumChunks(void) const
{
- LockChunks();
- int NumChunks = m_ChunkMap->GetNumChunks();
- UnlockChunks();
- return NumChunks;
+ return m_ChunkMap->GetNumChunks();
}