From 125c8f910c2043023dcbe5160228ba809c3b7f44 Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Sat, 1 Oct 2022 00:53:56 -0700 Subject: [PATCH] add get_player_card --- src/ChatCommands.cc | 85 +++++++++++++++++++++++++++--------------- src/ProxyCommands.cc | 33 +++++++++------- src/ProxyServer.hh | 4 +- src/SendCommands.cc | 89 +++++++++++++++++++++++++++++++------------- src/SendCommands.hh | 8 ++++ 5 files changed, 149 insertions(+), 70 deletions(-) diff --git a/src/ChatCommands.cc b/src/ChatCommands.cc index 4ace31a1..482cc9fc 100644 --- a/src/ChatCommands.cc +++ b/src/ChatCommands.cc @@ -243,6 +243,31 @@ static void server_command_get_self_card(shared_ptr, shared_ptr, + ProxyServer::LinkedSession& session, const std::u16string& u16args) { + string args = encode_sjis(u16args); + + bool any_card_sent = false; + for (const auto& p : session.lobby_players) { + if (!p.name.empty() && args == p.name) { + send_guild_card(session.client_channel, p.guild_card_number, decode_sjis(p.name), u"", u"", p.section_id, p.char_class); + any_card_sent = true; + } + } + + if (!any_card_sent) { + try { + size_t index = stoull(args, nullptr, 0); + const auto& p = session.lobby_players.at(index); + if (!p.name.empty()) { + send_guild_card(session.client_channel, p.guild_card_number, decode_sjis(p.name), u"", u"", p.section_id, p.char_class); + } + } catch (const exception& e) { + send_text_message_printf(session.client_channel, "Error: %s", e.what()); + } + } +} + //////////////////////////////////////////////////////////////////////////////// // Lobby commands @@ -924,39 +949,39 @@ struct ChatCommandDefinition { static const unordered_map chat_commands({ // TODO: implement command_help and actually use the usage strings here - {u"$allevent", {server_command_lobby_event_all, nullptr, u"Usage:\nallevent "}}, - {u"$ann", {server_command_announce, nullptr, u"Usage:\nann "}}, - {u"$arrow", {server_command_arrow, proxy_command_arrow, u"Usage:\narrow "}}, - {u"$ax", {server_command_ax, nullptr, u"Usage:\nax "}}, - {u"$ban", {server_command_ban, nullptr, u"Usage:\nban "}}, + {u"$allevent", {server_command_lobby_event_all, nullptr, u"Usage:\nallevent "}}, + {u"$ann", {server_command_announce, nullptr, u"Usage:\nann "}}, + {u"$arrow", {server_command_arrow, proxy_command_arrow, u"Usage:\narrow "}}, + {u"$ax", {server_command_ax, nullptr, u"Usage:\nax "}}, + {u"$ban", {server_command_ban, nullptr, u"Usage:\nban "}}, // TODO: implement this on proxy server - {u"$bbchar", {server_command_convert_char_to_bb, nullptr, u"Usage:\nbbchar <1-4>"}}, - {u"$cheat", {server_command_cheat, nullptr, u"Usage:\ncheat"}}, - {u"$dbgid", {server_command_dbgid, nullptr, u"Usage:\ndbgid"}}, - {u"$edit", {server_command_edit, nullptr , u"Usage:\nedit "}}, - {u"$event", {server_command_lobby_event, proxy_command_lobby_event, u"Usage:\nevent "}}, - {u"$gc", {server_command_get_self_card, nullptr, u"Usage:\ngc"}}, - {u"$infhp", {server_command_infinite_hp, proxy_command_infinite_hp, u"Usage:\ninfhp"}}, - {u"$inftp", {server_command_infinite_tp, proxy_command_infinite_tp, u"Usage:\ninftp"}}, - {u"$item", {server_command_item, proxy_command_item, u"Usage:\nitem "}}, - {u"$kick", {server_command_kick, nullptr, u"Usage:\nkick "}}, - {u"$li", {server_command_lobby_info, proxy_command_lobby_info, u"Usage:\nli"}}, - {u"$maxlevel", {server_command_max_level, nullptr, u"Usage:\nmax_level "}}, - {u"$minlevel", {server_command_min_level, nullptr, u"Usage:\nmin_level "}}, + {u"$bbchar", {server_command_convert_char_to_bb, nullptr, u"Usage:\nbbchar <1-4>"}}, + {u"$cheat", {server_command_cheat, nullptr, u"Usage:\ncheat"}}, + {u"$dbgid", {server_command_dbgid, nullptr, u"Usage:\ndbgid"}}, + {u"$edit", {server_command_edit, nullptr , u"Usage:\nedit "}}, + {u"$event", {server_command_lobby_event, proxy_command_lobby_event, u"Usage:\nevent "}}, + {u"$gc", {server_command_get_self_card, proxy_command_get_player_card, u"Usage:\ngc"}}, + {u"$infhp", {server_command_infinite_hp, proxy_command_infinite_hp, u"Usage:\ninfhp"}}, + {u"$inftp", {server_command_infinite_tp, proxy_command_infinite_tp, u"Usage:\ninftp"}}, + {u"$item", {server_command_item, proxy_command_item, u"Usage:\nitem "}}, + {u"$kick", {server_command_kick, nullptr, u"Usage:\nkick "}}, + {u"$li", {server_command_lobby_info, proxy_command_lobby_info, u"Usage:\nli"}}, + {u"$maxlevel", {server_command_max_level, nullptr, u"Usage:\nmax_level "}}, + {u"$minlevel", {server_command_min_level, nullptr, u"Usage:\nmin_level "}}, // TODO: implement this on proxy server - {u"$next", {server_command_next, nullptr, u"Usage:\nnext"}}, - {u"$password", {server_command_password, nullptr, u"Usage:\nlock [password]\nomit password to\nunlock game"}}, - {u"$persist", {server_command_persist, nullptr, u"Usage:\npersist"}}, - {u"$proxygc", {server_command_proxygc, proxy_command_proxygc, u"Usage:\nproxygc "}}, - {u"$rand", {server_command_rand, proxy_command_rand, u"Usage:\nrand [hex seed]\nomit seed to revert\nto default"}}, - {u"$secid", {server_command_secid, proxy_command_secid, u"Usage:\nsecid [section ID]\nomit section ID to\nrevert to normal"}}, - {u"$silence", {server_command_silence, nullptr, u"Usage:\nsilence "}}, + {u"$next", {server_command_next, nullptr, u"Usage:\nnext"}}, + {u"$password", {server_command_password, nullptr, u"Usage:\nlock [password]\nomit password to\nunlock game"}}, + {u"$persist", {server_command_persist, nullptr, u"Usage:\npersist"}}, + {u"$proxygc", {server_command_proxygc, proxy_command_proxygc, u"Usage:\nproxygc "}}, + {u"$rand", {server_command_rand, proxy_command_rand, u"Usage:\nrand [hex seed]\nomit seed to revert\nto default"}}, + {u"$secid", {server_command_secid, proxy_command_secid, u"Usage:\nsecid [section ID]\nomit section ID to\nrevert to normal"}}, + {u"$silence", {server_command_silence, nullptr, u"Usage:\nsilence "}}, // TODO: implement this on proxy server - {u"$song", {server_command_song, nullptr, u"Usage:\nsong "}}, - {u"$swa", {server_command_switch_assist, proxy_command_switch_assist, u"Usage:\nswa"}}, - {u"$type", {server_command_lobby_type, nullptr, u"Usage:\ntype "}}, - {u"$warp", {server_command_warp, proxy_command_warp, u"Usage:\nwarp "}}, - {u"$what", {server_command_what, nullptr, u"Usage:\nwhat"}}, + {u"$song", {server_command_song, nullptr, u"Usage:\nsong "}}, + {u"$swa", {server_command_switch_assist, proxy_command_switch_assist, u"Usage:\nswa"}}, + {u"$type", {server_command_lobby_type, nullptr, u"Usage:\ntype "}}, + {u"$warp", {server_command_warp, proxy_command_warp, u"Usage:\nwarp "}}, + {u"$what", {server_command_what, nullptr, u"Usage:\nwhat"}}, }); struct SplitCommand { diff --git a/src/ProxyCommands.cc b/src/ProxyCommands.cc index 6c579bae..38fccee8 100644 --- a/src/ProxyCommands.cc +++ b/src/ProxyCommands.cc @@ -1002,13 +1002,14 @@ static HandlerResult S_65_67_68(shared_ptr, num_replacements++; modified = true; } - session.lobby_players[index].guild_card_number = cmd.entries[x].lobby_data.guild_card; + auto& p = session.lobby_players[index]; + p.guild_card_number = cmd.entries[x].lobby_data.guild_card; ptext name = cmd.entries[x].disp.name; - session.lobby_players[index].name = name; + p.name = name; + p.section_id = cmd.entries[x].disp.section_id; + p.char_class = cmd.entries[x].disp.char_class; session.log.info("Added lobby player: (%zu) %" PRIu32 " %s", - index, - session.lobby_players[index].guild_card_number, - session.lobby_players[index].name.c_str()); + index, p.guild_card_number, p.name.c_str()); } } if (num_replacements > 1) { @@ -1057,17 +1058,18 @@ static HandlerResult S_64(shared_ptr, cmd->lobby_data[x].guild_card = session.license->serial_number; modified = true; } - session.lobby_players[x].guild_card_number = cmd->lobby_data[x].guild_card; + auto& p = session.lobby_players[x]; + p.guild_card_number = cmd->lobby_data[x].guild_card; if (cmd_ep3) { ptext name = cmd_ep3->players_ep3[x].disp.name; - session.lobby_players[x].name = name; + p.name = name; + p.section_id = cmd_ep3->players_ep3[x].disp.section_id; + p.char_class = cmd_ep3->players_ep3[x].disp.char_class; } else { - session.lobby_players[x].name.clear(); + p.name.clear(); } session.log.info("Added lobby player: (%zu) %" PRIu32 " %s", - x, - session.lobby_players[x].guild_card_number, - session.lobby_players[x].name.c_str()); + x, p.guild_card_number, p.name.c_str()); } if (session.override_section_id >= 0) { @@ -1098,8 +1100,9 @@ static HandlerResult S_66_69(shared_ptr, if (index >= session.lobby_players.size()) { session.log.warning("Lobby leave command references missing position"); } else { - session.lobby_players[index].guild_card_number = 0; - session.lobby_players[index].name.clear(); + auto& p = session.lobby_players[index]; + p.guild_card_number = 0; + p.name.clear(); session.log.info("Removed lobby player (%zu)", index); } update_leader_id(session, cmd.leader_id); @@ -1197,7 +1200,9 @@ template static HandlerResult C_6x(shared_ptr s, ProxyServer::LinkedSession& session, uint16_t command, uint32_t flag, string& data) { if (session.license && !data.empty()) { - if (data[0] == 0x06) { + // On BB, the 6x06 command is blank - the server generates the actual Guild + // Card contents and sends it to the target client. + if (data[0] == 0x06 && session.version != GameVersion::BB) { auto& cmd = check_size_t(data); if (cmd.guild_card_number == session.license->serial_number) { cmd.guild_card_number = session.remote_guild_card_number; diff --git a/src/ProxyServer.hh b/src/ProxyServer.hh index 9f01b83f..c2275627 100644 --- a/src/ProxyServer.hh +++ b/src/ProxyServer.hh @@ -78,7 +78,9 @@ public: struct LobbyPlayer { uint32_t guild_card_number; std::string name; - LobbyPlayer() : guild_card_number(0) { } + uint8_t section_id; + uint8_t char_class; + LobbyPlayer() : guild_card_number(0), section_id(0), char_class(0) { } }; std::vector lobby_players; size_t lobby_client_id; diff --git a/src/SendCommands.cc b/src/SendCommands.cc index 724caa29..69a9e807 100644 --- a/src/SendCommands.cc +++ b/src/SendCommands.cc @@ -770,54 +770,93 @@ void send_card_search_result( template -void send_guild_card_dc_pc_v3_t(shared_ptr c, shared_ptr source) { +void send_guild_card_dc_pc_v3_t( + Channel& ch, + uint32_t guild_card_number, + const u16string& name, + const u16string& description, + uint8_t section_id, + uint8_t char_class) { CmdT cmd; cmd.subcommand = 0x06; cmd.size = sizeof(CmdT) / 4; cmd.unused = 0x0000; cmd.player_tag = 0x00010000; - cmd.guild_card_number = source->license->serial_number; - cmd.name = source->game_data.player()->disp.name; + cmd.guild_card_number = guild_card_number; + cmd.name = name; remove_language_marker_inplace(cmd.name); - cmd.description = source->game_data.player()->guild_card_description; + cmd.description = description; cmd.present = 1; cmd.present2 = 1; - cmd.section_id = source->game_data.player()->disp.section_id; - cmd.char_class = source->game_data.player()->disp.char_class; - send_command_t(c, 0x62, c->lobby_client_id, cmd); + cmd.section_id = section_id; + cmd.char_class = char_class; + ch.send(0x60, 0x00, &cmd, sizeof(cmd)); } -void send_guild_card_bb(shared_ptr c, shared_ptr source) { +static void send_guild_card_bb( + Channel& ch, + uint32_t guild_card_number, + const u16string& name, + const u16string& team_name, + const u16string& description, + uint8_t section_id, + uint8_t char_class) { G_SendGuildCard_BB_6x06 cmd; cmd.subcommand = 0x06; cmd.size = sizeof(cmd) / 4; cmd.unused = 0x0000; - cmd.guild_card_number = source->license->serial_number; - cmd.name = remove_language_marker(source->game_data.player()->disp.name); - cmd.team_name = remove_language_marker(source->game_data.account()->team_name); - cmd.description = source->game_data.player()->guild_card_description; + cmd.guild_card_number = guild_card_number; + cmd.name = remove_language_marker(name); + cmd.team_name = remove_language_marker(team_name); + cmd.description = description; cmd.present = 1; cmd.present2 = 1; - cmd.section_id = source->game_data.player()->disp.section_id; - cmd.char_class = source->game_data.player()->disp.char_class; - send_command_t(c, 0x62, c->lobby_client_id, cmd); + cmd.section_id = section_id; + cmd.char_class = char_class; + ch.send(0x60, 0x00, &cmd, sizeof(cmd)); } -void send_guild_card(shared_ptr c, shared_ptr source) { - if (c->version() == GameVersion::DC) { - send_guild_card_dc_pc_v3_t(c, source); - } else if (c->version() == GameVersion::PC) { - send_guild_card_dc_pc_v3_t(c, source); - } else if ((c->version() == GameVersion::GC) || - (c->version() == GameVersion::XB)) { - send_guild_card_dc_pc_v3_t(c, source); - } else if (c->version() == GameVersion::BB) { - send_guild_card_bb(c, source); +void send_guild_card( + Channel& ch, + uint32_t guild_card_number, + const u16string& name, + const u16string& team_name, + const u16string& description, + uint8_t section_id, + uint8_t char_class) { + if (ch.version == GameVersion::DC) { + send_guild_card_dc_pc_v3_t( + ch, guild_card_number, name, description, section_id, char_class); + } else if (ch.version == GameVersion::PC) { + send_guild_card_dc_pc_v3_t( + ch, guild_card_number, name, description, section_id, char_class); + } else if ((ch.version == GameVersion::GC) || + (ch.version == GameVersion::XB)) { + send_guild_card_dc_pc_v3_t( + ch, guild_card_number, name, description, section_id, char_class); + } else if (ch.version == GameVersion::BB) { + send_guild_card_bb( + ch, guild_card_number, name, team_name, description, section_id, char_class); } else { throw logic_error("unimplemented versioned command"); } } +void send_guild_card(shared_ptr c, shared_ptr source) { + if (!source->license) { + throw runtime_error("source player does not have a license"); + } + + uint32_t guild_card_number = source->license->serial_number; + u16string name = source->game_data.player()->disp.name; + u16string description = source->game_data.player()->guild_card_description; + uint8_t section_id = source->game_data.player()->disp.section_id; + uint8_t char_class = source->game_data.player()->disp.char_class; + + send_guild_card( + c->channel, guild_card_number, name, u"", description, section_id, char_class); +} + //////////////////////////////////////////////////////////////////////////////// diff --git a/src/SendCommands.hh b/src/SendCommands.hh index b9b47472..0f67eb4e 100644 --- a/src/SendCommands.hh +++ b/src/SendCommands.hh @@ -182,6 +182,14 @@ void send_card_search_result( std::shared_ptr result, std::shared_ptr result_lobby); +void send_guild_card( + Channel& ch, + uint32_t guild_card_number, + const u16string& name, + const u16string& team_name, + const u16string& description, + uint8_t section_id, + uint8_t char_class); void send_guild_card(std::shared_ptr c, std::shared_ptr source); void send_menu(std::shared_ptr c, const std::u16string& menu_name, uint32_t menu_id, const std::vector& items, bool is_info_menu = false);