1
0

Added cBlockArea:Merge() API function to merge two block areas using different strategies.

git-svn-id: http://mc-server.googlecode.com/svn/trunk@1207 0a769ca7-a7f5-676a-18bf-c427514a06d6
This commit is contained in:
madmaxoft@gmail.com 2013-02-10 15:15:41 +00:00
parent c497a34536
commit 345da37e96
5 changed files with 273 additions and 9 deletions

View File

@ -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

View File

@ -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);

View File

@ -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 */

View File

@ -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<typename Combinator> 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)

View File

@ -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;