diff --git a/src/Client.cc b/src/Client.cc index bd93c05b..9b902f42 100644 --- a/src/Client.cc +++ b/src/Client.cc @@ -43,7 +43,7 @@ Client::Client( infinite_tp(false), switch_assist(false), can_chat(true) { - memset(&this->last_switch_enabled_subcommand, 0, sizeof(this->last_switch_enabled_subcommand)); + this->last_switch_enabled_command.subcommand = 0; int fd = bufferevent_getfd(this->bev); if (fd < 0) { this->is_virtual_connection = true; diff --git a/src/Client.hh b/src/Client.hh index 8783e847..51644385 100644 --- a/src/Client.hh +++ b/src/Client.hh @@ -10,6 +10,7 @@ #include "Text.hh" #include "PSOProtocol.hh" +#include "CommandFormats.hh" @@ -26,21 +27,6 @@ enum class ServerBehavior { PROXY_SERVER, }; -struct ClientConfig { - uint64_t magic; - uint8_t bb_game_state; - uint8_t bb_player_index; - uint16_t flags; - uint32_t proxy_destination_address; - uint16_t proxy_destination_port; - parray unused; -} __attribute__((packed)); - -struct ClientConfigBB { - ClientConfig cfg; - parray unused; -} __attribute__((packed)); - struct Client { enum Flag { // For patch server clients, client is Blue Burst rather than PC @@ -120,7 +106,7 @@ struct Client { bool infinite_hp; // cheats enabled bool infinite_tp; // cheats enabled bool switch_assist; // cheats enabled - std::string last_switch_enabled_subcommand; + G_SwitchStateChanged_6x05 last_switch_enabled_command; bool can_chat; std::string pending_bb_save_username; uint8_t pending_bb_save_player_index; diff --git a/src/CommandFormats.hh b/src/CommandFormats.hh index 44c0008b..d92956c6 100644 --- a/src/CommandFormats.hh +++ b/src/CommandFormats.hh @@ -36,6 +36,26 @@ +// This is the format of newserv's security data, which we call the client +// config. This data is opaque to the client, so this structure is not +// technically part of the PSO protocol. +struct ClientConfig { + uint64_t magic; + uint8_t bb_game_state; + uint8_t bb_player_index; + uint16_t flags; + uint32_t proxy_destination_address; + uint16_t proxy_destination_port; + parray unused; +} __attribute__((packed)); + +struct ClientConfigBB { + ClientConfig cfg; + parray unused; +} __attribute__((packed)); + + + // 00: Invalid command // 01 (S->C): Lobby message box @@ -1222,11 +1242,13 @@ struct G_ItemSubcommand { // TODO: make last_switch_enabled_subcommand in both Client and Proxy use this // when it's available -// struct G_SwitchStateChanged_6x05 { -// uint8_t subcommand; -// uint8_t size; -// TODO; -// }; +struct G_SwitchStateChanged_6x05 { + uint8_t subcommand; + uint8_t size; + parray unknown; // includes switch ID + uint8_t area; + uint8_t enabled; +}; // 06: Send guild card diff --git a/src/ProxyCommands.cc b/src/ProxyCommands.cc index 6342c18b..394cd2e4 100644 --- a/src/ProxyCommands.cc +++ b/src/ProxyCommands.cc @@ -646,13 +646,18 @@ bool process_client_60_62_6C_6D_C9_CB(shared_ptr, ProxyServer::LinkedSession& session, uint16_t, uint32_t, string& data) { check_implemented_subcommand(session.id, data); - if (!data.empty() && (data[0] == 0x05) && (data[data.size() - 1] == 0x01) && session.enable_switch_assist) { - if (!session.last_switch_enabled_subcommand.empty()) { - session.log(WARNING, "Switch assist: replaying previous enable subcommand"); - session.send_to_end(true, 0x60, 0x00, session.last_switch_enabled_subcommand); - session.send_to_end(false, 0x60, 0x00, session.last_switch_enabled_subcommand); + if (!data.empty() && (data[0] == 0x05) && session.enable_switch_assist) { + auto& cmd = check_size_t(data); + if (cmd.enabled) { + if (session.last_switch_enabled_command.subcommand == 0x05) { + session.log(INFO, "Switch assist: replaying previous enable command"); + session.send_to_end(true, 0x60, 0x00, &session.last_switch_enabled_command, + sizeof(session.last_switch_enabled_command)); + session.send_to_end(false, 0x60, 0x00, &session.last_switch_enabled_command, + sizeof(session.last_switch_enabled_command)); + } + session.last_switch_enabled_command = cmd; } - session.last_switch_enabled_subcommand = data; } return true; diff --git a/src/ProxyServer.cc b/src/ProxyServer.cc index e99fe993..d175b3f2 100644 --- a/src/ProxyServer.cc +++ b/src/ProxyServer.cc @@ -375,7 +375,9 @@ ProxyServer::LinkedSession::LinkedSession( override_lobby_event(-1), override_lobby_number(-1), lobby_players(12), - lobby_client_id(0) { } + lobby_client_id(0) { + this->last_switch_enabled_command.subcommand = 0; +} ProxyServer::LinkedSession::LinkedSession( ProxyServer* server, diff --git a/src/ProxyServer.hh b/src/ProxyServer.hh index 72b33399..27d92342 100644 --- a/src/ProxyServer.hh +++ b/src/ProxyServer.hh @@ -58,7 +58,7 @@ public: bool enable_chat_filter; bool enable_switch_assist; bool save_files; - std::string last_switch_enabled_subcommand; + G_SwitchStateChanged_6x05 last_switch_enabled_command; int16_t override_section_id; int16_t override_lobby_event; int16_t override_lobby_number; diff --git a/src/ReceiveSubcommands.cc b/src/ReceiveSubcommands.cc index 303290df..45218429 100644 --- a/src/ReceiveSubcommands.cc +++ b/src/ReceiveSubcommands.cc @@ -59,7 +59,7 @@ const PSOSubcommand* check_size_sc( static void forward_subcommand(shared_ptr l, shared_ptr c, - uint8_t command, uint8_t flag, const string& data) { + uint8_t command, uint8_t flag, const void* data, size_t size) { // if the command is an Ep3-only command, make sure an Ep3 client sent it bool command_is_ep3 = (command & 0xF0) == 0xC0; @@ -90,11 +90,16 @@ static void forward_subcommand(shared_ptr l, shared_ptr c, } } else { - send_command_excluding_client(l, c, command, flag, data.data(), data.size()); + send_command_excluding_client(l, c, command, flag, data, size); } } } +static void forward_subcommand(shared_ptr l, shared_ptr c, + uint8_t command, uint8_t flag, const string& data) { + forward_subcommand(l, c, command, flag, data.data(), data.size()); +} + //////////////////////////////////////////////////////////////////////////////// @@ -204,19 +209,20 @@ static void process_subcommand_use_technique(shared_ptr, static void process_subcommand_switch_state_changed(shared_ptr, shared_ptr l, shared_ptr c, uint8_t command, uint8_t flag, const string& data) { - const auto* p = check_size_sc(data, 0x0C); + auto& cmd = check_size_t(data); if (!l->is_game()) { return; } forward_subcommand(l, c, command, flag, data); - if (p[2].byte[3] == 1) { // If this is a switch enable command + if (cmd.enabled) { if ((l->flags & Lobby::Flag::CHEATS_ENABLED) && c->switch_assist && - !c->last_switch_enabled_subcommand.empty()) { + (c->last_switch_enabled_command.subcommand == 0x05)) { log(INFO, "[Switch assist] Replaying previous enable command"); - forward_subcommand(l, c, command, flag, c->last_switch_enabled_subcommand); - send_command(c, command, flag, c->last_switch_enabled_subcommand); + forward_subcommand(l, c, command, flag, &c->last_switch_enabled_command, + sizeof(c->last_switch_enabled_command)); + send_command(c, command, flag, c->last_switch_enabled_command); } - memcpy(&c->last_switch_enabled_subcommand, p, sizeof(c->last_switch_enabled_subcommand)); + c->last_switch_enabled_command = cmd; } }