From 6dcbfefa9f50a8dddc532a0d760471e1cddd7308 Mon Sep 17 00:00:00 2001 From: Federico Cecchetto Date: Sun, 29 May 2022 17:53:39 +0200 Subject: [PATCH] SP Mods --- data/ui_scripts/mods/loading.lua | 21 ++-- src/client/component/fonts.cpp | 6 +- src/client/component/logger.cpp | 13 +- src/client/component/mods.cpp | 4 +- src/client/component/ui_scripting.cpp | 163 +++++++++++++++++++------- src/client/game/symbols.hpp | 8 +- src/client/resources/json.lua | 2 +- 7 files changed, 151 insertions(+), 66 deletions(-) diff --git a/data/ui_scripts/mods/loading.lua b/data/ui_scripts/mods/loading.lua index 16cc3084..9600d8a5 100644 --- a/data/ui_scripts/mods/loading.lua +++ b/data/ui_scripts/mods/loading.lua @@ -2,15 +2,13 @@ game:addlocalizedstring("MENU_MODS", "MODS") game:addlocalizedstring("MENU_MODS_DESC", "Load installed mods.") game:addlocalizedstring("LUA_MENU_MOD_DESC_DEFAULT", "Load &&1.") game:addlocalizedstring("LUA_MENU_MOD_DESC", "&&1\nAuthor: &&2\nVersion: &&3") -game:addlocalizedstring("LUA_MENU_OPEN_STORE", "Open store") -game:addlocalizedstring("LUA_MENU_OPEN_STORE_DESC", "Download and install mods.") game:addlocalizedstring("LUA_MENU_LOADED_MOD", "Loaded mod: ^2&&1") game:addlocalizedstring("LUA_MENU_AVAILABLE_MODS", "Available mods") game:addlocalizedstring("LUA_MENU_UNLOAD", "Unload") game:addlocalizedstring("LUA_MENU_UNLOAD_DESC", "Unload the currently loaded mod.") function createdivider(menu, text) - local element = LUI.UIElement.new( { + local element = LUI.UIElement.new({ leftAnchor = true, rightAnchor = true, left = 0, @@ -26,7 +24,10 @@ function createdivider(menu, text) title_bar_text = Engine.ToUpperCase(text) })) + element.text = element:getFirstChild():getFirstChild():getNextSibling() + menu.list:addElement(element) + return element end function string:truncate(length) @@ -48,12 +49,17 @@ LUI.addmenubutton("main_campaign", { function getmodname(path) local name = path - local desc = Engine.Localize("@LUA_MENU_MOD_DESC_DEFAULT", name) + game:addlocalizedstring(name, name) + game:addlocalizedstring("LUA_MENU_MOD_DESC_DEFAULT", "Load &&1.") + local desc = Engine.Localize("LUA_MENU_MOD_DESC_DEFAULT", name) local infofile = path .. "/info.json" if (io.fileexists(infofile)) then pcall(function() local data = json.decode(io.readfile(infofile)) + game:addlocalizedstring(data.description, data.description) + game:addlocalizedstring(data.author, data.author) + game:addlocalizedstring(data.version, data.version) desc = Engine.Localize("@LUA_MENU_MOD_DESC", data.description, data.author, data.version) name = data.name @@ -63,7 +69,7 @@ function getmodname(path) return name, desc end -LUI.MenuBuilder.m_types_build["mods_menu"] = function(a1) +LUI.MenuBuilder.registerType("mods_menu", function(a1) local menu = LUI.MenuTemplate.new(a1, { menu_title = "@MENU_MODS", exclusiveController = 0, @@ -74,7 +80,8 @@ LUI.MenuBuilder.m_types_build["mods_menu"] = function(a1) local modfolder = game:getloadedmod() if (modfolder ~= "") then - createdivider(menu, Engine.Localize("@LUA_MENU_LOADED_MOD", getmodname(modfolder):truncate(24))) + local name = getmodname(modfolder) + createdivider(menu, Engine.Localize("@LUA_MENU_LOADED_MOD", name:truncate(24))) menu:AddButton("@LUA_MENU_UNLOAD", function() Engine.Exec("unloadmod") @@ -113,4 +120,4 @@ LUI.MenuBuilder.m_types_build["mods_menu"] = function(a1) menu.optionTextInfo = LUI.Options.AddOptionTextInfo(menu) return menu -end +end) diff --git a/src/client/component/fonts.cpp b/src/client/component/fonts.cpp index 989b112a..07f447ca 100644 --- a/src/client/component/fonts.cpp +++ b/src/client/component/fonts.cpp @@ -114,7 +114,7 @@ namespace fonts } data_.fonts.clear(); - utils::hook::set(SELECT_VALUE(0x14F09DBB8, 0x14FD61EE8), 0); // reset registered font count + utils::hook::set(SELECT_VALUE(0xF793E38_b, 0xE962188_b), 0); // reset registered font count }); } @@ -128,9 +128,9 @@ namespace fonts return; } - utils::hook::call(SELECT_VALUE(0x1404D41B6, 0x1405D9296), db_find_xasset_header_stub); + utils::hook::call(SELECT_VALUE(0x55C596_b, 0x67F6E6_b), db_find_xasset_header_stub); } }; } -//REGISTER_COMPONENT(fonts::component) +REGISTER_COMPONENT(fonts::component) diff --git a/src/client/component/logger.cpp b/src/client/component/logger.cpp index 5259ffbe..7acefc53 100644 --- a/src/client/component/logger.cpp +++ b/src/client/component/logger.cpp @@ -117,15 +117,10 @@ namespace logger public: void post_unpack() override { - if (game::environment::is_mp()) - { - // utils::hook::jump(0x27E210_b, print_warning, true); - utils::hook::jump(0x27CBB0_b, print_dev, true); - - } - - // lua print - utils::hook::jump(SELECT_VALUE(0x0E6E30_b, 0x1F6140_b), printf); + // lua stuff + utils::hook::jump(SELECT_VALUE(0x106010_b, 0x27CBB0_b), print_dev); // debug + utils::hook::jump(SELECT_VALUE(0x107680_b, 0x27E210_b), print_error); // error + utils::hook::jump(SELECT_VALUE(0x0E6E30_b, 0x1F6140_b), printf); // print com_error_hook.create(game::Com_Error, com_error_stub); } diff --git a/src/client/component/mods.cpp b/src/client/component/mods.cpp index 13d8cbdb..9e0552ee 100644 --- a/src/client/component/mods.cpp +++ b/src/client/component/mods.cpp @@ -61,7 +61,7 @@ namespace mods utils::io::create_directory("mods"); } - db_release_xassets_hook.create(SELECT_VALUE(0x0, 0x399740_b), db_release_xassets_stub); + db_release_xassets_hook.create(SELECT_VALUE(0x1F4DB0_b, 0x399740_b), db_release_xassets_stub); command::add("loadmod", [](const command::params& params) { @@ -116,4 +116,4 @@ namespace mods }; } -//REGISTER_COMPONENT(mods::component) +REGISTER_COMPONENT(mods::component) diff --git a/src/client/component/ui_scripting.cpp b/src/client/component/ui_scripting.cpp index 9c5bf61b..cbaa0f6a 100644 --- a/src/client/component/ui_scripting.cpp +++ b/src/client/component/ui_scripting.cpp @@ -13,6 +13,9 @@ #include "fps.hpp" #include "server_list.hpp" #include "filesystem.hpp" +#include "mods.hpp" +#include "fastfiles.hpp" +#include "scripting.hpp" #include "game/ui_scripting/execution.hpp" #include "game/scripting/execution.hpp" @@ -37,6 +40,7 @@ namespace ui_scripting utils::hook::detour hks_load_hook; const auto lui_common = utils::nt::load_resource(LUI_COMMON); + const auto lua_json = utils::nt::load_resource(LUA_JSON); struct script { @@ -211,6 +215,122 @@ namespace ui_scripting { localized_strings::override(string, value); }; + + game_type["sharedset"] = [](const game&, const std::string& key, const std::string& value) + { + scripting::shared_table.access([key, value](scripting::shared_table_t& table) + { + table[key] = value; + }); + }; + + game_type["sharedget"] = [](const game&, const std::string& key) + { + std::string result; + scripting::shared_table.access([key, &result](scripting::shared_table_t& table) + { + result = table[key]; + }); + return result; + }; + + game_type["sharedclear"] = [](const game&) + { + scripting::shared_table.access([](scripting::shared_table_t& table) + { + table.clear(); + }); + }; + + game_type["assetlist"] = [](const game&, const std::string& type_string) + { + auto table_ = table(); + auto index = 1; + auto type_index = -1; + + for (auto i = 0; i < ::game::XAssetType::ASSET_TYPE_COUNT; i++) + { + if (type_string == ::game::g_assetNames[i]) + { + type_index = i; + } + } + + if (type_index == -1) + { + throw std::runtime_error("Asset type does not exist"); + } + + const auto type = static_cast<::game::XAssetType>(type_index); + fastfiles::enum_assets(type, [type, &table_, &index](const ::game::XAssetHeader header) + { + const auto asset = ::game::XAsset{type, header}; + const std::string asset_name = ::game::DB_GetXAssetName(&asset); + table_[index++] = asset_name; + }, true); + + return table_; + }; + + game_type["getweapondisplayname"] = [](const game&, const std::string& name) + { + const auto alternate = name.starts_with("alt_"); + const auto weapon = ::game::G_GetWeaponForName(name.data()); + + char buffer[0x400] = {0}; + ::game::CG_GetWeaponDisplayName(weapon, alternate, buffer, 0x400); + + return std::string(buffer); + }; + + game_type["getloadedmod"] = [](const game&) + { + return mods::mod_path; + }; + + if (::game::environment::is_sp()) + { + using player = table; + auto player_type = player(); + lua["player"] = player_type; + + player_type["notify"] = [](const player&, const std::string& name, const variadic_args& va) + { + if (!::game::CL_IsCgameInitialized() || !::game::SV_Loaded()) + { + throw std::runtime_error("Not in game"); + } + + const auto to_string = get_globals()["tostring"]; + const auto arguments = get_return_values(); + std::vector args{}; + for (const auto& value : va) + { + const auto value_str = to_string(value); + + args.push_back(value_str[0].as()); + } + + ::scheduler::once([name, args]() + { + try + { + std::vector arguments{}; + + for (const auto& arg : args) + { + arguments.push_back(arg); + } + + const auto player = scripting::call("getentbynum", {0}).as(); + scripting::notify(player, name, arguments); + } + catch (...) + { + } + }, ::scheduler::pipeline::server); + }; + } } void start() @@ -227,6 +347,7 @@ namespace ui_scripting lua["luiglobals"] = lua; load_script("lui_common", lui_common); + load_script("lua_json", lua_json); for (const auto& path : filesystem::get_search_paths()) { @@ -379,46 +500,8 @@ namespace ui_scripting return; } - utils::hook::jump(SELECT_VALUE(0xE7419_b, 0x25E809_b), utils::hook::assemble([](utils::hook::assembler& a) - { - const auto loc = a.newLabel(); - - a.push(rax); - a.pushad64(); - a.call_aligned(db_find_xasset_header_stub); - a.mov(qword_ptr(rsp, 0x80), rax); - a.popad64(); - a.pop(rax); - - a.mov(rcx, r13); - a.test(rax, rax); - a.jnz(loc); - - a.jmp(SELECT_VALUE(0xE7426_b, 0x25E816_b)); - - a.bind(loc); - a.jmp(SELECT_VALUE(0xE748A_b, 0x25E87A_b)); - }), true); - - utils::hook::jump(SELECT_VALUE(0xE72CB_b, 0x25E6BB_b), utils::hook::assemble([](utils::hook::assembler& a) - { - const auto loc = a.newLabel(); - - a.push(rax); - a.pushad64(); - a.call_aligned(db_find_xasset_header_stub); - a.mov(qword_ptr(rsp, 0x80), rax); - a.popad64(); - a.pop(rax); - - a.test(rax, rax); - a.jnz(loc); - - a.jmp(SELECT_VALUE(0xE72D9_b, 0x25E6C9_b)); - - a.bind(loc); - a.jmp(SELECT_VALUE(0xE73EC_b, 0x25E7DC_b)); - }), true); + utils::hook::call(SELECT_VALUE(0xE7419_b, 0x25E809_b), db_find_xasset_header_stub); + utils::hook::call(SELECT_VALUE(0xE72CB_b, 0x25E6BB_b), db_find_xasset_header_stub); hks_load_hook.create(SELECT_VALUE(0xB46F0_b, 0x22C180_b), hks_load_stub); diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 30e85339..d23b7555 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -55,7 +55,7 @@ namespace game WEAK symbol Com_SetSlowMotion{0x0, 0x17E5F0}; WEAK symbol Com_Error{0x384820, 0x159860}; WEAK symbol Com_Quit_f{0x0, 0x1F9280}; - WEAK symbol Com_Shutdown{0x0, 0x0}; + WEAK symbol Com_Shutdown{0x3A6A50, 0x0}; WEAK symbol Quit{0x3A5A20, 0x17CF50}; @@ -64,7 +64,7 @@ namespace game WEAK symbol CG_SetClientDvarFromServer{0x0, 0x0}; WEAK symbol CG_GetWeaponDisplayName{0x0, 0x0}; + bool isAlternate, char* outputBuffer, int bufferLen)> CG_GetWeaponDisplayName{0x192B80, 0x104B70}; WEAK symbol CL_IsCgameInitialized{0x1A3210, 0x33C640}; WEAK symbol CL_VirtualLobbyShutdown{0x0, 0x0}; @@ -109,7 +109,7 @@ namespace game WEAK symbol G_Glass_Update{0x2992E0, 0x417940}; WEAK symbol G_GetClientScore{0x0, 0x0}; - WEAK symbol G_GetWeaponForName{0x4B18D0, 0x461180}; + WEAK symbol G_GetWeaponForName{0x2F20F0, 0x461180}; WEAK symbol G_GivePlayerWeapon{0x2F24F0, 0x461600}; WEAK symbol G_InitializeAmmo{0x0, 0x41C170}; @@ -198,7 +198,7 @@ namespace game WEAK symbol SV_GetClientPing{0x0, 0x551D70}; WEAK symbol SV_GetPlayerstateForClientNum{0x0, 0x551E10}; WEAK symbol SV_SetConfigstring{0x0, 0x553E60}; - WEAK symbol SV_Loaded{0x0, 0x553970}; + WEAK symbol SV_Loaded{0x4C4810, 0x553970}; WEAK symbol SV_KickClientNum{0x0, 0x54C060}; WEAK symbol SV_MapExists{0x0, 0x54C0C0}; WEAK symbol SV_ExecuteClientCommand{0x0, 0x0}; diff --git a/src/client/resources/json.lua b/src/client/resources/json.lua index 711ef786..84c44262 100644 --- a/src/client/resources/json.lua +++ b/src/client/resources/json.lua @@ -22,7 +22,7 @@ -- SOFTWARE. -- -local json = { _version = "0.1.2" } +json = { _version = "0.1.2" } ------------------------------------------------------------------------------- -- Encode