From 711bbf0a2134652c49627288f670822fceac2d4c Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Sun, 12 Mar 2023 00:09:59 -0800 Subject: [PATCH] add player notifications on proxy server --- src/Client.cc | 1 + src/Client.hh | 1 + src/Menu.hh | 29 +++++++++++++++-------------- src/ProxyCommands.cc | 14 ++++++++++++-- src/ProxyServer.cc | 30 ++++++++++++++++++------------ src/ProxyServer.hh | 3 ++- src/ReceiveCommands.cc | 5 +++++ 7 files changed, 54 insertions(+), 29 deletions(-) diff --git a/src/Client.cc b/src/Client.cc index 69ccebcc..efeba819 100644 --- a/src/Client.cc +++ b/src/Client.cc @@ -37,6 +37,7 @@ ClientOptions::ClientOptions() save_files(false), enable_chat_commands(true), enable_chat_filter(true), + enable_player_notifications(false), suppress_remote_login(false), zero_remote_guild_card(false), ep3_infinite_meseta(false), diff --git a/src/Client.hh b/src/Client.hh index 46acf2ad..c21bdbde 100644 --- a/src/Client.hh +++ b/src/Client.hh @@ -39,6 +39,7 @@ struct ClientOptions { bool save_files; bool enable_chat_commands; bool enable_chat_filter; + bool enable_player_notifications; bool suppress_remote_login; bool zero_remote_guild_card; bool ep3_infinite_meseta; diff --git a/src/Menu.hh b/src/Menu.hh index 82702b5b..7e14d261 100644 --- a/src/Menu.hh +++ b/src/Menu.hh @@ -57,20 +57,21 @@ namespace PatchesMenuItemID { } namespace ProxyOptionsMenuItemID { - constexpr uint32_t GO_BACK = 0xAAFFFFAA; - constexpr uint32_t CHAT_COMMANDS = 0xAA0000AA; - constexpr uint32_t CHAT_FILTER = 0xAA1111AA; - constexpr uint32_t INFINITE_HP = 0xAA2222AA; - constexpr uint32_t INFINITE_TP = 0xAA3333AA; - constexpr uint32_t SWITCH_ASSIST = 0xAA4444AA; - constexpr uint32_t BLOCK_EVENTS = 0xAA5555AA; - constexpr uint32_t BLOCK_PATCHES = 0xAA6666AA; - constexpr uint32_t SAVE_FILES = 0xAA7777AA; - constexpr uint32_t RED_NAME = 0xAA8888AA; - constexpr uint32_t BLANK_NAME = 0xAA9999AA; - constexpr uint32_t SUPPRESS_LOGIN = 0xAAAAAAAA; - constexpr uint32_t SKIP_CARD = 0xAABBBBAA; - constexpr uint32_t EP3_INFINITE_MESETA = 0xAACCCCAA; + constexpr uint32_t GO_BACK = 0xAAFFFFAA; + constexpr uint32_t CHAT_COMMANDS = 0xAA0000AA; + constexpr uint32_t CHAT_FILTER = 0xAA1111AA; + constexpr uint32_t PLAYER_NOTIFICATIONS = 0xAA2222AA; + constexpr uint32_t INFINITE_HP = 0xAA3333AA; + constexpr uint32_t INFINITE_TP = 0xAA4444AA; + constexpr uint32_t SWITCH_ASSIST = 0xAA5555AA; + constexpr uint32_t BLOCK_EVENTS = 0xAA6666AA; + constexpr uint32_t BLOCK_PATCHES = 0xAA7777AA; + constexpr uint32_t SAVE_FILES = 0xAA8888AA; + constexpr uint32_t RED_NAME = 0xAA9999AA; + constexpr uint32_t BLANK_NAME = 0xAAAAAAAA; + constexpr uint32_t SUPPRESS_LOGIN = 0xAABBBBAA; + constexpr uint32_t SKIP_CARD = 0xAACCCCAA; + constexpr uint32_t EP3_INFINITE_MESETA = 0xAADDDDAA; } diff --git a/src/ProxyCommands.cc b/src/ProxyCommands.cc index 3cc909f7..3bd593d8 100644 --- a/src/ProxyCommands.cc +++ b/src/ProxyCommands.cc @@ -116,7 +116,9 @@ static HandlerResult S_invalid(shared_ptr, static HandlerResult C_05(shared_ptr, ProxyServer::LinkedSession& session, uint16_t, uint32_t, string&) { - session.disconnect_action = ProxyServer::LinkedSession::DisconnectAction::SHORT_TIMEOUT; + session.disconnect_action = session.version == GameVersion::BB + ? ProxyServer::LinkedSession::DisconnectAction::MEDIUM_TIMEOUT + : ProxyServer::LinkedSession::DisconnectAction::SHORT_TIMEOUT; return HandlerResult::Type::FORWARD; } @@ -1307,14 +1309,18 @@ static HandlerResult S_65_67_68_EB(shared_ptr, if (index >= session.lobby_players.size()) { session.log.warning("Ignoring invalid player index %zu at position %zu", index, x); } else { + string name = encode_sjis(cmd.entries[x].disp.name); + if (session.license && (cmd.entries[x].lobby_data.guild_card == session.remote_guild_card_number)) { cmd.entries[x].lobby_data.guild_card = session.license->serial_number; num_replacements++; modified = true; + } else if (session.options.enable_player_notifications && command != 0x67) { + send_text_message_printf(session.client_channel, "$C6Join: %zu / %" PRIu32 "\n%s", + index, cmd.entries[x].lobby_data.guild_card.load(), name.c_str()); } auto& p = session.lobby_players[index]; p.guild_card_number = cmd.entries[x].lobby_data.guild_card; - string name = encode_sjis(cmd.entries[x].disp.name); p.name = name; p.section_id = cmd.entries[x].disp.section_id; p.char_class = cmd.entries[x].disp.char_class; @@ -1463,6 +1469,10 @@ static HandlerResult S_66_69_E9(shared_ptr, session.log.warning("Lobby leave command references missing position"); } else { auto& p = session.lobby_players[index]; + if (session.options.enable_player_notifications) { + send_text_message_printf(session.client_channel, "$C4Leave: %zu / %" PRIu32 "\n%s", + index, p.guild_card_number, p.name.c_str()); + } p.guild_card_number = 0; p.name.clear(); session.log.info("Removed lobby player (%zu)", index); diff --git a/src/ProxyServer.cc b/src/ProxyServer.cc index 97fa851d..a9b2c0d1 100644 --- a/src/ProxyServer.cc +++ b/src/ProxyServer.cc @@ -35,11 +35,6 @@ using namespace std::placeholders; -static const uint32_t LICENSED_SESSION_TIMEOUT_USECS = 5 * 60 * 1000000; // 5 minutes -static const uint32_t UNLICENSED_SESSION_TIMEOUT_USECS = 10 * 1000000; // 10 seconds - - - ProxyServer::ProxyServer( shared_ptr base, shared_ptr state) @@ -635,7 +630,6 @@ void ProxyServer::LinkedSession::dispatch_on_timeout( void ProxyServer::LinkedSession::on_timeout() { - this->log.info("Session timed out"); this->server->delete_session(this->id); } @@ -672,9 +666,6 @@ void ProxyServer::LinkedSession::on_error(Channel& ch, short events) { session->send_to_game_server("The server has\ndisconnected."); } session->disconnect(); - if (session->disconnect_action == ProxyServer::LinkedSession::DisconnectAction::CLOSE_IMMEDIATELY) { - session->server->delete_session(session->id); - } } } @@ -758,6 +749,22 @@ void ProxyServer::LinkedSession::send_to_game_server(const char* error_message) } } +uint64_t ProxyServer::LinkedSession::timeout_for_disconnect_action( + DisconnectAction action) { + switch (action) { + case DisconnectAction::LONG_TIMEOUT: + return 5 * 60 * 1000 * 1000; // 5 minutes + case DisconnectAction::MEDIUM_TIMEOUT: + return 30 * 1000 * 1000; // 30 seconds + case DisconnectAction::SHORT_TIMEOUT: + return 10 * 1000 * 1000; // 10 seconds + case DisconnectAction::CLOSE_IMMEDIATELY: + return 0; + default: + throw logic_error("disconnect action does not have a timeout"); + } +} + void ProxyServer::LinkedSession::disconnect() { // Disconnect both ends this->client_channel.disconnect(); @@ -765,9 +772,8 @@ void ProxyServer::LinkedSession::disconnect() { // Set a timeout to delete the session entirely (in case the client doesn't // reconnect) - bool use_long_timeout = (this->license.get() && (this->disconnect_action == DisconnectAction::LONG_TIMEOUT)); - struct timeval tv = usecs_to_timeval(use_long_timeout - ? LICENSED_SESSION_TIMEOUT_USECS : UNLICENSED_SESSION_TIMEOUT_USECS); + struct timeval tv = usecs_to_timeval(this->timeout_for_disconnect_action( + this->disconnect_action)); event_add(this->timeout_event.get(), &tv); } diff --git a/src/ProxyServer.hh b/src/ProxyServer.hh index 0a5df9f5..ad70f441 100644 --- a/src/ProxyServer.hh +++ b/src/ProxyServer.hh @@ -49,6 +49,7 @@ public: enum class DisconnectAction { LONG_TIMEOUT = 0, + MEDIUM_TIMEOUT, SHORT_TIMEOUT, CLOSE_IMMEDIATELY, }; @@ -146,6 +147,7 @@ public: std::shared_ptr detector_crypt); void connect(); + static uint64_t timeout_for_disconnect_action(DisconnectAction action); static void dispatch_on_timeout(evutil_socket_t fd, short what, void* ctx); static void on_input(Channel& ch, uint16_t, uint32_t, std::string& msg); static void on_error(Channel& ch, short events); @@ -155,7 +157,6 @@ public: void send_to_game_server(const char* error_message = nullptr); void disconnect(); - bool is_connected() const; }; diff --git a/src/ReceiveCommands.cc b/src/ReceiveCommands.cc index 4bb91bad..55d74051 100644 --- a/src/ReceiveCommands.cc +++ b/src/ReceiveCommands.cc @@ -75,6 +75,7 @@ static const unordered_map proxy_options_menu_descrip {ProxyOptionsMenuItemID::GO_BACK, u"Return to the\nproxy menu"}, {ProxyOptionsMenuItemID::CHAT_COMMANDS, u"Enable chat\ncommands"}, {ProxyOptionsMenuItemID::CHAT_FILTER, u"Enable escape\nsequences in\nchat messages\nand info board"}, + {ProxyOptionsMenuItemID::PLAYER_NOTIFICATIONS, u"Show a message\nwhen other players\njoin or leave"}, {ProxyOptionsMenuItemID::INFINITE_HP, u"Enable automatic HP\nrestoration when\nyou are hit by an\nenemy or trap\n\nCannot revive you\nfrom one-hit kills"}, {ProxyOptionsMenuItemID::INFINITE_TP, u"Enable automatic TP\nrestoration when\nyou cast any\ntechnique"}, {ProxyOptionsMenuItemID::SWITCH_ASSIST, u"Automatically try\nto unlock 2-player\ndoors when you step\non both switches\nsequentially"}, @@ -105,6 +106,7 @@ static vector proxy_options_menu_for_client( add_option(ProxyOptionsMenuItemID::CHAT_COMMANDS, c->options.enable_chat_commands, u"Chat commands"); add_option(ProxyOptionsMenuItemID::CHAT_FILTER, c->options.enable_chat_filter, u"Chat filter"); + add_option(ProxyOptionsMenuItemID::PLAYER_NOTIFICATIONS, c->options.enable_player_notifications, u"Player notifs"); if (!(c->flags & Client::Flag::IS_EPISODE_3)) { add_option(ProxyOptionsMenuItemID::INFINITE_HP, c->options.infinite_hp, u"Infinite HP"); add_option(ProxyOptionsMenuItemID::INFINITE_TP, c->options.infinite_tp, u"Infinite TP"); @@ -1785,6 +1787,9 @@ static void on_10(shared_ptr s, shared_ptr c, case ProxyOptionsMenuItemID::CHAT_FILTER: c->options.enable_chat_filter = !c->options.enable_chat_filter; goto resend_proxy_options_menu; + case ProxyOptionsMenuItemID::PLAYER_NOTIFICATIONS: + c->options.enable_player_notifications = !c->options.enable_player_notifications; + goto resend_proxy_options_menu; case ProxyOptionsMenuItemID::INFINITE_HP: c->options.infinite_hp = !c->options.infinite_hp; goto resend_proxy_options_menu;