1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2024-11-08 00:37:15 +01:00

Compare commits

..

7 Commits

Author SHA1 Message Date
Sandu Liviu Catalin
c0d142ab34 Update sqmod.h
Some checks reported errors
continuous-integration/drone/push Build was killed
2023-03-05 17:12:29 +02:00
Sandu Liviu Catalin
f77ec9482f Update Main.cpp 2023-03-05 17:11:38 +02:00
Sandu Liviu Catalin
4fc1e892f7 Update Core.cpp 2023-03-05 17:11:36 +02:00
Sandu Liviu Catalin
015047a935 Update Core.cpp 2023-03-05 17:00:39 +02:00
Sandu Liviu Catalin
bc1fc1d245 Allow external native plug-ins to interact wit the script.
Very primitive mechanism but better than nothing.
2023-03-05 15:38:59 +02:00
Sandu Liviu Catalin
2a069f3040 Update CMakeLists.txt 2023-03-05 15:37:30 +02:00
Sandu Liviu Catalin
d295828545 Add GetJSON method to buffer. 2023-03-05 15:37:24 +02:00
12 changed files with 402 additions and 25 deletions

View File

@ -3,7 +3,7 @@ project(SqMod)
# This plug-in only works on 64-bit # This plug-in only works on 64-bit
if(CMAKE_SIZEOF_VOID_P EQUAL 4) if(CMAKE_SIZEOF_VOID_P EQUAL 4)
message(FATAL_ERROR "SqMod does not support 32-but platforms anymore.") message(FATAL_ERROR "SqMod does not support 32-bit platforms anymore.")
endif() endif()
# Tell CMake where to find our scripts # Tell CMake where to find our scripts
@ -18,7 +18,7 @@ option(ENABLE_BUILTIN_MYSQL_C "Enable built-in MySQL connector library" OFF)
#option(FORCE_32BIT_BIN "Create a 32-bit executable binary if the compiler defaults to 64-bit." OFF) #option(FORCE_32BIT_BIN "Create a 32-bit executable binary if the compiler defaults to 64-bit." OFF)
# This option should only be available in certain conditions # This option should only be available in certain conditions
if(WIN32 AND MINGW) if(WIN32 AND MINGW)
option(COPY_DEPENDENCIES "Copy deppendent DLLs into the deps folder." OFF) option(COPY_DEPENDENCIES "Copy dependent DLLs into the deps folder." OFF)
endif() endif()
# C++14 is mandatory # C++14 is mandatory

View File

@ -1,5 +1,7 @@
# Create the Squirrel module # Create the Squirrel module
add_library(SqModule MODULE SqBase.hpp Main.cpp add_library(SqModule MODULE SqBase.hpp Main.cpp
# SDK
SDK/sqmod.h
# VCMP # VCMP
VCMP/vcmp.h VCMP/vcmp.h
VCMP/vcmp20.h VCMP/vcmp20.h
@ -114,6 +116,7 @@ add_library(SqModule MODULE SqBase.hpp Main.cpp
Core.cpp Core.hpp Core.cpp Core.hpp
Logger.cpp Logger.hpp Logger.cpp Logger.hpp
Register.cpp Register.cpp
Exports.cpp
) )
# Various definitions required by the plug-in # Various definitions required by the plug-in
target_compile_definitions(SqModule PRIVATE SCRAT_USE_EXCEPTIONS=1) target_compile_definitions(SqModule PRIVATE SCRAT_USE_EXCEPTIONS=1)
@ -201,6 +204,7 @@ else(WIN32)
endif(WIN32) endif(WIN32)
# Include current directory in the search path # Include current directory in the search path
target_include_directories(SqModule PRIVATE ${CMAKE_CURRENT_LIST_DIR}) target_include_directories(SqModule PRIVATE ${CMAKE_CURRENT_LIST_DIR})
target_include_directories(SqModule PRIVATE ${CMAKE_CURRENT_LIST_DIR}/SDK)
target_include_directories(SqModule PRIVATE ${CMAKE_CURRENT_LIST_DIR}/VCMP) target_include_directories(SqModule PRIVATE ${CMAKE_CURRENT_LIST_DIR}/VCMP)
target_include_directories(SqModule PRIVATE ${CMAKE_CURRENT_LIST_DIR}/Sqrat) target_include_directories(SqModule PRIVATE ${CMAKE_CURRENT_LIST_DIR}/Sqrat)
# Include PCRE directory in the header search path # Include PCRE directory in the header search path
@ -222,7 +226,7 @@ if(WIN32 AND MINGW AND COPY_DEPENDENCIES)
endif() endif()
# Make sure the deps folder exists # Make sure the deps folder exists
file(MAKE_DIRECTORY "${PROJECT_SOURCE_DIR}/bin/deps") file(MAKE_DIRECTORY "${PROJECT_SOURCE_DIR}/bin/deps")
# Copy dependencies into the plug-ins folder (only so it can be distributed with the DLL) # Copy dependencies into the deps folder (only so it can be distributed with the DLL)
file(COPY "${MINGW_BIN_PATH}/zlib1.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps") file(COPY "${MINGW_BIN_PATH}/zlib1.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
file(COPY "${MINGW_BIN_PATH}/libpq.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps") file(COPY "${MINGW_BIN_PATH}/libpq.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
file(COPY "${MINGW_BIN_PATH}/libzstd.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps") file(COPY "${MINGW_BIN_PATH}/libzstd.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
@ -245,17 +249,17 @@ if(WIN32 AND MINGW AND COPY_DEPENDENCIES)
file(COPY "${MINGW_BIN_PATH}/libp11-kit-0.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps") file(COPY "${MINGW_BIN_PATH}/libp11-kit-0.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
file(COPY "${MINGW_BIN_PATH}/libbrotlidec.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps") file(COPY "${MINGW_BIN_PATH}/libbrotlidec.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
file(COPY "${MINGW_BIN_PATH}/libbrotlicommon.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps") file(COPY "${MINGW_BIN_PATH}/libbrotlicommon.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
file(COPY "${MINGW_BIN_PATH}/libunistring-2.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps") file(COPY "${MINGW_BIN_PATH}/libunistring-5.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
file(COPY "${MINGW_BIN_PATH}/libnghttp2-14.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps") file(COPY "${MINGW_BIN_PATH}/libnghttp2-14.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
file(COPY "${MINGW_BIN_PATH}/libwinpthread-1.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps") file(COPY "${MINGW_BIN_PATH}/libwinpthread-1.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
file(COPY "${MINGW_BIN_PATH}/libstdc++-6.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps") file(COPY "${MINGW_BIN_PATH}/libstdc++-6.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
if(CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT FORCE_32BIT_BIN) if(CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT FORCE_32BIT_BIN)
file(COPY "${MINGW_BIN_PATH}/libgcc_s_seh-1.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps") file(COPY "${MINGW_BIN_PATH}/libgcc_s_seh-1.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
file(COPY "${MINGW_BIN_PATH}/libssl-1_1-x64.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps") file(COPY "${MINGW_BIN_PATH}/libssl-3-x64.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
file(COPY "${MINGW_BIN_PATH}/libcrypto-1_1-x64.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps") file(COPY "${MINGW_BIN_PATH}/libcrypto-3-x64.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
else() else()
file(COPY "${MINGW_BIN_PATH}/libssl-1_1.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps") file(COPY "${MINGW_BIN_PATH}/libssl-3.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
file(COPY "${MINGW_BIN_PATH}/libcrypto-1_1.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps") file(COPY "${MINGW_BIN_PATH}/libcrypto-3.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")
endif() endif()
if(POCO_UNBUNDLED) if(POCO_UNBUNDLED)
file(COPY "${MINGW_BIN_PATH}/libexpat-1.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps") file(COPY "${MINGW_BIN_PATH}/libexpat-1.dll" DESTINATION "${PROJECT_SOURCE_DIR}/bin/deps")

View File

@ -161,6 +161,7 @@ Core::Core() noexcept
, m_Scripts() , m_Scripts()
, m_PendingScripts() , m_PendingScripts()
, m_Options() , m_Options()
, m_ExtCommands{nullptr, nullptr, nullptr, nullptr}
, m_Blips() , m_Blips()
, m_Checkpoints() , m_Checkpoints()
, m_KeyBinds() , m_KeyBinds()
@ -441,9 +442,9 @@ bool Core::Execute()
m_LockPostLoadSignal = false; m_LockPostLoadSignal = false;
m_LockUnloadSignal = false; m_LockUnloadSignal = false;
//cLogDbg(m_Verbosity >= 1, "Signaling outside plug-ins to register their API"); cLogDbg(m_Verbosity >= 1, "Signaling outside plug-ins that the API is being registered");
// Tell modules to do their monkey business // Tell modules to do their monkey business
//_Func->SendPluginCommand(0xDEADBABE, ""); _Func->SendPluginCommand(SQMOD_LOAD_CMD, SQMOD_HOST_NAME);
// Load pending scripts while we're in the bounds of the allowed recursiveness // Load pending scripts while we're in the bounds of the allowed recursiveness
for (unsigned levels = 0; !m_PendingScripts.empty() && (levels < 8); ++levels) for (unsigned levels = 0; !m_PendingScripts.empty() && (levels < 8); ++levels)
@ -511,9 +512,9 @@ void Core::Terminate(bool shutdown)
// Clear the callbacks // Clear the callbacks
ResetSignalPair(mOnUnload); ResetSignalPair(mOnUnload);
//cLogDbg(m_Verbosity >= 1, "Signaling outside plug-ins to release their resources"); cLogDbg(m_Verbosity >= 1, "Signaling outside plug-ins to release their resources");
// Tell modules to do their monkey business // Tell modules to do their monkey business
//_Func->SendPluginCommand(0xDEADC0DE, ""); _Func->SendPluginCommand(SQMOD_TERMINATE_CMD, SQMOD_HOST_NAME);
} }
cLogDbg(m_Verbosity >= 1, "Clearing the entity containers"); cLogDbg(m_Verbosity >= 1, "Clearing the entity containers");
@ -596,9 +597,9 @@ void Core::Terminate(bool shutdown)
HSQUIRRELVM sq_vm = m_VM; HSQUIRRELVM sq_vm = m_VM;
m_VM = nullptr; m_VM = nullptr;
//cLogDbg(m_Verbosity >= 1, "Signaling outside plug-ins the virtual machine is closing"); cLogDbg(m_Verbosity >= 1, "Signaling outside plug-ins the virtual machine is closing");
// Tell modules to do their monkey business // Tell modules to do their monkey business
//_Func->SendPluginCommand(0xBAAAAAAD, ""); _Func->SendPluginCommand(SQMOD_CLOSING_CMD, SQMOD_HOST_NAME);
// Release any callbacks from the logger // Release any callbacks from the logger
Logger::Get().Release(); Logger::Get().Release();
cLogDbg(m_Verbosity >= 2, "Closing Virtual Machine"); cLogDbg(m_Verbosity >= 2, "Closing Virtual Machine");
@ -629,9 +630,9 @@ void Core::Terminate(bool shutdown)
// Destroy the VM context, if any // Destroy the VM context, if any
delete ctx; delete ctx;
//cLogDbg(m_Verbosity >= 1, "Signaling outside plug-ins to release the virtual machine"); cLogDbg(m_Verbosity >= 1, "Signaling outside plug-ins the virtual machine was closed");
// Tell modules to do their monkey business // Tell modules to do their monkey business
//_Func->SendPluginCommand(0xDEADBEAF, ""); _Func->SendPluginCommand(SQMOD_RELEASED_CMD, SQMOD_HOST_NAME);
} }
OutputMessage("Squirrel plug-in was successfully terminated"); OutputMessage("Squirrel plug-in was successfully terminated");
@ -904,6 +905,81 @@ String Core::FetchCodeLine(const SQChar * src, SQInteger line, bool trim)
return script->FetchLine(line, trim); return script->FetchLine(line, trim);
} }
// ------------------------------------------------------------------------------------------------
int32_t Core::RegisterExtCommand(ExtPluginCommand_t fn)
{
ExtPluginCommand_t * slot = nullptr;
// Find a free slot or matching function pointer in the pool
for (size_t i = 0; i < m_ExtCommands.max_size(); ++i)
{
// Is this slot available and are we still looking for a slot?
if (m_ExtCommands[i] == nullptr && slot == nullptr)
{
slot = &m_ExtCommands[i]; // Found a slot
}
// We keep looking for duplicates even if we found the slot
else if (m_ExtCommands[i] == fn)
{
return 0; // Already registered
}
}
// Do we have a free slot?
if (slot != nullptr)
{
*slot = fn; // Use this slot
return 1; // Successfully registered
}
// No space in the pool
return -1;
}
// ------------------------------------------------------------------------------------------------
int32_t Core::UnregisterExtCommand(ExtPluginCommand_t fn)
{
// Find the matching function pointer
for (size_t i = 0; i < m_ExtCommands.max_size(); ++i)
{
// Is this the same pointer?
if (m_ExtCommands[i] != nullptr && m_ExtCommands[i] == fn)
{
// Forget about it
m_ExtCommands[i] = nullptr;
return 1; // Successfully unregistered
}
}
// No space
return -1;
}
// ------------------------------------------------------------------------------------------------
int32_t Core::SendExtCommand(int32_t target, int32_t req, int32_t tag, const uint8_t * data, size_t size)
{
int32_t count = 0;
// Send the command to all registered function pointers
for (size_t i = 0; i < m_ExtCommands.max_size(); ++i)
{
if (m_ExtCommands[i] != nullptr)
{
const int32_t r = m_ExtCommands[i](target, req, tag, data, size);
// Command processed
++count;
// Command failed?
if (r < 0)
{
LogErr("External command failed (%i): target(%i), req(%i), tag(%i), data(%p), size (%zu)",
r, target, req, tag, data, size);
}
// Command consumed?
else if (r > 0)
{
break; // This function pointer requested exclusive access over this command
}
}
}
// Return how many function pointers received this command
return count;
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool Core::DoScripts(Scripts::iterator itr, Scripts::iterator end) bool Core::DoScripts(Scripts::iterator itr, Scripts::iterator end)
{ {
@ -2371,6 +2447,8 @@ void Core::InitEvents()
InitSignalPair(mOnServerOption, m_Events, "ServerOption"); InitSignalPair(mOnServerOption, m_Events, "ServerOption");
InitSignalPair(mOnScriptReload, m_Events, "ScriptReload"); InitSignalPair(mOnScriptReload, m_Events, "ScriptReload");
InitSignalPair(mOnScriptLoaded, m_Events, "ScriptLoaded"); InitSignalPair(mOnScriptLoaded, m_Events, "ScriptLoaded");
InitSignalPair(mOnExtCommandReply, m_Events, "ExtCommandReply");
InitSignalPair(mOnExtCommandEvent, m_Events, "ExtCommandEvent");
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Core::DropEvents() void Core::DropEvents()
@ -2516,6 +2594,8 @@ void Core::DropEvents()
ResetSignalPair(mOnServerOption); ResetSignalPair(mOnServerOption);
ResetSignalPair(mOnScriptReload); ResetSignalPair(mOnScriptReload);
ResetSignalPair(mOnScriptLoaded); ResetSignalPair(mOnScriptLoaded);
ResetSignalPair(mOnExtCommandReply);
ResetSignalPair(mOnExtCommandEvent);
m_Events.Release(); m_Events.Release();
} }
@ -2861,6 +2941,31 @@ static LightObj & SqGetClientDataBuffer()
return Core::Get().GetClientDataBuffer(); return Core::Get().GetClientDataBuffer();
} }
// ------------------------------------------------------------------------------------------------
static SQInteger SqSendExtCommand(int32_t target, int32_t req, int32_t tag, SqBuffer & buffer)
{
// Default to an empty/null buffer
const uint8_t * data = nullptr;
size_t size = 0;
// Does the buffer actually point to anything?
if (buffer.GetRef())
{
data = buffer.GetRef()->Begin< uint8_t >();
size = buffer.GetRef()->PositionAs< size_t >();
}
// Forward the request
return Core::Get().SendExtCommand(target, req, tag, data, size);
}
// ------------------------------------------------------------------------------------------------
static SQInteger SqSendExtCommandStr(int32_t target, int32_t req, int32_t tag, StackStrF & str)
{
// Forward the request
return Core::Get().SendExtCommand(target, req, tag,
reinterpret_cast< const uint8_t * >(str.mPtr),
str.mLen <= 0 ? 0 : static_cast< size_t >(str.mLen));
}
// ================================================================================================ // ================================================================================================
void Register_Core(HSQUIRRELVM vm) void Register_Core(HSQUIRRELVM vm)
{ {
@ -2910,6 +3015,8 @@ void Register_Core(HSQUIRRELVM vm)
.Func(_SC("DestroyPickup"), &SqDelPickup) .Func(_SC("DestroyPickup"), &SqDelPickup)
.Func(_SC("DestroyVehicle"), &SqDelVehicle) .Func(_SC("DestroyVehicle"), &SqDelVehicle)
.Func(_SC("ClientDataBuffer"), &SqGetClientDataBuffer) .Func(_SC("ClientDataBuffer"), &SqGetClientDataBuffer)
.Func(_SC("SendExtCommand"), &SqSendExtCommand)
.FmtFunc(_SC("SendExtCommandStr"), &SqSendExtCommandStr)
.Func(_SC("OnPreLoad"), &SqGetPreLoadEvent) .Func(_SC("OnPreLoad"), &SqGetPreLoadEvent)
.Func(_SC("OnPostLoad"), &SqGetPostLoadEvent) .Func(_SC("OnPostLoad"), &SqGetPostLoadEvent)
.Func(_SC("OnUnload"), &SqGetUnloadEvent) .Func(_SC("OnUnload"), &SqGetUnloadEvent)

View File

@ -9,6 +9,9 @@
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
#include <unordered_map> #include <unordered_map>
// ------------------------------------------------------------------------------------------------
#include "SDK/sqmod.h"
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
namespace SqMod { namespace SqMod {
@ -56,6 +59,8 @@ public:
typedef std::vector< ScriptSrc > Scripts; // List of loaded scripts. typedef std::vector< ScriptSrc > Scripts; // List of loaded scripts.
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
typedef std::unordered_map< String, String > Options; // List of custom options. typedef std::unordered_map< String, String > Options; // List of custom options.
// --------------------------------------------------------------------------------------------
typedef std::array< ExtPluginCommand_t, 4 > ExtCommands; // 4 external command parsers should be enough.
private: private:
@ -68,6 +73,7 @@ private:
Scripts m_Scripts; // Loaded scripts objects. Scripts m_Scripts; // Loaded scripts objects.
Scripts m_PendingScripts; // Pending scripts objects. Scripts m_PendingScripts; // Pending scripts objects.
Options m_Options; // Custom configuration options. Options m_Options; // Custom configuration options.
ExtCommands m_ExtCommands; // External command parsers pointers.
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
Blips m_Blips; // Blips pool. Blips m_Blips; // Blips pool.
@ -399,6 +405,23 @@ public:
*/ */
SQMOD_NODISCARD String FetchCodeLine(const SQChar * src, SQInteger line, bool trim = true); SQMOD_NODISCARD String FetchCodeLine(const SQChar * src, SQInteger line, bool trim = true);
/* --------------------------------------------------------------------------------------------
* Register a pointer to a function used to processes commands from script.
* Returns -1 it failed (no free slot), 0 if it was already registered and 1 if it succeeded.
*/
int32_t RegisterExtCommand(ExtPluginCommand_t fn);
/* --------------------------------------------------------------------------------------------
* Remove a pointer to a function used to processes commands from script.
* Returns -1 it failed (no free slot) and 1 if it succeeded.
*/
int32_t UnregisterExtCommand(ExtPluginCommand_t fn);
/* --------------------------------------------------------------------------------------------
* Send a command to all functions currently registered to receive them.
*/
int32_t SendExtCommand(int32_t target, int32_t req, int32_t tag, const uint8_t * data, size_t size);
protected: protected:
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
@ -710,6 +733,16 @@ public:
*/ */
void EmitClientScriptData(int32_t player_id, const uint8_t * data, size_t size); void EmitClientScriptData(int32_t player_id, const uint8_t * data, size_t size);
/* --------------------------------------------------------------------------------------------
* Send a response to the script that may have resulted from a previous command.
*/
void EmitExtCommandReply(int32_t sender, int32_t tag, const uint8_t * data, size_t size);
/* --------------------------------------------------------------------------------------------
* Forward an event to the script from an external plug-in.
*/
void EmitExtCommandEvent(int32_t sender, int32_t tag, const uint8_t * data, size_t size);
public: public:
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
@ -864,6 +897,8 @@ public:
SignalPair mOnServerOption{}; SignalPair mOnServerOption{};
SignalPair mOnScriptReload{}; SignalPair mOnScriptReload{};
SignalPair mOnScriptLoaded{}; SignalPair mOnScriptLoaded{};
SignalPair mOnExtCommandReply{};
SignalPair mOnExtCommandEvent{};
}; };
/* ------------------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------------------

View File

@ -347,7 +347,7 @@ void Core::EmitIncomingConnection(char * player_name, size_t name_buffer_size, c
// Release any stored buffer information // Release any stored buffer information
m_IncomingNameBuffer = nullptr; m_IncomingNameBuffer = nullptr;
m_IncomingNameCapacity = 0; m_IncomingNameCapacity = 0;
// We catched the exception so we can release the assigned buffer // We caught the exception so we can release the assigned buffer
throw; // re-throw it throw; // re-throw it
} }
// Release any stored buffer information // Release any stored buffer information
@ -2246,6 +2246,44 @@ void Core::EmitClientScriptData(int32_t player_id, const uint8_t * data, size_t
m_ClientData.Release(); m_ClientData.Release();
} }
// ------------------------------------------------------------------------------------------------
void Core::EmitExtCommandReply(int32_t sender, int32_t tag, const uint8_t * data, size_t size)
{
SQMOD_CO_EV_TRACEBACK("[TRACE<] Core::ExtCommandReply(%i, %i, %p, %zu)", sender, tag, data, size)
// Don't even bother if there's no one listening
if (!(mOnExtCommandReply.first->IsEmpty()))
{
// Allocate a buffer with the received size
Buffer b(static_cast< Buffer::SzType >(size));
// Replicate the data to the allocated buffer
b.Write(0, reinterpret_cast< Buffer::ConstPtr >(data), static_cast< Buffer::SzType >(size));
// Prepare an object for the obtained buffer
LightObj obj(SqTypeIdentity< SqBuffer >{}, m_VM, std::move(b));
// Forward the event call
(*mOnExtCommandReply.first)(sender, tag, obj, size);
}
SQMOD_CO_EV_TRACEBACK("[TRACE>] Core::ExtCommandReply")
}
// ------------------------------------------------------------------------------------------------
void Core::EmitExtCommandEvent(int32_t sender, int32_t tag, const uint8_t * data, size_t size)
{
SQMOD_CO_EV_TRACEBACK("[TRACE<] Core::ExtCommandEvent(%i, %i, %p, %zu)", sender, tag, data, size)
// Don't even bother if there's no one listening
if (!(mOnExtCommandEvent.first->IsEmpty()))
{
// Allocate a buffer with the received size
Buffer b(static_cast< Buffer::SzType >(size));
// Replicate the data to the allocated buffer
b.Write(0, reinterpret_cast< Buffer::ConstPtr >(data), static_cast< Buffer::SzType >(size));
// Prepare an object for the obtained buffer
LightObj obj(SqTypeIdentity< SqBuffer >{}, m_VM, std::move(b));
// Forward the event call
(*mOnExtCommandEvent.first)(sender, tag, obj, size);
}
SQMOD_CO_EV_TRACEBACK("[TRACE>] Core::ExtCommandEvent")
}
#undef NULL_SQOBJ_ // don't need this anymore #undef NULL_SQOBJ_ // don't need this anymore
} // Namespace:: SqMod } // Namespace:: SqMod

73
module/Exports.cpp Normal file
View File

@ -0,0 +1,73 @@
// ------------------------------------------------------------------------------------------------
#include "Core.hpp"
// ------------------------------------------------------------------------------------------------
#include <cstring>
// ------------------------------------------------------------------------------------------------
#include <sqmod.h>
// ------------------------------------------------------------------------------------------------
namespace SqMod {
// ------------------------------------------------------------------------------------------------
static int32_t RegisterCommandFn(ExtPluginCommand_t fn)
{
return Core::Get().RegisterExtCommand(fn);
}
// ------------------------------------------------------------------------------------------------
static int32_t UnregisterCommandFn(ExtPluginCommand_t fn)
{
return Core::Get().UnregisterExtCommand(fn);
}
// ------------------------------------------------------------------------------------------------
static int32_t SendCommandFn(int32_t target, int32_t req, int32_t tag, const uint8_t * data, size_t size)
{
return Core::Get().SendExtCommand(target, req, tag, data, size);
}
// ------------------------------------------------------------------------------------------------
static int32_t SendCommandReplyFn(int32_t sender, int32_t tag, const uint8_t * data, size_t size)
{
// Mark the initialization as successful by default
const CoreState cs(SQMOD_SUCCESS);
// Forward the call to the script callbacks
Core::Get().EmitExtCommandReply(sender, tag, data, size);
// Return the last known plug-in state
return Core::Get().GetState();
}
// ------------------------------------------------------------------------------------------------
static int32_t SendCommandEventFn(int32_t sender, int32_t tag, const uint8_t * data, size_t size)
{
// Mark the initialization as successful by default
const CoreState cs(SQMOD_SUCCESS);
// Forward the call to the script callbacks
Core::Get().EmitExtCommandEvent(sender, tag, data, size);
// Return the last known plug-in state
return Core::Get().GetState();
}
// ------------------------------------------------------------------------------------------------
static const SQ_MOD_EXPORTS g_SqModExports{
sizeof(SQ_MOD_EXPORTS),
&RegisterCommandFn,
&UnregisterCommandFn,
&SendCommandFn,
&SendCommandReplyFn,
&SendCommandEventFn
};
// The server needs a pointer to a pointer, and a persistent one
static const SQ_MOD_EXPORTS * g_SqModExportsPtr = &g_SqModExports;
// ------------------------------------------------------------------------------------------------
void InitExports()
{
// Tell the server about the pointer to the exports structure
_Func->ExportFunctions(_Info->pluginId, reinterpret_cast< const void ** >(&g_SqModExportsPtr), sizeof(HSQ_MOD_EXPORTS));
}
} // Namespace:: SqMod

View File

@ -351,6 +351,33 @@ Vector4 SqBuffer::ReadVector4() const
return {value}; return {value};
} }
// ------------------------------------------------------------------------------------------------
extern SQInteger SqFromNativeJSON(HSQUIRRELVM vm, const char * data, size_t size);
// ------------------------------------------------------------------------------------------------
SQInteger SqBuffer::GetJSON(HSQUIRRELVM vm) const
{
// Remember the current stack size
const SQInteger top = sq_gettop(vm);
// Was the JSON string size specified?
if (top < 2)
{
return sq_throwerror(vm, _SC("Please specify the size of the JSON string to parse"));
}
// Do we even point to a valid buffer?
if (!m_Buffer)
{
return sq_throwerror(vm, _SC("Invalid memory buffer reference"));
}
// Validate the buffer itself
else if (!(*m_Buffer))
{
return sq_throwerror(vm, _SC("Invalid memory buffer"));
}
// Attempt to create the JSON object and push it on the stack
return SqFromNativeJSON(vm, &m_Buffer->Cursor< char >(), static_cast< size_t >(Var< SQInteger >{vm, 2}.value));
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
SQInteger SqBuffer::GetCRC32(SQInteger n) const SQInteger SqBuffer::GetCRC32(SQInteger n) const
{ {
@ -500,6 +527,7 @@ void Register_Buffer(HSQUIRRELVM vm)
.Func(_SC("ADLER32"), &SqBuffer::GetADLER32) .Func(_SC("ADLER32"), &SqBuffer::GetADLER32)
.Func(_SC("Base32"), &SqBuffer::GetBase32) .Func(_SC("Base32"), &SqBuffer::GetBase32)
.Func(_SC("Base64"), &SqBuffer::GetBase64) .Func(_SC("Base64"), &SqBuffer::GetBase64)
.SquirrelMethod< SqBuffer, &SqBuffer::GetJSON >(_SC("GetJSON"))
); );
} }

View File

@ -782,6 +782,12 @@ public:
*/ */
SQMOD_NODISCARD Vector4 ReadVector4() const; SQMOD_NODISCARD Vector4 ReadVector4() const;
/* --------------------------------------------------------------------------------------------
* Transform a portion of the data in the buffer to a JSON object.
* This has the benefit that a temporary string doesn't have to be created.
*/
SQMOD_NODISCARD SQInteger GetJSON(HSQUIRRELVM vm) const;
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Compute the CRC-32 checksums on the data in the buffer. * Compute the CRC-32 checksums on the data in the buffer.
*/ */

View File

@ -149,6 +149,22 @@ static SQInteger SqFromJSON(HSQUIRRELVM vm) noexcept
return SQ_SUCCEEDED(r) ? 1 : r; return SQ_SUCCEEDED(r) ? 1 : r;
} }
// ------------------------------------------------------------------------------------------------
SQInteger SqFromNativeJSON(HSQUIRRELVM vm, const char * data, size_t size)
{
// Attempt to parse the specified JSON string
const sajson::document & document = sajson::parse(sajson::dynamic_allocation(), sajson::string(data, size));
// See if there was an error
if (!document.is_valid())
{
return sq_throwerror(vm, document.get_error_message_as_cstring());
}
// Process the nodes that were parsed from the string
SQInteger r = SqFromJson_Push(vm, document.get_root());
// We either have a value to return or we propagate some error
return SQ_SUCCEEDED(r) ? 1 : r;
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
CtxJSON & CtxJSON::OpenArray() CtxJSON & CtxJSON::OpenArray()
{ {

View File

@ -17,7 +17,7 @@ namespace SqMod {
static bool g_Reload = false; static bool g_Reload = false;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
//extern void InitExports(); extern void InitExports();
extern void InitializeNet(); extern void InitializeNet();
extern void InitializePocoDataConnectors(); extern void InitializePocoDataConnectors();
extern void ProcessRoutines(); extern void ProcessRoutines();
@ -97,7 +97,7 @@ static uint8_t OnServerInitialise()
{ {
SQMOD_SV_EV_TRACEBACK("[TRACE<] OnServerInitialise") SQMOD_SV_EV_TRACEBACK("[TRACE<] OnServerInitialise")
// Signal outside plug-ins to do fetch our proxies // Signal outside plug-ins to do fetch our proxies
//_Func->SendPluginCommand(0xDABBAD00, "%d", 1); _Func->SendPluginCommand(SQMOD_INITIALIZE_CMD, "%d", 1);
// Attempt to load the module core // Attempt to load the module core
if (Core::Get().Execute()) if (Core::Get().Execute())
{ {
@ -1083,7 +1083,7 @@ SQMOD_API_EXPORT unsigned int VcmpPluginInit(PluginFuncs * funcs, PluginCallback
_Clbk->OnEntityStreamingChange = OnEntityStreamingChange; _Clbk->OnEntityStreamingChange = OnEntityStreamingChange;
#endif #endif
// Attempt to initialize the plug-in exports // Attempt to initialize the plug-in exports
//InitExports(); InitExports();
// Dummy spacing // Dummy spacing
puts(""); puts("");
// Initialization was successful // Initialization was successful

View File

@ -1,6 +1,3 @@
#ifndef _REGISTER_HPP_
#define _REGISTER_HPP_
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
#include <squirrelex.h> #include <squirrelex.h>
@ -144,5 +141,3 @@ bool RegisterAPI(HSQUIRRELVM vm)
} }
} // Namespace:: SqMod } // Namespace:: SqMod
#endif // _REGISTER_HPP_

75
module/SDK/sqmod.h Normal file
View File

@ -0,0 +1,75 @@
#if !defined(_SQ_MOD_API_H_)
#define _SQ_MOD_API_H_
#include <stdint.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#ifndef SQMOD_API_EXPORT
#if defined(_MSC_VER)
#define SQMOD_API_EXPORT extern "C" __declspec(dllexport)
#elif defined(__GNUC__)
#define SQMOD_API_EXPORT extern "C"
#else
#define SQMOD_API_EXPORT extern "C"
#endif
#endif
#define SQMOD_HOST_NAME "SqModHost"
#define SQMOD_INITIALIZE_CMD 0xDABBAD00 // host plug-in was initialized
#define SQMOD_LOAD_CMD 0xDEADBABE // API is being registered
#define SQMOD_TERMINATE_CMD 0xDEADC0DE // release your resources
#define SQMOD_CLOSING_CMD 0xBAAAAAAD // virtual machine is closing
#define SQMOD_RELEASED_CMD 0xDEADBEAF // virtual machine was closed
#define SQMOD_API_VER 1
// --------------------------------------------------------------------------------------------
typedef int32_t(*ExtPluginCommand_t)(int32_t, int32_t, int32_t, const uint8_t *, size_t);
/* --------------------------------------------------------------------------------------------
* The structure exported by the host plug-in to import the module and squirrel API.
*/
typedef struct
{
uint32_t StructSize;
/* Register a pointer to a function used to processes commands from script.
This is like the functionality offered by SendPluginCommand but offers interaction from
script side without interfering with other native plugins. And also offers a few extra
methods of identification to provide back and forth communication.
It offers a bare minimum, primitive way of interacting with the script from native plug-ins.
return : -1 it failed (no free slot), 0 if it was already registered and 1 if it succeeded.
*/
int32_t (*RegisterCommand) (ExtPluginCommand_t fn);
/* Remove a pointer to a function used to processes commands from script.
return : -1 it failed (no free slot) and 1 if it succeeded.
*/
int32_t (*UnregisterCommand) (ExtPluginCommand_t fn);
/* Send a command to all functions currently registered to receive them. This is mostly used by the script.
target - ideally a unique value that can be used to identify the intended audience for the command.
req : ideally a unique value that can be used to identify the requested information from the command.
tag : ideally a unique value that can be used to identify a later response if one is generated.
data : binary data that represents the command payload. the command is free to interpret it however it wants.
size : size of the binary data. most likely in bytes but the command is free to interpret it however it wants.
*/
int32_t (*SendCommand) (int32_t target, int32_t req, int32_t tag, const uint8_t * data, size_t size);
/* Send a response to the script that may have resulted from a previous command. This is mostly by the native plug-ins.
sender : ideally a unique value that can be used to identify the intended who generated the response.
tag : ideally a unique value that can be used to identify what the generated response might contain/provide.
data : binary data that represents the command payload. the command is free to interpret it however it wants.
size : size of the binary data. most likely in bytes but the command is free to interpret it however it wants.
*/
int32_t (*SendCommandReply) (int32_t sender, int32_t tag, const uint8_t * data, size_t size);
/* Forward an event to the script from an external plug-in. This is mostly by the native plug-ins.
Similar to SendCommandReply but may not have been the result of a previous command.
*/
int32_t (*SendCommandEvent) (int32_t sender, int32_t tag, const uint8_t * data, size_t size);
} sq_mod_exports, SQ_MOD_EXPORTS, *HSQ_MOD_EXPORTS;
#ifdef __cplusplus
} /*extern "C"*/
#endif // __cplusplus
#endif /*_SQ_MOD_API_H_*/