From 826eb88e2e53af83283810dfc07999d10895e2d8 Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Sun, 26 Apr 2026 17:55:39 -0700 Subject: [PATCH] add __packed_ws_be__ --- src/BMLArchive.cc | 8 ++------ src/ChoiceSearch.hh | 4 +--- src/CommandFormats.hh | 34 +++++++++++----------------------- src/CommonFileFormats.hh | 8 ++------ src/CommonItemSet.hh | 5 +---- src/GSLArchive.cc | 5 +---- src/LevelTable.hh | 12 +++--------- src/PSOEncryption.hh | 4 +--- src/PlayerInventory.hh | 12 +++--------- src/PlayerSubordinates.hh | 27 +++++++-------------------- src/Quest.cc | 4 +--- src/RareItemSet.hh | 4 +--- src/SaveFileFormats.hh | 4 +--- src/Text.hh | 5 +++++ src/WordSelectTable.cc | 5 +---- 15 files changed, 41 insertions(+), 100 deletions(-) diff --git a/src/BMLArchive.cc b/src/BMLArchive.cc index 0b441cf2..a3dd0eb2 100644 --- a/src/BMLArchive.cc +++ b/src/BMLArchive.cc @@ -14,11 +14,9 @@ struct BMLHeaderT { parray unknown_a1; U32T num_entries; parray unknown_a2; -} __attribute__((packed)); +} __packed_ws_be__(BMLHeaderT, 0x40); using BMLHeader = BMLHeaderT; using BMLHeaderBE = BMLHeaderT; -check_struct_size(BMLHeader, 0x40); -check_struct_size(BMLHeaderBE, 0x40); template struct BMLHeaderEntryT { @@ -29,11 +27,9 @@ struct BMLHeaderEntryT { U32T compressed_gvm_size; U32T decompressed_gvm_size; parray unknown_a2; -} __attribute__((packed)); +} __packed_ws_be__(BMLHeaderEntryT, 0x40); using BMLHeaderEntry = BMLHeaderEntryT; using BMLHeaderEntryBE = BMLHeaderEntryT; -check_struct_size(BMLHeaderEntry, 0x40); -check_struct_size(BMLHeaderEntryBE, 0x40); template void BMLArchive::load_t() { diff --git a/src/ChoiceSearch.hh b/src/ChoiceSearch.hh index 2af70a5f..3d6b988b 100644 --- a/src/ChoiceSearch.hh +++ b/src/ChoiceSearch.hh @@ -40,11 +40,9 @@ struct ChoiceSearchConfigT { } return ret; } -} __attribute__((packed)); +} __packed_ws_be__(ChoiceSearchConfigT, 0x18); using ChoiceSearchConfig = ChoiceSearchConfigT; using ChoiceSearchConfigBE = ChoiceSearchConfigT; -check_struct_size(ChoiceSearchConfig, 0x18); -check_struct_size(ChoiceSearchConfigBE, 0x18); struct ChoiceSearchCategory { struct Choice { diff --git a/src/CommandFormats.hh b/src/CommandFormats.hh index e394edf0..7817681a 100644 --- a/src/CommandFormats.hh +++ b/src/CommandFormats.hh @@ -251,14 +251,13 @@ struct S_StartFileDownloads_Patch_11 { // 14 (S->C): Reconnect // Same format and usage as command 19 on the game server (described below), except the port field is big-endian. -template +template struct S_ReconnectT { be_uint32_t address = 0; - PortT port = 0; + U16T port = 0; le_uint16_t unused = 0; -} __attribute__((packed)); -using S_Reconnect_Patch_14 = S_ReconnectT; -check_struct_size(S_Reconnect_Patch_14, 0x08); +} __packed_ws_be__(S_ReconnectT, 0x08); +using S_Reconnect_Patch_14 = S_ReconnectT; // 15 (S->C): Login failure // No arguments. The client shows a message like "Incorrect game ID or password" and disconnects. @@ -724,8 +723,7 @@ struct C_WriteFileConfirmation_V3_BB_13_A7 { // connection; the server should send an appropriate command to enable it when the client connects. PSO Xbox seems to // ignore the address field, which makes sense given its networking architecture. -using S_Reconnect_19 = S_ReconnectT; -check_struct_size(S_Reconnect_19, 8); +using S_Reconnect_19 = S_ReconnectT; // Sylverant implements an IPv6 version of this command, but it's not obvious why. IPv6 technically did exist as a // draft standard at the time of PSO's development, but it wasn't widely used until over a decade later. IPv6 support @@ -3767,12 +3765,10 @@ struct G_UpdateEnemyStateT_6x0A { // 40000000 = entity is object (some entities have both this and 20000000 set; this appears to make TWindowLockOn // not show anything but the entity is still attackable, see TWindowLockOn_should_show_for_entity) // 80000000 = entity is item - typename std::conditional_t game_flags = 0; -} __attribute__((packed)); + U32T game_flags = 0; +} __packed_ws_be__(G_UpdateEnemyStateT_6x0A, 0x0C); using G_UpdateEnemyState_GC_6x0A = G_UpdateEnemyStateT_6x0A; using G_UpdateEnemyState_DC_PC_XB_BB_6x0A = G_UpdateEnemyStateT_6x0A; -check_struct_size(G_UpdateEnemyState_GC_6x0A, 0x0C); -check_struct_size(G_UpdateEnemyState_DC_PC_XB_BB_6x0A, 0x0C); // 6x0B: Update object state @@ -3838,11 +3834,9 @@ struct G_DragonBossActionsT_6x12 { le_uint32_t target_client_id = 0xFFFF; // 0xFFFF (not 0xFFFFFFFF) means no target F32T x = 0.0f; F32T z = 0.0f; -} __attribute__((packed)); +} __packed_ws_be__(G_DragonBossActionsT_6x12, 0x14); using G_DragonBossActions_DC_PC_XB_BB_6x12 = G_DragonBossActionsT_6x12; using G_DragonBossActions_GC_6x12 = G_DragonBossActionsT_6x12; -check_struct_size(G_DragonBossActions_DC_PC_XB_BB_6x12, 0x14); -check_struct_size(G_DragonBossActions_GC_6x12, 0x14); // 6x13: De Rol Le boss actions (not valid on Episode 3) @@ -4875,11 +4869,9 @@ struct G_WordSelectT_6x74 { uint8_t size = 0; U16T client_id = 0; WordSelectMessage message; -} __attribute__((packed)); +} __packed_ws_be__(G_WordSelectT_6x74, 0x20); using G_WordSelect_6x74 = G_WordSelectT_6x74; using G_WordSelectBE_6x74 = G_WordSelectT_6x74; -check_struct_size(G_WordSelect_6x74, 0x20); -check_struct_size(G_WordSelectBE_6x74, 0x20); // 6x75: Update quest flag // This command does nothing on Episode 3. @@ -5007,11 +4999,9 @@ struct G_BattleScoresT_6x7F { } __packed_ws__(Entry, 8); G_UnusedHeader header; parray entries; -} __attribute__((packed)); +} __packed_ws_be__(G_BattleScoresT_6x7F, 0x24); using G_BattleScores_6x7F = G_BattleScoresT_6x7F; using G_BattleScoresBE_6x7F = G_BattleScoresT_6x7F; -check_struct_size(G_BattleScores_6x7F, 0x24); -check_struct_size(G_BattleScoresBE_6x7F, 0x24); // 6x80: Trigger trap (not valid on Episode 3) @@ -5370,11 +5360,9 @@ struct G_GolDragonBossActionsT_6xA8 { F32T z = 0.0f; uint8_t unknown_a5 = 0; parray unused; -} __attribute__((packed)); +} __packed_ws_be__(G_GolDragonBossActionsT_6xA8, 0x18); using G_GolDragonBossActions_XB_BB_6xA8 = G_GolDragonBossActionsT_6xA8; using G_GolDragonBossActions_GC_6xA8 = G_GolDragonBossActionsT_6xA8; -check_struct_size(G_GolDragonBossActions_XB_BB_6xA8, 0x18); -check_struct_size(G_GolDragonBossActions_GC_6xA8, 0x18); // 6xA9: Barba Ray boss actions (not valid on pre-V3 or Episode 3) diff --git a/src/CommonFileFormats.hh b/src/CommonFileFormats.hh index 539701bd..60e8cfe6 100644 --- a/src/CommonFileFormats.hh +++ b/src/CommonFileFormats.hh @@ -131,11 +131,9 @@ struct ArrayRefT { /* 00 */ U32T count; /* 04 */ U32T offset; /* 08 */ -} __attribute__((packed)); +} __packed_ws_be__(ArrayRefT, 8); using ArrayRef = ArrayRefT; using ArrayRefBE = ArrayRefT; -check_struct_size(ArrayRef, 8); -check_struct_size(ArrayRefBE, 8); template struct RELFileFooterT { @@ -159,8 +157,6 @@ struct RELFileFooterT { parray, 2> unused1; U32T root_offset = 0; parray, 3> unused2; -} __attribute__((packed)); +} __packed_ws_be__(RELFileFooterT, 0x20); using RELFileFooter = RELFileFooterT; using RELFileFooterBE = RELFileFooterT; -check_struct_size(RELFileFooter, 0x20); -check_struct_size(RELFileFooterBE, 0x20); diff --git a/src/CommonItemSet.hh b/src/CommonItemSet.hh index 85a4fe82..a3b3c1aa 100644 --- a/src/CommonItemSet.hh +++ b/src/CommonItemSet.hh @@ -244,11 +244,9 @@ public: /* 50 */ U32T box_item_class_prob_table_offset; // There are several unused fields here. - } __attribute__((packed)); + } __packed_ws_be__(OffsetsT, 0x54); using Offsets = OffsetsT; using OffsetsBE = OffsetsT; - check_struct_size(Offsets, 0x54); - check_struct_size(OffsetsBE, 0x54); }; bool operator==(const CommonItemSet& other) const = default; @@ -337,7 +335,6 @@ public: ValueT value; WeightT weight; } __attribute__((packed)); - using WeightTableEntry8 = WeightTableEntry; using WeightTableEntry32 = WeightTableEntry; check_struct_size(WeightTableEntry8, 2); diff --git a/src/GSLArchive.cc b/src/GSLArchive.cc index 562df76c..3fa21d30 100644 --- a/src/GSLArchive.cc +++ b/src/GSLArchive.cc @@ -15,12 +15,9 @@ struct GSLHeaderEntryT { U32T offset; // In pages, so actual offset is this * 0x800 U32T size; uint64_t unused; -} __attribute__((packed)); - +} __packed_ws_be__(GSLHeaderEntryT, 0x30); using GSLHeaderEntry = GSLHeaderEntryT; using GSLHeaderEntryBE = GSLHeaderEntryT; -check_struct_size(GSLHeaderEntry, 0x30); -check_struct_size(GSLHeaderEntryBE, 0x30); template void GSLArchive::load_t() { diff --git a/src/LevelTable.hh b/src/LevelTable.hh index 07f4f4de..c43339d8 100644 --- a/src/LevelTable.hh +++ b/src/LevelTable.hh @@ -33,11 +33,9 @@ struct CharacterStatsT { ret.lck = this->lck; return ret; } -} __attribute__((packed)); +} __packed_ws_be__(CharacterStatsT, 0x0E); using CharacterStats = CharacterStatsT; using CharacterStatsBE = CharacterStatsT; -check_struct_size(CharacterStats, 0x0E); -check_struct_size(CharacterStatsBE, 0x0E); template struct PlayerStatsT { @@ -61,11 +59,9 @@ struct PlayerStatsT { ret.meseta = this->meseta; return ret; } -} __attribute__((packed)); +} __packed_ws_be__(PlayerStatsT, 0x24); using PlayerStats = PlayerStatsT; using PlayerStatsBE = PlayerStatsT; -check_struct_size(PlayerStats, 0x24); -check_struct_size(PlayerStatsBE, 0x24); template struct LevelStatsDeltaT { @@ -89,11 +85,9 @@ struct LevelStatsDeltaT { ps.mst += this->mst; ps.lck += this->lck; } -} __attribute__((packed)); +} __packed_ws_be__(LevelStatsDeltaT, 0x0C); using LevelStatsDelta = LevelStatsDeltaT; using LevelStatsDeltaBE = LevelStatsDeltaT; -check_struct_size(LevelStatsDelta, 0x0C); -check_struct_size(LevelStatsDeltaBE, 0x0C); class LevelTable { // This is the base class for all the LevelTable implementations. The public interface here only defines functions diff --git a/src/PSOEncryption.hh b/src/PSOEncryption.hh index 05b9a939..99825b5d 100644 --- a/src/PSOEncryption.hh +++ b/src/PSOEncryption.hh @@ -343,11 +343,9 @@ public: ret.store_raw(this->value); return ret; } -} __attribute__((packed)); +} __packed_ws_be__(ChallengeTimeT, 4); using ChallengeTime = ChallengeTimeT; using ChallengeTimeBE = ChallengeTimeT; -check_struct_size(ChallengeTime, 4); -check_struct_size(ChallengeTimeBE, 4); std::string decrypt_v2_registry_value(const void* data, size_t size); diff --git a/src/PlayerInventory.hh b/src/PlayerInventory.hh index af34b4d8..295ec033 100644 --- a/src/PlayerInventory.hh +++ b/src/PlayerInventory.hh @@ -76,11 +76,9 @@ struct PlayerInventoryItemT { bool is_equipped() const { return (this->flags & 8); } -} __attribute__((packed)); +} __packed_ws_be__(PlayerInventoryItemT, 0x1C); using PlayerInventoryItem = PlayerInventoryItemT; using PlayerInventoryItemBE = PlayerInventoryItemT; -check_struct_size(PlayerInventoryItem, 0x1C); -check_struct_size(PlayerInventoryItemBE, 0x1C); template struct PlayerBankItemT { @@ -100,11 +98,9 @@ struct PlayerBankItemT { ret.present = this->present; return ret; } -} __attribute__((packed)); +} __packed_ws_be__(PlayerBankItemT, 0x18); using PlayerBankItem = PlayerBankItemT; using PlayerBankItemBE = PlayerBankItemT; -check_struct_size(PlayerBankItem, 0x18); -check_struct_size(PlayerBankItemBE, 0x18); template struct PlayerInventoryT { @@ -291,11 +287,9 @@ struct PlayerInventoryT { ret.items = this->items; return ret; } -} __attribute__((packed)); +} __packed_ws_be__(PlayerInventoryT, 0x34C); using PlayerInventory = PlayerInventoryT; using PlayerInventoryBE = PlayerInventoryT; -check_struct_size(PlayerInventory, 0x34C); -check_struct_size(PlayerInventoryBE, 0x34C); template struct PlayerBankT { diff --git a/src/PlayerSubordinates.hh b/src/PlayerSubordinates.hh index e0db3466..7da0a487 100644 --- a/src/PlayerSubordinates.hh +++ b/src/PlayerSubordinates.hh @@ -312,11 +312,9 @@ struct PlayerVisualConfigT { ret.proportion_y = this->proportion_y; return ret; } -} __attribute__((packed)); +} __packed_ws_be__(PlayerVisualConfigT, 0x50); using PlayerVisualConfig = PlayerVisualConfigT; using PlayerVisualConfigBE = PlayerVisualConfigT; -check_struct_size(PlayerVisualConfig, 0x50); -check_struct_size(PlayerVisualConfigBE, 0x50); template struct PlayerDispDataDCPCV3T { @@ -331,11 +329,9 @@ struct PlayerDispDataDCPCV3T { } PlayerDispDataBB to_bb(Language to_language, Language from_language) const; -} __attribute__((packed)); +} __packed_ws_be__(PlayerDispDataDCPCV3T, 0xD0); using PlayerDispDataDCPCV3 = PlayerDispDataDCPCV3T; using PlayerDispDataDCPCV3BE = PlayerDispDataDCPCV3T; -check_struct_size(PlayerDispDataDCPCV3, 0xD0); -check_struct_size(PlayerDispDataDCPCV3BE, 0xD0); struct PlayerDispDataBBPreview { /* 00 */ le_uint32_t experience = 0; @@ -598,11 +594,9 @@ struct ChallengeAwardStateT { ret.maximum_rank = this->maximum_rank; return ret; } -} __attribute__((packed)); +} __packed_ws_be__(ChallengeAwardStateT, 8); using ChallengeAwardState = ChallengeAwardStateT; using ChallengeAwardStateBE = ChallengeAwardStateT; -check_struct_size(ChallengeAwardState, 8); -check_struct_size(ChallengeAwardStateBE, 8); template struct PlayerRecordsChallengeDCPCT { @@ -673,11 +667,9 @@ struct PlayerRecordsChallengeV3T { /* 00D8:00F4 */ pstring rank_title; /* 00E4:0100 */ parray unknown_l7; /* 0100:011C */ -} __attribute__((packed)); +} __packed_ws_be__(PlayerRecordsChallengeV3T, 0x100); using PlayerRecordsChallengeV3 = PlayerRecordsChallengeV3T; using PlayerRecordsChallengeV3BE = PlayerRecordsChallengeV3T; -check_struct_size(PlayerRecordsChallengeV3, 0x100); -check_struct_size(PlayerRecordsChallengeV3BE, 0x100); struct PlayerRecordsChallengeEp3 { /* 00:1C */ be_uint16_t title_color = 0x7FFF; // XRGB1555 @@ -704,8 +696,7 @@ struct PlayerRecordsChallengeEp3 { /* C8:E4 */ ChallengeAwardStateT ep2_online_award_state; /* D0:EC */ ChallengeAwardStateT ep1_offline_award_state; /* D8:F4 */ -} __attribute__((packed)); -check_struct_size(PlayerRecordsChallengeEp3, 0xD8); +} __packed_ws__(PlayerRecordsChallengeEp3, 0xD8); struct PlayerRecordsChallengeBB { /* 0000 */ le_uint16_t title_color = 0x7FFF; // XRGB1555 @@ -833,11 +824,9 @@ struct PlayerRecordsBattleT { } return ret; } -} __attribute__((packed)); +} __packed_ws_be__(PlayerRecordsBattleT, 0x18); using PlayerRecordsBattle = PlayerRecordsBattleT; using PlayerRecordsBattleBE = PlayerRecordsBattleT; -check_struct_size(PlayerRecordsBattle, 0x18); -check_struct_size(PlayerRecordsBattleBE, 0x18); template DestT convert_player_disp_data(const SrcT&, Language, Language) { @@ -1112,11 +1101,9 @@ struct SymbolChatT { ret.face_parts = this->face_parts; return ret; } -} __attribute__((packed)); +} __packed_ws_be__(SymbolChatT, 0x3C); using SymbolChat = SymbolChatT; using SymbolChatBE = SymbolChatT; -check_struct_size(SymbolChat, 0x3C); -check_struct_size(SymbolChatBE, 0x3C); struct TelepipeState { /* 00 */ le_uint16_t owner_client_id = 0xFFFF; diff --git a/src/Quest.cc b/src/Quest.cc index dac745e0..e5b6fc1a 100644 --- a/src/Quest.cc +++ b/src/Quest.cc @@ -51,11 +51,9 @@ struct PSOMemCardDLQFileEncryptedHeaderT { le_uint32_t decompressed_size; le_uint32_t round3_seed; // Data follows here. -} __attribute__((packed)); +} __packed_ws_be__(PSOMemCardDLQFileEncryptedHeaderT, 0x10); using PSOVMSDLQFileEncryptedHeader = PSOMemCardDLQFileEncryptedHeaderT; using PSOGCIDLQFileEncryptedHeader = PSOMemCardDLQFileEncryptedHeaderT; -check_struct_size(PSOVMSDLQFileEncryptedHeader, 0x10); -check_struct_size(PSOGCIDLQFileEncryptedHeader, 0x10); template string decrypt_download_quest_data_section( diff --git a/src/RareItemSet.hh b/src/RareItemSet.hh index b5d26a8f..a16d716b 100644 --- a/src/RareItemSet.hh +++ b/src/RareItemSet.hh @@ -93,11 +93,9 @@ protected: /* 08 */ U32T box_areas_offset; // -> parray /* 0C */ U32T box_rares_offset; // -> parray /* 10 */ - } __attribute__((packed)); + } __packed_ws_be__(OffsetsT, 0x10); using Offsets = OffsetsT; using OffsetsBE = OffsetsT; - check_struct_size(Offsets, 0x10); - check_struct_size(OffsetsBE, 0x10); struct BoxRare { uint8_t area_norm_plus_1; diff --git a/src/SaveFileFormats.hh b/src/SaveFileFormats.hh index 34354f10..ba4e6417 100644 --- a/src/SaveFileFormats.hh +++ b/src/SaveFileFormats.hh @@ -158,11 +158,9 @@ struct WordSelectMessageT { ret.unknown_a4 = this->unknown_a4; return ret; } -} __attribute__((packed)); +} __packed_ws_be__(WordSelectMessageT, 0x1C); using WordSelectMessage = WordSelectMessageT; using WordSelectMessageBE = WordSelectMessageT; -check_struct_size(WordSelectMessage, 0x1C); -check_struct_size(WordSelectMessageBE, 0x1C); template struct SaveFileChatShortcutEntryT { diff --git a/src/Text.hh b/src/Text.hh index 4830abd4..d97d9f9d 100644 --- a/src/Text.hh +++ b/src/Text.hh @@ -23,6 +23,11 @@ __attribute__((packed)); \ check_struct_size(StructT, Size) +#define __packed_ws_be__(StructT, Size) \ + __attribute__((packed)); \ + check_struct_size(StructT, Size); \ + check_struct_size(StructT, Size) + // Conversion functions std::string encode_utf8_char(uint32_t ch); diff --git a/src/WordSelectTable.cc b/src/WordSelectTable.cc index 21d7db3d..aa50748a 100644 --- a/src/WordSelectTable.cc +++ b/src/WordSelectTable.cc @@ -40,12 +40,9 @@ struct NonWindowsRootT { U32T table4; U32T article_types_table; U32T table6; -} __attribute__((packed)); - +} __packed_ws_be__(NonWindowsRootT, 0x1C); using NonWindowsRoot = NonWindowsRootT; using NonWindowsRootBE = NonWindowsRootT; -check_struct_size(NonWindowsRoot, 0x1C); -check_struct_size(NonWindowsRootBE, 0x1C); struct PCV2Root { le_uint32_t unknown_a1;