From fe4253834919d6c742c59c701d3d5ce8285f4504 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Sat, 24 Jun 2017 11:58:06 +0200 Subject: cBlockArea supports block entities. (#3795) --- src/Bindings/CMakeLists.txt | 1 + src/Bindings/LuaState.cpp | 24 + src/Bindings/LuaState.h | 4 + src/Bindings/ManualBindings.cpp | 373 ++--------- src/Bindings/ManualBindings.h | 96 ++- src/Bindings/ManualBindings_BlockArea.cpp | 998 ++++++++++++++++++++++++++++++ 6 files changed, 1158 insertions(+), 338 deletions(-) create mode 100644 src/Bindings/ManualBindings_BlockArea.cpp (limited to 'src/Bindings') diff --git a/src/Bindings/CMakeLists.txt b/src/Bindings/CMakeLists.txt index 2614ef9b2..747f22157 100644 --- a/src/Bindings/CMakeLists.txt +++ b/src/Bindings/CMakeLists.txt @@ -16,6 +16,7 @@ SET (SRCS LuaUDPEndpoint.cpp LuaWindow.cpp ManualBindings.cpp + ManualBindings_BlockArea.cpp ManualBindings_Network.cpp ManualBindings_RankManager.cpp ManualBindings_World.cpp diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp index 947e337fc..d18b6efcd 100644 --- a/src/Bindings/LuaState.cpp +++ b/src/Bindings/LuaState.cpp @@ -1762,6 +1762,30 @@ bool cLuaState::CheckParamEnd(int a_Param) +bool cLuaState::CheckParamSelf(const char * a_SelfClassName) +{ + tolua_Error tolua_err; + if (tolua_isusertype(m_LuaState, 1, a_SelfClassName, 0, &tolua_err) && !lua_isnil(m_LuaState, 1)) + { + return true; + } + + // Not the correct parameter + lua_Debug entry; + VERIFY(lua_getstack(m_LuaState, 0, &entry)); + VERIFY(lua_getinfo (m_LuaState, "n", &entry)); + AString ErrMsg = Printf( + "Error in function '%s'. The 'self' parameter is not of the expected type, \"instance of %s\". Make sure you're using the correct calling convention (obj:fn() instead of obj.fn()).", + (entry.name != nullptr) ? entry.name : "", a_SelfClassName + ); + tolua_error(m_LuaState, ErrMsg.c_str(), &tolua_err); + return false; +} + + + + + bool cLuaState::IsParamUserType(int a_Param, AString a_UserType) { ASSERT(IsValid()); diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h index 4320ce40e..674c7a240 100644 --- a/src/Bindings/LuaState.h +++ b/src/Bindings/LuaState.h @@ -788,6 +788,10 @@ public: /** Returns true if the specified parameter on the stack is nil (indicating an end-of-parameters) */ bool CheckParamEnd(int a_Param); + /** Returns true if the first parameter is an instance of the expected class name. + Returns false and logs a special warning ("wrong calling convention") if not. */ + bool CheckParamSelf(const char * a_SelfClassName); + bool IsParamUserType(int a_Param, AString a_UserType); bool IsParamNumber(int a_Param); diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index d8bd8b023..2c2de6296 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -31,7 +31,6 @@ #include "../BlockEntities/FlowerPotEntity.h" #include "../Generating/ChunkDesc.h" #include "../LineBlockTracer.h" -#include "../WorldStorage/SchematicFileSerializer.h" #include "../CompositeChat.h" #include "../StringCompression.h" #include "../CommandOutput.h" @@ -133,6 +132,46 @@ int cManualBindings::lua_do_error(lua_State * L, const char * a_pFormat, ...) +int cManualBindings::ApiParamError(lua_State * a_LuaState, const char * a_MsgFormat, ...) +{ + // Retrieve current function name + lua_Debug entry; + VERIFY(lua_getstack(a_LuaState, 0, &entry)); + VERIFY(lua_getinfo(a_LuaState, "n", &entry)); + + // Compose the error message: + va_list argp; + va_start(argp, a_MsgFormat); + AString msg; + + #ifdef __clang__ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wformat-nonliteral" + #endif + + AppendVPrintf(msg, a_MsgFormat, argp); + + #ifdef __clang__ + #pragma clang diagnostic pop + #endif + + va_end(argp); + AString errorMsg = Printf("%s: %s", (entry.name != nullptr) ? entry.name : "", msg.c_str()); + + // Log everything into the console: + LOGWARNING("%s", errorMsg.c_str()); + // cLuaState::LogStackTrace(a_LuaState); // Do NOT log stack trace, it is already output as part of the Lua error handling + cLuaState::LogStackValues(a_LuaState, "Parameters on the stack"); + + // Raise Lua error: + lua_pushstring(a_LuaState, errorMsg.c_str()); + return lua_error(a_LuaState); +} + + + + + // Lua bound functions with special return types static int tolua_Clamp(lua_State * tolua_S) { @@ -3199,324 +3238,6 @@ static int tolua_cHopperEntity_GetOutputBlockPos(lua_State * tolua_S) -static int tolua_cBlockArea_GetBlockTypeMeta(lua_State * tolua_S) -{ - // function cBlockArea::GetBlockTypeMeta() - // Exported manually because tolua generates extra input params for the outputs - - cLuaState L(tolua_S); - if ( - !L.CheckParamUserType(1, "cBlockArea") || - !L.CheckParamNumber (2, 4) - ) - { - return 0; - } - - cBlockArea * self = reinterpret_cast(tolua_tousertype(tolua_S, 1, nullptr)); - if (self == nullptr) - { - tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea:GetRelBlockTypeMeta'", nullptr); - return 0; - } - int BlockX = static_cast(tolua_tonumber(tolua_S, 2, 0)); - int BlockY = static_cast(tolua_tonumber(tolua_S, 3, 0)); - int BlockZ = static_cast(tolua_tonumber(tolua_S, 4, 0)); - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - self->GetBlockTypeMeta(BlockX, BlockY, BlockZ, BlockType, BlockMeta); - tolua_pushnumber(tolua_S, BlockType); - tolua_pushnumber(tolua_S, BlockMeta); - return 2; -} - - - - - -static int tolua_cBlockArea_GetOrigin(lua_State * tolua_S) -{ - // function cBlockArea::GetOrigin() - // Returns all three coords of the origin point - // Exported manually because there's no direct C++ equivalent, - // plus tolua would generate extra input params for the outputs - - cLuaState L(tolua_S); - if (!L.CheckParamUserType(1, "cBlockArea")) - { - return 0; - } - - cBlockArea * self = reinterpret_cast(tolua_tousertype(tolua_S, 1, nullptr)); - if (self == nullptr) - { - tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea:GetOrigin'", nullptr); - return 0; - } - - // Push the three origin coords: - lua_pushnumber(tolua_S, self->GetOriginX()); - lua_pushnumber(tolua_S, self->GetOriginY()); - lua_pushnumber(tolua_S, self->GetOriginZ()); - return 3; -} - - - - - -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, MinRelY, MinRelZ, MaxRelX, MaxRelY, MaxRelZ); - return 6; -} - - - - - -static int tolua_cBlockArea_GetRelBlockTypeMeta(lua_State * tolua_S) -{ - // function cBlockArea::GetRelBlockTypeMeta() - // Exported manually because tolua generates extra input params for the outputs - - cLuaState L(tolua_S); - if ( - !L.CheckParamUserType(1, "cBlockArea") || - !L.CheckParamNumber (2, 4) - ) - { - return 0; - } - - cBlockArea * self = reinterpret_cast(tolua_tousertype(tolua_S, 1, nullptr)); - if (self == nullptr) - { - tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea:GetRelBlockTypeMeta'", nullptr); - return 0; - } - int BlockX = static_cast(tolua_tonumber(tolua_S, 2, 0)); - int BlockY = static_cast(tolua_tonumber(tolua_S, 3, 0)); - int BlockZ = static_cast(tolua_tonumber(tolua_S, 4, 0)); - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - self->GetRelBlockTypeMeta(BlockX, BlockY, BlockZ, BlockType, BlockMeta); - tolua_pushnumber(tolua_S, BlockType); - tolua_pushnumber(tolua_S, BlockMeta); - return 2; -} - - - - - -static int tolua_cBlockArea_GetSize(lua_State * tolua_S) -{ - // function cBlockArea::GetSize() - // Returns all three sizes of the area - // Exported manually because there's no direct C++ equivalent, - // plus tolua would generate extra input params for the outputs - - cLuaState L(tolua_S); - if (!L.CheckParamUserType(1, "cBlockArea")) - { - return 0; - } - - cBlockArea * self = reinterpret_cast(tolua_tousertype(tolua_S, 1, nullptr)); - if (self == nullptr) - { - tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea:GetSize'", nullptr); - return 0; - } - - // Push the three origin coords: - lua_pushnumber(tolua_S, self->GetSizeX()); - lua_pushnumber(tolua_S, self->GetSizeY()); - lua_pushnumber(tolua_S, self->GetSizeZ()); - return 3; -} - - - - - -static int tolua_cBlockArea_GetCoordRange(lua_State * tolua_S) -{ - // function cBlockArea::GetCoordRange() - // Returns all three sizes of the area, miuns one, so that they represent the maximum coord value - // Exported manually because there's no direct C++ equivalent, - // plus tolua would generate extra input params for the outputs - - cLuaState L(tolua_S); - if (!L.CheckParamUserType(1, "cBlockArea")) - { - return 0; - } - - cBlockArea * self = reinterpret_cast(tolua_tousertype(tolua_S, 1, nullptr)); - if (self == nullptr) - { - tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea:GetSize'", nullptr); - return 0; - } - - // Push the three origin coords: - lua_pushnumber(tolua_S, self->GetSizeX() - 1); - lua_pushnumber(tolua_S, self->GetSizeY() - 1); - lua_pushnumber(tolua_S, self->GetSizeZ() - 1); - return 3; -} - - - - - -static int tolua_cBlockArea_LoadFromSchematicFile(lua_State * tolua_S) -{ - // function cBlockArea::LoadFromSchematicFile - // Exported manually because function has been moved to SchematicFileSerializer.cpp - cLuaState L(tolua_S); - if ( - !L.CheckParamUserType(1, "cBlockArea") || - !L.CheckParamString (2) || - !L.CheckParamEnd (3) - ) - { - return 0; - } - cBlockArea * self = reinterpret_cast(tolua_tousertype(tolua_S, 1, nullptr)); - if (self == nullptr) - { - tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea::LoadFromSchematicFile'", nullptr); - return 0; - } - - AString Filename = tolua_tostring(tolua_S, 2, 0); - bool res = cSchematicFileSerializer::LoadFromSchematicFile(*self, Filename); - tolua_pushboolean(tolua_S, res); - return 1; -} - - - - - -static int tolua_cBlockArea_LoadFromSchematicString(lua_State * tolua_S) -{ - // function cBlockArea::LoadFromSchematicString - // Exported manually because function has been moved to SchematicFileSerializer.cpp - cLuaState L(tolua_S); - if ( - !L.CheckParamUserType(1, "cBlockArea") || - !L.CheckParamString (2) || - !L.CheckParamEnd (3) - ) - { - return 0; - } - cBlockArea * self = reinterpret_cast(tolua_tousertype(tolua_S, 1, nullptr)); - if (self == nullptr) - { - tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea::LoadFromSchematicFile'", nullptr); - return 0; - } - - AString Data; - L.GetStackValue(2, Data); - bool res = cSchematicFileSerializer::LoadFromSchematicString(*self, Data); - tolua_pushboolean(tolua_S, res); - return 1; -} - - - - - -static int tolua_cBlockArea_SaveToSchematicFile(lua_State * tolua_S) -{ - // function cBlockArea::SaveToSchematicFile - // Exported manually because function has been moved to SchematicFileSerializer.cpp - cLuaState L(tolua_S); - if ( - !L.CheckParamUserType(1, "cBlockArea") || - !L.CheckParamString (2) || - !L.CheckParamEnd (3) - ) - { - return 0; - } - cBlockArea * self = reinterpret_cast(tolua_tousertype(tolua_S, 1, nullptr)); - if (self == nullptr) - { - tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea::SaveToSchematicFile'", nullptr); - return 0; - } - AString Filename = tolua_tostring(tolua_S, 2, 0); - bool res = cSchematicFileSerializer::SaveToSchematicFile(*self, Filename); - tolua_pushboolean(tolua_S, res); - return 1; -} - - - - - -static int tolua_cBlockArea_SaveToSchematicString(lua_State * tolua_S) -{ - // function cBlockArea::SaveToSchematicString - // Exported manually because function has been moved to SchematicFileSerializer.cpp - cLuaState L(tolua_S); - if ( - !L.CheckParamUserType(1, "cBlockArea") || - !L.CheckParamEnd (2) - ) - { - return 0; - } - cBlockArea * self = reinterpret_cast(tolua_tousertype(tolua_S, 1, nullptr)); - if (self == nullptr) - { - tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea::SaveToSchematicFile'", nullptr); - return 0; - } - - AString Data; - if (cSchematicFileSerializer::SaveToSchematicString(*self, Data)) - { - L.Push(Data); - return 1; - } - return 0; -} - - - - - static int tolua_cBoundingBox_CalcLineIntersection(lua_State * a_LuaState) { /* Function signatures: @@ -4031,19 +3752,6 @@ void cManualBindings::Bind(lua_State * tolua_S) tolua_function(tolua_S, "Base64Decode", tolua_Base64Decode); tolua_function(tolua_S, "md5", tolua_md5_obsolete); // OBSOLETE, use cCryptoHash.md5() instead - tolua_beginmodule(tolua_S, "cBlockArea"); - 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); - tolua_function(tolua_S, "LoadFromSchematicString", tolua_cBlockArea_LoadFromSchematicString); - tolua_function(tolua_S, "SaveToSchematicFile", tolua_cBlockArea_SaveToSchematicFile); - tolua_function(tolua_S, "SaveToSchematicString", tolua_cBlockArea_SaveToSchematicString); - tolua_endmodule(tolua_S); - tolua_beginmodule(tolua_S, "cBoundingBox"); tolua_function(tolua_S, "CalcLineIntersection", tolua_cBoundingBox_CalcLineIntersection); tolua_function(tolua_S, "Intersect", tolua_cBoundingBox_Intersect); @@ -4228,6 +3936,7 @@ void cManualBindings::Bind(lua_State * tolua_S) BindNetwork(tolua_S); BindRankManager(tolua_S); BindWorld(tolua_S); + BindBlockArea(tolua_S); tolua_endmodule(tolua_S); } diff --git a/src/Bindings/ManualBindings.h b/src/Bindings/ManualBindings.h index 98e3e88ef..889e33664 100644 --- a/src/Bindings/ManualBindings.h +++ b/src/Bindings/ManualBindings.h @@ -41,6 +41,10 @@ protected: Implemented in ManualBindings_World.cpp. */ static void BindWorld(lua_State * tolua_S); + /** Binds the manually implemented cBlockArea API functions to tlua_S. + Implemented in ManualBindings_BlockArea.cpp. */ + static void BindBlockArea(lua_State * tolua_S); + public: // Helper functions: @@ -48,6 +52,11 @@ public: static int tolua_do_error(lua_State * L, const char * a_pMsg, tolua_Error * a_pToLuaError); static int lua_do_error(lua_State * L, const char * a_pFormat, ...); + /** Formats and prints the message, prefixed with the current function name, then logs the stack contents and raises a Lua error. + To be used for bindings when they detect bad parameters. + Doesn't return, but a dummy return type is provided so that Lua API functions may do "return ApiParamError(...)". */ + static int ApiParamError(lua_State * a_LuaState, const char * a_MsgFormat, ...); + /** Binds the DoWith(ItemName) functions of regular classes. */ template < @@ -243,10 +252,11 @@ public: + /** Template for the bindings for the DoWithXYZAt(X, Y, Z) functions that don't need to check their coords. */ template < - class Ty1, - class Ty2, - bool (Ty1::*DoWithFn)(int, int, int, cItemCallback &) + class SELF, + class ITEM, + bool (SELF::*DoWithFn)(int, int, int, cItemCallback &) > static int DoWithXYZ(lua_State * tolua_S) { @@ -262,7 +272,7 @@ public: } // Get parameters: - Ty1 * Self = nullptr; + SELF * Self = nullptr; int BlockX = 0; int BlockY = 0; int BlockZ = 0; @@ -277,7 +287,7 @@ public: return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a valid callback function for parameter #5"); } - class cLuaCallback : public cItemCallback + class cLuaCallback : public cItemCallback { public: cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FnRef): @@ -287,7 +297,81 @@ public: } private: - virtual bool Item(Ty2 * a_Item) override + virtual bool Item(ITEM * a_Item) override + { + bool ret = false; + m_LuaState.Call(m_FnRef, a_Item, cLuaState::Return, ret); + return ret; + } + cLuaState & m_LuaState; + cLuaState::cRef & m_FnRef; + } Callback(L, FnRef); + + // Call the DoWith function: + bool res = (Self->*DoWithFn)(BlockX, BlockY, BlockZ, Callback); + + // Push the result as the return value: + L.Push(res); + return 1; + } + + + + + + /** Template for the bindings for the DoWithXYZAt(X, Y, Z) functions that need to check their coords. */ + template < + class SELF, + class ITEM, + bool (SELF::*DoWithFn)(int, int, int, cItemCallback &), + bool (SELF::*CoordCheckFn)(int, int, int) const + > + static int DoWithXYZ(lua_State * tolua_S) + { + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamNumber(2, 4) || + !L.CheckParamFunction(5) || + !L.CheckParamEnd(6) + ) + { + return 0; + } + + // Get parameters: + SELF * Self = nullptr; + int BlockX = 0; + int BlockY = 0; + int BlockZ = 0; + cLuaState::cRef FnRef; + L.GetStackValues(1, Self, BlockX, BlockY, BlockZ, FnRef); + if (Self == nullptr) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Invalid 'self'"); + } + if (!FnRef.IsValid()) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a valid callback function for parameter #5"); + } + if (!(Self->*CoordCheckFn)(BlockX, BlockY, BlockZ)) + { + return lua_do_error(tolua_S, Printf("Error in function call '#funcname#': The provided coordinates ({%d, %d, %d}) are not valid", + BlockX, BlockY, BlockZ + ).c_str()); + } + + class cLuaCallback : public cItemCallback + { + public: + cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FnRef): + m_LuaState(a_LuaState), + m_FnRef(a_FnRef) + { + } + + private: + virtual bool Item(ITEM * a_Item) override { bool ret = false; m_LuaState.Call(m_FnRef, a_Item, cLuaState::Return, ret); diff --git a/src/Bindings/ManualBindings_BlockArea.cpp b/src/Bindings/ManualBindings_BlockArea.cpp new file mode 100644 index 000000000..14462c6e9 --- /dev/null +++ b/src/Bindings/ManualBindings_BlockArea.cpp @@ -0,0 +1,998 @@ +// ManualBindings_BlockArea.cpp + +// Implements the manual bindings for functions in the cBlockArea class + +#include "Globals.h" +#include "tolua++/include/tolua++.h" +#include "../BlockArea.h" +#include "../World.h" +#include "ManualBindings.h" +#include "LuaState.h" +#include "PluginLua.h" +#include "../WorldStorage/SchematicFileSerializer.h" + + + + + + +/** Reads params that together form a Cuboid. +These can be: + - 6 numbers (MinX, MaxX, MinY, MaxY, MinZ, MaxZ) + - 2 Vector3-s (Min, Max) + - cCuboid +Returns the index of the first parameter following the Cuboid spec. +Raises an Api error if the params don't specify a Cuboid. +*/ +static int readCuboidOverloadParams(cLuaState & a_LuaState, int a_StartParam, cCuboid & a_Cuboid) +{ + if (a_LuaState.IsParamNumber(a_StartParam)) + { + // Assume the 6-number version: + if (!a_LuaState.GetStackValues(a_StartParam, a_Cuboid.p1.x, a_Cuboid.p2.x, a_Cuboid.p1.y, a_Cuboid.p2.y, a_Cuboid.p1.z, a_Cuboid.p2.z)) + { + return cManualBindings::ApiParamError(a_LuaState, "Cannot read the bounds parameters, expected 6 numbers."); + } + return a_StartParam + 6; + } + else if (a_LuaState.IsParamUserType(a_StartParam, "cCuboid")) + { + // Assume the cCuboid version: + cCuboid * c; + if (!a_LuaState.GetStackValues(a_StartParam, c)) + { + return cManualBindings::ApiParamError(a_LuaState, "Cannot read the bounds parameter, expected a cCuboid instance."); + } + a_Cuboid = *c; + return a_StartParam + 1; + } + else + { + // Assume the 2-Vector3i version: + Vector3i * p1; + Vector3i * p2; + if (!a_LuaState.GetStackValues(a_StartParam, p1, p2)) + { + return cManualBindings::ApiParamError(a_LuaState, "Cannot read the bounds parameter, expected two Vector3i instances."); + } + a_Cuboid.p1 = *p1; + a_Cuboid.p2 = *p2; + return a_StartParam + 2; + } +} + + + + + +/** Reads params that together form a Vector3i. +These can be: + - 3 numbers (x, y, z) + - Vector3i +Returns the index of the first parameter following the Vector3i spec. +Raises an Api error if the params don't specify a Vector3i. +*/ +static int readVector3iOverloadParams(cLuaState & a_LuaState, int a_StartParam, Vector3i & a_Coords, const char * a_ParamName) +{ + if (a_LuaState.IsParamNumber(a_StartParam)) + { + // Assume the 3-number version: + if (!a_LuaState.GetStackValues(a_StartParam, a_Coords.x, a_Coords.y, a_Coords.z)) + { + return cManualBindings::ApiParamError(a_LuaState, "Cannot read the %s, expected 3 numbers.", a_ParamName); + } + return a_StartParam + 3; + } + else + { + // Assume the Vector3i version: + Vector3i * c; + if (!a_LuaState.GetStackValues(a_StartParam, c)) + { + return cManualBindings::ApiParamError(a_LuaState, "Cannot read the %s, expected a Vector3i instance.", a_ParamName); + } + a_Coords = *c; + return a_StartParam + 1; + } +} + + + + + +/** Binding for the cBlockArea::Create() functions. Supports two overloads and one default parameter. */ +static int tolua_cBlockArea_Create(lua_State * a_LuaState) +{ + cLuaState L(a_LuaState); + if (!L.CheckParamSelf("cBlockArea")) + { + return 0; + } + cBlockArea * self = nullptr; + if (!L.GetStackValues(1, self)) + { + return cManualBindings::ApiParamError(a_LuaState, "Cannot read self."); + } + if (self == nullptr) + { + return cManualBindings::ApiParamError(a_LuaState, "Invalid 'self', must not be nil."); + } + + int dataTypes = cBlockArea::baTypes | cBlockArea::baMetas | cBlockArea::baBlockEntities; + Vector3i size; + auto dataTypesIdx = readVector3iOverloadParams(L, 2, size, "size"); + L.GetStackValue(dataTypesIdx, dataTypes); + if (!cBlockArea::IsValidDataTypeCombination(dataTypes)) + { + return cManualBindings::ApiParamError(a_LuaState, "Invalid combination of baDataTypes specified (%d).", dataTypes); + } + + // Create the area: + if ((size.x <= 0) || (size.y <= 0) || (size.z <= 0)) + { + return cManualBindings::ApiParamError(a_LuaState, "Invalid sizes, must be greater than zero, got {%d, %d, %d}", size.x, size.y, size.z); + } + ASSERT(self != nullptr); + self->Create(size, dataTypes); + return 0; +} + + + + + +/** Bindings for the cBlockArea:FillRelCuboid() functions. Supports coord overloads and one default parameter. */ +static int tolua_cBlockArea_FillRelCuboid(lua_State * a_LuaState) +{ + // Check the common params: + cLuaState L(a_LuaState); + if (!L.CheckParamSelf("cBlockArea")) + { + return 0; + } + + // Get the common params: + cBlockArea * self = nullptr; + if (!L.GetStackValues(1, self)) + { + return cManualBindings::ApiParamError(a_LuaState, "Cannot read self."); + } + if (self == nullptr) + { + return cManualBindings::ApiParamError(a_LuaState, "Invalid 'self', must not be nil."); + } + + // Check and get the overloaded params: + cCuboid bounds; + auto nextIdx = readCuboidOverloadParams(L, 2, bounds); + int dataTypes = cBlockArea::baTypes | cBlockArea::baMetas | cBlockArea::baBlockEntities; + BLOCKTYPE blockType; + NIBBLETYPE blockMeta = 0, blockLight = 0, blockSkyLight = 0x0f; + if (!L.GetStackValues(nextIdx, dataTypes, blockType)) + { + return cManualBindings::ApiParamError(a_LuaState, "Cannot read the datatypes or block type params"); + } + L.GetStackValues(nextIdx + 2, blockMeta, blockLight, blockSkyLight); // These values are optional + if (!cBlockArea::IsValidDataTypeCombination(dataTypes)) + { + return cManualBindings::ApiParamError(a_LuaState, "Invalid baDataTypes combination (%d).", dataTypes); + } + + // Check the coords, shift if needed: + bounds.Sort(); + bounds.ClampX(0, self->GetSizeX()); + bounds.ClampY(0, self->GetSizeY()); + bounds.ClampZ(0, self->GetSizeZ()); + + // Do the actual Fill: + self->FillRelCuboid(bounds, dataTypes, blockType, blockMeta, blockLight, blockSkyLight); + return 0; +} + + + + + +static int tolua_cBlockArea_GetBlockTypeMeta(lua_State * a_LuaState) +{ + // function cBlockArea::GetBlockTypeMeta() + + cLuaState L(a_LuaState); + if (!L.CheckParamSelf("cBlockArea")) + { + return 0; + } + + cBlockArea * self; + if (!L.GetStackValues(1, self)) + { + return cManualBindings::ApiParamError(a_LuaState, "Cannot read 'self'"); + } + if (self == nullptr) + { + return cManualBindings::ApiParamError(a_LuaState, "Invalid 'self', must not be nil."); + } + + Vector3i coords; + readVector3iOverloadParams(L, 2, coords, "coords"); + if (!self->IsValidCoords(coords)) + { + return cManualBindings::ApiParamError(a_LuaState, "Coords ({%d, %d, %d}) out of range ({%d, %d, %d} - {%d, %d, %d}).", + coords.x, coords.y, coords.z, + self->GetOriginX(), self->GetOriginY(), self->GetOriginZ(), + self->GetOriginX() + self->GetSizeX() - 1, self->GetOriginY() + self->GetSizeY() - 1, self->GetOriginZ() + self->GetSizeZ() - 1 + ); + } + BLOCKTYPE blockType; + NIBBLETYPE blockMeta; + self->GetBlockTypeMeta(coords.x, coords.y, coords.z, blockType, blockMeta); + L.Push(blockType, blockMeta); + return 2; +} + + + + + +static int tolua_cBlockArea_GetCoordRange(lua_State * a_LuaState) +{ + // function cBlockArea::GetCoordRange() + // Returns all three sizes of the area, each minus one, so that they represent the maximum coord value + // Exported manually because there's no direct C++ equivalent, + // plus tolua would generate extra input params for the outputs + + cLuaState L(a_LuaState); + if (!L.CheckParamSelf("cBlockArea")) + { + return 0; + } + + cBlockArea * self; + if (!L.GetStackValues(1, self)) + { + return cManualBindings::ApiParamError(a_LuaState, "Cannot read the 'self' parameter."); + } + if (self == nullptr) + { + return cManualBindings::ApiParamError(a_LuaState, "Invalid 'self', must not be nil."); + } + + L.Push(self->GetSizeX() - 1, self->GetSizeY() - 1, self->GetSizeZ() - 1); + return 3; +} + + + + + +static int tolua_cBlockArea_GetNonAirCropRelCoords(lua_State * a_LuaState) +{ + // function cBlockArea::GetNonAirCropRelCoords() + // Exported manually because tolua would generate extra input params for the outputs + + cLuaState L(a_LuaState); + if (!L.CheckParamSelf("cBlockArea")) + { + return 0; + } + + cBlockArea * self = nullptr; + BLOCKTYPE ignoreBlockType = E_BLOCK_AIR; + if (!L.GetStackValues(1, self, ignoreBlockType)) + { + return cManualBindings::ApiParamError(a_LuaState, "Cannot read params"); + } + if (self == nullptr) + { + return cManualBindings::ApiParamError(a_LuaState, "Invalid 'self', must not be nil"); + } + if (!self->HasBlockTypes()) + { + return cManualBindings::ApiParamError(a_LuaState, "The area doesn't contain baTypes datatype"); + } + + // 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, minRelY, minRelZ, maxRelX, maxRelY, maxRelZ); + return 6; +} + + + + + +static int tolua_cBlockArea_GetOrigin(lua_State * a_LuaState) +{ + // function cBlockArea::GetOrigin() + // Returns all three coords of the origin point + // Exported manually because there's no direct C++ equivalent, + // plus tolua would generate extra input params for the outputs + + cLuaState L(a_LuaState); + if (!L.CheckParamSelf("cBlockArea")) + { + return 0; + } + + cBlockArea * self; + if (!L.GetStackValues(1, self)) + { + return cManualBindings::ApiParamError(a_LuaState, "Cannot read the 'self' parameter."); + } + if (self == nullptr) + { + return cManualBindings::ApiParamError(a_LuaState, "Invalid 'self', must not be nil."); + } + + // Push the three origin coords: + L.Push(self->GetOriginX(), self->GetOriginY(), self->GetOriginZ()); + return 3; +} + + + + + +static int tolua_cBlockArea_GetRelBlockTypeMeta(lua_State * a_LuaState) +{ + // function cBlockArea::GetRelBlockTypeMeta() + // Exported manually because tolua generates extra input params for the outputs + + cLuaState L(a_LuaState); + if (!L.CheckParamSelf("cBlockArea")) + { + return 0; + } + + cBlockArea * self; + if (!L.GetStackValues(1, self)) + { + return cManualBindings::ApiParamError(a_LuaState, "Cannot read the 'self' parameter."); + } + if (self == nullptr) + { + return cManualBindings::ApiParamError(a_LuaState, "Invalid 'self', must not be nil."); + } + if (!self->HasBlockTypes()) + { + return cManualBindings::ApiParamError(a_LuaState, "The area doesn't contain baTypes datatype"); + } + if (!self->HasBlockMetas()) + { + return cManualBindings::ApiParamError(a_LuaState, "The area doesn't contain baMetas datatype"); + } + + Vector3i coords; + readVector3iOverloadParams(L, 2, coords, "coords"); + if (!self->IsValidRelCoords(coords)) + { + return cManualBindings::ApiParamError(a_LuaState, "The coords ({%d, %d, %d}) are out of range (max {%d, %d, %d}).", + coords.x, coords.y, coords.z, + self->GetSizeX() - 1, self->GetSizeY() - 1, self->GetSizeZ() - 1 + ); + } + BLOCKTYPE blockType; + NIBBLETYPE blockMeta; + self->GetRelBlockTypeMeta(coords.x, coords.y, coords.z, blockType, blockMeta); + L.Push(blockType, blockMeta); + return 2; +} + + + + + +static int tolua_cBlockArea_GetSize(lua_State * a_LuaState) +{ + // function cBlockArea::GetSize() + // Returns all three sizes of the area + // Exported manually because there's no direct C++ equivalent, + // plus tolua would generate extra input params for the outputs + + cLuaState L(a_LuaState); + if (!L.CheckParamSelf("cBlockArea")) + { + return 0; + } + + cBlockArea * self; + if (!L.GetStackValues(1, self)) + { + return cManualBindings::ApiParamError(a_LuaState, "Cannot read the 'self' parameter."); + } + if (self == nullptr) + { + return cManualBindings::ApiParamError(a_LuaState, "Invalid 'self', must not be nil."); + } + + L.Push(self->GetSizeX(), self->GetSizeY(), self->GetSizeZ()); + return 3; +} + + + + + +static int tolua_cBlockArea_LoadFromSchematicFile(lua_State * a_LuaState) +{ + // function cBlockArea::LoadFromSchematicFile + // Exported manually because function has been moved to SchematicFileSerializer.cpp + cLuaState L(a_LuaState); + if ( + !L.CheckParamSelf("cBlockArea") || + !L.CheckParamString(2) || + !L.CheckParamEnd(3) + ) + { + return 0; + } + cBlockArea * self; + AString fileName; + if (!L.GetStackValues(1, self, fileName)) + { + return cManualBindings::ApiParamError(a_LuaState, "Cannot read the parameters."); + } + if (self == nullptr) + { + return cManualBindings::ApiParamError(a_LuaState, "Invalid 'self', must not be nil."); + } + + L.Push(cSchematicFileSerializer::LoadFromSchematicFile(*self, fileName)); + return 1; +} + + + + + +static int tolua_cBlockArea_LoadFromSchematicString(lua_State * a_LuaState) +{ + // function cBlockArea::LoadFromSchematicString + // Exported manually because function has been moved to SchematicFileSerializer.cpp + cLuaState L(a_LuaState); + if ( + !L.CheckParamSelf("cBlockArea") || + !L.CheckParamString(2) || + !L.CheckParamEnd(3) + ) + { + return 0; + } + cBlockArea * self; + AString data; + if (!L.GetStackValues(1, self, data)) + { + return cManualBindings::ApiParamError(a_LuaState, "Cannot read the parameters."); + } + if (self == nullptr) + { + return cManualBindings::ApiParamError(a_LuaState, "Invalid 'self', must not be nil."); + } + + L.Push(cSchematicFileSerializer::LoadFromSchematicString(*self, data)); + return 1; +} + + + + + +/** Bindings for the cBlockArea:Read() functions. Supports three overloads and one default parameter. */ +static int tolua_cBlockArea_Read(lua_State * a_LuaState) +{ + // Check the common params: + cLuaState L(a_LuaState); + if ( + !L.CheckParamSelf("cBlockArea") || + !L.CheckParamUserType(2, "cWorld") + ) + { + return 0; + } + + // Get the common params: + cBlockArea * self = nullptr; + cWorld * world = nullptr; + if (!L.GetStackValues(1, self, world)) + { + return cManualBindings::ApiParamError(a_LuaState, "Cannot read self or world."); + } + if (world == nullptr) + { + return cManualBindings::ApiParamError(a_LuaState, "Invalid world instance. The world must be not nil."); + } + + // Check and get the overloaded params: + cCuboid bounds; + int dataTypes = cBlockArea::baTypes | cBlockArea::baMetas | cBlockArea::baBlockEntities; + auto dataTypesIdx = readCuboidOverloadParams(L, 3, bounds); + L.GetStackValues(dataTypesIdx, dataTypes); + if (!cBlockArea::IsValidDataTypeCombination(dataTypes)) + { + return cManualBindings::ApiParamError(a_LuaState, "Invalid baDataTypes combination (%d).", dataTypes); + } + + // Check the coords, shift if needed: + bounds.Sort(); + if (bounds.p1.y < 0) + { + LOGWARNING("cBlockArea:Read(): MinBlockY less than zero, adjusting to zero. Coords: {%d, %d, %d} - {%d, %d, %d}", + bounds.p1.x, bounds.p1.y, bounds.p1.z, bounds.p2.x, bounds.p2.y, bounds.p2.z + ); + L.LogStackTrace(); + bounds.p1.y = 0; + } + else if (bounds.p1.y >= cChunkDef::Height) + { + LOGWARNING("cBlockArea:Read(): MinBlockY more than chunk height, adjusting to chunk height. Coords: {%d, %d, %d} - {%d, %d, %d}", + bounds.p1.x, bounds.p1.y, bounds.p1.z, bounds.p2.x, bounds.p2.y, bounds.p2.z + ); + L.LogStackTrace(); + bounds.p1.y = cChunkDef::Height - 1; + } + if (bounds.p2.y < 0) + { + LOGWARNING("cBlockArea:Read(): MaxBlockY less than zero, adjusting to zero. Coords: {%d, %d, %d} - {%d, %d, %d}", + bounds.p1.x, bounds.p1.y, bounds.p1.z, bounds.p2.x, bounds.p2.y, bounds.p2.z + ); + L.LogStackTrace(); + bounds.p2.y = 0; + } + else if (bounds.p2.y > cChunkDef::Height) + { + LOGWARNING("cBlockArea:Read(): MaxBlockY more than chunk height, adjusting to chunk height. Coords: {%d, %d, %d} - {%d, %d, %d}", + bounds.p1.x, bounds.p1.y, bounds.p1.z, bounds.p2.x, bounds.p2.y, bounds.p2.z + ); + L.LogStackTrace(); + bounds.p2.y = cChunkDef::Height; + } + + // Do the actual read: + L.Push(self->Read(*world, bounds, dataTypes)); + return 1; +} + + + + + +/** Bindings for the cBlockArea:RelLine() functions. Supports two overloads and one default parameter. +Also supports "bastard overloads" (Vector3i, x, y, z), but we don't advertise those. */ +static int tolua_cBlockArea_RelLine(lua_State * a_LuaState) +{ + // Check the common params: + cLuaState L(a_LuaState); + if (!L.CheckParamSelf("cBlockArea")) + { + return 0; + } + + // Get the common params: + cBlockArea * self = nullptr; + if (!L.GetStackValues(1, self)) + { + return cManualBindings::ApiParamError(a_LuaState, "Cannot read self."); + } + + // Check and get the overloaded params: + Vector3i p1; + auto idx = readVector3iOverloadParams(L, 2, p1, "start coords"); + Vector3i p2; + idx = readVector3iOverloadParams(L, idx, p2, "end coords"); + int dataTypes = cBlockArea::baTypes | cBlockArea::baMetas | cBlockArea::baBlockEntities; + BLOCKTYPE blockType; + NIBBLETYPE blockMeta, blockLight, blockSkyLight; + L.GetStackValues(idx, dataTypes, blockType, blockMeta, blockLight, blockSkyLight); + if (!cBlockArea::IsValidDataTypeCombination(dataTypes)) + { + return cManualBindings::ApiParamError(a_LuaState, "Invalid baDataTypes combination (%d).", dataTypes); + } + + // Draw the line: + self->RelLine(p1, p2, dataTypes, blockType, blockMeta, blockLight, blockSkyLight); + return 0; +} + + + + + +static int tolua_cBlockArea_SaveToSchematicFile(lua_State * a_LuaState) +{ + // function cBlockArea::SaveToSchematicFile + // Exported manually because function has been moved to SchematicFileSerializer.cpp + cLuaState L(a_LuaState); + if ( + !L.CheckParamSelf("cBlockArea") || + !L.CheckParamString(2) || + !L.CheckParamEnd(3) + ) + { + return 0; + } + cBlockArea * self; + AString fileName; + if (!L.GetStackValues(1, self, fileName)) + { + return cManualBindings::ApiParamError(a_LuaState, "Cannot read the parameters."); + } + if (self == nullptr) + { + return cManualBindings::ApiParamError(a_LuaState, "Invalid 'self', must not be nil."); + } + + L.Push(cSchematicFileSerializer::SaveToSchematicFile(*self, fileName)); + return 1; +} + + + + + +static int tolua_cBlockArea_SaveToSchematicString(lua_State * a_LuaState) +{ + // function cBlockArea::SaveToSchematicString + // Exported manually because function has been moved to SchematicFileSerializer.cpp + cLuaState L(a_LuaState); + if ( + !L.CheckParamSelf("cBlockArea") || + !L.CheckParamEnd(2) + ) + { + return 0; + } + cBlockArea * self; + if (!L.GetStackValues(1, self)) + { + return cManualBindings::ApiParamError(a_LuaState, "Cannot read the 'self' parameter."); + } + if (self == nullptr) + { + return cManualBindings::ApiParamError(a_LuaState, "Invalid 'self', must not be nil."); + } + + AString data; + if (cSchematicFileSerializer::SaveToSchematicString(*self, data)) + { + L.Push(data); + return 1; + } + return 0; +} + + + + + +/** Bindings for the cBlockArea:Write() functions. Supports two overloads and one default parameter. */ +static int tolua_cBlockArea_Write(lua_State * a_LuaState) +{ + // Check the common params: + cLuaState L(a_LuaState); + if ( + !L.CheckParamSelf("cBlockArea") || + !L.CheckParamUserType(2, "cWorld") + ) + { + return 0; + } + + // Get the common params: + cBlockArea * self = nullptr; + cWorld * world = nullptr; + if (!L.GetStackValues(1, self, world)) + { + return cManualBindings::ApiParamError(a_LuaState, "Cannot read self or world."); + } + if (world == nullptr) + { + return cManualBindings::ApiParamError(a_LuaState, "Invalid world instance. The world must be not nil."); + } + + // Check and get the overloaded params: + Vector3i coords; + int dataTypes = cBlockArea::baTypes | cBlockArea::baMetas | cBlockArea::baBlockEntities; + auto dataTypesIdx = readVector3iOverloadParams(L, 3, coords, "coords"); + L.GetStackValues(dataTypesIdx, dataTypes); + + // Check the dataType parameter validity: + if (!cBlockArea::IsValidDataTypeCombination(dataTypes)) + { + return cManualBindings::ApiParamError(a_LuaState, "Invalid datatype combination (%d).", dataTypes); + } + if ((self->GetDataTypes() & dataTypes) != dataTypes) + { + return cManualBindings::ApiParamError(a_LuaState, "Requesting datatypes not present in the cBlockArea. Got only 0x%02x, requested 0x%02x", + self->GetDataTypes(), dataTypes + ); + } + + // Check and adjust the coord params: + // TODO: Should we report this as a failure? Because the result is definitely not what the plugin assumed + // ... Or should we silently clone-crop-write the cBlockArea so that the API call does what would be naturally expected? + // ... Or should we change the cBlockArea::Write() to allow out-of-range Y coords and do the cropping there? + // ... NOTE: We already support auto-crop in cBlockArea::Merge() itself + if (coords.y < 0) + { + LOGWARNING("cBlockArea:Write(): MinBlockY less than zero, adjusting to zero"); + L.LogStackTrace(); + coords.y = 0; + } + else if (coords.y > cChunkDef::Height - self->GetSizeY()) + { + LOGWARNING("cBlockArea:Write(): MinBlockY + m_SizeY more than chunk height, adjusting to chunk height"); + L.LogStackTrace(); + coords.y = cChunkDef::Height - self->GetSizeY(); + } + + // Do the actual write: + L.Push(self->Write(*world, coords, dataTypes)); + return 1; +} + + + + + +/** Templated bindings for the GetBlock___() functions. +DataType is either BLOCKTYPE or NIBBLETYPE. +DataTypeFlag is the ba___ constant used for the datatype being queried. +Fn is the getter function. +Also supports the Vector3i overloads (TODO: document these (?)). */ +template < + typename DataType, + int DataTypeFlag, + DataType (cBlockArea::*Fn)(int, int, int) const +> +static int GetBlock(lua_State * a_LuaState) +{ + // Check the common params: + cLuaState L(a_LuaState); + if (!L.CheckParamSelf("cBlockArea")) + { + return 0; + } + + // Read the common params: + cBlockArea * self; + if (!L.GetStackValues(1, self)) + { + return cManualBindings::ApiParamError(a_LuaState, "Cannot read the 'self' param."); + } + + // Check the datatype's presence: + if ((self->GetDataTypes() & DataTypeFlag) == 0) + { + return cManualBindings::ApiParamError(a_LuaState, "The area doesn't contain the datatype (%d).", DataTypeFlag); + } + + // Read the overloaded params: + Vector3i coords; + readVector3iOverloadParams(L, 2, coords, "coords"); + if (!self->IsValidCoords(coords)) + { + return cManualBindings::ApiParamError(a_LuaState, "The coords ({%d, %d, %d}) are out of range ({%d, %d, %d} - {%d, %d, %d}).", + coords.x, coords.y, coords.z, + self->GetOriginX(), self->GetOriginY(), self->GetOriginZ(), + self->GetOriginX() + self->GetSizeX() - 1, self->GetOriginY() + self->GetSizeY() - 1, self->GetOriginZ() + self->GetSizeZ() - 1 + ); + } + + // Get the block info: + L.Push((self->*Fn)(coords.x, coords.y, coords.z)); + return 1; +} + + + + + +/** Templated bindings for the GetRelBlock___() functions. +DataType is either BLOCKTYPE or NIBBLETYPE. +DataTypeFlag is the ba___ constant used for the datatype being queried. +Fn is the getter function. +Also supports the Vector3i overloads (TODO: document these (?)). */ +template < + typename DataType, + int DataTypeFlag, + DataType (cBlockArea::*Fn)(int, int, int) const +> +static int GetRelBlock(lua_State * a_LuaState) +{ + // Check the common params: + cLuaState L(a_LuaState); + if (!L.CheckParamSelf("cBlockArea")) + { + return 0; + } + + // Read the common params: + cBlockArea * self; + if (!L.GetStackValues(1, self)) + { + return cManualBindings::ApiParamError(a_LuaState, "Cannot read the 'self' param."); + } + + // Check the datatype's presence: + if ((self->GetDataTypes() & DataTypeFlag) == 0) + { + return cManualBindings::ApiParamError(a_LuaState, "The area doesn't contain the datatype (%d).", DataTypeFlag); + } + + // Read the overloaded params: + Vector3i coords; + readVector3iOverloadParams(L, 2, coords, "coords"); + if (!self->IsValidRelCoords(coords)) + { + return cManualBindings::ApiParamError(a_LuaState, "The coords ({%d, %d, %d}) are out of range ({%d, %d, %d}).", + coords.x, coords.y, coords.z, + self->GetSizeX(), self->GetSizeY(), self->GetSizeZ() + ); + } + + // Get the block info: + L.Push((self->*Fn)(coords.x, coords.y, coords.z)); + return 0; +} + + + + + +/** Templated bindings for the SetBlock___() functions. +DataType is either BLOCKTYPE or NIBBLETYPE. +DataTypeFlag is the ba___ constant used for the datatypebeing manipulated. +Fn is the setter function. +Also supports the Vector3i overloads (TODO: document these (?)). */ +template < + typename DataType, + int DataTypeFlag, + void (cBlockArea::*Fn)(int, int, int, DataType) +> +static int SetBlock(lua_State * a_LuaState) +{ + // Check the common params: + cLuaState L(a_LuaState); + if (!L.CheckParamSelf("cBlockArea")) + { + return 0; + } + + // Read the common params: + cBlockArea * self; + if (!L.GetStackValues(1, self)) + { + return cManualBindings::ApiParamError(a_LuaState, "Cannot read the 'self' param."); + } + + // Check the datatype's presence: + if ((self->GetDataTypes() & DataTypeFlag) == 0) + { + return cManualBindings::ApiParamError(a_LuaState, "The area doesn't contain the datatype (%d).", DataTypeFlag); + } + + // Read the overloaded params: + Vector3i coords; + auto idx = readVector3iOverloadParams(L, 2, coords, "coords"); + if (!self->IsValidCoords(coords)) + { + return cManualBindings::ApiParamError(a_LuaState, "The coords ({%d, %d, %d}) are out of range ({%d, %d, %d} - {%d, %d, %d}).", + coords.x, coords.y, coords.z, + self->GetOriginX(), self->GetOriginY(), self->GetOriginZ(), + self->GetOriginX() + self->GetSizeX() - 1, self->GetOriginY() + self->GetSizeY() - 1, self->GetOriginZ() + self->GetSizeZ() - 1 + ); + } + DataType data; + L.GetStackValues(idx, data); + + // Set the block info: + (self->*Fn)(coords.x, coords.y, coords.z, data); + return 0; +} + + + + + +/** Templated bindings for the SetRelBlock___() functions. +DataType is either BLOCKTYPE or NIBBLETYPE. +DataTypeFlag is the ba___ constant used for the datatypebeing manipulated. +Fn is the setter function. +Also supports the Vector3i overloads (TODO: document these (?)). */ +template < + typename DataType, + int DataTypeFlag, + void (cBlockArea::*Fn)(int, int, int, DataType) +> +static int SetRelBlock(lua_State * a_LuaState) +{ + // Check the common params: + cLuaState L(a_LuaState); + if (!L.CheckParamSelf("cBlockArea")) + { + return 0; + } + + // Read the common params: + cBlockArea * self; + if (!L.GetStackValues(1, self)) + { + return cManualBindings::ApiParamError(a_LuaState, "Cannot read the 'self' param."); + } + + // Check the datatype's presence: + if ((self->GetDataTypes() & DataTypeFlag) == 0) + { + return cManualBindings::ApiParamError(a_LuaState, "The area doesn't contain the datatype (%d).", DataTypeFlag); + } + + // Read the overloaded params: + Vector3i coords; + auto idx = readVector3iOverloadParams(L, 2, coords, "coords"); + if (!self->IsValidRelCoords(coords)) + { + return cManualBindings::ApiParamError(a_LuaState, "The coords ({%d, %d, %d}) are out of range ({%d, %d, %d}).", + coords.x, coords.y, coords.z, + self->GetSizeX(), self->GetSizeY(), self->GetSizeZ() + ); + } + DataType data; + L.GetStackValues(idx, data); + + // Set the block info: + (self->*Fn)(coords.x, coords.y, coords.z, data); + return 0; +} + + + + + +void cManualBindings::BindBlockArea(lua_State * a_LuaState) +{ + tolua_beginmodule(a_LuaState, nullptr); + tolua_beginmodule(a_LuaState, "cBlockArea"); + tolua_function(a_LuaState, "Create", tolua_cBlockArea_Create); + tolua_function(a_LuaState, "DoWithBlockEntityAt", DoWithXYZ); + tolua_function(a_LuaState, "DoWithBlockEntityRelAt", DoWithXYZ); + tolua_function(a_LuaState, "FillRelCuboid", tolua_cBlockArea_FillRelCuboid); + tolua_function(a_LuaState, "ForEachBlockEntity", ForEach< cBlockArea, cBlockEntity, &cBlockArea::ForEachBlockEntity>); + tolua_function(a_LuaState, "GetBlockLight", GetBlock); + tolua_function(a_LuaState, "GetBlockMeta", GetBlock); + tolua_function(a_LuaState, "GetBlockSkyLight", GetBlock); + tolua_function(a_LuaState, "GetBlockType", GetBlock); + tolua_function(a_LuaState, "GetBlockTypeMeta", tolua_cBlockArea_GetBlockTypeMeta); + tolua_function(a_LuaState, "GetCoordRange", tolua_cBlockArea_GetCoordRange); + tolua_function(a_LuaState, "GetNonAirCropRelCoords", tolua_cBlockArea_GetNonAirCropRelCoords); + tolua_function(a_LuaState, "GetOrigin", tolua_cBlockArea_GetOrigin); + tolua_function(a_LuaState, "GetRelBlockLight", GetRelBlock); + tolua_function(a_LuaState, "GetRelBlockMeta", GetRelBlock); + tolua_function(a_LuaState, "GetRelBlockSkyLight", GetRelBlock); + tolua_function(a_LuaState, "GetRelBlockType", GetRelBlock); + tolua_function(a_LuaState, "GetRelBlockTypeMeta", tolua_cBlockArea_GetRelBlockTypeMeta); + tolua_function(a_LuaState, "GetSize", tolua_cBlockArea_GetSize); + tolua_function(a_LuaState, "LoadFromSchematicFile", tolua_cBlockArea_LoadFromSchematicFile); + tolua_function(a_LuaState, "LoadFromSchematicString", tolua_cBlockArea_LoadFromSchematicString); + tolua_function(a_LuaState, "Read", tolua_cBlockArea_Read); + tolua_function(a_LuaState, "RelLine", tolua_cBlockArea_RelLine); + tolua_function(a_LuaState, "SaveToSchematicFile", tolua_cBlockArea_SaveToSchematicFile); + tolua_function(a_LuaState, "SaveToSchematicString", tolua_cBlockArea_SaveToSchematicString); + tolua_function(a_LuaState, "SetBlockType", SetBlock); + tolua_function(a_LuaState, "SetBlockMeta", SetBlock); + tolua_function(a_LuaState, "SetBlockLight", SetBlock); + tolua_function(a_LuaState, "SetBlockSkyLight", SetBlock); + tolua_function(a_LuaState, "SetRelBlockType", SetRelBlock); + tolua_function(a_LuaState, "SetRelBlockMeta", SetRelBlock); + tolua_function(a_LuaState, "SetRelBlockLight", SetRelBlock); + tolua_function(a_LuaState, "SetRelBlockSkyLight", SetRelBlock); + tolua_function(a_LuaState, "Write", tolua_cBlockArea_Write); + tolua_endmodule(a_LuaState); + tolua_endmodule(a_LuaState); +} + + + + -- cgit v1.2.3