mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2024-11-08 08:47:17 +01:00
bedf03c9cd
Fixed a bug in the Routine system that caused crashes when constructed with only the first three arguments because it wasn't attached. Implemented a gentle release of functions to not release them if the reference count is 1. Adjusted the Routine and Command system to not be necessary to include them in the module core. Moved the INI and XML libraries into their own namespace. Various other modifications and fixes.
1379 lines
49 KiB
C++
1379 lines
49 KiB
C++
// ------------------------------------------------------------------------------------------------
|
|
#include "Command.hpp"
|
|
#include "Core.hpp"
|
|
#include "Entity/Player.hpp"
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
#include <ctype.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <iterator>
|
|
#include <algorithm>
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
namespace SqMod {
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CmdManager * _Cmd = NULL;
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CSStr CmdArgSpecToStr(Uint8 spec)
|
|
{
|
|
switch (spec)
|
|
{
|
|
case CMDARG_ANY: return _SC("any");
|
|
case CMDARG_INTEGER: return _SC("integer");
|
|
case CMDARG_FLOAT: return _SC("float");
|
|
case CMDARG_BOOLEAN: return _SC("boolean");
|
|
case CMDARG_STRING:
|
|
case CMDARG_LOWER:
|
|
case CMDARG_UPPER:
|
|
case CMDARG_GREEDY: return _SC("string");
|
|
default: return _SC("unknown");
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CmdManager::CmdManager()
|
|
: m_Buffer(512)
|
|
, m_Commands()
|
|
, m_Invoker(SQMOD_UNKNOWN)
|
|
, m_Command()
|
|
, m_Argument()
|
|
, m_Argv()
|
|
, m_Argc(0)
|
|
{
|
|
/* ... */
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CmdManager::~CmdManager()
|
|
{
|
|
/* ... */
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CmdManager::Terminate()
|
|
{
|
|
// Release the script resources from command instances
|
|
for (CmdList::iterator itr = m_Commands.begin(); itr != m_Commands.end(); ++itr)
|
|
{
|
|
if (itr->second)
|
|
{
|
|
itr->second->m_OnExec.ReleaseGently();
|
|
itr->second->m_OnAuth.ReleaseGently();
|
|
itr->second->m_OnPost.ReleaseGently();
|
|
itr->second->m_OnFail.ReleaseGently();
|
|
}
|
|
}
|
|
// Release the script resources from this class
|
|
m_Argv.clear();
|
|
m_OnError.ReleaseGently();
|
|
m_OnAuth.ReleaseGently();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Int32 CmdManager::Run(Int32 invoker, CCStr command)
|
|
{
|
|
// Validate the string command
|
|
if (!command || strlen(command) <= 0)
|
|
{
|
|
SqError(CMDERR_EMPTY_COMMAND, _SC("Invalid or empty command name"), invoker);
|
|
return -1;
|
|
}
|
|
// Save the invoker identifier
|
|
m_Invoker = invoker;
|
|
// Skip whitespace until the command name
|
|
while (*command == ' ') ++command;
|
|
// Find where the command name ends
|
|
CCStr split = strchr(command, ' ');
|
|
// Are there any arguments specified?
|
|
if (split != NULL)
|
|
{
|
|
// Save the command name
|
|
m_Command.assign(command, (split - command));
|
|
// Skip white space after command name
|
|
while (*split == ' ') ++split;
|
|
// Save the command argument
|
|
m_Argument.assign(split);
|
|
}
|
|
// No arguments specified
|
|
else
|
|
{
|
|
m_Command.assign(command);
|
|
m_Argument.assign("");
|
|
}
|
|
// Did anything remain after cleaning?
|
|
if (m_Command.empty())
|
|
{
|
|
SqError(CMDERR_INVALID_COMMAND, _SC("Cannot execute invalid command name"), invoker);
|
|
return -1;
|
|
}
|
|
// Attempt to find the specified command
|
|
CmdList::iterator itr = m_Commands.find(m_Command);
|
|
// Have we found anything?
|
|
if (itr == m_Commands.end())
|
|
{
|
|
SqError(CMDERR_UNKNOWN_COMMAND, _SC("Unable to find the specified command"), m_Command.c_str());
|
|
return -1;
|
|
}
|
|
// Is the command instance valid? (just in case)
|
|
else if (!itr->second)
|
|
{
|
|
m_Commands.erase(itr);
|
|
SqError(CMDERR_UNKNOWN_COMMAND, _SC("Unable to find the specified command"), m_Command.c_str());
|
|
return -1;
|
|
}
|
|
// Save the command instance
|
|
m_Instance = itr->second;
|
|
// Place a lock on the command
|
|
m_Instance->m_Locked = true;
|
|
// Value returned by the command
|
|
Int32 ret = -1;
|
|
// Attempt to execute the command
|
|
try
|
|
{
|
|
ret = Exec();
|
|
}
|
|
catch (...)
|
|
{
|
|
SqError(CMDERR_EXECUTION_FAILED, _SC("Exceptions occurred during execution"), m_Invoker);
|
|
}
|
|
// Remove the lock from the command
|
|
m_Instance->m_Protected = false;
|
|
// Release the command instance
|
|
m_Instance = NULL;
|
|
// Return the result
|
|
return ret;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Int32 CmdManager::Exec()
|
|
{
|
|
// Clear previous arguments
|
|
m_Argv.clear();
|
|
// Reset the argument counter
|
|
m_Argc = 0;
|
|
// Make sure the invoker has enough authority to execute this command
|
|
if (!m_Instance->AuthCheckID(m_Invoker))
|
|
{
|
|
SqError(CMDERR_INSUFFICIENT_AUTH, _SC("Insufficient authority to execute command"), m_Invoker);
|
|
// Command failed
|
|
return -1;
|
|
}
|
|
// Make sure an executer was specified
|
|
else if (m_Instance->GetOnExec().IsNull())
|
|
{
|
|
SqError(CMDERR_MISSING_EXECUTER, _SC("No executer was specified for this command"), m_Invoker);
|
|
// Command failed
|
|
return -1;
|
|
}
|
|
// See if there are any arguments to parse
|
|
else if (!m_Argument.empty() && !Parse())
|
|
{
|
|
// The error message was reported while parsing
|
|
return -1;
|
|
}
|
|
// Make sure we have enough arguments specified
|
|
else if (m_Instance->GetMinArgC() > m_Argc)
|
|
{
|
|
SqError(CMDERR_INCOMPLETE_ARGS, _SC("Incomplete command arguments"), m_Instance->GetMinArgC());
|
|
// Command failed
|
|
return -1;
|
|
}
|
|
// The check during the parsing may omit the last argument
|
|
else if (m_Instance->GetMaxArgC() < m_Argc)
|
|
{
|
|
SqError(CMDERR_EXTRANEOUS_ARGS, _SC("Extraneous command arguments"), m_Instance->GetMaxArgC());
|
|
// Command failed
|
|
return -1;
|
|
}
|
|
// Check argument types against the command specifiers
|
|
for (Uint32 arg = 0; arg < m_Argc; ++arg)
|
|
{
|
|
if (!m_Instance->ArgCheck(arg, m_Argv[arg].first))
|
|
{
|
|
SqError(CMDERR_UNSUPPORTED_ARG, _SC("Unsupported command argument"), arg);
|
|
// Command failed
|
|
return -1;
|
|
}
|
|
}
|
|
// Result of the command execution
|
|
SQInteger result = -1;
|
|
// Do we have to call the command with an associative container?
|
|
if (m_Instance->m_Associate)
|
|
{
|
|
// Create the associative container
|
|
Table args(DefaultVM::Get());
|
|
// Copy the arguments into the table
|
|
for (Uint32 arg = 0; arg < m_Argc; ++arg)
|
|
{
|
|
// Do we have use the argument index as the key?
|
|
if (m_Instance->m_ArgTags[arg].empty())
|
|
{
|
|
args.SetValue(SQInteger(arg), m_Argv[arg].second);
|
|
}
|
|
// Nope, we have a name for this argument!
|
|
else
|
|
{
|
|
args.SetValue(m_Instance->m_ArgTags[arg].c_str(), m_Argv[arg].second);
|
|
}
|
|
}
|
|
// Attempt to execute the command with the specified arguments
|
|
result = m_Instance->Execute(_Core->GetPlayer(m_Invoker).mObj, args);
|
|
}
|
|
else
|
|
{
|
|
// Reserve an array for the extracted arguments
|
|
Array args(DefaultVM::Get(), m_Argc);
|
|
// Copy the arguments into the array
|
|
for (Uint32 arg = 0; arg < m_Argc; ++arg)
|
|
{
|
|
args.Bind(SQInteger(arg), m_Argv[arg].second);
|
|
}
|
|
// Attempt to execute the command with the specified arguments
|
|
result = m_Instance->Execute(_Core->GetPlayer(m_Invoker).mObj, args);
|
|
}
|
|
// See if an error occurred or an exception was thrown
|
|
if (Error::Occurred(DefaultVM::Get()))
|
|
{
|
|
SqError(CMDERR_EXECUTION_FAILED, _SC("Command execution failed"),
|
|
Error::Message(DefaultVM::Get()).c_str());
|
|
if (!m_Instance->m_OnFail.IsNull())
|
|
{
|
|
m_Instance->m_OnFail.Execute(_Core->GetPlayer(m_Invoker).mObj, result);
|
|
}
|
|
// Result is invalid at this point
|
|
result = -1;
|
|
}
|
|
// See if the command failed explicitly
|
|
else if (!result)
|
|
{
|
|
SqError(CMDERR_EXECUTION_FAILED, _SC("Command execution failed"),
|
|
_SC("executor evaluated to false"));
|
|
if (!m_Instance->m_OnFail.IsNull())
|
|
{
|
|
m_Instance->m_OnFail.Execute(_Core->GetPlayer(m_Invoker).mObj, result);
|
|
}
|
|
}
|
|
else if (!m_Instance->m_OnPost.IsNull())
|
|
{
|
|
m_Instance->m_OnPost.Execute(_Core->GetPlayer(m_Invoker).mObj, result);
|
|
}
|
|
// Return the result
|
|
return Int32(result);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool CmdManager::Parse()
|
|
{
|
|
// Is there anything to parse?
|
|
if (m_Argument.empty())
|
|
{
|
|
return true; /* Done parsing */
|
|
}
|
|
// Obtain the flags of the currently processed argument
|
|
Uint8 arg_flags = m_Instance->m_ArgSpec[m_Argc];
|
|
// Adjust the internal buffer if necessary (mostly never)
|
|
m_Buffer.Adjust< SQChar >(m_Argument.size());
|
|
// The iterator to the currently processed character
|
|
String::iterator itr = m_Argument.begin();
|
|
// Previous and currently processed character
|
|
SQChar prev = 0, elem = 0;
|
|
// Maximum arguments allowed to be processed
|
|
const Uint8 max_arg = m_Instance->m_MaxArgc;
|
|
// Process loop result
|
|
bool good = true;
|
|
// Process the specified command text
|
|
while (good)
|
|
{
|
|
// Extract the current characters before advancing
|
|
prev = elem, elem = *itr;
|
|
// See if there's anything left to parse
|
|
if (elem == 0)
|
|
{
|
|
break;
|
|
}
|
|
// Early check to prevent parsing extraneous arguments
|
|
else if (m_Argc >= max_arg)
|
|
{
|
|
SqError(CMDERR_EXTRANEOUS_ARGS, _SC("Extraneous command arguments"), max_arg);
|
|
// Parsing aborted
|
|
good = false;
|
|
// Stop parsing
|
|
break;
|
|
}
|
|
// Is this a greedy argument?
|
|
else if (arg_flags & CMDARG_GREEDY)
|
|
{
|
|
// Skip whitespace
|
|
while (*itr == ' ' && itr != m_Argument.end()) ++itr;
|
|
// Anything left to copy?
|
|
if (itr != m_Argument.end())
|
|
{
|
|
// Transform it into a script object
|
|
sq_pushstring(DefaultVM::Get(), &(*itr), std::distance(itr, m_Argument.end()));
|
|
}
|
|
// Just push an empty string
|
|
else
|
|
{
|
|
sq_pushstring(DefaultVM::Get(), _SC(""), 0);
|
|
}
|
|
// Get the object from the stack
|
|
Var< Object & > var(DefaultVM::Get(), -1);
|
|
// Pop the created object from the stack
|
|
if (!var.value.IsNull())
|
|
{
|
|
sq_pop(DefaultVM::Get(), 1);
|
|
}
|
|
// Add it to the argument list along with it's type
|
|
m_Argv.push_back(CmdArgs::value_type(CMDARG_STRING, var.value));
|
|
// Include this argument into the count
|
|
++m_Argc;
|
|
// Nothing left to parse
|
|
break;
|
|
}
|
|
// Do we have to extract a string argument?
|
|
else if ((elem == '\'' || elem == '"') && prev != '\\')
|
|
{
|
|
// Obtain the beginning and ending of the internal buffer
|
|
SStr str = m_Buffer.Begin< SQChar >();
|
|
CSStr end = (m_Buffer.End< SQChar >()-1); /* + null */
|
|
// Save the closing quote type
|
|
SQChar close = elem;
|
|
// Skip the opening quote
|
|
++itr;
|
|
// Attempt to consume the string argument
|
|
while (good)
|
|
{
|
|
// Extract the current characters before advancing
|
|
prev = elem, elem = *itr;
|
|
// See if there's anything left to parse
|
|
if (elem == 0)
|
|
{
|
|
SqError(CMDERR_SYNTAX_ERROR, _SC("String argument not closed properly"), m_Argc);
|
|
// Parsing aborted
|
|
good = false;
|
|
// Stop parsing
|
|
break;
|
|
}
|
|
// First un-escaped matching quote character ends the argument
|
|
else if (elem == close)
|
|
{
|
|
// Was this not escaped?
|
|
if (prev != '\\')
|
|
{
|
|
// Terminate the string value in the internal buffer
|
|
*str = 0;
|
|
// Stop parsing
|
|
break;
|
|
}
|
|
// Overwrite last character when replicating
|
|
else
|
|
{
|
|
--str;
|
|
}
|
|
}
|
|
// See if the internal buffer needs to scale
|
|
else if (str >= end)
|
|
{
|
|
// We should already have a buffer as big as the entire command!
|
|
SqError(CMDERR_BUFFER_OVERFLOW, _SC("Command buffer was exceeded unexpectedly"), m_Invoker);
|
|
// Parsing aborted
|
|
good = false;
|
|
// Stop parsing
|
|
break;
|
|
}
|
|
// Simply replicate the character to the internal buffer
|
|
*(str++) = elem;
|
|
// Advance to the next character
|
|
++itr;
|
|
}
|
|
// See if the argument was valid
|
|
if (!good)
|
|
{
|
|
// Propagate failure
|
|
break;
|
|
}
|
|
// Do we have to make the string lowercase?
|
|
else if (arg_flags & CMDARG_LOWER)
|
|
{
|
|
for (SStr chr = m_Buffer.Begin< SQChar >(); chr <= str; ++chr)
|
|
{
|
|
*chr = (SQChar)tolower(*chr);
|
|
}
|
|
}
|
|
// Do we have to make the string uppercase?
|
|
else if (arg_flags & CMDARG_UPPER)
|
|
{
|
|
for (SStr chr = m_Buffer.Begin< SQChar >(); chr <= str; ++chr)
|
|
{
|
|
*chr = (SQChar)toupper(*chr);
|
|
}
|
|
}
|
|
// Transform it into a script object
|
|
sq_pushstring(DefaultVM::Get(), m_Buffer.Get< SQChar >(), str - m_Buffer.Begin< SQChar >());
|
|
// Get the object from the stack
|
|
Var< Object & > var(DefaultVM::Get(), -1);
|
|
// Pop the created object from the stack
|
|
if (!var.value.IsNull())
|
|
{
|
|
sq_pop(DefaultVM::Get(), 1);
|
|
}
|
|
// Add it to the argument list along with it's type
|
|
m_Argv.push_back(CmdArgs::value_type(CMDARG_STRING, var.value));
|
|
// Advance to the next argument and obtain its flags
|
|
arg_flags = m_Instance->m_ArgSpec[++m_Argc];
|
|
}
|
|
// Ignore space characters until another valid character is found
|
|
else if (elem != ' ' && (prev == ' ' || prev == 0))
|
|
{
|
|
// Find the first character that marks the end of the argument
|
|
String::iterator pos = std::find(String::iterator(itr), m_Argument.end(), ' ');
|
|
// Copy all characters within range into the internal buffer
|
|
const Uint32 sz = m_Buffer.Write(0, &(*itr), std::distance(itr, pos));
|
|
// Update the main iterator position
|
|
itr = pos;
|
|
// Update the current character
|
|
elem = *itr;
|
|
// Make sure the argument string is null terminated
|
|
m_Buffer.At< SQChar >(sz) = 0;
|
|
// Used to exclude all other checks when a valid type was identified
|
|
bool identified = false;
|
|
// Attempt to treat the value as an integer number
|
|
if (!identified)
|
|
{
|
|
// Let's us know if the whole argument was part of the resulted value
|
|
CStr next = NULL;
|
|
// Attempt to extract the integer value from the string
|
|
Int64 value = strtol(m_Buffer.Data(), &next, 10);
|
|
// See if this whole string was indeed an integer
|
|
if (next == &m_Buffer.At< SQChar >(sz))
|
|
{
|
|
// Transform it into a script object
|
|
Var< SQInteger >::push(DefaultVM::Get(), SQInteger(value));
|
|
// Get the object from the stack
|
|
Var< Object & > var(DefaultVM::Get(), -1);
|
|
// Pop the created object from the stack
|
|
if (!var.value.IsNull())
|
|
{
|
|
sq_pop(DefaultVM::Get(), 1);
|
|
}
|
|
// Add it to the argument list along with it's type
|
|
m_Argv.push_back(CmdArgs::value_type(CMDARG_INTEGER, var.value));
|
|
// We identified the correct value
|
|
identified = true;
|
|
}
|
|
}
|
|
// Attempt to treat the value as an floating point number
|
|
if (!identified)
|
|
{
|
|
// Let's us know if the whole argument was part of the resulted value
|
|
CStr next = NULL;
|
|
// Attempt to extract the floating point value from the string
|
|
Float64 value = strtod(m_Buffer.Data(), &next);
|
|
// See if this whole string was indeed an floating point
|
|
if (next == &m_Buffer.At< SQChar >(sz))
|
|
{
|
|
// Transform it into a script object
|
|
Var< SQFloat >::push(DefaultVM::Get(), SQFloat(value));
|
|
// Get the object from the stack
|
|
Var< Object & > var(DefaultVM::Get(), -1);
|
|
// Pop the created object from the stack
|
|
if (!var.value.IsNull())
|
|
{
|
|
sq_pop(DefaultVM::Get(), 1);
|
|
}
|
|
// Add it to the argument list along with it's type
|
|
m_Argv.push_back(CmdArgs::value_type(CMDARG_FLOAT, var.value));
|
|
// We identified the correct value
|
|
identified = true;
|
|
}
|
|
}
|
|
// Attempt to treat the value as a boolean if possible
|
|
if (!identified && sz <= 6)
|
|
{
|
|
// Allocate memory for enough data to form a boolean value
|
|
SQChar lc[6];
|
|
// Fill the temporary buffer with data from the internal buffer
|
|
snprintf (lc, 6, "%.5s", m_Buffer.Data());
|
|
// Convert all characters to lowercase
|
|
for (Uint32 i = 0; i < 5; ++i)
|
|
{
|
|
lc[i] = tolower(lc[i]);
|
|
}
|
|
// Is this a boolean true value?
|
|
if (strcmp(m_Buffer.Data(), "true") == 0 || strcmp(m_Buffer.Data(), "on") == 0)
|
|
{
|
|
// Transform it into a script object
|
|
Var< bool >::push(DefaultVM::Get(), true);
|
|
// Get the object from the stack
|
|
Var< Object & > var(DefaultVM::Get(), -1);
|
|
// Pop the created object from the stack
|
|
if (!var.value.IsNull())
|
|
{
|
|
sq_pop(DefaultVM::Get(), 1);
|
|
}
|
|
// Add it to the argument list along with it's type
|
|
m_Argv.push_back(CmdArgs::value_type(CMDARG_BOOLEAN, var.value));
|
|
// We identified the correct value
|
|
identified = true;
|
|
}
|
|
// Is this a boolean false value?
|
|
else if (strcmp(m_Buffer.Data(), "false") == 0 || strcmp(m_Buffer.Data(), "off") == 0)
|
|
{
|
|
// Transform it into a script object
|
|
Var< bool >::push(DefaultVM::Get(), false);
|
|
// Get the object from the stack
|
|
Var< Object & > var(DefaultVM::Get(), -1);
|
|
// Pop the created object from the stack
|
|
if (!var.value.IsNull())
|
|
{
|
|
sq_pop(DefaultVM::Get(), 1);
|
|
}
|
|
// Add it to the argument list along with it's type
|
|
m_Argv.push_back(CmdArgs::value_type(CMDARG_BOOLEAN, var.value));
|
|
// We identified the correct value
|
|
identified = true;
|
|
}
|
|
}
|
|
// If everything else failed then simply treat the value as a string
|
|
if (!identified)
|
|
{
|
|
// Do we have to make the string lowercase?
|
|
if (arg_flags & CMDARG_LOWER)
|
|
{
|
|
for (Uint32 n = 0; n < sz; ++n)
|
|
{
|
|
m_Buffer.At< SQChar >(n) = (SQChar)tolower(m_Buffer.At< SQChar >(n));
|
|
}
|
|
}
|
|
// Do we have to make the string uppercase?
|
|
else if (arg_flags & CMDARG_UPPER)
|
|
{
|
|
for (Uint32 n = 0; n < sz; ++n)
|
|
{
|
|
m_Buffer.At< SQChar >(n) = (SQChar)toupper(m_Buffer.At< SQChar >(n));
|
|
}
|
|
}
|
|
// Transform it into a script object
|
|
sq_pushstring(DefaultVM::Get(), m_Buffer.Get< SQChar >(), sz);
|
|
// Get the object from the stack
|
|
Var< Object & > var(DefaultVM::Get(), -1);
|
|
// Pop the created object from the stack
|
|
if (!var.value.IsNull())
|
|
{
|
|
sq_pop(DefaultVM::Get(), 1);
|
|
}
|
|
// Add it to the argument list along with it's type
|
|
m_Argv.push_back(CmdArgs::value_type(CMDARG_STRING, var.value));
|
|
}
|
|
// Advance to the next argument and obtain its flags
|
|
arg_flags = m_Instance->m_ArgSpec[++m_Argc];
|
|
}
|
|
// Is there anything left to parse?
|
|
if (itr >= m_Argument.end())
|
|
{
|
|
break;
|
|
}
|
|
// Advance to the next character
|
|
++itr;
|
|
}
|
|
// Return whether the parsing was successful
|
|
return good;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CmdListener::Init(CSStr name, CSStr spec, Array & tags, Uint8 min, Uint8 max)
|
|
{
|
|
m_Name.assign("");
|
|
// Initialize the specifiers and tags to default values
|
|
for (Uint8 n = 0; n < SQMOD_MAX_CMD_ARGS; ++n)
|
|
{
|
|
m_ArgSpec[n] = CMDARG_ANY;
|
|
m_ArgTags[n].assign("");
|
|
}
|
|
m_MinArgc = 0;
|
|
m_MaxArgc = (SQMOD_MAX_CMD_ARGS - 1);
|
|
m_Spec.assign("");
|
|
m_Help.assign("");
|
|
m_Info.assign("");
|
|
m_OnAuth = _Cmd->GetOnAuth();
|
|
m_Authority = -1;
|
|
m_Protected = false;
|
|
m_Suspended = false;
|
|
m_Associate = false;
|
|
m_Locked = false;
|
|
// Set the minimum and maximum allowed arguments
|
|
SetMinArgC(min);
|
|
SetMaxArgC(max);
|
|
// Extract the specified argument tags
|
|
SetArgTags(tags);
|
|
// Bind to the specified command name
|
|
SetName(name);
|
|
// Apply the specified argument rules
|
|
SetSpec(spec);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CmdListener::CmdListener(CSStr name)
|
|
{
|
|
Init(name, _SC(""), NullArray(), 0, SQMOD_MAX_CMD_ARGS-1);
|
|
}
|
|
|
|
CmdListener::CmdListener(CSStr name, CSStr spec)
|
|
{
|
|
Init(name, spec, NullArray(), 0, SQMOD_MAX_CMD_ARGS-1);
|
|
}
|
|
|
|
CmdListener::CmdListener(CSStr name, CSStr spec, Array & tags)
|
|
{
|
|
Init(name, spec, tags, 0, SQMOD_MAX_CMD_ARGS-1);
|
|
}
|
|
|
|
CmdListener::CmdListener(CSStr name, CSStr spec, Uint8 min, Uint8 max)
|
|
{
|
|
Init(name, spec, NullArray(), min, max);
|
|
}
|
|
|
|
CmdListener::CmdListener(CSStr name, CSStr spec, Array & tags, Uint8 min, Uint8 max)
|
|
{
|
|
Init(name, spec, tags, min, max);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CmdListener::~CmdListener()
|
|
{
|
|
// See the instance must be detached
|
|
if (!m_Name.empty())
|
|
_Cmd->Detach(m_Name);
|
|
// Release callbacks
|
|
m_OnExec.ReleaseGently();
|
|
m_OnAuth.ReleaseGently();
|
|
m_OnPost.ReleaseGently();
|
|
m_OnFail.ReleaseGently();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Int32 CmdListener::Cmp(const CmdListener & o) const
|
|
{
|
|
if (m_Name == o.m_Name)
|
|
return 0;
|
|
else if (m_Name.size() > o.m_Name.size())
|
|
return 1;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CSStr CmdListener::ToString() const
|
|
{
|
|
return m_Name.c_str();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Uint8 CmdListener::GetArgFlags(Uint32 idx) const
|
|
{
|
|
if (idx < SQMOD_MAX_CMD_ARGS)
|
|
return m_ArgSpec[idx];
|
|
return CMDARG_ANY;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CSStr CmdListener::GetName() const
|
|
{
|
|
return m_Name.c_str();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CmdListener::SetName(CSStr name)
|
|
{
|
|
if (m_Locked)
|
|
SqThrow("Cannot change locked command: %s", m_Name.c_str());
|
|
else if (!name || strlen(name) <= 0)
|
|
SqThrow("Invalid command name: null");
|
|
else
|
|
{
|
|
// Detach from the current name if necessary
|
|
if (!m_Name.empty())
|
|
_Cmd->Detach(name);
|
|
// Now it's safe to assign the new name
|
|
m_Name.assign(name);
|
|
// We know the new name is valid
|
|
_Cmd->Attach(m_Name, this);
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CSStr CmdListener::GetSpec() const
|
|
{
|
|
return m_Spec.c_str();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CmdListener::SetSpec(CSStr spec)
|
|
{
|
|
if (ProcSpec(spec))
|
|
m_Spec.assign(spec);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Array CmdListener::GetArgTags() const
|
|
{
|
|
// Allocate an array to encapsulate all tags
|
|
Array arr(DefaultVM::Get(), SQMOD_MAX_CMD_ARGS);
|
|
// Put the tags to the allocated array
|
|
for (Uint32 arg = 0; arg < SQMOD_MAX_CMD_ARGS; ++arg)
|
|
arr.SetValue(arg, m_ArgTags[arg]);
|
|
// Return the array with the tags
|
|
return arr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CmdListener::SetArgTags(Array & tags)
|
|
{
|
|
// Attempt to retrieve the number of specified tags
|
|
const Uint32 max = static_cast< Uint32 >(tags.Length());
|
|
// If no tags were specified then clear current tags
|
|
if (tags.IsNull() || max == 0)
|
|
{
|
|
for (Uint8 n = 0; n < SQMOD_MAX_CMD_ARGS; ++n)
|
|
{
|
|
m_ArgTags[n].assign("");
|
|
}
|
|
}
|
|
// See if we're in range
|
|
else if (max < SQMOD_MAX_CMD_ARGS)
|
|
// Attempt to get all arguments in one go
|
|
tags.GetArray(m_ArgTags, max);
|
|
else
|
|
SqThrow("Argument tag (%u) is out of range (%u)", max, SQMOD_MAX_CMD_ARGS);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CSStr CmdListener::GetHelp() const
|
|
{
|
|
return m_Help.c_str();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CmdListener::SetHelp(CSStr help)
|
|
{
|
|
m_Help.assign(help);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CSStr CmdListener::GetInfo() const
|
|
{
|
|
return m_Info.c_str();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CmdListener::SetInfo(CSStr info)
|
|
{
|
|
m_Info.assign(info);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Int32 CmdListener::GetAuthority() const
|
|
{
|
|
return m_Authority;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CmdListener::SetAuthority(Int32 level)
|
|
{
|
|
m_Authority = level;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool CmdListener::GetProtected() const
|
|
{
|
|
return m_Protected;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CmdListener::SetProtected(bool toggle)
|
|
{
|
|
m_Protected = toggle;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool CmdListener::GetSuspended() const
|
|
{
|
|
return m_Suspended;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CmdListener::SetSuspended(bool toggle)
|
|
{
|
|
m_Suspended = toggle;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool CmdListener::GetAssociate() const
|
|
{
|
|
return m_Associate;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CmdListener::SetAssociate(bool toggle)
|
|
{
|
|
m_Associate = toggle;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Uint8 CmdListener::GetMinArgC() const
|
|
{
|
|
return m_MinArgc;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CmdListener::SetMinArgC(Uint8 val)
|
|
{
|
|
// Assuming (m_MaxArgc < SQMOD_MAX_CMD_ARGS) is always true
|
|
if (val <= m_MaxArgc)
|
|
m_MinArgc = val;
|
|
else
|
|
SqThrow("Minimum argument (%u) exceeds maximum (%u)", val, m_MaxArgc);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Uint8 CmdListener::GetMaxArgC() const
|
|
{
|
|
return m_MaxArgc;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CmdListener::SetMaxArgC(Uint8 val)
|
|
{
|
|
if (val < SQMOD_MAX_CMD_ARGS && val >= m_MinArgc)
|
|
m_MaxArgc = val;
|
|
else if (val < m_MinArgc)
|
|
SqThrow("Minimum argument (%u) exceeds maximum (%u)", m_MinArgc, val);
|
|
else
|
|
SqThrow("Argument (%u) is out of total range (%u)", val, SQMOD_MAX_CMD_ARGS);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool CmdListener::GetLocked() const
|
|
{
|
|
return m_Locked;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Function & CmdListener::GetOnExec()
|
|
{
|
|
return m_OnExec;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CmdListener::SetOnExec(Object & env, Function & func)
|
|
{
|
|
if (!m_Name.empty())
|
|
m_OnExec = Function(env.GetVM(), env.GetObject(), func.GetFunc());
|
|
else
|
|
SqThrow("Invalid commands cannot store script resources");
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Function & CmdListener::GetOnAuth()
|
|
{
|
|
return m_OnAuth;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CmdListener::SetOnAuth(Object & env, Function & func)
|
|
{
|
|
if (!m_Name.empty())
|
|
m_OnAuth = Function(env.GetVM(), env.GetObject(), func.GetFunc());
|
|
else
|
|
SqThrow("Invalid commands cannot store script resources");
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Function & CmdListener::GetOnPost()
|
|
{
|
|
return m_OnPost;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CmdListener::SetOnPost(Object & env, Function & func)
|
|
{
|
|
if (!m_Name.empty())
|
|
m_OnPost = Function(env.GetVM(), env.GetObject(), func.GetFunc());
|
|
else
|
|
SqThrow("Invalid commands cannot store script resources");
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
Function & CmdListener::GetOnFail()
|
|
{
|
|
return m_OnFail;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CmdListener::SetOnFail(Object & env, Function & func)
|
|
{
|
|
if (!m_Name.empty())
|
|
m_OnFail = Function(env.GetVM(), env.GetObject(), func.GetFunc());
|
|
else
|
|
SqThrow("Invalid commands cannot store script resources");
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
CSStr CmdListener::GetArgTag(Uint32 arg) const
|
|
{
|
|
if (arg < SQMOD_MAX_CMD_ARGS)
|
|
return m_ArgTags[arg].c_str();
|
|
SqThrow("Argument (%u) is out of total range (%u)", arg, SQMOD_MAX_CMD_ARGS);
|
|
return g_EmptyStr;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CmdListener::SetArgTag(Uint32 arg, CSStr name)
|
|
{
|
|
if (arg < SQMOD_MAX_CMD_ARGS)
|
|
m_ArgTags[arg].assign(name);
|
|
else
|
|
SqThrow("Argument (%u) is out of total range (%u)", arg, SQMOD_MAX_CMD_ARGS);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
void CmdListener::GenerateInfo(bool full)
|
|
{
|
|
// Clear any previously generated informational message
|
|
m_Info.clear();
|
|
// Process each supported command argument
|
|
for (Uint32 arg = 0; arg < m_MaxArgc; ++arg)
|
|
{
|
|
// If this is not a full command request then see if we must stop
|
|
if (!full)
|
|
{
|
|
// Default to stop if criteria are not meet
|
|
bool stop = true;
|
|
// Check all arguments after this and see if there's any left
|
|
for (Uint32 idx = arg; idx < m_MaxArgc; ++idx)
|
|
{
|
|
// If the argument has a name or a type specifier then it's valid
|
|
if (!m_ArgTags[idx].empty() || m_ArgSpec[idx] != CMDARG_ANY)
|
|
{
|
|
// We have more arguments that need to be parsed
|
|
stop = false;
|
|
// Go back to the main loop
|
|
break;
|
|
}
|
|
}
|
|
// Is there any argument left?
|
|
if (stop)
|
|
// Stop the main loop as well
|
|
break;
|
|
}
|
|
// Begin the argument block
|
|
m_Info += '<';
|
|
// If the current argument is beyond minimum then mark it as optional
|
|
if (arg >= m_MinArgc)
|
|
m_Info += '*';
|
|
// If the argument has a tag/name associated then add it as well
|
|
if (!m_ArgTags[arg].empty())
|
|
{
|
|
// Add the name first
|
|
m_Info += m_ArgTags[arg];
|
|
// Separate the name from the specifiers
|
|
m_Info += ':';
|
|
}
|
|
// Is this a greedy argument?
|
|
if (m_ArgSpec[arg] & CMDARG_GREEDY)
|
|
{
|
|
m_Info += _SC("...");
|
|
}
|
|
// If the argument has any explicit types specified
|
|
else if (m_ArgSpec[arg] != CMDARG_ANY)
|
|
{
|
|
// Does it support integers?
|
|
if (m_ArgSpec[arg] & CMDARG_INTEGER)
|
|
m_Info += _SC("integer");
|
|
// Does it support floats?
|
|
if (m_ArgSpec[arg] & CMDARG_FLOAT)
|
|
{
|
|
// Add a separator if this is not the first enabled type?
|
|
if (m_Info[m_Info.size()-1] != ':' && m_Info[m_Info.size()-1] != '<')
|
|
m_Info += ',';
|
|
// Now add the type name
|
|
m_Info += _SC("float");
|
|
}
|
|
// Does it support booleans?
|
|
if (m_ArgSpec[arg] & CMDARG_BOOLEAN)
|
|
{
|
|
// Add a separator if this is not the first enabled type?
|
|
if (m_Info[m_Info.size()-1] != ':' && m_Info[m_Info.size()-1] != '<')
|
|
m_Info += ',';
|
|
// Now add the type name
|
|
m_Info += _SC("boolean");
|
|
}
|
|
// Does it support strings?
|
|
if (m_ArgSpec[arg] & CMDARG_STRING)
|
|
{
|
|
// Add a separator if this is not the first enabled type?
|
|
if (m_Info[m_Info.size()-1] != ':' && m_Info[m_Info.size()-1] != '<')
|
|
m_Info += ',';
|
|
// Now add the type name
|
|
m_Info += _SC("string");
|
|
}
|
|
}
|
|
// Any kind of value is supported by this argument
|
|
else
|
|
m_Info += _SC("any");
|
|
// Stop the argument block
|
|
m_Info += '>';
|
|
// Don't process anything after greedy arguments
|
|
if (m_ArgSpec[arg] & CMDARG_GREEDY)
|
|
{
|
|
break;
|
|
}
|
|
// If this is not the last argument then add a separator
|
|
else if (arg+1 != m_MaxArgc)
|
|
m_Info += ' ';
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool CmdListener::ArgCheck(Uint32 arg, Uint8 flag) const
|
|
{
|
|
if (arg < SQMOD_MAX_CMD_ARGS)
|
|
{
|
|
const Uint8 f = m_ArgSpec[arg];
|
|
return (f == CMDARG_ANY) || /* Requires check? */
|
|
(f & flag) || /* Exact match? */
|
|
(f & CMDARG_GREEDY && flag & CMDARG_STRING);
|
|
}
|
|
SqThrow("Argument (%u) is out of total range (%u)", arg, SQMOD_MAX_CMD_ARGS);
|
|
return false;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool CmdListener::AuthCheck(CPlayer & player)
|
|
{
|
|
return AuthCheckID(player.GetID());
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool CmdListener::AuthCheckID(Int32 id)
|
|
{
|
|
// Do we need explicit authority verification?
|
|
if (!m_Protected)
|
|
return true;
|
|
// Allow execution by default
|
|
bool allow = true;
|
|
// Was there a custom authority inspector specified?
|
|
if (!m_OnAuth.IsNull())
|
|
{
|
|
// Ask the specified authority inspector if this execution should be allowed
|
|
SharedPtr< bool > ret = m_OnAuth.Evaluate< bool, Object & >(_Core->GetPlayer(id).mObj);
|
|
// See what the custom authority inspector said or default to disallow
|
|
allow = (!ret ? false : *ret);
|
|
}
|
|
// Can we use the default authority system?
|
|
else if (m_Authority >= 0)
|
|
allow = (_Core->GetPlayer(id).mAuthority >= m_Authority);
|
|
// Return result
|
|
return allow;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
SQInteger CmdListener::Execute(Object & invoker, Array & args)
|
|
{
|
|
// Attempt to evaluate the specified executer knowing the manager did the validations
|
|
SharedPtr< SQInteger > ret = m_OnExec.Evaluate< SQInteger, Object &, Array & >(invoker, args);
|
|
// See if the executer succeeded and return the result or default to failed
|
|
return (!ret ? 0 : *ret);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
SQInteger CmdListener::Execute(Object & invoker, Table & args)
|
|
{
|
|
// Attempt to evaluate the specified executer knowing the manager did the validations
|
|
SharedPtr< SQInteger > ret = m_OnExec.Evaluate< SQInteger, Object &, Table & >(invoker, args);
|
|
// See if the executer succeeded and return the result or default to failed
|
|
return (!ret ? 0 : *ret);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
bool CmdListener::ProcSpec(CSStr str)
|
|
{
|
|
// Reset current argument specifiers
|
|
memset(m_ArgSpec, CMDARG_ANY, sizeof(m_ArgSpec));
|
|
// Currently processed character
|
|
SQChar ch = 0;
|
|
// When parsing may continue
|
|
bool good = true;
|
|
// Currently processed argument
|
|
Uint32 idx = 0;
|
|
// Process each character in the specified command
|
|
while (good)
|
|
{
|
|
// Extract the current character before advancing
|
|
ch = *(str++);
|
|
// See if there are still things left to parse
|
|
if (ch == 0)
|
|
// Finished parsing successfully
|
|
break;
|
|
// See if we need to move to the next argument
|
|
else if (ch == '|')
|
|
{
|
|
if (idx >= SQMOD_MAX_CMD_ARGS)
|
|
{
|
|
SqThrow("Extraneous type specifiers: %d >= %d", idx, SQMOD_MAX_CMD_ARGS);
|
|
// Parsing failed
|
|
good = false;
|
|
// Stop parsing
|
|
break;
|
|
}
|
|
// Advance to the next argument
|
|
++idx;
|
|
}
|
|
// Simply ignore a type specifier delimiter
|
|
else if (ch != ',')
|
|
{
|
|
// Consume space when found
|
|
if (ch == ' ')
|
|
while (good)
|
|
{
|
|
ch = *(str++);
|
|
// Stop when the text ends or on the first non-space character
|
|
if (ch == 0 || ch != ' ')
|
|
break;
|
|
}
|
|
// See if there is a specifier left
|
|
if (!good)
|
|
// Propagate the stop
|
|
break;
|
|
// Apply the type specifier
|
|
switch(ch)
|
|
{
|
|
// Is this a greedy argument?
|
|
case 'g':
|
|
{
|
|
m_ArgSpec[idx] = CMDARG_GREEDY;
|
|
} break;
|
|
// Is this a integer type
|
|
case 'i':
|
|
{
|
|
m_ArgSpec[idx] |= CMDARG_INTEGER;
|
|
// Disable greedy argument flag if set
|
|
if (m_ArgSpec[idx] & CMDARG_GREEDY)
|
|
m_ArgSpec[idx] ^= CMDARG_GREEDY;
|
|
} break;
|
|
// Is this a float type
|
|
case 'f':
|
|
{
|
|
m_ArgSpec[idx] |= CMDARG_FLOAT;
|
|
// Disable greedy argument flag if set
|
|
if (m_ArgSpec[idx] & CMDARG_GREEDY)
|
|
m_ArgSpec[idx] ^= CMDARG_GREEDY;
|
|
} break;
|
|
// Is this a boolean type
|
|
case 'b':
|
|
{
|
|
m_ArgSpec[idx] |= CMDARG_BOOLEAN;
|
|
// Disable greedy argument flag if set
|
|
if (m_ArgSpec[idx] & CMDARG_GREEDY)
|
|
m_ArgSpec[idx] ^= CMDARG_GREEDY;
|
|
} break;
|
|
// Is this a string type
|
|
case 's':
|
|
{
|
|
m_ArgSpec[idx] |= CMDARG_STRING;
|
|
// Disable greedy argument flag if set
|
|
if (m_ArgSpec[idx] & CMDARG_GREEDY)
|
|
m_ArgSpec[idx] ^= CMDARG_GREEDY;
|
|
} break;
|
|
// Is this a lowercase string?
|
|
case 'l':
|
|
{
|
|
m_ArgSpec[idx] |= CMDARG_STRING;
|
|
m_ArgSpec[idx] |= CMDARG_LOWER;
|
|
// Disable greedy argument flag if set
|
|
if (m_ArgSpec[idx] & CMDARG_GREEDY)
|
|
m_ArgSpec[idx] ^= CMDARG_GREEDY;
|
|
} break;
|
|
// Is this a uppercase string?
|
|
case 'u':
|
|
{
|
|
m_ArgSpec[idx] |= CMDARG_STRING;
|
|
m_ArgSpec[idx] |= CMDARG_UPPER;
|
|
// Disable greedy argument flag if set
|
|
if (m_ArgSpec[idx] & CMDARG_GREEDY)
|
|
m_ArgSpec[idx] ^= CMDARG_GREEDY;
|
|
} break;
|
|
// Unknown type!
|
|
default:
|
|
{
|
|
SqThrow("Unknown type specifier (%c) at argument: %u", ch, idx);
|
|
// Parsing failed
|
|
good = false;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
// Reset all argument specifiers if failed
|
|
if (!good)
|
|
memset(m_ArgSpec, CMDARG_ANY, sizeof(m_ArgSpec));
|
|
// Attempt to generate an informational message
|
|
GenerateInfo(false);
|
|
// Return whether the parsing was successful
|
|
return good;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* Forward the call to run a command.
|
|
*/
|
|
Int32 RunCommand(Int32 invoker, CSStr command)
|
|
{
|
|
return _Cmd->Run(invoker, command);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* Forward the call to terminate the command system.
|
|
*/
|
|
void TerminateCommand()
|
|
{
|
|
_Cmd->Terminate();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
static Function & Cmd_GetOnError()
|
|
{
|
|
return _Cmd->GetOnError();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
static void Cmd_SetOnError(Object & env, Function & func)
|
|
{
|
|
_Cmd->SetOnError(env, func);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
static Function & Cmd_GetOnAuth()
|
|
{
|
|
return _Cmd->GetOnAuth();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
static void Cmd_SetOnAuth(Object & env, Function & func)
|
|
{
|
|
_Cmd->SetOnAuth(env, func);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
static Object & Cmd_GetInvoker()
|
|
{
|
|
return _Core->GetPlayer(_Cmd->GetInvoker()).mObj;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
static Int32 Cmd_GetInvokerID()
|
|
{
|
|
return _Cmd->GetInvoker();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
static CSStr Cmd_GetCommand()
|
|
{
|
|
return _Cmd->GetCommand();
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
static CSStr Cmd_GetArgument()
|
|
{
|
|
return _Cmd->GetArgument();
|
|
}
|
|
|
|
// ================================================================================================
|
|
void Register_Command(HSQUIRRELVM vm)
|
|
{
|
|
Table cmdns(vm);
|
|
|
|
cmdns.Bind(_SC("Listener"), Class< CmdListener, NoCopy< CmdListener > >(vm, _SC("Listener"))
|
|
/* Constructors */
|
|
.Ctor< CSStr >()
|
|
.Ctor< CSStr, CSStr >()
|
|
.Ctor< CSStr, CSStr, Array & >()
|
|
.Ctor< CSStr, CSStr, Uint8, Uint8 >()
|
|
.Ctor< CSStr, CSStr, Array &, Uint8, Uint8 >()
|
|
/* Metamethods */
|
|
.Func(_SC("_cmp"), &CmdListener::Cmp)
|
|
.Func(_SC("_tostring"), &CmdListener::ToString)
|
|
/* Properties */
|
|
.Prop(_SC("Name"), &CmdListener::GetName, &CmdListener::SetName)
|
|
.Prop(_SC("Spec"), &CmdListener::GetSpec, &CmdListener::SetSpec)
|
|
.Prop(_SC("Specifier"), &CmdListener::GetSpec, &CmdListener::SetSpec)
|
|
.Prop(_SC("Tags"), &CmdListener::GetArgTags, &CmdListener::SetArgTags)
|
|
.Prop(_SC("Help"), &CmdListener::GetHelp, &CmdListener::SetHelp)
|
|
.Prop(_SC("Info"), &CmdListener::GetInfo, &CmdListener::SetInfo)
|
|
.Prop(_SC("Authority"), &CmdListener::GetAuthority, &CmdListener::SetAuthority)
|
|
.Prop(_SC("Protected"), &CmdListener::GetProtected, &CmdListener::SetProtected)
|
|
.Prop(_SC("Suspended"), &CmdListener::GetSuspended, &CmdListener::SetSuspended)
|
|
.Prop(_SC("Associate"), &CmdListener::GetAssociate, &CmdListener::SetAssociate)
|
|
.Prop(_SC("MinArgs"), &CmdListener::GetMinArgC, &CmdListener::SetMinArgC)
|
|
.Prop(_SC("MaxArgs"), &CmdListener::GetMaxArgC, &CmdListener::SetMaxArgC)
|
|
.Prop(_SC("Locked"), &CmdListener::GetLocked)
|
|
.Prop(_SC("OnExec"), &CmdListener::GetOnExec)
|
|
.Prop(_SC("OnAuth"), &CmdListener::GetOnAuth)
|
|
.Prop(_SC("OnPost"), &CmdListener::GetOnPost)
|
|
.Prop(_SC("OnFail"), &CmdListener::GetOnFail)
|
|
/* Functions */
|
|
.Func(_SC("BindExec"), &CmdListener::SetOnExec)
|
|
.Func(_SC("BindAuth"), &CmdListener::SetOnAuth)
|
|
.Func(_SC("BindPost"), &CmdListener::SetOnPost)
|
|
.Func(_SC("BindFail"), &CmdListener::SetOnFail)
|
|
.Func(_SC("GetArgTag"), &CmdListener::GetArgTag)
|
|
.Func(_SC("SetArgTag"), &CmdListener::SetArgTag)
|
|
.Func(_SC("GenerateInfo"), &CmdListener::GenerateInfo)
|
|
.Func(_SC("ArgCheck"), &CmdListener::ArgCheck)
|
|
.Func(_SC("AuthCheck"), &CmdListener::AuthCheck)
|
|
.Func(_SC("AuthCheckID"), &CmdListener::AuthCheckID)
|
|
);
|
|
|
|
cmdns.Func(_SC("GetOnError"), &Cmd_GetOnError);
|
|
cmdns.Func(_SC("SetOnError"), &Cmd_SetOnError);
|
|
cmdns.Func(_SC("GetOnAuth"), &Cmd_GetOnAuth);
|
|
cmdns.Func(_SC("SetOnAuth"), &Cmd_SetOnAuth);
|
|
cmdns.Func(_SC("GetInvoker"), &Cmd_GetInvoker);
|
|
cmdns.Func(_SC("GetInvokerID"), &Cmd_GetInvokerID);
|
|
cmdns.Func(_SC("GetName"), &Cmd_GetCommand);
|
|
cmdns.Func(_SC("GetText"), &Cmd_GetArgument);
|
|
|
|
RootTable(vm).Bind(_SC("SqCmd"), cmdns);
|
|
|
|
ConstTable(vm).Enum(_SC("CmdArg"), Enumeration(vm)
|
|
.Const(_SC("Any"), CMDARG_ANY)
|
|
.Const(_SC("Integer"), CMDARG_INTEGER)
|
|
.Const(_SC("Float"), CMDARG_FLOAT)
|
|
.Const(_SC("Boolean"), CMDARG_BOOLEAN)
|
|
.Const(_SC("String"), CMDARG_STRING)
|
|
.Const(_SC("Lower"), CMDARG_LOWER)
|
|
.Const(_SC("Upper"), CMDARG_UPPER)
|
|
.Const(_SC("Greedy"), CMDARG_GREEDY)
|
|
);
|
|
|
|
ConstTable(vm).Enum(_SC("CmdErr"), Enumeration(vm)
|
|
.Const(_SC("Unknown"), CMDERR_UNKNOWN)
|
|
.Const(_SC("EmptyCommand"), CMDERR_EMPTY_COMMAND)
|
|
.Const(_SC("InvalidCommand"), CMDERR_INVALID_COMMAND)
|
|
.Const(_SC("SyntaxError"), CMDERR_SYNTAX_ERROR)
|
|
.Const(_SC("UnknownCommand"), CMDERR_UNKNOWN_COMMAND)
|
|
.Const(_SC("MissingExecuter"), CMDERR_MISSING_EXECUTER)
|
|
.Const(_SC("InsufficientAuth"), CMDERR_INSUFFICIENT_AUTH)
|
|
.Const(_SC("IncompleteArgs"), CMDERR_INCOMPLETE_ARGS)
|
|
.Const(_SC("ExtraneousArgs"), CMDERR_EXTRANEOUS_ARGS)
|
|
.Const(_SC("UnsupportedArg"), CMDERR_UNSUPPORTED_ARG)
|
|
.Const(_SC("ExecutionFailed"), CMDERR_EXECUTION_FAILED)
|
|
.Const(_SC("BufferOverflow"), CMDERR_BUFFER_OVERFLOW)
|
|
.Const(_SC("Max"), CMDERR_MAX)
|
|
);
|
|
}
|
|
|
|
} // Namespace:: SqMod
|