mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2025-02-21 20:27:13 +01:00
Implement association of arbitrary user data in command listeners.
Also keep track of all listener instances by having them link to eachother as a double linked list. This should make it easy to release any script resources at shutdown. Now that all listeners are being tracked, binding callbacks is less strict and does not require a listener to be attached anymore.
This commit is contained in:
parent
0111cc5a46
commit
4ad9402d8a
@ -8,6 +8,9 @@ namespace Cmd {
|
|||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
Controllers Controller::s_Controllers;
|
Controllers Controller::s_Controllers;
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
Listener * Listener::s_Head = nullptr;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
SQInteger Manager::Typename(HSQUIRRELVM vm)
|
SQInteger Manager::Typename(HSQUIRRELVM vm)
|
||||||
{
|
{
|
||||||
@ -1090,6 +1093,7 @@ void Register(HSQUIRRELVM vm)
|
|||||||
.Prop(_SC("Attached"), &Listener::Attached)
|
.Prop(_SC("Attached"), &Listener::Attached)
|
||||||
.Prop(_SC("Manager"), &Listener::GetManager)
|
.Prop(_SC("Manager"), &Listener::GetManager)
|
||||||
.Prop(_SC("Name"), &Listener::GetName, &Listener::SetName)
|
.Prop(_SC("Name"), &Listener::GetName, &Listener::SetName)
|
||||||
|
.Prop(_SC("Data"), &Listener::GetData, &Listener::SetData)
|
||||||
.Prop(_SC("Spec"), &Listener::GetSpec, &Listener::SetSpec)
|
.Prop(_SC("Spec"), &Listener::GetSpec, &Listener::SetSpec)
|
||||||
.Prop(_SC("Specifier"), &Listener::GetSpec, &Listener::SetSpec)
|
.Prop(_SC("Specifier"), &Listener::GetSpec, &Listener::SetSpec)
|
||||||
.Prop(_SC("Tags"), &Listener::GetArgTags, &Listener::SetArgTags)
|
.Prop(_SC("Tags"), &Listener::GetArgTags, &Listener::SetArgTags)
|
||||||
@ -1168,6 +1172,7 @@ void Register_Command(HSQUIRRELVM vm)
|
|||||||
void TerminateCommands()
|
void TerminateCommands()
|
||||||
{
|
{
|
||||||
Cmd::Controller::Terminate();
|
Cmd::Controller::Terminate();
|
||||||
|
Cmd::Listener::Terminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // Namespace:: SqMod
|
} // Namespace:: SqMod
|
||||||
|
@ -1116,6 +1116,25 @@ class Listener
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Release any trace of script resources from all the listener instances.
|
||||||
|
*/
|
||||||
|
static void Terminate()
|
||||||
|
{
|
||||||
|
// Go forward and release resources
|
||||||
|
for (Listener * node = s_Head; node != nullptr; node = node->m_Next)
|
||||||
|
{
|
||||||
|
node->m_Data.Release();
|
||||||
|
}
|
||||||
|
// Go backwards and release resources
|
||||||
|
for (Listener * node = s_Head; node != nullptr; node = node->m_Prev)
|
||||||
|
{
|
||||||
|
node->m_Data.Release();
|
||||||
|
}
|
||||||
|
// Kinda useless but Squirrel doesn't play nice with loose references
|
||||||
|
// Better safe than sorry
|
||||||
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Convenience constructor.
|
* Convenience constructor.
|
||||||
*/
|
*/
|
||||||
@ -1200,6 +1219,8 @@ public:
|
|||||||
, m_Protected(prot)
|
, m_Protected(prot)
|
||||||
, m_Suspended(false)
|
, m_Suspended(false)
|
||||||
, m_Associate(assoc)
|
, m_Associate(assoc)
|
||||||
|
, m_Prev(nullptr)
|
||||||
|
, m_Next(s_Head)
|
||||||
{
|
{
|
||||||
// Initialize the specifiers to default values
|
// Initialize the specifiers to default values
|
||||||
for (Uint8 n = 0; n < SQMOD_MAX_CMD_ARGS; ++n)
|
for (Uint8 n = 0; n < SQMOD_MAX_CMD_ARGS; ++n)
|
||||||
@ -1215,6 +1236,22 @@ public:
|
|||||||
SetMaxArgC(max);
|
SetMaxArgC(max);
|
||||||
// Generate information for the command
|
// Generate information for the command
|
||||||
GenerateInfo(false);
|
GenerateInfo(false);
|
||||||
|
// We're the head element now
|
||||||
|
s_Head = this;
|
||||||
|
// Was there a previous head?
|
||||||
|
if (m_Next != nullptr)
|
||||||
|
{
|
||||||
|
// Steal previous element from previous head
|
||||||
|
m_Prev = m_Next->m_Prev;
|
||||||
|
// Did that head element had a previous element?
|
||||||
|
if (m_Prev != nullptr)
|
||||||
|
{
|
||||||
|
// Tell it we're the next element now
|
||||||
|
m_Prev->m_Next = this;
|
||||||
|
}
|
||||||
|
// Tell the previous head that we're the previous element now
|
||||||
|
m_Next->m_Prev = this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
@ -1242,6 +1279,23 @@ public:
|
|||||||
m_OnAuth.ReleaseGently();
|
m_OnAuth.ReleaseGently();
|
||||||
m_OnPost.ReleaseGently();
|
m_OnPost.ReleaseGently();
|
||||||
m_OnFail.ReleaseGently();
|
m_OnFail.ReleaseGently();
|
||||||
|
// Is there an element behind us?
|
||||||
|
if (m_Prev != nullptr)
|
||||||
|
{
|
||||||
|
// Tell it to point to the element ahead of us
|
||||||
|
m_Prev->m_Next = m_Next;
|
||||||
|
}
|
||||||
|
// Is there an element ahead of us?
|
||||||
|
if (m_Next != nullptr)
|
||||||
|
{
|
||||||
|
// Tell it to point to the element behind us
|
||||||
|
m_Next->m_Prev = m_Prev;
|
||||||
|
}
|
||||||
|
// Are we the head element in the chain?
|
||||||
|
if (s_Head == this)
|
||||||
|
{
|
||||||
|
s_Head = m_Next == nullptr ? m_Prev : m_Next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
@ -1387,6 +1441,22 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve the associated user data.
|
||||||
|
*/
|
||||||
|
Object & GetData()
|
||||||
|
{
|
||||||
|
return m_Data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Modify the associated user data.
|
||||||
|
*/
|
||||||
|
void SetData(Object & data)
|
||||||
|
{
|
||||||
|
m_Data = data;
|
||||||
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Retrieve the argument specification string.
|
* Retrieve the argument specification string.
|
||||||
*/
|
*/
|
||||||
@ -1645,13 +1715,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
void SetOnExec(Object & env, Function & func)
|
void SetOnExec(Object & env, Function & func)
|
||||||
{
|
{
|
||||||
// Make sure that we are allowed to store script resources
|
|
||||||
if (m_Controller.Expired())
|
|
||||||
{
|
|
||||||
STHROWF("Detached commands cannot store script resources");
|
|
||||||
}
|
|
||||||
// Are we supposed to unbind current callback?
|
// Are we supposed to unbind current callback?
|
||||||
else if (func.IsNull())
|
if (func.IsNull())
|
||||||
{
|
{
|
||||||
m_OnExec.ReleaseGently();
|
m_OnExec.ReleaseGently();
|
||||||
}
|
}
|
||||||
@ -1679,13 +1744,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
void SetOnAuth(Object & env, Function & func)
|
void SetOnAuth(Object & env, Function & func)
|
||||||
{
|
{
|
||||||
// Make sure that we are allowed to store script resources
|
|
||||||
if (m_Controller.Expired())
|
|
||||||
{
|
|
||||||
STHROWF("Detached commands cannot store script resources");
|
|
||||||
}
|
|
||||||
// Are we supposed to unbind current callback?
|
// Are we supposed to unbind current callback?
|
||||||
else if (func.IsNull())
|
if (func.IsNull())
|
||||||
{
|
{
|
||||||
m_OnAuth.ReleaseGently();
|
m_OnAuth.ReleaseGently();
|
||||||
}
|
}
|
||||||
@ -1713,13 +1773,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
void SetOnPost(Object & env, Function & func)
|
void SetOnPost(Object & env, Function & func)
|
||||||
{
|
{
|
||||||
// Make sure that we are allowed to store script resources
|
|
||||||
if (m_Controller.Expired())
|
|
||||||
{
|
|
||||||
STHROWF("Detached listeners cannot store script resources");
|
|
||||||
}
|
|
||||||
// Are we supposed to unbind current callback?
|
// Are we supposed to unbind current callback?
|
||||||
else if (func.IsNull())
|
if (func.IsNull())
|
||||||
{
|
{
|
||||||
m_OnPost.ReleaseGently();
|
m_OnPost.ReleaseGently();
|
||||||
}
|
}
|
||||||
@ -1747,13 +1802,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
void SetOnFail(Object & env, Function & func)
|
void SetOnFail(Object & env, Function & func)
|
||||||
{
|
{
|
||||||
// Make sure that we are allowed to store script resources
|
|
||||||
if (m_Controller.Expired())
|
|
||||||
{
|
|
||||||
STHROWF("Detached listeners cannot store script resources");
|
|
||||||
}
|
|
||||||
// Are we supposed to unbind current callback?
|
// Are we supposed to unbind current callback?
|
||||||
else if (func.IsNull())
|
if (func.IsNull())
|
||||||
{
|
{
|
||||||
m_OnFail.ReleaseGently();
|
m_OnFail.ReleaseGently();
|
||||||
}
|
}
|
||||||
@ -1914,6 +1964,7 @@ private:
|
|||||||
|
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
String m_Name; // Name of the command that triggers this listener.
|
String m_Name; // Name of the command that triggers this listener.
|
||||||
|
Object m_Data; // Arbitrary user data associated with this particular instance.
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
ArgSpec m_ArgSpec; // List of argument type specifications.
|
ArgSpec m_ArgSpec; // List of argument type specifications.
|
||||||
@ -1941,6 +1992,13 @@ private:
|
|||||||
bool m_Protected; // Whether explicit authentication of the invoker is required.
|
bool m_Protected; // Whether explicit authentication of the invoker is required.
|
||||||
bool m_Suspended; // Whether this command should block further invocations.
|
bool m_Suspended; // Whether this command should block further invocations.
|
||||||
bool m_Associate; // Whether arguments are sent as table instead of array.
|
bool m_Associate; // Whether arguments are sent as table instead of array.
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------------
|
||||||
|
Listener * m_Prev; // Previous listener in the chain.
|
||||||
|
Listener * m_Next; // Next listener in the chain.
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------------
|
||||||
|
static Listener * s_Head; // The head of the listener chain.
|
||||||
};
|
};
|
||||||
|
|
||||||
} // Namespace:: Cmd
|
} // Namespace:: Cmd
|
||||||
|
Loading…
x
Reference in New Issue
Block a user