Skip to content

Fix 28 tables the game client reads differently - #251

Merged
SnosMe merged 3 commits into
poe-tool-dev:mainfrom
juddisjudd:client-key-targets
Oct 29, 2026
Merged

SnosMe merged 3 commits into
poe-tool-dev:mainfrom
juddisjudd:client-key-targets

Conversation

@juddisjudd

@juddisjudd juddisjudd commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Fixes 28 tables where the game client's loader reads the columns differently from the schema. Checked against PoE 2 0.5.5.5 and PoE 1 3.29.3.3.

Commits

  1. Checked against the bytes: 19 tables, both games.
  2. Client only: 9 PoE 2 tables whose rows are empty or fit both targets. Here only the client's loader decides. Drop this commit if you want byte evidence for everything.
  3. PoE 1: the same misreads in 5 PoE 1 tables, checked against the bytes.

Checks

  • Every string and list reads the variable data in the order the game writes it, and every key is null or in range. Run on PoE 2 0.5.5.4, 0.5.5.4.2 and 0.5.5.5, and on PoE 1.
  • poe_data_tools decodes the changed columns to the values below. Unchanged columns decode exactly as before.
  • ggpk-explorer lint: PoE 2 findings go from 16 to 8, PoE 1 from 26 to 23, none new.
Evidence per table

1. Checked against the bytes (PoE 2 unless marked)

  • BloodTypes: GroundEffect becomes Gibs: [MiscAnimated] (ExtraGoreRedBloodGib1 to 6; as GroundEffects it reads fadeout). _: [string] becomes CorpseStain: [MiscEffectPacks] (MonsterBloodCorpseStain, empty on every …NoCorpseStainEPK row).
  • BuffVisualShapeShiftOverride: ShapeShiftForm: ShapeShiftForms comes before ShapeShiftVisualIdentity. The form reads WereBear or Wolf. The visual identity reads Any, and once holds 11, past the 7 forms.
  • CharacterPanelStats: _: [i32] becomes [StatDescriptionFunctions], 16-byte keys (PerMinuteToPerSecond on the regeneration rows).
  • Characters: a 16-byte WeaponSoundType key at 136 (Unarmed). CharacterSize moves to 156. There it reads 2, as in PoE 1; before, it read 0.
  • Chests, UniqueChests (both games): Environment and AppearanceChestsKey become LockedError: BackendErrors (PoE 1: IzaroChestLocked, and SpiderChestLocked on "Strange Barrel").
  • CurrencyPerItemClassConditions: a Currency: CurrencyItems key comes first (the Regal, Exalted and Chaos tiers), then ItemClass (TowerAugmentation).
  • EnvironmentFootprints: points at FootstepAudio (Dirt, Clay, ShortGrass; as Environments it reads NoMusic, 1_1).
  • ExecuteGEAL (both games): the empty list starts at byte 59, not 58. Only then do its offsets fall in write order.
  • GoldVisualIdentities: Icon becomes Rarity. Normal, Magic and Rare sit beside the small, medium and large gold piles.
  • GrantedEffects: SupportWeaponRestrictions points at [WieldableClasses]. Mirage Archer reads Bow, Spear and Crossbow; as ItemClasses it reads Claw, Two Hand Mace and Active Skill Gem.
  • NPCDialogueStyles: the row and string become one [i32].
  • NPCMaster: Audio becomes Currency: CurrencyItems. Kirac reads CurrencyMapQuality; his own audio rows are elsewhere.
  • QuestRewards: runs of i32 become a Characters list, a string, [Mods] and [_], as in PoE 1.
  • UltimatumWagerTypes: CurrencyItem becomes BaseItemType: BaseItemTypes. It names the same item as each row's Id; as CurrencyItems, 15 of 21 rows read another currency.
  • WorldAreaLeagueChances: the four i32 at byte 20 become [i32] (for example [150, 80, 40, 30]).
  • WorldAreas: the i32 pairs at 299, 355 and 428 are strings. Every row points at the empty string.
  • BattlePassRewards (both games): four i32 become Track: BattlePassTracks. In PoE 1, each pass from Five on has 8 rows on Free and 8 on Basic.
  • MonsterVarieties (PoE 1): [i32] becomes [MultiPartAchievements] (the Synthesis boss reads DefeatVenariusWithoutDamageInPhase1).

2. Client only (PoE 2, except BetrayalUpgrades)

  • Empty lists get key types: ItemVisualIdentity, MonsterVarieties, UltimatumModifiers and WorldAreas, where PoE 1's same column has data, and BuffDefinitions.
  • BetrayalUpgrades (both games): GrantedEffectsKey becomes ItemVisualIdentityKey2. Both clients read it so; it is empty in both games.
  • ExpeditionCurrency: NPC becomes Faction. ExpeditionDealsDialogue: ExpeditionCurrency becomes NPC, and Rog's lines read Dealer.
  • KeywordPopupItemReference Rarity becomes ItemFrameType, Quest QuestFlag becomes WorldAreas, and QuestStaticRewards Achievement becomes CompletionNotification. Their values fit both targets.

3. PoE 1

  • CharacterPanelStats and WorldAreaLeagueChances: the same changes as in PoE 2 (DivideByOneHundred on crit rows; [50, 50, 50, 1]).
  • QuestRewards: the list at 106 is not empty. 36 rows hold [Archetypes] keys, such as VolcanicFissureBerserker.
  • ItemVisualIdentity: the bool moves in front of the two empty lists, which start at 532 and 548.
  • UniqueChests: _: [i32] becomes DaemonMods: [Mods], as in PoE 2 (Ventor's Strongbox reads VentorsStrongboxFakeDaemon).

Not changed: Mods byte 278, Flasks byte 44 and MapDeviceRecipes byte 100, where PoE 1's same column reads another target, and BetrayalUpgrades byte 52.

The new column names are my reading of the values. I am happy to change any of them.

…bytes

Key targets, lists, strings and one shifted list in PoE 2 and PoE 1 tables, each checked against PoE 2 0.5.5.5 and PoE 1 3.29.3.3.
These rows are empty in PoE 2, or the values fit both tables; the client indexes rows of the new target's size.
CharacterPanelStats, ItemVisualIdentity, QuestRewards, UniqueChests and WorldAreaLeagueChances, checked against PoE 1 3.29.3.3.
@SnosMe
SnosMe merged commit 6034b07 into poe-tool-dev:main Oct 29, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants