From 7c28ee05ccdcedf2361252d29334d5afc92915ae Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Sat, 30 Jul 2022 12:19:46 -0700 Subject: [PATCH] fix bb guild card save; implement comments --- README.md | 1 - src/CommandFormats.hh | 8 +++---- src/Player.cc | 14 +++++------ src/Player.hh | 23 +++++++----------- src/ReceiveCommands.cc | 54 +++++++++++++++++++++--------------------- src/SendCommands.cc | 8 +++---- 6 files changed, 51 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index 688fc5c7..d99a5984 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,6 @@ Feel free to submit GitHub issues if you find bugs or have feature requests. I'd This project is primarily for my own nostalgia; I offer no guarantees on how or when this project will advance. Current known issues / missing features: -- Guild card file modifications don't save on BB. - Episode 3 battles aren't implemented. - PSOBB is not well-tested and likely will disconnect or misbehave when clients try to use unimplemented features. GC is known to be stable and mostly complete; PC is not well-tested but is likely stable and complete as well. - Patches currently are platform-specific but not version-specific. This makes them quite a bit harder to write and use properly. diff --git a/src/CommandFormats.hh b/src/CommandFormats.hh index b4b684b4..7fd60d59 100644 --- a/src/CommandFormats.hh +++ b/src/CommandFormats.hh @@ -2607,8 +2607,8 @@ struct G_SendGuildCard_PC_V3 { ptext name; ptext description; parray unused2; - uint8_t reserved1; - uint8_t reserved2; + uint8_t present; + uint8_t present2; uint8_t section_id; uint8_t char_class; }; @@ -2623,8 +2623,8 @@ struct G_SendGuildCard_BB_6x06 { ptext name; ptext team_name; ptext description; - uint8_t reserved1; - uint8_t reserved2; + uint8_t present; + uint8_t present2; uint8_t section_id; uint8_t char_class; }; diff --git a/src/Player.cc b/src/Player.cc index c318df78..d6a84b26 100644 --- a/src/Player.cc +++ b/src/Player.cc @@ -269,16 +269,16 @@ PlayerDispDataBBPreview::PlayerDispDataBBPreview() noexcept GuildCardV3::GuildCardV3() noexcept : player_tag(0), - serial_number(0), - reserved1(1), - reserved2(1), + guild_card_number(0), + present(0), + present2(0), section_id(0), char_class(0) { } GuildCardBB::GuildCardBB() noexcept : guild_card_number(0), - reserved1(1), - reserved2(1), + present(0), + present2(0), section_id(0), char_class(0) { } @@ -287,8 +287,8 @@ void GuildCardBB::clear() { this->name.clear(); this->team_name.clear(); this->description.clear(); - this->reserved1 = 1; - this->reserved2 = 1; + this->present = 0; + this->present2 = 0; this->section_id = 0; this->char_class = 0; } diff --git a/src/Player.hh b/src/Player.hh index c7deedc8..8a4b9e50 100644 --- a/src/Player.hh +++ b/src/Player.hh @@ -211,11 +211,11 @@ struct PlayerDispDataBB { // GC format) struct GuildCardV3 { le_uint32_t player_tag; - le_uint32_t serial_number; + le_uint32_t guild_card_number; ptext name; ptext description; - uint8_t reserved1; // should be 1 - uint8_t reserved2; // should be 1 + uint8_t present; // should be 1 + uint8_t present2; // should be 1 uint8_t section_id; uint8_t char_class; @@ -228,8 +228,8 @@ struct GuildCardBB { ptext name; ptext team_name; ptext description; - uint8_t reserved1; // should be 1 - uint8_t reserved2; // should be 1 + uint8_t present; // should be 1 if guild card entry exists + uint8_t present2; // should be 1 if guild card entry exists uint8_t section_id; uint8_t char_class; @@ -240,21 +240,16 @@ struct GuildCardBB { // an entry in the BB guild card file struct GuildCardEntryBB { GuildCardBB data; - // TODO: Almost all of this space (0x58 char16_ts) is probably the comment, - // but is the unknown 4 bytes at the beginning or end of this space? - parray unknown_a1; + ptext comment; + parray unknown_a1; void clear(); } __attribute__((packed)); // the format of the BB guild card file struct GuildCardFileBB { - parray unknown_a1; - uint8_t num_guild_cards; // TODO: This is a guess. Verify this. - uint8_t unknown_a2; - parray unknown_a3; - GuildCardEntryBB entries[0x0068]; // that's 104 of them in decimal - parray unknown_a4; + parray unknown_a3; + GuildCardEntryBB entries[0x0069]; // that's 105 of them in decimal } __attribute__((packed)); struct KeyAndTeamConfigBB { diff --git a/src/ReceiveCommands.cc b/src/ReceiveCommands.cc index 8003fa23..1f2ac075 100644 --- a/src/ReceiveCommands.cc +++ b/src/ReceiveCommands.cc @@ -1583,6 +1583,7 @@ 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); switch (command) { case 0x01E8: { // Check guild card file checksum check_size_v(data.size(), sizeof(C_GuildCardChecksum_01E8)); @@ -1600,12 +1601,14 @@ void process_client_checksum_bb(shared_ptr, shared_ptr c, case 0x04E8: { // Add guild card auto& new_gc = check_size_t(data); auto& gcf = c->game_data.account()->guild_cards; - if (gcf.num_guild_cards < sizeof(gcf.entries) / sizeof(gcf.entries[0])) { - gcf.entries[gcf.num_guild_cards].data = new_gc; - gcf.entries[gcf.num_guild_cards].unknown_a1.clear(); - c->log.info("Added guild card %" PRIu32 " at position %hhu", - new_gc.guild_card_number.load(), gcf.num_guild_cards); - gcf.num_guild_cards++; + for (size_t z = 0; z < max_count; z++) { + if (!gcf.entries[z].data.present) { + gcf.entries[z].data = new_gc; + gcf.entries[z].unknown_a1.clear(); + c->log.info("Added guild card %" PRIu32 " at position %zu", + new_gc.guild_card_number.load(), z); + break; + } } break; } @@ -1613,25 +1616,25 @@ void process_client_checksum_bb(shared_ptr, shared_ptr c, auto& cmd = check_size_t(data); auto& gcf = c->game_data.account()->guild_cards; size_t z; - for (z = 0; z < gcf.num_guild_cards; z++) { + for (z = 0; z < max_count; z++) { if (gcf.entries[z].data.guild_card_number == cmd.guild_card_number) { break; } } - if (z < gcf.num_guild_cards) { + if (z < max_count) { c->log.info("Deleted guild card %" PRIu32 " at position %zu", cmd.guild_card_number.load(), z); - gcf.num_guild_cards--; - for (z = 0; z < gcf.num_guild_cards; 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 auto& new_gc = check_size_t(data); auto& gcf = c->game_data.account()->guild_cards; - for (size_t z = 0; z < gcf.num_guild_cards; z++) { + for (size_t z = 0; z < max_count; z++) { if (gcf.entries[z].data.guild_card_number == new_gc.guild_card_number) { gcf.entries[z].data = new_gc; c->log.info("Updated guild card %" PRIu32 " at position %zu", @@ -1653,34 +1656,31 @@ void process_client_checksum_bb(shared_ptr, shared_ptr c, break; } case 0x09E8: { // Write comment - // TODO: We need to know the comment storage format in the guild card file - // in order to implement this (see comment in Player.hh). The - // implementation should go very much like this: - // auto& cmd = check_size_t(data); - // auto& gcf = c->game_data.account()->guild_cards; - // for (size_t z = 0; z < gcf.num_guild_cards; z++) { - // if (gcf.entries[z].data.guild_card_number == cmd.guild_card_number) { - // gcf.entries[z].comment = cmd.comment; - // c->log.info("Updated comment on guild card %" PRIu32 " at position %zu", - // cmd.guild_card_number.load(), z); - // } - // } - throw runtime_error("guild card comments 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_count; z++) { + if (gcf.entries[z].data.guild_card_number == cmd.guild_card_number) { + gcf.entries[z].comment = cmd.comment; + c->log.info("Updated comment on guild card %" PRIu32 " at position %zu", + cmd.guild_card_number.load(), z); + break; + } + } break; } case 0x0AE8: { // Move guild card in list auto& cmd = check_size_t(data); auto& gcf = c->game_data.account()->guild_cards; - if (cmd.position >= gcf.num_guild_cards) { + if (cmd.position >= max_count) { throw invalid_argument("invalid new position"); } size_t index; - for (index = 0; index < gcf.num_guild_cards; index++) { + for (index = 0; index < max_count; index++) { if (gcf.entries[index].data.guild_card_number == cmd.guild_card_number) { break; } } - if (index >= gcf.num_guild_cards) { + if (index >= max_count) { throw invalid_argument("player does not have requested guild card"); } auto moved_gc = gcf.entries[index]; diff --git a/src/SendCommands.cc b/src/SendCommands.cc index c37d48f4..bf6367da 100644 --- a/src/SendCommands.cc +++ b/src/SendCommands.cc @@ -706,8 +706,8 @@ void send_guild_card_pc_v3_t(shared_ptr c, shared_ptr source) { cmd.name = source->game_data.player()->disp.name; remove_language_marker_inplace(cmd.name); cmd.description = source->game_data.player()->guild_card_description; - cmd.reserved1 = 1; - cmd.reserved2 = 1; + 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); @@ -722,8 +722,8 @@ void send_guild_card_bb(shared_ptr c, shared_ptr source) { 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.reserved1 = 1; - cmd.reserved2 = 1; + 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);