diff --git a/src/Client.cc b/src/Client.cc index 69aac99f..d37792e3 100644 --- a/src/Client.cc +++ b/src/Client.cc @@ -45,6 +45,7 @@ Client::Client( lobby_client_id(0), lobby_arrow_color(0), prefer_high_lobby_client_id(false), + preferred_lobby_id(-1), next_exp_value(0), override_section_id(-1), override_random_seed(-1), diff --git a/src/Client.hh b/src/Client.hh index 0bc46c55..0f73b23d 100644 --- a/src/Client.hh +++ b/src/Client.hh @@ -118,6 +118,7 @@ struct Client { uint8_t lobby_client_id; // which client number is this person? uint8_t lobby_arrow_color; // lobby arrow color ID bool prefer_high_lobby_client_id; + int64_t preferred_lobby_id; // <0 = no preference ClientGameData game_data; // Miscellaneous (used by chat commands) diff --git a/src/CommandFormats.hh b/src/CommandFormats.hh index a7661fdd..b21b7a96 100644 --- a/src/CommandFormats.hh +++ b/src/CommandFormats.hh @@ -1196,7 +1196,9 @@ struct C_Login_PC_9D { ptext name; }; struct C_LoginExtended_PC_9D : C_Login_PC_9D { - parray unknown_a2; + le_uint32_t menu_id; + le_uint32_t preferred_lobby_id; + parray unknown_a1; // TODO: target_player_name is somewhere in here }; // 9E (C->S): Log in with client config @@ -1213,7 +1215,11 @@ struct C_Login_GC_9E : C_Login_PC_9D { } client_config; }; struct C_LoginExtended_GC_9E : C_Login_GC_9E { - parray unknown_a2; + le_uint32_t menu_id; + le_uint32_t preferred_lobby_id; + parray unknown_a1; + ptext target_player_name; + parray unknown_a2; }; struct C_LoginExtended_BB_9E { diff --git a/src/ReceiveCommands.cc b/src/ReceiveCommands.cc index a1564708..0ba0659d 100644 --- a/src/ReceiveCommands.cc +++ b/src/ReceiveCommands.cc @@ -270,6 +270,12 @@ void process_login_d_e_pc_gc(shared_ptr s, shared_ptr c, const auto& cmd = check_size_t(data, sizeof(C_Login_GC_9E), sizeof(C_LoginExtended_GC_9E)); base_cmd = &cmd; + if (cmd.is_extended) { + const auto& cmd = check_size_t(data); + if (cmd.menu_id == MenuID::LOBBY) { + c->preferred_lobby_id = cmd.preferred_lobby_id; + } + } try { c->import_config(cmd.client_config.cfg); @@ -1124,12 +1130,8 @@ void process_change_lobby(shared_ptr s, shared_ptr c, // selection and add them to any lobby with room. If they're already in a // lobby, then they used the lobby teleporter - add them to a specific lobby. if (c->lobby_id == 0) { - shared_ptr new_lobby; - try { - new_lobby = s->find_lobby(cmd.item_id); - } catch (const out_of_range&) { } - - s->add_client_to_available_lobby(c, new_lobby); + c->preferred_lobby_id = cmd.item_id; + s->add_client_to_available_lobby(c); // If the client already is in a lobby, then they're using the lobby // teleporter; add them to the lobby they requested or send a failure message. diff --git a/src/SendCommands.cc b/src/SendCommands.cc index 462db23d..4917b007 100644 --- a/src/SendCommands.cc +++ b/src/SendCommands.cc @@ -618,6 +618,10 @@ void send_card_search_result_t( shared_ptr c, shared_ptr result, shared_ptr result_lobby) { + static const vector version_to_port_name({ + "dc-lobby", "pc-lobby", "bb-lobby", "gc-lobby", "bb-lobby"}); + const auto& port_name = version_to_port_name.at(static_cast(c->version)); + S_GuildCardSearchResult cmd; cmd.player_tag = 0x00010000; cmd.searcher_guild_card_number = c->license->serial_number; @@ -625,23 +629,22 @@ void send_card_search_result_t( cmd.reconnect_command_header.size = sizeof(cmd.reconnect_command_header) + sizeof(cmd.reconnect_command); cmd.reconnect_command_header.command = 0x19; cmd.reconnect_command_header.flag = 0x00; - // TODO: make this actually make sense... currently we just take the sockname - // for the target client. This also doesn't work if the client is on a virtual - // connection (the address and port are zero). - const sockaddr_in* local_addr = reinterpret_cast( - &result->channel.local_addr); - cmd.reconnect_command.address = local_addr->sin_addr.s_addr; - cmd.reconnect_command.port = ntohs(local_addr->sin_port); + cmd.reconnect_command.address = s->connect_address_for_client(c); + cmd.reconnect_command.port = s->name_to_port_config.at(port_name)->port; cmd.reconnect_command.unused = 0; auto encoded_server_name = encode_sjis(s->name); string location_string; if (result_lobby->is_game()) { string encoded_lobby_name = encode_sjis(result_lobby->name); - location_string = string_printf("%s,BLOCK00,%s", + location_string = string_printf("%s,BLOCK01,%s", encoded_lobby_name.c_str(), encoded_server_name.c_str()); + } else if (result_lobby->flags & Lobby::Flag::EPISODE_3_ONLY) { + location_string = string_printf("BLOCK01-C%02" PRIu32 ",BLOCK01,%s", + result_lobby->lobby_id - 15, encoded_server_name.c_str()); } else { - location_string = string_printf(",BLOCK00,%s", encoded_server_name.c_str()); + location_string = string_printf("BLOCK01-%02" PRIu32 ",BLOCK01,%s", + result_lobby->lobby_id, encoded_server_name.c_str()); } cmd.location_string = location_string; cmd.menu_id = MenuID::LOBBY; diff --git a/src/ServerState.cc b/src/ServerState.cc index 8b4aadb9..1311907d 100644 --- a/src/ServerState.cc +++ b/src/ServerState.cc @@ -52,14 +52,16 @@ ServerState::ServerState() ep3_only_lobbies.end()); } -void ServerState::add_client_to_available_lobby( - shared_ptr c, shared_ptr preferred_lobby) { +void ServerState::add_client_to_available_lobby(shared_ptr c) { shared_ptr added_to_lobby; - if (preferred_lobby) { + if (c->preferred_lobby_id >= 0) { try { - preferred_lobby->add_client(c); - added_to_lobby = preferred_lobby; + auto l = this->find_lobby(c->preferred_lobby_id); + if (!l->is_game() && (l->flags & Lobby::Flag::PUBLIC)) { + l->add_client(c); + added_to_lobby = l; + } } catch (const out_of_range&) { } } diff --git a/src/ServerState.hh b/src/ServerState.hh index dce20a77..77b84f67 100644 --- a/src/ServerState.hh +++ b/src/ServerState.hh @@ -91,8 +91,7 @@ struct ServerState { ServerState(); - void add_client_to_available_lobby(std::shared_ptr c, - std::shared_ptr preferred_lobby = nullptr); + void add_client_to_available_lobby(std::shared_ptr c); void remove_client_from_lobby(std::shared_ptr c); bool change_client_lobby(std::shared_ptr c, std::shared_ptr new_lobby);