2016-02-20 23:25:00 +01:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
2015-09-30 02:56:11 +02:00
|
|
|
#include "Core.hpp"
|
|
|
|
#include "Logger.hpp"
|
2021-01-30 07:51:39 +01:00
|
|
|
#include "Core/Areas.hpp"
|
|
|
|
#include "Core/Signal.hpp"
|
|
|
|
#include "Core/Buffer.hpp"
|
2021-03-27 18:53:49 +01:00
|
|
|
#include "Core/ThreadPool.hpp"
|
2021-01-30 07:51:39 +01:00
|
|
|
#include "Library/IO/Buffer.hpp"
|
2015-09-30 02:56:11 +02:00
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
#include "Entity/Blip.hpp"
|
|
|
|
#include "Entity/Checkpoint.hpp"
|
2021-01-30 07:51:39 +01:00
|
|
|
#include "Entity/KeyBind.hpp"
|
2016-02-20 23:25:00 +01:00
|
|
|
#include "Entity/Object.hpp"
|
|
|
|
#include "Entity/Pickup.hpp"
|
|
|
|
#include "Entity/Player.hpp"
|
|
|
|
#include "Entity/Vehicle.hpp"
|
2015-09-30 02:56:11 +02:00
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
#include <sqstdio.h>
|
|
|
|
#include <sqstdblob.h>
|
|
|
|
#include <sqstdmath.h>
|
|
|
|
#include <sqstdsystem.h>
|
|
|
|
#include <sqstdstring.h>
|
2016-02-20 23:25:00 +01:00
|
|
|
#include <SimpleIni.h>
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-05-22 05:20:38 +02:00
|
|
|
#include <cstdio>
|
|
|
|
#include <cstdarg>
|
2015-09-30 02:56:11 +02:00
|
|
|
#include <exception>
|
2016-02-20 23:25:00 +01:00
|
|
|
#include <stdexcept>
|
|
|
|
#include <algorithm>
|
2015-09-30 02:56:11 +02:00
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
namespace SqMod {
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
extern bool RegisterAPI(HSQUIRRELVM vm);
|
2015-09-30 02:56:11 +02:00
|
|
|
|
2016-02-23 04:23:56 +01:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
2021-02-02 18:07:02 +01:00
|
|
|
extern void ZmqTerminate();
|
2021-02-03 14:32:12 +01:00
|
|
|
extern void AnnounceTerminate();
|
2016-11-16 23:23:59 +01:00
|
|
|
extern void InitializeTasks();
|
2016-05-22 05:20:38 +02:00
|
|
|
extern void InitializeRoutines();
|
2017-06-19 03:09:35 +02:00
|
|
|
extern void TerminateAreas();
|
2016-11-16 23:23:59 +01:00
|
|
|
extern void TerminateTasks();
|
2021-02-05 12:32:37 +01:00
|
|
|
extern void TerminatePrivileges();
|
2016-05-22 05:20:38 +02:00
|
|
|
extern void TerminateRoutines();
|
2016-07-03 02:22:00 +02:00
|
|
|
extern void TerminateCommands();
|
2016-10-30 17:26:37 +01:00
|
|
|
extern void TerminateSignals();
|
2021-09-07 19:55:05 +02:00
|
|
|
extern void TerminateNet();
|
2021-09-05 17:15:02 +02:00
|
|
|
extern void TerminatePocoNet();
|
2021-02-08 11:11:47 +01:00
|
|
|
extern void TerminatePocoData();
|
2016-02-23 04:23:56 +01:00
|
|
|
|
2016-06-18 19:31:35 +02:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
2021-01-30 07:51:39 +01:00
|
|
|
extern Buffer GetRealFilePath(const SQChar * path);
|
2016-06-18 19:31:35 +02:00
|
|
|
|
2021-03-15 06:02:48 +01:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
#ifdef VCMP_ENABLE_OFFICIAL
|
|
|
|
extern void LgCheckpointSetID(LgCheckpoint * inst, int32_t id);
|
|
|
|
extern void LgObjectSetID(LgObject * inst, int32_t id);
|
|
|
|
extern void LgPickupSetID(LgPickup * inst, int32_t id);
|
|
|
|
extern void LgPlayerSetID(LgPlayer * inst, int32_t id);
|
|
|
|
extern void LgVehicleSetID(LgVehicle * inst, int32_t id);
|
|
|
|
extern LightObj LgCheckpointObj(HSQUIRRELVM vm, int32_t id);
|
|
|
|
extern LightObj LgObjectObj(HSQUIRRELVM vm, int32_t id);
|
|
|
|
extern LightObj LgPickupObj(HSQUIRRELVM vm, int32_t id);
|
|
|
|
extern LightObj LgPlayerObj(HSQUIRRELVM vm, int32_t id);
|
|
|
|
extern LightObj LgVehicleObj(HSQUIRRELVM vm, int32_t id);
|
2021-03-20 15:56:44 +01:00
|
|
|
extern void LgStreamLoadInput(const void * data, size_t size);
|
2021-03-15 06:02:48 +01:00
|
|
|
#endif
|
|
|
|
|
2016-06-18 19:31:35 +02:00
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
|
|
* Loader used to process a section from the configuration file and look for scripts to load.
|
|
|
|
*/
|
2021-07-03 18:46:39 +02:00
|
|
|
struct ScriptLoader
|
2016-06-18 19:31:35 +02:00
|
|
|
{
|
|
|
|
// --------------------------------------------------------------------------------------------
|
2021-07-03 18:46:39 +02:00
|
|
|
CSimpleIniA & m_Config; // The processed configuration.
|
|
|
|
Function m_Callback{}; // Null callback.
|
2021-07-04 01:19:37 +02:00
|
|
|
LightObj m_Context{}; // Callback context.
|
2016-06-18 19:31:35 +02:00
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
|
|
* Default constructor.
|
|
|
|
*/
|
2020-03-22 09:31:43 +01:00
|
|
|
explicit ScriptLoader(CSimpleIniA & conf)
|
2021-07-04 01:19:37 +02:00
|
|
|
: m_Config(conf), m_Callback(), m_Context()
|
2016-06-18 19:31:35 +02:00
|
|
|
{
|
|
|
|
/* ... */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
|
|
* Function call operator.
|
|
|
|
*/
|
2021-07-03 18:46:39 +02:00
|
|
|
bool operator () (const char * key, const char * val)
|
2016-06-18 19:31:35 +02:00
|
|
|
{
|
|
|
|
// Validate the specified key
|
|
|
|
if (!key || *key == '\0')
|
|
|
|
{
|
|
|
|
return true; // Move to the next element!
|
|
|
|
}
|
|
|
|
// Identify the load option
|
|
|
|
if (std::strcmp(key, "Section") == 0)
|
|
|
|
{
|
|
|
|
return m_Config.ProcAllValues(val, ScriptLoader(m_Config));
|
|
|
|
}
|
|
|
|
else if (std::strcmp(key, "Compile") == 0)
|
|
|
|
{
|
2021-07-04 01:19:37 +02:00
|
|
|
return Core::Get().LoadScript(val, m_Callback, m_Context, true);
|
2016-06-18 19:31:35 +02:00
|
|
|
}
|
|
|
|
else if (std::strcmp(key, "Execute") == 0)
|
|
|
|
{
|
2021-07-04 01:19:37 +02:00
|
|
|
return Core::Get().LoadScript(val, m_Callback, m_Context, false);
|
2016-06-18 19:31:35 +02:00
|
|
|
}
|
|
|
|
// Move to the next element!
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-07-16 14:45:36 +02:00
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
|
|
* Implements RAII to make sure that entity containers area cleaned up at all costs.
|
|
|
|
*/
|
2016-07-16 18:39:51 +02:00
|
|
|
class ContainerCleaner
|
2016-07-16 14:45:36 +02:00
|
|
|
{
|
|
|
|
// --------------------------------------------------------------------------------------------
|
2016-07-16 18:39:51 +02:00
|
|
|
EntityType m_Type; // The type of entity container to clear.
|
2016-07-16 14:45:36 +02:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
|
|
* Default constructor.
|
|
|
|
*/
|
2016-07-16 18:39:51 +02:00
|
|
|
template < typename T > ContainerCleaner(T & container, EntityType type, bool destroy)
|
2016-07-16 14:45:36 +02:00
|
|
|
: m_Type(type)
|
|
|
|
{
|
|
|
|
for (auto & ent : container)
|
|
|
|
{
|
2017-02-21 20:24:59 +01:00
|
|
|
ent.Destroy(destroy, SQMOD_DESTROY_CLEANUP, NullLightObj());
|
2016-07-16 14:45:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
|
|
* Destructor.
|
|
|
|
*/
|
|
|
|
~ContainerCleaner()
|
|
|
|
{
|
|
|
|
Core::Get().ClearContainer(m_Type);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-09-30 02:56:11 +02:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-05-22 05:20:38 +02:00
|
|
|
Core Core::s_Inst;
|
2016-03-24 04:28:55 +01:00
|
|
|
|
2015-09-30 02:56:11 +02:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
2020-03-22 09:31:43 +01:00
|
|
|
Core::Core() noexcept
|
2016-02-20 23:25:00 +01:00
|
|
|
: m_State(0)
|
2021-03-15 06:02:48 +01:00
|
|
|
#ifdef VCMP_ENABLE_OFFICIAL
|
|
|
|
, m_Official(false)
|
|
|
|
#endif
|
2016-03-24 05:43:02 +01:00
|
|
|
, m_VM(nullptr)
|
2016-02-20 23:25:00 +01:00
|
|
|
, m_Scripts()
|
2016-08-19 18:46:26 +02:00
|
|
|
, m_PendingScripts()
|
2016-02-20 23:25:00 +01:00
|
|
|
, m_Options()
|
2023-03-05 14:38:59 +01:00
|
|
|
, m_ExtCommands{nullptr, nullptr, nullptr, nullptr}
|
2016-02-20 23:25:00 +01:00
|
|
|
, m_Blips()
|
|
|
|
, m_Checkpoints()
|
2021-01-30 07:51:39 +01:00
|
|
|
, m_KeyBinds()
|
2016-02-20 23:25:00 +01:00
|
|
|
, m_Objects()
|
|
|
|
, m_Pickups()
|
|
|
|
, m_Players()
|
|
|
|
, m_Vehicles()
|
2017-02-21 20:24:59 +01:00
|
|
|
, m_Events()
|
2016-05-22 05:20:38 +02:00
|
|
|
, m_CircularLocks(0)
|
2016-05-24 18:26:43 +02:00
|
|
|
, m_ReloadHeader(0)
|
|
|
|
, m_ReloadPayload()
|
2016-05-22 05:20:38 +02:00
|
|
|
, m_IncomingNameBuffer(nullptr)
|
|
|
|
, m_IncomingNameCapacity(0)
|
2017-06-19 03:09:35 +02:00
|
|
|
, m_AreasEnabled(false)
|
2016-06-17 02:33:58 +02:00
|
|
|
, m_Debugging(false)
|
2016-06-18 19:31:35 +02:00
|
|
|
, m_Executed(false)
|
2016-07-16 18:39:51 +02:00
|
|
|
, m_Shutdown(false)
|
2016-08-25 02:08:44 +02:00
|
|
|
, m_LockPreLoadSignal(false)
|
|
|
|
, m_LockPostLoadSignal(false)
|
|
|
|
, m_LockUnloadSignal(false)
|
2016-08-27 11:15:51 +02:00
|
|
|
, m_EmptyInit(false)
|
2016-08-25 11:22:39 +02:00
|
|
|
, m_Verbosity(1)
|
2021-07-23 16:31:05 +02:00
|
|
|
, m_ClientData()
|
2020-05-04 17:50:33 +02:00
|
|
|
, m_NullBlip()
|
|
|
|
, m_NullCheckpoint()
|
2021-01-30 07:51:39 +01:00
|
|
|
, m_NullKeyBind()
|
2020-05-04 17:50:33 +02:00
|
|
|
, m_NullObject()
|
|
|
|
, m_NullPickup()
|
|
|
|
, m_NullPlayer()
|
|
|
|
, m_NullVehicle()
|
2015-09-30 02:56:11 +02:00
|
|
|
{
|
2016-05-22 05:20:38 +02:00
|
|
|
/* ... */
|
2015-09-30 02:56:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-02-20 23:25:00 +01:00
|
|
|
Core::~Core()
|
2015-09-30 02:56:11 +02:00
|
|
|
{
|
2016-05-22 05:20:38 +02:00
|
|
|
if (m_VM)
|
|
|
|
{
|
2016-07-16 16:52:55 +02:00
|
|
|
Terminate(true);
|
2016-05-22 05:20:38 +02:00
|
|
|
}
|
2015-09-30 02:56:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-05-22 05:20:38 +02:00
|
|
|
bool Core::Initialize()
|
2015-09-30 02:56:11 +02:00
|
|
|
{
|
2016-05-22 05:20:38 +02:00
|
|
|
// Make sure the plug-in was not already initialized
|
|
|
|
if (m_VM != nullptr)
|
2016-03-26 17:16:01 +01:00
|
|
|
{
|
2016-05-22 05:20:38 +02:00
|
|
|
OutputError("Plug-in was already initialized");
|
2016-02-20 23:25:00 +01:00
|
|
|
return true;
|
2016-03-26 17:16:01 +01:00
|
|
|
}
|
2016-02-20 23:25:00 +01:00
|
|
|
|
|
|
|
CSimpleIniA conf(false, true, true);
|
|
|
|
// Attempt to load the configurations from disk
|
|
|
|
SI_Error ini_ret = conf.LoadFile("sqmod.ini");
|
|
|
|
// See if the configurations could be loaded
|
|
|
|
if (ini_ret < 0)
|
2015-09-30 02:56:11 +02:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
switch (ini_ret)
|
|
|
|
{
|
|
|
|
case SI_FAIL:
|
2016-07-16 18:39:51 +02:00
|
|
|
{
|
2016-05-22 05:20:38 +02:00
|
|
|
OutputError("Failed to load the configuration file. Probably invalid");
|
2016-07-16 18:39:51 +02:00
|
|
|
} break;
|
2016-02-20 23:25:00 +01:00
|
|
|
case SI_NOMEM:
|
2016-07-16 18:39:51 +02:00
|
|
|
{
|
2016-05-22 05:20:38 +02:00
|
|
|
OutputError("Run out of memory while loading the configuration file");
|
2016-07-16 18:39:51 +02:00
|
|
|
} break;
|
2016-02-20 23:25:00 +01:00
|
|
|
case SI_FILE:
|
2016-07-16 18:39:51 +02:00
|
|
|
{
|
2016-05-22 05:20:38 +02:00
|
|
|
OutputError("Failed to load the configuration file. %s", std::strerror(errno));
|
2016-07-16 18:39:51 +02:00
|
|
|
} break;
|
|
|
|
default: OutputError("Failed to load the configuration file for some unforeseen reason");
|
2016-02-20 23:25:00 +01:00
|
|
|
}
|
|
|
|
// Failed to load the configuration file
|
|
|
|
return false;
|
2015-09-30 02:56:11 +02:00
|
|
|
}
|
2021-03-27 18:53:49 +01:00
|
|
|
// Attempt to initialize the thread pool
|
|
|
|
if (!ThreadPool::Get().Initialize(conf.GetLongValue("General", "WorkerThreads",
|
|
|
|
static_cast< long >(std::thread::hardware_concurrency()))))
|
|
|
|
{
|
|
|
|
ThreadPool::Get().Terminate();
|
|
|
|
return false;
|
2021-03-27 23:19:09 +01:00
|
|
|
} else cLogDbg(m_Verbosity >= 1, "Initialized %zu worker threads", ThreadPool::Get().GetThreadCount());
|
2021-03-15 06:02:48 +01:00
|
|
|
#ifdef VCMP_ENABLE_OFFICIAL
|
|
|
|
// See if debugging options should be enabled
|
|
|
|
m_Official = conf.GetBoolValue("Squirrel", "OfficialCompatibility", m_Official);
|
|
|
|
#endif
|
2019-06-16 01:51:16 +02:00
|
|
|
// See if debugging options should be enabled
|
|
|
|
m_Debugging = conf.GetBoolValue("Squirrel", "Debugging", m_Debugging);
|
2016-08-27 11:15:51 +02:00
|
|
|
// Configure the empty initialization
|
|
|
|
m_EmptyInit = conf.GetBoolValue("Squirrel", "EmptyInit", false);
|
2016-08-25 11:22:39 +02:00
|
|
|
// Configure the verbosity level
|
|
|
|
m_Verbosity = conf.GetLongValue("Log", "VerbosityLevel", 1);
|
2016-05-22 05:20:38 +02:00
|
|
|
// Initialize the log filename
|
|
|
|
Logger::Get().SetLogFilename(conf.GetValue("Log", "Filename", nullptr));
|
|
|
|
// Configure the logging timestamps
|
|
|
|
Logger::Get().ToggleConsoleTime(conf.GetBoolValue("Log", "ConsoleTimestamp", false));
|
|
|
|
Logger::Get().ToggleLogFileTime(conf.GetBoolValue("Log", "LogFileTimestamp", true));
|
|
|
|
// Apply the specified logging filters only after initialization was completed
|
|
|
|
Logger::Get().ToggleConsoleLevel(LOGL_DBG, conf.GetBoolValue("Log", "ConsoleDebug", true));
|
|
|
|
Logger::Get().ToggleConsoleLevel(LOGL_USR, conf.GetBoolValue("Log", "ConsoleUser", true));
|
|
|
|
Logger::Get().ToggleConsoleLevel(LOGL_SCS, conf.GetBoolValue("Log", "ConsoleSuccess", true));
|
|
|
|
Logger::Get().ToggleConsoleLevel(LOGL_INF, conf.GetBoolValue("Log", "ConsoleInfo", true));
|
|
|
|
Logger::Get().ToggleConsoleLevel(LOGL_WRN, conf.GetBoolValue("Log", "ConsoleWarning", true));
|
|
|
|
Logger::Get().ToggleConsoleLevel(LOGL_ERR, conf.GetBoolValue("Log", "ConsoleError", true));
|
|
|
|
Logger::Get().ToggleConsoleLevel(LOGL_FTL, conf.GetBoolValue("Log", "ConsoleFatal", true));
|
|
|
|
Logger::Get().ToggleLogFileLevel(LOGL_DBG, conf.GetBoolValue("Log", "LogFileDebug", true));
|
|
|
|
Logger::Get().ToggleLogFileLevel(LOGL_USR, conf.GetBoolValue("Log", "LogFileUser", true));
|
|
|
|
Logger::Get().ToggleLogFileLevel(LOGL_SCS, conf.GetBoolValue("Log", "LogFileSuccess", true));
|
|
|
|
Logger::Get().ToggleLogFileLevel(LOGL_INF, conf.GetBoolValue("Log", "LogFileInfo", true));
|
|
|
|
Logger::Get().ToggleLogFileLevel(LOGL_WRN, conf.GetBoolValue("Log", "LogFileWarning", true));
|
|
|
|
Logger::Get().ToggleLogFileLevel(LOGL_ERR, conf.GetBoolValue("Log", "LogFileError", true));
|
|
|
|
Logger::Get().ToggleLogFileLevel(LOGL_FTL, conf.GetBoolValue("Log", "LogFileFatal", true));
|
|
|
|
|
2016-08-25 11:22:39 +02:00
|
|
|
cLogDbg(m_Verbosity >= 1, "Resizing the entity containers");
|
2016-05-22 05:20:38 +02:00
|
|
|
// Make sure the entity containers have the proper size
|
|
|
|
m_Blips.resize(SQMOD_BLIP_POOL);
|
|
|
|
m_Checkpoints.resize(SQMOD_CHECKPOINT_POOL);
|
2021-01-30 07:51:39 +01:00
|
|
|
m_KeyBinds.resize(SQMOD_KEYBIND_POOL);
|
2016-05-22 05:20:38 +02:00
|
|
|
m_Objects.resize(SQMOD_OBJECT_POOL);
|
|
|
|
m_Pickups.resize(SQMOD_PICKUP_POOL);
|
|
|
|
m_Players.resize(SQMOD_PLAYER_POOL);
|
|
|
|
m_Vehicles.resize(SQMOD_VEHICLE_POOL);
|
|
|
|
|
|
|
|
// Attempt to read the virtual machine stack size
|
2021-01-30 07:51:39 +01:00
|
|
|
const long stack_size = conf.GetLongValue("Squirrel", "StackSize", SQMOD_STACK_SIZE);
|
2016-05-22 05:20:38 +02:00
|
|
|
// Make sure that the retrieved number is within range
|
|
|
|
if (!stack_size)
|
2016-02-20 23:25:00 +01:00
|
|
|
{
|
2016-05-22 05:20:38 +02:00
|
|
|
LogWrn("Invalid virtual machine stack size: %lu", stack_size);
|
|
|
|
// Stop the initialization process
|
|
|
|
return false;
|
2016-02-20 23:25:00 +01:00
|
|
|
}
|
2015-09-30 02:56:11 +02:00
|
|
|
|
2016-08-25 11:22:39 +02:00
|
|
|
cLogDbg(m_Verbosity >= 1, "Creating a virtual machine (%ld stack size)", stack_size);
|
2016-05-22 05:20:38 +02:00
|
|
|
// Attempt to create the script virtual machine
|
|
|
|
m_VM = sq_open(ConvTo< SQInteger >::From(stack_size));
|
2016-03-10 04:57:13 +01:00
|
|
|
// See if the virtual machine could be created
|
2016-02-20 23:25:00 +01:00
|
|
|
if (cLogFtl(!m_VM, "Unable to create the virtual machine"))
|
|
|
|
{
|
2016-05-22 05:20:38 +02:00
|
|
|
return false; // Unable to load the plug-in properly!
|
2016-02-20 23:25:00 +01:00
|
|
|
}
|
2016-05-22 05:20:38 +02:00
|
|
|
|
2016-03-10 04:57:13 +01:00
|
|
|
// Set this as the default VM
|
2016-02-20 23:25:00 +01:00
|
|
|
DefaultVM::Set(m_VM);
|
2016-05-22 05:20:38 +02:00
|
|
|
// Configure error handling
|
|
|
|
ErrorHandling::Enable(conf.GetBoolValue("Squirrel", "ErrorHandling", true));
|
2021-03-28 01:58:47 +01:00
|
|
|
// Create VM context instance
|
|
|
|
sq_setforeignptr(m_VM, new VMContext());
|
2016-02-20 23:25:00 +01:00
|
|
|
|
2016-07-03 02:27:18 +02:00
|
|
|
// Prevent common null objects from using dead virtual machines
|
|
|
|
NullArray() = Array();
|
|
|
|
NullTable() = Table();
|
|
|
|
NullObject() = Object();
|
2017-02-21 20:24:59 +01:00
|
|
|
NullLightObj() = LightObj();
|
2016-07-03 02:27:18 +02:00
|
|
|
NullFunction() = Function();
|
|
|
|
|
2016-08-25 11:22:39 +02:00
|
|
|
cLogDbg(m_Verbosity >= 1, "Registering the standard libraries");
|
2016-03-10 04:57:13 +01:00
|
|
|
// Push the root table on the stack
|
2016-02-20 23:25:00 +01:00
|
|
|
sq_pushroottable(m_VM);
|
2016-03-10 04:57:13 +01:00
|
|
|
// Register the standard library on the pushed table
|
2016-02-20 23:25:00 +01:00
|
|
|
sqstd_register_iolib(m_VM);
|
|
|
|
sqstd_register_bloblib(m_VM);
|
|
|
|
sqstd_register_mathlib(m_VM);
|
|
|
|
sqstd_register_systemlib(m_VM);
|
|
|
|
sqstd_register_stringlib(m_VM);
|
2016-03-10 04:57:13 +01:00
|
|
|
// Pop the root table from the stack
|
2016-02-20 23:25:00 +01:00
|
|
|
sq_pop(m_VM, 1);
|
|
|
|
|
2016-08-25 11:22:39 +02:00
|
|
|
cLogDbg(m_Verbosity >= 1, "Setting the script output function");
|
2016-03-10 04:57:13 +01:00
|
|
|
// Tell the VM to use these functions to output user on error messages
|
2016-02-20 23:25:00 +01:00
|
|
|
sq_setprintfunc(m_VM, PrintFunc, ErrorFunc);
|
|
|
|
|
2016-08-25 11:22:39 +02:00
|
|
|
cLogDbg(m_Verbosity >= 1, "Setting the script error handlers");
|
2016-03-10 04:57:13 +01:00
|
|
|
// Tell the VM to trigger this function on compile time errors
|
2016-02-20 23:25:00 +01:00
|
|
|
sq_setcompilererrorhandler(m_VM, CompilerErrorHandler);
|
2016-03-10 04:57:13 +01:00
|
|
|
// Push the runtime error handler on the stack and create a closure
|
2016-02-20 23:25:00 +01:00
|
|
|
sq_newclosure(m_VM, RuntimeErrorHandler, 0);
|
2016-03-10 04:57:13 +01:00
|
|
|
// Tell the VM to trigger this function on runtime errors
|
2016-02-20 23:25:00 +01:00
|
|
|
sq_seterrorhandler(m_VM);
|
|
|
|
|
2016-08-25 11:22:39 +02:00
|
|
|
cLogDbg(m_Verbosity >= 1, "Registering the plug-in API");
|
2016-05-22 05:20:38 +02:00
|
|
|
// Attempt to register the plug-in API
|
2020-05-04 17:50:33 +02:00
|
|
|
if (!RegisterAPI(m_VM))
|
2016-03-26 17:16:01 +01:00
|
|
|
{
|
2020-05-04 17:50:33 +02:00
|
|
|
LogFtl("Unable to register the plug-in API");
|
2016-03-10 04:57:13 +01:00
|
|
|
return false; // Can't execute scripts without a valid API!
|
2016-03-26 17:16:01 +01:00
|
|
|
}
|
2016-02-20 23:25:00 +01:00
|
|
|
|
2017-02-21 20:24:59 +01:00
|
|
|
// Initialize the module global events
|
|
|
|
InitEvents();
|
|
|
|
|
|
|
|
// Initialize load stage signals
|
|
|
|
InitSignalPair(mOnPreLoad, NullLightObj(), nullptr);
|
|
|
|
InitSignalPair(mOnPostLoad, NullLightObj(), nullptr);
|
|
|
|
InitSignalPair(mOnUnload, NullLightObj(), nullptr);
|
2021-07-04 04:17:32 +02:00
|
|
|
InitSignalPair(mOnScript, NullLightObj(), nullptr);
|
2017-02-21 20:24:59 +01:00
|
|
|
|
2016-06-18 19:31:35 +02:00
|
|
|
CSimpleIniA::TNamesDepend scripts;
|
|
|
|
// Attempt to retrieve the list of keys to make sure there's actually something to process
|
2020-05-06 00:20:39 +02:00
|
|
|
if (conf.GetAllKeys("Scripts", scripts) && !scripts.empty())
|
2016-02-20 23:25:00 +01:00
|
|
|
{
|
2016-06-18 19:31:35 +02:00
|
|
|
// Attempt to load the specified scripts
|
|
|
|
if (!conf.ProcAllValues("Scripts", ScriptLoader(conf)))
|
2016-03-26 17:16:01 +01:00
|
|
|
{
|
2016-06-18 19:31:35 +02:00
|
|
|
LogErr("Unable to load the specified scripts");
|
|
|
|
// Either no script was found or failed to load
|
|
|
|
return false;
|
2016-06-17 00:40:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-10 04:57:13 +01:00
|
|
|
// See if any script could be queued for loading
|
2016-08-27 11:15:51 +02:00
|
|
|
if (m_PendingScripts.empty() && !m_EmptyInit)
|
2016-02-20 23:25:00 +01:00
|
|
|
{
|
2016-03-10 04:57:13 +01:00
|
|
|
LogErr("No scripts loaded. No reason to load the plug-in");
|
2016-02-20 23:25:00 +01:00
|
|
|
// No point in loading the plug-in
|
2015-09-30 02:56:11 +02:00
|
|
|
return false;
|
|
|
|
}
|
2016-05-22 05:20:38 +02:00
|
|
|
|
2016-08-25 11:22:39 +02:00
|
|
|
cLogDbg(m_Verbosity >= 1, "Reading the options from the general section");
|
2016-03-10 04:57:13 +01:00
|
|
|
// Read options only after loading was successful
|
2016-02-20 23:25:00 +01:00
|
|
|
CSimpleIniA::TNamesDepend options;
|
2016-03-10 04:57:13 +01:00
|
|
|
// Are there any options to read?
|
2020-05-06 00:20:39 +02:00
|
|
|
if (conf.GetAllKeys("Options", options) || !options.empty())
|
2016-02-20 23:25:00 +01:00
|
|
|
{
|
2019-08-17 14:52:04 +02:00
|
|
|
cLogDbg(m_Verbosity >= 1, "Found (%" PRINT_SZ_FMT ") options in the configuration file",
|
|
|
|
static_cast< SQUnsignedInteger >(options.size()));
|
2016-02-20 23:25:00 +01:00
|
|
|
// Process all the specified keys under the [Options] section
|
2016-03-10 04:57:13 +01:00
|
|
|
for (const auto & option : options)
|
2016-02-20 23:25:00 +01:00
|
|
|
{
|
2016-03-10 04:57:13 +01:00
|
|
|
CSimpleIniA::TNamesDepend values;
|
|
|
|
// Get the values of all keys with the same name
|
|
|
|
if (!conf.GetAllValues("Options", option.pItem, values))
|
2016-03-26 17:16:01 +01:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
continue;
|
2016-03-26 17:16:01 +01:00
|
|
|
}
|
2016-02-20 23:25:00 +01:00
|
|
|
// Sort the keys in their original order
|
2016-03-10 04:57:13 +01:00
|
|
|
values.sort(CSimpleIniA::Entry::LoadOrder());
|
|
|
|
// Save each option option and overwrite existing value
|
|
|
|
for (const auto & value : values)
|
2016-03-26 17:16:01 +01:00
|
|
|
{
|
2016-03-10 04:57:13 +01:00
|
|
|
m_Options[option.pItem] = value.pItem;
|
2016-03-26 17:16:01 +01:00
|
|
|
}
|
2016-02-20 23:25:00 +01:00
|
|
|
}
|
|
|
|
}
|
2015-09-30 02:56:11 +02:00
|
|
|
|
2016-11-16 23:23:59 +01:00
|
|
|
// Initialize routines and tasks
|
2016-05-22 05:20:38 +02:00
|
|
|
InitializeRoutines();
|
2016-11-16 23:23:59 +01:00
|
|
|
InitializeTasks();
|
2020-04-17 16:42:09 +02:00
|
|
|
// Initialize third-party
|
2016-02-20 23:25:00 +01:00
|
|
|
|
|
|
|
// Initialization successful
|
2015-09-30 02:56:11 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-02-20 23:25:00 +01:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-05-22 05:20:38 +02:00
|
|
|
bool Core::Execute()
|
2015-09-30 02:56:11 +02:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
// Are there any scripts to execute?
|
2016-08-27 11:15:51 +02:00
|
|
|
if (m_PendingScripts.empty())
|
2016-05-22 05:20:38 +02:00
|
|
|
{
|
2016-08-27 11:15:51 +02:00
|
|
|
// Are we allowed to continue without any scripts?
|
|
|
|
if (m_EmptyInit)
|
|
|
|
{
|
|
|
|
LogWrn("No scripts to execute. Empty initialization was forced");
|
|
|
|
// Allow empty initialization since it was requested
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
LogWrn("No scripts to execute. Plug-in has no purpose");
|
|
|
|
// No reason to execute the plug-in
|
|
|
|
return false;
|
2016-05-22 05:20:38 +02:00
|
|
|
}
|
2016-03-10 04:57:13 +01:00
|
|
|
|
2016-08-25 02:08:44 +02:00
|
|
|
// Unlock signal containers
|
|
|
|
m_LockPreLoadSignal = false;
|
|
|
|
m_LockPostLoadSignal = false;
|
|
|
|
m_LockUnloadSignal = false;
|
|
|
|
|
2023-03-05 14:38:59 +01:00
|
|
|
cLogDbg(m_Verbosity >= 1, "Signaling outside plug-ins that the API is being registered");
|
2016-05-22 05:20:38 +02:00
|
|
|
// Tell modules to do their monkey business
|
2023-03-05 16:00:39 +01:00
|
|
|
_Func->SendPluginCommand(SQMOD_LOAD_CMD, "");
|
2016-02-27 10:57:10 +01:00
|
|
|
|
2016-08-19 18:46:26 +02:00
|
|
|
// Load pending scripts while we're in the bounds of the allowed recursiveness
|
2020-05-04 17:50:33 +02:00
|
|
|
for (unsigned levels = 0; !m_PendingScripts.empty() && (levels < 8); ++levels)
|
2016-06-18 12:09:08 +02:00
|
|
|
{
|
2016-08-19 18:46:26 +02:00
|
|
|
// Remember the last script from the pool
|
|
|
|
const Scripts::size_type last = m_Scripts.size();
|
|
|
|
// Push pending scripts to the back of the list
|
|
|
|
std::move(m_PendingScripts.begin(), m_PendingScripts.end(), std::back_inserter(m_Scripts));
|
|
|
|
// Clear all pending scripts, if any
|
|
|
|
m_PendingScripts.clear();
|
|
|
|
// Process all pending scripts
|
2020-05-04 17:50:33 +02:00
|
|
|
if (!DoScripts(m_Scripts.begin() + last, m_Scripts.end()))
|
2016-06-18 19:31:35 +02:00
|
|
|
{
|
2016-08-19 18:46:26 +02:00
|
|
|
return false; // One of the scripts failed to execute
|
2016-03-10 04:57:13 +01:00
|
|
|
}
|
2016-09-11 19:48:20 +02:00
|
|
|
|
2019-08-17 14:43:50 +02:00
|
|
|
cLogDbg(m_Verbosity >= 2, "Completed execution of stage (%u) scripts. Pending scripts %" PRINT_SZ_FMT,
|
2019-08-17 14:52:04 +02:00
|
|
|
levels, static_cast< SQUnsignedInteger >(m_PendingScripts.size()));
|
2016-02-20 23:25:00 +01:00
|
|
|
}
|
2020-03-21 12:54:38 +01:00
|
|
|
// Force enable null entities if not already enabled by script
|
|
|
|
EnableNullEntities();
|
2016-03-24 07:44:01 +01:00
|
|
|
|
2021-01-17 10:22:53 +01:00
|
|
|
// At this point, the scripts were executed
|
|
|
|
m_Executed = true;
|
|
|
|
|
2016-08-25 02:08:44 +02:00
|
|
|
m_LockPreLoadSignal = true;
|
2017-02-21 20:24:59 +01:00
|
|
|
// Trigger callbacks that must initialize stuff before the loaded event is triggered
|
|
|
|
(*mOnPreLoad.first)();
|
|
|
|
// Clear the callbacks
|
|
|
|
ResetSignalPair(mOnPreLoad);
|
2016-08-25 02:08:44 +02:00
|
|
|
|
2016-06-26 15:30:19 +02:00
|
|
|
// Notify the script callback that the scripts were loaded
|
|
|
|
EmitScriptLoaded();
|
|
|
|
|
2016-08-25 02:08:44 +02:00
|
|
|
m_LockPostLoadSignal = true;
|
2017-02-21 20:24:59 +01:00
|
|
|
// Trigger callbacks that must initialize stuff after the loaded event is triggered
|
|
|
|
(*mOnPostLoad.first)();
|
|
|
|
// Clear the callbacks
|
|
|
|
ResetSignalPair(mOnPostLoad);
|
2016-08-25 02:08:44 +02:00
|
|
|
|
2016-03-24 07:44:01 +01:00
|
|
|
// Import already existing entities
|
|
|
|
ImportPlayers();
|
|
|
|
ImportBlips();
|
|
|
|
ImportCheckpoints();
|
2021-01-30 07:51:39 +01:00
|
|
|
ImportKeyBinds();
|
2016-03-24 07:44:01 +01:00
|
|
|
ImportObjects();
|
|
|
|
ImportPickups();
|
|
|
|
ImportVehicles();
|
2021-01-17 10:22:53 +01:00
|
|
|
|
2021-07-04 13:08:03 +02:00
|
|
|
cLogDbg(m_Executed && m_Verbosity >= 2, "Successfully executed specified scripts");
|
2016-05-22 05:20:38 +02:00
|
|
|
// Successfully executed
|
2021-01-17 10:22:53 +01:00
|
|
|
return m_Executed;
|
2015-09-30 02:56:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-07-16 16:52:55 +02:00
|
|
|
void Core::Terminate(bool shutdown)
|
2015-09-30 02:56:11 +02:00
|
|
|
{
|
2016-07-16 18:39:51 +02:00
|
|
|
m_Shutdown = shutdown;
|
|
|
|
// Is there a virtual machine present?
|
2016-05-22 05:20:38 +02:00
|
|
|
if (m_VM)
|
|
|
|
{
|
2016-08-25 02:08:44 +02:00
|
|
|
m_LockUnloadSignal = true;
|
2017-02-21 20:24:59 +01:00
|
|
|
// Trigger callbacks that must de-initialize stuff before the scripts are unloaded
|
|
|
|
(*mOnUnload.first)();
|
|
|
|
// Clear the callbacks
|
|
|
|
ResetSignalPair(mOnUnload);
|
2016-08-25 02:08:44 +02:00
|
|
|
|
2023-03-05 14:38:59 +01:00
|
|
|
cLogDbg(m_Verbosity >= 1, "Signaling outside plug-ins to release their resources");
|
2016-05-22 05:20:38 +02:00
|
|
|
// Tell modules to do their monkey business
|
2023-03-05 16:00:39 +01:00
|
|
|
_Func->SendPluginCommand(SQMOD_TERMINATE_CMD, "");
|
2016-05-22 05:20:38 +02:00
|
|
|
}
|
2021-07-04 04:17:32 +02:00
|
|
|
|
2016-08-25 11:22:39 +02:00
|
|
|
cLogDbg(m_Verbosity >= 1, "Clearing the entity containers");
|
2016-02-20 23:25:00 +01:00
|
|
|
// Release all entity resources by clearing the containers
|
2016-07-16 18:39:51 +02:00
|
|
|
const ContainerCleaner cc_players(m_Players, ENT_PLAYER, !shutdown);
|
|
|
|
const ContainerCleaner cc_vehicles(m_Vehicles, ENT_VEHICLE, !shutdown);
|
|
|
|
const ContainerCleaner cc_objects(m_Objects, ENT_OBJECT, !shutdown);
|
|
|
|
const ContainerCleaner cc_pickups(m_Pickups, ENT_PICKUP, !shutdown);
|
|
|
|
const ContainerCleaner cc_checkpoints(m_Checkpoints, ENT_CHECKPOINT, !shutdown);
|
|
|
|
const ContainerCleaner cc_blips(m_Blips, ENT_BLIP, !shutdown);
|
2021-01-30 07:51:39 +01:00
|
|
|
const ContainerCleaner cc_keybinds(m_KeyBinds, ENT_KEYBIND, !shutdown);
|
2020-04-20 03:46:05 +02:00
|
|
|
|
2021-03-27 23:19:09 +01:00
|
|
|
// Terminate the thread pool
|
|
|
|
ThreadPool::Get().Terminate();
|
|
|
|
cLogDbg(m_Verbosity >= 1, "Thread pool terminated");
|
2016-11-16 23:23:59 +01:00
|
|
|
// Release all resources from routines and tasks
|
2016-05-22 05:20:38 +02:00
|
|
|
TerminateRoutines();
|
2021-03-27 23:19:09 +01:00
|
|
|
cLogDbg(m_Verbosity >= 2, "Routines terminated");
|
2016-11-16 23:23:59 +01:00
|
|
|
TerminateTasks();
|
2021-03-27 23:19:09 +01:00
|
|
|
cLogDbg(m_Verbosity >= 2, "Tasks terminated");
|
2016-07-03 02:22:00 +02:00
|
|
|
// Release all resources from command managers
|
|
|
|
TerminateCommands();
|
2021-03-27 23:19:09 +01:00
|
|
|
cLogDbg(m_Verbosity >= 2, "Commands terminated");
|
2016-10-30 17:26:37 +01:00
|
|
|
// Release all resources from signals
|
|
|
|
TerminateSignals();
|
2021-03-27 23:19:09 +01:00
|
|
|
cLogDbg(m_Verbosity >= 2, "Signals terminated");
|
2017-06-19 03:09:35 +02:00
|
|
|
// Release all managed areas
|
|
|
|
TerminateAreas();
|
2021-03-27 23:19:09 +01:00
|
|
|
cLogDbg(m_Verbosity >= 2, "Areas terminated");
|
2020-05-11 16:51:39 +02:00
|
|
|
// Release privilege managers
|
2021-02-05 12:32:37 +01:00
|
|
|
TerminatePrivileges();
|
2021-03-27 23:19:09 +01:00
|
|
|
cLogDbg(m_Verbosity >= 2, "Privileges terminated");
|
2021-02-03 14:32:12 +01:00
|
|
|
// Release announcers
|
|
|
|
AnnounceTerminate();
|
2021-03-27 23:19:09 +01:00
|
|
|
cLogDbg(m_Verbosity >= 1, "Announcer terminated");
|
2021-09-07 19:55:05 +02:00
|
|
|
// Release network
|
|
|
|
TerminateNet();
|
|
|
|
cLogDbg(m_Verbosity >= 1, "Network terminated");
|
2021-02-08 11:11:47 +01:00
|
|
|
// Release Poco statement results
|
2021-09-05 17:15:02 +02:00
|
|
|
TerminatePocoNet();
|
2021-02-08 11:11:47 +01:00
|
|
|
TerminatePocoData();
|
2021-03-27 23:19:09 +01:00
|
|
|
cLogDbg(m_Verbosity >= 1, "Poco terminated");
|
2021-02-02 18:07:02 +01:00
|
|
|
// Release ZMQ sockets
|
|
|
|
ZmqTerminate();
|
2021-03-27 23:19:09 +01:00
|
|
|
cLogDbg(m_Verbosity >= 1, "ZMQ terminated");
|
2016-03-24 08:32:44 +01:00
|
|
|
// In case there's a payload for reload
|
2016-05-24 18:26:43 +02:00
|
|
|
m_ReloadPayload.Release();
|
2016-05-22 05:20:38 +02:00
|
|
|
// Release null objects in case any reference to valid objects is stored in them
|
|
|
|
NullArray().Release();
|
|
|
|
NullTable().Release();
|
|
|
|
NullObject().Release();
|
2017-02-21 20:24:59 +01:00
|
|
|
NullLightObj().Release();
|
2020-04-27 12:10:54 +02:00
|
|
|
NullFunction().Release();
|
2021-07-23 16:31:05 +02:00
|
|
|
// Release client data buffer, if any
|
|
|
|
m_ClientData.Release();
|
2016-08-07 00:54:33 +02:00
|
|
|
// Release null entity instances
|
|
|
|
m_NullBlip.Release();
|
|
|
|
m_NullCheckpoint.Release();
|
2021-01-30 07:51:39 +01:00
|
|
|
m_NullKeyBind.Release();
|
2016-08-07 00:54:33 +02:00
|
|
|
m_NullObject.Release();
|
|
|
|
m_NullPickup.Release();
|
|
|
|
m_NullPlayer.Release();
|
|
|
|
m_NullVehicle.Release();
|
2021-03-27 23:19:09 +01:00
|
|
|
cLogDbg(m_Verbosity >= 2, "Temporary script objects released");
|
2016-02-20 23:25:00 +01:00
|
|
|
// Is there a VM to close?
|
|
|
|
if (m_VM)
|
|
|
|
{
|
2016-09-04 00:27:00 +02:00
|
|
|
cLogDbg(m_Verbosity >= 1, "Releasing any final resources and all loaded scripts");
|
2016-02-20 23:25:00 +01:00
|
|
|
// Release all script callbacks
|
2021-07-04 04:17:32 +02:00
|
|
|
ResetSignalPair(mOnScript);
|
2017-02-21 20:24:59 +01:00
|
|
|
DropEvents();
|
2016-02-20 23:25:00 +01:00
|
|
|
// Release the script instances
|
|
|
|
m_Scripts.clear();
|
2016-08-19 18:46:26 +02:00
|
|
|
m_PendingScripts.clear(); // Just in case
|
2016-06-18 19:31:35 +02:00
|
|
|
// Specify that no scripts are left executed
|
|
|
|
m_Executed = false;
|
2021-03-28 01:58:47 +01:00
|
|
|
// Retrieve the VM context before closing
|
|
|
|
VMContext * ctx = GetVMContext(m_VM);
|
2016-05-22 05:20:38 +02:00
|
|
|
// Assertions during close may cause double delete/close!
|
2016-02-20 23:25:00 +01:00
|
|
|
HSQUIRRELVM sq_vm = m_VM;
|
2016-03-24 05:43:02 +01:00
|
|
|
m_VM = nullptr;
|
2016-09-02 13:11:39 +02:00
|
|
|
|
2023-03-05 14:38:59 +01:00
|
|
|
cLogDbg(m_Verbosity >= 1, "Signaling outside plug-ins the virtual machine is closing");
|
2016-09-02 13:11:39 +02:00
|
|
|
// Tell modules to do their monkey business
|
2023-03-05 16:00:39 +01:00
|
|
|
_Func->SendPluginCommand(SQMOD_CLOSING_CMD, "");
|
2019-05-01 17:00:24 +02:00
|
|
|
// Release any callbacks from the logger
|
|
|
|
Logger::Get().Release();
|
2021-03-28 01:58:47 +01:00
|
|
|
cLogDbg(m_Verbosity >= 2, "Closing Virtual Machine");
|
|
|
|
// Release class object references before closing the VM
|
|
|
|
for (auto & c : ctx->classes)
|
|
|
|
{
|
|
|
|
c.second->Release();
|
|
|
|
}
|
2016-02-20 23:25:00 +01:00
|
|
|
// Attempt to close the VM
|
|
|
|
sq_close(sq_vm);
|
2021-03-28 01:58:47 +01:00
|
|
|
// Reset class objects before destructor is invoked
|
|
|
|
for (auto & c : ctx->classes)
|
|
|
|
{
|
|
|
|
c.second->Reset();
|
|
|
|
}
|
|
|
|
// Go through each class and check for leftover objects
|
|
|
|
for (auto & c : ctx->classes)
|
|
|
|
{
|
|
|
|
// Retrieve the number of elements left in the container
|
|
|
|
size_t n = c.second->InstanceCount();
|
|
|
|
// Log however many are left, if any
|
|
|
|
if (n != 0)
|
|
|
|
{
|
|
|
|
cLogDbg(m_Verbosity >= 1, "%zu leaked (%s) objects", n, c.first.c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cLogDbg(m_Verbosity >= 2, "Destroying VM Context");
|
|
|
|
// Destroy the VM context, if any
|
|
|
|
delete ctx;
|
2016-06-26 15:18:23 +02:00
|
|
|
|
2023-03-05 14:38:59 +01:00
|
|
|
cLogDbg(m_Verbosity >= 1, "Signaling outside plug-ins the virtual machine was closed");
|
2016-06-26 15:18:23 +02:00
|
|
|
// Tell modules to do their monkey business
|
2023-03-05 16:00:39 +01:00
|
|
|
_Func->SendPluginCommand(SQMOD_RELEASED_CMD, "");
|
2016-02-20 23:25:00 +01:00
|
|
|
}
|
2016-07-16 14:45:36 +02:00
|
|
|
|
2016-08-25 11:22:39 +02:00
|
|
|
OutputMessage("Squirrel plug-in was successfully terminated");
|
2015-09-30 02:56:11 +02:00
|
|
|
}
|
|
|
|
|
2016-05-24 05:51:40 +02:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
2016-05-24 18:26:43 +02:00
|
|
|
bool Core::Reload()
|
2016-05-24 05:51:40 +02:00
|
|
|
{
|
|
|
|
// Are we already reloading?
|
|
|
|
if (m_CircularLocks & CCL_RELOAD_SCRIPTS)
|
|
|
|
{
|
|
|
|
return false; // Already reloading!
|
|
|
|
}
|
2016-06-03 20:26:19 +02:00
|
|
|
// Prevent circular reloads when we send plug-in commands
|
2021-01-30 07:51:39 +01:00
|
|
|
const BitGuardU32 bg(m_CircularLocks, static_cast< uint32_t >(CCL_RELOAD_SCRIPTS));
|
2016-05-24 05:51:40 +02:00
|
|
|
// Allow reloading by default
|
|
|
|
Core::Get().SetState(1);
|
|
|
|
// Emit the reload event
|
2016-05-24 18:26:43 +02:00
|
|
|
Core::Get().EmitScriptReload(m_ReloadHeader, m_ReloadPayload);
|
2016-05-24 05:51:40 +02:00
|
|
|
// Are we allowed to reload?
|
|
|
|
if (!Core::Get().GetState())
|
|
|
|
{
|
|
|
|
return false; // Request denied!
|
|
|
|
}
|
|
|
|
// Terminate the current VM and release resources
|
2016-07-16 16:52:55 +02:00
|
|
|
Terminate(false);
|
2016-05-24 18:26:43 +02:00
|
|
|
// Reset the reload header after termination
|
|
|
|
m_ReloadHeader = -1;
|
|
|
|
// Attempt to initialize the central core and load resources
|
|
|
|
return (Initialize() && Execute());
|
2016-05-24 05:51:40 +02:00
|
|
|
}
|
|
|
|
|
2020-03-21 12:54:38 +01:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
void Core::EnableNullEntities()
|
|
|
|
{
|
|
|
|
// Create the null entity instances
|
2020-05-04 17:50:33 +02:00
|
|
|
if (m_NullBlip.IsNull()) m_NullBlip = LightObj(DeleteGuard< CBlip >(new CBlip(-1)));
|
|
|
|
if (m_NullCheckpoint.IsNull()) m_NullCheckpoint = LightObj(DeleteGuard< CCheckpoint >(new CCheckpoint(-1)));
|
2021-01-30 07:51:39 +01:00
|
|
|
if (m_NullKeyBind.IsNull()) m_NullKeyBind = LightObj(DeleteGuard< CKeyBind >(new CKeyBind(-1)));
|
2020-05-04 17:50:33 +02:00
|
|
|
if (m_NullObject.IsNull()) m_NullObject = LightObj(DeleteGuard< CObject >(new CObject(-1)));
|
|
|
|
if (m_NullPickup.IsNull()) m_NullPickup = LightObj(DeleteGuard< CPickup >(new CPickup(-1)));
|
|
|
|
if (m_NullPlayer.IsNull()) m_NullPlayer = LightObj(DeleteGuard< CPlayer >(new CPlayer(-1)));
|
|
|
|
if (m_NullVehicle.IsNull()) m_NullVehicle = LightObj(DeleteGuard< CVehicle >(new CVehicle(-1)));
|
2020-03-21 12:54:38 +01:00
|
|
|
}
|
|
|
|
|
2015-09-30 02:56:11 +02:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
2020-05-10 11:56:23 +02:00
|
|
|
const String & Core::GetOption(const String & name) const
|
2015-09-30 02:56:11 +02:00
|
|
|
{
|
2020-05-06 00:20:39 +02:00
|
|
|
auto elem = m_Options.find(name);
|
2020-05-10 11:56:23 +02:00
|
|
|
return (elem == m_Options.end()) ? NullString() : elem->second;
|
2015-09-30 02:56:11 +02:00
|
|
|
}
|
|
|
|
|
2016-03-11 19:04:26 +01:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
2020-05-10 11:56:23 +02:00
|
|
|
const String & Core::GetOption(const String & name, const String & value) const
|
2016-03-11 19:04:26 +01:00
|
|
|
{
|
2020-05-06 00:20:39 +02:00
|
|
|
auto elem = m_Options.find(name);
|
2020-05-10 11:56:23 +02:00
|
|
|
return (elem == m_Options.end()) ? value : elem->second;
|
2016-03-11 19:04:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2020-05-10 11:56:23 +02:00
|
|
|
void Core::SetOption(const String & name, const String & value)
|
2015-09-30 02:56:11 +02:00
|
|
|
{
|
2016-02-20 23:25:00 +01:00
|
|
|
m_Options[name] = value;
|
2015-09-30 02:56:11 +02:00
|
|
|
}
|
|
|
|
|
2019-06-16 01:12:51 +02:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
2021-01-30 07:51:39 +01:00
|
|
|
Core::Scripts::iterator Core::FindScript(const SQChar * src)
|
2019-06-16 01:12:51 +02:00
|
|
|
{
|
|
|
|
// Iterate over loaded scripts
|
2020-05-06 00:20:39 +02:00
|
|
|
for (auto itr = m_Scripts.begin(); itr != m_Scripts.end(); ++itr)
|
2019-06-16 01:12:51 +02:00
|
|
|
{
|
|
|
|
// Is this script the source we're looking for?
|
|
|
|
if (itr->mPath.compare(0, String::npos, src) == 0)
|
|
|
|
{
|
|
|
|
return itr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Not found!
|
|
|
|
return m_Scripts.end();
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2021-01-30 07:51:39 +01:00
|
|
|
Core::Scripts::iterator Core::FindPendingScript(const SQChar * src)
|
2019-06-16 01:12:51 +02:00
|
|
|
{
|
|
|
|
// Iterate over loaded scripts
|
2020-05-06 00:20:39 +02:00
|
|
|
for (auto itr = m_PendingScripts.begin(); itr != m_PendingScripts.end(); ++itr)
|
2019-06-16 01:12:51 +02:00
|
|
|
{
|
|
|
|
// Is this script the source we're looking for?
|
|
|
|
if (itr->mPath.compare(0, String::npos, src) == 0)
|
|
|
|
{
|
|
|
|
return itr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Not found!
|
|
|
|
return m_PendingScripts.end();
|
|
|
|
}
|
|
|
|
|
2016-03-10 04:57:13 +01:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
2021-07-04 01:19:37 +02:00
|
|
|
bool Core::LoadScript(const SQChar * filepath, Function & cb, LightObj & ctx, bool delay)
|
2016-03-10 04:57:13 +01:00
|
|
|
{
|
|
|
|
// Is the specified path empty?
|
2016-05-22 05:20:38 +02:00
|
|
|
if (!filepath || *filepath == '\0')
|
2016-03-26 17:16:01 +01:00
|
|
|
{
|
2016-06-18 19:31:35 +02:00
|
|
|
LogErr("Cannot load script with empty or invalid path");
|
|
|
|
// Failed to load
|
|
|
|
return false;
|
|
|
|
}
|
2016-08-19 18:46:26 +02:00
|
|
|
|
2016-06-18 19:31:35 +02:00
|
|
|
Buffer bpath;
|
|
|
|
// Attempt to get the real file path
|
|
|
|
try
|
|
|
|
{
|
|
|
|
bpath = GetRealFilePath(filepath);
|
|
|
|
}
|
|
|
|
catch (const std::exception & e)
|
|
|
|
{
|
|
|
|
LogErr("Unable to load script: %s", e.what());
|
|
|
|
// Failed to load
|
|
|
|
return false;
|
|
|
|
}
|
2016-08-19 18:46:26 +02:00
|
|
|
|
2016-06-18 19:31:35 +02:00
|
|
|
// Make the path into a string
|
|
|
|
String path(bpath.Data(), bpath.Position());
|
2016-08-19 18:46:26 +02:00
|
|
|
|
2016-03-10 04:57:13 +01:00
|
|
|
// See if it wasn't already loaded
|
2016-06-17 02:28:37 +02:00
|
|
|
if (std::find_if(m_Scripts.cbegin(), m_Scripts.cend(), [&path](Scripts::const_reference s) {
|
2021-07-04 12:59:00 +02:00
|
|
|
#ifdef SQMOD_OS_WINDOWS
|
|
|
|
// Windows does not have case sensitive filenames and we can end up trying to load the same file more than once
|
|
|
|
return s.mPath.size() == path.size() && strnicmp(s.mPath.c_str(), path.c_str(), path.size()) == 0;
|
|
|
|
#else
|
2016-06-17 02:28:37 +02:00
|
|
|
return (s.mPath == path);
|
2021-07-04 12:59:00 +02:00
|
|
|
#endif
|
2016-06-17 02:28:37 +02:00
|
|
|
}) != m_Scripts.end())
|
2021-03-27 18:53:49 +01:00
|
|
|
{ // NOLINT(bugprone-branch-clone)
|
2016-03-10 04:57:13 +01:00
|
|
|
LogWrn("Script was specified before: %s", path.c_str());
|
2021-07-04 12:59:00 +02:00
|
|
|
return false; // We didn't actually fail to load it
|
2016-03-26 17:16:01 +01:00
|
|
|
}
|
2016-08-19 18:46:26 +02:00
|
|
|
// Also check the pending scripts container
|
|
|
|
else if (std::find_if(m_PendingScripts.cbegin(), m_PendingScripts.cend(), [&path](Scripts::const_reference s) {
|
2021-07-04 12:59:00 +02:00
|
|
|
#ifdef SQMOD_OS_WINDOWS
|
|
|
|
// Windows does not have case sensitive filenames and we can end up trying to load the same file more than once
|
|
|
|
return s.mPath.size() == path.size() && strnicmp(s.mPath.c_str(), path.c_str(), path.size()) == 0;
|
|
|
|
#else
|
2016-08-19 18:46:26 +02:00
|
|
|
return (s.mPath == path);
|
2021-07-04 12:59:00 +02:00
|
|
|
#endif
|
2016-08-19 18:46:26 +02:00
|
|
|
}) != m_PendingScripts.end())
|
|
|
|
{
|
|
|
|
LogWrn("Script was specified before: %s", path.c_str());
|
2021-07-04 12:59:00 +02:00
|
|
|
return false; // We didn't actually fail to load it
|
2016-08-19 18:46:26 +02:00
|
|
|
}
|
2016-06-18 19:31:35 +02:00
|
|
|
// Were the scripts already executed? Then there's no need to queue them
|
|
|
|
else if (m_Executed)
|
|
|
|
{
|
|
|
|
// Create a new script container and insert it into the script pool
|
2021-07-04 01:19:37 +02:00
|
|
|
m_Scripts.emplace_back(path, cb, ctx, delay, m_Debugging);
|
2016-06-18 19:31:35 +02:00
|
|
|
|
|
|
|
// Attempt to load and compile the script file
|
|
|
|
try
|
|
|
|
{
|
2020-04-30 21:28:01 +02:00
|
|
|
m_Scripts.back().mExec.CompileFile(path);
|
2016-06-18 19:31:35 +02:00
|
|
|
}
|
2021-01-30 07:51:39 +01:00
|
|
|
catch (const std::exception & e)
|
2016-06-18 19:31:35 +02:00
|
|
|
{
|
2021-04-20 17:20:02 +02:00
|
|
|
LogFtl("Unable to compile (%s) exception caught: %s", path.c_str(), e.what());
|
2016-08-19 18:46:26 +02:00
|
|
|
// Remove the script container since it's invalid
|
|
|
|
m_Scripts.pop_back();
|
|
|
|
// Failed to compile properly
|
2016-06-18 19:31:35 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// At this point the script should be completely loaded
|
2020-04-30 21:28:01 +02:00
|
|
|
cLogDbg(m_Verbosity >= 3, "Compiled script: %s", path.c_str());
|
2016-06-18 19:31:35 +02:00
|
|
|
|
|
|
|
// Attempt to execute the compiled script code
|
|
|
|
try
|
|
|
|
{
|
2021-07-03 18:46:39 +02:00
|
|
|
auto & s = m_Scripts.back();
|
|
|
|
// Attempt to run the script
|
|
|
|
s.mExec.Run();
|
|
|
|
// Does someone need to be notified?
|
|
|
|
if (!s.mFunc.IsNull())
|
|
|
|
{
|
2021-07-04 01:19:37 +02:00
|
|
|
// Invoke the associated script
|
|
|
|
s.mFunc.Execute(s.mPath, s.mCtx);
|
|
|
|
// Release callback since we know it exists
|
|
|
|
s.mFunc.Release();
|
2021-07-03 18:46:39 +02:00
|
|
|
}
|
2021-07-04 04:17:32 +02:00
|
|
|
// Invoke the global callback
|
|
|
|
(*mOnScript.first)(s.mPath, s.mCtx);
|
2021-07-04 01:19:37 +02:00
|
|
|
// Release context, if any
|
|
|
|
s.mCtx.Release();
|
2016-06-18 19:31:35 +02:00
|
|
|
}
|
2021-01-30 07:51:39 +01:00
|
|
|
catch (const std::exception & e)
|
2016-06-18 19:31:35 +02:00
|
|
|
{
|
2021-04-20 17:20:02 +02:00
|
|
|
LogFtl("Unable to execute (%s) exception caught: %s", path.c_str(), e.what());
|
2021-07-04 01:19:37 +02:00
|
|
|
// Release callback and context objects, if any
|
|
|
|
m_Scripts.back().mFunc.Release();
|
|
|
|
m_Scripts.back().mCtx.Release();
|
2016-08-19 18:46:26 +02:00
|
|
|
// Remove the script container since it's invalid
|
|
|
|
m_Scripts.pop_back();
|
2016-06-18 19:31:35 +02:00
|
|
|
// Failed to execute properly
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// At this point the script should be completely loaded
|
2020-04-30 21:28:01 +02:00
|
|
|
cLogScs(m_Verbosity >= 2, "Executed script: %s", path.c_str());
|
2016-06-18 19:31:35 +02:00
|
|
|
}
|
2016-05-22 05:20:38 +02:00
|
|
|
// We don't compile the scripts yet. We just store their path and prepare the objects
|
2016-03-10 04:57:13 +01:00
|
|
|
else
|
2016-03-26 17:16:01 +01:00
|
|
|
{
|
2016-09-11 19:48:20 +02:00
|
|
|
cLogDbg(m_Verbosity >= 2, "Pending %s script: %s", (delay ? "deferred" : "immediate"), path.c_str());
|
2020-04-30 21:28:01 +02:00
|
|
|
// Attempt to queue the script
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// Create a new script container and insert it into the pending script pool
|
2021-07-04 01:19:37 +02:00
|
|
|
m_PendingScripts.emplace_back(path, cb, ctx, delay, m_Debugging);
|
2020-04-30 21:28:01 +02:00
|
|
|
}
|
2021-01-30 07:51:39 +01:00
|
|
|
catch (const std::exception & e)
|
2020-04-30 21:28:01 +02:00
|
|
|
{
|
|
|
|
LogFtl("Unable to queue: %s", e.what());
|
|
|
|
// Failed to queue script
|
|
|
|
return false;
|
|
|
|
}
|
2016-03-26 17:16:01 +01:00
|
|
|
}
|
2016-08-19 18:46:26 +02:00
|
|
|
|
|
|
|
// At this point the script exists in one of the pools
|
2016-03-10 04:57:13 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-05-22 05:20:38 +02:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
2021-01-30 07:51:39 +01:00
|
|
|
void Core::SetIncomingName(const SQChar * name)
|
2016-05-22 05:20:38 +02:00
|
|
|
{
|
|
|
|
// Is there an incoming connection buffer that we can write to?
|
|
|
|
if (!m_IncomingNameBuffer)
|
|
|
|
{
|
|
|
|
STHROWF("No incoming player name buffer available");
|
|
|
|
}
|
|
|
|
// Is the specified name valid?
|
|
|
|
else if (!name || *name == '\0')
|
|
|
|
{
|
|
|
|
STHROWF("Invalid player name for incoming connection");
|
|
|
|
}
|
|
|
|
// Calculate the length of the specified name
|
|
|
|
const size_t len = std::strlen(name);
|
|
|
|
// Is the length of the name out of bounds?
|
|
|
|
if (len > m_IncomingNameCapacity)
|
|
|
|
{
|
|
|
|
STHROWF("The specified name exceeds the designated buffer");
|
|
|
|
}
|
|
|
|
// Does the name satisfy the minimum length required?
|
|
|
|
else if (len < 2)
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("The specified name needs to be at least 2 characters: {}", len);
|
2016-05-22 05:20:38 +02:00
|
|
|
}
|
|
|
|
// Copy the specified name to the assigned buffer
|
|
|
|
std::strncpy(m_IncomingNameBuffer, name, m_IncomingNameCapacity);
|
|
|
|
// Make sure that the name inside the buffer is null terminated
|
|
|
|
m_IncomingNameBuffer[len] = '\0';
|
|
|
|
}
|
|
|
|
|
2019-06-16 01:51:16 +02:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
2021-01-30 07:51:39 +01:00
|
|
|
String Core::FetchCodeLine(const SQChar * src, SQInteger line, bool trim)
|
2019-06-16 01:51:16 +02:00
|
|
|
{
|
|
|
|
// Find the script we're looking for
|
2020-05-06 00:20:39 +02:00
|
|
|
auto script = FindScript(src);
|
2019-06-16 01:51:16 +02:00
|
|
|
// Do we have a valid script and line?
|
2019-08-17 14:43:50 +02:00
|
|
|
if ((script == m_Scripts.end()) || !(script->mInfo) || (static_cast< SQInteger >(script->mLine.size()) < line))
|
2019-06-16 01:51:16 +02:00
|
|
|
{
|
|
|
|
return String{}; // No such script!
|
|
|
|
}
|
|
|
|
// Fetch the line of code
|
|
|
|
return script->FetchLine(line, trim);
|
|
|
|
}
|
|
|
|
|
2023-03-05 14:38:59 +01:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-08-19 18:46:26 +02:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
bool Core::DoScripts(Scripts::iterator itr, Scripts::iterator end)
|
|
|
|
{
|
2020-05-06 00:20:39 +02:00
|
|
|
auto itr_state = itr;
|
2016-08-19 18:46:26 +02:00
|
|
|
|
2016-08-25 11:22:39 +02:00
|
|
|
cLogDbg(Get().m_Verbosity >= 1, "Attempting to compile the specified scripts");
|
2016-08-19 18:46:26 +02:00
|
|
|
// Compile scripts first so that the constants can take effect
|
|
|
|
for (; itr != end; ++itr)
|
|
|
|
{
|
|
|
|
// Is this script already compiled?
|
|
|
|
if (!(*itr).mExec.IsNull())
|
|
|
|
{
|
|
|
|
continue; // Already compiled!
|
|
|
|
}
|
|
|
|
|
|
|
|
// Attempt to load and compile the script file
|
|
|
|
try
|
|
|
|
{
|
|
|
|
(*itr).mExec.CompileFile((*itr).mPath);
|
|
|
|
}
|
2021-01-30 07:51:39 +01:00
|
|
|
catch (const std::exception & e)
|
2016-08-19 18:46:26 +02:00
|
|
|
{
|
2021-04-20 17:20:02 +02:00
|
|
|
LogFtl("Unable to compile (%s) exception caught: %s", (*itr).mPath.c_str(), e.what());
|
2016-08-19 18:46:26 +02:00
|
|
|
// Failed to execute properly
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-09-11 19:48:20 +02:00
|
|
|
cLogDbg(Get().m_Verbosity >= 3, "Compiled script: %s", (*itr).mPath.c_str());
|
2016-08-19 18:46:26 +02:00
|
|
|
|
|
|
|
// Should we delay the execution of this script?
|
|
|
|
if ((*itr).mDelay)
|
|
|
|
{
|
|
|
|
continue; // Execute later!
|
|
|
|
}
|
|
|
|
|
|
|
|
// Attempt to execute the compiled script code
|
|
|
|
try
|
|
|
|
{
|
2021-07-03 18:46:39 +02:00
|
|
|
auto & s = *itr;
|
|
|
|
// Attempt to run the script
|
|
|
|
s.mExec.Run();
|
|
|
|
// Does someone need to be notified?
|
|
|
|
if (!s.mFunc.IsNull())
|
|
|
|
{
|
2021-07-04 01:19:37 +02:00
|
|
|
// Invoke the associated script
|
|
|
|
s.mFunc.Execute(s.mPath, s.mCtx);
|
|
|
|
// Release callback since we know it exists
|
|
|
|
s.mFunc.Release();
|
2021-07-03 18:46:39 +02:00
|
|
|
}
|
2021-07-04 04:17:32 +02:00
|
|
|
// Invoke the global callback
|
|
|
|
(*Core::Get().mOnScript.first)(s.mPath, s.mCtx);
|
2021-07-04 01:19:37 +02:00
|
|
|
// Release context, if any
|
|
|
|
s.mCtx.Release();
|
2016-08-19 18:46:26 +02:00
|
|
|
}
|
2021-01-30 07:51:39 +01:00
|
|
|
catch (const std::exception & e)
|
2016-08-19 18:46:26 +02:00
|
|
|
{
|
2021-04-20 17:20:02 +02:00
|
|
|
LogFtl("Unable to execute (%s) exception caught: %s", (*itr).mPath.c_str(), e.what());
|
2021-07-04 01:19:37 +02:00
|
|
|
// Release callback and context objects, if any
|
|
|
|
itr->mFunc.Release();
|
|
|
|
itr->mCtx.Release();
|
2016-08-19 18:46:26 +02:00
|
|
|
// Failed to execute properly
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-09-11 19:48:20 +02:00
|
|
|
cLogScs(Get().m_Verbosity >= 2, "Executed script: %s", (*itr).mPath.c_str());
|
2016-08-19 18:46:26 +02:00
|
|
|
}
|
|
|
|
|
2016-09-11 19:48:20 +02:00
|
|
|
cLogDbg(Get().m_Verbosity >= 1, "Attempting to execute the delayed scripts");
|
2016-08-19 18:46:26 +02:00
|
|
|
// Execute scripts only after compilation successful
|
|
|
|
for (itr = itr_state; itr != end; ++itr)
|
|
|
|
{
|
|
|
|
// Was this script delayed from execution?
|
|
|
|
if (!(*itr).mDelay)
|
|
|
|
{
|
|
|
|
continue; // Already executed!
|
|
|
|
}
|
|
|
|
|
|
|
|
// Attempt to execute the compiled script code
|
|
|
|
try
|
|
|
|
{
|
2021-07-03 18:46:39 +02:00
|
|
|
auto & s = *itr;
|
|
|
|
// Attempt to run the script
|
|
|
|
s.mExec.Run();
|
|
|
|
// Does someone need to be notified?
|
|
|
|
if (!s.mFunc.IsNull())
|
|
|
|
{
|
2021-07-04 01:19:37 +02:00
|
|
|
// Invoke the associated script
|
|
|
|
s.mFunc.Execute(s.mPath, s.mCtx);
|
|
|
|
// Release callback since we know it exists
|
|
|
|
s.mFunc.Release();
|
2021-07-03 18:46:39 +02:00
|
|
|
}
|
2021-07-04 04:17:32 +02:00
|
|
|
// Invoke the global callback
|
|
|
|
(*Core::Get().mOnScript.first)(s.mPath, s.mCtx);
|
2021-07-04 01:19:37 +02:00
|
|
|
// Release context, if any
|
|
|
|
s.mCtx.Release();
|
2016-08-19 18:46:26 +02:00
|
|
|
}
|
2021-01-30 07:51:39 +01:00
|
|
|
catch (const std::exception & e)
|
2016-08-19 18:46:26 +02:00
|
|
|
{
|
2021-07-03 18:46:39 +02:00
|
|
|
LogFtl("Unable to execute (%s) exception caught: %s", (*itr).mPath.c_str(), e.what());
|
2021-07-04 01:19:37 +02:00
|
|
|
// Release callback and context objects, if any
|
|
|
|
itr->mFunc.Release();
|
|
|
|
itr->mCtx.Release();
|
2016-08-19 18:46:26 +02:00
|
|
|
// Failed to execute properly
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-09-11 19:48:20 +02:00
|
|
|
cLogScs(Get().m_Verbosity >= 2, "Executed script: %s", (*itr).mPath.c_str());
|
2016-08-19 18:46:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// At this point the scripts were loaded and executed successfully
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-02-20 23:25:00 +01:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
2021-01-30 07:51:39 +01:00
|
|
|
void Core::PrintFunc(HSQUIRRELVM /*vm*/, const SQChar * msg, ...)
|
2015-09-30 02:56:11 +02:00
|
|
|
{
|
2016-05-22 05:20:38 +02:00
|
|
|
// Initialize the variable argument list
|
2016-02-20 23:25:00 +01:00
|
|
|
va_list args;
|
|
|
|
va_start(args, msg);
|
2016-05-22 05:20:38 +02:00
|
|
|
// Forward the message to the logger
|
2020-09-08 21:44:04 +02:00
|
|
|
Logger::Get().SendFv(LOGL_USR, false, msg, args);
|
2016-05-22 05:20:38 +02:00
|
|
|
// Finalize the variable argument list
|
2016-02-20 23:25:00 +01:00
|
|
|
va_end(args);
|
2015-09-30 02:56:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2021-01-30 07:51:39 +01:00
|
|
|
void Core::ErrorFunc(HSQUIRRELVM vm, const SQChar * msg, ...)
|
2015-09-30 02:56:11 +02:00
|
|
|
{
|
2016-05-22 05:20:38 +02:00
|
|
|
// Initialize the variable argument list
|
2016-02-20 23:25:00 +01:00
|
|
|
va_list args;
|
|
|
|
va_start(args, msg);
|
2016-05-22 05:20:38 +02:00
|
|
|
// Tell the logger to display debugging information
|
2020-09-08 21:44:04 +02:00
|
|
|
Logger::Get().DebugFv(vm, msg, args);
|
2016-05-22 05:20:38 +02:00
|
|
|
// Finalize the variable argument list
|
2016-02-20 23:25:00 +01:00
|
|
|
va_end(args);
|
2015-09-30 02:56:11 +02:00
|
|
|
}
|
|
|
|
|
2016-02-20 23:25:00 +01:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
SQInteger Core::RuntimeErrorHandler(HSQUIRRELVM vm)
|
2015-09-30 02:56:11 +02:00
|
|
|
{
|
2016-05-22 05:20:38 +02:00
|
|
|
// Was there a value thrown?
|
2016-02-20 23:25:00 +01:00
|
|
|
if (sq_gettop(vm) < 1)
|
2016-03-22 03:27:11 +01:00
|
|
|
{
|
2016-05-22 05:20:38 +02:00
|
|
|
return SQ_OK; // No error to display!
|
2016-03-22 03:27:11 +01:00
|
|
|
}
|
2019-05-01 15:04:29 +02:00
|
|
|
// Attempt to generate the string value
|
|
|
|
StackStrF val(vm, 2);
|
|
|
|
// Have we failed to retrieve the string?
|
|
|
|
if (SQ_FAILED(val.Proc(false)))
|
2016-03-22 03:27:11 +01:00
|
|
|
{
|
2020-09-08 21:44:04 +02:00
|
|
|
Logger::Get().DebugF(vm, _SC("Unknown runtime error has occurred"));
|
2016-03-22 03:27:11 +01:00
|
|
|
}
|
2016-02-20 23:25:00 +01:00
|
|
|
else
|
2016-03-22 03:27:11 +01:00
|
|
|
{
|
2020-09-08 21:44:04 +02:00
|
|
|
Logger::Get().DebugF(vm, _SC("%s"), val.mPtr);
|
2016-03-22 03:27:11 +01:00
|
|
|
}
|
2016-05-22 05:20:38 +02:00
|
|
|
// We handled the error
|
2016-02-20 23:25:00 +01:00
|
|
|
return SQ_OK;
|
2015-09-30 02:56:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2021-01-30 07:51:39 +01:00
|
|
|
void Core::CompilerErrorHandler(HSQUIRRELVM /*vm*/, const SQChar * desc, const SQChar * src, SQInteger line, SQInteger column)
|
2015-11-07 11:17:39 +01:00
|
|
|
{
|
2019-06-16 01:12:51 +02:00
|
|
|
// Should we include code in output? (we count lines from 0, squirrel counts from 1)
|
|
|
|
if ((line <= 0) || !Core::Get().IsDebugging() || !Core::Get().CompilerErrorHandlerEx(desc, src, --line, column)) {
|
|
|
|
LogFtl("Message: %s\n[\n=>Location: %s\n=>Line: %" PRINT_INT_FMT "\n=>Column: %" PRINT_INT_FMT "\n]", desc, src, line, column);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2021-01-30 07:51:39 +01:00
|
|
|
bool Core::CompilerErrorHandlerEx(const SQChar * desc, const SQChar * src, SQInteger line, SQInteger column)
|
2019-06-16 01:12:51 +02:00
|
|
|
{
|
2019-06-16 01:51:16 +02:00
|
|
|
// Grab the associated line of code
|
|
|
|
String code = FetchCodeLine(src, line, true);
|
2019-06-16 02:22:53 +02:00
|
|
|
// Contains an arrow pointing at the exact column
|
|
|
|
String point;
|
|
|
|
// Do we have a valid column?
|
|
|
|
if (column >= 0)
|
|
|
|
{
|
|
|
|
// The `=>Code: ` is included as white space
|
|
|
|
point.resize(8, ' ');
|
|
|
|
// The line towards the arrow
|
|
|
|
point.resize(column+7, '-');
|
|
|
|
// Append the actual arrow
|
|
|
|
point.push_back('^');
|
|
|
|
// Include the new line here
|
|
|
|
point.push_back('\n');
|
|
|
|
}
|
2019-06-16 01:51:16 +02:00
|
|
|
// Valid line of code?
|
|
|
|
if (!code.empty())
|
2019-06-16 01:12:51 +02:00
|
|
|
{
|
2019-06-16 01:51:16 +02:00
|
|
|
// Display the error message with the code included
|
2019-06-16 02:22:53 +02:00
|
|
|
LogFtl("Message: %s\n[\n=>Location: %s\n=>Line: %" PRINT_SZ_FMT "\n=>Column: %" PRINT_INT_FMT "\n=>Code: %s\n%s]",
|
|
|
|
desc, src, ++line, column, code.c_str(), point.c_str());
|
2019-06-16 01:51:16 +02:00
|
|
|
// We displayed the information
|
|
|
|
return true;
|
2019-06-16 01:12:51 +02:00
|
|
|
}
|
2019-06-16 01:51:16 +02:00
|
|
|
// No code to show. Fall back to normal message
|
2019-06-16 01:12:51 +02:00
|
|
|
return true;
|
2015-11-07 11:17:39 +01:00
|
|
|
}
|
|
|
|
|
2021-01-30 07:51:39 +01:00
|
|
|
// --------------------------------------------------------------------------------------------
|
|
|
|
void Core::ImportBlips()
|
|
|
|
{
|
|
|
|
// Information about the blip entity
|
|
|
|
int32_t world = -1, scale = -1, sprid = -1;
|
|
|
|
uint32_t color = 0;
|
|
|
|
float x = 0.0, y = 0.0, z = 0.0;
|
|
|
|
|
|
|
|
for (int32_t i = 0; i < SQMOD_BLIP_POOL; ++i)
|
|
|
|
{
|
|
|
|
// See if this entity exists on the server and whether was not allocated already
|
|
|
|
if (_Func->CheckEntityExists(vcmpEntityPoolBlip, i) && INVALID_ENTITY(m_Blips[i].mID))
|
|
|
|
{
|
|
|
|
_Func->GetCoordBlipInfo(i, &world, &x, &y, &z, &scale, &color, &sprid);
|
|
|
|
// Make the properties available before triggering the event
|
|
|
|
m_Blips[i].mWorld = world;
|
|
|
|
m_Blips[i].mScale = scale;
|
|
|
|
m_Blips[i].mSprID = sprid;
|
|
|
|
m_Blips[i].mPosition.SetVector3Ex(x, y, z);
|
|
|
|
m_Blips[i].mColor.SetRGBA(color);
|
|
|
|
// Attempt to allocate the instance
|
|
|
|
AllocBlip(i, false, SQMOD_CREATE_IMPORT, NullLightObj());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
void Core::ImportCheckpoints()
|
|
|
|
{
|
|
|
|
for (int32_t i = 0; i < SQMOD_CHECKPOINT_POOL; ++i)
|
|
|
|
{
|
|
|
|
// See if this entity exists on the server and whether was not allocated already
|
|
|
|
if (_Func->CheckEntityExists(vcmpEntityPoolCheckPoint, i) && INVALID_ENTITY(m_Checkpoints[i].mID))
|
|
|
|
{
|
|
|
|
AllocCheckpoint(i, false, SQMOD_CREATE_IMPORT, NullLightObj());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
void Core::ImportKeyBinds()
|
|
|
|
{
|
|
|
|
/* @NOTE This function is disabled because VC:MP server seems bugged
|
|
|
|
* and does not return vcmpErrorNoSuchEntity when the key-bind does not exist.
|
|
|
|
* Therefore causing incorrect behavior in the plugin.
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
// Information about the key-bind entity
|
|
|
|
uint8_t release = 0;
|
|
|
|
int32_t first = -1, second = -1, third = -1;
|
|
|
|
|
|
|
|
for (int32_t i = 0; i < SQMOD_KEYBIND_POOL; ++i)
|
|
|
|
{
|
|
|
|
// See if this entity exists on the server and whether was not allocated already
|
|
|
|
if ((_Func->GetKeyBindData(i, &release, &first, &second, &third) != vcmpErrorNoSuchEntity)
|
|
|
|
&& (INVALID_ENTITY(m_KeyBinds[i].mID)))
|
|
|
|
{
|
|
|
|
// Make the properties available before triggering the event
|
|
|
|
m_KeyBinds[i].mFirst = first;
|
|
|
|
m_KeyBinds[i].mSecond = second;
|
|
|
|
m_KeyBinds[i].mThird = third;
|
|
|
|
m_KeyBinds[i].mRelease = release;
|
|
|
|
// Attempt to allocate the instance
|
|
|
|
AllocKeyBind(i, false, SQMOD_CREATE_IMPORT, NullLightObj());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
void Core::ImportObjects()
|
|
|
|
{
|
|
|
|
for (int32_t i = 0; i < SQMOD_OBJECT_POOL; ++i)
|
|
|
|
{
|
|
|
|
// See if this entity exists on the server and whether was not allocated already
|
|
|
|
if (_Func->CheckEntityExists(vcmpEntityPoolObject, i) && INVALID_ENTITY(m_Objects[i].mID))
|
|
|
|
{
|
|
|
|
AllocObject(i, false, SQMOD_CREATE_IMPORT, NullLightObj());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
void Core::ImportPickups()
|
|
|
|
{
|
|
|
|
for (int32_t i = 0; i < SQMOD_PICKUP_POOL; ++i)
|
|
|
|
{
|
|
|
|
// See if this entity exists on the server and whether was not allocated already
|
|
|
|
if (_Func->CheckEntityExists(vcmpEntityPoolPickup, i) && (INVALID_ENTITY(m_Pickups[i].mID)))
|
|
|
|
{
|
|
|
|
AllocPickup(i, false, SQMOD_CREATE_IMPORT, NullLightObj());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
void Core::ImportPlayers()
|
|
|
|
{
|
|
|
|
for (int32_t i = 0; i < SQMOD_PLAYER_POOL; ++i)
|
|
|
|
{
|
|
|
|
// See if this entity exists on the server and whether was not allocated already
|
|
|
|
if (_Func->IsPlayerConnected(i) && (INVALID_ENTITY(m_Players[i].mID)))
|
|
|
|
{
|
|
|
|
ConnectPlayer(i, SQMOD_CREATE_IMPORT, NullLightObj());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
void Core::ImportVehicles()
|
|
|
|
{
|
|
|
|
for (int32_t i = 0; i < SQMOD_VEHICLE_POOL; ++i)
|
|
|
|
{
|
|
|
|
// See if this entity exists on the server and whether was not allocated already
|
|
|
|
if (_Func->CheckEntityExists(vcmpEntityPoolVehicle, i) && INVALID_ENTITY(m_Vehicles[i].mID))
|
|
|
|
{
|
|
|
|
AllocVehicle(i, false, SQMOD_CREATE_IMPORT, NullLightObj());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------------------
|
|
|
|
BlipInst & Core::AllocBlip(int32_t id, bool owned, int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Make sure that the specified entity identifier is valid
|
|
|
|
if (INVALID_ENTITYEX(id, SQMOD_BLIP_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Cannot allocate blip with invalid identifier: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Retrieve the specified entity instance
|
|
|
|
BlipInst & inst = m_Blips[id];
|
|
|
|
// Make sure that the instance isn't already allocated
|
|
|
|
if (VALID_ENTITY(inst.mID))
|
|
|
|
{
|
|
|
|
return inst; // Return the existing instance
|
|
|
|
}
|
|
|
|
// Instantiate the entity manager
|
|
|
|
DeleteGuard< CBlip > dg(new CBlip(id));
|
|
|
|
// Create the script object
|
|
|
|
inst.mObj = LightObj(dg.Get(), m_VM);
|
|
|
|
// Store the manager instance itself
|
|
|
|
inst.mInst = dg.Get();
|
|
|
|
// The instance is now managed by the script
|
|
|
|
dg.Release();
|
|
|
|
// Make sure that both the instance and script object could be created
|
|
|
|
if (!inst.mInst || inst.mObj.IsNull())
|
|
|
|
{
|
|
|
|
inst.ResetInstance();
|
2021-03-15 06:02:48 +01:00
|
|
|
// Make sure that if an instance was created, it points to nothing
|
|
|
|
if (inst.mInst)
|
|
|
|
{
|
|
|
|
inst.mInst->m_ID = -1;
|
|
|
|
}
|
|
|
|
// Make sure that if an object was created, it is released
|
|
|
|
if (!inst.mObj.IsNull())
|
|
|
|
{
|
|
|
|
inst.mObj.Release();
|
|
|
|
}
|
2021-01-30 07:51:39 +01:00
|
|
|
// Now we can throw the error
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Unable to create a blip instance for: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Assign the specified entity identifier
|
|
|
|
inst.mID = id;
|
|
|
|
// Specify whether the entity is owned by this plug-in
|
|
|
|
if (owned)
|
|
|
|
{
|
|
|
|
inst.mFlags |= ENF_OWNED;
|
|
|
|
}
|
|
|
|
else if (inst.mFlags & ENF_OWNED)
|
|
|
|
{
|
|
|
|
inst.mFlags ^= ENF_OWNED;
|
|
|
|
}
|
|
|
|
// Initialize the instance events
|
|
|
|
inst.InitEvents();
|
|
|
|
// Let the script callbacks know about this entity
|
|
|
|
EmitBlipCreated(id, header, payload);
|
|
|
|
// Return the allocated instance
|
|
|
|
return inst;
|
|
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------------------
|
|
|
|
CheckpointInst & Core::AllocCheckpoint(int32_t id, bool owned, int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Make sure that the specified entity identifier is valid
|
|
|
|
if (INVALID_ENTITYEX(id, SQMOD_CHECKPOINT_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Cannot allocate checkpoint with invalid identifier: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Retrieve the specified entity instance
|
|
|
|
CheckpointInst & inst = m_Checkpoints[id];
|
|
|
|
// Make sure that the instance isn't already allocated
|
|
|
|
if (VALID_ENTITY(inst.mID))
|
|
|
|
{
|
|
|
|
return inst; // Return the existing instance
|
|
|
|
}
|
2021-03-15 06:02:48 +01:00
|
|
|
#ifdef VCMP_ENABLE_OFFICIAL
|
|
|
|
// Do we need to support legacy API?
|
|
|
|
if (IsOfficial())
|
|
|
|
{
|
|
|
|
// Create the legacy wrapper object
|
|
|
|
inst.mLgObj = LgCheckpointObj(m_VM, id);
|
|
|
|
// Obtain the legacy wrapper instance
|
|
|
|
inst.mLgInst = inst.mLgObj.CastI< LgCheckpoint >();
|
|
|
|
// Make sure that both the instance and script object could be created
|
|
|
|
if (!inst.mLgInst || inst.mLgObj.IsNull())
|
|
|
|
{
|
|
|
|
inst.ResetInstance();
|
|
|
|
// Make sure that if an instance was created, it points to nothing
|
|
|
|
if (inst.mLgInst)
|
|
|
|
{
|
|
|
|
LgCheckpointSetID(inst.mLgInst, -1);
|
|
|
|
}
|
|
|
|
// Make sure that if an object was created, it is released
|
|
|
|
if (!inst.mLgObj.IsNull())
|
|
|
|
{
|
|
|
|
inst.mLgObj.Release();
|
|
|
|
}
|
|
|
|
// Now we can throw the error
|
|
|
|
STHROWF("Unable to create a checkpoint wrapper instance for: {}", id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2021-01-30 07:51:39 +01:00
|
|
|
// Instantiate the entity manager
|
|
|
|
DeleteGuard< CCheckpoint > dg(new CCheckpoint(id));
|
|
|
|
// Create the script object
|
|
|
|
inst.mObj = LightObj(dg.Get(), m_VM);
|
|
|
|
// Store the manager instance itself
|
|
|
|
inst.mInst = dg.Get();
|
|
|
|
// The instance is now managed by the script
|
|
|
|
dg.Release();
|
|
|
|
// Make sure that both the instance and script object could be created
|
|
|
|
if (!inst.mInst || inst.mObj.IsNull())
|
|
|
|
{
|
|
|
|
inst.ResetInstance();
|
2021-03-15 06:02:48 +01:00
|
|
|
#ifdef VCMP_ENABLE_OFFICIAL
|
|
|
|
// Discard legacy wrapper instance
|
|
|
|
if (IsOfficial())
|
|
|
|
{
|
|
|
|
LgCheckpointSetID(inst.mLgInst, -1);
|
|
|
|
inst.mLgObj.Release();
|
|
|
|
inst.mLgInst = nullptr;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
// Make sure that if an instance was created, it points to nothing
|
|
|
|
if (inst.mInst)
|
|
|
|
{
|
|
|
|
inst.mInst->m_ID = -1;
|
|
|
|
}
|
|
|
|
// Make sure that if an object was created, it is released
|
|
|
|
if (!inst.mObj.IsNull())
|
|
|
|
{
|
|
|
|
inst.mObj.Release();
|
|
|
|
}
|
2021-01-30 07:51:39 +01:00
|
|
|
// Now we can throw the error
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Unable to create a checkpoint instance for: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Assign the specified entity identifier
|
|
|
|
inst.mID = id;
|
|
|
|
// Specify whether the entity is owned by this plug-in
|
|
|
|
if (owned)
|
|
|
|
{
|
|
|
|
inst.mFlags |= ENF_OWNED;
|
|
|
|
}
|
|
|
|
else if (inst.mFlags & ENF_OWNED)
|
|
|
|
{
|
|
|
|
inst.mFlags ^= ENF_OWNED;
|
|
|
|
}
|
|
|
|
// Initialize the instance events
|
|
|
|
inst.InitEvents();
|
|
|
|
// Let the script callbacks know about this entity
|
|
|
|
EmitCheckpointCreated(id, header, payload);
|
|
|
|
// Return the allocated instance
|
|
|
|
return inst;
|
|
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------------------
|
|
|
|
KeyBindInst & Core::AllocKeyBind(int32_t id, bool owned, int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Make sure that the specified entity identifier is valid
|
|
|
|
if (INVALID_ENTITYEX(id, SQMOD_KEYBIND_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Cannot allocate keybind with invalid identifier: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Retrieve the specified entity instance
|
|
|
|
KeyBindInst & inst = m_KeyBinds[id];
|
|
|
|
// Make sure that the instance isn't already allocated
|
|
|
|
if (VALID_ENTITY(inst.mID))
|
|
|
|
{
|
|
|
|
return inst; // Return the existing instance
|
|
|
|
}
|
|
|
|
// Instantiate the entity manager
|
|
|
|
DeleteGuard< CKeyBind > dg(new CKeyBind(id));
|
|
|
|
// Create the script object
|
|
|
|
inst.mObj = LightObj(dg.Get(), m_VM);
|
|
|
|
// Store the manager instance itself
|
|
|
|
inst.mInst = dg.Get();
|
|
|
|
// The instance is now managed by the script
|
|
|
|
dg.Release();
|
|
|
|
// Make sure that both the instance and script object could be created
|
|
|
|
if (!inst.mInst || inst.mObj.IsNull())
|
|
|
|
{
|
|
|
|
inst.ResetInstance();
|
2021-03-15 06:02:48 +01:00
|
|
|
// Make sure that if an instance was created, it points to nothing
|
|
|
|
if (inst.mInst)
|
|
|
|
{
|
|
|
|
inst.mInst->m_ID = -1;
|
|
|
|
}
|
|
|
|
// Make sure that if an object was created, it is released
|
|
|
|
if (!inst.mObj.IsNull())
|
|
|
|
{
|
|
|
|
inst.mObj.Release();
|
|
|
|
}
|
2021-01-30 07:51:39 +01:00
|
|
|
// Now we can throw the error
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Unable to create a keybind instance for: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Assign the specified entity identifier
|
|
|
|
inst.mID = id;
|
|
|
|
// Specify whether the entity is owned by this plug-in
|
|
|
|
if (owned)
|
|
|
|
{
|
|
|
|
inst.mFlags |= ENF_OWNED;
|
|
|
|
}
|
|
|
|
else if (inst.mFlags & ENF_OWNED)
|
|
|
|
{
|
|
|
|
inst.mFlags ^= ENF_OWNED;
|
|
|
|
}
|
|
|
|
// Initialize the instance events
|
|
|
|
inst.InitEvents();
|
|
|
|
// Let the script callbacks know about this entity
|
|
|
|
EmitKeyBindCreated(id, header, payload);
|
|
|
|
// Return the allocated instance
|
|
|
|
return inst;
|
|
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------------------
|
|
|
|
ObjectInst & Core::AllocObject(int32_t id, bool owned, int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Make sure that the specified entity identifier is valid
|
|
|
|
if (INVALID_ENTITYEX(id, SQMOD_OBJECT_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Cannot allocate object with invalid identifier: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Retrieve the specified entity instance
|
|
|
|
ObjectInst & inst = m_Objects[id];
|
|
|
|
// Make sure that the instance isn't already allocated
|
|
|
|
if (VALID_ENTITY(inst.mID))
|
|
|
|
{
|
|
|
|
return inst; // Return the existing instance
|
|
|
|
}
|
2021-03-15 06:02:48 +01:00
|
|
|
#ifdef VCMP_ENABLE_OFFICIAL
|
|
|
|
// Do we need to support legacy API?
|
|
|
|
if (IsOfficial())
|
|
|
|
{
|
|
|
|
// Create the legacy wrapper object
|
|
|
|
inst.mLgObj = LgObjectObj(m_VM, id);
|
|
|
|
// Obtain the legacy wrapper instance
|
|
|
|
inst.mLgInst = inst.mLgObj.CastI< LgObject >();
|
|
|
|
// Make sure that both the instance and script object could be created
|
|
|
|
if (!inst.mLgInst || inst.mLgObj.IsNull())
|
|
|
|
{
|
|
|
|
inst.ResetInstance();
|
|
|
|
// Make sure that if an instance was created, it points to nothing
|
|
|
|
if (inst.mLgInst)
|
|
|
|
{
|
|
|
|
LgObjectSetID(inst.mLgInst, -1);
|
|
|
|
}
|
|
|
|
// Make sure that if an object was created, it is released
|
|
|
|
if (!inst.mLgObj.IsNull())
|
|
|
|
{
|
|
|
|
inst.mLgObj.Release();
|
|
|
|
}
|
|
|
|
// Now we can throw the error
|
|
|
|
STHROWF("Unable to create a object wrapper instance for: {}", id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2021-01-30 07:51:39 +01:00
|
|
|
// Instantiate the entity manager
|
|
|
|
DeleteGuard< CObject > dg(new CObject(id));
|
|
|
|
// Create the script object
|
|
|
|
inst.mObj = LightObj(dg.Get(), m_VM);
|
|
|
|
// Store the manager instance itself
|
|
|
|
inst.mInst = dg.Get();
|
|
|
|
// The instance is now managed by the script
|
|
|
|
dg.Release();
|
|
|
|
// Make sure that both the instance and script object could be created
|
|
|
|
if (!inst.mInst || inst.mObj.IsNull())
|
|
|
|
{
|
|
|
|
inst.ResetInstance();
|
2021-03-15 06:02:48 +01:00
|
|
|
#ifdef VCMP_ENABLE_OFFICIAL
|
|
|
|
// Discard legacy wrapper instance
|
|
|
|
if (IsOfficial())
|
|
|
|
{
|
|
|
|
LgObjectSetID(inst.mLgInst, -1);
|
|
|
|
inst.mLgObj.Release();
|
|
|
|
inst.mLgInst = nullptr;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
// Make sure that if an instance was created, it points to nothing
|
|
|
|
if (inst.mInst)
|
|
|
|
{
|
|
|
|
inst.mInst->m_ID = -1;
|
|
|
|
}
|
|
|
|
// Make sure that if an object was created, it is released
|
|
|
|
if (!inst.mObj.IsNull())
|
|
|
|
{
|
|
|
|
inst.mObj.Release();
|
|
|
|
}
|
2021-01-30 07:51:39 +01:00
|
|
|
// Now we can throw the error
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Unable to create a object instance for: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Assign the specified entity identifier
|
|
|
|
inst.mID = id;
|
|
|
|
// Specify whether the entity is owned by this plug-in
|
|
|
|
if (owned)
|
|
|
|
{
|
|
|
|
inst.mFlags |= ENF_OWNED;
|
|
|
|
}
|
|
|
|
else if (inst.mFlags & ENF_OWNED)
|
|
|
|
{
|
|
|
|
inst.mFlags ^= ENF_OWNED;
|
|
|
|
}
|
|
|
|
// Initialize the instance events
|
|
|
|
inst.InitEvents();
|
|
|
|
// Let the script callbacks know about this entity
|
|
|
|
EmitObjectCreated(id, header, payload);
|
|
|
|
// Return the allocated instance
|
|
|
|
return inst;
|
|
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------------------
|
|
|
|
PickupInst & Core::AllocPickup(int32_t id, bool owned, int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Make sure that the specified entity identifier is valid
|
|
|
|
if (INVALID_ENTITYEX(id, SQMOD_PICKUP_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Cannot allocate pickup with invalid identifier: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Retrieve the specified entity instance
|
|
|
|
PickupInst & inst = m_Pickups[id];
|
|
|
|
// Make sure that the instance isn't already allocated
|
|
|
|
if (VALID_ENTITY(inst.mID))
|
|
|
|
{
|
|
|
|
return inst; // Return the existing instance
|
|
|
|
}
|
2021-03-15 06:02:48 +01:00
|
|
|
#ifdef VCMP_ENABLE_OFFICIAL
|
|
|
|
// Do we need to support legacy API?
|
|
|
|
if (IsOfficial())
|
|
|
|
{
|
|
|
|
// Create the legacy wrapper object
|
|
|
|
inst.mLgObj = LgPickupObj(m_VM, id);
|
|
|
|
// Obtain the legacy wrapper instance
|
|
|
|
inst.mLgInst = inst.mLgObj.CastI< LgPickup >();
|
|
|
|
// Make sure that both the instance and script object could be created
|
|
|
|
if (!inst.mLgInst || inst.mLgObj.IsNull())
|
|
|
|
{
|
|
|
|
inst.ResetInstance();
|
|
|
|
// Make sure that if an instance was created, it points to nothing
|
|
|
|
if (inst.mLgInst)
|
|
|
|
{
|
|
|
|
LgPickupSetID(inst.mLgInst, -1);
|
|
|
|
}
|
|
|
|
// Make sure that if an object was created, it is released
|
|
|
|
if (!inst.mLgObj.IsNull())
|
|
|
|
{
|
|
|
|
inst.mLgObj.Release();
|
|
|
|
}
|
|
|
|
// Now we can throw the error
|
|
|
|
STHROWF("Unable to create a pickup wrapper instance for: {}", id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2021-01-30 07:51:39 +01:00
|
|
|
// Instantiate the entity manager
|
|
|
|
DeleteGuard< CPickup > dg(new CPickup(id));
|
|
|
|
// Create the script object
|
|
|
|
inst.mObj = LightObj(dg.Get(), m_VM);
|
|
|
|
// Store the manager instance itself
|
|
|
|
inst.mInst = dg.Get();
|
|
|
|
// The instance is now managed by the script
|
|
|
|
dg.Release();
|
|
|
|
// Make sure that both the instance and script object could be created
|
|
|
|
if (!inst.mInst || inst.mObj.IsNull())
|
|
|
|
{
|
|
|
|
inst.ResetInstance();
|
2021-03-15 06:02:48 +01:00
|
|
|
#ifdef VCMP_ENABLE_OFFICIAL
|
|
|
|
// Discard legacy wrapper instance
|
|
|
|
if (IsOfficial())
|
|
|
|
{
|
|
|
|
LgPickupSetID(inst.mLgInst, -1);
|
|
|
|
inst.mLgObj.Release();
|
|
|
|
inst.mLgInst = nullptr;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
// Make sure that if an instance was created, it points to nothing
|
|
|
|
if (inst.mInst)
|
|
|
|
{
|
|
|
|
inst.mInst->m_ID = -1;
|
|
|
|
}
|
|
|
|
// Make sure that if an object was created, it is released
|
|
|
|
if (!inst.mObj.IsNull())
|
|
|
|
{
|
|
|
|
inst.mObj.Release();
|
|
|
|
}
|
2021-01-30 07:51:39 +01:00
|
|
|
// Now we can throw the error
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Unable to create a pickup instance for: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Assign the specified entity identifier
|
|
|
|
inst.mID = id;
|
|
|
|
// Specify whether the entity is owned by this plug-in
|
|
|
|
if (owned)
|
|
|
|
{
|
|
|
|
inst.mFlags |= ENF_OWNED;
|
|
|
|
}
|
|
|
|
else if (inst.mFlags & ENF_OWNED)
|
|
|
|
{
|
|
|
|
inst.mFlags ^= ENF_OWNED;
|
|
|
|
}
|
|
|
|
// Initialize the instance events
|
|
|
|
inst.InitEvents();
|
|
|
|
// Let the script callbacks know about this entity
|
|
|
|
EmitPickupCreated(id, header, payload);
|
|
|
|
// Return the allocated instance
|
|
|
|
return inst;
|
|
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------------------
|
|
|
|
VehicleInst & Core::AllocVehicle(int32_t id, bool owned, int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Make sure that the specified entity identifier is valid
|
|
|
|
if (INVALID_ENTITYEX(id, SQMOD_VEHICLE_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Cannot allocate vehicle with invalid identifier: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Retrieve the specified entity instance
|
|
|
|
VehicleInst & inst = m_Vehicles[id];
|
|
|
|
// Make sure that the instance isn't already allocated
|
|
|
|
if (VALID_ENTITY(inst.mID))
|
|
|
|
{
|
|
|
|
return inst; // Return the existing instance
|
|
|
|
}
|
2021-03-15 06:02:48 +01:00
|
|
|
#ifdef VCMP_ENABLE_OFFICIAL
|
|
|
|
// Do we need to support legacy API?
|
|
|
|
if (IsOfficial())
|
|
|
|
{
|
|
|
|
// Create the legacy wrapper object
|
|
|
|
inst.mLgObj = LgVehicleObj(m_VM, id);
|
|
|
|
// Obtain the legacy wrapper instance
|
|
|
|
inst.mLgInst = inst.mLgObj.CastI< LgVehicle >();
|
|
|
|
// Make sure that both the instance and script object could be created
|
|
|
|
if (!inst.mLgInst || inst.mLgObj.IsNull())
|
|
|
|
{
|
|
|
|
inst.ResetInstance();
|
|
|
|
// Make sure that if an instance was created, it points to nothing
|
|
|
|
if (inst.mLgInst)
|
|
|
|
{
|
|
|
|
LgVehicleSetID(inst.mLgInst, -1);
|
|
|
|
}
|
|
|
|
// Make sure that if an object was created, it is released
|
|
|
|
if (!inst.mLgObj.IsNull())
|
|
|
|
{
|
|
|
|
inst.mLgObj.Release();
|
|
|
|
}
|
|
|
|
// Now we can throw the error
|
|
|
|
STHROWF("Unable to create a vehicle wrapper instance for: {}", id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2021-01-30 07:51:39 +01:00
|
|
|
// Instantiate the entity manager
|
|
|
|
DeleteGuard< CVehicle > dg(new CVehicle(id));
|
|
|
|
// Create the script object
|
|
|
|
inst.mObj = LightObj(dg.Get(), m_VM);
|
|
|
|
// Store the manager instance itself
|
|
|
|
inst.mInst = dg.Get();
|
|
|
|
// The instance is now managed by the script
|
|
|
|
dg.Release();
|
|
|
|
// Make sure that both the instance and script object could be created
|
|
|
|
if (!inst.mInst || inst.mObj.IsNull())
|
|
|
|
{
|
|
|
|
inst.ResetInstance();
|
2021-03-15 06:02:48 +01:00
|
|
|
#ifdef VCMP_ENABLE_OFFICIAL
|
|
|
|
// Discard legacy wrapper instance
|
|
|
|
if (IsOfficial())
|
|
|
|
{
|
|
|
|
LgVehicleSetID(inst.mLgInst, -1);
|
|
|
|
inst.mLgObj.Release();
|
|
|
|
inst.mLgInst = nullptr;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
// Make sure that if an instance was created, it points to nothing
|
|
|
|
if (inst.mInst)
|
|
|
|
{
|
|
|
|
inst.mInst->m_ID = -1;
|
|
|
|
}
|
|
|
|
// Make sure that if an object was created, it is released
|
|
|
|
if (!inst.mObj.IsNull())
|
|
|
|
{
|
|
|
|
inst.mObj.Release();
|
|
|
|
}
|
2021-01-30 07:51:39 +01:00
|
|
|
// Now we can throw the error
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Unable to create a vehicle instance for: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Assign the specified entity identifier
|
|
|
|
inst.mID = id;
|
|
|
|
// Specify whether the entity is owned by this plug-in
|
|
|
|
if (owned)
|
|
|
|
{
|
|
|
|
inst.mFlags |= ENF_OWNED;
|
|
|
|
}
|
|
|
|
else if (inst.mFlags & ENF_OWNED)
|
|
|
|
{
|
|
|
|
inst.mFlags ^= ENF_OWNED;
|
|
|
|
}
|
|
|
|
// Should we enable area tracking?
|
|
|
|
if (m_AreasEnabled)
|
|
|
|
{
|
|
|
|
inst.mFlags |= ENF_AREA_TRACK;
|
|
|
|
}
|
|
|
|
// Initialize the instance events
|
|
|
|
inst.InitEvents();
|
|
|
|
// Let the script callbacks know about this entity
|
|
|
|
EmitVehicleCreated(id, header, payload);
|
|
|
|
// Return the allocated instance
|
|
|
|
return inst;
|
|
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------------------
|
|
|
|
void Core::DeallocBlip(int32_t id, bool destroy, int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Make sure that the specified entity identifier is valid
|
|
|
|
if (INVALID_ENTITYEX(id, SQMOD_BLIP_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Cannot deallocate blip with invalid identifier: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Retrieve the specified entity instance
|
|
|
|
BlipInst & inst = m_Blips[id];
|
|
|
|
// Make sure that the instance is even allocated and we are allowed to destroy it
|
|
|
|
if (VALID_ENTITY(inst.mID) && !(inst.mFlags & ENF_LOCKED))
|
|
|
|
{
|
|
|
|
inst.Destroy(destroy, header, payload); // Now attempt to destroy the entity from the server
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------------------
|
|
|
|
void Core::DeallocCheckpoint(int32_t id, bool destroy, int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Make sure that the specified entity identifier is valid
|
|
|
|
if (INVALID_ENTITYEX(id, SQMOD_CHECKPOINT_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Cannot deallocate checkpoint with invalid identifier: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Retrieve the specified entity instance
|
|
|
|
CheckpointInst & inst = m_Checkpoints[id];
|
|
|
|
// Make sure that the instance is even allocated and we are allowed to destroy it
|
|
|
|
if (VALID_ENTITY(inst.mID) && !(inst.mFlags & ENF_LOCKED))
|
|
|
|
{
|
|
|
|
inst.Destroy(destroy, header, payload); // Now attempt to destroy the entity from the server
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------------------
|
|
|
|
void Core::DeallocKeyBind(int32_t id, bool destroy, int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Make sure that the specified entity identifier is valid
|
|
|
|
if (INVALID_ENTITYEX(id, SQMOD_KEYBIND_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Cannot deallocate keybind with invalid identifier: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Retrieve the specified entity instance
|
|
|
|
KeyBindInst & inst = m_KeyBinds[id];
|
|
|
|
// Make sure that the instance is even allocated and we are allowed to destroy it
|
|
|
|
if (VALID_ENTITY(inst.mID) && !(inst.mFlags & ENF_LOCKED))
|
|
|
|
{
|
|
|
|
inst.Destroy(destroy, header, payload); // Now attempt to destroy the entity from the server
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------------------
|
|
|
|
void Core::DeallocObject(int32_t id, bool destroy, int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Make sure that the specified entity identifier is valid
|
|
|
|
if (INVALID_ENTITYEX(id, SQMOD_OBJECT_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Cannot deallocate object with invalid identifier: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Retrieve the specified entity instance
|
|
|
|
ObjectInst & inst = m_Objects[id];
|
|
|
|
// Make sure that the instance is even allocated and we are allowed to destroy it
|
|
|
|
if (VALID_ENTITY(inst.mID) && !(inst.mFlags & ENF_LOCKED))
|
|
|
|
{
|
|
|
|
inst.Destroy(destroy, header, payload); // Now attempt to destroy the entity from the server
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------------------
|
|
|
|
void Core::DeallocPickup(int32_t id, bool destroy, int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Make sure that the specified entity identifier is valid
|
|
|
|
if (INVALID_ENTITYEX(id, SQMOD_PICKUP_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Cannot deallocate pickup with invalid identifier: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Retrieve the specified entity instance
|
|
|
|
PickupInst & inst = m_Pickups[id];
|
|
|
|
// Make sure that the instance is even allocated and we are allowed to destroy it
|
|
|
|
if (VALID_ENTITY(inst.mID) && !(inst.mFlags & ENF_LOCKED))
|
|
|
|
{
|
|
|
|
inst.Destroy(destroy, header, payload); // Now attempt to destroy the entity from the server
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------------------
|
|
|
|
void Core::DeallocVehicle(int32_t id, bool destroy, int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Make sure that the specified entity identifier is valid
|
|
|
|
if (INVALID_ENTITYEX(id, SQMOD_VEHICLE_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Cannot deallocate vehicle with invalid identifier: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Retrieve the specified entity instance
|
|
|
|
VehicleInst & inst = m_Vehicles[id];
|
|
|
|
// Make sure that the instance is even allocated and we are allowed to destroy it
|
|
|
|
if (VALID_ENTITY(inst.mID) && !(inst.mFlags & ENF_LOCKED))
|
|
|
|
{
|
|
|
|
inst.Destroy(destroy, header, payload); // Now attempt to destroy the entity from the server
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------------------
|
2021-03-20 10:51:40 +01:00
|
|
|
BlipInst & Core::NewBlip(int32_t index, int32_t world, float x, float y, float z,
|
|
|
|
int32_t scale, uint32_t color, int32_t spr_id,
|
2021-01-30 07:51:39 +01:00
|
|
|
int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Request the server to create this entity
|
2021-03-20 10:51:40 +01:00
|
|
|
const int32_t id = _Func->CreateCoordBlip(index, world, x, y, z, scale, color, spr_id);
|
2021-01-30 07:51:39 +01:00
|
|
|
// See if the entity creation failed on the server
|
|
|
|
if (_Func->GetLastError() == vcmpErrorPoolExhausted)
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Blip pool was exhausted: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Validate the identifier returned by the server
|
|
|
|
else if (INVALID_ENTITYEX(id, SQMOD_BLIP_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Server returned invalid blip: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Attempt to allocate this entity and grab the reference to the instance
|
|
|
|
BlipInst & inst = AllocBlip(id, true, header, payload);
|
|
|
|
// Just in case it was created during the notification for changes in entity pool
|
|
|
|
if (VALID_ENTITY(inst.mID))
|
|
|
|
{
|
|
|
|
inst.mFlags |= ENF_OWNED;
|
|
|
|
}
|
|
|
|
// Now we can return the script object
|
2021-03-20 10:51:40 +01:00
|
|
|
return inst;
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------------------
|
2021-03-20 10:51:40 +01:00
|
|
|
CheckpointInst & Core::NewCheckpoint(int32_t player, int32_t world, bool sphere, float x, float y, float z,
|
2021-01-30 07:51:39 +01:00
|
|
|
uint8_t r, uint8_t g, uint8_t b, uint8_t a, float radius,
|
|
|
|
int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Request the server to create this entity
|
|
|
|
const int32_t id = _Func->CreateCheckPoint(player, world, sphere, x, y, z, r, g, b, a, radius);
|
|
|
|
// See if the entity creation failed on the server
|
|
|
|
if (_Func->GetLastError() == vcmpErrorNoSuchEntity)
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Invalid player reference: {}", player);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
else if (_Func->GetLastError() == vcmpErrorPoolExhausted)
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Checkpoint pool was exhausted: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Validate the identifier returned by the server
|
|
|
|
else if (INVALID_ENTITYEX(id, SQMOD_CHECKPOINT_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Server returned invalid checkpoint: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Attempt to allocate this entity and grab the reference to the instance
|
|
|
|
CheckpointInst & inst = AllocCheckpoint(id, true, header, payload);
|
|
|
|
// Just in case it was created during the notification for changes in entity pool
|
|
|
|
if (VALID_ENTITY(inst.mID))
|
|
|
|
{
|
|
|
|
inst.mFlags |= ENF_OWNED;
|
|
|
|
}
|
|
|
|
// Now we can return the script object
|
2021-03-20 10:51:40 +01:00
|
|
|
return inst;
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------------------
|
2021-03-20 10:51:40 +01:00
|
|
|
KeyBindInst & Core::NewKeyBind(int32_t slot, bool release, int32_t primary, int32_t secondary, int32_t alternative,
|
2021-01-30 07:51:39 +01:00
|
|
|
int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Should we obtain a new keybind slot automatically?
|
|
|
|
if (slot < 0)
|
|
|
|
{
|
|
|
|
slot = _Func->GetKeyBindUnusedSlot();
|
|
|
|
}
|
|
|
|
// Validate the keybind slot returned by the server
|
|
|
|
if (INVALID_ENTITYEX(slot, SQMOD_KEYBIND_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Server returned invalid keybind slot: {}", slot);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Request the server to create this entity
|
|
|
|
const vcmpError result = _Func->RegisterKeyBind(slot, release, primary, secondary, alternative);
|
|
|
|
// See if the entity creation failed on the server
|
|
|
|
if (result == vcmpErrorArgumentOutOfBounds)
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Out of bounds keybind argument: {}", slot);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Attempt to allocate this entity and grab the reference to the instance
|
|
|
|
KeyBindInst & inst = AllocKeyBind(slot, true, header, payload);
|
|
|
|
// Just in case it was created during the notification for changes in entity pool
|
|
|
|
if (VALID_ENTITY(inst.mID))
|
|
|
|
{
|
|
|
|
inst.mFlags |= ENF_OWNED;
|
|
|
|
}
|
|
|
|
// Now we can return the script object
|
2021-03-20 10:51:40 +01:00
|
|
|
return inst;
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------------------
|
2021-03-20 10:51:40 +01:00
|
|
|
ObjectInst & Core::NewObject(int32_t model, int32_t world, float x, float y, float z, int32_t alpha,
|
2021-01-30 07:51:39 +01:00
|
|
|
int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Request the server to create this entity
|
|
|
|
const int32_t id = _Func->CreateObject(model, world, x, y, z, alpha);
|
|
|
|
// See if the entity creation failed on the server
|
|
|
|
if (_Func->GetLastError() == vcmpErrorPoolExhausted)
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Object pool was exhausted: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Validate the identifier returned by the server
|
|
|
|
else if (INVALID_ENTITYEX(id, SQMOD_OBJECT_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Server returned invalid object: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Attempt to allocate this entity and grab the reference to the instance
|
|
|
|
ObjectInst & inst = AllocObject(id, true, header, payload);
|
|
|
|
// Just in case it was created during the notification for changes in entity pool
|
|
|
|
if (VALID_ENTITY(inst.mID))
|
|
|
|
{
|
|
|
|
inst.mFlags |= ENF_OWNED;
|
|
|
|
}
|
|
|
|
// Now we can return the script object
|
2021-03-20 10:51:40 +01:00
|
|
|
return inst;
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------------------
|
2021-03-20 10:51:40 +01:00
|
|
|
PickupInst & Core::NewPickup(int32_t model, int32_t world, int32_t quantity,
|
2021-01-30 07:51:39 +01:00
|
|
|
float x, float y, float z, int32_t alpha, bool automatic,
|
|
|
|
int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Request the server to create this entity
|
|
|
|
const int32_t id = _Func->CreatePickup(model, world, quantity, x, y, z, alpha, automatic);
|
|
|
|
// See if the entity creation failed on the server
|
|
|
|
if (_Func->GetLastError() == vcmpErrorPoolExhausted)
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Pickup pool was exhausted: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Validate the identifier returned by the server
|
|
|
|
else if (INVALID_ENTITYEX(id, SQMOD_PICKUP_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Server returned invalid pickup: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Attempt to allocate this entity and grab the reference to the instance
|
|
|
|
PickupInst & inst = AllocPickup(id, true, header, payload);
|
|
|
|
// Just in case it was created during the notification for changes in entity pool
|
|
|
|
if (VALID_ENTITY(inst.mID))
|
|
|
|
{
|
|
|
|
inst.mFlags |= ENF_OWNED;
|
|
|
|
}
|
|
|
|
// Now we can return the script object
|
2021-03-20 10:51:40 +01:00
|
|
|
return inst;
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------------------
|
2021-03-20 10:51:40 +01:00
|
|
|
VehicleInst & Core::NewVehicle(int32_t model, int32_t world, float x, float y, float z,
|
2021-01-30 07:51:39 +01:00
|
|
|
float angle, int32_t primary, int32_t secondary,
|
|
|
|
int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
|
|
|
|
// Request the server to create this entity
|
|
|
|
const int32_t id = _Func->CreateVehicle(model, world, x, y, z, angle, primary, secondary);
|
|
|
|
// See if the entity creation failed on the server
|
|
|
|
if (_Func->GetLastError() == vcmpErrorArgumentOutOfBounds)
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Out of bounds vehicle argument: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
else if (_Func->GetLastError() == vcmpErrorPoolExhausted)
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Vehicle pool was exhausted: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Validate the identifier returned by the server
|
|
|
|
else if (INVALID_ENTITYEX(id, SQMOD_VEHICLE_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Server returned invalid vehicle: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Attempt to allocate this entity and grab the reference to the instance
|
|
|
|
VehicleInst & inst = AllocVehicle(id, true, header, payload);
|
|
|
|
// Just in case it was created during the notification for changes in entity pool
|
|
|
|
if (VALID_ENTITY(inst.mID))
|
|
|
|
{
|
|
|
|
inst.mFlags |= ENF_OWNED;
|
|
|
|
}
|
|
|
|
// Now we can return the script object
|
2021-03-20 10:51:40 +01:00
|
|
|
return inst;
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------------------------
|
|
|
|
bool Core::DelBlip(int32_t id, int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Attempt to destroy and deallocate the specified entity instance
|
|
|
|
DeallocBlip(id, true, header, payload);
|
|
|
|
// The entity could be destroyed
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
bool Core::DelCheckpoint(int32_t id, int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Attempt to destroy and deallocate the specified entity instance
|
|
|
|
DeallocCheckpoint(id, true, header, payload);
|
|
|
|
// The entity could be destroyed
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
bool Core::DelKeyBind(int32_t id, int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Attempt to destroy and deallocate the specified entity instance
|
|
|
|
DeallocKeyBind(id, true, header, payload);
|
|
|
|
// The entity could be destroyed
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
bool Core::DelObject(int32_t id, int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Attempt to destroy and deallocate the specified entity instance
|
|
|
|
DeallocObject(id, true, header, payload);
|
|
|
|
// The entity could be destroyed
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
bool Core::DelPickup(int32_t id, int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Attempt to destroy and deallocate the specified entity instance
|
|
|
|
DeallocPickup(id, true, header, payload);
|
|
|
|
// The entity could be destroyed
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
bool Core::DelVehicle(int32_t id, int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Attempt to destroy and deallocate the specified entity instance
|
|
|
|
DeallocVehicle(id, true, header, payload);
|
|
|
|
// The entity could be destroyed
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
void Core::ConnectPlayer(int32_t id, int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Make sure that the specified entity identifier is valid
|
|
|
|
if (INVALID_ENTITYEX(id, SQMOD_PLAYER_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Cannot allocate player with invalid identifier: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Retrieve the specified entity instance
|
|
|
|
PlayerInst & inst = m_Players[id];
|
|
|
|
// Make sure that the instance isn't already allocated
|
|
|
|
if (VALID_ENTITY(inst.mID))
|
|
|
|
{
|
|
|
|
return; // Nothing to allocate!
|
|
|
|
}
|
2021-03-15 06:02:48 +01:00
|
|
|
#ifdef VCMP_ENABLE_OFFICIAL
|
|
|
|
// Do we need to support legacy API?
|
|
|
|
if (IsOfficial())
|
|
|
|
{
|
|
|
|
// Create the legacy wrapper object
|
|
|
|
inst.mLgObj = LgPlayerObj(m_VM, id);
|
|
|
|
// Obtain the legacy wrapper instance
|
|
|
|
inst.mLgInst = inst.mLgObj.CastI< LgPlayer >();
|
|
|
|
// Make sure that both the instance and script object could be created
|
|
|
|
if (!inst.mLgInst || inst.mLgObj.IsNull())
|
|
|
|
{
|
|
|
|
inst.ResetInstance();
|
|
|
|
// Make sure that if an instance was created, it points to nothing
|
|
|
|
if (inst.mLgInst)
|
|
|
|
{
|
|
|
|
LgPlayerSetID(inst.mLgInst, -1);
|
|
|
|
}
|
|
|
|
// Make sure that if an object was created, it is released
|
|
|
|
if (!inst.mLgObj.IsNull())
|
|
|
|
{
|
|
|
|
inst.mLgObj.Release();
|
|
|
|
}
|
|
|
|
// Now we can throw the error
|
|
|
|
STHROWF("Unable to create a player wrapper instance for: {}", id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2021-01-30 07:51:39 +01:00
|
|
|
// Instantiate the entity manager
|
|
|
|
DeleteGuard< CPlayer > dg(new CPlayer(id));
|
|
|
|
// Create the script object
|
|
|
|
inst.mObj = LightObj(dg.Get(), m_VM);
|
|
|
|
// Store the manager instance itself
|
|
|
|
inst.mInst = dg.Get();
|
|
|
|
// The instance is now managed by the script
|
|
|
|
dg.Release();
|
|
|
|
// Make sure that both the instance and script object could be created
|
|
|
|
if (!inst.mInst || inst.mObj.IsNull())
|
|
|
|
{
|
|
|
|
inst.ResetInstance();
|
2021-03-15 06:02:48 +01:00
|
|
|
#ifdef VCMP_ENABLE_OFFICIAL
|
|
|
|
// Discard legacy wrapper instance
|
|
|
|
if (IsOfficial())
|
|
|
|
{
|
|
|
|
LgPlayerSetID(inst.mLgInst, -1);
|
|
|
|
inst.mLgObj.Release();
|
|
|
|
inst.mLgInst = nullptr;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
// Make sure that if an instance was created, it points to nothing
|
|
|
|
if (inst.mInst)
|
|
|
|
{
|
|
|
|
inst.mInst->m_ID = -1;
|
|
|
|
}
|
|
|
|
// Make sure that if an object was created, it is released
|
|
|
|
if (!inst.mObj.IsNull())
|
|
|
|
{
|
|
|
|
inst.mObj.Release();
|
|
|
|
}
|
|
|
|
// Now we can throw the error
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Unable to create a player instance for: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Assign the specified entity identifier
|
|
|
|
inst.mID = id;
|
|
|
|
// Should we enable area tracking?
|
|
|
|
if (m_AreasEnabled)
|
|
|
|
{
|
|
|
|
inst.mFlags |= ENF_AREA_TRACK;
|
|
|
|
}
|
|
|
|
// Initialize the position
|
|
|
|
_Func->GetPlayerPosition(id, &inst.mLastPosition.x, &inst.mLastPosition.y, &inst.mLastPosition.z);
|
|
|
|
// Initialize the remaining attributes
|
|
|
|
inst.mLastWeapon = _Func->GetPlayerWeapon(id);
|
|
|
|
inst.mLastHealth = _Func->GetPlayerHealth(id);
|
|
|
|
inst.mLastArmour = _Func->GetPlayerArmour(id);
|
|
|
|
inst.mLastHeading = _Func->GetPlayerHeading(id);
|
|
|
|
// Initialize the instance events
|
|
|
|
inst.InitEvents();
|
|
|
|
// Let the script callbacks know about this entity
|
|
|
|
EmitPlayerCreated(id, header, payload);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
void Core::DisconnectPlayer(int32_t id, int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Make sure that the specified entity identifier is valid
|
|
|
|
if (INVALID_ENTITYEX(id, SQMOD_PLAYER_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Cannot deallocate player with invalid identifier: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Retrieve the specified entity instance
|
|
|
|
PlayerInst & inst = m_Players[id];
|
|
|
|
// Make sure that the instance is even allocated and we are allowed to destroy it
|
|
|
|
if (VALID_ENTITY(inst.mID) && !(inst.mFlags & ENF_LOCKED))
|
|
|
|
{
|
|
|
|
inst.Destroy(false, header, payload); // Now attempt to destroy the entity from the server
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
void Core::ClearContainer(EntityType type)
|
|
|
|
{
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case ENT_BLIP:
|
|
|
|
{
|
|
|
|
m_Blips.clear();
|
|
|
|
} break;
|
|
|
|
case ENT_CHECKPOINT:
|
|
|
|
{
|
|
|
|
m_Checkpoints.clear();
|
|
|
|
} break;
|
|
|
|
case ENT_KEYBIND:
|
|
|
|
{
|
|
|
|
m_KeyBinds.clear();
|
|
|
|
} break;
|
|
|
|
case ENT_OBJECT:
|
|
|
|
{
|
|
|
|
m_Objects.clear();
|
|
|
|
} break;
|
|
|
|
case ENT_PICKUP:
|
|
|
|
{
|
|
|
|
m_Pickups.clear();
|
|
|
|
} break;
|
|
|
|
case ENT_PLAYER:
|
|
|
|
{
|
|
|
|
m_Players.clear();
|
|
|
|
} break;
|
|
|
|
case ENT_VEHICLE:
|
|
|
|
{
|
|
|
|
m_Vehicles.clear();
|
|
|
|
} break;
|
|
|
|
default: STHROWF("Cannot clear unknown entity type container");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
void Core::InitEvents()
|
|
|
|
{
|
|
|
|
// Ignore the call if already initialized
|
|
|
|
if (!m_Events.IsNull())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Create a new table on the stack
|
|
|
|
sq_newtableex(SqVM(), 128);
|
|
|
|
// Grab the table object from the stack
|
|
|
|
m_Events = LightObj(-1, SqVM());
|
|
|
|
// Pop the table object from the stack
|
|
|
|
sq_pop(SqVM(), 1);
|
|
|
|
// Proceed to initializing the events
|
|
|
|
InitSignalPair(mOnCustomEvent, m_Events, "CustomEvent");
|
|
|
|
InitSignalPair(mOnBlipCreated, m_Events, "BlipCreated");
|
|
|
|
InitSignalPair(mOnCheckpointCreated, m_Events, "CheckpointCreated");
|
|
|
|
InitSignalPair(mOnKeyBindCreated, m_Events, "KeyBindCreated");
|
|
|
|
InitSignalPair(mOnObjectCreated, m_Events, "ObjectCreated");
|
|
|
|
InitSignalPair(mOnPickupCreated, m_Events, "PickupCreated");
|
|
|
|
InitSignalPair(mOnPlayerCreated, m_Events, "PlayerCreated");
|
|
|
|
InitSignalPair(mOnVehicleCreated, m_Events, "VehicleCreated");
|
|
|
|
InitSignalPair(mOnBlipDestroyed, m_Events, "BlipDestroyed");
|
|
|
|
InitSignalPair(mOnCheckpointDestroyed, m_Events, "CheckpointDestroyed");
|
|
|
|
InitSignalPair(mOnKeyBindDestroyed, m_Events, "KeyBindDestroyed");
|
|
|
|
InitSignalPair(mOnObjectDestroyed, m_Events, "ObjectDestroyed");
|
|
|
|
InitSignalPair(mOnPickupDestroyed, m_Events, "PickupDestroyed");
|
|
|
|
InitSignalPair(mOnPlayerDestroyed, m_Events, "PlayerDestroyed");
|
|
|
|
InitSignalPair(mOnVehicleDestroyed, m_Events, "VehicleDestroyed");
|
|
|
|
InitSignalPair(mOnBlipCustom, m_Events, "BlipCustom");
|
|
|
|
InitSignalPair(mOnCheckpointCustom, m_Events, "CheckpointCustom");
|
|
|
|
InitSignalPair(mOnKeyBindCustom, m_Events, "KeyBindCustom");
|
|
|
|
InitSignalPair(mOnObjectCustom, m_Events, "ObjectCustom");
|
|
|
|
InitSignalPair(mOnPickupCustom, m_Events, "PickupCustom");
|
|
|
|
InitSignalPair(mOnPlayerCustom, m_Events, "PlayerCustom");
|
|
|
|
InitSignalPair(mOnVehicleCustom, m_Events, "VehicleCustom");
|
|
|
|
#if SQMOD_SDK_LEAST(2, 1)
|
|
|
|
InitSignalPair(mOnCheckpointStream, m_Events, "CheckpointStream");
|
|
|
|
InitSignalPair(mOnObjectStream, m_Events, "ObjectStream");
|
|
|
|
InitSignalPair(mOnPickupStream, m_Events, "PickupStream");
|
|
|
|
InitSignalPair(mOnPlayerStream, m_Events, "PlayerStream");
|
|
|
|
InitSignalPair(mOnVehicleStream, m_Events, "VehicleStream");
|
|
|
|
#endif
|
|
|
|
InitSignalPair(mOnServerStartup, m_Events, "ServerStartup");
|
|
|
|
InitSignalPair(mOnServerShutdown, m_Events, "ServerShutdown");
|
|
|
|
InitSignalPair(mOnServerFrame, m_Events, "ServerFrame");
|
|
|
|
InitSignalPair(mOnIncomingConnection, m_Events, "IncomingConnection");
|
|
|
|
InitSignalPair(mOnPlayerRequestClass, m_Events, "PlayerRequestClass");
|
|
|
|
InitSignalPair(mOnPlayerRequestSpawn, m_Events, "PlayerRequestSpawn");
|
|
|
|
InitSignalPair(mOnPlayerSpawn, m_Events, "PlayerSpawn");
|
|
|
|
InitSignalPair(mOnPlayerWasted, m_Events, "PlayerWasted");
|
|
|
|
InitSignalPair(mOnPlayerKilled, m_Events, "PlayerKilled");
|
|
|
|
InitSignalPair(mOnPlayerEmbarking, m_Events, "PlayerEmbarking");
|
|
|
|
InitSignalPair(mOnPlayerEmbarked, m_Events, "PlayerEmbarked");
|
|
|
|
InitSignalPair(mOnPlayerDisembark, m_Events, "PlayerDisembark");
|
|
|
|
InitSignalPair(mOnPlayerRename, m_Events, "PlayerRename");
|
|
|
|
InitSignalPair(mOnPlayerState, m_Events, "PlayerState");
|
|
|
|
InitSignalPair(mOnStateNone, m_Events, "StateNone");
|
|
|
|
InitSignalPair(mOnStateNormal, m_Events, "StateNormal");
|
|
|
|
InitSignalPair(mOnStateAim, m_Events, "StateAim");
|
|
|
|
InitSignalPair(mOnStateDriver, m_Events, "StateDriver");
|
|
|
|
InitSignalPair(mOnStatePassenger, m_Events, "StatePassenger");
|
|
|
|
InitSignalPair(mOnStateEnterDriver, m_Events, "StateEnterDriver");
|
|
|
|
InitSignalPair(mOnStateEnterPassenger, m_Events, "StateEnterPassenger");
|
|
|
|
InitSignalPair(mOnStateExit, m_Events, "StateExit");
|
|
|
|
InitSignalPair(mOnStateUnspawned, m_Events, "StateUnspawned");
|
|
|
|
InitSignalPair(mOnPlayerAction, m_Events, "PlayerAction");
|
|
|
|
InitSignalPair(mOnActionNone, m_Events, "ActionNone");
|
|
|
|
InitSignalPair(mOnActionNormal, m_Events, "ActionNormal");
|
|
|
|
InitSignalPair(mOnActionAiming, m_Events, "ActionAiming");
|
|
|
|
InitSignalPair(mOnActionShooting, m_Events, "ActionShooting");
|
|
|
|
InitSignalPair(mOnActionJumping, m_Events, "ActionJumping");
|
|
|
|
InitSignalPair(mOnActionLieDown, m_Events, "ActionLieDown");
|
|
|
|
InitSignalPair(mOnActionGettingUp, m_Events, "ActionGettingUp");
|
|
|
|
InitSignalPair(mOnActionJumpVehicle, m_Events, "ActionJumpVehicle");
|
|
|
|
InitSignalPair(mOnActionDriving, m_Events, "ActionDriving");
|
|
|
|
InitSignalPair(mOnActionDying, m_Events, "ActionDying");
|
|
|
|
InitSignalPair(mOnActionWasted, m_Events, "ActionWasted");
|
|
|
|
InitSignalPair(mOnActionEmbarking, m_Events, "ActionEmbarking");
|
|
|
|
InitSignalPair(mOnActionDisembarking, m_Events, "ActionDisembarking");
|
|
|
|
InitSignalPair(mOnPlayerBurning, m_Events, "PlayerBurning");
|
|
|
|
InitSignalPair(mOnPlayerCrouching, m_Events, "PlayerCrouching");
|
|
|
|
InitSignalPair(mOnPlayerGameKeys, m_Events, "PlayerGameKeys");
|
|
|
|
InitSignalPair(mOnPlayerStartTyping, m_Events, "PlayerStartTyping");
|
|
|
|
InitSignalPair(mOnPlayerStopTyping, m_Events, "PlayerStopTyping");
|
|
|
|
InitSignalPair(mOnPlayerAway, m_Events, "PlayerAway");
|
|
|
|
InitSignalPair(mOnPlayerMessage, m_Events, "PlayerMessage");
|
|
|
|
InitSignalPair(mOnPlayerCommand, m_Events, "PlayerCommand");
|
|
|
|
InitSignalPair(mOnPlayerPrivateMessage, m_Events, "PlayerPrivateMessage");
|
|
|
|
InitSignalPair(mOnPlayerKeyPress, m_Events, "PlayerKeyPress");
|
|
|
|
InitSignalPair(mOnPlayerKeyRelease, m_Events, "PlayerKeyRelease");
|
|
|
|
InitSignalPair(mOnPlayerSpectate, m_Events, "PlayerSpectate");
|
|
|
|
InitSignalPair(mOnPlayerUnspectate, m_Events, "PlayerUnspectate");
|
|
|
|
InitSignalPair(mOnPlayerCrashReport, m_Events, "PlayerCrashReport");
|
|
|
|
InitSignalPair(mOnPlayerModuleList, m_Events, "PlayerModuleList");
|
|
|
|
InitSignalPair(mOnVehicleExplode, m_Events, "VehicleExplode");
|
|
|
|
InitSignalPair(mOnVehicleRespawn, m_Events, "VehicleRespawn");
|
|
|
|
InitSignalPair(mOnObjectShot, m_Events, "ObjectShot");
|
|
|
|
InitSignalPair(mOnObjectTouched, m_Events, "ObjectTouched");
|
|
|
|
InitSignalPair(mOnObjectWorld, m_Events, "ObjectWorld");
|
|
|
|
InitSignalPair(mOnObjectAlpha, m_Events, "ObjectAlpha");
|
|
|
|
InitSignalPair(mOnObjectReport, m_Events, "ObjectReport");
|
|
|
|
InitSignalPair(mOnPickupClaimed, m_Events, "PickupClaimed");
|
|
|
|
InitSignalPair(mOnPickupCollected, m_Events, "PickupCollected");
|
|
|
|
InitSignalPair(mOnPickupRespawn, m_Events, "PickupRespawn");
|
|
|
|
InitSignalPair(mOnPickupWorld, m_Events, "PickupWorld");
|
|
|
|
InitSignalPair(mOnPickupAlpha, m_Events, "PickupAlpha");
|
|
|
|
InitSignalPair(mOnPickupAutomatic, m_Events, "PickupAutomatic");
|
|
|
|
InitSignalPair(mOnPickupAutoTimer, m_Events, "PickupAutoTimer");
|
|
|
|
InitSignalPair(mOnPickupOption, m_Events, "PickupOption");
|
|
|
|
InitSignalPair(mOnCheckpointEntered, m_Events, "CheckpointEntered");
|
|
|
|
InitSignalPair(mOnCheckpointExited, m_Events, "CheckpointExited");
|
|
|
|
InitSignalPair(mOnCheckpointWorld, m_Events, "CheckpointWorld");
|
|
|
|
InitSignalPair(mOnCheckpointRadius, m_Events, "CheckpointRadius");
|
|
|
|
InitSignalPair(mOnEntityPool, m_Events, "EntityPool");
|
|
|
|
InitSignalPair(mOnClientScriptData, m_Events, "ClientScriptData");
|
|
|
|
InitSignalPair(mOnPlayerUpdate, m_Events, "PlayerUpdate");
|
|
|
|
InitSignalPair(mOnVehicleUpdate, m_Events, "VehicleUpdate");
|
|
|
|
InitSignalPair(mOnPlayerHealth, m_Events, "PlayerHealth");
|
|
|
|
InitSignalPair(mOnPlayerArmour, m_Events, "PlayerArmour");
|
|
|
|
InitSignalPair(mOnPlayerWeapon, m_Events, "PlayerWeapon");
|
|
|
|
InitSignalPair(mOnPlayerHeading, m_Events, "PlayerHeading");
|
|
|
|
InitSignalPair(mOnPlayerPosition, m_Events, "PlayerPosition");
|
|
|
|
InitSignalPair(mOnPlayerOption, m_Events, "PlayerOption");
|
|
|
|
InitSignalPair(mOnPlayerAdmin, m_Events, "PlayerAdmin");
|
|
|
|
InitSignalPair(mOnPlayerWorld, m_Events, "PlayerWorld");
|
|
|
|
InitSignalPair(mOnPlayerTeam, m_Events, "PlayerTeam");
|
|
|
|
InitSignalPair(mOnPlayerSkin, m_Events, "PlayerSkin");
|
|
|
|
InitSignalPair(mOnPlayerMoney, m_Events, "PlayerMoney");
|
|
|
|
InitSignalPair(mOnPlayerScore, m_Events, "PlayerScore");
|
|
|
|
InitSignalPair(mOnPlayerWantedLevel, m_Events, "PlayerWantedLevel");
|
|
|
|
InitSignalPair(mOnPlayerImmunity, m_Events, "PlayerImmunity");
|
|
|
|
InitSignalPair(mOnPlayerAlpha, m_Events, "PlayerAlpha");
|
|
|
|
InitSignalPair(mOnPlayerEnterArea, m_Events, "PlayerEnterArea");
|
|
|
|
InitSignalPair(mOnPlayerLeaveArea, m_Events, "PlayerLeaveArea");
|
|
|
|
InitSignalPair(mOnVehicleColor, m_Events, "VehicleColor");
|
|
|
|
InitSignalPair(mOnVehicleHealth, m_Events, "VehicleHealth");
|
|
|
|
InitSignalPair(mOnVehiclePosition, m_Events, "VehiclePosition");
|
|
|
|
InitSignalPair(mOnVehicleRotation, m_Events, "VehicleRotation");
|
|
|
|
InitSignalPair(mOnVehicleOption, m_Events, "VehicleOption");
|
|
|
|
InitSignalPair(mOnVehicleWorld, m_Events, "VehicleWorld");
|
|
|
|
InitSignalPair(mOnVehicleImmunity, m_Events, "VehicleImmunity");
|
|
|
|
InitSignalPair(mOnVehiclePartStatus, m_Events, "VehiclePartStatus");
|
|
|
|
InitSignalPair(mOnVehicleTyreStatus, m_Events, "VehicleTyreStatus");
|
|
|
|
InitSignalPair(mOnVehicleDamageData, m_Events, "VehicleDamageData");
|
|
|
|
InitSignalPair(mOnVehicleRadio, m_Events, "VehicleRadio");
|
|
|
|
InitSignalPair(mOnVehicleHandlingRule, m_Events, "VehicleHandlingRule");
|
|
|
|
InitSignalPair(mOnVehicleEnterArea, m_Events, "VehicleEnterArea");
|
|
|
|
InitSignalPair(mOnVehicleLeaveArea, m_Events, "VehicleLeaveArea");
|
|
|
|
#if SQMOD_SDK_LEAST(2, 1)
|
|
|
|
InitSignalPair(mOnEntityStream, m_Events, "EntityStream");
|
|
|
|
#endif
|
|
|
|
InitSignalPair(mOnServerOption, m_Events, "ServerOption");
|
|
|
|
InitSignalPair(mOnScriptReload, m_Events, "ScriptReload");
|
2021-07-04 13:08:03 +02:00
|
|
|
InitSignalPair(mOnScriptLoaded, m_Events, "ScriptLoaded");
|
2023-03-05 14:38:59 +01:00
|
|
|
InitSignalPair(mOnExtCommandReply, m_Events, "ExtCommandReply");
|
|
|
|
InitSignalPair(mOnExtCommandEvent, m_Events, "ExtCommandEvent");
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
void Core::DropEvents()
|
|
|
|
{
|
|
|
|
ResetSignalPair(mOnCustomEvent);
|
|
|
|
ResetSignalPair(mOnBlipCreated);
|
|
|
|
ResetSignalPair(mOnCheckpointCreated);
|
|
|
|
ResetSignalPair(mOnKeyBindCreated);
|
|
|
|
ResetSignalPair(mOnObjectCreated);
|
|
|
|
ResetSignalPair(mOnPickupCreated);
|
|
|
|
ResetSignalPair(mOnPlayerCreated);
|
|
|
|
ResetSignalPair(mOnVehicleCreated);
|
|
|
|
ResetSignalPair(mOnBlipDestroyed);
|
|
|
|
ResetSignalPair(mOnCheckpointDestroyed);
|
|
|
|
ResetSignalPair(mOnKeyBindDestroyed);
|
|
|
|
ResetSignalPair(mOnObjectDestroyed);
|
|
|
|
ResetSignalPair(mOnPickupDestroyed);
|
|
|
|
ResetSignalPair(mOnPlayerDestroyed);
|
|
|
|
ResetSignalPair(mOnVehicleDestroyed);
|
|
|
|
ResetSignalPair(mOnBlipCustom);
|
|
|
|
ResetSignalPair(mOnCheckpointCustom);
|
|
|
|
ResetSignalPair(mOnKeyBindCustom);
|
|
|
|
ResetSignalPair(mOnObjectCustom);
|
|
|
|
ResetSignalPair(mOnPickupCustom);
|
|
|
|
ResetSignalPair(mOnPlayerCustom);
|
|
|
|
ResetSignalPair(mOnVehicleCustom);
|
|
|
|
#if SQMOD_SDK_LEAST(2, 1)
|
|
|
|
ResetSignalPair(mOnCheckpointStream);
|
|
|
|
ResetSignalPair(mOnObjectStream);
|
|
|
|
ResetSignalPair(mOnPickupStream);
|
|
|
|
ResetSignalPair(mOnPlayerStream);
|
|
|
|
ResetSignalPair(mOnVehicleStream);
|
|
|
|
#endif
|
|
|
|
ResetSignalPair(mOnServerStartup);
|
|
|
|
ResetSignalPair(mOnServerShutdown);
|
|
|
|
ResetSignalPair(mOnServerFrame);
|
|
|
|
ResetSignalPair(mOnIncomingConnection);
|
|
|
|
ResetSignalPair(mOnPlayerRequestClass);
|
|
|
|
ResetSignalPair(mOnPlayerRequestSpawn);
|
|
|
|
ResetSignalPair(mOnPlayerSpawn);
|
|
|
|
ResetSignalPair(mOnPlayerWasted);
|
|
|
|
ResetSignalPair(mOnPlayerKilled);
|
|
|
|
ResetSignalPair(mOnPlayerEmbarking);
|
|
|
|
ResetSignalPair(mOnPlayerEmbarked);
|
|
|
|
ResetSignalPair(mOnPlayerDisembark);
|
|
|
|
ResetSignalPair(mOnPlayerRename);
|
|
|
|
ResetSignalPair(mOnPlayerState);
|
|
|
|
ResetSignalPair(mOnStateNone);
|
|
|
|
ResetSignalPair(mOnStateNormal);
|
|
|
|
ResetSignalPair(mOnStateAim);
|
|
|
|
ResetSignalPair(mOnStateDriver);
|
|
|
|
ResetSignalPair(mOnStatePassenger);
|
|
|
|
ResetSignalPair(mOnStateEnterDriver);
|
|
|
|
ResetSignalPair(mOnStateEnterPassenger);
|
|
|
|
ResetSignalPair(mOnStateExit);
|
|
|
|
ResetSignalPair(mOnStateUnspawned);
|
|
|
|
ResetSignalPair(mOnPlayerAction);
|
|
|
|
ResetSignalPair(mOnActionNone);
|
|
|
|
ResetSignalPair(mOnActionNormal);
|
|
|
|
ResetSignalPair(mOnActionAiming);
|
|
|
|
ResetSignalPair(mOnActionShooting);
|
|
|
|
ResetSignalPair(mOnActionJumping);
|
|
|
|
ResetSignalPair(mOnActionLieDown);
|
|
|
|
ResetSignalPair(mOnActionGettingUp);
|
|
|
|
ResetSignalPair(mOnActionJumpVehicle);
|
|
|
|
ResetSignalPair(mOnActionDriving);
|
|
|
|
ResetSignalPair(mOnActionDying);
|
|
|
|
ResetSignalPair(mOnActionWasted);
|
|
|
|
ResetSignalPair(mOnActionEmbarking);
|
|
|
|
ResetSignalPair(mOnActionDisembarking);
|
|
|
|
ResetSignalPair(mOnPlayerBurning);
|
|
|
|
ResetSignalPair(mOnPlayerCrouching);
|
|
|
|
ResetSignalPair(mOnPlayerGameKeys);
|
|
|
|
ResetSignalPair(mOnPlayerStartTyping);
|
|
|
|
ResetSignalPair(mOnPlayerStopTyping);
|
|
|
|
ResetSignalPair(mOnPlayerAway);
|
|
|
|
ResetSignalPair(mOnPlayerMessage);
|
|
|
|
ResetSignalPair(mOnPlayerCommand);
|
|
|
|
ResetSignalPair(mOnPlayerPrivateMessage);
|
|
|
|
ResetSignalPair(mOnPlayerKeyPress);
|
|
|
|
ResetSignalPair(mOnPlayerKeyRelease);
|
|
|
|
ResetSignalPair(mOnPlayerSpectate);
|
|
|
|
ResetSignalPair(mOnPlayerUnspectate);
|
|
|
|
ResetSignalPair(mOnPlayerCrashReport);
|
|
|
|
ResetSignalPair(mOnPlayerModuleList);
|
|
|
|
ResetSignalPair(mOnVehicleExplode);
|
|
|
|
ResetSignalPair(mOnVehicleRespawn);
|
|
|
|
ResetSignalPair(mOnObjectShot);
|
|
|
|
ResetSignalPair(mOnObjectTouched);
|
|
|
|
ResetSignalPair(mOnObjectWorld);
|
|
|
|
ResetSignalPair(mOnObjectAlpha);
|
|
|
|
ResetSignalPair(mOnObjectReport);
|
|
|
|
ResetSignalPair(mOnPickupClaimed);
|
|
|
|
ResetSignalPair(mOnPickupCollected);
|
|
|
|
ResetSignalPair(mOnPickupRespawn);
|
|
|
|
ResetSignalPair(mOnPickupWorld);
|
|
|
|
ResetSignalPair(mOnPickupAlpha);
|
|
|
|
ResetSignalPair(mOnPickupAutomatic);
|
|
|
|
ResetSignalPair(mOnPickupAutoTimer);
|
|
|
|
ResetSignalPair(mOnPickupOption);
|
|
|
|
ResetSignalPair(mOnCheckpointEntered);
|
|
|
|
ResetSignalPair(mOnCheckpointExited);
|
|
|
|
ResetSignalPair(mOnCheckpointWorld);
|
|
|
|
ResetSignalPair(mOnCheckpointRadius);
|
|
|
|
ResetSignalPair(mOnEntityPool);
|
|
|
|
ResetSignalPair(mOnClientScriptData);
|
|
|
|
ResetSignalPair(mOnPlayerUpdate);
|
|
|
|
ResetSignalPair(mOnVehicleUpdate);
|
|
|
|
ResetSignalPair(mOnPlayerHealth);
|
|
|
|
ResetSignalPair(mOnPlayerArmour);
|
|
|
|
ResetSignalPair(mOnPlayerWeapon);
|
|
|
|
ResetSignalPair(mOnPlayerHeading);
|
|
|
|
ResetSignalPair(mOnPlayerPosition);
|
|
|
|
ResetSignalPair(mOnPlayerOption);
|
|
|
|
ResetSignalPair(mOnPlayerAdmin);
|
|
|
|
ResetSignalPair(mOnPlayerWorld);
|
|
|
|
ResetSignalPair(mOnPlayerTeam);
|
|
|
|
ResetSignalPair(mOnPlayerSkin);
|
|
|
|
ResetSignalPair(mOnPlayerMoney);
|
|
|
|
ResetSignalPair(mOnPlayerScore);
|
|
|
|
ResetSignalPair(mOnPlayerWantedLevel);
|
|
|
|
ResetSignalPair(mOnPlayerImmunity);
|
|
|
|
ResetSignalPair(mOnPlayerAlpha);
|
|
|
|
ResetSignalPair(mOnPlayerEnterArea);
|
|
|
|
ResetSignalPair(mOnPlayerLeaveArea);
|
|
|
|
ResetSignalPair(mOnVehicleColor);
|
|
|
|
ResetSignalPair(mOnVehicleHealth);
|
|
|
|
ResetSignalPair(mOnVehiclePosition);
|
|
|
|
ResetSignalPair(mOnVehicleRotation);
|
|
|
|
ResetSignalPair(mOnVehicleOption);
|
|
|
|
ResetSignalPair(mOnVehicleWorld);
|
|
|
|
ResetSignalPair(mOnVehicleImmunity);
|
|
|
|
ResetSignalPair(mOnVehiclePartStatus);
|
|
|
|
ResetSignalPair(mOnVehicleTyreStatus);
|
|
|
|
ResetSignalPair(mOnVehicleDamageData);
|
|
|
|
ResetSignalPair(mOnVehicleRadio);
|
|
|
|
ResetSignalPair(mOnVehicleHandlingRule);
|
|
|
|
ResetSignalPair(mOnVehicleEnterArea);
|
|
|
|
ResetSignalPair(mOnVehicleLeaveArea);
|
|
|
|
#if SQMOD_SDK_LEAST(2, 1)
|
|
|
|
ResetSignalPair(mOnEntityStream);
|
|
|
|
#endif
|
|
|
|
ResetSignalPair(mOnServerOption);
|
|
|
|
ResetSignalPair(mOnScriptReload);
|
2021-07-04 13:08:03 +02:00
|
|
|
ResetSignalPair(mOnScriptLoaded);
|
2023-03-05 14:38:59 +01:00
|
|
|
ResetSignalPair(mOnExtCommandReply);
|
|
|
|
ResetSignalPair(mOnExtCommandEvent);
|
2021-01-30 07:51:39 +01:00
|
|
|
m_Events.Release();
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
extern bool GetReloadStatus();
|
|
|
|
extern void SetReloadStatus(bool toggle);
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
SQMOD_DECL_TYPENAME(CoreStateTypename, _SC("SqCoreState"))
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static SQInteger SqLoadScript(HSQUIRRELVM vm)
|
|
|
|
{
|
|
|
|
const int32_t top = sq_gettop(vm);
|
|
|
|
// Was the delay option specified?
|
|
|
|
if (top <= 1)
|
|
|
|
{
|
|
|
|
return sq_throwerror(vm, "Missing delay parameter");
|
|
|
|
}
|
|
|
|
// Was the script path specified?
|
|
|
|
else if (top <= 2)
|
|
|
|
{
|
|
|
|
return sq_throwerror(vm, "Missing script path");
|
|
|
|
}
|
|
|
|
// Whether the script execution is delayed
|
|
|
|
SQBool delay = SQFalse;
|
|
|
|
// Attempt to generate the string value
|
|
|
|
StackStrF val(vm, 3);
|
|
|
|
// Have we failed to retrieve the string?
|
|
|
|
if (SQ_FAILED(val.Proc(true)))
|
|
|
|
{
|
|
|
|
return val.mRes; // Propagate the error!
|
|
|
|
}
|
|
|
|
else if (SQ_FAILED(sq_getbool(vm, 2, &delay)))
|
|
|
|
{
|
|
|
|
return sq_throwerror(vm, "Failed to retrieve the delay parameter");
|
|
|
|
}
|
2021-07-03 18:46:39 +02:00
|
|
|
Function cb;
|
2021-07-04 01:19:37 +02:00
|
|
|
LightObj ctx;
|
2021-01-30 07:51:39 +01:00
|
|
|
// Forward the call to the actual implementation
|
2021-07-04 01:19:37 +02:00
|
|
|
sq_pushbool(vm, Core::Get().LoadScript(val.mPtr, cb, ctx, static_cast< bool >(delay)));
|
2021-01-30 07:51:39 +01:00
|
|
|
// We have an argument on the stack
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2021-07-03 18:46:39 +02:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
2021-07-04 01:19:37 +02:00
|
|
|
static bool SqLoadScriptNotify(bool delay, StackStrF & path, LightObj & ctx, Function & cb)
|
2021-07-03 18:46:39 +02:00
|
|
|
{
|
2021-07-04 01:19:37 +02:00
|
|
|
return Core::Get().LoadScript(path.mPtr, cb, ctx, delay);
|
2021-07-03 18:46:39 +02:00
|
|
|
}
|
|
|
|
|
2021-01-30 07:51:39 +01:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static SQInteger SqGetEvents(HSQUIRRELVM vm)
|
|
|
|
{
|
|
|
|
// Push the events table object on the stack
|
|
|
|
sq_pushobject(vm, Core::Get().GetEvents().mObj);
|
|
|
|
// Specify that we're returning a value
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2021-07-04 04:17:32 +02:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static SQInteger SqGetOnScript(HSQUIRRELVM vm)
|
|
|
|
{
|
|
|
|
// Push the events table object on the stack
|
|
|
|
sq_pushobject(vm, Core::Get().mOnScript.second);
|
|
|
|
// Specify that we're returning a value
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2021-01-30 07:51:39 +01:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static void SqEmitCustomEvent(int32_t group, int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
Core::Get().EmitCustomEvent(group, header, payload);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static SQInteger SqForceEnableNullEntities(HSQUIRRELVM SQ_UNUSED_ARG(vm))
|
|
|
|
{
|
|
|
|
Core::Get().EnableNullEntities();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static LightObj & SqGetPreLoadEvent()
|
|
|
|
{
|
|
|
|
return Core::Get().GetPreLoadEvent();
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static LightObj & SqGetPostLoadEvent()
|
|
|
|
{
|
|
|
|
return Core::Get().GetPostLoadEvent();
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static LightObj & SqGetUnloadEvent()
|
|
|
|
{
|
|
|
|
return Core::Get().GetUnloadEvent();
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static bool SqGetReloadStatus()
|
|
|
|
{
|
|
|
|
return GetReloadStatus();
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static void SqSetReloadStatus(bool toggle)
|
|
|
|
{
|
|
|
|
SetReloadStatus(toggle);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static void SqReloadBecause(int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Assign the reload info
|
|
|
|
Core::Get().SetReloadInfo(header, payload);
|
|
|
|
// Enable reloading
|
|
|
|
SetReloadStatus(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static void SqSetReloadInfo(int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
Core::Get().SetReloadInfo(header, payload);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static int32_t SqGetReloadHeader()
|
|
|
|
{
|
|
|
|
return Core::Get().GetReloadHeader();
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static LightObj & SqGetReloadPayload()
|
|
|
|
{
|
|
|
|
return Core::Get().GetReloadPayload();
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static int32_t SqGetState()
|
|
|
|
{
|
|
|
|
return Core::Get().GetState();
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static void SqSetState(int32_t value)
|
|
|
|
{
|
|
|
|
return Core::Get().SetState(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static bool SqGetAreasEnabled()
|
|
|
|
{
|
|
|
|
return Core::Get().AreasEnabled();
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static void SqSetAreasEnabled(bool toggle)
|
|
|
|
{
|
|
|
|
Core::Get().AreasEnabled(toggle);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static const String & SqGetOption(StackStrF & name)
|
|
|
|
{
|
|
|
|
return Core::Get().GetOption(String(name.mPtr, name.mLen));
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static const String & SqGetOptionOr(StackStrF & name, StackStrF & value)
|
|
|
|
{
|
|
|
|
static String s;
|
|
|
|
s.assign(value.mPtr, value.GetSize());
|
|
|
|
return Core::Get().GetOption(String(name.mPtr, name.mLen), s);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static void SqSetOption(StackStrF & name, StackStrF & value)
|
|
|
|
{
|
|
|
|
Core::Get().SetOption(String(name.mPtr, name.mLen), String(value.mPtr, value.mLen));
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static LightObj & SqGetBlip(int32_t id)
|
|
|
|
{
|
|
|
|
// Validate the identifier first
|
|
|
|
if (INVALID_ENTITYEX(id, SQMOD_BLIP_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Out of range blip identifier: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Return the requested information
|
|
|
|
return Core::Get().GetBlip(id).mObj;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static LightObj & SqGetCheckpoint(int32_t id)
|
|
|
|
{
|
|
|
|
// Validate the identifier first
|
|
|
|
if (INVALID_ENTITYEX(id, SQMOD_CHECKPOINT_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Out of range checkpoint identifier: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Return the requested information
|
|
|
|
return Core::Get().GetCheckpoint(id).mObj;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static LightObj & SqGetKeyBind(int32_t id)
|
|
|
|
{
|
|
|
|
// Validate the identifier first
|
|
|
|
if (INVALID_ENTITYEX(id, SQMOD_KEYBIND_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Out of range keybind identifier: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Return the requested information
|
|
|
|
return Core::Get().GetKeyBind(id).mObj;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static LightObj & SqGetObj(int32_t id)
|
|
|
|
{
|
|
|
|
// Validate the identifier first
|
|
|
|
if (INVALID_ENTITYEX(id, SQMOD_OBJECT_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Out of range object identifier: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Return the requested information
|
|
|
|
return Core::Get().GetObj(id).mObj;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static LightObj & SqGetPickup(int32_t id)
|
|
|
|
{
|
|
|
|
// Validate the identifier first
|
|
|
|
if (INVALID_ENTITYEX(id, SQMOD_PICKUP_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Out of range blip identifier: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Return the requested information
|
|
|
|
return Core::Get().GetPickup(id).mObj;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static LightObj & SqGetPlayer(int32_t id)
|
|
|
|
{
|
|
|
|
// Validate the identifier first
|
|
|
|
if (INVALID_ENTITYEX(id, SQMOD_PLAYER_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Out of range player identifier: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Return the requested information
|
|
|
|
return Core::Get().GetPlayer(id).mObj;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static LightObj & SqGetVehicle(int32_t id)
|
|
|
|
{
|
|
|
|
// Validate the identifier first
|
|
|
|
if (INVALID_ENTITYEX(id, SQMOD_VEHICLE_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Out of range vehicle identifier: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Return the requested information
|
|
|
|
return Core::Get().GetVehicle(id).mObj;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static bool SqDelBlip(int32_t id, int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Validate the identifier first
|
|
|
|
if (INVALID_ENTITYEX(id, SQMOD_BLIP_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Out of range blip identifier: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Perform the requested operation
|
|
|
|
return Core::Get().DelBlip(id, header, payload);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static bool SqDelCheckpoint(int32_t id, int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Validate the identifier first
|
|
|
|
if (INVALID_ENTITYEX(id, SQMOD_CHECKPOINT_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Out of range checkpoint identifier: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Perform the requested operation
|
|
|
|
return Core::Get().DelCheckpoint(id, header, payload);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static bool SqDelKeyBind(int32_t id, int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Validate the identifier first
|
|
|
|
if (INVALID_ENTITYEX(id, SQMOD_KEYBIND_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Out of range keybind identifier: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Perform the requested operation
|
|
|
|
return Core::Get().DelKeyBind(id, header, payload);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static bool SqDelObject(int32_t id, int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Validate the identifier first
|
|
|
|
if (INVALID_ENTITYEX(id, SQMOD_OBJECT_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Out of range object identifier: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Perform the requested operation
|
|
|
|
return Core::Get().DelObject(id, header, payload);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static bool SqDelPickup(int32_t id, int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Validate the identifier first
|
|
|
|
if (INVALID_ENTITYEX(id, SQMOD_PICKUP_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Out of range blip identifier: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Perform the requested operation
|
|
|
|
return Core::Get().DelPickup(id, header, payload);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static bool SqDelVehicle(int32_t id, int32_t header, LightObj & payload)
|
|
|
|
{
|
|
|
|
// Validate the identifier first
|
|
|
|
if (INVALID_ENTITYEX(id, SQMOD_VEHICLE_POOL))
|
|
|
|
{
|
2021-02-03 16:50:39 +01:00
|
|
|
STHROWF("Out of range vehicle identifier: {}", id);
|
2021-01-30 07:51:39 +01:00
|
|
|
}
|
|
|
|
// Perform the requested operation
|
|
|
|
return Core::Get().DelVehicle(id, header, payload);
|
|
|
|
}
|
|
|
|
|
2021-07-23 16:31:05 +02:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
static LightObj & SqGetClientDataBuffer()
|
|
|
|
{
|
|
|
|
return Core::Get().GetClientDataBuffer();
|
|
|
|
}
|
|
|
|
|
2023-03-05 14:38:59 +01:00
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2021-01-30 07:51:39 +01:00
|
|
|
// ================================================================================================
|
|
|
|
void Register_Core(HSQUIRRELVM vm)
|
|
|
|
{
|
|
|
|
Table corens(vm);
|
|
|
|
|
|
|
|
corens.Bind(_SC("State"),
|
|
|
|
Class< CoreState, NoCopy< CoreState > >(vm, CoreStateTypename::Str)
|
|
|
|
// Constructors
|
|
|
|
.Ctor()
|
|
|
|
.Ctor< int >()
|
|
|
|
// Meta-methods
|
|
|
|
.SquirrelFunc(_SC("_typename"), &CoreStateTypename::Fn)
|
|
|
|
// Member Properties
|
2021-02-23 15:36:17 +01:00
|
|
|
.Prop(_SC("Value"), &CoreState::GetState, &CoreState::SetState)
|
|
|
|
.Prop(_SC("Init"), &CoreState::GetStart)
|
|
|
|
// Member Methods
|
|
|
|
.Func(_SC("Propose"), &CoreState::SetState)
|
|
|
|
.Func(_SC("Regress"), &CoreState::Regress)
|
2021-01-30 07:51:39 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
corens
|
|
|
|
.Func(_SC("Reload"), &SqSetReloadStatus)
|
|
|
|
.Func(_SC("Reloading"), &SqGetReloadStatus)
|
|
|
|
.Func(_SC("ReloadBecause"), &SqReloadBecause)
|
|
|
|
.Func(_SC("SetReloadInfo"), &SqSetReloadInfo)
|
|
|
|
.Func(_SC("GetReloadHeader"), &SqGetReloadHeader)
|
|
|
|
.Func(_SC("GetReloadPayload"), &SqGetReloadPayload)
|
|
|
|
.Func(_SC("CustomEvent"), &SqEmitCustomEvent)
|
|
|
|
.Func(_SC("GetState"), &SqGetState)
|
|
|
|
.Func(_SC("SetState"), &SqSetState)
|
|
|
|
.Func(_SC("AreasEnabled"), &SqGetAreasEnabled)
|
|
|
|
.Func(_SC("SetAreasEnabled"), &SqSetAreasEnabled)
|
|
|
|
.Func(_SC("GetOption"), &SqGetOption)
|
|
|
|
.Func(_SC("GetOptionOr"), &SqGetOptionOr)
|
|
|
|
.Func(_SC("SetOption"), &SqSetOption)
|
|
|
|
.Func(_SC("GetBlip"), &SqGetBlip)
|
|
|
|
.Func(_SC("GetCheckpoint"), &SqGetCheckpoint)
|
|
|
|
.Func(_SC("GetKeyBind"), &SqGetKeyBind)
|
|
|
|
.Func(_SC("GetObj"), &SqGetObj)
|
|
|
|
.Func(_SC("GetPickup"), &SqGetPickup)
|
|
|
|
.Func(_SC("GetPlayer"), &SqGetPlayer)
|
|
|
|
.Func(_SC("GetVehicle"), &SqGetVehicle)
|
|
|
|
.Func(_SC("DestroyBlip"), &SqDelBlip)
|
|
|
|
.Func(_SC("DestroyCheckpoint"), &SqDelCheckpoint)
|
|
|
|
.Func(_SC("DestroyKeyBind"), &SqDelKeyBind)
|
|
|
|
.Func(_SC("DestroyObject"), &SqDelObject)
|
|
|
|
.Func(_SC("DestroyPickup"), &SqDelPickup)
|
|
|
|
.Func(_SC("DestroyVehicle"), &SqDelVehicle)
|
2021-07-23 16:31:05 +02:00
|
|
|
.Func(_SC("ClientDataBuffer"), &SqGetClientDataBuffer)
|
2023-03-05 14:38:59 +01:00
|
|
|
.Func(_SC("SendExtCommand"), &SqSendExtCommand)
|
|
|
|
.FmtFunc(_SC("SendExtCommandStr"), &SqSendExtCommandStr)
|
2021-01-30 07:51:39 +01:00
|
|
|
.Func(_SC("OnPreLoad"), &SqGetPreLoadEvent)
|
|
|
|
.Func(_SC("OnPostLoad"), &SqGetPostLoadEvent)
|
|
|
|
.Func(_SC("OnUnload"), &SqGetUnloadEvent)
|
2021-07-03 18:46:39 +02:00
|
|
|
.CbFunc(_SC("LoadScriptNotify"), &SqLoadScriptNotify)
|
2021-01-30 07:51:39 +01:00
|
|
|
.SquirrelFunc(_SC("ForceEnableNullEntities"), &SqForceEnableNullEntities)
|
|
|
|
.SquirrelFunc(_SC("LoadScript"), &SqLoadScript, -3, ".b.")
|
2021-07-04 04:17:32 +02:00
|
|
|
.SquirrelFunc(_SC("OnScript"), &SqGetOnScript)
|
2021-01-30 07:51:39 +01:00
|
|
|
.SquirrelFunc(_SC("On"), &SqGetEvents);
|
|
|
|
|
|
|
|
RootTable(vm).Bind(_SC("SqCore"), corens);
|
|
|
|
}
|
|
|
|
|
2015-09-30 02:56:11 +02:00
|
|
|
} // Namespace:: SqMod
|
2018-07-29 11:25:44 +02:00
|
|
|
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
2021-01-30 07:51:39 +01:00
|
|
|
* Include event functionality.
|
2018-07-29 11:25:44 +02:00
|
|
|
*/
|
|
|
|
#include "Core/Events.inc"
|