diff --git a/src/client/component/gsc.cpp b/src/client/component/gsc.cpp index 435314e7..8f6d9722 100644 --- a/src/client/component/gsc.cpp +++ b/src/client/component/gsc.cpp @@ -46,13 +46,52 @@ namespace gsc std::unordered_map main_handles; std::unordered_map init_handles; - std::unordered_map loaded_scripts; + std::unordered_map functions; std::optional gsc_error; - char* allocate_buffer(std::uint32_t size) + utils::memory::allocator scriptfile_allocator; + std::unordered_map loaded_scripts; + + struct { - return static_cast(game::PMem_AllocFromSource_NoDebug(size, 4, 1, 5)); + char* buf = nullptr; + char* pos = nullptr; + unsigned int size = 0x1000000; + } script_memory; + + char* allocate_buffer(size_t size) + { + if (script_memory.buf == nullptr) + { + script_memory.buf = game::PMem_AllocFromSource_NoDebug(script_memory.size, 4, 1, game::PMEM_SOURCE_SCRIPT); + script_memory.pos = script_memory.buf; + } + + if (script_memory.pos + size > script_memory.buf + script_memory.size) + { + game::Com_Error(game::ERR_FATAL, "Out of custom script memory"); + } + + const auto pos = script_memory.pos; + script_memory.pos += size; + return pos; + } + + void free_script_memory() + { + game::PMem_PopFromSource_NoDebug(script_memory.buf, script_memory.size, 4, 1, game::PMEM_SOURCE_SCRIPT); + script_memory.buf = nullptr; + script_memory.pos = nullptr; + } + + void clear() + { + main_handles.clear(); + init_handles.clear(); + loaded_scripts.clear(); + scriptfile_allocator.clear(); + free_script_memory(); } bool read_scriptfile(const std::string& name, std::string* data) @@ -123,7 +162,7 @@ namespace gsc return nullptr; } - const auto script_file_ptr = reinterpret_cast(allocate_buffer(sizeof(game::ScriptFile))); + const auto script_file_ptr = scriptfile_allocator.allocate(); script_file_ptr->name = file_name; const auto stack = assembler->output_stack(); @@ -132,15 +171,12 @@ namespace gsc const auto script = assembler->output_script(); script_file_ptr->bytecodeLen = static_cast(script.size()); - const auto script_size = script.size(); - const auto buffer_size = script_size + stack.size() + 2; + script_file_ptr->buffer = game::Hunk_AllocateTempMemoryHigh(stack.size() + 1); + std::memcpy(script_file_ptr->buffer, stack.data(), stack.size()); - const auto buffer = allocate_buffer(static_cast(buffer_size)); - std::memcpy(buffer, script.data(), script_size); - std::memcpy(&buffer[script_size], stack.data(), stack.size()); + script_file_ptr->bytecode = allocate_buffer(script.size() + 1); + std::memcpy(script_file_ptr->bytecode, script.data(), script.size()); - script_file_ptr->bytecode = &buffer[0]; - script_file_ptr->buffer = &buffer[script.size()]; script_file_ptr->compressedLen = 0; loaded_scripts[real_name] = script_file_ptr; @@ -197,19 +233,10 @@ namespace gsc } } - void clear() - { - main_handles.clear(); - init_handles.clear(); - loaded_scripts.clear(); - } - void load_gametype_script_stub(void* a1, void* a2) { utils::hook::invoke(0x1404E1400, a1, a2); - clear(); - fastfiles::enum_assets(game::ASSET_TYPE_RAWFILE, [](game::XAssetHeader header) { std::string name = header.rawfile->name; @@ -562,6 +589,27 @@ namespace gsc return decompiler->output(); } + + void pmem_init_stub() + { + utils::hook::invoke(0x14061EC80); + + const auto type_0 = &game::g_scriptmem[0]; + const auto type_1 = &game::g_scriptmem[1]; + + const auto size_0 = 0x200000; // default size + const auto size_1 = 0x200000 + script_memory.size; + + const auto block = reinterpret_cast(VirtualAlloc(NULL, size_0 + size_1, MEM_RESERVE, PAGE_READWRITE)); + + type_0->buf = block; + type_0->size = size_0; + + type_1->buf = block + size_0; + type_1->size = size_1; + + utils::hook::set(0x14061EC72, size_0 + size_1); + } } game::ScriptFile* find_script(game::XAssetType /*type*/, const char* name, int /*allow_create_default*/) @@ -645,6 +693,9 @@ namespace gsc utils::hook::nop(0x1405CA683, 8); utils::hook::call(0x1405CA683, vm_call_builtin_stub); + // Increase script memory + utils::hook::call(0x1405A4798, pmem_init_stub); + add_function("print", [](const game::scr_entref_t ref) { const auto num = game::Scr_GetNumParam(); diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index e26001d6..b2381ce1 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -866,7 +866,7 @@ namespace game int compressedLen; int len; int bytecodeLen; - const char* buffer; + char* buffer; char* bytecode; }; @@ -1386,6 +1386,28 @@ namespace game int vertAlign; }; + enum PMem_Source + { + PMEM_SOURCE_EXTERNAL = 0x0, + PMEM_SOURCE_DATABASE = 0x1, + PMEM_SOURCE_DEFAULT_LOW = 0x2, + PMEM_SOURCE_DEFAULT_HIGH = 0x3, + PMEM_SOURCE_MOVIE = 0x4, + PMEM_SOURCE_SCRIPT = 0x5, + }; + + struct physical_memory + { + char __pad0[0x10]; + char* buf; + char __pad1[0x8]; + int unk1; + size_t size; + char __pad2[0x500]; + }; + + static_assert(sizeof(physical_memory) == 0x530); + namespace hks { struct lua_State; diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 0a25474c..dbe355f7 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -94,6 +94,8 @@ namespace game WEAK symbol G_SelectWeapon{0x14051C0D0}; WEAK symbol WorldPosToScreenPos{0x14036F310}; + WEAK symbol Hunk_AllocateTempMemoryHigh{0x140614790}; + WEAK symbol I_CleanStr{0x140620660}; WEAK symbol Scr_ExecThread{0x1405C6F40}; WEAK symbol Scr_RegisterFunction{0x1405BC7B0}; - WEAK symbol PMem_AllocFromSource_NoDebug{0x14061E680}; + WEAK symbol PMem_AllocFromSource_NoDebug{0x14061E680}; + WEAK symbol PMem_PopFromSource_NoDebug{0x14061EDF0}; WEAK symbol VM_Execute{0x1405C8DB0}; @@ -237,6 +242,8 @@ namespace game WEAK symbol g_script_error{0x14BA9CD40}; WEAK symbol g_classMap{0x140BF95C0}; + WEAK symbol g_scriptmem{0x14CC9FEC0}; + WEAK symbol scr_VarGlob{0x14B617C00}; WEAK symbol scr_VmPub{0x14BA9EE40}; WEAK symbol scr_function_stack{0x14BAA93C0};