diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index a3695fe17..7c9a2e0cb 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -120,6 +120,7 @@ g_APIDesc = GetOriginX = { Params = "", Return = "number", Notes = "Returns the origin x-coord" }, GetOriginY = { Params = "", Return = "number", Notes = "Returns the origin y-coord" }, GetOriginZ = { Params = "", Return = "number", Notes = "Returns the origin z-coord" }, + GetNonAirCropRelCoords = { Params = "[IgnoreBlockType]", Return = "MinRelX, MinRelY, MinRelZ, MaxRelX, MaxRelY, MaxRelZ", Notes = "Returns the minimum and maximum coords in each direction for the first non-ignored block in each direction. If there are no non-ignored blocks within the area, or blocktypes are not present, the returned values are reverse-ranges (MinX <- m_RangeX, MaxX <- 0 etc.). IgnoreBlockType defaults to air." }, GetRelBlockLight = { Params = "RelBlockX, RelBlockY, RelBlockZ", Return = "NIBBLETYPE", Notes = "Returns the blocklight at the specified relative coords" }, GetRelBlockMeta = { Params = "RelBlockX, RelBlockY, RelBlockZ", Return = "NIBBLETYPE", Notes = "Returns the block meta at the specified relative coords" }, GetRelBlockSkyLight = { Params = "RelBlockX, RelBlockY, RelBlockZ", Return = "NIBBLETYPE", Notes = "Returns the skylight at the specified relative coords" }, @@ -197,13 +198,14 @@ g_APIDesc = baMetas = { Notes = "Operations should work on block metas" }, baLight = { Notes = "Operations should work on block (emissive) light" }, baSkyLight = { Notes = "Operations should work on skylight" }, - msDifference = { Notes = "Block becomes air if Src and Dst are the same. Otherwise it becomes the source block." }, - msOverwrite = { Notes = "Src overwrites anything in Dst" }, - msFillAir = { Notes = "Dst is overwritten by Src only where Src has air blocks" }, - msImprint = { Notes = "Src overwrites Dst anywhere where Dst has non-air blocks" }, + msDifference = { Notes = "Block becomes air if 'self' and src are the same. Otherwise it becomes the src block." }, + msFillAir = { Notes = "'self' is overwritten by Src only where 'self' has air blocks" }, + msImprint = { Notes = "Src overwrites 'self' anywhere where 'self' has non-air blocks" }, msLake = { Notes = "Special mode for merging lake images" }, + msMask = { Notes = "The blocks that are exactly the same are kept in 'self', all differing blocks are replaced by air"}, + msOverwrite = { Notes = "Src overwrites anything in 'self'" }, + msSimpleCompare = { Notes = "The blocks that are exactly the same are replaced with air, all differing blocks are replaced by stone"}, msSpongePrint = { Notes = "Similar to msImprint, sponge block doesn't overwrite anything, all other blocks overwrite everything"}, - msMask = { Notes = "The blocks that are exactly the same are kept in Dst, all differing blocks are replaced by air"}, }, ConstantGroups = { @@ -287,7 +289,7 @@ g_APIDesc = - + @@ -321,7 +323,7 @@ g_APIDesc =
area block Notes
this Src result self Src result
A sponge A Sponge is the NOP block
- + @@ -337,13 +339,45 @@ g_APIDesc =
area block Notes
this Src result self Src result
A sponge A Sponge is the NOP block
- +
area block Notes
this Src result self Src result
A A A Same blocks are kept
A non-A air Differing blocks are replaced with air
+ +

+ msDifference - the blocks that are the same in both areas are replaced with air, all the + differing blocks are kept from the first area. Meta is used in the comparison, too, two blocks of the + same type but different meta are considered different. +

+ + + + + + + + + +
area block Notes
self Src result
A A air Same blocks are replaced with air
A non-A A Differing blocks are kept from 'self'
+ +

+ msSimpleCompare - the blocks that are the same in both areas are replaced with air, all the + differing blocks are replaced with stone. Meta is used in the comparison, too, two blocks of the + same type but different meta are considered different. +

+ + + + + + + + + +
area block Notes
self Src result
A A air Same blocks are replaced with air
A non-A stone Differing blocks are replaced with stone
]], }, -- Merge strategies }, -- AdditionalInfo diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp index 38e008b2a..ed31e678f 100644 --- a/src/Bindings/LuaState.cpp +++ b/src/Bindings/LuaState.cpp @@ -937,6 +937,18 @@ void cLuaState::GetStackValue(int a_StackPos, AString & a_Value) +void cLuaState::GetStackValue(int a_StackPos, BLOCKTYPE & a_ReturnedVal) +{ + if (lua_isnumber(m_LuaState, a_StackPos)) + { + a_ReturnedVal = static_cast(tolua_tonumber(m_LuaState, a_StackPos, a_ReturnedVal)); + } +} + + + + + void cLuaState::GetStackValue(int a_StackPos, bool & a_ReturnedVal) { a_ReturnedVal = (tolua_toboolean(m_LuaState, a_StackPos, a_ReturnedVal ? 1 : 0) > 0); @@ -995,6 +1007,24 @@ void cLuaState::GetStackValue(int a_StackPos, int & a_ReturnedVal) +void cLuaState::GetStackValue(int a_StackPos, pBlockArea & a_ReturnedVal) +{ + if (lua_isnil(m_LuaState, a_StackPos)) + { + a_ReturnedVal = nullptr; + return; + } + tolua_Error err; + if (tolua_isusertype(m_LuaState, a_StackPos, "cBlockArea", false, &err)) + { + a_ReturnedVal = *(reinterpret_cast(lua_touserdata(m_LuaState, a_StackPos))); + } +} + + + + + void cLuaState::GetStackValue(int a_StackPos, pBoundingBox & a_ReturnedVal) { if (lua_isnil(m_LuaState, a_StackPos)) @@ -1005,7 +1035,7 @@ void cLuaState::GetStackValue(int a_StackPos, pBoundingBox & a_ReturnedVal) tolua_Error err; if (tolua_isusertype(m_LuaState, a_StackPos, "cBoundingBox", false, &err)) { - a_ReturnedVal = *((cBoundingBox **)lua_touserdata(m_LuaState, a_StackPos)); + a_ReturnedVal = *(reinterpret_cast(lua_touserdata(m_LuaState, a_StackPos))); } } diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h index a6e121eb7..6bedbf5ec 100644 --- a/src/Bindings/LuaState.h +++ b/src/Bindings/LuaState.h @@ -37,6 +37,7 @@ extern "C" +class cBlockArea; class cBlockEntity; class cBoundingBox; class cChunkDesc; @@ -68,6 +69,7 @@ struct HTTPRequest; struct HTTPTemplateRequest; struct TakeDamageInfo; +typedef cBlockArea * pBlockArea; typedef cBoundingBox * pBoundingBox; typedef cMapManager * pMapManager; typedef cPluginManager * pPluginManager; @@ -244,11 +246,13 @@ public: // GetStackValue() retrieves the value at a_StackPos, if it is a valid type. If not, a_Value is unchanged. // Enum values are clamped to their allowed range. void GetStackValue(int a_StackPos, AString & a_Value); + void GetStackValue(int a_StackPos, BLOCKTYPE & a_Value); void GetStackValue(int a_StackPos, bool & a_Value); void GetStackValue(int a_StackPos, cRef & a_Ref); void GetStackValue(int a_StackPos, double & a_Value); void GetStackValue(int a_StackPos, eWeather & a_Value); void GetStackValue(int a_StackPos, int & a_Value); + void GetStackValue(int a_StackPos, pBlockArea & a_Value); void GetStackValue(int a_StackPos, pBoundingBox & a_Value); void GetStackValue(int a_StackPos, pMapManager & a_Value); void GetStackValue(int a_StackPos, pPluginManager & a_Value); diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index c4b12aa84..8e909827c 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -3187,6 +3187,44 @@ static int tolua_cBlockArea_GetOrigin(lua_State * tolua_S) +static int tolua_cBlockArea_GetNonAirCropRelCoords(lua_State * tolua_S) +{ + // function cBlockArea::GetNonAirCropRelCoords() + // Exported manually because tolua would generate extra input params for the outputs + + cLuaState L(tolua_S); + if (!L.CheckParamUserType(1, "cBlockArea")) + { + return 0; + } + + cBlockArea * self = nullptr; + BLOCKTYPE IgnoreBlockType = E_BLOCK_AIR; + L.GetStackValues(1, self, IgnoreBlockType); + if (self == nullptr) + { + tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea:GetNonAirCropRelCoords'", nullptr); + return 0; + } + + // Calculate the crop coords: + int MinRelX, MinRelY, MinRelZ, MaxRelX, MaxRelY, MaxRelZ; + self->GetNonAirCropRelCoords(MinRelX, MinRelY, MinRelZ, MaxRelX, MaxRelY, MaxRelZ, IgnoreBlockType); + + // Push the six crop coords: + L.Push(MinRelX); + L.Push(MinRelY); + L.Push(MinRelZ); + L.Push(MaxRelX); + L.Push(MaxRelY); + L.Push(MaxRelZ); + return 6; +} + + + + + static int tolua_cBlockArea_GetRelBlockTypeMeta(lua_State * tolua_S) { // function cBlockArea::GetRelBlockTypeMeta() @@ -3687,6 +3725,7 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_function(tolua_S, "GetBlockTypeMeta", tolua_cBlockArea_GetBlockTypeMeta); tolua_function(tolua_S, "GetCoordRange", tolua_cBlockArea_GetCoordRange); tolua_function(tolua_S, "GetOrigin", tolua_cBlockArea_GetOrigin); + tolua_function(tolua_S, "GetNonAirCropRelCoords", tolua_cBlockArea_GetNonAirCropRelCoords); tolua_function(tolua_S, "GetRelBlockTypeMeta", tolua_cBlockArea_GetRelBlockTypeMeta); tolua_function(tolua_S, "GetSize", tolua_cBlockArea_GetSize); tolua_function(tolua_S, "LoadFromSchematicFile", tolua_cBlockArea_LoadFromSchematicFile); diff --git a/src/BlockArea.cpp b/src/BlockArea.cpp index 4c3da0535..600940d96 100644 --- a/src/BlockArea.cpp +++ b/src/BlockArea.cpp @@ -245,6 +245,26 @@ void MergeCombinatorDifference(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBL +/** Combinator used for cBlockArea::msSimpleCompare merging */ +template +void MergeCombinatorSimpleCompare(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) +{ + if ((a_DstType == a_SrcType) && (!MetaValid || (a_DstMeta == a_SrcMeta))) + { + // The blocktypes are the same, and the blockmetas are not present or are the same + a_DstType = E_BLOCK_AIR; + } + else + { + // The blocktypes or blockmetas differ + a_DstType = E_BLOCK_STONE; + } +} + + + + + /** Combinator used for cBlockArea::msMask merging */ template void MergeCombinatorMask(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) @@ -1614,6 +1634,73 @@ void cBlockArea::GetRelBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTY +void cBlockArea::GetNonAirCropRelCoords(int & a_MinRelX, int & a_MinRelY, int & a_MinRelZ, int & a_MaxRelX, int & a_MaxRelY, int & a_MaxRelZ, BLOCKTYPE a_IgnoreBlockType) +{ + // Check if blocktypes are valid: + if (m_BlockTypes == nullptr) + { + LOGWARNING("%s: BlockTypes have not been read!", __FUNCTION__); + a_MinRelX = 1; + a_MaxRelX = 0; + return; + } + + // Walk all the blocks and find the min and max coords for the non-ignored ones: + int MaxX = 0, MinX = m_Size.x - 1; + int MaxY = 0, MinY = m_Size.y - 1; + int MaxZ = 0, MinZ = m_Size.z - 1; + for (int y = 0; y < m_Size.y; y++) + { + for (int z = 0; z < m_Size.z; z++) + { + for (int x = 0; x < m_Size.x; x++) + { + if (m_BlockTypes[MakeIndex(x, y, z)] == a_IgnoreBlockType) + { + continue; + } + // The block is not ignored, update any coords that need updating: + if (x < MinX) + { + MinX = x; + } + if (x > MaxX) + { + MaxX = x; + } + if (y < MinY) + { + MinY = y; + } + if (y > MaxY) + { + MaxY = y; + } + if (z < MinZ) + { + MinZ = z; + } + if (z > MaxZ) + { + MaxZ = z; + } + } // for x + } // for z + } // for y + + // Assign to the output: + a_MinRelX = MinX; + a_MinRelY = MinY; + a_MinRelZ = MinZ; + a_MaxRelX = MaxX; + a_MaxRelY = MaxY; + a_MaxRelZ = MaxZ; +} + + + + + int cBlockArea::GetDataTypes(void) const { int res = 0; @@ -2121,10 +2208,12 @@ void cBlockArea::RelSetData( + + template void cBlockArea::MergeByStrategy(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy, const NIBBLETYPE * SrcMetas, NIBBLETYPE * DstMetas) { - // Block types are compulsory, block metas are voluntary + // Block types are compulsory, block metas are optional if (!HasBlockTypes() || !a_Src.HasBlockTypes()) { LOGWARNING("%s: cannot merge because one of the areas doesn't have blocktypes.", __FUNCTION__); @@ -2230,6 +2319,20 @@ void cBlockArea::MergeByStrategy(const cBlockArea & a_Src, int a_RelX, int a_Rel return; } // case msDifference + case cBlockArea::msSimpleCompare: + { + 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_Size.x, m_Size.y, m_Size.z + ); + return; + } // case msSimpleCompare + case cBlockArea::msMask: { InternalMergeBlocks >( diff --git a/src/BlockArea.h b/src/BlockArea.h index 348e960dd..ce417ceb4 100644 --- a/src/BlockArea.h +++ b/src/BlockArea.h @@ -54,6 +54,7 @@ public: msLake, msSpongePrint, msDifference, + msSimpleCompare, msMask, } ; @@ -156,6 +157,22 @@ public: | A | sponge | A | Sponge is the NOP block | * | B | B | Everything else overwrites anything + msDifference: + Used to determine the differences between two areas. Only the differring blocks are preserved: + | area block | | + | this | Src | result | + +------+-------+--------+ + | A | A | air | Same blocks are replaced with air + | A | non-A | A | Differring blocks are kept from "this" + + msSimpleCompare: + Used to determine the differences between two areas. Blocks that differ are replaced with stone, same blocks are replaced with air + | area block | | + | this | Src | result | + +------+-------+--------+ + | A | A | air | Same blocks are replaced with air + | A | non-A | stone | Differring blocks are replaced with stone + msMask: Combines two areas, the blocks that are the same are kept, differing ones are reset to air | area block | | @@ -288,6 +305,11 @@ public: bool HasBlockSkyLights(void) const { return (m_BlockSkyLight != nullptr); } // tolua_end + + /** Returns the minimum and maximum coords in each direction for the first non-ignored block in each direction. + If there are no non-ignored blocks within the area, or blocktypes are not present, the returned values are reverse-ranges (MinX <- m_RangeX, MaxX <- 0 etc.) + Exported to Lua in ManualBindings.cpp. */ + void GetNonAirCropRelCoords(int & a_MinRelX, int & a_MinRelY, int & a_MinRelZ, int & a_MaxRelX, int & a_MaxRelY, int & a_MaxRelZ, BLOCKTYPE a_IgnoreBlockType = E_BLOCK_AIR); // Clients can use these for faster access to all blocktypes. Be careful though! /** Returns the internal pointer to the block types */