// ManualBindings_World.cpp // Implements the manual Lua API bindings for the cWorld class #include "Globals.h" #include "tolua++/include/tolua++.h" #include "../World.h" #include "../Broadcaster.h" #include "ManualBindings.h" #include "LuaState.h" #include "PluginLua.h" #include "LuaChunkStay.h" static int tolua_cWorld_BroadcastParticleEffect(lua_State * tolua_S) { /* Function signature: World:BroadcastParticleEffect("Name", PosX, PosY, PosZ, OffX, OffY, OffZ, ParticleData, ParticleAmount, [ExcludeClient], [OptionalParam1], [OptionalParam2] */ cLuaState L(tolua_S); if ( !L.CheckParamUserType(1, "cWorld") || !L.CheckParamString (2) || !L.CheckParamNumber (3, 10) ) { return 0; } // Read the params: cWorld * World = nullptr; AString Name; float PosX, PosY, PosZ, OffX, OffY, OffZ; float ParticleData; int ParticleAmmount; cClientHandle * ExcludeClient = nullptr; L.GetStackValues(1, World, Name, PosX, PosY, PosZ, OffX, OffY, OffZ, ParticleData, ParticleAmmount, ExcludeClient); if (World == nullptr) { LOGWARNING("World:BroadcastParticleEffect(): invalid world parameter"); L.LogStackTrace(); return 0; } // Read up to 2 more optional data params: std::array data; for (int i = 0; (i < 2) && L.IsParamNumber(11 + i); i++) { L.GetStackValue(11 + i, data[i]); } World->GetBroadcaster().BroadcastParticleEffect(Name, Vector3f(PosX, PosY, PosZ), Vector3f(OffX, OffY, OffZ), ParticleData, ParticleAmmount, ExcludeClient); return 0; } static int tolua_cWorld_ChunkStay(lua_State * tolua_S) { /* Function signature: World:ChunkStay(ChunkCoordTable, OnChunkAvailable, OnAllChunksAvailable) ChunkCoordTable == { {Chunk1x, Chunk1z}, {Chunk2x, Chunk2z}, ... } */ cLuaState L(tolua_S); if ( !L.CheckParamUserType (1, "cWorld") || !L.CheckParamTable (2) || !L.CheckParamFunctionOrNil(3, 4) ) { return 0; } cPluginLua * Plugin = cManualBindings::GetLuaPlugin(tolua_S); if (Plugin == nullptr) { return 0; } // Read the params: cWorld * World = (cWorld *)tolua_tousertype(tolua_S, 1, nullptr); if (World == nullptr) { LOGWARNING("World:ChunkStay(): invalid world parameter"); L.LogStackTrace(); return 0; } cLuaChunkStay * ChunkStay = new cLuaChunkStay(*Plugin); if (!ChunkStay->AddChunks(2)) { delete ChunkStay; ChunkStay = nullptr; return 0; } ChunkStay->Enable(*World->GetChunkMap(), 3, 4); return 0; } static int tolua_cWorld_GetBlockInfo(lua_State * tolua_S) { // Exported manually, because tolua would generate useless additional parameters (a_BlockType .. a_BlockSkyLight) // Function signature: GetBlockInfo(BlockX, BlockY, BlockZ) -> BlockValid, [BlockType, BlockMeta, BlockSkyLight, BlockBlockLight] // Check params: cLuaState L(tolua_S); if ( !L.CheckParamUserType(1, "cWorld") || !L.CheckParamNumber(2, 4) || !L.CheckParamEnd(5) ) { return 0; } // Get params: cWorld * Self = nullptr; int BlockX, BlockY, BlockZ; L.GetStackValues(1, Self, BlockX, BlockY, BlockZ); if (Self == nullptr) { return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Invalid 'self'"); } // Call the function: BLOCKTYPE BlockType; NIBBLETYPE BlockMeta, BlockSkyLight, BlockBlockLight; bool res = Self->GetBlockInfo(BlockX, BlockY, BlockZ, BlockType, BlockMeta, BlockSkyLight, BlockBlockLight); // Push the returned values: L.Push(res); if (res) { L.Push(BlockType); L.Push(BlockMeta); L.Push(BlockSkyLight); L.Push(BlockBlockLight); return 5; } return 1; } static int tolua_cWorld_GetBlockTypeMeta(lua_State * tolua_S) { // Exported manually, because tolua would generate useless additional parameters (a_BlockType, a_BlockMeta) // Function signature: GetBlockTypeMeta(BlockX, BlockY, BlockZ) -> BlockValid, [BlockType, BlockMeta] // Check params: cLuaState L(tolua_S); if ( !L.CheckParamUserType(1, "cWorld") || !L.CheckParamNumber(2, 4) || !L.CheckParamEnd(5) ) { return 0; } // Get params: cWorld * Self = nullptr; int BlockX, BlockY, BlockZ; L.GetStackValues(1, Self, BlockX, BlockY, BlockZ); if (Self == nullptr) { return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Invalid 'self'"); } // Call the function: BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; bool res = Self->GetBlockTypeMeta(BlockX, BlockY, BlockZ, BlockType, BlockMeta); // Push the returned values: L.Push(res); if (res) { L.Push(BlockType); L.Push(BlockMeta); return 3; } return 1; } static int tolua_cWorld_GetSignLines(lua_State * tolua_S) { // Exported manually, because tolua would generate useless additional parameters (a_Line1 .. a_Line4) // Check params: cLuaState L(tolua_S); if ( !L.CheckParamUserType(1, "cWorld") || !L.CheckParamNumber(2, 4) || !L.CheckParamEnd(5) ) { return 0; } // Get params: cWorld * Self = nullptr; int BlockX, BlockY, BlockZ; L.GetStackValues(1, Self, BlockX, BlockY, BlockZ); if (Self == nullptr) { return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Invalid 'self'"); } // Call the function: AString Line1, Line2, Line3, Line4; bool res = Self->GetSignLines(BlockX, BlockY, BlockZ, Line1, Line2, Line3, Line4); // Push the returned values: L.Push(res); if (res) { L.Push(Line1); L.Push(Line2); L.Push(Line3); L.Push(Line4); return 5; } return 1; } static int tolua_cWorld_PrepareChunk(lua_State * tolua_S) { /* Function signature: World:PrepareChunk(ChunkX, ChunkZ, Callback) */ // Check the param types: cLuaState L(tolua_S); if ( !L.CheckParamUserType (1, "cWorld") || !L.CheckParamNumber (2, 3) || !L.CheckParamFunctionOrNil(4) ) { return 0; } // Read the params: cWorld * world = nullptr; int chunkX = 0, chunkZ = 0; L.GetStackValues(1, world, chunkX, chunkZ); if (world == nullptr) { LOGWARNING("World:PrepareChunk(): invalid world parameter"); L.LogStackTrace(); return 0; } // Wrap the Lua callback inside a C++ callback class: class cCallback: public cChunkCoordCallback { public: cCallback(lua_State * a_LuaState): m_LuaState(a_LuaState), m_Callback(m_LuaState, 4) { } // cChunkCoordCallback override: virtual void Call(int a_CBChunkX, int a_CBChunkZ) override { if (m_Callback.IsValid()) { m_LuaState.Call(m_Callback, a_CBChunkX, a_CBChunkZ); } // This is the last reference of this object, we must delete it so that it doesn't leak: delete this; } protected: cLuaState m_LuaState; cLuaState::cRef m_Callback; }; cCallback * callback = new cCallback(tolua_S); // Call the chunk preparation: world->PrepareChunk(chunkX, chunkZ, callback); return 0; } class cLuaWorldTask : public cWorld::cTask, public cPluginLua::cResettable { public: cLuaWorldTask(cPluginLua & a_Plugin, int a_FnRef) : cPluginLua::cResettable(a_Plugin), m_FnRef(a_FnRef) { } protected: int m_FnRef; // cWorld::cTask overrides: virtual void Run(cWorld & a_World) override { cCSLock Lock(m_CSPlugin); if (m_Plugin != nullptr) { m_Plugin->Call(m_FnRef, &a_World); } } } ; static int tolua_cWorld_QueueTask(lua_State * tolua_S) { // Binding for cWorld::QueueTask // Params: function // Retrieve the cPlugin from the LuaState: cPluginLua * Plugin = cManualBindings::GetLuaPlugin(tolua_S); if (Plugin == nullptr) { // An error message has been already printed in GetLuaPlugin() return 0; } // Retrieve the args: cWorld * self = (cWorld *)tolua_tousertype(tolua_S, 1, nullptr); if (self == nullptr) { return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Not called on an object instance"); } if (!lua_isfunction(tolua_S, 2)) { return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a function for parameter #1"); } // Create a reference to the function: int FnRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); if (FnRef == LUA_REFNIL) { return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #1"); } auto task = std::make_shared(*Plugin, FnRef); Plugin->AddResettable(task); self->QueueTask(task); return 0; } static int tolua_cWorld_SetSignLines(lua_State * tolua_S) { // Exported manually, because tolua would generate useless additional return values (a_Line1 .. a_Line4) // Check params: cLuaState L(tolua_S); if ( !L.CheckParamUserType(1, "cWorld") || !L.CheckParamNumber(2, 4) || !L.CheckParamString(5, 8) || !L.CheckParamEnd(9) ) { return 0; } // Get params: cWorld * Self = nullptr; int BlockX, BlockY, BlockZ; AString Line1, Line2, Line3, Line4; L.GetStackValues(1, Self, BlockX, BlockY, BlockZ, Line1, Line2, Line3, Line4); if (Self == nullptr) { return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Invalid 'self'"); } // Call the function: bool res = Self->SetSignLines(BlockX, BlockY, BlockZ, Line1, Line2, Line3, Line4); // Push the returned values: L.Push(res); return 1; } class cLuaScheduledWorldTask : public cWorld::cTask, public cPluginLua::cResettable { public: cLuaScheduledWorldTask(cPluginLua & a_Plugin, int a_FnRef) : cPluginLua::cResettable(a_Plugin), m_FnRef(a_FnRef) { } protected: int m_FnRef; // cWorld::cTask overrides: virtual void Run(cWorld & a_World) override { cCSLock Lock(m_CSPlugin); if (m_Plugin != nullptr) { m_Plugin->Call(m_FnRef, &a_World); } } }; static int tolua_cWorld_ScheduleTask(lua_State * tolua_S) { // Binding for cWorld::ScheduleTask // Params: function, Ticks // Retrieve the cPlugin from the LuaState: cPluginLua * Plugin = cManualBindings::GetLuaPlugin(tolua_S); if (Plugin == nullptr) { // An error message has been already printed in GetLuaPlugin() return 0; } // Retrieve the args: cLuaState L(tolua_S); if ( !L.CheckParamUserType(1, "cWorld") || !L.CheckParamNumber (2) || !L.CheckParamFunction(3) ) { return 0; } cWorld * World = (cWorld *)tolua_tousertype(tolua_S, 1, nullptr); if (World == nullptr) { return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Not called on an object instance"); } // Create a reference to the function: int FnRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); if (FnRef == LUA_REFNIL) { return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #1"); } int DelayTicks = (int)tolua_tonumber(tolua_S, 2, 0); auto task = std::make_shared(*Plugin, FnRef); Plugin->AddResettable(task); World->ScheduleTask(DelayTicks, task); return 0; } static int tolua_cWorld_TryGetHeight(lua_State * tolua_S) { /* Exported manually, because tolua would require the out-only param a_Height to be used when calling Function signature: world:TryGetHeight(a_World, a_BlockX, a_BlockZ) -> IsValid, Height */ // Check params: cLuaState L(tolua_S); if ( !L.CheckParamUserType(1, "cWorld") || !L.CheckParamNumber(2, 3) || !L.CheckParamEnd(4) ) { return 0; } // Get params: cWorld * self = nullptr; int BlockX, BlockZ; L.GetStackValues(1, self, BlockX, BlockZ); if (self == nullptr) { tolua_error(tolua_S, "Invalid 'self' in function 'TryGetHeight'", nullptr); return 0; } // Call the implementation: int Height = 0; bool res = self->TryGetHeight(BlockX, BlockZ, Height); L.Push(res ? 1 : 0); if (res) { L.Push(Height); return 2; } return 1; } void cManualBindings::BindWorld(lua_State * tolua_S) { tolua_beginmodule(tolua_S, nullptr); tolua_beginmodule(tolua_S, "cWorld"); tolua_function(tolua_S, "BroadcastParticleEffect", tolua_cWorld_BroadcastParticleEffect); tolua_function(tolua_S, "ChunkStay", tolua_cWorld_ChunkStay); tolua_function(tolua_S, "DoWithBlockEntityAt", DoWithXYZ); tolua_function(tolua_S, "DoWithBeaconAt", DoWithXYZ); tolua_function(tolua_S, "DoWithChestAt", DoWithXYZ); tolua_function(tolua_S, "DoWithDispenserAt", DoWithXYZ); tolua_function(tolua_S, "DoWithDropSpenserAt", DoWithXYZ); tolua_function(tolua_S, "DoWithDropperAt", DoWithXYZ); tolua_function(tolua_S, "DoWithEntityByID", DoWithID< cWorld, cEntity, &cWorld::DoWithEntityByID>); tolua_function(tolua_S, "DoWithFurnaceAt", DoWithXYZ); tolua_function(tolua_S, "DoWithNoteBlockAt", DoWithXYZ); tolua_function(tolua_S, "DoWithCommandBlockAt", DoWithXYZ); tolua_function(tolua_S, "DoWithMobHeadAt", DoWithXYZ); tolua_function(tolua_S, "DoWithFlowerPotAt", DoWithXYZ); tolua_function(tolua_S, "DoWithPlayer", DoWith< cWorld, cPlayer, &cWorld::DoWithPlayer>); tolua_function(tolua_S, "FindAndDoWithPlayer", DoWith< cWorld, cPlayer, &cWorld::FindAndDoWithPlayer>); tolua_function(tolua_S, "DoWithPlayerByUUID", DoWith< cWorld, cPlayer, &cWorld::DoWithPlayerByUUID>); tolua_function(tolua_S, "ForEachBlockEntityInChunk", ForEachInChunk); tolua_function(tolua_S, "ForEachChestInChunk", ForEachInChunk); tolua_function(tolua_S, "ForEachEntity", ForEach< cWorld, cEntity, &cWorld::ForEachEntity>); tolua_function(tolua_S, "ForEachEntityInBox", ForEachInBox< cWorld, cEntity, &cWorld::ForEachEntityInBox>); tolua_function(tolua_S, "ForEachEntityInChunk", ForEachInChunk); tolua_function(tolua_S, "ForEachFurnaceInChunk", ForEachInChunk); tolua_function(tolua_S, "ForEachPlayer", ForEach< cWorld, cPlayer, &cWorld::ForEachPlayer>); tolua_function(tolua_S, "GetBlockInfo", tolua_cWorld_GetBlockInfo); tolua_function(tolua_S, "GetBlockTypeMeta", tolua_cWorld_GetBlockTypeMeta); tolua_function(tolua_S, "GetSignLines", tolua_cWorld_GetSignLines); tolua_function(tolua_S, "PrepareChunk", tolua_cWorld_PrepareChunk); tolua_function(tolua_S, "QueueTask", tolua_cWorld_QueueTask); tolua_function(tolua_S, "ScheduleTask", tolua_cWorld_ScheduleTask); tolua_function(tolua_S, "SetSignLines", tolua_cWorld_SetSignLines); tolua_function(tolua_S, "TryGetHeight", tolua_cWorld_TryGetHeight); tolua_endmodule(tolua_S); tolua_endmodule(tolua_S); }