h1-mod/src/client/component/fps.cpp

212 lines
5.3 KiB
C++
Raw Normal View History

2022-02-05 23:20:45 -05:00
#include <std_include.hpp>
#include "loader/component_loader.hpp"
2022-03-05 10:38:34 -05:00
#include "fps.hpp"
2022-02-05 23:20:45 -05:00
#include "game/game.hpp"
#include "game/dvars.hpp"
2022-05-20 15:11:58 -04:00
#include "dvars.hpp"
2022-02-05 23:20:45 -05:00
#include <utils/hook.hpp>
#include <utils/string.hpp>
#include <component/scheduler.hpp>
namespace fps
{
namespace
{
2022-05-25 17:56:10 -04:00
utils::hook::detour sub_5D6810_hook;
2022-02-26 17:03:29 -05:00
game::dvar_t* cg_drawfps;
game::dvar_t* cg_drawping;
2022-02-23 15:23:00 -05:00
float fps_color_good[4] = {0.6f, 1.0f, 0.0f, 1.0f};
float fps_color_ok[4] = {1.0f, 0.7f, 0.3f, 1.0f};
float fps_color_bad[4] = {1.0f, 0.3f, 0.3f, 1.0f};
float ping_color[4] = {1.0f, 1.0f, 1.0f, 0.65f};
2022-02-05 23:20:45 -05:00
struct cg_perf_data
{
std::chrono::time_point<std::chrono::steady_clock> perf_start;
std::int32_t current_ms{};
std::int32_t previous_ms{};
std::int32_t frame_ms{};
std::int32_t history[32]{};
std::int32_t count{};
std::int32_t index{};
std::int32_t instant{};
std::int32_t total{};
float average{};
float variance{};
std::int32_t min{};
std::int32_t max{};
};
2022-02-23 15:23:00 -05:00
cg_perf_data cg_perf{};
2022-02-05 23:20:45 -05:00
void perf_calc_fps(cg_perf_data* data, const std::int32_t value)
{
data->history[data->index % 32] = value;
data->instant = value;
data->min = 0x7FFFFFFF;
data->max = 0;
data->average = 0.0f;
data->variance = 0.0f;
data->total = 0;
for (auto i = 0; i < data->count; ++i)
{
const std::int32_t idx = (data->index - i) % 32;
if (idx < 0)
{
break;
}
data->total += data->history[idx];
if (data->min > data->history[idx])
{
data->min = data->history[idx];
}
if (data->max < data->history[idx])
{
data->max = data->history[idx];
}
}
data->average = static_cast<float>(data->total) / static_cast<float>(data->count);
++data->index;
}
void perf_update()
{
cg_perf.count = 32;
cg_perf.current_ms = static_cast<std::int32_t>(std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() - cg_perf.perf_start).count());
cg_perf.frame_ms = cg_perf.current_ms - cg_perf.previous_ms;
cg_perf.previous_ms = cg_perf.current_ms;
perf_calc_fps(&cg_perf, cg_perf.frame_ms);
}
void cg_draw_fps()
{
2022-02-26 17:03:29 -05:00
if (cg_drawfps->current.integer > 0)
2022-02-05 23:20:45 -05:00
{
2022-03-05 10:38:34 -05:00
const auto fps = fps::get_fps();
2022-02-05 23:20:45 -05:00
2022-02-26 17:03:29 -05:00
const auto font = game::R_RegisterFont("fonts/fira_mono_regular.ttf", 25);
2022-05-20 15:11:58 -04:00
if (font)
{
const auto fps_string = utils::string::va("%i", fps);
2022-02-05 23:20:45 -05:00
2022-05-20 15:11:58 -04:00
const auto x = (game::ScrPlace_GetViewPlacement()->realViewportSize[0] - 15.0f) -
game::R_TextWidth(fps_string, 0x7FFFFFFF, font);
const auto y = font->pixelHeight + 10.f;
2022-02-05 23:20:45 -05:00
2022-05-20 15:11:58 -04:00
const auto fps_color = fps >= 60 ? fps_color_good : (fps >= 30 ? fps_color_ok : fps_color_bad);
game::R_AddCmdDrawText(fps_string, 0x7FFFFFFF, font, x, y, 1.f, 1.f, 0.0f, fps_color, 6);
}
2022-02-05 23:20:45 -05:00
}
}
void cg_draw_ping()
{
2022-03-02 17:50:40 -05:00
if (cg_drawping->current.integer > 0 && game::CL_IsCgameInitialized() && !game::VirtualLobby_Loaded())
2022-02-05 23:20:45 -05:00
{
2022-02-26 17:03:29 -05:00
const auto font = game::R_RegisterFont("fonts/consolefont", 20);
2022-03-05 10:38:34 -05:00
const auto ping_string = utils::string::va("Ping: %i", *game::mp::ping);
2022-02-05 23:20:45 -05:00
const auto x = (game::ScrPlace_GetViewPlacement()->realViewportSize[0] - 375.0f) - game::R_TextWidth(
2022-02-26 17:03:29 -05:00
ping_string, 0x7FFFFFFF, font);
2022-02-05 23:20:45 -05:00
2022-02-26 17:03:29 -05:00
const auto y = font->pixelHeight + 15.f;
game::R_AddCmdDrawText(ping_string, 0x7FFFFFFF, font, x, y, 1.f, 1.f, 0.0f, ping_color, 6);
2022-02-05 23:20:45 -05:00
}
}
2022-05-20 15:11:58 -04:00
game::dvar_t* cg_draw_fps_register_stub()
2022-02-05 23:20:45 -05:00
{
2022-03-12 18:56:15 -05:00
cg_drawfps = dvars::register_int("cg_drawFps", 0, 0, 2, game::DVAR_FLAG_SAVED, "Draw frames per second");
2022-02-26 17:03:29 -05:00
return cg_drawfps;
2022-02-05 23:20:45 -05:00
}
2022-05-25 17:56:10 -04:00
void sub_5D6810_stub()
{
perf_update();
sub_5D6810_hook.invoke<void>();
}
2022-02-05 23:20:45 -05:00
}
2022-03-05 10:38:34 -05:00
int get_fps()
{
return static_cast<std::int32_t>(static_cast<float>(1000.0f / static_cast<float>(cg_perf.
average))
+ 9.313225746154785e-10);
}
2022-02-05 23:20:45 -05:00
class component final : public component_interface
{
public:
void post_unpack() override
{
if (game::environment::is_dedi())
{
return;
}
// fps setup
cg_perf.perf_start = std::chrono::high_resolution_clock::now();
2022-05-25 17:56:10 -04:00
if (game::environment::is_mp())
2022-05-20 15:11:58 -04:00
{
2022-05-25 17:56:10 -04:00
utils::hook::jump(SELECT_VALUE(0, 0x343847_b), utils::hook::assemble([](utils::hook::assembler& a)
{
a.pushad64();
a.call_aligned(perf_update);
a.popad64();
a.call(0x702250_b);
a.mov(edx, 3);
a.xor_(ecx, ecx);
a.jmp(0x343853_b);
}), true);
// Don't register cg_drawfps
utils::hook::nop(0x31D74F_b, 0x1C);
utils::hook::nop(0x31D76F_b, 0x7);
}
else
{
sub_5D6810_hook.create(0x5D6810_b, sub_5D6810_stub);
// Don't register cg_drawfps
utils::hook::nop(0x15C97D_b, 0x20);
utils::hook::nop(0x15C9A1_b, 0x7);
}
2022-02-05 23:20:45 -05:00
scheduler::loop(cg_draw_fps, scheduler::pipeline::renderer);
2022-02-26 17:03:29 -05:00
2022-05-20 15:11:58 -04:00
cg_drawfps = dvars::register_int("cg_drawFps", 0, 0, 2, game::DVAR_FLAG_SAVED, "Draw frames per second");
2022-02-26 17:03:29 -05:00
2022-02-05 23:20:45 -05:00
if (game::environment::is_mp())
{
2022-02-05 23:48:17 -05:00
// fix ping value
2022-05-20 15:11:58 -04:00
utils::hook::nop(0x342C6C_b, 2);
2022-02-05 23:48:17 -05:00
2022-03-12 18:56:15 -05:00
cg_drawping = dvars::register_int("cg_drawPing", 0, 0, 1, game::DVAR_FLAG_SAVED, "Choose to draw ping");
2022-02-05 23:48:17 -05:00
2022-02-05 23:20:45 -05:00
scheduler::loop(cg_draw_ping, scheduler::pipeline::renderer);
}
2022-03-05 10:38:34 -05:00
2022-03-12 18:56:15 -05:00
dvars::register_bool("cg_infobar_fps", false, game::DVAR_FLAG_SAVED, "Show server latency");
dvars::register_bool("cg_infobar_ping", false, game::DVAR_FLAG_SAVED, "Show FPS counter");
2022-02-05 23:20:45 -05:00
}
};
}
2022-05-20 15:11:58 -04:00
REGISTER_COMPONENT(fps::component)