From 24d3d5dac40562f22a43eb9934c90165ace92a35 Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Mon, 25 Feb 2013 19:06:37 +0000 Subject: AnvilStats: Added ChunkExtract mode of operation, splitting Anvil files into individual chunks. Both original zlibbed chunks and re-gzipped chunks are output. git-svn-id: http://mc-server.googlecode.com/svn/trunk@1223 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- AnvilStats/AnvilStats.cpp | 9 ++-- AnvilStats/AnvilStats.vcproj | 16 +++++++ AnvilStats/BiomeMap.h | 2 +- AnvilStats/ChunkExtract.cpp | 104 ++++++++++++++++++++++++++++++++++++++++++ AnvilStats/ChunkExtract.h | 66 +++++++++++++++++++++++++++ AnvilStats/HeightMap.h | 2 +- AnvilStats/Processor.cpp | 4 +- VC2008/profile_run.cmd | 5 +- source/OSSupport/File.cpp | 3 +- source/OSSupport/GZipFile.cpp | 4 +- source/OSSupport/GZipFile.h | 4 +- 11 files changed, 205 insertions(+), 14 deletions(-) create mode 100644 AnvilStats/ChunkExtract.cpp create mode 100644 AnvilStats/ChunkExtract.h diff --git a/AnvilStats/AnvilStats.cpp b/AnvilStats/AnvilStats.cpp index a72548a5d..ef4d33ca5 100644 --- a/AnvilStats/AnvilStats.cpp +++ b/AnvilStats/AnvilStats.cpp @@ -8,6 +8,7 @@ #include "Statistics.h" #include "BiomeMap.h" #include "HeightMap.h" +#include "ChunkExtract.h" @@ -22,6 +23,7 @@ int main(int argc, char * argv[]) LOG(" 0 - statistics"); LOG(" 1 - biome map"); LOG(" 2 - height map"); + LOG(" 3 - extract chunks"); LOG("\nNo method number present, aborting."); return -1; } @@ -39,9 +41,10 @@ int main(int argc, char * argv[]) cCallbackFactory * Factory = NULL; switch (atol(argv[1])) { - case 0: Factory = new cStatisticsFactory; break; - case 1: Factory = new cBiomeMapFactory; break; - case 2: Factory = new cHeightMapFactory; break; + case 0: Factory = new cStatisticsFactory; break; + case 1: Factory = new cBiomeMapFactory; break; + case 2: Factory = new cHeightMapFactory; break; + case 3: Factory = new cChunkExtractFactory(WorldFolder); break; default: { LOG("Unknown method \"%s\", aborting.", argv[1]); diff --git a/AnvilStats/AnvilStats.vcproj b/AnvilStats/AnvilStats.vcproj index e67634f9c..8e8af8dfa 100644 --- a/AnvilStats/AnvilStats.vcproj +++ b/AnvilStats/AnvilStats.vcproj @@ -273,6 +273,14 @@ RelativePath=".\Callback.h" > + + + + @@ -401,6 +409,14 @@ RelativePath="..\source\OSSupport\File.h" > + + + + diff --git a/AnvilStats/BiomeMap.h b/AnvilStats/BiomeMap.h index 170216f46..f0d306c04 100644 --- a/AnvilStats/BiomeMap.h +++ b/AnvilStats/BiomeMap.h @@ -57,7 +57,7 @@ class cBiomeMapFactory : public: virtual ~cBiomeMapFactory(); - virtual cCallback * CreateNewCallback(void) + virtual cCallback * CreateNewCallback(void) override { return new cBiomeMap; } diff --git a/AnvilStats/ChunkExtract.cpp b/AnvilStats/ChunkExtract.cpp new file mode 100644 index 000000000..30bdda9f3 --- /dev/null +++ b/AnvilStats/ChunkExtract.cpp @@ -0,0 +1,104 @@ + +// 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" +#include "../source/OSSupport/GZipFile.h" + + + + + +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; + } + + // Copy data from mAnvilFile to ChunkFile: + mAnvilFile.Seek(a_DataOffset); + for (int BytesToCopy = a_CompressedDataSize; BytesToCopy > 0; ) + { + 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; +} \ No newline at end of file diff --git a/AnvilStats/ChunkExtract.h b/AnvilStats/ChunkExtract.h new file mode 100644 index 000000000..5e0ed8a9a --- /dev/null +++ b/AnvilStats/ChunkExtract.h @@ -0,0 +1,66 @@ + +// ChunkExtract.h + +// Declares the cChunkExtract class representing a cCallback descendant that extracts raw chunk data into separate .chunk files + + + + + +#pragma once + +#include "Callback.h" + + + + + +class cChunkExtract : + public cCallback +{ +public: + cChunkExtract(const AString & iWorldFolder); + +protected: + AString mWorldFolder; + cFile mAnvilFile; + int mCurAnvilX; // X-coord of mAnvilFile, in Anvil-coords (1 Anvil-coord = 32 chunks) + int mCurAnvilZ; // Z-coord of mAnvilFile, -"- + int mCurChunkX; // X-coord of the chunk being processed + int mCurChunkZ; // Z-coord of the chunk being processed + + /// Opens new anvil file into mAnvilFile, sets mCurAnvilX and mCurAnvilZ + void OpenAnvilFile(int a_AnvilX, int a_AnvilZ); + + // cCallback overrides: + virtual bool OnNewChunk(int a_ChunkX, int a_ChunkZ) override; + virtual bool OnHeader(int a_FileOffset, unsigned char a_NumSectors, int a_Timestamp) override { return false; } + virtual bool OnCompressedDataSizePos(int a_CompressedDataSize, int a_DataOffset, char a_CompressionMethod) override; + virtual bool OnDecompressedData(const char * a_DecompressedNBT, int a_DataSize) override; +} ; + + + + + +class cChunkExtractFactory : + public cCallbackFactory +{ +public: + cChunkExtractFactory(const AString & iWorldFolder) : + mWorldFolder(iWorldFolder) + { + } + + virtual cCallback * CreateNewCallback(void) override + { + return new cChunkExtract(mWorldFolder); + } + +protected: + AString mWorldFolder; +} ; + + + + diff --git a/AnvilStats/HeightMap.h b/AnvilStats/HeightMap.h index 3263329a9..4f9e702d5 100644 --- a/AnvilStats/HeightMap.h +++ b/AnvilStats/HeightMap.h @@ -69,7 +69,7 @@ class cHeightMapFactory : public: virtual ~cHeightMapFactory(); - virtual cCallback * CreateNewCallback(void) + virtual cCallback * CreateNewCallback(void) override { return new cHeightMap; } diff --git a/AnvilStats/Processor.cpp b/AnvilStats/Processor.cpp index 02070a8fc..8b506791c 100644 --- a/AnvilStats/Processor.cpp +++ b/AnvilStats/Processor.cpp @@ -507,12 +507,12 @@ void cProcessor::ProcessWorld(const AString & a_WorldFolder, cCallbackFactory & // (One more thread can be in the file-read IO block while all other threads crunch the numbers) int NumThreads = GetNumCores() + 1; - /* + //* // Limit the number of threads in DEBUG mode to 1 for easier debugging #ifdef _DEBUG NumThreads = 1; #endif // _DEBUG - */ + //*/ for (int i = 0; i < NumThreads; i++) { diff --git a/VC2008/profile_run.cmd b/VC2008/profile_run.cmd index 3b6a2f99d..47c2630d2 100644 --- a/VC2008/profile_run.cmd +++ b/VC2008/profile_run.cmd @@ -14,7 +14,8 @@ set app=MCServer_profiled.exe :: outputdir is relative to appdir! set outputdir=..\Profiling -set output=%outputdir%\profile.vsp +set outputname=profile.vsp +set output=%outputdir%\%outputname% @@ -50,7 +51,7 @@ if errorlevel 1 goto haderror cd %outputdir% :: generate the report files (.csv) -%pt%\vsperfreport /summary:all %output% /symbolpath:"srv*C:\Programovani\Symbols*http://msdl.microsoft.com/download/symbols" +%pt%\vsperfreport /summary:all %outputname% /symbolpath:"srv*C:\Programovani\Symbols*http://msdl.microsoft.com/download/symbols" if errorlevel 1 goto haderror diff --git a/source/OSSupport/File.cpp b/source/OSSupport/File.cpp index 15a37a36f..bd2670217 100644 --- a/source/OSSupport/File.cpp +++ b/source/OSSupport/File.cpp @@ -94,10 +94,9 @@ bool cFile::Open(const AString & iFileName, eMode iMode) void cFile::Close(void) { - ASSERT(IsOpen()); // You should not close file objects that don't have an open file. - if (!IsOpen()) { + // Closing an unopened file is a legal nop return; } diff --git a/source/OSSupport/GZipFile.cpp b/source/OSSupport/GZipFile.cpp index dbdef3a8b..c57de5198 100644 --- a/source/OSSupport/GZipFile.cpp +++ b/source/OSSupport/GZipFile.cpp @@ -85,7 +85,7 @@ int cGZipFile::ReadRestOfFile(AString & a_Contents) -bool cGZipFile::Write(const AString & a_Contents) +bool cGZipFile::Write(const char * a_Contents, int a_Size) { if (m_File == NULL) { @@ -99,7 +99,7 @@ bool cGZipFile::Write(const AString & a_Contents) return false; } - return (gzwrite(m_File, a_Contents.data(), a_Contents.size()) != 0); + return (gzwrite(m_File, a_Contents, a_Size) != 0); } diff --git a/source/OSSupport/GZipFile.h b/source/OSSupport/GZipFile.h index 10fb447dd..f20b4d11e 100644 --- a/source/OSSupport/GZipFile.h +++ b/source/OSSupport/GZipFile.h @@ -37,7 +37,9 @@ public: int ReadRestOfFile(AString & a_Contents); /// Writes a_Contents into file, compressing it along the way. Returns true if successful. Multiple writes are supported. - bool Write(const AString & a_Contents); + bool Write(const AString & a_Contents) { return Write(a_Contents.data(), (int)(a_Contents.size())); } + + bool Write(const char * a_Data, int a_Size); protected: gzFile m_File; -- cgit v1.2.3