From afdbb1d71bb69cf20cd7458e192be0c9308515ba Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Wed, 6 Feb 2013 22:29:29 +0000 Subject: cBlockArea can now be loaded from a .schematic file. git-svn-id: http://mc-server.googlecode.com/svn/trunk@1195 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/BlockArea.cpp | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) (limited to 'source/BlockArea.cpp') diff --git a/source/BlockArea.cpp b/source/BlockArea.cpp index 4f8de925c..cdabf0378 100644 --- a/source/BlockArea.cpp +++ b/source/BlockArea.cpp @@ -7,6 +7,8 @@ #include "Globals.h" #include "BlockArea.h" #include "World.h" +#include "zlib.h" +#include "WorldStorage/FastNBT.h" @@ -188,6 +190,46 @@ void cBlockArea::DumpToRawFile(const AString & a_FileName) +bool cBlockArea::LoadFromSchematicFile(const AString & a_FileName) +{ + // Un-GZip the contents: + AString Contents; + gzFile File = gzopen(a_FileName.c_str(), "rb"); + if (File == NULL) + { + LOG("Cannot open the schematic file \"%s\".", a_FileName.c_str()); + return false; + } + // Since the gzip format doesn't really support getting the uncompressed length, we need to read incrementally. Yuck! + int NumBytesRead = 0; + char Buffer[32 KiB]; + while ((NumBytesRead = gzread(File, Buffer, sizeof(Buffer))) > 0) + { + Contents.append(Buffer, NumBytesRead); + } + if (NumBytesRead < 0) + { + LOG("Cannot read GZipped data in the schematic file \"%s\", error %d", a_FileName.c_str(), NumBytesRead); + gzclose(File); + return false; + } + gzclose(File); + + // TODO: 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); +} + + + + + void cBlockArea::Crop(int a_AddMinX, int a_SubMaxX, int a_AddMinY, int a_SubMaxY, int a_AddMinZ, int a_SubMaxZ) { if (HasBlockTypes()) @@ -799,3 +841,83 @@ void cBlockArea::CropNibbles(NIBBLEARRAY & a_Array, int a_AddMinX, int a_SubMaxX + +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); + + 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; +} + + + + -- cgit v1.2.3