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_