1
0
Fork 0

Changed cLuaWindow callbacks to use cLuaState::cCallback.

This commit is contained in:
Mattes D 2016-06-10 21:30:07 +02:00
parent a473725121
commit fb4c3fc4d9
7 changed files with 245 additions and 185 deletions

View File

@ -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) void cLuaState::cCallback::Invalidate(void)
{ {
cCSLock Lock(m_CS); 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) bool cLuaState::GetStackValue(int a_StackPos, AString & a_Value)
{ {
size_t len = 0; 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 // Format string consisting only of %s is used to appease the compiler
LOG("%s", (a_Header != nullptr) ? a_Header : "Lua C API Stack contents:"); 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) int cLuaState::ReportFnCallErrors(lua_State * a_LuaState)
{ {
LOGWARNING("LUA: %s", lua_tostring(a_LuaState, -1)); 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) void cLuaState::TrackCallback(cCallback & a_Callback)
{ {
// Get the CanonLuaState global from Lua: // Get the CanonLuaState global from Lua:
auto cb = WalkToNamedGlobal(g_CanonLuaStateGlobalName); auto canonState = QueryCanonLuaState();
if (!cb.IsValid()) if (canonState == nullptr)
{ {
LOGWARNING("%s: Lua state %p has invalid CanonLuaState!", __FUNCTION__, reinterpret_cast<void *>(m_LuaState)); LOGWARNING("%s: Lua state %p has invalid CanonLuaState!", __FUNCTION__, reinterpret_cast<void *>(m_LuaState));
return; return;
} }
auto & canonState = *reinterpret_cast<cLuaState *>(lua_touserdata(m_LuaState, -1));
// Add the callback: // Add the callback:
cCSLock Lock(canonState.m_CSTrackedCallbacks); cCSLock Lock(canonState->m_CSTrackedCallbacks);
canonState.m_TrackedCallbacks.push_back(&a_Callback); canonState->m_TrackedCallbacks.push_back(&a_Callback);
} }
@ -1840,17 +1885,16 @@ void cLuaState::TrackCallback(cCallback & a_Callback)
void cLuaState::UntrackCallback(cCallback & a_Callback) void cLuaState::UntrackCallback(cCallback & a_Callback)
{ {
// Get the CanonLuaState global from Lua: // Get the CanonLuaState global from Lua:
auto cb = WalkToNamedGlobal(g_CanonLuaStateGlobalName); auto canonState = QueryCanonLuaState();
if (!cb.IsValid()) if (canonState == nullptr)
{ {
LOGWARNING("%s: Lua state %p has invalid CanonLuaState!", __FUNCTION__, reinterpret_cast<void *>(m_LuaState)); LOGWARNING("%s: Lua state %p has invalid CanonLuaState!", __FUNCTION__, reinterpret_cast<void *>(m_LuaState));
return; return;
} }
auto & canonState = *reinterpret_cast<cLuaState *>(lua_touserdata(m_LuaState, -1));
// Remove the callback: // Remove the callback:
cCSLock Lock(canonState.m_CSTrackedCallbacks); cCSLock Lock(canonState->m_CSTrackedCallbacks);
auto & trackedCallbacks = canonState.m_TrackedCallbacks; auto & trackedCallbacks = canonState->m_TrackedCallbacks;
trackedCallbacks.erase(std::remove_if(trackedCallbacks.begin(), trackedCallbacks.end(), trackedCallbacks.erase(std::remove_if(trackedCallbacks.begin(), trackedCallbacks.end(),
[&a_Callback](cCallback * a_StoredCallback) [&a_Callback](cCallback * a_StoredCallback)
{ {

View File

@ -83,6 +83,15 @@ public:
/** Returns the Lua state associated with the value. */ /** Returns the Lua state associated with the value. */
lua_State * GetLuaState(void) { return m_LuaState; } 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: protected:
lua_State * m_LuaState; lua_State * m_LuaState;
int m_Ref; int m_Ref;
@ -158,6 +167,10 @@ public:
/** Returns true if the contained callback is valid. */ /** Returns true if the contained callback is valid. */
bool IsValid(void); 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: protected:
friend class cLuaState; friend class cLuaState;
@ -330,6 +343,9 @@ public:
void Push(const UInt32 a_Value); void Push(const UInt32 a_Value);
void Push(std::chrono::milliseconds a_time); 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. // GetStackValue() retrieves the value at a_StackPos, if it is a valid type. If not, a_Value is unchanged.
// Returns whether value was changed // Returns whether value was changed
// Enum values are checked for their allowed values and fail if the value is not assigned. // 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); void ToString(int a_StackPos, AString & a_String);
/** Logs all the elements' types on the API stack, with an optional header for the listing. */ /** 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. */ /** 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: protected:

View File

@ -15,14 +15,13 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// cLuaWindow: // cLuaWindow:
cLuaWindow::cLuaWindow(cWindow::WindowType a_WindowType, int a_SlotsX, int a_SlotsY, const AString & 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), Super(a_WindowType, a_Title),
m_Contents(a_SlotsX, a_SlotsY), m_Contents(a_SlotsX, a_SlotsY),
m_Plugin(nullptr), m_LuaState(a_LuaState.QueryCanonLuaState())
m_LuaRef(LUA_REFNIL),
m_OnClosingFnRef(LUA_REFNIL),
m_OnSlotChangedFnRef(LUA_REFNIL)
{ {
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_Contents.AddListener(*this);
m_SlotAreas.push_back(new cSlotAreaItemGrid(m_Contents, *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 // Only one Lua state can be a cLuaWindow object callback:
ASSERT((m_Plugin == nullptr) || (m_Plugin == a_Plugin)); ASSERT(a_OnClosing->IsSameLuaState(*m_LuaState));
ASSERT(m_LuaRef == LUA_REFNIL);
m_Plugin = a_Plugin; // Store the new reference, releasing the old one if appropriate:
m_LuaRef = a_LuaRef; m_OnClosing = a_OnClosing;
} }
bool cLuaWindow::IsLuaReferenced(void) const void cLuaWindow::SetOnSlotChanged(cLuaState::cCallbackPtr a_OnSlotChanged)
{ {
return ((m_Plugin != nullptr) && (m_LuaRef != LUA_REFNIL)); // Only one Lua state can be a cLuaWindow object callback:
ASSERT(a_OnSlotChanged->IsSameLuaState(*m_LuaState));
// Store the new reference, releasing the old one if appropriate:
m_OnSlotChanged = a_OnSlotChanged;
} }
void cLuaWindow::SetOnClosing(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 // 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:
ASSERT((m_Plugin == nullptr) || (m_Plugin == a_Plugin)); if (m_PlayerCount == 0)
// If there already was a function, unreference it first
if (m_OnClosingFnRef != LUA_REFNIL)
{ {
m_Plugin->Unreference(m_OnClosingFnRef); m_LuaRef.CreateFromObject(*m_LuaState, this);
} }
// Store the new reference ++m_PlayerCount;
m_Plugin = a_Plugin; Super::OpenedByPlayer(a_Player);
m_OnClosingFnRef = a_FnRef;
}
void cLuaWindow::SetOnSlotChanged(cPluginLua * 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 == nullptr) || (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;
} }
@ -132,17 +111,27 @@ void cLuaWindow::SetOnSlotChanged(cPluginLua * a_Plugin, int a_FnRef)
bool cLuaWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) bool cLuaWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse)
{ {
// First notify the plugin through the registered callback: // First notify the plugin through the registered callback:
if (m_OnClosingFnRef != LUA_REFNIL) if (m_OnClosing != nullptr)
{ {
ASSERT(m_Plugin != nullptr); bool res;
if (m_Plugin->CallbackWindowClosing(m_OnClosingFnRef, *this, a_Player, a_CanRefuse)) 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) // The callback disagrees (the higher levels check the CanRefuse flag compliance)
return false; 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) void cLuaWindow::Destroy(void)
{ {
super::Destroy(); Super::Destroy();
if ((m_LuaRef != LUA_REFNIL) && (m_Plugin != nullptr))
{
// The object is referenced by Lua, un-reference it
m_Plugin->Unreference(m_LuaRef);
}
// Lua will take care of this object, it will garbage-collect it, so we must not delete it! // Lua will take care of this object, it will garbage-collect it, so we must not delete it!
m_IsDestroyed = false; 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 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);
} }
} }

View File

@ -9,6 +9,8 @@
#pragma once #pragma once
#include <atomic>
#include "LuaState.h"
#include "../UI/Window.h" #include "../UI/Window.h"
#include "../ItemGrid.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 /** 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: This object needs extra care with its lifetime management:
- It is created by Lua, so Lua expects to garbage-collect it later - 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 - 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() 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. 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 - Lua could GC the window while a player is still using it
cPlayer:OpenWindow check if the window is of this class, and if so, make a global Lua reference for this object. The object creates a Lua reference to itself when opened by a player and
This reference needs to be unreferenced in the Destroy() function. */ removes the reference when the last player closes the window.
*/
// tolua_begin // tolua_begin
class cLuaWindow : class cLuaWindow :
public cWindow public cWindow
// tolua_end // tolua_end
, public cItemGrid::cListener , public cItemGrid::cListener
// tolua_begin { // tolua_export
{ typedef cWindow Super;
typedef cWindow super;
public: public:
/** Create a window of the specified type, with a slot grid of a_SlotsX * a_SlotsY size */ /** 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); 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(); virtual ~cLuaWindow();
/** Returns the internal representation of the contents that are manipulated by Lua */ /** Returns the internal representation of the contents that are manipulated by Lua */
@ -52,36 +49,37 @@ public:
// tolua_end // tolua_end
/** Sets the plugin reference and the internal Lua object reference index /** Sets the Lua callback function to call when the window is about to close */
used for preventing Lua's GC to collect this class while the window is open. */ void SetOnClosing(cLuaState::cCallbackPtr a_OnClosing);
void SetLuaRef(cPluginLua * a_Plugin, int a_LuaRef);
/** Returns true if SetLuaRef() has been called */ /** Sets the Lua callback function to call when a slot is changed */
bool IsLuaReferenced(void) const; void SetOnSlotChanged(cLuaState::cCallbackPtr a_OnSlotChanged);
/** 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 callback function (Lua reference) to call when a slot is changed */
void SetOnSlotChanged(cPluginLua * a_Plugin, int a_FnRef);
protected: protected:
/** Contents of the non-inventory part */ /** Contents of the non-inventory part */
cItemGrid m_Contents; cItemGrid m_Contents;
/** The plugin that has opened the window and owns the m_LuaRef */ /** The Lua state that has opened the window and owns the m_LuaRef */
cPluginLua * m_Plugin; cLuaState * m_LuaState;
/** The Lua object reference, used for keeping the object alive as long as any player has the window open */ /** The Lua callback to call when the window is closing for any player */
int m_LuaRef; cLuaState::cCallbackPtr m_OnClosing;
/** The Lua reference for the callback to call when the window is closing for any player */ /** The Lua callback to call when a slot has changed */
int m_OnClosingFnRef; cLuaState::cCallbackPtr m_OnSlotChanged;
/** Number of players that are currently using the window.
Used to manager the m_LuaRef lifetime. */
std::atomic<int> m_PlayerCount;
/** 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: // cWindow overrides:
virtual void OpenedByPlayer(cPlayer & a_Player) override;
virtual bool ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) override; virtual bool ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) override;
virtual void Destroy(void) 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; virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override;

View File

@ -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) static int tolua_cPlayer_PermissionMatches(lua_State * tolua_S)
{ {
// Function signature: cPlayer:PermissionMatches(PermissionStr, TemplateStr) -> bool // Function signature: cPlayer:PermissionMatches(PermissionStr, TemplateStr) -> bool
@ -1679,36 +1630,25 @@ static int tolua_cPlayer_PermissionMatches(lua_State * tolua_S)
template < template <
class OBJTYPE, 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) static int tolua_SetObjectCallback(lua_State * tolua_S)
{ {
// Function signature: OBJTYPE:SetWhateverCallback(CallbackFunction) // 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: // Get the parameters - self and the function reference:
OBJTYPE * self = reinterpret_cast<OBJTYPE *>(tolua_tousertype(tolua_S, 1, nullptr)); cLuaState L(tolua_S);
if (self == nullptr) OBJTYPE * self;
cLuaState::cCallbackPtr callback;
if (!L.GetStackValues(1, self, callback))
{ {
LOGWARNING("%s: invalid self (%p)", __FUNCTION__, static_cast<void *>(self)); LOGWARNING("%s: Cannot get parameters", __FUNCTION__);
return 0; L.LogStackTrace();
}
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__);
return 0; return 0;
} }
// Set the callback // Set the callback
(self->*SetCallback)(Plugin, FnRef); (self->*SetCallback)(callback);
return 0; 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) static int tolua_cRoot_GetBuildCommitID(lua_State * tolua_S)
{ {
cLuaState L(tolua_S); cLuaState L(tolua_S);
@ -3343,7 +3356,7 @@ static int tolua_cBoundingBox_CalcLineIntersection(lua_State * a_LuaState)
const cBoundingBox * bbox; const cBoundingBox * bbox;
if (!L.GetStackValues(1, bbox, pt1, pt2)) // Try the regular signature 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); tolua_error(a_LuaState, "Invalid function params. Expected either bbox:CalcLineIntersection(pt1, pt2) or cBoundingBox:CalcLineIntersection(min, max, pt1, pt2).", nullptr);
return 0; return 0;
} }
@ -3373,7 +3386,7 @@ static int tolua_cBoundingBox_Intersect(lua_State * a_LuaState)
const cBoundingBox * other; const cBoundingBox * other;
if (!L.GetStackValues(1, self, other)) if (!L.GetStackValues(1, self, other))
{ {
L.LogStack(); L.LogStackValues();
tolua_error(a_LuaState, "Invalid function params. Expected bbox:Intersect(otherBbox).", nullptr); tolua_error(a_LuaState, "Invalid function params. Expected bbox:Intersect(otherBbox).", nullptr);
return 0; return 0;
} }
@ -3746,6 +3759,9 @@ void cManualBindings::Bind(lua_State * tolua_S)
tolua_endmodule(tolua_S); tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cLuaWindow"); 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, "SetOnClosing", tolua_SetObjectCallback<cLuaWindow, &cLuaWindow::SetOnClosing>);
tolua_function(tolua_S, "SetOnSlotChanged", tolua_SetObjectCallback<cLuaWindow, &cLuaWindow::SetOnSlotChanged>); tolua_function(tolua_S, "SetOnSlotChanged", tolua_SetObjectCallback<cLuaWindow, &cLuaWindow::SetOnSlotChanged>);
tolua_endmodule(tolua_S); tolua_endmodule(tolua_S);
@ -3766,7 +3782,6 @@ void cManualBindings::Bind(lua_State * tolua_S)
tolua_beginmodule(tolua_S, "cPlayer"); tolua_beginmodule(tolua_S, "cPlayer");
tolua_function(tolua_S, "GetPermissions", tolua_cPlayer_GetPermissions); tolua_function(tolua_S, "GetPermissions", tolua_cPlayer_GetPermissions);
tolua_function(tolua_S, "GetRestrictions", tolua_cPlayer_GetRestrictions); 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_function(tolua_S, "PermissionMatches", tolua_cPlayer_PermissionMatches);
tolua_endmodule(tolua_S); tolua_endmodule(tolua_S);

View File

@ -224,11 +224,11 @@ public:
cWindow * GetWindow(void) { return m_CurrentWindow; } // tolua_export cWindow * GetWindow(void) { return m_CurrentWindow; } // tolua_export
const cWindow * GetWindow(void) const { return m_CurrentWindow; } 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 // 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 */ /** 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); void CloseWindow(bool a_CanRefuse = true);

View File

@ -307,7 +307,7 @@ bool cWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse)
// Checks whether the player is still holding an item // Checks whether the player is still holding an item
if (!a_Player.GetDraggingItem().IsEmpty()) 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); a_Player.TossHeldItem(a_Player.GetDraggingItem().m_ItemCount);
} }