Merge pull request #1346 from mc-server/AnvilStatsHeights
Anvil stats heights
This commit is contained in:
commit
3da27fb7a3
1
Tools/AnvilStats/.gitignore
vendored
1
Tools/AnvilStats/.gitignore
vendored
@ -11,3 +11,4 @@ Profiling
|
||||
*.png
|
||||
world/
|
||||
*.html
|
||||
*.xls
|
||||
|
@ -118,5 +118,27 @@ add_executable(AnvilStats
|
||||
${SHARED_OSS_HDR}
|
||||
)
|
||||
|
||||
|
||||
target_link_libraries(AnvilStats zlib)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Under MSVC we need to enlarge the default stack size for the executable:
|
||||
if (MSVC)
|
||||
get_target_property(TEMP AnvilStats LINK_FLAGS)
|
||||
if (TEMP STREQUAL "TEMP-NOTFOUND")
|
||||
SET(TEMP "") # set to empty string
|
||||
message("LINKER_FLAGS not found")
|
||||
else ()
|
||||
SET(TEMP "${TEMP} ") # a space to cleanly separate from existing content
|
||||
message("LINKER_FLAGS: ${LINKER_FLAGS}")
|
||||
endif ()
|
||||
# append our values
|
||||
SET(TEMP "${TEMP}/STACK:16777216")
|
||||
set_target_properties(AnvilStats PROPERTIES LINK_FLAGS ${TEMP})
|
||||
endif ()
|
||||
|
||||
|
||||
|
||||
|
@ -241,6 +241,17 @@ public:
|
||||
|
||||
|
||||
|
||||
/** Clamp value to the specified range. */
|
||||
template <typename T>
|
||||
T Clamp(T a_Value, T a_Min, T a_Max)
|
||||
{
|
||||
return (a_Value < a_Min) ? a_Min : ((a_Value > a_Max) ? a_Max : a_Value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Common headers (part 2, with macros):
|
||||
#include "../../src/ChunkDef.h"
|
||||
#include "../../src/BlockID.h"
|
||||
|
@ -28,6 +28,7 @@ cProcessor::cThread::cThread(cCallback & a_Callback, cProcessor & a_ParentProces
|
||||
m_Callback(a_Callback),
|
||||
m_ParentProcessor(a_ParentProcessor)
|
||||
{
|
||||
LOG("Created a new thread: %p", this);
|
||||
super::Start();
|
||||
}
|
||||
|
||||
@ -35,11 +36,20 @@ cProcessor::cThread::cThread(cCallback & a_Callback, cProcessor & a_ParentProces
|
||||
|
||||
|
||||
|
||||
void cProcessor::cThread::WaitForStart(void)
|
||||
{
|
||||
m_HasStarted.Wait();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProcessor::cThread::Execute(void)
|
||||
{
|
||||
LOG("Started a new thread: %d", cIsThread::GetCurrentID());
|
||||
LOG("Started a new thread: %p, ID %d", this, cIsThread::GetCurrentID());
|
||||
|
||||
m_ParentProcessor.m_ThreadsHaveStarted.Set();
|
||||
m_HasStarted.Set();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
@ -52,7 +62,7 @@ void cProcessor::cThread::Execute(void)
|
||||
ProcessFile(FileName);
|
||||
} // for-ever
|
||||
|
||||
LOG("Thread %d terminated", cIsThread::GetCurrentID());
|
||||
LOG("Thread %p (ID %d) terminated", this, cIsThread::GetCurrentID());
|
||||
}
|
||||
|
||||
|
||||
@ -522,20 +532,18 @@ void cProcessor::ProcessWorld(const AString & a_WorldFolder, cCallbackFactory &
|
||||
#endif // _DEBUG
|
||||
//*/
|
||||
|
||||
// Start all the threads:
|
||||
for (int i = 0; i < NumThreads; i++)
|
||||
{
|
||||
cCallback * Callback = a_CallbackFactory.GetNewCallback();
|
||||
m_Threads.push_back(new cThread(*Callback, *this));
|
||||
}
|
||||
|
||||
// Wait for the first thread to start processing:
|
||||
m_ThreadsHaveStarted.Wait();
|
||||
|
||||
// Wait for all threads to finish
|
||||
// simply by calling each thread's destructor sequentially
|
||||
// Wait for all threads to finish:
|
||||
LOG("Waiting for threads to finish");
|
||||
for (cThreads::iterator itr = m_Threads.begin(), end = m_Threads.end(); itr != end; ++itr)
|
||||
{
|
||||
(*itr)->WaitForStart();
|
||||
delete *itr;
|
||||
} // for itr - m_Threads[]
|
||||
LOG("Processor finished");
|
||||
|
@ -30,6 +30,7 @@ class cProcessor
|
||||
|
||||
cCallback & m_Callback;
|
||||
cProcessor & m_ParentProcessor;
|
||||
cEvent m_HasStarted;
|
||||
|
||||
// cIsThread override:
|
||||
virtual void Execute(void) override;
|
||||
@ -48,6 +49,9 @@ class cProcessor
|
||||
|
||||
public:
|
||||
cThread(cCallback & a_Callback, cProcessor & a_ParentProcessor);
|
||||
|
||||
/** Waits until the thread starts processing the callback code. */
|
||||
void WaitForStart(void);
|
||||
} ;
|
||||
|
||||
typedef std::vector<cThread *> cThreads;
|
||||
@ -65,10 +69,12 @@ protected:
|
||||
AStringList m_FileQueue;
|
||||
|
||||
cThreads m_Threads;
|
||||
cEvent m_ThreadsHaveStarted; // This is signalled by each thread to notify the parent thread that it can start waiting for those threads
|
||||
|
||||
|
||||
|
||||
/** Populates m_FileQueue with Anvil files from the specified folder. */
|
||||
void PopulateFileQueue(const AString & a_WorldFolder);
|
||||
|
||||
/** Returns one filename from m_FileQueue, and removes the name from the queue. */
|
||||
AString GetOneFileName(void);
|
||||
} ;
|
||||
|
||||
|
@ -26,9 +26,11 @@ cStatistics::cStats::cStats(void) :
|
||||
m_MinChunkZ(0x7fffffff),
|
||||
m_MaxChunkZ(0x80000000)
|
||||
{
|
||||
memset(m_BiomeCounts, 0, sizeof(m_BiomeCounts));
|
||||
memset(m_BlockCounts, 0, sizeof(m_BlockCounts));
|
||||
memset(m_SpawnerEntity, 0, sizeof(m_SpawnerEntity));
|
||||
memset(m_BiomeCounts, 0, sizeof(m_BiomeCounts));
|
||||
memset(m_BlockCounts, 0, sizeof(m_BlockCounts));
|
||||
memset(m_PerHeightBlockCounts, 0, sizeof(m_PerHeightBlockCounts));
|
||||
memset(m_PerHeightSpawners, 0, sizeof(m_PerHeightSpawners));
|
||||
memset(m_SpawnerEntity, 0, sizeof(m_SpawnerEntity));
|
||||
}
|
||||
|
||||
|
||||
@ -46,6 +48,11 @@ void cStatistics::cStats::Add(const cStatistics::cStats & a_Stats)
|
||||
for (int j = 0; j <= 255; j++)
|
||||
{
|
||||
m_BlockCounts[i][j] += a_Stats.m_BlockCounts[i][j];
|
||||
m_PerHeightBlockCounts[i][j] += a_Stats.m_PerHeightBlockCounts[i][j];
|
||||
}
|
||||
for (int j = 0; j < ARRAYCOUNT(m_PerHeightSpawners[0]); j++)
|
||||
{
|
||||
m_PerHeightSpawners[i][j] += a_Stats.m_PerHeightSpawners[i][j];
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < ARRAYCOUNT(m_SpawnerEntity); i++)
|
||||
@ -149,6 +156,7 @@ bool cStatistics::OnSection
|
||||
|
||||
for (int y = 0; y < 16; y++)
|
||||
{
|
||||
int Height = (int)a_Y * 16 + y;
|
||||
for (int z = 0; z < 16; z++)
|
||||
{
|
||||
for (int x = 0; x < 16; x++)
|
||||
@ -156,6 +164,7 @@ bool cStatistics::OnSection
|
||||
unsigned char Biome = m_BiomeData[x + 16 * z]; // Cannot use cChunkDef, different datatype
|
||||
unsigned char BlockType = cChunkDef::GetBlock(a_BlockTypes, x, y, z);
|
||||
m_Stats.m_BlockCounts[Biome][BlockType] += 1;
|
||||
m_Stats.m_PerHeightBlockCounts[Height][BlockType] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -259,16 +268,27 @@ bool cStatistics::OnTileTick(
|
||||
|
||||
void cStatistics::OnSpawner(cParsedNBT & a_NBT, int a_TileEntityTag)
|
||||
{
|
||||
// Get the spawned entity type:
|
||||
int EntityIDTag = a_NBT.FindChildByName(a_TileEntityTag, "EntityId");
|
||||
if ((EntityIDTag < 0) || (a_NBT.GetType(EntityIDTag) != TAG_String))
|
||||
{
|
||||
return;
|
||||
}
|
||||
eEntityType Ent = GetEntityType(a_NBT.GetString(EntityIDTag));
|
||||
if (Ent < ARRAYCOUNT(m_Stats.m_SpawnerEntity))
|
||||
if (Ent >= ARRAYCOUNT(m_Stats.m_SpawnerEntity))
|
||||
{
|
||||
m_Stats.m_SpawnerEntity[Ent] += 1;
|
||||
return;
|
||||
}
|
||||
m_Stats.m_SpawnerEntity[Ent] += 1;
|
||||
|
||||
// Get the spawner pos:
|
||||
int PosYTag = a_NBT.FindChildByName(a_TileEntityTag, "y");
|
||||
if ((PosYTag < 0) || (a_NBT.GetType(PosYTag) != TAG_Int))
|
||||
{
|
||||
return;
|
||||
}
|
||||
int BlockY = Clamp(a_NBT.GetInt(PosYTag), 0, 255);
|
||||
m_Stats.m_PerHeightSpawners[BlockY][Ent] += 1;
|
||||
}
|
||||
|
||||
|
||||
@ -316,10 +336,14 @@ cStatisticsFactory::~cStatisticsFactory()
|
||||
SaveBiomes();
|
||||
LOG(" BlockTypes.xls");
|
||||
SaveBlockTypes();
|
||||
LOG(" PerHeightBlockTypes.xls");
|
||||
SavePerHeightBlockTypes();
|
||||
LOG(" BiomeBlockTypes.xls");
|
||||
SaveBiomeBlockTypes();
|
||||
LOG(" Spawners.xls");
|
||||
SaveSpawners();
|
||||
LOG(" PerHeightSpawners.xls");
|
||||
SavePerHeightSpawners();
|
||||
}
|
||||
|
||||
|
||||
@ -395,6 +419,61 @@ void cStatisticsFactory::SaveBlockTypes(void)
|
||||
|
||||
|
||||
|
||||
void cStatisticsFactory::SavePerHeightBlockTypes(void)
|
||||
{
|
||||
// Export as two tables: biomes 0-127 and 128-255, because OpenOffice doesn't support more than 256 columns
|
||||
|
||||
cFile f;
|
||||
if (!f.Open("PerHeightBlockTypes.xls", cFile::fmWrite))
|
||||
{
|
||||
LOG("Cannot write to file PerHeightBlockTypes.xls. Statistics not written.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Write header:
|
||||
f.Printf("Blocks 0 - 127:\nHeight");
|
||||
for (int i = 0; i < 128; i++)
|
||||
{
|
||||
f.Printf("\t%s(%d)", GetBlockTypeString(i), i);
|
||||
}
|
||||
f.Printf("\n");
|
||||
|
||||
// Write first half:
|
||||
for (int y = 0; y < 256; y++)
|
||||
{
|
||||
f.Printf("%d", y);
|
||||
for (int BlockType = 0; BlockType < 128; BlockType++)
|
||||
{
|
||||
f.Printf("\t%llu", m_CombinedStats.m_PerHeightBlockCounts[y][BlockType]);
|
||||
} // for BlockType
|
||||
f.Printf("\n");
|
||||
} // for y - height (0 - 127)
|
||||
f.Printf("\n");
|
||||
|
||||
// Write second header:
|
||||
f.Printf("Blocks 128 - 255:\nHeight");
|
||||
for (int i = 128; i < 256; i++)
|
||||
{
|
||||
f.Printf("\t%s(%d)", GetBlockTypeString(i), i);
|
||||
}
|
||||
f.Printf("\n");
|
||||
|
||||
// Write second half:
|
||||
for (int y = 0; y < 256; y++)
|
||||
{
|
||||
f.Printf("%d", y);
|
||||
for (int BlockType = 128; BlockType < 256; BlockType++)
|
||||
{
|
||||
f.Printf("\t%llu", m_CombinedStats.m_PerHeightBlockCounts[y][BlockType]);
|
||||
} // for BlockType
|
||||
f.Printf("\n");
|
||||
} // for y - height (0 - 127)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cStatisticsFactory::SaveBiomeBlockTypes(void)
|
||||
{
|
||||
// Export as two tables: biomes 0-127 and 128-255, because OpenOffice doesn't support more than 256 columns
|
||||
@ -521,3 +600,41 @@ void cStatisticsFactory::SaveSpawners(void)
|
||||
|
||||
|
||||
|
||||
|
||||
void cStatisticsFactory::SavePerHeightSpawners(void)
|
||||
{
|
||||
cFile f;
|
||||
if (!f.Open("PerHeightSpawners.xls", cFile::fmWrite))
|
||||
{
|
||||
LOG("Cannot write to file PerHeightSpawners.xls. Statistics not written.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Write header:
|
||||
f.Printf("Height\tTotal");
|
||||
for (int i = 0; i < entMax; i++)
|
||||
{
|
||||
f.Printf("\t%s", GetEntityTypeString((eEntityType)i));
|
||||
}
|
||||
f.Printf("\n");
|
||||
|
||||
// Write individual lines:
|
||||
for (int y = 0; y < 256; y++)
|
||||
{
|
||||
UInt64 Total = 0;
|
||||
for (int i = 0; i < entMax; i++)
|
||||
{
|
||||
Total += m_CombinedStats.m_PerHeightSpawners[y][i];
|
||||
}
|
||||
f.Printf("%d\t%llu", y, Total);
|
||||
for (int i = 0; i < entMax; i++)
|
||||
{
|
||||
f.Printf("\t%llu", m_CombinedStats.m_PerHeightSpawners[y][i]);
|
||||
}
|
||||
f.Printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -31,6 +31,8 @@ public:
|
||||
UInt64 m_NumEntities;
|
||||
UInt64 m_NumTileEntities;
|
||||
UInt64 m_NumTileTicks;
|
||||
UInt64 m_PerHeightBlockCounts[256][256]; // First dimension is the height, second dimension is BlockType
|
||||
UInt64 m_PerHeightSpawners[256][entMax + 1]; // First dimension is the height, second dimension is spawned entity type
|
||||
int m_MinChunkX, m_MaxChunkX; // X coords range
|
||||
int m_MinChunkZ, m_MaxChunkZ; // Z coords range
|
||||
|
||||
@ -74,6 +76,8 @@ protected:
|
||||
|
||||
virtual bool OnEmptySection(unsigned char a_Y) override;
|
||||
|
||||
virtual bool OnSectionsFinished(void) override { return false; } // continue processing
|
||||
|
||||
virtual bool OnEntity(
|
||||
const AString & a_EntityType,
|
||||
double a_PosX, double a_PosY, double a_PosZ,
|
||||
@ -128,9 +132,11 @@ protected:
|
||||
void JoinResults(void);
|
||||
void SaveBiomes(void);
|
||||
void SaveBlockTypes(void);
|
||||
void SavePerHeightBlockTypes(void);
|
||||
void SaveBiomeBlockTypes(void);
|
||||
void SaveStatistics(void);
|
||||
void SaveSpawners(void);
|
||||
void SavePerHeightSpawners(void);
|
||||
} ;
|
||||
|
||||
|
||||
|
@ -272,7 +272,7 @@ extern const char * GetEntityTypeString(eEntityType a_EntityType)
|
||||
int GetNumCores(void)
|
||||
{
|
||||
// Get number of cores by querying the system process affinity mask (Windows-specific)
|
||||
DWORD Affinity, ProcAffinity;
|
||||
DWORD_PTR Affinity, ProcAffinity;
|
||||
GetProcessAffinityMask(GetCurrentProcess(), &ProcAffinity, &Affinity);
|
||||
int NumCores = 0;
|
||||
while (Affinity > 0)
|
||||
|
Loading…
Reference in New Issue
Block a user