Merge pull request #575 from worktycho/GeneratingBenchmark
More Interfaces to decouple Generator from the rest of the code
This commit is contained in:
commit
f78a62a5e3
@ -201,5 +201,9 @@ if (NOT MSVC)
|
|||||||
string(REPLACE "-w" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
|
string(REPLACE "-w" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(${BUILD_TOOLS})
|
||||||
|
add_subdirectory(Tools/GeneratorPerformanceTest/)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_subdirectory (src)
|
add_subdirectory (src)
|
||||||
|
|
||||||
|
12
Tools/GeneratorPerformanceTest/CMakeLists.txt
Normal file
12
Tools/GeneratorPerformanceTest/CMakeLists.txt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
cmake_minimum_required(VERSION 2.8)
|
||||||
|
project(GeneratorPerformanceTest)
|
||||||
|
|
||||||
|
include_directories(../../src/Generating)
|
||||||
|
include_directories(../../src)
|
||||||
|
include_directories(../../lib)
|
||||||
|
|
||||||
|
add_executable(GeneratorPerformanceTest GeneratorPerformanceTest.cpp ../../src/StringUtils ../../src/MCLogger ../../src/Log ../../src/BlockID ../../src/Noise ../../src/Enchantments ../../src/BlockArea)
|
||||||
|
|
||||||
|
target_link_libraries(GeneratorPerformanceTest Generating)
|
||||||
|
|
@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "ChunkGenerator.h"
|
||||||
|
|
||||||
|
int main(int argc, char * argv[]) {
|
||||||
|
cChunkGenerator Generator = cChunkGenerator();
|
||||||
|
}
|
@ -13,6 +13,7 @@
|
|||||||
#include "../Entities/Player.h"
|
#include "../Entities/Player.h"
|
||||||
#include "../WebAdmin.h"
|
#include "../WebAdmin.h"
|
||||||
#include "../ClientHandle.h"
|
#include "../ClientHandle.h"
|
||||||
|
#include "../BlockArea.h"
|
||||||
#include "../BlockEntities/ChestEntity.h"
|
#include "../BlockEntities/ChestEntity.h"
|
||||||
#include "../BlockEntities/CommandBlockEntity.h"
|
#include "../BlockEntities/CommandBlockEntity.h"
|
||||||
#include "../BlockEntities/DispenserEntity.h"
|
#include "../BlockEntities/DispenserEntity.h"
|
||||||
@ -22,6 +23,7 @@
|
|||||||
#include "../BlockEntities/NoteEntity.h"
|
#include "../BlockEntities/NoteEntity.h"
|
||||||
#include "md5/md5.h"
|
#include "md5/md5.h"
|
||||||
#include "../LineBlockTracer.h"
|
#include "../LineBlockTracer.h"
|
||||||
|
#include "../WorldStorage/SchematicFileSerializer.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -2234,6 +2236,63 @@ static int tolua_cHopperEntity_GetOutputBlockPos(lua_State * tolua_S)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int tolua_cBlockArea_LoadFromSchematicFile(lua_State * tolua_S)
|
||||||
|
{
|
||||||
|
// function cBlockArea::LoadFromSchematicFile
|
||||||
|
// Exported manually because function has been moved to SchematicFileSerilizer.cpp
|
||||||
|
cLuaState L(tolua_S);
|
||||||
|
if (
|
||||||
|
!L.CheckParamUserType(1, "cBlockArea") ||
|
||||||
|
!L.CheckParamString (2) ||
|
||||||
|
!L.CheckParamEnd (3)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, 0);
|
||||||
|
if (self == NULL)
|
||||||
|
{
|
||||||
|
tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea::LoadFromSchematicFile'", NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
AString Filename = tolua_tostring(tolua_S, 2, 0);
|
||||||
|
bool res = cSchematicFileSerializer::LoadFromSchematicFile(*self,Filename);
|
||||||
|
tolua_pushboolean(tolua_S, res);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int tolua_cBlockArea_SaveToSchematicFile(lua_State * tolua_S)
|
||||||
|
{
|
||||||
|
// function cBlockArea::SaveToSchematicFile
|
||||||
|
// Exported manually because function has been moved to SchematicFileSerilizer.cpp
|
||||||
|
cLuaState L(tolua_S);
|
||||||
|
if (
|
||||||
|
!L.CheckParamUserType(1, "cBlockArea") ||
|
||||||
|
!L.CheckParamString (2) ||
|
||||||
|
!L.CheckParamEnd (3)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, 0);
|
||||||
|
if (self == NULL)
|
||||||
|
{
|
||||||
|
tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea::SaveToSchematicFile'", NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
AString Filename = tolua_tostring(tolua_S, 2, 0);
|
||||||
|
bool res = cSchematicFileSerializer::SaveToSchematicFile(*self,Filename);
|
||||||
|
tolua_pushboolean(tolua_S, res);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void ManualBindings::Bind(lua_State * tolua_S)
|
void ManualBindings::Bind(lua_State * tolua_S)
|
||||||
{
|
{
|
||||||
tolua_beginmodule(tolua_S, NULL);
|
tolua_beginmodule(tolua_S, NULL);
|
||||||
@ -2249,6 +2308,11 @@ void ManualBindings::Bind(lua_State * tolua_S)
|
|||||||
tolua_function(tolua_S, "GetFolderContents", tolua_cFile_GetFolderContents);
|
tolua_function(tolua_S, "GetFolderContents", tolua_cFile_GetFolderContents);
|
||||||
tolua_endmodule(tolua_S);
|
tolua_endmodule(tolua_S);
|
||||||
|
|
||||||
|
tolua_beginmodule(tolua_S, "cBlockArea");
|
||||||
|
tolua_function(tolua_S, "LoadFromSchematicFile", tolua_cBlockArea_LoadFromSchematicFile);
|
||||||
|
tolua_function(tolua_S, "SaveToSchematicFile", tolua_cBlockArea_SaveToSchematicFile);
|
||||||
|
tolua_endmodule(tolua_S);
|
||||||
|
|
||||||
tolua_beginmodule(tolua_S, "cHopperEntity");
|
tolua_beginmodule(tolua_S, "cHopperEntity");
|
||||||
tolua_function(tolua_S, "GetOutputBlockPos", tolua_cHopperEntity_GetOutputBlockPos);
|
tolua_function(tolua_S, "GetOutputBlockPos", tolua_cHopperEntity_GetOutputBlockPos);
|
||||||
tolua_endmodule(tolua_S);
|
tolua_endmodule(tolua_S);
|
||||||
|
@ -6,9 +6,7 @@
|
|||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "BlockArea.h"
|
#include "BlockArea.h"
|
||||||
#include "World.h"
|
|
||||||
#include "OSSupport/GZipFile.h"
|
#include "OSSupport/GZipFile.h"
|
||||||
#include "WorldStorage/FastNBT.h"
|
|
||||||
#include "Blocks/BlockHandler.h"
|
#include "Blocks/BlockHandler.h"
|
||||||
|
|
||||||
|
|
||||||
@ -266,7 +264,7 @@ void cBlockArea::SetOrigin(int a_OriginX, int a_OriginY, int a_OriginZ)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cBlockArea::Read(cWorld * a_World, int a_MinBlockX, int a_MaxBlockX, int a_MinBlockY, int a_MaxBlockY, int a_MinBlockZ, int a_MaxBlockZ, int a_DataTypes)
|
bool cBlockArea::Read(cForEachChunkProvider * a_ForEachChunkProvider, int a_MinBlockX, int a_MaxBlockX, int a_MinBlockY, int a_MaxBlockY, int a_MinBlockZ, int a_MaxBlockZ, int a_DataTypes)
|
||||||
{
|
{
|
||||||
// Normalize the coords:
|
// Normalize the coords:
|
||||||
if (a_MinBlockX > a_MaxBlockX)
|
if (a_MinBlockX > a_MaxBlockX)
|
||||||
@ -327,7 +325,7 @@ bool cBlockArea::Read(cWorld * a_World, int a_MinBlockX, int a_MaxBlockX, int a_
|
|||||||
cChunkDef::AbsoluteToRelative(a_MaxBlockX, a_MaxBlockY, a_MaxBlockZ, MaxChunkX, MaxChunkZ);
|
cChunkDef::AbsoluteToRelative(a_MaxBlockX, a_MaxBlockY, a_MaxBlockZ, MaxChunkX, MaxChunkZ);
|
||||||
|
|
||||||
// Query block data:
|
// Query block data:
|
||||||
if (!a_World->ForEachChunkInRect(MinChunkX, MaxChunkX, MinChunkZ, MaxChunkZ, Reader))
|
if (!a_ForEachChunkProvider->ForEachChunkInRect(MinChunkX, MaxChunkX, MinChunkZ, MaxChunkZ, Reader))
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
return false;
|
return false;
|
||||||
@ -340,7 +338,7 @@ bool cBlockArea::Read(cWorld * a_World, int a_MinBlockX, int a_MaxBlockX, int a_
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cBlockArea::Write(cWorld * a_World, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes)
|
bool cBlockArea::Write(cForEachChunkProvider * a_ForEachChunkProvider, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes)
|
||||||
{
|
{
|
||||||
ASSERT((a_DataTypes & GetDataTypes()) == a_DataTypes); // Are you requesting only the data that I have?
|
ASSERT((a_DataTypes & GetDataTypes()) == a_DataTypes); // Are you requesting only the data that I have?
|
||||||
a_DataTypes = a_DataTypes & GetDataTypes(); // For release builds, silently cut off the datatypes that I don't have
|
a_DataTypes = a_DataTypes & GetDataTypes(); // For release builds, silently cut off the datatypes that I don't have
|
||||||
@ -357,7 +355,7 @@ bool cBlockArea::Write(cWorld * a_World, int a_MinBlockX, int a_MinBlockY, int a
|
|||||||
a_MinBlockY = cChunkDef::Height - m_SizeY;
|
a_MinBlockY = cChunkDef::Height - m_SizeY;
|
||||||
}
|
}
|
||||||
|
|
||||||
return a_World->WriteBlockArea(*this, a_MinBlockX, a_MinBlockY, a_MinBlockZ, a_DataTypes);
|
return a_ForEachChunkProvider->WriteBlockArea(*this, a_MinBlockX, a_MinBlockY, a_MinBlockZ, a_DataTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -448,85 +446,12 @@ void cBlockArea::DumpToRawFile(const AString & a_FileName)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cBlockArea::LoadFromSchematicFile(const AString & a_FileName)
|
|
||||||
{
|
|
||||||
// Un-GZip the contents:
|
|
||||||
AString Contents;
|
|
||||||
cGZipFile File;
|
|
||||||
if (!File.Open(a_FileName, cGZipFile::fmRead))
|
|
||||||
{
|
|
||||||
LOG("Cannot open the schematic file \"%s\".", a_FileName.c_str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int NumBytesRead = File.ReadRestOfFile(Contents);
|
|
||||||
if (NumBytesRead < 0)
|
|
||||||
{
|
|
||||||
LOG("Cannot read GZipped data in the schematic file \"%s\", error %d", a_FileName.c_str(), NumBytesRead);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
File.Close();
|
|
||||||
|
|
||||||
// Parse the NBT:
|
|
||||||
cParsedNBT NBT(Contents.data(), Contents.size());
|
|
||||||
if (!NBT.IsValid())
|
|
||||||
{
|
|
||||||
LOG("Cannot parse the NBT in the schematic file \"%s\".", a_FileName.c_str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return LoadFromSchematicNBT(NBT);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cBlockArea::SaveToSchematicFile(const AString & a_FileName)
|
|
||||||
{
|
|
||||||
cFastNBTWriter Writer("Schematic");
|
|
||||||
Writer.AddShort("Width", m_SizeX);
|
|
||||||
Writer.AddShort("Height", m_SizeY);
|
|
||||||
Writer.AddShort("Length", m_SizeZ);
|
|
||||||
Writer.AddString("Materials", "Alpha");
|
|
||||||
if (HasBlockTypes())
|
|
||||||
{
|
|
||||||
Writer.AddByteArray("Blocks", (const char *)m_BlockTypes, GetBlockCount());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AString Dummy(GetBlockCount(), 0);
|
|
||||||
Writer.AddByteArray("Blocks", Dummy.data(), Dummy.size());
|
|
||||||
}
|
|
||||||
if (HasBlockMetas())
|
|
||||||
{
|
|
||||||
Writer.AddByteArray("Data", (const char *)m_BlockMetas, GetBlockCount());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AString Dummy(GetBlockCount(), 0);
|
|
||||||
Writer.AddByteArray("Data", Dummy.data(), Dummy.size());
|
|
||||||
}
|
|
||||||
// TODO: Save entities and block entities
|
|
||||||
Writer.BeginList("Entities", TAG_Compound);
|
|
||||||
Writer.EndList();
|
|
||||||
Writer.BeginList("TileEntities", TAG_Compound);
|
|
||||||
Writer.EndList();
|
|
||||||
Writer.Finish();
|
|
||||||
|
|
||||||
// Save to file
|
|
||||||
cGZipFile File;
|
|
||||||
if (!File.Open(a_FileName, cGZipFile::fmWrite))
|
|
||||||
{
|
|
||||||
LOG("Cannot open file \"%s\" for writing.", a_FileName.c_str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!File.Write(Writer.GetResult()))
|
|
||||||
{
|
|
||||||
LOG("Cannot write data to file \"%s\".", a_FileName.c_str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -2018,89 +1943,6 @@ void cBlockArea::ExpandNibbles(NIBBLEARRAY & a_Array, int a_SubMinX, int a_AddMa
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cBlockArea::LoadFromSchematicNBT(cParsedNBT & a_NBT)
|
|
||||||
{
|
|
||||||
int TMaterials = a_NBT.FindChildByName(a_NBT.GetRoot(), "Materials");
|
|
||||||
if ((TMaterials > 0) && (a_NBT.GetType(TMaterials) == TAG_String))
|
|
||||||
{
|
|
||||||
AString Materials = a_NBT.GetString(TMaterials);
|
|
||||||
if (Materials.compare("Alpha") != 0)
|
|
||||||
{
|
|
||||||
LOG("Materials tag is present and \"%s\" instead of \"Alpha\". Possibly a wrong-format schematic file.", Materials.c_str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int TSizeX = a_NBT.FindChildByName(a_NBT.GetRoot(), "Width");
|
|
||||||
int TSizeY = a_NBT.FindChildByName(a_NBT.GetRoot(), "Height");
|
|
||||||
int TSizeZ = a_NBT.FindChildByName(a_NBT.GetRoot(), "Length");
|
|
||||||
if (
|
|
||||||
(TSizeX < 0) || (TSizeY < 0) || (TSizeZ < 0) ||
|
|
||||||
(a_NBT.GetType(TSizeX) != TAG_Short) ||
|
|
||||||
(a_NBT.GetType(TSizeY) != TAG_Short) ||
|
|
||||||
(a_NBT.GetType(TSizeZ) != TAG_Short)
|
|
||||||
)
|
|
||||||
{
|
|
||||||
LOG("Dimensions are missing from the schematic file (%d, %d, %d), (%d, %d, %d)",
|
|
||||||
TSizeX, TSizeY, TSizeZ,
|
|
||||||
a_NBT.GetType(TSizeX), a_NBT.GetType(TSizeY), a_NBT.GetType(TSizeZ)
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SizeX = a_NBT.GetShort(TSizeX);
|
|
||||||
int SizeY = a_NBT.GetShort(TSizeY);
|
|
||||||
int SizeZ = a_NBT.GetShort(TSizeZ);
|
|
||||||
if ((SizeX < 1) || (SizeY < 1) || (SizeZ < 1))
|
|
||||||
{
|
|
||||||
LOG("Dimensions are invalid in the schematic file: %d, %d, %d", SizeX, SizeY, SizeZ);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int TBlockTypes = a_NBT.FindChildByName(a_NBT.GetRoot(), "Blocks");
|
|
||||||
int TBlockMetas = a_NBT.FindChildByName(a_NBT.GetRoot(), "Data");
|
|
||||||
if ((TBlockTypes < 0) || (a_NBT.GetType(TBlockTypes) != TAG_ByteArray))
|
|
||||||
{
|
|
||||||
LOG("BlockTypes are invalid in the schematic file: %d", TBlockTypes);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool AreMetasPresent = (TBlockMetas > 0) && (a_NBT.GetType(TBlockMetas) == TAG_ByteArray);
|
|
||||||
|
|
||||||
Clear();
|
|
||||||
SetSize(SizeX, SizeY, SizeZ, AreMetasPresent ? (baTypes | baMetas) : baTypes);
|
|
||||||
|
|
||||||
// Copy the block types and metas:
|
|
||||||
int NumBytes = m_SizeX * m_SizeY * m_SizeZ;
|
|
||||||
if (a_NBT.GetDataLength(TBlockTypes) < NumBytes)
|
|
||||||
{
|
|
||||||
LOG("BlockTypes truncated in the schematic file (exp %d, got %d bytes). Loading partial.",
|
|
||||||
NumBytes, a_NBT.GetDataLength(TBlockTypes)
|
|
||||||
);
|
|
||||||
NumBytes = a_NBT.GetDataLength(TBlockTypes);
|
|
||||||
}
|
|
||||||
memcpy(m_BlockTypes, a_NBT.GetData(TBlockTypes), NumBytes);
|
|
||||||
|
|
||||||
if (AreMetasPresent)
|
|
||||||
{
|
|
||||||
int NumBytes = m_SizeX * m_SizeY * m_SizeZ;
|
|
||||||
if (a_NBT.GetDataLength(TBlockMetas) < NumBytes)
|
|
||||||
{
|
|
||||||
LOG("BlockMetas truncated in the schematic file (exp %d, got %d bytes). Loading partial.",
|
|
||||||
NumBytes, a_NBT.GetDataLength(TBlockMetas)
|
|
||||||
);
|
|
||||||
NumBytes = a_NBT.GetDataLength(TBlockMetas);
|
|
||||||
}
|
|
||||||
memcpy(m_BlockMetas, a_NBT.GetData(TBlockMetas), NumBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cBlockArea::RelSetData(
|
void cBlockArea::RelSetData(
|
||||||
int a_RelX, int a_RelY, int a_RelZ,
|
int a_RelX, int a_RelY, int a_RelZ,
|
||||||
int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta,
|
int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta,
|
||||||
|
@ -12,18 +12,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "ForEachChunkProvider.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// fwd: World.h
|
|
||||||
class cWorld;
|
|
||||||
|
|
||||||
// fwd: FastNBT.h
|
|
||||||
class cParsedNBT;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// tolua_begin
|
// tolua_begin
|
||||||
@ -68,13 +57,13 @@ public:
|
|||||||
void SetOrigin(int a_OriginX, int a_OriginY, int a_OriginZ);
|
void SetOrigin(int a_OriginX, int a_OriginY, int a_OriginZ);
|
||||||
|
|
||||||
/// Reads an area of blocks specified. Returns true if successful. All coords are inclusive.
|
/// Reads an area of blocks specified. Returns true if successful. All coords are inclusive.
|
||||||
bool Read(cWorld * a_World, int a_MinBlockX, int a_MaxBlockX, int a_MinBlockY, int a_MaxBlockY, int a_MinBlockZ, int a_MaxBlockZ, int a_DataTypes = baTypes | baMetas);
|
bool Read(cForEachChunkProvider * a_ForEachChunkProvider, int a_MinBlockX, int a_MaxBlockX, int a_MinBlockY, int a_MaxBlockY, int a_MinBlockZ, int a_MaxBlockZ, int a_DataTypes = baTypes | baMetas);
|
||||||
|
|
||||||
// TODO: Write() is not too good an interface: if it fails, there's no way to repeat only for the parts that didn't write
|
// TODO: Write() is not too good an interface: if it fails, there's no way to repeat only for the parts that didn't write
|
||||||
// A better way may be to return a list of cBlockAreas for each part that didn't succeed writing, so that the caller may try again
|
// A better way may be to return a list of cBlockAreas for each part that didn't succeed writing, so that the caller may try again
|
||||||
|
|
||||||
/// Writes the area back into cWorld at the coords specified. Returns true if successful in all chunks, false if only partially / not at all
|
/// Writes the area back into cWorld at the coords specified. Returns true if successful in all chunks, false if only partially / not at all
|
||||||
bool Write(cWorld * a_World, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes = baTypes | baMetas);
|
bool Write(cForEachChunkProvider * a_ForEachChunkProvider, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes = baTypes | baMetas);
|
||||||
|
|
||||||
/// Copies this object's contents into the specified BlockArea.
|
/// Copies this object's contents into the specified BlockArea.
|
||||||
void CopyTo(cBlockArea & a_Into) const;
|
void CopyTo(cBlockArea & a_Into) const;
|
||||||
@ -85,12 +74,6 @@ public:
|
|||||||
/// For testing purposes only, dumps the area into a file.
|
/// For testing purposes only, dumps the area into a file.
|
||||||
void DumpToRawFile(const AString & a_FileName);
|
void DumpToRawFile(const AString & a_FileName);
|
||||||
|
|
||||||
/// Loads an area from a .schematic file. Returns true if successful
|
|
||||||
bool LoadFromSchematicFile(const AString & a_FileName);
|
|
||||||
|
|
||||||
/// Saves the area into a .schematic file. Returns true if successful
|
|
||||||
bool SaveToSchematicFile(const AString & a_FileName);
|
|
||||||
|
|
||||||
/// Crops the internal contents by the specified amount of blocks from each border.
|
/// Crops the internal contents by the specified amount of blocks from each border.
|
||||||
void Crop(int a_AddMinX, int a_SubMaxX, int a_AddMinY, int a_SubMaxY, int a_AddMinZ, int a_SubMaxZ);
|
void Crop(int a_AddMinX, int a_SubMaxX, int a_AddMinY, int a_SubMaxY, int a_AddMinZ, int a_SubMaxZ);
|
||||||
|
|
||||||
@ -233,6 +216,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class cChunkDesc;
|
friend class cChunkDesc;
|
||||||
|
friend class cSchematicFileSerializer;
|
||||||
|
|
||||||
class cChunkReader :
|
class cChunkReader :
|
||||||
public cChunkDataCallback
|
public cChunkDataCallback
|
||||||
@ -292,9 +276,6 @@ protected:
|
|||||||
void ExpandBlockTypes(int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMaxY, int a_SubMinZ, int a_AddMaxZ);
|
void ExpandBlockTypes(int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMaxY, int a_SubMinZ, int a_AddMaxZ);
|
||||||
void ExpandNibbles (NIBBLEARRAY & a_Array, int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMaxY, int a_SubMinZ, int a_AddMaxZ);
|
void ExpandNibbles (NIBBLEARRAY & a_Array, int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMaxY, int a_SubMinZ, int a_AddMaxZ);
|
||||||
|
|
||||||
/// Loads the area from a schematic file uncompressed and parsed into a NBT tree. Returns true if successful.
|
|
||||||
bool LoadFromSchematicNBT(cParsedNBT & a_NBT);
|
|
||||||
|
|
||||||
/// Sets the specified datatypes at the specified location.
|
/// Sets the specified datatypes at the specified location.
|
||||||
void RelSetData(
|
void RelSetData(
|
||||||
int a_RelX, int a_RelY, int a_RelZ,
|
int a_RelX, int a_RelY, int a_RelZ,
|
||||||
|
14
src/ForEachChunkProvider.h
Normal file
14
src/ForEachChunkProvider.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
class cChunkDataCallback;
|
||||||
|
|
||||||
|
class cBlockArea;
|
||||||
|
|
||||||
|
class cForEachChunkProvider
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual bool ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ, cChunkDataCallback & a_Callback) = 0;
|
||||||
|
|
||||||
|
virtual bool WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes) = 0;
|
||||||
|
};
|
@ -9,3 +9,5 @@ file(GLOB SOURCE
|
|||||||
)
|
)
|
||||||
|
|
||||||
add_library(Generating ${SOURCE})
|
add_library(Generating ${SOURCE})
|
||||||
|
|
||||||
|
target_link_libraries(Generating OSSupport iniFile)
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "Item.h"
|
#include "Item.h"
|
||||||
#include "Mobs/Monster.h"
|
#include "Mobs/Monster.h"
|
||||||
#include "Entities/ProjectileEntity.h"
|
#include "Entities/ProjectileEntity.h"
|
||||||
|
#include "ForEachChunkProvider.h"
|
||||||
#include "Scoreboard.h"
|
#include "Scoreboard.h"
|
||||||
|
|
||||||
|
|
||||||
@ -61,7 +62,7 @@ typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback;
|
|||||||
|
|
||||||
|
|
||||||
// tolua_begin
|
// tolua_begin
|
||||||
class cWorld
|
class cWorld : public cForEachChunkProvider
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -314,7 +315,7 @@ public:
|
|||||||
bool IsChunkLighted(int a_ChunkX, int a_ChunkZ);
|
bool IsChunkLighted(int a_ChunkX, int a_ChunkZ);
|
||||||
|
|
||||||
/** Calls the callback for each chunk in the coords specified (all cords are inclusive). Returns true if all chunks have been processed successfully */
|
/** Calls the callback for each chunk in the coords specified (all cords are inclusive). Returns true if all chunks have been processed successfully */
|
||||||
bool ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ, cChunkDataCallback & a_Callback);
|
virtual bool ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ, cChunkDataCallback & a_Callback);
|
||||||
|
|
||||||
// tolua_begin
|
// tolua_begin
|
||||||
|
|
||||||
@ -360,7 +361,7 @@ public:
|
|||||||
Prefer cBlockArea::Write() instead, this is the internal implementation; cBlockArea does error checking, too.
|
Prefer cBlockArea::Write() instead, this is the internal implementation; cBlockArea does error checking, too.
|
||||||
a_DataTypes is a bitmask of cBlockArea::baXXX constants ORed together.
|
a_DataTypes is a bitmask of cBlockArea::baXXX constants ORed together.
|
||||||
*/
|
*/
|
||||||
bool WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes);
|
virtual bool WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes);
|
||||||
|
|
||||||
// tolua_begin
|
// tolua_begin
|
||||||
|
|
||||||
|
172
src/WorldStorage/SchematicFileSerializer.cpp
Normal file
172
src/WorldStorage/SchematicFileSerializer.cpp
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
|
||||||
|
#include "OSSupport/GZipFile.h"
|
||||||
|
#include "FastNBT.h"
|
||||||
|
|
||||||
|
#include "SchematicFileSerializer.h"
|
||||||
|
|
||||||
|
bool cSchematicFileSerializer::LoadFromSchematicFile(cBlockArea & a_BlockArea, const AString & a_FileName)
|
||||||
|
{
|
||||||
|
// Un-GZip the contents:
|
||||||
|
AString Contents;
|
||||||
|
cGZipFile File;
|
||||||
|
if (!File.Open(a_FileName, cGZipFile::fmRead))
|
||||||
|
{
|
||||||
|
LOG("Cannot open the schematic file \"%s\".", a_FileName.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int NumBytesRead = File.ReadRestOfFile(Contents);
|
||||||
|
if (NumBytesRead < 0)
|
||||||
|
{
|
||||||
|
LOG("Cannot read GZipped data in the schematic file \"%s\", error %d", a_FileName.c_str(), NumBytesRead);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
File.Close();
|
||||||
|
|
||||||
|
// Parse the NBT:
|
||||||
|
cParsedNBT NBT(Contents.data(), Contents.size());
|
||||||
|
if (!NBT.IsValid())
|
||||||
|
{
|
||||||
|
LOG("Cannot parse the NBT in the schematic file \"%s\".", a_FileName.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LoadFromSchematicNBT(a_BlockArea, NBT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cSchematicFileSerializer::SaveToSchematicFile(cBlockArea & a_BlockArea, const AString & a_FileName)
|
||||||
|
{
|
||||||
|
cFastNBTWriter Writer("Schematic");
|
||||||
|
Writer.AddShort("Width", a_BlockArea.m_SizeX);
|
||||||
|
Writer.AddShort("Height", a_BlockArea.m_SizeY);
|
||||||
|
Writer.AddShort("Length", a_BlockArea.m_SizeZ);
|
||||||
|
Writer.AddString("Materials", "Alpha");
|
||||||
|
if (a_BlockArea.HasBlockTypes())
|
||||||
|
{
|
||||||
|
Writer.AddByteArray("Blocks", (const char *)a_BlockArea.m_BlockTypes, a_BlockArea.GetBlockCount());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AString Dummy(a_BlockArea.GetBlockCount(), 0);
|
||||||
|
Writer.AddByteArray("Blocks", Dummy.data(), Dummy.size());
|
||||||
|
}
|
||||||
|
if (a_BlockArea.HasBlockMetas())
|
||||||
|
{
|
||||||
|
Writer.AddByteArray("Data", (const char *)a_BlockArea.m_BlockMetas, a_BlockArea.GetBlockCount());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AString Dummy(a_BlockArea.GetBlockCount(), 0);
|
||||||
|
Writer.AddByteArray("Data", Dummy.data(), Dummy.size());
|
||||||
|
}
|
||||||
|
// TODO: Save entities and block entities
|
||||||
|
Writer.BeginList("Entities", TAG_Compound);
|
||||||
|
Writer.EndList();
|
||||||
|
Writer.BeginList("TileEntities", TAG_Compound);
|
||||||
|
Writer.EndList();
|
||||||
|
Writer.Finish();
|
||||||
|
|
||||||
|
// Save to file
|
||||||
|
cGZipFile File;
|
||||||
|
if (!File.Open(a_FileName, cGZipFile::fmWrite))
|
||||||
|
{
|
||||||
|
LOG("Cannot open file \"%s\" for writing.", a_FileName.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!File.Write(Writer.GetResult()))
|
||||||
|
{
|
||||||
|
LOG("Cannot write data to file \"%s\".", a_FileName.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cParsedNBT & a_NBT)
|
||||||
|
{
|
||||||
|
int TMaterials = a_NBT.FindChildByName(a_NBT.GetRoot(), "Materials");
|
||||||
|
if ((TMaterials > 0) && (a_NBT.GetType(TMaterials) == TAG_String))
|
||||||
|
{
|
||||||
|
AString Materials = a_NBT.GetString(TMaterials);
|
||||||
|
if (Materials.compare("Alpha") != 0)
|
||||||
|
{
|
||||||
|
LOG("Materials tag is present and \"%s\" instead of \"Alpha\". Possibly a wrong-format schematic file.", Materials.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int TSizeX = a_NBT.FindChildByName(a_NBT.GetRoot(), "Width");
|
||||||
|
int TSizeY = a_NBT.FindChildByName(a_NBT.GetRoot(), "Height");
|
||||||
|
int TSizeZ = a_NBT.FindChildByName(a_NBT.GetRoot(), "Length");
|
||||||
|
if (
|
||||||
|
(TSizeX < 0) || (TSizeY < 0) || (TSizeZ < 0) ||
|
||||||
|
(a_NBT.GetType(TSizeX) != TAG_Short) ||
|
||||||
|
(a_NBT.GetType(TSizeY) != TAG_Short) ||
|
||||||
|
(a_NBT.GetType(TSizeZ) != TAG_Short)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
LOG("Dimensions are missing from the schematic file (%d, %d, %d), (%d, %d, %d)",
|
||||||
|
TSizeX, TSizeY, TSizeZ,
|
||||||
|
a_NBT.GetType(TSizeX), a_NBT.GetType(TSizeY), a_NBT.GetType(TSizeZ)
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SizeX = a_NBT.GetShort(TSizeX);
|
||||||
|
int SizeY = a_NBT.GetShort(TSizeY);
|
||||||
|
int SizeZ = a_NBT.GetShort(TSizeZ);
|
||||||
|
if ((SizeX < 1) || (SizeY < 1) || (SizeZ < 1))
|
||||||
|
{
|
||||||
|
LOG("Dimensions are invalid in the schematic file: %d, %d, %d", SizeX, SizeY, SizeZ);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TBlockTypes = a_NBT.FindChildByName(a_NBT.GetRoot(), "Blocks");
|
||||||
|
int TBlockMetas = a_NBT.FindChildByName(a_NBT.GetRoot(), "Data");
|
||||||
|
if ((TBlockTypes < 0) || (a_NBT.GetType(TBlockTypes) != TAG_ByteArray))
|
||||||
|
{
|
||||||
|
LOG("BlockTypes are invalid in the schematic file: %d", TBlockTypes);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool AreMetasPresent = (TBlockMetas > 0) && (a_NBT.GetType(TBlockMetas) == TAG_ByteArray);
|
||||||
|
|
||||||
|
a_BlockArea.Clear();
|
||||||
|
a_BlockArea.SetSize(SizeX, SizeY, SizeZ, AreMetasPresent ? (cBlockArea::baTypes | cBlockArea::baMetas) : cBlockArea::baTypes);
|
||||||
|
|
||||||
|
// Copy the block types and metas:
|
||||||
|
int NumBytes = a_BlockArea.m_SizeX * a_BlockArea.m_SizeY * a_BlockArea.m_SizeZ;
|
||||||
|
if (a_NBT.GetDataLength(TBlockTypes) < NumBytes)
|
||||||
|
{
|
||||||
|
LOG("BlockTypes truncated in the schematic file (exp %d, got %d bytes). Loading partial.",
|
||||||
|
NumBytes, a_NBT.GetDataLength(TBlockTypes)
|
||||||
|
);
|
||||||
|
NumBytes = a_NBT.GetDataLength(TBlockTypes);
|
||||||
|
}
|
||||||
|
memcpy(a_BlockArea.m_BlockTypes, a_NBT.GetData(TBlockTypes), NumBytes);
|
||||||
|
|
||||||
|
if (AreMetasPresent)
|
||||||
|
{
|
||||||
|
int NumBytes = a_BlockArea.m_SizeX * a_BlockArea.m_SizeY * a_BlockArea.m_SizeZ;
|
||||||
|
if (a_NBT.GetDataLength(TBlockMetas) < NumBytes)
|
||||||
|
{
|
||||||
|
LOG("BlockMetas truncated in the schematic file (exp %d, got %d bytes). Loading partial.",
|
||||||
|
NumBytes, a_NBT.GetDataLength(TBlockMetas)
|
||||||
|
);
|
||||||
|
NumBytes = a_NBT.GetDataLength(TBlockMetas);
|
||||||
|
}
|
||||||
|
memcpy(a_BlockArea.m_BlockMetas, a_NBT.GetData(TBlockMetas), NumBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
29
src/WorldStorage/SchematicFileSerializer.h
Normal file
29
src/WorldStorage/SchematicFileSerializer.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../BlockArea.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// fwd: FastNBT.h
|
||||||
|
class cParsedNBT;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cSchematicFileSerializer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// Loads an area from a .schematic file. Returns true if successful
|
||||||
|
static bool LoadFromSchematicFile(cBlockArea & a_BlockArea, const AString & a_FileName);
|
||||||
|
|
||||||
|
/// Saves the area into a .schematic file. Returns true if successful
|
||||||
|
static bool SaveToSchematicFile(cBlockArea & a_BlockArea, const AString & a_FileName);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// Loads the area from a schematic file uncompressed and parsed into a NBT tree. Returns true if successful.
|
||||||
|
static bool LoadFromSchematicNBT(cBlockArea & a_BlockArea, cParsedNBT & a_NBT);
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user