2013-07-29 07:13:03 -04:00
|
|
|
|
|
|
|
// ChunkExtract.cpp
|
|
|
|
|
|
|
|
// Implements the cChunkExtract class representing a cCallback descendant that extracts raw chunk data into separate .chunk files
|
|
|
|
|
|
|
|
#include "Globals.h"
|
|
|
|
#include "ChunkExtract.h"
|
2013-11-28 04:05:39 -05:00
|
|
|
#include "../../src/OSSupport/GZipFile.h"
|
2013-07-29 07:13:03 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cChunkExtract::cChunkExtract(const AString & iWorldFolder) :
|
|
|
|
mWorldFolder(iWorldFolder)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool cChunkExtract::OnNewChunk(int a_ChunkX, int a_ChunkZ)
|
|
|
|
{
|
|
|
|
int AnvilX = (a_ChunkX - ((a_ChunkX > 0) ? 0 : 31)) / 32;
|
|
|
|
int AnvilZ = (a_ChunkZ - ((a_ChunkZ > 0) ? 0 : 31)) / 32;
|
|
|
|
if ((AnvilX != mCurAnvilX) || (AnvilZ != mCurAnvilZ))
|
|
|
|
{
|
|
|
|
OpenAnvilFile(AnvilX, AnvilZ);
|
|
|
|
}
|
|
|
|
mCurChunkX = a_ChunkX;
|
|
|
|
mCurChunkZ = a_ChunkZ;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool cChunkExtract::OnCompressedDataSizePos(int a_CompressedDataSize, int a_DataOffset, char a_CompressionMethod)
|
|
|
|
{
|
|
|
|
if (!mAnvilFile.IsOpen())
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
cFile ChunkFile;
|
|
|
|
AString ChunkPath = Printf("%d.%d.zchunk", mCurChunkX, mCurChunkZ);
|
|
|
|
if (!ChunkFile.Open(ChunkPath, cFile::fmWrite))
|
|
|
|
{
|
|
|
|
LOG("Cannot open zchunk file \"%s\" for writing. Chunk [%d, %d] skipped.", ChunkPath.c_str(), mCurChunkX, mCurChunkZ);
|
|
|
|
return false;
|
|
|
|
}
|
2017-12-23 07:49:08 -05:00
|
|
|
|
2013-07-29 07:13:03 -04:00
|
|
|
// Copy data from mAnvilFile to ChunkFile:
|
|
|
|
mAnvilFile.Seek(a_DataOffset);
|
2017-12-23 07:49:08 -05:00
|
|
|
for (int BytesToCopy = a_CompressedDataSize; BytesToCopy > 0;)
|
2013-07-29 07:13:03 -04:00
|
|
|
{
|
|
|
|
char Buffer[64000];
|
|
|
|
int NumBytes = std::min(BytesToCopy, (int)sizeof(Buffer));
|
|
|
|
int BytesRead = mAnvilFile.Read(Buffer, NumBytes);
|
|
|
|
if (BytesRead != NumBytes)
|
|
|
|
{
|
|
|
|
LOG("Cannot copy chunk data, chunk [%d, %d] is probably corrupted. Skipping chunk.", mCurChunkX, mCurChunkZ);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
ChunkFile.Write(Buffer, BytesRead);
|
|
|
|
BytesToCopy -= BytesRead;
|
|
|
|
} // for BytesToCopy
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool cChunkExtract::OnDecompressedData(const char * a_DecompressedNBT, int a_DataSize)
|
|
|
|
{
|
|
|
|
ASSERT(mAnvilFile.IsOpen()); // If it weren't, the OnCompressedDataSizePos would've prevented this from running
|
|
|
|
AString FileName = Printf("%d.%d.gzchunk", mCurChunkX, mCurChunkZ);
|
|
|
|
cGZipFile GZipChunk;
|
|
|
|
if (!GZipChunk.Open(FileName, cGZipFile::fmWrite))
|
|
|
|
{
|
|
|
|
LOG("Cannot open gzchunk file \"%s\" for writing. Chunk [%d, %d] skipped.", FileName.c_str(), mCurChunkX, mCurChunkZ);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
GZipChunk.Write(a_DecompressedNBT, a_DataSize);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cChunkExtract::OpenAnvilFile(int a_AnvilX, int a_AnvilZ)
|
|
|
|
{
|
|
|
|
mAnvilFile.Close();
|
|
|
|
AString FileName = Printf("%s/r.%d.%d.mca", mWorldFolder.c_str(), a_AnvilX, a_AnvilZ);
|
|
|
|
if (!mAnvilFile.Open(FileName, cFile::fmRead))
|
|
|
|
{
|
|
|
|
LOG("Cannot open Anvil file \"%s\" for reading", FileName.c_str());
|
|
|
|
}
|
|
|
|
mCurAnvilX = a_AnvilX;
|
|
|
|
mCurAnvilZ = a_AnvilZ;
|
2017-12-23 07:49:08 -05:00
|
|
|
}
|