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 --- MCServer/Plugins/Debuggers/Debuggers.lua | 17 +++++ source/Bindings.cpp | 38 +++++++++- source/Bindings.h | 2 +- source/BlockArea.cpp | 122 +++++++++++++++++++++++++++++++ source/BlockArea.h | 11 ++- 5 files changed, 187 insertions(+), 3 deletions(-) diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index 6776fa480..ba410dd49 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -69,6 +69,7 @@ function OnPlayerUsingItem(Player, BlockX, BlockY, BlockZ, BlockFace, CursorX, C local HeldItem = Player:GetEquippedItem(); + if (HeldItem.m_ItemType == E_ITEM_STICK) then -- Magic sTick of ticking: set the pointed block for ticking at the next tick Player:SendMessage(cChatColor.LightGray .. "Setting next block tick to {" .. BlockX .. ", " .. BlockY .. ", " .. BlockZ .. "}") @@ -76,6 +77,7 @@ function OnPlayerUsingItem(Player, BlockX, BlockY, BlockZ, BlockFace, CursorX, C return true end + if (HeldItem.m_ItemType == E_ITEM_BLAZE_ROD) then -- Magic rod of query: show block types and metas for both neighbors of the pointed face local Type = 0; @@ -104,6 +106,7 @@ function OnPlayerUsingItem(Player, BlockX, BlockY, BlockZ, BlockFace, CursorX, C end end + -- Rclk with a diamond to read a block area, dump it, crop it, dump it again, crop it again... if (Player:GetEquippedItem().m_ItemType == E_ITEM_DIAMOND) then local Area = cBlockArea(); @@ -132,6 +135,20 @@ function OnPlayerUsingItem(Player, BlockX, BlockY, BlockZ, BlockFace, CursorX, C return false; end + + -- Rclk with an eye of ender places a predefined schematic at the cursor + if (Player:GetEquippedItem().m_ItemType == E_ITEM_EYE_OF_ENDER) then + local Area = cBlockArea(); + if not(Area:LoadFromSchematicFile("schematics/test.schematic")) then + LOG("Loading failed"); + return false; + end + LOG("Schematic loaded, placing now."); + Area:Write(Player:GetWorld(), BlockX, BlockY, BlockZ); + LOG("Done."); + return false; + end + end diff --git a/source/Bindings.cpp b/source/Bindings.cpp index 188f99259..ffbb74431 100644 --- a/source/Bindings.cpp +++ b/source/Bindings.cpp @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 02/06/13 17:53:00. +** Generated automatically by tolua++-1.0.92 on 02/06/13 22:02:40. */ #ifndef __cplusplus @@ -17859,6 +17859,41 @@ static int tolua_AllToLua_cBlockArea_DumpToRawFile00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* method: LoadFromSchematicFile of class cBlockArea */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cBlockArea_LoadFromSchematicFile00 +static int tolua_AllToLua_cBlockArea_LoadFromSchematicFile00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cBlockArea",0,&tolua_err) || + !tolua_iscppstring(tolua_S,2,0,&tolua_err) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cBlockArea* self = (cBlockArea*) tolua_tousertype(tolua_S,1,0); + const AString a_FileName = ((const AString) tolua_tocppstring(tolua_S,2,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'LoadFromSchematicFile'", NULL); +#endif + { + bool tolua_ret = (bool) self->LoadFromSchematicFile(a_FileName); + tolua_pushboolean(tolua_S,(bool)tolua_ret); + tolua_pushcppstring(tolua_S,(const char*)a_FileName); + } + } + return 2; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'LoadFromSchematicFile'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* method: Crop of class cBlockArea */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cBlockArea_Crop00 static int tolua_AllToLua_cBlockArea_Crop00(lua_State* tolua_S) @@ -21740,6 +21775,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"Write",tolua_AllToLua_cBlockArea_Write00); tolua_function(tolua_S,"Write",tolua_AllToLua_cBlockArea_Write01); tolua_function(tolua_S,"DumpToRawFile",tolua_AllToLua_cBlockArea_DumpToRawFile00); + tolua_function(tolua_S,"LoadFromSchematicFile",tolua_AllToLua_cBlockArea_LoadFromSchematicFile00); tolua_function(tolua_S,"Crop",tolua_AllToLua_cBlockArea_Crop00); tolua_function(tolua_S,"SetRelBlockType",tolua_AllToLua_cBlockArea_SetRelBlockType00); tolua_function(tolua_S,"SetBlockType",tolua_AllToLua_cBlockArea_SetBlockType00); diff --git a/source/Bindings.h b/source/Bindings.h index afbeaeaec..2ee3ca938 100644 --- a/source/Bindings.h +++ b/source/Bindings.h @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 02/06/13 17:53:01. +** Generated automatically by tolua++-1.0.92 on 02/06/13 22:02:40. */ /* Exported function */ 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; +} + + + + diff --git a/source/BlockArea.h b/source/BlockArea.h index 797c37de6..58f5cf061 100644 --- a/source/BlockArea.h +++ b/source/BlockArea.h @@ -16,9 +16,12 @@ -// fwd: "cWorld.h" +// fwd: World.h class cWorld; +// fwd: FastNBT.h +class cParsedNBT; + @@ -59,6 +62,9 @@ public: // 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 + /// Loads an area from a .schematic file. Returns true if successful + bool LoadFromSchematicFile(const AString & a_FileName); + /// 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); @@ -166,6 +172,9 @@ protected: // Crop helpers: void CropBlockTypes(int a_AddMinX, int a_SubMaxX, int a_AddMinY, int a_SubMaxY, int a_AddMinZ, int a_SubMaxZ); void CropNibbles (NIBBLEARRAY & a_Array, int a_AddMinX, int a_SubMaxX, int a_AddMinY, int a_SubMaxY, int a_AddMinZ, int a_SubMaxZ); + + /// Loads the area from a schematic file uncompressed and parsed into a NBT tree. Returns true if successful. + bool LoadFromSchematicNBT(cParsedNBT & a_NBT); // tolua_begin } ; -- cgit v1.2.3