use safe packed string types

This commit is contained in:
Martin Michelsen
2022-03-31 23:23:02 -07:00
parent 832135a505
commit 8a9e1a2049
22 changed files with 1040 additions and 879 deletions
+200 -203
View File
@@ -8,21 +8,23 @@
#include <phosg/Encoding.hh>
#include "Version.hh"
#include "Text.hh"
// raw item data
// TODO: use parray for the fields here
struct ItemData {
union {
uint8_t item_data1[12];
uint16_t item_data1w[6];
uint32_t item_data1d[3];
le_uint16_t item_data1w[6];
le_uint32_t item_data1d[3];
} __attribute__((packed));
uint32_t item_id;
union {
uint8_t item_data2[4];
uint16_t item_data2w[2];
uint32_t item_data2d;
le_uint16_t item_data2w[2];
le_uint32_t item_data2d;
} __attribute__((packed));
uint32_t primary_identifier() const;
@@ -32,9 +34,9 @@ struct PlayerBankItem;
// an item in a player's inventory
struct PlayerInventoryItem {
uint16_t equip_flags;
uint16_t tech_flag;
uint32_t game_flags;
le_uint16_t equip_flags;
le_uint16_t tech_flag;
le_uint32_t game_flags;
ItemData data;
PlayerBankItem to_bank_item() const;
@@ -43,8 +45,8 @@ struct PlayerInventoryItem {
// an item in a player's bank
struct PlayerBankItem {
ItemData data;
uint16_t amount;
uint16_t show_flags;
le_uint16_t amount;
le_uint16_t show_flags;
PlayerInventoryItem to_inventory_item() const;
} __attribute__((packed));
@@ -62,8 +64,8 @@ struct PlayerInventory {
// a player's bank
struct PlayerBank {
uint32_t num_items;
uint32_t meseta;
le_uint32_t num_items;
le_uint32_t meseta;
PlayerBankItem items[200];
void load(const std::string& filename);
@@ -80,13 +82,13 @@ struct PlayerBank {
// simple player stats
struct PlayerStats {
uint16_t atp;
uint16_t mst;
uint16_t evp;
uint16_t hp;
uint16_t dfp;
uint16_t ata;
uint16_t lck;
le_uint16_t atp;
le_uint16_t mst;
le_uint16_t evp;
le_uint16_t hp;
le_uint16_t dfp;
le_uint16_t ata;
le_uint16_t lck;
} __attribute__((packed));
struct PlayerDispDataBB;
@@ -94,34 +96,33 @@ struct PlayerDispDataBB;
// PC/GC player appearance and stats data
struct PlayerDispDataPCGC { // 0xD0 in size
PlayerStats stats;
uint16_t unknown1;
uint32_t unknown2[2];
uint32_t level;
uint32_t experience;
uint32_t meseta;
char name[16];
uint32_t unknown3[2];
uint32_t name_color;
parray<uint8_t, 0x0A> unknown_a1;
le_uint32_t level;
le_uint32_t experience;
le_uint32_t meseta;
ptext<char, 0x10> name;
uint64_t unknown_a2;
le_uint32_t name_color;
uint8_t extra_model;
uint8_t unused[15];
uint32_t name_color_checksum;
parray<uint8_t, 0x0F> unused;
le_uint32_t name_color_checksum;
uint8_t section_id;
uint8_t char_class;
uint8_t v2_flags;
uint8_t version;
uint32_t v1_flags;
uint16_t costume;
uint16_t skin;
uint16_t face;
uint16_t head;
uint16_t hair;
uint16_t hair_r;
uint16_t hair_g;
uint16_t hair_b;
float proportion_x;
float proportion_y;
uint8_t config[0x48];
uint8_t technique_levels[0x14];
le_uint32_t v1_flags;
le_uint16_t costume;
le_uint16_t skin;
le_uint16_t face;
le_uint16_t head;
le_uint16_t hair;
le_uint16_t hair_r;
le_uint16_t hair_g;
le_uint16_t hair_b;
le_float proportion_x;
le_float proportion_y;
parray<uint8_t, 0x48> config;
parray<uint8_t, 0x14> technique_levels;
void enforce_pc_limits();
PlayerDispDataBB to_bb() const;
@@ -129,66 +130,64 @@ struct PlayerDispDataPCGC { // 0xD0 in size
// BB player preview format
struct PlayerDispDataBBPreview {
uint32_t experience;
uint32_t level;
char guild_card[16];
uint32_t unknown3[2];
uint32_t name_color;
le_uint32_t experience;
le_uint32_t level;
ptext<char, 0x10> guild_card;
uint64_t unknown_a2;
le_uint32_t name_color;
uint8_t extra_model;
uint8_t unused[15];
uint32_t name_color_checksum;
parray<uint8_t, 0x0F> unused;
le_uint32_t name_color_checksum;
uint8_t section_id;
uint8_t char_class;
uint8_t v2_flags;
uint8_t version;
uint32_t v1_flags;
uint16_t costume;
uint16_t skin;
uint16_t face;
uint16_t head;
uint16_t hair;
uint16_t hair_r;
uint16_t hair_g;
uint16_t hair_b;
float proportion_x;
float proportion_y;
char16_t name[16];
le_uint32_t v1_flags;
le_uint16_t costume;
le_uint16_t skin;
le_uint16_t face;
le_uint16_t head;
le_uint16_t hair;
le_uint16_t hair_r;
le_uint16_t hair_g;
le_uint16_t hair_b;
le_float proportion_x;
le_float proportion_y;
ptext<char16_t, 0x10> name;
uint32_t play_time;
} __attribute__((packed));
// BB player appearance and stats data
struct PlayerDispDataBB {
PlayerStats stats;
uint16_t unknown1;
uint32_t unknown2[2];
uint32_t level;
uint32_t experience;
uint32_t meseta;
char guild_card[0x10];
uint32_t unknown3[2];
uint32_t name_color;
parray<uint8_t, 0x0A> unknown_a1;
le_uint32_t level;
le_uint32_t experience;
le_uint32_t meseta;
ptext<char, 0x10> guild_card;
uint64_t unknown_a2;
le_uint32_t name_color;
uint8_t extra_model;
uint8_t unused[11];
uint32_t play_time; // not actually a game field; used only by my server
uint32_t name_color_checksum;
parray<uint8_t, 0x0F> unused;
le_uint32_t name_color_checksum;
uint8_t section_id;
uint8_t char_class;
uint8_t v2_flags;
uint8_t version;
uint32_t v1_flags;
uint16_t costume;
uint16_t skin;
uint16_t face;
uint16_t head;
uint16_t hair;
uint16_t hair_r;
uint16_t hair_g;
uint16_t hair_b;
float proportion_x;
float proportion_y;
char16_t name[0x10];
uint8_t config[0xE8];
uint8_t technique_levels[0x14];
le_uint32_t v1_flags;
le_uint16_t costume;
le_uint16_t skin;
le_uint16_t face;
le_uint16_t head;
le_uint16_t hair;
le_uint16_t hair_r;
le_uint16_t hair_g;
le_uint16_t hair_b;
le_float proportion_x;
le_float proportion_y;
ptext<char16_t, 0x10> name;
parray<uint8_t, 0xE8> config;
parray<uint8_t, 0x14> technique_levels;
inline void enforce_pc_limits() { }
PlayerDispDataPCGC to_pcgc() const;
@@ -199,10 +198,10 @@ struct PlayerDispDataBB {
struct GuildCardGC {
uint32_t player_tag;
uint32_t serial_number;
char name[0x18];
char desc[0x6C];
le_uint32_t player_tag;
le_uint32_t serial_number;
ptext<char, 0x18> name;
ptext<char, 0x6C> desc;
uint8_t reserved1; // should be 1
uint8_t reserved2; // should be 1
uint8_t section_id;
@@ -211,10 +210,10 @@ struct GuildCardGC {
// BB guild card format
struct GuildCardBB {
uint32_t serial_number;
char16_t name[0x18];
char16_t teamname[0x10];
char16_t desc[0x58];
le_uint32_t serial_number;
ptext<char16_t, 0x18> name;
ptext<char16_t, 0x10> teamname;
ptext<char16_t, 0x58> desc;
uint8_t reserved1; // should be 1
uint8_t reserved2; // should be 1
uint8_t section_id;
@@ -224,66 +223,66 @@ struct GuildCardBB {
// an entry in the BB guild card file
struct GuildCardEntryBB {
GuildCardBB data;
uint8_t unknown[0xB4];
parray<uint8_t, 0xB4> unknown;
} __attribute__((packed));
// the format of the BB guild card file
struct GuildCardFileBB {
uint8_t unknown[0x1F84];
parray<uint8_t, 0x1F84> unknown_a1;
GuildCardEntryBB entry[0x0068]; // that's 104 of them in decimal
uint8_t unknown2[0x01AC];
parray<uint8_t, 0x01AC> unknown_a2;
} __attribute__((packed));
// PSOBB key config and team info
struct KeyAndTeamConfigBB {
uint8_t unknown[0x0114]; // 0000
uint8_t key_config[0x016C]; // 0114
uint8_t joystick_config[0x0038]; // 0280
uint32_t serial_number; // 02B8
uint32_t team_id; // 02BC
uint32_t team_info[2]; // 02C0
uint16_t team_privilege_level; // 02C8
uint16_t reserved; // 02CA
char16_t team_name[0x0010]; // 02CC
uint8_t team_flag[0x0800]; // 02EC
uint32_t team_rewards[2]; // 0AEC
parray<uint8_t, 0x0114> unknown_a1; // 0000
parray<uint8_t, 0x016C> key_config; // 0114
parray<uint8_t, 0x0038> joystick_config; // 0280
le_uint32_t serial_number; // 02B8
le_uint32_t team_id; // 02BC
le_uint64_t team_info; // 02C0
le_uint16_t team_privilege_level; // 02C8
le_uint16_t reserved; // 02CA
ptext<char16_t, 0x0010> team_name; // 02CC
parray<uint8_t, 0x0800> team_flag; // 02EC
le_uint64_t team_rewards; // 0AEC
} __attribute__((packed));
// BB account data
struct PlayerAccountDataBB {
uint8_t symbol_chats[0x04E0];
parray<uint8_t, 0x04E0> symbol_chats;
KeyAndTeamConfigBB key_config;
GuildCardFileBB guild_cards;
uint32_t options;
uint8_t shortcuts[0x0A40]; // chat shortcuts (@1FB4 in E7 command)
le_uint32_t options;
parray<uint8_t, 0x0A40> shortcuts; // chat shortcuts (@1FB4 in E7 command)
} __attribute__((packed));
struct PlayerLobbyDataPC {
uint32_t player_tag;
uint32_t guild_card;
le_uint32_t player_tag;
le_uint32_t guild_card;
be_uint32_t ip_address;
uint32_t client_id;
char16_t name[16];
le_uint32_t client_id;
ptext<char16_t, 0x10> name;
} __attribute__((packed));
struct PlayerLobbyDataGC {
uint32_t player_tag;
uint32_t guild_card;
le_uint32_t player_tag;
le_uint32_t guild_card;
be_uint32_t ip_address;
uint32_t client_id;
char name[16];
le_uint32_t client_id;
ptext<char, 0x10> name;
} __attribute__((packed));
struct PlayerLobbyDataBB {
uint32_t player_tag;
uint32_t guild_card;
le_uint32_t player_tag;
le_uint32_t guild_card;
be_uint32_t ip_address; // Guess - the official builds didn't use this, but all other versions have it
uint32_t unknown1[4];
uint32_t client_id;
char16_t name[16];
uint32_t unknown2;
parray<uint8_t, 0x10> unknown_a1;
le_uint32_t client_id;
ptext<char16_t, 0x10> name;
le_uint32_t unknown2;
} __attribute__((packed));
@@ -296,107 +295,105 @@ struct PSOPlayerDataPC { // for command 0x61
struct PSOPlayerDataGC { // for command 0x61
PlayerInventory inventory;
PlayerDispDataPCGC disp;
char unknown[0x134];
char info_board[0xAC];
uint32_t blocked[0x1E];
uint32_t auto_reply_enabled;
parray<uint8_t, 0x134> unknown;
ptext<char, 0xAC> info_board;
parray<le_uint32_t, 0x1E> blocked_senders;
le_uint32_t auto_reply_enabled;
char auto_reply[0];
} __attribute__((packed));
struct PSOPlayerDataBB { // for command 0x61
PlayerInventory inventory;
PlayerDispDataBB disp;
char unused[0x174];
char16_t info_board[0xAC];
uint32_t blocked[0x1E];
uint32_t auto_reply_enabled;
ptext<char, 0x174> unused;
ptext<char16_t, 0xAC> info_board;
parray<le_uint32_t, 0x1E> blocked_senders;
le_uint32_t auto_reply_enabled;
char16_t auto_reply[0];
} __attribute__((packed));
// complete BB player data format (used in E7 command)
struct PlayerBB {
PlayerInventory inventory; // 0000 // player
PlayerDispDataBB disp; // 034C // player
uint8_t unknown[0x0010]; // 04DC //
uint32_t option_flags; // 04EC // account
uint8_t quest_data1[0x0208]; // 04F0 // player
PlayerBank bank; // 06F8 // player
uint32_t serial_number; // 19C0 // player
char16_t name[0x18]; // 19C4 // player
char16_t team_name[0x10]; // 19C4 // player
char16_t guild_card_desc[0x58]; // 1A14 // player
uint8_t reserved1; // 1AC4 // player
uint8_t reserved2; // 1AC5 // player
uint8_t section_id; // 1AC6 // player
uint8_t char_class; // 1AC7 // player
uint32_t unknown3; // 1AC8 //
uint8_t symbol_chats[0x04E0]; // 1ACC // account
uint8_t shortcuts[0x0A40]; // 1FAC // account
char16_t auto_reply[0x00AC]; // 29EC // player
char16_t info_board[0x00AC]; // 2B44 // player
uint8_t unknown5[0x001C]; // 2C9C //
uint8_t challenge_data[0x0140]; // 2CB8 // player
uint8_t tech_menu_config[0x0028]; // 2DF8 // player
uint8_t unknown6[0x002C]; // 2E20 //
uint8_t quest_data2[0x0058]; // 2E4C // player
KeyAndTeamConfigBB key_config; // 2EA4 // account
} __attribute__((packed)); // total size: 39A0
PlayerInventory inventory; // 0000 // player
PlayerDispDataBB disp; // 034C // player
parray<uint8_t, 0x0010> unknown; // 04DC //
le_uint32_t option_flags; // 04EC // account
parray<uint8_t, 0x0208> quest_data1; // 04F0 // player
PlayerBank bank; // 06F8 // player
le_uint32_t serial_number; // 19C0 // player
ptext<char16_t, 0x18> name; // 19C4 // player
ptext<char16_t, 0x10> team_name; // 19C4 // player
ptext<char16_t, 0x58> guild_card_desc; // 1A14 // player
uint8_t reserved1; // 1AC4 // player
uint8_t reserved2; // 1AC5 // player
uint8_t section_id; // 1AC6 // player
uint8_t char_class; // 1AC7 // player
le_uint32_t unknown3; // 1AC8 //
parray<uint8_t, 0x04E0> symbol_chats; // 1ACC // account
parray<uint8_t, 0x0A40> shortcuts; // 1FAC // account
ptext<char16_t, 0x00AC> auto_reply; // 29EC // player
ptext<char16_t, 0x00AC> info_board; // 2B44 // player
parray<uint8_t, 0x001C> unknown5; // 2C9C //
parray<uint8_t, 0x0140> challenge_data; // 2CB8 // player
parray<uint8_t, 0x0028> tech_menu_config; // 2DF8 // player
parray<uint8_t, 0x002C> unknown6; // 2E20 //
parray<uint8_t, 0x0058> quest_data2; // 2E4C // player
KeyAndTeamConfigBB key_config; // 2EA4 // account
} __attribute__((packed)); // total size: 39A0
struct SavedPlayerBB { // .nsc file format
char signature[0x40];
ptext<char, 0x40> signature;
PlayerDispDataBBPreview preview;
char16_t auto_reply[0x00AC];
PlayerBank bank;
uint8_t challenge_data[0x0140];
PlayerDispDataBB disp;
char16_t guild_card_desc[0x58];
char16_t info_board[0x00AC];
PlayerInventory inventory;
uint8_t quest_data1[0x0208];
uint8_t quest_data2[0x0058];
uint8_t tech_menu_config[0x0028];
ptext<char16_t, 0x00AC> auto_reply;
PlayerBank bank;
parray<uint8_t, 0x0140> challenge_data;
PlayerDispDataBB disp;
ptext<char16_t, 0x58> guild_card_desc;
ptext<char16_t, 0x00AC> info_board;
PlayerInventory inventory;
parray<uint8_t, 0x0208> quest_data1;
parray<uint8_t, 0x0058> quest_data2;
parray<uint8_t, 0x0028> tech_menu_config;
} __attribute__((packed));
struct SavedAccountBB { // .nsa file format
char signature[0x40];
uint32_t blocked[0x001E];
GuildCardFileBB guild_cards;
KeyAndTeamConfigBB key_config;
uint32_t option_flags;
uint8_t shortcuts[0x0A40];
uint8_t symbol_chats[0x04E0];
char16_t team_name[0x0010];
ptext<char, 0x40> signature;
parray<le_uint32_t, 0x001E> blocked_senders;
GuildCardFileBB guild_cards;
KeyAndTeamConfigBB key_config;
le_uint32_t option_flags;
parray<uint8_t, 0x0A40> shortcuts;
parray<uint8_t, 0x04E0> symbol_chats;
ptext<char16_t, 0x0010> team_name;
} __attribute__((packed));
// complete player info stored by the server
struct Player {
uint32_t loaded_from_shipgate_time;
char16_t auto_reply[0x00AC]; // player
PlayerBank bank; // player
char bank_name[0x20];
uint32_t blocked[0x001E]; // account
uint8_t challenge_data[0x0140]; // player
PlayerDispDataBB disp; // player
uint8_t ep3_config[0x2408];
char16_t guild_card_desc[0x58]; // player
GuildCardFileBB guild_cards; // account
PlayerInventoryItem identify_result;
char16_t info_board[0x00AC]; // player
PlayerInventory inventory; // player
KeyAndTeamConfigBB key_config; // account
uint32_t option_flags; // account
uint8_t quest_data1[0x0208]; // player
uint8_t quest_data2[0x0058]; // player
uint32_t serial_number;
std::vector<ItemData> current_shop_contents;
uint8_t shortcuts[0x0A40]; // account
uint8_t symbol_chats[0x04E0]; // account
char16_t team_name[0x0010]; // account
uint8_t tech_menu_config[0x0028]; // player
le_uint32_t loaded_from_shipgate_time;
ptext<char16_t, 0x00AC> auto_reply; // player
PlayerBank bank; // player
ptext<char, 0x0020> bank_name; // not saved
parray<le_uint32_t, 0x001E> blocked_senders; // account
parray<uint8_t, 0x0140> challenge_data; // player
PlayerDispDataBB disp; // player
parray<uint8_t, 0x2408> ep3_config; // not saved
ptext<char16_t, 0x0058> guild_card_desc; // player
GuildCardFileBB guild_cards; // account
PlayerInventoryItem identify_result; // not saved
ptext<char16_t, 0x00AC> info_board; // player
PlayerInventory inventory; // player
KeyAndTeamConfigBB key_config; // account
le_uint32_t option_flags; // account
parray<uint8_t, 0x0208> quest_data1; // player
parray<uint8_t, 0x0058> quest_data2; // player
le_uint32_t serial_number; // account identifier
std::vector<ItemData> current_shop_contents; // not saved
parray<uint8_t, 0x0A40> shortcuts; // account
parray<uint8_t, 0x04E0> symbol_chats; // account
ptext<char16_t, 0x0010> team_name; // account
parray<uint8_t, 0x0028> tech_menu_config; // player
void load_player_data(const std::string& filename);
void save_player_data(const std::string& filename) const;
@@ -419,7 +416,7 @@ struct Player {
uint32_t compute_guild_card_checksum(const void* data, size_t size);
std::string filename_for_player_bb(const std::string& username, uint8_t player_index);
std::string filename_for_bank_bb(const std::string& username, const char* bank_name);
std::string filename_for_bank_bb(const std::string& username, const std::string& bank_name);
std::string filename_for_class_template_bb(uint8_t char_class);
std::string filename_for_account_bb(const std::string& username);