// LuaChunkStay.cpp
// 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"
cLuaChunkStay::cLuaChunkStay(cPluginLua & a_Plugin) :
m_Plugin(a_Plugin),
m_LuaState(nullptr)
{
}
bool cLuaChunkStay::AddChunks(int a_ChunkCoordTableStackPos)
{
// 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("%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(static_cast<size_t>(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);
}
// 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::AddChunkCoord(cLuaState & L, int a_Index)
{
// 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;
}
// 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, ChunkZ));
}
void cLuaChunkStay::Enable(cChunkMap & a_ChunkMap, cLuaState::cCallbackPtr a_OnChunkAvailable, cLuaState::cCallbackPtr a_OnAllChunksAvailable)
{
m_OnChunkAvailable = a_OnChunkAvailable;
m_OnAllChunksAvailable = a_OnAllChunksAvailable;
// Enable the ChunkStay:
super::Enable(a_ChunkMap);
}
void cLuaChunkStay::OnChunkAvailable(int a_ChunkX, int a_ChunkZ)
{
if (m_OnChunkAvailable != nullptr)
{
m_OnChunkAvailable->Call(a_ChunkX, a_ChunkZ);
}
}
bool cLuaChunkStay::OnAllChunksAvailable(void)
{
if (m_OnAllChunksAvailable != nullptr)
{
// Call the callback:
m_OnAllChunksAvailable->Call();
// Remove the callback references - they won't be needed anymore
m_OnChunkAvailable.reset();
m_OnAllChunksAvailable.reset();
}
// Disable the ChunkStay by returning true
return true;
}
void cLuaChunkStay::OnDisabled(void)
{
// This object is no longer needed, delete it
delete this;
}