From 9cebc9157cf43ba639227b9d79b980b3613dda1e Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Mon, 10 Feb 2014 22:47:10 +0100 Subject: Rewritten Lua ChunkStay API into a single function, cWorld:ChunkStay(). This fixes problems with indeterminate class object lifespan (Lua-GC) and forgetting to disable it or keep it until ready. --- src/Bindings/LuaChunkStay.cpp | 146 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 120 insertions(+), 26 deletions(-) (limited to 'src/Bindings/LuaChunkStay.cpp') diff --git a/src/Bindings/LuaChunkStay.cpp b/src/Bindings/LuaChunkStay.cpp index f84964f56..0e982637f 100644 --- a/src/Bindings/LuaChunkStay.cpp +++ b/src/Bindings/LuaChunkStay.cpp @@ -1,18 +1,20 @@ // LuaChunkStay.cpp -// Implements the cLuaChunkStay class representing a cChunkStay binding for plugins +// Implements the cLuaChunkStay class representing a cChunkStay binding for plugins, used by cWorld:ChunkStay() Lua API #include "Globals.h" #include "LuaChunkStay.h" +#include "PluginLua.h" #include "../World.h" -cLuaChunkStay::cLuaChunkStay(void) : - m_LuaState((lua_State *)NULL) // Want a detached Lua state by default +cLuaChunkStay::cLuaChunkStay(cPluginLua & a_Plugin) : + m_Plugin(a_Plugin), + m_LuaState(NULL) { } @@ -20,39 +22,107 @@ cLuaChunkStay::cLuaChunkStay(void) : -void cLuaChunkStay::Enable( - cWorld & a_World, lua_State * a_LuaState, - int a_OnChunkAvailableStackPos, int a_OnAllChunksAvailableStackPos -) +bool cLuaChunkStay::AddChunks(int a_ChunkCoordTableStackPos) { - if (m_LuaState.IsValid()) + // This function is expected to be called just once, with all the coords in a table + ASSERT(m_Chunks.empty()); + + cPluginLua::cOperation Op(m_Plugin); + cLuaState & L = Op(); + + // Check that we got a table: + if (!lua_istable(L, a_ChunkCoordTableStackPos)) { - LOGWARNING("LuaChunkStay: Already enabled. Ignoring this call."); - cLuaState::LogStackTrace(a_LuaState); - return; + LOGWARNING("%s: The parameter is not a table of coords (got %s). Ignoring the call.", + __FUNCTION__, lua_typename(L, lua_type(L, a_ChunkCoordTableStackPos)) + ); + L.LogStackTrace(); + return false; + } + + // Add each set of coords: + int NumChunks = luaL_getn(L, a_ChunkCoordTableStackPos); + m_Chunks.reserve(NumChunks); + for (int idx = 1; idx <= NumChunks; idx++) + { + // Push the idx-th element of the array onto stack top, check that it's a table: + lua_rawgeti(L, a_ChunkCoordTableStackPos, idx); + if (!lua_istable(L, -1)) + { + LOGWARNING("%s: Element #%d is not a table (got %s). Ignoring the element.", + __FUNCTION__, idx, lua_typename(L, -1) + ); + L.LogStackTrace(); + lua_pop(L, 1); + continue; + } + AddChunkCoord(L, idx); + lua_pop(L, 1); } - m_LuaState.Attach(a_LuaState); - m_OnChunkAvailable.RefStack(m_LuaState, a_OnChunkAvailableStackPos); - m_OnAllChunksAvailable.RefStack(m_LuaState, a_OnAllChunksAvailableStackPos); - super::Enable(*a_World.GetChunkMap()); + + // If there are no chunks, log a warning and return failure: + if (m_Chunks.empty()) + { + LOGWARNING("%s: Zero chunks to stay.", __FUNCTION__); + L.LogStackTrace(); + return false; + } + + // All ok + return true; } -void cLuaChunkStay::Disable(void) +void cLuaChunkStay::AddChunkCoord(cLuaState & L, int a_Index) { - super::Disable(); - - // If the state was valid (bound to Lua functions), unbind those functions: - if (!m_LuaState.IsValid()) + // Check that the element has 2 coords: + int NumCoords = luaL_getn(L, -1); + if (NumCoords != 2) { + LOGWARNING("%s: Element #%d doesn't contain 2 coords (got %d). Ignoring the element.", + __FUNCTION__, a_Index, NumCoords + ); return; } - m_OnAllChunksAvailable.UnRef(); - m_OnChunkAvailable.UnRef(); - m_LuaState.Detach(); + + // Read the two coords from the element: + lua_rawgeti(L, -1, 1); + lua_rawgeti(L, -2, 2); + int ChunkX = luaL_checkint(L, -2); + int ChunkZ = luaL_checkint(L, -1); + lua_pop(L, 2); + + // Check that a coord is not yet present: + for (cChunkCoordsVector::iterator itr = m_Chunks.begin(), end = m_Chunks.end(); itr != end; ++itr) + { + if ((itr->m_ChunkX == ChunkX) && (itr->m_ChunkZ == ChunkZ)) + { + LOGWARNING("%s: Element #%d is a duplicate, ignoring it.", + __FUNCTION__, a_Index + ); + return; + } + } // for itr - m_Chunks[] + + m_Chunks.push_back(cChunkCoords(ChunkX, ZERO_CHUNK_Y, ChunkZ)); +} + + + + + +void cLuaChunkStay::Enable(cChunkMap & a_ChunkMap, int a_OnChunkAvailableStackPos, int a_OnAllChunksAvailableStackPos) +{ + // Get the references to the callback functions: + m_LuaState = &m_Plugin.GetLuaState(); + m_OnChunkAvailable.RefStack(*m_LuaState, a_OnChunkAvailableStackPos); + m_OnAllChunksAvailable.RefStack(*m_LuaState, a_OnAllChunksAvailableStackPos); + + // Enable the ChunkStay: + super::Enable(a_ChunkMap); } @@ -61,19 +131,43 @@ void cLuaChunkStay::Disable(void) void cLuaChunkStay::OnChunkAvailable(int a_ChunkX, int a_ChunkZ) { - m_LuaState.Call(m_OnChunkAvailable, a_ChunkX, a_ChunkZ); + // DEBUG: + LOGD("LuaChunkStay: Chunk [%d, %d] is now available, calling the callback...", a_ChunkX, a_ChunkZ); + + cPluginLua::cOperation Op(m_Plugin); + Op().Call((int)m_OnChunkAvailable, a_ChunkX, a_ChunkZ); } -void cLuaChunkStay::OnAllChunksAvailable(void) +bool cLuaChunkStay::OnAllChunksAvailable(void) { - m_LuaState.Call(m_OnAllChunksAvailable); + { + // Call the callback: + cPluginLua::cOperation Op(m_Plugin); + Op().Call((int)m_OnAllChunksAvailable); + + // Remove the callback references - they won't be needed anymore + m_OnChunkAvailable.UnRef(); + m_OnAllChunksAvailable.UnRef(); + } + + // Disable the ChunkStay by returning true + return true; } +void cLuaChunkStay::OnDisabled(void) +{ + // This object is no longer needed, delete it + delete this; +} + + + + -- cgit v1.2.3