1
0

AnvilStats: Overall statistics and mobspawner statistics.

git-svn-id: http://mc-server.googlecode.com/svn/trunk@899 0a769ca7-a7f5-676a-18bf-c427514a06d6
This commit is contained in:
madmaxoft@gmail.com 2012-09-29 13:33:45 +00:00
parent b903b29057
commit cead22a206
8 changed files with 574 additions and 66 deletions

View File

@ -13,6 +13,13 @@
// fwd:
class cParsedNBT;
/** The base class for all chunk-processor callbacks, declares the interface.
The processor calls each virtual function in the order they are declared here with the specified args.
If the function returns true, the processor moves on to next chunk and starts calling the callbacks again from start with
@ -68,7 +75,42 @@ public:
*/
virtual bool OnEmptySection(unsigned char a_Y) { return false; }
// TODO: entities, tile-entities, tile-ticks
/** Called for each entity in the chunk.
Common parameters are parsed from the NBT.
The callback may parse any other param from the a_NBT and a_NBTTag parameters.
The a_NBTTag parameter points to the entity compound tag inside the Entities tag.
*/
virtual bool OnEntity(
const AString & a_EntityType,
double a_PosX, double a_PosY, double a_PosZ,
double a_SpeedX, double a_SpeedY, double a_SpeedZ,
float a_Yaw, float a_Pitch,
float a_FallDistance,
short a_FireTicksLeft,
short a_AirTicks,
char a_IsOnGround,
cParsedNBT & a_NBT,
int a_NBTTag
) { return true; }
/** Called for each tile entity in the chunk.
Common parameters are parsed from the NBT.
The callback may parse any other param from the a_NBT and a_NBTTag parameters.
The a_NBTTag parameter points to the tile entity compound tag inside the TileEntities tag.
*/
virtual bool OnTileEntity(
const AString & a_EntityType,
int a_PosX, int a_PosY, int a_PosZ,
cParsedNBT & a_NBT,
int a_NBTTag
) { return true; }
/// Called for each tile tick in the chunk
virtual bool OnTileTick(
int a_BlockType,
int a_TicksLeft,
int a_PosX, int a_PosY, int a_PosZ
) { return true; }
} ;
typedef std::vector<cCallback *> cCallbacks;

View File

@ -15,6 +15,8 @@
// Disable some warnings that we don't care about:
#pragma warning(disable:4100)
#define _CRT_SECURE_NO_WARNINGS
#define OBSOLETE __declspec(deprecated)
@ -149,6 +151,7 @@ typedef short Int16;
#include <map>
#include <algorithm>
#include <memory>
#include <ctime>

View File

@ -256,7 +256,21 @@ void cProcessor::cThread::ProcessParsedChunkData(int a_ChunkX, int a_ChunkZ, cPa
{
return;
}
// TODO: entities, tile-entities etc.
if (ProcessChunkEntities(a_ChunkX, a_ChunkZ, a_NBT, LevelTag))
{
return;
}
if (ProcessChunkTileEntities(a_ChunkX, a_ChunkZ, a_NBT, LevelTag))
{
return;
}
if (ProcessChunkTileTicks(a_ChunkX, a_ChunkZ, a_NBT, LevelTag))
{
return;
}
}
@ -323,6 +337,134 @@ bool cProcessor::cThread::ProcessChunkSections(int a_ChunkX, int a_ChunkZ, cPars
bool cProcessor::cThread::ProcessChunkEntities(int a_ChunkX, int a_ChunkZ, cParsedNBT & a_NBT, int a_LevelTag)
{
int EntitiesTag = a_NBT.FindChildByName(a_LevelTag, "Entities");
if (EntitiesTag < 0)
{
return false;
}
for (int EntityTag = a_NBT.GetFirstChild(EntitiesTag); EntityTag > 0; EntityTag = a_NBT.GetNextSibling(EntityTag))
{
int PosTag = a_NBT.FindChildByName(EntityTag, "Pos");
if (PosTag < 0)
{
continue;
}
int SpeedTag = a_NBT.FindChildByName(EntityTag, "Motion");
if (SpeedTag < 0)
{
continue;
}
int RotTag = a_NBT.FindChildByName(EntityTag, "Rotation");
if (RotTag < 0)
{
continue;
}
double Pos[3];
for (int i = 0, tag = a_NBT.GetFirstChild(PosTag); (i < 3) && (tag > 0); i++)
{
Pos[i] = a_NBT.GetDouble(tag);
}
double Speed[3];
for (int i = 0, tag = a_NBT.GetFirstChild(SpeedTag); (i < 3) && (tag > 0); i++)
{
Speed[i] = a_NBT.GetDouble(tag);
}
float Rot[2];
for (int i = 0, tag = a_NBT.GetFirstChild(RotTag); (i < 2) && (tag > 0); i++)
{
Rot[i] = a_NBT.GetFloat(tag);
}
if (m_Callback.OnEntity(
a_NBT.GetString(a_NBT.FindChildByName(EntityTag, "id")),
Pos[0], Pos[1], Pos[2],
Speed[0], Speed[1], Speed[2],
Rot[0], Rot[1],
a_NBT.GetFloat(a_NBT.FindChildByName(EntityTag, "FallDistance")),
a_NBT.GetShort(a_NBT.FindChildByName(EntityTag, "Fire")),
a_NBT.GetShort(a_NBT.FindChildByName(EntityTag, "Air")),
a_NBT.GetByte(a_NBT.FindChildByName(EntityTag, "OnGround")),
a_NBT, EntityTag
))
{
return true;
}
} // for EntityTag - Entities[]
return false;
}
bool cProcessor::cThread::ProcessChunkTileEntities(int a_ChunkX, int a_ChunkZ, cParsedNBT & a_NBT, int a_LevelTag)
{
int TileEntitiesTag = a_NBT.FindChildByName(a_LevelTag, "TileEntities");
if (TileEntitiesTag < 0)
{
return false;
}
for (int TileEntityTag = a_NBT.GetFirstChild(TileEntitiesTag); TileEntityTag > 0; TileEntityTag = a_NBT.GetNextSibling(TileEntityTag))
{
if (m_Callback.OnTileEntity(
a_NBT.GetString(a_NBT.FindChildByName(TileEntityTag, "id")),
a_NBT.GetInt(a_NBT.FindChildByName(TileEntityTag, "x")),
a_NBT.GetInt(a_NBT.FindChildByName(TileEntityTag, "y")),
a_NBT.GetInt(a_NBT.FindChildByName(TileEntityTag, "z")),
a_NBT, TileEntityTag
))
{
return true;
}
} // for EntityTag - Entities[]
return false;
}
bool cProcessor::cThread::ProcessChunkTileTicks(int a_ChunkX, int a_ChunkZ, cParsedNBT & a_NBT, int a_LevelTag)
{
int TileTicksTag = a_NBT.FindChildByName(a_LevelTag, "TileTicks");
if (TileTicksTag < 0)
{
return false;
}
for (int TileTickTag = a_NBT.GetFirstChild(TileTicksTag); TileTickTag > 0; TileTickTag = a_NBT.GetNextSibling(TileTickTag))
{
int iTag = a_NBT.FindChildByName(TileTicksTag, "i");
int tTag = a_NBT.FindChildByName(TileTicksTag, "t");
int xTag = a_NBT.FindChildByName(TileTicksTag, "x");
int yTag = a_NBT.FindChildByName(TileTicksTag, "y");
int zTag = a_NBT.FindChildByName(TileTicksTag, "z");
if ((iTag < 0) || (tTag < 0) || (xTag < 0) || (yTag < 0) || (zTag < 0))
{
continue;
}
if (m_Callback.OnTileTick(
a_NBT.GetInt(iTag),
a_NBT.GetInt(iTag),
a_NBT.GetInt(iTag),
a_NBT.GetInt(iTag),
a_NBT.GetInt(iTag)
))
{
return true;
}
} // for EntityTag - Entities[]
return false;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cProcessor:

View File

@ -39,7 +39,12 @@ class cProcessor
void ProcessChunk(const char * a_FileData, int a_ChunkX, int a_ChunkZ, unsigned a_SectorStart, unsigned a_SectorSize, unsigned a_TimeStamp);
void ProcessCompressedChunkData(int a_ChunkX, int a_ChunkZ, const char * a_CompressedData, int a_CompressedSize);
void ProcessParsedChunkData(int a_ChunkX, int a_ChunkZ, cParsedNBT & a_NBT);
// The following processing parts return true if they were interrupted by the callback, causing the processing of current chunk to abort
bool ProcessChunkSections(int a_ChunkX, int a_ChunkZ, cParsedNBT & a_NBT, int a_LevelTag);
bool ProcessChunkEntities(int a_ChunkX, int a_ChunkZ, cParsedNBT & a_NBT, int a_LevelTag);
bool ProcessChunkTileEntities(int a_ChunkX, int a_ChunkZ, cParsedNBT & a_NBT, int a_LevelTag);
bool ProcessChunkTileTicks(int a_ChunkX, int a_ChunkZ, cParsedNBT & a_NBT, int a_LevelTag);
public:
cThread(cCallback & a_Callback, cProcessor & a_ParentProcessor);

View File

@ -5,7 +5,56 @@
#include "Globals.h"
#include "Statistics.h"
#include "Utils.h"
#include "../source/WorldStorage/FastNBT.h"
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cStatistics::cStats:
cStatistics::cStats::cStats(void) :
m_TotalChunks(0),
m_BiomeNumChunks(0),
m_BlockNumChunks(0),
m_NumEntities(0),
m_NumTileEntities(0),
m_NumTileTicks(0)
{
memset(m_BiomeCounts, 0, sizeof(m_BiomeCounts));
memset(m_BlockCounts, 0, sizeof(m_BlockCounts));
memset(m_SpawnerEntity, 0, sizeof(m_SpawnerEntity));
}
void cStatistics::cStats::Add(const cStatistics::cStats & a_Stats)
{
for (int i = 0; i <= 255; i++)
{
m_BiomeCounts[i] += a_Stats.m_BiomeCounts[i];
}
for (int i = 0; i <= 255; i++)
{
for (int j = 0; j <= 255; j++)
{
m_BlockCounts[i][j] += a_Stats.m_BlockCounts[i][j];
}
}
for (int i = 0; i < ARRAYCOUNT(m_SpawnerEntity); i++)
{
m_SpawnerEntity[i] += a_Stats.m_SpawnerEntity[i];
}
m_BiomeNumChunks += a_Stats.m_BiomeNumChunks;
m_BlockNumChunks += a_Stats.m_BlockNumChunks;
m_TotalChunks += a_Stats.m_TotalChunks;
m_NumEntities += a_Stats.m_NumEntities;
m_NumTileEntities += a_Stats.m_NumTileEntities;
m_NumTileTicks += a_Stats.m_NumTileTicks;
}
@ -14,13 +63,8 @@
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cStatistics:
cStatistics::cStatistics(void) :
m_TotalChunks(0),
m_BiomeNumChunks(0),
m_BlockNumChunks(0)
cStatistics::cStatistics(void)
{
memset(m_BiomeCounts, 0, sizeof(m_BiomeCounts));
memset(m_BlockCounts, 0, sizeof(m_BlockCounts));
}
@ -29,7 +73,7 @@ cStatistics::cStatistics(void) :
bool cStatistics::OnNewChunk(int a_ChunkX, int a_ChunkZ)
{
m_TotalChunks++;
m_Stats.m_TotalChunks++;
m_IsBiomesValid = false;
m_IsFirstSectionInChunk = true;
return false;
@ -43,9 +87,9 @@ bool cStatistics::OnBiomes(const unsigned char * a_BiomeData)
{
for (int i = 0; i < 16 * 16; i++)
{
m_BiomeCounts[a_BiomeData[i]] += 1;
m_Stats.m_BiomeCounts[a_BiomeData[i]] += 1;
}
m_BiomeNumChunks += 1;
m_Stats.m_BiomeNumChunks += 1;
memcpy(m_BiomeData, a_BiomeData, sizeof(m_BiomeData));
m_IsBiomesValid = true;
return false;
@ -80,12 +124,12 @@ 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_BlockCounts[Biome][BlockType] += 1;
m_Stats.m_BlockCounts[Biome][BlockType] += 1;
}
}
}
m_BlockNumChunks += m_IsFirstSectionInChunk ? 1 : 0;
m_Stats.m_BlockNumChunks += m_IsFirstSectionInChunk ? 1 : 0;
m_IsFirstSectionInChunk = false;
return false;
@ -109,10 +153,58 @@ bool cStatistics::OnEmptySection(unsigned char a_Y)
for (int x = 0; x < 16; x++)
{
unsigned char Biome = m_BiomeData[x + 16 * z]; // Cannot use cChunkDef, different datatype
m_BlockCounts[Biome][0] += 16; // 16 blocks in a column, all air
m_Stats.m_BlockCounts[Biome][0] += 16; // 16 blocks in a column, all air
}
}
m_Stats.m_BlockNumChunks += m_IsFirstSectionInChunk ? 1 : 0;
m_IsFirstSectionInChunk = false;
return false;
}
bool cStatistics::OnEntity(
const AString & a_EntityType,
double a_PosX, double a_PosY, double a_PosZ,
double a_SpeedX, double a_SpeedY, double a_SpeedZ,
float a_Yaw, float a_Pitch,
float a_FallDistance,
short a_FireTicksLeft,
short a_AirTicks,
char a_IsOnGround,
cParsedNBT & a_NBT,
int a_NBTTag
)
{
m_Stats.m_NumEntities += 1;
// TODO
return false;
}
bool cStatistics::OnTileEntity(
const AString & a_EntityType,
int a_PosX, int a_PosY, int a_PosZ,
cParsedNBT & a_NBT,
int a_NBTTag
)
{
m_Stats.m_NumTileEntities += 1;
if (a_EntityType == "MobSpawner")
{
OnSpawner(a_NBT, a_NBTTag);
}
return false;
}
@ -120,17 +212,58 @@ bool cStatistics::OnEmptySection(unsigned char a_Y)
bool cStatistics::OnTileTick(
int a_BlockType,
int a_TicksLeft,
int a_PosX, int a_PosY, int a_PosZ
)
{
m_Stats.m_NumTileTicks += 1;
return false;
}
void cStatistics::OnSpawner(cParsedNBT & a_NBT, int a_TileEntityTag)
{
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))
{
m_Stats.m_SpawnerEntity[Ent] += 1;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cStatisticsFactory:
cStatisticsFactory::cStatisticsFactory(void) :
m_BeginTick(clock())
{
}
cStatisticsFactory::~cStatisticsFactory()
{
// Join the results together:
LOG("cStatistics:");
LOG(" Joining results...");
JoinResults();
LOG(" Total %d chunks went through", m_TotalChunks);
LOG(" Biomes processed for %d chunks", m_BiomeNumChunks);
LOG(" Total %d chunks went through", m_CombinedStats.m_TotalChunks);
LOG(" Biomes processed for %d chunks", m_CombinedStats.m_BiomeNumChunks);
// Check the number of blocks processed
Int64 TotalBlocks = 0;
@ -138,20 +271,24 @@ cStatisticsFactory::~cStatisticsFactory()
{
for (int j = 0; j < 255; j++)
{
TotalBlocks += m_BlockCounts[i][j];
TotalBlocks += m_CombinedStats.m_BlockCounts[i][j];
}
}
Int64 ExpTotalBlocks = (Int64)m_BlockNumChunks * 16LL * 16LL * 256LL;
LOG(" BlockIDs processed for %d chunks, %lld blocks (exp %lld; %s)", m_BlockNumChunks, TotalBlocks, ExpTotalBlocks, (TotalBlocks == ExpTotalBlocks) ? "match" : "failed");
Int64 ExpTotalBlocks = (Int64)(m_CombinedStats.m_BlockNumChunks) * 16LL * 16LL * 256LL;
LOG(" BlockIDs processed for %d chunks, %lld blocks (exp %lld; %s)", m_CombinedStats.m_BlockNumChunks, TotalBlocks, ExpTotalBlocks, (TotalBlocks == ExpTotalBlocks) ? "match" : "failed");
// Save statistics:
LOG(" Saving statistics into files:");
LOG(" Biomes.txt");
LOG(" Statistics.txt");
SaveStatistics();
LOG(" Biomes.xls");
SaveBiomes();
LOG(" BlockTypes.txt");
LOG(" BlockTypes.xls");
SaveBlockTypes();
LOG(" BiomeBlockTypes.txt");
LOG(" BiomeBlockTypes.xls");
SaveBiomeBlockTypes();
LOG(" Spawners.xls");
SaveSpawners();
}
@ -160,28 +297,9 @@ cStatisticsFactory::~cStatisticsFactory()
void cStatisticsFactory::JoinResults(void)
{
m_BiomeNumChunks = 0;
m_BlockNumChunks = 0;
m_TotalChunks = 0;
memset(m_BiomeCounts, 0, sizeof(m_BiomeCounts));
memset(m_BlockCounts, 0, sizeof(m_BlockCounts));
for (cCallbacks::iterator itr = m_Callbacks.begin(), end = m_Callbacks.end(); itr != end; ++itr)
{
cStatistics * stats = (cStatistics *)(*itr);
for (int i = 0; i <= 255; i++)
{
m_BiomeCounts[i] += stats->m_BiomeCounts[i];
}
for (int i = 0; i <= 255; i++)
{
for (int j = 0; j <= 255; j++)
{
m_BlockCounts[i][j] += stats->m_BlockCounts[i][j];
}
}
m_BiomeNumChunks += stats->m_BiomeNumChunks;
m_BlockNumChunks += stats->m_BlockNumChunks;
m_TotalChunks += stats->m_TotalChunks;
m_CombinedStats.Add(((cStatistics *)(*itr))->GetStats());
} // for itr - m_Callbacks[]
}
@ -197,7 +315,7 @@ void cStatisticsFactory::SaveBiomes(void)
LOG("Cannot write to file Biomes.xls. Statistics not written.");
return;
}
double TotalColumns = (double)m_BiomeNumChunks * 16 * 16; // Total number of columns processed
double TotalColumns = (double)(m_CombinedStats.m_BiomeNumChunks) * 16 * 16 / 100; // Total number of columns processed; convert into percent
if (TotalColumns < 1)
{
// Avoid division by zero
@ -206,7 +324,7 @@ void cStatisticsFactory::SaveBiomes(void)
for (int i = 0; i <= 255; i++)
{
AString Line;
Printf(Line, "%s\t%d\t%d\t%.05f\n", GetBiomeString(i), i, m_BiomeCounts[i], ((double)m_BiomeCounts[i]) / TotalColumns);
Printf(Line, "%s\t%d\t%d\t%.05f\n", GetBiomeString(i), i, m_CombinedStats.m_BiomeCounts[i], ((double)(m_CombinedStats.m_BiomeCounts[i])) / TotalColumns);
f.Write(Line.c_str(), Line.length());
}
}
@ -223,7 +341,7 @@ void cStatisticsFactory::SaveBlockTypes(void)
LOG("Cannot write to file Biomes.xls. Statistics not written.");
return;
}
double TotalBlocks = ((double)m_BlockNumChunks) * 16 * 16 * 256 / 100; // Total number of blocks processed
double TotalBlocks = ((double)(m_CombinedStats.m_BlockNumChunks)) * 16 * 16 * 256 / 100; // Total number of blocks processed; convert into percent
if (TotalBlocks < 1)
{
// Avoid division by zero
@ -234,13 +352,12 @@ void cStatisticsFactory::SaveBlockTypes(void)
int Count = 0;
for (int Biome = 0; Biome <= 255; ++Biome)
{
Count += m_BlockCounts[Biome][i];
Count += m_CombinedStats.m_BlockCounts[Biome][i];
}
AString Line;
Printf(Line, "%s\t%d\t%d\t%.08f\n", GetBlockTypeString(i), i, Count, ((double)Count) / TotalBlocks);
f.Write(Line.c_str(), Line.length());
}
// TODO
}
@ -282,7 +399,7 @@ void cStatisticsFactory::SaveBiomeBlockTypes(void)
Printf(Line, "%s\t%d", GetBlockTypeString(BlockType), BlockType);
for (int Biome = 0; Biome <= 127; Biome++)
{
AppendPrintf(Line, "\t%d", m_BlockCounts[Biome][BlockType]);
AppendPrintf(Line, "\t%d", m_CombinedStats.m_BlockCounts[Biome][BlockType]);
}
Line.append("\n");
f.Write(Line.c_str(), Line.length());
@ -310,7 +427,7 @@ void cStatisticsFactory::SaveBiomeBlockTypes(void)
Printf(Line, "%s\t%d", GetBlockTypeString(BlockType), BlockType);
for (int Biome = 128; Biome <= 255; Biome++)
{
AppendPrintf(Line, "\t%d", m_BlockCounts[Biome][BlockType]);
AppendPrintf(Line, "\t%d", m_CombinedStats.m_BlockCounts[Biome][BlockType]);
}
Line.append("\n");
f.Write(Line.c_str(), Line.length());
@ -321,3 +438,45 @@ void cStatisticsFactory::SaveBiomeBlockTypes(void)
void cStatisticsFactory::SaveStatistics(void)
{
cFile f;
if (!f.Open("Statistics.txt", cFile::fmWrite))
{
LOG("Cannot write to file Statistics.txt. Statistics not written.");
return;
}
int Elapsed = (clock() - m_BeginTick) / CLOCKS_PER_SEC;
f.Printf("Time elapsed: %d seconds (%d hours, %d minutes and %d seconds)\n", Elapsed, Elapsed / 3600, (Elapsed / 60) % 60, Elapsed % 60);
f.Printf("Total chunks processed: %d\n", m_CombinedStats.m_TotalChunks);
f.Printf("Chunk processing speed: %.02f chunks per second\n", (double)(m_CombinedStats.m_TotalChunks) / Elapsed);
f.Printf("Biomes counted for %d chunks.\n", m_CombinedStats.m_BiomeNumChunks);
f.Printf("Blocktypes counted for %d chunks.\n", m_CombinedStats.m_BlockNumChunks);
f.Printf("Total blocks counted: %lld\n", (Int64)(m_CombinedStats.m_BlockNumChunks) * 16 * 16 * 256);
f.Printf("Total biomes counted: %lld\n", (Int64)(m_CombinedStats.m_BiomeNumChunks) * 16 * 16);
f.Printf("Total entities counted: %d\n", m_CombinedStats.m_NumEntities);
f.Printf("Total tile entities counted: %d\n", m_CombinedStats.m_NumTileEntities);
f.Printf("Total tile ticks counted: %d\n", m_CombinedStats.m_NumTileTicks);
}
void cStatisticsFactory::SaveSpawners(void)
{
cFile f;
if (!f.Open("Spawners.xls", cFile::fmWrite))
{
LOG("Cannot write to file Spawners.xls. Statistics not written.");
return;
}
f.Printf("Entity type\tTotal count\tCount per chunk\n");
for (int i = 0; i < entMax; i++)
{
f.Printf("%s\t%d\t%0.4f\n", GetEntityTypeString((eEntityType)i), m_CombinedStats.m_SpawnerEntity[i], (double)(m_CombinedStats.m_SpawnerEntity[i]) / m_CombinedStats.m_BlockNumChunks);
}
}

View File

@ -10,6 +10,7 @@
#pragma once
#include "Callback.h"
#include "Utils.h"
@ -18,20 +19,35 @@
class cStatistics :
public cCallback
{
friend class cStatisticsFactory;
public:
class cStats
{
public:
int m_TotalChunks; // Total number of chunks that go through this callback (OnNewChunk())
int m_BiomeCounts[256];
int m_BlockCounts[256][256]; // First dimension is the biome, second dimension is BlockType
int m_BiomeNumChunks; // Num chunks that have been processed for biome stats
int m_BlockNumChunks; // Num chunks that have been processed for block stats
int m_NumEntities;
int m_NumTileEntities;
int m_NumTileTicks;
int m_SpawnerEntity[entMax + 1];
cStats(void);
void Add(const cStats & a_Stats);
} ;
cStatistics(void);
const cStats & GetStats(void) const { return m_Stats; }
protected:
int m_TotalChunks; // Total number of chunks that go through this callback (OnNewChunk())
int m_BiomeCounts[256];
int m_BlockCounts[256][256]; // First dimension is the biome, second dimension is BlockType
int m_BiomeNumChunks; // Num chunks that have been processed for biome stats
int m_BlockNumChunks; // Num chunks that have been processed for block stats
bool m_IsBiomesValid; // Set to true in OnBiomes(), reset to false in OnNewChunk(); if true, the m_BiomeData is valid for the current chunk
unsigned char m_BiomeData[16 * 16];
bool m_IsFirstSectionInChunk; // True if there was no section in the chunk yet. Set by OnNewChunk(), reset by OnSection()
cStats m_Stats;
bool m_IsBiomesValid; // Set to true in OnBiomes(), reset to false in OnNewChunk(); if true, the m_BiomeData is valid for the current chunk
unsigned char m_BiomeData[16 * 16];
bool m_IsFirstSectionInChunk; // True if there was no section in the chunk yet. Set by OnNewChunk(), reset by OnSection()
// cCallback overrides:
virtual bool OnNewChunk(int a_ChunkX, int a_ChunkZ) override;
@ -51,7 +67,36 @@ protected:
const NIBBLETYPE * a_BlockLight,
const NIBBLETYPE * a_BlockSkyLight
) override;
virtual bool OnEmptySection(unsigned char a_Y) override;
virtual bool OnEntity(
const AString & a_EntityType,
double a_PosX, double a_PosY, double a_PosZ,
double a_SpeedX, double a_SpeedY, double a_SpeedZ,
float a_Yaw, float a_Pitch,
float a_FallDistance,
short a_FireTicksLeft,
short a_AirTicks,
char a_IsOnGround,
cParsedNBT & a_NBT,
int a_NBTTag
) override;
virtual bool OnTileEntity(
const AString & a_EntityType,
int a_PosX, int a_PosY, int a_PosZ,
cParsedNBT & a_NBT,
int a_NBTTag
) override;
virtual bool OnTileTick(
int a_BlockType,
int a_TicksLeft,
int a_PosX, int a_PosY, int a_PosZ
) override;
void OnSpawner(cParsedNBT & a_NBT, int a_TileEntityTag);
} ;
@ -62,6 +107,7 @@ class cStatisticsFactory :
public cCallbackFactory
{
public:
cStatisticsFactory(void);
virtual ~cStatisticsFactory();
virtual cCallback * CreateNewCallback(void)
@ -71,17 +117,16 @@ public:
protected:
// The results, combined, are stored here:
int m_TotalChunks;
int m_BiomeCounts[256];
int m_BlockCounts[256][256]; // First dimension is the biome, second dimension is BlockType
int m_BiomeNumChunks; // Num chunks that have been processed for biome stats
int m_BlockNumChunks; // Num chunks that have been processed for block stats
cStatistics::cStats m_CombinedStats;
clock_t m_BeginTick;
void JoinResults(void);
void SaveBiomes(void);
void SaveBlockTypes(void);
void SaveBiomeBlockTypes(void);
void SaveStatistics(void);
void SaveSpawners(void);
} ;

View File

@ -10,6 +10,47 @@
struct
{
eEntityType Type;
const char * String;
} g_EntityTypes[] =
{
{entBat, "Bat"},
{entBlaze, "Blaze"},
{entCaveSpider, "CaveSpider"},
{entChicken, "Chicken"},
{entCow, "Cow"},
{entCreeper, "Creeper"},
{entEnderDragon, "EnderDragon"},
{entEnderman, "Enderman"},
{entGhast, "Ghast"},
{entGiant, "Giant"},
{entLavaSlime, "LavaSlime"},
{entMushroomCow, "MushroomCow"},
{entOzelot, "Ozelot"},
{entPig, "Pig"},
{entPigZombie, "PigZombie"},
{entSheep, "Sheep"},
{entSilverfish, "Slverfish"},
{entSkeleton, "Skeleton"},
{entSlime, "Slime"},
{entSnowMan, "SnowMan"},
{entSpider, "Spider"},
{entSquid, "Squid"},
{entVillager, "Villager"},
{entVillagerGolem, "VillagerGolem"},
{entWitch, "Witch"},
{entWitherBoss, "WitherBoss"},
{entWolf, "Wolf"},
{entZombie, "Zombie"},
{entUnknown, "Unknown"},
} ;
const char * GetBiomeString(unsigned char a_Biome)
{
static const char * BiomeNames[] = // Biome names, as equivalent to their index
@ -203,6 +244,31 @@ const char * GetBlockTypeString(unsigned char a_BlockType)
eEntityType GetEntityType(const AString & a_EntityTypeString)
{
for (int i = 0; i < ARRAYCOUNT(g_EntityTypes); i++)
{
if (a_EntityTypeString == g_EntityTypes[i].String)
{
return g_EntityTypes[i].Type;
}
}
return entUnknown;
}
extern const char * GetEntityTypeString(eEntityType a_EntityType)
{
return g_EntityTypes[a_EntityType].String;
}
int GetNumCores(void)
{
// Get number of cores by querying the system process affinity mask (Windows-specific)

View File

@ -7,8 +7,54 @@
#pragma once
enum eEntityType
{
entBat,
entBlaze,
entCaveSpider,
entChicken,
entCow,
entCreeper,
entEnderDragon,
entEnderman,
entGhast,
entGiant,
entLavaSlime,
entMushroomCow,
entOzelot,
entPig,
entPigZombie,
entSheep,
entSilverfish,
entSkeleton,
entSlime,
entSnowMan,
entSpider,
entSquid,
entVillager,
entVillagerGolem,
entWitch,
entWitherBoss,
entWolf,
entZombie,
entUnknown,
entMax = entUnknown,
} ;
extern const char * GetBiomeString(unsigned char a_Biome);
extern const char * GetBlockTypeString(unsigned char a_BlockType);
extern eEntityType GetEntityType(const AString & a_EntityTypeString);
extern const char * GetEntityTypeString(eEntityType a_EntityType);
extern int GetNumCores(void);