split team membership struct from base BB system file
This commit is contained in:
+1
-1
@@ -1418,7 +1418,7 @@ static void server_command_edit(shared_ptr<Client> c, const std::string& args) {
|
||||
p->guild_card.language = new_language;
|
||||
auto sys = c->system_file(false);
|
||||
if (sys) {
|
||||
sys->base.language = new_language;
|
||||
sys->language = new_language;
|
||||
}
|
||||
} else if (tokens.at(0) == "secid" && cheats_allowed) {
|
||||
uint8_t secid = section_id_for_name(tokens.at(1));
|
||||
|
||||
+12
-58
@@ -759,32 +759,24 @@ void Client::load_all_files() {
|
||||
if (this->character_data) {
|
||||
player_data_log.info("Using loaded character file %s", char_filename.c_str());
|
||||
} else if (phosg::isfile(char_filename)) {
|
||||
auto f = phosg::fopen_unique(char_filename, "rb");
|
||||
auto header = phosg::freadx<PSOCommandHeaderBB>(f.get());
|
||||
if (header.size != 0x399C) {
|
||||
throw runtime_error("incorrect size in character file header");
|
||||
}
|
||||
if (header.command != 0x00E7) {
|
||||
throw runtime_error("incorrect command in character file header");
|
||||
}
|
||||
if (header.flag != 0x00000000) {
|
||||
throw runtime_error("incorrect flag in character file header");
|
||||
}
|
||||
static_assert(sizeof(PSOBBCharacterFile) + sizeof(PSOBBFullSystemFile) == 0x3994, ".psochar size is incorrect");
|
||||
this->character_data = make_shared<PSOBBCharacterFile>(phosg::freadx<PSOBBCharacterFile>(f.get()));
|
||||
auto psochar = load_psochar(char_filename, !this->system_data);
|
||||
this->character_data = psochar.character_file;
|
||||
files_manager->set_character(char_filename, this->character_data);
|
||||
player_data_log.info("Loaded character data from %s", char_filename.c_str());
|
||||
|
||||
// If there was no .psosys file, load the system file from the .psochar
|
||||
// If there was no .psosys file, use the system file from the .psochar
|
||||
// file instead
|
||||
if (!this->system_data) {
|
||||
this->system_data = make_shared<PSOBBBaseSystemFile>(phosg::freadx<PSOBBBaseSystemFile>(f.get()));
|
||||
if (!psochar.system_file) {
|
||||
throw logic_error("account system data not present, and also not loaded from psochar file");
|
||||
}
|
||||
this->system_data = psochar.system_file;
|
||||
files_manager->set_system(sys_filename, this->system_data);
|
||||
player_data_log.info("Loaded system data from %s", char_filename.c_str());
|
||||
}
|
||||
|
||||
this->update_character_data_after_load(this->character_data);
|
||||
this->system_data->base.language = this->language();
|
||||
this->system_data->language = this->language();
|
||||
|
||||
} else {
|
||||
player_data_log.info("Character file is missing: %s", char_filename.c_str());
|
||||
@@ -813,7 +805,7 @@ void Client::load_all_files() {
|
||||
throw runtime_error("account data header is incorrect");
|
||||
}
|
||||
if (!this->system_data) {
|
||||
this->system_data = make_shared<PSOBBBaseSystemFile>(nsa_data->system_file.base);
|
||||
this->system_data = make_shared<PSOBBBaseSystemFile>(nsa_data->system_file);
|
||||
files_manager->set_system(sys_filename, this->system_data);
|
||||
player_data_log.info("Loaded legacy system data from %s", nsa_filename.c_str());
|
||||
}
|
||||
@@ -949,23 +941,7 @@ void Client::save_character_file(
|
||||
const string& filename,
|
||||
shared_ptr<const PSOBBBaseSystemFile> system,
|
||||
shared_ptr<const PSOBBCharacterFile> character) {
|
||||
auto f = phosg::fopen_unique(filename, "wb");
|
||||
PSOCommandHeaderBB header = {sizeof(PSOCommandHeaderBB) + sizeof(PSOBBCharacterFile) + sizeof(PSOBBBaseSystemFile) + sizeof(PSOBBTeamMembership), 0x00E7, 0x00000000};
|
||||
phosg::fwritex(f.get(), header);
|
||||
phosg::fwritex(f.get(), *character);
|
||||
phosg::fwritex(f.get(), *system);
|
||||
// TODO: Technically, we should write the actual team membership struct to the
|
||||
// file here, but that would cause Client to depend on Account, which
|
||||
// it currently does not. This data doesn't matter at all for correctness
|
||||
// within newserv, since it ignores this data entirely and instead generates
|
||||
// the membership struct from the team ID in the Account and the team's state.
|
||||
// So, writing correct data here would mostly be for compatibility with other
|
||||
// PSO servers. But if the other server is newserv, then this data would be
|
||||
// used anyway, and if it's not, then it would presumably have a different set
|
||||
// of teams with a different set of team IDs anyway, so the membership struct
|
||||
// here would be useless either way.
|
||||
static const PSOBBTeamMembership empty_membership;
|
||||
phosg::fwritex(f.get(), empty_membership);
|
||||
save_psochar(filename, system, character);
|
||||
player_data_log.info("Saved character file %s", filename.c_str());
|
||||
}
|
||||
|
||||
@@ -1007,18 +983,7 @@ void Client::save_guild_card_file() const {
|
||||
|
||||
void Client::load_backup_character(uint32_t account_id, size_t index) {
|
||||
string filename = this->backup_character_filename(account_id, index, false);
|
||||
auto f = phosg::fopen_unique(filename, "rb");
|
||||
auto header = phosg::freadx<PSOCommandHeaderBB>(f.get());
|
||||
if (header.size != 0x399C) {
|
||||
throw runtime_error("incorrect size in character file header");
|
||||
}
|
||||
if (header.command != 0x00E7) {
|
||||
throw runtime_error("incorrect command in character file header");
|
||||
}
|
||||
if (header.flag != 0x00000000) {
|
||||
throw runtime_error("incorrect flag in character file header");
|
||||
}
|
||||
this->character_data = make_shared<PSOBBCharacterFile>(phosg::freadx<PSOBBCharacterFile>(f.get()));
|
||||
this->character_data = load_psochar(filename, false).character_file;
|
||||
this->update_character_data_after_load(this->character_data);
|
||||
this->v1_v2_last_reported_disp.reset();
|
||||
}
|
||||
@@ -1106,18 +1071,7 @@ void Client::use_character_bank(int8_t index) {
|
||||
this->external_bank_character_index = index;
|
||||
player_data_log.info("Using loaded character file %s for external bank", filename.c_str());
|
||||
} else if (phosg::isfile(filename)) {
|
||||
auto f = phosg::fopen_unique(filename, "rb");
|
||||
auto header = phosg::freadx<PSOCommandHeaderBB>(f.get());
|
||||
if (header.size != 0x399C) {
|
||||
throw runtime_error("incorrect size in character file header");
|
||||
}
|
||||
if (header.command != 0x00E7) {
|
||||
throw runtime_error("incorrect command in character file header");
|
||||
}
|
||||
if (header.flag != 0x00000000) {
|
||||
throw runtime_error("incorrect flag in character file header");
|
||||
}
|
||||
this->external_bank_character = make_shared<PSOBBCharacterFile>(phosg::freadx<PSOBBCharacterFile>(f.get()));
|
||||
this->external_bank_character = load_psochar(filename, false).character_file;
|
||||
this->update_character_data_after_load(this->external_bank_character);
|
||||
this->external_bank_character_index = index;
|
||||
files_manager->set_character(filename, this->external_bank_character);
|
||||
|
||||
@@ -3017,7 +3017,11 @@ struct S_TournamentEntryList_Ep3_E2 {
|
||||
} __packed_ws__(S_TournamentEntryList_Ep3_E2, 0x584);
|
||||
|
||||
// E2 (S->C): Set system file contents (BB)
|
||||
// See PSOBBFullSystemFile in SaveFileFormats.hh for format
|
||||
|
||||
struct S_SyncSystemFile_BB_E2 {
|
||||
PSOBBBaseSystemFile system_file;
|
||||
PSOBBTeamMembership team_membership;
|
||||
} __packed_ws__(S_SyncSystemFile_BB_E2, 0xAF0);
|
||||
|
||||
// E3 (S->C): Game or tournament info (Episode 3)
|
||||
// The header.flag argument determines which fields are valid (and which panes
|
||||
@@ -3201,7 +3205,8 @@ struct C_CreateSpectatorTeam_Ep3_E7 {
|
||||
|
||||
struct SC_SyncSaveFiles_BB_E7 {
|
||||
/* 0000 */ PSOBBCharacterFile char_file;
|
||||
/* 2EA4 */ PSOBBFullSystemFile system_file;
|
||||
/* 2EA4 */ PSOBBBaseSystemFile system_file;
|
||||
/* 30DC */ PSOBBTeamMembership team_membership;
|
||||
/* 3994 */
|
||||
} __packed_ws__(SC_SyncSaveFiles_BB_E7, 0x3994);
|
||||
|
||||
|
||||
@@ -3798,13 +3798,12 @@ static void on_E7_BB(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
|
||||
p->challenge_records = cmd.char_file.challenge_records;
|
||||
p->battle_records = cmd.char_file.battle_records;
|
||||
p->death_count = cmd.char_file.death_count;
|
||||
*c->system_file() = cmd.system_file.base;
|
||||
*c->system_file() = cmd.system_file;
|
||||
}
|
||||
|
||||
static void on_E2_BB(shared_ptr<Client> c, uint16_t, uint32_t, string& data) {
|
||||
auto& cmd = check_size_t<PSOBBFullSystemFile>(data);
|
||||
auto sys = c->system_file();
|
||||
*sys = cmd.base;
|
||||
const auto& cmd = check_size_t<S_SyncSystemFile_BB_E2>(data);
|
||||
*c->system_file() = cmd.system_file;
|
||||
c->save_system_file();
|
||||
|
||||
S_SystemFileCreated_00E1_BB out_cmd = {1};
|
||||
|
||||
+46
-1
@@ -327,7 +327,7 @@ uint32_t PSOBBGuildCardFile::checksum() const {
|
||||
|
||||
PSOBBBaseSystemFile::PSOBBBaseSystemFile() {
|
||||
// This field is based on 1/1/2000, not 1/1/1970, so adjust appropriately
|
||||
this->base.creation_timestamp = (phosg::now() - 946684800000000ULL) / 1000000;
|
||||
this->creation_timestamp = (phosg::now() - 946684800000000ULL) / 1000000;
|
||||
for (size_t z = 0; z < DEFAULT_KEY_CONFIG.size(); z++) {
|
||||
this->key_config[z] = DEFAULT_KEY_CONFIG[z];
|
||||
}
|
||||
@@ -742,6 +742,51 @@ shared_ptr<PSOBBCharacterFile> PSOBBCharacterFile::create_from_xb(const PSOXBCha
|
||||
return ret;
|
||||
}
|
||||
|
||||
LoadedPSOCHARFile load_psochar(const string& filename, bool load_system) {
|
||||
auto f = phosg::fopen_unique(filename, "rb");
|
||||
auto header = phosg::freadx<PSOCommandHeaderBB>(f.get());
|
||||
if (header.size != 0x399C) {
|
||||
throw runtime_error("incorrect size in character file header");
|
||||
}
|
||||
if (header.command != 0x00E7) {
|
||||
throw runtime_error("incorrect command in character file header");
|
||||
}
|
||||
if (header.flag != 0x00000000) {
|
||||
throw runtime_error("incorrect flag in character file header");
|
||||
}
|
||||
static_assert(sizeof(PSOBBCharacterFile) + sizeof(PSOBBBaseSystemFile) + sizeof(PSOBBTeamMembership) == 0x3994, ".psochar size is incorrect");
|
||||
|
||||
LoadedPSOCHARFile ret;
|
||||
ret.character_file = make_shared<PSOBBCharacterFile>(phosg::freadx<PSOBBCharacterFile>(f.get()));
|
||||
if (load_system) {
|
||||
ret.system_file = make_shared<PSOBBBaseSystemFile>(phosg::freadx<PSOBBBaseSystemFile>(f.get()));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void save_psochar(
|
||||
const std::string& filename,
|
||||
std::shared_ptr<const PSOBBBaseSystemFile> system,
|
||||
std::shared_ptr<const PSOBBCharacterFile> character) {
|
||||
auto f = phosg::fopen_unique(filename, "wb");
|
||||
PSOCommandHeaderBB header = {sizeof(PSOCommandHeaderBB) + sizeof(PSOBBCharacterFile) + sizeof(PSOBBBaseSystemFile) + sizeof(PSOBBTeamMembership), 0x00E7, 0x00000000};
|
||||
phosg::fwritex(f.get(), header);
|
||||
phosg::fwritex(f.get(), *character);
|
||||
phosg::fwritex(f.get(), *system);
|
||||
// TODO: Technically, we should write the actual team membership struct to
|
||||
// the file here, but that would cause Client to depend on Account, which it
|
||||
// currently does not. This data doesn't matter at all for correctness within
|
||||
// newserv, since it ignores this data entirely and instead generates the
|
||||
// membership struct from the team ID in the Account and the team's state.
|
||||
// So, writing correct data here would mostly be for compatibility with other
|
||||
// PSO servers. But if the other server is newserv, then this data wouldn't
|
||||
// be used anyway, and if it's not, then it would presumably have a different
|
||||
// set of teams with a different set of team IDs anyway, so the membership
|
||||
// struct here would be useless either way.
|
||||
static const PSOBBTeamMembership empty_membership;
|
||||
phosg::fwritex(f.get(), empty_membership);
|
||||
}
|
||||
|
||||
PSODCV2CharacterFile PSOBBCharacterFile::to_dc_v2() const {
|
||||
uint8_t language = this->inventory.language;
|
||||
|
||||
|
||||
+15
-11
@@ -279,8 +279,7 @@ struct PSOBBMinimalSystemFile {
|
||||
/* 0114 */
|
||||
} __packed_ws__(PSOBBMinimalSystemFile, 0x114);
|
||||
|
||||
struct PSOBBBaseSystemFile {
|
||||
/* 0000 */ PSOBBMinimalSystemFile base;
|
||||
struct PSOBBBaseSystemFile : PSOBBMinimalSystemFile {
|
||||
/* 0114 */ parray<uint8_t, 0x016C> key_config;
|
||||
/* 0280 */ parray<uint8_t, 0x0038> joystick_config;
|
||||
/* 02B8 */
|
||||
@@ -288,14 +287,6 @@ struct PSOBBBaseSystemFile {
|
||||
PSOBBBaseSystemFile();
|
||||
} __packed_ws__(PSOBBBaseSystemFile, 0x2B8);
|
||||
|
||||
struct PSOBBFullSystemFile {
|
||||
/* 0000 */ PSOBBBaseSystemFile base;
|
||||
/* 02B8 */ PSOBBTeamMembership team_membership;
|
||||
/* 0AF0 */
|
||||
|
||||
PSOBBFullSystemFile() = default;
|
||||
} __packed_ws__(PSOBBFullSystemFile, 0xAF0);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Character files
|
||||
|
||||
@@ -757,6 +748,18 @@ struct PSOBBCharacterFile {
|
||||
void recompute_stats(std::shared_ptr<const LevelTable> level_table);
|
||||
} __packed_ws__(PSOBBCharacterFile, 0x2EA4);
|
||||
|
||||
struct LoadedPSOCHARFile {
|
||||
std::shared_ptr<PSOBBBaseSystemFile> system_file; // Null if load_system is false
|
||||
std::shared_ptr<PSOBBCharacterFile> character_file; // Never null
|
||||
// Team membership is present in the file, but ignored by newserv
|
||||
};
|
||||
|
||||
LoadedPSOCHARFile load_psochar(const std::string& filename, bool load_system);
|
||||
void save_psochar(
|
||||
const std::string& filename,
|
||||
std::shared_ptr<const PSOBBBaseSystemFile> system,
|
||||
std::shared_ptr<const PSOBBCharacterFile> character);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Guild Card files
|
||||
|
||||
@@ -864,7 +867,8 @@ struct LegacySavedAccountDataBB { // .nsa file format
|
||||
/* 0000 */ pstring<TextEncoding::ASCII, 0x40> signature;
|
||||
/* 0040 */ parray<le_uint32_t, 0x001E> blocked_senders;
|
||||
/* 00B8 */ PSOBBGuildCardFile guild_card_file;
|
||||
/* D648 */ PSOBBFullSystemFile system_file;
|
||||
/* D648 */ PSOBBBaseSystemFile system_file;
|
||||
/* D880 */ PSOBBTeamMembership team_membership;
|
||||
/* E138 */ le_uint32_t unused = 0;
|
||||
/* E13C */ le_uint32_t option_flags = 0x00040058;
|
||||
/* E140 */ parray<SaveFileShortcutEntryBB, 0x10> shortcuts;
|
||||
|
||||
+5
-5
@@ -619,8 +619,8 @@ void send_client_init_bb(shared_ptr<Client> c, uint32_t error_code) {
|
||||
void send_system_file_bb(shared_ptr<Client> c) {
|
||||
auto team = c->team();
|
||||
|
||||
PSOBBFullSystemFile cmd;
|
||||
cmd.base = *c->system_file();
|
||||
S_SyncSystemFile_BB_E2 cmd;
|
||||
cmd.system_file = *c->system_file();
|
||||
if (team) {
|
||||
cmd.team_membership = team->membership_for_member(c->login->account->account_id);
|
||||
}
|
||||
@@ -754,14 +754,14 @@ void send_complete_player_bb(shared_ptr<Client> c) {
|
||||
if (c->config.check_flag(Client::Flag::FORCE_ENGLISH_LANGUAGE_BB)) {
|
||||
p->inventory.language = 1;
|
||||
p->guild_card.language = 1;
|
||||
sys->base.language = 1;
|
||||
sys->language = 1;
|
||||
}
|
||||
|
||||
SC_SyncSaveFiles_BB_E7 cmd;
|
||||
cmd.char_file = *p;
|
||||
cmd.system_file.base = *sys;
|
||||
cmd.system_file = *sys;
|
||||
if (team) {
|
||||
cmd.system_file.team_membership = team->membership_for_member(c->login->account->account_id);
|
||||
cmd.team_membership = team->membership_for_member(c->login->account->account_id);
|
||||
}
|
||||
send_command_t(c, 0x00E7, 0x00000000, cmd);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user