summaryrefslogtreecommitdiffstats
path: root/src/World.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/World.cpp')
-rw-r--r--src/World.cpp95
1 files changed, 63 insertions, 32 deletions
diff --git a/src/World.cpp b/src/World.cpp
index 4ddd11f59..7ad350e24 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -11,6 +11,7 @@
#include "ChunkMap.h"
#include "Generating/ChunkDesc.h"
#include "OSSupport/Timer.h"
+#include "SetChunkData.h"
// Serializers
#include "WorldStorage/ScoreboardSerializer.h"
@@ -719,6 +720,17 @@ void cWorld::Tick(float a_Dt, int a_LastTickDurationMSec)
// Call the plugins
cPluginManager::Get()->CallHookWorldTick(*this, a_Dt, a_LastTickDurationMSec);
+ // Set any chunk data that has been queued for setting:
+ cSetChunkDataPtrs SetChunkDataQueue;
+ {
+ cCSLock Lock(m_CSSetChunkDataQueue);
+ std::swap(SetChunkDataQueue, m_SetChunkDataQueue);
+ }
+ for (cSetChunkDataPtrs::iterator itr = SetChunkDataQueue.begin(), end = SetChunkDataQueue.end(); itr != end; ++itr)
+ {
+ SetChunkData(**itr);
+ } // for itr - SetChunkDataQueue[]
+
// We need sub-tick precision here, that's why we store the time in seconds and calculate ticks off of it
m_WorldAgeSecs += (double)a_Dt / 1000.0;
m_TimeOfDaySecs += (double)a_Dt / 1000.0;
@@ -2217,47 +2229,59 @@ void cWorld::MarkChunkSaved (int a_ChunkX, int a_ChunkZ)
-void cWorld::SetChunkData(
- int a_ChunkX, int a_ChunkZ,
- const BLOCKTYPE * a_BlockTypes,
- 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,
- bool a_MarkDirty
-)
+void cWorld::QueueSetChunkData(const cSetChunkDataPtr & a_SetChunkData)
{
// Validate biomes, if needed:
- cChunkDef::BiomeMap BiomeMap;
- const cChunkDef::BiomeMap * Biomes = a_BiomeMap;
- if (a_BiomeMap == NULL)
+ if (!a_SetChunkData->AreBiomesValid())
{
// The biomes are not assigned, get them from the generator:
- Biomes = &BiomeMap;
- m_Generator.GenerateBiomes(a_ChunkX, a_ChunkZ, BiomeMap);
+ m_Generator.GenerateBiomes(a_SetChunkData->GetChunkX(), a_SetChunkData->GetChunkZ(), a_SetChunkData->GetBiomes());
+ a_SetChunkData->MarkBiomesValid();
}
- m_ChunkMap->SetChunkData(
- a_ChunkX, a_ChunkZ,
- a_BlockTypes, a_BlockMeta, a_BlockLight, a_BlockSkyLight,
- a_HeightMap, *Biomes,
- a_BlockEntities,
- a_MarkDirty
- );
+ // Validate heightmap, if needed:
+ if (!a_SetChunkData->IsHeightMapValid())
+ {
+ a_SetChunkData->CalculateHeightMap();
+ }
+
+ // Store a copy of the data in the queue:
+ // TODO: If the queue is too large, wait for it to get processed. Not likely, though.
+ cCSLock Lock(m_CSSetChunkDataQueue);
+ m_SetChunkDataQueue.push_back(a_SetChunkData);
+}
+
+
+
+
+
+void cWorld::SetChunkData(cSetChunkData & a_SetChunkData)
+{
+ ASSERT(a_SetChunkData.AreBiomesValid());
+ ASSERT(a_SetChunkData.IsHeightMapValid());
+
+ m_ChunkMap->SetChunkData(a_SetChunkData);
// Initialize the entities (outside the m_ChunkMap's CS, to fix FS #347):
- for (cEntityList::iterator itr = a_Entities.begin(), end = a_Entities.end(); itr != end; ++itr)
+ cEntityList Entities;
+ std::swap(a_SetChunkData.GetEntities(), Entities);
+ for (cEntityList::iterator itr = Entities.begin(), end = Entities.end(); itr != end; ++itr)
{
(*itr)->Initialize(*this);
}
// If a client is requesting this chunk, send it to them:
- if (m_ChunkMap->HasChunkAnyClients(a_ChunkX, a_ChunkZ))
+ int ChunkX = a_SetChunkData.GetChunkX();
+ int ChunkZ = a_SetChunkData.GetChunkZ();
+ if (m_ChunkMap->HasChunkAnyClients(ChunkX, ChunkZ))
+ {
+ m_ChunkSender.ChunkReady(ChunkX, ChunkZ);
+ }
+
+ // Save the chunk right after generating, so that we don't have to generate it again on next run
+ if (a_SetChunkData.ShouldMarkDirty())
{
- m_ChunkSender.ChunkReady(a_ChunkX, a_ChunkZ);
+ m_Storage.QueueSaveChunk(ChunkX, 0, ChunkZ);
}
}
@@ -2975,21 +2999,31 @@ int cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eTyp
int cWorld::SpawnMobFinalize(cMonster * a_Monster)
{
+ // Invalid cMonster object. Bail out.
if (!a_Monster)
+ {
return -1;
+ }
+
+ // Give the mob full health.
a_Monster->SetHealth(a_Monster->GetMaxHealth());
+
+ // A plugin doesn't agree with the spawn. bail out.
if (cPluginManager::Get()->CallHookSpawningMonster(*this, *a_Monster))
{
delete a_Monster;
a_Monster = NULL;
return -1;
}
+
+ // Initialize the monster into the current world.
if (!a_Monster->Initialize(*this))
{
delete a_Monster;
a_Monster = NULL;
return -1;
}
+
BroadcastSpawnEntity(*a_Monster);
cPluginManager::Get()->CallHookSpawnedMonster(*this, *a_Monster);
@@ -3285,17 +3319,14 @@ void cWorld::cChunkGeneratorCallbacks::OnChunkGenerated(cChunkDesc & a_ChunkDesc
cChunkDef::BlockNibbles BlockMetas;
a_ChunkDesc.CompressBlockMetas(BlockMetas);
- m_World->SetChunkData(
+ m_World->QueueSetChunkData(cSetChunkDataPtr(new cSetChunkData(
a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ(),
a_ChunkDesc.GetBlockTypes(), BlockMetas,
NULL, NULL, // We don't have lighting, chunk will be lighted when needed
&a_ChunkDesc.GetHeightMap(), &a_ChunkDesc.GetBiomeMap(),
a_ChunkDesc.GetEntities(), a_ChunkDesc.GetBlockEntities(),
true
- );
-
- // Save the chunk right after generating, so that we don't have to generate it again on next run
- m_World->GetStorage().QueueSaveChunk(a_ChunkDesc.GetChunkX(), 0, a_ChunkDesc.GetChunkZ());
+ )));
}