From f35b102d44f9f6584486cb04503e079e2a97327f Mon Sep 17 00:00:00 2001 From: quaK Date: Mon, 15 Jul 2024 17:20:10 +0300 Subject: [PATCH] add loadscreen support --- src/client/component/branding.cpp | 7 +- src/client/component/loadscreen.cpp | 208 ++++++++++++++++++++++++++++ src/client/component/party.cpp | 6 +- src/client/game/structs.hpp | 30 ++++ src/client/game/symbols.hpp | 23 ++- 5 files changed, 266 insertions(+), 8 deletions(-) create mode 100644 src/client/component/loadscreen.cpp diff --git a/src/client/component/branding.cpp b/src/client/component/branding.cpp index e7ad38fa..200fecca 100644 --- a/src/client/component/branding.cpp +++ b/src/client/component/branding.cpp @@ -53,14 +53,13 @@ namespace branding if (dvars::branding && dvars::branding->current.enabled) { #if GIT_DIRTY == 1 - const auto font = game::R_RegisterFont("fonts/blender_pro_medium.ttf", 32); + const auto* placement = game::ScrPlace_GetViewPlacement(); + const auto font = game::UI_GetFontHandle(placement, game::FONT_TYPE_HUD_BIG_FONT, 1.0f); if (!font) return; static const auto offset_from_corner = 75.0f; - static float text_color[4] = { 0.4f, 0.69f, 1.0f, 0.69f }; - - const auto* placement = game::ScrPlace_GetViewPlacement(); + const auto x = (placement->realViewportSize[0] - offset_from_corner) - (game::R_TextWidth(version_buffer, std::numeric_limits::max(), font)); const auto height = (placement->realViewportSize[1] - offset_from_corner) + 5.0f; // remove some off the offset diff --git a/src/client/component/loadscreen.cpp b/src/client/component/loadscreen.cpp new file mode 100644 index 00000000..709080f1 --- /dev/null +++ b/src/client/component/loadscreen.cpp @@ -0,0 +1,208 @@ +#include +#include "loader/component_loader.hpp" + +#include "game/game.hpp" +#include "dvars.hpp" + +#include +#include + +namespace loadscreen +{ + namespace + { + bool CG_IsShowingProgress_FastFile() + { + return game::LoadBar_GetLoadedFraction() > 0.0; + } + + void UI_DrawLoadScreenInfo() + { + auto* mapname = game::Dvar_FindVar("ui_mapname")->current.string; + auto* gametype = game::Dvar_FindVar("ui_gametype")->current.string; + + auto* mapname_ui = game::UI_GetMapDisplayName(mapname); + auto* gametype_ui = game::UI_GetGameTypeDisplayName(gametype); + + const auto* placement = game::ScrPlace_GetActivePlacement(); + + { + const auto scale_mapname = 0.4f; + const auto scale_gametype = 0.3f; + + auto* font_mapname = game::UI_GetFontHandle(placement, game::FONT_TYPE_OBJECTIVE_FONT, scale_mapname); + auto* font_gametype = game::UI_GetFontHandle(placement, game::FONT_TYPE_OBJECTIVE_FONT, scale_gametype); + + auto text_width_mapname = game::UI_TextWidth(mapname_ui, 0, font_mapname, scale_mapname); + auto text_width_gametype = game::UI_TextWidth(gametype_ui, 0, font_gametype, scale_gametype); + + game::UI_DrawText(placement, mapname_ui, std::numeric_limits::max(), font_mapname, (640.0f - (float)text_width_mapname) * 0.5f, 89.0f, + 0, 0, scale_mapname, game::colorWhite, game::FONT_STYLE_SHADOW); + + game::UI_DrawText(placement, gametype_ui, std::numeric_limits::max(), font_gametype, (640.0f - (float)text_width_gametype) * 0.5f, 89.0f + 8.0f + font_mapname->pixelHeight * scale_mapname, + 0, 0, scale_gametype, game::colorWhite, game::FONT_STYLE_SHADOW); + } + + game::uiClientState_t cstate{}; + game::CL_GetClientState(0, &cstate); + + bool displayConnectionInfo = true; + if (!_stricmp(cstate.servername, "localhost")) + { + displayConnectionInfo = false; + } + if (game::LoadBar_GetLoadedFraction() >= 1.0f) + { + displayConnectionInfo = true; + } + + if (displayConnectionInfo) + { + const char* s = nullptr; + switch (cstate.connState) + { + case game::CA_CONNECTING: + s = game::UI_SafeTranslateString("EXE_AWAITINGCONNECTION"); + s = game::UI_ReplaceConversionInt(s, cstate.connectPacketCount); + break; + case game::CA_CHALLENGING: + s = game::UI_SafeTranslateString("EXE_AWAITINGCHALLENGE"); + s = game::UI_ReplaceConversionInt(s, cstate.connectPacketCount); + break; + case game::CA_CONNECTED: + s = game::UI_SafeTranslateString("EXE_AWAITINGGAMESTATE"); + break; + case game::CA_SENDINGSTATS: + s = game::UI_SafeTranslateString("EXE_UPLOADINGSTATS"); + break; + case game::CA_LOADING: + case game::CA_PRIMED: + s = game::UI_SafeTranslateString("EXE_AWAITINGHOST"); + break; + default: + break; + } + + auto scale = 0.25f; + auto* font = game::UI_GetFontHandle(placement, game::FONT_TYPE_TEXT_FONT, scale); + auto width = game::UI_TextWidth(s, 0, font, scale); + + game::UI_DrawText( + placement, + s, + std::numeric_limits::max(), + font, + (640.0f - (float)width) * 0.5f, + 420.0f, + 0, + 0, + scale, + game::colorWhite, + game::FONT_STYLE_SHADOW); + } + + if (!CG_IsShowingProgress_FastFile() && *game::cl_serverLoadingMap && *game::g_waitingForServer) + { + const char* s = nullptr; + const char* dots = ""; + + const auto val = (game::Sys_Milliseconds() / 500) & 3; + switch (val) + { + case 1: + dots = "."; + break; + case 2: + dots = ".."; + break; + case 3: + dots = "..."; + break; + default: + dots = ""; + break; + } + + s = game::UI_SafeTranslateString("CGAME_WAITINGFORSERVERLOAD"); + const char* sa = utils::string::va("%s%s", s, dots); + + auto scale = 0.25f; + auto* font = game::UI_GetFontHandle(placement, game::FONT_TYPE_TEXT_FONT, scale); + auto width = game::UI_TextWidth(sa, 0, font, scale); + + game::UI_DrawText( + placement, + sa, + std::numeric_limits::max(), + font, + (640.0f - (float)width) * 0.5f, + 400.0f, + 0, + 0, + scale, + game::colorWhite, + game::FONT_STYLE_SHADOW); + } + } + + void UI_DrawLoadScreenMaterial() + { + auto* mapname = game::Dvar_FindVar("ui_mapname")->current.string; + auto* loadscreen_name = utils::string::va("loadscreen_%s", mapname); + auto* material = game::Material_RegisterHandle(loadscreen_name); + if (!material || game::DB_IsXAssetDefault(game::ASSET_TYPE_MATERIAL, loadscreen_name)) + { + return; + } + + const auto* placement = game::ScrPlace_GetActivePlacement(); + + game::R_AddCmdDrawStretchPic(0.0f, 0.0f, placement->realViewportSize[0], placement->realViewportSize[1], 0.0f, 0.0f, 1.0f, 1.0f, (float*)game::colorWhite.get(), material, 0); + + auto* vignette_name = "load_vignette"; + auto* vignette = game::Material_RegisterHandle(vignette_name); + if (vignette && !game::DB_IsXAssetDefault(game::ASSET_TYPE_MATERIAL, vignette_name)) + { + static const game::vec4_t colorBlack{ 0.0f, 0.0f, 0.0f, 1.0f }; + game::R_AddCmdDrawStretchPic(0.0f, 0.0f, placement->realViewportSize[0], placement->realViewportSize[1], 0.0f, 0.0f, 1.0f, 1.0f, (float*)&colorBlack, vignette, 0); + } + } + + void UI_DrawLoadBarState() + { + const auto* placement = game::ScrPlace_GetActivePlacement(); + + static const game::vec4_t color{ 0.2f, 0.2f, 0.2f, 1.0f }; + + game::UI_FillRect(placement, 192.0f, 430.0f, 256.0f, 2.0f, 0, 0, &color); + game::UI_DrawLoadBar(placement, 192.0f, 430.0f, 256.0f, 2.0f, 0, 0, game::colorWhite, *game::whiteMaterial); + } + + void UI_DrawTempConnectScreen([[maybe_unused]] int localClientNum) + { + UI_DrawLoadScreenMaterial(); + UI_DrawLoadScreenInfo(); + UI_DrawLoadBarState(); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_dedi()) + { + return; + } + + //utils::hook::jump(0x1409BC7D7, UI_DrawTempConnectScreen); + utils::hook::call(0x1409BC84C, UI_DrawTempConnectScreen); + + // Allows loading of _load fastfiles + dvars::override::register_bool("frontEndUseLoadFastfiles", true, game::DVAR_FLAG_NONE); + } + }; +} + +REGISTER_COMPONENT(loadscreen::component) \ No newline at end of file diff --git a/src/client/component/party.cpp b/src/client/component/party.cpp index aa1449fb..1d1452e4 100644 --- a/src/client/component/party.cpp +++ b/src/client/component/party.cpp @@ -369,16 +369,18 @@ namespace party return; } + command::execute(utils::string::va("seta ui_mapname %s", mapname.data()), true); + auto* gametype = game::Dvar_FindVar("g_gametype"); if (gametype && gametype->current.string) { - command::execute(utils::string::va("ui_gametype %s", gametype->current.string), true); + command::execute(utils::string::va("seta ui_gametype %s", gametype->current.string), true); } auto* hardcore = game::Dvar_FindVar("g_hardcore"); if (hardcore) { - command::execute(utils::string::va("ui_hardcore %s", hardcore->current.enabled), true); + command::execute(utils::string::va("seta ui_hardcore %s", hardcore->current.enabled), true); } perform_game_initialization(); diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index 1f5046cc..b7688247 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -465,6 +465,19 @@ namespace game char __pad0[131112]; netadr_s address; }; + + enum FontType + { + FONT_TYPE_BIG_FONT = 2, + FONT_TYPE_SMALL_FONT = 3, + FONT_TYPE_BOLD_FONT = 4, + FONT_TYPE_CONSOLE_FONT = 5, + FONT_TYPE_OBJECTIVE_FONT = 6, + FONT_TYPE_TEXT_FONT = 7, + FONT_TYPE_EXTRA_BIG_FONT = 8, + FONT_TYPE_HUD_BIG_FONT = 9, + FONT_TYPE_HUD_SMALL_FONT = 10, + }; struct GfxFont { @@ -585,6 +598,15 @@ namespace game vec4_t outlineGlowColor; }; + struct ComGameStartupData + { + int state; + char mapname[64]; + char gameType[64]; + unsigned int loadTime; + bool isServer; + }; + namespace entity { enum connstate_t : std::uint32_t @@ -602,6 +624,14 @@ namespace game CA_MAP_RESTART = 0xA, }; + struct uiClientState_t + { + connstate_t connState; + int connectPacketCount; + char servername[1024]; + char messageString[1024]; + }; + struct clientUIActive_t { bool active; diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 21cb0aa1..5002822a 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -60,6 +60,7 @@ namespace game WEAK symbol CL_MainMP_ConnectAndPreloadMap{ 0x1409AED80 }; + WEAK symbol CL_GetClientState{ 0x1409BFFF0 }; WEAK symbol CL_Keys_RemoveCatcher{ 0x1409A9B00 }; @@ -165,6 +166,8 @@ namespace game WEAK symbol Live_SyncOnlineDataFlags{ 0x140DC5CE0 }; WEAK symbol Live_GetXuid{ 0x140D32A20 }; + WEAK symbol LoadBar_GetLoadedFraction{ 0x1405DE190 }; + WEAK symbol Lobby_GetPartyData{ 0x1409C3E20 }; WEAK symbol Material_RegisterHandle{ 0x140E11CE0 }; @@ -184,12 +187,12 @@ namespace game WEAK symbol R_RegisterFont{ 0x140DFC670 }; WEAK symbol R_TextWidth{ 0x140DFC770 }; - WEAK symbol R_GetFontHeight{ 0x1412727B0 }; + WEAK symbol R_GetFontHeight{ 0x1412727B0 }; WEAK symbol R_Font_GetLegacyFontStyle{ 0x140DFBD00 }; WEAK symbol R_SyncRenderThread{ 0x140E27EE0 }; WEAK symbol R_AddCmdDrawStretchPic{ 0x140E24DC0 }; - WEAK symbol AddBaseDrawTextCmd{ 0x140E23D90 }; #define R_AddCmdDrawText(TXT, MC, F, X, Y, XS, YS, R, C, S) \ @@ -243,6 +246,7 @@ namespace game WEAK symbol Scr_AllocGlobalString{ 0x140C03C70 }; WEAK symbol ScrPlace_GetViewPlacement{ 0x1409E4090 }; + WEAK symbol ScrPlace_GetActivePlacement{ 0x1409E4060 }; WEAK symbol StringTable_Lookup{ 0x140CE7950 }; WEAK symbol StringTable_GetColumnValueForRow{ 0x140CE78E0 }; @@ -283,6 +287,15 @@ namespace game WEAK symbol UI_GetGameTypeDisplayName{ 0x140CC61C0 }; WEAK symbol UI_RunMenuScript{ 0x140CC9710 }; WEAK symbol UI_SafeTranslateString{ 0x140CC9790 }; + WEAK symbol UI_ReplaceConversionInt{ 0x140CC91A0 }; + WEAK symbol UI_GetFontHandle{ 0x140CD1240 }; + WEAK symbol UI_FillRect{ 0x140CBDE30 }; + WEAK symbol UI_DrawLoadBar{ 0x140CBDC40 }; + WEAK symbol UI_DrawText{ 0x140CC5C00 }; + WEAK symbol UI_TextWidth{ 0x140CC9FA0 }; WEAK symbol XAnimGetLengthMsec{ 0x140D761C0 }; @@ -365,6 +378,12 @@ namespace game WEAK symbol g_HitLocNames{ 0x14196AAF0 }; + WEAK symbol cl_serverLoadingMap{ 0x141FE5D74 }; + WEAK symbol g_waitingForServer{ 0x14523ED91 }; + + WEAK symbol whiteMaterial{ 0x141FE5ED0 }; + WEAK symbol colorWhite{ 0x141524800 }; + namespace hks { WEAK symbol lua_state{ 0x144FC35F0 };