diff --git a/src/Episode3/DataIndex.hh b/src/Episode3/DataIndex.hh index 2a2cec9b..ff19474e 100644 --- a/src/Episode3/DataIndex.hh +++ b/src/Episode3/DataIndex.hh @@ -582,29 +582,48 @@ struct DeckDefinition { } __attribute__((packed)); // 0x84 bytes in total struct PlayerConfig { - // Offsets in comments in this struct are relative to start of 61/98 command - /* 0728 */ parray unknown_a1; - /* 087C */ uint8_t is_encrypted; - /* 087D */ uint8_t basis; - /* 087E */ parray unknown_a3; + // The first offsets in the comments in this struct are relative to start of + // 61/98 command; the second are relative to the start of the + // Ep3PlayerDataSegment structure in the reverse-engineering project. + // TODO: Fill in the unknown fields here by looking around callsites of + // get_player_data_segment + /* 0728:---- */ parray unknown_a1; + /* 087C:0000 */ uint8_t is_encrypted; + /* 087D:0001 */ uint8_t basis; + /* 087E:0002 */ parray unused; // The following fields (here through the beginning of decks) are encrypted // using the trivial algorithm, with the basis specified above, if // is_encrypted is equal to 1. - /* 0880 */ parray card_counts; - /* 0B70 */ parray unknown_a4; - /* 0C9A */ parray unknown_a5; - // This field appears to be doubly-encrypted, likely with the same trivial - // algorithm (but not the same basis). - /* 0CCC */ parray unknown_a6; - /* 0D3C */ parray unknown_a7; - /* 1B5C */ parray decks; - /* 2840 */ uint64_t unknown_a8; - /* 2848 */ be_uint32_t offline_clv_exp; // CLvOff = this / 100 - /* 284C */ be_uint32_t online_clv_exp; // CLvOn = this / 100 - /* 2850 */ parray unknown_a9; - /* 299C */ ptext name; - // Other records are probably somewhere in here - e.g. win/loss, play time, etc. - /* 29AC */ parray unknown_a10; + // It appears the card counts field in this structure is actually 1000 (0x3E8) + // bytes long, even though in every other place the counts array appears it's + // 0x2F0 bytes long. They presumably did this because of the checksum logic. + /* 0880:0004 */ parray card_counts; + // These are a form of checksum of the card counts array, but they don't cover + // the entire array and instead read from later parts of this structure. This + // appears to be due to a copy/paste error in the original code. The algorithm + // sums the card_counts [0] through [19] and places that sum in + // card_count_checksums[0], then sums card counts [50] through [69] and places + // that sum in card_count_checksums[1], etc. Presumably they intended to use + // 20 as the stride instead of 50, which would have exactly covered the entire + // card_counts array. + /* 0C68:03EC */ parray card_count_checksums; + // Yes, these are actually 64-bit integers. They include card IDs and some + // other data, encoded in a way I don't fully understand yet. + /* 0CCC:0450 */ parray unknown_a4; + /* 1ADC:1260 */ parray unknown_a7; + /* 1B5C:12E0 */ parray decks; + /* 2840:1FC4 */ parray unknown_a8; + /* 2848:1FCC */ be_uint32_t offline_clv_exp; // CLvOff = this / 100 + /* 284C:1FD0 */ be_uint32_t online_clv_exp; // CLvOn = this / 100 + struct UnknownA9 { + /* 00 */ be_uint32_t unknown_a1; + /* 04 */ ptext unknown_a2; + } __attribute__((packed)); + /* 2850:1FD4 */ parray unknown_a9; + /* 294C:20D0 */ parray unknown_a10; + /* 299C:2120 */ ptext name; + /* 29AC:2130 */ parray unknown_a11; + /* 2A78:21FC */ } __attribute__((packed)); enum class HPType : uint8_t { diff --git a/src/Player.hh b/src/Player.hh index d7ab0389..dcb58b17 100644 --- a/src/Player.hh +++ b/src/Player.hh @@ -370,6 +370,8 @@ struct PlayerChallengeDataV3 { parray unknown_a6; // 0x18 bytes parray unknown_a7; } __attribute__((packed)) unknown_a1; // 0x100 bytes + // On Episode 3, unknown_a2[0] is win count, [1] is loss count, and [4] is + // disconnect count parray unknown_a2; parray unknown_a3; } __attribute__((packed)); // 0x11C bytes diff --git a/src/ProxyCommands.cc b/src/ProxyCommands.cc index ce225237..ad828b23 100644 --- a/src/ProxyCommands.cc +++ b/src/ProxyCommands.cc @@ -1016,7 +1016,17 @@ static HandlerResult C_GXB_61(shared_ptr, } else { PSOPlayerDataV3* pd; if (flag == 4) { // Episode 3 - pd = reinterpret_cast(&check_size_t(data)); + auto& ep3_pd = check_size_t(data); + if (ep3_pd.ep3_config.is_encrypted) { + decrypt_trivial_gci_data( + &ep3_pd.ep3_config.card_counts, + offsetof(Episode3::PlayerConfig, decks) - offsetof(Episode3::PlayerConfig, card_counts), + ep3_pd.ep3_config.basis); + ep3_pd.ep3_config.is_encrypted = 0; + ep3_pd.ep3_config.basis = 0; + modified = true; + } + pd = reinterpret_cast(&ep3_pd); } else { pd = &check_size_t(data, sizeof(PSOPlayerDataV3), 0xFFFF); }