Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add multi_hitsounds #158

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions common/include/common/config/GameConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ struct GameConfig
CfgVar<bool> glares = true;
CfgVar<bool> show_enemy_bullets = true;
CfgVar<bool> linear_pitch = false;
CfgVar<bool> multi_hitsounds = true;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add some description in README about those modes because i'm not sure how this feature works currently

CfgVar<bool> multi_hitsounds_legacy_mode = true;

bool load();
void save();
Expand Down
2 changes: 2 additions & 0 deletions common/src/config/GameConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ bool GameConfig::visit_vars(T&& visitor, bool is_save)
result &= visitor(dash_faction_key, "Big HUD", big_hud);
result &= visitor(dash_faction_key, "Reticle Scale", reticle_scale);
result &= visitor(dash_faction_key, "Mesh Static Lighting", mesh_static_lighting);
result &= visitor(dash_faction_key, "multi_hitsounds", multi_hitsounds);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keep registry key naming convention

result &= visitor(dash_faction_key, "multi_hitsounds_legacy_mode", multi_hitsounds_legacy_mode);
return result;
}

Expand Down
2 changes: 2 additions & 0 deletions game_patch/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ set(SRCS
multi/multi.cpp
multi/kill.cpp
multi/network.cpp
multi/custom_packets.cpp
multi/custom_packets.h
multi/level_download.cpp
multi/server.h
multi/server.cpp
Expand Down
1 change: 1 addition & 0 deletions game_patch/misc/player.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ struct PlayerAdditionalData
{
bool is_browser = false;
bool is_muted = false;
uint8_t multi_hitsounds = 0;
int last_hitsound_sent_ms = 0;
std::map<std::string, PlayerNetGameSaveData> saves;
rf::Vector3 last_teleport_pos;
Expand Down
119 changes: 119 additions & 0 deletions game_patch/multi/custom_packets.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
#include <array>
#include <xlog/xlog.h>
#include "../main/main.h"
#include "../rf/multi.h"
#include "../rf/sound/sound.h"
#include "../rf/player/player.h"
#include "../misc/player.h"
#include "../multi/multi.h"
#include "../purefaction/pf.h"
#include "custom_packets.h"

namespace custom_packets {
// Do not drop hitsound packets to save bandwidth, since hitsound packets are
// significantly smaller than sound packets.
void send_hitsound_packet(rf::Player* player){
if (!rf::is_server) {
return;
}

rf_packet_header packet{};
packet.type = static_cast<uint8_t>(custom_packet_type::hitsound);
packet.size = 0;

rf::multi_io_send(player, &packet, sizeof(packet));
}

void process_hitsound_packet(void* data, int len, const rf::NetAddr& addr, rf::Player* player) {
if (rf::is_server) {
return;
}

rf_packet_header packet;
if (len < sizeof(packet)) {
xlog::trace("Cannot process a hitsound packet; invalid length");
return;
}

float invalid = std::numeric_limits<float>::quiet_NaN();
rf::Vector3 position{invalid, invalid, invalid};
rf::snd_play_3d(29, position, 1.0f, rf::zero_vector, 0);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently sound id is configurable on the server. I'd like it to stay this way.

}

void send_configure_hitsounds_packet(rf::Player* player) {
if (rf::is_server) {
return;
}

configure_hitsounds_packet packet{};
packet.hdr.type = static_cast<uint8_t>(custom_packet_type::configure_hitsounds);
packet.hdr.size = sizeof(packet) - sizeof(packet.hdr);

if (g_game_config.multi_hitsounds_legacy_mode) {
packet.level = 0;
}
else if (g_game_config.multi_hitsounds) {
packet.level = 2;
}
else {
packet.level = 1;
}

rf::multi_io_send_reliable(player, &packet, sizeof(packet), 0);
}

void process_configure_hitsounds_packet(void* data, int len, const rf::NetAddr& addr, rf::Player* player) {
if (!rf::is_server) {
return;
}

configure_hitsounds_packet packet;
if (len < sizeof(packet)) {
xlog::trace("Cannot process a configure_hitsounds packet; invalid length");
return;
}

std::memcpy(&packet, data, sizeof(packet));

if (packet.level > 2) {
xlog::trace("Cannot process a configure_hitsounds packet; invalid level");
return;
}

PlayerAdditionalData& pdata = get_player_additional_data(player);
pdata.multi_hitsounds = packet.level;

constexpr int NETPLAYER_STATE_IN_GAME = 2;
if (player->net_data->state == NETPLAYER_STATE_IN_GAME) {
static const std::array<std::string, 3> messages {
"\xA6 Hitsounds are set to legacy mode",
"\xA6 Hitsounds are disabled",
"\xA6 Hitsounds are enabled",
};
send_chat_line_packet(messages[pdata.multi_hitsounds].c_str(), player);
}
}

bool process_packet(void* data, int len, const rf::NetAddr& addr, rf::Player* player) {
rf_packet_header header;
if (len < static_cast<int>(sizeof(header))) {
xlog::trace("Cannot process a custom packet; invalid length");
return false;
}

std::memcpy(&header, data, sizeof(header));

switch (static_cast<custom_packet_type>(header.type)) {
case custom_packet_type::configure_hitsounds: {
process_configure_hitsounds_packet(data, len, addr, player);
return true;
}
case custom_packet_type::hitsound: {
process_hitsound_packet(data, len, addr, player);
return true;
}
}

return false;
}
}
26 changes: 26 additions & 0 deletions game_patch/multi/custom_packets.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#pragma once

#include "../purefaction/pf_packets.h"

namespace rf {
struct NetAddr;
struct Player;
}

namespace custom_packets {
enum class custom_packet_type : uint8_t {
configure_hitsounds = 200,
hitsound = 201,
};

struct configure_hitsounds_packet {
rf_packet_header hdr;
uint8_t level;
};

void send_hitsound_packet(rf::Player* player);
void process_hitsound_packet(void* data, int len, const rf::NetAddr& addr, rf::Player* player);
void send_configure_hitsounds_packet(rf::Player* player);
void process_configure_hitsounds_packet(void* data, int len, const rf::NetAddr& addr, rf::Player* player);
bool process_packet(void* data, int len, const rf::NetAddr& addr, rf::Player* player);
}
54 changes: 46 additions & 8 deletions game_patch/multi/network.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "multi.h"
#include "server.h"
#include "server_internal.h"
#include "custom_packets.h"
#include "../main/main.h"
#include "../rf/multi.h"
#include "../rf/misc.h"
Expand Down Expand Up @@ -740,6 +741,7 @@ CodeInjection process_join_accept_send_game_info_req_injection{
rf::NetAddr* server_addr = regs.edi;
xlog::trace("Sending game_info_req to %x:%d", server_addr->ip_addr, server_addr->port);
rf::send_game_info_req_packet(*server_addr);
custom_packets::send_configure_hitsounds_packet(rf::local_player);
},
};

Expand Down Expand Up @@ -1025,13 +1027,6 @@ void __fastcall multi_io_stats_add_new(void *this_, int edx, int size, bool is_s

FunHook<void __fastcall(void*, int, int, bool, int)> multi_io_stats_add_hook{0x0047CAC0, multi_io_stats_add_new};

static void process_custom_packet(void* data, int len, const rf::NetAddr& addr, rf::Player* player)
{
#if MASK_AS_PF
pf_process_packet(data, len, addr, player);
#endif
}

CodeInjection multi_io_process_packets_injection{
0x0047918D,
[](auto& regs) {
Expand All @@ -1043,7 +1038,13 @@ CodeInjection multi_io_process_packets_injection{
int len = regs.edi;
auto& addr = *addr_as_ref<rf::NetAddr*>(stack_frame + 0xC);
auto player = addr_as_ref<rf::Player*>(stack_frame + 0x10);
process_custom_packet(data + offset, len, addr, player);
#ifdef HAS_PF
if (!pf_process_packet(data, len, addr, player)) {
custom_packets::process_packet(data + offset, len, addr, player);
}
#else
custom_packets::process_packet(data + offset, len, addr, player);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would be better if this could be not repeated - maybe use something like bool processed = false; if PF: processed = ...

#endif
regs.eip = 0x00479194;
}
},
Expand Down Expand Up @@ -1082,8 +1083,45 @@ CallHook<int()> game_info_num_players_hook{
},
};

ConsoleCommand2 multi_hitsounds_cmd{
"multi_hitsounds",
[] (std::optional<std::string> arg) {
if (!rf::is_server) {
if (g_game_config.multi_hitsounds_legacy_mode) {
rf::console::printf("You need to disable multi_hitsounds_legacy_mode");
return;
}
if (arg.value_or("") != "?") {
g_game_config.multi_hitsounds = !g_game_config.multi_hitsounds;
g_game_config.save();
custom_packets::send_configure_hitsounds_packet(rf::local_player);
}
rf::console::printf("multi_hitsounds is %s", g_game_config.multi_hitsounds ? "enabled" : "disabled");
}
},
"Toggle hitsounds; applies to compatible servers",
};

ConsoleCommand2 multi_hitsounds_legacy_mode_cmd{
"multi_hitsounds_legacy_mode",
[] (std::optional<std::string> arg) {
if (!rf::is_server) {
if (arg.value_or("") != "?") {
g_game_config.multi_hitsounds_legacy_mode = !g_game_config.multi_hitsounds_legacy_mode;
g_game_config.save();
custom_packets::send_configure_hitsounds_packet(rf::local_player);
}
rf::console::printf("multi_hitsounds_legacy_mode is %s", g_game_config.multi_hitsounds_legacy_mode ? "enabled" : "disabled");
}
},
"Toggle legacy mode for hitsounds; applies to compatible servers",
};

void network_init()
{
multi_hitsounds_cmd.register_cmd();
multi_hitsounds_legacy_mode_cmd.register_cmd();

// Improve simultaneous ping
rf::simultaneous_ping = 32;

Expand Down
9 changes: 8 additions & 1 deletion game_patch/multi/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "server.h"
#include "server_internal.h"
#include "multi.h"
#include "custom_packets.h"
#include "../os/console.h"
#include "../misc/player.h"
#include "../main/main.h"
Expand Down Expand Up @@ -383,7 +384,13 @@ FunHook<float(rf::Entity*, float, int, int, int)> entity_damage_hook{
auto* damaged_player_stats = static_cast<PlayerStatsNew*>(damaged_player->stats);
damaged_player_stats->add_damage_received(real_damage);

if (g_additional_server_config.hit_sounds.enabled) {
auto& pdata = get_player_additional_data(killer_player);
if (pdata.multi_hitsounds) {
if (pdata.multi_hitsounds == 2) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

enum > magic constant

custom_packets::send_hitsound_packet(killer_player);
}
}
else if (g_additional_server_config.hit_sounds.enabled) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want more configuration for the server owners so they can force hitsounds disabled, no matter what the client configured.
3 server-side modes: enable, disable, force disabled (naming suggestion, can be changed)
3 client-side modes: auto (use server setting), enable (if not forced disabled on the server), disable

send_hit_sound_packet(killer_player);
}
}
Expand Down