diff --git a/src/client/component/gsc/script_error.cpp b/src/client/component/gsc/script_error.cpp index a6880e82..456aadd9 100644 --- a/src/client/component/gsc/script_error.cpp +++ b/src/client/component/gsc/script_error.cpp @@ -79,14 +79,12 @@ namespace gsc { const auto& pos = function.value(); unknown_function_error = std::format( - "while processing function '{}' in script '{}':\nunknown script '{}' ({})", - pos.first, pos.second, scripting::current_file, scripting::current_file_id + "while processing function '{}' in script '{}':\nunknown script '{}'", pos.first, pos.second, scripting::current_file ); } else { - unknown_function_error = std::format("unknown script '{}' ({})", - scripting::current_file, scripting::current_file_id); + unknown_function_error = std::format("unknown script '{}'", scripting::current_file); } } @@ -96,8 +94,7 @@ namespace gsc const auto name = scripting::get_token(thread_name); unknown_function_error = std::format( - "while processing script '{}':\nunknown function '{}::{}'", - scripting::current_file, filename, name + "while processing script '{}':\nunknown function '{}::{}'", scripting::current_file, filename, name ); } diff --git a/src/client/component/gsc/script_loading.cpp b/src/client/component/gsc/script_loading.cpp index 200104a2..23db164e 100644 --- a/src/client/component/gsc/script_loading.cpp +++ b/src/client/component/gsc/script_loading.cpp @@ -28,22 +28,23 @@ namespace gsc std::unordered_map init_handles; utils::memory::allocator scriptfile_allocator; - std::unordered_map loaded_scripts; + std::unordered_map loaded_scripts; + + char* script_mem_buf = nullptr; + std::uint64_t script_mem_buf_size = 0; struct { char* buf = nullptr; char* pos = nullptr; - const unsigned int size = 0x100000i64; + const std::uint64_t size = 0x100000i64; } script_memory; char* allocate_buffer(size_t size) { if (script_memory.buf == nullptr) { - game::PMem_BeginAlloc("custom_gsc_script", 1); - script_memory.buf = game::PMem_AllocFromSource_NoDebug(script_memory.size, 4, 0, 1); // 3rd paramter unused because of 4th - game::PMem_EndAlloc("custom_gsc_script", 1); + script_memory.buf = script_mem_buf; script_memory.pos = script_memory.buf; } @@ -59,9 +60,12 @@ namespace gsc void free_script_memory() { - game::PMem_Free("custom_gsc_script", 1); - script_memory.buf = nullptr; - script_memory.pos = nullptr; + if (script_memory.buf != nullptr) + { + memset(script_memory.buf, 0, reinterpret_cast(script_memory.pos) - reinterpret_cast(script_memory.buf)); + script_memory.buf = nullptr; + script_memory.pos = nullptr; + } } void clear() @@ -106,7 +110,7 @@ namespace gsc return itr->second; } - if (game::Com_FrontEndScene_IsActive()) + if (game::Com_FrontEnd_IsInFrontEnd()) { return nullptr; } @@ -117,8 +121,10 @@ namespace gsc return nullptr; } + // TODO: check if needed in IW7 // filter out "GSC rawfiles" that were used for development usage and are not meant for us. // each "GSC rawfile" has a ScriptFile counterpart to be used instead + /* if (game::DB_XAssetExists(game::ASSET_TYPE_SCRIPTFILE, file_name) && !game::DB_IsXAssetDefault(game::ASSET_TYPE_SCRIPTFILE, file_name)) { @@ -129,6 +135,7 @@ namespace gsc return game::DB_FindXAssetHeader(game::ASSET_TYPE_SCRIPTFILE, file_name, false).scriptfile; } } + */ console::debug("Loading custom gsc '%s.gsc'", real_name.data()); @@ -225,14 +232,8 @@ namespace gsc return; } - console::debug("load_script: getting handles for '%s'\n", name.data()); - - const auto main_token = gsc_ctx->token_id("main"); - const auto init_token = gsc_ctx->token_id("init"); - const auto main_handle = game::Scr_GetFunctionHandle(name.data(), main_token); - const auto init_handle = game::Scr_GetFunctionHandle(name.data(), init_token); - - console::debug("main token: %u (%u), init token: %u (%u)\n", main_token, main_handle, init_token, init_handle); + const auto main_handle = game::Scr_GetFunctionHandle(name.data(), gsc_ctx->token_id("main")); + const auto init_handle = game::Scr_GetFunctionHandle(name.data(), gsc_ctx->token_id("init")); if (main_handle) { @@ -267,8 +268,6 @@ namespace gsc const auto relative = path.lexically_relative(root_dir).generic_string(); const auto base_name = relative.substr(0, relative.size() - 4); - console::debug("load_script called on %s\n", base_name.data()); - load_script(base_name); } } @@ -285,11 +284,12 @@ namespace gsc void load_scripts_stub() { - if (!game::Com_FrontEndScene_IsActive()) + if (!game::Com_FrontEnd_IsInFrontEnd()) { for (const auto& path : filesystem::get_search_paths()) { - load_scripts(path, "scripts/"); + load_scripts(path, "userscripts/"); + load_scripts(path, "userscripts/"s + game::Com_GameMode_GetActiveGameModeStr() + "/"); } } @@ -354,7 +354,7 @@ namespace gsc { for (auto& function_handle : main_handles) { - console::info("Executing '%s::main'\n", function_handle.first.data()); + console::debug("Executing '%s::main'\n", function_handle.first.data()); game::RemoveRefToObject(game::Scr_ExecThread(function_handle.second, 0)); } @@ -366,17 +366,46 @@ namespace gsc { for (auto& function_handle : init_handles) { - console::info("Executing '%s::init'\n", function_handle.first.data()); + console::debug("Executing '%s::init'\n", function_handle.first.data()); game::RemoveRefToObject(game::Scr_ExecThread(function_handle.second, 0)); } scr_load_level_hook.invoke(); } utils::hook::detour g_shutdown_game_hook; - void g_shutdown_game_stub(bool full_clear) + void g_shutdown_game_stub(int full_clear, int a2) { - clear(); - g_shutdown_game_hook.invoke(full_clear); + if (full_clear && a2) + { + clear(); + } + g_shutdown_game_hook.invoke(full_clear, a2); + } + + // donetsk developers will paste this in days + utils::hook::detour db_alloc_x_zone_memory_internal_hook; + void db_alloc_x_zone_memory_internal_stub(unsigned __int64* blockSize, const char* filename, game::XZoneMemory* zoneMem, unsigned int type) + { + bool patch = false; // ugly fix for script memory allocation + if (!_stricmp(filename, "code_post_gfx") && type == 2) + { + patch = true; + console::debug("patching memory for '%s'\n", filename); + } + + if (patch) + { + blockSize[game::XFILE_BLOCK_SCRIPT] += script_memory.size; + } + + db_alloc_x_zone_memory_internal_hook.invoke(blockSize, filename, zoneMem, type); + + if (patch) + { + blockSize[game::XFILE_BLOCK_SCRIPT] -= script_memory.size; + script_mem_buf = zoneMem->blocks[game::XFILE_BLOCK_SCRIPT].alloc + blockSize[game::XFILE_BLOCK_SCRIPT]; + script_mem_buf_size = script_memory.size; + } } } @@ -403,6 +432,9 @@ namespace gsc public: void post_unpack() override { + // Allocate script memory (PMem doesn't work) + db_alloc_x_zone_memory_internal_hook.create(0xA75450_b, db_alloc_x_zone_memory_internal_stub); + // Load our scripts with an uncompressed stack utils::hook::call(0xC09DA7_b, db_get_raw_buffer_stub); @@ -422,10 +454,8 @@ namespace gsc // execute init handle scr_load_level_hook.create(0xB51B40_b, scr_load_level_stub); - /* - // clear memory (G_MainMP_ShutdownGameMemory) - g_shutdown_game_hook.create(0xC56C80_b, g_shutdown_game_stub); - */ + // clear memory (SV_GameMP_ShutdownGameVM) + g_shutdown_game_hook.create(0xBB36D86_b, g_shutdown_game_stub); } void pre_destroy() override diff --git a/src/client/component/scripting.cpp b/src/client/component/scripting.cpp index e68c2bbe..ad1d70cc 100644 --- a/src/client/component/scripting.cpp +++ b/src/client/component/scripting.cpp @@ -27,7 +27,6 @@ namespace scripting utils::concurrency::container shared_table; std::string current_file; - unsigned int current_file_id{}; namespace { @@ -44,11 +43,8 @@ namespace scripting utils::hook::detour sl_get_canonical_string_hook; - utils::hook::detour db_find_xasset_header_hook; - - const char* current_script_file_name; - - game::dvar_t* g_dump_scripts; + std::string current_script_file; + unsigned int current_file_id{}; std::vector> shutdown_callbacks; @@ -115,13 +111,12 @@ namespace scripting void process_script_stub(const char* filename) { - current_script_file_name = filename; + current_script_file = filename; const auto file_id = atoi(filename); if (file_id) { current_file_id = static_cast(file_id); - current_file = scripting::get_token(current_file_id); } else { @@ -135,10 +130,14 @@ namespace scripting void add_function_sort(unsigned int id, const char* pos) { std::string filename = current_file; + if (current_file_id) + { + filename = scripting::get_token(current_file_id); + } if (!script_function_table_sort.contains(filename)) { - const auto script = gsc::find_script(game::ASSET_TYPE_SCRIPTFILE, current_script_file_name, false); + const auto script = gsc::find_script(game::ASSET_TYPE_SCRIPTFILE, current_script_file.data(), false); if (script) { const auto end = &script->bytecode[script->bytecodeLen]; @@ -162,7 +161,15 @@ namespace scripting { add_function_sort(thread_name, code_pos); - add_function(current_file, thread_name, code_pos); + if (current_file_id) + { + const auto name = get_token(current_file_id); + add_function(name, thread_name, code_pos); + } + else + { + add_function(current_file, thread_name, code_pos); + } scr_set_thread_position_hook.invoke(thread_name, code_pos); } @@ -212,9 +219,6 @@ namespace scripting scr_set_thread_position_hook.create(0xBFD190_b, scr_set_thread_position_stub); process_script_hook.create(0xC09D20_b, process_script_stub); sl_get_canonical_string_hook.create(game::SL_GetCanonicalString, sl_get_canonical_string_stub); - - // clear memory (SV_GameMP_ShutdownGameVM) - g_shutdown_game_hook.create(0xB21CC0_b, g_shutdown_game_stub); } }; } diff --git a/src/client/component/scripting.hpp b/src/client/component/scripting.hpp index 14f2bd49..12598b9c 100644 --- a/src/client/component/scripting.hpp +++ b/src/client/component/scripting.hpp @@ -13,7 +13,6 @@ namespace scripting extern utils::concurrency::container shared_table; extern std::string current_file; - extern unsigned int current_file_id; void on_shutdown(const std::function& callback); std::optional get_canonical_string(const unsigned int id); diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index 0c4d2804..ddfbb152 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -3267,16 +3267,78 @@ namespace game 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, - PMEM_SOURCE_UNK5 = 0x5, - PMEM_SOURCE_UNK6 = 0x6, - PMEM_SOURCE_UNK7 = 0x7, - PMEM_SOURCE_UNK8 = 0x8, - PMEM_SOURCE_CUSTOMIZATION = 0x9, + PMEM_SOURCE_SCRIPT = 0x1, + }; + + enum PMem_Direction : __int32 + { + PHYS_ALLOC_LOW = 0x0, + PHYS_ALLOC_HIGH = 0x1, + PHYS_ALLOC_COUNT = 0x2, + }; + + enum Mem_PageID + { + }; + + struct Mem_PageRange + { + Mem_PageID firstPageID; + Mem_PageID lastPageID; + }; + + struct PhysicalMemoryAllocation + { + const char* name; + char* prev_buffer; + char* next_buffer; + unsigned __int64 pos; + Mem_PageRange pageRange; + }; + + struct PhysicalMemoryPrim + { + const char* name; + unsigned int allocListCount; + char __pad0[4]; + unsigned __int8* buf; + unsigned __int64 unk_pos; + int unk1; + char __pad2[4]; + unsigned __int64 pos; + PhysicalMemoryAllocation allocList[32]; + }; + + struct PhysicalMemory + { + PhysicalMemoryPrim prim[2]; + }; + + struct XBlock + { + char* alloc; + unsigned __int64 size; + }; + + struct XZoneMemory + { + XBlock blocks[10]; + char __pad0[200]; // unk size + }; + + enum XFileBlock + { + XFILE_BLOCK_TEMP_ADDITIONAL = 0x0, + XFILE_BLOCK_TEMP = 0x1, + XFILE_BLOCK_TEMP_PRELOAD = 0x2, + XFILE_BLOCK_CALLBACK = 0x3, + XFILE_BLOCK_RUNTIME = 0x4, + XFILE_BLOCK_RUNTIME_VIDEO = 0x5, + XFILE_BLOCK_CACHED_VIDEO = 0x6, + XFILE_BLOCK_PHYSICAL = 0x7, + XFILE_BLOCK_VIRTUAL = 0x8, + XFILE_BLOCK_SCRIPT = 0x9, + MAX_XFILE_COUNT = 0xA, }; enum VariableType diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 9faf3b27..efbab8d4 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -276,9 +276,6 @@ namespace game WEAK game::symbol pmem_size{ 0x7686A28 }; WEAK game::symbol pmem_buffer{ 0x7686A20 }; - /* - WEAK game::symbol g_mem{ 0xD5F26E0, 0xC92E1E0 }; - WEAK game::symbol g_scriptmem{ 0xD5F3140, 0xC92EC40 }; - WEAK game::symbol g_physmem{ 0xD5F3BA0, 0xC92F6A0 }; - */ + WEAK game::symbol g_mem{ 0x7685560 }; + WEAK game::symbol g_scriptmem{ 0x7685FC0 }; }