summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/LuaWindow.cpp48
-rw-r--r--source/LuaWindow.h13
-rw-r--r--source/ManualBindings.cpp39
-rw-r--r--source/Player.cpp21
-rw-r--r--source/Plugin_NewLua.cpp24
-rw-r--r--source/Plugin_NewLua.h7
-rw-r--r--source/UI/Window.cpp4
-rw-r--r--source/UI/Window.h4
8 files changed, 151 insertions, 9 deletions
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);