mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2024-11-08 00:37:15 +01:00
Implement command alias.
This commit is contained in:
parent
6b8da10deb
commit
5b155731fa
@ -39,7 +39,10 @@ Command::Command(std::size_t hash, String name, Listener * ptr, CtrPtr ctr)
|
|||||||
{
|
{
|
||||||
if (mPtr)
|
if (mPtr)
|
||||||
{
|
{
|
||||||
mPtr->m_Controller = mCtr; // Create controller association
|
// Create controller association
|
||||||
|
mPtr->m_Controller = mCtr;
|
||||||
|
// Increment alias count
|
||||||
|
mPtr->AddAliases(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@ -48,7 +51,10 @@ Command::Command(std::size_t hash, String name, const Object & obj, CtrPtr ctr)
|
|||||||
{
|
{
|
||||||
if (mPtr)
|
if (mPtr)
|
||||||
{
|
{
|
||||||
mPtr->m_Controller = mCtr; // Create controller association
|
// Create controller association
|
||||||
|
mPtr->m_Controller = mCtr;
|
||||||
|
// Increment alias count
|
||||||
|
mPtr->AddAliases(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +64,10 @@ Command::Command(std::size_t hash, String name, Object && obj, CtrPtr ctr)
|
|||||||
{
|
{
|
||||||
if (mPtr)
|
if (mPtr)
|
||||||
{
|
{
|
||||||
mPtr->m_Controller = mCtr; // Create controller association
|
// Create controller association
|
||||||
|
mPtr->m_Controller = mCtr;
|
||||||
|
// Increment alias count
|
||||||
|
mPtr->AddAliases(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +77,10 @@ Command::Command(std::size_t hash, String name, Listener * ptr, const Object & o
|
|||||||
{
|
{
|
||||||
if (mPtr)
|
if (mPtr)
|
||||||
{
|
{
|
||||||
mPtr->m_Controller = mCtr; // Create controller association
|
// Create controller association
|
||||||
|
mPtr->m_Controller = mCtr;
|
||||||
|
// Increment alias count
|
||||||
|
mPtr->AddAliases(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,7 +90,10 @@ Command::Command(std::size_t hash, String name, Listener * ptr, Object && obj, C
|
|||||||
{
|
{
|
||||||
if (mPtr)
|
if (mPtr)
|
||||||
{
|
{
|
||||||
mPtr->m_Controller = mCtr; // Create controller association
|
// Create controller association
|
||||||
|
mPtr->m_Controller = mCtr;
|
||||||
|
// Increment alias count
|
||||||
|
mPtr->AddAliases(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,7 +102,12 @@ Command::~Command()
|
|||||||
{
|
{
|
||||||
if (mPtr)
|
if (mPtr)
|
||||||
{
|
{
|
||||||
mPtr->m_Controller.Reset(); // Break controller association
|
// The listener will continue to be associated with the controller as long as an alias points to it
|
||||||
|
if (mPtr->SubAliases(1) == 0)
|
||||||
|
{
|
||||||
|
// Break controller association
|
||||||
|
mPtr->m_Controller.Reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,6 +170,63 @@ Object & Controller::Attach(Object && obj, Listener * ptr)
|
|||||||
return m_Commands.back().mObj;
|
return m_Commands.back().mObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
Object & Controller::Attach(Object && obj, Listener * ptr, String name)
|
||||||
|
{
|
||||||
|
// Is there anything that we can attach
|
||||||
|
if (obj.IsNull() && ptr == nullptr)
|
||||||
|
{
|
||||||
|
STHROWF("Cannot attach invalid command listener");
|
||||||
|
}
|
||||||
|
// Are we supposed to grab the object?
|
||||||
|
else if (obj.IsNull())
|
||||||
|
{
|
||||||
|
// Obtain the initial stack size
|
||||||
|
const StackGuard sg;
|
||||||
|
// Push the instance on the stack
|
||||||
|
ClassType< Listener >::PushInstance(SqVM(), ptr);
|
||||||
|
// Grab the instance from the stack
|
||||||
|
obj = Var< Object >(SqVM(), -1).value;
|
||||||
|
}
|
||||||
|
// Are we supposed to grab the instance?
|
||||||
|
else if (ptr == nullptr)
|
||||||
|
{
|
||||||
|
// Obtain the initial stack size
|
||||||
|
const StackGuard sg(obj.GetVM());
|
||||||
|
// Push the object on the stack
|
||||||
|
Var< Object & >::push(obj.GetVM(), obj);
|
||||||
|
// Grab the instance from the stack
|
||||||
|
ptr = Var< Listener * >(obj.GetVM(), -1).value;
|
||||||
|
}
|
||||||
|
// At this point we should have both the instance and the object
|
||||||
|
if (obj.IsNull() || ptr == nullptr)
|
||||||
|
{
|
||||||
|
STHROWF("Unable to obtain the command listener");
|
||||||
|
}
|
||||||
|
// Validate the command name
|
||||||
|
if (name.empty())
|
||||||
|
{
|
||||||
|
STHROWF("Cannot attach command without a name");
|
||||||
|
}
|
||||||
|
// Obtain the unique identifier of the specified name
|
||||||
|
const std::size_t hash = std::hash< String >()(name);
|
||||||
|
// Make sure the command doesn't already exist
|
||||||
|
for (const auto & cmd : m_Commands)
|
||||||
|
{
|
||||||
|
// Are the hashes identical?
|
||||||
|
if (cmd.mHash == hash)
|
||||||
|
{
|
||||||
|
// Include information necessary to help identify hash collisions!
|
||||||
|
STHROWF("Command '{}' already exists as '{}' for hash ({})",
|
||||||
|
name.c_str(), cmd.mName.c_str(), hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Attempt to insert the command
|
||||||
|
m_Commands.emplace_back(hash, std::move(name), ptr, std::move(obj), m_Manager->GetCtr());
|
||||||
|
// Return the script object of the listener
|
||||||
|
return m_Commands.back().mObj;
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
Object Manager::Create(StackStrF & name, StackStrF & spec, Array & tags, uint8_t min, uint8_t max, SQInteger auth, bool prot, bool assoc)
|
Object Manager::Create(StackStrF & name, StackStrF & spec, Array & tags, uint8_t min, uint8_t max, SQInteger auth, bool prot, bool assoc)
|
||||||
{
|
{
|
||||||
@ -933,6 +1010,19 @@ void Listener::GenerateInfo(bool full)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
Listener & Listener::Rebind(StackStrF & name)
|
||||||
|
{
|
||||||
|
if (m_Controller.Expired())
|
||||||
|
{
|
||||||
|
STHROWF("Command must be attached to a manager before having an alias.");
|
||||||
|
}
|
||||||
|
// Create an alias for this command listener
|
||||||
|
m_Controller.Lock()->Attach(Object{}, this, name.ToStr());
|
||||||
|
// Allow chaining
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Listener::ProcSpec(const SQChar * str)
|
void Listener::ProcSpec(const SQChar * str)
|
||||||
{
|
{
|
||||||
@ -1136,6 +1226,7 @@ void Register(HSQUIRRELVM vm)
|
|||||||
.Prop(_SC("Associate"), &Listener::GetAssociate, &Listener::SetAssociate)
|
.Prop(_SC("Associate"), &Listener::GetAssociate, &Listener::SetAssociate)
|
||||||
.Prop(_SC("MinArgs"), &Listener::GetMinArgC, &Listener::SetMinArgC)
|
.Prop(_SC("MinArgs"), &Listener::GetMinArgC, &Listener::SetMinArgC)
|
||||||
.Prop(_SC("MaxArgs"), &Listener::GetMaxArgC, &Listener::SetMaxArgC)
|
.Prop(_SC("MaxArgs"), &Listener::GetMaxArgC, &Listener::SetMaxArgC)
|
||||||
|
.Prop(_SC("AliasCount"), &Listener::GetAliases)
|
||||||
.Prop(_SC("OnExec"), &Listener::GetOnExec)
|
.Prop(_SC("OnExec"), &Listener::GetOnExec)
|
||||||
.Prop(_SC("OnAuth"), &Listener::GetOnAuth)
|
.Prop(_SC("OnAuth"), &Listener::GetOnAuth)
|
||||||
.Prop(_SC("OnAudit"), &Listener::GetOnAudit)
|
.Prop(_SC("OnAudit"), &Listener::GetOnAudit)
|
||||||
@ -1159,6 +1250,7 @@ void Register(HSQUIRRELVM vm)
|
|||||||
.Func(_SC("ArgCheck"), &Listener::ArgCheck)
|
.Func(_SC("ArgCheck"), &Listener::ArgCheck)
|
||||||
.Func(_SC("AuthCheck"), &Listener::AuthCheck)
|
.Func(_SC("AuthCheck"), &Listener::AuthCheck)
|
||||||
.Func(_SC("GenerateInfo"), &Listener::GenerateInfo)
|
.Func(_SC("GenerateInfo"), &Listener::GenerateInfo)
|
||||||
|
.FmtFunc(_SC("Rebind"), &Listener::Rebind)
|
||||||
);
|
);
|
||||||
|
|
||||||
RootTable(vm).Bind(_SC("SqCmd"), cmdns);
|
RootTable(vm).Bind(_SC("SqCmd"), cmdns);
|
||||||
|
@ -255,11 +255,11 @@ public:
|
|||||||
struct Command
|
struct Command
|
||||||
{
|
{
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
std::size_t mHash; // The unique hash that identifies this command.
|
std::size_t mHash{0}; // The unique hash that identifies this command.
|
||||||
String mName; // The unique name that identifies this command.
|
String mName{}; // The unique name that identifies this command.
|
||||||
Listener* mPtr; // The listener that reacts to this command.
|
Listener* mPtr{nullptr}; // The listener that reacts to this command.
|
||||||
Object mObj; // A strong reference to the script object.
|
Object mObj{}; // A strong reference to the script object.
|
||||||
CtrPtr mCtr; // The associated controller.
|
CtrPtr mCtr{}; // The associated controller.
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Construct a command and the also create a script object from the specified listener.
|
* Construct a command and the also create a script object from the specified listener.
|
||||||
@ -418,7 +418,7 @@ protected:
|
|||||||
bool Parse(Context & ctx);
|
bool Parse(Context & ctx);
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Attach a command listener to a certain name.
|
* Attach a command listener to the associated name.
|
||||||
*/
|
*/
|
||||||
Object & Attach(Object & obj, Listener * ptr)
|
Object & Attach(Object & obj, Listener * ptr)
|
||||||
{
|
{
|
||||||
@ -426,7 +426,7 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Attach a command listener to a certain name.
|
* Attach a command listener to the associated name.
|
||||||
*/
|
*/
|
||||||
Object & Attach(const Object & obj, Listener * ptr)
|
Object & Attach(const Object & obj, Listener * ptr)
|
||||||
{
|
{
|
||||||
@ -434,10 +434,31 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Attach a command listener to a certain name.
|
* Attach a command listener to the associated name.
|
||||||
*/
|
*/
|
||||||
Object & Attach(Object && obj, Listener * ptr);
|
Object & Attach(Object && obj, Listener * ptr);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Attach a command listener to a certain name.
|
||||||
|
*/
|
||||||
|
Object & Attach(Object & obj, Listener * ptr, String name)
|
||||||
|
{
|
||||||
|
return Attach(Object(obj), ptr, std::move(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Attach a command listener to a certain name.
|
||||||
|
*/
|
||||||
|
Object & Attach(const Object & obj, Listener * ptr, String name)
|
||||||
|
{
|
||||||
|
return Attach(Object(obj), ptr, std::move(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Attach a command listener to a certain name.
|
||||||
|
*/
|
||||||
|
Object & Attach(Object && obj, Listener * ptr, String name);
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Detach a command listener from a certain name.
|
* Detach a command listener from a certain name.
|
||||||
*/
|
*/
|
||||||
@ -445,17 +466,10 @@ protected:
|
|||||||
{
|
{
|
||||||
// Obtain the unique identifier of the specified name
|
// Obtain the unique identifier of the specified name
|
||||||
const std::size_t hash = std::hash< String >()(name);
|
const std::size_t hash = std::hash< String >()(name);
|
||||||
// Iterator to the found command, if any
|
|
||||||
auto itr = m_Commands.cbegin();
|
|
||||||
// Attempt to find the specified command
|
// Attempt to find the specified command
|
||||||
for (; itr != m_Commands.cend(); ++itr)
|
auto itr = std::find_if(m_Commands.cbegin(), m_Commands.cend(), [=](Commands::const_reference c) {
|
||||||
{
|
return (c.mHash == hash);
|
||||||
// Are the hashes identical?
|
});
|
||||||
if (itr->mHash == hash)
|
|
||||||
{
|
|
||||||
break; // We found our command!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Make sure the command exist before attempting to remove it
|
// Make sure the command exist before attempting to remove it
|
||||||
if (itr != m_Commands.end())
|
if (itr != m_Commands.end())
|
||||||
{
|
{
|
||||||
@ -468,17 +482,10 @@ protected:
|
|||||||
*/
|
*/
|
||||||
void Detach(Listener * ptr)
|
void Detach(Listener * ptr)
|
||||||
{
|
{
|
||||||
// Iterator to the found command, if any
|
|
||||||
auto itr = m_Commands.cbegin();
|
|
||||||
// Attempt to find the specified command
|
// Attempt to find the specified command
|
||||||
for (; itr != m_Commands.cend(); ++itr)
|
auto itr = std::find_if(m_Commands.cbegin(), m_Commands.cend(), [=](Commands::const_reference c) {
|
||||||
{
|
return (c.mPtr == ptr);
|
||||||
// Are the instances identical?
|
});
|
||||||
if (itr->mPtr == ptr)
|
|
||||||
{
|
|
||||||
break; // We found our command!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Make sure the command exists before attempting to remove it
|
// Make sure the command exists before attempting to remove it
|
||||||
if (itr != m_Commands.end())
|
if (itr != m_Commands.end())
|
||||||
{
|
{
|
||||||
@ -1200,6 +1207,7 @@ public:
|
|||||||
, m_ArgTags()
|
, m_ArgTags()
|
||||||
, m_MinArgc(0)
|
, m_MinArgc(0)
|
||||||
, m_MaxArgc(SQMOD_MAX_CMD_ARGS-1)
|
, m_MaxArgc(SQMOD_MAX_CMD_ARGS-1)
|
||||||
|
, m_Aliases(0)
|
||||||
, m_Spec()
|
, m_Spec()
|
||||||
, m_Help()
|
, m_Help()
|
||||||
, m_Info()
|
, m_Info()
|
||||||
@ -1336,6 +1344,42 @@ public:
|
|||||||
return m_Name;
|
return m_Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Increment the number of names that point to this command.
|
||||||
|
*/
|
||||||
|
uint16_t AddAliases(uint16_t n)
|
||||||
|
{
|
||||||
|
m_Aliases += n;
|
||||||
|
// Return new alias count
|
||||||
|
return m_Aliases;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Decrement the number of names that point to this command.
|
||||||
|
*/
|
||||||
|
uint16_t SubAliases(uint16_t n)
|
||||||
|
{
|
||||||
|
m_Aliases -= n;
|
||||||
|
// Return new alias count
|
||||||
|
return m_Aliases;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve the number of names that point to this command.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD uint16_t GetAliases() const
|
||||||
|
{
|
||||||
|
return m_Aliases;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Modify the number of names that point to this command.
|
||||||
|
*/
|
||||||
|
void SetAliases(uint16_t n)
|
||||||
|
{
|
||||||
|
m_Aliases = n;
|
||||||
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Retrieve the number of weak references to the managed controller.
|
* Retrieve the number of weak references to the managed controller.
|
||||||
*/
|
*/
|
||||||
@ -1906,6 +1950,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
void GenerateInfo(bool full);
|
void GenerateInfo(bool full);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Create an alias for this command listener.
|
||||||
|
*/
|
||||||
|
Listener & Rebind(StackStrF & name);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
@ -1955,6 +2004,7 @@ private:
|
|||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
uint8_t m_MinArgc; // Minimum number of arguments supported by this listener.
|
uint8_t m_MinArgc; // Minimum number of arguments supported by this listener.
|
||||||
uint8_t m_MaxArgc; // Maximum number of arguments supported by this listener.
|
uint8_t m_MaxArgc; // Maximum number of arguments supported by this listener.
|
||||||
|
uint16_t m_Aliases; // Number of aliases that point to this command.
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
String m_Spec; // String used to generate the argument type specification list.
|
String m_Spec; // String used to generate the argument type specification list.
|
||||||
|
Loading…
Reference in New Issue
Block a user