diff --git a/src/CommandFormats.hh b/src/CommandFormats.hh index 7fd60d59..dde7b3ea 100644 --- a/src/CommandFormats.hh +++ b/src/CommandFormats.hh @@ -1781,13 +1781,17 @@ struct S_ChoiceSearchResultEntry_V3_C4 { // client_id field in each entry before sending. // C6 (C->S): Set blocked senders list (V3/BB) +// The command always contains the same number of entries, even if the entries +// at the end are blank (zero). -struct C_SetBlockedSenders_V3_BB_C6 { - // The command always contains 30 entries, even if the entries at the end are - // blank (zero). - parray blocked_senders; +template +struct C_SetBlockedSenders_C6 { + parray blocked_senders; }; +struct C_SetBlockedSenders_V3_C6 : C_SetBlockedSenders_C6<30> { }; +struct C_SetBlockedSenders_BB_C6 : C_SetBlockedSenders_C6<28> { }; + // C7 (C->S): Enable simple mail auto-reply (V3/BB) // Same format as 1A/D5 command (plain text). // Server does not respond @@ -2299,7 +2303,7 @@ struct C_DeleteGuildCard_BB_05E8_08E8 { le_uint32_t guild_card_number; }; -// 06E8 (C->S): Set guild card text +// 06E8 (C->S): Update (overwrite) guild card // Format is GuildCardBB (see Player.hh) // 07E8 (C->S): Add blocked user diff --git a/src/Player.cc b/src/Player.cc index d6a84b26..5fcec9a4 100644 --- a/src/Player.cc +++ b/src/Player.cc @@ -271,14 +271,14 @@ GuildCardV3::GuildCardV3() noexcept : player_tag(0), guild_card_number(0), present(0), - present2(0), + language(0), section_id(0), char_class(0) { } GuildCardBB::GuildCardBB() noexcept : guild_card_number(0), present(0), - present2(0), + language(0), section_id(0), char_class(0) { } @@ -288,7 +288,7 @@ void GuildCardBB::clear() { this->team_name.clear(); this->description.clear(); this->present = 0; - this->present2 = 0; + this->language = 0; this->section_id = 0; this->char_class = 0; } diff --git a/src/Player.hh b/src/Player.hh index 8a4b9e50..3fea0cf8 100644 --- a/src/Player.hh +++ b/src/Player.hh @@ -215,7 +215,7 @@ struct GuildCardV3 { ptext name; ptext description; uint8_t present; // should be 1 - uint8_t present2; // should be 1 + uint8_t language; uint8_t section_id; uint8_t char_class; @@ -229,7 +229,7 @@ struct GuildCardBB { ptext team_name; ptext description; uint8_t present; // should be 1 if guild card entry exists - uint8_t present2; // should be 1 if guild card entry exists + uint8_t language; uint8_t section_id; uint8_t char_class; @@ -248,8 +248,10 @@ struct GuildCardEntryBB { // the format of the BB guild card file struct GuildCardFileBB { - parray unknown_a3; - GuildCardEntryBB entries[0x0069]; // that's 105 of them in decimal + parray unknown_a1; + GuildCardBB blocked[0x1C]; + parray unknown_a2; + GuildCardEntryBB entries[0x69]; } __attribute__((packed)); struct KeyAndTeamConfigBB { diff --git a/src/ReceiveCommands.cc b/src/ReceiveCommands.cc index 1f2ac075..26e6fe76 100644 --- a/src/ReceiveCommands.cc +++ b/src/ReceiveCommands.cc @@ -1583,7 +1583,8 @@ void process_player_preview_request_bb(shared_ptr, shared_ptr, shared_ptr c, uint16_t command, uint32_t, const string& data) { - constexpr size_t max_count = sizeof(GuildCardFileBB) / sizeof(GuildCardEntryBB); + constexpr size_t max_count = sizeof(GuildCardFileBB::entries) / sizeof(GuildCardEntryBB); + constexpr size_t max_blocked = sizeof(GuildCardFileBB::blocked) / sizeof(GuildCardBB); switch (command) { case 0x01E8: { // Check guild card file checksum check_size_v(data.size(), sizeof(C_GuildCardChecksum_01E8)); @@ -1615,20 +1616,17 @@ void process_client_checksum_bb(shared_ptr, shared_ptr c, case 0x05E8: { // Delete guild card auto& cmd = check_size_t(data); auto& gcf = c->game_data.account()->guild_cards; - size_t z; - for (z = 0; z < max_count; z++) { + for (size_t z = 0; z < max_count; z++) { if (gcf.entries[z].data.guild_card_number == cmd.guild_card_number) { + c->log.info("Deleted guild card %" PRIu32 " at position %zu", + cmd.guild_card_number.load(), z); + for (z = 0; z < max_count - 1; z++) { + gcf.entries[z] = gcf.entries[z + 1]; + } + gcf.entries[max_count - 1].clear(); break; } } - if (z < max_count) { - c->log.info("Deleted guild card %" PRIu32 " at position %zu", - cmd.guild_card_number.load(), z); - for (z = 0; z < max_count - 1; z++) { - gcf.entries[z] = gcf.entries[z + 1]; - } - gcf.entries[max_count - 1].clear(); - } break; } case 0x06E8: { // Update guild card @@ -1644,15 +1642,36 @@ void process_client_checksum_bb(shared_ptr, shared_ptr c, break; } case 0x07E8: { // Add blocked user - // TODO: Where do these go in GuildCardFileBB? - // auto& cmd = check_size_t(data); - throw runtime_error("blocked users are not yet implemented on BB"); + auto& new_gc = check_size_t(data); + auto& gcf = c->game_data.account()->guild_cards; + for (size_t z = 0; z < max_blocked; z++) { + if (!gcf.blocked[z].present) { + gcf.blocked[z] = new_gc; + c->log.info("Added blocked guild card %" PRIu32 " at position %zu", + new_gc.guild_card_number.load(), z); + // Note: The client also sends a C6 command, so we don't have to + // manually sync the actual blocked senders list here + break; + } + } break; } case 0x08E8: { // Delete blocked user - // TODO: Where do these go in GuildCardFileBB? - // auto& cmd = check_size_t(data); - throw runtime_error("blocked users are not yet implemented on BB"); + auto& cmd = check_size_t(data); + auto& gcf = c->game_data.account()->guild_cards; + for (size_t z = 0; z < max_blocked; z++) { + if (gcf.blocked[z].guild_card_number == cmd.guild_card_number) { + c->log.info("Deleted blocked guild card %" PRIu32 " at position %zu", + cmd.guild_card_number.load(), z); + for (z = 0; z < max_blocked - 1; z++) { + gcf.blocked[z] = gcf.blocked[z + 1]; + } + gcf.blocked[max_blocked - 1].clear(); + // Note: The client also sends a C6 command, so we don't have to + // manually sync the actual blocked senders list here + break; + } + } break; } case 0x09E8: { // Write comment @@ -1932,8 +1951,13 @@ void process_disable_auto_reply(shared_ptr, shared_ptr c, void process_set_blocked_senders_list(shared_ptr, shared_ptr c, uint16_t, uint32_t, const string& data) { // C6 - const auto& cmd = check_size_t(data); - c->game_data.account()->blocked_senders = cmd.blocked_senders; + if (c->version == GameVersion::BB) { + const auto& cmd = check_size_t(data); + c->game_data.account()->blocked_senders = cmd.blocked_senders; + } else { + const auto& cmd = check_size_t(data); + c->game_data.account()->blocked_senders = cmd.blocked_senders; + } }