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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
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)
|
||||
{
|
||||
@ -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)
|
||||
{
|
||||
@ -1136,6 +1226,7 @@ void Register(HSQUIRRELVM vm)
|
||||
.Prop(_SC("Associate"), &Listener::GetAssociate, &Listener::SetAssociate)
|
||||
.Prop(_SC("MinArgs"), &Listener::GetMinArgC, &Listener::SetMinArgC)
|
||||
.Prop(_SC("MaxArgs"), &Listener::GetMaxArgC, &Listener::SetMaxArgC)
|
||||
.Prop(_SC("AliasCount"), &Listener::GetAliases)
|
||||
.Prop(_SC("OnExec"), &Listener::GetOnExec)
|
||||
.Prop(_SC("OnAuth"), &Listener::GetOnAuth)
|
||||
.Prop(_SC("OnAudit"), &Listener::GetOnAudit)
|
||||
@ -1159,6 +1250,7 @@ void Register(HSQUIRRELVM vm)
|
||||
.Func(_SC("ArgCheck"), &Listener::ArgCheck)
|
||||
.Func(_SC("AuthCheck"), &Listener::AuthCheck)
|
||||
.Func(_SC("GenerateInfo"), &Listener::GenerateInfo)
|
||||
.FmtFunc(_SC("Rebind"), &Listener::Rebind)
|
||||
);
|
||||
|
||||
RootTable(vm).Bind(_SC("SqCmd"), cmdns);
|
||||
|
@ -255,11 +255,11 @@ public:
|
||||
struct Command
|
||||
{
|
||||
// --------------------------------------------------------------------------------------------
|
||||
std::size_t mHash; // The unique hash that identifies this command.
|
||||
String mName; // The unique name that identifies this command.
|
||||
Listener* mPtr; // The listener that reacts to this command.
|
||||
Object mObj; // A strong reference to the script object.
|
||||
CtrPtr mCtr; // The associated controller.
|
||||
std::size_t mHash{0}; // The unique hash that identifies this command.
|
||||
String mName{}; // The unique name that identifies this command.
|
||||
Listener* mPtr{nullptr}; // The listener that reacts to this command.
|
||||
Object mObj{}; // A strong reference to the script object.
|
||||
CtrPtr mCtr{}; // The associated controller.
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Construct a command and the also create a script object from the specified listener.
|
||||
@ -418,7 +418,7 @@ protected:
|
||||
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)
|
||||
{
|
||||
@ -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)
|
||||
{
|
||||
@ -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);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* 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.
|
||||
*/
|
||||
@ -445,17 +466,10 @@ protected:
|
||||
{
|
||||
// Obtain the unique identifier of the specified 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
|
||||
for (; itr != m_Commands.cend(); ++itr)
|
||||
{
|
||||
// Are the hashes identical?
|
||||
if (itr->mHash == hash)
|
||||
{
|
||||
break; // We found our command!
|
||||
}
|
||||
}
|
||||
auto itr = std::find_if(m_Commands.cbegin(), m_Commands.cend(), [=](Commands::const_reference c) {
|
||||
return (c.mHash == hash);
|
||||
});
|
||||
// Make sure the command exist before attempting to remove it
|
||||
if (itr != m_Commands.end())
|
||||
{
|
||||
@ -468,17 +482,10 @@ protected:
|
||||
*/
|
||||
void Detach(Listener * ptr)
|
||||
{
|
||||
// Iterator to the found command, if any
|
||||
auto itr = m_Commands.cbegin();
|
||||
// Attempt to find the specified command
|
||||
for (; itr != m_Commands.cend(); ++itr)
|
||||
{
|
||||
// Are the instances identical?
|
||||
if (itr->mPtr == ptr)
|
||||
{
|
||||
break; // We found our command!
|
||||
}
|
||||
}
|
||||
auto itr = std::find_if(m_Commands.cbegin(), m_Commands.cend(), [=](Commands::const_reference c) {
|
||||
return (c.mPtr == ptr);
|
||||
});
|
||||
// Make sure the command exists before attempting to remove it
|
||||
if (itr != m_Commands.end())
|
||||
{
|
||||
@ -1200,6 +1207,7 @@ public:
|
||||
, m_ArgTags()
|
||||
, m_MinArgc(0)
|
||||
, m_MaxArgc(SQMOD_MAX_CMD_ARGS-1)
|
||||
, m_Aliases(0)
|
||||
, m_Spec()
|
||||
, m_Help()
|
||||
, m_Info()
|
||||
@ -1336,6 +1344,42 @@ public:
|
||||
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.
|
||||
*/
|
||||
@ -1906,6 +1950,11 @@ public:
|
||||
*/
|
||||
void GenerateInfo(bool full);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Create an alias for this command listener.
|
||||
*/
|
||||
Listener & Rebind(StackStrF & name);
|
||||
|
||||
protected:
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
@ -1955,6 +2004,7 @@ private:
|
||||
// --------------------------------------------------------------------------------------------
|
||||
uint8_t m_MinArgc; // Minimum 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.
|
||||
|
Loading…
Reference in New Issue
Block a user