arkparser 0.3.2__tar.gz → 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {arkparser-0.3.2 → arkparser-0.4.0}/PKG-INFO +107 -56
- {arkparser-0.3.2 → arkparser-0.4.0}/README.md +106 -55
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/__init__.py +5 -1
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/data_models.py +45 -10
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/export.py +607 -18
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/files/base.py +10 -6
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser.egg-info/PKG-INFO +107 -56
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser.egg-info/SOURCES.txt +2 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/pyproject.toml +1 -1
- arkparser-0.4.0/tests/test_cloud_export.py +45 -0
- arkparser-0.4.0/tests/test_cryopod_export.py +122 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/LICENSE +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/common/__init__.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/common/binary_reader.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/common/exceptions.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/common/map_config.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/common/normalization.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/common/types.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/common/version_detection.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/files/__init__.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/files/cloud_inventory.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/files/profile.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/files/tribe.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/files/world_save.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/game_objects/__init__.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/game_objects/container.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/game_objects/game_object.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/game_objects/location.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/properties/__init__.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/properties/base.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/properties/byte_property.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/properties/compound.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/properties/primitives.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/properties/registry.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/structs/__init__.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/structs/base.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/structs/colors.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/structs/misc.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/structs/property_list.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/structs/registry.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser/structs/vectors.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser.egg-info/dependency_links.txt +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser.egg-info/requires.txt +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/arkparser.egg-info/top_level.txt +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/setup.cfg +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/tests/test_asa_header_position.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/tests/test_binary_reader.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/tests/test_binary_reader_layouts.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/tests/test_cloud_inventory.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/tests/test_current_stats.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/tests/test_data_models.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/tests/test_export.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/tests/test_game_objects.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/tests/test_profile.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/tests/test_tribe.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/tests/test_v13_property_layouts.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/tests/test_version_detection.py +0 -0
- {arkparser-0.3.2 → arkparser-0.4.0}/tests/test_world_save.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: arkparser
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Pure Python parser for ARK: Survival Evolved and ARK: Survival Ascended save files
|
|
5
5
|
Author: Vertyco
|
|
6
6
|
License-Expression: MIT
|
|
@@ -57,7 +57,7 @@ A pure-Python library for parsing ARK: Survival Evolved (ASE) and ARK: Survival
|
|
|
57
57
|
- **World Saves** (`.ark`): full map state (creatures, structures, items, players)
|
|
58
58
|
- **Dual format**: automatic ASE (v5-12) / ASA (v13-14+, SQLite) detection
|
|
59
59
|
- **Legacy-parity export**: drop-in JSON output matching `ASVExport.exe` schema, plus parser-only extras under `extra_*` keys
|
|
60
|
-
- **Fast**: pure-Python `BinaryReader` (`int.from_bytes` + `struct.Struct` unpackers, slots-based dataclasses)
|
|
60
|
+
- **Fast**: pure-Python `BinaryReader` (`int.from_bytes` + `struct.Struct` unpackers, slots-based dataclasses), a 30 MB ASE save (65k objects) loads in ~3s on CPython 3.14
|
|
61
61
|
|
|
62
62
|
## Installation
|
|
63
63
|
|
|
@@ -180,10 +180,10 @@ The parser reuses the legacy short stat tokens consistently across every export
|
|
|
180
180
|
|
|
181
181
|
These map 1:1 to in-game stat indices 0..11. Stat blocks use suffixes to disambiguate:
|
|
182
182
|
|
|
183
|
-
- **no suffix
|
|
184
|
-
- **`-w
|
|
185
|
-
- **`-t
|
|
186
|
-
- **`-m
|
|
183
|
+
- **no suffix**, base wild stats (wild creatures, players)
|
|
184
|
+
- **`-w`**, base wild stats (tamed creatures, points the creature had before being tamed)
|
|
185
|
+
- **`-t`**, post-tame level-up points (tamed creatures only)
|
|
186
|
+
- **`-m`**, mutation points applied (tamed creatures only)
|
|
187
187
|
|
|
188
188
|
The legacy ASVExport.exe emitted only the visible 8 stats (`hp`, `stam`, `melee`, `weight`, `speed`, `food`, `oxy`, `craft`) under each suffix. The parser appends the four legacy never surfaced (`torp`, `water`, `temp`, `fort`) at the end of each block, so e.g. a tamed creature now carries `torp-w`, `water-w`, `temp-w`, `fort-w` alongside the legacy `hp-w`..`craft-w`.
|
|
189
189
|
|
|
@@ -209,8 +209,8 @@ The legacy ASVExport.exe emitted only the visible 8 stats (`hp`, `stam`, `melee`
|
|
|
209
209
|
| `torp-t`, `water-t`, `temp-t`, `fort-t` | added | same source, indices legacy never emitted |
|
|
210
210
|
| `hp-m` .. `fort-m` (all 12) | added | `NumberOfMutationsAppliedTamed[i]` (mutation point counts per stat) |
|
|
211
211
|
| `c0` .. `c5` | legacy | `ColorSetIndices[i]` |
|
|
212
|
-
| `mut-f`, `mut-m` | legacy | **Ancestor-line totals.** `RandomMutationsFemale` and `RandomMutationsMale
|
|
213
|
-
| `cryo` | legacy | `
|
|
212
|
+
| `mut-f`, `mut-m` | legacy | **Ancestor-line totals.** `RandomMutationsFemale` and `RandomMutationsMale`, single integers counting the total number of mutations that occurred down the maternal and paternal ancestry lines respectively. These are *not* per-stat, they share the `-m` token with the per-stat mutation block below but mean a different thing. Kept under the legacy names for ASVExport parity. |
|
|
213
|
+
| `cryo` | legacy | `True` for creatures embedded inside cryopod / soultrap / vivarium / dinoball items in the world save, `False` for actor-in-world tames. `export_tamed` walks `WorldSave.iter_cryopod_creatures()` and emits one ASV_Tamed record per embedded creature in addition to the actor-in-world tames; on busy PvE servers cryopodded tames are the majority of the roster (e.g. 10,277 of 11,054 on a live Ragnarok_WP). Cluster-uploaded tames also surface here (via `export_cluster_uploads`) with `cryo=True`. |
|
|
214
214
|
| `ccc` | legacy | `"{x} {y} {z}"` from `LocationData` |
|
|
215
215
|
| `dinoid` | legacy | string form of `id` |
|
|
216
216
|
| `isMating` | legacy | `bEnableTamedMating` |
|
|
@@ -220,29 +220,29 @@ The legacy ASVExport.exe emitted only the visible 8 stats (`hp`, `stam`, `melee`
|
|
|
220
220
|
| `uploadedServer` | legacy | `UploadedFromServerName` |
|
|
221
221
|
| `maturation` | legacy | `str(int(BabyAge * 100))` (string for legacy parity) |
|
|
222
222
|
| `traits` | legacy | `CreatureTraits` (full list of mutation trait class names) |
|
|
223
|
-
| `inventory` | legacy | items from `MyInventoryComponent.InventoryItems`. Each entry carries `itemId`, `qty`, `blueprint
|
|
223
|
+
| `inventory` | legacy | items from `MyInventoryComponent.InventoryItems`. Each entry carries `itemId`, `qty`, `blueprint`, plus a full snake_case property dump flattened in at the top level (`id`, `rating`, `durability`, `quality`, `damage`, `armor`, `durability_max`, `hypo`, `hyper`, `clip_size`, `weight`, `crafter`, `crafter_tribe`, `skill_bonus`, `loaded_ammo`, `spoils_at`, `spoiled_at`, `c0`..`c5`, `egg_*`, etc). `item_stat_values` is unpacked into the universal 8-slot ARK map (slot 0 `gen_quality`, 1 `armor`, 2 `durability_max`, 3 `damage`, 4 `clip_size`, 5 `hypo`, 6 `weight`, 7 `hyperthermal_insulation`); raw uint16s scaled by the per-blueprint multiplier (which lives in the UE blueprint, not the save). Default / unset values are filtered (no `craft_queue=0`, `skin=-1`, `color_pre_skin=[0]*6`, NaN spoil timers, etc). When the item is a **cryopod / soultrap / vivarium / dinoball** with an embedded creature, the entry is enriched with `dino_id` (combined 64-bit id matching the corresponding `ASV_Tamed` record), `dino_creature` (species / class name), and `dino_name` (`TamedName` if set). Cryopods stored in containers (cryofridges, vaults, dedicated storage) get the same enrichment. |
|
|
224
224
|
| `father_id`, `mother_id` | added | combined dino id from the first `DinoAncestors` entry (`null` when missing) |
|
|
225
225
|
| `father_name`, `mother_name` | added | name strings from the first `DinoAncestors` entry |
|
|
226
226
|
| `level_added` | added | `ExtraCharacterLevel` (post-tame levels, broken out from `lvl`) |
|
|
227
227
|
| `experience` | added | `ExperiencePoints` (status), integer |
|
|
228
228
|
| `wandering` | added | `bEnableTamedWandering` |
|
|
229
229
|
| `tamed_at` | added | ISO 8601 datetime with local TZ, converted from `TamedAtTime` (in-game seconds) via `file_mtime + (tamed_at - game_time)`. `null` when the save lacks the anchors. |
|
|
230
|
-
| `last_ally_in_range` | added | ISO 8601 datetime with local TZ
|
|
230
|
+
| `last_ally_in_range` | added | ISO 8601 datetime with local TZ, converted from `LastInAllyRangeTime` / `LastInAllyRangeSerialized` via the same anchor formula as `tamed_at`. `null` when the save lacks the anchors. |
|
|
231
231
|
| `imprinter_player_id` | added | `ImprinterPlayerDataID` |
|
|
232
232
|
| `imprinter_net_id` | added | `ImprinterPlayerUniqueNetId` (ASA only) |
|
|
233
233
|
| `taming_team_id` | added | `TamingTeamID` (fallback tribe id when `TargetingTeam` was stripped on cryo) |
|
|
234
|
-
| `owning_player_id`, `owning_player_name` | added | `OwningPlayerID` / `OwningPlayerName
|
|
235
|
-
| `aggression_level` | added | `TamedAggressionLevel
|
|
236
|
-
| `ai_targeting_range` | added | `TamedAITargetingRange
|
|
237
|
-
| `follow_stopping_distance` | added | `FollowStoppingDistance
|
|
234
|
+
| `owning_player_id`, `owning_player_name` | added | `OwningPlayerID` / `OwningPlayerName`, current owner (may differ from the original `tamer` after transfer / cryo). |
|
|
235
|
+
| `aggression_level` | added | `TamedAggressionLevel`, 0 Passive, 1 Neutral, 2 Aggressive, 3 Passive Flee, 4 Attack-My-Target (ARK in-game order). |
|
|
236
|
+
| `ai_targeting_range` | added | `TamedAITargetingRange`, aggro range (UE units). |
|
|
237
|
+
| `follow_stopping_distance` | added | `FollowStoppingDistance`, follow-AI stopping radius. |
|
|
238
238
|
| `is_flying` | added | `bIsFlying`. |
|
|
239
|
-
| `is_turret_mode` | added | `bIsInTurretMode
|
|
240
|
-
| `ignore_whistles`, `only_target_conscious`, `attack_team_member_dinos` | added | `bIgnoreAllWhistles` / `bOnlyTargetConscious` / `bAttackTeamMemberDinos
|
|
241
|
-
| `next_cuddle_food`, `next_cuddle_type` | added | `BabyCuddleFood` / `BabyCuddleType
|
|
242
|
-
| `latest_uploaded_server`, `previous_uploaded_server` | added | `LatestUploadedFromServerName` / `PreviousUploadedFromServerName
|
|
239
|
+
| `is_turret_mode` | added | `bIsInTurretMode`, e.g. plant Y, Tek tape sentry mode. |
|
|
240
|
+
| `ignore_whistles`, `only_target_conscious`, `attack_team_member_dinos` | added | `bIgnoreAllWhistles` / `bOnlyTargetConscious` / `bAttackTeamMemberDinos`, behavior toggles. |
|
|
241
|
+
| `next_cuddle_food`, `next_cuddle_type` | added | `BabyCuddleFood` / `BabyCuddleType`, next imprint requirement. |
|
|
242
|
+
| `latest_uploaded_server`, `previous_uploaded_server` | added | `LatestUploadedFromServerName` / `PreviousUploadedFromServerName`, recent upload history alongside the legacy `uploadedServer`. |
|
|
243
243
|
| `saddle_structures` | added | List of structure object-ref strings placed on this creature's platform saddle (paracer / brontosaurus / titanosaur etc.). |
|
|
244
|
-
| `harvest_resource_levels` | added | `HarvestResourceLevels
|
|
245
|
-
| `wild_spawn_region` | added | `OriginalNPCVolumeName
|
|
244
|
+
| `harvest_resource_levels` | added | `HarvestResourceLevels`, per-resource harvest levels (mortar / feeding trough variants). |
|
|
245
|
+
| `wild_spawn_region` | added | `OriginalNPCVolumeName`, name of the `NPCZoneVolume` where this creature first spawned. Lets consumers answer "where on the map did this tame originate". |
|
|
246
246
|
| `downloaded_at` | added | ISO 8601 datetime of the last cluster/obelisk download (`DinoDownloadedAtTime`). `null` when the creature was never cluster-downloaded. |
|
|
247
247
|
| `original_created` | added | ISO 8601 datetime of the dino's first spawn (`OriginalCreationTime`), e.g. when the egg was laid or the wild dino spawned. Distinct from `tamed_at`. |
|
|
248
248
|
| `next_mating_at` | added | ISO 8601 datetime when the next mating is allowed (`NextAllowedMatingTime`). `null` when no cooldown is set. |
|
|
@@ -250,7 +250,7 @@ The legacy ASVExport.exe emitted only the visible 8 stats (`hp`, `stam`, `melee`
|
|
|
250
250
|
| `last_baby_age_update` | added | ISO 8601 datetime of `LastUpdatedBabyAgeAtTime`. |
|
|
251
251
|
| `last_gestation_update` | added | ISO 8601 datetime of `LastUpdatedGestationAtTime`. |
|
|
252
252
|
| `next_cuddle` | added | ISO 8601 datetime of `BabyNextCuddleTime`. |
|
|
253
|
-
| `current_stats` | added | Live in-world stat values from the dino's status component (`CurrentStatusValues[0..11]`) as a `{hp, stam, torp, oxy, food, water, temp, weight, melee, speed, fort, craft}` dict of floats. These are the *current* values (e.g. `hp: 11013.62` = current HP, drops as the dino takes damage). Max values are NOT persisted by ARK
|
|
253
|
+
| `current_stats` | added | Live in-world stat values from the dino's status component (`CurrentStatusValues[0..11]`) as a `{hp, stam, torp, oxy, food, water, temp, weight, melee, speed, fort, craft}` dict of floats. These are the *current* values (e.g. `hp: 11013.62` = current HP, drops as the dino takes damage). Max values are NOT persisted by ARK, compute downstream from species stat tables + `*-w`/`*-t` points + `imprint` + server multipliers if you need them. `null` when the status component carries no `CurrentStatusValues` entries (e.g. uninitialised baby actor). |
|
|
254
254
|
|
|
255
255
|
#### `ASV_Wild` schema
|
|
256
256
|
|
|
@@ -267,7 +267,7 @@ The legacy ASVExport.exe emitted only the visible 8 stats (`hp`, `stam`, `melee`
|
|
|
267
267
|
| `tameable` | legacy | mirror of legacy `ContentWildCreature.IsTameable` rule |
|
|
268
268
|
| `trait` | legacy | first entry of `CreatureTraits` (or empty string) |
|
|
269
269
|
| `traits` | added | full `CreatureTraits` list |
|
|
270
|
-
| `wild_spawn_region` | added | `OriginalNPCVolumeName
|
|
270
|
+
| `wild_spawn_region` | added | `OriginalNPCVolumeName`, `NPCZoneVolume` the creature spawned in. |
|
|
271
271
|
| `current_stats` | added | Live in-world stat values from the creature's status component (`CurrentStatusValues[0..11]`) as a `{hp, stam, torp, oxy, food, water, temp, weight, melee, speed, fort, craft}` dict of floats. Max values are NOT in the save (would need species stat tables). `null` when uninitialised. |
|
|
272
272
|
|
|
273
273
|
#### Player data: `.arkprofile` vs in-world pawn
|
|
@@ -284,7 +284,7 @@ The export pipeline (`export_players`) loops over `save.profiles` (a list the ca
|
|
|
284
284
|
- If it's a `Profile` instance → `_player_from_profile` runs: fills core identity (name, gender, level, stats, tribe id, engram count, experience, active datetime from `LastLoginTime`). Leaves `lat`/`lon`/`ccc` as zero, `inventory` empty, pawn-state flags (`is_sleeping`, `is_dead`, `chibi_levels`, …) absent.
|
|
285
285
|
- Otherwise it's treated as a wrapped `(profile, objects)` pair pointing at an in-world `PlayerPawn` → `_player_from_object` runs: fills location, inventory, pawn-state flags, body/hair cosmetics, death timestamps, and `active` from `SavedLastTimeHadController`.
|
|
286
286
|
|
|
287
|
-
For the richest output, hand `export_players` **both
|
|
287
|
+
For the richest output, hand `export_players` **both**, assemble a wrapper for each player that carries the `Profile` (for offline identity) *and* the in-world pawn (when present) so the merged record gets identity + live state. The current validation script only passes `Profile` instances, which is why fields like `is_sleeping` / `body_colors` / `current_weapon` show up empty in the validation output even though the parser supports them.
|
|
288
288
|
|
|
289
289
|
#### `ASV_Players` schema
|
|
290
290
|
|
|
@@ -309,18 +309,18 @@ For the richest output, hand `export_players` **both** — assemble a wrapper fo
|
|
|
309
309
|
| `inventory` | legacy (now populated) | Items from the pawn's `MyInventoryComponent` when built from an in-world pawn. Empty list otherwise. |
|
|
310
310
|
| `engram_points` | added | `TotalEngramPoints` |
|
|
311
311
|
| `experience` | added | `ExperiencePoints` (status), integer |
|
|
312
|
-
| `is_sleeping`, `is_dead` | added | `bIsSleeping` / `bIsDead
|
|
312
|
+
| `is_sleeping`, `is_dead` | added | `bIsSleeping` / `bIsDead`, pawn state flags. Always `false` for profile-sourced records (no pawn). |
|
|
313
313
|
| `is_prone`, `is_crouched`, `hat_hidden` | added | `bIsProne` / `bIsCrouched` / `bHatHidden`. |
|
|
314
|
-
| `current_weapon` | added | `CurrentWeapon` ref
|
|
315
|
-
| `seated_on_ref` | added | `SeatingStructure` ref
|
|
316
|
-
| `original_hair_color` | added | `OriginalHairColor
|
|
314
|
+
| `current_weapon` | added | `CurrentWeapon` ref, equipped weapon identifier. |
|
|
315
|
+
| `seated_on_ref` | added | `SeatingStructure` ref, what the player is sitting on (chair / saddle). |
|
|
316
|
+
| `original_hair_color` | added | `OriginalHairColor`, color index at character creation. |
|
|
317
317
|
| `head_hair_growth`, `facial_hair_growth` | added | `PercentOfFullHeadHairGrowth` / `PercentOfFullFacialHairGrowth`. |
|
|
318
|
-
| `body_colors` | added | `BodyColors
|
|
318
|
+
| `body_colors` | added | `BodyColors`, per-region skin color indices. |
|
|
319
319
|
| `died_at` | added | ISO 8601 datetime of `LocalDiedAtTime`. |
|
|
320
320
|
| `corpse_destruction` | added | ISO 8601 datetime of `CorpseDestructionTime`. |
|
|
321
|
-
| `chibi_levels` | added | `NumChibiLevelUps
|
|
322
|
-
| `ascensions_scorched` | added | `NumAscensionsScorched
|
|
323
|
-
| `current_stats` | added | Live in-world stat values for the player from the pawn's `MyCharacterStatusComponent` (`CurrentStatusValues[0..11]`) as a `{hp, stam, torp, oxy, food, water, temp, weight, melee, speed, fort, craft}` dict of floats. For profile-sourced records the parser joins on `PlayerDataID == LinkedPlayerDataID` to find the spawned pawn in the world save. `null` when the player has no in-world pawn (never spawned this server / corpse cleared) or the status component has no values
|
|
321
|
+
| `chibi_levels` | added | `NumChibiLevelUps`, bonus levels from chibi pets. |
|
|
322
|
+
| `ascensions_scorched` | added | `NumAscensionsScorched`, ASE ascension counter (legacy `ContentPlayer` parses the ASA ascension block differently; this is the ASE-specific field). |
|
|
323
|
+
| `current_stats` | added | Live in-world stat values for the player from the pawn's `MyCharacterStatusComponent` (`CurrentStatusValues[0..11]`) as a `{hp, stam, torp, oxy, food, water, temp, weight, melee, speed, fort, craft}` dict of floats. For profile-sourced records the parser joins on `PlayerDataID == LinkedPlayerDataID` to find the spawned pawn in the world save. `null` when the player has no in-world pawn (never spawned this server / corpse cleared) or the status component has no values, only currently / recently spawned characters have live stats. Max values are NOT persisted by ARK. |
|
|
324
324
|
|
|
325
325
|
#### `ASV_Tribes` schema
|
|
326
326
|
|
|
@@ -329,7 +329,7 @@ For the richest output, hand `export_players` **both** — assemble a wrapper fo
|
|
|
329
329
|
| `tribeid` | legacy | `TribeID` / parser `Tribe.tribe_id` |
|
|
330
330
|
| `tribe` | legacy | tribe name |
|
|
331
331
|
| `players` | legacy | member count |
|
|
332
|
-
| `members` | legacy | list of `{ign, lvl, playerid, playername, steamid}`. `lvl` and `steamid` only populate when a matching `.arkprofile` is loaded into `save.profiles
|
|
332
|
+
| `members` | legacy | list of `{ign, lvl, playerid, playername, steamid}`. `lvl` and `steamid` only populate when a matching `.arkprofile` is loaded into `save.profiles`, the `.arktribe` file itself doesn't carry per-member level / platform id, so the parser cross-references by `player_id`. Empty (`""`) when no profile is available for that member. |
|
|
333
333
|
| `tames`, `structures` | legacy | counts derived from `WorldSave` (creatures + structures whose `TargetingTeam` matches) |
|
|
334
334
|
| `uploadedTames` | legacy | reserved (currently `0`) |
|
|
335
335
|
| `active` | legacy | ISO 8601 datetime of the most recent tribe log entry, converted from in-game "Day N, HH:MM:SS" via the save's anchor. `null` when no parseable log entries or anchors are missing. |
|
|
@@ -350,7 +350,7 @@ For the richest output, hand `export_players` **both** — assemble a wrapper fo
|
|
|
350
350
|
|
|
351
351
|
| Field | Origin | Source / formula |
|
|
352
352
|
|---|---|---|
|
|
353
|
-
| `id` | added | `GameObject.id
|
|
353
|
+
| `id` | added | `GameObject.id`, internal numeric identifier. Cross-references the values in other records' `linked_structures` / `saddle_structures` / `attached_dino_id` lists. |
|
|
354
354
|
| `tribeid` | legacy | `TargetingTeam` |
|
|
355
355
|
| `tribe` | legacy | `OwnerName` |
|
|
356
356
|
| `struct` | legacy | `GameObject.class_name` |
|
|
@@ -369,27 +369,27 @@ For the richest output, hand `export_players` **both** — assemble a wrapper fo
|
|
|
369
369
|
| `feeding_exclusions` | added | `FeedingDinoList` class names when `DinoFeedingListType == 2` |
|
|
370
370
|
| `health` | added | `Health` (often `0.0` because ARK strips live health on save) |
|
|
371
371
|
| `max_health` | added | `MaxHealth` |
|
|
372
|
-
| `owning_player_id`, `owning_player_name` | added | `OwningPlayerID` / `OwningPlayerName
|
|
373
|
-
| `colors` | added | `StructureColors
|
|
374
|
-
| `current_item_count`, `max_item_count` | added | `CurrentItemCount` / `MaxItemCount
|
|
375
|
-
| `num_bullets` | added | `NumBullets
|
|
376
|
-
| `range_setting` | added | `RangeSetting
|
|
377
|
-
| `has_fuel` | added | `bHasFuel
|
|
372
|
+
| `owning_player_id`, `owning_player_name` | added | `OwningPlayerID` / `OwningPlayerName`, who placed the structure (distinct from `tribe`, which is the current owning tribe). |
|
|
373
|
+
| `colors` | added | `StructureColors`, list of 6 color region indices (0 = unpainted). |
|
|
374
|
+
| `current_item_count`, `max_item_count` | added | `CurrentItemCount` / `MaxItemCount`, container fullness (e.g. dedicated storage, generators). Both `0` for non-container structures. |
|
|
375
|
+
| `num_bullets` | added | `NumBullets`, loaded ammo count on auto-turrets. `0` for non-turrets. |
|
|
376
|
+
| `range_setting` | added | `RangeSetting`, turret targeting range tier (`0` Low, `1` Med, `2` High, `3` Highest). `0` for non-turrets too, disambiguate via `num_bullets` / `struct`. |
|
|
377
|
+
| `has_fuel` | added | `bHasFuel`, generator / lamp fuel state. |
|
|
378
378
|
| `is_foundation` | added | `bIsFoundation`. |
|
|
379
|
-
| `placement_snapped` | added | `bWasPlacementSnapped
|
|
380
|
-
| `variant` | added | `CurrentVariant
|
|
381
|
-
| `selected_resource_class` | added | `SelectedResourceClass` ref
|
|
379
|
+
| `placement_snapped` | added | `bWasPlacementSnapped`, placement-snap flag. |
|
|
380
|
+
| `variant` | added | `CurrentVariant`, structure variant index (e.g. flexible pipe / gate style). |
|
|
381
|
+
| `selected_resource_class` | added | `SelectedResourceClass` ref, resource type chosen on dedicated storage / similar. |
|
|
382
382
|
| `resource_count` | added | `ResourceCount`. |
|
|
383
383
|
| `dedicated_storage_version` | added | `SavedDedicatedStorageVersion`. |
|
|
384
|
-
| `painting_ref` | added | `PaintingComponent` ref
|
|
385
|
-
| `saddle_dino_ref`, `attached_dino_id` | added | `SaddleDino` ref + `AttachedToDinoID1/2` combined
|
|
386
|
-
| `linked_structures` | added | `LinkedStructures
|
|
384
|
+
| `painting_ref` | added | `PaintingComponent` ref, canvas component identifier when painted. |
|
|
385
|
+
| `saddle_dino_ref`, `attached_dino_id` | added | `SaddleDino` ref + `AttachedToDinoID1/2` combined, links saddle-mounted structures back to their host dino. |
|
|
386
|
+
| `linked_structures` | added | `LinkedStructures`, refs of network-linked structures (pipes / wires / gates → motors). Useful for reconstructing infrastructure topology. |
|
|
387
387
|
| `last_activated` | added | ISO 8601 datetime of `LastActivatedTime`. |
|
|
388
388
|
| `last_deactivated` | added | ISO 8601 datetime of `LastDeactivatedTime`. |
|
|
389
|
-
| `last_fire` | added | ISO 8601 datetime of `LastFireTime
|
|
389
|
+
| `last_fire` | added | ISO 8601 datetime of `LastFireTime`, last turret discharge. |
|
|
390
390
|
| `last_reload` | added | ISO 8601 datetime of `LastLongReloadStartTime`. |
|
|
391
391
|
| `last_fuel_check` | added | ISO 8601 datetime of `LastCheckedFuelTime`. |
|
|
392
|
-
| `pin_code` | added | `CurrentPinCode
|
|
392
|
+
| `pin_code` | added | `CurrentPinCode`, the active PIN code on the structure as a single integer. Falls back to the first non-zero entry of the legacy `CurrentPinCodes` array (always zero on every observed save). Pruned when `0`. **Sensitive credential**, exposed for tribe-admin auditing; downstream UIs should gate this behind admin-only views. |
|
|
393
393
|
|
|
394
394
|
#### `ASV_MapStructures` schema
|
|
395
395
|
|
|
@@ -399,18 +399,48 @@ For the richest output, hand `export_players` **both** — assemble a wrapper fo
|
|
|
399
399
|
| `lat`, `lon`, `ccc` | legacy | location via `MapConfig` |
|
|
400
400
|
| `inventory` | legacy | inventory items (only meaningful for beaver dams / dropped supply crates) |
|
|
401
401
|
|
|
402
|
-
### Cluster-uploaded creatures
|
|
402
|
+
### Cluster-uploaded creatures and items
|
|
403
403
|
|
|
404
|
-
|
|
404
|
+
Pass the cluster directory to `export_all` / `export_to_files` to fold cluster data into the per-map output:
|
|
405
405
|
|
|
406
406
|
```python
|
|
407
407
|
export_to_files(save, "output/", map_config, cluster="path/to/cluster")
|
|
408
408
|
# or equivalently:
|
|
409
409
|
data = export_all(save, map_config, cluster="path/to/cluster")
|
|
410
|
-
# data["ASV_Tamed"] now includes
|
|
410
|
+
# data["ASV_Tamed"] - now includes cluster cryopod tames (cryo=True)
|
|
411
|
+
# data["ASV_Players"] - each player's inventory now contains their
|
|
412
|
+
# uploaded items (entries tagged "uploaded": true),
|
|
413
|
+
# matched by cloud-file stem (xuid) ==
|
|
414
|
+
# Profile.unique_id.
|
|
411
415
|
```
|
|
412
416
|
|
|
413
|
-
|
|
417
|
+
Cluster items are spliced into the owning player's `inventory`; no separate `ASV_ClusterItems` file is emitted. The match works because every cluster file is named after the owning player's Steam id / platform UUID, which is the same value as `Profile.unique_id`.
|
|
418
|
+
|
|
419
|
+
Pre-loaded `CloudInventory` instances also work (`cluster=[inv1, inv2, ...]`).
|
|
420
|
+
|
|
421
|
+
### Standalone cloud-inventory inspection
|
|
422
|
+
|
|
423
|
+
For staff tools that need to inspect a single user's obelisk / cluster file in isolation (no worldsave context, no per-player matching), use `export_cloud_inventory`:
|
|
424
|
+
|
|
425
|
+
```python
|
|
426
|
+
from arkparser import CloudInventory, export_cloud_inventory
|
|
427
|
+
|
|
428
|
+
cloud = CloudInventory.load("/cluster/2533274802706466") # ASE xuid
|
|
429
|
+
# or
|
|
430
|
+
cloud = CloudInventory.load("/cluster/000297eb6c36484ab95c75d7bbbc8629") # ASA UUID
|
|
431
|
+
|
|
432
|
+
data = export_cloud_inventory(cloud)
|
|
433
|
+
# {
|
|
434
|
+
# "ASV_Tamed": [ ... every dino, cryopod-embedded or otherwise ... ],
|
|
435
|
+
# "ASV_Items": [ ... every uploaded item, snake_case flat stats ... ],
|
|
436
|
+
# }
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
Each `ASV_Items` entry carries `itemId`, `qty`, `blueprint`, `id` (combined ItemID1_ItemID2), `upload_time` (ISO 8601 with UTC offset), and item-class-specific stats (`durability_max`, `damage`, `armor`, `hypo`, `hyper`, `crafter`, `crafter_tribe`, `skill_bonus`, `loaded_ammo`, `quality`, `rating`, `c0`..`c5` paint regions, `drop_location`, `egg_*` for fertilized eggs, `dino_*` for cryopod items, etc). Default / unset fields are filtered, NaN floats dropped, `"Unknown"` crafter strings nulled.
|
|
440
|
+
|
|
441
|
+
The low-level helpers are also available:
|
|
442
|
+
- `export_cluster_uploads(cluster_invs, map_config=None) -> list[dict]` — tamed-shape records (incl. cryopod-as-item dinos) across the supplied cloud files
|
|
443
|
+
- `export_cluster_items(cluster_invs) -> list[dict]` — every uploaded item across the supplied cloud files
|
|
414
444
|
|
|
415
445
|
## Package Structure
|
|
416
446
|
|
|
@@ -559,14 +589,16 @@ All four expose `from_*` constructors and `to_dict()` for serialization.
|
|
|
559
589
|
|---|---|---|
|
|
560
590
|
| `export_tamed(save, map_config=None)` | `list[dict]` | `ASV_Tamed` records |
|
|
561
591
|
| `export_wild(save, map_config=None)` | `list[dict]` | `ASV_Wild` records |
|
|
562
|
-
| `export_players(save, map_config=None)` | `list[dict]` | `ASV_Players` records (from Profile parsers) |
|
|
592
|
+
| `export_players(save, map_config=None, cluster_inventories=None)` | `list[dict]` | `ASV_Players` records (from Profile parsers). Pass `cluster_inventories` to splice each player's uploaded items into their `inventory` (entries tagged `uploaded: true`, matched by xuid stem == `Profile.unique_id`) |
|
|
563
593
|
| `export_tribes(save)` | `list[dict]` | `ASV_Tribes` records |
|
|
564
594
|
| `export_structures(save, map_config=None)` | `list[dict]` | `ASV_Structures` records |
|
|
565
595
|
| `export_tribe_logs(save)` | `list[dict]` | `ASV_TribeLogs` records |
|
|
566
596
|
| `export_map_structures(save, map_config=None)` | `list[dict]` | `ASV_MapStructures` records |
|
|
567
|
-
| `export_all(save, map_config=None)` | `dict[str, list[dict]]` | All seven exports keyed by ASV filename stem |
|
|
568
|
-
| `export_cluster_uploads(cluster_inventories, map_config=None)` | `list[dict]` | Tamed-shape records for creatures stored in cluster `CloudInventory` files (decoded from `ArkTamedDinosData[].DinoData` blobs) |
|
|
569
|
-
| `
|
|
597
|
+
| `export_all(save, map_config=None, cluster=None)` | `dict[str, list[dict]]` | All seven exports keyed by ASV filename stem. `cluster` accepts a directory path or pre-loaded `CloudInventory` iterable; splices cluster tames into `ASV_Tamed` and cluster items into `ASV_Players[i].inventory` |
|
|
598
|
+
| `export_cluster_uploads(cluster_inventories, map_config=None)` | `list[dict]` | Tamed-shape records for creatures stored in cluster `CloudInventory` files (decoded from `ArkTamedDinosData[].DinoData` blobs and `ArkItems[].CustomItemDatas` cryopod blobs) |
|
|
599
|
+
| `export_cluster_items(cluster_inventories)` | `list[dict]` | Every uploaded item across the supplied cloud files, snake_case flat stats included |
|
|
600
|
+
| `export_cloud_inventory(cloud, map_config=None)` | `dict[str, list[dict]]` | Standalone inspection of a single `CloudInventory`. Returns `{"ASV_Tamed": [...], "ASV_Items": [...]}` for staff tools that need to see one user's obelisk file without worldsave context |
|
|
601
|
+
| `export_to_files(save, output_dir, map_config=None, wrap=True, cluster=None, compact=False)` | `list[Path]` | Writes each export to `<dir>/<ASV_Name>.json`. `wrap=True` (default) emits the legacy `{map, day, time, data}` envelope; `wrap=False` writes the flat list |
|
|
570
602
|
|
|
571
603
|
Schema policy:
|
|
572
604
|
|
|
@@ -614,7 +646,26 @@ Schema policy:
|
|
|
614
646
|
| World Save | Binary file | SQLite database |
|
|
615
647
|
| Compression | None | zlib + custom RLE |
|
|
616
648
|
|
|
617
|
-
ASA worldsave property layouts differ between **v13** (`TheIsland_WP` and older single-player saves
|
|
649
|
+
ASA worldsave property layouts differ between **v13** (`TheIsland_WP` and older single-player saves, legacy `AsaSavegameToolkit`-style `dataSize + position + typeRef + byte` body) and **v14+** (current production ASA, marker-based body). Both are parsed by version-aware property readers; `WorldSave.version` is the source of truth.
|
|
650
|
+
|
|
651
|
+
### Known limitation: ASA cryopod property blocks are partially decoded
|
|
652
|
+
|
|
653
|
+
ASA cryopods (`PrimalItem_WeaponEmptyCryopod_C`, `SoulTrap`, `Vivarium`, `DinoBall`) store the embedded creature snapshot inside the item's `CustomItemDatas.CustomDataBytes.ByteArrays[0]` as a **zlib + custom-RLE compressed `AsaDataStore` blob**. The parser surfaces the snapshot via the simpler `CustomDataStrings` / `CustomDataFloats` accessors, exposing **species, tamed name, level, color regions, and `CurrentStatusValues[0..11]`** on each cryopodded creature.
|
|
654
|
+
|
|
655
|
+
What is **NOT yet extracted** from ASA cryopod blobs:
|
|
656
|
+
|
|
657
|
+
- `DinoID1` / `DinoID2` (and therefore `id` / `dinoid`)
|
|
658
|
+
- `TamingTeamID` / `TargetingTeam` (and therefore `tribeid`)
|
|
659
|
+
- `TamerString`, `OwningPlayerID`, `OwningPlayerName`
|
|
660
|
+
- `TamedOnServerName`, `UploadedFromServerName`
|
|
661
|
+
- `BaseCharacterLevel` vs `ExtraCharacterLevel` split (only the displayed total surfaces)
|
|
662
|
+
- Mutation counts, imprint quality, ancestors, behavioural toggles, etc.
|
|
663
|
+
|
|
664
|
+
ASA cryopod records therefore come back with `tribeid: 0`, `tamer: ""`, `dinoid: "0"`, `imprint: 0.0` on the otherwise-rich tamed schema. The compressed property block at the C#-reported `PropertyOffset + 1` decompresses cleanly through both zlib and the custom RLE (matching `AsaCompressedData.cs` byte-for-byte), and the surrounding `AsaGameObject` headers parse correctly, but the property-list bytes that follow do **not** form valid name-table references under any alignment we tried (including the layout `AsaPropertyRegistry.ReadProperty` uses). The legacy AsaSavegameToolkit wraps `ReadProperties` in a swallowing try/catch (`AsaGameObject.cs:178-193`), so it is plausible that **no current open-source tool extracts this data** either.
|
|
665
|
+
|
|
666
|
+
**ASE cryopod records are fully populated** via the in-place property-list blob, `from_cryopod_bytes` surfaces every legacy ASV_Tamed field.
|
|
667
|
+
|
|
668
|
+
If you crack the ASA cryopod block format (e.g. via UE5 source-level RE on `UPropertySerializer` for these compressed stores, or a working reference output to byte-diff against), please open a PR, the bytes are correctly decompressed and exposed in `WorldSave.iter_cryopod_creatures()`, only the property reader is missing.
|
|
618
669
|
|
|
619
670
|
## Testing
|
|
620
671
|
|