From d3af34572d570b559f1882f0f5da2d48148b0eb8 Mon Sep 17 00:00:00 2001 From: fed <58637860+fedddddd@users.noreply.github.com> Date: Tue, 4 Oct 2022 22:47:16 +0200 Subject: [PATCH] Allow custom gsc scripts to load game gsc --- deps/extra/gsc-tool/interface.cpp | 10 ++++++ deps/extra/gsc-tool/interface.hpp | 2 ++ src/client/component/gsc.cpp | 51 ++++++++++++++++++++++++++++++- 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/deps/extra/gsc-tool/interface.cpp b/deps/extra/gsc-tool/interface.cpp index e9964b5c..218ed650 100644 --- a/deps/extra/gsc-tool/interface.cpp +++ b/deps/extra/gsc-tool/interface.cpp @@ -13,8 +13,18 @@ namespace gsc return compiler; } + std::unique_ptr decompiler() + { + return std::make_unique(); + } + std::unique_ptr assembler() { return std::make_unique(); } + + std::unique_ptr disassembler() + { + return std::make_unique(); + } } diff --git a/deps/extra/gsc-tool/interface.hpp b/deps/extra/gsc-tool/interface.hpp index 4d98ad35..133e6ae2 100644 --- a/deps/extra/gsc-tool/interface.hpp +++ b/deps/extra/gsc-tool/interface.hpp @@ -3,5 +3,7 @@ namespace gsc { std::unique_ptr compiler(); + std::unique_ptr decompiler(); std::unique_ptr assembler(); + std::unique_ptr disassembler(); } diff --git a/src/client/component/gsc.cpp b/src/client/component/gsc.cpp index 7e3cf59a..df4e30ba 100644 --- a/src/client/component/gsc.cpp +++ b/src/client/component/gsc.cpp @@ -19,7 +19,10 @@ #include #include +#include #include +#include +#include #include #include @@ -36,7 +39,9 @@ namespace gsc game::dvar_t* developer_script = nullptr; auto compiler = ::gsc::compiler(); + auto decompiler = ::gsc::decompiler(); auto assembler = ::gsc::assembler(); + auto disassembler = ::gsc::disassembler(); std::unordered_map main_handles; std::unordered_map init_handles; @@ -511,6 +516,41 @@ namespace gsc current_filename = filename; scr_emit_function_hook.invoke(filename, thread_name, code_pos); } + + std::string get_script_file_name(const std::string& name) + { + const auto id = xsk::gsc::h2::resolver::token_id(name); + if (id == 0) + { + return name; + } + + return std::to_string(id); + } + + std::vector decompile_scriptfile(const std::string& name) + { + const auto scriptfile = game::DB_FindXAssetHeader(game::ASSET_TYPE_SCRIPTFILE, name.data(), false).scriptfile; + if (scriptfile == nullptr) + { + throw std::runtime_error(std::format("couldn't load scriptfile {}", name)); + } + + console::info("Decompiling scriptfile %s\n", name.data()); + + std::vector stack{scriptfile->buffer, scriptfile->buffer + scriptfile->len}; + std::vector bytecode{scriptfile->bytecode, scriptfile->bytecode + scriptfile->bytecodeLen}; + + auto decompressed_stack = xsk::utils::zlib::decompress(stack, static_cast(stack.size())); + + disassembler->disassemble(name, bytecode, decompressed_stack); + auto output = disassembler->output(); + + decompiler->decompile(name, output); + const auto data = decompiler->output(); + + return std::vector{data.begin(), data.end()}; + } } game::ScriptFile* find_script(game::XAssetType /*type*/, const char* name, int /*allow_create_default*/) @@ -546,7 +586,15 @@ namespace gsc std::string file_buffer; if (!read_scriptfile(real_name, &file_buffer) || file_buffer.empty()) { - throw std::runtime_error(std::format("could not load gsc file '{}'", real_name)); + const auto name = get_script_file_name(include_name); + if (game::DB_XAssetExists(game::ASSET_TYPE_SCRIPTFILE, name.data())) + { + return decompile_scriptfile(name); + } + else + { + throw std::runtime_error(std::format("could not load gsc file '{}'", real_name)); + } } std::vector result; @@ -661,6 +709,7 @@ namespace gsc { if (free_scripts) { + xsk::gsc::h2::resolver::cleanup(); clear(); } });