diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index 484ea88b..f35e2d2d 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -588,9 +588,15 @@ function HandleTestWndCmd(a_Split, a_Player) return (attempt <= 3); -- refuse twice, then allow end + -- Log the slot changes + local OnSlotChanged = function(Window, SlotNum) + LOG("Window \"" .. Window:GetWindowTitle() .. "\" slot " .. SlotNum .. " changed."); + end + local Window = cLuaWindow(WindowType, WindowSizeX, WindowSizeY, "TestWnd"); Window:SetSlot(a_Player, 0, cItem(E_ITEM_DIAMOND, 64)); Window:SetOnClosing(OnClosing); + Window:SetOnSlotChanged(OnSlotChanged); a_Player:OpenWindow(Window); diff --git a/source/LuaWindow.cpp b/source/LuaWindow.cpp index 5ed52179..f6277250 100644 --- a/source/LuaWindow.cpp +++ b/source/LuaWindow.cpp @@ -25,6 +25,7 @@ cLuaWindow::cLuaWindow(cWindow::WindowType a_WindowType, int a_SlotsX, int a_Slo m_OnClosingFnRef(LUA_REFNIL), m_OnSlotChangedFnRef(LUA_REFNIL) { + m_Contents.AddListener(*this); m_SlotAreas.push_back(new cSlotAreaItemGrid(m_Contents, *this)); // If appropriate, add an Armor slot area: @@ -96,6 +97,26 @@ void cLuaWindow::SetOnClosing(cPlugin_NewLua * a_Plugin, int a_FnRef) +void cLuaWindow::SetOnSlotChanged(cPlugin_NewLua * a_Plugin, int a_FnRef) +{ + // Either m_Plugin is not set or equal to the passed plugin; only one plugin can use one cLuaWindow object + ASSERT((m_Plugin == NULL) || (m_Plugin == a_Plugin)); + + // If there already was a function, unreference it first + if (m_OnSlotChangedFnRef != LUA_REFNIL) + { + m_Plugin->Unreference(m_OnSlotChangedFnRef); + } + + // Store the new reference + m_Plugin = a_Plugin; + m_OnSlotChangedFnRef = a_FnRef; +} + + + + + bool cLuaWindow::ClosedByPlayer(cPlayer & a_Player) { // First notify the plugin through the registered callback: @@ -133,3 +154,22 @@ void cLuaWindow::Destroy(void) + +void cLuaWindow::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) +{ + if (a_ItemGrid != &m_Contents) + { + ASSERT(!"Invalid ItemGrid in callback"); + return; + } + + // If an OnSlotChanged callback has been registered, call it: + if (m_OnSlotChangedFnRef != LUA_REFNIL) + { + m_Plugin->CallbackWindowSlotChanged(m_OnSlotChangedFnRef, *this, a_SlotNum); + } +} + + + + diff --git a/source/LuaWindow.h b/source/LuaWindow.h index 30c07bdb..dc4497df 100644 --- a/source/LuaWindow.h +++ b/source/LuaWindow.h @@ -10,6 +10,7 @@ #pragma once #include "UI/Window.h" +#include "ItemGrid.h" @@ -35,7 +36,8 @@ cPlayer:OpenWindow check if the window is of this class, and if so, make a globa This reference needs to be unreferenced in the Destroy() function. */ class cLuaWindow : - public cWindow + public cWindow, + public cItemGrid::cListener { typedef cWindow super; @@ -83,6 +85,9 @@ protected: // cWindow overrides: virtual bool ClosedByPlayer(cPlayer & a_Player) override; virtual void Destroy(void) override; + + // cItemGrid::cListener overrides: + virtual void OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) override; } ; // tolua_export diff --git a/source/ManualBindings.cpp b/source/ManualBindings.cpp index 96cd1437..0f8f1ad2 100644 --- a/source/ManualBindings.cpp +++ b/source/ManualBindings.cpp @@ -938,9 +938,13 @@ static int tolua_cPlayer_OpenWindow(lua_State * tolua_S) -static int tolua_cLuaWindow_SetOnClosing(lua_State * tolua_S) +template < + class OBJTYPE, + void (OBJTYPE::*SetCallback)(cPlugin_NewLua * a_Plugin, int a_FnRef) +> +static int tolua_SetObjectCallback(lua_State * tolua_S) { - // Function signature: cPlayer:SetOnClosing(CallbackFunction) + // Function signature: OBJTYPE:SetWhateverCallback(CallbackFunction) // Retrieve the plugin instance from the Lua state cPlugin_NewLua * Plugin = GetLuaPlugin(tolua_S); @@ -950,14 +954,14 @@ static int tolua_cLuaWindow_SetOnClosing(lua_State * tolua_S) return 0; } - // Get the parameters: - cLuaWindow * self = (cLuaWindow *)tolua_tousertype(tolua_S, 1, NULL); + // Get the parameters - self and the function reference: + OBJTYPE * self = (OBJTYPE *)tolua_tousertype(tolua_S, 1, NULL); if (self == NULL) { LOGWARNING("%s: invalid self (%p)", __FUNCTION__, self); return 0; } - int FnRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); // Store function reference + int FnRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); // Store function reference for later retrieval if (FnRef == LUA_REFNIL) { LOGERROR("%s: Cannot create a function reference. Callback not set.", __FUNCTION__); @@ -965,7 +969,7 @@ static int tolua_cLuaWindow_SetOnClosing(lua_State * tolua_S) } // Set the callback - self->SetOnClosing(Plugin, FnRef); + (self->*SetCallback)(Plugin, FnRef); return 0; } @@ -1301,7 +1305,8 @@ void ManualBindings::Bind( lua_State* tolua_S ) tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cLuaWindow"); - tolua_function(tolua_S, "SetOnClosing", tolua_cLuaWindow_SetOnClosing); + tolua_function(tolua_S, "SetOnClosing", tolua_SetObjectCallback); + tolua_function(tolua_S, "SetOnSlotChanged", tolua_SetObjectCallback); tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cPlugin_NewLua"); diff --git a/source/Plugin_NewLua.cpp b/source/Plugin_NewLua.cpp index dd3db7d6..a76b5180 100644 --- a/source/Plugin_NewLua.cpp +++ b/source/Plugin_NewLua.cpp @@ -1667,6 +1667,8 @@ void cPlugin_NewLua::Unreference(int a_LuaRef) bool cPlugin_NewLua::CallbackWindowClosing(int a_FnRef, cWindow & a_Window, cPlayer & a_Player) { + ASSERT(a_FnRef != LUA_REFNIL); + cCSLock Lock(m_CriticalSection); lua_rawgeti(m_LuaState, LUA_REGISTRYINDEX, a_FnRef); // Push the function to be called tolua_pushusertype(m_LuaState, &a_Window, "cWindow"); @@ -1689,6 +1691,27 @@ bool cPlugin_NewLua::CallbackWindowClosing(int a_FnRef, cWindow & a_Window, cPla +void cPlugin_NewLua::CallbackWindowSlotChanged(int a_FnRef, cWindow & a_Window, int a_SlotNum) +{ + ASSERT(a_FnRef != LUA_REFNIL); + + cCSLock Lock(m_CriticalSection); + lua_rawgeti(m_LuaState, LUA_REGISTRYINDEX, a_FnRef); // Push the function to be called + tolua_pushusertype(m_LuaState, &a_Window, "cWindow"); + tolua_pushnumber (m_LuaState, a_SlotNum); + + // Call function: + int s = lua_pcall(m_LuaState, 2, 0, 0); + if (report_errors(m_LuaState, s)) + { + LOGERROR("LUA error in %s. Stack size: %i", __FUNCTION__, lua_gettop(m_LuaState)); + } +} + + + + + // Helper functions bool cPlugin_NewLua::PushFunction(const char * a_FunctionName, bool a_bLogError /* = true */) { diff --git a/source/Plugin_NewLua.h b/source/Plugin_NewLua.h index fc3565bb..34ab85ca 100644 --- a/source/Plugin_NewLua.h +++ b/source/Plugin_NewLua.h @@ -108,6 +108,9 @@ public: /// Calls the plugin-specified "cLuaWindow closing" callback. Returns true only if the callback returned true bool CallbackWindowClosing(int a_FnRef, cWindow & a_Window, cPlayer & a_Player); + /// Calls the plugin-specified "cLuaWindow slot changed" callback. + void CallbackWindowSlotChanged(int a_FnRef, cWindow & a_Window, int a_SlotNum); + protected: cCriticalSection m_CriticalSection; lua_State * m_LuaState;