1
0
cuberite-2a/source/cChunkMap.cpp
faketruth 50a7722242 Terrain generation is synchronous again, async generation has bugs.
Made some funky smart pointer things for chunks.
Fixed a bug where the client would override the player position on the server and back again, resulting in sending too many chunks to the client which it doesn't even need.
Fixed some compiler warnings in cPickup.cpp


git-svn-id: http://mc-server.googlecode.com/svn/trunk@164 0a769ca7-a7f5-676a-18bf-c427514a06d6
2012-01-19 18:12:39 +00:00

728 lines
19 KiB
C++

#include "cChunkMap.h"
#include "cChunk.h"
#include "cMCLogger.h"
#include "cWorld.h"
#include "cRoot.h"
#include "cMakeDir.h"
#ifndef _WIN32
#include <cstring> // memcpy
#include <cstdlib> // abs
#include <math.h> // floorf
#include <stdio.h> // sprintf and stuff
#define sprintf_s( dest, size, format, ... ) sprintf( dest, format, __VA_ARGS__ )
#endif
#include "zlib.h"
#include <json/json.h>
#define USE_MEMCPY
#define LAYER_SIZE (32)
cChunkMap::cChunkMap( int a_Width, int a_Height, cWorld* a_World )
: m_Nodes( new cChunkNode[ a_Width * a_Height ] )
, m_Width( a_Width )
, m_Height( a_Height )
, m_Layers( 0 )
, m_NumLayers( 0 )
, m_World( a_World )
{
}
cChunkMap::~cChunkMap()
{
delete [] m_Nodes;
}
cChunkMap::cChunkNode::cChunkNode()
{
m_Size = 0;
m_Allocated = 0;
m_Chunks = 0;
}
cChunkMap::cChunkNode::~cChunkNode()
{
if( m_Allocated > 0 )
{
for( unsigned int i = 0; i < m_Size; ++i )
{
delete m_Chunks[i];
}
delete [] m_Chunks;
}
// m_Chunks = 0;
// m_Allocated = 0;
// m_Size = 0;
}
void cChunkMap::cChunkNode::push_back( cChunk* a_Chunk )
{
if( m_Allocated == 0 )
{
resize( 1 );
}
if( m_Size >= m_Allocated )
{
resize( m_Allocated*2 );
}
m_Chunks[ m_Size ] = a_Chunk;
m_Size++;
}
void cChunkMap::cChunkNode::resize( unsigned int a_NewSize )
{
cChunk** TempChunks = new cChunk*[a_NewSize];
if( m_Allocated > 0 )
{
#ifdef USE_MEMCPY
memcpy( TempChunks, m_Chunks, sizeof( cChunk* ) * m_Size );
#else
for( unsigned int i = 0; i < a_NewSize; ++i )
TempChunks[i] = m_Chunks[i];
#endif
delete [] m_Chunks;
}
m_Chunks = TempChunks;
m_Allocated = a_NewSize;
}
void cChunkMap::cChunkNode::erase( cChunk* a_Chunk )
{
if( m_Size == 0 ) return;
cChunk** TempChunks = new cChunk*[m_Size];
unsigned int TempIdx = 0;
for( unsigned int i = 0; i < m_Size; ++i )
{
if( m_Chunks[i] != a_Chunk )
{
TempChunks[TempIdx] = m_Chunks[i];
TempIdx++;
}
}
delete [] m_Chunks;
m_Chunks = 0;
if( TempIdx > 0 )
{
m_Chunks = new cChunk*[ TempIdx ];
#ifdef USE_MEMCPY
memcpy( m_Chunks, TempChunks, sizeof( cChunk* ) * TempIdx );
#else
for( unsigned int i = 0; i < TempIdx; ++i )
m_Chunks[i] = TempChunks[i];
#endif
}
delete [] TempChunks;
m_Allocated = TempIdx;
m_Size = TempIdx;
}
cChunkMap::cChunkData* cChunkMap::cChunkLayer::GetChunk( int a_X, int a_Z )
{
const int LocalX = a_X - m_X * LAYER_SIZE;
const int LocalZ = a_Z - m_Z * LAYER_SIZE;
//LOG("LocalX:%i LocalZ:%i", LocalX, LocalZ );
if( LocalX < LAYER_SIZE && LocalZ < LAYER_SIZE && LocalX > -1 && LocalZ > -1 )
return &m_Chunks[ LocalX + LocalZ * LAYER_SIZE ];
return 0;
}
bool cChunkMap::RemoveLayer( cChunkLayer* a_Layer )
{
cChunkLayer* NewLayers = 0;
if( m_NumLayers > 1 )
NewLayers = new cChunkLayer[m_NumLayers-1];
int idx = 0;
bool bExcludedLayer = false;
for( int i = 0; i < m_NumLayers; ++i )
{
if( &m_Layers[i] != a_Layer )
{
if( idx < m_NumLayers-1 )
{
NewLayers[ idx ] = m_Layers[i];
idx++;
}
}
else
bExcludedLayer = true;
}
if( !bExcludedLayer )
{
LOGWARN("Could not remove layer, because layer was not found %i %i", a_Layer->m_X, a_Layer->m_Z);
delete [] NewLayers;
return false;
}
if( m_Layers ) delete [] m_Layers;
m_Layers = NewLayers;
m_NumLayers--;
return true;
}
cChunkMap::cChunkLayer* cChunkMap::AddLayer( const cChunkLayer & a_Layer )
{
cChunkLayer* TempLayers = new cChunkLayer[m_NumLayers+1];
if( m_NumLayers > 0 )
{
memcpy( TempLayers, m_Layers, sizeof( cChunkLayer ) * m_NumLayers );
delete [] m_Layers;
}
m_Layers = TempLayers;
m_Layers[m_NumLayers] = a_Layer;
cChunkLayer* NewLayer = &m_Layers[m_NumLayers];
m_NumLayers++;
return NewLayer;
}
void cChunkMap::AddChunk( cChunk* a_Chunk )
{
/* // OLD
m_Nodes[ MakeHash( a_Chunk->GetPosX(), a_Chunk->GetPosZ() ) ].push_back( a_Chunk );
*/
// NEW
const int LayerX = (int)(floorf((float)a_Chunk->GetPosX() / (float)(LAYER_SIZE)));
const int LayerZ = (int)(floorf((float)a_Chunk->GetPosZ() / (float)(LAYER_SIZE)));
cChunkLayer* FoundLayer = GetLayer( LayerX, LayerZ );
if( !FoundLayer )
{
cChunkLayer NewLayer( LAYER_SIZE*LAYER_SIZE );
NewLayer.m_X = LayerX;
NewLayer.m_Z = LayerZ;
FoundLayer = AddLayer( NewLayer );
LOGWARN("Created new layer %i %i (total layers %i)", LayerX, LayerZ, m_NumLayers );
}
//Get local coordinates in layer
const int LocalX = a_Chunk->GetPosX() - LayerX * LAYER_SIZE;
const int LocalZ = a_Chunk->GetPosZ() - LayerZ * LAYER_SIZE;
if( FoundLayer->m_Chunks[ LocalX + LocalZ * LAYER_SIZE ].m_LiveChunk )
LOGWARN("WARNING: Added chunk to layer while it was already loaded!");
if( FoundLayer->m_Chunks[ LocalX + LocalZ * LAYER_SIZE ].m_Compressed )
LOGWARN("WARNING: Added chunk to layer while a compressed version exists!");
FoundLayer->m_Chunks[ LocalX + LocalZ * LAYER_SIZE ].m_LiveChunk = a_Chunk;
FoundLayer->m_NumChunksLoaded++;
}
void cChunkMap::RemoveChunk( cChunk* a_Chunk )
{
/* // OLD
m_Nodes[ MakeHash( a_Chunk->GetPosX(), a_Chunk->GetPosZ() ) ].erase( a_Chunk );
*/
// NEW
cChunkLayer* Layer = GetLayerForChunk( a_Chunk->GetPosX(), a_Chunk->GetPosZ() );
if( Layer )
{
cChunkData* Data = Layer->GetChunk( a_Chunk->GetPosX(), a_Chunk->GetPosZ() );
if( Data->m_LiveChunk )
{
CompressChunk( Data );
Data->m_LiveChunk = 0; // Set live chunk to 0
}
Layer->m_NumChunksLoaded--;
}
}
void cChunkMap::CompressChunk( cChunkData* a_ChunkData )
{
if( a_ChunkData->m_LiveChunk )
{
// Delete already present compressed data
if( a_ChunkData->m_Compressed ) delete [] a_ChunkData->m_Compressed;
// Get Json data
Json::Value root;
std::string JsonData = "";
a_ChunkData->m_LiveChunk->SaveToJson( root );
if( !root.empty() )
{
Json::StyledWriter writer; // TODO FIXME: change to FastWriter ? :D
JsonData = writer.write( root );
}
unsigned int TotalSize = cChunk::c_BlockDataSize + JsonData.size();
uLongf CompressedSize = compressBound( TotalSize );
a_ChunkData->m_Compressed = new char[CompressedSize];
char* DataSource = a_ChunkData->m_LiveChunk->pGetBlockData();
if( JsonData.size() > 0 )
{
// Move stuff around, so data is aligned in memory
DataSource = new char[TotalSize];
memcpy( DataSource, a_ChunkData->m_LiveChunk->pGetBlockData(), cChunk::c_BlockDataSize );
memcpy( DataSource + cChunk::c_BlockDataSize, JsonData.c_str(), JsonData.size() );
}
int errorcode = compress2( (Bytef*)a_ChunkData->m_Compressed, &CompressedSize, (const Bytef*)DataSource, TotalSize, Z_DEFAULT_COMPRESSION);
if( errorcode != Z_OK )
{
LOGERROR("Error compressing data (%i)", errorcode );
}
a_ChunkData->m_CompressedSize = CompressedSize;
a_ChunkData->m_UncompressedSize = TotalSize;
if( DataSource != a_ChunkData->m_LiveChunk->pGetBlockData() )
delete [] DataSource;
}
}
unsigned int cChunkMap::MakeHash( int a_X, int a_Z )
{
const unsigned int HashX = abs( a_X ) % m_Width;
const unsigned int HashZ = abs( a_Z ) % m_Height;
return HashX + HashZ * m_Width;
}
cChunkMap::cChunkLayer* cChunkMap::GetLayerForChunk( int a_ChunkX, int a_ChunkZ )
{
const int LayerX = (int)(floorf((float)a_ChunkX / (float)(LAYER_SIZE)));
const int LayerZ = (int)(floorf((float)a_ChunkZ / (float)(LAYER_SIZE)));
return GetLayer( LayerX, LayerZ );
}
cChunkMap::cChunkLayer* cChunkMap::GetLayer( int a_LayerX, int a_LayerZ )
{
// Find layer in memory
for( int i = 0; i < m_NumLayers; ++i )
{
if( m_Layers[i].m_X == a_LayerX && m_Layers[i].m_Z == a_LayerZ )
{
return &m_Layers[i];
}
}
// Find layer on disk
cChunkLayer* Layer = LoadLayer( a_LayerX, a_LayerZ );
if( !Layer ) return 0;
cChunkLayer* NewLayer = AddLayer( *Layer );
delete Layer;
return NewLayer;
}
cChunk* cChunkMap::GetChunk( int a_X, int a_Y, int a_Z )
{
/* // OLD
unsigned int Hash = MakeHash( a_X, a_Z );
cChunkNode & Node = m_Nodes[ Hash ];
cChunk** Chunks = Node.GetChunks();
for( unsigned int i = 0; i < Node.size(); ++i )
{
if( Chunks[i]->GetPosX() == a_X && // Check if we found the right chunk
Chunks[i]->GetPosY() == a_Y &&
Chunks[i]->GetPosZ() == a_Z )
{
return Chunks[i];
}
}
*/
// NEW
cChunkLayer* Layer = GetLayerForChunk( a_X, a_Z );
if( Layer )
{
cChunkData* Data = Layer->GetChunk( a_X, a_Z );
if( Data->m_LiveChunk ) return Data->m_LiveChunk;
// Decompress cached chunk
if( Data->m_Compressed )
{
uLongf DestSize = Data->m_UncompressedSize;
char* BlockData = new char[ DestSize ];
int errorcode = uncompress( (Bytef*)BlockData, &DestSize, (Bytef*)Data->m_Compressed, Data->m_CompressedSize );
if( Data->m_UncompressedSize != DestSize )
{
LOGWARN("Lulwtf, expected uncompressed size differs!");
delete [] BlockData;
}
else if( errorcode != Z_OK )
{
LOGERROR("ERROR: Decompressing chunk data! %i", errorcode );
switch( errorcode )
{
case Z_MEM_ERROR:
LOGERROR("Not enough memory");
break;
case Z_BUF_ERROR:
LOGERROR("Not enough room in output buffer");
break;
case Z_DATA_ERROR:
LOGERROR("Input data corrupted or incomplete");
break;
default:
break;
};
delete [] BlockData;
}
else
{
cChunk* Chunk = new cChunk(a_X, a_Y, a_Z, m_World);
memcpy( Chunk->m_BlockData, BlockData, cChunk::c_BlockDataSize );
Chunk->CalculateHeightmap();
Data->m_LiveChunk = Chunk;
Layer->m_NumChunksLoaded++;
if( DestSize > cChunk::c_BlockDataSize ) // We gots some extra data :D
{
LOGINFO("Parsing trailing JSON");
Json::Value root; // will contains the root value after parsing.
Json::Reader reader;
if( !reader.parse( BlockData + cChunk::c_BlockDataSize, root, false ) )
{
LOGERROR("Failed to parse trailing JSON!");
}
else
{
//Json::StyledWriter writer;
//LOGINFO("Trailing Json:" );
//printf("%s", writer.write( root ).c_str() );
Chunk->LoadFromJson( root );
}
}
delete [] BlockData;
delete [] Data->m_Compressed; Data->m_Compressed = 0; Data->m_CompressedSize = 0;
return Chunk;
}
}
}
return 0;
}
void cChunkMap::Tick( float a_Dt )
{
/* // OLD
for( int i = 0; i < m_Width*m_Height; ++i )
{
cChunkNode & Node = m_Nodes[ i ];
cChunk** Chunks = Node.GetChunks();
for( unsigned int i = 0; i < Node.size(); ++i )
{
Chunks[i]->Tick( a_Dt );
}
}
*/
// NEW
for( int l = 0; l < m_NumLayers; ++l )
{
for( int i = 0; i < LAYER_SIZE*LAYER_SIZE; ++i )
{
cChunk* Chunk = m_Layers[l].m_Chunks[i].m_LiveChunk;
if( Chunk )
Chunk->Tick( a_Dt );
}
}
}
void cChunkMap::UnloadUnusedChunks()
{
cWorld* World = m_World;
/* // OLD
for( int i = 0; i < m_Width*m_Height; ++i )
{
cChunkNode & Node = m_Nodes[ i ];
cChunk** Chunks = Node.GetChunks();
for( unsigned int i = 0; i < Node.size(); ++i )
{
if( Chunks[i]->GetClients().size() == 0 )
{
Chunks[i]->SaveToDisk();
LOG("Unloading %p", Chunks[i] );
World->RemoveSpread( Chunks[i] );
cChunk* TheChunk = Chunks[i];
RemoveChunk( TheChunk );
delete TheChunk;
//Node.erase( Chunks[i] );
Chunks = Node.GetChunks(); // Chunks pointer is no longer valid, get a new one
}
}
}
*/
// NEW
for( int l = 0; l < m_NumLayers; ++l )
{
cChunkLayer & Layer = m_Layers[l];
for( int i = 0; i < LAYER_SIZE*LAYER_SIZE; ++i )
{
cChunk* Chunk = Layer.m_Chunks[i].m_LiveChunk;
if( Chunk && Chunk->GetClients().size() == 0 && Chunk->GetReferenceCount() <= 0 )
{
Chunk->SaveToDisk();
World->RemoveSpread( ptr_cChunk( Chunk ) );
RemoveChunk( Chunk );
delete Chunk;
}
}
// Unload layers
if( Layer.m_NumChunksLoaded == 0 )
{
SaveLayer( &Layer );
for( int i = 0; i < LAYER_SIZE*LAYER_SIZE; ++i ) // Free all chunk data for layer
{
if( Layer.m_Chunks[i].m_Compressed )
delete [] Layer.m_Chunks[i].m_Compressed;
if( Layer.m_Chunks[i].m_LiveChunk )
delete Layer.m_Chunks[i].m_LiveChunk;
}
if( RemoveLayer( &Layer ) ) l--;
}
else if( Layer.m_NumChunksLoaded < 0 )
{
LOGERROR("WTF! Chunks loaded in layer is %i !!", Layer.m_NumChunksLoaded );
}
}
}
bool cChunkMap::RemoveEntityFromChunk( cEntity & a_Entity, cChunk* a_CalledFrom /* = 0 */ )
{
/* // OLD
for( int i = 0; i < m_Width*m_Height; ++i )
{
cChunkNode & Node = m_Nodes[ i ];
cChunk** Chunks = Node.GetChunks();
for( unsigned int i = 0; i < Node.size(); ++i )
{
if( Chunks[i] != a_CalledFrom )
{
if( Chunks[i]->RemoveEntity( a_Entity, a_CalledFrom ) )
return true;
}
}
}
*/
// NEW
for( int i = 0; i < m_NumLayers; ++i )
{
cChunkLayer & Layer = m_Layers[i];
for( int i = 0; i < LAYER_SIZE*LAYER_SIZE; ++i )
{
cChunk* Chunk = Layer.m_Chunks[i].m_LiveChunk;
if( Chunk != a_CalledFrom )
{
if( Chunk && Chunk->RemoveEntity( a_Entity, a_CalledFrom ) )
return true;
}
}
}
LOG("WARNING: Entity was not found in any chunk!");
return false;
}
void cChunkMap::SaveAllChunks()
{
for( int i = 0; i < m_Width*m_Height; ++i )
{
cChunkNode & Node = m_Nodes[ i ];
cChunk** Chunks = Node.GetChunks();
for( unsigned int i = 0; i < Node.size(); ++i )
{
Chunks[i]->SaveToDisk();
}
}
for( int i = 0; i < m_NumLayers; ++i )
{
SaveLayer( &m_Layers[i] );
}
}
/********************************
* Saving and loading
**/
void cChunkMap::SaveLayer( cChunkLayer* a_Layer )
{
std::string WorldName = m_World->GetName();
cMakeDir::MakeDir( WorldName.c_str() );
char SourceFile[128];
sprintf_s(SourceFile, 128, ( WorldName + "/X%i_Z%i.pak").c_str(), a_Layer->m_X, a_Layer->m_Z );
FILE* f = 0;
#ifdef _WIN32
if( fopen_s(&f, SourceFile, "wb" ) == 0 ) // no error
#else
if( (f = fopen(SourceFile, "wb" )) != 0 ) // no error
#endif
{
//---------------
// Header
char PakVersion = 1;
char ChunkVersion = 1;
fwrite( &PakVersion, sizeof(PakVersion), 1, f ); // pak version
fwrite( &ChunkVersion, sizeof(ChunkVersion), 1, f ); // chunk version
// Count number of chunks in layer
short NumChunks = 0;
for( int i = 0; i < LAYER_SIZE*LAYER_SIZE; ++i )
{
if( a_Layer->m_Chunks[i].m_Compressed || a_Layer->m_Chunks[i].m_LiveChunk )
NumChunks++;
}
fwrite( &NumChunks, sizeof( NumChunks ), 1, f );
LOG("Num Chunks in layer: %i", NumChunks );
//---------------
// Chunk headers
for( int z = 0; z < LAYER_SIZE; ++z )
{
for( int x = 0; x < LAYER_SIZE; ++x )
{
cChunkData & Data = a_Layer->m_Chunks[x + z*LAYER_SIZE];
CompressChunk( &Data );
if( Data.m_Compressed || Data.m_LiveChunk )
{
int ChunkX = a_Layer->m_X*LAYER_SIZE + x;
int ChunkZ = a_Layer->m_Z*LAYER_SIZE + z;
unsigned int Size = Data.m_CompressedSize; // Needs to be size of compressed data
unsigned int USize = Data.m_UncompressedSize; // Uncompressed size
fwrite( &ChunkX, sizeof( ChunkX ), 1, f );
fwrite( &ChunkZ, sizeof( ChunkZ ), 1, f );
fwrite( &Size, sizeof( Size ), 1, f );
fwrite( &USize, sizeof( USize ), 1, f );
}
}
}
//----------------
// Chunk data
for( int i = 0; i < LAYER_SIZE*LAYER_SIZE; ++i )
{
char* Compressed = a_Layer->m_Chunks[i].m_Compressed;
if( Compressed )
{
fwrite( Compressed, a_Layer->m_Chunks[i].m_CompressedSize, 1, f );
if(a_Layer->m_Chunks[i].m_LiveChunk) // If there's a live chunk we have no need for compressed data
{
delete [] a_Layer->m_Chunks[i].m_Compressed;
a_Layer->m_Chunks[i].m_Compressed = 0;
a_Layer->m_Chunks[i].m_CompressedSize = 0;
}
}
}
fclose(f);
}
else
{
LOGERROR("ERROR: Could not write to file %s", SourceFile );
}
}
cChunkMap::cChunkLayer* cChunkMap::LoadLayer(int a_LayerX, int a_LayerZ )
{
std::string WorldName = m_World->GetName();
char SourceFile[128];
sprintf_s(SourceFile, 128, (WorldName + "/X%i_Z%i.pak").c_str(), a_LayerX, a_LayerZ );
FILE* f = 0;
#ifdef _WIN32
if( fopen_s(&f, SourceFile, "rb" ) == 0 ) // no error
#else
if( (f = fopen(SourceFile, "rb" )) != 0 ) // no error
#endif
{
char PakVersion = 0;
char ChunkVersion = 0;
if( fread( &PakVersion, sizeof(PakVersion), 1, f) != 1 ) { LOGERROR("ERROR 1 READING FROM FILE %s", SourceFile); fclose(f); return false; }
if( PakVersion != 1 ) { LOGERROR("WRONG PAK VERSION!"); fclose(f); return 0; }
if( fread( &ChunkVersion, sizeof(ChunkVersion), 1, f) != 1 ) { LOGERROR("ERROR 2 READING FROM FILE %s", SourceFile); fclose(f); return false; }
if( ChunkVersion != 1 ) { LOGERROR("WRONG CHUNK VERSION!"); fclose(f); return 0; }
short NumChunks = 0;
if( fread( &NumChunks, sizeof(NumChunks), 1, f) != 1 ) { LOGERROR("ERROR 3 READING FROM FILE %s", SourceFile); fclose(f); return false; }
LOG("Num chunks: %i", NumChunks );
LOG("Source File: %s", SourceFile );
cChunkLayer* Layer = new cChunkLayer( LAYER_SIZE*LAYER_SIZE );
Layer->m_X = a_LayerX;
Layer->m_Z = a_LayerZ;
cChunkData** OrderedData = new cChunkData*[ NumChunks ]; // So we can loop over the chunks in the order they were loaded
// Loop over all chunk headers
for( short i = 0; i < NumChunks; ++i )
{
int ChunkX = 0;
int ChunkZ = 0;
if( fread( &ChunkX, sizeof(ChunkX), 1, f) != 1 ) { LOGERROR("ERROR 4 READING FROM FILE %s", SourceFile); fclose(f); return false; }
if( fread( &ChunkZ, sizeof(ChunkZ), 1, f) != 1 ) { LOGERROR("ERROR 5 READING FROM FILE %s", SourceFile); fclose(f); return false; }
cChunkData* Data = Layer->GetChunk( ChunkX, ChunkZ );
if( Data )
{
if( fread( &Data->m_CompressedSize, sizeof(Data->m_CompressedSize), 1, f) != 1 ) { LOGERROR("ERROR 6 READING FROM FILE %s", SourceFile); fclose(f); return false; }
if( fread( &Data->m_UncompressedSize, sizeof(Data->m_UncompressedSize), 1, f) != 1 ) { LOGERROR("ERROR 7 READING FROM FILE %s", SourceFile); fclose(f); return false; }
}
else
{
LOGERROR("Chunk with wrong coordinates in pak file! %i %i", ChunkX, ChunkZ );
fclose(f);
return 0;
}
OrderedData[i] = Data;
}
// Loop over chunks again, in the order they were loaded, and load their compressed data
for( short i = 0; i < NumChunks; ++i )
{
cChunkData* Data = OrderedData[i];
Data->m_Compressed = new char[ Data->m_CompressedSize ];
//printf("Compressed chunk size: %i\n",Data->m_CompressedSize);
if( fread( Data->m_Compressed, Data->m_CompressedSize, 1, f) != 1 ) { LOGERROR("ERROR 8 READING FROM FILE %s", SourceFile); fclose(f); return false; }
/* // Some testing...
uLongf DestSize = Data->m_UncompressedSize;
char* BlockData = new char[ DestSize ];
int errorcode = uncompress( (Bytef*)BlockData, &DestSize, (Bytef*)Data->m_Compressed, Data->m_CompressedSize );
if( errorcode != Z_OK )
{
LOGERROR("lulwut");
}
*/
}
delete [] OrderedData;
fclose(f);
return Layer;
}
else
{
//LOGWARN("Could not open file %s", SourceFile );
}
return 0;
}
int cChunkMap::GetNumChunks()
{
int NumChunks = 0;
for( int i = 0; i < m_NumLayers; ++i )
{
NumChunks += m_Layers[i].m_NumChunksLoaded;
}
return NumChunks;
}