diff --git a/data/ui_scripts/hud_info/__init__.lua b/data/ui_scripts/hud_info/__init__.lua new file mode 100644 index 0000000..07dfbdd --- /dev/null +++ b/data/ui_scripts/hud_info/__init__.lua @@ -0,0 +1,6 @@ +if (game:issingleplayer()) then + return +end + +require("settings") +require("hud") \ No newline at end of file diff --git a/data/ui_scripts/hud_info/hud.lua b/data/ui_scripts/hud_info/hud.lua new file mode 100644 index 0000000..f6a3bb0 --- /dev/null +++ b/data/ui_scripts/hud_info/hud.lua @@ -0,0 +1,163 @@ +local mphud = luiglobals.require("LUI.mp_hud.MPHud") +local barheight = 18 +local textheight = 13 +local textoffsety = barheight / 2 - textheight / 2 + +function createinfobar() + local infobar = LUI.UIElement.new({ + left = 180, + top = 5, + height = barheight, + width = 70, + leftAnchor = true, + topAnchor = true + }) + + infobar:registerAnimationState("hud_on", { + alpha = 1 + }) + + infobar:registerAnimationState("hud_off", { + alpha = 0 + }) + + return infobar +end + +function populateinfobar(infobar) + elementoffset = 0 + + if (Engine.GetDvarBool("cg_infobar_fps")) then + infobar:addElement(infoelement({ + label = "FPS: ", + getvalue = function() + return game:getfps() + end, + width = 70, + interval = 100 + })) + end + + if (Engine.GetDvarBool("cg_infobar_ping")) then + infobar:addElement(infoelement({ + label = "Latency: ", + getvalue = function() + return game:getping() .. " ms" + end, + width = 115, + interval = 100 + })) + end +end + +function infoelement(data) + local container = LUI.UIElement.new({ + bottomAnchor = true, + leftAnchor = true, + topAnchor = true, + width = data.width, + left = elementoffset + }) + + elementoffset = elementoffset + data.width + 10 + + local background = LUI.UIImage.new({ + bottomAnchor = true, + leftAnchor = true, + topAnchor = true, + rightAnchor = true, + color = { + r = 0.3, + g = 0.3, + b = 0.3, + }, + material = luiglobals.RegisterMaterial("distort_hud_bkgnd_ui_blur") + }) + + local labelfont = luiglobals.RegisterFont("fonts/bodyFontBold", textheight) + + local label = LUI.UIText.new({ + left = 5, + top = textoffsety + 1, + font = labelfont, + height = textheight, + leftAnchor = true, + topAnchor = true, + color = { + r = 0.8, + g = 0.8, + b = 0.8, + } + }) + + label:setText(data.label) + + local _, _, left = luiglobals.GetTextDimensions(data.label, labelfont, textheight) + local value = LUI.UIText.new({ + left = left + 5, + top = textoffsety, + font = luiglobals.RegisterFont("fonts/bodyFont", textheight), + height = textheight + 1, + leftAnchor = true, + topAnchor = true, + color = { + r = 0.6, + g = 0.6, + b = 0.6, + } + }) + + value:addElement(LUI.UITimer.new(data.interval, "update")) + value:setText(data.getvalue()) + value:addEventHandler("update", function() + value:setText(data.getvalue()) + end) + + container:addElement(background) + container:addElement(label) + container:addElement(value) + + return container +end + +local updatehudvisibility = mphud.updateHudVisibility +mphud.updateHudVisibility = function(a1, a2) + updatehudvisibility(a1, a2) + + local root = Engine.GetLuiRoot() + local menus = root:AnyActiveMenusInStack() + local infobar = root.infobar + + if (not infobar) then + return + end + + if (menus) then + infobar:animateToState("hud_off") + else + infobar:animateToState("hud_on") + end +end + +local mphud = LUI.MenuBuilder.m_types_build["mp_hud"] +LUI.MenuBuilder.m_types_build["mp_hud"] = function() + local hud = mphud() + + if (Engine.InFrontend()) then + return hud + end + + local infobar = createinfobar() + local root = Engine.GetLuiRoot() + root.infobar = infobar + populateinfobar(infobar) + + root:registerEventHandler("update_hud_infobar_settings", function() + infobar:removeAllChildren() + populateinfobar(infobar) + end) + + hud.static:addElement(infobar) + + return hud +end \ No newline at end of file diff --git a/data/ui_scripts/hud_info/settings.lua b/data/ui_scripts/hud_info/settings.lua new file mode 100644 index 0000000..7a8e5e7 --- /dev/null +++ b/data/ui_scripts/hud_info/settings.lua @@ -0,0 +1,156 @@ +local pcoptions = luiglobals.require("LUI.PCOptions") + +game:addlocalizedstring("LUA_MENU_FPS", "FPS Counter") +game:addlocalizedstring("LUA_MENU_FPS_DESC", "Show FPS Counter") + +game:addlocalizedstring("LUA_MENU_LATENCY", "Server Latency") +game:addlocalizedstring("LUA_MENU_LATENCY_DESC", "Show server latency") + +pcoptions.VideoOptionsFeeder = function() + local items = { + pcoptions.OptionFactory( + "ui_r_displayMode", + "@LUA_MENU_DISPLAY_MODE", + nil, + { + { + text = "@LUA_MENU_MODE_FULLSCREEN", + value = "fullscreen" + }, + { + text = "@LUA_MENU_MODE_WINDOWED_NO_BORDER", + value = "windowed_no_border" + }, + { + text = "@LUA_MENU_MODE_WINDOWED", + value = "windowed" + } + }, + nil, + true + ), + pcoptions.SliderOptionFactory( + "profileMenuOption_blacklevel", + "@MENU_BRIGHTNESS", + "@MENU_BRIGHTNESS_DESC1", + luiglobals.SliderBounds.PCBrightness.Min, + luiglobals.SliderBounds.PCBrightness.Max, + luiglobals.SliderBounds.PCBrightness.Step, + function(element) + element:processEvent({ + name = "brightness_over", + immediate = true + }) + end, + function(element) + element:processEvent({ + name = "brightness_up", + immediate = true + }) + end, + true, + nil, + "brightness_updated" + ), + pcoptions.OptionFactoryProfileData( + "renderColorBlind", + "profile_toggleRenderColorBlind", + "@LUA_MENU_COLORBLIND_FILTER", + "@LUA_MENU_COLOR_BLIND_DESC", + { + { + text = "@LUA_MENU_ENABLED", + value = true + }, + { + text = "@LUA_MENU_DISABLED", + value = false + } + }, + nil, + false + ) + } + + if Engine.IsMultiplayer() and not Engine.IsZombiesMode() then + table.insert(items, pcoptions.OptionFactory( + "cg_paintballFx", + "@LUA_MENU_PAINTBALL", + "@LUA_MENU_PAINTBALL_DESC", + { + { + text = "@LUA_MENU_ENABLED", + value = true + }, + { + text = "@LUA_MENU_DISABLED", + value = false + } + }, + nil, + false, + false + )) + end + + table.insert(items, pcoptions.OptionFactory( + "cg_infobar_ping", + "@LUA_MENU_LATENCY", + "@LUA_MENU_LATENCY_DESC", + { + { + text = "@LUA_MENU_ENABLED", + value = true + }, + { + text = "@LUA_MENU_DISABLED", + value = false + } + }, + function() + Engine.GetLuiRoot():processEvent({ + name = "update_hud_infobar_settings" + }) + end, + false, + false + )) + + table.insert(items, pcoptions.OptionFactory( + "cg_infobar_fps", + "@LUA_MENU_FPS", + "@LUA_MENU_FPS_DESC", + { + { + text = "@LUA_MENU_ENABLED", + value = true + }, + { + text = "@LUA_MENU_DISABLED", + value = false + } + }, + function() + Engine.GetLuiRoot():processEvent({ + name = "update_hud_infobar_settings" + }) + end, + false, + false + )) + + table.insert(items, { + type = "UIGenericButton", + id = "option_advanced_video", + properties = { + style = luiglobals.GenericButtonSettings.Styles.GlassButton, + button_text = Engine.Localize("@LUA_MENU_ADVANCED_VIDEO"), + desc_text = "", + button_action_func = pcoptions.ButtonMenuAction, + text_align_without_content = LUI.Alignment.Left, + menu = "advanced_video" + } + }) + + return items +end diff --git a/src/client/component/fps.cpp b/src/client/component/fps.cpp index 3772883..9f24a7b 100644 --- a/src/client/component/fps.cpp +++ b/src/client/component/fps.cpp @@ -1,6 +1,9 @@ #include #include "loader/component_loader.hpp" + #include "scheduler.hpp" +#include "fps.hpp" +#include "localized_strings.hpp" #include "game/game.hpp" #include "game/dvars.hpp" @@ -91,11 +94,10 @@ namespace fps void cg_draw_fps() { const auto* draw_fps = game::Dvar_FindVar("cg_drawFPS"); - if (draw_fps && draw_fps->current.integer > 0 /*&& game::CL_IsCgameInitialized()*/) + + if (draw_fps && draw_fps->current.integer > 0) { - const auto fps = static_cast(static_cast(1000.0f / static_cast(cg_perf. - average)) - + 9.313225746154785e-10); + const auto fps = fps::get_fps(); auto* font = game::R_RegisterFont("fonts/consolefont"); if (!font) return; @@ -119,12 +121,10 @@ namespace fps const auto* draw_ping = game::Dvar_FindVar("cg_drawPing"); if (draw_ping && draw_ping->current.integer > 0 && game::CL_IsCgameInitialized()) { - const auto ping = *reinterpret_cast(0x1417E6A84); - auto* font = game::R_RegisterFont("fonts/consolefont"); if (!font) return; - auto* const ping_string = utils::string::va("Ping: %i", ping); + auto* const ping_string = utils::string::va("Ping: %i", *game::mp::ping); const auto scale = 1.0f; @@ -144,6 +144,13 @@ namespace fps } } + int get_fps() + { + return static_cast(static_cast(1000.0f / static_cast(cg_perf. + average)) + + 9.313225746154785e-10); + } + class component final : public component_interface { public: @@ -170,6 +177,9 @@ namespace fps game::Dvar_RegisterInt("cg_drawPing", 0, 0, 1, game::DVAR_FLAG_SAVED, "Choose to draw ping"); scheduler::loop(cg_draw_ping, scheduler::pipeline::renderer); } + + game::Dvar_RegisterBool("cg_infobar_ping", false, game::DVAR_FLAG_SAVED, "Show server latency"); + game::Dvar_RegisterBool("cg_infobar_fps", false, game::DVAR_FLAG_SAVED, "Show FPS counter"); } }; } diff --git a/src/client/component/fps.hpp b/src/client/component/fps.hpp new file mode 100644 index 0000000..74f937d --- /dev/null +++ b/src/client/component/fps.hpp @@ -0,0 +1,6 @@ +#pragma once + +namespace fps +{ + int get_fps(); +} \ No newline at end of file diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 1503aec..2460b21 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -276,6 +276,8 @@ namespace game WEAK symbol gameTime{0, 0x144959C2C}; WEAK symbol serverTime{0, 0x1496C4B00}; + WEAK symbol ping{0, 0x1417E6A84}; + WEAK symbol sv_serverId_value{0, 0x1488A9A60}; WEAK symbol virtualLobby_loaded{0, 0x1417E161D}; diff --git a/src/client/game/ui_scripting/lua/context.cpp b/src/client/game/ui_scripting/lua/context.cpp index d6d05f1..4c175ca 100644 --- a/src/client/game/ui_scripting/lua/context.cpp +++ b/src/client/game/ui_scripting/lua/context.cpp @@ -7,6 +7,8 @@ #include "../../../component/ui_scripting.hpp" #include "../../../component/command.hpp" +#include "../../../component/fps.hpp" +#include "../../../component/localized_strings.hpp" #include "component/game_console.hpp" #include "component/scheduler.hpp" @@ -39,6 +41,32 @@ namespace ui_scripting::lua return scheduler.add(callback, milliseconds, false); }; + game_type["getfps"] = [](const game&) + { + return fps::get_fps(); + }; + + game_type["getping"] = [](const game&) + { + return *::game::mp::ping; + }; + + game_type["issingleplayer"] = [](const game&) + { + return ::game::environment::is_sp(); + }; + + game_type["ismultiplayer"] = [](const game&) + { + return ::game::environment::is_mp(); + }; + + game_type["addlocalizedstring"] = [](const game&, const std::string& string, + const std::string& value) + { + localized_strings::override(string, value); + }; + auto userdata_type = state.new_usertype("userdata_"); userdata_type["new"] = sol::property(