From 386d58b5862d8b76925c6523721594887606e82a Mon Sep 17 00:00:00 2001 From: faketruth Date: Mon, 3 Oct 2011 18:41:19 +0000 Subject: MCServer c++ source files git-svn-id: http://mc-server.googlecode.com/svn/trunk@3 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/cChunkLoader.cpp | 364 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 364 insertions(+) create mode 100644 source/cChunkLoader.cpp (limited to 'source/cChunkLoader.cpp') diff --git a/source/cChunkLoader.cpp b/source/cChunkLoader.cpp new file mode 100644 index 000000000..a5d07818d --- /dev/null +++ b/source/cChunkLoader.cpp @@ -0,0 +1,364 @@ +#if 0 // ignore all contents of this file +#include "cChunkLoader.h" +#include "cChunk.h" +#include "cMCLogger.h" +#include "BlockID.h" +#include "cCriticalSection.h" +#include "cEvent.h" +#include "cThread.h" +#include "cSleep.h" + +#include "cChestEntity.h" +#include "cFurnaceEntity.h" +#include "cSignEntity.h" + +#include +#ifndef _WIN32 +#include +#include +#include +#include // for mkdir +#include +#else +#include +#endif + +#include + +struct ChunkData +{ + ChunkData() + : x( 0 ) + , z( 0 ) + , Data( 0 ) + , LiveChunk( 0 ) + {} + int x, z; + unsigned int DataSize; + unsigned int ChunkStart; + char* Data; + cChunk* LiveChunk; +}; + +typedef std::list< ChunkData > ChunkDataList; +struct cChunkLoader::ChunkPack +{ + ChunkDataList AllChunks; + int x, y, z; +}; + +typedef std::list< cChunkLoader::ChunkPack > ChunkPackList; +struct cChunkLoader::ChunkPacks +{ + ChunkPackList AllPacks; +}; + +cChunkLoader::cChunkLoader() + : m_bStop( false ) + , m_CriticalSection( new cCriticalSection() ) + , m_Event( new cEvent() ) + , m_ChunkPacks( new ChunkPacks ) +{ + cThread( SaveThread, this ); +} + +cChunkLoader::~cChunkLoader() +{ + m_bStop = true; + m_Event->Wait(); + delete m_CriticalSection; +} + +void cChunkLoader::SaveThread( void* a_Param ) +{ + cChunkLoader* self = (cChunkLoader*)a_Param; + while( !self->m_bStop ) + { + cSleep::MilliSleep( 1000 ); // Only check for saving once a second + } + self->m_Event->Set(); +} + +cChunk* cChunkLoader::LoadChunk( int a_X, int a_Y, int a_Z ) +{ + m_CriticalSection->Lock(); + cChunk* Chunk = 0; + + Chunk = LoadOldFormat( a_X, a_Y, a_Z ); + if( Chunk ) { Chunk->CalculateHeightmap(); } + else + { + 1; // load new format() + } + + m_CriticalSection->Unlock(); + return Chunk; +} + +bool cChunkLoader::SaveChunk( const cChunk & a_Chunk ) +{ + m_CriticalSection->Lock(); + bool Success = SaveOldFormat( a_Chunk ); + m_CriticalSection->Unlock(); + + return Success; +} + +/************************************************** + * Old format stuffs + **/ + +cChunk* cChunkLoader::LoadOldFormat( int a_X, int a_Y, int a_Z ) +{ + char SourceFile[128]; + sprintf_s(SourceFile, 128, "world/X%i_Y%i_Z%i.bin", a_X, a_Y, a_Z ); + + FILE* f = 0; + #ifdef _WIN32 + if( fopen_s(&f, SourceFile, "rb" ) == 0 ) // no error + #else + if( (f = fopen(SourceFile, "rb" )) != 0 ) // no error + #endif + { + cChunk* Chunk = new cChunk( a_X, a_Y, a_Z ); + if( fread( Chunk->m_BlockData, sizeof(char)*cChunk::c_BlockDataSize, 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", SourceFile); fclose(f); return false; } + + // Now load Block Entities + ENUM_BLOCK_ID BlockType; + while( fread( &BlockType, sizeof(ENUM_BLOCK_ID), 1, f) == 1 ) + { + switch( BlockType ) + { + case E_BLOCK_CHEST: + { + cChestEntity* ChestEntity = new cChestEntity( 0, 0, 0 ); + if( !ChestEntity->LoadFromFile( f ) ) + { + LOGERROR("ERROR READING CHEST FROM FILE %s", SourceFile ); + delete ChestEntity; + fclose(f); + return false; + } + Chunk->m_BlockEntities.push_back( ChestEntity ); + } + break; + case E_BLOCK_FURNACE: + { + cFurnaceEntity* FurnaceEntity = new cFurnaceEntity( 0, 0, 0 ); + if( !FurnaceEntity->LoadFromFile( f ) ) + { + LOGERROR("ERROR READING FURNACE FROM FILE %s", SourceFile ); + delete FurnaceEntity; + fclose(f); + return false; + } + Chunk->m_BlockEntities.push_back( FurnaceEntity ); + Chunk->m_TickBlockEntities.push_back( FurnaceEntity ); // They need tickin' + } + break; + case E_BLOCK_SIGN_POST: + case E_BLOCK_WALLSIGN: + { + cSignEntity* SignEntity = new cSignEntity(BlockType, 0, 0, 0 ); + if( !SignEntity->LoadFromFile( f ) ) + { + LOGERROR("ERROR READING SIGN FROM FILE %s", SourceFile ); + delete SignEntity; + fclose(f); + return false; + } + Chunk->m_BlockEntities.push_back( SignEntity ); + } + break; + default: + break; + } + } + + fclose(f); + return Chunk; + } + else + { + return 0; + } +} + +bool cChunkLoader::SaveOldFormat( const cChunk & a_Chunk ) +{ + char SourceFile[128]; + sprintf_s(SourceFile, 128, "world/X%i_Y%i_Z%i.bin", a_Chunk.m_PosX, a_Chunk.m_PosY, a_Chunk.m_PosZ ); + + #ifdef _WIN32 + { + SECURITY_ATTRIBUTES Attrib; + Attrib.nLength = sizeof(SECURITY_ATTRIBUTES); + Attrib.lpSecurityDescriptor = NULL; + Attrib.bInheritHandle = false; + ::CreateDirectory("world", &Attrib); + } + #else + { + mkdir("world", S_IRWXU | S_IRWXG | S_IRWXO); + } + #endif + + FILE* f = 0; +#ifdef _WIN32 + if( fopen_s(&f, SourceFile, "wb" ) == 0 ) // no error + #else + if( (f = fopen(SourceFile, "wb" )) != 0 ) // no error + #endif + { + fwrite( a_Chunk.m_BlockData, sizeof(char)*cChunk::c_BlockDataSize, 1, f ); + + // Now write Block Entities + for( std::list::const_iterator itr = a_Chunk.m_BlockEntities.begin(); itr != a_Chunk.m_BlockEntities.end(); ++itr) + { + cBlockEntity* BlockEntity = *itr; + switch( BlockEntity->GetBlockType() ) + { + case E_BLOCK_CHEST: + { + cChestEntity* ChestEntity = reinterpret_cast< cChestEntity* >( BlockEntity ); + ChestEntity->WriteToFile( f ); + } + break; + case E_BLOCK_FURNACE: + { + cFurnaceEntity* FurnaceEntity = reinterpret_cast< cFurnaceEntity* >( BlockEntity ); + FurnaceEntity->WriteToFile( f ); + } + break; + case E_BLOCK_SIGN_POST: + case E_BLOCK_WALLSIGN: + { + cSignEntity* SignEntity = reinterpret_cast< cSignEntity* >( BlockEntity ); + SignEntity->WriteToFile( f ); + } + break; + default: + break; + } + } + + fclose(f); + return true; + } + else + { + LOGERROR("ERROR WRITING TO FILE %s", SourceFile); + return false; + } +} + + +/****************************************** + * New format + **/ + +cChunk* cChunkLoader::LoadFormat1( int a_X, int a_Y, int a_Z ) +{ + int PakX = (int)(floorf((float)a_X / 16.f)); + int PakY = (int)(floorf((float)a_Y / 16.f)); + int PakZ = (int)(floorf((float)a_Z / 16.f)); + + ChunkPack * Pack = 0; + ChunkPackList & PackList = m_ChunkPacks->AllPacks; + for( ChunkPackList::iterator itr = PackList.begin(); itr != PackList.end(); ++itr ) + { + if( itr->x == PakX && itr->y == PakY && itr->z == PakZ ) + { + Pack = &(*itr); + break; + } + } + + + if( !Pack ) // The pack was not in memory, so try to load it from disk + { + Pack = LoadPak1( PakX, PakY, PakZ ); // Load .pak file from disk + if( Pack ) + { + PackList.push_back( *Pack ); // Add it to the loaded list + } + } + + if( Pack ) // Allright, the pack is in memory + { + ChunkData * Data = 0; + ChunkDataList & ChunkList = Pack->AllChunks; + for( ChunkDataList::iterator itr = ChunkList.begin(); itr != ChunkList.end(); ++itr ) + { + if( itr->x == a_X && itr->z == a_Z ) + { + Data = &(*itr); + break; + } + } + + if( !Data ) // Sorry, chunk does not exist (yet) + return 0; + + if( Data->LiveChunk ) // This chunk is already loaded and decoded (this should actually never happen) + return Data->LiveChunk; + + // Decompress chunk, and return brand new chunk + + // doing it... + + return 0; // actually return the chunk + } + + return 0; // .pak file didn't exist +} + +cChunkLoader::ChunkPack* cChunkLoader::LoadPak1( int PakX, int PakY, int PakZ ) +{ + char SourceFile[128]; + sprintf_s(SourceFile, 128, "world/X%i_Y%i_Z%i.pak", PakX, PakY, PakZ ); + + FILE* f = 0; + #ifdef _WIN32 + if( fopen_s(&f, SourceFile, "rb" ) == 0 ) // no error + #else + if( (f = fopen(SourceFile, "rb" )) != 0 ) // no error + #endif + { + cChunkLoader::ChunkPack * Pack = new cChunkLoader::ChunkPack; + Pack->x = PakX; + Pack->y = PakY; + Pack->z = PakZ; + + short Version = 0; + if( fread( &Version, sizeof( short ), 1, f ) != 1 ) { LOGERROR("Error reading file %s", SourceFile ); return 0; } + if( Version != 1 ) { LOGERROR("Wrong pak version! %s", SourceFile ); return 0; } + short NumChunks = 0; + if( fread( &NumChunks, sizeof( short ), 1, f ) != 1 ) { LOGERROR("Error reading file %s", SourceFile ); return 0; } + + // Load all the headers + for( short i = 0; i < NumChunks; ++i ) + { + ChunkData Data; + if( fread( &Data.x, sizeof( int ), 1, f ) != 1 ) { LOGERROR("Error reading file %s", SourceFile ); return 0; } + if( fread( &Data.z, sizeof( int ), 1, f ) != 1 ) { LOGERROR("Error reading file %s", SourceFile ); return 0; } + if( fread( &Data.DataSize, sizeof( unsigned int ), 1, f ) != 1 ) { LOGERROR("Error reading file %s", SourceFile ); return 0; } + if( fread( &Data.ChunkStart, sizeof( unsigned int ), 1, f ) != 1 ) { LOGERROR("Error reading file %s", SourceFile ); return 0; } + Pack->AllChunks.push_back( Data ); + } + + // Load all compressed chunk data in the order the headers were loaded + ChunkDataList::iterator itr = Pack->AllChunks.begin(); + for( short i = 0; i < NumChunks; ++i ) + { + itr->Data = new char[ itr->DataSize ]; + if( fread( itr->Data, sizeof( char ) * itr->DataSize, 1, f ) != 1 ) { LOGERROR("Error reading file %s", SourceFile ); return 0; } + ++itr; + } + + // And we're done :) + return Pack; + } + return 0; +} +#endif \ No newline at end of file -- cgit v1.2.3