Changed cLuaWindow callbacks to use cLuaState::cCallback.
This commit is contained in:
parent
5dfcc15d1f
commit
af200dfaae
@ -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;
|
||||
@ -1647,7 +1678,7 @@ int cLuaState::CopyStackFrom(cLuaState & a_SrcLuaState, int a_SrcStart, int a_Sr
|
||||
LOGWARNING("%s: Unsupported value: '%s' at stack position %d. Can only copy numbers, strings, bools and classes!",
|
||||
__FUNCTION__, lua_typename(a_SrcLuaState, t), i
|
||||
);
|
||||
a_SrcLuaState.LogStack("Stack where copying failed:");
|
||||
a_SrcLuaState.LogStackValues("Stack where copying failed:");
|
||||
lua_pop(m_LuaState, i - a_SrcStart);
|
||||
return -1;
|
||||
}
|
||||
@ -1674,16 +1705,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:");
|
||||
@ -1708,6 +1739,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));
|
||||
@ -1745,17 +1791,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);
|
||||
}
|
||||
|
||||
|
||||
@ -1765,17 +1810,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)
|
||||
{
|
||||
|
@ -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.
|
||||
@ -499,10 +515,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:
|
||||
|
||||
|
@ -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));
|
||||
|
||||
// Store the new reference, releasing the old one if appropriate:
|
||||
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
|
||||
ASSERT((m_Plugin == nullptr) || (m_Plugin == a_Plugin));
|
||||
|
||||
// If there already was a function, unreference it first
|
||||
if (m_OnClosingFnRef != 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_OnClosingFnRef);
|
||||
m_LuaRef.CreateFromObject(*m_LuaState, this);
|
||||
}
|
||||
|
||||
// Store the new reference
|
||||
m_Plugin = a_Plugin;
|
||||
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;
|
||||
++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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
/** Sets the Lua callback function to call when the window is about to close */
|
||||
void SetOnClosing(cLuaState::cCallbackPtr a_OnClosing);
|
||||
|
||||
/** 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 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 object reference, used for keeping the object alive as long as any player has the window open */
|
||||
int m_LuaRef;
|
||||
/** The Lua callback to call when the window is closing for any player */
|
||||
cLuaState::cCallbackPtr m_OnClosing;
|
||||
|
||||
/** The Lua reference for the callback to call when the window is closing for any player */
|
||||
int m_OnClosingFnRef;
|
||||
/** The Lua callback to call when a slot has changed */
|
||||
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:
|
||||
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;
|
||||
|
@ -1599,55 +1599,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
|
||||
@ -1678,36 +1629,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)
|
||||
cLuaState L(tolua_S);
|
||||
OBJTYPE * self;
|
||||
cLuaState::cCallbackPtr callback;
|
||||
if (!L.GetStackValues(1, self, callback))
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@ -2799,6 +2739,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);
|
||||
@ -3642,6 +3655,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);
|
||||
@ -3662,7 +3678,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);
|
||||
|
||||
|
@ -225,11 +225,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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user