fix typo
This commit is contained in:
parent
3b52e11a45
commit
9be09b5873
@ -62,6 +62,7 @@ namespace game
|
||||
Scr_GetFunctionHandle_t Scr_GetFunctionHandle;
|
||||
Scr_ExecThread_t Scr_ExecThread;
|
||||
Scr_FreeThread_t Scr_FreeThread;
|
||||
Scr_RegisterFunction_t Scr_RegisterFunction;
|
||||
|
||||
GetObjectType_t GetObjectType;
|
||||
|
||||
@ -788,6 +789,7 @@ namespace game
|
||||
native::Scr_GetFunctionHandle = native::Scr_GetFunctionHandle_t(SELECT_VALUE(0x51DD50, 0x5618A0));
|
||||
native::Scr_ExecThread = native::Scr_ExecThread_t(SELECT_VALUE(0x4FC590, 0x56E240));
|
||||
native::Scr_FreeThread = native::Scr_FreeThread_t(SELECT_VALUE(0x51FD90, 0x569E20));
|
||||
native::Scr_RegisterFunction = native::Scr_RegisterFunction_t(SELECT_VALUE(0x49E190, 0x561520));
|
||||
|
||||
native::GetObjectType = native::GetObjectType_t(SELECT_VALUE(0x4D8FE0, 0x565C60));
|
||||
|
||||
|
@ -140,6 +140,9 @@ namespace game
|
||||
typedef void (*Scr_FreeThread_t)(unsigned short handle);
|
||||
extern Scr_FreeThread_t Scr_FreeThread;
|
||||
|
||||
typedef void (*Scr_RegisterFunction_t)(void* func, int type, unsigned int name);
|
||||
extern Scr_RegisterFunction_t Scr_RegisterFunction;
|
||||
|
||||
typedef unsigned int(*GetObjectType_t)(unsigned int id);
|
||||
extern GetObjectType_t GetObjectType;
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include <std_include.hpp>
|
||||
#include "game/game.hpp"
|
||||
|
||||
#include "module/gsc/script_extension.hpp"
|
||||
|
||||
#include "functions.hpp"
|
||||
|
||||
#include <utils/string.hpp>
|
||||
@ -67,10 +69,10 @@ namespace scripting
|
||||
|
||||
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);
|
||||
auto** function_table = gsc::func_table;
|
||||
auto** method_table = gsc::meth_table;
|
||||
|
||||
if (index < 0x1C7)
|
||||
if (index < gsc::scr_func_max_id)
|
||||
{
|
||||
return reinterpret_cast<game::native::BuiltinFunction*>(function_table)[index - 1];
|
||||
}
|
||||
|
@ -2,14 +2,141 @@
|
||||
#include <loader/module_loader.hpp>
|
||||
#include "game/game.hpp"
|
||||
|
||||
#include "script_extension.hpp"
|
||||
#include "script_error.hpp"
|
||||
|
||||
#include "module/console.hpp"
|
||||
#include "module/scripting.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/string.hpp>
|
||||
|
||||
#include <gsc_interface.hpp>
|
||||
|
||||
namespace gsc
|
||||
{
|
||||
std::uint16_t scr_func_max_id = 0x1C7;
|
||||
std::uint16_t scr_meth_max_id = 0x830C;
|
||||
|
||||
void* func_table[500];
|
||||
void* meth_table[900];
|
||||
|
||||
namespace
|
||||
{
|
||||
struct builtin_function
|
||||
{
|
||||
std::string name;
|
||||
std::uint16_t id; // actual 'name'
|
||||
void(*actionFunc)();
|
||||
};
|
||||
|
||||
struct builtin_method
|
||||
{
|
||||
std::string name;
|
||||
std::uint16_t id;
|
||||
void(*actionFunc)(game::native::scr_entref_t);
|
||||
};
|
||||
|
||||
utils::hook::detour scr_register_function_hook;
|
||||
|
||||
std::vector<builtin_function> custom_functions;
|
||||
std::vector<builtin_method> custom_methods;
|
||||
|
||||
std::unordered_map<const char*, const char*> replaced_funcs;
|
||||
|
||||
const char* vm_execute_code_pos = nullptr;
|
||||
DWORD vm_execute_addr;
|
||||
|
||||
DWORD vm_execute_func_addr;
|
||||
DWORD vm_execute_meth_addr;
|
||||
|
||||
void scr_register_function_stub(void* func, [[maybe_unused]] int type, unsigned int name)
|
||||
{
|
||||
assert(name);
|
||||
|
||||
if ((name - 1) < scr_func_max_id)
|
||||
{
|
||||
func_table[name] = func;
|
||||
}
|
||||
else
|
||||
{
|
||||
meth_table[name] = func;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int scr_get_function_stub(char** p_name, int* type)
|
||||
{
|
||||
std::memset(func_table, 0, sizeof(func_table));
|
||||
|
||||
for (const auto& func : custom_functions)
|
||||
{
|
||||
scr_register_function_stub(reinterpret_cast<void*>(func.actionFunc), 0, func.id);
|
||||
}
|
||||
|
||||
return utils::hook::invoke<unsigned int>(SELECT_VALUE(0x4CAC00, 0x527750), p_name, type); // Scr_GetFunction
|
||||
}
|
||||
|
||||
unsigned int scr_get_method_stub(const char** p_name, int* type)
|
||||
{
|
||||
std::memset(meth_table, 0, sizeof(meth_table));
|
||||
|
||||
for (const auto& meth : custom_methods)
|
||||
{
|
||||
scr_register_function_stub(reinterpret_cast<void*>(meth.actionFunc), 0, meth.id);
|
||||
}
|
||||
|
||||
return utils::hook::invoke<unsigned int>(SELECT_VALUE(0x51A4F0, 0x5277C0), p_name, type); // Scr_GetMethod
|
||||
}
|
||||
|
||||
const char* get_replaced_func_pos(const char* pos)
|
||||
{
|
||||
if (const auto itr = replaced_funcs.find(pos); itr != replaced_funcs.end())
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
__declspec(naked) void vm_execute_func_stub()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov eax, dword ptr ds:[func_table + eax * 4]
|
||||
|
||||
jmp vm_execute_func_addr
|
||||
}
|
||||
}
|
||||
|
||||
__declspec(naked) void vm_execute_meth_stub()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov edx, dword ptr ds:[meth_table + ecx * 4]
|
||||
|
||||
jmp vm_execute_meth_addr
|
||||
}
|
||||
}
|
||||
|
||||
__declspec(naked) void vm_execute_stub()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
pushad
|
||||
|
||||
push esi
|
||||
call get_replaced_func_pos;
|
||||
mov vm_execute_code_pos, eax
|
||||
pop esi
|
||||
|
||||
popad
|
||||
|
||||
mov esi, vm_execute_code_pos
|
||||
|
||||
jmp vm_execute_addr
|
||||
}
|
||||
}
|
||||
|
||||
void scr_print()
|
||||
{
|
||||
for (std::size_t i = 0; i < game::native::Scr_GetNumParam(); ++i)
|
||||
@ -29,13 +156,112 @@ namespace gsc
|
||||
}
|
||||
}
|
||||
|
||||
void register_function(const std::string& name, const game::native::BuiltinFunction& func)
|
||||
{
|
||||
const auto lowered_name = utils::string::to_lower(name);
|
||||
|
||||
constexpr auto is_duplicate = [](const std::string s)
|
||||
{
|
||||
return [s](const builtin_function& f) { return s == f.name; };
|
||||
};
|
||||
|
||||
if (std::ranges::any_of(custom_functions, is_duplicate(lowered_name)))
|
||||
{
|
||||
console::error("Function '%s' is already registered!", name.data());
|
||||
return;
|
||||
}
|
||||
|
||||
++scr_func_max_id;
|
||||
custom_functions.push_back({ name, scr_func_max_id, func });
|
||||
cxt->func_add(name, scr_func_max_id);
|
||||
}
|
||||
|
||||
void register_method(const std::string& name, const game::native::BuiltinMethod& meth)
|
||||
{
|
||||
const auto lowered_name = utils::string::to_lower(name);
|
||||
|
||||
constexpr auto is_duplicate = [](const std::string s)
|
||||
{
|
||||
return [s](const builtin_method& m) { return s == m.name; };
|
||||
};
|
||||
|
||||
if (std::ranges::any_of(custom_methods, is_duplicate(lowered_name)))
|
||||
{
|
||||
console::error("Method '%s' already registered!", name.data());
|
||||
return;
|
||||
}
|
||||
|
||||
++scr_meth_max_id;
|
||||
custom_methods.push_back({ name, scr_meth_max_id, meth });
|
||||
cxt->meth_add(name, scr_meth_max_id);
|
||||
}
|
||||
|
||||
const char* get_code_pos(int index)
|
||||
{
|
||||
if (static_cast<unsigned int>(index) >= game::native::scr_VmPub->outparamcount)
|
||||
{
|
||||
scr_error("Scr_GetCodePos: index is out of range");
|
||||
return "";
|
||||
}
|
||||
|
||||
const auto* value = &game::native::scr_VmPub->top[-index];
|
||||
|
||||
if (value->type != game::native::VAR_FUNCTION)
|
||||
{
|
||||
scr_error("Scr_GetCodePos requires a function as parameter");
|
||||
return "";
|
||||
}
|
||||
|
||||
return value->u.codePosValue;
|
||||
}
|
||||
|
||||
class script_extension final : public module
|
||||
{
|
||||
public:
|
||||
void post_load() override
|
||||
{
|
||||
utils::hook(SELECT_VALUE(0x4B4F87, 0x561F27), scr_get_function_stub, HOOK_CALL).install()->quick();
|
||||
utils::hook(SELECT_VALUE(0x4B4F92, 0x561F32), scr_get_method_stub, HOOK_CALL).install()->quick();
|
||||
|
||||
utils::hook(SELECT_VALUE(0x611C5B, 0x56C8EB), vm_execute_func_stub, HOOK_JUMP).install()->quick();
|
||||
utils::hook::nop(SELECT_VALUE(0x611C5B + 5, 0x56C8EB + 5), 2);
|
||||
|
||||
utils::hook(SELECT_VALUE(0x611F4C, 0x56CBDC), vm_execute_meth_stub, HOOK_JUMP).install()->quick();
|
||||
utils::hook::nop(SELECT_VALUE(0x611F4C + 5, 0x56CBDC + 5), 2);
|
||||
|
||||
vm_execute_func_addr = SELECT_VALUE(0x611C62, 0x56C8F2);
|
||||
vm_execute_meth_addr = SELECT_VALUE(0x611F53, 0x56CBE3);
|
||||
|
||||
scr_register_function_hook.create(SELECT_VALUE(0x49E190, 0x561520), scr_register_function_stub);
|
||||
|
||||
utils::hook::set<game::native::BuiltinFunction>(SELECT_VALUE(0x92B8DC, 0x8ABDC4), scr_print);
|
||||
utils::hook::set<game::native::BuiltinFunction>(SELECT_VALUE(0x92B8E8, 0x8ABDD0), scr_print_ln);
|
||||
|
||||
vm_execute_addr = SELECT_VALUE(0x610A90, 0x56B720);
|
||||
utils::hook(SELECT_VALUE(0x611EF1, 0x56CB81), vm_execute_stub, HOOK_JUMP).install()->quick();
|
||||
|
||||
scripting::on_shutdown([](int free_scripts) -> void
|
||||
{
|
||||
if (free_scripts)
|
||||
{
|
||||
replaced_funcs.clear();
|
||||
}
|
||||
});
|
||||
|
||||
add_gsc_functions();
|
||||
}
|
||||
|
||||
static void add_gsc_functions()
|
||||
{
|
||||
register_function("replacefunc", []
|
||||
{
|
||||
if (scr_get_type(0) != game::native::VAR_FUNCTION || scr_get_type(1) != game::native::VAR_FUNCTION)
|
||||
{
|
||||
scr_error("ReplaceFunc requires two functions pointers");
|
||||
}
|
||||
|
||||
replaced_funcs[get_code_pos(0)] = get_code_pos(1);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
12
src/module/gsc/script_extension.hpp
Normal file
12
src/module/gsc/script_extension.hpp
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
namespace gsc
|
||||
{
|
||||
extern void* func_table[500];
|
||||
extern void* meth_table[900];
|
||||
|
||||
extern std::uint16_t scr_func_max_id;
|
||||
|
||||
void register_function(const std::string& name, const game::native::BuiltinFunction& func);
|
||||
void register_method(const std::string& name, const game::native::BuiltinMethod& meth);
|
||||
}
|
@ -16,8 +16,6 @@
|
||||
|
||||
namespace gsc
|
||||
{
|
||||
std::uint16_t scr_func_max_id = 0x1C7;
|
||||
|
||||
namespace
|
||||
{
|
||||
utils::memory::allocator script_file_allocator;
|
||||
@ -69,7 +67,7 @@ namespace gsc
|
||||
std::vector<std::uint8_t> stack_data;
|
||||
stack_data.assign(decompressed_stack.begin(), decompressed_stack.end());
|
||||
|
||||
return {{script_file->bytecode, static_cast<std::uint32_t>(script_file->bytecodeLen)} , stack_data};
|
||||
return { { script_file->bytecode, static_cast<std::uint32_t>(script_file->bytecodeLen) } , stack_data };
|
||||
}
|
||||
|
||||
game::native::ScriptFile* load_custom_script(const char* file_name, const std::string& real_name)
|
||||
@ -100,7 +98,7 @@ namespace gsc
|
||||
const auto script_file_ptr = static_cast<game::native::ScriptFile*>(script_file_allocator.allocate(sizeof(game::native::ScriptFile)));
|
||||
script_file_ptr->name = file_name;
|
||||
|
||||
const auto compressed_stack = utils::compression::zlib::compress({reinterpret_cast<const char*>(output_script.second.data), output_script.second.size});
|
||||
const auto compressed_stack = utils::compression::zlib::compress( {reinterpret_cast<const char*>(output_script.second.data), output_script.second.size} );
|
||||
const auto byte_code_size = output_script.first.size + 1;
|
||||
|
||||
script_file_ptr->len = static_cast<int>(output_script.second.size);
|
||||
@ -269,7 +267,7 @@ namespace gsc
|
||||
std::vector<std::uint8_t> script_data;
|
||||
script_data.assign(file_buffer.begin(), file_buffer.end());
|
||||
|
||||
return {{}, script_data};
|
||||
return { {}, script_data };
|
||||
});
|
||||
|
||||
utils::hook::invoke<void>(SELECT_VALUE(0x4B4EE0, 0x561E80));
|
||||
|
Loading…
Reference in New Issue
Block a user