From 5afe3fb8d2716086e32acfc66bf706d0b824e507 Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Sat, 2 Apr 2022 00:53:04 -0700 Subject: [PATCH] implement switch assist on proxy server --- src/ProxyServer.cc | 51 +++++++++++++++++++++++++---------- src/ProxyServer.hh | 2 ++ src/ServerShell.cc | 66 ++++++++++++++++++---------------------------- 3 files changed, 64 insertions(+), 55 deletions(-) diff --git a/src/ProxyServer.cc b/src/ProxyServer.cc index 9d058d43..7e879107 100644 --- a/src/ProxyServer.cc +++ b/src/ProxyServer.cc @@ -580,17 +580,13 @@ void ProxyServer::LinkedSession::disconnect() { -static void check_implemented_subcommand( - uint64_t id, uint16_t command, const string& data) { - if (command == 0x60 || command == 0x6C || command == 0xC9 || - command == 0x62 || command == 0x6D || command == 0xCB) { - if (data.size() < 4) { - log(WARNING, "[ProxyServer/%08" PRIX64 "] Received broadcast/target command with no contents", id); - } else { - if (!subcommand_is_implemented(data[0])) { - log(WARNING, "[ProxyServer/%08" PRIX64 "] Received subcommand %02hhX which is not implemented on the server", - id, data[0]); - } +static void check_implemented_subcommand(uint64_t id, const string& data) { + if (data.size() < 4) { + log(WARNING, "[ProxyServer/%08" PRIX64 "] Received broadcast/target command with no contents", id); + } else { + if (!subcommand_is_implemented(data[0])) { + log(WARNING, "[ProxyServer/%08" PRIX64 "] Received subcommand %02hhX which is not implemented on the server", + id, data[0]); } } } @@ -601,7 +597,6 @@ void ProxyServer::LinkedSession::on_client_input() { [&](uint16_t command, uint32_t flag, string& data) { print_received_command(command, flag, data.data(), data.size(), this->version, name.c_str()); - check_implemented_subcommand(this->id, command, data); bool should_forward = true; switch (command) { @@ -624,6 +619,26 @@ void ProxyServer::LinkedSession::on_client_input() { } break; + case 0x60: + case 0x62: + case 0x6C: + case 0x6D: + case 0xC9: + case 0xCB: + check_implemented_subcommand(this->id, data); + if (!data.empty() && (data[0] == 0x05) && (data[data.size() - 1] == 0x01) && this->enable_switch_assist) { + if (!this->last_switch_enabled_subcommand.empty()) { + log(WARNING, "[ProxyServer/%08" PRIX64 "] Switch assist: replaying previous enable subcommand", + this->id); + send_command(this->client_bev.get(), this->version, + this->client_output_crypt.get(), 0x60, 0x00, + this->last_switch_enabled_subcommand.data(), + this->last_switch_enabled_subcommand.size(), name.c_str()); + } + this->last_switch_enabled_subcommand = data; + } + break; + case 0xA0: // Change ship case 0xA1: { // Change block if ((this->version == GameVersion::PATCH) || (this->version == GameVersion::BB)) { @@ -724,7 +739,6 @@ void ProxyServer::LinkedSession::on_server_input() { [&](uint16_t command, uint32_t flag, string& data) { print_received_command(command, flag, data.data(), data.size(), this->version, name.c_str()); - check_implemented_subcommand(this->id, command, data); // In the case of server init commands, the client output crypt cannot // be set until after we forwarwd the command to the client, hence this @@ -991,6 +1005,15 @@ void ProxyServer::LinkedSession::on_server_input() { break; } + case 0x60: + case 0x62: + case 0x6C: + case 0x6D: + case 0xC9: + case 0xCB: + check_implemented_subcommand(this->id, data); + break; + case 0x44: case 0xA6: { if (this->version != GameVersion::GC) { @@ -1163,7 +1186,7 @@ void ProxyServer::LinkedSession::on_server_input() { if (this->override_lobby_event >= 0) { cmd->event = this->override_lobby_event; } - if (this->override_lobby_event >= 0) { + if (this->override_lobby_number >= 0) { cmd->lobby_number = this->override_lobby_number; } } diff --git a/src/ProxyServer.hh b/src/ProxyServer.hh index f4cf6e2b..8d665445 100644 --- a/src/ProxyServer.hh +++ b/src/ProxyServer.hh @@ -53,6 +53,8 @@ public: ClientConfig newserv_client_config; bool suppress_newserv_commands; bool enable_chat_filter; + bool enable_switch_assist; + std::string last_switch_enabled_subcommand; int16_t override_section_id; int16_t override_lobby_event; int16_t override_lobby_number; diff --git a/src/ServerShell.cc b/src/ServerShell.cc index 6f01ed36..d1e34509 100644 --- a/src/ServerShell.cc +++ b/src/ServerShell.cc @@ -31,6 +31,16 @@ shared_ptr ServerShell::get_proxy_session() { return this->state->proxy_server->get_session(); } +static void set_boolean(bool* target, const string& args) { + if (args == "on") { + *target = true; + } else if (args == "off") { + *target = false; + } else { + throw invalid_argument("argument must be \"on\" or \"off\""); + } +} + void ServerShell::execute_command(const string& command) { // find the entry in the command table and run the command size_t command_end = skip_non_whitespace(command, 0); @@ -93,19 +103,17 @@ Proxy commands (these will only work when exactly one client is connected):\n\ Set your info board contents with arbitrary data.\n\ marker \n\ Send a lobby marker message to the server.\n\ - event \n\ - Send a lobby event update to yourself.\n\ warp \n\ Send yourself to a specific area.\n\ - set-section-id [section-id]\n\ + set-override-section-id [section-id]\n\ Override the section ID for games you create or join. This affects the\n\ active drop chart if you are the leader of the game and the server doesn't\n\ override drops entirely. If no argument is given, clears the override.\n\ - set-event [event]\n\ + set-override-event [event]\n\ Override the lobby event for all lobbies and games you join. This applies\n\ only to you; other players do not see this override. If no argument is\n\ given, clears the override.\n\ - set-lobby-number [number]\n\ + set-override-lobby-number [number]\n\ Override the lobby type for all lobbies you join. This applies only to you;\n\ other players do not see this override. If no argument is given, clears the\n\ override.\n\ @@ -298,14 +306,6 @@ Proxy commands (these will only work when exactly one client is connected):\n\ session->send_to_end(data, true); - } else if (command_name == "event") { - auto session = this->get_proxy_session(); - - string data("\xDA\x00\x04\x00", 4); - data[1] = stod(command_args); - - session->send_to_end(data, false); - } else if (command_name == "warp") { auto session = this->get_proxy_session(); @@ -335,7 +335,7 @@ Proxy commands (these will only work when exactly one client is connected):\n\ session->send_to_end(data, true); - } else if (command_name == "set-section-id") { + } else if (command_name == "set-override-section-id") { auto session = this->get_proxy_session(); if (command_args.empty()) { session->override_section_id = -1; @@ -343,15 +343,18 @@ Proxy commands (these will only work when exactly one client is connected):\n\ session->override_section_id = section_id_for_name(command_args); } - } else if (command_name == "set-event") { + } else if (command_name == "set-override-event") { auto session = this->get_proxy_session(); if (command_args.empty()) { session->override_lobby_event = -1; } else { session->override_lobby_event = event_for_name(command_args); + string data("\xDA\x00\x04\x00", 4); + data[1] = session->override_lobby_event; + session->send_to_end(data, false); } - } else if (command_name == "set-lobby-number") { + } else if (command_name == "set-override-lobby-number") { auto session = this->get_proxy_session(); if (command_args.empty()) { session->override_lobby_number = -1; @@ -361,42 +364,23 @@ Proxy commands (these will only work when exactly one client is connected):\n\ } else if (command_name == "set-chat-filter") { auto session = this->get_proxy_session(); - - if (command_args == "on") { - session->enable_chat_filter = true; - } else if (command_args == "off") { - session->enable_chat_filter = false; - } else { - throw invalid_argument("argument must be \"on\" or \"off\""); - } + set_boolean(&session->enable_chat_filter, command_args); } else if (command_name == "set-chat-safety") { auto session = this->get_proxy_session(); + set_boolean(&session->suppress_newserv_commands, command_args); - if (command_args == "on") { - session->suppress_newserv_commands = true; - } else if (command_args == "off") { - session->suppress_newserv_commands = false; - } else { - throw invalid_argument("argument must be \"on\" or \"off\""); - } + } else if (command_name == "set-switch-assist") { + auto session = this->get_proxy_session(); + set_boolean(&session->enable_switch_assist, command_args); } else if (command_name == "set-save-files") { if (this->state->proxy_server.get()) { - if (command_args == "on") { - this->state->proxy_server->save_files = true; - } else if (command_args == "off") { - this->state->proxy_server->save_files = false; - } else { - throw invalid_argument("argument must be \"on\" or \"off\""); - } - + set_boolean(&this->state->proxy_server->save_files, command_args); } else { throw invalid_argument("proxy server is not available"); } - - } else { throw invalid_argument("unknown command; try \'help\'"); }