diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index 1775c960e..018e56f29 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -53,6 +53,20 @@ function Initialize(Plugin) end f:close(); end + + + -- Debug block area merging: + local BA1 = cBlockArea(); + local BA2 = cBlockArea(); + if (BA1:LoadFromSchematicFile("schematics/test.schematic")) then + if (BA2:LoadFromSchematicFile("schematics/fountain.schematic")) then + BA2:SetRelBlockType(0, 0, 0, E_BLOCK_LAPIS_BLOCK); + BA2:SetRelBlockType(1, 0, 0, E_BLOCK_LAPIS_BLOCK); + BA2:SetRelBlockType(2, 0, 0, E_BLOCK_LAPIS_BLOCK); + BA1:Merge(BA2, 1, 10, 1, cBlockArea.msImprint); + BA1:SaveToSchematicFile("schematics/merge.schematic"); + end + end return true end diff --git a/source/Bindings.cpp b/source/Bindings.cpp index 49e54129d..eb4d9ef8f 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/09/13 10:54:12. +** Generated automatically by tolua++-1.0.92 on 02/10/13 14:41:15. */ #ifndef __cplusplus @@ -4601,14 +4601,14 @@ static int tolua_AllToLua_cEntity_GetLookVector00(lua_State* tolua_S) #ifndef TOLUA_RELEASE tolua_Error tolua_err; if ( - !tolua_isusertype(tolua_S,1,"cEntity",0,&tolua_err) || + !tolua_isusertype(tolua_S,1,"const cEntity",0,&tolua_err) || !tolua_isnoobj(tolua_S,2,&tolua_err) ) goto tolua_lerror; else #endif { - cEntity* self = (cEntity*) tolua_tousertype(tolua_S,1,0); + const cEntity* self = (const cEntity*) tolua_tousertype(tolua_S,1,0); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetLookVector'", NULL); #endif @@ -18081,6 +18081,47 @@ static int tolua_AllToLua_cBlockArea_Expand00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* method: Merge of class cBlockArea */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cBlockArea_Merge00 +static int tolua_AllToLua_cBlockArea_Merge00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cBlockArea",0,&tolua_err) || + (tolua_isvaluenil(tolua_S,2,&tolua_err) || !tolua_isusertype(tolua_S,2,"const cBlockArea",0,&tolua_err)) || + !tolua_isnumber(tolua_S,3,0,&tolua_err) || + !tolua_isnumber(tolua_S,4,0,&tolua_err) || + !tolua_isnumber(tolua_S,5,0,&tolua_err) || + !tolua_isnumber(tolua_S,6,0,&tolua_err) || + !tolua_isnoobj(tolua_S,7,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cBlockArea* self = (cBlockArea*) tolua_tousertype(tolua_S,1,0); + const cBlockArea* a_Src = ((const cBlockArea*) tolua_tousertype(tolua_S,2,0)); + int a_RelX = ((int) tolua_tonumber(tolua_S,3,0)); + int a_RelY = ((int) tolua_tonumber(tolua_S,4,0)); + int a_RelZ = ((int) tolua_tonumber(tolua_S,5,0)); + cBlockArea::eMergeStrategy a_Strategy = ((cBlockArea::eMergeStrategy) (int) tolua_tonumber(tolua_S,6,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'Merge'", NULL); +#endif + { + self->Merge(*a_Src,a_RelX,a_RelY,a_RelZ,a_Strategy); + } + } + return 0; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'Merge'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* method: SetRelBlockType of class cBlockArea */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cBlockArea_SetRelBlockType00 static int tolua_AllToLua_cBlockArea_SetRelBlockType00(lua_State* tolua_S) @@ -22196,6 +22237,9 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_constant(tolua_S,"baMetas",cBlockArea::baMetas); tolua_constant(tolua_S,"baLight",cBlockArea::baLight); tolua_constant(tolua_S,"baSkyLight",cBlockArea::baSkyLight); + tolua_constant(tolua_S,"msOverwrite",cBlockArea::msOverwrite); + tolua_constant(tolua_S,"msFillAir",cBlockArea::msFillAir); + tolua_constant(tolua_S,"msImprint",cBlockArea::msImprint); tolua_function(tolua_S,"new",tolua_AllToLua_cBlockArea_new00); tolua_function(tolua_S,"new_local",tolua_AllToLua_cBlockArea_new00_local); tolua_function(tolua_S,".call",tolua_AllToLua_cBlockArea_new00_local); @@ -22212,6 +22256,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"SaveToSchematicFile",tolua_AllToLua_cBlockArea_SaveToSchematicFile00); tolua_function(tolua_S,"Crop",tolua_AllToLua_cBlockArea_Crop00); tolua_function(tolua_S,"Expand",tolua_AllToLua_cBlockArea_Expand00); + tolua_function(tolua_S,"Merge",tolua_AllToLua_cBlockArea_Merge00); tolua_function(tolua_S,"SetRelBlockType",tolua_AllToLua_cBlockArea_SetRelBlockType00); tolua_function(tolua_S,"SetBlockType",tolua_AllToLua_cBlockArea_SetBlockType00); tolua_function(tolua_S,"SetRelBlockMeta",tolua_AllToLua_cBlockArea_SetRelBlockMeta00); diff --git a/source/Bindings.h b/source/Bindings.h index 76536279e..1c5011759 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/09/13 10:54:12. +** Generated automatically by tolua++-1.0.92 on 02/10/13 14:41:16. */ /* Exported function */ diff --git a/source/BlockArea.cpp b/source/BlockArea.cpp index 472b14c59..01c1cf4c1 100644 --- a/source/BlockArea.cpp +++ b/source/BlockArea.cpp @@ -14,6 +14,87 @@ +// This wild construct allows us to pass a function argument and still have it inlined by the compiler :) +/// Merges two blocktypes and blockmetas of the specified sizes and offsets using the specified combinator function +template void InternalMergeBlocks( + BLOCKTYPE * a_DstTypes, const BLOCKTYPE * a_SrcTypes, + NIBBLETYPE * a_DstMetas, const NIBBLETYPE * a_SrcMetas, + int a_SizeX, int a_SizeY, int a_SizeZ, + int a_SrcOffX, int a_SrcOffY, int a_SrcOffZ, + int a_DstOffX, int a_DstOffY, int a_DstOffZ, + int a_SrcSizeX, int a_SrcSizeY, int a_SrcSizeZ, + int a_DstSizeX, int a_DstSizeY, int a_DstSizeZ, + Combinator a_Combinator +) +{ + for (int y = 0; y < a_SizeY; y++) + { + int SrcBaseY = (y + a_SrcOffY) * a_SrcSizeX * a_SrcSizeZ; + int DstBaseY = (y + a_DstOffY) * a_DstSizeX * a_DstSizeZ; + for (int z = 0; z < a_SizeZ; z++) + { + int SrcBaseZ = SrcBaseY + (z + a_SrcOffZ) * a_SrcSizeX; + int DstBaseZ = DstBaseY + (z + a_DstOffZ) * a_DstSizeX; + int SrcIdx = SrcBaseZ + a_SrcOffX; + int DstIdx = DstBaseZ + a_DstOffX; + for (int x = 0; x < a_SizeX; x++) + { + a_Combinator(a_DstTypes[DstIdx], a_SrcTypes[SrcIdx], a_DstMetas[DstIdx], a_SrcMetas[SrcIdx]); + ++DstIdx; + ++SrcIdx; + } // for x + } // for z + } // for y +} + + + + + +/// Combinator used for cBlockArea::msOverwrite merging +static void MergeCombinatorOverwrite(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) +{ + a_DstType = a_SrcType; + a_DstMeta = a_SrcMeta; +} + + + + + +/// Combinator used for cBlockArea::msFillAir merging +static void MergeCombinatorFillAir(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) +{ + if (a_DstType == E_BLOCK_AIR) + { + a_DstType = a_SrcType; + a_DstMeta = a_SrcMeta; + } + // "else" is the default, already in place +} + + + + + +/// Combinator used for cBlockArea::msImprint merging +static void MergeCombinatorImprint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) +{ + if (a_SrcType != E_BLOCK_AIR) + { + a_DstType = a_SrcType; + a_DstMeta = a_SrcMeta; + } + // "else" is the default, already in place +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cBlockArea: + cBlockArea::cBlockArea(void) : m_SizeX(0), m_SizeY(0), @@ -300,7 +381,7 @@ bool cBlockArea::SaveToSchematicFile(const AString & a_FileName) Writer.EndList(); Writer.Finish(); - // TODO: Save to file + // Save to file cGZipFile File; if (!File.Open(a_FileName, cGZipFile::fmWrite)) { @@ -392,6 +473,104 @@ void cBlockArea::Expand(int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMa +void cBlockArea::Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy) +{ + // Block types are compulsory, block metas are voluntary + if (!HasBlockTypes() || !a_Src.HasBlockTypes()) + { + LOGWARNING("%s: cannot merge because one of the areas doesn't have blocktypes.", __FUNCTION__); + return; + } + + // Dst is *this, Src is a_Src + int SrcOffX = std::max(0, -a_RelX); // Offset in Src where to start reading + int DstOffX = std::max(0, a_RelX); // Offset in Dst where to start writing + int SizeX = std::min(a_Src.GetSizeX() - SrcOffX, GetSizeX() - DstOffX); // How many blocks to copy + + int SrcOffY = std::max(0, -a_RelY); // Offset in Src where to start reading + int DstOffY = std::max(0, a_RelY); // Offset in Dst where to start writing + int SizeY = std::min(a_Src.GetSizeY() - SrcOffY, GetSizeY() - DstOffY); // How many blocks to copy + + int SrcOffZ = std::max(0, -a_RelZ); // Offset in Src where to start reading + int DstOffZ = std::max(0, a_RelZ); // Offset in Dst where to start writing + int SizeZ = std::min(a_Src.GetSizeZ() - SrcOffZ, GetSizeZ() - DstOffZ); // How many blocks to copy + + const NIBBLETYPE * SrcMetas = a_Src.GetBlockMetas(); + NIBBLETYPE * DstMetas = m_BlockMetas; + bool IsDummyMetas = ((SrcMetas == NULL) || (DstMetas == NULL)); + + if (IsDummyMetas) + { + SrcMetas = new NIBBLETYPE[a_Src.GetBlockCount()]; + DstMetas = new NIBBLETYPE[GetBlockCount()]; + } + + switch (a_Strategy) + { + case msOverwrite: + { + InternalMergeBlocks( + m_BlockTypes, a_Src.GetBlockTypes(), + DstMetas, SrcMetas, + SizeX, SizeY, SizeZ, + SrcOffX, SrcOffY, SrcOffZ, + DstOffX, DstOffY, DstOffZ, + a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), + m_SizeX, m_SizeY, m_SizeZ, + MergeCombinatorOverwrite + ); + break; + } // case msOverwrite + + case msFillAir: + { + InternalMergeBlocks( + m_BlockTypes, a_Src.GetBlockTypes(), + DstMetas, SrcMetas, + SizeX, SizeY, SizeZ, + SrcOffX, SrcOffY, SrcOffZ, + DstOffX, DstOffY, DstOffZ, + a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), + m_SizeX, m_SizeY, m_SizeZ, + MergeCombinatorFillAir + ); + break; + } // case msFillAir + + case msImprint: + { + InternalMergeBlocks( + m_BlockTypes, a_Src.GetBlockTypes(), + DstMetas, SrcMetas, + SizeX, SizeY, SizeZ, + SrcOffX, SrcOffY, SrcOffZ, + DstOffX, DstOffY, DstOffZ, + a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), + m_SizeX, m_SizeY, m_SizeZ, + MergeCombinatorImprint + ); + break; + } // case msImprint + + default: + { + LOGWARNING("Unknown block area merge strategy: %d", a_Strategy); + ASSERT(!"Unknown block area merge strategy"); + break; + } + } // switch (a_Strategy) + + if (IsDummyMetas) + { + delete[] SrcMetas; + delete[] DstMetas; + } +} + + + + + void cBlockArea::SetRelBlockType(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType) { if (m_BlockTypes == NULL) diff --git a/source/BlockArea.h b/source/BlockArea.h index b1a2d9053..787731434 100644 --- a/source/BlockArea.h +++ b/source/BlockArea.h @@ -44,6 +44,13 @@ public: baSkyLight = 8, } ; + enum eMergeStrategy + { + msOverwrite, + msFillAir, + msImprint, + } ; + cBlockArea(void); ~cBlockArea(); @@ -80,6 +87,25 @@ public: /// Expands the internal contents by the specified amount of blocks from each border void Expand(int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMaxY, int a_SubMinZ, int a_AddMaxZ); + /** Merges another block area into this one, using the specified block combinating strategy + This function combines another BlockArea into the current object. + The strategy parameter specifies how individual blocks are combined together, using the table below. + + | area block | result | + | this | Src | msOverwrite | msFillAir | msImprint | + +------+-----+-------------+-----------+-----------+ + | air | air | air | air | air | + | A | air | air | A | A | + | air | B | B | B | B | + | A | B | B | A | B | + + So to sum up: + - msOverwrite completely overwrites all blocks with the Src's blocks + - msFillAir overwrites only those blocks that were air + - msImprint overwrites with only those blocks that are non-air + */ + void Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy); + // Setters: void SetRelBlockType (int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType); void SetBlockType (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType); @@ -125,10 +151,10 @@ public: // Clients can use these for faster access to all blocktypes. Be careful though! /// Returns the internal pointer to the block types - BLOCKTYPE * GetBlockTypes (void) { return m_BlockTypes; } - NIBBLETYPE * GetBlockMetas (void) { return m_BlockMetas; } // NOTE: one byte per block! - NIBBLETYPE * GetBlockLight (void) { return m_BlockLight; } // NOTE: one byte per block! - NIBBLETYPE * GetBlockSkyLight(void) { return m_BlockSkyLight; } // NOTE: one byte per block! + BLOCKTYPE * GetBlockTypes (void) const { return m_BlockTypes; } + NIBBLETYPE * GetBlockMetas (void) const { return m_BlockMetas; } // NOTE: one byte per block! + NIBBLETYPE * GetBlockLight (void) const { return m_BlockLight; } // NOTE: one byte per block! + NIBBLETYPE * GetBlockSkyLight(void) const { return m_BlockSkyLight; } // NOTE: one byte per block! int GetBlockCount(void) const { return m_SizeX * m_SizeY * m_SizeZ; } int MakeIndex(int a_RelX, int a_RelY, int a_RelZ) const;