Implemented synchronous chunk loading; optimized cChunkStay interface for speed (though still unused ;)
git-svn-id: http://mc-server.googlecode.com/svn/trunk@336 0a769ca7-a7f5-676a-18bf-c427514a06d6
This commit is contained in:
parent
bccd52530f
commit
230f98a774
@ -60,15 +60,15 @@ cWSSCompact::~cWSSCompact()
|
||||
|
||||
bool cWSSCompact::LoadChunk(const cChunkCoords & a_Chunk)
|
||||
{
|
||||
cPAKFile * f = LoadPAKFile(a_Chunk);
|
||||
if (f == NULL)
|
||||
AString ChunkData;
|
||||
int UncompressedSize = 0;
|
||||
if (!GetChunkData(a_Chunk, UncompressedSize, ChunkData))
|
||||
{
|
||||
// For some reason we couldn't locate the file
|
||||
LOG("Cannot locate a proper PAK file for chunk [%d, %d]", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ);
|
||||
// The reason for failure is already printed in GetChunkData()
|
||||
return false;
|
||||
}
|
||||
|
||||
return f->LoadChunk(a_Chunk, m_World);
|
||||
return LoadChunkFromData(a_Chunk, UncompressedSize, ChunkData, m_World);
|
||||
}
|
||||
|
||||
|
||||
@ -77,6 +77,8 @@ bool cWSSCompact::LoadChunk(const cChunkCoords & a_Chunk)
|
||||
|
||||
bool cWSSCompact::SaveChunk(const cChunkCoords & a_Chunk)
|
||||
{
|
||||
cCSLock Lock(m_CS);
|
||||
|
||||
cPAKFile * f = LoadPAKFile(a_Chunk);
|
||||
if (f == NULL)
|
||||
{
|
||||
@ -93,6 +95,8 @@ bool cWSSCompact::SaveChunk(const cChunkCoords & a_Chunk)
|
||||
|
||||
cWSSCompact::cPAKFile * cWSSCompact::LoadPAKFile(const cChunkCoords & a_Chunk)
|
||||
{
|
||||
// ASSUMES that m_CS has been locked
|
||||
|
||||
// We need to retain this weird conversion code, because some edge chunks are in the wrong PAK file
|
||||
const int LayerX = (int)(floorf((float)a_Chunk.m_ChunkX / 32.0f));
|
||||
const int LayerZ = (int)(floorf((float)a_Chunk.m_ChunkZ / 32.0f));
|
||||
@ -136,6 +140,121 @@ cWSSCompact::cPAKFile * cWSSCompact::LoadPAKFile(const cChunkCoords & a_Chunk)
|
||||
|
||||
|
||||
|
||||
bool cWSSCompact::GetChunkData(const cChunkCoords & a_Chunk, int & a_UncompressedSize, AString & a_Data)
|
||||
{
|
||||
cCSLock Lock(m_CS);
|
||||
cPAKFile * f = LoadPAKFile(a_Chunk);
|
||||
if (f == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return f->GetChunkData(a_Chunk, a_UncompressedSize, a_Data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
// TODO: Rewrite saving to use the same principles as loading
|
||||
bool cWSSCompact::SetChunkData(const cChunkCoords & a_Chunk, int a_UncompressedSize, const AString & a_Data)
|
||||
{
|
||||
cCSLock Lock(m_CS);
|
||||
cPAKFile * f = LoadPAKFile(a_Chunk);
|
||||
if (f == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return f->SetChunkData(a_Chunk, a_UncompressedSize, a_Data);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cWSSCompact::EraseChunkData(const cChunkCoords & a_Chunk)
|
||||
{
|
||||
cCSLock Lock(m_CS);
|
||||
cPAKFile * f = LoadPAKFile(a_Chunk);
|
||||
if (f == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return f->EraseChunkData(a_Chunk);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWSSCompact::LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities, cWorld * a_World)
|
||||
{
|
||||
// Load chests
|
||||
Json::Value AllChests = a_Value.get("Chests", Json::nullValue);
|
||||
if (!AllChests.empty())
|
||||
{
|
||||
for (Json::Value::iterator itr = AllChests.begin(); itr != AllChests.end(); ++itr )
|
||||
{
|
||||
Json::Value & Chest = *itr;
|
||||
cChestEntity * ChestEntity = new cChestEntity(0,0,0, a_World);
|
||||
if (!ChestEntity->LoadFromJson( Chest ) )
|
||||
{
|
||||
LOGERROR("ERROR READING CHEST FROM JSON!" );
|
||||
delete ChestEntity;
|
||||
}
|
||||
else
|
||||
{
|
||||
a_BlockEntities.push_back( ChestEntity );
|
||||
}
|
||||
} // for itr - AllChests[]
|
||||
}
|
||||
|
||||
// Load furnaces
|
||||
Json::Value AllFurnaces = a_Value.get("Furnaces", Json::nullValue);
|
||||
if( !AllFurnaces.empty() )
|
||||
{
|
||||
for( Json::Value::iterator itr = AllFurnaces.begin(); itr != AllFurnaces.end(); ++itr )
|
||||
{
|
||||
Json::Value & Furnace = *itr;
|
||||
cFurnaceEntity * FurnaceEntity = new cFurnaceEntity(0,0,0, a_World);
|
||||
if( !FurnaceEntity->LoadFromJson( Furnace ) )
|
||||
{
|
||||
LOGERROR("ERROR READING FURNACE FROM JSON!" );
|
||||
delete FurnaceEntity;
|
||||
}
|
||||
else
|
||||
{
|
||||
a_BlockEntities.push_back( FurnaceEntity );
|
||||
}
|
||||
} // for itr - AllFurnaces[]
|
||||
}
|
||||
|
||||
// Load signs
|
||||
Json::Value AllSigns = a_Value.get("Signs", Json::nullValue);
|
||||
if( !AllSigns.empty() )
|
||||
{
|
||||
for( Json::Value::iterator itr = AllSigns.begin(); itr != AllSigns.end(); ++itr )
|
||||
{
|
||||
Json::Value & Sign = *itr;
|
||||
cSignEntity * SignEntity = new cSignEntity( E_BLOCK_SIGN_POST, 0,0,0, a_World);
|
||||
if ( !SignEntity->LoadFromJson( Sign ) )
|
||||
{
|
||||
LOGERROR("ERROR READING SIGN FROM JSON!" );
|
||||
delete SignEntity;
|
||||
}
|
||||
else
|
||||
{
|
||||
a_BlockEntities.push_back( SignEntity );
|
||||
}
|
||||
} // for itr - AllSigns[]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cWSSCompact::cPAKFile
|
||||
|
||||
@ -214,7 +333,7 @@ cWSSCompact::cPAKFile::~cPAKFile()
|
||||
|
||||
|
||||
|
||||
bool cWSSCompact::cPAKFile::LoadChunk(const cChunkCoords & a_Chunk, cWorld * a_World)
|
||||
bool cWSSCompact::cPAKFile::GetChunkData(const cChunkCoords & a_Chunk, int & a_UncompressedSize, AString & a_Data)
|
||||
{
|
||||
int ChunkX = a_Chunk.m_ChunkX;
|
||||
int ChunkZ = a_Chunk.m_ChunkZ;
|
||||
@ -235,7 +354,9 @@ bool cWSSCompact::cPAKFile::LoadChunk(const cChunkCoords & a_Chunk, cWorld * a_W
|
||||
return false;
|
||||
}
|
||||
|
||||
return LoadChunk(a_Chunk, Offset, Header, a_World);
|
||||
a_UncompressedSize = Header->m_UncompressedSize;
|
||||
a_Data.assign(m_DataContents, Offset, Header->m_CompressedSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -259,39 +380,36 @@ bool cWSSCompact::cPAKFile::SaveChunk(const cChunkCoords & a_Chunk, cWorld * a_W
|
||||
|
||||
|
||||
|
||||
bool cWSSCompact::cPAKFile::LoadChunk(const cChunkCoords & a_Chunk, int a_Offset, sChunkHeader * a_Header, cWorld * a_World)
|
||||
bool cWSSCompact::LoadChunkFromData(const cChunkCoords & a_Chunk, int & a_UncompressedSize, const AString & a_Data, cWorld * a_World)
|
||||
{
|
||||
// Crude data integrity check:
|
||||
if (a_Header->m_UncompressedSize < cChunk::c_BlockDataSize)
|
||||
if (a_UncompressedSize < cChunk::c_BlockDataSize)
|
||||
{
|
||||
LOGWARNING("Chunk [%d, %d] has too short decompressed data (%d out of %d needed), erasing",
|
||||
LOGWARNING("Chunk [%d, %d] has too short decompressed data (%d bytes out of %d needed), erasing",
|
||||
a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ,
|
||||
a_Header->m_UncompressedSize, cChunk::c_BlockDataSize
|
||||
a_UncompressedSize, cChunk::c_BlockDataSize
|
||||
);
|
||||
EraseChunk(a_Chunk);
|
||||
m_NumDirty++;
|
||||
EraseChunkData(a_Chunk);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Decompress the data:
|
||||
AString UncompressedData;
|
||||
int errorcode = UncompressString(m_DataContents.data() + a_Offset, a_Header->m_CompressedSize, UncompressedData, a_Header->m_UncompressedSize);
|
||||
int errorcode = UncompressString(a_Data.data(), a_Data.size(), UncompressedData, a_UncompressedSize);
|
||||
if (errorcode != Z_OK)
|
||||
{
|
||||
LOGERROR("Error %d decompressing data for chunk [%d, %d] from file \"%s\"",
|
||||
LOGERROR("Error %d decompressing data for chunk [%d, %d]",
|
||||
errorcode,
|
||||
a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ,
|
||||
m_FileName.c_str()
|
||||
a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a_Header->m_UncompressedSize != (int)UncompressedData.size())
|
||||
if (a_UncompressedSize != (int)UncompressedData.size())
|
||||
{
|
||||
LOGWARNING("Uncompressed data size differs (exp %d, got %d) for chunk [%d, %d] from file \"%s\"",
|
||||
a_Header->m_UncompressedSize, UncompressedData.size(),
|
||||
a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ,
|
||||
m_FileName.c_str()
|
||||
LOGWARNING("Uncompressed data size differs (exp %d bytes, got %d) for chunk [%d, %d]",
|
||||
a_UncompressedSize, UncompressedData.size(),
|
||||
a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@ -299,13 +417,15 @@ bool cWSSCompact::cPAKFile::LoadChunk(const cChunkCoords & a_Chunk, int a_Offset
|
||||
cEntityList Entities;
|
||||
cBlockEntityList BlockEntities;
|
||||
|
||||
if (a_Header->m_UncompressedSize > cChunk::c_BlockDataSize ) // We gots some extra data :D
|
||||
if (a_UncompressedSize > cChunk::c_BlockDataSize)
|
||||
{
|
||||
Json::Value root; // will contain the root value after parsing.
|
||||
Json::Reader reader;
|
||||
if ( !reader.parse( UncompressedData.data() + cChunk::c_BlockDataSize, root, false ) )
|
||||
{
|
||||
LOGERROR("Failed to parse trailing JSON!");
|
||||
LOGERROR("Failed to parse trailing JSON in chunk [%d, %d]!",
|
||||
a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -322,7 +442,7 @@ bool cWSSCompact::cPAKFile::LoadChunk(const cChunkCoords & a_Chunk, int a_Offset
|
||||
|
||||
|
||||
|
||||
void cWSSCompact::cPAKFile::EraseChunk(const cChunkCoords & a_Chunk)
|
||||
bool cWSSCompact::cPAKFile::EraseChunkData(const cChunkCoords & a_Chunk)
|
||||
{
|
||||
int ChunkX = a_Chunk.m_ChunkX;
|
||||
int ChunkZ = a_Chunk.m_ChunkZ;
|
||||
@ -334,10 +454,12 @@ void cWSSCompact::cPAKFile::EraseChunk(const cChunkCoords & a_Chunk)
|
||||
m_DataContents.erase(Offset, (*itr)->m_CompressedSize);
|
||||
delete *itr;
|
||||
itr = m_ChunkHeaders.erase(itr);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
Offset += (*itr)->m_CompressedSize;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -376,7 +498,7 @@ bool cWSSCompact::cPAKFile::SaveChunkToData(const cChunkCoords & a_Chunk, cWorld
|
||||
}
|
||||
|
||||
// Erase any existing data for the chunk:
|
||||
EraseChunk(a_Chunk);
|
||||
EraseChunkData(a_Chunk);
|
||||
|
||||
// Save the header:
|
||||
sChunkHeader * Header = new sChunkHeader;
|
||||
@ -438,70 +560,3 @@ void cWSSCompact::cPAKFile::SynchronizeFile(void)
|
||||
|
||||
|
||||
|
||||
|
||||
void cWSSCompact::cPAKFile::LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities, cWorld * a_World)
|
||||
{
|
||||
// Load chests
|
||||
Json::Value AllChests = a_Value.get("Chests", Json::nullValue);
|
||||
if (!AllChests.empty())
|
||||
{
|
||||
for (Json::Value::iterator itr = AllChests.begin(); itr != AllChests.end(); ++itr )
|
||||
{
|
||||
Json::Value & Chest = *itr;
|
||||
cChestEntity * ChestEntity = new cChestEntity(0,0,0, a_World);
|
||||
if (!ChestEntity->LoadFromJson( Chest ) )
|
||||
{
|
||||
LOGERROR("ERROR READING CHEST FROM JSON!" );
|
||||
delete ChestEntity;
|
||||
}
|
||||
else
|
||||
{
|
||||
a_BlockEntities.push_back( ChestEntity );
|
||||
}
|
||||
} // for itr - AllChests[]
|
||||
}
|
||||
|
||||
// Load furnaces
|
||||
Json::Value AllFurnaces = a_Value.get("Furnaces", Json::nullValue);
|
||||
if( !AllFurnaces.empty() )
|
||||
{
|
||||
for( Json::Value::iterator itr = AllFurnaces.begin(); itr != AllFurnaces.end(); ++itr )
|
||||
{
|
||||
Json::Value & Furnace = *itr;
|
||||
cFurnaceEntity * FurnaceEntity = new cFurnaceEntity(0,0,0, a_World);
|
||||
if( !FurnaceEntity->LoadFromJson( Furnace ) )
|
||||
{
|
||||
LOGERROR("ERROR READING FURNACE FROM JSON!" );
|
||||
delete FurnaceEntity;
|
||||
}
|
||||
else
|
||||
{
|
||||
a_BlockEntities.push_back( FurnaceEntity );
|
||||
}
|
||||
} // for itr - AllFurnaces[]
|
||||
}
|
||||
|
||||
// Load signs
|
||||
Json::Value AllSigns = a_Value.get("Signs", Json::nullValue);
|
||||
if( !AllSigns.empty() )
|
||||
{
|
||||
for( Json::Value::iterator itr = AllSigns.begin(); itr != AllSigns.end(); ++itr )
|
||||
{
|
||||
Json::Value & Sign = *itr;
|
||||
cSignEntity * SignEntity = new cSignEntity( E_BLOCK_SIGN_POST, 0,0,0, a_World);
|
||||
if ( !SignEntity->LoadFromJson( Sign ) )
|
||||
{
|
||||
LOGERROR("ERROR READING SIGN FROM JSON!" );
|
||||
delete SignEntity;
|
||||
}
|
||||
else
|
||||
{
|
||||
a_BlockEntities.push_back( SignEntity );
|
||||
}
|
||||
} // for itr - AllSigns[]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -37,6 +37,10 @@ protected:
|
||||
cPAKFile(const AString & a_FileName, int a_LayerX, int a_LayerZ);
|
||||
~cPAKFile();
|
||||
|
||||
bool GetChunkData(const cChunkCoords & a_Chunk, int & a_UncompressedSize, AString & a_Data);
|
||||
bool SetChunkData(const cChunkCoords & a_Chunk, int a_UncompressedSize, const AString & a_Data);
|
||||
bool EraseChunkData(const cChunkCoords & a_Chunk);
|
||||
|
||||
bool SaveChunk(const cChunkCoords & a_Chunk, cWorld * a_World);
|
||||
bool LoadChunk(const cChunkCoords & a_Chunk, cWorld * a_World);
|
||||
|
||||
@ -55,19 +59,32 @@ protected:
|
||||
int m_NumDirty; // Number of chunks that were written into m_DataContents but not into the file
|
||||
|
||||
bool LoadChunk(const cChunkCoords & a_Chunk, int a_Offset, sChunkHeader * a_Header, cWorld * a_World);
|
||||
void EraseChunk(const cChunkCoords & a_Chunk); // Erases the chunk data from m_DataContents and updates m_ChunkHeaders
|
||||
bool SaveChunkToData(const cChunkCoords & a_Chunk, cWorld * a_World); // Saves the chunk to m_DataContents, updates headers and m_NumDirty
|
||||
void SynchronizeFile(void); // Writes m_DataContents along with the headers to file, resets m_NumDirty
|
||||
void LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities, cWorld * a_World);
|
||||
} ;
|
||||
|
||||
typedef std::list<cPAKFile *> cPAKFiles;
|
||||
|
||||
cCriticalSection m_CS;
|
||||
cPAKFiles m_PAKFiles; // A MRU cache of PAK files
|
||||
|
||||
/// Loads the correct PAK file either from cache or from disk, manages the m_PAKFiles cache
|
||||
cPAKFile * LoadPAKFile(const cChunkCoords & a_Chunk);
|
||||
|
||||
/// Gets chunk data from the correct file; locks CS as needed
|
||||
bool GetChunkData(const cChunkCoords & a_Chunk, int & a_UncompressedSize, AString & a_Data);
|
||||
|
||||
/// Sets chunk data to the correct file; locks CS as needed
|
||||
bool SetChunkData(const cChunkCoords & a_Chunk, int a_UncompressedSize, const AString & a_Data);
|
||||
|
||||
/// Erases chunk data from the correct file; locks CS as needed
|
||||
bool EraseChunkData(const cChunkCoords & a_Chunk);
|
||||
|
||||
/// Loads the chunk from the data (no locking needed)
|
||||
bool LoadChunkFromData(const cChunkCoords & a_Chunk, int & a_UncompressedSize, const AString & a_Data, cWorld * a_World);
|
||||
|
||||
void LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities, cWorld * a_World);
|
||||
|
||||
// cWSSchema overrides:
|
||||
virtual bool LoadChunk(const cChunkCoords & a_Chunk) override;
|
||||
virtual bool SaveChunk(const cChunkCoords & a_Chunk) override;
|
||||
|
@ -335,7 +335,8 @@ bool cWorldStorage::LoadOneChunk(void)
|
||||
}
|
||||
HasMore = (m_LoadQueue.size() > 0);
|
||||
}
|
||||
if (ShouldLoad && !LoadChunk(cChunkCoords(ToLoad.m_ChunkX, ToLoad.m_ChunkY, ToLoad.m_ChunkZ)))
|
||||
|
||||
if (ShouldLoad && !LoadChunk(ToLoad.m_ChunkX, ToLoad.m_ChunkY, ToLoad.m_ChunkZ))
|
||||
{
|
||||
if (ToLoad.m_Generate)
|
||||
{
|
||||
@ -389,22 +390,26 @@ bool cWorldStorage::SaveOneChunk(void)
|
||||
|
||||
|
||||
|
||||
bool cWorldStorage::LoadChunk(const cChunkCoords & a_Chunk)
|
||||
bool cWorldStorage::LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
||||
{
|
||||
if (m_World->IsChunkValid(a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ))
|
||||
if (m_World->IsChunkValid(a_ChunkX, a_ChunkY, a_ChunkZ))
|
||||
{
|
||||
// Already loaded (can happen, since the queue is async)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_SaveSchema->LoadChunk(a_Chunk))
|
||||
cChunkCoords Coords(a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||
|
||||
// First try the schema that is used for saving
|
||||
if (m_SaveSchema->LoadChunk(Coords))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// If it didn't have the chunk, try all the other schemas:
|
||||
for (cWSSchemaList::iterator itr = m_Schemas.begin(); itr != m_Schemas.end(); ++itr)
|
||||
{
|
||||
if (((*itr) != m_SaveSchema) && (*itr)->LoadChunk(a_Chunk))
|
||||
if (((*itr) != m_SaveSchema) && (*itr)->LoadChunk(Coords))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -100,6 +100,9 @@ public:
|
||||
void QueueLoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, bool a_Generate); // Queues the chunk for loading; if not loaded, the chunk will be generated if a_Generate is true
|
||||
void QueueSaveChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||
|
||||
/// Loads the chunk specified; returns true on success, false on failure
|
||||
bool LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||
|
||||
void UnqueueLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||
void UnqueueSave(const cChunkCoords & a_Chunk);
|
||||
|
||||
@ -150,9 +153,6 @@ protected:
|
||||
|
||||
/// Saves one chunk from the queue (if any queued); returns true if there are more chunks in the save queue
|
||||
bool SaveOneChunk(void);
|
||||
|
||||
/// Loads the chunk specified; returns true on success, false on failure
|
||||
bool LoadChunk(const cChunkCoords & a_Chunk);
|
||||
} ;
|
||||
|
||||
|
||||
|
@ -106,12 +106,12 @@ cChunkMap::cChunkLayer * cChunkMap::GetLayerForChunk( int a_ChunkX, int a_ChunkZ
|
||||
|
||||
cChunkPtr cChunkMap::GetChunk( int a_ChunkX, int a_ChunkY, int a_ChunkZ )
|
||||
{
|
||||
cCSLock Lock(m_CSLayers);
|
||||
// No need to lock m_CSLayers, since it's already locked by the operation that called us
|
||||
cChunkLayer * Layer = GetLayerForChunk( a_ChunkX, a_ChunkZ );
|
||||
if (Layer == NULL)
|
||||
{
|
||||
// An error must have occurred, since layers are automatically created if they don't exist
|
||||
return cChunkPtr();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cChunkPtr Chunk = Layer->GetChunk(a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||
@ -132,12 +132,12 @@ cChunkPtr cChunkMap::GetChunk( int a_ChunkX, int a_ChunkY, int a_ChunkZ )
|
||||
|
||||
cChunkPtr cChunkMap::GetChunkNoGen( int a_ChunkX, int a_ChunkY, int a_ChunkZ )
|
||||
{
|
||||
cCSLock Lock(m_CSLayers);
|
||||
// No need to lock m_CSLayers, since it's already locked by the operation that called us
|
||||
cChunkLayer * Layer = GetLayerForChunk( a_ChunkX, a_ChunkZ );
|
||||
if (Layer == NULL)
|
||||
{
|
||||
// An error must have occurred, since layers are automatically created if they don't exist
|
||||
return cChunkPtr();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cChunkPtr Chunk = Layer->GetChunk(a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||
@ -157,6 +157,23 @@ cChunkPtr cChunkMap::GetChunkNoGen( int a_ChunkX, int a_ChunkY, int a_ChunkZ )
|
||||
|
||||
|
||||
|
||||
cChunkPtr cChunkMap::GetChunkNoLoad( int a_ChunkX, int a_ChunkY, int a_ChunkZ )
|
||||
{
|
||||
// No need to lock m_CSLayers, since it's already locked by the operation that called us
|
||||
cChunkLayer * Layer = GetLayerForChunk( a_ChunkX, a_ChunkZ );
|
||||
if (Layer == NULL)
|
||||
{
|
||||
// An error must have occurred, since layers are automatically created if they don't exist
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return Layer->GetChunk(a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkMap::BroadcastToChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const cPacket & a_Packet, cClientHandle * a_Exclude)
|
||||
{
|
||||
// Broadcasts a_Packet to all clients in the chunk where block [x, y, z] is, except to client a_Exclude
|
||||
@ -261,7 +278,7 @@ void cChunkMap::MarkChunkSaved (int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
||||
void cChunkMap::ChunkDataLoaded(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities)
|
||||
{
|
||||
cCSLock Lock(m_CSLayers);
|
||||
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||
cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||
if (Chunk == NULL)
|
||||
{
|
||||
return;
|
||||
@ -277,7 +294,7 @@ void cChunkMap::ChunkDataLoaded(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const
|
||||
void cChunkMap::ChunkDataGenerated(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities)
|
||||
{
|
||||
cCSLock Lock(m_CSLayers);
|
||||
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||
cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||
if (Chunk == NULL)
|
||||
{
|
||||
return;
|
||||
@ -329,13 +346,7 @@ bool cChunkMap::GetChunkBlocks(int a_ChunkX, int a_ChunkY, int a_ChunkZ, char *
|
||||
bool cChunkMap::IsChunkValid(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
||||
{
|
||||
cCSLock Lock(m_CSLayers);
|
||||
cChunkLayer * Layer = GetLayerForChunk( a_ChunkX, a_ChunkZ );
|
||||
if (Layer == NULL)
|
||||
{
|
||||
// An error must have occurred, since layers are automatically created if they don't exist
|
||||
return false;
|
||||
}
|
||||
cChunkPtr Chunk = Layer->GetChunk(a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||
cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||
return (Chunk != NULL) && Chunk->IsValid();
|
||||
}
|
||||
|
||||
@ -405,6 +416,7 @@ void cChunkMap::FastSetBlocks(sSetBlockList & a_BlockList)
|
||||
{
|
||||
int ChunkX = a_BlockList.front().ChunkX;
|
||||
int ChunkZ = a_BlockList.front().ChunkZ;
|
||||
cCSLock Lock(m_CSLayers);
|
||||
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
|
||||
if ((Chunk != NULL) && Chunk->IsValid())
|
||||
{
|
||||
@ -477,7 +489,7 @@ char cChunkMap::GetBlock(int a_X, int a_Y, int a_Z)
|
||||
AbsoluteToRelative( a_X, a_Y, a_Z, ChunkX, ChunkZ );
|
||||
|
||||
cCSLock Lock(m_CSLayers);
|
||||
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
|
||||
cChunkPtr Chunk = GetChunk(ChunkX, ZERO_CHUNK_Y, ChunkZ);
|
||||
if ((Chunk != NULL) && Chunk->IsValid())
|
||||
{
|
||||
return Chunk->GetBlock(a_X, a_Y, a_Z);
|
||||
@ -653,7 +665,7 @@ void cChunkMap::CompareChunkClients(int a_ChunkX1, int a_ChunkY1, int a_ChunkZ1,
|
||||
bool cChunkMap::AddChunkClient(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client)
|
||||
{
|
||||
cCSLock Lock(m_CSLayers);
|
||||
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||
cChunkPtr Chunk = GetChunk(a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||
if (Chunk == NULL)
|
||||
{
|
||||
return false;
|
||||
@ -697,7 +709,7 @@ void cChunkMap::RemoveClientFromChunks(cClientHandle * a_Client, const cChunkCoo
|
||||
bool cChunkMap::SendChunkTo(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client)
|
||||
{
|
||||
cCSLock Lock(m_CSLayers);
|
||||
cChunkPtr Chunk = GetChunk(a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||
if ((Chunk == NULL) || !Chunk->IsValid())
|
||||
{
|
||||
return false;
|
||||
@ -754,6 +766,43 @@ void cChunkMap::TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
||||
|
||||
|
||||
|
||||
/// Loads the chunk synchronously, if not already loaded. Doesn't generate. Returns true if chunk valid (even if already loaded before)
|
||||
bool cChunkMap::LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
||||
{
|
||||
{
|
||||
cCSLock Lock(m_CSLayers);
|
||||
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||
if (Chunk == NULL)
|
||||
{
|
||||
// Internal error
|
||||
return false;
|
||||
}
|
||||
if (Chunk->IsValid())
|
||||
{
|
||||
// Already loaded
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return m_World->GetStorage().LoadChunk(a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// Loads the chunks specified. Doesn't report failure, other than chunks being !IsValid()
|
||||
void cChunkMap::LoadChunks(const cChunkCoordsList & a_Chunks)
|
||||
{
|
||||
for (cChunkCoordsList::const_iterator itr = a_Chunks.begin(); itr != a_Chunks.end(); ++itr)
|
||||
{
|
||||
LoadChunk(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ);
|
||||
} // for itr - a_Chunks[]
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkMap::UpdateSign(int a_X, int a_Y, int a_Z, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4)
|
||||
{
|
||||
cCSLock Lock(m_CSLayers);
|
||||
@ -771,15 +820,18 @@ void cChunkMap::UpdateSign(int a_X, int a_Y, int a_Z, const AString & a_Line1, c
|
||||
|
||||
|
||||
|
||||
void cChunkMap::ChunkStay(int a_ChunkX, int a_ChunkY, int a_ChunkZ, bool a_Stay)
|
||||
void cChunkMap::ChunksStay(const cChunkCoordsList & a_Chunks, bool a_Stay)
|
||||
{
|
||||
cCSLock Lock(m_CSLayers);
|
||||
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||
if (Chunk == NULL)
|
||||
for (cChunkCoordsList::const_iterator itr = a_Chunks.begin(); itr != a_Chunks.end(); ++itr)
|
||||
{
|
||||
return;
|
||||
cChunkPtr Chunk = GetChunkNoLoad(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ);
|
||||
if (Chunk == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Chunk->Stay(a_Stay);
|
||||
}
|
||||
Chunk->Stay(a_Stay);
|
||||
}
|
||||
|
||||
|
||||
@ -856,7 +908,7 @@ cChunkMap::cChunkLayer::~cChunkLayer()
|
||||
cChunkPtr cChunkMap::cChunkLayer::GetChunk( int a_ChunkX, int a_ChunkY, int a_ChunkZ )
|
||||
{
|
||||
// Always returns an assigned chunkptr, but the chunk needn't be valid (loaded / generated) - callers must check
|
||||
|
||||
|
||||
const int LocalX = a_ChunkX - m_LayerX * LAYER_SIZE;
|
||||
const int LocalZ = a_ChunkZ - m_LayerZ * LAYER_SIZE;
|
||||
|
||||
@ -934,7 +986,7 @@ void cChunkMap::cChunkLayer::UnloadUnusedChunks(void)
|
||||
{
|
||||
if ((m_Chunks[i] != NULL) && (m_Chunks[i]->CanUnload()))
|
||||
{
|
||||
// The chunk destructor calls our GetChunk() while removing its entities
|
||||
// The cChunk destructor calls our GetChunk() while removing its entities
|
||||
// so we still need to be able to return the chunk. Therefore we first delete, then NULLify
|
||||
// Doing otherwise results in bug http://forum.mc-server.org/showthread.php?tid=355
|
||||
delete m_Chunks[i];
|
||||
@ -975,7 +1027,8 @@ void cChunkMap::ChunkValidated(void)
|
||||
// cChunkStay:
|
||||
|
||||
cChunkStay::cChunkStay(cWorld * a_World) :
|
||||
m_World(a_World)
|
||||
m_World(a_World),
|
||||
m_IsEnabled(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -994,17 +1047,11 @@ cChunkStay::~cChunkStay()
|
||||
|
||||
void cChunkStay::Clear(void)
|
||||
{
|
||||
cChunkCoordsList Chunks;
|
||||
if (m_IsEnabled)
|
||||
{
|
||||
cCSLock Lock(m_CS);
|
||||
std::swap(Chunks, m_Chunks);
|
||||
Disable();
|
||||
}
|
||||
|
||||
// Un-"stay" all chunks:
|
||||
for (cChunkCoordsList::const_iterator itr = Chunks.begin(); itr != Chunks.end(); ++itr)
|
||||
{
|
||||
m_World->ChunkStay(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ, false);
|
||||
} // for itr - Chunks[]
|
||||
m_Chunks.clear();
|
||||
}
|
||||
|
||||
|
||||
@ -1013,16 +1060,17 @@ void cChunkStay::Clear(void)
|
||||
|
||||
void cChunkStay::Add(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
||||
{
|
||||
cCSLock Lock(m_CS);
|
||||
ASSERT(!m_IsEnabled);
|
||||
|
||||
for (cChunkCoordsList::const_iterator itr = m_Chunks.begin(); itr != m_Chunks.end(); ++itr)
|
||||
{
|
||||
if ((itr->m_ChunkX == a_ChunkX) && (itr->m_ChunkY == a_ChunkY) && (itr->m_ChunkZ == a_ChunkZ))
|
||||
{
|
||||
// Already "stayed"
|
||||
// Already present
|
||||
return;
|
||||
}
|
||||
} // for itr - Chunks[]
|
||||
m_World->ChunkStay(a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||
m_Chunks.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ));
|
||||
}
|
||||
|
||||
|
||||
@ -1031,13 +1079,14 @@ void cChunkStay::Add(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
||||
|
||||
void cChunkStay::Remove(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
||||
{
|
||||
cCSLock Lock(m_CS);
|
||||
ASSERT(!m_IsEnabled);
|
||||
|
||||
for (cChunkCoordsList::const_iterator itr = m_Chunks.begin(); itr != m_Chunks.end(); ++itr)
|
||||
{
|
||||
if ((itr->m_ChunkX == a_ChunkX) && (itr->m_ChunkY == a_ChunkY) && (itr->m_ChunkZ == a_ChunkZ))
|
||||
{
|
||||
// Found, un-"stay"
|
||||
m_World->ChunkStay(a_ChunkX, a_ChunkY, a_ChunkZ, false);
|
||||
m_Chunks.erase(itr);
|
||||
return;
|
||||
}
|
||||
} // for itr - Chunks[]
|
||||
@ -1046,3 +1095,27 @@ void cChunkStay::Remove(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkStay::Enable(void)
|
||||
{
|
||||
ASSERT(!m_IsEnabled);
|
||||
|
||||
m_World->ChunksStay(*this, true);
|
||||
m_IsEnabled = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkStay::Disable(void)
|
||||
{
|
||||
ASSERT(m_IsEnabled);
|
||||
|
||||
m_World->ChunksStay(*this, false);
|
||||
m_IsEnabled = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -83,10 +83,16 @@ public:
|
||||
/// Touches the chunk, causing it to be loaded or generated
|
||||
void TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||
|
||||
/// Loads the chunk, if not already loaded. Doesn't generate. Returns true if chunk valid (even if already loaded before)
|
||||
bool LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||
|
||||
/// Loads the chunks specified. Doesn't report failure, other than chunks being !IsValid()
|
||||
void LoadChunks(const cChunkCoordsList & a_Chunks);
|
||||
|
||||
void UpdateSign(int a_X, int a_Y, int a_Z, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4);
|
||||
|
||||
/// Marks (a_Stay == true) or unmarks (a_Stay == false) a chunk as non-unloadable; to be used only by cChunkStay!
|
||||
void ChunkStay(int a_ChunkX, int a_ChunkY, int a_ChunkZ, bool a_Stay = true);
|
||||
/// Marks (a_Stay == true) or unmarks (a_Stay == false) chunks as non-unloadable; to be used only by cChunkStay!
|
||||
void ChunksStay(const cChunkCoordsList & a_Chunks, bool a_Stay = true);
|
||||
|
||||
void Tick( float a_Dt, MTRand & a_TickRand );
|
||||
|
||||
@ -170,8 +176,9 @@ private:
|
||||
|
||||
cWorld * m_World;
|
||||
|
||||
cChunkPtr GetChunk ( int a_ChunkX, int a_ChunkY, int a_ChunkZ ); // Also queues the chunk for loading / generating if not valid
|
||||
cChunkPtr GetChunkNoGen( int a_ChunkX, int a_ChunkY, int a_ChunkZ ); // Also queues the chunk for loading if not valid; doesn't generate
|
||||
cChunkPtr GetChunk (int a_ChunkX, int a_ChunkY, int a_ChunkZ); // Also queues the chunk for loading / generating if not valid
|
||||
cChunkPtr GetChunkNoGen (int a_ChunkX, int a_ChunkY, int a_ChunkZ); // Also queues the chunk for loading if not valid; doesn't generate
|
||||
cChunkPtr GetChunkNoLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ); // Doesn't load, doesn't generate
|
||||
};
|
||||
|
||||
|
||||
@ -179,7 +186,9 @@ private:
|
||||
|
||||
|
||||
/** Makes chunks stay loaded until this object is cleared or destroyed
|
||||
Works by setting internal flags in the cChunk that it should not be unloaded
|
||||
Works by setting internal flags in the cChunk that it should not be unloaded.
|
||||
To optimize for speed, cChunkStay has an Enabled flag, it will "stay" the chunks only when enabled and it will refuse manipulations when enabled
|
||||
The object itself is not made thread-safe, it's supposed to be used from a single thread only.
|
||||
*/
|
||||
class cChunkStay
|
||||
{
|
||||
@ -192,11 +201,18 @@ public:
|
||||
void Add(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||
void Remove(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||
|
||||
void Enable(void);
|
||||
void Disable(void);
|
||||
|
||||
// Allow cChunkStay be passed to functions expecting a const cChunkCoordsList &
|
||||
operator const cChunkCoordsList(void) const {return m_Chunks; }
|
||||
|
||||
protected:
|
||||
|
||||
cWorld * m_World;
|
||||
|
||||
cCriticalSection m_CS;
|
||||
bool m_IsEnabled;
|
||||
|
||||
cChunkCoordsList m_Chunks;
|
||||
} ;
|
||||
|
||||
|
@ -1288,6 +1288,24 @@ void cWorld::TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
||||
|
||||
|
||||
|
||||
bool cWorld::LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
||||
{
|
||||
return m_ChunkMap->LoadChunk(a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWorld::LoadChunks(const cChunkCoordsList & a_Chunks)
|
||||
{
|
||||
m_ChunkMap->LoadChunks(a_Chunks);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWorld::UpdateSign(int a_X, int a_Y, int a_Z, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4)
|
||||
{
|
||||
m_ChunkMap->UpdateSign(a_X, a_Y, a_Z, a_Line1, a_Line2, a_Line3, a_Line4);
|
||||
@ -1297,9 +1315,9 @@ void cWorld::UpdateSign(int a_X, int a_Y, int a_Z, const AString & a_Line1, cons
|
||||
|
||||
|
||||
|
||||
void cWorld::ChunkStay(int a_ChunkX, int a_ChunkY, int a_ChunkZ, bool a_Stay)
|
||||
void cWorld::ChunksStay(const cChunkCoordsList & a_Chunks, bool a_Stay)
|
||||
{
|
||||
m_ChunkMap->ChunkStay(a_ChunkX, a_ChunkY, a_ChunkZ, a_Stay);
|
||||
m_ChunkMap->ChunksStay(a_Chunks, a_Stay);
|
||||
}
|
||||
|
||||
|
||||
|
@ -127,10 +127,16 @@ public:
|
||||
/// Touches the chunk, causing it to be loaded or generated
|
||||
void TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||
|
||||
/// Loads the chunk, if not already loaded. Doesn't generate. Returns true if chunk valid (even if already loaded before)
|
||||
bool LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||
|
||||
/// Loads the chunks specified. Doesn't report failure, other than chunks being !IsValid()
|
||||
void LoadChunks(const cChunkCoordsList & a_Chunks);
|
||||
|
||||
void UpdateSign(int a_X, int a_Y, int a_Z, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4);
|
||||
|
||||
/// Marks (a_Stay == true) or unmarks (a_Stay == false) a chunk as non-unloadable; to be used only by cChunkStay!
|
||||
void ChunkStay(int a_ChunkX, int a_ChunkY, int a_ChunkZ, bool a_Stay = true);
|
||||
/// Marks (a_Stay == true) or unmarks (a_Stay == false) chunks as non-unloadable. To be used only by cChunkStay!
|
||||
void ChunksStay(const cChunkCoordsList & a_Chunks, bool a_Stay = true);
|
||||
|
||||
// TODO: Export to Lua
|
||||
bool DoWithEntity( int a_UniqueID, cEntityCallback & a_Callback );
|
||||
|
Loading…
Reference in New Issue
Block a user