arkparser 0.1.16__tar.gz → 0.3.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.0/PKG-INFO +627 -0
- arkparser-0.3.0/README.md +593 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/__init__.py +20 -44
- arkparser-0.3.0/arkparser/common/binary_reader.py +290 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/common/normalization.py +18 -6
- arkparser-0.3.0/arkparser/export.py +1575 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/files/profile.py +23 -1
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/files/world_save.py +55 -31
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/game_objects/container.py +5 -5
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/game_objects/game_object.py +36 -36
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/game_objects/location.py +1 -1
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/properties/base.py +24 -19
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/properties/byte_property.py +35 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/properties/compound.py +126 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/properties/primitives.py +13 -14
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/structs/property_list.py +15 -7
- arkparser-0.3.0/arkparser.egg-info/PKG-INFO +627 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser.egg-info/SOURCES.txt +2 -9
- {arkparser-0.1.16 → arkparser-0.3.0}/pyproject.toml +1 -1
- arkparser-0.3.0/tests/test_binary_reader_layouts.py +52 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/tests/test_export.py +92 -120
- arkparser-0.3.0/tests/test_v13_property_layouts.py +255 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/tests/test_world_save.py +29 -20
- arkparser-0.1.16/PKG-INFO +0 -856
- arkparser-0.1.16/README.md +0 -822
- arkparser-0.1.16/arkparser/common/binary_reader.py +0 -406
- arkparser-0.1.16/arkparser/export.py +0 -726
- arkparser-0.1.16/arkparser/models/__init__.py +0 -29
- arkparser-0.1.16/arkparser/models/character.py +0 -230
- arkparser-0.1.16/arkparser/models/creature.py +0 -603
- arkparser-0.1.16/arkparser/models/item.py +0 -207
- arkparser-0.1.16/arkparser/models/player.py +0 -267
- arkparser-0.1.16/arkparser/models/stats.py +0 -226
- arkparser-0.1.16/arkparser/models/structure.py +0 -176
- arkparser-0.1.16/arkparser/models/tribe.py +0 -295
- arkparser-0.1.16/arkparser.egg-info/PKG-INFO +0 -856
- arkparser-0.1.16/tests/test_models.py +0 -242
- {arkparser-0.1.16 → arkparser-0.3.0}/LICENSE +0 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/common/__init__.py +0 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/common/exceptions.py +0 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/common/map_config.py +0 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/common/types.py +0 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/common/version_detection.py +0 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/data_models.py +0 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/files/__init__.py +0 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/files/base.py +0 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/files/cloud_inventory.py +0 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/files/tribe.py +0 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/game_objects/__init__.py +0 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/properties/__init__.py +0 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/properties/registry.py +0 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/structs/__init__.py +0 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/structs/base.py +0 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/structs/colors.py +0 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/structs/misc.py +0 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/structs/registry.py +0 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser/structs/vectors.py +0 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser.egg-info/dependency_links.txt +0 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser.egg-info/requires.txt +0 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/arkparser.egg-info/top_level.txt +0 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/setup.cfg +0 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/tests/test_binary_reader.py +0 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/tests/test_cloud_inventory.py +0 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/tests/test_data_models.py +0 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/tests/test_game_objects.py +0 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/tests/test_profile.py +0 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/tests/test_tribe.py +0 -0
- {arkparser-0.1.16 → arkparser-0.3.0}/tests/test_version_detection.py +0 -0
arkparser-0.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,627 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: arkparser
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Pure Python parser for ARK: Survival Evolved and ARK: Survival Ascended save files
|
|
5
|
+
Author: Vertyco
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/vertyco/arkparser
|
|
8
|
+
Project-URL: Repository, https://github.com/vertyco/arkparser
|
|
9
|
+
Project-URL: Documentation, https://github.com/vertyco/arkparser#readme
|
|
10
|
+
Project-URL: Issues, https://github.com/vertyco/arkparser/issues
|
|
11
|
+
Keywords: ark,survival,evolved,ascended,savegame,parser,binary,ase,asa,game,save-file
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Classifier: Topic :: Games/Entertainment
|
|
23
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
|
+
Classifier: Typing :: Typed
|
|
25
|
+
Requires-Python: >=3.10
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest>=9.0; extra == "dev"
|
|
30
|
+
Requires-Dist: ruff>=0.15; extra == "dev"
|
|
31
|
+
Requires-Dist: build>=1.4; extra == "dev"
|
|
32
|
+
Requires-Dist: twine>=6.0; extra == "dev"
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
|
|
35
|
+
# ARK Save Parser
|
|
36
|
+
|
|
37
|
+
[](https://www.python.org/)
|
|
38
|
+
[](https://www.python.org/)
|
|
39
|
+
[](https://www.python.org/)
|
|
40
|
+
[](https://www.python.org/)
|
|
41
|
+
[](https://www.python.org/)
|
|
42
|
+
|
|
43
|
+

|
|
44
|
+

|
|
45
|
+

|
|
46
|
+

|
|
47
|
+
|
|
48
|
+
A pure-Python library for parsing ARK: Survival Evolved (ASE) and ARK: Survival Ascended (ASA) save files. Zero third-party dependencies.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Features
|
|
53
|
+
|
|
54
|
+
- **Player Profiles** (`.arkprofile`): platform gamertag, character name, level, stats, engrams
|
|
55
|
+
- **Tribe Data** (`.arktribe`): members, ranks, logs, alliances
|
|
56
|
+
- **Cloud Inventory / Obelisk**: uploaded creatures, items, cryopod contents
|
|
57
|
+
- **World Saves** (`.ark`): full map state (creatures, structures, items, players)
|
|
58
|
+
- **Dual format**: automatic ASE (v5-12) / ASA (v13-14+, SQLite) detection
|
|
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) — a 30 MB ASE save (65k objects) loads in ~3s on CPython 3.14
|
|
61
|
+
|
|
62
|
+
## Installation
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pip install arkparser
|
|
66
|
+
# or editable install for development
|
|
67
|
+
pip install -e .
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Quick Start
|
|
71
|
+
|
|
72
|
+
### Player Profile
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from arkparser import Profile
|
|
76
|
+
|
|
77
|
+
profile = Profile.load("path/to/player.arkprofile") # auto-detects ASE/ASA
|
|
78
|
+
|
|
79
|
+
print(profile.player_name) # Platform gamertag / display name
|
|
80
|
+
print(profile.character_name) # In-game character name
|
|
81
|
+
print(profile.level) # 105
|
|
82
|
+
print(profile.tribe_id) # 1729028872
|
|
83
|
+
print(profile.engram_blueprints) # ["EngramEntry_Campfire_C", ...]
|
|
84
|
+
print(profile.get_stat(0)) # Health level-up points
|
|
85
|
+
print(profile.to_dict()) # Full dict export
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Tribe Data
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from arkparser import Tribe
|
|
92
|
+
|
|
93
|
+
tribe = Tribe.load("path/to/tribe.arktribe")
|
|
94
|
+
|
|
95
|
+
print(tribe.name) # "My Tribe"
|
|
96
|
+
print(tribe.tribe_id) # 1729028872
|
|
97
|
+
print(tribe.member_count) # 3
|
|
98
|
+
for member in tribe.get_members():
|
|
99
|
+
print(f" {member['name']} (ID: {member['player_id']})")
|
|
100
|
+
print(tribe.log_entries) # ["Day 45: Tamed a Rex", ...]
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Cloud Inventory / Obelisk
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
from arkparser import CloudInventory
|
|
107
|
+
|
|
108
|
+
inv = CloudInventory.load("path/to/obelisk_file") # or use Obelisk alias
|
|
109
|
+
|
|
110
|
+
for creature in inv.uploaded_creatures:
|
|
111
|
+
print(f" {creature.species} Lv{creature.level} - {creature.name}")
|
|
112
|
+
|
|
113
|
+
for item in inv.uploaded_items:
|
|
114
|
+
print(f" {item.display_name} x{item.quantity} ({item.quality_name})")
|
|
115
|
+
if item.is_cryopod and item.cryopod_creature:
|
|
116
|
+
cryo = item.cryopod_creature
|
|
117
|
+
print(f" Contains: {cryo.species} Lv{cryo.level}")
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### World Save
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
from arkparser import WorldSave
|
|
124
|
+
|
|
125
|
+
save = WorldSave.load("path/to/Extinction.ark") # ASE
|
|
126
|
+
save = WorldSave.load("path/to/Extinction_WP.ark") # ASA
|
|
127
|
+
|
|
128
|
+
print(f"Objects: {save.object_count}")
|
|
129
|
+
print(f"Creatures: {len(save.get_creatures())}")
|
|
130
|
+
print(f"Structures: {len(save.get_structures())}")
|
|
131
|
+
print(f"Parse errors: {save.parse_error_count}")
|
|
132
|
+
print(f"Is ASA: {save.is_asa}")
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Cryopod-stored Creatures
|
|
136
|
+
|
|
137
|
+
Tamed creatures stored inside in-world cryopods aren't returned by `get_tamed_creatures()`. Iterate them via `WorldSave.iter_cryopod_creatures()`:
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
for item_obj, cryo in save.iter_cryopod_creatures():
|
|
141
|
+
print(f"{cryo.species} Lv{cryo.level} (in {item_obj.class_name})")
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Direct GameObject Access
|
|
145
|
+
|
|
146
|
+
`arkparser` exposes the raw `GameObject` graph for callers that need flexibility beyond the default exports:
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
for obj in save.get_tamed_creatures():
|
|
150
|
+
name = obj.get_property_value("TamedName") or "<unnamed>"
|
|
151
|
+
tribe = obj.get_property_value("TargetingTeam") or 0
|
|
152
|
+
print(f"{obj.class_name} - {name} (tribe {tribe})")
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### JSON Export (Legacy ASV Schema)
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
from arkparser import export_all, export_to_files
|
|
159
|
+
from arkparser.common import get_map_config
|
|
160
|
+
|
|
161
|
+
map_config = get_map_config("extinction.ark")
|
|
162
|
+
|
|
163
|
+
data = export_all(save, map_config)
|
|
164
|
+
# {"ASV_Tamed": [...], "ASV_Wild": [...], "ASV_Players": [...],
|
|
165
|
+
# "ASV_Tribes": [...], "ASV_Structures": [...], "ASV_TribeLogs": [...],
|
|
166
|
+
# "ASV_MapStructures": [...]}
|
|
167
|
+
|
|
168
|
+
export_to_files(save, "output/", map_config)
|
|
169
|
+
# Writes ASV_Tamed.json, ASV_Wild.json, ..., ASV_MapStructures.json
|
|
170
|
+
# Each file is wrapped with the legacy `{map, day, time, data}` envelope.
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Each export wraps a flat list of record dicts in the legacy `{map, day, time, data}` envelope (with `wrap=True`). Tables below document every field in each record. Fields present in the original `ASVExport.exe` output are marked **legacy**; fields added by this parser are marked **added** and use plain descriptive names (no namespace prefix).
|
|
174
|
+
|
|
175
|
+
#### Stat-token convention
|
|
176
|
+
|
|
177
|
+
The parser reuses the legacy short stat tokens consistently across every export and every stat block:
|
|
178
|
+
|
|
179
|
+
`hp` `stam` `torp` `oxy` `food` `water` `temp` `weight` `melee` `speed` `fort` `craft`
|
|
180
|
+
|
|
181
|
+
These map 1:1 to in-game stat indices 0..11. Stat blocks use suffixes to disambiguate:
|
|
182
|
+
|
|
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
|
+
|
|
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
|
+
|
|
190
|
+
#### `ASV_Tamed` schema
|
|
191
|
+
|
|
192
|
+
| Field | Origin | Source / formula |
|
|
193
|
+
|---|---|---|
|
|
194
|
+
| `id` | legacy | `(DinoID1 << 32) \| DinoID2` |
|
|
195
|
+
| `tribeid` | legacy | `TargetingTeam` |
|
|
196
|
+
| `tribe` | legacy | `TribeName` (or `null` when blank) |
|
|
197
|
+
| `tamer` | legacy | `TamerString` |
|
|
198
|
+
| `imprinter` | legacy | `ImprinterName` |
|
|
199
|
+
| `imprint` | legacy | `DinoImprintingQuality` (status) |
|
|
200
|
+
| `creature` | legacy | `GameObject.class_name` |
|
|
201
|
+
| `name` | legacy | `TamedName` |
|
|
202
|
+
| `sex` | legacy | `"Female"` if `bIsFemale` else `"Male"` |
|
|
203
|
+
| `base` | legacy | `BaseCharacterLevel` (status) |
|
|
204
|
+
| `lvl` | legacy | `BaseCharacterLevel + ExtraCharacterLevel` |
|
|
205
|
+
| `lat`, `lon` | legacy | `MapConfig.ue_to_lat(y)` / `ue_to_lon(x)` |
|
|
206
|
+
| `hp-w` .. `craft-w` | legacy | `NumberOfLevelUpPointsApplied[i]` (wild stat points) |
|
|
207
|
+
| `torp-w`, `water-w`, `temp-w`, `fort-w` | added | same source, indices legacy never emitted |
|
|
208
|
+
| `hp-t` .. `craft-t` | legacy | `NumberOfLevelUpPointsAppliedTamed[i]` |
|
|
209
|
+
| `torp-t`, `water-t`, `temp-t`, `fort-t` | added | same source, indices legacy never emitted |
|
|
210
|
+
| `hp-m` .. `fort-m` (all 12) | added | `NumberOfMutationsAppliedTamed[i]` (mutation point counts per stat) |
|
|
211
|
+
| `c0` .. `c5` | legacy | `ColorSetIndices[i]` |
|
|
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 | `IsInCryo` |
|
|
214
|
+
| `ccc` | legacy | `"{x} {y} {z}"` from `LocationData` |
|
|
215
|
+
| `dinoid` | legacy | string form of `id` |
|
|
216
|
+
| `isMating` | legacy | `bEnableTamedMating` |
|
|
217
|
+
| `isNeutered` | legacy | `bNeutered` |
|
|
218
|
+
| `isClone` | legacy | `bIsClone` or `bIsCloneDino` |
|
|
219
|
+
| `tamedServer` | legacy | `TamedOnServerName` |
|
|
220
|
+
| `uploadedServer` | legacy | `UploadedFromServerName` |
|
|
221
|
+
| `maturation` | legacy | `str(int(BabyAge * 100))` (string for legacy parity) |
|
|
222
|
+
| `traits` | legacy | `CreatureTraits` (full list of mutation trait class names) |
|
|
223
|
+
| `inventory` | legacy | items from `MyInventoryComponent.InventoryItems`. Each entry carries `itemId`, `qty`, `blueprint`. 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
|
+
| `father_id`, `mother_id` | added | combined dino id from the first `DinoAncestors` entry (`null` when missing) |
|
|
225
|
+
| `father_name`, `mother_name` | added | name strings from the first `DinoAncestors` entry |
|
|
226
|
+
| `level_added` | added | `ExtraCharacterLevel` (post-tame levels, broken out from `lvl`) |
|
|
227
|
+
| `experience` | added | `ExperiencePoints` (status), integer |
|
|
228
|
+
| `wandering` | added | `bEnableTamedWandering` |
|
|
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 — converted from `LastInAllyRangeTime` / `LastInAllyRangeSerialized` via the same anchor formula as `tamed_at`. `null` when the save lacks the anchors. |
|
|
231
|
+
| `imprinter_player_id` | added | `ImprinterPlayerDataID` |
|
|
232
|
+
| `imprinter_net_id` | added | `ImprinterPlayerUniqueNetId` (ASA only) |
|
|
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` — 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
|
+
| `is_flying` | added | `bIsFlying`. |
|
|
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
|
+
| `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` — 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
|
+
| `downloaded_at` | added | ISO 8601 datetime of the last cluster/obelisk download (`DinoDownloadedAtTime`). `null` when the creature was never cluster-downloaded. |
|
|
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
|
+
| `next_mating_at` | added | ISO 8601 datetime when the next mating is allowed (`NextAllowedMatingTime`). `null` when no cooldown is set. |
|
|
249
|
+
| `last_stasis` | added | ISO 8601 datetime of `LastEnterStasisTime` (last time the creature entered stasis). |
|
|
250
|
+
| `last_baby_age_update` | added | ISO 8601 datetime of `LastUpdatedBabyAgeAtTime`. |
|
|
251
|
+
| `last_gestation_update` | added | ISO 8601 datetime of `LastUpdatedGestationAtTime`. |
|
|
252
|
+
| `next_cuddle` | added | ISO 8601 datetime of `BabyNextCuddleTime`. |
|
|
253
|
+
|
|
254
|
+
#### `ASV_Wild` schema
|
|
255
|
+
|
|
256
|
+
| Field | Origin | Source / formula |
|
|
257
|
+
|---|---|---|
|
|
258
|
+
| `id`, `dinoid` | legacy | `(DinoID1 << 32) \| DinoID2` and its string form |
|
|
259
|
+
| `creature` | legacy | `GameObject.class_name` |
|
|
260
|
+
| `sex` | legacy | `"Female"` if `bIsFemale` else `"Male"` |
|
|
261
|
+
| `lvl` | legacy | `BaseCharacterLevel` (status) |
|
|
262
|
+
| `lat`, `lon`, `ccc` | legacy | location, via `MapConfig` |
|
|
263
|
+
| `hp` .. `craft` | legacy | `NumberOfLevelUpPointsApplied[i]` (8 visible stats) |
|
|
264
|
+
| `torp`, `water`, `temp`, `fort` | added | same source, indices legacy never emitted |
|
|
265
|
+
| `c0` .. `c5` | legacy | `ColorSetIndices[i]` |
|
|
266
|
+
| `tameable` | legacy | mirror of legacy `ContentWildCreature.IsTameable` rule |
|
|
267
|
+
| `trait` | legacy | first entry of `CreatureTraits` (or empty string) |
|
|
268
|
+
| `traits` | added | full `CreatureTraits` list |
|
|
269
|
+
| `wild_spawn_region` | added | `OriginalNPCVolumeName` — `NPCZoneVolume` the creature spawned in. |
|
|
270
|
+
|
|
271
|
+
#### Player data: `.arkprofile` vs in-world pawn
|
|
272
|
+
|
|
273
|
+
ARK keeps player data in **two distinct places**, and the parser builds `ASV_Players` records from whichever source you hand it:
|
|
274
|
+
|
|
275
|
+
| Source | Persistence | Coverage | Has location? | Has inventory? |
|
|
276
|
+
|---|---|---|---|---|
|
|
277
|
+
| **`.arkprofile`** parsed via `Profile.load(...)` | Survives logout, server restart, and character death | Every player who ever logged in | No (profile carries no in-world position) | No (profile only stores engrams / hairstyles / unlocked customizations, not the live inventory) |
|
|
278
|
+
| **In-world `PlayerPawn`** GameObject inside `WorldSave` | Only present while the character is spawned on the map (i.e. not logged out / dead with corpse cleared) | Currently-online or recently-disconnected players | Yes (`obj.location` → `lat`/`lon`/`ccc`) | Yes (live `MyInventoryComponent` contents) |
|
|
279
|
+
|
|
280
|
+
The export pipeline (`export_players`) loops over `save.profiles` (a list the caller assembles). For each entry:
|
|
281
|
+
|
|
282
|
+
- 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.
|
|
283
|
+
- 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`.
|
|
284
|
+
|
|
285
|
+
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.
|
|
286
|
+
|
|
287
|
+
#### `ASV_Players` schema
|
|
288
|
+
|
|
289
|
+
| Field | Origin | Source / formula |
|
|
290
|
+
|---|---|---|
|
|
291
|
+
| `playerid` | legacy | `PlayerDataID` |
|
|
292
|
+
| `steam` | legacy | platform gamertag (`PlatformProfileName` / profile `PlayerName`) |
|
|
293
|
+
| `name` | legacy | in-game character name |
|
|
294
|
+
| `tribeid` | legacy | `TribeId` / `TribeID` |
|
|
295
|
+
| `tribe` | legacy | tribe name |
|
|
296
|
+
| `sex` | legacy | `"Female"` / `"Male"` |
|
|
297
|
+
| `lvl` | legacy | `BaseCharacterLevel + ExtraCharacterLevel` |
|
|
298
|
+
| `lat`, `lon` | legacy | `0.0` (profile/cluster files carry no in-world location) |
|
|
299
|
+
| `hp` .. `craft`, `fort` | legacy | `NumberOfLevelUpPointsApplied[i]` (10 visible stats) |
|
|
300
|
+
| `torp`, `temp` | added | same source, indices legacy never emitted |
|
|
301
|
+
| `active` | legacy | last-active datetime; currently `null` (placeholder for parity) |
|
|
302
|
+
| `ccc` | legacy | `"0 0 0"` (no in-world position from profile/cluster source) |
|
|
303
|
+
| `achievements`, `inventory`, `netAddress` | legacy | reserved arrays/string (currently empty for parity) |
|
|
304
|
+
| `steamid`, `dataFile` | legacy | platform net id and `{steamid}.arkprofile` filename |
|
|
305
|
+
| `active` | legacy (now populated) | ISO 8601 datetime of last login, converted from profile `LastLoginTime` or in-world pawn `SavedLastTimeHadController`. Legacy schema reserved the field but the old C# exporter only filled it for in-world pawns; the parser fills it for profiles too. `null` when neither source is present. |
|
|
306
|
+
| `lat`, `lon`, `ccc` | legacy (now populated) | In-world position when the record was built from a `PlayerPawn` GameObject. Records sourced from profile / cluster files keep the legacy `0` / `"0 0 0"` placeholders since profiles carry no world position. |
|
|
307
|
+
| `inventory` | legacy (now populated) | Items from the pawn's `MyInventoryComponent` when built from an in-world pawn. Empty list otherwise. |
|
|
308
|
+
| `engram_points` | added | `TotalEngramPoints` |
|
|
309
|
+
| `experience` | added | `ExperiencePoints` (status), integer |
|
|
310
|
+
| `is_sleeping`, `is_dead` | added | `bIsSleeping` / `bIsDead` — pawn state flags. Always `false` for profile-sourced records (no pawn). |
|
|
311
|
+
| `is_prone`, `is_crouched`, `hat_hidden` | added | `bIsProne` / `bIsCrouched` / `bHatHidden`. |
|
|
312
|
+
| `current_weapon` | added | `CurrentWeapon` ref — equipped weapon identifier. |
|
|
313
|
+
| `seated_on_ref` | added | `SeatingStructure` ref — what the player is sitting on (chair / saddle). |
|
|
314
|
+
| `original_hair_color` | added | `OriginalHairColor` — color index at character creation. |
|
|
315
|
+
| `head_hair_growth`, `facial_hair_growth` | added | `PercentOfFullHeadHairGrowth` / `PercentOfFullFacialHairGrowth`. |
|
|
316
|
+
| `body_colors` | added | `BodyColors` — per-region skin color indices. |
|
|
317
|
+
| `died_at` | added | ISO 8601 datetime of `LocalDiedAtTime`. |
|
|
318
|
+
| `corpse_destruction` | added | ISO 8601 datetime of `CorpseDestructionTime`. |
|
|
319
|
+
| `chibi_levels` | added | `NumChibiLevelUps` — bonus levels from chibi pets. |
|
|
320
|
+
| `ascensions_scorched` | added | `NumAscensionsScorched` — ASE ascension counter (legacy `ContentPlayer` parses the ASA ascension block differently; this is the ASE-specific field). |
|
|
321
|
+
|
|
322
|
+
#### `ASV_Tribes` schema
|
|
323
|
+
|
|
324
|
+
| Field | Origin | Source / formula |
|
|
325
|
+
|---|---|---|
|
|
326
|
+
| `tribeid` | legacy | `TribeID` / parser `Tribe.tribe_id` |
|
|
327
|
+
| `tribe` | legacy | tribe name |
|
|
328
|
+
| `players` | legacy | member count |
|
|
329
|
+
| `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. |
|
|
330
|
+
| `tames`, `structures` | legacy | counts derived from `WorldSave` (creatures + structures whose `TargetingTeam` matches) |
|
|
331
|
+
| `uploadedTames` | legacy | reserved (currently `0`) |
|
|
332
|
+
| `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. |
|
|
333
|
+
| `dataFile` | legacy | `"{tribeid}.arktribe"` filename pattern. |
|
|
334
|
+
| `owner_id` | added | `OwnerPlayerDataID` / parser `Tribe.owner_player_id` |
|
|
335
|
+
| `owner_name` | added | `OwnerPlayerName` (object form only; parser-tribe form has no equivalent) |
|
|
336
|
+
| `alliance_ids` | added | `TribeAlliances[i]` |
|
|
337
|
+
|
|
338
|
+
#### `ASV_TribeLogs` schema
|
|
339
|
+
|
|
340
|
+
| Field | Origin | Source / formula |
|
|
341
|
+
|---|---|---|
|
|
342
|
+
| `tribeid` | legacy | `TribeID` / `Tribe.tribe_id` |
|
|
343
|
+
| `tribe` | legacy | tribe name |
|
|
344
|
+
| `logs` | legacy | raw `TribeLog` strings (newest-first, formatted by ARK with `Day N, HH:MM:SS: <message>`) |
|
|
345
|
+
|
|
346
|
+
#### `ASV_Structures` schema
|
|
347
|
+
|
|
348
|
+
| Field | Origin | Source / formula |
|
|
349
|
+
|---|---|---|
|
|
350
|
+
| `id` | added | `GameObject.id` — internal numeric identifier. Cross-references the values in other records' `linked_structures` / `saddle_structures` / `attached_dino_id` lists. |
|
|
351
|
+
| `tribeid` | legacy | `TargetingTeam` |
|
|
352
|
+
| `tribe` | legacy | `OwnerName` |
|
|
353
|
+
| `struct` | legacy | `GameObject.class_name` |
|
|
354
|
+
| `name` | legacy | `BoxName` (empty when it matches the class name, mirroring legacy's no-rename strip) |
|
|
355
|
+
| `locked` | legacy | `bIsPinLocked` or `bIsLocked` |
|
|
356
|
+
| `created` | legacy (richer) | ISO 8601 datetime with the local TZ of the parser machine, computed `save.file_mtime + (OriginalCreationTime - game_time)` (mirrors legacy `ContentContainer.GetApproxDateTimeOf`). `null` when the anchors are missing. |
|
|
357
|
+
| `inventory` | legacy | items from `MyInventoryComponent.InventoryItems` |
|
|
358
|
+
| `lat`, `lon`, `ccc` | legacy | location via `MapConfig`, **rounded to 2 decimals** (parser-only nicety, not legacy parity) |
|
|
359
|
+
| `powered` | added | `bIsPowered` or `bHasFuel` |
|
|
360
|
+
| `switched_on` | added | `bContainerActivated` (lamps / fridges / etc.) |
|
|
361
|
+
| `decay_reset` | added | `bHasResetDecayTime` |
|
|
362
|
+
| `last_ally_in_range_seconds` | added | raw `LastInAllyRangeTime` / `LastInAllyRangeTimeSerialized` / `LastInAllyRangeSerialized` (in-game seconds, float) |
|
|
363
|
+
| `last_ally_in_range` | added | ISO 8601 datetime with local TZ. `null` when the save lacks the anchors. |
|
|
364
|
+
| `painting_id` | added | `UniquePaintingId` |
|
|
365
|
+
| `feeding_inclusions` | added | `FeedingDinoList` class names when `DinoFeedingListType == 1` (ASA feeding troughs) |
|
|
366
|
+
| `feeding_exclusions` | added | `FeedingDinoList` class names when `DinoFeedingListType == 2` |
|
|
367
|
+
| `health` | added | `Health` (often `0.0` because ARK strips live health on save) |
|
|
368
|
+
| `max_health` | added | `MaxHealth` |
|
|
369
|
+
| `owning_player_id`, `owning_player_name` | added | `OwningPlayerID` / `OwningPlayerName` — who placed the structure (distinct from `tribe`, which is the current owning tribe). |
|
|
370
|
+
| `colors` | added | `StructureColors` — list of 6 color region indices (0 = unpainted). |
|
|
371
|
+
| `current_item_count`, `max_item_count` | added | `CurrentItemCount` / `MaxItemCount` — container fullness (e.g. dedicated storage, generators). Both `0` for non-container structures. |
|
|
372
|
+
| `num_bullets` | added | `NumBullets` — loaded ammo count on auto-turrets. `0` for non-turrets. |
|
|
373
|
+
| `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`. |
|
|
374
|
+
| `has_fuel` | added | `bHasFuel` — generator / lamp fuel state. |
|
|
375
|
+
| `is_foundation` | added | `bIsFoundation`. |
|
|
376
|
+
| `placement_snapped` | added | `bWasPlacementSnapped` — placement-snap flag. |
|
|
377
|
+
| `variant` | added | `CurrentVariant` — structure variant index (e.g. flexible pipe / gate style). |
|
|
378
|
+
| `selected_resource_class` | added | `SelectedResourceClass` ref — resource type chosen on dedicated storage / similar. |
|
|
379
|
+
| `resource_count` | added | `ResourceCount`. |
|
|
380
|
+
| `dedicated_storage_version` | added | `SavedDedicatedStorageVersion`. |
|
|
381
|
+
| `painting_ref` | added | `PaintingComponent` ref — canvas component identifier when painted. |
|
|
382
|
+
| `saddle_dino_ref`, `attached_dino_id` | added | `SaddleDino` ref + `AttachedToDinoID1/2` combined — links saddle-mounted structures back to their host dino. |
|
|
383
|
+
| `linked_structures` | added | `LinkedStructures` — refs of network-linked structures (pipes / wires / gates → motors). Useful for reconstructing infrastructure topology. |
|
|
384
|
+
| `last_activated` | added | ISO 8601 datetime of `LastActivatedTime`. |
|
|
385
|
+
| `last_deactivated` | added | ISO 8601 datetime of `LastDeactivatedTime`. |
|
|
386
|
+
| `last_fire` | added | ISO 8601 datetime of `LastFireTime` — last turret discharge. |
|
|
387
|
+
| `last_reload` | added | ISO 8601 datetime of `LastLongReloadStartTime`. |
|
|
388
|
+
| `last_fuel_check` | added | ISO 8601 datetime of `LastCheckedFuelTime`. |
|
|
389
|
+
| `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. |
|
|
390
|
+
|
|
391
|
+
#### `ASV_MapStructures` schema
|
|
392
|
+
|
|
393
|
+
| Field | Origin | Source / formula |
|
|
394
|
+
|---|---|---|
|
|
395
|
+
| `struct` | legacy | ASV label assigned by class-name match (e.g. `ASV_Terminal`, `ASV_BeaverDam`, `ASV_Artifact`) |
|
|
396
|
+
| `lat`, `lon`, `ccc` | legacy | location via `MapConfig` |
|
|
397
|
+
| `inventory` | legacy | inventory items (only meaningful for beaver dams / dropped supply crates) |
|
|
398
|
+
|
|
399
|
+
### Cluster-uploaded creatures
|
|
400
|
+
|
|
401
|
+
To match the legacy exporter's behaviour of including cluster-uploaded tames (creatures stored in obelisk/cloud-inventory files), pass the cluster directory to `export_all` / `export_to_files`:
|
|
402
|
+
|
|
403
|
+
```python
|
|
404
|
+
export_to_files(save, "output/", map_config, cluster="path/to/cluster")
|
|
405
|
+
# or equivalently:
|
|
406
|
+
data = export_all(save, map_config, cluster="path/to/cluster")
|
|
407
|
+
# data["ASV_Tamed"] now includes both world tames and cluster uploads.
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
Pre-loaded `CloudInventory` instances also work (`cluster=[inv1, inv2, ...]`). The low-level helper `export_cluster_uploads(cluster_invs, map_config)` is still available if you need cluster-only output.
|
|
411
|
+
|
|
412
|
+
## Package Structure
|
|
413
|
+
|
|
414
|
+
```
|
|
415
|
+
arkparser/
|
|
416
|
+
├── __init__.py # Public API
|
|
417
|
+
├── data_models.py # UploadedCreature, UploadedItem, CryopodCreature, DinoStats
|
|
418
|
+
├── export.py # Legacy-parity JSON export functions
|
|
419
|
+
├── common/ # Binary reader, types, exceptions, map configs, version detection
|
|
420
|
+
├── files/ # File parsers (Profile, Tribe, CloudInventory, WorldSave)
|
|
421
|
+
├── game_objects/ # GameObject, GameObjectContainer, LocationData
|
|
422
|
+
├── properties/ # Property parsing system (ArrayProperty, StructProperty, etc.)
|
|
423
|
+
└── structs/ # Struct types (Vector, Color, Guid, etc.)
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
## API Reference
|
|
427
|
+
|
|
428
|
+
### File Parsers
|
|
429
|
+
|
|
430
|
+
All file parsers expose `load(source)` which accepts `str`, `Path`, or `bytes` and auto-detects ASE/ASA format.
|
|
431
|
+
|
|
432
|
+
#### Profile (`arkparser.Profile`)
|
|
433
|
+
|
|
434
|
+
Parser for `.arkprofile` player profile files.
|
|
435
|
+
|
|
436
|
+
| Property | Type | Description |
|
|
437
|
+
|---|---|---|
|
|
438
|
+
| `player_name` | `str \| None` | Platform gamertag / display name |
|
|
439
|
+
| `character_name` | `str \| None` | In-game character name (falls back to `player_name`) |
|
|
440
|
+
| `player_id` | `int \| None` | Unique player ID |
|
|
441
|
+
| `unique_id` | `str \| None` | Platform ID (Steam/Xbox numeric ID) |
|
|
442
|
+
| `tribe_id` | `int \| None` | Tribe ID (auto-tribe = `player_id` when no explicit tribe) |
|
|
443
|
+
| `is_female` | `bool \| None` | Gender flag |
|
|
444
|
+
| `level` | `int` | Current level |
|
|
445
|
+
| `experience` | `float` | Total XP |
|
|
446
|
+
| `total_engram_points` | `int` | Engram points spent |
|
|
447
|
+
| `engram_blueprints` | `list[str]` | Learned engram blueprint paths |
|
|
448
|
+
| `objects` | `list[GameObject]` | Raw parsed game objects |
|
|
449
|
+
|
|
450
|
+
`get_stat(index)` returns the level-up points allocated to the given stat (0=Health … 11=Crafting). `to_dict()` returns a flat profile dictionary.
|
|
451
|
+
|
|
452
|
+
#### Tribe (`arkparser.Tribe`)
|
|
453
|
+
|
|
454
|
+
Parser for `.arktribe` tribe data files.
|
|
455
|
+
|
|
456
|
+
| Property | Type | Description |
|
|
457
|
+
|---|---|---|
|
|
458
|
+
| `name` | `str \| None` | Tribe name |
|
|
459
|
+
| `tribe_id` | `int \| None` | Unique tribe ID |
|
|
460
|
+
| `owner_player_id` | `int \| None` | Tribe owner's player ID |
|
|
461
|
+
| `member_ids` / `member_names` / `member_ranks` | `list[...]` | Member arrays |
|
|
462
|
+
| `member_count` | `int` | Number of members |
|
|
463
|
+
| `log_entries` | `list[str]` | Raw tribe log strings |
|
|
464
|
+
| `alliance_ids` | `list[int]` | Allied tribe IDs |
|
|
465
|
+
| `government_type` | `int` | 0=Player, 1=Tribe, 2=Personal |
|
|
466
|
+
|
|
467
|
+
`get_members()` returns a list of `{player_id, name, rank}` dicts.
|
|
468
|
+
|
|
469
|
+
#### CloudInventory (`arkparser.CloudInventory`, alias `Obelisk`)
|
|
470
|
+
|
|
471
|
+
Parser for obelisk / cloud-inventory data files.
|
|
472
|
+
|
|
473
|
+
| Property | Type | Description |
|
|
474
|
+
|---|---|---|
|
|
475
|
+
| `uploaded_creatures` | `list[UploadedCreature]` | Uploaded creatures with stats |
|
|
476
|
+
| `uploaded_items` | `list[UploadedItem]` | Uploaded items (includes cryopods) |
|
|
477
|
+
| `creatures` / `items` / `characters` | `list[GameObject]` | Raw GameObjects |
|
|
478
|
+
| `creature_count` / `item_count` / `character_count` | `int` | Counts |
|
|
479
|
+
|
|
480
|
+
#### WorldSave (`arkparser.WorldSave`)
|
|
481
|
+
|
|
482
|
+
Unified parser for `.ark` world save files. Auto-detects ASE binary vs ASA SQLite.
|
|
483
|
+
|
|
484
|
+
| Property | Type | Description |
|
|
485
|
+
|---|---|---|
|
|
486
|
+
| `version` | `int` | Save format version |
|
|
487
|
+
| `game_time` | `float` | In-game time (seconds) |
|
|
488
|
+
| `save_count` | `int` | Save counter (ASE v9+) |
|
|
489
|
+
| `is_asa` | `bool` | Whether ASA SQLite format |
|
|
490
|
+
| `objects` | `list[GameObject]` | All parsed game objects |
|
|
491
|
+
| `object_count` | `int` | Total object count |
|
|
492
|
+
| `parse_error_count` / `parse_errors` | `int` / `list[str]` | Errors encountered |
|
|
493
|
+
| `container` | `GameObjectContainer` | Relationship-aware container |
|
|
494
|
+
| `actor_locations` | `dict[str, LocationData]` | GUID → location (ASA only) |
|
|
495
|
+
| `data_files` | `list[str]` | External data file references |
|
|
496
|
+
| `name_table` | `list[str] \| dict[int, str]` | Deduplicated name strings |
|
|
497
|
+
|
|
498
|
+
Key methods:
|
|
499
|
+
|
|
500
|
+
| Method | Returns | Description |
|
|
501
|
+
|---|---|---|
|
|
502
|
+
| `load(source, load_properties=True, max_objects=None)` | `WorldSave` | Load and parse a world save |
|
|
503
|
+
| `get_creatures()` | `list[GameObject]` | All creatures |
|
|
504
|
+
| `get_tamed_creatures()` / `get_wild_creatures()` | `list[GameObject]` | Filtered creature sets |
|
|
505
|
+
| `get_structures()` | `list[GameObject]` | Tribe-owned placed structures |
|
|
506
|
+
| `get_player_pawns()` | `list[GameObject]` | Player characters on the map |
|
|
507
|
+
| `get_terminals()` / `get_supply_drops()` / `get_artifact_crates()` | `list[GameObject]` | Map-element objects |
|
|
508
|
+
| `get_map_resources()` / `get_nests()` | `list[GameObject]` | Veins, charge nodes, beaver dams, nests |
|
|
509
|
+
| `get_items()` | `list[GameObject]` | Item objects |
|
|
510
|
+
| `get_objects_by_class(pattern)` | `list[GameObject]` | Substring class match |
|
|
511
|
+
| `get_object_by_guid(guid)` | `GameObject \| None` | Lookup by GUID (ASA) |
|
|
512
|
+
| `get_actor_location(guid)` | `LocationData \| None` | Actor location by GUID (ASA) |
|
|
513
|
+
| `iter_cryopod_creatures()` | `Iterator[(GameObject, CryopodCreature)]` | Walk filled cryopods |
|
|
514
|
+
|
|
515
|
+
### Game Objects
|
|
516
|
+
|
|
517
|
+
#### GameObject (`arkparser.GameObject`)
|
|
518
|
+
|
|
519
|
+
| Field | Type | Description |
|
|
520
|
+
|---|---|---|
|
|
521
|
+
| `id` | `int` | Object index within the save |
|
|
522
|
+
| `guid` | `str` | 16-byte GUID (ASA only) |
|
|
523
|
+
| `class_name` | `str` | UE4 class name |
|
|
524
|
+
| `is_item` | `bool` | Whether this is an item / blueprint / engram |
|
|
525
|
+
| `names` | `list[str]` | ArkName list (1 for actors, 2+ for components) |
|
|
526
|
+
| `location` | `LocationData \| None` | World position and rotation |
|
|
527
|
+
| `properties` | `list[Property]` | Parsed property list |
|
|
528
|
+
| `parent` / `components` | `GameObject \| None` / `dict[str, GameObject]` | Relationships |
|
|
529
|
+
|
|
530
|
+
Lookup helpers: `get_property(name, index=None)`, `get_property_value(name, default=None, index=None)`, `get_properties_by_name(name)`, `has_property(name)`, `to_dict()`.
|
|
531
|
+
|
|
532
|
+
#### GameObjectContainer (`arkparser.GameObjectContainer`)
|
|
533
|
+
|
|
534
|
+
Relationship-aware container. Supports `len()`, iteration, indexing. Same filter methods as `WorldSave` (`get_creatures`, `get_structures`, `get_player_pawns`, …) plus `find_by_class_pattern(pattern)`.
|
|
535
|
+
|
|
536
|
+
#### LocationData (`arkparser.LocationData`)
|
|
537
|
+
|
|
538
|
+
`x`, `y`, `z`, `pitch`, `yaw`, `roll` floats. `position` / `rotation` tuple properties, `to_dict()`.
|
|
539
|
+
|
|
540
|
+
### Cloud-Inventory Data Models
|
|
541
|
+
|
|
542
|
+
| Class | Purpose |
|
|
543
|
+
|---|---|
|
|
544
|
+
| `UploadedCreature` | Cloud creature record (class, level, stats, IDs, upload time) |
|
|
545
|
+
| `UploadedItem` | Cloud item record with `.is_cryopod` / `.cryopod_creature` accessors |
|
|
546
|
+
| `CryopodCreature` | Parsed creature snapshot from a cryopod blob (creature + status properties) |
|
|
547
|
+
| `DinoStats` | Current/max stat values for a creature |
|
|
548
|
+
|
|
549
|
+
All four expose `from_*` constructors and `to_dict()` for serialization.
|
|
550
|
+
|
|
551
|
+
### Export Functions
|
|
552
|
+
|
|
553
|
+
`arkparser.export` produces dicts matching the legacy `ASVExport.exe` schema. Optional `map_config` adds `lat` / `lon` GPS keys.
|
|
554
|
+
|
|
555
|
+
| Function | Returns | Description |
|
|
556
|
+
|---|---|---|
|
|
557
|
+
| `export_tamed(save, map_config=None)` | `list[dict]` | `ASV_Tamed` records |
|
|
558
|
+
| `export_wild(save, map_config=None)` | `list[dict]` | `ASV_Wild` records |
|
|
559
|
+
| `export_players(save, map_config=None)` | `list[dict]` | `ASV_Players` records (from Profile parsers) |
|
|
560
|
+
| `export_tribes(save)` | `list[dict]` | `ASV_Tribes` records |
|
|
561
|
+
| `export_structures(save, map_config=None)` | `list[dict]` | `ASV_Structures` records |
|
|
562
|
+
| `export_tribe_logs(save)` | `list[dict]` | `ASV_TribeLogs` records |
|
|
563
|
+
| `export_map_structures(save, map_config=None)` | `list[dict]` | `ASV_MapStructures` records |
|
|
564
|
+
| `export_all(save, map_config=None)` | `dict[str, list[dict]]` | All seven exports keyed by ASV filename stem |
|
|
565
|
+
| `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) |
|
|
566
|
+
| `export_to_files(save, output_dir, map_config=None, wrap=True)` | `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 |
|
|
567
|
+
|
|
568
|
+
Schema policy:
|
|
569
|
+
|
|
570
|
+
- **Legacy keys** (`hp-w`, `ccc`, `dinoid`, `mut-f`, `lat`, `lon`, `tribeid`, etc.) are frozen; they mirror `ASVExport.exe` exactly. They are emitted on every record regardless of value.
|
|
571
|
+
- **Empty parser-added fields are omitted.** Added keys whose value is `None`, `""`, `[]`, `false`, or numeric `0` are dropped from the output (ARK property absence already encodes the default). Consumers must read added fields with `.get(key, default)` rather than expecting the key to exist. Lists like `colors` / `body_colors` / `harvest_resource_levels` are also dropped when every element is zero.
|
|
572
|
+
- **Parser additions** sit alongside the legacy keys with descriptive snake_case names (no `extra_*` prefix). See the per-export schema tables above for the full list.
|
|
573
|
+
- **Stat tokens** are uniform across every export: `hp`, `stam`, `torp`, `oxy`, `food`, `water`, `temp`, `weight`, `melee`, `speed`, `fort`, `craft`. Stat blocks use the suffixes `-w` (wild base, tamed only), `-t` (tamed level-ups), `-m` (mutations); wild creatures and players use the unsuffixed form.
|
|
574
|
+
|
|
575
|
+
### Map Config (`arkparser.common.map_config`)
|
|
576
|
+
|
|
577
|
+
| Function | Returns | Description |
|
|
578
|
+
|---|---|---|
|
|
579
|
+
| `get_map_config(filename)` | `MapConfig` | Lookup by save filename (case-insensitive) |
|
|
580
|
+
| `get_map_config_by_name(name)` | `MapConfig` | Lookup by display name |
|
|
581
|
+
| `list_maps()` | `list[MapConfig]` | All registered map configs |
|
|
582
|
+
|
|
583
|
+
`MapConfig` methods: `ue_to_lat(y)`, `ue_to_lon(x)`, `ue_to_gps(x, y)`, `ccc_string(x, y, z)`.
|
|
584
|
+
|
|
585
|
+
### Version Detection (`arkparser.common.version_detection`)
|
|
586
|
+
|
|
587
|
+
| Function | Returns | Description |
|
|
588
|
+
|---|---|---|
|
|
589
|
+
| `detect_format(source)` | `ArkFileFormat` | `ASE`, `ASA`, or `UNKNOWN` |
|
|
590
|
+
| `detect_file_type(source)` | `ArkFileType` | `PROFILE`, `TRIBE`, `CLOUD_INVENTORY`, `WORLD_SAVE`, or `UNKNOWN` |
|
|
591
|
+
| `get_save_version(source)` | `int` | Version number (-1 if invalid) |
|
|
592
|
+
|
|
593
|
+
### Exceptions
|
|
594
|
+
|
|
595
|
+
| Exception | Description |
|
|
596
|
+
|---|---|
|
|
597
|
+
| `ArkParseError` | Base exception for all parsing errors |
|
|
598
|
+
| `CorruptDataError` | File data appears corrupted or invalid |
|
|
599
|
+
| `UnknownPropertyError` | Unrecognized property type encountered |
|
|
600
|
+
| `UnknownStructError` | Unrecognized struct type encountered |
|
|
601
|
+
| `UnexpectedDataError` | Data doesn't match expected values |
|
|
602
|
+
| `EndOfDataError` | Attempted to read past end of data |
|
|
603
|
+
|
|
604
|
+
## Format Support
|
|
605
|
+
|
|
606
|
+
| Feature | ASE (v5-12) | ASA (v13-14+) |
|
|
607
|
+
|---------|-------------|---------------|
|
|
608
|
+
| Vectors | Float (4 bytes) | Double (8 bytes) |
|
|
609
|
+
| Object IDs | Int32 index | 16-byte GUID |
|
|
610
|
+
| Booleans | Int32 | Int16 |
|
|
611
|
+
| World Save | Binary file | SQLite database |
|
|
612
|
+
| Compression | None | zlib + custom RLE |
|
|
613
|
+
|
|
614
|
+
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.
|
|
615
|
+
|
|
616
|
+
## Testing
|
|
617
|
+
|
|
618
|
+
```powershell
|
|
619
|
+
.\.venv\Scripts\Activate.ps1
|
|
620
|
+
python -m pytest tests/ -v
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
Tests live in `tests/`. Byte-level layout tests (`test_v13_property_layouts.py`, `test_binary_reader_layouts.py`) pin the canonical v13/v14 property body byte sequences with no file-fixture dependency. Integration tests (`test_world_save.py`, `test_export.py`, etc.) skip cleanly when their referenced save files are not present under `references/examples/`.
|
|
624
|
+
|
|
625
|
+
## Credits
|
|
626
|
+
|
|
627
|
+
Built by reverse-engineering ARK save formats with heavy reference to [ASV (Ark Save Visualizer)](https://github.com/miragedmuk/ASV) by **miragedmuk**. The C# implementation in ASV is the primary reference for porting binary parsing logic to Python.
|