summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/Bindings/LuaState.cpp70
-rw-r--r--src/Bindings/LuaState.h24
-rw-r--r--src/Bindings/LuaWindow.cpp95
-rw-r--r--src/Bindings/LuaWindow.h72
-rw-r--r--src/Bindings/ManualBindings.cpp157
-rw-r--r--src/Entities/Player.h6
-rw-r--r--src/UI/Window.cpp2
7 files changed, 243 insertions, 183 deletions
diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp
index 28274d681..550737704 100644
--- a/src/Bindings/LuaState.cpp
+++ b/src/Bindings/LuaState.cpp
@@ -180,6 +180,25 @@ bool cLuaState::cCallback::IsValid(void)
+bool cLuaState::cCallback::IsSameLuaState(cLuaState & a_LuaState)
+{
+ cCSLock lock(m_CS);
+ if (!m_Ref.IsValid())
+ {
+ return false;
+ }
+ auto canonState = a_LuaState.QueryCanonLuaState();
+ if (canonState == nullptr)
+ {
+ return false;
+ }
+ return (m_Ref.GetLuaState() == static_cast<lua_State *>(*canonState));
+}
+
+
+
+
+
void cLuaState::cCallback::Invalidate(void)
{
cCSLock Lock(m_CS);
@@ -919,6 +938,18 @@ void cLuaState::Push(std::chrono::milliseconds a_Value)
+void cLuaState::Pop(int a_NumValuesToPop)
+{
+ ASSERT(IsValid());
+
+ lua_pop(m_LuaState, a_NumValuesToPop);
+ m_NumCurrentFunctionArgs -= a_NumValuesToPop;
+}
+
+
+
+
+
bool cLuaState::GetStackValue(int a_StackPos, AString & a_Value)
{
size_t len = 0;
@@ -1748,16 +1779,16 @@ void cLuaState::ToString(int a_StackPos, AString & a_String)
-void cLuaState::LogStack(const char * a_Header)
+void cLuaState::LogStackValues(const char * a_Header)
{
- LogStack(m_LuaState, a_Header);
+ LogStackValues(m_LuaState, a_Header);
}
-void cLuaState::LogStack(lua_State * a_LuaState, const char * a_Header)
+void cLuaState::LogStackValues(lua_State * a_LuaState, const char * a_Header)
{
// Format string consisting only of %s is used to appease the compiler
LOG("%s", (a_Header != nullptr) ? a_Header : "Lua C API Stack contents:");
@@ -1783,6 +1814,21 @@ void cLuaState::LogStack(lua_State * a_LuaState, const char * a_Header)
+cLuaState * cLuaState::QueryCanonLuaState(void)
+{
+ // Get the CanonLuaState global from Lua:
+ auto cb = WalkToNamedGlobal(g_CanonLuaStateGlobalName);
+ if (!cb.IsValid())
+ {
+ return nullptr;
+ }
+ return reinterpret_cast<cLuaState *>(lua_touserdata(m_LuaState, -1));
+}
+
+
+
+
+
int cLuaState::ReportFnCallErrors(lua_State * a_LuaState)
{
LOGWARNING("LUA: %s", lua_tostring(a_LuaState, -1));
@@ -1820,17 +1866,16 @@ int cLuaState::BreakIntoDebugger(lua_State * a_LuaState)
void cLuaState::TrackCallback(cCallback & a_Callback)
{
// Get the CanonLuaState global from Lua:
- auto cb = WalkToNamedGlobal(g_CanonLuaStateGlobalName);
- if (!cb.IsValid())
+ auto canonState = QueryCanonLuaState();
+ if (canonState == nullptr)
{
LOGWARNING("%s: Lua state %p has invalid CanonLuaState!", __FUNCTION__, reinterpret_cast<void *>(m_LuaState));
return;
}
- auto & canonState = *reinterpret_cast<cLuaState *>(lua_touserdata(m_LuaState, -1));
// Add the callback:
- cCSLock Lock(canonState.m_CSTrackedCallbacks);
- canonState.m_TrackedCallbacks.push_back(&a_Callback);
+ cCSLock Lock(canonState->m_CSTrackedCallbacks);
+ canonState->m_TrackedCallbacks.push_back(&a_Callback);
}
@@ -1840,17 +1885,16 @@ void cLuaState::TrackCallback(cCallback & a_Callback)
void cLuaState::UntrackCallback(cCallback & a_Callback)
{
// Get the CanonLuaState global from Lua:
- auto cb = WalkToNamedGlobal(g_CanonLuaStateGlobalName);
- if (!cb.IsValid())
+ auto canonState = QueryCanonLuaState();
+ if (canonState == nullptr)
{
LOGWARNING("%s: Lua state %p has invalid CanonLuaState!", __FUNCTION__, reinterpret_cast<void *>(m_LuaState));
return;
}
- auto & canonState = *reinterpret_cast<cLuaState *>(lua_touserdata(m_LuaState, -1));
// Remove the callback:
- cCSLock Lock(canonState.m_CSTrackedCallbacks);
- auto & trackedCallbacks = canonState.m_TrackedCallbacks;
+ cCSLock Lock(canonState->m_CSTrackedCallbacks);
+ auto & trackedCallbacks = canonState->m_TrackedCallbacks;
trackedCallbacks.erase(std::remove_if(trackedCallbacks.begin(), trackedCallbacks.end(),
[&a_Callback](cCallback * a_StoredCallback)
{
diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h
index a3f15dcc9..faa43b6d6 100644
--- a/src/Bindings/LuaState.h
+++ b/src/Bindings/LuaState.h
@@ -83,6 +83,15 @@ public:
/** Returns the Lua state associated with the value. */
lua_State * GetLuaState(void) { return m_LuaState; }
+ /** Creates a Lua reference to the specified object instance in the specified Lua state.
+ This is useful to make anti-GC references for objects that were created by Lua and need to stay alive longer than Lua GC would normally guarantee. */
+ template <typename T> void CreateFromObject(cLuaState & a_LuaState, T && a_Object)
+ {
+ a_LuaState.Push(std::forward<T>(a_Object));
+ RefStack(a_LuaState, -1);
+ a_LuaState.Pop();
+ }
+
protected:
lua_State * m_LuaState;
int m_Ref;
@@ -158,6 +167,10 @@ public:
/** Returns true if the contained callback is valid. */
bool IsValid(void);
+ /** Returns true if the callback resides in the specified Lua state.
+ Internally, compares the callback's canon Lua state. */
+ bool IsSameLuaState(cLuaState & a_LuaState);
+
protected:
friend class cLuaState;
@@ -330,6 +343,9 @@ public:
void Push(const UInt32 a_Value);
void Push(std::chrono::milliseconds a_time);
+ /** Pops the specified number of values off the top of the Lua stack. */
+ void Pop(int a_NumValuesToPop = 1);
+
// GetStackValue() retrieves the value at a_StackPos, if it is a valid type. If not, a_Value is unchanged.
// Returns whether value was changed
// Enum values are checked for their allowed values and fail if the value is not assigned.
@@ -511,10 +527,14 @@ public:
void ToString(int a_StackPos, AString & a_String);
/** Logs all the elements' types on the API stack, with an optional header for the listing. */
- void LogStack(const char * a_Header = nullptr);
+ void LogStackValues(const char * a_Header = nullptr);
/** Logs all the elements' types on the API stack, with an optional header for the listing. */
- static void LogStack(lua_State * a_LuaState, const char * a_Header = nullptr);
+ static void LogStackValues(lua_State * a_LuaState, const char * a_Header = nullptr);
+
+ /** Returns the canon Lua state (the primary cLuaState instance that was used to create, rather than attach, the lua_State structure).
+ Returns nullptr if the canon Lua state cannot be queried. */
+ cLuaState * QueryCanonLuaState(void);
protected:
diff --git a/src/Bindings/LuaWindow.cpp b/src/Bindings/LuaWindow.cpp
index 706397a27..bf3f7cfde 100644
--- a/src/Bindings/LuaWindow.cpp
+++ b/src/Bindings/LuaWindow.cpp
@@ -15,14 +15,13 @@
////////////////////////////////////////////////////////////////////////////////
// cLuaWindow:
-cLuaWindow::cLuaWindow(cWindow::WindowType a_WindowType, int a_SlotsX, int a_SlotsY, const AString & a_Title) :
- super(a_WindowType, a_Title),
+cLuaWindow::cLuaWindow(cLuaState & a_LuaState, cWindow::WindowType a_WindowType, int a_SlotsX, int a_SlotsY, const AString & a_Title) :
+ Super(a_WindowType, a_Title),
m_Contents(a_SlotsX, a_SlotsY),
- m_Plugin(nullptr),
- m_LuaRef(LUA_REFNIL),
- m_OnClosingFnRef(LUA_REFNIL),
- m_OnSlotChangedFnRef(LUA_REFNIL)
+ m_LuaState(a_LuaState.QueryCanonLuaState())
{
+ ASSERT(m_LuaState != nullptr); // We must have a valid Lua state; this assert fails only if there was no Canon Lua state
+
m_Contents.AddListener(*this);
m_SlotAreas.push_back(new cSlotAreaItemGrid(m_Contents, *this));
@@ -67,62 +66,42 @@ cLuaWindow::~cLuaWindow()
-void cLuaWindow::SetLuaRef(cPluginLua * a_Plugin, int a_LuaRef)
+void cLuaWindow::SetOnClosing(cLuaState::cCallbackPtr a_OnClosing)
{
- // Either m_Plugin is not set or equal to the passed plugin; only one plugin can use one cLuaWindow object
- ASSERT((m_Plugin == nullptr) || (m_Plugin == a_Plugin));
- ASSERT(m_LuaRef == LUA_REFNIL);
- m_Plugin = a_Plugin;
- m_LuaRef = a_LuaRef;
-}
-
-
-
+ // Only one Lua state can be a cLuaWindow object callback:
+ ASSERT(a_OnClosing->IsSameLuaState(*m_LuaState));
-
-bool cLuaWindow::IsLuaReferenced(void) const
-{
- return ((m_Plugin != nullptr) && (m_LuaRef != LUA_REFNIL));
+ // Store the new reference, releasing the old one if appropriate:
+ m_OnClosing = a_OnClosing;
}
-void cLuaWindow::SetOnClosing(cPluginLua * a_Plugin, int a_FnRef)
+void cLuaWindow::SetOnSlotChanged(cLuaState::cCallbackPtr a_OnSlotChanged)
{
- // Either m_Plugin is not set or equal to the passed plugin; only one plugin can use one cLuaWindow object
- ASSERT((m_Plugin == nullptr) || (m_Plugin == a_Plugin));
+ // Only one Lua state can be a cLuaWindow object callback:
+ ASSERT(a_OnSlotChanged->IsSameLuaState(*m_LuaState));
- // 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;
+ // Store the new reference, releasing the old one if appropriate:
+ m_OnSlotChanged = a_OnSlotChanged;
}
-void cLuaWindow::SetOnSlotChanged(cPluginLua * a_Plugin, int a_FnRef)
+void cLuaWindow::OpenedByPlayer(cPlayer & a_Player)
{
- // Either m_Plugin is not set or equal to the passed plugin; only one plugin can use one cLuaWindow object
- ASSERT((m_Plugin == nullptr) || (m_Plugin == a_Plugin));
-
- // If there already was a function, unreference it first
- if (m_OnSlotChangedFnRef != LUA_REFNIL)
+ // If the first player is opening the window, create a Lua Reference to the window object so that Lua will not GC it until the last player closes the window:
+ if (m_PlayerCount == 0)
{
- m_Plugin->Unreference(m_OnSlotChangedFnRef);
+ m_LuaRef.CreateFromObject(*m_LuaState, this);
}
- // Store the new reference
- m_Plugin = a_Plugin;
- m_OnSlotChangedFnRef = a_FnRef;
+ ++m_PlayerCount;
+ Super::OpenedByPlayer(a_Player);
}
@@ -132,17 +111,27 @@ void cLuaWindow::SetOnSlotChanged(cPluginLua * a_Plugin, int a_FnRef)
bool cLuaWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse)
{
// First notify the plugin through the registered callback:
- if (m_OnClosingFnRef != LUA_REFNIL)
+ if (m_OnClosing != nullptr)
{
- ASSERT(m_Plugin != nullptr);
- if (m_Plugin->CallbackWindowClosing(m_OnClosingFnRef, *this, a_Player, a_CanRefuse))
+ bool res;
+ if (
+ m_OnClosing->Call(this, &a_Player, a_CanRefuse, cLuaState::Return, res) && // The callback succeeded
+ res // The callback says not to close the window
+ )
{
// The callback disagrees (the higher levels check the CanRefuse flag compliance)
return false;
}
}
- return super::ClosedByPlayer(a_Player, a_CanRefuse);
+ // If the last player has closed the window, release the Lua reference, so that Lua may GC the object:
+ --m_PlayerCount;
+ if (m_PlayerCount == 0)
+ {
+ m_LuaRef.UnRef();
+ }
+
+ return Super::ClosedByPlayer(a_Player, a_CanRefuse);
}
@@ -151,13 +140,7 @@ bool cLuaWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse)
void cLuaWindow::Destroy(void)
{
- super::Destroy();
-
- if ((m_LuaRef != LUA_REFNIL) && (m_Plugin != nullptr))
- {
- // The object is referenced by Lua, un-reference it
- m_Plugin->Unreference(m_LuaRef);
- }
+ Super::Destroy();
// Lua will take care of this object, it will garbage-collect it, so we must not delete it!
m_IsDestroyed = false;
@@ -178,7 +161,7 @@ void cLuaWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Pl
}
}
- super::DistributeStackToAreas(a_ItemStack, a_Player, Areas, a_ShouldApply, false);
+ Super::DistributeStackToAreas(a_ItemStack, a_Player, Areas, a_ShouldApply, false);
}
@@ -194,9 +177,9 @@ void cLuaWindow::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
}
// If an OnSlotChanged callback has been registered, call it:
- if (m_OnSlotChangedFnRef != LUA_REFNIL)
+ if (m_OnSlotChanged != nullptr)
{
- m_Plugin->CallbackWindowSlotChanged(m_OnSlotChangedFnRef, *this, a_SlotNum);
+ m_OnSlotChanged->Call(this, a_SlotNum);
}
}
diff --git a/src/Bindings/LuaWindow.h b/src/Bindings/LuaWindow.h
index f292a5154..2a16d91ed 100644
--- a/src/Bindings/LuaWindow.h
+++ b/src/Bindings/LuaWindow.h
@@ -9,6 +9,8 @@
#pragma once
+#include <atomic>
+#include "LuaState.h"
#include "../UI/Window.h"
#include "../ItemGrid.h"
@@ -16,35 +18,30 @@
-// fwd: PluginLua.h
-class cPluginLua;
-
-
-
-
-
/** A window that has been created by a Lua plugin and is handled entirely by that plugin
This object needs extra care with its lifetime management:
- It is created by Lua, so Lua expects to garbage-collect it later
-- normal cWindow objects are deleted in their ClosedByPlayer() function if the last player closes them
-To overcome this, this object overloads the Destroy functions, which doesn't let the ClosedByPlayer()
-delete the window, but rather leaves it dangling, with only Lua having the reference to it.
-Additionally, to forbid Lua from deleting this object while it is used by players, the manual bindings for
-cPlayer:OpenWindow check if the window is of this class, and if so, make a global Lua reference for this object.
-This reference needs to be unreferenced in the Destroy() function. */
+- Normal cWindow objects are deleted in their ClosedByPlayer() function if the last player closes them
+ To overcome this, this object overloads the Destroy functions, which doesn't let the ClosedByPlayer()
+ delete the window, but rather leaves it dangling, with only Lua having the reference to it.
+- Lua could GC the window while a player is still using it
+ The object creates a Lua reference to itself when opened by a player and
+ removes the reference when the last player closes the window.
+*/
// tolua_begin
class cLuaWindow :
public cWindow
// tolua_end
, public cItemGrid::cListener
- // tolua_begin
-{
- typedef cWindow super;
+{ // tolua_export
+ typedef cWindow Super;
public:
- /** Create a window of the specified type, with a slot grid of a_SlotsX * a_SlotsY size */
- cLuaWindow(cWindow::WindowType a_WindowType, int a_SlotsX, int a_SlotsY, const AString & a_Title);
+ /** Create a window of the specified type, with a slot grid of a_SlotsX * a_SlotsY size.
+ Exported in ManualBindings.cpp */
+ cLuaWindow(cLuaState & a_LuaState, cWindow::WindowType a_WindowType, int a_SlotsX, int a_SlotsY, const AString & a_Title);
+ // tolua_begin
virtual ~cLuaWindow();
/** Returns the internal representation of the contents that are manipulated by Lua */
@@ -52,36 +49,37 @@ public:
// tolua_end
- /** Sets the plugin reference and the internal Lua object reference index
- used for preventing Lua's GC to collect this class while the window is open. */
- void SetLuaRef(cPluginLua * a_Plugin, int a_LuaRef);
-
- /** 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(cPluginLua * a_Plugin, int a_FnRef);
+ /** Sets the Lua callback function to call when the window is about to close */
+ void SetOnClosing(cLuaState::cCallbackPtr a_OnClosing);
- /** Sets the callback function (Lua reference) to call when a slot is changed */
- void SetOnSlotChanged(cPluginLua * a_Plugin, int a_FnRef);
+ /** Sets the Lua callback function to call when a slot is changed */
+ void SetOnSlotChanged(cLuaState::cCallbackPtr a_OnSlotChanged);
protected:
+
/** Contents of the non-inventory part */
cItemGrid m_Contents;
- /** The plugin that has opened the window and owns the m_LuaRef */
- cPluginLua * m_Plugin;
+ /** The Lua state that has opened the window and owns the m_LuaRef */
+ cLuaState * m_LuaState;
+
+ /** The Lua callback to call when the window is closing for any player */
+ cLuaState::cCallbackPtr m_OnClosing;
+
+ /** The Lua callback to call when a slot has changed */
+ cLuaState::cCallbackPtr m_OnSlotChanged;
- /** The Lua object reference, used for keeping the object alive as long as any player has the window open */
- int m_LuaRef;
+ /** Number of players that are currently using the window.
+ Used to manager the m_LuaRef lifetime. */
+ std::atomic<int> m_PlayerCount;
- /** The Lua reference for the callback to call when the window is closing for any player */
- int m_OnClosingFnRef;
+ /** Reference to self, to keep Lua from GCing the object while a player is still using it.
+ Created when the first player opens the window, destroyed when the last player closes the window. */
+ cLuaState::cRef m_LuaRef;
- /** The Lua reference for the callback to call when a slot has changed */
- int m_OnSlotChangedFnRef;
// cWindow overrides:
+ virtual void OpenedByPlayer(cPlayer & a_Player) override;
virtual bool ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) override;
virtual void Destroy(void) override;
virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override;
diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp
index 7cf79d5da..28120fdc5 100644
--- a/src/Bindings/ManualBindings.cpp
+++ b/src/Bindings/ManualBindings.cpp
@@ -1600,55 +1600,6 @@ static int tolua_cPlayer_GetRestrictions(lua_State * tolua_S)
-static int tolua_cPlayer_OpenWindow(lua_State * tolua_S)
-{
- // Function signature: cPlayer:OpenWindow(Window)
-
- // Retrieve the plugin instance from the Lua state
- cPluginLua * Plugin = cManualBindings::GetLuaPlugin(tolua_S);
- if (Plugin == nullptr)
- {
- return 0;
- }
-
- // Get the parameters:
- cPlayer * self = reinterpret_cast<cPlayer *>(tolua_tousertype(tolua_S, 1, nullptr));
- cWindow * wnd = reinterpret_cast<cWindow *>(tolua_tousertype(tolua_S, 2, nullptr));
- if ((self == nullptr) || (wnd == nullptr))
- {
- LOGWARNING("%s: invalid self (%p) or wnd (%p)", __FUNCTION__, static_cast<void *>(self), static_cast<void *>(wnd));
- return 0;
- }
-
- // If cLuaWindow, add a reference, so that Lua won't delete the cLuaWindow object mid-processing
- tolua_Error err;
- if (tolua_isusertype(tolua_S, 2, "cLuaWindow", 0, &err))
- {
- cLuaWindow * LuaWnd = reinterpret_cast<cLuaWindow *>(wnd);
- // Only if not already referenced
- if (!LuaWnd->IsLuaReferenced())
- {
- int LuaRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX);
- if (LuaRef == LUA_REFNIL)
- {
- LOGWARNING("%s: Cannot create a window reference. Cannot open window \"%s\".",
- __FUNCTION__, wnd->GetWindowTitle().c_str()
- );
- return 0;
- }
- LuaWnd->SetLuaRef(Plugin, LuaRef);
- }
- }
-
- // Open the window
- self->OpenWindow(wnd);
- return 0;
-}
-
-
-
-
-
static int tolua_cPlayer_PermissionMatches(lua_State * tolua_S)
{
// Function signature: cPlayer:PermissionMatches(PermissionStr, TemplateStr) -> bool
@@ -1679,36 +1630,25 @@ static int tolua_cPlayer_PermissionMatches(lua_State * tolua_S)
template <
class OBJTYPE,
- void (OBJTYPE::*SetCallback)(cPluginLua * a_Plugin, int a_FnRef)
+ void (OBJTYPE::*SetCallback)(cLuaState::cCallbackPtr a_CallbackFn)
>
static int tolua_SetObjectCallback(lua_State * tolua_S)
{
// Function signature: OBJTYPE:SetWhateverCallback(CallbackFunction)
- // Retrieve the plugin instance from the Lua state
- cPluginLua * Plugin = cManualBindings::GetLuaPlugin(tolua_S);
- if (Plugin == nullptr)
- {
- // Warning message has already been printed by GetLuaPlugin(), bail out silently
- return 0;
- }
-
// Get the parameters - self and the function reference:
- OBJTYPE * self = reinterpret_cast<OBJTYPE *>(tolua_tousertype(tolua_S, 1, nullptr));
- if (self == nullptr)
- {
- LOGWARNING("%s: invalid self (%p)", __FUNCTION__, static_cast<void *>(self));
- return 0;
- }
- int FnRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); // Store function reference for later retrieval
- if (FnRef == LUA_REFNIL)
+ cLuaState L(tolua_S);
+ OBJTYPE * self;
+ cLuaState::cCallbackPtr callback;
+ if (!L.GetStackValues(1, self, callback))
{
- LOGERROR("%s: Cannot create a function reference. Callback not set.", __FUNCTION__);
+ LOGWARNING("%s: Cannot get parameters", __FUNCTION__);
+ L.LogStackTrace();
return 0;
}
// Set the callback
- (self->*SetCallback)(Plugin, FnRef);
+ (self->*SetCallback)(callback);
return 0;
}
@@ -2800,6 +2740,79 @@ static int tolua_cLineBlockTracer_Trace(lua_State * tolua_S)
+static int tolua_cLuaWindow_new(lua_State * tolua_S)
+{
+ // Function signature:
+ // cLuaWindow:new(type, slotsX, slotsY, title)
+
+ // Check params:
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamUserTable(1, "cLuaWindow") ||
+ !L.CheckParamNumber(2, 4) ||
+ !L.CheckParamString(5) ||
+ !L.CheckParamEnd(6)
+ )
+ {
+ return 0;
+ }
+
+ // Read params:
+ int windowType, slotsX, slotsY;
+ AString title;
+ if (!L.GetStackValues(2, windowType, slotsX, slotsY, title))
+ {
+ LOGWARNING("%s: Cannot read Lua parameters", __FUNCTION__);
+ L.LogStackValues();
+ L.LogStackTrace();
+ }
+
+ // Create the window and return it:
+ L.Push(new cLuaWindow(L, static_cast<cLuaWindow::WindowType>(windowType), slotsX, slotsY, title));
+ return 1;
+}
+
+
+
+
+
+static int tolua_cLuaWindow_new_local(lua_State * tolua_S)
+{
+ // Function signature:
+ // cLuaWindow:new(type, slotsX, slotsY, title)
+
+ // Check params:
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamUserTable(1, "cLuaWindow") ||
+ !L.CheckParamNumber(2, 4) ||
+ !L.CheckParamString(5) ||
+ !L.CheckParamEnd(6)
+ )
+ {
+ return 0;
+ }
+
+ // Read params:
+ int windowType, slotsX, slotsY;
+ AString title;
+ if (!L.GetStackValues(2, windowType, slotsX, slotsY, title))
+ {
+ LOGWARNING("%s: Cannot read Lua parameters", __FUNCTION__);
+ L.LogStackValues();
+ L.LogStackTrace();
+ }
+
+ // Create the window, register it for GC and return it:
+ L.Push(new cLuaWindow(L, static_cast<cLuaWindow::WindowType>(windowType), slotsX, slotsY, title));
+ tolua_register_gc(tolua_S, lua_gettop(tolua_S));
+ return 1;
+}
+
+
+
+
+
static int tolua_cRoot_GetBuildCommitID(lua_State * tolua_S)
{
cLuaState L(tolua_S);
@@ -3343,7 +3356,7 @@ static int tolua_cBoundingBox_CalcLineIntersection(lua_State * a_LuaState)
const cBoundingBox * bbox;
if (!L.GetStackValues(1, bbox, pt1, pt2)) // Try the regular signature
{
- L.LogStack();
+ L.LogStackValues();
tolua_error(a_LuaState, "Invalid function params. Expected either bbox:CalcLineIntersection(pt1, pt2) or cBoundingBox:CalcLineIntersection(min, max, pt1, pt2).", nullptr);
return 0;
}
@@ -3373,7 +3386,7 @@ static int tolua_cBoundingBox_Intersect(lua_State * a_LuaState)
const cBoundingBox * other;
if (!L.GetStackValues(1, self, other))
{
- L.LogStack();
+ L.LogStackValues();
tolua_error(a_LuaState, "Invalid function params. Expected bbox:Intersect(otherBbox).", nullptr);
return 0;
}
@@ -3746,6 +3759,9 @@ void cManualBindings::Bind(lua_State * tolua_S)
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cLuaWindow");
+ tolua_function(tolua_S, "new", tolua_cLuaWindow_new);
+ tolua_function(tolua_S, "new_local", tolua_cLuaWindow_new_local);
+ tolua_function(tolua_S, ".call", tolua_cLuaWindow_new_local);
tolua_function(tolua_S, "SetOnClosing", tolua_SetObjectCallback<cLuaWindow, &cLuaWindow::SetOnClosing>);
tolua_function(tolua_S, "SetOnSlotChanged", tolua_SetObjectCallback<cLuaWindow, &cLuaWindow::SetOnSlotChanged>);
tolua_endmodule(tolua_S);
@@ -3766,7 +3782,6 @@ void cManualBindings::Bind(lua_State * tolua_S)
tolua_beginmodule(tolua_S, "cPlayer");
tolua_function(tolua_S, "GetPermissions", tolua_cPlayer_GetPermissions);
tolua_function(tolua_S, "GetRestrictions", tolua_cPlayer_GetRestrictions);
- tolua_function(tolua_S, "OpenWindow", tolua_cPlayer_OpenWindow);
tolua_function(tolua_S, "PermissionMatches", tolua_cPlayer_PermissionMatches);
tolua_endmodule(tolua_S);
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index 2f1e892dc..f6e9da45e 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -224,11 +224,11 @@ public:
cWindow * GetWindow(void) { return m_CurrentWindow; } // tolua_export
const cWindow * GetWindow(void) const { return m_CurrentWindow; }
- /** Opens the specified window; closes the current one first using CloseWindow() */
- void OpenWindow(cWindow * a_Window); // Exported in ManualBindings.cpp
-
// tolua_begin
+ /** Opens the specified window; closes the current one first using CloseWindow() */
+ void OpenWindow(cWindow * a_Window);
+
/** Closes the current window, resets current window to m_InventoryWindow. A plugin may refuse the closing if a_CanRefuse is true */
void CloseWindow(bool a_CanRefuse = true);
diff --git a/src/UI/Window.cpp b/src/UI/Window.cpp
index 5a2e55feb..4582d6cf4 100644
--- a/src/UI/Window.cpp
+++ b/src/UI/Window.cpp
@@ -307,7 +307,7 @@ bool cWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse)
// Checks whether the player is still holding an item
if (!a_Player.GetDraggingItem().IsEmpty())
{
- LOGD("Player holds item! Dropping it...");
+ LOGD("Player is holding an item while closing their window, dropping it as a pickup...");
a_Player.TossHeldItem(a_Player.GetDraggingItem().m_ItemCount);
}