From 086c8b1834bfca6a4af912abbd13fd570f7b0b33 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Wed, 16 Dec 2015 15:04:47 +0100 Subject: Revised the explosion-related Lua API and docs. Fixes #2746. --- src/Bindings/LuaState.cpp | 66 +++++++------- src/Bindings/LuaState.h | 4 +- src/Bindings/ManualBindings_World.cpp | 162 +++++++++++++++++++++++++++------- src/Bindings/PluginLua.cpp | 48 +++++----- 4 files changed, 192 insertions(+), 88 deletions(-) (limited to 'src/Bindings') diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp index f5b2cac4a..953b6f17b 100644 --- a/src/Bindings/LuaState.cpp +++ b/src/Bindings/LuaState.cpp @@ -807,25 +807,6 @@ void cLuaState::Push(UInt32 a_Value) -void cLuaState::Push(void * a_Ptr) -{ - UNUSED(a_Ptr); - ASSERT(IsValid()); - - // Investigate the cause of this - what is the callstack? - // One code path leading here is the OnHookExploding / OnHookExploded with exotic parameters. Need to decide what to do with them - LOGWARNING("Lua engine: attempting to push a plain pointer, pushing nil instead."); - LOGWARNING("This indicates an unimplemented part of MCS bindings"); - LogStackTrace(); - - lua_pushnil(m_LuaState); - m_NumCurrentFunctionArgs += 1; -} - - - - - void cLuaState::Push(std::chrono::milliseconds a_Value) { ASSERT(IsValid()); @@ -838,20 +819,6 @@ void cLuaState::Push(std::chrono::milliseconds a_Value) -/* -void cLuaState::PushUserType(void * a_Object, const char * a_Type) -{ - ASSERT(IsValid()); - - tolua_pushusertype(m_LuaState, a_Object, a_Type); - m_NumCurrentFunctionArgs += 1; -} -*/ - - - - - bool cLuaState::GetStackValue(int a_StackPos, AString & a_Value) { size_t len = 0; @@ -1197,6 +1164,39 @@ bool cLuaState::CheckParamNumber(int a_StartParam, int a_EndParam) +bool cLuaState::CheckParamBool(int a_StartParam, int a_EndParam) +{ + ASSERT(IsValid()); + + if (a_EndParam < 0) + { + a_EndParam = a_StartParam; + } + + tolua_Error tolua_err; + for (int i = a_StartParam; i <= a_EndParam; i++) + { + if (tolua_isboolean(m_LuaState, i, 0, &tolua_err)) + { + continue; + } + // Not the correct parameter + lua_Debug entry; + VERIFY(lua_getstack(m_LuaState, 0, &entry)); + VERIFY(lua_getinfo (m_LuaState, "n", &entry)); + AString ErrMsg = Printf("#ferror in function '%s'.", (entry.name != nullptr) ? entry.name : "?"); + tolua_error(m_LuaState, ErrMsg.c_str(), &tolua_err); + return false; + } // for i - Param + + // All params checked ok + return true; +} + + + + + bool cLuaState::CheckParamString(int a_StartParam, int a_EndParam) { ASSERT(IsValid()); diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h index 6b600e150..f66605332 100644 --- a/src/Bindings/LuaState.h +++ b/src/Bindings/LuaState.h @@ -259,7 +259,6 @@ public: void Push(int a_Value); void Push(long a_Value); void Push(const UInt32 a_Value); - void Push(void * a_Ptr); void Push(std::chrono::milliseconds a_time); // GetStackValue() retrieves the value at a_StackPos, if it is a valid type. If not, a_Value is unchanged. @@ -375,6 +374,9 @@ public: /** Returns true if the specified parameters on the stack are numbers; also logs warning if not */ bool CheckParamNumber(int a_StartParam, int a_EndParam = -1); + /** Returns true if the specified parameters on the stack are bools; also logs warning if not */ + bool CheckParamBool(int a_StartParam, int a_EndParam = -1); + /** Returns true if the specified parameters on the stack are strings; also logs warning if not */ bool CheckParamString(int a_StartParam, int a_EndParam = -1); diff --git a/src/Bindings/ManualBindings_World.cpp b/src/Bindings/ManualBindings_World.cpp index 20fe880c1..225e71af5 100644 --- a/src/Bindings/ManualBindings_World.cpp +++ b/src/Bindings/ManualBindings_World.cpp @@ -110,6 +110,99 @@ static int tolua_cWorld_ChunkStay(lua_State * tolua_S) + +static int tolua_cWorld_DoExplosionAt(lua_State * tolua_S) +{ + /* Function signature: + World:DoExplosionAt(ExplosionSize, BlockX, BlockY, BlockZ, CanCauseFire, SourceType, [SourceData]) + */ + + cLuaState L(tolua_S); + if ( + !L.CheckParamUserType (1, "cWorld") || + !L.CheckParamNumber (2, 5) || + !L.CheckParamBool (6) || + !L.CheckParamNumber (7) || + !L.CheckParamEnd (9) + ) + { + return 0; + } + + // Read the params: + cWorld * World; + double ExplosionSize; + int BlockX, BlockY, BlockZ; + bool CanCauseFire; + int SourceTypeInt; + if (!L.GetStackValues(1, World, ExplosionSize, BlockX, BlockY, BlockZ, CanCauseFire, SourceTypeInt)) + { + LOGWARNING("World:DoExplosionAt(): invalid parameters"); + L.LogStackTrace(); + return 0; + } + if ((SourceTypeInt < 0) || (SourceTypeInt >= esMax)) + { + LOGWARNING("World:DoExplosionAt(): Invalid source type"); + L.LogStackTrace(); + return 0; + } + eExplosionSource SourceType; + void * SourceData; + switch (SourceTypeInt) + { + case esBed: + { + // esBed receives a Vector3i SourceData param: + Vector3i * pos = nullptr; + L.GetStackValue(8, pos); + SourceType = esBed; + SourceData = pos; + break; + } + + case esEnderCrystal: + case esGhastFireball: + case esMonster: + case esPrimedTNT: + case esWitherBirth: + case esWitherSkull: + { + // These all receive a cEntity descendant SourceData param: + cEntity * ent = nullptr; + L.GetStackValue(8, ent); + SourceType = static_cast(SourceTypeInt); + SourceData = ent; + break; + } + + case esOther: + case esPlugin: + { + // esOther and esPlugin ignore their SourceData params + SourceType = static_cast(SourceTypeInt); + SourceData = nullptr; + break; + } + + default: + { + LOGWARNING("cWorld:DoExplosionAt(): invalid SourceType parameter: %d", SourceTypeInt); + L.LogStackTrace(); + return 0; + } + } + + // Create the actual explosion: + World->DoExplosionAt(ExplosionSize, BlockX, BlockY, BlockZ, CanCauseFire, SourceType, SourceData); + + return 0; +} + + + + + static int tolua_cWorld_ForEachLoadedChunk(lua_State * tolua_S) { // Exported manually, because tolua doesn't support converting functions to functor types. @@ -576,41 +669,42 @@ 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, "DoWithBrewingstandAt", 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, "BroadcastParticleEffect", tolua_cWorld_BroadcastParticleEffect); + tolua_function(tolua_S, "ChunkStay", tolua_cWorld_ChunkStay); + tolua_function(tolua_S, "DoExplosionAt", tolua_cWorld_DoExplosionAt); + tolua_function(tolua_S, "DoWithBeaconAt", DoWithXYZ); + tolua_function(tolua_S, "DoWithBlockEntityAt", DoWithXYZ); + tolua_function(tolua_S, "DoWithBrewingstandAt", DoWithXYZ); + tolua_function(tolua_S, "DoWithChestAt", DoWithXYZ); + tolua_function(tolua_S, "DoWithCommandBlockAt", 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, "DoWithFlowerPotAt", DoWithXYZ); + tolua_function(tolua_S, "DoWithFurnaceAt", DoWithXYZ); + tolua_function(tolua_S, "DoWithMobHeadAt", DoWithXYZ); + tolua_function(tolua_S, "DoWithNoteBlockAt", DoWithXYZ); + tolua_function(tolua_S, "DoWithPlayer", DoWith< cWorld, cPlayer, &cWorld::DoWithPlayer>); + tolua_function(tolua_S, "DoWithPlayerByUUID", DoWith< cWorld, cPlayer, &cWorld::DoWithPlayerByUUID>); + tolua_function(tolua_S, "FindAndDoWithPlayer", DoWith< cWorld, cPlayer, &cWorld::FindAndDoWithPlayer>); + tolua_function(tolua_S, "ForEachBlockEntityInChunk", ForEachInChunk); tolua_function(tolua_S, "ForEachBrewingstandInChunk", 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, "ForEachLoadedChunk", tolua_cWorld_ForEachLoadedChunk); - 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_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, "ForEachLoadedChunk", tolua_cWorld_ForEachLoadedChunk); + 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); } diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp index 3038264d2..1b7a18ff1 100644 --- a/src/Bindings/PluginLua.cpp +++ b/src/Bindings/PluginLua.cpp @@ -667,16 +667,20 @@ bool cPluginLua::OnExploded(cWorld & a_World, double a_ExplosionSize, bool a_Can { switch (a_Source) { - case esOther: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break; - case esPrimedTNT: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast(a_SourceData), cLuaState::Return, res); break; - case esMonster: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast(a_SourceData), cLuaState::Return, res); break; - case esBed: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast(a_SourceData), cLuaState::Return, res); break; - case esEnderCrystal: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast(a_SourceData), cLuaState::Return, res); break; - case esGhastFireball: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break; - case esWitherSkullBlack: - case esWitherSkullBlue: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break; - case esWitherBirth: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break; - case esPlugin: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break; + case esBed: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast (a_SourceData), cLuaState::Return, res); break; + case esEnderCrystal: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast (a_SourceData), cLuaState::Return, res); break; + case esGhastFireball: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast(a_SourceData), cLuaState::Return, res); break; + case esMonster: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast (a_SourceData), cLuaState::Return, res); break; + case esOther: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, cLuaState::Return, res); break; + case esPlugin: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, cLuaState::Return, res); break; + case esPrimedTNT: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast (a_SourceData), cLuaState::Return, res); break; + case esWitherBirth: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast (a_SourceData), cLuaState::Return, res); break; + case esWitherSkull: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast (a_SourceData), cLuaState::Return, res); break; + case esMax: + { + ASSERT(!"Invalid explosion source"); + return false; + } } if (res) { @@ -703,16 +707,20 @@ bool cPluginLua::OnExploding(cWorld & a_World, double & a_ExplosionSize, bool & { switch (a_Source) { - case esOther: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; - case esPrimedTNT: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast(a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; - case esMonster: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast(a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; - case esBed: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast(a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; - case esEnderCrystal: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast(a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; - case esGhastFireball: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; - case esWitherSkullBlack: - case esWitherSkullBlue: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; - case esWitherBirth: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; - case esPlugin: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; + case esBed: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast (a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; + case esEnderCrystal: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast (a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; + case esGhastFireball: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast(a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; + case esMonster: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast (a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; + case esOther: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; + case esPlugin: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; + case esPrimedTNT: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast (a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; + case esWitherBirth: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast (a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; + case esWitherSkull: m_LuaState.Call(static_cast(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, reinterpret_cast (a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; + case esMax: + { + ASSERT(!"Invalid explosion source"); + return false; + } } if (res) { -- cgit v1.2.3