From c8c15e05e34f2c6b955de60d45a2a572907b9c6b Mon Sep 17 00:00:00 2001 From: is-this-c <87069698+is-this-c@users.noreply.github.com> Date: Sun, 6 Oct 2024 15:30:02 +1300 Subject: [PATCH 1/8] Improve PF packet logic --- docs/CHANGELOG.md | 1 + game_patch/misc/player.h | 3 +++ game_patch/multi/multi.h | 2 ++ game_patch/multi/network.cpp | 2 +- game_patch/purefaction/pf.cpp | 32 +++++++++++++++++++++-------- game_patch/purefaction/pf_packets.h | 1 + 6 files changed, 32 insertions(+), 9 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 20828c6c..3d4c8fea 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -52,6 +52,7 @@ Contributions: - [@is-this-c](https://github.com/is-this-c) - Support `©` in TrueType fonts + - Improve PF packet logic Version 1.8.0 (released 2022-09-17) ----------------------------------- diff --git a/game_patch/misc/player.h b/game_patch/misc/player.h index 829f1f12..cc92b770 100644 --- a/game_patch/misc/player.h +++ b/game_patch/misc/player.h @@ -1,10 +1,12 @@ #include #include +#include #include #include #include "../rf/math/vector.h" #include "../rf/math/matrix.h" #include "../rf/os/timestamp.h" +#include "../purefaction/pf_packets.h" // Forward declarations namespace rf @@ -20,6 +22,7 @@ struct PlayerNetGameSaveData struct PlayerAdditionalData { + std::optional received_ac_status{}; bool is_browser = false; bool is_muted = false; int last_hitsound_sent_ms = 0; diff --git a/game_patch/multi/multi.h b/game_patch/multi/multi.h index 035790fa..e22a0a45 100644 --- a/game_patch/multi/multi.h +++ b/game_patch/multi/multi.h @@ -13,6 +13,7 @@ struct PlayerStatsNew : rf::PlayerLevelStats float num_shots_fired; float damage_received; float damage_given; + std::optional received_accuracy{}; void inc_kills() { @@ -67,6 +68,7 @@ struct PlayerStatsNew : rf::PlayerLevelStats max_streak = 0; damage_received = 0; damage_given = 0; + received_accuracy.reset(); } }; diff --git a/game_patch/multi/network.cpp b/game_patch/multi/network.cpp index 73bfe00a..061bb10d 100644 --- a/game_patch/multi/network.cpp +++ b/game_patch/multi/network.cpp @@ -1029,7 +1029,7 @@ CodeInjection multi_io_process_packets_injection{ 0x0047918D, [](auto& regs) { int packet_type = regs.esi; - if (packet_type > 0x37) { + if (packet_type > 0x37 || packet_type == static_cast(pf_packet_type::player_stats)) { auto stack_frame = regs.esp + 0x1C; std::byte* data = regs.ecx; int offset = regs.ebp; diff --git a/game_patch/purefaction/pf.cpp b/game_patch/purefaction/pf.cpp index 143e2b9c..1b50d0d9 100644 --- a/game_patch/purefaction/pf.cpp +++ b/game_patch/purefaction/pf.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -9,6 +10,7 @@ #include "pf.h" #include "pf_packets.h" #include "pf_ac.h" +#include "../misc/player.h" void pf_send_reliable_packet(rf::Player* player, const void* data, int len) { @@ -35,7 +37,8 @@ static void send_pf_announce_player_packet(rf::Player* player, pf_pure_status pu announce_packet.hdr.size = sizeof(announce_packet) - sizeof(announce_packet.hdr); announce_packet.version = pf_announce_player_packet_version; announce_packet.player_id = player->net_data->player_id; - announce_packet.is_pure = static_cast(pure_status); + announce_packet.is_pure = static_cast(get_player_additional_data(player).is_browser + ? pf_pure_status::rfsb : pure_status); auto player_list = SinglyLinkedList(rf::player_list); for (auto& other_player : player_list) { @@ -64,17 +67,25 @@ static void process_pf_player_announce_packet(const void* data, size_t len, [[ m } xlog::trace("PF player_announce packet: player {} is_pure {}", announce_packet.player_id, announce_packet.is_pure); + + if (rf::Player* player = rf::multi_find_player_by_id(announce_packet.player_id); player + && announce_packet.is_pure <= static_cast(pf_pure_status::_last_variant)) { + get_player_additional_data(player).received_ac_status + = std::optional{static_cast(announce_packet.is_pure)}; + } if (announce_packet.player_id == rf::local_player->net_data->player_id) { - static const char* pf_verification_status_names[] = { "none", "blue", "gold", "red" }; - const auto* pf_verification_status = + static constinit const std::array pf_verification_status_names{ + {"none", "blue", "gold", "fail", "old_blue", "rfsb"} + }; + const std::string_view pf_verification_status = announce_packet.is_pure < std::size(pf_verification_status_names) ? pf_verification_status_names[announce_packet.is_pure] : "unknown"; xlog::info("PF Verification Status: {} ({})", pf_verification_status, announce_packet.is_pure); } } -static void send_pf_player_stats_packet(rf::Player* player) +void send_pf_player_stats_packet(rf::Player* player) { // Send: server -> client assert(rf::is_server); @@ -92,10 +103,11 @@ static void send_pf_player_stats_packet(rf::Player* player) auto& player_stats = *static_cast(current_player.stats); pf_player_stats_packet::player_stats out_stats; out_stats.player_id = current_player.net_data->player_id; - out_stats.is_pure = static_cast(pf_ac_get_pure_status(¤t_player)); - out_stats.accuracy = 0; - out_stats.streak_max = 0; - out_stats.streak_current = 0; + out_stats.is_pure = static_cast(get_player_additional_data(¤t_player).is_browser + ? pf_pure_status::rfsb : pf_ac_get_pure_status(¤t_player)); + out_stats.accuracy = static_cast(player_stats.calc_accuracy() * 100.f); + out_stats.streak_max = player_stats.max_streak; + out_stats.streak_current = player_stats.current_streak; out_stats.kills = player_stats.num_kills; out_stats.deaths = player_stats.num_deaths; out_stats.team_kills = 0; @@ -157,6 +169,10 @@ static void process_pf_player_stats_packet(const void* data, size_t len, [[ mayb auto* player = rf::multi_find_player_by_id(in_stats.player_id); if (player) { auto& stats = *static_cast(player->stats); + // Ignore `is_pure`. Why is it in `player_stats`? + stats.received_accuracy = std::optional{in_stats.accuracy}; + stats.max_streak = in_stats.streak_max; + stats.current_streak = in_stats.streak_current; stats.num_kills = in_stats.kills; stats.num_deaths = in_stats.deaths; } diff --git a/game_patch/purefaction/pf_packets.h b/game_patch/purefaction/pf_packets.h index 2da2f5f7..096c5237 100755 --- a/game_patch/purefaction/pf_packets.h +++ b/game_patch/purefaction/pf_packets.h @@ -24,6 +24,7 @@ enum class pf_pure_status : uint8_t fail = 3, old_pure = 4, rfsb = 5, + _last_variant = rfsb, }; struct rf_packet_header From a4e6dfb60f7eb340c156d732de4d7476a0dc2ce6 Mon Sep 17 00:00:00 2001 From: is-this-c <87069698+is-this-c@users.noreply.github.com> Date: Tue, 26 Nov 2024 05:05:59 +1300 Subject: [PATCH 2/8] Update pf.cpp --- game_patch/purefaction/pf.cpp | 37 +++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/game_patch/purefaction/pf.cpp b/game_patch/purefaction/pf.cpp index 1b50d0d9..68c38022 100644 --- a/game_patch/purefaction/pf.cpp +++ b/game_patch/purefaction/pf.cpp @@ -37,8 +37,11 @@ static void send_pf_announce_player_packet(rf::Player* player, pf_pure_status pu announce_packet.hdr.size = sizeof(announce_packet) - sizeof(announce_packet.hdr); announce_packet.version = pf_announce_player_packet_version; announce_packet.player_id = player->net_data->player_id; - announce_packet.is_pure = static_cast(get_player_additional_data(player).is_browser - ? pf_pure_status::rfsb : pure_status); + announce_packet.is_pure = static_cast( + get_player_additional_data(player).is_browser + ? pf_pure_status::rfsb + : pure_status + ); auto player_list = SinglyLinkedList(rf::player_list); for (auto& other_player : player_list) { @@ -53,7 +56,7 @@ static void process_pf_player_announce_packet(const void* data, size_t len, [[ m return; } - pf_player_announce_packet announce_packet; + pf_player_announce_packet announce_packet{}; if (len < sizeof(announce_packet)) { xlog::trace("Invalid length in PF player_announce packet"); return; @@ -78,9 +81,10 @@ static void process_pf_player_announce_packet(const void* data, size_t len, [[ m static constinit const std::array pf_verification_status_names{ {"none", "blue", "gold", "fail", "old_blue", "rfsb"} }; - const std::string_view pf_verification_status = - announce_packet.is_pure < std::size(pf_verification_status_names) - ? pf_verification_status_names[announce_packet.is_pure] : "unknown"; + const std::string_view pf_verification_status + = announce_packet.is_pure < std::size(pf_verification_status_names) + ? pf_verification_status_names[announce_packet.is_pure] + : "unknown"; xlog::info("PF Verification Status: {} ({})", pf_verification_status, announce_packet.is_pure); } } @@ -91,7 +95,7 @@ void send_pf_player_stats_packet(rf::Player* player) assert(rf::is_server); std::byte packet_buf[rf::max_packet_size]; - pf_player_stats_packet stats_packet; + pf_player_stats_packet stats_packet{}; stats_packet.hdr.type = static_cast(pf_packet_type::player_stats); stats_packet.hdr.size = sizeof(stats_packet) - sizeof(stats_packet.hdr); stats_packet.version = pf_player_stats_packet_version; @@ -101,10 +105,13 @@ void send_pf_player_stats_packet(rf::Player* player) auto player_list = SinglyLinkedList{rf::player_list}; for (auto& current_player : player_list) { auto& player_stats = *static_cast(current_player.stats); - pf_player_stats_packet::player_stats out_stats; + pf_player_stats_packet::player_stats out_stats{}; out_stats.player_id = current_player.net_data->player_id; - out_stats.is_pure = static_cast(get_player_additional_data(¤t_player).is_browser - ? pf_pure_status::rfsb : pf_ac_get_pure_status(¤t_player)); + out_stats.is_pure = static_cast( + get_player_additional_data(¤t_player).is_browser + ? pf_pure_status::rfsb + : pf_ac_get_pure_status(¤t_player) + ); out_stats.accuracy = static_cast(player_stats.calc_accuracy() * 100.f); out_stats.streak_max = player_stats.max_streak; out_stats.streak_current = player_stats.current_streak; @@ -141,7 +148,7 @@ static void process_pf_player_stats_packet(const void* data, size_t len, [[ mayb return; } - pf_player_stats_packet stats_packet; + pf_player_stats_packet stats_packet{}; if (len < sizeof(stats_packet)) { xlog::trace("Invalid length in PF player_stats packet"); return; @@ -163,7 +170,7 @@ static void process_pf_player_stats_packet(const void* data, size_t len, [[ mayb const std::byte* player_stats_ptr = static_cast(data) + sizeof(stats_packet); for (int i = 0; i < stats_packet.player_count; ++i) { - pf_player_stats_packet::player_stats in_stats; + pf_player_stats_packet::player_stats in_stats{}; std::memcpy(&in_stats, player_stats_ptr, sizeof(in_stats)); player_stats_ptr += sizeof(in_stats); auto* player = rf::multi_find_player_by_id(in_stats.player_id); @@ -191,7 +198,7 @@ static void process_pf_players_request_packet([[ maybe_unused ]] const void* dat return; } - pf_players_packet players_packet; + pf_players_packet players_packet{}; players_packet.hdr.type = static_cast(pf_packet_type::players); players_packet.version = 1; players_packet.show_ip = 0; @@ -220,7 +227,7 @@ bool pf_process_packet(const void* data, int len, const rf::NetAddr& addr, rf::P return true; } - rf_packet_header header; + rf_packet_header header{}; if (len < static_cast(sizeof(header))) { return false; } @@ -247,7 +254,7 @@ bool pf_process_packet(const void* data, int len, const rf::NetAddr& addr, rf::P bool pf_process_raw_unreliable_packet(const void* data, int len, const rf::NetAddr& addr) { - rf_packet_header header; + rf_packet_header header{}; if (len < static_cast(sizeof(header))) { return false; } From ea5d5cf1228c20cb66de4f838e5c63ec85cd6b80 Mon Sep 17 00:00:00 2001 From: is-this-c <87069698+is-this-c@users.noreply.github.com> Date: Tue, 26 Nov 2024 05:12:48 +1300 Subject: [PATCH 3/8] Update pf.cpp --- game_patch/purefaction/pf.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/game_patch/purefaction/pf.cpp b/game_patch/purefaction/pf.cpp index 68c38022..66187e12 100644 --- a/game_patch/purefaction/pf.cpp +++ b/game_patch/purefaction/pf.cpp @@ -38,9 +38,7 @@ static void send_pf_announce_player_packet(rf::Player* player, pf_pure_status pu announce_packet.version = pf_announce_player_packet_version; announce_packet.player_id = player->net_data->player_id; announce_packet.is_pure = static_cast( - get_player_additional_data(player).is_browser - ? pf_pure_status::rfsb - : pure_status + get_player_additional_data(player).is_browser ? pf_pure_status::rfsb : pure_status ); auto player_list = SinglyLinkedList(rf::player_list); @@ -107,10 +105,9 @@ void send_pf_player_stats_packet(rf::Player* player) auto& player_stats = *static_cast(current_player.stats); pf_player_stats_packet::player_stats out_stats{}; out_stats.player_id = current_player.net_data->player_id; + const pf_pure_status pure_status = pf_ac_get_pure_status(¤t_player); out_stats.is_pure = static_cast( - get_player_additional_data(¤t_player).is_browser - ? pf_pure_status::rfsb - : pf_ac_get_pure_status(¤t_player) + get_player_additional_data(¤t_player).is_browser ? pf_pure_status::rfsb : pure_status ); out_stats.accuracy = static_cast(player_stats.calc_accuracy() * 100.f); out_stats.streak_max = player_stats.max_streak; From aa617dc4a158d6f481159b62c4dd1bbce1ddbcf9 Mon Sep 17 00:00:00 2001 From: is-this-c <87069698+is-this-c@users.noreply.github.com> Date: Mon, 2 Dec 2024 17:45:04 +1300 Subject: [PATCH 4/8] Update CHANGELOG.md --- docs/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 791c8c42..1abe1292 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -51,7 +51,7 @@ Version 1.9.0 (not released yet) - Support `©` in TrueType fonts - Improve frag messages - Search in command descriptions in `.` command -- Improve PF packet logic +- Improve support for PF network protocol [@Mystyle-48](https://github.com/Mystyle-48) - Simplify installation detection in setup and launcher From b204bac1e793d5cd5915291ea1e48346e3e647cd Mon Sep 17 00:00:00 2001 From: is-this-c <87069698+is-this-c@users.noreply.github.com> Date: Mon, 2 Dec 2024 17:50:21 +1300 Subject: [PATCH 5/8] Update CHANGELOG.md --- docs/CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 1abe1292..69a44d16 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -49,9 +49,9 @@ Version 1.9.0 (not released yet) [@is-this-c](https://github.com/is-this-c) - Support `©` in TrueType fonts -- Improve frag messages -- Search in command descriptions in `.` command -- Improve support for PF network protocol +- Improve frag message format +- Search command descriptions for `.` command +- Improve PF network protocol compatibility [@Mystyle-48](https://github.com/Mystyle-48) - Simplify installation detection in setup and launcher From b11357c48c26f156155d50426cd7c56a30db23eb Mon Sep 17 00:00:00 2001 From: is-this-c <87069698+is-this-c@users.noreply.github.com> Date: Mon, 2 Dec 2024 18:16:15 +1300 Subject: [PATCH 6/8] Update pf.cpp --- game_patch/purefaction/pf.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/game_patch/purefaction/pf.cpp b/game_patch/purefaction/pf.cpp index 66187e12..29e100cc 100644 --- a/game_patch/purefaction/pf.cpp +++ b/game_patch/purefaction/pf.cpp @@ -173,7 +173,9 @@ static void process_pf_player_stats_packet(const void* data, size_t len, [[ mayb auto* player = rf::multi_find_player_by_id(in_stats.player_id); if (player) { auto& stats = *static_cast(player->stats); - // Ignore `is_pure`. Why is it in `player_stats`? + if (in_stats.is_pure <= static_cast(pf_pure_status::_last_variant)) { + stats.received_ac_status = std::optional{static_cast(in_stats.is_pure)}; + } stats.received_accuracy = std::optional{in_stats.accuracy}; stats.max_streak = in_stats.streak_max; stats.current_streak = in_stats.streak_current; From f1570c5532461c021258bfbcb8d0135c182eea53 Mon Sep 17 00:00:00 2001 From: is-this-c <87069698+is-this-c@users.noreply.github.com> Date: Mon, 2 Dec 2024 18:43:04 +1300 Subject: [PATCH 7/8] Update pf.cpp --- game_patch/purefaction/pf.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/game_patch/purefaction/pf.cpp b/game_patch/purefaction/pf.cpp index 29e100cc..a70a0443 100644 --- a/game_patch/purefaction/pf.cpp +++ b/game_patch/purefaction/pf.cpp @@ -174,7 +174,8 @@ static void process_pf_player_stats_packet(const void* data, size_t len, [[ mayb if (player) { auto& stats = *static_cast(player->stats); if (in_stats.is_pure <= static_cast(pf_pure_status::_last_variant)) { - stats.received_ac_status = std::optional{static_cast(in_stats.is_pure)}; + get_player_additional_data(player).received_ac_status + = std::optional{static_cast(in_stats.is_pure)}; } stats.received_accuracy = std::optional{in_stats.accuracy}; stats.max_streak = in_stats.streak_max; From 8bf8d7b59f80f894e396e5c6e8d263444df606c4 Mon Sep 17 00:00:00 2001 From: is-this-c <87069698+is-this-c@users.noreply.github.com> Date: Mon, 2 Dec 2024 18:43:45 +1300 Subject: [PATCH 8/8] Update CHANGELOG.md --- docs/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 69a44d16..3dbc8119 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -50,7 +50,7 @@ Version 1.9.0 (not released yet) [@is-this-c](https://github.com/is-this-c) - Support `©` in TrueType fonts - Improve frag message format -- Search command descriptions for `.` command +- Search command descriptions in `.` command - Improve PF network protocol compatibility [@Mystyle-48](https://github.com/Mystyle-48)