refine some BB structures
This commit is contained in:
+38
-20
@@ -11,6 +11,7 @@
|
||||
#include "Episode3/PlayerStateSubordinates.hh"
|
||||
#include "PSOProtocol.hh"
|
||||
#include "Player.hh"
|
||||
#include "SaveFileFormats.hh"
|
||||
#include "Text.hh"
|
||||
|
||||
#define __packed__ __attribute__((packed))
|
||||
@@ -2428,7 +2429,7 @@ struct C_CreateGame_BB_C1 : C_CreateGame<TextEncoding::UTF16> {
|
||||
// C2 (C->S): Set choice search parameters (DCv2 and later versions)
|
||||
// Internal name: PutChoiceList
|
||||
// Server does not respond.
|
||||
// The ChoiceSearchConfig structure is defined in Player.hh.
|
||||
// The ChoiceSearchConfig structure is defined in PlayerSubordinates.hh.
|
||||
|
||||
struct C_ChoiceSearchSelections_DC_C2_C3 : ChoiceSearchConfig<le_uint32_t> {
|
||||
} __packed__;
|
||||
@@ -2890,8 +2891,8 @@ struct S_TournamentEntryList_GC_Ep3_E2 {
|
||||
parray<Entry, 0x20> entries;
|
||||
} __packed__;
|
||||
|
||||
// E2 (S->C): Team and key config (BB)
|
||||
// See KeyAndTeamConfigBB in Player.hh for format
|
||||
// E2 (S->C): Set system file contents (BB)
|
||||
// See PSOBBSystemFile in SaveFileFormats.hh for format
|
||||
|
||||
// E3 (S->C): Game or tournament info (Episode 3)
|
||||
// The header.flag argument determines which fields are valid (and which panes
|
||||
@@ -3042,7 +3043,9 @@ struct S_ClientInit_BB_00E6 {
|
||||
le_uint32_t guild_card_number = 0;
|
||||
le_uint32_t team_id = 0;
|
||||
ClientConfigBB cfg;
|
||||
le_uint32_t caps = 0x00000102;
|
||||
uint8_t can_create_team = 1;
|
||||
uint8_t episode_4_unlocked = 1;
|
||||
parray<uint8_t, 2> unused;
|
||||
} __packed__;
|
||||
|
||||
// E7 (C->S): Create spectator team (Episode 3)
|
||||
@@ -3086,7 +3089,7 @@ struct SC_SyncCharacterSaveFile_BB_00E7 {
|
||||
/* 2DF8 */ parray<uint8_t, 0x0028> tech_menu_config; // player
|
||||
/* 2E20 */ parray<uint8_t, 0x002C> unknown_a6;
|
||||
/* 2E4C */ parray<le_uint32_t, 0x0016> quest_data2; // player
|
||||
/* 2EA4 */ KeyAndTeamConfigBB key_config; // account
|
||||
/* 2EA4 */ PSOBBSystemFile system_file; // account
|
||||
/* 3994 */
|
||||
} __attribute__((packed));
|
||||
|
||||
@@ -3171,7 +3174,7 @@ struct S_GuildCardChecksumResponse_BB_02E8 {
|
||||
// Server should send the guild card file data using DC commands.
|
||||
|
||||
// 04E8 (C->S): Add guild card
|
||||
// Format is GuildCardBB (see Player.hh)
|
||||
// Format is GuildCardBB (see PlayerSubordinates.hh)
|
||||
|
||||
// 05E8 (C->S): Delete guild card
|
||||
|
||||
@@ -3182,10 +3185,10 @@ struct C_DeleteGuildCard_BB_05E8_08E8 {
|
||||
// 06E8 (C->S): Update (overwrite) guild card
|
||||
// Note: This command is also sent when the player writes a comment on their own
|
||||
// guild card.
|
||||
// Format is GuildCardBB (see Player.hh)
|
||||
// Format is GuildCardBB (see PlayerSubordinates.hh)
|
||||
|
||||
// 07E8 (C->S): Add blocked user
|
||||
// Format is GuildCardBB (see Player.hh)
|
||||
// Format is GuildCardBB (see PlayerSubordinates.hh)
|
||||
|
||||
// 08E8 (C->S): Delete blocked user
|
||||
// Same format as 05E8.
|
||||
@@ -3444,19 +3447,33 @@ struct C_LeaveCharacterSelect_BB_00EC {
|
||||
// disbanded because the target game ends.
|
||||
|
||||
// ED (C->S): Update account data (BB)
|
||||
// There are several subcommands (noted in the union below) that each update a
|
||||
// There are several subcommands (noted in the structs below) that each update a
|
||||
// specific kind of account data.
|
||||
// TODO: Actually define these structures and don't just treat them as raw data
|
||||
|
||||
union C_UpdateAccountData_BB_ED {
|
||||
le_uint32_t option = 0; // 01ED
|
||||
parray<uint8_t, 0x4E0> symbol_chats; // 02ED
|
||||
parray<uint8_t, 0xA40> chat_shortcuts; // 03ED
|
||||
parray<uint8_t, 0x16C> key_config; // 04ED
|
||||
parray<uint8_t, 0x38> pad_config; // 05ED
|
||||
parray<uint8_t, 0x28> tech_menu; // 06ED
|
||||
parray<uint8_t, 0xE8> customize; // 07ED
|
||||
parray<uint8_t, 0x140> challenge_battle_config; // 08ED
|
||||
struct C_UpdateAccountOptionFlags_BB_01ED {
|
||||
le_uint32_t option_flags = 0;
|
||||
} __packed__;
|
||||
struct C_UpdateAccountSymbolChats_BB_02ED {
|
||||
parray<uint8_t, 0x4E0> symbol_chats;
|
||||
} __packed__;
|
||||
struct C_UpdateAccountChatShortcuts_BB_03ED {
|
||||
parray<uint8_t, 0xA40> chat_shortcuts;
|
||||
} __packed__;
|
||||
struct C_UpdateAccountKeyConfig_BB_04ED {
|
||||
parray<uint8_t, 0x16C> key_config;
|
||||
} __packed__;
|
||||
struct C_UpdateAccountPadConfig_BB_05ED {
|
||||
parray<uint8_t, 0x38> pad_config;
|
||||
} __packed__;
|
||||
struct C_UpdateAccountTechMenu_BB_06ED {
|
||||
parray<uint8_t, 0x28> tech_menu;
|
||||
} __packed__;
|
||||
struct C_UpdateAccountCustomizeMenu_BB_07ED {
|
||||
parray<uint8_t, 0xE8> customize;
|
||||
} __packed__;
|
||||
struct C_UpdateAccountChallengeAndBattleConfig_BB_08ED {
|
||||
parray<uint8_t, 0x140> challenge_battle_config;
|
||||
} __packed__;
|
||||
|
||||
// EE: Trade cards (Episode 3)
|
||||
@@ -3533,8 +3550,9 @@ struct S_SetShutdownCommand_BB_01EF {
|
||||
} __packed__;
|
||||
|
||||
// F0 (S->C): Force update player lobby data (BB)
|
||||
// Format is PlayerLobbyDataBB (in Player.hh). This command overwrites the lobby
|
||||
// data for the player given by .client_id without reloading the game or lobby.
|
||||
// Format is PlayerLobbyDataBB (in PlayerSubordinates.hh). This command
|
||||
// overwrites the lobby data for the player given by .client_id without
|
||||
// reloading the game or lobby.
|
||||
|
||||
// F1: Invalid command
|
||||
// F2: Invalid command
|
||||
|
||||
+3
-2
@@ -14,6 +14,7 @@
|
||||
#include "ItemNameIndex.hh"
|
||||
#include "LevelTable.hh"
|
||||
#include "PlayerSubordinates.hh"
|
||||
#include "SaveFileFormats.hh"
|
||||
#include "Text.hh"
|
||||
#include "Version.hh"
|
||||
|
||||
@@ -83,8 +84,8 @@ enum AccountFlag {
|
||||
struct SavedAccountDataBB { // .nsa file format
|
||||
pstring<TextEncoding::ASCII, 0x40> signature;
|
||||
parray<le_uint32_t, 0x001E> blocked_senders;
|
||||
GuildCardFileBB guild_cards;
|
||||
KeyAndTeamConfigBB key_config;
|
||||
PSOBBGuildCardFile guild_card_file;
|
||||
PSOBBSystemFile system_file;
|
||||
le_uint32_t newserv_flags;
|
||||
le_uint32_t option_flags;
|
||||
parray<uint8_t, 0x0A40> shortcuts;
|
||||
|
||||
@@ -221,15 +221,6 @@ void GuildCardBB::clear() {
|
||||
this->char_class = 0;
|
||||
}
|
||||
|
||||
void GuildCardEntryBB::clear() {
|
||||
this->data.clear();
|
||||
this->unknown_a1.clear(0);
|
||||
}
|
||||
|
||||
uint32_t GuildCardFileBB::checksum() const {
|
||||
return crc32(this, sizeof(*this));
|
||||
}
|
||||
|
||||
void PlayerBank::load(const string& filename) {
|
||||
*this = player_files_cache.get_obj_or_load<PlayerBank>(filename).obj;
|
||||
for (uint32_t x = 0; x < this->num_items; x++) {
|
||||
|
||||
@@ -236,39 +236,6 @@ struct GuildCardBB {
|
||||
void clear();
|
||||
} __attribute__((packed));
|
||||
|
||||
// an entry in the BB guild card file
|
||||
struct GuildCardEntryBB {
|
||||
GuildCardBB data;
|
||||
pstring<TextEncoding::UTF16, 0x58> comment;
|
||||
parray<uint8_t, 0x4> unknown_a1;
|
||||
|
||||
void clear();
|
||||
} __attribute__((packed));
|
||||
|
||||
// the format of the BB guild card file
|
||||
struct GuildCardFileBB {
|
||||
parray<uint8_t, 0x114> unknown_a1;
|
||||
GuildCardBB blocked[0x1C];
|
||||
parray<uint8_t, 0x180> unknown_a2;
|
||||
GuildCardEntryBB entries[0x69];
|
||||
|
||||
uint32_t checksum() const;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct KeyAndTeamConfigBB {
|
||||
parray<uint8_t, 0x0114> unknown_a1; // 0000
|
||||
parray<uint8_t, 0x016C> key_config; // 0114
|
||||
parray<uint8_t, 0x0038> joystick_config; // 0280
|
||||
le_uint32_t guild_card_number = 0; // 02B8
|
||||
le_uint32_t team_id = 0; // 02BC
|
||||
le_uint64_t team_info = 0; // 02C0
|
||||
le_uint16_t team_privilege_level = 0; // 02C8
|
||||
le_uint16_t reserved = 0; // 02CA
|
||||
pstring<TextEncoding::UTF16, 0x0010> team_name; // 02CC
|
||||
parray<uint8_t, 0x0800> team_flag; // 02EC
|
||||
le_uint32_t team_rewards = 0; // 0AEC
|
||||
} __attribute__((packed));
|
||||
|
||||
struct PlayerLobbyDataPC {
|
||||
le_uint32_t player_tag = 0;
|
||||
le_uint32_t guild_card = 0;
|
||||
|
||||
+46
-38
@@ -2905,7 +2905,7 @@ static void on_06(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
|
||||
|
||||
static void on_00E0_BB(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
|
||||
check_size_v(data.size(), 0);
|
||||
send_team_and_key_config_bb(c);
|
||||
send_system_file_bb(c);
|
||||
c->game_data.account()->newserv_flags &= ~AccountFlag::IN_DRESSING_ROOM;
|
||||
c->log.info("Cleared dressing room flag for account");
|
||||
}
|
||||
@@ -2941,12 +2941,12 @@ static void on_00E3_BB(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
|
||||
}
|
||||
|
||||
static void on_00E8_BB(shared_ptr<Client> c, uint16_t command, uint32_t, string& data) {
|
||||
constexpr size_t max_count = sizeof(GuildCardFileBB::entries) / sizeof(GuildCardEntryBB);
|
||||
constexpr size_t max_blocked = sizeof(GuildCardFileBB::blocked) / sizeof(GuildCardBB);
|
||||
constexpr size_t max_count = sizeof(PSOBBGuildCardFile::entries) / sizeof(PSOBBGuildCardFile::Entry);
|
||||
constexpr size_t max_blocked = sizeof(PSOBBGuildCardFile::blocked) / sizeof(GuildCardBB);
|
||||
switch (command) {
|
||||
case 0x01E8: { // Check guild card file checksum
|
||||
const auto& cmd = check_size_t<C_GuildCardChecksum_01E8>(data);
|
||||
uint32_t checksum = c->game_data.account()->guild_cards.checksum();
|
||||
uint32_t checksum = c->game_data.account()->guild_card_file.checksum();
|
||||
c->log.info("(Guild card file) Server checksum = %08" PRIX32 ", client checksum = %08" PRIX32,
|
||||
checksum, cmd.checksum.load());
|
||||
S_GuildCardChecksumResponse_BB_02E8 response = {
|
||||
@@ -2960,7 +2960,7 @@ static void on_00E8_BB(shared_ptr<Client> c, uint16_t command, uint32_t, string&
|
||||
break;
|
||||
case 0x04E8: { // Add guild card
|
||||
auto& new_gc = check_size_t<GuildCardBB>(data);
|
||||
auto& gcf = c->game_data.account()->guild_cards;
|
||||
auto& gcf = c->game_data.account()->guild_card_file;
|
||||
for (size_t z = 0; z < max_count; z++) {
|
||||
if (!gcf.entries[z].data.present) {
|
||||
gcf.entries[z].data = new_gc;
|
||||
@@ -2974,7 +2974,7 @@ static void on_00E8_BB(shared_ptr<Client> c, uint16_t command, uint32_t, string&
|
||||
}
|
||||
case 0x05E8: { // Delete guild card
|
||||
auto& cmd = check_size_t<C_DeleteGuildCard_BB_05E8_08E8>(data);
|
||||
auto& gcf = c->game_data.account()->guild_cards;
|
||||
auto& gcf = c->game_data.account()->guild_card_file;
|
||||
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",
|
||||
@@ -2990,7 +2990,7 @@ static void on_00E8_BB(shared_ptr<Client> c, uint16_t command, uint32_t, string&
|
||||
}
|
||||
case 0x06E8: { // Update guild card
|
||||
auto& new_gc = check_size_t<GuildCardBB>(data);
|
||||
auto& gcf = c->game_data.account()->guild_cards;
|
||||
auto& gcf = c->game_data.account()->guild_card_file;
|
||||
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;
|
||||
@@ -3002,7 +3002,7 @@ static void on_00E8_BB(shared_ptr<Client> c, uint16_t command, uint32_t, string&
|
||||
}
|
||||
case 0x07E8: { // Add blocked user
|
||||
auto& new_gc = check_size_t<GuildCardBB>(data);
|
||||
auto& gcf = c->game_data.account()->guild_cards;
|
||||
auto& gcf = c->game_data.account()->guild_card_file;
|
||||
for (size_t z = 0; z < max_blocked; z++) {
|
||||
if (!gcf.blocked[z].present) {
|
||||
gcf.blocked[z] = new_gc;
|
||||
@@ -3017,7 +3017,7 @@ static void on_00E8_BB(shared_ptr<Client> c, uint16_t command, uint32_t, string&
|
||||
}
|
||||
case 0x08E8: { // Delete blocked user
|
||||
auto& cmd = check_size_t<C_DeleteGuildCard_BB_05E8_08E8>(data);
|
||||
auto& gcf = c->game_data.account()->guild_cards;
|
||||
auto& gcf = c->game_data.account()->guild_card_file;
|
||||
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",
|
||||
@@ -3035,7 +3035,7 @@ static void on_00E8_BB(shared_ptr<Client> c, uint16_t command, uint32_t, string&
|
||||
}
|
||||
case 0x09E8: { // Write comment
|
||||
auto& cmd = check_size_t<C_WriteGuildCardComment_BB_09E8>(data);
|
||||
auto& gcf = c->game_data.account()->guild_cards;
|
||||
auto& gcf = c->game_data.account()->guild_card_file;
|
||||
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;
|
||||
@@ -3048,7 +3048,7 @@ static void on_00E8_BB(shared_ptr<Client> c, uint16_t command, uint32_t, string&
|
||||
}
|
||||
case 0x0AE8: { // Move guild card in list
|
||||
auto& cmd = check_size_t<C_MoveGuildCard_BB_0AE8>(data);
|
||||
auto& gcf = c->game_data.account()->guild_cards;
|
||||
auto& gcf = c->game_data.account()->guild_card_file;
|
||||
if (cmd.position >= max_count) {
|
||||
throw invalid_argument("invalid new position");
|
||||
}
|
||||
@@ -3157,37 +3157,47 @@ static void on_00E5_BB(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
|
||||
}
|
||||
|
||||
static void on_xxED_BB(shared_ptr<Client> c, uint16_t command, uint32_t, string& data) {
|
||||
const auto* cmd = reinterpret_cast<const C_UpdateAccountData_BB_ED*>(data.data());
|
||||
|
||||
switch (command) {
|
||||
case 0x01ED:
|
||||
check_size_v(data.size(), sizeof(cmd->option));
|
||||
c->game_data.account()->option_flags = cmd->option;
|
||||
case 0x01ED: {
|
||||
const auto& cmd = check_size_t<C_UpdateAccountOptionFlags_BB_01ED>(data);
|
||||
c->game_data.account()->option_flags = cmd.option_flags;
|
||||
break;
|
||||
case 0x02ED:
|
||||
check_size_v(data.size(), sizeof(cmd->symbol_chats));
|
||||
c->game_data.account()->symbol_chats = cmd->symbol_chats;
|
||||
}
|
||||
case 0x02ED: {
|
||||
const auto& cmd = check_size_t<C_UpdateAccountSymbolChats_BB_02ED>(data);
|
||||
c->game_data.account()->symbol_chats = cmd.symbol_chats;
|
||||
break;
|
||||
case 0x03ED:
|
||||
check_size_v(data.size(), sizeof(cmd->chat_shortcuts));
|
||||
c->game_data.account()->shortcuts = cmd->chat_shortcuts;
|
||||
}
|
||||
case 0x03ED: {
|
||||
const auto& cmd = check_size_t<C_UpdateAccountChatShortcuts_BB_03ED>(data);
|
||||
c->game_data.account()->shortcuts = cmd.chat_shortcuts;
|
||||
break;
|
||||
case 0x04ED:
|
||||
check_size_v(data.size(), sizeof(cmd->key_config));
|
||||
c->game_data.account()->key_config.key_config = cmd->key_config;
|
||||
}
|
||||
case 0x04ED: {
|
||||
const auto& cmd = check_size_t<C_UpdateAccountKeyConfig_BB_04ED>(data);
|
||||
c->game_data.account()->system_file.key_config = cmd.key_config;
|
||||
break;
|
||||
case 0x05ED:
|
||||
check_size_v(data.size(), sizeof(cmd->pad_config));
|
||||
c->game_data.account()->key_config.joystick_config = cmd->pad_config;
|
||||
}
|
||||
case 0x05ED: {
|
||||
const auto& cmd = check_size_t<C_UpdateAccountPadConfig_BB_05ED>(data);
|
||||
c->game_data.account()->system_file.joystick_config = cmd.pad_config;
|
||||
break;
|
||||
case 0x06ED:
|
||||
check_size_v(data.size(), sizeof(cmd->tech_menu));
|
||||
c->game_data.player()->tech_menu_config = cmd->tech_menu;
|
||||
}
|
||||
case 0x06ED: {
|
||||
const auto& cmd = check_size_t<C_UpdateAccountTechMenu_BB_06ED>(data);
|
||||
c->game_data.player()->tech_menu_config = cmd.tech_menu;
|
||||
break;
|
||||
case 0x07ED:
|
||||
check_size_v(data.size(), sizeof(cmd->customize));
|
||||
c->game_data.player()->disp.config = cmd->customize;
|
||||
}
|
||||
case 0x07ED: {
|
||||
const auto& cmd = check_size_t<C_UpdateAccountCustomizeMenu_BB_07ED>(data);
|
||||
c->game_data.player()->disp.config = cmd.customize;
|
||||
break;
|
||||
}
|
||||
case 0x08ED: {
|
||||
check_size_t<C_UpdateAccountChallengeAndBattleConfig_BB_08ED>(data);
|
||||
// TODO: Save this data appropriately
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw invalid_argument("unknown account command");
|
||||
}
|
||||
@@ -3208,10 +3218,8 @@ static void on_00E7_BB(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
|
||||
}
|
||||
|
||||
static void on_00E2_BB(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
|
||||
// Some clients have only a uint32_t at the end for team rewards
|
||||
auto& cmd = check_size_t<KeyAndTeamConfigBB>(data,
|
||||
sizeof(KeyAndTeamConfigBB) - 4, sizeof(KeyAndTeamConfigBB));
|
||||
c->game_data.account()->key_config = cmd;
|
||||
auto& cmd = check_size_t<PSOBBSystemFile>(data);
|
||||
c->game_data.account()->system_file = cmd;
|
||||
}
|
||||
|
||||
static void on_89(shared_ptr<Client> c, uint16_t, uint32_t flag, string& data) {
|
||||
|
||||
@@ -180,3 +180,12 @@ Image PSOGCSnapshotFile::decode_image() const {
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void PSOBBGuildCardFile::Entry::clear() {
|
||||
this->data.clear();
|
||||
this->unknown_a1.clear(0);
|
||||
}
|
||||
|
||||
uint32_t PSOBBGuildCardFile::checksum() const {
|
||||
return crc32(this, sizeof(*this));
|
||||
}
|
||||
|
||||
+48
-1
@@ -10,8 +10,9 @@
|
||||
#include <phosg/Strings.hh>
|
||||
#include <string>
|
||||
|
||||
#include "Episode3/DataIndexes.hh"
|
||||
#include "PSOEncryption.hh"
|
||||
#include "Player.hh"
|
||||
#include "PlayerSubordinates.hh"
|
||||
#include "Text.hh"
|
||||
|
||||
struct ShuffleTables {
|
||||
@@ -117,6 +118,52 @@ struct PSOGCEp3SystemFile {
|
||||
/* 012C */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct PSOBBSystemFileBase {
|
||||
/* 0000 */ be_uint32_t checksum = 0;
|
||||
/* 0004 */ be_int16_t music_volume = -50;
|
||||
/* 0006 */ int8_t sound_volume = 0;
|
||||
/* 0007 */ uint8_t language = 0;
|
||||
/* 0008 */ be_uint32_t server_time_delta_frames = 1728000;
|
||||
/* 000C */ be_uint16_t udp_behavior = 0; // 0 = auto, 1 = on, 2 = off
|
||||
/* 000E */ be_uint16_t surround_sound_enabled = 0;
|
||||
/* 0010 */ parray<uint8_t, 0x0100> event_flags;
|
||||
/* 0110 */ le_uint32_t creation_timestamp = 0;
|
||||
/* 0114 */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct PSOBBSystemFile {
|
||||
/* 0000 */ PSOBBSystemFileBase base;
|
||||
/* 0114 */ parray<uint8_t, 0x016C> key_config;
|
||||
/* 0280 */ parray<uint8_t, 0x0038> joystick_config;
|
||||
/* 02B8 */ le_uint32_t guild_card_number = 0;
|
||||
/* 02BC */ le_uint32_t team_id = 0;
|
||||
/* 02C0 */ le_uint64_t team_info = 0;
|
||||
/* 02C8 */ le_uint16_t team_privilege_level = 0;
|
||||
/* 02CA */ le_uint16_t reserved = 0;
|
||||
/* 02CC */ pstring<TextEncoding::UTF16, 0x0010> team_name;
|
||||
/* 02EC */ parray<uint8_t, 0x0800> team_flag;
|
||||
/* 0AEC */ le_uint32_t team_rewards = 0;
|
||||
/* 0AF0 */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct PSOBBGuildCardFile {
|
||||
struct Entry {
|
||||
/* 0000 */ GuildCardBB data;
|
||||
/* 0108 */ pstring<TextEncoding::UTF16, 0x58> comment;
|
||||
/* 01B8 */ parray<uint8_t, 0x4> unknown_a1;
|
||||
/* 01BC */
|
||||
|
||||
void clear();
|
||||
} __attribute__((packed));
|
||||
|
||||
PSOBBSystemFileBase system_file;
|
||||
parray<GuildCardBB, 0x1C> blocked;
|
||||
parray<uint8_t, 0x180> unknown_a2;
|
||||
parray<Entry, 0x69> entries;
|
||||
|
||||
uint32_t checksum() const;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct PSOGCSaveFileSymbolChatEntry {
|
||||
/* 00 */ be_uint32_t present;
|
||||
/* 04 */ pstring<TextEncoding::SJIS, 0x18> name;
|
||||
|
||||
+10
-11
@@ -476,12 +476,13 @@ void send_client_init_bb(shared_ptr<Client> c, uint32_t error) {
|
||||
cmd.guild_card_number = c->license->serial_number;
|
||||
cmd.team_id = static_cast<uint32_t>(random_object<uint32_t>());
|
||||
cmd.cfg = c->export_config_bb();
|
||||
cmd.caps = 0x00000102;
|
||||
cmd.can_create_team = 1;
|
||||
cmd.episode_4_unlocked = 1;
|
||||
send_command_t(c, 0x00E6, 0x00000000, cmd);
|
||||
}
|
||||
|
||||
void send_team_and_key_config_bb(shared_ptr<Client> c) {
|
||||
send_command_t(c, 0x00E2, 0x00000000, c->game_data.account()->key_config);
|
||||
void send_system_file_bb(shared_ptr<Client> c) {
|
||||
send_command_t(c, 0x00E2, 0x00000000, c->game_data.account()->system_file);
|
||||
}
|
||||
|
||||
void send_player_preview_bb(shared_ptr<Client> c, uint8_t player_index,
|
||||
@@ -499,26 +500,24 @@ void send_player_preview_bb(shared_ptr<Client> c, uint8_t player_index,
|
||||
}
|
||||
|
||||
void send_guild_card_header_bb(shared_ptr<Client> c) {
|
||||
uint32_t checksum = c->game_data.account()->guild_cards.checksum();
|
||||
S_GuildCardHeader_BB_01DC cmd = {1, sizeof(GuildCardFileBB), checksum};
|
||||
uint32_t checksum = c->game_data.account()->guild_card_file.checksum();
|
||||
S_GuildCardHeader_BB_01DC cmd = {1, sizeof(PSOBBGuildCardFile), checksum};
|
||||
send_command_t(c, 0x01DC, 0x00000000, cmd);
|
||||
}
|
||||
|
||||
void send_guild_card_chunk_bb(shared_ptr<Client> c, size_t chunk_index) {
|
||||
size_t chunk_offset = chunk_index * 0x6800;
|
||||
if (chunk_offset >= sizeof(GuildCardFileBB)) {
|
||||
if (chunk_offset >= sizeof(PSOBBGuildCardFile)) {
|
||||
throw logic_error("attempted to send chunk beyond end of guild card file");
|
||||
}
|
||||
|
||||
S_GuildCardFileChunk_02DC cmd;
|
||||
|
||||
size_t data_size = min<size_t>(
|
||||
sizeof(GuildCardFileBB) - chunk_offset, sizeof(cmd.data));
|
||||
|
||||
size_t data_size = min<size_t>(sizeof(PSOBBGuildCardFile) - chunk_offset, sizeof(cmd.data));
|
||||
cmd.unknown = 0;
|
||||
cmd.chunk_index = chunk_index;
|
||||
cmd.data.assign_range(
|
||||
reinterpret_cast<const uint8_t*>(&c->game_data.account()->guild_cards) + chunk_offset,
|
||||
reinterpret_cast<const uint8_t*>(&c->game_data.account()->guild_card_file) + chunk_offset,
|
||||
data_size, 0);
|
||||
|
||||
send_command(c, 0x02DC, 0x00000000, &cmd, sizeof(cmd) - sizeof(cmd.data) + data_size);
|
||||
@@ -643,7 +642,7 @@ void send_complete_player_bb(shared_ptr<Client> c) {
|
||||
cmd.tech_menu_config = player->tech_menu_config;
|
||||
cmd.unknown_a6.clear(0);
|
||||
cmd.quest_data2 = player->quest_data2;
|
||||
cmd.key_config = account->key_config;
|
||||
cmd.system_file = account->system_file;
|
||||
|
||||
send_command_t(c, 0x00E7, 0x00000000, cmd);
|
||||
}
|
||||
|
||||
+1
-1
@@ -160,7 +160,7 @@ void send_pc_console_split_reconnect(
|
||||
uint16_t console_port);
|
||||
|
||||
void send_client_init_bb(std::shared_ptr<Client> c, uint32_t error);
|
||||
void send_team_and_key_config_bb(std::shared_ptr<Client> c);
|
||||
void send_system_file_bb(std::shared_ptr<Client> c);
|
||||
void send_player_preview_bb(std::shared_ptr<Client> c, uint8_t player_index,
|
||||
const PlayerDispDataBBPreview* preview);
|
||||
void send_accept_client_checksum_bb(std::shared_ptr<Client> c);
|
||||
|
||||
Reference in New Issue
Block a user