diff options
author | Mattes D <github@xoft.cz> | 2016-06-10 21:30:07 +0200 |
---|---|---|
committer | Mattes D <github@xoft.cz> | 2016-06-27 20:51:50 +0200 |
commit | fb4c3fc4d9325c28b8640f0e717e5e320334a7c6 (patch) | |
tree | b1d7eef0cb2311acc421eb5e2abae68139e9b250 | |
parent | Removed the cPluginLua::cResettable class. (diff) | |
download | cuberite-fb4c3fc4d9325c28b8640f0e717e5e320334a7c6.tar cuberite-fb4c3fc4d9325c28b8640f0e717e5e320334a7c6.tar.gz cuberite-fb4c3fc4d9325c28b8640f0e717e5e320334a7c6.tar.bz2 cuberite-fb4c3fc4d9325c28b8640f0e717e5e320334a7c6.tar.lz cuberite-fb4c3fc4d9325c28b8640f0e717e5e320334a7c6.tar.xz cuberite-fb4c3fc4d9325c28b8640f0e717e5e320334a7c6.tar.zst cuberite-fb4c3fc4d9325c28b8640f0e717e5e320334a7c6.zip |
-rw-r--r-- | src/Bindings/LuaState.cpp | 70 | ||||
-rw-r--r-- | src/Bindings/LuaState.h | 24 | ||||
-rw-r--r-- | src/Bindings/LuaWindow.cpp | 95 | ||||
-rw-r--r-- | src/Bindings/LuaWindow.h | 72 | ||||
-rw-r--r-- | src/Bindings/ManualBindings.cpp | 157 | ||||
-rw-r--r-- | src/Entities/Player.h | 6 | ||||
-rw-r--r-- | src/UI/Window.cpp | 2 |
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); } |