diff --git a/src/ReceiveCommands.cc b/src/ReceiveCommands.cc index 4eda4ce4..87e233a8 100644 --- a/src/ReceiveCommands.cc +++ b/src/ReceiveCommands.cc @@ -6139,16 +6139,39 @@ static asio::awaitable on_EA_BB(std::shared_ptr c, Channel::Messag send_command(added_c, 0x04EA, 0x00000005); } else { - added_c->login->account->bb_team_id = team->team_id; - added_c->login->account->save(); - s->team_index->add_member( - team->team_id, - added_c->login->account->account_id, - added_c->character_file()->disp.visual.name.decode(added_c->language())); + const uint32_t added_account_id = added_c->login->account->account_id; + const std::string added_name = added_c->character_file()->disp.visual.name.decode(added_c->language()); + + if (TeamSync::relay_team_actions_enabled()) { + if (!TeamSync::enqueue_team_member_add(team->team_id, added_account_id, added_name)) { + send_command(c, 0x04EA, 0x00000006); + send_command(added_c, 0x04EA, 0x00000006); + break; + } + + if (!co_await TeamSync::exchange_once_now()) { + send_command(c, 0x04EA, 0x00000006); + send_command(added_c, 0x04EA, 0x00000006); + break; + } + + auto refreshed_added_team = s->team_index->get_by_account_id(added_account_id); + if (!refreshed_added_team || refreshed_added_team->team_id != team->team_id) { + send_command(c, 0x04EA, 0x00000006); + send_command(added_c, 0x04EA, 0x00000006); + break; + } + + } else { + added_c->login->account->bb_team_id = team->team_id; + added_c->login->account->save(); + s->team_index->add_member(team->team_id, added_account_id, added_name); + } + 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); + s, team, added_account_id, TeamMetadataChange::TEAM_MEMBER_COUNT); } } } @@ -6161,10 +6184,30 @@ static asio::awaitable on_EA_BB(std::shared_ptr c, Channel::Messag bool is_removing_self = (cmd.guild_card_number == c->login->account->account_id); if (is_removing_self || (team->members.at(c->login->account->account_id).privilege_level() >= 0x30)) { - s->team_index->remove_member(cmd.guild_card_number); - auto removed_account = s->account_index->from_account_id(cmd.guild_card_number); - removed_account->bb_team_id = 0; - removed_account->save(); + if (TeamSync::relay_team_actions_enabled()) { + if (!TeamSync::enqueue_team_member_remove(cmd.guild_card_number)) { + send_command(c, 0x06EA, 0x00000001); + break; + } + + if (!co_await TeamSync::exchange_once_now()) { + send_command(c, 0x06EA, 0x00000001); + break; + } + + auto removed_account = s->account_index->from_account_id(cmd.guild_card_number); + if (removed_account->bb_team_id != 0) { + send_command(c, 0x06EA, 0x00000001); + break; + } + + } else { + s->team_index->remove_member(cmd.guild_card_number); + auto removed_account = s->account_index->from_account_id(cmd.guild_card_number); + removed_account->bb_team_id = 0; + removed_account->save(); + } + send_command(c, 0x06EA, 0x00000000); std::shared_ptr removed_c; diff --git a/src/TeamSync.cc b/src/TeamSync.cc index f96126a7..821fc4a4 100644 --- a/src/TeamSync.cc +++ b/src/TeamSync.cc @@ -35,6 +35,10 @@ struct OutboundEvent { uint64_t seq = 0; std::string type; + uint32_t team_id = 0; + uint32_t account_id = 0; + std::string name; + std::string team_name; uint32_t creator_account_id = 0; std::string creator_name; @@ -480,6 +484,58 @@ bool enqueue_team_create(const std::string& team_name, uint32_t creator_account_ return true; } +bool enqueue_team_member_add(uint32_t team_id, uint32_t account_id, const std::string& name) { + auto cfg = get_config(); + if (!cfg.enabled || !cfg.relay_team_actions) { + return false; + } + if (team_id == 0 || account_id == 0 || name.empty()) { + return false; + } + + std::lock_guard g(exchange_state_mutex); + if (outbound_events.size() >= MAX_OUTBOUND_EVENTS) { + std::fprintf(stderr, + "[TeamSync] warning outbound_event_dropped reason=queue_full source=%s team_namespace=%s type=team_member_add\n", + source_label(cfg).c_str(), + cfg.team_namespace.c_str()); + return false; + } + + OutboundEvent ev; + ev.type = "team_member_add"; + ev.team_id = team_id; + ev.account_id = account_id; + ev.name = name; + outbound_events.emplace_back(std::move(ev)); + return true; +} + +bool enqueue_team_member_remove(uint32_t account_id) { + auto cfg = get_config(); + if (!cfg.enabled || !cfg.relay_team_actions) { + return false; + } + if (account_id == 0) { + return false; + } + + std::lock_guard g(exchange_state_mutex); + if (outbound_events.size() >= MAX_OUTBOUND_EVENTS) { + std::fprintf(stderr, + "[TeamSync] warning outbound_event_dropped reason=queue_full source=%s team_namespace=%s type=team_member_remove\n", + source_label(cfg).c_str(), + cfg.team_namespace.c_str()); + return false; + } + + OutboundEvent ev; + ev.type = "team_member_remove"; + ev.account_id = account_id; + outbound_events.emplace_back(std::move(ev)); + return true; +} + void set_canonical_team_state_callback(CanonicalTeamStateCallback cb) { std::lock_guard g(canonical_team_state_callback_mutex); canonical_team_state_callback = std::move(cb); @@ -522,6 +578,22 @@ static std::string exchange_body_for_current_state(const Config& cfg) { ev.creator_account_id, json_escape(ev.creator_name), json_escape(ev.team_name)); + + } else if (ev.type == "team_member_add") { + parts += std::format( + "{{\"seq\":{},\"type\":\"team_member_add\",\"team_namespace\":\"{}\",\"team_id\":{},\"account_id\":{},\"name\":\"{}\"}}", + ev.seq, + json_escape(cfg.team_namespace), + ev.team_id, + ev.account_id, + json_escape(ev.name)); + + } else if (ev.type == "team_member_remove") { + parts += std::format( + "{{\"seq\":{},\"type\":\"team_member_remove\",\"team_namespace\":\"{}\",\"account_id\":{}}}", + ev.seq, + json_escape(cfg.team_namespace), + ev.account_id); } } diff --git a/src/TeamSync.hh b/src/TeamSync.hh index ee3d33d8..be9a47e2 100644 --- a/src/TeamSync.hh +++ b/src/TeamSync.hh @@ -35,6 +35,8 @@ bool relay_team_chat_enabled(); bool relay_team_actions_enabled(); bool enqueue_team_create(const std::string& team_name, uint32_t creator_account_id, const std::string& creator_name); +bool enqueue_team_member_add(uint32_t team_id, uint32_t account_id, const std::string& name); +bool enqueue_team_member_remove(uint32_t account_id); asio::awaitable exchange_once_now(); using CanonicalTeamStateCallback = std::function;