Add replaceFunc to gsc + fix entity struct
This commit is contained in:
parent
e2ae531833
commit
4ae0e604df
@ -14,6 +14,8 @@
|
|||||||
#include "game/scripting/functions.hpp"
|
#include "game/scripting/functions.hpp"
|
||||||
#include "game/scripting/lua/error.hpp"
|
#include "game/scripting/lua/error.hpp"
|
||||||
|
|
||||||
|
#include "notifies.hpp"
|
||||||
|
|
||||||
#include <xsk/gsc/types.hpp>
|
#include <xsk/gsc/types.hpp>
|
||||||
#include <xsk/gsc/interfaces/compiler.hpp>
|
#include <xsk/gsc/interfaces/compiler.hpp>
|
||||||
#include <xsk/gsc/interfaces/assembler.hpp>
|
#include <xsk/gsc/interfaces/assembler.hpp>
|
||||||
@ -28,174 +30,20 @@
|
|||||||
|
|
||||||
namespace gsc
|
namespace gsc
|
||||||
{
|
{
|
||||||
|
void* func_table[0x1000]{};
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
game::dvar_t* developer_script = nullptr;
|
game::dvar_t* developer_script = nullptr;
|
||||||
|
|
||||||
std::unordered_map<int, std::string> opcodes =
|
|
||||||
{
|
|
||||||
{0x17, "SET_NEW_LOCAL_VARIABLE_FIELD_CACHED0"},
|
|
||||||
{0x18, "EVAL_SELF_FIELD_VARIABLE"},
|
|
||||||
{0x19, "RETN"},
|
|
||||||
{0x1A, "CALL_BUILTIN_FUNC_0"},
|
|
||||||
{0x1B, "CALL_BUILTIN_FUNC_1"},
|
|
||||||
{0x1C, "CALL_BUILTIN_FUNC_2"},
|
|
||||||
{0x1D, "CALL_BUILTIN_FUNC_3"},
|
|
||||||
{0x1E, "CALL_BUILTIN_FUNC_4"},
|
|
||||||
{0x1F, "CALL_BUILTIN_FUNC_5"},
|
|
||||||
{0x20, "CALL_BUILTIN_FUNC"},
|
|
||||||
{0x21, "BOOL_NOT"},
|
|
||||||
{0x22, "CALL_FAR_METHOD_THEAD"},
|
|
||||||
{0x23, "JMP_EXPR_TRUE"},
|
|
||||||
{0x24, "SET_LEVEL_FIELD_VARIABLE_FIELD"},
|
|
||||||
{0x25, "CAST_BOOL"},
|
|
||||||
{0x26, "EVAL_NEW_LOCAL_ARRAY_REF_CACHED0"},
|
|
||||||
{0x27, "CALL_BUILTIN_FUNC_POINTER"},
|
|
||||||
{0x28, "INEQUALITY"},
|
|
||||||
{0x29, "GET_THISTHREAD"},
|
|
||||||
{0x2A, "CLEAR_FIELD_VARIABLE"},
|
|
||||||
{0x2B, "GET_FLOAT"},
|
|
||||||
{0x2C, "SAFE_CREATE_VARIABLE_FIELD_CACHED"},
|
|
||||||
{0x2D, "CALL_FAR_FUNC2"},
|
|
||||||
{0x2E, "CALL_FAR_FUNC"},
|
|
||||||
{0x2F, "CALL_FAR_FUNC_CHILD_THREAD"},
|
|
||||||
{0x30, "CLEAR_LOCAL_VARIABLE_FIELD_CACHED0"},
|
|
||||||
{0x31, "CLEAR_LOCAL_VARIABLE_FIELD_CACHED"},
|
|
||||||
{0x32, "CHECK_CLEAR_PARAMS"},
|
|
||||||
{0x33, "CAST_FIELD_OBJ"},
|
|
||||||
{0x34, "END"},
|
|
||||||
{0x35, "SIZE"},
|
|
||||||
{0x36, "EMPTY_ARRAY"},
|
|
||||||
{0x37, "BIT_AND"},
|
|
||||||
{0x38, "LESSEQUAL"},
|
|
||||||
{0x39, "VOIDCODEPOS"},
|
|
||||||
{0x3A, "CALL_METHOD_THREAD_POINTER"},
|
|
||||||
{0x3B, "ENDSWITCH"},
|
|
||||||
{0x3C, "CLEAR_VARIABLE_FIELD"},
|
|
||||||
{0x3D, "DIV"},
|
|
||||||
{0x3E, "CALL_FAR_METHOD_CHILD_THEAD"},
|
|
||||||
{0x3F, "GET_USHORT"},
|
|
||||||
{0x40, "JMP_TRUE"},
|
|
||||||
{0x41, "GET_SELF"},
|
|
||||||
{0x42, "CALL_FAR_FUNC_THREAD"},
|
|
||||||
{0x43, "CALL_LOCAL_FUNC_THREAD"},
|
|
||||||
{0x44, "SET_LOCAL_VARIABLE_FIELD_CACHED0"},
|
|
||||||
{0x45, "SET_LOCAL_VARIABLE_FIELD_CACHED"},
|
|
||||||
{0x46, "PLUS"},
|
|
||||||
{0x47, "BOOL_COMPLEMENT"},
|
|
||||||
{0x48, "CALL_METHOD_POINTER"},
|
|
||||||
{0x49, "INC"},
|
|
||||||
{0x4A, "REMOVE_LOCAL_VARIABLES"},
|
|
||||||
{0x4B, "JMP_EXPR_FALSE"},
|
|
||||||
{0x4C, "SWITCH"},
|
|
||||||
{0x4D, "CLEAR_PARAMS"},
|
|
||||||
{0x4E, "EVAL_LOCAL_VARIABLE_REF_CACHED0"},
|
|
||||||
{0x4F, "EVAL_LOCAL_VARIABLE_REF_CACHED"},
|
|
||||||
{0x50, "CALL_LOCAL_METHOD"},
|
|
||||||
{0x51, "EVAL_FIELD_VARIABLE"},
|
|
||||||
{0x52, "EVAL_FIELD_VARIABLE_REF"},
|
|
||||||
{0x53, "GET_STRING"},
|
|
||||||
{0x54, "CALL_FUNC_POINTER"},
|
|
||||||
{0x55, "EVAL_LEVEL_FIELD_VARIABLE"},
|
|
||||||
{0x56, "GET_VECTOR"},
|
|
||||||
{0x57, "ENDON"},
|
|
||||||
{0x58, "GREATEREQUAL"},
|
|
||||||
{0x59, "GET_SELF_OBJ"},
|
|
||||||
{0x5A, "SET_ANIM_FIELD_VARIABLE_FIELD"},
|
|
||||||
{0x5B, "SET_VARIABLE_FIELD"},
|
|
||||||
{0x5C, "CALL_LOCAL_FUNC2"},
|
|
||||||
{0x5D, "CALL_LOCAL_FUNC"},
|
|
||||||
{0x5E, "EVAL_LOCAL_ARRAY_REF_CACHED0"},
|
|
||||||
{0x5F, "EVAL_LOCAL_ARRAY_REF_CACHED"},
|
|
||||||
{0x60, "GET_FAR_FUNC"},
|
|
||||||
{0x61, "LESS"},
|
|
||||||
{0x62, "GET_GAME_REF"},
|
|
||||||
{0x63, "WAITFRAME"},
|
|
||||||
{0x64, "WAITTILLFRAMEEND"},
|
|
||||||
{0x65, "SAFE_SET_VARIABLE_FIELD_CACHED0"},
|
|
||||||
{0x66, "SAFE_SET_VARIABLE_FIELD_CACHED"},
|
|
||||||
{0x67, "CALL_METHOD_CHILD_THREAD_POINTER"},
|
|
||||||
{0x68, "GET_LEVEL"},
|
|
||||||
{0x69, "NOTIFY"},
|
|
||||||
{0x6A, "DEC_TOP"},
|
|
||||||
{0x6B, "SHIFT_LEFT"},
|
|
||||||
{0x6C, "CALL_LOCAL_METHOD_THREAD"},
|
|
||||||
{0x6D, "CALL_LOCAL_METHOD_CHILD_THREAD"},
|
|
||||||
{0x6E, "GREATER"},
|
|
||||||
{0x6F, "EVAL_LOCAL_VARIABLE_CACHED0"},
|
|
||||||
{0x70, "EVAL_LOCAL_VARIABLE_CACHED1"},
|
|
||||||
{0x71, "EVAL_LOCAL_VARIABLE_CACHED2"},
|
|
||||||
{0x72, "EVAL_LOCAL_VARIABLE_CACHED3"},
|
|
||||||
{0x73, "EVAL_LOCAL_VARIABLE_CACHED4"},
|
|
||||||
{0x74, "EVAL_LOCAL_VARIABLE_CACHED5"},
|
|
||||||
{0x75, "EVAL_LOCAL_VARIABLE_CACHED"},
|
|
||||||
{0x76, "SAFE_SET_WAITTILL_VARIABLE_FIELD_CACHED"},
|
|
||||||
{0x77, "JMP"},
|
|
||||||
{0x78, "CALL_FUNC_THREAD_POINTER"},
|
|
||||||
{0x79, "GET_ZERO"},
|
|
||||||
{0x7A, "WAIT"},
|
|
||||||
{0x7B, "MINUS"},
|
|
||||||
{0x7C, "SET_SELF_FIELD_VARIABLE_FIELD"},
|
|
||||||
{0x7D, "EVAL_NEW_LOCAL_VARIABLE_REF_CACHED0"},
|
|
||||||
{0x7E, "MULT"},
|
|
||||||
{0x7F, "CREATE_LOCAL_VARIABLE"},
|
|
||||||
{0x80, "CALL_LOCAL_FUNC_CHILD_THREAD"},
|
|
||||||
{0x81, "GET_INT"},
|
|
||||||
{0x82, "MOD"},
|
|
||||||
{0x83, "EVAL_ANIM_FIELD_VARIABLE_REF"},
|
|
||||||
{0x84, "GET_BUILTIN_FUNC"},
|
|
||||||
{0x85, "GET_GAME"},
|
|
||||||
{0x86, "WAITTILL"},
|
|
||||||
{0x87, "DEC"},
|
|
||||||
{0x88, "EVAL_LOCAL_VARIABLE_OBJECT_CACHED"},
|
|
||||||
{0x89, "PRE_CALL"},
|
|
||||||
{0x8A, "GET_ANIM"},
|
|
||||||
{0x8B, "GET_UNDEFINED"},
|
|
||||||
{0x8C, "EVAL_LEVEL_FIELD_VARIABLE_REF"},
|
|
||||||
{0x8D, "GET_ANIM_OBJ"},
|
|
||||||
{0x8E, "GET_LEVEL_OBJ"},
|
|
||||||
{0x8F, "BIT_EXOR"},
|
|
||||||
{0x90, "EQUALITY"},
|
|
||||||
{0x91, "CLEAR_ARRAY"},
|
|
||||||
{0x92, "JMP_BACK"},
|
|
||||||
{0x93, "GET_ANIMATION"},
|
|
||||||
{0x94, "EVAL_ANIM_FIELD_VARIABLE"},
|
|
||||||
{0x95, "GET_ANIMTREE"},
|
|
||||||
{0x96, "GET_ISTRING"},
|
|
||||||
{0x97, "EVAL_ARRAY_REF"},
|
|
||||||
{0x98, "EVAL_SELF_FIELD_VARIABLE_REF"},
|
|
||||||
{0x99, "GET_NBYTE"},
|
|
||||||
{0x9A, "GET_BUILTIN_METHOD"},
|
|
||||||
{0x9B, "CALL_BUILTIN_METHOD_POINTER"},
|
|
||||||
{0x9C, "EVAL_ARRAY"},
|
|
||||||
{0x9D, "VECTOR"},
|
|
||||||
{0x9E, "CALL_FAR_METHOD"},
|
|
||||||
{0x9F, "EVAL_LOCAL_ARRAY_CACHED"},
|
|
||||||
{0xA0, "GET_BYTE"},
|
|
||||||
{0xA1, "CALL_FUNC_CHILD_THREAD_POINTER"},
|
|
||||||
{0xA2, "BIT_OR"},
|
|
||||||
{0xA3, "ADD_ARRAY"},
|
|
||||||
{0xA4, "WAITTILLMATCH2"},
|
|
||||||
{0xA5, "WAITTILLMATCH"},
|
|
||||||
{0xA6, "GET_LOCAL_FUNC"},
|
|
||||||
{0xA7, "GET_NUSHORT"},
|
|
||||||
{0xA8, "SHIFT_RIGHT"},
|
|
||||||
{0xA9, "CALL_BUILTIN_METHOD_0"},
|
|
||||||
{0xAA, "CALL_BUILTIN_METHOD_1"},
|
|
||||||
{0xAB, "CALL_BUILTIN_METHOD_2"},
|
|
||||||
{0xAC, "CALL_BUILTIN_METHOD_3"},
|
|
||||||
{0xAD, "CALL_BUILTIN_METHOD_4"},
|
|
||||||
{0xAE, "CALL_BUILTIN_METHOD_5"},
|
|
||||||
{0xAF, "CALL_BUILTIN_METHOD"},
|
|
||||||
{0xB0, "JMP_FALSE"},
|
|
||||||
};
|
|
||||||
|
|
||||||
auto compiler = ::gsc::compiler();
|
auto compiler = ::gsc::compiler();
|
||||||
auto assembler = ::gsc::assembler();
|
auto assembler = ::gsc::assembler();
|
||||||
|
|
||||||
std::unordered_map<std::string, unsigned int> main_handles;
|
std::unordered_map<std::string, unsigned int> main_handles;
|
||||||
std::unordered_map<std::string, unsigned int> init_handles;
|
std::unordered_map<std::string, unsigned int> init_handles;
|
||||||
std::unordered_map<std::string, game::ScriptFile*> loaded_scripts;
|
std::unordered_map<std::string, game::ScriptFile*> loaded_scripts;
|
||||||
|
std::unordered_map<unsigned int, scripting::script_function> functions;
|
||||||
|
std::optional<std::string> gsc_error;
|
||||||
|
|
||||||
char* allocate_buffer(size_t size)
|
char* allocate_buffer(size_t size)
|
||||||
{
|
{
|
||||||
@ -416,24 +264,32 @@ namespace gsc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool force_error_print = false;
|
||||||
void* vm_error_stub(void* a1)
|
void* vm_error_stub(void* a1)
|
||||||
{
|
{
|
||||||
if (!developer_script->current.enabled)
|
if (!developer_script->current.enabled || force_error_print)
|
||||||
{
|
{
|
||||||
return utils::hook::invoke<void*>(0x140614670, a1);
|
return utils::hook::invoke<void*>(0x140614670, a1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
force_error_print = false;
|
||||||
|
|
||||||
console::warn("*********** script runtime error *************\n");
|
console::warn("*********** script runtime error *************\n");
|
||||||
|
|
||||||
const auto opcode_id = *reinterpret_cast<std::uint8_t*>(0x14BAA93E8);
|
const auto opcode_id = *reinterpret_cast<std::uint8_t*>(0x14BAA93E8);
|
||||||
const auto opcode = get_opcode_name(opcode_id);
|
const auto opcode = get_opcode_name(opcode_id);
|
||||||
|
const std::string error_str = gsc_error.has_value()
|
||||||
|
? utils::string::va(": %s", gsc_error.value().data())
|
||||||
|
: "";
|
||||||
if (opcode.has_value())
|
if (opcode.has_value())
|
||||||
{
|
{
|
||||||
console::warn("while processing instruction %s\n", opcode.value().data());
|
console::warn("while processing instruction %s%s\n",
|
||||||
|
opcode.value().data(), error_str.data());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
console::warn("while processing instruction 0x%X\n", opcode_id);
|
console::warn("while processing instruction 0x%X%s\n",
|
||||||
|
opcode_id, error_str.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
print_callstack();
|
print_callstack();
|
||||||
@ -446,6 +302,42 @@ namespace gsc
|
|||||||
game::Com_Error(game::ERR_DROP, "LinkFile: unknown function in script '%s.gsc'",
|
game::Com_Error(game::ERR_DROP, "LinkFile: unknown function in script '%s.gsc'",
|
||||||
scripting::current_file.data());
|
scripting::current_file.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void register_gsc_functions_stub(void* a1, void* a2)
|
||||||
|
{
|
||||||
|
utils::hook::invoke<void>(0x140509F20, a1, a2);
|
||||||
|
for (const auto& func : functions)
|
||||||
|
{
|
||||||
|
game::Scr_RegisterFunction(func.second, 0, func.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scripting::script_value get_argument(int index)
|
||||||
|
{
|
||||||
|
if (index >= static_cast<int>(game::scr_VmPub->outparamcount))
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto value = &game::scr_VmPub->top[-index];
|
||||||
|
|
||||||
|
return scripting::script_value(*value);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto function_id_start = 0x320;
|
||||||
|
void add_function(const std::string& name, scripting::script_function function)
|
||||||
|
{
|
||||||
|
const auto id = ++function_id_start;
|
||||||
|
scripting::function_map[name] = id;
|
||||||
|
functions[id] = function;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_gsc_error(const std::string& error)
|
||||||
|
{
|
||||||
|
force_error_print = true;
|
||||||
|
gsc_error = error;
|
||||||
|
game::Scr_ErrorInternal();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
game::ScriptFile* find_script(game::XAssetType /*type*/, const char* name, int /*allow_create_default*/)
|
game::ScriptFile* find_script(game::XAssetType /*type*/, const char* name, int /*allow_create_default*/)
|
||||||
@ -510,6 +402,42 @@ namespace gsc
|
|||||||
utils::hook::call(0x1405BC583, unknown_function_stub);
|
utils::hook::call(0x1405BC583, unknown_function_stub);
|
||||||
utils::hook::call(0x1405BC5CF, unknown_function_stub);
|
utils::hook::call(0x1405BC5CF, unknown_function_stub);
|
||||||
|
|
||||||
|
utils::hook::call(0x1405BCBAB, register_gsc_functions_stub);
|
||||||
|
utils::hook::set<uint32_t>(0x1405BC7BC, 0x1000); // change builtin func count
|
||||||
|
|
||||||
|
#define RVA(ptr) static_cast<uint32_t>(reinterpret_cast<size_t>(ptr) - 0x140000000)
|
||||||
|
std::memcpy(&func_table, reinterpret_cast<void*>(0x14B153F90), 0x1900);
|
||||||
|
utils::hook::set<uint32_t>(0x1405BC7C2 + 4, RVA(&func_table));
|
||||||
|
utils::hook::inject(0x1405BCB78 + 3, &func_table);
|
||||||
|
utils::hook::set<uint32_t>(0x1405CA678 + 4, RVA(&func_table));
|
||||||
|
|
||||||
|
add_function("replacefunc", [](const game::scr_entref_t ref)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const auto what = get_argument(0).get_raw();
|
||||||
|
const auto with = get_argument(1).get_raw();
|
||||||
|
|
||||||
|
if (what.type != game::SCRIPT_FUNCTION)
|
||||||
|
{
|
||||||
|
set_gsc_error("replaceFunc: parameter 0 must be a function");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (with.type != game::SCRIPT_FUNCTION)
|
||||||
|
{
|
||||||
|
set_gsc_error("replaceFunc: parameter 0 must be a function");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
notifies::set_gsc_hook(what.u.codePosValue, with.u.codePosValue);
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
set_gsc_error(utils::string::va("replaceFunc: %s", e.what()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
scripting::on_shutdown([](int free_scripts)
|
scripting::on_shutdown([](int free_scripts)
|
||||||
{
|
{
|
||||||
if (free_scripts)
|
if (free_scripts)
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace gsc
|
namespace gsc
|
||||||
{
|
{
|
||||||
|
extern void* func_table[0x1000];
|
||||||
|
|
||||||
game::ScriptFile* find_script(game::XAssetType /*type*/, const char* name, int /*allow_create_default*/);
|
game::ScriptFile* find_script(game::XAssetType /*type*/, const char* name, int /*allow_create_default*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,15 +12,23 @@
|
|||||||
|
|
||||||
namespace notifies
|
namespace notifies
|
||||||
{
|
{
|
||||||
std::unordered_map<const char*, sol::protected_function> vm_execute_hooks;
|
|
||||||
bool hook_enabled = true;
|
bool hook_enabled = true;
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
struct gsc_hook_t
|
||||||
|
{
|
||||||
|
bool is_lua_hook{};
|
||||||
|
const char* target_pos{};
|
||||||
|
sol::protected_function lua_function;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unordered_map<const char*, gsc_hook_t> vm_execute_hooks;
|
||||||
utils::hook::detour scr_entity_damage_hook;
|
utils::hook::detour scr_entity_damage_hook;
|
||||||
std::vector<sol::protected_function> entity_damage_callbacks;
|
std::vector<sol::protected_function> entity_damage_callbacks;
|
||||||
|
|
||||||
char empty_function[2] = {0x32, 0x34}; // CHECK_CLEAR_PARAMS, END
|
char empty_function[2] = {0x32, 0x34}; // CHECK_CLEAR_PARAMS, END
|
||||||
|
const char* target_function = nullptr;
|
||||||
|
|
||||||
unsigned int local_id_to_entity(unsigned int local_id)
|
unsigned int local_id_to_entity(unsigned int local_id)
|
||||||
{
|
{
|
||||||
@ -43,21 +51,30 @@ namespace notifies
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto& hook = vm_execute_hooks[pos];
|
const auto& hook = vm_execute_hooks[pos];
|
||||||
const auto state = hook.lua_state();
|
if (hook.is_lua_hook)
|
||||||
|
|
||||||
const scripting::entity self = local_id_to_entity(game::scr_VmPub->function_frame->fs.localId);
|
|
||||||
|
|
||||||
std::vector<sol::lua_value> args;
|
|
||||||
|
|
||||||
const auto top = game::scr_function_stack->top;
|
|
||||||
|
|
||||||
for (auto* value = top; value->type != game::SCRIPT_END; --value)
|
|
||||||
{
|
{
|
||||||
args.push_back(scripting::lua::convert(state, *value));
|
const auto& function = hook.lua_function;
|
||||||
}
|
const auto state = function.lua_state();
|
||||||
|
|
||||||
const auto result = hook(self, sol::as_args(args));
|
const scripting::entity self = local_id_to_entity(game::scr_VmPub->function_frame->fs.localId);
|
||||||
scripting::lua::handle_error(result);
|
|
||||||
|
std::vector<sol::lua_value> args;
|
||||||
|
|
||||||
|
const auto top = game::scr_function_stack->top;
|
||||||
|
|
||||||
|
for (auto* value = top; value->type != game::SCRIPT_END; --value)
|
||||||
|
{
|
||||||
|
args.push_back(scripting::lua::convert(state, *value));
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto result = function(self, sol::as_args(args));
|
||||||
|
scripting::lua::handle_error(result);
|
||||||
|
target_function = empty_function;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
target_function = hook.target_pos;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -89,7 +106,8 @@ namespace notifies
|
|||||||
a.bind(replace);
|
a.bind(replace);
|
||||||
|
|
||||||
a.popad64();
|
a.popad64();
|
||||||
a.mov(r14, reinterpret_cast<char*>(empty_function));
|
a.mov(rax, qword_ptr(reinterpret_cast<int64_t>(&target_function)));
|
||||||
|
a.mov(r14, rax);
|
||||||
a.jmp(end);
|
a.jmp(end);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,12 +202,39 @@ namespace notifies
|
|||||||
entity_damage_callbacks.clear();
|
entity_damage_callbacks.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_lua_hook(const char* pos, const sol::protected_function& callback)
|
||||||
|
{
|
||||||
|
gsc_hook_t hook;
|
||||||
|
hook.is_lua_hook = true;
|
||||||
|
hook.lua_function = callback;
|
||||||
|
vm_execute_hooks[pos] = hook;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_gsc_hook(const char* source, const char* target)
|
||||||
|
{
|
||||||
|
gsc_hook_t hook;
|
||||||
|
hook.is_lua_hook = false;
|
||||||
|
hook.target_pos = target;
|
||||||
|
vm_execute_hooks[source] = hook;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_hook(const char* pos)
|
||||||
|
{
|
||||||
|
vm_execute_hooks.erase(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t get_hook_count()
|
||||||
|
{
|
||||||
|
return vm_execute_hooks.size();
|
||||||
|
}
|
||||||
|
|
||||||
class component final : public component_interface
|
class component final : public component_interface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void post_unpack() override
|
void post_unpack() override
|
||||||
{
|
{
|
||||||
utils::hook::jump(0x1405C90A5, utils::hook::assemble(vm_execute_stub), true);
|
const auto a = utils::hook::assemble(vm_execute_stub);
|
||||||
|
utils::hook::jump(0x1405C90A5, a, true);
|
||||||
|
|
||||||
scr_entity_damage_hook.create(0x1404BD2E0, scr_entity_damage_stub);
|
scr_entity_damage_hook.create(0x1404BD2E0, scr_entity_damage_stub);
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,13 @@
|
|||||||
|
|
||||||
namespace notifies
|
namespace notifies
|
||||||
{
|
{
|
||||||
extern std::unordered_map<const char*, sol::protected_function> vm_execute_hooks;
|
|
||||||
extern bool hook_enabled;
|
extern bool hook_enabled;
|
||||||
|
|
||||||
|
void set_lua_hook(const char* pos, const sol::protected_function&);
|
||||||
|
void set_gsc_hook(const char* source, const char* target);
|
||||||
|
void clear_hook(const char* pos);
|
||||||
|
size_t get_hook_count();
|
||||||
|
|
||||||
void add_entity_damage_callback(const sol::protected_function&);
|
void add_entity_damage_callback(const sol::protected_function&);
|
||||||
void clear_callbacks();
|
void clear_callbacks();
|
||||||
}
|
}
|
@ -2061,6 +2061,7 @@ namespace scripting
|
|||||||
{"export", 13703},
|
{"export", 13703},
|
||||||
{"animation", 70},
|
{"animation", 70},
|
||||||
{"spammed_model", 49508},
|
{"spammed_model", 49508},
|
||||||
|
{"vehicletype", 1282},
|
||||||
|
|
||||||
// script
|
// script
|
||||||
{"script_flag", 31190},
|
{"script_flag", 31190},
|
||||||
@ -2102,5 +2103,11 @@ namespace scripting
|
|||||||
{"script_drone", 31152},
|
{"script_drone", 31152},
|
||||||
{"script_health", 31247},
|
{"script_health", 31247},
|
||||||
{"script_friendname", 31217},
|
{"script_friendname", 31217},
|
||||||
|
{"script_airspeed", 31027},
|
||||||
|
{"script_missiles", 31293},
|
||||||
|
{"script_spotlight", 31447},
|
||||||
|
{"script_team", 31474},
|
||||||
|
{"script_ai_invulnerable", 31024},
|
||||||
|
{"script_mp_style_helicopter", 31353},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#include <std_include.hpp>
|
#include <std_include.hpp>
|
||||||
#include "functions.hpp"
|
#include "functions.hpp"
|
||||||
|
|
||||||
|
#include "../../component/gsc.hpp"
|
||||||
|
|
||||||
#include <utils/string.hpp>
|
#include <utils/string.hpp>
|
||||||
|
|
||||||
namespace scripting
|
namespace scripting
|
||||||
@ -59,7 +61,7 @@ namespace scripting
|
|||||||
|
|
||||||
script_function get_function_by_index(const unsigned index)
|
script_function get_function_by_index(const unsigned index)
|
||||||
{
|
{
|
||||||
static const auto function_table = 0x14B153F90;
|
static const auto function_table = &gsc::func_table;
|
||||||
static const auto method_table = 0x14B155890;
|
static const auto method_table = 0x14B155890;
|
||||||
|
|
||||||
if (index < 0x320)
|
if (index < 0x320)
|
||||||
|
@ -533,18 +533,18 @@ namespace scripting::lua
|
|||||||
const std::string function_name, const sol::protected_function& function)
|
const std::string function_name, const sol::protected_function& function)
|
||||||
{
|
{
|
||||||
const auto pos = get_function_pos(filename, function_name);
|
const auto pos = get_function_pos(filename, function_name);
|
||||||
notifies::vm_execute_hooks[pos] = function;
|
notifies::set_lua_hook(pos, function);
|
||||||
|
|
||||||
auto detour = sol::table::create(function.lua_state());
|
auto detour = sol::table::create(function.lua_state());
|
||||||
|
|
||||||
detour["disable"] = [pos]()
|
detour["disable"] = [pos]()
|
||||||
{
|
{
|
||||||
notifies::vm_execute_hooks.erase(pos);
|
notifies::clear_hook(pos);
|
||||||
};
|
};
|
||||||
|
|
||||||
detour["enable"] = [pos, function]()
|
detour["enable"] = [&]()
|
||||||
{
|
{
|
||||||
notifies::vm_execute_hooks[pos] = function;
|
notifies::set_lua_hook(pos, function);
|
||||||
};
|
};
|
||||||
|
|
||||||
detour["invoke"] = [filename, function_name](const entity& entity, const sol::this_state s, sol::variadic_args va)
|
detour["invoke"] = [filename, function_name](const entity& entity, const sol::this_state s, sol::variadic_args va)
|
||||||
|
@ -144,11 +144,10 @@ namespace scripting::lua
|
|||||||
game::VariableValue convert_function(sol::lua_value value)
|
game::VariableValue convert_function(sol::lua_value value)
|
||||||
{
|
{
|
||||||
const auto function = value.as<sol::protected_function>();
|
const auto function = value.as<sol::protected_function>();
|
||||||
const auto index = (char*)notifies::vm_execute_hooks.size() + 1;
|
const auto index = reinterpret_cast<char*>(notifies::get_hook_count() + 1);
|
||||||
|
notifies::set_lua_hook(index, function);
|
||||||
|
|
||||||
notifies::vm_execute_hooks[index] = function;
|
game::VariableValue func{};
|
||||||
|
|
||||||
game::VariableValue func;
|
|
||||||
func.type = game::SCRIPT_FUNCTION;
|
func.type = game::SCRIPT_FUNCTION;
|
||||||
func.u.codePosValue = index;
|
func.u.codePosValue = index;
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ namespace game
|
|||||||
|
|
||||||
struct EntityState
|
struct EntityState
|
||||||
{
|
{
|
||||||
char entityNum;
|
uint16_t entityNum;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum scr_string_t
|
enum scr_string_t
|
||||||
@ -75,25 +75,33 @@ namespace game
|
|||||||
|
|
||||||
struct gentity_s
|
struct gentity_s
|
||||||
{
|
{
|
||||||
EntityState s;
|
char __pad0[26];
|
||||||
char __pad0[0x1B];
|
|
||||||
vec3_t origin;
|
vec3_t origin;
|
||||||
char __pad1[0x98];
|
char __pad1[100];
|
||||||
|
EntityState s;
|
||||||
|
char __pad2[50];
|
||||||
Bounds box;
|
Bounds box;
|
||||||
char __pad2[0x4];
|
char __pad3[4];
|
||||||
Bounds absBox;
|
Bounds absBox;
|
||||||
char __pad3[0x24];
|
char __pad4[36];
|
||||||
gclient_s* client;
|
gclient_s* client;
|
||||||
char __pad4[0x30];
|
char __pad5[48];
|
||||||
scr_string_t script_classname;
|
scr_string_t script_classname;
|
||||||
char __pad5[0x18];
|
char __pad6[24];
|
||||||
char flags;
|
char flags;
|
||||||
char __pad6[0x188];
|
char __pad7[395];
|
||||||
}; // size = 760
|
}; // size = 760
|
||||||
|
|
||||||
//auto a = sizeof(gentity_s);
|
//auto a = sizeof(gentity_s);
|
||||||
|
|
||||||
static_assert(sizeof(gentity_s) == 760);
|
static_assert(sizeof(gentity_s) == 760);
|
||||||
|
static_assert(offsetof(gentity_s, origin) == 28);
|
||||||
|
static_assert(offsetof(gentity_s, box) == 192);
|
||||||
|
static_assert(offsetof(gentity_s, absBox) == 220);
|
||||||
|
static_assert(offsetof(gentity_s, client) == 280);
|
||||||
|
static_assert(offsetof(gentity_s, script_classname) == 336);
|
||||||
|
static_assert(offsetof(gentity_s, flags) == 364);
|
||||||
|
static_assert(offsetof(gentity_s, s) == 140);
|
||||||
|
|
||||||
struct pathlink_s
|
struct pathlink_s
|
||||||
{
|
{
|
||||||
|
@ -128,6 +128,7 @@ namespace game
|
|||||||
WEAK symbol<int()> Scr_GetNumParam{0x1405C7940};
|
WEAK symbol<int()> Scr_GetNumParam{0x1405C7940};
|
||||||
WEAK symbol<unsigned int(const char* script, unsigned int name)> Scr_GetFunctionHandle{0x1405BCD50};
|
WEAK symbol<unsigned int(const char* script, unsigned int name)> Scr_GetFunctionHandle{0x1405BCD50};
|
||||||
WEAK symbol<unsigned int(int handle, unsigned int paramcount)> Scr_ExecThread{0x1405C6F40};
|
WEAK symbol<unsigned int(int handle, unsigned int paramcount)> Scr_ExecThread{0x1405C6F40};
|
||||||
|
WEAK symbol<unsigned int(void* func, int type, unsigned int name)> Scr_RegisterFunction{0x1405BC7B0};
|
||||||
|
|
||||||
WEAK symbol<unsigned int(unsigned int localId, const char* pos, unsigned int paramcount)> VM_Execute{0x1405C8DB0};
|
WEAK symbol<unsigned int(unsigned int localId, const char* pos, unsigned int paramcount)> VM_Execute{0x1405C8DB0};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user