diff options
-rw-r--r-- | MCServer/Plugins/Debuggers/Debuggers.lua | 9 | ||||
-rw-r--r-- | source/LuaWindow.cpp | 48 | ||||
-rw-r--r-- | source/LuaWindow.h | 13 | ||||
-rw-r--r-- | source/ManualBindings.cpp | 39 | ||||
-rw-r--r-- | source/Player.cpp | 21 | ||||
-rw-r--r-- | source/Plugin_NewLua.cpp | 24 | ||||
-rw-r--r-- | source/Plugin_NewLua.h | 7 | ||||
-rw-r--r-- | source/UI/Window.cpp | 4 | ||||
-rw-r--r-- | source/UI/Window.h | 4 |
9 files changed, 160 insertions, 9 deletions
diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index 076cec9ca..484ea88be 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -580,8 +580,17 @@ function HandleTestWndCmd(a_Split, a_Player) return true;
end
+ -- Test out the OnClosing callback's ability to refuse to close the window
+ local attempt = 1;
+ local OnClosing = function(Window, Player)
+ Player:SendMessage("Window closing attempt #" .. attempt);
+ attempt = attempt + 1;
+ return (attempt <= 3); -- refuse twice, then allow
+ end
+
local Window = cLuaWindow(WindowType, WindowSizeX, WindowSizeY, "TestWnd");
Window:SetSlot(a_Player, 0, cItem(E_ITEM_DIAMOND, 64));
+ Window:SetOnClosing(OnClosing);
a_Player:OpenWindow(Window);
diff --git a/source/LuaWindow.cpp b/source/LuaWindow.cpp index d7b67d552..5ed521793 100644 --- a/source/LuaWindow.cpp +++ b/source/LuaWindow.cpp @@ -7,6 +7,7 @@ #include "LuaWindow.h"
#include "UI/SlotArea.h"
#include "Plugin_NewLua.h"
+#include "Player.h"
#include "lauxlib.h" // Needed for LUA_REFNIL
@@ -20,7 +21,9 @@ cLuaWindow::cLuaWindow(cWindow::WindowType a_WindowType, int a_SlotsX, int a_Slo super(a_WindowType, a_Title),
m_Contents(a_SlotsX, a_SlotsY),
m_Plugin(NULL),
- m_LuaRef(LUA_REFNIL)
+ m_LuaRef(LUA_REFNIL),
+ m_OnClosingFnRef(LUA_REFNIL),
+ m_OnSlotChangedFnRef(LUA_REFNIL)
{
m_SlotAreas.push_back(new cSlotAreaItemGrid(m_Contents, *this));
@@ -53,7 +56,8 @@ cLuaWindow::~cLuaWindow() void cLuaWindow::SetLuaRef(cPlugin_NewLua * a_Plugin, int a_LuaRef)
{
- ASSERT(m_Plugin == NULL);
+ // 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));
ASSERT(m_LuaRef == LUA_REFNIL);
m_Plugin = a_Plugin;
m_LuaRef = a_LuaRef;
@@ -72,6 +76,46 @@ bool cLuaWindow::IsLuaReferenced(void) const +void cLuaWindow::SetOnClosing(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_OnClosingFnRef != LUA_REFNIL)
+ {
+ m_Plugin->Unreference(m_OnClosingFnRef);
+ }
+
+ // Store the new reference
+ m_Plugin = a_Plugin;
+ m_OnClosingFnRef = a_FnRef;
+}
+
+
+
+
+
+bool cLuaWindow::ClosedByPlayer(cPlayer & a_Player)
+{
+ // First notify the plugin through the registered callback:
+ if (m_OnClosingFnRef != LUA_REFNIL)
+ {
+ ASSERT(m_Plugin != NULL);
+ if (m_Plugin->CallbackWindowClosing(m_OnClosingFnRef, *this, a_Player))
+ {
+ // The callback disagrees
+ return false;
+ }
+ }
+
+ return super::ClosedByPlayer(a_Player);
+}
+
+
+
+
+
void cLuaWindow::Destroy(void)
{
super::Destroy();
diff --git a/source/LuaWindow.h b/source/LuaWindow.h index c474fa1ab..30c07bdbf 100644 --- a/source/LuaWindow.h +++ b/source/LuaWindow.h @@ -58,6 +58,12 @@ public: /// Returns true if SetLuaRef() has been called
bool IsLuaReferenced(void) const;
+ /// Sets the callback function (Lua reference) to call when the window is about to close
+ void SetOnClosing(cPlugin_NewLua * a_Plugin, int a_FnRef);
+
+ /// Sets the callback function (Lua reference) to call when a slot is changed
+ void SetOnSlotChanged(cPlugin_NewLua * a_Plugin, int a_FnRef);
+
protected:
/// Contents of the non-inventory part
cItemGrid m_Contents;
@@ -68,7 +74,14 @@ protected: /// The Lua object reference, used for keeping the object alive as long as any player has the window open
int m_LuaRef;
+ /// The Lua reference for the callback to call when the window is closing for any player
+ int m_OnClosingFnRef;
+
+ /// The Lua reference for the callback to call when a slot has changed
+ int m_OnSlotChangedFnRef;
+
// cWindow overrides:
+ virtual bool ClosedByPlayer(cPlayer & a_Player) override;
virtual void Destroy(void) override;
} ; // tolua_export
diff --git a/source/ManualBindings.cpp b/source/ManualBindings.cpp index ceb24da30..96cd14370 100644 --- a/source/ManualBindings.cpp +++ b/source/ManualBindings.cpp @@ -938,6 +938,41 @@ static int tolua_cPlayer_OpenWindow(lua_State * tolua_S) +static int tolua_cLuaWindow_SetOnClosing(lua_State * tolua_S) +{ + // Function signature: cPlayer:SetOnClosing(CallbackFunction) + + // Retrieve the plugin instance from the Lua state + cPlugin_NewLua * Plugin = GetLuaPlugin(tolua_S); + if (Plugin == NULL) + { + // Warning message has already been printed by GetLuaPlugin(), bail out silently + return 0; + } + + // Get the parameters: + cLuaWindow * self = (cLuaWindow *)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 + if (FnRef == LUA_REFNIL) + { + LOGERROR("%s: Cannot create a function reference. Callback not set.", __FUNCTION__); + return 0; + } + + // Set the callback + self->SetOnClosing(Plugin, FnRef); + return 0; +} + + + + + static int tolua_cPlugin_NewLua_AddWebTab(lua_State * tolua_S) { cPlugin_NewLua * self = (cPlugin_NewLua*)tolua_tousertype(tolua_S,1,0); @@ -1265,6 +1300,10 @@ void ManualBindings::Bind( lua_State* tolua_S ) tolua_function(tolua_S, "OpenWindow", tolua_cPlayer_OpenWindow); tolua_endmodule(tolua_S); + tolua_beginmodule(tolua_S, "cLuaWindow"); + tolua_function(tolua_S, "SetOnClosing", tolua_cLuaWindow_SetOnClosing); + tolua_endmodule(tolua_S); + tolua_beginmodule(tolua_S, "cPlugin_NewLua"); tolua_function(tolua_S, "AddWebTab", tolua_cPlugin_NewLua_AddWebTab); tolua_function(tolua_S, "AddTab", tolua_cPlugin_NewLua_AddTab); diff --git a/source/Player.cpp b/source/Player.cpp index 8970719f1..519837f6a 100644 --- a/source/Player.cpp +++ b/source/Player.cpp @@ -435,7 +435,10 @@ Vector3d cPlayer::GetEyePosition() void cPlayer::OpenWindow(cWindow * a_Window) { - CloseWindow(); + if (a_Window != m_CurrentWindow) + { + CloseWindow(); + } a_Window->OpenedByPlayer(*this); m_CurrentWindow = a_Window; a_Window->SendWholeWindow(*GetClientHandle()); @@ -453,8 +456,17 @@ void cPlayer::CloseWindow(void) return; } - m_CurrentWindow->ClosedByPlayer(*this); - m_CurrentWindow = m_InventoryWindow; + if (m_CurrentWindow->ClosedByPlayer(*this)) + { + // Close accepted, go back to inventory window (the default): + m_CurrentWindow = m_InventoryWindow; + } + else + { + // Re-open the window + m_CurrentWindow->OpenedByPlayer(*this); + m_CurrentWindow->SendWholeWindow(*GetClientHandle()); + } } @@ -467,8 +479,7 @@ void cPlayer::CloseWindowIfID(char a_WindowID) { return; } - m_CurrentWindow->ClosedByPlayer(*this); - m_CurrentWindow = m_InventoryWindow; + CloseWindow(); } diff --git a/source/Plugin_NewLua.cpp b/source/Plugin_NewLua.cpp index df18cfa9b..dd3db7d6a 100644 --- a/source/Plugin_NewLua.cpp +++ b/source/Plugin_NewLua.cpp @@ -1665,6 +1665,30 @@ void cPlugin_NewLua::Unreference(int a_LuaRef) +bool cPlugin_NewLua::CallbackWindowClosing(int a_FnRef, cWindow & a_Window, cPlayer & a_Player) +{ + 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_pushusertype(m_LuaState, &a_Player, "cPlayer"); + + // Call function: + int s = lua_pcall(m_LuaState, 2, 1, 0); + if (report_errors(m_LuaState, s)) + { + LOGERROR("LUA error in %s. Stack size: %i", __FUNCTION__, lua_gettop(m_LuaState)); + return false; + } + + bool bRetVal = (tolua_toboolean(m_LuaState, -1, false) > 0); + lua_pop(m_LuaState, 1); + return bRetVal; +} + + + + + // 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 acc43c7a4..fc3565bbc 100644 --- a/source/Plugin_NewLua.h +++ b/source/Plugin_NewLua.h @@ -11,8 +11,12 @@ +// fwd: Lua typedef struct lua_State lua_State; +// fwd: UI/Window.h +class cWindow; + @@ -101,6 +105,9 @@ public: /// Removes a previously referenced object (luaL_unref()) void Unreference(int a_LuaRef); + /// 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); + protected: cCriticalSection m_CriticalSection; lua_State * m_LuaState; diff --git a/source/UI/Window.cpp b/source/UI/Window.cpp index 661f9f62f..f353d0721 100644 --- a/source/UI/Window.cpp +++ b/source/UI/Window.cpp @@ -251,7 +251,7 @@ void cWindow::OpenedByPlayer(cPlayer & a_Player) -void cWindow::ClosedByPlayer(cPlayer & a_Player) +bool cWindow::ClosedByPlayer(cPlayer & a_Player) { // Checks whether the player is still holding an item if (a_Player.IsDraggingItem()) @@ -285,6 +285,8 @@ void cWindow::ClosedByPlayer(cPlayer & a_Player) { delete this; } + + return true; } diff --git a/source/UI/Window.h b/source/UI/Window.h index 1f2495a46..68774aa59 100644 --- a/source/UI/Window.h +++ b/source/UI/Window.h @@ -106,7 +106,9 @@ public: ); void OpenedByPlayer(cPlayer & a_Player); - void ClosedByPlayer(cPlayer & a_Player); + + /// Called when a player closes this window; notifies all slot areas. Returns true if close accepted + virtual bool ClosedByPlayer(cPlayer & a_Player); void SendWholeWindow(cClientHandle & a_Client); void BroadcastWholeWindow(void); |