diff --git a/.gitmodules b/.gitmodules index e92c76fd..af79585d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -45,3 +45,6 @@ path = deps/zlib url = https://github.com/madler/zlib.git branch = develop +[submodule "deps/curl"] + path = deps/curl + url = https://github.com/curl/curl.git diff --git a/data/ui_scripts/patches/__init__.lua b/data/ui_scripts/patches/__init__.lua index 291f5367..85c92abf 100644 --- a/data/ui_scripts/patches/__init__.lua +++ b/data/ui_scripts/patches/__init__.lua @@ -4,6 +4,7 @@ end if (Engine.InFrontend()) then require("shaderdialog") + require("gamemodes") end -- defined in mp_hud/hudutils.lua diff --git a/data/ui_scripts/extra_gamemodes/__init__.lua b/data/ui_scripts/patches/gamemodes.lua similarity index 80% rename from data/ui_scripts/extra_gamemodes/__init__.lua rename to data/ui_scripts/patches/gamemodes.lua index 5608b759..6bdadc82 100644 --- a/data/ui_scripts/extra_gamemodes/__init__.lua +++ b/data/ui_scripts/patches/gamemodes.lua @@ -1,7 +1,3 @@ -if (game:issingleplayer() or not Engine.InFrontend()) then - return -end - Cac.GameModes.Data = { Standard = { Label = Engine.Localize("@MPUI_STANDARD_CAPS"), diff --git a/data/ui_scripts/server_list/serverlist.lua b/data/ui_scripts/server_list/serverlist.lua index daed0300..10e48598 100644 --- a/data/ui_scripts/server_list/serverlist.lua +++ b/data/ui_scripts/server_list/serverlist.lua @@ -7,6 +7,8 @@ end game:addlocalizedstring("MENU_NUMPLAYERS", "Players") game:addlocalizedstring("MENU_PING", "Ping") +game:addlocalizedstring("SERVERLIST_PLAYER_COUNT", "&&1 Players") +game:addlocalizedstring("SERVERLIST_SERVER_COUNT", "&&1 Servers") local columns = { { @@ -195,8 +197,33 @@ function menu_systemlink_join(f19_arg0, f19_arg1) SystemLinkJoinMenu.UpdateCounterText(menu, nil) Lobby.BuildServerList(Engine.GetFirstActiveController()) + local playercount = LUI.UIText.new({ + rightAnchor = true, + topAnchor = true, + height = 18, + bottom = 58, + font = CoD.TextSettings.BodyFont.Font, + width = 300, + alignment = LUI.Alignment.Right, + }) + menu:addElement(playercount) + + local servercount = LUI.UIText.new({ + rightAnchor = true, + topAnchor = true, + height = 18, + bottom = 58 - 25, + font = CoD.TextSettings.BodyFont.Font, + width = 300, + alignment = LUI.Alignment.Right, + }) + menu:addElement(servercount) + menu.list:registerEventHandler(LUI.UIScrollIndicator.UpdateEvent, function(element, event) SystemLinkJoinMenu.UpdateCounterText(menu, event) + + playercount:setText(Engine.Localize("@SERVERLIST_PLAYER_COUNT", serverlist:getplayercount())) + servercount:setText(Engine.Localize("@SERVERLIST_SERVER_COUNT", serverlist:getservercount())) end) SystemLinkJoinMenu.UpdateGameList(menu) diff --git a/deps/asmjit b/deps/asmjit index 06d0bade..35f92e87 160000 --- a/deps/asmjit +++ b/deps/asmjit @@ -1 +1 @@ -Subproject commit 06d0badec53710a4f572cf5642881ce570c5d274 +Subproject commit 35f92e8706db78c6aa7482b5e1cdb59c5972a965 diff --git a/deps/curl b/deps/curl new file mode 160000 index 00000000..e2e7f54b --- /dev/null +++ b/deps/curl @@ -0,0 +1 @@ +Subproject commit e2e7f54b7bea521fa8373095d0f43261a720cda0 diff --git a/deps/premake/curl.lua b/deps/premake/curl.lua new file mode 100644 index 00000000..8db164e1 --- /dev/null +++ b/deps/premake/curl.lua @@ -0,0 +1,73 @@ +curl = { + source = path.join(dependencies.basePath, "curl"), +} + +function curl.import() + links { "curl" } + + filter "toolset:msc*" + links { "Crypt32.lib" } + filter {} + + curl.includes() +end + +function curl.includes() +filter "toolset:msc*" + includedirs { + path.join(curl.source, "include"), + } + + defines { + "CURL_STRICTER", + "CURL_STATICLIB", + "CURL_DISABLE_LDAP", + } +filter {} +end + +function curl.project() + if not os.istarget("windows") then + return + end + + project "curl" + language "C" + + curl.includes() + + includedirs { + path.join(curl.source, "lib"), + } + + files { + path.join(curl.source, "lib/**.c"), + path.join(curl.source, "lib/**.h"), + } + + defines { + "BUILDING_LIBCURL", + } + + filter "toolset:msc*" + + defines { + "USE_SCHANNEL", + "USE_WINDOWS_SSPI", + "USE_THREADS_WIN32", + } + + filter "toolset:not msc*" + + defines { + "USE_GNUTLS", + "USE_THREADS_POSIX", + } + + filter {} + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, curl) \ No newline at end of file diff --git a/deps/sol2 b/deps/sol2 index c9055478..dca62a0f 160000 --- a/deps/sol2 +++ b/deps/sol2 @@ -1 +1 @@ -Subproject commit c9055478c7c437f9a97610329701652673ab8262 +Subproject commit dca62a0f02bb45f3de296de3ce00b1275eb34c25 diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index 21ede068..268d23ab 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -42,7 +42,7 @@ namespace auth std::string get_protected_data() { - std::string input = "X-Labs-H1Mod-Auth"; + std::string input = "H1Mod-Auth"; DATA_BLOB data_in{}, data_out{}; data_in.pbData = reinterpret_cast(input.data()); diff --git a/src/client/component/discord.cpp b/src/client/component/discord.cpp index e0693fa5..2495b7bd 100644 --- a/src/client/component/discord.cpp +++ b/src/client/component/discord.cpp @@ -138,21 +138,37 @@ namespace discord { const auto data = utils::http::get_data( utils::string::va(AVATAR_URL, id.data(), avatar.data())); - if (data.has_value()) + if (!data.has_value()) { - materials::add(utils::string::va(AVATAR, id.data()), data.value()); + return; } + + const auto& value = data.value(); + if (value.code != CURLE_OK) + { + return; + } + + materials::add(utils::string::va(AVATAR, id.data()), value.buffer); } bool has_default_avatar = false; void download_default_avatar() { const auto data = utils::http::get_data(DEFAULT_AVATAR_URL); - if (data.has_value()) + if (!data.has_value()) { - has_default_avatar = true; - materials::add(DEFAULT_AVATAR, data.value()); + return; } + + const auto& value = data.value(); + if (value.code != CURLE_OK) + { + return; + } + + has_default_avatar = true; + materials::add(DEFAULT_AVATAR, value.buffer); } } diff --git a/src/client/component/lui.cpp b/src/client/component/lui.cpp index 53f652b4..0738d570 100644 --- a/src/client/component/lui.cpp +++ b/src/client/component/lui.cpp @@ -5,16 +5,67 @@ #include "command.hpp" #include "console.hpp" +#include "scheduler.hpp" #include namespace lui { + namespace + { + uint64_t event_count{}; + bool begin_game_message_event_stub(int a1, const char* name, void* a3) + { + if (event_count > 30) + { + return false; + } + else + { + event_count++; + } + + return utils::hook::invoke(0x2655A0_b, a1, name, a3); + } + } + class component final : public component_interface { public: void post_unpack() override { + if (game::environment::is_mp()) + { + // Patch game message overflow + utils::hook::call(0x266E6B_b, begin_game_message_event_stub); + + scheduler::loop([]() + { + if (event_count > 0) + { + event_count--; + } + }, scheduler::pipeline::lui, 50ms); + } + + // Increase max extra LUI memory + /*const auto max_memory = 0x900000 * 2; + utils::hook::set(0x278E61_b - 4, max_memory); + utils::hook::set(0x27A2C5_b - 4, max_memory); + utils::hook::set(0x27A993_b - 4, max_memory); + utils::hook::set(0x27AB3A_b - 4, max_memory); + utils::hook::set(0x27AB35_b - 4, max_memory); + utils::hook::set(0x27C002_b - 4, max_memory);*/ + + // Increase max extra frontend memory + /*const auto max_frontend_memory = 0x180000 * 2; + utils::hook::set(0x278EA6_b - 4, max_frontend_memory); + utils::hook::set(0x278F01_b - 4, max_frontend_memory); + utils::hook::set(0x27A2D4_b - 4, max_frontend_memory); + utils::hook::set(0x27A2E3_b - 4, max_frontend_memory); + utils::hook::set(0x27F9E9_b - 4, max_frontend_memory); + utils::hook::set(0x27FA84_b - 4, max_frontend_memory);*/ + command::add("lui_open", [](const command::params& params) { if (params.size() <= 1) diff --git a/src/client/component/patches.cpp b/src/client/component/patches.cpp index a5cae4f8..36208f5f 100644 --- a/src/client/component/patches.cpp +++ b/src/client/component/patches.cpp @@ -123,9 +123,10 @@ namespace patches const auto menu_id = atoi(params.get(1)); const auto client = &svs_clients[ent->s.entityNum]; - // 22 => "end_game" - if (menu_id == 22 && client->header.remoteAddress.type != game::NA_LOOPBACK) + // 32 => "end_game" + if (menu_id == 32 && client->header.remoteAddress.type != game::NA_LOOPBACK) { + game::SV_DropClient_Internal(client, "PLATFORM_STEAM_KICK_CHEAT", true); return; } @@ -158,7 +159,7 @@ namespace patches void missing_content_error_stub(int, const char*) { - game::Com_Error(game::ERR_DROP, utils::string::va("MISSING FILE\n%s.ff", + game::Com_Error(game::ERR_DROP, utils::string::va("MISSING FILE\n%s.ff", fastfiles::get_current_fastfile().data())); } @@ -194,15 +195,74 @@ namespace patches char buffer[2048]; - va_list ap; - va_start(ap, fmt); + { + va_list ap; + va_start(ap, fmt); - vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, fmt, ap); + vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, fmt, ap); - va_end(ap); + va_end(ap); + } return utils::hook::invoke(SELECT_VALUE(0x429200_b, 0x5AF0F0_b), dest, size, "%s", buffer); } + + void create_2d_texture_stub_1(const char* fmt, ...) + { + fmt = "Create2DTexture( %s, %i, %i, %i, %i ) failed\n\n" + "Disable shader caching, lower graphic settings, free up RAM, or update your GPU drivers."; + + char buffer[2048]; + + { + va_list ap; + va_start(ap, fmt); + + vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, fmt, ap); + + va_end(ap); + } + + game::Sys_Error("%s", buffer); + } + + void create_2d_texture_stub_2(game::errorParm code, const char* fmt, ...) + { + fmt = "Create2DTexture( %s, %i, %i, %i, %i ) failed\n\n" + "Disable shader caching, lower graphic settings, free up RAM, or update your GPU drivers."; + + char buffer[2048]; + + { + va_list ap; + va_start(ap, fmt); + + vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, fmt, ap); + + va_end(ap); + } + + game::Com_Error(code, "%s", buffer); + } + + void swap_chain_stub(game::errorParm code, const char* fmt, ...) + { + fmt = "IDXGISwapChain::Present failed: %s\n\n" + "Disable shader caching, lower graphic settings, free up RAM, or update your GPU drivers."; + + char buffer[2048]; + + { + va_list ap; + va_start(ap, fmt); + + vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, fmt, ap); + + va_end(ap); + } + + game::Com_Error(code, "%s", buffer); + } } class component final : public component_interface @@ -242,13 +302,10 @@ namespace patches utils::hook::call(SELECT_VALUE(0x376EB5_b, 0x156D41_b), db_read_raw_file_stub); // Remove useless information from errors + add additional help to common errors - utils::hook::set(SELECT_VALUE(0x7E3DF0_b, 0x937B80_b), - "Create2DTexture( %s, %i, %i, %i, %i ) failed\n\n" - "Disable shader caching, lower graphic settings, free up RAM, or update your GPU drivers."); - utils::hook::set(SELECT_VALUE(0x800EA8_b, 0x954FF0_b), - "IDXGISwapChain::Present failed: %s\n\n" - "Disable shader caching, lower graphic settings, free up RAM, or update your GPU drivers."); - utils::hook::call(SELECT_VALUE(0x457BC9_b, 0x1D8E09_b), out_of_memory_text_stub); // "Out of memory. You are probably low on disk space." + utils::hook::call(SELECT_VALUE(0x55E919_b, 0x681A69_b), create_2d_texture_stub_1); // Sys_Error for "Create2DTexture( %s, %i, %i, %i, %i ) failed" + utils::hook::call(SELECT_VALUE(0x55EACB_b, 0x681C1B_b), create_2d_texture_stub_2); // Com_Error for ^ + utils::hook::call(SELECT_VALUE(0x5B35BA_b, 0x6CB1BC_b), swap_chain_stub); // Com_Error for "IDXGISwapChain::Present failed: %s" + utils::hook::call(SELECT_VALUE(0x457BC9_b, 0x1D8E09_b), out_of_memory_text_stub); // Com_sprintf for "Out of memory. You are probably low on disk space." // "fix" for rare 'Out of memory error' error // this will *at least* generate the configs for mp/sp, which is the #1 issue diff --git a/src/client/component/server_list.cpp b/src/client/component/server_list.cpp index f5059e35..c74c259c 100644 --- a/src/client/component/server_list.cpp +++ b/src/client/component/server_list.cpp @@ -375,6 +375,23 @@ namespace server_list insert_server(std::move(server)); } + int get_player_count() + { + std::lock_guard _(mutex); + auto count = 0; + for (const auto& server : servers) + { + count += server.clients - server.bots; + } + return count; + } + + int get_server_count() + { + std::lock_guard _(mutex); + return static_cast(servers.size()); + } + class component final : public component_interface { public: diff --git a/src/client/component/server_list.hpp b/src/client/component/server_list.hpp index d9974cfa..14119c2d 100644 --- a/src/client/component/server_list.hpp +++ b/src/client/component/server_list.hpp @@ -9,4 +9,7 @@ namespace server_list void handle_info_response(const game::netadr_s& address, const utils::info_string& info); bool sl_key_event(int key, int down); + + int get_player_count(); + int get_server_count(); } \ No newline at end of file diff --git a/src/client/component/ui_scripting.cpp b/src/client/component/ui_scripting.cpp index ec6418c3..7c2e8ea8 100644 --- a/src/client/component/ui_scripting.cpp +++ b/src/client/component/ui_scripting.cpp @@ -17,6 +17,7 @@ #include "fastfiles.hpp" #include "scripting.hpp" #include "updater.hpp" +#include "server_list.hpp" #include "game/ui_scripting/execution.hpp" #include "game/scripting/execution.hpp" @@ -342,6 +343,12 @@ namespace ui_scripting ::game::Dvar_SetFromStringByNameFromSource("virtualLobbyPresentable", "1", ::game::DvarSetSource::DVAR_SOURCE_INTERNAL); }; + auto server_list_table = table(); + lua["serverlist"] = server_list_table; + + server_list_table["getplayercount"] = server_list::get_player_count; + server_list_table["getservercount"] = server_list::get_server_count; + auto updater_table = table(); lua["updater"] = updater_table; diff --git a/src/client/component/updater.cpp b/src/client/component/updater.cpp index ab2c748a..044c81b4 100644 --- a/src/client/component/updater.cpp +++ b/src/client/component/updater.cpp @@ -26,9 +26,9 @@ #define DATA_PATH "data/" #define DATA_PATH_DEV "data-dev/" -#define ERR_UPDATE_CHECK_FAIL "Failed to check for updates" +#define ERR_UPDATE_CHECK_FAIL "Failed to check for updates:\n%s" #define ERR_UPDATE_CHECK_FAIL_BAD_RESPONSE "Bad response" -#define ERR_DOWNLOAD_FAIL "Failed to download file " +#define ERR_DOWNLOAD_FAIL "Failed to download file %s:\n%s" #define ERR_WRITE_FAIL "Failed to write file " #define BINARY_NAME "h1-mod.exe" @@ -139,7 +139,7 @@ namespace updater return utils::string::va("%i", uint32_t(time(nullptr))); } - std::optional download_file(const std::string& name) + std::optional download_file(const std::string& name) { return utils::http::get_data(MASTER + select(DATA_PATH, DATA_PATH_DEV) + name + "?" + get_time_str()); } @@ -191,6 +191,12 @@ namespace updater return {}; } + + std::string curl_error(CURLcode code) + { + const auto str_error = curl_easy_strerror(code); + return utils::string::va("%s (%i)", str_error, code); + } } // workaround @@ -337,12 +343,20 @@ namespace updater if (!files_data.has_value()) { - set_update_check_status(true, false, ERR_UPDATE_CHECK_FAIL); + set_update_check_status(true, false, utils::string::va(ERR_UPDATE_CHECK_FAIL, "Unknown error")); + return; + } + + const auto& value = files_data.value(); + if (value.code != CURLE_OK) + { + const auto error = curl_error(value.code); + set_update_check_status(true, false, utils::string::va(ERR_UPDATE_CHECK_FAIL, error.data())); return; } rapidjson::Document j; - j.Parse(files_data.value().data()); + j.Parse(value.buffer.data()); if (!j.IsArray()) { @@ -433,11 +447,19 @@ namespace updater if (!data.has_value()) { - set_update_download_status(true, false, ERR_DOWNLOAD_FAIL + file); + set_update_download_status(true, false, utils::string::va(ERR_DOWNLOAD_FAIL, file.data(), "Unknown error")); return; } - downloads.push_back({file, data.value()}); + const auto& value = data.value(); + if (value.code != CURLE_OK) + { + const auto error = curl_error(value.code); + set_update_download_status(true, false, utils::string::va(ERR_DOWNLOAD_FAIL, file.data(), error.data())); + return; + } + + downloads.push_back({file, value.buffer}); } for (const auto& download : downloads) diff --git a/src/client/game/scripting/function_tables.cpp b/src/client/game/scripting/function_tables.cpp index ff0a8000..a397741e 100644 --- a/src/client/game/scripting/function_tables.cpp +++ b/src/client/game/scripting/function_tables.cpp @@ -1500,12 +1500,12 @@ namespace scripting {"_meth_82e8", 0x82E8}, // SP 0x000000 MP 0x411730 {"_meth_82e9", 0x82E9}, // SP 0x000000 MP 0x411720 {"_meth_82ea", 0x82EA}, // SP 0x2905B0 MP 0x40BAD0 - {"_meth_82eb", 0x82EB}, // SP 0x28F5E0 MP 0x40AB90 - {"_meth_82ec", 0x82EC}, // SP 0x28F6D0 MP 0x40ACC0 + {"fragbuttonpressed", 0x82EB}, // SP 0x28F5E0 MP 0x40AB90 + {"secondaryoffhandbuttonpressed", 0x82EC}, // SP 0x28F6D0 MP 0x40ACC0 {"issighted", 0x82ED}, // SP 0x2919D0 MP 0x40D2E0 {"setvelocity", 0x82EE}, // SP 0x28DC30 MP 0x4090E0 {"_meth_82ef", 0x82EF}, // SP 0x28E570 MP 0x409920 - {"_meth_82f0", 0x82F0}, // SP 0x28E980 MP 0x409B70 + {"getnormalizedmovement", 0x82F0}, // SP 0x28E980 MP 0x409B70 {"playlocalsound", 0x82F1}, // SP 0x28DAC0 MP 0x409330 {"stoplocalsound", 0x82F2}, // SP 0x28DBA0 MP 0x409420 {"setweaponammoclip", 0x82F3}, // SP 0x2928A0 MP 0x405D60 @@ -1603,7 +1603,7 @@ namespace scripting {"botsetstance", 0x8350}, // SP 0x000000 MP 0x5473D0 {"botsetscriptmove", 0x8351}, // SP 0x000000 MP 0x547250 {"_meth_8352", 0x8352}, // SP 0x000000 MP 0x546EA0 - {"_meth_8353", 0x8353}, // SP 0x000000 MP 0x547090 + {"botsetscriptgoal", 0x8353}, // SP 0x000000 MP 0x547090 {"botclearscriptgoal", 0x8354}, // SP 0x000000 MP 0x544F60 {"getnearestnode", 0x8355}, // SP 0x000000 MP 0x546DE0 {"botclearscriptenemy", 0x8356}, // SP 0x000000 MP 0x544EE0 @@ -1616,7 +1616,7 @@ namespace scripting {"_meth_835e", 0x835E}, // SP 0x000000 MP 0x5460F0 {"botfindnoderandom", 0x835F}, // SP 0x000000 MP 0x544FE0 {"botmemoryevent", 0x8360}, // SP 0x000000 MP 0x545E50 - {"_meth_8362", 0x8362}, // SP 0x000000 MP 0x546190 + {"botnodepick", 0x8362}, // SP 0x000000 MP 0x546190 {"bothasscriptgoal", 0x8363}, // SP 0x000000 MP 0x545B70 {"botgetpersonality", 0x8364}, // SP 0x000000 MP 0x545700 {"_meth_8365", 0x8365}, // SP 0x000000 MP 0x5474A0 @@ -2890,10 +2890,10 @@ namespace scripting {"origin", 0x2DF}, {"other", 0x2E0}, {"over", 0x2E1}, - {"owner", 0x2E2}, + {"_not_owner", 0x2E2}, // was "owner" {"pacifist", 0x2E3}, {"pacifistwait", 0x2E4}, - {"pain", 0x2E5}, + {"owner", 0x2E5}, // was "pain" {"pantssize", 0x2E6}, {"parentindex", 0x2E7}, {"parentname", 0x2E8}, @@ -2925,10 +2925,10 @@ namespace scripting {"perkrestricted", 0x302}, {"perks", 0x303}, {"perkslots", 0x304}, - {"pers", 0x305}, + {"_not_pers", 0x305}, // was "pers" {"persistentperksunlocked", 0x306}, {"persistentweaponsunlocked", 0x307}, - {"phone_off", 0x308}, + {"pers", 0x308}, // was "phone_off" {"phone_on", 0x309}, {"physics_finished", 0x30A}, {"physics_impact", 0x30B}, @@ -3312,10 +3312,10 @@ namespace scripting {"tag_sight_off", 0x485}, {"tag_sight_on", 0x486}, {"tag_stow_back_mid_attach", 0x487}, - {"tag_stowed_back", 0x488}, + {"_not_tag_stowed_back", 0x488}, // was "tag_stowed_back" {"tag_stowed_hip_rear", 0x489}, {"tag_sync", 0x48A}, - {"tag_tip", 0x48B}, + {"tag_stowed_back", 0x48B}, // was "tag_tip" {"tag_turret", 0x48C}, {"tag_turret_base", 0x48D}, {"tag_turret_pitch", 0x48E}, @@ -3340,10 +3340,10 @@ namespace scripting {"target", 0x4A1}, {"target_script_trigger", 0x4A2}, {"targetname", 0x4A3}, - {"team", 0x4A4}, + {"_not_team", 0x4A4}, // was "team" {"team3", 0x4A5}, {"teambalanced", 0x4A6}, - {"teammode_axisallies", 0x4A7}, + {"team", 0x4A7}, // was "teammode_axisallies" {"teammode_ffa", 0x4A8}, {"teammovewaittime", 0x4A9}, {"their_score", 0x4AA}, @@ -3370,10 +3370,10 @@ namespace scripting {"traversecost", 0x4BF}, {"traversesoonnotifydist", 0x4C0}, {"trend", 0x4C1}, - {"trigger", 0x4C2}, + {"_not_trigger", 0x4C2}, // was "trigger" {"trigger_damage", 0x4C3}, {"trigger_use", 0x4C4}, - {"trigger_use_touch", 0x4C5}, + {"trigger", 0x4C5}, // was "trigger_use_touch" {"truck_cam", 0x4C6}, {"turnrate", 0x4C7}, {"turret_deactivate", 0x4C8}, @@ -3492,5 +3492,97 @@ namespace scripting {"codescripts/struct", 0x53E}, {"codescripts/message", 0x53F}, {"maps/mp/gametypes/_callbacksetup", 0x540}, + + // additional findings from gametype/map scripts - mikey (6/26/2022) + {"common_scripts/_fx", 0xA4FB}, + {"common_scripts/_pipes", 0xA4F9}, + {"common_scripts/utility", 0xA4FA}, + + {"QuickMessageToAll", 0x70a2}, + {"SetupCallbacks", 0x8301}, + {"_effect", 0x58f}, + {"_objective_delete", 0x603}, + {"addSpawnPoints", 0x82f}, + {"addStartSpawnPoints", 0x831}, + {"addToCharactersArray", 0x848}, + {"allowUse", 0xab2}, + {"applyLoadout", 0xcae}, // has applyLoadout notify like IW6's giveLoadout does at the end + similar logic + {"characters", 0x1c8e}, + {"checkDynamicSpawns", 0x1cfa}, + {"clearOnVictimDisconnect", 0x1ef9}, + {"conf_fx", 0x20e9}, + {"console", 0x2153}, + {"createUseObject", 0x244c}, + {"curOrigin", 0x24c8}, + {"deleteObjPoint", 0x2859}, + {"dogtags", 0x2cdf}, + {"finalKill", 0x373e}, + {"findBoxCenter", 0x3779}, + {"forfeitInProgress", 0x39df}, + {"gamemodeModifyPlayerDamage", 0x3bf6}, + {"getNextObjID", 0x4041}, + {"getOtherTeam", 0x4067}, + {"getSpawnPoint", 0x40d2}, + {"getSpawnpoint_FreeForAll", 0x40d5}, + {"getTeamSpawnPoints", 0x411f}, + {"giveLoadout", 0x41e0}, // this may not even be giveLoadout but it's a wrapper for it and it does the same logic so + {"guid", 0x4450}, + {"inGracePeriod", 0x4c6d}, + {"initSpawns", 0x4e26}, + {"initializeMatchRules", 0x4de0}, + {"initializeTagPathVariables", 0x4de3}, + {"mapCenter", 0x5986}, + {"maps/mp/_compass", 0xa731}, + {"maps/mp/_load", 0xa74c}, + {"maps/mp/_utility", 0xa764}, + {"maps/mp/gametypes/_class", 0xA78B}, + {"maps/mp/gametypes/_damage", 0xA78D}, + {"maps/mp/gametypes/_gameobjects", 0xA794}, + {"maps/mp/gametypes/_globallogic", 0xA797}, + {"maps/mp/gametypes/_menus", 0xa7a9}, + {"maps/mp/gametypes/_objpoints", 0xa7ac}, + {"maps/mp/gametypes/_spawnlogic", 0xa7b9}, + {"maps/mp/gametypes/_spawnscoring", 0xa7ba}, + {"matchRules_damageMultiplier", 0x59e6}, + {"matchRules_vampirism", 0x59eb}, + {"modifyPlayerDamage", 0x5d51}, + {"objId", 0x6304}, + {"onForfeit", 0x64af}, + {"onNormalDeath", 0x64bf}, + {"onPlayerScore", 0x64d5}, + {"onStartGameType", 0x64ec}, + {"onUse", 0x64f8}, + {"participants", 0x669d}, + {"reInitializeMatchRulesOnMigration", 0x7307}, + {"registerHalfTimeDvar", 0x72ef}, + {"registerNumLivesDvar", 0x72f4}, + {"registerRoundLimitDvar", 0x72f6}, + {"registerRoundSwitchDvar", 0x72f7}, + {"registerScoreLimitDvar", 0x72f8}, + {"registerTimeLimitDvar", 0x72f9}, + {"registerWinLimitDvar", 0x72fe}, + {"removeFromCharactersArray", 0x73a7}, + {"setClass", 0x7f3b}, + {"setCommonRulesFromMatchRulesData", 0x7f3f}, + {"setObjectiveHintText", 0x7fc3}, + {"setObjectiveScoreText", 0x7fc4}, + {"setObjectiveText", 0x7fc5}, + {"setUseTime", 0x834c}, + {"setupMiniMap", 0x8324}, + {"showToTeam", 0x8535}, + {"spawnDogTags", 0x899e}, + {"spawnMaxs", 0x89f3}, + {"spawnMins", 0x89f6}, + {"spawnPoints", 0x8a01}, + {"splitscreen", 0x8a7c}, + {"tag_stowed_hip", 0x90d3}, + {"tagTeamUpdater", 0x910a}, + {"teamBased", 0x91eb}, + {"teamNameList", 0x91f7}, + {"teamObjIds", 0x6305}, + {"teamSpawnPoints", 0x9201}, + {"v", 0x9c42}, + {"visuals", 0x9e9c}, + {"multiTeamBased", 0x5fec}, }; } diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index cbe7db08..95a50f2b 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -197,6 +197,7 @@ namespace game WEAK symbol SV_ExecuteClientCommand{0x0, 0x0}; WEAK symbol SV_FastRestart{0x0, 0x54BE00}; WEAK symbol SV_SendServerCommand{0x0, 0x1CC040}; + WEAK symbol SV_DropClient_Internal{0x0, 0x54E7F0}; WEAK symbol Sys_ShowConsole{0x0, 0x0}; WEAK symbol Sys_Error{0x0, 0x1D8710}; @@ -295,6 +296,7 @@ namespace game WEAK symbol hksi_lua_getinfo{0xB84D0, 0x22FFE0}; WEAK symbol hksi_lua_getstack{0xB87A0, 0x2302B0}; WEAK symbol hksi_luaL_error{0xBF120, 0x22F930}; + WEAK symbol hksi_lua_gc{0, 0x236EF0}; WEAK symbol typenames{0x98CD20, 0x10AD750}; } } diff --git a/src/client/main.cpp b/src/client/main.cpp index e8862c4a..1c078970 100644 --- a/src/client/main.cpp +++ b/src/client/main.cpp @@ -181,16 +181,6 @@ void limit_parallel_dll_loading() RegCloseKey(key); } -// solution for other processes that may launch the mod -void apply_proper_directory() -{ - char module_path[MAX_PATH]; - GetModuleFileNameA(nullptr, module_path, MAX_PATH); - PathRemoveFileSpecA(module_path); - SetCurrentDirectoryA(module_path); - SetDllDirectoryA(module_path); -} - int main() { ShowWindow(GetConsoleWindow(), SW_HIDE); @@ -217,8 +207,6 @@ int main() try { - //apply_proper_directory(); - if (!component_loader::post_start()) return 0; auto mode = detect_mode_from_arguments(); diff --git a/src/client/resource.rc b/src/client/resource.rc index 1e84f3de..b833631f 100644 --- a/src/client/resource.rc +++ b/src/client/resource.rc @@ -74,7 +74,7 @@ BEGIN VALUE "FileDescription", "H1-Mod" VALUE "FileVersion", VERSION_FILE VALUE "InternalName", "H1-Mod" - VALUE "LegalCopyright", "Copyright (C) 2021 H1-Mod. All rights reserved." + VALUE "LegalCopyright", "Copyright © 2022 H1-Mod. All rights reserved." VALUE "Licence", "GPLv3" VALUE "Info", "https://h1.gg" VALUE "OriginalFilename", "h1-mod.exe" diff --git a/src/common/utils/http.cpp b/src/common/utils/http.cpp index 3cb59991..bdb3da42 100644 --- a/src/common/utils/http.cpp +++ b/src/common/utils/http.cpp @@ -4,41 +4,61 @@ namespace utils::http { - std::optional get_data(const std::string& url) + namespace { - CComPtr stream; - - if (FAILED(URLOpenBlockingStreamA(nullptr, url.data(), &stream, 0, nullptr))) + size_t write_callback(void* contents, const size_t size, const size_t nmemb, void* userp) { - return {}; + auto* buffer = static_cast(userp); + + const auto total_size = size * nmemb; + buffer->append(static_cast(contents), total_size); + return total_size; } - - char buffer[0x1000]; - std::string result; - - HRESULT status{}; - - do - { - DWORD bytes_read = 0; - status = stream->Read(buffer, sizeof(buffer), &bytes_read); - - if (bytes_read > 0) - { - result.append(buffer, bytes_read); - } - } - while (SUCCEEDED(status) && status != S_FALSE); - - if (FAILED(status)) - { - return {}; - } - - return {result}; } - std::future> get_data_async(const std::string& url) + std::optional get_data(const std::string& url) + { + curl_slist* header_list = nullptr; + auto* curl = curl_easy_init(); + if (!curl) + { + return {}; + } + + auto _ = gsl::finally([&]() + { + curl_slist_free_all(header_list); + curl_easy_cleanup(curl); + }); + + std::string buffer{}; + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list); + curl_easy_setopt(curl, CURLOPT_URL, url.data()); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1); + + const auto code = curl_easy_perform(curl); + + if (code == CURLE_OK) + { + result result; + result.code = code; + result.buffer = std::move(buffer); + + return result; + } + else + { + result result; + result.code = code; + + return result; + } + } + + std::future> get_data_async(const std::string& url) { return std::async(std::launch::async, [url]() { diff --git a/src/common/utils/http.hpp b/src/common/utils/http.hpp index 65628a9f..7361a7b2 100644 --- a/src/common/utils/http.hpp +++ b/src/common/utils/http.hpp @@ -3,9 +3,18 @@ #include #include #include +#include + +#include namespace utils::http { - std::optional get_data(const std::string& url); - std::future> get_data_async(const std::string& url); + struct result + { + CURLcode code; + std::string buffer; + }; + + std::optional get_data(const std::string& url); + std::future> get_data_async(const std::string& url); } diff --git a/src/common/utils/toast.cpp b/src/common/utils/toast.cpp index b39ca5fa..a9002bf3 100644 --- a/src/common/utils/toast.cpp +++ b/src/common/utils/toast.cpp @@ -29,7 +29,7 @@ namespace utils instance->setAppName(L"H1-Mod"); instance->setAppUserModelId( - WinToastLib::WinToast::configureAUMI(L"X Labs", L"H1-Mod", L"", L"20201212")); + WinToastLib::WinToast::configureAUMI(L"H1-Mod", L"H1", L"", L"20201212")); WinToastLib::WinToast::WinToastError error; success = instance->initialize(&error); diff --git a/src/runner/resource.rc b/src/runner/resource.rc index ba86c6f4..ce3e7244 100644 --- a/src/runner/resource.rc +++ b/src/runner/resource.rc @@ -60,7 +60,7 @@ BEGIN BEGIN BLOCK "040904b0" BEGIN - VALUE "CompanyName", "X Labs" + VALUE "CompanyName", "H1-Mod" VALUE "FileDescription", "Steam mod runner" VALUE "FileVersion", "1.0.0.0" VALUE "InternalName", "Runner" diff --git a/src/tlsdll/resource.rc b/src/tlsdll/resource.rc index 2a778f5f..90a44764 100644 --- a/src/tlsdll/resource.rc +++ b/src/tlsdll/resource.rc @@ -60,7 +60,7 @@ BEGIN BEGIN BLOCK "040904b0" BEGIN - VALUE "CompanyName", "X Labs" + VALUE "CompanyName", "H1-Mod" VALUE "FileDescription", "TLS index allocation dll" VALUE "FileVersion", "1.0.0.0" VALUE "InternalName", "TLS DLL"