Skip to content

Cryopod detection misses ASA "Dinoball" items entirely (casing + CustomDataName mismatch), and stats are empty once decoded #2

Description

@tycoonverena

Body

arkparser version: 0.7.2
Game: ARK: Survival Ascended (dedicated PvE cluster)
Map tested: custom map ("Astraeos_WP"), but this looks structural, not map-specific

Summary

On my ASA server, WorldSave.iter_cryopod_creatures() returns 0 results even though the server has ~15,000 filled dinoballs. I tracked this down to two separate bugs that stack on top of each other, plus a third, deeper issue once the first two are fixed (cryopodded creatures decode with empty stat dicts).

Bug 1 — CRYOPOD_CLASS_PATTERNS casing mismatch

arkparser/common/types.py:

CRYOPOD_CLASS_PATTERNS: tuple[str, ...] = (
    "Cryopod",
    "SoulTrap",
    "Vivarium",
    "DinoBall",   # capital B
)

The actual dinoball item class on this ASA server is ItemDinoball_C — lowercase "b". Since the match is a case-sensitive substring check (any(p in cn for p in CRYOPOD_CLASS_PATTERNS)), it never matches. I found 14,975 ItemDinoball_C objects in one save, 0 of which were recognized as cryopod-class items.

Dumping every "cryo"-ish class name in the same save also turned up a few related items, for reference:

   14975  ItemDinoball_C                     (matches "DinoBall"? NO — casing)
     195  DinoballStorageBox_C
     195  InventoryDinoballStorageBox_C
     133  PrimalItem_WeaponEmptyCryopod_C
      57  ItemDinoballStack_C
      32  ItemDinoballStorageBox_C
      31  ItemStructureDinoballDisplayCase_C
      22  VivariumV2_CS_C
      22  PrimalInventory_Vivarium_CS_C
       9  PrimalItemStructure_Vivarium_CS_C

Suggested fix: add "Dinoball" (lowercase b) to CRYOPOD_CLASS_PATTERNS alongside the existing "DinoBall" entry (I left the original as-is in case some ASE save legitimately uses that casing).

Bug 2 — CustomDataName mismatch in iter_cryopod_creatures() / _decode_inventory_cryopod()

Even after fixing bug 1, iter_cryopod_creatures() still returned 0. Both WorldSave.iter_cryopod_creatures() (files/world_save.py) and export.py's _decode_inventory_cryopod() only accept an embedded CustomItemDatas entry when:

entry.get("CustomDataName") != "Dino"

On this ASA server, the entry holding the actual creature data is named DinoballItemData, not "Dino". There's also a sibling entry named DinoballTooltipData (display text only, not the creature blob) that should stay ignored.

Once I widened the check to entry.get("CustomDataName") not in ("Dino", "DinoballItemData"), CryopodCreature.from_asa_cryopod_data(entry) (which was already implemented and already handles this exact strings/floats shape!) successfully decoded name/species/level/colors for every sample I checked.

Suggested fix: accept "DinoballItemData" as an additional valid entry name in both call sites, alongside "Dino".

Combined impact of bugs 1+2

After patching both locally, iter_cryopod_creatures() went from 0 to 14,931 decoded creatures on the same save, correctly attributed to the right tribes via the existing owner-lookup fallback (verified one tribe: 12,491 of its cryopodded dinos correctly resolved to the right tribe id). So the fix itself works well for identity/tribe/name/level/species — this is a big deal for anyone running ASA where cryo is the majority of a tribe's roster (as your own docstring on iter_cryopod_creatures already notes: "2,158 of 2,518 on-map tames on the live SE PvE reference" were in cryo — that's presumably the same class of bug hitting ASE saves too if any of them use similarly-cased item classes).

Bug 3 (unresolved on my end) — stat data (HP/Stam/Melee/etc.) is empty for ASA cryopods

Once decoded via from_asa_cryopod_data(), the resulting CryopodCreature has current_stats={}, max_stats={}, base_stats={}, level_ups_wild={}, level_ups_tamed={} — only identity fields (class_name/name/species/level/colors) come through. For my use case (an ARK server-manager web app) this means cryopodded dinos show up with correct name/tribe/level but 0 for every wild/mutated/tamed stat point.

Investigating further: CustomDataBytes.ByteArrays[0].Bytes (the same blob from_cryopod_bytes() is meant to parse) is not the plain ASE format that function expects. On this ASA server it's:

  • 12-byte header: 3x little-endian int32. First value is constant (1031) across every sample I checked; the second value exactly equals the decompressed payload length; the third is unclear (roughly ~1.3x the decompressed length).
  • Followed immediately by a standard zlib stream (\x78\x9c magic at byte offset 12), which decompresses cleanly with plain zlib.decompress().

The decompressed payload is not in the format from_cryopod_bytes() expects either (no leading GUID + obj_count int32 — reading it that way gives nonsense). It does contain readable, correctly-spelled property/level names like BaseCharacterLevel, NumberOfLevelUpPointsApplied, NumberOfMutationsAppliedTamed, DinoImprintingQuality, DoubleProperty, DinoAncestors, ImprinterPlayerUniqueNetId, plus a full soft-object path (/Game/ASA/Dinos/<Species>/<Species>_Character_BP.<Species>_Character_BP_C) near the front, and what looks like a level/world name and tamer/tribe name as separate strings — so the stat values are clearly present somewhere in there, just in a layout I haven't reverse-engineered (looks structurally closer to the object/property-tag layout used in the cloud/obelisk inventory format than to the plain from_cryopod_bytes() layout, but isn't identical to that either — e.g. the class name here is a full path, not the short name _read_asa_object_header reads).

I didn't want to guess further at an undocumented binary layout without a way to verify correctness against ground truth, so I'm flagging it here rather than shipping a possibly-wrong decoder. Happy to share a redacted/anonymized sample blob if that'd help, since I can't attach live save data directly.

What I changed locally (happy to open a PR instead, if preferred)

  • arkparser/common/types.py: added "Dinoball" to CRYOPOD_CLASS_PATTERNS.
  • arkparser/files/world_save.py (iter_cryopod_creatures): accept "DinoballItemData" alongside "Dino" for CustomDataName.
  • arkparser/export.py (_decode_inventory_cryopod): same CustomDataName widening, for cryopods discovered inside other inventories (cryofridges, vaults, dedicated storage, etc.).

Thanks for the great library — legacy-parity plus the cryopod-recovery feature has been a huge upgrade over the dead ASVExport.exe pipeline for us.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions