Make fps capping accurate

This commit is contained in:
fed 2023-10-09 18:14:43 +02:00
parent 34b7170542
commit fe6b3c763f
No known key found for this signature in database
GPG Key ID: 1D2C630F04722996
3 changed files with 88 additions and 59 deletions

View File

@ -11,27 +11,27 @@
#include <utils/hook.hpp> #include <utils/hook.hpp>
#define fps_font game::R_RegisterFont("fonts/fira_mono_regular.ttf", 25) #define fps_font game::R_RegisterFont("fonts/fira_mono_regular.ttf", 25)
#define speed_font game::R_RegisterFont("fonts/fira_mono_regular.ttf", 50) #define speed_font game::R_RegisterFont("fonts/bank.ttf", 70)
#define material_white game::Material_RegisterHandle("white") #define material_white game::Material_RegisterHandle("white")
namespace fps namespace fps
{ {
namespace namespace
{ {
game::dvar_t* cg_drawFps; game::dvar_t* cg_draw_fps;
game::dvar_t* cg_drawSpeed; game::dvar_t* cg_draw_speed;
game::dvar_t* cg_speedGraph; game::dvar_t* cg_speed_graph;
game::dvar_t* cg_speedGraphColor; game::dvar_t* cg_speed_graph_color;
game::dvar_t* cg_speedGraphFontColor; game::dvar_t* cg_speed_graph_font_color;
game::dvar_t* cg_speedGraphBackgroundColor; game::dvar_t* cg_speed_graph_background_color;
game::dvar_t* cg_speedGraphX; game::dvar_t* cg_speed_graph_x;
game::dvar_t* cg_speedGraphY; game::dvar_t* cg_speed_graph_y;
game::dvar_t* cg_speedGraphWidth; game::dvar_t* cg_speed_graph_width;
game::dvar_t* cg_speedGraphHeight; game::dvar_t* cg_speed_graph_height;
game::dvar_t* cg_speedGraphIncludeZAxis; game::dvar_t* cg_speed_graph_include_zaxis;
game::dvar_t* cg_drawGameTime; game::dvar_t* cg_draw_game_time;
float fps_color_good[4] = {0.6f, 1.0f, 0.0f, 1.0f}; 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_ok[4] = {1.0f, 0.7f, 0.3f, 1.0f};
@ -46,7 +46,8 @@ namespace fps
std::deque<float> speed_history; std::deque<float> speed_history;
utils::hook::detour sub_7C55D0_hook; utils::hook::detour sub_1407C55D0_hook;
utils::hook::detour com_frame_hook;
struct cg_perf_data struct cg_perf_data
{ {
@ -114,7 +115,7 @@ namespace fps
perf_calc_fps(&cg_perf, cg_perf.frame_ms); perf_calc_fps(&cg_perf, cg_perf.frame_ms);
sub_7C55D0_hook.invoke<void>(); sub_1407C55D0_hook.invoke<void>();
} }
void check_resize() void check_resize()
@ -131,38 +132,42 @@ namespace fps
void draw_line(float x, float y, float width, float height) void draw_line(float x, float y, float width, float height)
{ {
game::R_AddCmdDrawStretchPic(x, y, width, height, 0.0f, 0.0f, 0.0f, 0.0f, game::R_AddCmdDrawStretchPic(x, y, width, height, 0.0f, 0.0f, 0.0f, 0.0f,
cg_speedGraphColor->current.vector, material_white); cg_speed_graph_color->current.vector, material_white);
} }
std::chrono::high_resolution_clock::time_point last_speed_sample; std::chrono::high_resolution_clock::time_point last_speed_sample;
void draw_speed() void draw_speed()
{ {
if (!cg_drawSpeed->current.enabled) if (!cg_draw_speed->current.enabled)
{ {
return; return;
} }
const auto speed = static_cast<float>(sqrt( static auto prev_speed = 0.f;
pow(game::g_clients[0].velocity[0], 2) +
pow(game::g_clients[0].velocity[1], 2) + const auto ps = game::CG_GetPredictedPlayerState(0);
pow(game::g_clients[0].velocity[2], 2) const auto speed = static_cast<float>(std::sqrt(
std::pow(ps->velocity[0], 2) +
std::pow(ps->velocity[1], 2)
)); ));
const auto font = speed_font; const auto font = speed_font;
const auto speed_string = utils::string::va("%i\n", static_cast<int>(speed)); const auto speed_string = utils::string::va("%i", static_cast<int>(speed));
const auto width = game::R_TextWidth(speed_string, 0x7FFFFFFF, font); const auto width = game::R_TextWidth(speed_string, 0x7FFFFFFF, font);
const auto x = (screen_max[0] / 2) - (width / 2); const auto x = (screen_max[0] / 2) - (width / 2);
const auto y = screen_max[1] - 400.f; const auto y = screen_max[1] - 300.f;
const auto color = speed >= 300.f const auto color = speed >= prev_speed
? color_blue ? color_blue
: fps_color_bad; : fps_color_bad;
prev_speed = speed;
game::R_AddCmdDrawText(speed_string, 0x7FFFFFFF, font, x, game::R_AddCmdDrawText(speed_string, 0x7FFFFFFF, font, x,
y, 1.0f, 1.0f, 0.0f, color, 0); y, 1.0f, 1.0f, 0.0f, color, 4);
} }
void draw_box(const float x, const float y, const float w, const float h, float* color) void draw_box(const float x, const float y, const float w, const float h, float* color)
@ -185,7 +190,7 @@ namespace fps
void draw_speed_graph() void draw_speed_graph()
{ {
if (!cg_speedGraph->current.enabled) if (!cg_speed_graph->current.enabled)
{ {
return; return;
} }
@ -193,11 +198,11 @@ namespace fps
const auto speed = static_cast<float>(sqrt( const auto speed = static_cast<float>(sqrt(
pow(game::g_clients[0].velocity[0], 2) + pow(game::g_clients[0].velocity[0], 2) +
pow(game::g_clients[0].velocity[1], 2) + pow(game::g_clients[0].velocity[1], 2) +
(cg_speedGraphIncludeZAxis->current.enabled ? pow(game::g_clients[0].velocity[2], 2) : 0) (cg_speed_graph_include_zaxis->current.enabled ? pow(game::g_clients[0].velocity[2], 2) : 0)
)); ));
const auto base_width = relative(cg_speedGraphWidth->current.integer); const auto base_width = relative(cg_speed_graph_width->current.integer);
const auto base_height = relative(cg_speedGraphHeight->current.integer); const auto base_height = relative(cg_speed_graph_height->current.integer);
const auto max = static_cast<int>(base_width); const auto max = static_cast<int>(base_width);
if (static_cast<int>(speed_history.size()) > max) if (static_cast<int>(speed_history.size()) > max)
@ -221,12 +226,12 @@ namespace fps
} }
} }
const auto base_x = relative(cg_speedGraphX->current.integer); const auto base_x = relative(cg_speed_graph_x->current.integer);
const auto base_y = screen_max[1] - relative(cg_speedGraphY->current.integer); const auto base_y = screen_max[1] - relative(cg_speed_graph_y->current.integer);
const auto width = 1.f; const auto width = 1.f;
draw_box(base_x, base_y - base_height - 4.f, base_width + 5.f, draw_box(base_x, base_y - base_height - 4.f, base_width + 5.f,
base_height + 4.f, cg_speedGraphBackgroundColor->current.vector); base_height + 4.f, cg_speed_graph_background_color->current.vector);
const auto diff = max - static_cast<int>(speed_history.size()); const auto diff = max - static_cast<int>(speed_history.size());
@ -251,12 +256,12 @@ namespace fps
const auto text_y = base_y - (base_height / 2.f) + (font_height / 2.f); const auto text_y = base_y - (base_height / 2.f) + (font_height / 2.f);
game::R_AddCmdDrawText(speed_string, 0x7FFFFFFF, font, text_x, game::R_AddCmdDrawText(speed_string, 0x7FFFFFFF, font, text_x,
text_y, 1.0f, 1.0f, 0.0f, cg_speedGraphFontColor->current.vector, 0); text_y, 1.0f, 1.0f, 0.0f, cg_speed_graph_font_color->current.vector, 0);
} }
void draw_fps() void draw_fps()
{ {
if (cg_drawFps->current.integer < 1) if (cg_draw_fps->current.integer < 1)
{ {
return; return;
} }
@ -275,7 +280,7 @@ namespace fps
void draw_pos() void draw_pos()
{ {
if (cg_drawFps->current.integer < 2) if (cg_draw_fps->current.integer < 2)
{ {
return; return;
} }
@ -294,7 +299,7 @@ namespace fps
void draw_game_time() void draw_game_time()
{ {
if (!cg_drawGameTime->current.enabled) if (!cg_draw_game_time->current.enabled)
{ {
return; return;
} }
@ -313,24 +318,24 @@ namespace fps
const auto text = utils::string::va("%d:%02d.%02d", m, s, ms); const auto text = utils::string::va("%d:%02d.%02d", m, s, ms);
const auto height = relative(24); const auto height = relative(24);
const auto base_width = relative(cg_speedGraphWidth->current.integer); const auto base_width = relative(cg_speed_graph_width->current.integer);
const auto base_height = cg_speedGraph->current.enabled ? relative(cg_speedGraphHeight->current.integer) : 0; const auto base_height = cg_speed_graph->current.enabled ? relative(cg_speed_graph_height->current.integer) : 0;
const auto base_x = relative(cg_speedGraphX->current.integer); const auto base_x = relative(cg_speed_graph_x->current.integer);
const auto base_y = screen_max[1] - relative(cg_speedGraphY->current.integer) - base_height - height const auto base_y = screen_max[1] - relative(cg_speed_graph_y->current.integer) - base_height - height
- (cg_speedGraph->current.enabled ? 2.f : 0.f); - (cg_speed_graph->current.enabled ? 2.f : 0.f);
const auto font_height = relative(20); const auto font_height = relative(20);
const auto font = game::R_RegisterFont("fonts/default.otf", static_cast<int>(font_height)); const auto font = game::R_RegisterFont("fonts/default.otf", static_cast<int>(font_height));
const auto text_width = game::R_TextWidth(text, 0x7FFFFFFF, font); const auto text_width = game::R_TextWidth(text, 0x7FFFFFFF, font);
draw_box(base_x, base_y, base_width + 5.f, draw_box(base_x, base_y, base_width + 5.f,
height, cg_speedGraphBackgroundColor->current.vector); height, cg_speed_graph_background_color->current.vector);
const auto text_y = base_y + (height / 2.f) + ((font_height + relative(5)) / 2.f); const auto text_y = base_y + (height / 2.f) + ((font_height + relative(5)) / 2.f);
game::R_AddCmdDrawText(text, 0x7FFFFFFF, font, base_x + base_width - text_width, game::R_AddCmdDrawText(text, 0x7FFFFFFF, font, base_x + base_width - text_width,
text_y, 1.0f, 1.0f, 0.0f, cg_speedGraphFontColor->current.vector, 0); text_y, 1.0f, 1.0f, 0.0f, cg_speed_graph_font_color->current.vector, 0);
} }
void draw() void draw()
@ -353,6 +358,26 @@ namespace fps
draw_speed_graph(); draw_speed_graph();
draw_game_time(); draw_game_time();
} }
void com_frame_stub()
{
const auto start = std::chrono::high_resolution_clock::now();
com_frame_hook.invoke<void>();
auto max_fps = (*dvars::com_max_fps)->current.integer;
if (max_fps == 0)
{
max_fps = 1000;
}
constexpr auto nano_secs = std::chrono::duration_cast<std::chrono::nanoseconds>(1s);
const auto frame_time = nano_secs / max_fps;
while (std::chrono::high_resolution_clock::now() - start < frame_time)
{
std::this_thread::sleep_for(100ns);
}
}
} }
class component final : public component_interface class component final : public component_interface
@ -362,30 +387,34 @@ namespace fps
{ {
scheduler::loop(draw, scheduler::pipeline::renderer); scheduler::loop(draw, scheduler::pipeline::renderer);
sub_7C55D0_hook.create(0x1407C55D0, perf_update); sub_1407C55D0_hook.create(0x1407C55D0, perf_update);
cg_drawSpeed = dvars::register_bool("cg_drawSpeed", 0, game::DVAR_FLAG_SAVED, "Draw speed"); cg_draw_speed = dvars::register_bool("cg_drawSpeed", 0, game::DVAR_FLAG_SAVED, "Draw speed");
cg_drawFps = dvars::register_int("cg_drawFPS", 0, 0, 4, game::DVAR_FLAG_SAVED, "Draw fps"); cg_draw_fps = dvars::register_int("cg_drawFPS", 0, 0, 4, game::DVAR_FLAG_SAVED, "Draw fps");
cg_speedGraph = dvars::register_bool("cg_speedGraph", 0, game::DVAR_FLAG_SAVED, "Enable speed graph"); cg_speed_graph = dvars::register_bool("cg_speedGraph", 0, game::DVAR_FLAG_SAVED, "Enable speed graph");
cg_speedGraphColor = dvars::register_vec4("cg_speedGraphColor", cg_speed_graph_color = dvars::register_vec4("cg_speedGraphColor",
1.f, 0.f, 0.f, 1.0f, 0.f, 1.f, game::DVAR_FLAG_SAVED, "Speed graph color"); 1.f, 0.f, 0.f, 1.0f, 0.f, 1.f, game::DVAR_FLAG_SAVED, "Speed graph color");
cg_speedGraphFontColor = dvars::register_vec4("cg_speedGraphFontColor", cg_speed_graph_font_color = dvars::register_vec4("cg_speedGraphFontColor",
1.f, 1.f, 1.f, 1.f, 0.f, 1.f, game::DVAR_FLAG_SAVED, "Speed graph font color"); 1.f, 1.f, 1.f, 1.f, 0.f, 1.f, game::DVAR_FLAG_SAVED, "Speed graph font color");
cg_speedGraphBackgroundColor = dvars::register_vec4("cg_speedGraphBackgroundColor", cg_speed_graph_background_color = dvars::register_vec4("cg_speedGraphBackgroundColor",
0.f, 0.f, 0.f, 0.8f, 0.f, 1.f, game::DVAR_FLAG_SAVED, "Speed graph background color"); 0.f, 0.f, 0.f, 0.8f, 0.f, 1.f, game::DVAR_FLAG_SAVED, "Speed graph background color");
cg_speedGraphX = dvars::register_int("cg_speedGraphX", 15, 0, 1000, game::DVAR_FLAG_SAVED, "Speed graph x position"); cg_speed_graph_x = dvars::register_int("cg_speedGraphX", 15, 0, 1000, game::DVAR_FLAG_SAVED, "Speed graph x position");
cg_speedGraphY = dvars::register_int("cg_speedGraphY", 15, 0, 1000, game::DVAR_FLAG_SAVED, "Speed graph y position"); cg_speed_graph_y = dvars::register_int("cg_speedGraphY", 15, 0, 1000, game::DVAR_FLAG_SAVED, "Speed graph y position");
cg_speedGraphWidth = dvars::register_int("cg_speedGraphWidth", 200, 0, 1000, game::DVAR_FLAG_SAVED, "Speed graph width"); cg_speed_graph_width = dvars::register_int("cg_speedGraphWidth", 200, 0, 1000, game::DVAR_FLAG_SAVED, "Speed graph width");
cg_speedGraphHeight = dvars::register_int("cg_speedGraphHeight", 80, 0, 1000, game::DVAR_FLAG_SAVED, "Speed graph height"); cg_speed_graph_height = dvars::register_int("cg_speedGraphHeight", 80, 0, 1000, game::DVAR_FLAG_SAVED, "Speed graph height");
cg_speedGraphIncludeZAxis = dvars::register_bool("cg_speedGraphIncludeZAxis", false, game::DVAR_FLAG_SAVED, cg_speed_graph_include_zaxis = dvars::register_bool("cg_speedGraphIncludeZAxis", false, game::DVAR_FLAG_SAVED,
"Include velocity on the z axis when calculating the speed"); "Include velocity on the z axis when calculating the speed");
cg_drawGameTime = dvars::register_bool("cg_drawGameTime", false, game::DVAR_FLAG_SAVED, "Draw game time"); cg_draw_game_time = dvars::register_bool("cg_drawGameTime", false, game::DVAR_FLAG_SAVED, "Draw game time");
// Make fps capping accurate
utils::hook::nop(0x1405A38B9, 5);
com_frame_hook.create(0x1405A3740, com_frame_stub);
} }
}; };
} }

View File

@ -28,8 +28,6 @@ namespace dvars
game::dvar_t* g_enableElevators = nullptr; game::dvar_t* g_enableElevators = nullptr;
game::dvar_t** cg_draw_2d = reinterpret_cast<game::dvar_t**>(0x141E39EC0);
std::string dvar_get_vector_domain(const int components, const game::dvar_limits& domain) std::string dvar_get_vector_domain(const int components, const game::dvar_limits& domain)
{ {
if (domain.vector.min == -FLT_MAX) if (domain.vector.min == -FLT_MAX)

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "structs.hpp" #include "structs.hpp"
#include "game.hpp"
#include <string> #include <string>
namespace dvars namespace dvars
@ -36,7 +37,8 @@ namespace dvars
extern game::dvar_t* g_enableElevators; extern game::dvar_t* g_enableElevators;
extern game::dvar_t** cg_draw_2d; WEAK game::symbol<game::dvar_t*> com_max_fps{0x14AE2C890};
WEAK game::symbol<game::dvar_t*> cg_draw_2d{0x141E39EC0};
extern std::vector<dvar_info> dvar_list; extern std::vector<dvar_info> dvar_list;