diff --git a/.gitmodules b/.gitmodules index 85554ed..0166e43 100644 --- a/.gitmodules +++ b/.gitmodules @@ -26,10 +26,6 @@ [submodule "deps/udis86"] path = deps/udis86 url = https://github.com/vmt/udis86.git -[submodule "deps/ChaiScript"] - path = deps/ChaiScript - url = https://github.com/ChaiScript/ChaiScript.git - branch = master [submodule "deps/zstd"] path = deps/zstd url = https://github.com/facebook/zstd.git diff --git a/deps/ChaiScript b/deps/ChaiScript deleted file mode 160000 index 69123db..0000000 --- a/deps/ChaiScript +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 69123db3dcde16cb38adae753c40edde86254246 diff --git a/deps/premake/chaiscript.lua b/deps/premake/chaiscript.lua deleted file mode 100644 index 25fe76d..0000000 --- a/deps/premake/chaiscript.lua +++ /dev/null @@ -1,23 +0,0 @@ -chaiscript = { - source = path.join(dependencies.basePath, "ChaiScript"), -} - -function chaiscript.import() - chaiscript.includes() - - defines { - --"CHAISCRIPT_NO_THREADS" -- :( - } -end - -function chaiscript.includes() - includedirs { - path.join(chaiscript.source, "include"), - } -end - -function chaiscript.project() - -end - -table.insert(dependencies, chaiscript) diff --git a/src/game/game.cpp b/src/game/game.cpp index 95a777b..4026fdd 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -39,10 +39,17 @@ namespace game SL_GetStringOfSize_t SL_GetStringOfSize; Scr_AddEntityNum_t Scr_AddEntityNum; + Scr_AddString_t Scr_AddString; + Scr_AddInt_t Scr_AddInt; + Scr_AddFloat_t Scr_AddFloat; Scr_Notify_t Scr_Notify; Scr_NotifyLevel_t Scr_NotifyLevel; Scr_GetNumParam_t Scr_GetNumParam; Scr_GetString_t Scr_GetString; + Scr_CastString_t Scr_CastString; + Scr_ErrorInternal_t Scr_ErrorInternal; + + GetObjectType_t GetObjectType; Sys_ShowConsole_t Sys_ShowConsole; Sys_Error_t Sys_Error; @@ -66,6 +73,7 @@ namespace game SV_Cmd_TokenizeString_t SV_Cmd_TokenizeString; SV_Cmd_EndTokenizedString_t SV_Cmd_EndTokenizedString; SV_SpawnServer_t SV_SpawnServer; + SV_GetConfigstring_t SV_GetConfigstring; XUIDToString_t XUIDToString; @@ -90,6 +98,8 @@ namespace game player_die_t player_die; + LargeLocalResetToMark_t LargeLocalResetToMark; + decltype(longjmp)* _longjmp; CmdArgs* sv_cmd_args; @@ -99,6 +109,7 @@ namespace game char** scrMemTreePub; char* scrMemTreeGlob; + function_stack_t* scr_function_stack; scrVarPub_t* scr_VarPub; scrVmPub_t* scr_VmPub; @@ -167,17 +178,17 @@ namespace game void AddRefToValue(VariableValue* value) { - if (value->type == SCRIPT_OBJECT) + if (value->type == VAR_POINTER) { ++scrVarGlob[4 * value->u.entityId]; } - else if ((value->type & ~1) == SCRIPT_STRING) + else if ((value->type & ~1) == VAR_STRING) { static const auto size = is_sp() ? 16 : 12; const auto ref_count = reinterpret_cast(*scrMemTreePub + size * value->u.stringValue); InterlockedIncrement(ref_count); } - else if (value->type == SCRIPT_VECTOR) + else if (value->type == VAR_VECTOR) { if (!*PBYTE(value->u.vectorValue - 1)) { @@ -269,8 +280,8 @@ namespace game static auto ent_array = reinterpret_cast(SELECT_VALUE(0x19AFC82, 0x1E72182)); scr_entref_t result; - result.raw.classnum = static_cast(class_array[2 * id]) >> 8; - result.raw.entnum = ent_array[4 * id]; + result.classnum = static_cast(class_array[2 * id]) >> 8; + result.entnum = ent_array[4 * id]; return result; } @@ -323,19 +334,6 @@ namespace game (SELECT_VALUE(0x42CAD0, 0x52BCC0))(classnum, entnum, offset); } - void Scr_AddString(const char* value) - { - reinterpret_cast (SELECT_VALUE(0x4A5600, 0x56AC00))(value); - } - - void Scr_AddInt(int value) - { - IncInParam(); - - scr_VmPub->top->type = SCRIPT_INTEGER; - scr_VmPub->top->u.intValue = value; - } - const char* SL_ConvertToString(const unsigned int stringValue) { if (!stringValue) return nullptr; @@ -723,11 +721,18 @@ namespace game native::SL_GetStringOfSize = native::SL_GetStringOfSize_t(SELECT_VALUE(0x4E13F0, 0x564650)); native::Scr_AddEntityNum = native::Scr_AddEntityNum_t(SELECT_VALUE(0x0, 0x56ABC0)); + native::Scr_AddString = native::Scr_AddString_t(SELECT_VALUE(0x4A5600, 0x56AC00)); + native::Scr_AddInt = native::Scr_AddInt_t(SELECT_VALUE(0x42DE20, 0x56AA20)); + native::Scr_AddFloat = native::Scr_AddFloat_t(SELECT_VALUE(0x5349D0, 0x56AA70)); native::Scr_Notify = native::Scr_Notify_t(SELECT_VALUE(0x4895B0, 0x52B190)); native::Scr_NotifyLevel = native::Scr_NotifyLevel_t(SELECT_VALUE(0x445E10, 0x56B6B0)); native::Scr_GetNumParam = native::Scr_GetNumParam_t(SELECT_VALUE(0x4C6FE0, 0x56AA10)); native::Scr_GetString = native::Scr_GetString_t(SELECT_VALUE(0x497530, 0x56A3D0)); + native::Scr_CastString = native::Scr_CastString_t(SELECT_VALUE(0x447CE0, 0x566EE0)); + native::Scr_ErrorInternal = native::Scr_ErrorInternal_t(SELECT_VALUE(0x42B910, 0x568FD0)); + + native::GetObjectType = native::GetObjectType_t(SELECT_VALUE(0x4D8FE0, 0x565C60)); native::Sys_ShowConsole = native::Sys_ShowConsole_t(SELECT_VALUE(0x470AF0, 0x5CF590)); native::Sys_Error = native::Sys_Error_t(SELECT_VALUE(0x490D90, 0x5CC3B0)); @@ -752,6 +757,7 @@ namespace game native::SV_Cmd_TokenizeString = native::SV_Cmd_TokenizeString_t(SELECT_VALUE(0x0, 0x545D40)); native::SV_Cmd_EndTokenizedString = native::SV_Cmd_EndTokenizedString_t(SELECT_VALUE(0x0, 0x545D70)); native::SV_SpawnServer = native::SV_SpawnServer_t(SELECT_VALUE(0x0, 0x575020)); + native::SV_GetConfigstring = native::SV_GetConfigstring_t(SELECT_VALUE(0x4C6E30, 0x573D50)); native::mp::SV_GameSendServerCommand = native::mp::SV_GameSendServerCommand_t(0x573220); native::mp::SV_GetGuid = native::mp::SV_GetGuid_t(0x573990); @@ -783,6 +789,8 @@ namespace game native::player_die = native::player_die_t(SELECT_VALUE(0x0, 0x503460)); + native::LargeLocalResetToMark = native::LargeLocalResetToMark_t(SELECT_VALUE(0x524350, 0x5B7150)); + native::_longjmp = reinterpret_cast(SELECT_VALUE(0x73AC20, 0x7363BC)); native::sv_cmd_args = reinterpret_cast(SELECT_VALUE(0x1757218, 0x1CAA998)); @@ -792,6 +800,7 @@ namespace game native::scrMemTreePub = reinterpret_cast(SELECT_VALUE(0x196FB00, 0x1E32000)); native::scrMemTreeGlob = reinterpret_cast(SELECT_VALUE(0x186DA00, 0x1D6FF00)); + native::scr_function_stack = reinterpret_cast(SELECT_VALUE(0x1BF255C, 0x20B4A5C)); native::scr_VarPub = reinterpret_cast(SELECT_VALUE(0x0, 0x208E188)); native::scr_VmPub = reinterpret_cast(SELECT_VALUE(0x1BF2580, 0x20B4A80)); diff --git a/src/game/game.hpp b/src/game/game.hpp index 3ef8baa..6bb0ebd 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -70,7 +70,7 @@ namespace game typedef void* (*MT_AllocIndex_t)(int numBytes, int type); extern MT_AllocIndex_t MT_AllocIndex; - typedef void (*RemoveRefToValue_t)(scriptType_e type, VariableUnion u); + typedef void (*RemoveRefToValue_t)(int type, VariableUnion u); extern RemoveRefToValue_t RemoveRefToValue; typedef unsigned int (*SL_GetStringOfSize_t)(const char* str, unsigned int user, unsigned int len, int type); @@ -79,6 +79,15 @@ namespace game typedef void (*Scr_AddEntityNum_t)(int entnum, unsigned int classnum); extern Scr_AddEntityNum_t Scr_AddEntityNum; + typedef void (*Scr_AddString_t)(const char* value); + extern Scr_AddString_t Scr_AddString; + + typedef void (*Scr_AddInt_t)(int value); + extern Scr_AddInt_t Scr_AddInt; + + typedef void (*Scr_AddFloat_t)(float value); + extern Scr_AddFloat_t Scr_AddFloat; + typedef void (*Scr_Notify_t)(gentity_s* ent, scr_string_t, unsigned int paramcount); extern Scr_Notify_t Scr_Notify; @@ -91,6 +100,15 @@ namespace game typedef const char* (*Scr_GetString_t)(unsigned int index); extern Scr_GetString_t Scr_GetString; + typedef bool (*Scr_CastString_t)(VariableValue* value); + extern Scr_CastString_t Scr_CastString; + + typedef void (*Scr_ErrorInternal_t)(); + extern Scr_ErrorInternal_t Scr_ErrorInternal; + + typedef unsigned int(*GetObjectType_t)(unsigned int id); + extern GetObjectType_t GetObjectType; + typedef void (*Sys_ShowConsole_t)(); extern Sys_ShowConsole_t Sys_ShowConsole; @@ -139,6 +157,9 @@ namespace game typedef void (*SV_SpawnServer_t)(const char* server, int mapIsPreloaded, int savegame); extern SV_SpawnServer_t SV_SpawnServer; + typedef void (*SV_GetConfigstring_t)(int index, char* buffer, int bufferSize); + extern SV_GetConfigstring_t SV_GetConfigstring; + typedef void (*XUIDToString_t)(const unsigned __int64* xuid, char* str); extern XUIDToString_t XUIDToString; @@ -182,6 +203,9 @@ namespace game typedef void (*player_die_t)(gentity_s* self, const gentity_s* inflictor, gentity_s* attacker, int damage, int meansOfDeath, const Weapon* iWeapon, bool isAlternate, const float* vDir, const hitLocation_t hitLoc, int psTimeOffset); extern player_die_t player_die; + typedef void (*LargeLocalResetToMark_t)(int markPos); + extern LargeLocalResetToMark_t LargeLocalResetToMark; + extern decltype(longjmp)* _longjmp; constexpr auto CMD_MAX_NESTING = 8; @@ -192,6 +216,7 @@ namespace game extern char** scrMemTreePub; extern char* scrMemTreeGlob; + extern function_stack_t* scr_function_stack; extern scrVarPub_t* scr_VarPub; extern scrVmPub_t* scr_VmPub; @@ -293,8 +318,6 @@ namespace game scr_entref_t Scr_GetEntityIdRef(unsigned int id); void Scr_NotifyId(unsigned int id, unsigned int stringValue, unsigned int paramcount); int Scr_SetObjectField(unsigned int classnum, int entnum, int offset); - void Scr_AddString(const char* value); - void Scr_AddInt(int value); const char* SL_ConvertToString(unsigned int stringValue); unsigned int SL_GetString(const char* str, unsigned int user); diff --git a/src/game/scripting/context.cpp b/src/game/scripting/context.cpp deleted file mode 100644 index 34850b0..0000000 --- a/src/game/scripting/context.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include "context_initializer.hpp" - -namespace game::scripting -{ - context::context() : executer_(this), scheduler_(this), parameters_(this), event_handler_(this) - { - context_initializer::initialize(this); - } - - executer* context::get_executer() - { - return &this->executer_; - } - - scheduler* context::get_scheduler() - { - return &this->scheduler_; - } - - parameters* context::get_parameters() - { - return &this->parameters_; - } - - event_handler* context::get_event_handler() - { - return &this->event_handler_; - } - - chaiscript::ChaiScript* context::get_chai() - { - return &this->chai_; - } -} diff --git a/src/game/scripting/context.hpp b/src/game/scripting/context.hpp deleted file mode 100644 index b2e8e5d..0000000 --- a/src/game/scripting/context.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once -#include "executer.hpp" -#include "scheduler.hpp" -#include "parameters.hpp" -#include "event_handler.hpp" - -namespace game::scripting -{ - class context final - { - public: - context(); - - chaiscript::ChaiScript* get_chai(); - - executer* get_executer(); - scheduler* get_scheduler(); - parameters* get_parameters(); - event_handler* get_event_handler(); - - private: - chaiscript::ChaiScript chai_; - - executer executer_; - scheduler scheduler_; - parameters parameters_; - event_handler event_handler_; - }; -} diff --git a/src/game/scripting/context_initializer.cpp b/src/game/scripting/context_initializer.cpp deleted file mode 100644 index e81c6af..0000000 --- a/src/game/scripting/context_initializer.cpp +++ /dev/null @@ -1,115 +0,0 @@ -#include -#include "context_initializer.hpp" - -#include "utils/string.hpp" - -namespace game::scripting::context_initializer -{ - void initialize_entity(context* context) - { - auto* const chai = context->get_chai(); - - chai->add(chaiscript::user_type(), "_entity"); - chai->add(chaiscript::constructor(), "_entity"); - chai->add(chaiscript::constructor(), "_entity"); - - chai->add(chaiscript::fun([](entity& lhs, const entity& rhs) -> entity& - { - return lhs = rhs; - }), "="); - - chai->add(chaiscript::fun(&entity::get), "get"); - chai->add(chaiscript::fun(&entity::set), "set"); - - chai->add(chaiscript::fun(&entity::on_notify), "onNotify"); - chai->add(chaiscript::fun([](const entity& ent, const std::string& event, - const std::function)>& - callback) - { - return ent.on_notify(event, callback, false); - }), "onNotify"); - - chai->add(chaiscript::fun([context](const std::string& event, - const std::function)>& - callback) - { - generic_event_listener listener; - listener.event = event; - listener.is_volatile = false; - listener.callback = callback; - - return context->get_event_handler()->add_event_listener(listener); - }), "onNotify"); - - chai->add(chaiscript::fun([context](const std::string& event, - const std::function)>& - callback, const bool is_volatile) - { - generic_event_listener listener; - listener.event = event; - listener.is_volatile = is_volatile; - listener.callback = callback; - - return context->get_event_handler()->add_event_listener(listener); - }), "onNotify"); - - chai->add_global(chaiscript::Boxed_Value(0), "gsc"); - - chai->add(chaiscript::fun([context](const entity& entity, const std::string& function, - const std::vector& arguments) - { - const auto function_lower = utils::string::to_lower(function); - - if (function_lower == "notify" && !arguments.empty()) - { - const auto real_arguments = std::vector( - arguments.begin() + 1, arguments.end()); - - entity.notify(chaiscript::boxed_cast(arguments[0]), real_arguments); - } - else if (context->get_executer()->function_exists(function_lower, false)) - { - return entity.call(function_lower, arguments); - } - - return chaiscript::Boxed_Value(0); - }), "method_missing"); - - chai->add(chaiscript::fun([context](const chaiscript::Boxed_Value&/*object*/, - const std::string& function, - const std::vector& arguments) - { - const auto function_lower = utils::string::to_lower(function); - - if (context->get_executer()->function_exists(function_lower, true)) - { - return context->get_executer()->call(function_lower, 0, arguments); - } - - return chaiscript::Boxed_Value(0); - }), "method_missing"); - } - - void initialize(context* context) - { - initialize_entity(context); - - auto* const chai = context->get_chai(); - - chai->add(chaiscript::fun([](const std::string& string) - { - printf("%s\n", string.data()); - }), "print"); - - chai->add(chaiscript::fun([](const std::string& string) - { - MessageBoxA(nullptr, string.data(), nullptr, 0); - }), "alert"); - - const auto level_id = *native::levelEntityId; - chai->add_global(chaiscript::var(entity(context, level_id)), "level"); - } -} diff --git a/src/game/scripting/context_initializer.hpp b/src/game/scripting/context_initializer.hpp deleted file mode 100644 index 8075246..0000000 --- a/src/game/scripting/context_initializer.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once -#include "context.hpp" - -namespace game::scripting::context_initializer -{ - void initialize(context* context); -} diff --git a/src/game/scripting/entity.cpp b/src/game/scripting/entity.cpp deleted file mode 100644 index 1085356..0000000 --- a/src/game/scripting/entity.cpp +++ /dev/null @@ -1,126 +0,0 @@ -#include -#include "context.hpp" - -namespace game::scripting -{ - entity::entity() : entity(nullptr, 0) - { - } - - entity::entity(const entity& other) : entity() - { - this->operator=(other); - } - - entity::entity(entity&& other) noexcept : entity() - { - this->operator=(std::move(other)); - } - - entity::entity(context* context, const unsigned int entity_id) : context_(context), entity_id_(entity_id) - { - this->add(); - } - - entity::~entity() - { - this->release(); - } - - entity& entity::operator=(const entity& other) - { - if (&other != this) - { - this->~entity(); - - this->context_ = other.context_; - this->entity_id_ = other.entity_id_; - - this->add(); - } - - return *this; - } - - entity& entity::operator=(entity&& other) noexcept - { - if (&other != this) - { - this->~entity(); - - this->context_ = other.context_; - this->entity_id_ = other.entity_id_; - - other.context_ = nullptr; - other.entity_id_ = 0; - } - - return *this; - } - - event_listener_handle entity::on_notify(const std::string& event, - const std::function)>& - callback, - const bool is_volatile) - const - { - event_listener listener; - listener.event = event; - listener.callback = callback; - listener.entity_id = this->entity_id_; - listener.is_volatile = is_volatile; - - return this->context_->get_event_handler()->add_event_listener(listener); - } - - unsigned int entity::get_entity_id() const - { - return this->entity_id_; - } - - native::scr_entref_t entity::get_entity_reference() const - { - return game::native::Scr_GetEntityIdRef(this->get_entity_id()); - } - - chaiscript::Boxed_Value entity::call(const std::string& function, - const std::vector& arguments) const - { - return this->context_->get_executer()->call(function, this->get_entity_id(), arguments); - } - - void entity::notify(const std::string& event, - const std::vector& arguments) const - { - this->context_->get_executer()->notify(event, this->get_entity_id(), arguments); - } - - void entity::set(const std::string& field, const chaiscript::Boxed_Value& value) const - { - this->context_->get_executer()->set_entity_field(field, this->get_entity_id(), value); - } - - chaiscript::Boxed_Value entity::get(const std::string& field) const - { - return this->context_->get_executer()->get_entity_field(field, this->get_entity_id()); - } - - void entity::add() const - { - if (this->entity_id_) - { - native::VariableValue value{}; - value.type = native::SCRIPT_OBJECT; - value.u.entityId = this->entity_id_; - native::AddRefToValue(&value); - } - } - - void entity::release() const - { - if (this->entity_id_) - { - native::RemoveRefToValue(native::SCRIPT_OBJECT, {static_cast(this->entity_id_)}); - } - } -} diff --git a/src/game/scripting/entity.hpp b/src/game/scripting/entity.hpp deleted file mode 100644 index 2e90e5e..0000000 --- a/src/game/scripting/entity.hpp +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once -#include "game/game.hpp" - -namespace game::scripting -{ - class context; - class event_listener_handle; - - class entity final - { - public: - entity(); - entity(const entity& other); - entity(entity&& other) noexcept; - entity(context* context, unsigned int entity_id); - ~entity(); - - entity& operator=(const entity& other); - entity& operator=(entity&& other) noexcept; - - event_listener_handle on_notify(const std::string& event, - const std::function)>& callback, - bool is_volatile) const; - - unsigned int get_entity_id() const; - game::native::scr_entref_t get_entity_reference() const; - - chaiscript::Boxed_Value call(const std::string& function, - const std::vector& arguments) const; - void notify(const std::string& event, const std::vector& arguments) const; - - void set(const std::string& field, const chaiscript::Boxed_Value& value) const; - chaiscript::Boxed_Value get(const std::string& field) const; - - private: - context* context_; - unsigned int entity_id_; - - void add() const; - void release() const; - }; -} diff --git a/src/game/scripting/event.hpp b/src/game/scripting/event.hpp deleted file mode 100644 index da918cd..0000000 --- a/src/game/scripting/event.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include "game/game.hpp" - -namespace game::scripting -{ - class event final - { - public: - std::string name; - unsigned int entity_id; - std::vector arguments; - }; -} diff --git a/src/game/scripting/event_handler.cpp b/src/game/scripting/event_handler.cpp deleted file mode 100644 index 322bc20..0000000 --- a/src/game/scripting/event_handler.cpp +++ /dev/null @@ -1,157 +0,0 @@ -#include - -#include "context.hpp" - -namespace game::scripting -{ - event_handler::event_handler(context* context) : context_(context) - { - const auto chai = this->context_->get_chai(); - - chai->add(chaiscript::user_type(), "_event_listener_handle"); - chai->add(chaiscript::constructor(), "_event_listener_handle"); - chai->add(chaiscript::constructor(), - "_event_listener_handle"); - - chai->add(chaiscript::fun( - [](event_listener_handle& lhs, const event_listener_handle& rhs) -> event_listener_handle& - { - return lhs = rhs; - }), "="); - - chai->add(chaiscript::fun([this](const event_listener_handle& handle) - { - this->remove(handle); - }), "clear"); - } - - void event_handler::dispatch(event* event) - { - try - { - std::vector arguments; - - for (auto argument : event->arguments) - { - arguments.push_back(this->context_->get_parameters()->load(argument)); - } - - this->dispatch_to_specific_listeners(event, arguments); - this->dispatch_to_generic_listeners(event, arguments); - } - catch (chaiscript::exception::eval_error& e) - { - throw std::runtime_error(e.pretty_print()); - } - } - - void event_handler::dispatch_to_specific_listeners(event* event, - const std::vector& arguments) - { - this->event_listeners_.access([&](task_list& tasks) - { - for (auto listener = tasks.begin(); listener != tasks.end();) - { - if (listener->event == event->name && listener->entity_id == event->entity_id) - { - if (listener->is_volatile) - { - listener = tasks.erase(listener); - continue; - } - - listener->callback(arguments); - } - - ++listener; - } - }); - } - - void event_handler::dispatch_to_generic_listeners(event* event, - const std::vector& arguments) - { - this->generic_event_listeners_.access([&](generic_task_list& tasks) - { - for (auto listener = tasks.begin(); listener != tasks.end();) - { - if (listener->event == event->name) - { - if (listener->is_volatile) - { - listener = tasks.erase(listener); - continue; - } - - listener->callback(entity(this->context_, event->entity_id), arguments); - } - - ++listener; - } - }); - } - - event_listener_handle event_handler::add_event_listener(event_listener listener) - { - listener.id = ++this->current_listener_id_; - this->event_listeners_.access([listener](task_list& tasks) - { - tasks.emplace_back(std::move(listener)); - }); - return {listener.id}; - } - - event_listener_handle event_handler::add_event_listener(generic_event_listener listener) - { - listener.id = ++this->current_listener_id_; - this->generic_event_listeners_.access([listener](generic_task_list& tasks) - { - tasks.emplace_back(std::move(listener)); - }); - return {listener.id}; - } - - void event_handler::clear() - { - this->event_listeners_.access([](task_list& tasks) - { - tasks.clear(); - }); - - this->generic_event_listeners_.access([](generic_task_list& tasks) - { - tasks.clear(); - }); - } - - void event_handler::remove(const event_listener_handle& handle) - { - this->event_listeners_.access([handle](task_list& tasks) - { - for (auto i = tasks.begin(); i != tasks.end();) - { - if (i->id == handle.id) - { - i = tasks.erase(i); - return; - } - - ++i; - } - }); - - this->generic_event_listeners_.access([handle](generic_task_list& tasks) - { - for (auto i = tasks.begin(); i != tasks.end();) - { - if (i->id == handle.id) - { - i = tasks.erase(i); - return; - } - - ++i; - } - }); - } -} diff --git a/src/game/scripting/event_handler.hpp b/src/game/scripting/event_handler.hpp deleted file mode 100644 index aab1317..0000000 --- a/src/game/scripting/event_handler.hpp +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once -#include -#include "entity.hpp" -#include "event.hpp" - -namespace game::scripting -{ - class context; - - class event_listener_handle - { - public: - unsigned long long id = 0; - }; - - class event_listener final : public event_listener_handle - { - public: - std::string event = {}; - unsigned int entity_id = 0; - std::function)> callback = {}; - bool is_volatile = false; - }; - - class generic_event_listener final : public event_listener_handle - { - public: - std::string event = {}; - std::function)> callback = {}; - bool is_volatile = false; - }; - - class event_handler final - { - public: - explicit event_handler(context* context); - - void dispatch(event* event); - - event_listener_handle add_event_listener(event_listener listener); - event_listener_handle add_event_listener(generic_event_listener listener); - - void clear(); - - private: - context* context_; - std::atomic_int64_t current_listener_id_ = 0; - - using task_list = std::vector; - utils::concurrency::container event_listeners_; - - using generic_task_list = std::vector; - utils::concurrency::container generic_event_listeners_; - - void dispatch_to_specific_listeners(event* event, const std::vector& arguments); - void dispatch_to_generic_listeners(event* event, const std::vector& arguments); - - void remove(const event_listener_handle& handle); - }; -} diff --git a/src/game/scripting/executer.cpp b/src/game/scripting/executer.cpp deleted file mode 100644 index 14c0c1c..0000000 --- a/src/game/scripting/executer.cpp +++ /dev/null @@ -1,150 +0,0 @@ -#include -#include "game/game.hpp" - -#include - -#include "functions.hpp" -#include "stack_isolation.hpp" -#include "safe_executer.hpp" -#include "context.hpp" - -namespace game::scripting -{ - executer::executer(context* context) : context_(context) - { - } - - int executer::get_field_id(const int classnum, const std::string& field) const - { - const auto field_name = utils::string::to_lower(field); - const auto class_id = native::g_classMap[classnum].id; - const auto field_str = native::SL_GetString(field_name.data(), 1); - const auto _ = gsl::finally([field_str]() - { - native::RemoveRefToValue(native::SCRIPT_STRING, {int(field_str)}); - }); - - const auto offset = native::FindVariable(class_id, field_str); - if (offset) - { - const auto index = 4 * (offset + 0xC800 * (class_id & 1)); - return PINT(SELECT_VALUE(0x1A3BC80, 0x1EFE180))[index]; - } - - return -1; - } - - void executer::set_entity_field(const std::string& field, const unsigned int entity_id, - const chaiscript::Boxed_Value& value) - { - const auto entref = native::Scr_GetEntityIdRef(entity_id); - const int id = get_field_id(entref.raw.classnum, field); - - if (id != -1) - { - stack_isolation _; - this->context_->get_parameters()->push(value); - - native::scr_VmPub->outparamcount = native::scr_VmPub->inparamcount; - native::scr_VmPub->inparamcount = 0; - - if (!safe_executer::set_entity_field(entref, id)) - { - throw std::runtime_error("Failed to set value for field '" + field + "'"); - } - } - else - { - this->entity_fields_[entity_id][field] = value; - } - } - - chaiscript::Boxed_Value executer::get_entity_field(const std::string& field, const unsigned int entity_id) - { - const auto entref = native::Scr_GetEntityIdRef(entity_id); - const auto id = this->get_field_id(entref.raw.classnum, field); - - if (id != -1) - { - stack_isolation _; - - native::VariableValue value{}; - if (!safe_executer::get_entity_field(entref, id, &value)) - { - throw std::runtime_error("Failed to get value for field '" + field + "'"); - } - - const auto $ = gsl::finally([value]() - { - native::RemoveRefToValue(value.type, value.u); - }); - - return this->context_->get_parameters()->load(value); - } - else - { - const auto& map = this->entity_fields_[entity_id]; - const auto value = map.find(field); - if (value != map.end()) - { - return value->second; - } - } - - return {}; - } - - void executer::notify(const std::string& event, const unsigned int entity_id, - std::vector arguments) const - { - stack_isolation _; - - std::reverse(arguments.begin(), arguments.end()); - for (auto argument : arguments) - { - this->context_->get_parameters()->push(argument); - } - - const auto event_id = native::SL_GetString(event.data(), 0); - native::Scr_NotifyId(entity_id, event_id, native::scr_VmPub->inparamcount); - } - - chaiscript::Boxed_Value executer::call(const std::string& function, const unsigned int entity_id, - std::vector arguments) const - { - const auto function_index = ::scripting::find_function_index(function, entity_id == 0); - if (function_index < 0) - { - throw std::runtime_error("No function found for name '" + function + "'"); - } - - const auto entity = function_index > 0x1C7 - ? native::Scr_GetEntityIdRef(entity_id) - : native::scr_entref_t{~0u}; - - const auto function_ptr = ::scripting::get_function_by_index(function_index); - - stack_isolation _; - - std::reverse(arguments.begin(), arguments.end()); - for (const auto& argument : arguments) - { - this->context_->get_parameters()->push(argument); - } - - native::scr_VmPub->outparamcount = native::scr_VmPub->inparamcount; - native::scr_VmPub->inparamcount = 0; - - if (!safe_executer::call(function_ptr, entity)) - { - throw std::runtime_error("Error executing function '" + function + "'"); - } - - return this->context_->get_parameters()->get_return_value(); - } - - bool executer::function_exists(const std::string& function, bool prefer_global) - { - return ::scripting::find_function_index(function, prefer_global) >= 0; - } -} diff --git a/src/game/scripting/executer.hpp b/src/game/scripting/executer.hpp deleted file mode 100644 index 8fab705..0000000 --- a/src/game/scripting/executer.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -namespace game::scripting -{ - class context; - - class executer final - { - public: - explicit executer(context* context); - - void set_entity_field(const std::string& field, unsigned int entity_id, - const chaiscript::Boxed_Value& value); - chaiscript::Boxed_Value get_entity_field(const std::string& field, unsigned int entity_id); - - void notify(const std::string& event, unsigned int entity_id, - std::vector arguments) const; - - chaiscript::Boxed_Value call(const std::string& function, unsigned int entity_id, - std::vector arguments) const; - - static bool function_exists(const std::string& function, bool prefer_global); - - private: - context* context_; - - std::unordered_map> entity_fields_; - - int get_field_id(int classnum, const std::string& field) const; - }; -} diff --git a/src/game/scripting/functions.cpp b/src/game/scripting/functions.cpp index 8a1336a..74d04bb 100644 --- a/src/game/scripting/functions.cpp +++ b/src/game/scripting/functions.cpp @@ -1,4 +1,6 @@ #include +#include "game/game.hpp" + #include "functions.hpp" #include @@ -70,20 +72,20 @@ namespace scripting return game::native::SL_GetCanonicalString(name.data()); } - game::native::scr_call_t get_function_by_index(const std::uint32_t index) + game::native::BuiltinFunction get_function_by_index(const std::uint32_t index) { static const auto function_table = SELECT_VALUE(0x186C68C, 0x1D6EB34); static const auto method_table = SELECT_VALUE(0x184CDB0, 0x1D4F258); if (index < 0x1C7) { - return reinterpret_cast(function_table)[index - 1]; + return reinterpret_cast(function_table)[index - 1]; } - return reinterpret_cast(method_table)[index]; + return reinterpret_cast(method_table)[index]; } - game::native::scr_call_t find_function(const std::string& name, const bool prefer_global) + game::native::BuiltinFunction find_function(const std::string& name, const bool prefer_global) { const auto index = find_function_index(name, prefer_global); if (index < 0) return nullptr; diff --git a/src/game/scripting/functions.hpp b/src/game/scripting/functions.hpp index 6efcb68..b73230b 100644 --- a/src/game/scripting/functions.hpp +++ b/src/game/scripting/functions.hpp @@ -1,5 +1,4 @@ #pragma once -#include "game/game.hpp" namespace scripting { @@ -8,6 +7,4 @@ namespace scripting unsigned int find_token_id(const std::string& name); int find_function_index(const std::string& name, bool prefer_global); - game::native::scr_call_t get_function_by_index(std::uint32_t index); - game::native::scr_call_t find_function(const std::string& name, bool prefer_global); } diff --git a/src/game/scripting/parameters.cpp b/src/game/scripting/parameters.cpp deleted file mode 100644 index a7ac408..0000000 --- a/src/game/scripting/parameters.cpp +++ /dev/null @@ -1,156 +0,0 @@ -#include -#include "context.hpp" - -namespace game::scripting -{ - parameters::parameters(context* context) : context_(context) - { - } - - chaiscript::Boxed_Value parameters::load(const native::VariableValue value) const - { - if (value.type == native::SCRIPT_STRING) - { - const std::string string = native::SL_ConvertToString(value.u.stringValue); - return chaiscript::var(string); - } - if (value.type == native::SCRIPT_FLOAT) - { - return chaiscript::var(value.u.floatValue); - } - if (value.type == native::SCRIPT_INTEGER) - { - return chaiscript::var(value.u.intValue); - } - if (value.type == native::SCRIPT_OBJECT) - { - return chaiscript::var(entity(this->context_, value.u.entityId)); - } - if (value.type == native::SCRIPT_VECTOR) - { - std::vector values; - values.push_back(chaiscript::var(value.u.vectorValue[0])); - values.push_back(chaiscript::var(value.u.vectorValue[1])); - values.push_back(chaiscript::var(value.u.vectorValue[2])); - - return chaiscript::var(values); - } - - return {}; - } - - void parameters::push(const chaiscript::Boxed_Value& value) const - { - if (native::scr_VmPub->outparamcount) - { - native::Scr_ClearOutParams(); - } - - if (native::scr_VmPub->top == native::scr_VmPub->maxStack) - { - throw std::runtime_error("Internal script stack overflow"); - } - - native::VariableValue* value_ptr = ++native::scr_VmPub->top; - ++native::scr_VmPub->inparamcount; - - value_ptr->type = native::SCRIPT_NONE; - value_ptr->u.intValue = 0; - - if (value.get_type_info() == typeid(float)) - { - const auto real_value = this->context_->get_chai()->boxed_cast(value); - value_ptr->type = native::SCRIPT_FLOAT; - value_ptr->u.floatValue = real_value; - } - else if (value.get_type_info() == typeid(double)) - { - const auto real_value = this->context_->get_chai()->boxed_cast(value); - value_ptr->type = native::SCRIPT_FLOAT; - value_ptr->u.floatValue = static_cast(real_value); - } - else if (value.get_type_info() == typeid(int)) - { - const auto real_value = this->context_->get_chai()->boxed_cast(value); - value_ptr->type = native::SCRIPT_INTEGER; - value_ptr->u.intValue = real_value; - } - else if (value.get_type_info() == typeid(unsigned int)) - { - const auto real_value = this->context_->get_chai()->boxed_cast(value); - value_ptr->type = native::SCRIPT_INTEGER; - value_ptr->u.intValue = static_cast(real_value); - } - else if (value.get_type_info() == typeid(bool)) - { - const auto real_value = this->context_->get_chai()->boxed_cast(value); - value_ptr->type = native::SCRIPT_INTEGER; - value_ptr->u.intValue = real_value; - } - else if (value.get_type_info() == typeid(entity)) - { - const auto real_value = this->context_->get_chai()->boxed_cast(value); - value_ptr->type = native::SCRIPT_OBJECT; - value_ptr->u.entityId = real_value.get_entity_id(); - - game::native::AddRefToValue(value_ptr); - } - else if (value.get_type_info() == typeid(std::string)) - { - const auto real_value = this->context_->get_chai()->boxed_cast(value); - value_ptr->type = native::SCRIPT_STRING; - value_ptr->u.stringValue = game::native::SL_GetString(real_value.data(), 0); - } - else if (value.get_type_info() == typeid(std::vector)) - { - float values[3]; - const auto real_value = this->context_->get_chai()->boxed_cast - >(value); - if (real_value.size() != 3) - { - throw std::runtime_error("Invalid vector length. Size must be exactly 3"); - } - - const auto unbox_float = [&real_value, this](const size_t index) -> float - { - const auto value = real_value[index]; - if (value.get_type_info() == typeid(float)) - { - return this->context_->get_chai()->boxed_cast(value); - } - if (value.get_type_info() == typeid(double)) - { - return float(this->context_->get_chai()->boxed_cast(value)); - } - if (value.get_type_info() == typeid(int)) - { - return float(this->context_->get_chai()->boxed_cast(value)); - } - - throw std::runtime_error("Vector element at index " + std::to_string(index) + " is not a number"); - }; - - values[0] = unbox_float(0); - values[1] = unbox_float(1); - values[2] = unbox_float(2); - - value_ptr->type = native::SCRIPT_VECTOR; - value_ptr->u.vectorValue = native::Scr_AllocVector(values); - } - else - { - throw std::runtime_error("Unable to unbox value of type '"s + value.get_type_info().bare_name() + "'"); - } - } - - chaiscript::Boxed_Value parameters::get_return_value() const - { - if (native::scr_VmPub->inparamcount == 0) return {}; - - native::Scr_ClearOutParams(); - native::scr_VmPub->outparamcount = native::scr_VmPub->inparamcount; - native::scr_VmPub->inparamcount = 0; - - return this->load(native::scr_VmPub->top[1 - native::scr_VmPub->outparamcount]); - } -} diff --git a/src/game/scripting/parameters.hpp b/src/game/scripting/parameters.hpp deleted file mode 100644 index 244e368..0000000 --- a/src/game/scripting/parameters.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once -#include "game/game.hpp" - -namespace game::scripting -{ - class context; - - class parameters final - { - public: - explicit parameters(context* context); - - void push(const chaiscript::Boxed_Value& value) const; - chaiscript::Boxed_Value load(native::VariableValue value) const; - - chaiscript::Boxed_Value get_return_value() const; - private: - context* context_; - }; -} diff --git a/src/game/scripting/safe_executer.cpp b/src/game/scripting/safe_executer.cpp deleted file mode 100644 index 0731ec0..0000000 --- a/src/game/scripting/safe_executer.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include -#include "safe_executer.hpp" - -#pragma warning(push) -#pragma warning(disable: 4611) - -namespace game::scripting::safe_executer -{ - static_assert(sizeof(jmp_buf) == 64); - - bool call(const native::scr_call_t function, const native::scr_entref_t entref) - { - *native::g_script_error_level += 1; - if (setjmp(native::g_script_error[*native::g_script_error_level])) - { - *native::g_script_error_level -= 1; - return false; - } - - function(entref.val); - - *native::g_script_error_level -= 1; - return true; - } - - bool set_entity_field(const native::scr_entref_t entref, const int offset) - { - *native::g_script_error_level += 1; - if (setjmp(native::g_script_error[*native::g_script_error_level])) - { - *native::g_script_error_level -= 1; - return false; - } - - native::Scr_SetObjectField(entref.raw.classnum, entref.raw.entnum, offset); - - *native::g_script_error_level -= 1; - return true; - } - - bool get_entity_field(const native::scr_entref_t entref, const int offset, native::VariableValue* value) - { - *native::g_script_error_level += 1; - if (setjmp(native::g_script_error[*native::g_script_error_level])) - { - value->type = native::SCRIPT_NONE; - value->u.intValue = 0; - *native::g_script_error_level -= 1; - return false; - } - - *value = native::GetEntityFieldValue(entref.raw.classnum, entref.raw.entnum, offset); - - *native::g_script_error_level -= 1; - return true; - } -} - -#pragma warning(pop) diff --git a/src/game/scripting/safe_executer.hpp b/src/game/scripting/safe_executer.hpp deleted file mode 100644 index 0579f66..0000000 --- a/src/game/scripting/safe_executer.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "game/game.hpp" - -namespace game::scripting::safe_executer -{ - bool call(const native::scr_call_t function, const native::scr_entref_t entref); - bool set_entity_field(const native::scr_entref_t entref, const int offset); - bool get_entity_field(const native::scr_entref_t entref, const int offset, native::VariableValue* value); -} diff --git a/src/game/scripting/scheduler.cpp b/src/game/scripting/scheduler.cpp deleted file mode 100644 index 1a4c169..0000000 --- a/src/game/scripting/scheduler.cpp +++ /dev/null @@ -1,120 +0,0 @@ -#include - -#include "context.hpp" - -namespace game::scripting -{ - scheduler::scheduler(context* context) : context_(context) - { - const auto chai = this->context_->get_chai(); - - chai->add(chaiscript::user_type(), "_task_handle"); - chai->add(chaiscript::constructor(), "_task_handle"); - chai->add(chaiscript::constructor(), "_task_handle"); - - chai->add(chaiscript::fun([](task_handle& lhs, const task_handle& rhs) -> task_handle& - { - return lhs = rhs; - }), "="); - - chai->add(chaiscript::fun( - [this](const std::function& callback, const long long milliseconds) -> task_handle - { - return this->add(callback, milliseconds, true); - }), "setTimeout"); - - chai->add(chaiscript::fun( - [this](const std::function& callback, const long long milliseconds) -> task_handle - { - return this->add(callback, milliseconds, false); - }), "setInterval"); - - const auto clear = [this](const task_handle& handle) - { - this->remove(handle); - }; - - chai->add(chaiscript::fun(clear), "clear"); - chai->add(chaiscript::fun(clear), "clearTimeout"); - chai->add(chaiscript::fun(clear), "clearInterval"); - } - - void scheduler::run_frame() - { - this->tasks_.access([&](task_list& tasks) - { - for (auto i = tasks.begin(); i != tasks.end();) - { - const auto now = std::chrono::steady_clock::now(); - const auto diff = now - i->last_execution; - - if (diff < i->delay) - { - ++i; - continue; - } - - i->last_execution = now; - - if (i->is_volatile) - { - i = tasks.erase(i); - } - else - { - i->callback(); - ++i; - } - } - }); - } - - void scheduler::clear() - { - this->tasks_.access([&](task_list& tasks) - { - tasks.clear(); - }); - } - - task_handle scheduler::add(const std::function& callback, const long long milliseconds, - const bool is_volatile) - { - return this->add(callback, std::chrono::milliseconds(milliseconds), is_volatile); - } - - task_handle scheduler::add(const std::function& callback, const std::chrono::milliseconds delay, - const bool is_volatile) - { - task task; - task.is_volatile = is_volatile; - task.callback = callback; - task.delay = delay; - task.last_execution = std::chrono::steady_clock::now(); - task.id = ++this->current_task_id_; - - this->tasks_.access([&task](task_list& tasks) - { - tasks.emplace_back(std::move(task)); - }); - - return {task.id}; - } - - void scheduler::remove(const task_handle& handle) - { - this->tasks_.access([&](task_list& tasks) - { - for (auto i = tasks.begin(); i != tasks.end();) - { - if (i->id == handle.id) - { - i = tasks.erase(i); - break; - } - - ++i; - } - }); - } -} diff --git a/src/game/scripting/scheduler.hpp b/src/game/scripting/scheduler.hpp deleted file mode 100644 index 3783b66..0000000 --- a/src/game/scripting/scheduler.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once -#include - -namespace game::scripting -{ - class context; - - class task_handle - { - public: - std::uint64_t id = 0; - }; - - class task final : public task_handle - { - public: - std::chrono::steady_clock::time_point last_execution{}; - std::function callback{}; - std::chrono::milliseconds delay{}; - bool is_volatile = false; - }; - - class scheduler final - { - public: - explicit scheduler(context* context); - - void run_frame(); - void clear(); - - private: - context* context_; - - using task_list = std::vector; - utils::concurrency::container tasks_; - std::atomic_int64_t current_task_id_ = 0; - - task_handle add(const std::function& callback, long long milliseconds, bool is_volatile); - task_handle add(const std::function& callback, std::chrono::milliseconds delay, bool is_volatile); - - void remove(const task_handle& handle); - }; -} diff --git a/src/game/scripting/stack_isolation.cpp b/src/game/scripting/stack_isolation.cpp deleted file mode 100644 index 604c210..0000000 --- a/src/game/scripting/stack_isolation.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include "stack_isolation.hpp" - -namespace game::scripting -{ - stack_isolation::stack_isolation() - { - this->in_param_count_ = native::scr_VmPub->inparamcount; - this->out_param_count_ = native::scr_VmPub->outparamcount; - this->top_ = native::scr_VmPub->top; - this->max_stack_ = native::scr_VmPub->maxStack; - - native::scr_VmPub->top = this->stack_; - native::scr_VmPub->maxStack = &this->stack_[ARRAYSIZE(this->stack_) - 1]; - native::scr_VmPub->inparamcount = 0; - native::scr_VmPub->outparamcount = 0; - } - - stack_isolation::~stack_isolation() - { - native::Scr_ClearOutParams(); - native::scr_VmPub->inparamcount = this->in_param_count_; - native::scr_VmPub->outparamcount = this->out_param_count_; - native::scr_VmPub->top = this->top_; - native::scr_VmPub->maxStack = this->max_stack_; - } -} diff --git a/src/game/scripting/stack_isolation.hpp b/src/game/scripting/stack_isolation.hpp deleted file mode 100644 index 0241599..0000000 --- a/src/game/scripting/stack_isolation.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once -#include "game/game.hpp" - -namespace game::scripting -{ - class stack_isolation final - { - public: - stack_isolation(); - ~stack_isolation(); - - private: - native::VariableValue stack_[512]{}; - - native::VariableValue* max_stack_; - native::VariableValue* top_; - unsigned int in_param_count_; - unsigned int out_param_count_; - }; -} diff --git a/src/game/scripting/variable_value.cpp b/src/game/scripting/variable_value.cpp deleted file mode 100644 index b1d7f91..0000000 --- a/src/game/scripting/variable_value.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include -#include "variable_value.hpp" - -namespace game::scripting -{ - variable_value::variable_value(const native::VariableValue& value) - { - this->assign(value); - } - - variable_value::variable_value(const variable_value& other) noexcept - { - this->operator=(other); - } - - variable_value::variable_value(variable_value&& other) noexcept - { - this->operator=(std::move(other)); - } - - variable_value& variable_value::operator=(const variable_value& other) noexcept - { - if (this != &other) - { - this->release(); - this->assign(other.value_); - } - - return *this; - } - - variable_value& variable_value::operator=(variable_value&& other) noexcept - { - if (this != &other) - { - this->release(); - this->value_ = other.value_; - other.value_.type = native::SCRIPT_NONE; - } - - return *this; - } - - variable_value::~variable_value() - { - this->release(); - } - - const native::VariableValue& variable_value::get() const - { - return this->value_; - } - - void variable_value::assign(const native::VariableValue& value) - { - this->value_ = value; - native::AddRefToValue(&this->value_); - } - - void variable_value::release() - { - if (this->value_.type != native::SCRIPT_NONE) - { - native::RemoveRefToValue(this->value_.type, this->value_.u); - this->value_.type = native::SCRIPT_NONE; - } - } -} diff --git a/src/game/scripting/variable_value.hpp b/src/game/scripting/variable_value.hpp deleted file mode 100644 index 34361a4..0000000 --- a/src/game/scripting/variable_value.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once -#include "game/game.hpp" - -namespace game::scripting -{ - class variable_value - { - public: - variable_value() = default; - variable_value(const native::VariableValue& value); - variable_value(const variable_value& other) noexcept; - variable_value(variable_value&& other) noexcept; - - variable_value& operator=(const variable_value& other) noexcept; - variable_value& operator=(variable_value&& other) noexcept; - - ~variable_value(); - - const native::VariableValue& get() const; - - private: - void assign(const native::VariableValue& value); - void release(); - - native::VariableValue value_{{0}, native::SCRIPT_NONE}; - }; -} diff --git a/src/game/structs.hpp b/src/game/structs.hpp index 2748a0d..c5ca166 100644 --- a/src/game/structs.hpp +++ b/src/game/structs.hpp @@ -523,34 +523,50 @@ namespace game int freeFlags; }; - struct scr_entref_raw + struct scr_entref_t { unsigned __int16 entnum; unsigned __int16 classnum; }; - union scr_entref_t - { - unsigned int val; - scr_entref_raw raw; - }; - - typedef void (__cdecl * scr_call_t)(int entref); + typedef void(*BuiltinFunction)(); + typedef void(*BuiltinMethod)(scr_entref_t); typedef unsigned __int16 scr_string_t; - enum scriptType_e + enum { - SCRIPT_NONE = 0, - SCRIPT_OBJECT = 1, - SCRIPT_STRING = 2, - SCRIPT_ISTRING = 2, - SCRIPT_VECTOR = 4, - SCRIPT_FLOAT = 5, - SCRIPT_INTEGER = 6, - SCRIPT_CODEPOS = 7, - SCRIPT_END = 8, - // Custom + VAR_UNDEFINED = 0x0, + VAR_BEGIN_REF = 0x1, + VAR_POINTER = 0x1, + VAR_STRING = 0x2, + VAR_ISTRING = 0x3, + VAR_VECTOR = 0x4, + VAR_END_REF = 0x5, + VAR_FLOAT = 0x5, + VAR_INTEGER = 0x6, + VAR_CODEPOS = 0x7, + VAR_PRECODEPOS = 0x8, + VAR_FUNCTION = 0x9, + VAR_BUILTIN_FUNCTION = 0xA, + VAR_BUILTIN_METHOD = 0xB, + VAR_STACK = 0xC, + VAR_ANIMATION = 0xD, + VAR_PRE_ANIMATION = 0xE, + VAR_THREAD = 0xF, + VAR_NOTIFY_THREAD = 0x10, + VAR_TIME_THREAD = 0x11, + VAR_CHILD_THREAD = 0x12, + VAR_OBJECT = 0x13, + VAR_DEAD_ENTITY = 0x14, + VAR_ENTITY = 0x15, + VAR_ARRAY = 0x16, + VAR_DEAD_THREAD = 0x17, + VAR_COUNT = 0x18, + VAR_FREE = 0x18, + VAR_THREAD_LIST = 0x19, + VAR_ENDON_LIST = 0x1A, + VAR_TOTAL_COUNT = 0x1B, }; struct VariableStackBuffer @@ -578,7 +594,7 @@ namespace game struct VariableValue { VariableUnion u; - scriptType_e type; + int type; }; struct function_stack_t @@ -603,10 +619,6 @@ namespace game int function_count; function_frame_t* function_frame; VariableValue* top; - /*bool debugCode; - bool abort_on_error; - bool terminal_error; - bool block_execution;*/ unsigned int inparamcount; unsigned int outparamcount; unsigned int breakpointOutparamcount; @@ -910,7 +922,7 @@ namespace game PLAYERVIEWLOCKCOUNT = 0x3, }; - enum playerStateFlag + enum { PMF_PRONE = 0x1, PMF_DUCKED = 0x2, @@ -1382,6 +1394,11 @@ namespace game namespace mp { + enum ConfigString + { + CS_EFFECT_NAMES = 0x9DC, + }; + struct client_t { clientHeader_t header; @@ -1402,6 +1419,11 @@ namespace game namespace sp { + enum ConfigString + { + CS_EFFECT_NAMES = 0xB8F, + }; + struct usercmd_s { int serverTime; diff --git a/src/module/dw.cpp b/src/module/dw.cpp index 76cc5ed..e5ffd97 100644 --- a/src/module/dw.cpp +++ b/src/module/dw.cpp @@ -412,7 +412,13 @@ namespace demonware void dw::bd_logger_stub(int /*type*/, const char* const /*channelName*/, const char*, const char* const /*file*/, const char* const function, const unsigned int /*line*/, const char* const msg, ...) { - char buffer[2048]; + static const auto* bd_logger_enabled = game::native::Dvar_RegisterBool("bd_logger_enabled", false, game::native::DVAR_NONE, "Enable bdLogger"); + if (!bd_logger_enabled->current.enabled) + { + return; + } + + char buffer[2048]{}; va_list ap; va_start(ap, msg); diff --git a/src/module/game_log.cpp b/src/module/game_log.cpp index b758ee4..3c81190 100644 --- a/src/module/game_log.cpp +++ b/src/module/game_log.cpp @@ -1,13 +1,13 @@ #include #include +#include "game/game.hpp" #include -#include "game/game.hpp" - #include "game_log.hpp" #include "scheduler.hpp" #include "file_system.hpp" +#include "scripting.hpp" const game::native::dvar_t* game_log::g_log; const game::native::dvar_t* game_log::g_logSync; @@ -120,9 +120,7 @@ void game_log::post_load() utils::hook::set(0x8AC858, gscr_log_print); utils::hook(0x50D135, g_init_game_stub, HOOK_CALL).install()->quick(); - - utils::hook(0x573C82, g_shutdown_game_stub, HOOK_CALL).install()->quick(); - utils::hook(0x573D3A, g_shutdown_game_stub, HOOK_CALL).install()->quick(); + scripting::on_shutdown(g_shutdown_game_stub); utils::hook(0x50D5F4, exit_level_stub, HOOK_JUMP).install()->quick(); diff --git a/src/module/gsc/script_error.cpp b/src/module/gsc/script_error.cpp index 5053e50..0d9fb3e 100644 --- a/src/module/gsc/script_error.cpp +++ b/src/module/gsc/script_error.cpp @@ -3,24 +3,63 @@ #include "game/game.hpp" #include "script_error.hpp" +#include "script_loading.hpp" +#include "module/log_file.hpp" #include "module/scripting.hpp" #include #include +#include +#include + using namespace utils::string; namespace gsc { namespace { + // Array count confirmed at TODO + std::array var_typename = + { + "undefined", + "object", + "string", + "localized string", + "vector", + "float", + "int", + "codepos", + "precodepos", + "function", + "builtin function", + "builtin method", + "stack", + "animation", + "pre animation", + "thread", + "thread", + "thread", + "thread", + "struct", + "removed entity", + "entity", + "array", + "removed thread", + "", + "thread list", + "endon list", + }; + utils::hook::detour scr_emit_function_hook; unsigned int current_filename = 0; std::string unknown_function_error; + char gsc_error_msg[1024]; + void scr_emit_function_stub(unsigned int filename, unsigned int thread_name, char* code_pos) { current_filename = filename; @@ -82,6 +121,142 @@ namespace gsc return res; } + + std::optional get_opcode_name(const std::uint8_t opcode) + { + try + { + return {xsk::gsc::iw5::resolver::opcode_name(opcode)}; + } + catch (...) + { + return {}; + } + } + + void builtin_call_error(const std::string& error) + { + const auto pos = game::native::scr_function_stack->pos; + const auto function_id = *reinterpret_cast(reinterpret_cast(pos - 2)); + + if (function_id > (scr_func_max_id - 1)) + { + log_file::info("in call to builtin method \"%s\"%s\n", xsk::gsc::iw5::resolver::method_name(function_id).data(), error.data()); + } + else + { + log_file::info("in call to builtin function \"%s\"%s\n", xsk::gsc::iw5::resolver::function_name(function_id).data(), error.data()); + } + } + + void vm_error_stub(int mark_pos) + { + log_file::info("******* script runtime error ********\n"); + + const auto opcode_id = *reinterpret_cast(SELECT_VALUE(0x1BF6928, 0x20B8E28)); + const auto error = (*gsc_error_msg) ? std::format(": {}\n", gsc_error_msg) : std::string(); + + if ((opcode_id >= 0x84 && opcode_id <= 0x8A) || (opcode_id >= 0x8B && opcode_id <= 0x91)) + { + builtin_call_error(error); + } + else + { + const auto opcode = get_opcode_name(opcode_id); + if (opcode.has_value()) + { + log_file::info("while processing instruction %s%s\n", opcode.value().data(), error.data()); + } + else + { + log_file::info("while processing instruction 0x%X%s\n", opcode_id, error.data()); + } + } + + ZeroMemory(gsc_error_msg, sizeof(gsc_error_msg)); + + log_file::info("************************************\n"); + + game::native::LargeLocalResetToMark(mark_pos); + } + + void scr_fx_param_error([[maybe_unused]] int param_index, const char* error_string, int fx_id) + { + assert(error_string); + + char fx_name[0x400]{}; + + if (fx_id) + { + const auto index = SELECT_VALUE(game::native::sp::CS_EFFECT_NAMES, game::native::mp::CS_EFFECT_NAMES); + game::native::SV_GetConfigstring(fx_id + index, fx_name, 1024); + } + else + { + strncpy_s(fx_name, "not successfully loaded", _TRUNCATE); + } + + scr_error(va("%s (effect = %s)\n", error_string, fx_name)); + } + + void gscr_cast_int() + { + switch (scr_get_type(0)) + { + case game::native::VAR_STRING: + game::native::Scr_AddInt(std::atoi(game::native::Scr_GetString(0))); + break; + case game::native::VAR_FLOAT: + game::native::Scr_AddInt(static_cast(scr_get_float(0))); + break; + case game::native::VAR_INTEGER: + game::native::Scr_AddInt(scr_get_int(0)); + break; + default: + scr_error(va("cannot cast %s to int", scr_get_type_name(0))); + break; + } + } + + void gscr_cast_float() + { + switch (scr_get_type(0)) + { + case game::native::VAR_STRING: + game::native::Scr_AddFloat(static_cast(std::atof(game::native::Scr_GetString(0)))); + break; + case game::native::VAR_FLOAT: + game::native::Scr_AddFloat(scr_get_float(0)); + break; + case game::native::VAR_INTEGER: + game::native::Scr_AddFloat(static_cast(scr_get_int(0))); + break; + default: + scr_error(va("cannot cast %s to float", scr_get_type_name(0))); + break; + } + } + + void assert_cmd() + { + if (!scr_get_int(0)) + { + scr_error("Assert fail"); + } + } + + void assert_ex_cmd() + { + if (!scr_get_int(0)) + { + scr_error(utils::string::va("Assert fail: %s", game::native::Scr_GetString(1))); + } + } + + void assert_msg_cmd() + { + scr_error(utils::string::va("Assert fail: %s", game::native::Scr_GetString(0))); + } } std::optional> find_function(const char* pos) @@ -101,6 +276,177 @@ namespace gsc return {}; } + unsigned int scr_get_object(unsigned int index) + { + if (index < game::native::scr_VmPub->outparamcount) + { + auto* value = game::native::scr_VmPub->top - index; + if (value->type == game::native::VAR_POINTER) + { + return value->u.pointerValue; + } + + scr_error(va("Type %s is not an object", var_typename[value->type])); + } + + scr_error(va("Parameter %u does not exist", index + 1)); + return 0; + } + + unsigned int scr_get_const_string(unsigned int index) + { + if (index < game::native::scr_VmPub->outparamcount) + { + auto* value = game::native::scr_VmPub->top - index; + if (game::native::Scr_CastString(value)) + { + assert(value->type == game::native::VAR_STRING); + return value->u.stringValue; + } + + game::native::Scr_ErrorInternal(); + } + + scr_error(va("Parameter %u does not exist", index + 1)); + return 0; + } + + unsigned int scr_get_const_istring(unsigned int index) + { + if (index < game::native::scr_VmPub->outparamcount) + { + auto* value = game::native::scr_VmPub->top - index; + if (value->type == game::native::VAR_ISTRING) + { + return value->u.stringValue; + } + + scr_error(va("Type %s is not a localized string", var_typename[value->type])); + } + + scr_error(va("Parameter %u does not exist", index + 1)); + return 0; + } + + void scr_validate_localized_string_ref([[maybe_unused]] int parm_index, const char* token, int token_len) + { + assert(token); + assert(token_len >= 0); + + if (token_len < 2) + { + return; + } + + for (auto char_iter = 0; char_iter < token_len; ++char_iter) + { + if (!std::isalnum(static_cast(token[char_iter])) && token[char_iter] != '_') + { + scr_error(va("Illegal localized string reference: %s must contain only alpha-numeric characters and underscores", token)); + } + } + } + + void scr_get_vector(unsigned int index, float* vector_value) + { + if (index < game::native::scr_VmPub->outparamcount) + { + auto* value = game::native::scr_VmPub->top - index; + if (value->type == game::native::VAR_VECTOR) + { + std::memcpy(vector_value, value->u.vectorValue, sizeof(game::native::vec3_t)); + return; + } + + scr_error(va("Type %s is not a vector", var_typename[value->type])); + } + + scr_error(va("Parameter %u does not exist", index + 1)); + } + + int scr_get_int(unsigned int index) + { + if (index < game::native::scr_VmPub->outparamcount) + { + auto* value = game::native::scr_VmPub->top - index; + if (value->type == game::native::VAR_INTEGER) + { + return value->u.intValue; + } + + scr_error(va("Type %s is not an int", var_typename[value->type])); + } + + scr_error(va("Parameter %u does not exist", index + 1)); + return 0; + } + + float scr_get_float(unsigned int index) + { + if (index < game::native::scr_VmPub->outparamcount) + { + auto* value = game::native::scr_VmPub->top - index; + if (value->type == game::native::VAR_FLOAT) + { + return value->u.floatValue; + } + + if (value->type == game::native::VAR_INTEGER) + { + return static_cast(value->u.intValue); + } + + scr_error(va("Type %s is not a float", var_typename[value->type])); + } + + scr_error(va("Parameter %u does not exist", index + 1)); + return 0.0f; + } + + int scr_get_pointer_type(unsigned int index) + { + if (index < game::native::scr_VmPub->outparamcount) + { + if ((game::native::scr_VmPub->top - index)->type == game::native::VAR_POINTER) + { + return static_cast(game::native::GetObjectType((game::native::scr_VmPub->top - index)->u.pointerValue)); + } + + scr_error(va("Type %s is not an object", var_typename[(game::native::scr_VmPub->top - index)->type])); + } + + scr_error(va("Parameter %u does not exist", index + 1)); + return 0; + } + + int scr_get_type(unsigned int index) + { + if (index < game::native::scr_VmPub->outparamcount) + { + return (game::native::scr_VmPub->top - index)->type; + } + + scr_error(va("Parameter %u does not exist", index + 1)); + return 0; + } + + void scr_error(const char* error) + { + strncpy_s(gsc_error_msg, error, _TRUNCATE); + game::native::Scr_ErrorInternal(); + } + + const char* scr_get_type_name(unsigned int index) + { + if (index < game::native::scr_VmPub->outparamcount) + { + return var_typename[(game::native::scr_VmPub->top - index)->type]; + } + + scr_error(va("Parameter %u does not exist", index + 1)); + return nullptr; + } + class error final : public module { public: @@ -111,6 +457,29 @@ namespace gsc utils::hook(SELECT_VALUE(0x60DABA, 0x5615FA), &compile_error_stub, HOOK_CALL).install()->quick(); utils::hook(SELECT_VALUE(0x60DAD1, 0x561611), &compile_error_stub, HOOK_CALL).install()->quick(); utils::hook(SELECT_VALUE(0x40DCFA, 0x56144A), &find_variable_stub, HOOK_CALL).install()->quick(); + + utils::hook(SELECT_VALUE(0x612BFC, 0x56D87D), &vm_error_stub, HOOK_CALL).install()->quick(); // LargeLocalResetToMark + + // Restore basic error messages for commonly used scr functions + utils::hook(SELECT_VALUE(0x52F730, 0x56A630), &scr_get_object, HOOK_JUMP).install()->quick(); + utils::hook(SELECT_VALUE(0x40FDE0, 0x56A200), &scr_get_const_string, HOOK_JUMP).install()->quick(); + utils::hook(SELECT_VALUE(0x4FD700, 0x56A420), &scr_get_const_istring, HOOK_JUMP).install()->quick(); + utils::hook(SELECT_VALUE(0x536FAC, 0x523FAE), &scr_validate_localized_string_ref, HOOK_CALL).install()->quick(); // Scr_ConstructMessageString + utils::hook(SELECT_VALUE(0x452E90, 0x56A4D0), &scr_get_vector, HOOK_JUMP).install()->quick(); + utils::hook(SELECT_VALUE(0x51B520, 0x56A010), &scr_get_int, HOOK_JUMP).install()->quick(); + utils::hook(SELECT_VALUE(0x4D8B50, 0x56A190), &scr_get_float, HOOK_JUMP).install()->quick(); + + utils::hook(SELECT_VALUE(0x4C02D0, 0x51F230), &scr_fx_param_error, HOOK_JUMP).install()->quick(); + + utils::hook(SELECT_VALUE(0x4D6510, 0x56A980), &scr_get_pointer_type, HOOK_JUMP).install()->quick(); + utils::hook(SELECT_VALUE(0x4958D0, 0x56A8C0), &scr_get_type, HOOK_JUMP).install()->quick(); + + utils::hook::set(SELECT_VALUE(0x92BB58, 0x8AC040), gscr_cast_int); + utils::hook::set(SELECT_VALUE(0x92BB64, 0x8AC04C), gscr_cast_float); + + utils::hook::set(SELECT_VALUE(0x92B93C, 0x8ABE24), assert_cmd); + utils::hook::set(SELECT_VALUE(0x92B948, 0x8ABE30), assert_ex_cmd); + utils::hook::set(SELECT_VALUE(0x92B954, 0x8ABE3C), assert_msg_cmd); } void pre_destroy() override diff --git a/src/module/gsc/script_error.hpp b/src/module/gsc/script_error.hpp index 284af43..bd3ba18 100644 --- a/src/module/gsc/script_error.hpp +++ b/src/module/gsc/script_error.hpp @@ -3,4 +3,18 @@ namespace gsc { std::optional> find_function(const char* pos); + + unsigned int scr_get_object(unsigned int index); + unsigned int scr_get_const_string(unsigned int index); + unsigned int scr_get_const_istring(unsigned int index); + void scr_validate_localized_string_ref(int parm_index, const char* token, int token_len); + void scr_get_vector(unsigned int index, float* vector_value); + int scr_get_int(unsigned int index); + float scr_get_float(unsigned int index); + + int scr_get_pointer_type(unsigned int index); + int scr_get_type(unsigned int index); + const char* scr_get_type_name(unsigned int index); + + void scr_error(const char* error); } diff --git a/src/module/gsc/script_loading.cpp b/src/module/gsc/script_loading.cpp index c1da12a..8cc6cec 100644 --- a/src/module/gsc/script_loading.cpp +++ b/src/module/gsc/script_loading.cpp @@ -19,6 +19,8 @@ namespace gsc { + std::uint16_t scr_func_max_id = 0x1C7; + namespace { auto compiler = ::gsc::compiler(); @@ -165,6 +167,23 @@ namespace gsc utils::hook(SELECT_VALUE(0x44685E, 0x56B13E), find_script, HOOK_CALL).install()->quick(); utils::hook(SELECT_VALUE(0x446868, 0x56B148), db_is_x_asset_default, HOOK_CALL).install()->quick(); + // Allow custom scripts to include other custom scripts + xsk::gsc::iw5::resolver::init([](const auto& include_name) -> std::vector + { + const auto real_name = include_name + ".gsc"; + + std::string file_buffer; + if (!read_script_file(real_name, &file_buffer) || file_buffer.empty()) + { + throw std::runtime_error(std::format("Could not load gsc file '{}'", real_name)); + } + + std::vector result; + result.assign(file_buffer.begin(), file_buffer.end()); + + return result; + }); + scripting::on_shutdown([](int free_scripts) -> void { if (free_scripts) diff --git a/src/module/gsc/script_loading.hpp b/src/module/gsc/script_loading.hpp index e84756a..471288c 100644 --- a/src/module/gsc/script_loading.hpp +++ b/src/module/gsc/script_loading.hpp @@ -2,5 +2,7 @@ namespace gsc { + extern std::uint16_t scr_func_max_id; + game::native::ScriptFile* find_script(game::native::XAssetType type, const char* name, int allow_create_default); } diff --git a/src/module/log_file.cpp b/src/module/log_file.cpp index fa821a2..20b1307 100644 --- a/src/module/log_file.cpp +++ b/src/module/log_file.cpp @@ -79,6 +79,8 @@ void log_file::info(const char* fmt, ...) { com_log_print_message(msg); } + + printf("%s", msg); } void log_file::post_load() @@ -86,7 +88,7 @@ void log_file::post_load() // The game closes the logfile handle in Com_Quit_f com_logfile = game::native::Dvar_RegisterInt("logfile", 1, - 0, 2, 0, "Write to log file - 0 = disabled, 1 = async file write, 2 = Sync every write"); + 0, 2, game::native::DVAR_NONE, "Write to log file - 0 = disabled, 1 = async file write, 2 = Sync every write"); log_file_name = SELECT_VALUE("console_sp.log", "console_mp.log"); } diff --git a/src/module/patches.cpp b/src/module/patches.cpp index 9bd843c..633c94f 100644 --- a/src/module/patches.cpp +++ b/src/module/patches.cpp @@ -73,7 +73,7 @@ private: static __declspec(noreturn) void long_jump_stub(jmp_buf buf, const int value) noexcept(false) { -#ifdef DEBUG +#ifdef _DEBUG { printf("Unwinding the stack...\n"); } diff --git a/src/module/scripting.cpp b/src/module/scripting.cpp index 070273f..30af425 100644 --- a/src/module/scripting.cpp +++ b/src/module/scripting.cpp @@ -1,14 +1,11 @@ #include #include +#include "game/game.hpp" + #include -#include -#include "game/scripting/context.hpp" #include "game/scripting/functions.hpp" -#include "scheduler.hpp" -#include "scripting.hpp" - #include "gsc/script_loading.hpp" namespace scripting @@ -129,171 +126,13 @@ namespace scripting public: void post_load() override { - start_hook_.initialize(SELECT_VALUE(0x50C575, 0x50D4F2), &start_execution_stub, HOOK_CALL) // - ->install() // - ->quick(); - - stop_hook_.initialize(SELECT_VALUE(0x528B04, 0x569E46), &stop_execution_stub, HOOK_CALL) // - ->install() // - ->quick(); - - utils::hook(SELECT_VALUE(0x4F9706, 0x5772A0), &frame_stub, HOOK_CALL).install()->quick(); - utils::hook(SELECT_VALUE(0x4FFA48, 0x5774AB), &frame_stub, HOOK_CALL).install()->quick(); - // Only relevant one? - - utils::hook(SELECT_VALUE(0x6109F3, 0x56B637), &vm_notify_stub, HOOK_CALL).install()->quick(); - utils::hook(SELECT_VALUE(0x6128BE, 0x56D541), &vm_notify_stub, HOOK_CALL).install()->quick(); - - if (game::is_sp()) - { - utils::hook(0x50C57E, &frame_stub, HOOK_CALL).install()->quick(); - utils::hook(0x6523A3, &frame_stub, HOOK_CALL).install()->quick(); - utils::hook(0x5145D2, &frame_stub, HOOK_CALL).install()->quick(); - - utils::hook(0x610970, &vm_notify_stub, HOOK_JUMP).install()->quick(); - } - utils::hook(SELECT_VALUE(0x44690A, 0x56B1EA), &scr_set_thread_position, HOOK_CALL).install()->quick(); utils::hook(SELECT_VALUE(0x4232A8, 0x561748), &process_script, HOOK_CALL).install()->quick(); utils::hook(SELECT_VALUE(0x651E1B, 0x573C82), &g_shutdown_game_stub, HOOK_CALL).install()->quick(); utils::hook(SELECT_VALUE(0x651ECC, 0x573D3A), &g_shutdown_game_stub, HOOK_CALL).install()->quick(); } - - void pre_destroy() override - { - this->scripts_.clear(); - } - - private: - std::vector> scripts_; - - void load_scripts() - { - const auto script_dir = "userraw/scripts/"s; - - if (!utils::io::directory_exists(script_dir)) - { - return; - } - - const auto scripts = utils::io::list_files(script_dir); - - for (const auto& script : scripts) - { - if (script.substr(script.find_last_of('.') + 1) == "chai") - { - try - { - auto context = std::make_unique(); - context->get_chai()->eval_file(script); - this->scripts_.push_back(std::move(context)); - } - catch (chaiscript::exception::eval_error& e) - { - throw std::runtime_error(e.pretty_print()); - } - } - } - } - - void start_execution() - { - try - { - this->load_scripts(); - } - catch (std::exception& e) - { - propagate_error(e); - } - } - - void stop_execution() - { - this->scripts_.clear(); - } - - void run_frame() const - { - for (const auto& script : this->scripts_) - { - script->get_scheduler()->run_frame(); - } - } - - void dispatch(game::scripting::event* event) const - { - for (const auto& script : this->scripts_) - { - script->get_event_handler()->dispatch(event); - } - } - - static utils::hook start_hook_; - static utils::hook stop_hook_; - - static void propagate_error(const std::exception& e) - { - printf("\n******* Script execution error *******\n"); - printf("%s\n", e.what()); - printf("**************************************\n\n"); - - scheduler::once([] - { - game::native::Com_Error(game::native::errorParm_t::ERR_SCRIPT, "Script execution error\n(see console for actual details)\n"); - }, scheduler::pipeline::main); - } - - static void start_execution_stub() - { - module_loader::get()->start_execution(); - static_cast(start_hook_.get_original())(); - } - - static void stop_execution_stub() - { - module_loader::get()->stop_execution(); - static_cast(stop_hook_.get_original())(); - } - - static void vm_notify_stub(const unsigned int notify_id, const unsigned short type, - game::native::VariableValue* stack) - { - try - { - game::scripting::event e; - e.name = game::native::SL_ConvertToString(type); - e.entity_id = notify_id; - - if (e.name == "touch") return; // Skip that for now - - for (auto* value = stack; value->type != game::native::SCRIPT_END; --value) - { - e.arguments.emplace_back(*value); - } - - module_loader::get()->dispatch(&e); - } - catch (std::exception& e) - { - propagate_error(e); - } - - game::native::VM_Notify(notify_id, type, stack); - } - - static int frame_stub(const int a1, const int a2) - { - module_loader::get()->run_frame(); - return game::native::G_RunFrame(a1, a2); - } }; - - utils::hook scripting_class::start_hook_; - utils::hook scripting_class::stop_hook_; } - - REGISTER_MODULE(scripting::scripting_class) diff --git a/src/module/test_clients.cpp b/src/module/test_clients.cpp index 65ed8c1..3383095 100644 --- a/src/module/test_clients.cpp +++ b/src/module/test_clients.cpp @@ -90,7 +90,7 @@ game::native::gentity_s* test_clients::sv_add_test_client() game::native::SV_ClientEnterWorld(client, &cmd); - assert(client->gentity != nullptr); + assert(client->gentity); return client->gentity; } @@ -99,7 +99,7 @@ void test_clients::gscr_add_test_client() { const auto* ent = sv_add_test_client(); - if (ent != nullptr) + if (ent) { game::native::Scr_AddEntityNum(ent->s.number, 0); } diff --git a/src/std_include.hpp b/src/std_include.hpp index 248a7c4..bb26e64 100644 --- a/src/std_include.hpp +++ b/src/std_include.hpp @@ -6,7 +6,6 @@ #pragma warning(push) #pragma warning(disable: 4244) #pragma warning(disable: 4458) -#pragma warning(disable: 4702) #pragma warning(disable: 6297) #pragma warning(disable: 6385) #pragma warning(disable: 6386) @@ -44,11 +43,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include @@ -62,8 +63,6 @@ #include -#include - #pragma comment(lib, "gdiplus.lib") #pragma comment(lib, "ws2_32.lib")