From 3857cda4e5b5894aae2e108e1c4d36f5022d665a Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Sun, 9 Mar 2025 16:11:34 -0700 Subject: [PATCH] fix team member count updates --- src/CommandFormats.hh | 22 ++++++------------- src/ReceiveCommands.cc | 50 ++++++++++-------------------------------- src/SendCommands.cc | 31 ++++++++++---------------- src/SendCommands.hh | 7 +++--- 4 files changed, 34 insertions(+), 76 deletions(-) diff --git a/src/CommandFormats.hh b/src/CommandFormats.hh index ae715ae8..f7e939a8 100644 --- a/src/CommandFormats.hh +++ b/src/CommandFormats.hh @@ -3488,32 +3488,24 @@ struct C_ChangeTeamMemberPrivilegeLevel_BB_11EA { le_uint32_t guild_card_number = 0; } __packed_ws__(C_ChangeTeamMemberPrivilegeLevel_BB_11EA, 4); -// 12EA (S->C): Team membership information +// 12EA (S->C): Update team membership // This updates the client's view of its system file. -struct S_TeamMembershipInformation_BB_12EA { +struct S_UpdateTeamMembership_BB_12EA { // If skip_update_system_file is not zero, the client ignores the command. // It's not clear why this field exists. le_uint32_t skip_update_system_file = 0; PSOBBBaseTeamMembership membership; -} __packed_ws__(S_TeamMembershipInformation_BB_12EA, 0x38); +} __packed_ws__(S_UpdateTeamMembership_BB_12EA, 0x38); // 13EA: Team info for lobby players // header.flag specifies the number of entries. struct S_TeamInfoForPlayer_BB_13EA_15EA_Entry { - // The client uses the first four of these to determine if the player is in a - // team or not - if they are all zero, the player is not in a team. - /* 0000 */ le_uint32_t guild_card_number = 0; - /* 0004 */ le_uint32_t team_id = 0; - /* 0008 */ le_uint32_t reward_flags = 0; - /* 000C */ le_uint32_t unknown_a6 = 0; - /* 0010 */ uint8_t privilege_level = 0; - /* 0011 */ uint8_t team_member_count = 0; - /* 0012 */ uint8_t unknown_a8 = 0; - /* 0013 */ uint8_t unknown_a9 = 0; - /* 0014 */ pstring team_name; - /* 0034 */ le_uint32_t guild_card_number2 = 0; + // The client uses the first four fields of the membership to determine if + // the player is in a team: if any are nonzero, the player is in a team. + /* 0000 */ PSOBBBaseTeamMembership membership; + /* 0034 */ le_uint32_t guild_card_number = 0; /* 0038 */ le_uint32_t lobby_client_id = 0; /* 003C */ pstring player_name; /* 005C */ parray flag_data; diff --git a/src/ReceiveCommands.cc b/src/ReceiveCommands.cc index 466a2383..59d74f6b 100644 --- a/src/ReceiveCommands.cc +++ b/src/ReceiveCommands.cc @@ -5237,7 +5237,7 @@ static void on_EA_BB(shared_ptr c, uint16_t command, uint32_t flag, stri c->login->account->save(); send_command(c, 0x02EA, 0x00000000); - send_team_membership_change_notifications(c); + send_team_metadata_change_notifications(s, team, c->login->account->account_id, TeamMetadataChange::TEAM_CREATED); } break; } @@ -5271,10 +5271,10 @@ static void on_EA_BB(shared_ptr c, uint16_t command, uint32_t flag, stri team->team_id, added_c->login->account->account_id, added_c->character()->disp.name.decode(added_c->language())); - - send_team_membership_change_notifications(added_c); send_command(c, 0x04EA, 0x00000000); send_command(added_c, 0x04EA, 0x00000000); + send_team_metadata_change_notifications( + s, team, added_c->login->account->account_id, TeamMetadataChange::TEAM_MEMBER_COUNT); } } } @@ -5302,9 +5302,8 @@ static void on_EA_BB(shared_ptr c, uint16_t command, uint32_t flag, stri } catch (const out_of_range&) { } } - if (removed_c) { - send_team_membership_change_notifications(removed_c); - } + send_team_metadata_change_notifications( + s, team, removed_c->login->account->account_id, TeamMetadataChange::TEAM_MEMBER_COUNT); } else { // TODO: Figure out the right error code to use here. send_command(c, 0x06EA, 0x00000001); @@ -5348,7 +5347,7 @@ static void on_EA_BB(shared_ptr c, uint16_t command, uint32_t flag, stri if (team && team->members.at(c->login->account->account_id).check_flag(TeamIndex::Team::Member::Flag::IS_MASTER)) { const auto& cmd = check_size_t(data); s->team_index->set_flag_data(team->team_id, cmd.flag_data); - send_team_metadata_change_notifications(s, team, TeamMetadataChange::FLAG_DATA); + send_team_metadata_change_notifications(s, team, 0, TeamMetadataChange::FLAG_DATA); } break; } @@ -5357,7 +5356,7 @@ static void on_EA_BB(shared_ptr c, uint16_t command, uint32_t flag, stri if (team && team->members.at(c->login->account->account_id).check_flag(TeamIndex::Team::Member::Flag::IS_MASTER)) { s->team_index->disband(team->team_id); send_command(c, 0x10EA, 0x00000000); - send_team_metadata_change_notifications(s, team, TeamMetadataChange::TEAM_DISBANDED); + send_team_metadata_change_notifications(s, team, 0, TeamMetadataChange::TEAM_DISBANDED); } break; } @@ -5370,14 +5369,11 @@ static void on_EA_BB(shared_ptr c, uint16_t command, uint32_t flag, stri } // The client only sends this command with flag = 0x00, 0x30, or 0x40 - bool send_updates_for_this_m = false; - bool send_updates_for_other_m = false; - bool send_master_transfer_updates = false; switch (flag) { case 0x00: // Demote member if (s->team_index->demote_leader(c->login->account->account_id, cmd.guild_card_number)) { send_command(c, 0x11EA, 0x00000000); - send_updates_for_other_m = true; + send_team_metadata_change_notifications(s, team, cmd.guild_card_number, 0); } else { send_command(c, 0x11EA, 0x00000005); } @@ -5385,7 +5381,7 @@ static void on_EA_BB(shared_ptr c, uint16_t command, uint32_t flag, stri case 0x30: // Promote member if (s->team_index->promote_leader(c->login->account->account_id, cmd.guild_card_number)) { send_command(c, 0x11EA, 0x00000000); - send_updates_for_other_m = true; + send_team_metadata_change_notifications(s, team, cmd.guild_card_number, 0); } else { send_command(c, 0x11EA, 0x00000005); } @@ -5393,33 +5389,11 @@ static void on_EA_BB(shared_ptr c, uint16_t command, uint32_t flag, stri case 0x40: // Transfer master s->team_index->change_master(c->login->account->account_id, cmd.guild_card_number); send_command(c, 0x11EA, 0x00000000); - send_updates_for_this_m = true; - send_updates_for_other_m = true; - send_master_transfer_updates = true; + send_team_metadata_change_notifications(s, team, cmd.guild_card_number, TeamMetadataChange::TEAM_MASTER); break; default: throw runtime_error("invalid privilege level"); } - - if (send_master_transfer_updates) { - for (const auto& it : team->members) { - try { - auto other_c = s->find_client(nullptr, it.second.account_id); - send_update_lobby_data_bb(other_c); - } catch (const out_of_range&) { - } - } - } - if (send_updates_for_this_m) { - send_team_membership_change_notifications(c); - } - if (send_updates_for_other_m) { - try { - auto other_c = s->find_client(nullptr, cmd.guild_card_number); - send_team_membership_change_notifications(other_c); - } catch (const out_of_range&) { - } - } } break; } @@ -5454,7 +5428,7 @@ static void on_EA_BB(shared_ptr c, uint16_t command, uint32_t flag, stri s->team_index->buy_reward(team->team_id, reward.key, reward.team_points, reward.reward_flag); if (reward.reward_flag != TeamIndex::Team::RewardFlag::NONE) { - send_team_metadata_change_notifications(s, team, TeamMetadataChange::REWARD_FLAGS); + send_team_metadata_change_notifications(s, team, 0, TeamMetadataChange::REWARD_FLAGS); } if (!reward.reward_item.empty()) { c->current_bank().add_item(reward.reward_item, *s->item_stack_limits(c->version())); @@ -5477,7 +5451,7 @@ static void on_EA_BB(shared_ptr c, uint16_t command, uint32_t flag, stri } else { s->team_index->rename(team->team_id, new_team_name); send_command(c, 0x1FEA, 0x00000000); - send_team_metadata_change_notifications(s, team, TeamMetadataChange::TEAM_NAME); + send_team_metadata_change_notifications(s, team, 0, TeamMetadataChange::TEAM_NAME); } break; } diff --git a/src/SendCommands.cc b/src/SendCommands.cc index e2eb6d72..952a721b 100644 --- a/src/SendCommands.cc +++ b/src/SendCommands.cc @@ -4118,9 +4118,9 @@ void send_change_event(shared_ptr s, uint8_t new_event) { //////////////////////////////////////////////////////////////////////////////// // BB teams -void send_team_membership_info(shared_ptr c) { +void send_update_team_membership(shared_ptr c) { auto team = c->team(); - S_TeamMembershipInformation_BB_12EA cmd; + S_UpdateTeamMembership_BB_12EA cmd; if (team) { cmd.membership = team->base_membership_for_member(c->login->account->account_id); } @@ -4131,14 +4131,10 @@ static S_TeamInfoForPlayer_BB_13EA_15EA_Entry team_metadata_for_client(shared_pt auto team = c->team(); S_TeamInfoForPlayer_BB_13EA_15EA_Entry cmd; cmd.lobby_client_id = c->lobby_client_id; - cmd.guild_card_number2 = c->login->account->account_id; + cmd.guild_card_number = c->login->account->account_id; cmd.player_name = c->character()->disp.name; if (team) { - cmd.guild_card_number = c->login->account->account_id; - cmd.team_id = team->team_id; - cmd.privilege_level = team->members.at(c->login->account->account_id).privilege_level(); - cmd.team_member_count = min(team->members.size(), 100); - cmd.team_name.encode(team->name); + cmd.membership = team->base_membership_for_member(c->login->account->account_id); if (team->flag_data) { cmd.flag_data = *team->flag_data; } @@ -4317,31 +4313,26 @@ void send_team_reward_list(shared_ptr c, bool show_purchased) { void send_team_metadata_change_notifications( shared_ptr s, shared_ptr team, + uint32_t changed_member_account_id, uint8_t what) { using TMC = TeamMetadataChange; for (const auto& it : team->members) { try { auto member_c = s->find_client(nullptr, it.second.account_id); - if (what & TMC::TEAM_MASTER) { + bool is_changed_client = (member_c->login && (member_c->login->account->account_id == changed_member_account_id)); + if (is_changed_client || (what & TMC::TEAM_MASTER)) { send_update_lobby_data_bb(member_c); } - if (what & (TMC::TEAM_MASTER | TMC::TEAM_NAME)) { - send_team_membership_info(member_c); + if (is_changed_client || (what & (TMC::TEAM_MASTER | TMC::TEAM_NAME | TMC::TEAM_MEMBER_COUNT))) { + send_update_team_membership(member_c); } - if (what & (TMC::TEAM_MASTER | TMC::FLAG_DATA | TMC::TEAM_NAME)) { + if (is_changed_client || (what & (TMC::TEAM_MASTER | TMC::FLAG_DATA | TMC::TEAM_NAME | TMC::TEAM_MEMBER_COUNT))) { send_update_team_metadata_for_client(member_c); } - if (what & TMC::REWARD_FLAGS) { + if (is_changed_client || (what & TMC::REWARD_FLAGS)) { send_update_team_reward_flags(member_c); } } catch (const out_of_range&) { } } } - -void send_team_membership_change_notifications(shared_ptr changed_c) { - send_update_lobby_data_bb(changed_c); - send_update_team_metadata_for_client(changed_c); - send_team_membership_info(changed_c); - send_update_team_reward_flags(changed_c); -} diff --git a/src/SendCommands.hh b/src/SendCommands.hh index e334b265..cd0202a0 100644 --- a/src/SendCommands.hh +++ b/src/SendCommands.hh @@ -447,7 +447,7 @@ void send_change_event(std::shared_ptr c, uint8_t new_event); void send_change_event(std::shared_ptr l, uint8_t new_event); void send_change_event(std::shared_ptr s, uint8_t new_event); -void send_team_membership_info(std::shared_ptr c); // 12EA +void send_update_team_membership(std::shared_ptr c); // 12EA void send_update_team_metadata_for_client(std::shared_ptr c); // 15EA (to all clients in lobby, with only c's data) void send_all_nearby_team_metadatas_to_client(std::shared_ptr c, bool is_13EA); // 13EA/15EA (to only c, with all lobby clients' data) void send_update_team_reward_flags(std::shared_ptr c); // 1DEA @@ -461,11 +461,12 @@ enum TeamMetadataChange : uint8_t { FLAG_DATA = 0x02, REWARD_FLAGS = 0x04, TEAM_NAME = 0x08, + TEAM_MEMBER_COUNT = 0x10, + TEAM_CREATED = 0xFF, TEAM_DISBANDED = 0xFF, }; - void send_team_metadata_change_notifications( std::shared_ptr s, std::shared_ptr team, + uint32_t changed_member_account_id, uint8_t what); -void send_team_membership_change_notifications(std::shared_ptr changed_c);