diff --git a/cbp/Module.cbp b/cbp/Module.cbp index 0328d10c..fe5453e1 100644 --- a/cbp/Module.cbp +++ b/cbp/Module.cbp @@ -127,6 +127,8 @@ + + @@ -149,6 +151,8 @@ + + diff --git a/source/Base/Buffer.cpp b/source/Base/Buffer.cpp new file mode 100644 index 00000000..03bf3ce4 --- /dev/null +++ b/source/Base/Buffer.cpp @@ -0,0 +1,122 @@ +#include "Base/Buffer.hpp" + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +// ------------------------------------------------------------------------------------------------ +Buffer::Buffer() + : m_Data(nullptr), m_Size(0) +{ + /* ... */ +} + +// ------------------------------------------------------------------------------------------------ +Buffer::Buffer(SzType sz) + : m_Data(Alloc(sz)), m_Size(m_Data == nullptr ? 0 : sz) +{ + /* ... */ +} + +// ------------------------------------------------------------------------------------------------ +Buffer::Buffer(Buffer && o) + : m_Data(o.m_Data), m_Size(o.m_Size) +{ + o.m_Data = nullptr; +} + +// ------------------------------------------------------------------------------------------------ +Buffer::~Buffer() +{ + Free(m_Data); +} + +// ------------------------------------------------------------------------------------------------ +Buffer & Buffer::operator = (Buffer && o) +{ + if (m_Data != o.m_Data) + { + m_Data = o.m_Data; + m_Size = o.m_Size; + + o.m_Data = nullptr; + } + + return *this; +} + +// ------------------------------------------------------------------------------------------------ +void Buffer::Resize(SzType sz) +{ + if (!sz) + { + Free(m_Data); + } + else if (sz != m_Size) + { + Pointer data = m_Data; + m_Data = Alloc(sz); + + if (sz > m_Size) + { + Copy(data, m_Size); + } + else + { + Copy(data, sz); + } + + m_Size = sz; + Free(data); + } +} + +// ------------------------------------------------------------------------------------------------ +void Buffer::Reserve(SzType sz) +{ + if (!sz) + { + return; + } + else if (sz > m_Size) + { + Pointer data = m_Data; + m_Data = Alloc(sz); + + Copy(data, m_Size); + + m_Size = sz; + Free(data); + } +} + +// ------------------------------------------------------------------------------------------------ +void Buffer::Copy(ConstPtr buf, SzType sz) +{ + memcpy(m_Data, buf, sz * sizeof(Value)); +} + +// ------------------------------------------------------------------------------------------------ +Buffer::Pointer Buffer::Alloc(SzType sz) +{ + Pointer mem = reinterpret_cast< Pointer >(malloc(sz * sizeof(Value))); + + if (!mem) + { + return nullptr; + } + + return mem; +} + +// ------------------------------------------------------------------------------------------------ +void Buffer::Free(Pointer buf) +{ + if (buf != nullptr) + { + free(buf); + } +} + + + +} // Namespace:: SqMod diff --git a/source/Base/Buffer.hpp b/source/Base/Buffer.hpp new file mode 100644 index 00000000..8cbd0c6d --- /dev/null +++ b/source/Base/Buffer.hpp @@ -0,0 +1,230 @@ +#ifndef _BASE_BUFFER_HPP_ +#define _BASE_BUFFER_HPP_ + +// ------------------------------------------------------------------------------------------------ +#include "Config.hpp" + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +/* ------------------------------------------------------------------------------------------------ + * ... +*/ +class Buffer +{ +public: + + // -------------------------------------------------------------------------------------------- + typedef SQChar Value; + + // -------------------------------------------------------------------------------------------- + typedef Value & Reference; + typedef const Value & ConstRef; + + // -------------------------------------------------------------------------------------------- + typedef Value * Pointer; + typedef const Value * ConstPtr; + + // -------------------------------------------------------------------------------------------- + typedef SQUint32 SzType; + + /* -------------------------------------------------------------------------------------------- + * ... + */ + Buffer(); + + /* -------------------------------------------------------------------------------------------- + * ... + */ + Buffer(SzType sz); + + /* -------------------------------------------------------------------------------------------- + * ... + */ + Buffer(const Buffer &) = delete; + + /* -------------------------------------------------------------------------------------------- + * ... + */ + Buffer(Buffer && o); + + /* -------------------------------------------------------------------------------------------- + * ... + */ + ~Buffer(); + + /* -------------------------------------------------------------------------------------------- + * ... + */ + Buffer & operator = (const Buffer &) = delete; + + /* -------------------------------------------------------------------------------------------- + * ... + */ + Buffer & operator = (Buffer && o); + + /* -------------------------------------------------------------------------------------------- + * ... + */ + bool operator == (const Buffer & o) const + { + return (m_Size == o.m_Size); + } + + /* -------------------------------------------------------------------------------------------- + * ... + */ + bool operator != (const Buffer & o) const + { + return (m_Size != o.m_Size); + } + + /* -------------------------------------------------------------------------------------------- + * ... + */ + bool operator < (const Buffer & o) const + { + return (m_Size < o.m_Size); + } + + /* -------------------------------------------------------------------------------------------- + * ... + */ + bool operator > (const Buffer & o) const + { + return (m_Size > o.m_Size); + } + + /* -------------------------------------------------------------------------------------------- + * ... + */ + bool operator <= (const Buffer & o) const + { + return (m_Size <= o.m_Size); + } + + /* -------------------------------------------------------------------------------------------- + * ... + */ + bool operator >= (const Buffer & o) const + { + return (m_Size >= o.m_Size); + } + + /* -------------------------------------------------------------------------------------------- + * ... + */ + operator bool () const + { + return (m_Data != nullptr); + } + + /* -------------------------------------------------------------------------------------------- + * ... + */ + operator ! () const + { + return (m_Data == nullptr); + } + + /* -------------------------------------------------------------------------------------------- + * ... + */ + Pointer Begin() + { + return m_Data; + } + + /* -------------------------------------------------------------------------------------------- + * ... + */ + ConstPtr Begin() const + { + return m_Data; + } + + /* -------------------------------------------------------------------------------------------- + * ... + */ + Pointer End() + { + return m_Data + m_Size; + } + + /* -------------------------------------------------------------------------------------------- + * ... + */ + ConstPtr End() const + { + return m_Data + m_Size; + } + + /* -------------------------------------------------------------------------------------------- + * ... + */ + Pointer Data() + { + return m_Data; + } + + /* -------------------------------------------------------------------------------------------- + * ... + */ + ConstPtr Data() const + { + return m_Data; + } + + /* -------------------------------------------------------------------------------------------- + * ... + */ + SzType Size() const + { + return m_Size; + } + + /* -------------------------------------------------------------------------------------------- + * ... + */ + void Resize(SzType sz); + + /* -------------------------------------------------------------------------------------------- + * ... + */ + void Reserve(SzType sz); + + /* -------------------------------------------------------------------------------------------- + * ... + */ + void Increase(SzType sz) + { + Reserve(m_Size + sz); + } + +protected: + + /* -------------------------------------------------------------------------------------------- + * ... + */ + void Copy(ConstPtr buf, SzType sz); + + /* -------------------------------------------------------------------------------------------- + * ... + */ + static Pointer Alloc(SzType sz); + + /* -------------------------------------------------------------------------------------------- + * ... + */ + static void Free(Pointer buf); + +private: + + // -------------------------------------------------------------------------------------------- + Pointer m_Data; + SzType m_Size; +}; + +} // Namespace:: SqMod + +#endif // _BASE_BUFFER_HPP_ diff --git a/source/Base/Shared.cpp b/source/Base/Shared.cpp index 1806b541..c15ee4d9 100644 --- a/source/Base/Shared.cpp +++ b/source/Base/Shared.cpp @@ -28,10 +28,10 @@ namespace SqMod { // ------------------------------------------------------------------------------------------------ static std::unique_ptr RG32_MT19937 = std::unique_ptr( \ - new std::mt19937(static_cast(std::time(0)))); + new std::mt19937(_SCU32(std::time(0)))); static std::unique_ptr RG64_MT19937 = std::unique_ptr( \ - new std::mt19937_64(static_cast(std::time(0)))); + new std::mt19937_64(_SCU32(std::time(0)))); // ------------------------------------------------------------------------------------------------ static std::uniform_int_distribution Int8_Dist(std::numeric_limits::min(), std::numeric_limits::max()); @@ -258,30 +258,30 @@ void LogFtl(const char * fmt, ...) const SQChar * ToStringF(const char * fmt, ...) { // Acquire a buffer from the buffer pool - Core::Buffer vbuf = _Core->PullBuffer(); + Buffer vbuf = _Core->PullBuffer(128); // Get direct access to the buffer data - Core::Buffer::value_type * buf = vbuf.data(); + Buffer::Pointer buf = vbuf.Data(); // Variable arguments structure va_list args; // Get the specified arguments va_start (args, fmt); // Run the specified format - int ret = std::vsnprintf(buf, vbuf.size() * sizeof(Core::Buffer::value_type), fmt, args); + int ret = std::vsnprintf(buf, vbuf.Size() * sizeof(Buffer::Value), fmt, args); // Check for buffer overflows - if (static_cast(ret) >= vbuf.size()) + if (_SCU32(ret) >= vbuf.Size()) { - // Throw error - LogErr("Buffer overflow object to string conversion: %d > %d", ret, vbuf.size()); - // Return an empty string - buf[0] = '\0'; + // Scale buffer + vbuf.Reserve(ret); + // Run the specified format + ret = std::vsnprintf(buf, vbuf.Size() * sizeof(Buffer::Value), fmt, args); } // Check for formatting errors - else if (ret < 0) + if (ret < 0) { // Throw error - LogErr("Failed to convert object to string"); + LogErr("Failed to run the specified string format"); // Return an empty string - buf[0] = '\0'; + buf[0] = 0; } // Return the buffer back to the buffer pool _Core->PushBuffer(std::move(vbuf)); @@ -293,11 +293,11 @@ const SQChar * ToStringF(const char * fmt, ...) const SQChar * InsertStr(const SQChar * f, const std::vector< const SQChar * > & a) { // Acquire a buffer from the buffer pool - Core::Buffer vbuf = _Core->PullBuffer(); + Buffer vbuf = _Core->PullBuffer(128); // Get direct access to the buffer data - Core::Buffer::value_type * buf = vbuf.data(); + Buffer::Pointer buf = vbuf.Data(); // Get the size of the buffer - const Core::Buffer::size_type sz = vbuf.size(); + const Buffer::SzType sz = vbuf.Size(); // Size of the resulted string and the number of specified arguments unsigned n = 0, s = a.size(); // See if the format string is valid @@ -375,17 +375,17 @@ const SQChar * InsStr(const SQChar * f) const SQChar * LeftStr(const SQChar * t, SQChar f, SQUint32 w) { // Acquire a buffer from the buffer pool - Core::Buffer vbuf = _Core->PullBuffer(); + Buffer vbuf = _Core->PullBuffer(w); // Get direct access to the buffer data - Core::Buffer::value_type * buf = vbuf.data(); + Buffer::Pointer buf = vbuf.Data(); // Get the length of the string SQUint32 n = strlen(t); // Fill the buffer with the specified fill character - memset(buf, f, w * sizeof(Core::Buffer::value_type)); + memset(buf, f, w * sizeof(Buffer::Value)); // Is the width in bounds? - if (w >= vbuf.size()) + if (w >= vbuf.Size()) { - LogWrn("Invalid width specified: %d > %d", w, vbuf.size()); + LogWrn("Invalid width specified: %d > %d", w, vbuf.Size()); // Invalidate the width w = 0; } @@ -415,17 +415,17 @@ const SQChar * LeftStr(const SQChar * t, SQChar f, SQUint32 w) const SQChar * LeftStr(const SQChar * t, SQChar f, SQUint32 w, SQUint32 o) { // Acquire a buffer from the buffer pool - Core::Buffer vbuf = _Core->PullBuffer(); + Buffer vbuf = _Core->PullBuffer(w); // Get direct access to the buffer data - Core::Buffer::value_type * buf = vbuf.data(); + Buffer::Pointer buf = vbuf.Data(); // Get the length of the string SQUint32 n = strlen(t); // Fill the buffer with the specified fill character - memset(buf, f, w * sizeof(Core::Buffer::value_type)); + memset(buf, f, w * sizeof(Buffer::Value)); // Is the width in bounds? - if (w >= vbuf.size()) + if (w >= vbuf.Size()) { - LogWrn("Invalid width specified: %d > %d", w, vbuf.size()); + LogWrn("Invalid width specified: %d > %d", w, vbuf.Size()); // Invalidate the width w = 0; } @@ -456,17 +456,17 @@ const SQChar * LeftStr(const SQChar * t, SQChar f, SQUint32 w, SQUint32 o) const SQChar * RightStr(const SQChar * t, SQChar f, SQUint32 w) { // Acquire a buffer from the buffer pool - Core::Buffer vbuf = _Core->PullBuffer(); + Buffer vbuf = _Core->PullBuffer(w); // Get direct access to the buffer data - Core::Buffer::value_type * buf = vbuf.data(); + Buffer::Pointer buf = vbuf.Data(); // Get the length of the string SQUint32 n = strlen(t); // Fill the buffer with the specified fill character - memset(buf, f, w * sizeof(Core::Buffer::value_type)); + memset(buf, f, w * sizeof(Buffer::Value)); // Is the width in bounds? - if (w >= vbuf.size()) + if (w >= vbuf.Size()) { - LogWrn("Invalid width specified: %d > %d", w, vbuf.size()); + LogWrn("Invalid width specified: %d > %d", w, vbuf.Size()); // Invalidate the width w = 0; } @@ -496,17 +496,17 @@ const SQChar * RightStr(const SQChar * t, SQChar f, SQUint32 w) const SQChar * RightStr(const SQChar * t, SQChar f, SQUint32 w, SQUint32 o) { // Acquire a buffer from the buffer pool - Core::Buffer vbuf = _Core->PullBuffer(); + Buffer vbuf = _Core->PullBuffer(w); // Get direct access to the buffer data - Core::Buffer::value_type * buf = vbuf.data(); + Buffer::Pointer buf = vbuf.Data(); // Get the length of the string SQUint32 n = strlen(t); // Fill the buffer with the specified fill character - memset(buf, f, w * sizeof(Core::Buffer::value_type)); + memset(buf, f, w * sizeof(Buffer::Value)); // Is the width in bounds? - if (w >= vbuf.size()) + if (w >= vbuf.Size()) { - LogWrn("Invalid width specified: %d > %d", w, vbuf.size()); + LogWrn("Invalid width specified: %d > %d", w, vbuf.Size()); // Invalidate the width w = 0; } @@ -537,17 +537,17 @@ const SQChar * RightStr(const SQChar * t, SQChar f, SQUint32 w, SQUint32 o) const SQChar * CenterStr(const SQChar * t, SQChar f, SQUint32 w) { // Acquire a buffer from the buffer pool - Core::Buffer vbuf = _Core->PullBuffer(); + Buffer vbuf = _Core->PullBuffer(w); // Get direct access to the buffer data - Core::Buffer::value_type * buf = vbuf.data(); + Buffer::Pointer buf = vbuf.Data(); // Get the length of the string SQUint32 n = strlen(t); // Fill the buffer with the specified fill character - memset(buf, f, w * sizeof(Core::Buffer::value_type)); + memset(buf, f, w * sizeof(Buffer::Value)); // Is the width in bounds? - if (w >= vbuf.size()) + if (w >= vbuf.Size()) { - LogWrn("Invalid width specified: %d > %d", w, vbuf.size()); + LogWrn("Invalid width specified: %d > %d", w, vbuf.Size()); // Invalidate the width w = 0; } @@ -577,13 +577,13 @@ const SQChar * CenterStr(const SQChar * t, SQChar f, SQUint32 w) // ------------------------------------------------------------------------------------------------ void InitMTRG32() { - RG32_MT19937.reset(new std::mt19937(static_cast(std::time(0)))); + RG32_MT19937.reset(new std::mt19937(_SCU32(std::time(0)))); } // ------------------------------------------------------------------------------------------------ void InitMTRG64() { - RG64_MT19937.reset(new std::mt19937_64(static_cast(std::time(0)))); + RG64_MT19937.reset(new std::mt19937_64(_SCU32(std::time(0)))); } // ------------------------------------------------------------------------------------------------ diff --git a/source/Command.cpp b/source/Command.cpp new file mode 100644 index 00000000..74a15748 --- /dev/null +++ b/source/Command.cpp @@ -0,0 +1,1015 @@ +#include "Command.hpp" +#include "Register.hpp" +#include "Core.hpp" +#include "Entity.hpp" + +// ------------------------------------------------------------------------------------------------ +#include + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +// ------------------------------------------------------------------------------------------------ +const CmdManager::Pointer _Cmd = CmdManager::Inst(); + +// ------------------------------------------------------------------------------------------------ +void CmdManager::_Finalizer(CmdManager * ptr) +{ + delete ptr; /* Assuming 'delete' checks for NULL */ +} + +// ------------------------------------------------------------------------------------------------ +CmdManager::Pointer CmdManager::Inst() +{ + if (!_Cmd) + { + return Pointer(new CmdManager(), &CmdManager::_Finalizer); + } + + return Pointer(nullptr, &CmdManager::_Finalizer); +} + +// ------------------------------------------------------------------------------------------------ +CmdManager::CmdManager() + : m_Commands(), m_Invoker(SQMOD_UNKNOWN), m_Argv() +{ + /* ... */ +} + +// ------------------------------------------------------------------------------------------------ +CmdManager::~CmdManager() +{ + /* ... */ +} + +// ------------------------------------------------------------------------------------------------ +void CmdManager::VMClose() +{ + // Release the reference to the specified callbacks + m_OnError.Release2(); + // We must not keep arguments + m_Argv.fill(CmdArgs::value_type(CMDARG_ANY, NullData())); + // Reset the argument counter + m_Argc = 0; +} + +// ------------------------------------------------------------------------------------------------ +void CmdManager::Bind(const String & name, CmdListener * cmd) +{ + // If it doesn't exist then it will be created + m_Commands[name] = cmd; +} + +// ------------------------------------------------------------------------------------------------ +void CmdManager::Unbind(const String & name) +{ + m_Commands.erase(name); +} + +// ------------------------------------------------------------------------------------------------ +Function & CmdManager::GetOnError() +{ + return m_OnError; +} + +// ------------------------------------------------------------------------------------------------ +void CmdManager::SetOnError(Function & func) +{ + m_OnError = func; +} + +// ------------------------------------------------------------------------------------------------ +Function & CmdManager::GetOnAuth() +{ + return m_OnAuth; +} + +// ------------------------------------------------------------------------------------------------ +void CmdManager::SetOnAuth(Function & func) +{ + m_OnAuth = func; +} + +// ------------------------------------------------------------------------------------------------ +const SQChar * CmdManager::GetName() +{ + return m_Name.c_str(); +} + +// ------------------------------------------------------------------------------------------------ +const SQChar * CmdManager::GetText() +{ + return m_Text.c_str(); +} + +// ------------------------------------------------------------------------------------------------ +void CmdManager::Execute(SQInt32 invoker, const String & str) +{ + // Save the invoker identifier + m_Invoker = invoker; + // Find where the command name ends + String::size_type split_pos = str.find_first_of(' '); + // Attempt to separate the command name from arguments + if (split_pos != String::npos) + { + m_Name = str.substr(0, split_pos); + m_Text = str.substr(split_pos+1); + } + // No arguments specified + else + { + m_Name = str; + m_Text = _SC(""); + } + // Attempt to find a command with this name + CmdPool::iterator itr = m_Commands.find(m_Name); + // See if a command with this name could be found + if (itr != m_Commands.end()) + { + // Place a lock on the command + itr->second->m_Lock = true; + // Attempt to execute the command + Exec(*itr->second); + // Take the lock from the command + itr->second->m_Lock = false; + } + else + { + Error(CMDERR_UNKNOWN_COMMAND, _SC("No such command exists: %s"), m_Name.c_str()); + } +} + +// ------------------------------------------------------------------------------------------------ +void CmdManager::Exec(CmdListener & cmd) +{ + // See if the invoker has enough authority to execute this command + if (!cmd.AuthCheck(m_Invoker)) + { + Error(CMDERR_INSUFFICIENT_AUTH, _SC("Insufficient authority to execute command")); + // Command failed + return; + } + // See if an executer was specified + if (cmd.GetOnExec().IsNull()) + { + Error(CMDERR_MISSING_EXECUTER, _SC("No executer was specified for this command")); + // Command failed + return; + } + // See if there are any arguments to parse + if (!m_Text.empty() && !Parse(cmd.GetMaxArgC())) + { + // The error message was reported while parsing + return; + } + // See if we have enough arguments specified + if (cmd.GetMinArgC() > m_Argc) + { + Error(CMDERR_INCOMPLETE_ARGS, _SC("Incomplete command arguments: %u < %u"), + m_Argc, cmd.GetMinArgC()); + // Command failed + return; + } + // Check argument types agains the command specifiers + for (Uint32 arg = 0; arg < m_Argc; ++arg) + { + if (!cmd.ArgCheck(arg, m_Argv[arg].first)) + { + Error(CMDERR_UNSUPPORTED_ARG, _SC("Unsupported command argument: %u -> %s"), + arg, CmdArgSpecToStr(m_Argv[arg].first)); + // Command failed + return; + } + } + // Reserve an array for the extracted arguments + Array args(DefaultVM::Get(), m_Argc); + // Copy the arguments into the array + for (SQUint32 arg = 0; arg < m_Argc; ++arg) + { + args.Bind(arg, m_Argv[arg].second); + } + // Attempt to execute the command with the specified arguments + bool result = cmd.Execute(m_Invoker, args); + // See if an error occured + if (Error::Occurred(DefaultVM::Get())) + { + Error(CMDERR_EXECUTION_FAILED, _SC("Command execution failed: %s"), Error::Message(DefaultVM::Get()).c_str()); + } + // See if the command failed + else if (!result) + { + Error(CMDERR_EXECUTION_FAILED, _SC("Command execution failed")); + } +} + +// ------------------------------------------------------------------------------------------------ +bool CmdManager::Parse(SQUint32 max) +{ + // Clear previous arguments + m_Argv.fill(CmdArgs::value_type(CMDARG_ANY, NullData())); + // Reset the argument counter + m_Argc = 0; + // Request a temporary buffer + Buffer buffer = _Core->PullBuffer(128); + // Internal start and end of the temporary buffer + SQChar * cur = nullptr, * end = nullptr; + // The pointer to the currently processed character + const SQChar * str = m_Text.c_str(); + // Currently and previously processed character + SQChar ch = 0, pr = 0; + // When parsing may continue + bool good = true; + // Process the specified command text + while (good) + { + // Extract the current character before advancing + ch = *(str++); + // See if there's anything left to parse + if (ch == 0) + { + // Finished parsing + break; + } + else if (m_Argc > max) + { + Error(CMDERR_EXTRANEOUS_ARGS, _SC("Extraneous command arguments: %u > %u"), + m_Argc, max); + // Parsing failed + good = false; + // Stop parsing + break; + } + // See if we have to extract a string argument + else if ((ch == '\'' || ch == '"') && pr != '\\') + { + // Obtain the internal beginning and ending of the temporary buffer + cur = buffer.Begin(), end = (buffer.End()-1); /* + null */ + // Attempt to consume the string argument + while (good) + { + // Extract the current character before advancing + ch = *(str++); + // See if there's anything left to parse + if (ch == 0) + { + Error(CMDERR_SYNTAX_ERROR, _SC("String not closed properly near command argument: %u"), m_Argc); + // Parsing failed + good = false; + // Stop parsing + break; + } + // First un-escaped single or double quote character ends argument + if (ch == '\'' || ch == '"') + { + // Was this not escaped? + if (pr != '\\') + { + // Terminate the string value in the temporary buffer + *cur = 0; + // Stop parsing + break; + } + else + { + // Overwrite last character when replicating + --cur; + } + } + // See if the temporary buffer needs to scale + else if (cur == end) + { + // Attempt to increase the size of the temporary buffer + buffer.Increase(512); + // Obtain the internal beginning and ending of the temporary buffer again + cur = (buffer.Begin() + (buffer.Size()-512)), end = (buffer.End()-1); /* + null */ + } + // Simply replicate the character to the temporary buffer + *(cur++) = ch; + // Save current argument as the previous one + pr = ch; + } + // See if the argument was valid + if (!good) + { + // Propagate failure + break; + } + // Transform it into a squirrel object + sq_pushstring(DefaultVM::Get(), buffer.Data(), cur - buffer.Begin()); + // Get the object from the squirrel VM + Var< SqObj > 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[m_Argc].first = CMDARG_STRING; + m_Argv[m_Argc].second = var.value; + // Move to the next argument + ++m_Argc; + } + // Ignore space until another valid argument is found + else if (ch != ' ' && (pr == ' ' || pr == 0)) + { + // Obtain the internal beginning and ending of the temporary buffer + cur = buffer.Begin(), end = (buffer.End()-1); /* + null */ + // Move back to the previous character before extracting + --str; + // Attempt to consume the argument value + while (good) + { + // Extract the current character before advancing + ch = *(str++); + // See if there's anything left to parse + if (ch == 0) + { + // Move to the previous character so the main loop can stop + --str; + // Argument ended + break; + } + else if (ch == ' ') + { + // Argument ended + break; + } + // See if the buffer needs to scale + else if (cur == end) + { + // Attempt to increase the size of the temporary buffer + buffer.Increase(512); + // Obtain the internal beginning and ending of the temporary buffer again + cur = buffer.Begin() + (buffer.Size()-512), end = (buffer.End()-1); /* + null */ + } + // Simply replicate the character to the temporary buffer + *(cur++) = ch; + // Save current argument as the previous one + pr = ch; + } + // Terminate the string value in the temporary buffer + *cur = 0; + // Used to exclude all other checks when a valid type was found + bool found = false; + // Attempt to treat the value as an integer number + if (!found) + { + SQChar * next = NULL; + // Attempt to extract the integer value + Int64 value = strtol(buffer.Data(), &next, 10); + // See if this whole string was an integer + if (next == cur) + { + // Transform it into a squirrel object + Var< SQInteger >::push(DefaultVM::Get(), _SCSQI(value)); + // Get the object from the squirrel VM + Var< SqObj > 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[m_Argc].first = CMDARG_INTEGER; + m_Argv[m_Argc].second = var.value; + // Move to the next argument + ++m_Argc; + // We've found the correct value + found = true; + } + } + // Attempt to treat the value as a float number + if (!found) + { + SQChar * next = 0; + // Attempt to extract the floating point value + Float64 value = strtod(buffer.Data(), &next); + // See if this whole string was a float value + if (next == cur) + { + // Transform it into a squirrel object + Var< SQFloat >::push(DefaultVM::Get(), _SCSQF(value)); + // Get the object from the squirrel VM + Var< SqObj > 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[m_Argc].first = CMDARG_FLOAT; + m_Argv[m_Argc].second = var.value; + // Move to the next argument + ++m_Argc; + // We've found the correct value + found = true; + } + } + // Attempt to treat the value as a boolean + if (!found) + { + if (strcmp(buffer.Data(), "true") == 0 || strcmp(buffer.Data(), "on") == 0) + { + // Transform it into a squirrel object + Var< bool >::push(DefaultVM::Get(), true); + // Get the object from the squirrel VM + Var< SqObj > 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[m_Argc].first = CMDARG_BOOLEAN; + m_Argv[m_Argc].second = var.value; + // Move to the next argument + ++m_Argc; + // We've found the correct value + found = true; + } + else if (strcmp(buffer.Data(), "false") == 0 || strcmp(buffer.Data(), "off") == 0) + { + // Transform it into a squirrel object + Var< bool >::push(DefaultVM::Get(), false); + // Get the object from the squirrel VM + Var< SqObj > 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[m_Argc].first = CMDARG_BOOLEAN; + m_Argv[m_Argc].second = var.value; + // Move to the next argument + ++m_Argc; + // We've found the correct value + found = true; + } + } + // If everything else failed then simply treat the value as a string + if (!found) + { + // Transform it into a squirrel object + Var< const SQChar * >::push(DefaultVM::Get(), buffer.Data(), (cur - buffer.Begin())); + // Get the object from the squirrel VM + Var< SqObj > 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[m_Argc].first = CMDARG_STRING; + m_Argv[m_Argc].second = var.value; + // Move to the next argument + ++m_Argc; + } + } + // Save current argument as the previous one + pr = ch; + } + // Return the borrowed buffer + _Core->PushBuffer(std::move(buffer)); + // Return whether the parsing was successful + return good; +} + +// ------------------------------------------------------------------------------------------------ +CmdListener::CmdListener() + : CmdListener(_SC(""), _SC("")) +{ + /* ... */ +} + +// ------------------------------------------------------------------------------------------------ +CmdListener::CmdListener(const SQChar * name) + : CmdListener(name, _SC("")) +{ + /* ... */ +} + +// ------------------------------------------------------------------------------------------------ +CmdListener::CmdListener(const SQChar * name, const SQChar * spec) + : m_Args({{0}}) + , m_MinArgc(0) + , m_MaxArgc(MAX_CMD_ARGS) + , m_Name() + , m_Spec() + , m_Help() + , m_Info() + , m_OnAuth(_Cmd->GetOnAuth()) + , m_OnExec() + , m_Tag() + , m_Data() + , m_Level(SQMOD_UNKNOWN) + , m_Suspended(false) + , m_Authority(false) + , m_Lock(false) +{ + // Bind to the specified command name + SetName(name); + // Apply the specified argument rules + SetSpec(spec); + // Receive notification when the VM is about to be closed to release object references + _Core->VMClose.Connect< CmdListener, &CmdListener::VMClose >(this); +} + +// ------------------------------------------------------------------------------------------------ +CmdListener::~CmdListener() +{ + // Stop receiving notification when the VM is about to be closed + _Core->VMClose.Disconnect< CmdListener, &CmdListener::VMClose >(this); +} + +// ------------------------------------------------------------------------------------------------ +void CmdListener::VMClose() +{ + // Release the reference to the specified callbacks + m_OnAuth.Release2(); + m_OnExec.Release2(); + // Release the reference to the specified user data + m_Data.Release(); +} + +// ------------------------------------------------------------------------------------------------ +SQInt32 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; + } +} + +// ------------------------------------------------------------------------------------------------ +const SQChar * CmdListener::ToString() const +{ + return m_Name.c_str(); +} + +// ------------------------------------------------------------------------------------------------ +const SQChar * CmdListener::GetTag() const +{ + return m_Tag.c_str(); +} + +// ------------------------------------------------------------------------------------------------ +void CmdListener::SetTag(const SQChar * tag) +{ + m_Tag.assign(tag); +} + +// ------------------------------------------------------------------------------------------------ +SqObj & CmdListener::GetData() +{ + return m_Data; +} + +// ------------------------------------------------------------------------------------------------ +void CmdListener::SetData(SqObj & data) +{ + m_Data = data; +} + +// ------------------------------------------------------------------------------------------------ +const SQChar * CmdListener::GetName() const +{ + return m_Name.c_str(); +} + +// ------------------------------------------------------------------------------------------------ +void CmdListener::SetName(const SQChar * name) +{ + if (!m_Lock) + { + // If there's a name then we're already binded + if (!m_Name.empty()) + { + _Cmd->Unbind(name); + } + // Assign the new name + m_Name.assign(name); + // If the new name is valid then bind to it + if (!m_Name.empty()) + { + _Cmd->Bind(name, this); + } + } + else + { + LogWrn("Attempting to while command is under active lock: %s", m_Name.c_str()); + } +} + +// ------------------------------------------------------------------------------------------------ +const SQChar * CmdListener::GetSpec() const +{ + return m_Spec.c_str(); +} + +// ------------------------------------------------------------------------------------------------ +void CmdListener::SetSpec(const SQChar * spec) +{ + if (ProcSpec(spec)) + { + m_Spec.assign(spec); + } +} + +// ------------------------------------------------------------------------------------------------ +const SQChar * CmdListener::GetHelp() const +{ + return m_Help.c_str(); +} + +// ------------------------------------------------------------------------------------------------ +void CmdListener::SetHelp(const SQChar * help) +{ + m_Help.assign(help); +} + +// ------------------------------------------------------------------------------------------------ +const SQChar * CmdListener::GetInfo() const +{ + return m_Info.c_str(); +} + +// ------------------------------------------------------------------------------------------------ +void CmdListener::SetInfo(const SQChar * info) +{ + m_Info.assign(info); +} + +// ------------------------------------------------------------------------------------------------ +Function & CmdListener::GetOnAuth() +{ + return m_OnAuth; +} + +// ------------------------------------------------------------------------------------------------ +void CmdListener::SetOnAuth(Function & func) +{ + m_OnAuth = func; +} + +// ------------------------------------------------------------------------------------------------ +Function & CmdListener::GetOnExec() +{ + return m_OnExec; +} + +// ------------------------------------------------------------------------------------------------ +void CmdListener::SetOnExec(Function & func) +{ + m_OnExec = func; +} + +// ------------------------------------------------------------------------------------------------ +SQInt32 CmdListener::GetLevel() const +{ + return m_Level; +} + +// ------------------------------------------------------------------------------------------------ +void CmdListener::SetLevel(SQInt32 level) +{ + m_Level = level; +} + +// ------------------------------------------------------------------------------------------------ +bool CmdListener::GetSuspended() const +{ + return m_Suspended; +} + +// ------------------------------------------------------------------------------------------------ +void CmdListener::SetSuspended(bool toggle) +{ + m_Suspended = toggle; +} + +// ------------------------------------------------------------------------------------------------ +bool CmdListener::GetAuthority() const +{ + return m_Authority; +} + +// ------------------------------------------------------------------------------------------------ +void CmdListener::SetAuthority(bool toggle) +{ + m_Authority = toggle; +} + +// ------------------------------------------------------------------------------------------------ +SQUint32 CmdListener::GetMinArgC() const +{ + return m_MinArgc; +} + +// ------------------------------------------------------------------------------------------------ +void CmdListener::SetMinArgC(SQUint32 val) +{ + if (val < MAX_CMD_ARGS && val <= m_MaxArgc) + { + m_MinArgc = val; + } + else if (val > m_MaxArgc) + { + LogWrn("Attempting to using a value bigger then maximum: %u > %u", + val, m_MaxArgc); + } + else + { + LogWrn("Attempting to using an out of bounds value %u > %u", + val, MAX_CMD_ARGS); + } +} + +// ------------------------------------------------------------------------------------------------ +SQUint32 CmdListener::GetMaxArgC() const +{ + return m_MaxArgc; +} + +// ------------------------------------------------------------------------------------------------ +void CmdListener::SetMaxArgC(SQUint32 val) +{ + if (val < MAX_CMD_ARGS && val >= m_MinArgc) + { + m_MaxArgc = val; + } + else if (val < m_MinArgc) + { + LogWrn("Attempting to using a value smaller then minimum: %u < %u", + val, m_MinArgc); + } + else + { + LogWrn("Attempting to using an out of bounds value: %u > %d", + val, MAX_CMD_ARGS); + } +} + +// ------------------------------------------------------------------------------------------------ +bool CmdListener::ArgCheck(SQUint32 arg, Uint8 mask) const +{ + if (arg < MAX_CMD_ARGS) + { + return (m_Args[arg] & mask) || m_Args[arg] == CMDARG_ANY; + } + else + { + LogErr("Unable to because : argument is out of bounds %u > %u", + arg, MAX_CMD_ARGS); + } + // Argument failed inspection + return false; +} + +// ------------------------------------------------------------------------------------------------ +bool CmdListener::AuthCheck(SQInt32 id) +{ + // Allow execution by default + bool allow = true; + // Do we need explicit authority verification? + if (m_Authority) + { + // 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, SQInt32 >(id); + // 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_Level >= 0) + { + allow = (Reference< CPlayer >::Get(id).Level >= m_Level); + } + } + // Return result + return allow; +} + +// ------------------------------------------------------------------------------------------------ +bool CmdListener::Execute(SQInt32 invoker, Array & args) +{ + bool result = false; + // Was there an executer specified? + if (!m_OnExec.IsNull()) + { + // Attempt to evaluate the specified executer + SharedPtr< bool > ret = m_OnExec.Evaluate< bool, SQInt32, Array & >(invoker, args); + // See if the executer succeded or default to failed + result = !ret ? false : *ret; + } + // Return result + return result; +} + +// ------------------------------------------------------------------------------------------------ +bool CmdListener::ProcSpec(const SQChar * str) +{ + // Currently processed character + SQChar ch = 0; + // When parsing may continue + bool good = true; + // Currently processed argument + SQUint32 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 > MAX_CMD_ARGS) + { + LogErr("Unable to because : argument is out of bounds %u > %u", + idx, MAX_CMD_ARGS); + // Parsing failed + good = false; + // Stop parsing + break; + } + // Move 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 stop + break; + } + // Apply the type specifier + switch(ch) + { + // Enable the integer type + case 'i': m_Args[idx] |= CMDARG_INTEGER; break; + // Enable the float type + case 'f': m_Args[idx] |= CMDARG_FLOAT; break; + // Enable the boolean type + case 'b': m_Args[idx] |= CMDARG_BOOLEAN; break; + // Enable the string type + case 's': m_Args[idx] |= CMDARG_STRING; break; + // Unknown type! + default: + { + LogErr("Unable to because : unknown type specifier %u -> %c", + idx, ch); + // Parsing failed + good = false; + } + break; + } + } + } + // Reset all argument specifiers if failed + if (!good) + { + m_Args.fill(CMDARG_ANY); + } + // Return whether the parsing was successful + return good; +} + +// ------------------------------------------------------------------------------------------------ +const SQChar * 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: return _SC("string"); + default: return _SC("unknown"); + } +} + +// ------------------------------------------------------------------------------------------------ +Function & Cmd_GetOnError() +{ + return _Cmd->GetOnError(); +} + +// ------------------------------------------------------------------------------------------------ +void Cmd_SetOnError(Function & func) +{ + _Cmd->SetOnError(func); +} + +// ------------------------------------------------------------------------------------------------ +Function & Cmd_GetOnAuth() +{ + return _Cmd->GetOnAuth(); +} + +// ------------------------------------------------------------------------------------------------ +void Cmd_SetOnAuth(Function & func) +{ + _Cmd->SetOnAuth(func); +} + +// ------------------------------------------------------------------------------------------------ +const SQChar * Cmd_GetName() +{ + return _Cmd->GetName(); +} + +// ------------------------------------------------------------------------------------------------ +const SQChar * Cmd_GetText() +{ + return _Cmd->GetText(); +} + +// ================================================================================================ +bool Register_Cmd(HSQUIRRELVM vm) +{ + // // Attempt to create the Cmd namespace + Sqrat::Table cmdns(vm); + + // Output debugging information + LogDbg("Beginning registration of type"); + // Attempt to register the specified type + cmdns.Bind(_SC("Listener"), Sqrat::Class< CmdListener, NoCopy< CmdListener > >(vm, _SC("Listener")) + /* Constructors */ + .Ctor() + .Ctor< const SQChar * >() + .Ctor< const SQChar *, const SQChar * >() + /* Metamethods */ + .Func(_SC("_cmp"), &CmdListener::Cmp) + .Func(_SC("_tostring"), &CmdListener::ToString) + /* Properties */ + .Prop(_SC("ltag"), &CmdListener::GetTag, &CmdListener::SetTag) + .Prop(_SC("ldata"), &CmdListener::GetData, &CmdListener::SetData) + .Prop(_SC("name"), &CmdListener::GetName, &CmdListener::SetName) + .Prop(_SC("spec"), &CmdListener::GetSpec, &CmdListener::SetSpec) + .Prop(_SC("help"), &CmdListener::GetHelp, &CmdListener::SetHelp) + .Prop(_SC("info"), &CmdListener::GetInfo, &CmdListener::SetInfo) + .Prop(_SC("on_auth"), &CmdListener::GetOnAuth, &CmdListener::SetOnAuth) + .Prop(_SC("on_exec"), &CmdListener::GetOnExec, &CmdListener::SetOnExec) + .Prop(_SC("level"), &CmdListener::GetLevel, &CmdListener::SetLevel) + .Prop(_SC("suspended"), &CmdListener::GetSuspended, &CmdListener::SetSuspended) + .Prop(_SC("auth"), &CmdListener::GetAuthority, &CmdListener::SetAuthority) + .Prop(_SC("authority"), &CmdListener::GetAuthority, &CmdListener::SetAuthority) + .Prop(_SC("min_args"), &CmdListener::GetMinArgC, &CmdListener::SetMinArgC) + .Prop(_SC("max_args"), &CmdListener::GetMaxArgC, &CmdListener::SetMaxArgC) + /* Functions */ + ); + + // Output debugging information + LogDbg("Registration of type was successful"); + + // Output debugging information + LogDbg("Beginning registration of type"); + // Attempt to register the free functions + cmdns.Func(_SC("get_on_error"), &Cmd_GetOnError); + cmdns.Func(_SC("set_on_error"), &Cmd_SetOnError); + cmdns.Func(_SC("get_on_auth"), &Cmd_GetOnAuth); + cmdns.Func(_SC("set_on_auth"), &Cmd_SetOnAuth); + cmdns.Func(_SC("get_name"), &Cmd_GetName); + cmdns.Func(_SC("get_text"), &Cmd_GetText); + // Output debugging information + LogDbg("Registration of type was successful"); + + // Attempt to bind the namespace to the root table + Sqrat::RootTable(vm).Bind(_SC("Cmd"), cmdns); + // Registration succeeded + return true; +} + + +} // Namespace:: SqMod diff --git a/source/Command.hpp b/source/Command.hpp new file mode 100644 index 00000000..ca541f49 --- /dev/null +++ b/source/Command.hpp @@ -0,0 +1,537 @@ +#ifndef _COMMAND_HPP_ +#define _COMMAND_HPP_ + +// ------------------------------------------------------------------------------------------------ +#include "Common.hpp" + +// ------------------------------------------------------------------------------------------------ +#include + +// ------------------------------------------------------------------------------------------------ +namespace SqMod { + +/* ------------------------------------------------------------------------------------------------ + * Flags of the types of values supported by the command arguments. +*/ +enum CmdArgType +{ + CMDARG_ANY = 0, + CMDARG_INTEGER = (1 << 1), + CMDARG_FLOAT = (1 << 2), + CMDARG_BOOLEAN = (1 << 3), + CMDARG_STRING = (1 << 4), +}; + +/* ------------------------------------------------------------------------------------------------ + * Convert a command type specifier to a name string. +*/ +const SQChar * CmdArgSpecToStr(Uint8 spec); + +/* ------------------------------------------------------------------------------------------------ + * The type of error that's being reported by the command manager. +*/ +enum CmdError +{ + CMDERR_UNKNOWN = 0, + CMDERR_SYNTAX_ERROR, + CMDERR_UNKNOWN_COMMAND, + CMDERR_MISSING_EXECUTER, + CMDERR_INSUFFICIENT_AUTH, + CMDERR_INCOMPLETE_ARGS, + CMDERR_EXTRANEOUS_ARGS, + CMDERR_UNSUPPORTED_ARG, + CMDERR_EXECUTION_FAILED, +}; + +// ------------------------------------------------------------------------------------------------ +class CmdListener; + +// ------------------------------------------------------------------------------------------------ +#define MAX_CMD_ARGS 12 + +/* ------------------------------------------------------------------------------------------------ + * Helper class used to simplify the code for creating and managing commands. +*/ +class CmdManager +{ + // -------------------------------------------------------------------------------------------- + friend class std::unique_ptr< CmdManager, void(*)(CmdManager *) >; + +protected: + + /* -------------------------------------------------------------------------------------------- + * The type of container for storing command listeners. + */ + typedef std::unordered_map< String, CmdListener * > CmdPool; + + /* -------------------------------------------------------------------------------------------- + * The type of container for storing command arguments. + */ + typedef std::array< std::pair< Uint8, SqObj >, MAX_CMD_ARGS > CmdArgs; + + /* -------------------------------------------------------------------------------------------- + * Default constructor. + */ + CmdManager(); + + /* -------------------------------------------------------------------------------------------- + * Copy constructor (disabled). + */ + CmdManager(const CmdManager &) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move constructor (disabled). + */ + CmdManager(CmdManager &&) = delete; + + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + ~CmdManager(); + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator (disabled). + */ + CmdManager & operator = (const CmdManager &) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator (disabled). + */ + CmdManager & operator = (CmdManager &&) = delete; + + /* -------------------------------------------------------------------------------------------- + * Called by the smart pointer to delete the instance of this class. + */ + static void _Finalizer(CmdManager * ptr); + +public: + + // -------------------------------------------------------------------------------------------- + typedef std::unique_ptr< CmdManager, void(*)(CmdManager *) > Pointer; + + /* -------------------------------------------------------------------------------------------- + * Creates an instance of this type if one doesn't already exist and returns it. + */ + static Pointer Inst(); + + /* -------------------------------------------------------------------------------------------- + * Called by the core class before the VM is clodes to release all resources. + */ + void VMClose(); + + /* -------------------------------------------------------------------------------------------- + * Bind a command listener to a certain command name. + */ + void Bind(const String & name, CmdListener * cmd); + + /* -------------------------------------------------------------------------------------------- + * Unbind a command listener from a certain command name. + */ + void Unbind(const String & name); + + /* -------------------------------------------------------------------------------------------- + * Retrieve the currently used error handler. + */ + Function & GetOnError(); + + /* -------------------------------------------------------------------------------------------- + * Change the error handler. + */ + void SetOnError(Function & func); + + /* -------------------------------------------------------------------------------------------- + * Retrieve the default authority inspector. + */ + Function & GetOnAuth(); + + /* -------------------------------------------------------------------------------------------- + * Change the default authority inspector. + */ + void SetOnAuth(Function & func); + + /* -------------------------------------------------------------------------------------------- + * Retrieve the name of the currently executed command. + */ + const SQChar * GetName(); + + /* -------------------------------------------------------------------------------------------- + * Retrieve the argument text of the currently executed command. + */ + const SQChar * GetText(); + + /* -------------------------------------------------------------------------------------------- + * Execute the specified command for the specified player. + */ + void Execute(SQInt32 invoker, const String & str); + +protected: + + /* -------------------------------------------------------------------------------------------- + * Execute the specified comand. + */ + void Exec(CmdListener & cmd); + + /* -------------------------------------------------------------------------------------------- + * Forward the error message to the error handler. + */ + template < typename... Args> void Error(SQInt32 type, const SQChar * msg, Args&&... args) + { + // Skip if there's no error handler + if (!m_OnError.IsNull()) + { + m_OnError.Execute< SQInt32, const SQChar * >(type, ToStringF(msg, std::forward< Args >(args)...)); + } + } + + /* -------------------------------------------------------------------------------------------- + * Parse the specified argument text and extract the arguments from it. + */ + bool Parse(SQUint32 max); + +private: + + /* -------------------------------------------------------------------------------------------- + * List of command listeners and their associated names. + */ + CmdPool m_Commands; + + /* -------------------------------------------------------------------------------------------- + * Currently and last command invoker. + */ + SQInt32 m_Invoker; + + /* -------------------------------------------------------------------------------------------- + * Currently and last used command name. + */ + String m_Name; + + /* -------------------------------------------------------------------------------------------- + * Currently and last used command argument text. + */ + String m_Text; + + /* -------------------------------------------------------------------------------------------- + * Extracted values from the argument text. + */ + CmdArgs m_Argv; + + /* -------------------------------------------------------------------------------------------- + * Number of values extracted from the argument text. + */ + SQUint32 m_Argc; + + /* -------------------------------------------------------------------------------------------- + * Custom error handler. + */ + Function m_OnError; + + /* -------------------------------------------------------------------------------------------- + * Default authority inspector for newlly created commands. + */ + Function m_OnAuth; +}; + +// ------------------------------------------------------------------------------------------------ +extern const CmdManager::Pointer _Cmd; + +/* ------------------------------------------------------------------------------------------------ + * Class used to bind to certain commands. +*/ +class CmdListener +{ +public: + + // -------------------------------------------------------------------------------------------- + friend class CmdManager; + + /* -------------------------------------------------------------------------------------------- + * Default constructor. + */ + CmdListener(); + + /* -------------------------------------------------------------------------------------------- + * Construct and instance and attach it to the specified name. + */ + CmdListener(const SQChar * name); + + /* -------------------------------------------------------------------------------------------- + * Construct and instance and attach it to the specified name. + */ + CmdListener(const SQChar * name, const SQChar * spec); + + /* -------------------------------------------------------------------------------------------- + * Copy constructor (disabled). + */ + CmdListener(const CmdListener & o) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move constructor (disabled). + */ + CmdListener(CmdListener && o) = delete; + + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + ~CmdListener(); + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator (disabled). + */ + CmdListener & operator = (const CmdListener & o) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator (disabled). + */ + CmdListener & operator = (CmdListener && o) = delete; + + /* -------------------------------------------------------------------------------------------- + * Used to released stored resouces before the VM is closed. + */ + void VMClose(); + + /* -------------------------------------------------------------------------------------------- + * Compare two instances of this type. + */ + SQInt32 Cmp(const CmdListener & o) const; + + /* -------------------------------------------------------------------------------------------- + * Attempt to convert this instance to a string. + */ + const SQChar * ToString() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the local tag. + */ + const SQChar * GetTag() const; + + /* -------------------------------------------------------------------------------------------- + * Change the local tag. + */ + void SetTag(const SQChar * tag); + + /* -------------------------------------------------------------------------------------------- + * Retrieve the local data. + */ + SqObj & GetData(); + + /* -------------------------------------------------------------------------------------------- + * Change the local data. + */ + void SetData(SqObj & data); + + /* -------------------------------------------------------------------------------------------- + * Retrieve the name of the command. + */ + const SQChar * GetName() const; + + /* -------------------------------------------------------------------------------------------- + * Change the name of the command. + */ + void SetName(const SQChar * name); + + /* -------------------------------------------------------------------------------------------- + * Retrieve the argument type specifiers for this command as a string. + */ + const SQChar * GetSpec() const; + + /* -------------------------------------------------------------------------------------------- + * Change the argument type specifiers for this command by extracing them from a string. + */ + void SetSpec(const SQChar * spec); + + /* -------------------------------------------------------------------------------------------- + * Retrieve the help text associated with this command. + */ + const SQChar * GetHelp() const; + + /* -------------------------------------------------------------------------------------------- + * Change the help text associated with this command. + */ + void SetHelp(const SQChar * help); + + /* -------------------------------------------------------------------------------------------- + * Retrieve the informational text associated with this command. + */ + const SQChar * GetInfo() const; + + /* -------------------------------------------------------------------------------------------- + * Chage the informational text associated with this command. + */ + void SetInfo(const SQChar * info); + + /* -------------------------------------------------------------------------------------------- + * Retrieve the function responsible for testing the invoker authority. + */ + Function & GetOnAuth(); + + /* -------------------------------------------------------------------------------------------- + * Change the function responsible for testing the invoker authority. + */ + void SetOnAuth(Function & func); + + /* -------------------------------------------------------------------------------------------- + * Retrieve the function responsible for processing the command. + */ + Function & GetOnExec(); + + /* -------------------------------------------------------------------------------------------- + * Change the function responsible for processing the command. + */ + void SetOnExec(Function & func); + + /* -------------------------------------------------------------------------------------------- + * Retrieve the internal level required to execute this command. + */ + SQInt32 GetLevel() const; + + /* -------------------------------------------------------------------------------------------- + * Change the internal level required to execute this command. + */ + void SetLevel(SQInt32 level); + + /* -------------------------------------------------------------------------------------------- + * See whether this command listener is allowed to execute or not. + */ + bool GetSuspended() const; + + /* -------------------------------------------------------------------------------------------- + * Set whether this command listener is allowed to execute or not. + */ + void SetSuspended(bool toggle); + + /* -------------------------------------------------------------------------------------------- + * See whether this command needs explicit authority clearance to execute. + */ + bool GetAuthority() const; + + /* -------------------------------------------------------------------------------------------- + * Set whether this command needs explicit authority clearance to execute. + */ + void SetAuthority(bool toggle); + + /* -------------------------------------------------------------------------------------------- + * Retrieve the minimum arguments allowed required to execute this command. + */ + SQUint32 GetMinArgC() const; + + /* -------------------------------------------------------------------------------------------- + * Change the minimum arguments allowed required to execute this command. + */ + void SetMinArgC(SQUint32 val); + + /* -------------------------------------------------------------------------------------------- + * Retrieve the maximum arguments allowed required to execute this command. + */ + SQUint32 GetMaxArgC() const; + + /* -------------------------------------------------------------------------------------------- + * Change the maximum arguments allowed required to execute this command. + */ + void SetMaxArgC(SQUint32 val); + + /* -------------------------------------------------------------------------------------------- + * Check whether the specified argument is compatible with the specified type. + */ + bool ArgCheck(SQUint32 arg, Uint8 mask) const; + + /* -------------------------------------------------------------------------------------------- + * Sheck whether the specified player is allowed to execute this command. + */ + bool AuthCheck(SQInt32 id); + + /* -------------------------------------------------------------------------------------------- + * Attempt to execute this command. + */ + bool Execute(SQInt32 invoker, Array & args); + +protected: + + // -------------------------------------------------------------------------------------------- + typedef std::array< Uint8 , MAX_CMD_ARGS > Args; + + /* -------------------------------------------------------------------------------------------- + * Process the specifiers string. + */ + bool ProcSpec(const SQChar * spec); + +private: + + /* -------------------------------------------------------------------------------------------- + * Array of type specifiers for each of the command arguments. + */ + Args m_Args; + + /* -------------------------------------------------------------------------------------------- + * Minimum arguments allowed to execute this command. + */ + SQUint32 m_MinArgc; + + /* -------------------------------------------------------------------------------------------- + * Maximum arguments allowed to execute this command. + */ + SQUint32 m_MaxArgc; + + /* -------------------------------------------------------------------------------------------- + * The name of the command. + */ + String m_Name; + + /* -------------------------------------------------------------------------------------------- + * The specifiers for each of the command arguments represented as a string. + */ + String m_Spec; + + /* -------------------------------------------------------------------------------------------- + * Help about the purpose and requirements of the command. + */ + String m_Help; + + /* -------------------------------------------------------------------------------------------- + * Information for when the command execution failed. + */ + String m_Info; + + /* -------------------------------------------------------------------------------------------- + * Function responsible for deciding whether the invoker is allowed to execute. + */ + Function m_OnAuth; + + /* -------------------------------------------------------------------------------------------- + * Function responsible for processing the received command arguments. + */ + Function m_OnExec; + + /* -------------------------------------------------------------------------------------------- + * Arbitrary tag associated with this instance. + */ + String m_Tag; + + /* -------------------------------------------------------------------------------------------- + * Arbitrary data associated with this instance. + */ + SqObj m_Data; + + /* -------------------------------------------------------------------------------------------- + * The level required to execute this command. + */ + SQInt32 m_Level; + + /* -------------------------------------------------------------------------------------------- + * Whether the command is allowed to execute or not. + */ + bool m_Suspended; + + /* -------------------------------------------------------------------------------------------- + * Whether this command needs an explicit authority verification in order to execute. + */ + bool m_Authority; + + /* -------------------------------------------------------------------------------------------- + * Whether the command is allowed to change name. + */ + bool m_Lock; +}; + +} // Namespace:: SqMod + +#endif // _COMMAND_HPP_ diff --git a/source/Common.cpp b/source/Common.cpp index d43e512c..746ac7aa 100644 --- a/source/Common.cpp +++ b/source/Common.cpp @@ -111,16 +111,12 @@ static void VC_Frame(float delta) static void VC_PlayerConnect(int player) { - static SqObj playload; - playload.Release(); - _Core->ConnectPlayer(player, SQMOD_CREATE_AUTOMATIC, playload); + _Core->ConnectPlayer(player, SQMOD_CREATE_AUTOMATIC, NullData()); } static void VC_PlayerDisconnect(int player, int reason) { - static SqObj playload; - playload.Release(); - _Core->DisconnectPlayer(player, reason, playload); + _Core->DisconnectPlayer(player, reason, NullData()); } static void VC_PlayerBeginTyping(int player) diff --git a/source/Core.cpp b/source/Core.cpp index 28906e12..733fbb8f 100644 --- a/source/Core.cpp +++ b/source/Core.cpp @@ -4,6 +4,7 @@ #include "Register.hpp" // ------------------------------------------------------------------------------------------------ +#include "Command.hpp" #include "Misc/Automobile.hpp" #include "Misc/Model.hpp" @@ -146,23 +147,65 @@ void Core::SetOption(const String & name, const String & value) } // ------------------------------------------------------------------------------------------------ -Core::Buffer Core::PullBuffer(unsigned sz) +SQFloat Core::GetUptime() const +{ + return m_Uptime; +} + +// ------------------------------------------------------------------------------------------------ +Buffer Core::PullBuffer(unsigned sz) { // The container that will manage the buffer Buffer buf; // See if there's any buffers available in the pool if (m_BufferPool.empty()) { - // Create a new buffer if one wasn't available - buf.resize(sz); + // Create a new buffer if one wasn't available + buf.Reserve(sz); } - // Just fetch one from the pool - else + // Is the last buffer big enough? + else if (m_BufferPool.back().Size() >= sz) { // Fetch the buffer buf = std::move(m_BufferPool.back()); // Remove it from the pool - m_BufferPool.pop(); + m_BufferPool.pop_back(); + } + // Is the first buffer big enough? + else if (m_BufferPool.front().Size() >= sz) + { + // Fetch the buffer + buf = std::move(m_BufferPool.front()); + // Remove it from the pool + m_BufferPool.pop_front(); + } + // Just fetch one from the pool if possible + else + { + // Get an iterator to the beginning of the pool + auto itr = m_BufferPool.begin(); + // See if there are any buffers with the size we need + for (; itr != m_BufferPool.end(); ++itr) + { + if (itr->Size() >= sz) + { + // Stop searching + break; + } + } + // Have we found anything? + if (itr != m_BufferPool.end()) + { + // Fetch the buffer + buf = std::move((*itr)); + // Remove it from the pool + m_BufferPool.erase(itr); + } + // Just make one to satisfy the requested size + else + { + buf.Reserve(sz); + } } // Give the obtained buffer return std::move(buf); @@ -172,10 +215,10 @@ Core::Buffer Core::PullBuffer(unsigned sz) void Core::PushBuffer(Buffer && buf) { // Make sure we don't store empty buffers - if (!buf.empty()) + if (buf) { // Return the specified buffer back to the pool - m_BufferPool.push(std::move(buf)); + m_BufferPool.push_back(std::move(buf)); } } @@ -185,7 +228,7 @@ void Core::MakeBuffer(unsigned num, unsigned sz) // Create the specified number of buffers while (num--) { - m_BufferPool.emplace(sz); + m_BufferPool.emplace_back(sz); } } @@ -200,17 +243,16 @@ void Core::ConnectPlayer(SQInt32 id, SQInt32 header, SqObj & payload) } else { - LogErr("Unable to create a new instance"); + LogErr("Unable to activate player instance: %d", id); } } void Core::DisconnectPlayer(SQInt32 id, SQInt32 header, SqObj & payload) { - // Check to be sure we have this player instance active - if (Reference< CPlayer >::Verify(id)) + // Attempt to deactivate this player instance + if (!EntMan< CPlayer >::Deactivate(id, header, payload, true)) { - // Trigger the specific event - OnPlayerDestroyed(id, header, payload); + LogErr("Unable to deactivate player instance: %d", id); } } @@ -383,7 +425,7 @@ void Core::DestroyVM() if (m_VM != nullptr) { // Let instances know that they should release links to this VM - VMClose.Emit(); + OnVMClose(); // Release the references to the script objects m_Scripts.clear(); // Release the reference to the root table @@ -618,9 +660,9 @@ void Core::PrintFunc(HSQUIRRELVM vm, const SQChar * str, ...) va_list args; va_start(args, str); // Acquire a buffer from the buffer pool - Core::Buffer vbuf = _Core->PullBuffer(); + Buffer vbuf = _Core->PullBuffer(); // Attempt to process the specified format string - SQInt32 fmt_ret = std::vsnprintf(vbuf.data(), vbuf.size(), str, args); + SQInt32 fmt_ret = std::vsnprintf(vbuf.Data(), vbuf.Size(), str, args); // See if the formatting was successful if (fmt_ret < 0) { @@ -630,12 +672,12 @@ void Core::PrintFunc(HSQUIRRELVM vm, const SQChar * str, ...) return; } // See if the buffer was big enough - else if (_SCSZT(fmt_ret) > vbuf.size()) + else if (_SCU32(fmt_ret) > vbuf.Size()) { // Resize the buffer to accommodate the required size - vbuf.resize(++fmt_ret); + vbuf.Reserve(++fmt_ret); // Attempt to process the specified format string again - fmt_ret = std::vsnprintf(vbuf.data(), vbuf.size(), str, args); + fmt_ret = std::vsnprintf(vbuf.Data(), vbuf.Size(), str, args); // See if the formatting was successful if (fmt_ret < 0) { @@ -648,7 +690,7 @@ void Core::PrintFunc(HSQUIRRELVM vm, const SQChar * str, ...) // Release the arguments list va_end(args); // Output the buffer content - LogMsg("%s", vbuf.data()); + LogMsg("%s", vbuf.Data()); // Return the buffer back to the buffer pool _Core->PushBuffer(std::move(vbuf)); } @@ -660,9 +702,9 @@ void Core::ErrorFunc(HSQUIRRELVM vm, const SQChar * str, ...) va_list args; va_start(args, str); // Acquire a buffer from the buffer pool - Core::Buffer vbuf = _Core->PullBuffer(); + Buffer vbuf = _Core->PullBuffer(); // Attempt to process the specified format string - SQInt32 fmt_ret = std::vsnprintf(vbuf.data(), vbuf.size(), str, args); + SQInt32 fmt_ret = std::vsnprintf(vbuf.Data(), vbuf.Size(), str, args); // See if the formatting was successful if (fmt_ret < 0) { @@ -672,12 +714,12 @@ void Core::ErrorFunc(HSQUIRRELVM vm, const SQChar * str, ...) return; } // See if the buffer was big enough - else if (_SCSZT(fmt_ret) > vbuf.size()) + else if (_SCU32(fmt_ret) > vbuf.Size()) { // Resize the buffer to accommodate the required size - vbuf.resize(++fmt_ret); + vbuf.Reserve(++fmt_ret); // Attempt to process the specified format string again - fmt_ret = std::vsnprintf(vbuf.data(), vbuf.size(), str, args); + fmt_ret = std::vsnprintf(vbuf.Data(), vbuf.Size(), str, args); // See if the formatting was successful if (fmt_ret < 0) { @@ -690,7 +732,7 @@ void Core::ErrorFunc(HSQUIRRELVM vm, const SQChar * str, ...) // Release the arguments list va_end(args); // Output the buffer content - LogErr("%s", vbuf.data()); + LogErr("%s", vbuf.Data()); // Return the buffer back to the buffer pool _Core->PushBuffer(std::move(vbuf)); } @@ -1150,6 +1192,9 @@ void Core::OnPlayerChat(SQInt32 player, const SQChar * message) void Core::OnPlayerCommand(SQInt32 player, const SQChar * command) { + // Send it to the command manager + _Cmd->Execute(player, command); + // Forward to instances PlayerCommand.Emit(player, command); Reference< CPlayer >::Get(player).PlayerCommand.Emit(player, command); } @@ -1504,6 +1549,7 @@ void Core::OnSphereExited(SQInt32 player, SQInt32 sphere) // ------------------------------------------------------------------------------------------------ void Core::OnServerFrame(SQFloat delta) { + m_Uptime += delta; ServerFrame.Emit(delta); } @@ -1558,6 +1604,15 @@ void Core::OnLogMessage(SQInt32 type, const SQChar * message) LogMessage.Emit(type, message); } +// ------------------------------------------------------------------------------------------------ +void Core::OnVMClose() +{ + // Call base classes manually + _Cmd->VMClose(); + // Froward to instances + VMClose.Emit(); +} + // ------------------------------------------------------------------------------------------------ void Core::OnPlayerUpdate(SQInt32 player, SQInt32 type) { diff --git a/source/Core.hpp b/source/Core.hpp index 630ad17e..f281def4 100644 --- a/source/Core.hpp +++ b/source/Core.hpp @@ -6,10 +6,11 @@ #include "Signal.hpp" // ------------------------------------------------------------------------------------------------ +#include "Base/Buffer.hpp" #include "Base/Vector3.hpp" // ------------------------------------------------------------------------------------------------ -#include +#include #include #include #include @@ -23,9 +24,11 @@ class Core protected: // -------------------------------------------------------------------------------------------- - friend class std::unique_ptr; + friend class std::unique_ptr< Core, void(*)(Core *) >; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * ... + */ struct TPlayer { SQInt32 Weapon; @@ -35,7 +38,10 @@ protected: bool Fresh; }; - // -------------------------------------------------------------------------------------------- + + /* -------------------------------------------------------------------------------------------- + * ... + */ struct TVehicle { SQFloat Health; @@ -43,48 +49,88 @@ protected: bool Fresh; }; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * ... + */ typedef std::array TPlayerInstPool; + + /* -------------------------------------------------------------------------------------------- + * ... + */ typedef std::array TVehicleInstPool; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * ... + */ typedef std::unique_ptr SqRootTable; + + /* -------------------------------------------------------------------------------------------- + * ... + */ typedef std::unordered_map SqScriptPool; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * ... + */ typedef std::unordered_map OptionPool; -public: - - // -------------------------------------------------------------------------------------------- - typedef std::vector< SQChar > Buffer; - typedef std::queue< Buffer > BufferPool; + /* -------------------------------------------------------------------------------------------- + * ... + */ + typedef std::list< Buffer > BufferPool; private: - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * ... + */ SQInteger m_State; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * ... + */ OptionPool m_Options; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * ... + */ HSQUIRRELVM m_VM; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * ... + */ SqRootTable m_RootTable; + + /* -------------------------------------------------------------------------------------------- + * ... + */ SqScriptPool m_Scripts; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * ... + */ String m_ErrorMsg; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * ... + */ TPlayerInstPool m_PlayerTrack; + + /* -------------------------------------------------------------------------------------------- + * ... + */ TVehicleInstPool m_VehicleTrack; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * ... + */ BufferPool m_BufferPool; + /* -------------------------------------------------------------------------------------------- + * ... + */ + SQFloat m_Uptime; + protected: // -------------------------------------------------------------------------------------------- @@ -93,80 +139,173 @@ protected: // -------------------------------------------------------------------------------------------- ~Core(); - // -------------------------------------------------------------------------------------------- - Core(Core const &) = delete; - Core(Core &&) = delete; + /* -------------------------------------------------------------------------------------------- + * ... + */ + Core(Core const &) = delete; - // -------------------------------------------------------------------------------------------- - Core & operator=(Core const &) = delete; - Core & operator=(Core &&) = delete; + /* -------------------------------------------------------------------------------------------- + * ... + */ + Core(Core &&) = delete; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * ... + */ + Core & operator=(Core const &) = delete; + + /* -------------------------------------------------------------------------------------------- + * ... + */ + Core & operator=(Core &&) = delete; + + /* -------------------------------------------------------------------------------------------- + * ... + */ static void _Finalizer(Core * ptr); public: // -------------------------------------------------------------------------------------------- - typedef std::unique_ptr Pointer; + typedef std::unique_ptr< Core, void(*)(Core *) > Pointer; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * ... + */ static Pointer Inst(); - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * ... + */ bool Init(); + + /* -------------------------------------------------------------------------------------------- + * ... + */ bool Load(); - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * ... + */ void Deinit(); + + /* -------------------------------------------------------------------------------------------- + * ... + */ void Unload(); - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * ... + */ void Terminate(); - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * ... + */ void SetState(SQInteger val); + + /* -------------------------------------------------------------------------------------------- + * ... + */ SQInteger GetState() const; - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * ... + */ String GetOption(const String & name) const; + + /* -------------------------------------------------------------------------------------------- + * ... + */ void SetOption(const String & name, const String & value); - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * ... + */ + SQFloat GetUptime() const; + + /* -------------------------------------------------------------------------------------------- + * ... + */ Buffer PullBuffer(unsigned sz = 4096); + + /* -------------------------------------------------------------------------------------------- + * ... + */ void PushBuffer(Buffer && buf); + + /* -------------------------------------------------------------------------------------------- + * ... + */ void MakeBuffer(unsigned num, unsigned sz = 4096); - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * ... + */ void ConnectPlayer(SQInt32 id, SQInt32 header, SqObj & payload); + + /* -------------------------------------------------------------------------------------------- + * ... + */ void DisconnectPlayer(SQInt32 id, SQInt32 header, SqObj & payload); protected: - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * ... + */ bool Configure(); - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * ... + */ bool CreateVM(); + + /* -------------------------------------------------------------------------------------------- + * ... + */ void DestroyVM(); - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * ... + */ bool LoadScripts(); - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * ... + */ bool Compile(const String & name); + + /* -------------------------------------------------------------------------------------------- + * ... + */ bool Execute(); - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * ... + */ void PrintCallstack(); public: - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * ... + */ static void PrintFunc(HSQUIRRELVM vm, const SQChar * str, ...); + + /* -------------------------------------------------------------------------------------------- + * ... + */ static void ErrorFunc(HSQUIRRELVM vm, const SQChar * str, ...); - // -------------------------------------------------------------------------------------------- + /* -------------------------------------------------------------------------------------------- + * ... + */ static SQInteger RuntimeErrorHandler(HSQUIRRELVM vm); + + /* -------------------------------------------------------------------------------------------- + * ... + */ static void CompilerErrorHandler(HSQUIRRELVM vm, const SQChar * desc, const SQChar * src, SQInteger line, SQInteger column); protected: @@ -410,6 +549,9 @@ public: // -------------------------------------------------------------------------------------------- void OnLogMessage(SQInt32 type, const SQChar * message); + // -------------------------------------------------------------------------------------------- + void OnVMClose(); + // -------------------------------------------------------------------------------------------- void OnPlayerUpdate(SQInt32 player, SQInt32 type); void OnVehicleUpdate(SQInt32 vehicle, SQInt32 type); diff --git a/source/Entity.hpp b/source/Entity.hpp index ab6472fb..a2e6eda8 100644 --- a/source/Entity.hpp +++ b/source/Entity.hpp @@ -1048,7 +1048,7 @@ private: { // ---------------------------------------------------------------------------------------- Player() - : ID(-1), Root(0), Owned(false), Fresh(true) + : ID(-1), Root(0), Owned(false), Fresh(true), Level(0) { /* ... */ } @@ -1063,6 +1063,9 @@ private: bool Owned; /* Useless but required by the instance activation system */ bool Fresh; + // ---------------------------------------------------------------------------------------- + SQInt32 Level; + // ---------------------------------------------------------------------------------------- SqTag Tag; SqObj Data; @@ -2218,7 +2221,7 @@ protected: { if (VALID_ENTITY(m_ID)) { - if (s_Instances[m_ID].Root) + if (s_Instances[m_ID].Root != nullptr) { m_Next = s_Instances[m_ID].Root; m_Prev = m_Next->m_Prev; @@ -2236,23 +2239,23 @@ protected: { if (VALID_ENTITY(m_ID)) { - if (m_Next) + if (m_Next != nullptr) { m_Next->m_Prev = m_Prev; } - if (m_Prev) + if (m_Prev != nullptr) { m_Prev->m_Next = m_Next; } if (s_Instances[m_ID].Root == this) { - s_Instances[m_ID].Root = (m_Next ? m_Next : (m_Prev ? m_Prev : 0)); + s_Instances[m_ID].Root = (m_Next ? m_Next : (m_Prev ? m_Prev : nullptr)); } - m_Next = 0; - m_Prev = 0; + m_Next = nullptr; + m_Prev = nullptr; } } @@ -2292,8 +2295,8 @@ public: : m_ID(Verify(id) ? id : SQMOD_UNKNOWN) , m_Tag() , m_Data() - , m_Prev(0) - , m_Next(0) + , m_Prev(nullptr) + , m_Next(nullptr) , m_Persistent(false) { InsertIntoChain(); @@ -2306,8 +2309,8 @@ public: : m_ID(r.m_ID) , m_Tag(r.m_Tag) , m_Data(r.m_Data) - , m_Prev(0) - , m_Next(0) + , m_Prev(nullptr) + , m_Next(nullptr) , m_Persistent(r.m_Persistent) { InsertIntoChain(); @@ -2320,8 +2323,8 @@ public: : m_ID(r.m_ID) , m_Tag(r.m_Tag) , m_Data(r.m_Data) - , m_Prev(0) - , m_Next(0) + , m_Prev(nullptr) + , m_Next(nullptr) , m_Persistent(r.m_Persistent) { InsertIntoChain(); @@ -2601,15 +2604,8 @@ public: // Make sure the reference is valid if (VALID_ENTITYEX(m_ID, Max)) { - // Count this instance - ++refs; - // Count backward references - for (RefType * ref = m_Prev; ref; ref = ref->m_Prev) - { - ++refs; - } // Count forward references - for (RefType * ref = m_Next; ref; ref = ref->m_Next) + for (RefType * ref = s_Instances[m_ID].Root; ref != nullptr; ref = ref->m_Next) { ++refs; } @@ -2626,21 +2622,8 @@ public: // Make sure the reference is valid if (VALID_ENTITYEX(m_ID, Max)) { - // Count this instance if persistent - if (m_Persistent) - { - ++refs; - } - // Count backward references - for (RefType * ref = m_Prev; ref; ref = ref->m_Prev) - { - if (ref->m_Persistent) - { - ++refs; - } - } // Count forward references - for (RefType * ref = m_Next; ref; ref = ref->m_Next) + for (RefType * ref = s_Instances[m_ID].Root; ref != nullptr; ref = ref->m_Next) { if (ref->m_Persistent) { @@ -2725,33 +2708,8 @@ private: RefType::s_Instances[id].GDestroyed().Emit(id, header, payload); } - RefType * ref = 0, * bkp = 0; - // Get the pointer to the first backward reference - ref = RefType::s_Instances[id].Root->m_Prev; - // Deactivate backward references - while (ref) - { - if (ref->m_Persistent) - { - // Just disable the entity if persistent - ref->m_ID = SQMOD_UNKNOWN; - // Move to the previous reference - ref = ref->m_Prev; - } - else - { - // Backup the current reference - bkp = ref; - // Move to the previous reference before unchaining - ref = ref->m_Prev; - // Now it's safe to unchain the reference - bkp->RemoveFromChain(); - } - } - // Get the pointer to the first forward reference - ref = RefType::s_Instances[id].Root->m_Next; // Deactivate forward references - while (ref) + for (RefType * ref = RefType::s_Instances[id].Root, * bkp = nullptr; ref != nullptr;) { if (ref->m_Persistent) { diff --git a/source/Entity/Player.cpp b/source/Entity/Player.cpp index 38bb5b0f..24ceb072 100644 --- a/source/Entity/Player.cpp +++ b/source/Entity/Player.cpp @@ -25,6 +25,34 @@ CPlayer::CPlayer(const Reference< CPlayer > & o) /* ... */ } +// ------------------------------------------------------------------------------------------------ +SQInt32 CPlayer::GetLevel() const +{ + if (VALID_ENTITY(m_ID)) + { + return Get(m_ID).Level; + } + else + { + LogWrn(_SC("Attempting to using an invalid reference: %d"), m_ID); + } + + return SQMOD_UNKNOWN; +} + +// ------------------------------------------------------------------------------------------------ +void CPlayer::SetLevel(SQInt32 val) const +{ + if (VALID_ENTITY(m_ID)) + { + Get(m_ID).Level = val; + } + else + { + LogWrn(_SC("Attempting to using an invalid reference: %d"), m_ID); + } +} + // ------------------------------------------------------------------------------------------------ bool CPlayer::IsStreamedFor(const Reference < CPlayer > & player) const { diff --git a/source/Entity/Player.hpp b/source/Entity/Player.hpp index c8ebe2d9..378da111 100644 --- a/source/Entity/Player.hpp +++ b/source/Entity/Player.hpp @@ -35,6 +35,16 @@ public: */ CPlayer(const Reference< CPlayer > & o); + /* -------------------------------------------------------------------------------------------- + * See whether the referenced player instance has administrator privileges. + */ + SQInt32 GetLevel() const; + + /* -------------------------------------------------------------------------------------------- + * Set whether the referenced player instance has administrator privileges. + */ + void SetLevel(SQInt32 val) const; + /* -------------------------------------------------------------------------------------------- * See if the referenced player instance is streamed for the specified player. */ diff --git a/source/Library/IRC/Session.cpp b/source/Library/IRC/Session.cpp index 4ac46628..2503d51d 100644 --- a/source/Library/IRC/Session.cpp +++ b/source/Library/IRC/Session.cpp @@ -18,6 +18,19 @@ bool Session::s_Initialized = false; // ------------------------------------------------------------------------------------------------ Session::Session() : m_Session(irc_create_session(GetCallbacks())) + , m_Server(_SC("")) + , m_Passwd(_SC("")) + , m_Nick(_SC("")) + , m_User(_SC("")) + , m_Name(_SC("")) + , m_Port(6667) + , m_Tries(3) + , m_Wait(5.0f) + , m_LeftTries(0) + , m_NextTry(0.0f) + , m_SessionTime(0.0f) + , m_Reconnect(false) + , m_IPv6(false) { if (!m_Session) { @@ -55,12 +68,38 @@ Session::~Session() // ------------------------------------------------------------------------------------------------ void Session::Process(SQFloat delta) { - SQMOD_UNUSED_VAR(delta); + m_SessionTime += delta; // Make sure that the IRC session is connected if (!irc_is_connected(m_Session)) { - // @TODO: reconnect it, or abort - LogWrn("Session is not connected"); + // Do we meet the condition to attempt to reconnect? + if (m_Reconnect && (m_LeftTries != 0) && (m_NextTry <= m_SessionTime)) + { + // Take out one try + --m_LeftTries; + // Update the timepoint for the next try + m_NextTry = (m_SessionTime + m_Wait); + // Attempt to reconnect + if (m_IPv6) + { + irc_connect6(m_Session, m_Server.c_str(), m_Port, + m_Passwd.empty() ? NULL : m_Passwd.c_str(), + m_Nick.c_str(), + m_User.empty() ? NULL : m_User.c_str(), + m_Name.empty() ? NULL : m_Name.c_str() + ); + } + else + { + irc_connect(m_Session, m_Server.c_str(), m_Port, + m_Passwd.empty() ? NULL : m_Passwd.c_str(), + m_Nick.c_str(), + m_User.empty() ? NULL : m_User.c_str(), + m_Name.empty() ? NULL : m_Name.c_str() + ); + } + } + // We're done for now return; } // Create the structures for select() @@ -285,6 +324,153 @@ void Session::SetData(SqObj & data) m_Data = data; } +// ------------------------------------------------------------------------------------------------ +const SQChar * Session::GetServer() const +{ + return m_Server.c_str(); +} + +// ------------------------------------------------------------------------------------------------ +void Session::SetServer(const SQChar * server) +{ + m_Server.assign(server); +} + +// ------------------------------------------------------------------------------------------------ +const SQChar * Session::GetPassword() const +{ + return m_Passwd.c_str(); +} + +// ------------------------------------------------------------------------------------------------ +void Session::SetPassword(const SQChar * passwd) +{ + m_Passwd.assign(passwd); +} + +// ------------------------------------------------------------------------------------------------ +const SQChar * Session::GetNick() const +{ + return m_Nick.c_str(); +} + +// ------------------------------------------------------------------------------------------------ +void Session::SetNick(const SQChar * nick) +{ + m_Nick.assign(nick); +} + +// ------------------------------------------------------------------------------------------------ +const SQChar * Session::GetUser() const +{ + return m_User.c_str(); +} + +// ------------------------------------------------------------------------------------------------ +void Session::SetUser(const SQChar * user) +{ + m_User.assign(user); +} + +// ------------------------------------------------------------------------------------------------ +const SQChar * Session::GetName() const +{ + return m_Name.c_str(); +} + +// ------------------------------------------------------------------------------------------------ +void Session::SetName(const SQChar * name) +{ + m_Name.assign(name); +} + +// ------------------------------------------------------------------------------------------------ +SQUint32 Session::GetPort() const +{ + return m_Port; +} + +// ------------------------------------------------------------------------------------------------ +void Session::SetPort(SQUint32 port) +{ + m_Port = port > _NLMAX(Uint16) ? _NLMAX(Uint16) : port; +} + +// ------------------------------------------------------------------------------------------------ +SQUint32 Session::GetTries() const +{ + return m_Tries; +} + +// ------------------------------------------------------------------------------------------------ +void Session::SetTries(SQUint32 num) +{ + if (m_Tries < num) + { + m_LeftTries += (num - m_Tries); + } + else + { + m_LeftTries -= (m_Tries - num); + } + + m_Tries = num; +} + +// ------------------------------------------------------------------------------------------------ +SQFloat Session::GetWait() const +{ + return m_Wait; +} + +// ------------------------------------------------------------------------------------------------ +void Session::SetWait(SQFloat time) +{ + m_Wait = time; +} + +// ------------------------------------------------------------------------------------------------ +SQUint32 Session::GetLeftTries() const +{ + return m_LeftTries; +} + +// ------------------------------------------------------------------------------------------------ +void Session::SetLeftTries(SQUint32 num) +{ + m_LeftTries = num; +} + +// ------------------------------------------------------------------------------------------------ +SQFloat Session::GetNextTry() const +{ + return m_NextTry; +} + +// ------------------------------------------------------------------------------------------------ +void Session::SetNextTry(SQFloat time) +{ + m_NextTry = time; +} + +// ------------------------------------------------------------------------------------------------ +SQFloat Session::GetSessionTime() const +{ + return m_SessionTime; +} + +// ------------------------------------------------------------------------------------------------ +bool Session::GetReconnect() const +{ + return m_Reconnect; +} + +// ------------------------------------------------------------------------------------------------ +bool Session::GetIPv6() const +{ + return m_IPv6; +} + // ------------------------------------------------------------------------------------------------ Function Session::GetOnConnect() { @@ -670,11 +856,35 @@ bool Session::IsValid() const } // ------------------------------------------------------------------------------------------------ -SQInt32 Session::Connect(const SQChar * server, SQUint32 port, const SQChar * nick) +SQInt32 Session::Connect() { - if (m_Session != nullptr) + if (m_Session != nullptr && !irc_is_connected(m_Session) && !m_Server.empty() && !m_Nick.empty()) { - return irc_connect(m_Session, server, port, NULL, nick, NULL, NULL); + // Enable the reconnection system + m_Reconnect = true; + m_LeftTries = m_Tries; + m_NextTry = (m_SessionTime + m_Wait); + // This is not an IPv6 connection + m_IPv6 = false; + // Attempt to connect + return irc_connect(m_Session, m_Server.c_str(), m_Port, + m_Passwd.empty() ? NULL : m_Passwd.c_str(), + m_Nick.c_str(), + m_User.empty() ? NULL : m_User.c_str(), + m_Name.empty() ? NULL : m_Name.c_str() + ); + } + else if (irc_is_connected(m_Session)) + { + LogWrn("Attempting to while already connected to server"); + } + else if (m_Server.empty()) + { + LogWrn("Attempting to without specifying a server first"); + } + else if (m_Nick.empty()) + { + LogWrn("Attempting to without specifying a nickname first"); } else { @@ -684,28 +894,50 @@ SQInt32 Session::Connect(const SQChar * server, SQUint32 port, const SQChar * ni return SQMOD_UNKNOWN; } +// ------------------------------------------------------------------------------------------------ +SQInt32 Session::Connect(const SQChar * server, SQUint32 port, const SQChar * nick) +{ + return Connect(server, port, NULL, nick, NULL, NULL); +} + // ------------------------------------------------------------------------------------------------ SQInt32 Session::Connect(const SQChar * server, SQUint32 port, const SQChar * nick, const SQChar * passwd) { - if (m_Session != nullptr) - { - return irc_connect(m_Session, server, port, passwd, nick, NULL, NULL); - } - else - { - LogWrn("Attempting to using an invalid session: null"); - } - - return SQMOD_UNKNOWN; + return Connect(server, port, passwd, nick, NULL, NULL); } // ------------------------------------------------------------------------------------------------ SQInt32 Session::Connect(const SQChar * server, SQUint32 port, const SQChar * nick, const SQChar * passwd, const SQChar * username) { - if (m_Session != nullptr) + return Connect(server, port, passwd, nick, username, NULL); +} + +// ------------------------------------------------------------------------------------------------ +SQInt32 Session::Connect(const SQChar * server, SQUint32 port, const SQChar * nick, const SQChar * passwd, + const SQChar * username, const SQChar * realname) +{ + if (m_Session != nullptr && !irc_is_connected(m_Session)) { - return irc_connect(m_Session, server, port, passwd, nick, username, NULL); + // Save information + SetServer(server == NULL ? _SC("") : server); + SetPort(port); + SetPassword(passwd == NULL ? _SC("") : passwd); + SetNick(nick == NULL ? _SC("") : nick); + SetUser(username == NULL ? _SC("") : username); + SetName(realname == NULL ? _SC("") : realname); + // Enable the reconnection system + m_Reconnect = true; + m_LeftTries = m_Tries; + m_NextTry = (m_SessionTime + m_Wait); + // This is not an IPv6 connection + m_IPv6 = false; + // Attempt to connect + return irc_connect(m_Session, server, m_Port, passwd, nick, username, realname); + } + else if (irc_is_connected(m_Session)) + { + LogWrn("Attempting to while already connected to server"); } else { @@ -716,12 +948,35 @@ SQInt32 Session::Connect(const SQChar * server, SQUint32 port, const SQChar * ni } // ------------------------------------------------------------------------------------------------ -SQInt32 Session::Connect(const SQChar * server, SQUint32 port, const SQChar * nick, const SQChar * passwd, - const SQChar * username, const SQChar * realname) +SQInt32 Session::Connect6() { - if (m_Session != nullptr) + if (m_Session != nullptr && !irc_is_connected(m_Session) && !m_Server.empty() && !m_Nick.empty()) { - return irc_connect(m_Session, server, port, passwd, nick, username, realname); + // Enable the reconnection system + m_Reconnect = true; + m_LeftTries = m_Tries; + m_NextTry = (m_SessionTime + m_Wait); + // This is an IPv6 connection + m_IPv6 = true; + // Attempt to connect + return irc_connect6(m_Session, m_Server.c_str(), m_Port, + m_Passwd.empty() ? NULL : m_Passwd.c_str(), + m_Nick.c_str(), + m_User.empty() ? NULL : m_User.c_str(), + m_Name.empty() ? NULL : m_Name.c_str() + ); + } + else if (irc_is_connected(m_Session)) + { + LogWrn("Attempting to while already connected to server"); + } + else if (m_Server.empty()) + { + LogWrn("Attempting to without specifying a server first"); + } + else if (m_Nick.empty()) + { + LogWrn("Attempting to without specifying a nickname first"); } else { @@ -734,56 +989,47 @@ SQInt32 Session::Connect(const SQChar * server, SQUint32 port, const SQChar * ni // ------------------------------------------------------------------------------------------------ SQInt32 Session::Connect6(const SQChar * server, SQUint32 port, const SQChar * nick) { - if (m_Session != nullptr) - { - return irc_connect6(m_Session, server, port, NULL, nick, NULL, NULL); - } - else - { - LogWrn("Attempting to using an invalid session: null"); - } - - return SQMOD_UNKNOWN; + return Connect6(server, port, NULL, nick, NULL, NULL); } // ------------------------------------------------------------------------------------------------ SQInt32 Session::Connect6(const SQChar * server, SQUint32 port, const SQChar * nick, const SQChar * passwd) { - if (m_Session != nullptr) - { - return irc_connect6(m_Session, server, port, passwd, nick, NULL, NULL); - } - else - { - LogWrn("Attempting to using an invalid session: null"); - } - - return SQMOD_UNKNOWN; + return Connect6(server, port, passwd, nick, NULL, NULL); } // ------------------------------------------------------------------------------------------------ SQInt32 Session::Connect6(const SQChar * server, SQUint32 port, const SQChar * nick, const SQChar * passwd, const SQChar * username) { - if (m_Session != nullptr) - { - return irc_connect6(m_Session, server, port, passwd, nick, username, NULL); - } - else - { - LogWrn("Attempting to using an invalid session: null"); - } - - return SQMOD_UNKNOWN; + return Connect6(server, port, passwd, nick, username, NULL); } // ------------------------------------------------------------------------------------------------ SQInt32 Session::Connect6(const SQChar * server, SQUint32 port, const SQChar * nick, const SQChar * passwd, const SQChar * username, const SQChar * realname) { - if (m_Session != nullptr) + if (m_Session != nullptr && !irc_is_connected(m_Session)) { - return irc_connect6(m_Session, server, port, passwd, nick, username, realname); + // Save infomation + SetServer(server == NULL ? _SC("") : server); + SetPort(port); + SetPassword(passwd == NULL ? _SC("") : passwd); + SetNick(nick == NULL ? _SC("") : nick); + SetUser(username == NULL ? _SC("") : username); + SetName(realname == NULL ? _SC("") : realname); + // Enable the reconnection system + m_Reconnect = true; + m_LeftTries = m_Tries; + m_NextTry = (m_SessionTime + m_Wait); + // This is an IPv6 connection + m_IPv6 = true; + // Attempt to connect + return irc_connect6(m_Session, server, m_Port, passwd, nick, username, realname); + } + else if (irc_is_connected(m_Session)) + { + LogWrn("Attempting to while already connected to server"); } else { @@ -798,6 +1044,9 @@ void Session::Disconnect() { if (m_Session != nullptr) { + // Disable the reconnection system + m_Reconnect = false; + // Attempt to disconnect irc_disconnect(m_Session); } else @@ -824,16 +1073,7 @@ bool Session::IsConnected() // ------------------------------------------------------------------------------------------------ SQInt32 Session::CmdJoin(const SQChar * channel) { - if (m_Session != nullptr) - { - return irc_cmd_join(m_Session, channel, NULL); - } - else - { - LogWrn("Attempting to using an invalid session: null"); - } - - return SQMOD_UNKNOWN; + return CmdJoin(channel, NULL); } // ------------------------------------------------------------------------------------------------ @@ -899,16 +1139,7 @@ SQInt32 Session::CmdNames(const SQChar * channel) // ------------------------------------------------------------------------------------------------ SQInt32 Session::CmdList() { - if (m_Session != nullptr) - { - return irc_cmd_list(m_Session, NULL); - } - else - { - LogWrn("Attempting to using an invalid session: null"); - } - - return SQMOD_UNKNOWN; + return CmdList(NULL); } // ------------------------------------------------------------------------------------------------ @@ -929,16 +1160,7 @@ SQInt32 Session::CmdList(const SQChar * channel) // ------------------------------------------------------------------------------------------------ SQInt32 Session::CmdTopic(const SQChar * channel) { - if (m_Session != nullptr) - { - return irc_cmd_topic(m_Session, channel, NULL); - } - else - { - LogWrn("Attempting to using an invalid session: null"); - } - - return SQMOD_UNKNOWN; + return (channel, NULL); } // ------------------------------------------------------------------------------------------------ @@ -959,16 +1181,7 @@ SQInt32 Session::CmdTopic(const SQChar * channel, const SQChar * topic) // ------------------------------------------------------------------------------------------------ SQInt32 Session::CmdChannelMode(const SQChar * channel) { - if (m_Session != nullptr) - { - return irc_cmd_channel_mode(m_Session, channel, NULL); - } - else - { - LogWrn("Attempting to using an invalid session: null"); - } - - return SQMOD_UNKNOWN; + return CmdChannelMode(channel, NULL); } // ------------------------------------------------------------------------------------------------ @@ -989,16 +1202,7 @@ SQInt32 Session::CmdChannelMode(const SQChar * channel, const SQChar * mode) // ------------------------------------------------------------------------------------------------ SQInt32 Session::CmdUserMode() { - if (m_Session != nullptr) - { - return irc_cmd_user_mode(m_Session, NULL); - } - else - { - LogWrn("Attempting to using an invalid session: null"); - } - - return SQMOD_UNKNOWN; + return CmdUserMode(NULL); } // ------------------------------------------------------------------------------------------------ @@ -1019,16 +1223,7 @@ SQInt32 Session::CmdUserMode(const SQChar * mode) // ------------------------------------------------------------------------------------------------ SQInt32 Session::CmdKick(const SQChar * nick, const SQChar * channel) { - if (m_Session != nullptr) - { - return irc_cmd_kick(m_Session, nick, channel, NULL); - } - else - { - LogWrn("Attempting to using an invalid session: null"); - } - - return SQMOD_UNKNOWN; + return CmdKick(nick, channel, NULL); } // ------------------------------------------------------------------------------------------------ @@ -1154,16 +1349,8 @@ SQInt32 Session::CmdWhois(const SQChar * nick) // ------------------------------------------------------------------------------------------------ SQInt32 Session::CmdQuit() { - if (m_Session != nullptr) - { - return irc_cmd_quit(m_Session, NULL); - } - else - { - LogWrn("Attempting to using an invalid session: null"); - } - return SQMOD_UNKNOWN; + return CmdQuit(NULL); } // ------------------------------------------------------------------------------------------------ @@ -1289,6 +1476,9 @@ void Session::OnConnect(irc_session_t * session, const char * event, const char } else { + // Prevent any attempts to reconnect now + inst->m_Reconnect = false; + // Now forward event ForwardEvent(inst, inst->m_OnConnect, event, origin, params, count); } } @@ -1597,7 +1787,7 @@ void Session::OnDcc_Send_Req(irc_session_t * session, const char * nick, const c const SQChar * GetNick(const SQChar * origin) { // Attempt to retrieve the nickname - irc_target_get_nick(origin, g_Buffer, std::extent< decltype(g_Buffer) >::value * sizeof(SQChar)); + irc_target_get_nick(origin, g_Buffer, sizeof(g_Buffer)); // Return the nickname that could be retrieved return g_Buffer; } @@ -1606,7 +1796,7 @@ const SQChar * GetNick(const SQChar * origin) const SQChar * GetHost(const SQChar * target) { // Attempt to retrieve the nickname - irc_target_get_host(target, g_Buffer, std::extent< decltype(g_Buffer) >::value * sizeof(SQChar)); + irc_target_get_host(target, g_Buffer, sizeof(g_Buffer)); // Return the nickname that could be retrieved return g_Buffer; } @@ -1633,6 +1823,20 @@ bool Register_IRC(HSQUIRRELVM vm) /* Properties */ .Prop(_SC("ltag"), &Session::GetTag, &Session::SetTag) .Prop(_SC("ldata"), &Session::GetData, &Session::SetData) + .Prop(_SC("server"), &Session::GetData, &Session::SetData) + .Prop(_SC("server"), &Session::GetServer, &Session::SetServer) + .Prop(_SC("passwd"), &Session::GetPassword, &Session::SetPassword) + .Prop(_SC("nick"), &Session::GetNick, &Session::SetNick) + .Prop(_SC("user"), &Session::GetUser, &Session::SetUser) + .Prop(_SC("name"), &Session::GetName, &Session::SetName) + .Prop(_SC("port"), &Session::GetPort, &Session::SetPort) + .Prop(_SC("tries"), &Session::GetTries, &Session::SetTries) + .Prop(_SC("wait"), &Session::GetWait, &Session::SetWait) + .Prop(_SC("left_tries"), &Session::GetLeftTries, &Session::SetLeftTries) + .Prop(_SC("next_try"), &Session::GetNextTry, &Session::SetNextTry) + .Prop(_SC("session_time"), &Session::GetSessionTime) + .Prop(_SC("reconnect"), &Session::GetReconnect) + .Prop(_SC("ipv6"), &Session::GetIPv6) .Prop(_SC("on_connect"), &Session::GetOnConnect, &Session::SetOnConnect) .Prop(_SC("on_nick"), &Session::GetOnNick, &Session::SetOnNick) .Prop(_SC("on_quit"), &Session::GetOnQuit, &Session::SetOnQuit) @@ -1718,6 +1922,8 @@ bool Register_IRC(HSQUIRRELVM vm) .Func(_SC("set_option"), &Session::SetOption) .Func(_SC("reset_option"), &Session::ResetOption) /* Overloads */ + .Overload< SQInt32 (Session::*)(void) > + (_SC("connect"), &Session::Connect) .Overload< SQInt32 (Session::*)(const SQChar *, SQUint32, const SQChar *) > (_SC("connect"), &Session::Connect) .Overload< SQInt32 (Session::*)(const SQChar *, SQUint32, const SQChar *, const SQChar *) > @@ -1726,6 +1932,8 @@ bool Register_IRC(HSQUIRRELVM vm) (_SC("connect"), &Session::Connect) .Overload< SQInt32 (Session::*)(const SQChar *, SQUint32, const SQChar *, const SQChar *, const SQChar *, const SQChar *) > (_SC("connect"), &Session::Connect) + .Overload< SQInt32 (Session::*)(void) > + (_SC("connect6"), &Session::Connect6) .Overload< SQInt32 (Session::*)(const SQChar *, SQUint32, const SQChar *) > (_SC("connect6"), &Session::Connect6) .Overload< SQInt32 (Session::*)(const SQChar *, SQUint32, const SQChar *, const SQChar *) > @@ -1763,6 +1971,7 @@ bool Register_IRC(HSQUIRRELVM vm) .Overload< SQInt32 (Session::*)(const SQChar *) > (_SC("cmd_quit"), &Session::CmdQuit) ); + // Output debugging information LogDbg("Registration of type was successful"); diff --git a/source/Library/IRC/Session.hpp b/source/Library/IRC/Session.hpp index ee05a9f2..e9cb7fb7 100644 --- a/source/Library/IRC/Session.hpp +++ b/source/Library/IRC/Session.hpp @@ -130,6 +130,121 @@ public: */ void SetData(SqObj & data); + /* -------------------------------------------------------------------------------------------- + * ... + */ + const SQChar * GetServer() const; + + /* -------------------------------------------------------------------------------------------- + * ... + */ + void SetServer(const SQChar * server); + + /* -------------------------------------------------------------------------------------------- + * ... + */ + const SQChar * GetPassword() const; + + /* -------------------------------------------------------------------------------------------- + * ... + */ + void SetPassword(const SQChar * passwd); + + /* -------------------------------------------------------------------------------------------- + * ... + */ + const SQChar * GetNick() const; + + /* -------------------------------------------------------------------------------------------- + * ... + */ + void SetNick(const SQChar * nick); + + /* -------------------------------------------------------------------------------------------- + * ... + */ + const SQChar * GetUser() const; + + /* -------------------------------------------------------------------------------------------- + * ... + */ + void SetUser(const SQChar * user); + + /* -------------------------------------------------------------------------------------------- + * ... + */ + const SQChar * GetName() const; + + /* -------------------------------------------------------------------------------------------- + * ... + */ + void SetName(const SQChar * name); + + /* -------------------------------------------------------------------------------------------- + * ... + */ + SQUint32 GetPort() const; + + /* -------------------------------------------------------------------------------------------- + * ... + */ + void SetPort(SQUint32 port); + + /* -------------------------------------------------------------------------------------------- + * ... + */ + SQUint32 GetTries() const; + + /* -------------------------------------------------------------------------------------------- + * ... + */ + void SetTries(SQUint32 num); + + /* -------------------------------------------------------------------------------------------- + * ... + */ + SQFloat GetWait() const; + + /* -------------------------------------------------------------------------------------------- + * ... + */ + void SetWait(SQFloat time); + + /* -------------------------------------------------------------------------------------------- + * ... + */ + SQUint32 GetLeftTries() const; + + /* -------------------------------------------------------------------------------------------- + * ... + */ + void SetLeftTries(SQUint32 num); + + /* -------------------------------------------------------------------------------------------- + * ... + */ + SQFloat GetNextTry() const; + + /* -------------------------------------------------------------------------------------------- + * ... + */ + void SetNextTry(SQFloat time); + + /* -------------------------------------------------------------------------------------------- + * ... + */ + SQFloat GetSessionTime() const; + + /* -------------------------------------------------------------------------------------------- + * ... + */ + bool GetReconnect() const; + + /* -------------------------------------------------------------------------------------------- + * ... + */ + bool GetIPv6() const; + /* -------------------------------------------------------------------------------------------- * ... */ @@ -450,6 +565,11 @@ public: */ bool IsValid() const; + /* -------------------------------------------------------------------------------------------- + * ... + */ + SQInt32 Connect(); + /* -------------------------------------------------------------------------------------------- * ... */ @@ -472,6 +592,11 @@ public: SQInt32 Connect(const SQChar * server, SQUint32 port, const SQChar * nick, const SQChar * passwd, const SQChar * username, const SQChar * realname); + /* -------------------------------------------------------------------------------------------- + * ... + */ + SQInt32 Connect6(); + /* -------------------------------------------------------------------------------------------- * ... */ @@ -666,6 +791,55 @@ private: */ irc_session_t* m_Session; + /* -------------------------------------------------------------------------------------------- + * ... + */ + String m_Server; + String m_Passwd; + String m_Nick; + String m_User; + String m_Name; + + /* -------------------------------------------------------------------------------------------- + * ... + */ + SQInt32 m_Port; + + /* -------------------------------------------------------------------------------------------- + * ... + */ + SQUint32 m_Tries; + + /* -------------------------------------------------------------------------------------------- + * ... + */ + SQFloat m_Wait; + + /* -------------------------------------------------------------------------------------------- + * ... + */ + SQUint32 m_LeftTries; + + /* -------------------------------------------------------------------------------------------- + * ... + */ + SQFloat m_NextTry; + + /* -------------------------------------------------------------------------------------------- + * ... + */ + SQFloat m_SessionTime; + + /* -------------------------------------------------------------------------------------------- + * ... + */ + bool m_Reconnect; + + /* -------------------------------------------------------------------------------------------- + * ... + */ + bool m_IPv6; + /* -------------------------------------------------------------------------------------------- * ... */ diff --git a/source/Register.cpp b/source/Register.cpp index 4a808afc..c1b98523 100644 --- a/source/Register.cpp +++ b/source/Register.cpp @@ -76,7 +76,9 @@ bool RegisterAPI(HSQUIRRELVM vm) _Log->cFtl(!Register_BasicEvent(vm), "Unable to register: BasicEvent") || \ _Log->cFtl(!Register_GlobalEvent(vm), "Unable to register: GlobalEvent") || \ _Log->cFtl(!Register_LocalEvent(vm), "Unable to register: LocalEvent") || \ - _Log->cFtl(!Register_Event(vm), "Unable to register: Event") + _Log->cFtl(!Register_Event(vm), "Unable to register: Event") || \ + + _Log->cFtl(!Register_Cmd(vm), "Unable to register: Command") ) return false; return true; diff --git a/source/Register.hpp b/source/Register.hpp index 66f322a5..5c3e3220 100644 --- a/source/Register.hpp +++ b/source/Register.hpp @@ -109,6 +109,11 @@ bool Register_Event(HSQUIRRELVM vm); // ------------------------------------------------------------------------------------------------ bool Register_Utility(HSQUIRRELVM vm); +// ------------------------------------------------------------------------------------------------ +bool Register_Log(HSQUIRRELVM vm); +bool Register_Core(HSQUIRRELVM vm); +bool Register_Cmd(HSQUIRRELVM vm); + } // Namespace:: SqMod #endif // _REGISTER_HPP_