diff --git a/README.md b/README.md index 01651765..fa5dae7f 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ Current known issues / missing features: - The trade window isn't implemented yet. - PSO PC and PSOBB are essentially entirely untested. Only GC is fairly well-tested. - Add all the chat commands that khyller used to have. (Most, but not all, currently exist in newserv.) +- The command structures are defined in multiple places. Centralize them. ## Usage diff --git a/src/LevelTable.hh b/src/LevelTable.hh index 27eef5f0..bedd1a0a 100644 --- a/src/LevelTable.hh +++ b/src/LevelTable.hh @@ -16,7 +16,7 @@ struct LevelStats { uint32_t experience; // EXP value of this level void apply(PlayerStats& ps) const; -}; +} __attribute__((packed)); // level table format (PlyLevelTbl.prs) struct LevelTable { @@ -28,4 +28,4 @@ struct LevelTable { const PlayerStats& base_stats_for_class(uint8_t char_class) const; const LevelStats& stats_for_level(uint8_t char_class, uint8_t level) const; -}; +} __attribute__((packed)); diff --git a/src/Map.cc b/src/Map.cc index efbd363c..85fbbeeb 100644 --- a/src/Map.cc +++ b/src/Map.cc @@ -74,7 +74,7 @@ struct EnemyEntry { uint32_t reserved14; uint32_t skin; uint32_t reserved15; -}; +} __attribute__((packed)); static vector parse_map(uint8_t episode, uint8_t difficulty, const BattleParams* battle_params, const EnemyEntry* map, diff --git a/src/Map.hh b/src/Map.hh index d14bfeac..4f162c11 100644 --- a/src/Map.hh +++ b/src/Map.hh @@ -17,7 +17,7 @@ struct BattleParams { uint8_t unknown[14]; uint32_t experience; uint32_t difficulty; -}; +} __attribute__((packed)); struct BattleParamTable { BattleParams entries[2][3][4][0x60]; // online/offline, episode, difficulty, monster type @@ -28,13 +28,13 @@ struct BattleParamTable { uint8_t monster_type) const; const BattleParams* get_subtable(bool solo, uint8_t episode, uint8_t difficulty) const; -}; +} __attribute__((packed)); struct BattleParamIndex { BattleParamTable table_for_episode[3]; -}; +} __attribute__((packed)); // an enemy entry as loaded by the game struct PSOEnemy { @@ -46,7 +46,7 @@ struct PSOEnemy { PSOEnemy(); PSOEnemy(uint32_t experience, uint32_t rt_index); -}; +} __attribute__((packed)); std::vector load_map(const char* filename, uint8_t episode, uint8_t difficulty, const BattleParams* bp, bool alt_enemies); diff --git a/src/PSOEncryption.hh b/src/PSOEncryption.hh index a198ec3a..003d8844 100644 --- a/src/PSOEncryption.hh +++ b/src/PSOEncryption.hh @@ -59,7 +59,7 @@ public: struct KeyFile { uint32_t initial_keys[18]; uint32_t private_keys[1024]; - }; + } __attribute__((packed)); PSOBBEncryption(const KeyFile& key, const void* seed, size_t seed_size); diff --git a/src/Player.hh b/src/Player.hh index bdc0797f..5820c7f4 100644 --- a/src/Player.hh +++ b/src/Player.hh @@ -17,16 +17,16 @@ struct ItemData { uint8_t item_data1[12]; uint16_t item_data1w[6]; 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; - }; + } __attribute__((packed)); uint32_t primary_identifier() const; -}; +} __attribute__((packed)); struct PlayerBankItem; @@ -38,7 +38,7 @@ struct PlayerInventoryItem { ItemData data; PlayerBankItem to_bank_item() const; -}; +} __attribute__((packed)); // an item in a player's bank struct PlayerBankItem { @@ -47,7 +47,7 @@ struct PlayerBankItem { uint16_t show_flags; PlayerInventoryItem to_inventory_item() const; -}; +} __attribute__((packed)); // a player's inventory (remarkably, the format is the same in all versions of PSO) struct PlayerInventory { @@ -58,7 +58,7 @@ struct PlayerInventory { PlayerInventoryItem items[30]; size_t find_item(uint32_t item_id); -}; +} __attribute__((packed)); // a player's bank struct PlayerBank { @@ -74,7 +74,7 @@ struct PlayerBank { void add_item(const PlayerBankItem& item); void remove_item(uint32_t item_id, uint32_t amount, PlayerBankItem* item); size_t find_item(uint32_t item_id); -}; +} __attribute__((packed)); @@ -87,7 +87,7 @@ struct PlayerStats { uint16_t dfp; uint16_t ata; uint16_t lck; -}; +} __attribute__((packed)); struct PlayerDispDataBB; @@ -124,7 +124,7 @@ struct PlayerDispDataPCGC { // 0xD0 in size uint8_t technique_levels[0x14]; PlayerDispDataBB to_bb() const; -}; +} __attribute__((packed)); // BB player preview format struct PlayerDispDataBBPreview { @@ -153,7 +153,7 @@ struct PlayerDispDataBBPreview { float proportion_y; char16_t name[16]; uint32_t play_time; -}; +} __attribute__((packed)); // BB player appearance and stats data struct PlayerDispDataBB { @@ -192,7 +192,7 @@ struct PlayerDispDataBB { PlayerDispDataPCGC to_pcgc() const; PlayerDispDataBBPreview to_preview() const; void apply_preview(const PlayerDispDataBBPreview&); -}; +} __attribute__((packed)); @@ -205,7 +205,7 @@ struct GuildCardGC { uint8_t reserved2; // should be 1 uint8_t section_id; uint8_t char_class; -}; +} __attribute__((packed)); // BB guild card format struct GuildCardBB { @@ -217,20 +217,20 @@ struct GuildCardBB { uint8_t reserved2; // should be 1 uint8_t section_id; uint8_t char_class; -}; +} __attribute__((packed)); // an entry in the BB guild card file struct GuildCardEntryBB { GuildCardBB data; uint8_t unknown[0xB4]; -}; +} __attribute__((packed)); // the format of the BB guild card file struct GuildCardFileBB { uint8_t unknown[0x1F84]; GuildCardEntryBB entry[0x0068]; // that's 104 of them in decimal uint8_t unknown2[0x01AC]; -}; +} __attribute__((packed)); // PSOBB key config and team info struct KeyAndTeamConfigBB { @@ -242,10 +242,10 @@ struct KeyAndTeamConfigBB { uint32_t team_info[2]; // 02C0 uint16_t team_privilege_level; // 02C8 uint16_t reserved; // 02CA - char16_t team_name[0x0010]; // 02CC + char16_t team_name[0x0010]; // 02CC uint8_t team_flag[0x0800]; // 02EC uint32_t team_rewards[2]; // 0AEC -}; +} __attribute__((packed)); // BB account data struct PlayerAccountDataBB { @@ -254,7 +254,7 @@ struct PlayerAccountDataBB { GuildCardFileBB guild_cards; uint32_t options; uint8_t shortcuts[0x0A40]; // chat shortcuts (@1FB4 in E7 command) -}; +} __attribute__((packed)); @@ -264,7 +264,7 @@ struct PlayerLobbyDataPC { be_uint32_t ip_address; uint32_t client_id; char16_t name[16]; -}; +} __attribute__((packed)); struct PlayerLobbyDataGC { uint32_t player_tag; @@ -272,7 +272,7 @@ struct PlayerLobbyDataGC { be_uint32_t ip_address; uint32_t client_id; char name[16]; -}; +} __attribute__((packed)); struct PlayerLobbyDataBB { uint32_t player_tag; @@ -281,14 +281,14 @@ struct PlayerLobbyDataBB { uint32_t client_id; char16_t name[16]; uint32_t unknown2; -}; +} __attribute__((packed)); struct PSOPlayerDataPC { // for command 0x61 PlayerInventory inventory; PlayerDispDataPCGC disp; -}; +} __attribute__((packed)); struct PSOPlayerDataGC { // for command 0x61 PlayerInventory inventory; @@ -298,7 +298,7 @@ struct PSOPlayerDataGC { // for command 0x61 uint32_t blocked[0x1E]; uint32_t auto_reply_enabled; char auto_reply[0]; -}; +} __attribute__((packed)); struct PSOPlayerDataBB { // for command 0x61 PlayerInventory inventory; @@ -308,19 +308,19 @@ struct PSOPlayerDataBB { // for command 0x61 uint32_t blocked[0x1E]; uint32_t auto_reply_enabled; char16_t auto_reply[0]; -}; +} __attribute__((packed)); // PC/GC lobby player data (used in lobby/game join commands) struct PlayerLobbyJoinDataPCGC { PlayerInventory inventory; PlayerDispDataPCGC disp; -}; +} __attribute__((packed)); // BB lobby player data (used in lobby/game join commands) struct PlayerLobbyJoinDataBB { PlayerInventory inventory; PlayerDispDataBB disp; -}; +} __attribute__((packed)); // complete BB player data format (used in E7 command) struct PlayerBB { @@ -349,7 +349,7 @@ struct PlayerBB { uint8_t unknown6[0x002C]; // 2E20 // uint8_t quest_data2[0x0058]; // 2E4C // player KeyAndTeamConfigBB key_config; // 2EA4 // account -}; // total size: 39A0 +} __attribute__((packed)); // total size: 39A0 @@ -367,7 +367,7 @@ struct SavedPlayerBB { // .nsc file format uint8_t quest_data1[0x0208]; uint8_t quest_data2[0x0058]; uint8_t tech_menu_config[0x0028]; -}; +} __attribute__((packed)); struct SavedAccountBB { // .nsa file format char signature[0x40]; @@ -378,7 +378,7 @@ struct SavedAccountBB { // .nsa file format uint8_t shortcuts[0x0A40]; uint8_t symbol_chats[0x04E0]; char16_t team_name[0x0010]; -}; +} __attribute__((packed)); // complete player info stored by the server struct Player { @@ -424,7 +424,7 @@ struct Player { void add_item(const PlayerInventoryItem& item); void remove_item(uint32_t item_id, uint32_t amount, PlayerInventoryItem* item); size_t find_item(uint32_t item_id); -}; +} __attribute__((packed)); diff --git a/src/Quest.cc b/src/Quest.cc index 59e13562..7708aeda 100644 --- a/src/Quest.cc +++ b/src/Quest.cc @@ -22,7 +22,7 @@ struct PSODownloadQuestHeader { be_uint32_t size; // Note: use PSO PC encryption, even for GC quests. be_uint32_t encryption_seed; -}; +} __attribute__((packed)); @@ -80,7 +80,7 @@ struct PSOQuestHeaderDC { // same for dc v1 and v2, thankfully char name[0x20]; char short_description[0x80]; char long_description[0x120]; -}; +} __attribute__((packed)); struct PSOQuestHeaderPC { uint32_t start_offset; @@ -93,7 +93,7 @@ struct PSOQuestHeaderPC { char16_t name[0x20]; char16_t short_description[0x80]; char16_t long_description[0x120]; -}; +} __attribute__((packed)); struct PSOQuestHeaderGC { uint32_t start_offset; @@ -107,7 +107,7 @@ struct PSOQuestHeaderGC { char name[0x20]; char short_description[0x80]; char long_description[0x120]; -}; +} __attribute__((packed)); struct PSOQuestHeaderGCEpisode3 { // there's actually a lot of other important stuff in here but I'm lazy. it @@ -119,7 +119,7 @@ struct PSOQuestHeaderGCEpisode3 { char location2[0x3C]; char description[0x190]; uint8_t unused2[0x3A34]; -}; +} __attribute__((packed)); struct PSOQuestHeaderBB { uint32_t start_offset; @@ -135,7 +135,7 @@ struct PSOQuestHeaderBB { char16_t name[0x20]; char16_t short_description[0x80]; char16_t long_description[0x120]; -}; +} __attribute__((packed)); @@ -375,7 +375,7 @@ string Quest::decode_gci(const string& filename) { uint32_t unknown2; uint32_t decompressed_size; uint32_t unknown4; - }; + } __attribute__((packed)); if (compressed_data_with_header.size() < sizeof(DecryptedHeader)) { throw runtime_error("GCI file compressed data truncated during header"); } diff --git a/src/RareItemSet.hh b/src/RareItemSet.hh index 4057ddce..62ca43c2 100644 --- a/src/RareItemSet.hh +++ b/src/RareItemSet.hh @@ -7,9 +7,10 @@ struct RareItemDrop { uint8_t probability; uint8_t item_code[3]; -}; +} __attribute__((packed)); struct RareItemSet { + // 0x280 in size; describes one difficulty, section ID, and episode RareItemDrop rares[0x65]; // 0000 - 0194 in file uint8_t box_areas[0x1E]; // 0194 - 01B2 in file RareItemDrop box_rares[0x1E]; // 01B2 - 022A in file @@ -17,6 +18,6 @@ struct RareItemSet { RareItemSet(const char* filename, uint8_t episode, uint8_t difficulty, uint8_t secid); -}; // 0x280 in size; describes one difficulty, section ID, and episode +} __attribute__((packed)); bool sample_rare_item(uint8_t pc); diff --git a/src/ReceiveCommands.cc b/src/ReceiveCommands.cc index e22901c4..87e59642 100644 --- a/src/ReceiveCommands.cc +++ b/src/ReceiveCommands.cc @@ -229,7 +229,7 @@ void process_login_a_dc_pc_gc(shared_ptr s, shared_ptr c, char unused[0x20]; char serial_number[0x10]; char access_key[0x10]; - }; + } __attribute__((packed)); check_size(size, sizeof(Cmd)); const auto* cmd = reinterpret_cast(data); @@ -265,7 +265,7 @@ void process_login_c_dc_pc_gc(shared_ptr s, shared_ptr c, char serial_number[0x30]; char access_key[0x30]; char password[0x30]; - }; + } __attribute__((packed)); check_size(size, sizeof(Cmd)); const auto* cmd = reinterpret_cast(data); @@ -354,7 +354,7 @@ void process_login_bb(shared_ptr s, shared_ptr c, char password[0x10]; char unused3[0x30]; ClientConfig cfg; - }; + } __attribute__((packed)); check_size(size, sizeof(Cmd)); const auto* cmd = reinterpret_cast(data); @@ -436,12 +436,12 @@ void process_ep3_jukebox(shared_ptr s, shared_ptr c, uint32_t transaction_num; uint32_t value; uint32_t unknown_token; - }; + } __attribute__((packed)); struct OutputCmd { uint32_t remaining_meseta; uint32_t unknown; uint32_t unknown_token; - }; + } __attribute__((packed)); check_size(size, sizeof(InputCmd)); const auto* in_cmd = reinterpret_cast(data); @@ -582,7 +582,7 @@ void process_menu_item_info_request(shared_ptr s, shared_ptr(data); @@ -664,10 +664,10 @@ void process_menu_selection(shared_ptr s, shared_ptr c, uint32_t menu_id; uint32_t item_id; union { - char16_t password_pc_bb[0]; - char password_dc_gc[0]; - }; - }; + char16_t pc_bb[0]; + char dc_gc[0]; + } __attribute__((packed)) password; + } __attribute__((packed)); check_size(size, sizeof(Cmd), sizeof(Cmd) + 0x10 * (1 + uses_unicode)); const auto* cmd = reinterpret_cast(data); @@ -796,9 +796,9 @@ void process_menu_selection(shared_ptr s, shared_ptr c, char16_t password[0x10]; if (size > sizeof(Cmd)) { if (uses_unicode) { - char16cpy(password, cmd->password_pc_bb, 0x10); + char16cpy(password, cmd->password.pc_bb, 0x10); } else { - decode_sjis(password, cmd->password_dc_gc, 0x10); + decode_sjis(password, cmd->password.dc_gc, 0x10); } } @@ -918,7 +918,7 @@ void process_change_lobby(shared_ptr s, shared_ptr c, struct Cmd { uint32_t menu_id; uint32_t item_id; - }; + } __attribute__((packed)); check_size(size, sizeof(Cmd)); const auto* cmd = reinterpret_cast(data); @@ -1173,7 +1173,7 @@ void process_chat_pc_bb(shared_ptr s, shared_ptr c, struct Cmd { uint32_t unused[2]; char16_t text[0]; - }; + } __attribute__((packed)); check_size(size, sizeof(Cmd), 0xFFFF); const auto* cmd = reinterpret_cast(data); @@ -1185,7 +1185,7 @@ void process_chat_dc_gc(shared_ptr s, shared_ptr c, struct Cmd { uint32_t unused[2]; char text[0]; - }; + } __attribute__((packed)); check_size(size, sizeof(Cmd), 0xFFFF); const auto* cmd = reinterpret_cast(data); @@ -1207,7 +1207,7 @@ void process_player_preview_request_bb(shared_ptr, shared_ptr(data); @@ -1257,7 +1257,7 @@ void process_guild_card_data_request_bb(shared_ptr, shared_ptr(data); @@ -1282,7 +1282,7 @@ void process_create_character_bb(shared_ptr s, shared_ptr c struct Cmd { uint32_t player_index; PlayerDispDataBBPreview preview; - }; + } __attribute__((packed)); check_size(size, sizeof(Cmd)); const auto* cmd = reinterpret_cast(data); @@ -1346,7 +1346,7 @@ void process_change_account_data_bb(shared_ptr, shared_ptr uint8_t pad_config[0x38]; // 05ED uint8_t tech_menu[0x28]; // 06ED uint8_t customize[0xE8]; // 07ED - }; + } __attribute__((packed)); const auto* cmd = reinterpret_cast(data); switch (command) { @@ -1414,7 +1414,7 @@ void process_card_search(shared_ptr s, shared_ptr c, uint32_t player_tag; uint32_t searcher_serial_number; uint32_t target_serial_number; - }; + } __attribute__((packed)); check_size(size, sizeof(Cmd)); const auto* cmd = reinterpret_cast(data); @@ -1495,7 +1495,7 @@ void process_simple_mail(shared_ptr s, shared_ptr c, char from_name[16]; uint32_t target_serial_number; char data[0x200]; // on GC this appears to contain uninitialized memory! - }; + } __attribute__((packed)); check_size(size, sizeof(Cmd)); const auto* cmd = reinterpret_cast(data); @@ -1724,7 +1724,7 @@ void process_create_game_pc(shared_ptr s, shared_ptr c, uint8_t battle_mode; uint8_t challenge_mode; uint8_t unused2; - }; + } __attribute__((packed)); check_size(size, sizeof(Cmd)); const auto* cmd = reinterpret_cast(data); @@ -1746,7 +1746,7 @@ void process_create_game_dc_gc(shared_ptr s, shared_ptr c, uint8_t battle_mode; uint8_t challenge_mode; uint8_t episode; - }; + } __attribute__((packed)); check_size(size, sizeof(Cmd)); const auto* cmd = reinterpret_cast(data); @@ -1787,7 +1787,7 @@ void process_create_game_bb(shared_ptr s, shared_ptr c, uint8_t episode; uint8_t solo_mode; uint8_t unused2[3]; - }; + } __attribute__((packed)); check_size(size, sizeof(Cmd)); const auto* cmd = reinterpret_cast(data); @@ -1859,7 +1859,7 @@ void process_login_patch(shared_ptr s, shared_ptr c, uint32_t unused[3]; char username[0x10]; char password[0x10]; - }; + } __attribute__((packed)); check_size(size, sizeof(Cmd)); const auto* cmd = reinterpret_cast(data); diff --git a/src/ReceiveSubcommands.cc b/src/ReceiveSubcommands.cc index 37f893b3..825ee0f0 100644 --- a/src/ReceiveSubcommands.cc +++ b/src/ReceiveSubcommands.cc @@ -27,7 +27,7 @@ struct ItemSubcommand { uint8_t unused; uint32_t item_id; uint32_t amount; -}; +} __attribute__((packed)); @@ -221,7 +221,7 @@ static void process_subcommand_drop_item(shared_ptr, float x; float y; float z; - }; + } __attribute__((packed)); auto* cmd = reinterpret_cast(p); if ((cmd->size != 6) || (cmd->client_id != c->lobby_client_id)) { @@ -253,7 +253,7 @@ static void process_subcommand_drop_stacked_item(shared_ptr, float y; uint32_t item_id; uint32_t amount; - }; + } __attribute__((packed)); auto* cmd = reinterpret_cast(p); if (!l->is_game() || (cmd->size != 6) || (cmd->client_id != c->lobby_client_id)) { @@ -293,7 +293,7 @@ static void process_subcommand_pick_up_item(shared_ptr, uint32_t item_id; uint8_t area; uint8_t unused2[3]; - }; + } __attribute__((packed)); auto* cmd = reinterpret_cast(p); if (!l->is_game() || (cmd->size != 3) || (cmd->client_id != c->lobby_client_id)) { @@ -417,7 +417,7 @@ static void process_subcommand_bank_action(shared_ptr, uint8_t action; uint8_t item_amount; uint16_t unused2; - }; + } __attribute__((packed)); auto* cmd = reinterpret_cast(p); if (!l->is_game() || (cmd->size != 4)) { @@ -474,7 +474,7 @@ static void process_subcommand_sort_inventory(shared_ptr, uint8_t size; uint16_t unused; uint32_t item_ids[30]; - }; + } __attribute__((packed)); auto* cmd = reinterpret_cast(p); if (cmd->size != 31) { @@ -521,7 +521,7 @@ static void process_subcommand_enemy_drop_item(shared_ptr s, float x; float y; uint32_t unknown[2]; - }; + } __attribute__((packed)); auto* cmd = reinterpret_cast(p); if ((cmd->size != 6) || !l->is_game()) { @@ -586,7 +586,7 @@ static void process_subcommand_box_drop_item(shared_ptr s, float x; float y; uint32_t unknown[6]; - }; + } __attribute__((packed)); auto* cmd = reinterpret_cast(p); if ((cmd->size != 10) || !l->is_game()) { @@ -655,7 +655,7 @@ static void process_subcommand_monster_hit(shared_ptr, uint16_t enemy_id; uint16_t damage; uint32_t flags; - }; + } __attribute__((packed)); auto* cmd = reinterpret_cast(p); if (cmd->size != 10) { @@ -694,7 +694,7 @@ static void process_subcommand_monster_killed(shared_ptr s, uint16_t enemy_id; uint16_t killer_client_id; uint32_t unused; - }; + } __attribute__((packed)); auto* cmd = reinterpret_cast(p); if (!l->is_game() || (cmd->size != 3) || (cmd->enemy_id >= l->enemies.size() || diff --git a/src/SendCommands.cc b/src/SendCommands.cc index efe6f658..b3df3ac8 100644 --- a/src/SendCommands.cc +++ b/src/SendCommands.cc @@ -205,7 +205,7 @@ static void send_server_init_bb(shared_ptr s, shared_ptr c) uint8_t server_key[0x30]; uint8_t client_key[0x30]; char after_message[200]; - } cmd; + } __attribute__((packed)) cmd; memset(&cmd, 0, sizeof(cmd)); strcpy(cmd.copyright, bb_game_server_copyright); @@ -227,7 +227,7 @@ static void send_server_init_patch(shared_ptr c) { uint32_t client_key; // BB rejects the command if it's not exactly this size, so we can't add the // anti-copyright message... lawyers plz be kind kthx - } cmd; + } __attribute__((packed)) cmd; uint32_t server_key = random_object(); uint32_t client_key = random_object(); @@ -263,7 +263,7 @@ void send_update_client_config(shared_ptr c) { uint32_t player_tag; uint32_t serial_number; ClientConfig config; - } cmd = { + } __attribute__((packed)) cmd = { 0x00010000, c->license->serial_number, c->export_config(), @@ -280,7 +280,7 @@ void send_reconnect(shared_ptr c, uint32_t address, uint16_t port) { be_uint32_t address; uint16_t port; uint16_t unused; - } cmd = {address, port, 0}; + } __attribute__((packed)) cmd = {address, port, 0}; send_command(c, 0x19, 0x00, cmd); } @@ -298,7 +298,7 @@ void send_pc_gc_split_reconnect(shared_ptr c, uint32_t address, be_uint32_t gc_address; uint16_t gc_port; uint8_t unused2[0xB0 - 0x23]; - } cmd; + } __attribute__((packed)) cmd; memset(&cmd, 0, sizeof(cmd)); cmd.pc_address = address; cmd.pc_port = pc_port; @@ -321,7 +321,7 @@ void send_client_init_bb(shared_ptr c, uint32_t error) { uint32_t team_id; // just randomize it; teams aren't supported ClientConfig cfg; uint32_t caps; // should be 0x00000102 - } cmd = { + } __attribute__((packed)) cmd = { error, 0x00010000, c->license->serial_number, @@ -346,14 +346,14 @@ void send_player_preview_bb(shared_ptr c, uint8_t player_index, struct { uint32_t player_index; uint32_t error; - } cmd = {player_index, 0x00000002}; + } __attribute__((packed)) cmd = {player_index, 0x00000002}; send_command(c, 0x00E4, 0x00000000, cmd); } else { struct { uint32_t player_index; PlayerDispDataBBPreview preview; - } cmd = {player_index, *preview}; + } __attribute__((packed)) cmd = {player_index, *preview}; send_command(c, 0x00E3, 0x00000000, cmd); } } @@ -363,7 +363,7 @@ void send_accept_client_checksum_bb(shared_ptr c) { struct { uint32_t verify; uint32_t unused; - } cmd = {1, 0}; + } __attribute__((packed)) cmd = {1, 0}; send_command(c, 0x02E8, 0x00000000, cmd); } @@ -375,7 +375,7 @@ void send_guild_card_header_bb(shared_ptr c) { uint32_t unknown; // should be 1 uint32_t filesize; // 0x0000490 uint32_t checksum; - } cmd = {1, 0x490, checksum}; + } __attribute__((packed)) cmd = {1, 0x490, checksum}; send_command(c, 0x01DC, 0x00000000, cmd); } @@ -407,7 +407,7 @@ void send_stream_file_bb(shared_ptr c) { uint32_t checksum; uint32_t offset; char filename[0x40]; - }; + } __attribute__((packed)); auto index_data = file_cache.get("system/blueburst/streamfile.ind"); if (index_data->size() % sizeof(StreamFileEntry)) { @@ -422,7 +422,7 @@ void send_stream_file_bb(shared_ptr c) { struct { uint32_t chunk_index; uint8_t data[0x6800]; - } chunk_cmd; + } __attribute__((packed)) chunk_cmd; chunk_cmd.chunk_index = 0; uint32_t buffer_offset = 0; @@ -464,7 +464,7 @@ void send_approve_player_choice_bb(shared_ptr c) { struct { uint32_t player_index; uint32_t unused; - } cmd = {c->bb_player_index, 1}; + } __attribute__((packed)) cmd = {c->bb_player_index, 1}; send_command(c, 0x00E4, 0x00000000, cmd); } @@ -493,7 +493,7 @@ void send_check_directory_patch(shared_ptr c, const char* dir) { struct LargeMessageOptionalHeader { uint32_t unused; uint32_t serial_number; -}; +} __attribute__((packed)); static void send_large_message_pc_patch_bb(shared_ptr c, uint8_t command, const char16_t* text, uint32_t from_serial_number, bool include_header) { @@ -594,7 +594,7 @@ void send_simple_mail_gc(std::shared_ptr c, uint32_t from_serial_number, char from_name[0x10]; uint32_t to_serial_number; char text[0x200]; - } cmd; + } __attribute__((packed)) cmd; memset(&cmd, 0, sizeof(cmd)); cmd.player_tag = 0x00010000; @@ -624,7 +624,7 @@ static void send_info_board_pc_bb(shared_ptr c, shared_ptr l) { struct Entry { char16_t name[0x10]; char16_t message[0xAC]; - }; + } __attribute__((packed)); vector entries; for (const auto& c : l->clients) { @@ -647,7 +647,7 @@ static void send_info_board_dc_gc(shared_ptr c, shared_ptr l) { struct Entry { char name[0x10]; char message[0xAC]; - }; + } __attribute__((packed)); vector entries; for (const auto& c : l->clients) { @@ -693,23 +693,23 @@ static void send_card_search_result_dc_pc_gc(shared_ptr s, uint8_t dcgc_command; uint8_t dcgc_flag; uint16_t dcgc_size; - }; + } __attribute__((packed)); struct { uint16_t pc_size; uint8_t pc_command; uint8_t pc_flag; - }; - }; + } __attribute__((packed)); + } __attribute__((packed)); uint32_t address; uint16_t port; uint16_t unused; - } destination_command; + } __attribute__((packed)) destination_command; char location_string[0x44]; uint32_t menu_id; uint32_t lobby_id; char unused[0x3C]; char16_t name[0x20]; - } cmd; + } __attribute__((packed)) cmd; memset(&cmd, 0, sizeof(cmd)); cmd.player_tag = 0x00010000; @@ -766,13 +766,13 @@ static void send_card_search_result_bb(shared_ptr s, uint32_t address; uint16_t port; uint16_t unused; - } destination_command; + } __attribute__((packed)) destination_command; char location_string[0x44]; uint32_t menu_id; uint32_t lobby_id; char unused[0x3C]; char16_t name[0x20]; - } cmd; + } __attribute__((packed)) cmd; memset(&cmd, 0, sizeof(cmd)); cmd.player_tag = 0x00010000; @@ -828,7 +828,7 @@ static void send_guild_card_gc(shared_ptr c, shared_ptr source) uint8_t reserved2; uint8_t section_id; uint8_t char_class; - } cmd; + } __attribute__((packed)) cmd; cmd.subcommand = 0x06; cmd.subsize = 0x25; @@ -860,7 +860,7 @@ static void send_guild_card_bb(shared_ptr c, shared_ptr source) uint8_t reserved2; uint8_t section_id; uint8_t char_class; - } cmd; + } __attribute__((packed)) cmd; cmd.subcommand = 0x06; cmd.subsize = 0x43; @@ -902,7 +902,7 @@ static void send_menu_pc_bb(shared_ptr c, const char16_t* menu_name, uint32_t item_id; uint16_t flags; // should be 0x0F04 char16_t text[17]; - }; + } __attribute__((packed)); vector entries; entries.emplace_back(); @@ -944,7 +944,7 @@ static void send_menu_dc_gc(shared_ptr c, const char16_t* menu_name, uint32_t item_id; uint16_t flags; // should be 0x0F04 char text[18]; - }; + } __attribute__((packed)); vector entries; entries.emplace_back(); @@ -1004,7 +1004,7 @@ static void send_game_menu_pc(shared_ptr c, shared_ptr s) { char16_t name[0x10]; uint8_t episode; uint8_t flags; - }; + } __attribute__((packed)); vector entries; { @@ -1046,7 +1046,7 @@ static void send_game_menu_gc(shared_ptr c, shared_ptr s) { char name[0x10]; uint8_t episode; uint8_t flags; - }; + } __attribute__((packed)); vector entries; { @@ -1093,7 +1093,7 @@ static void send_game_menu_bb(shared_ptr c, shared_ptr s) { char16_t name[0x10]; uint8_t episode; uint8_t flags; - }; + } __attribute__((packed)); vector entries; { @@ -1151,7 +1151,7 @@ static void send_quest_menu_pc(shared_ptr c, uint32_t menu_id, uint32_t quest_id; char16_t name[0x20]; char16_t short_desc[0x70]; - }; + } __attribute__((packed)); vector entries; for (const auto& quest : quests) { @@ -1174,7 +1174,7 @@ static void send_quest_menu_pc(std::shared_ptr c, uint32_t menu_id, uint32_t item_id; char16_t name[0x20]; char16_t short_desc[0x70]; - }; + } __attribute__((packed)); vector entries; for (const auto& item : items) { @@ -1197,7 +1197,7 @@ static void send_quest_menu_gc(shared_ptr c, uint32_t menu_id, uint32_t quest_id; char name[0x20]; char short_desc[0x70]; - }; + } __attribute__((packed)); vector entries; for (const auto& quest : quests) { @@ -1220,7 +1220,7 @@ static void send_quest_menu_gc(shared_ptr c, uint32_t menu_id, uint32_t item_id; char name[0x20]; char short_desc[0x70]; - }; + } __attribute__((packed)); vector entries; for (const auto& item : items) { @@ -1245,7 +1245,7 @@ static void send_quest_menu_bb(shared_ptr c, uint32_t menu_id, uint32_t quest_id; char16_t name[0x20]; char16_t short_desc[0x7A]; - }; + } __attribute__((packed)); vector entries; for (const auto& quest : quests) { @@ -1270,7 +1270,7 @@ static void send_quest_menu_bb(shared_ptr c, uint32_t menu_id, uint32_t item_id; char16_t name[0x20]; char16_t short_desc[0x7A]; - }; + } __attribute__((packed)); vector entries; for (const auto& item : items) { @@ -1321,7 +1321,7 @@ void send_lobby_list(shared_ptr c, shared_ptr s) { uint32_t menu_id; uint32_t item_id; uint32_t unused; // should be 0x00000000 - }; + } __attribute__((packed)); vector entries; for (shared_ptr l : s->all_lobbies()) { @@ -1364,7 +1364,7 @@ static void send_join_game_pc(shared_ptr c, shared_ptr l) { uint8_t unused2; uint8_t solo_mode; uint8_t unused3; - } cmd; + } __attribute__((packed)) cmd; size_t player_count = 0; memcpy(cmd.variations, l->variations, sizeof(cmd.variations)); @@ -1458,7 +1458,7 @@ static void send_join_game_bb(shared_ptr c, shared_ptr l) { uint8_t unused2; uint8_t solo_mode; uint8_t unused3; - } cmd; + } __attribute__((packed)) cmd; size_t player_count = 0; memcpy(cmd.variations, l->variations, sizeof(cmd.variations)); @@ -1500,7 +1500,7 @@ static void send_join_lobby_pc(shared_ptr c, shared_ptr l) { uint16_t block_number; uint16_t event; uint32_t unused; - } cmd = { + } __attribute__((packed)) cmd = { c->lobby_client_id, l->leader_id, 0x01, @@ -1513,7 +1513,7 @@ static void send_join_lobby_pc(shared_ptr c, shared_ptr l) { struct Entry { PlayerLobbyDataPC lobby_data; PlayerLobbyJoinDataPCGC data; - }; + } __attribute__((packed)); vector entries; for (size_t x = 0; x < l->max_clients; x++) { @@ -1557,7 +1557,7 @@ static void send_join_lobby_gc(shared_ptr c, shared_ptr l) { uint16_t block_number; uint16_t event; uint32_t unused; - } cmd = { + } __attribute__((packed)) cmd = { c->lobby_client_id, l->leader_id, 0x01, @@ -1570,7 +1570,7 @@ static void send_join_lobby_gc(shared_ptr c, shared_ptr l) { struct Entry { PlayerLobbyDataGC lobby_data; PlayerLobbyJoinDataPCGC data; - }; + } __attribute__((packed)); vector entries; for (size_t x = 0; x < l->max_clients; x++) { @@ -1606,7 +1606,7 @@ static void send_join_lobby_bb(shared_ptr c, shared_ptr l) { uint16_t block_number; uint16_t event; uint32_t unused; - } cmd = { + } __attribute__((packed)) cmd = { c->lobby_client_id, l->leader_id, 0x01, @@ -1619,7 +1619,7 @@ static void send_join_lobby_bb(shared_ptr c, shared_ptr l) { struct Entry { PlayerLobbyDataBB lobby_data; PlayerLobbyJoinDataBB data; - }; + } __attribute__((packed)); vector entries; for (size_t x = 0; x < l->max_clients; x++) { @@ -1693,7 +1693,7 @@ static void send_player_join_notification_pc(shared_ptr c, uint32_t unused; PlayerLobbyDataPC lobby_data; PlayerLobbyJoinDataPCGC data; - } cmd = { + } __attribute__((packed)) cmd = { 0xFF, l->leader_id, 0x01, @@ -1722,7 +1722,7 @@ static void send_player_join_notification_gc(shared_ptr c, uint32_t unused; PlayerLobbyDataGC lobby_data; PlayerLobbyJoinDataPCGC data; - } cmd = { + } __attribute__((packed)) cmd = { 0xFF, l->leader_id, 0x01, @@ -1751,7 +1751,7 @@ static void send_player_join_notification_bb(shared_ptr c, uint32_t unused; PlayerLobbyDataBB lobby_data; PlayerLobbyJoinDataBB data; - } cmd = { + } __attribute__((packed)) cmd = { 0xFF, l->leader_id, 0x01, @@ -1789,7 +1789,7 @@ void send_player_leave_notification(shared_ptr l, uint8_t leaving_client_ uint8_t client_id; uint8_t leader_id; uint16_t unused; - } cmd = {leaving_client_id, l->leader_id, 0}; + } __attribute__((packed)) cmd = {leaving_client_id, l->leader_id, 0}; send_command(l, l->is_game() ? 0x66 : 0x69, leaving_client_id, cmd); } @@ -1807,7 +1807,7 @@ void send_arrow_update(shared_ptr l) { uint32_t player_tag; uint32_t serial_number; uint32_t arrow_color; - }; + } __attribute__((packed)); vector entries; for (size_t x = 0; x < l->max_clients; x++) { @@ -1926,7 +1926,7 @@ void send_drop_item(shared_ptr l, const ItemData& item, float y; uint32_t unused2; ItemData data; - } cmd = {0x5F, 0x0A, 0x0000, area, from_enemy, request_id, x, y, 0, item}; + } __attribute__((packed)) cmd = {0x5F, 0x0A, 0x0000, area, from_enemy, request_id, x, y, 0, item}; send_command(l, 0x60, 0x00, cmd); } @@ -1943,7 +1943,7 @@ void send_drop_stacked_item(shared_ptr l, const ItemData& item, float y; uint32_t unused3; ItemData data; - } cmd = {0x5D, 0x09, 0x0000, area, 0, x, y, 0, item}; + } __attribute__((packed)) cmd = {0x5D, 0x09, 0x0000, area, 0, x, y, 0, item}; send_command(l, 0x60, 0x00, cmd); } @@ -1957,7 +1957,7 @@ void send_pick_up_item(shared_ptr l, shared_ptr c, uint16_t client_id2; uint16_t area; uint32_t item_id; - } cmd = {0x59, 0x03, c->lobby_client_id, c->lobby_client_id, area, item_id}; + } __attribute__((packed)) cmd = {0x59, 0x03, c->lobby_client_id, c->lobby_client_id, area, item_id}; send_command(l, 0x60, 0x00, cmd); } @@ -1970,7 +1970,7 @@ void send_create_inventory_item(shared_ptr l, shared_ptr c, uint16_t client_id; ItemData item; uint32_t unused; - } cmd = {0xBE, 0x07, c->lobby_client_id, item, 0}; + } __attribute__((packed)) cmd = {0xBE, 0x07, c->lobby_client_id, item, 0}; send_command(l, 0x60, 0x00, cmd); } @@ -1983,7 +1983,7 @@ void send_destroy_item(shared_ptr l, shared_ptr c, uint16_t client_id; uint32_t item_id; uint32_t amount; - } cmd = {0x29, 0x03, c->lobby_client_id, item_id, amount}; + } __attribute__((packed)) cmd = {0x29, 0x03, c->lobby_client_id, item_id, amount}; send_command(l, 0x60, 0x00, cmd); } @@ -2001,7 +2001,7 @@ void send_bank(shared_ptr c) { uint32_t checksum; // can be random; client won't notice uint32_t numItems; uint32_t meseta; - } cmd = {0xBC, 0, 0, 0, checksum, c->player.bank.num_items, c->player.bank.meseta}; + } __attribute__((packed)) cmd = {0xBC, 0, 0, 0, checksum, c->player.bank.num_items, c->player.bank.meseta}; size_t size = 8 + sizeof(cmd) + items.size() * sizeof(PlayerBankItem); cmd.size = size; @@ -2019,7 +2019,7 @@ void send_shop(shared_ptr c, uint8_t shop_type) { uint8_t num_items; uint16_t unused; ItemData entries[20]; - } cmd = { + } __attribute__((packed)) cmd = { 0xB6, 0x2C, 0x037F, @@ -2104,7 +2104,7 @@ void send_ep3_rank_update(shared_ptr c) { uint32_t meseta; uint32_t max_meseta; uint32_t jukebox_songs_unlocked; - } cmd = {0, "\0\0\0\0\0\0\0\0\0\0\0", 0x00FFFFFF, 0x00FFFFFF, 0xFFFFFFFF}; + } __attribute__((packed)) cmd = {0, "\0\0\0\0\0\0\0\0\0\0\0", 0x00FFFFFF, 0x00FFFFFF, 0xFFFFFFFF}; send_command(c, 0xB7, 0x00, cmd); } @@ -2140,10 +2140,6 @@ void send_ep3_map_data(shared_ptr l, uint32_t map_id) { -//////////////////////////////////////////////////////////////////////////////// -// CommandLoadQuestFile: sends a quest file to the client. -// the _OpenFile functions send the begin command (44/A6), and the _SendChunk functions send a chunk of data (13/A7). - static void send_quest_open_file_pc_gc(shared_ptr c, const string& filename, uint32_t file_size, bool is_download_quest, bool is_ep3_quest) { @@ -2153,7 +2149,7 @@ static void send_quest_open_file_pc_gc(shared_ptr c, uint16_t flags; char filename[0x10]; uint32_t file_size; - } cmd; + } __attribute__((packed)) cmd; memset(&cmd, 0, sizeof(cmd)); strncpy(cmd.name, filename.c_str(), 0x1F); cmd.flags = 2 + is_ep3_quest; @@ -2171,7 +2167,7 @@ static void send_quest_open_file_bb(shared_ptr c, char filename[0x10]; uint32_t file_size; char name[0x18]; - } cmd; + } __attribute__((packed)) cmd; memset(&cmd, 0, sizeof(cmd)); cmd.flags = 2 + is_ep3_quest; strncpy(cmd.filename, filename.c_str(), 0x0F); @@ -2189,7 +2185,7 @@ static void send_quest_file_chunk(shared_ptr c, const char* filename, char filename[0x10]; uint8_t data[0x400]; uint32_t data_size; - } cmd; + } __attribute__((packed)) cmd; memset(cmd.filename, 0, 0x10); strncpy(cmd.filename, filename, 0x0F); memcpy(cmd.data, data, size); diff --git a/src/SendCommands.hh b/src/SendCommands.hh index a9859af0..ef699fb7 100644 --- a/src/SendCommands.hh +++ b/src/SendCommands.hh @@ -147,7 +147,7 @@ struct JoinGameCommand_GC_64 { struct { PlayerInventory inventory; PlayerDispDataPCGC disp; - } player[4]; // only used on ep3 + } __attribute__((packed)) player[4]; // only used on ep3 } __attribute__((packed)); void send_join_lobby(std::shared_ptr c, std::shared_ptr l);