arkparser 0.1.0__py3-none-any.whl
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/__init__.py +117 -0
- arkparser/common/__init__.py +72 -0
- arkparser/common/binary_reader.py +402 -0
- arkparser/common/exceptions.py +99 -0
- arkparser/common/map_config.py +166 -0
- arkparser/common/types.py +249 -0
- arkparser/common/version_detection.py +195 -0
- arkparser/data_models.py +801 -0
- arkparser/export.py +485 -0
- arkparser/files/__init__.py +25 -0
- arkparser/files/base.py +309 -0
- arkparser/files/cloud_inventory.py +259 -0
- arkparser/files/profile.py +205 -0
- arkparser/files/tribe.py +155 -0
- arkparser/files/world_save.py +699 -0
- arkparser/game_objects/__init__.py +32 -0
- arkparser/game_objects/container.py +180 -0
- arkparser/game_objects/game_object.py +273 -0
- arkparser/game_objects/location.py +87 -0
- arkparser/models/__init__.py +29 -0
- arkparser/models/character.py +227 -0
- arkparser/models/creature.py +642 -0
- arkparser/models/item.py +207 -0
- arkparser/models/player.py +263 -0
- arkparser/models/stats.py +226 -0
- arkparser/models/structure.py +176 -0
- arkparser/models/tribe.py +291 -0
- arkparser/properties/__init__.py +77 -0
- arkparser/properties/base.py +329 -0
- arkparser/properties/byte_property.py +230 -0
- arkparser/properties/compound.py +1125 -0
- arkparser/properties/primitives.py +803 -0
- arkparser/properties/registry.py +236 -0
- arkparser/py.typed +0 -0
- arkparser/structs/__init__.py +60 -0
- arkparser/structs/base.py +63 -0
- arkparser/structs/colors.py +108 -0
- arkparser/structs/misc.py +133 -0
- arkparser/structs/property_list.py +101 -0
- arkparser/structs/registry.py +140 -0
- arkparser/structs/vectors.py +221 -0
- arkparser-0.1.0.dist-info/METADATA +833 -0
- arkparser-0.1.0.dist-info/RECORD +46 -0
- arkparser-0.1.0.dist-info/WHEEL +5 -0
- arkparser-0.1.0.dist-info/licenses/LICENSE +21 -0
- arkparser-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Struct Registry - Type Dispatch for Struct Reading.
|
|
3
|
+
|
|
4
|
+
This module provides the central registry for reading structs from binary data.
|
|
5
|
+
It dispatches to the appropriate struct class based on the struct type name.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import typing as t
|
|
11
|
+
|
|
12
|
+
from ..common.binary_reader import BinaryReader
|
|
13
|
+
from .base import Struct
|
|
14
|
+
from .colors import Color, LinearColor
|
|
15
|
+
from .misc import CustomItemDataRef, Guid, UniqueNetIdRepl
|
|
16
|
+
from .property_list import StructPropertyList
|
|
17
|
+
from .vectors import IntPoint, IntVector, Quat, Rotator, Vector, Vector2D
|
|
18
|
+
|
|
19
|
+
# Type alias for struct reader functions
|
|
20
|
+
StructReader = t.Callable[[BinaryReader, bool], Struct]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# Registry mapping struct type names to their classes
|
|
24
|
+
STRUCT_REGISTRY: dict[str, type[Struct]] = {
|
|
25
|
+
# Vectors and transforms
|
|
26
|
+
"Vector": Vector,
|
|
27
|
+
"Vector2D": Vector2D,
|
|
28
|
+
"Rotator": Rotator,
|
|
29
|
+
"Quat": Quat,
|
|
30
|
+
"IntPoint": IntPoint,
|
|
31
|
+
"IntVector": IntVector,
|
|
32
|
+
# Colors
|
|
33
|
+
"Color": Color,
|
|
34
|
+
"LinearColor": LinearColor,
|
|
35
|
+
# Misc
|
|
36
|
+
"UniqueNetIdRepl": UniqueNetIdRepl,
|
|
37
|
+
"Guid": Guid,
|
|
38
|
+
"CustomItemDataRef": CustomItemDataRef,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# Some array names map to specific struct types
|
|
43
|
+
# Used when reading struct arrays where the element type isn't explicitly stated
|
|
44
|
+
ARRAY_NAME_TO_STRUCT_TYPE: dict[str, str] = {
|
|
45
|
+
"CustomColors": "Color",
|
|
46
|
+
"CustomColours_60_7D3267C846B277953C0C41AEBD54FBCB": "LinearColor",
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def read_struct(
|
|
51
|
+
reader: BinaryReader,
|
|
52
|
+
struct_type: str,
|
|
53
|
+
is_asa: bool = False,
|
|
54
|
+
has_index_prefix: bool = False,
|
|
55
|
+
name_table: list[str] | None = None,
|
|
56
|
+
worldsave_format: bool = False,
|
|
57
|
+
) -> Struct:
|
|
58
|
+
"""
|
|
59
|
+
Read a struct from the binary reader.
|
|
60
|
+
|
|
61
|
+
Dispatches to the appropriate struct class based on the type name.
|
|
62
|
+
Unknown struct types are read as property lists.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
reader: The binary reader positioned at the struct data.
|
|
66
|
+
struct_type: The struct type name (e.g., "Vector", "Color").
|
|
67
|
+
is_asa: True for ASA format, False for ASE.
|
|
68
|
+
has_index_prefix: True if struct data starts with an int32 array index
|
|
69
|
+
(common in ASA indexed struct properties after the first element).
|
|
70
|
+
name_table: Optional name table for world saves (version 6+).
|
|
71
|
+
worldsave_format: True for ASA WorldSave SQLite object format.
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
The parsed Struct object.
|
|
75
|
+
"""
|
|
76
|
+
# Skip the array index prefix if present (ASA indexed struct properties)
|
|
77
|
+
if has_index_prefix:
|
|
78
|
+
_array_index = reader.read_int32()
|
|
79
|
+
|
|
80
|
+
# Look up the struct type in the registry
|
|
81
|
+
struct_class = STRUCT_REGISTRY.get(struct_type)
|
|
82
|
+
|
|
83
|
+
if struct_class is not None:
|
|
84
|
+
# Native struct - use the class's read method
|
|
85
|
+
result = struct_class.read(reader, is_asa, worldsave_format=worldsave_format)
|
|
86
|
+
# Note: Unlike property lists, native structs do NOT have a trailing
|
|
87
|
+
# null byte - the StructProperty extra_byte is read before this function
|
|
88
|
+
# is called, and the struct data is exactly data_size bytes.
|
|
89
|
+
return result
|
|
90
|
+
else:
|
|
91
|
+
# Unknown struct type - read as property list
|
|
92
|
+
return StructPropertyList.read(
|
|
93
|
+
reader,
|
|
94
|
+
is_asa,
|
|
95
|
+
struct_type=struct_type,
|
|
96
|
+
name_table=name_table,
|
|
97
|
+
worldsave_format=worldsave_format,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def read_struct_for_array(
|
|
102
|
+
reader: BinaryReader,
|
|
103
|
+
array_name: str,
|
|
104
|
+
is_asa: bool = False,
|
|
105
|
+
name_table: list[str] | None = None,
|
|
106
|
+
) -> Struct:
|
|
107
|
+
"""
|
|
108
|
+
Read a struct element from a struct array.
|
|
109
|
+
|
|
110
|
+
Uses the array name to determine the struct type if possible.
|
|
111
|
+
For unknown array names, reads as property list.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
reader: The binary reader positioned at the struct data.
|
|
115
|
+
array_name: The name of the array property.
|
|
116
|
+
is_asa: True for ASA format, False for ASE.
|
|
117
|
+
name_table: Optional name table for world saves (version 6+).
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
The parsed Struct object.
|
|
121
|
+
"""
|
|
122
|
+
# Try to map array name to struct type
|
|
123
|
+
struct_type = ARRAY_NAME_TO_STRUCT_TYPE.get(array_name)
|
|
124
|
+
|
|
125
|
+
if struct_type:
|
|
126
|
+
# Known array type
|
|
127
|
+
return read_struct(reader, struct_type, is_asa, name_table=name_table)
|
|
128
|
+
else:
|
|
129
|
+
# Unknown array - read as property list
|
|
130
|
+
return StructPropertyList.read(reader, is_asa, struct_type="PropertyList", name_table=name_table)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def is_native_struct(struct_type: str) -> bool:
|
|
134
|
+
"""Check if a struct type is a known native struct."""
|
|
135
|
+
return struct_type in STRUCT_REGISTRY
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def get_array_struct_type(array_name: str) -> str | None:
|
|
139
|
+
"""Get the struct type for a named array, if known."""
|
|
140
|
+
return ARRAY_NAME_TO_STRUCT_TYPE.get(array_name)
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Vector and Rotation Structs.
|
|
3
|
+
|
|
4
|
+
Geometric structs used for positions, rotations, and quaternions.
|
|
5
|
+
Note: ASE uses Float (4 bytes), ASA uses Double (8 bytes) for vectors.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import typing as t
|
|
11
|
+
from dataclasses import dataclass
|
|
12
|
+
|
|
13
|
+
from .base import NativeStruct
|
|
14
|
+
|
|
15
|
+
if t.TYPE_CHECKING:
|
|
16
|
+
from ..common.binary_reader import BinaryReader
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class Vector(NativeStruct):
|
|
21
|
+
"""
|
|
22
|
+
3D Vector (x, y, z).
|
|
23
|
+
|
|
24
|
+
ASE: 3 x Float (12 bytes)
|
|
25
|
+
ASA: 3 x Double (24 bytes)
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
x: float = 0.0
|
|
29
|
+
y: float = 0.0
|
|
30
|
+
z: float = 0.0
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def struct_type(self) -> str:
|
|
34
|
+
return "Vector"
|
|
35
|
+
|
|
36
|
+
def to_dict(self) -> dict[str, float]:
|
|
37
|
+
return {"x": self.x, "y": self.y, "z": self.z}
|
|
38
|
+
|
|
39
|
+
@classmethod
|
|
40
|
+
def read(cls, reader: BinaryReader, is_asa: bool = False, **kwargs: t.Any) -> Vector:
|
|
41
|
+
"""Read a Vector from the archive."""
|
|
42
|
+
if is_asa:
|
|
43
|
+
return cls(
|
|
44
|
+
x=reader.read_double(),
|
|
45
|
+
y=reader.read_double(),
|
|
46
|
+
z=reader.read_double(),
|
|
47
|
+
)
|
|
48
|
+
else:
|
|
49
|
+
return cls(
|
|
50
|
+
x=reader.read_float(),
|
|
51
|
+
y=reader.read_float(),
|
|
52
|
+
z=reader.read_float(),
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@dataclass
|
|
57
|
+
class Vector2D(NativeStruct):
|
|
58
|
+
"""
|
|
59
|
+
2D Vector (x, y).
|
|
60
|
+
|
|
61
|
+
ASE: 2 x Float (8 bytes)
|
|
62
|
+
ASA: 2 x Double (16 bytes)
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
x: float = 0.0
|
|
66
|
+
y: float = 0.0
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def struct_type(self) -> str:
|
|
70
|
+
return "Vector2D"
|
|
71
|
+
|
|
72
|
+
def to_dict(self) -> dict[str, float]:
|
|
73
|
+
return {"x": self.x, "y": self.y}
|
|
74
|
+
|
|
75
|
+
@classmethod
|
|
76
|
+
def read(cls, reader: BinaryReader, is_asa: bool = False, **kwargs: t.Any) -> Vector2D:
|
|
77
|
+
"""Read a Vector2D from the archive."""
|
|
78
|
+
if is_asa:
|
|
79
|
+
return cls(
|
|
80
|
+
x=reader.read_double(),
|
|
81
|
+
y=reader.read_double(),
|
|
82
|
+
)
|
|
83
|
+
else:
|
|
84
|
+
return cls(
|
|
85
|
+
x=reader.read_float(),
|
|
86
|
+
y=reader.read_float(),
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@dataclass
|
|
91
|
+
class Rotator(NativeStruct):
|
|
92
|
+
"""
|
|
93
|
+
Rotation angles (pitch, yaw, roll).
|
|
94
|
+
|
|
95
|
+
ASE: 3 x Float (12 bytes)
|
|
96
|
+
ASA: 3 x Double (24 bytes)
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
pitch: float = 0.0
|
|
100
|
+
yaw: float = 0.0
|
|
101
|
+
roll: float = 0.0
|
|
102
|
+
|
|
103
|
+
@property
|
|
104
|
+
def struct_type(self) -> str:
|
|
105
|
+
return "Rotator"
|
|
106
|
+
|
|
107
|
+
def to_dict(self) -> dict[str, float]:
|
|
108
|
+
return {"pitch": self.pitch, "yaw": self.yaw, "roll": self.roll}
|
|
109
|
+
|
|
110
|
+
@classmethod
|
|
111
|
+
def read(cls, reader: BinaryReader, is_asa: bool = False, **kwargs: t.Any) -> Rotator:
|
|
112
|
+
"""Read a Rotator from the archive."""
|
|
113
|
+
if is_asa:
|
|
114
|
+
return cls(
|
|
115
|
+
pitch=reader.read_double(),
|
|
116
|
+
yaw=reader.read_double(),
|
|
117
|
+
roll=reader.read_double(),
|
|
118
|
+
)
|
|
119
|
+
else:
|
|
120
|
+
return cls(
|
|
121
|
+
pitch=reader.read_float(),
|
|
122
|
+
yaw=reader.read_float(),
|
|
123
|
+
roll=reader.read_float(),
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@dataclass
|
|
128
|
+
class Quat(NativeStruct):
|
|
129
|
+
"""
|
|
130
|
+
Quaternion rotation (x, y, z, w).
|
|
131
|
+
|
|
132
|
+
ASE: 4 x Float (16 bytes)
|
|
133
|
+
ASA: 4 x Float (16 bytes) for non-worldsave, 4 x Double (32 bytes) for worldsave
|
|
134
|
+
"""
|
|
135
|
+
|
|
136
|
+
x: float = 0.0
|
|
137
|
+
y: float = 0.0
|
|
138
|
+
z: float = 0.0
|
|
139
|
+
w: float = 0.0
|
|
140
|
+
|
|
141
|
+
@property
|
|
142
|
+
def struct_type(self) -> str:
|
|
143
|
+
return "Quat"
|
|
144
|
+
|
|
145
|
+
def to_dict(self) -> dict[str, float]:
|
|
146
|
+
return {"x": self.x, "y": self.y, "z": self.z, "w": self.w}
|
|
147
|
+
|
|
148
|
+
@classmethod
|
|
149
|
+
def read(cls, reader: BinaryReader, is_asa: bool = False, worldsave_format: bool = False, **kwargs: t.Any) -> Quat:
|
|
150
|
+
"""Read a Quat from the archive."""
|
|
151
|
+
if worldsave_format:
|
|
152
|
+
# WorldSave uses doubles for quaternions
|
|
153
|
+
return cls(
|
|
154
|
+
x=reader.read_double(),
|
|
155
|
+
y=reader.read_double(),
|
|
156
|
+
z=reader.read_double(),
|
|
157
|
+
w=reader.read_double(),
|
|
158
|
+
)
|
|
159
|
+
else:
|
|
160
|
+
return cls(
|
|
161
|
+
x=reader.read_float(),
|
|
162
|
+
y=reader.read_float(),
|
|
163
|
+
z=reader.read_float(),
|
|
164
|
+
w=reader.read_float(),
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
@dataclass
|
|
169
|
+
class IntPoint(NativeStruct):
|
|
170
|
+
"""
|
|
171
|
+
2D Integer point (x, y).
|
|
172
|
+
|
|
173
|
+
Always 2 x Int32 (8 bytes).
|
|
174
|
+
"""
|
|
175
|
+
|
|
176
|
+
x: int = 0
|
|
177
|
+
y: int = 0
|
|
178
|
+
|
|
179
|
+
@property
|
|
180
|
+
def struct_type(self) -> str:
|
|
181
|
+
return "IntPoint"
|
|
182
|
+
|
|
183
|
+
def to_dict(self) -> dict[str, int]:
|
|
184
|
+
return {"x": self.x, "y": self.y}
|
|
185
|
+
|
|
186
|
+
@classmethod
|
|
187
|
+
def read(cls, reader: BinaryReader, is_asa: bool = False, **kwargs: t.Any) -> IntPoint:
|
|
188
|
+
"""Read an IntPoint from the archive."""
|
|
189
|
+
return cls(
|
|
190
|
+
x=reader.read_int32(),
|
|
191
|
+
y=reader.read_int32(),
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
@dataclass
|
|
196
|
+
class IntVector(NativeStruct):
|
|
197
|
+
"""
|
|
198
|
+
3D Integer vector (x, y, z).
|
|
199
|
+
|
|
200
|
+
Always 3 x Int32 (12 bytes).
|
|
201
|
+
"""
|
|
202
|
+
|
|
203
|
+
x: int = 0
|
|
204
|
+
y: int = 0
|
|
205
|
+
z: int = 0
|
|
206
|
+
|
|
207
|
+
@property
|
|
208
|
+
def struct_type(self) -> str:
|
|
209
|
+
return "IntVector"
|
|
210
|
+
|
|
211
|
+
def to_dict(self) -> dict[str, int]:
|
|
212
|
+
return {"x": self.x, "y": self.y, "z": self.z}
|
|
213
|
+
|
|
214
|
+
@classmethod
|
|
215
|
+
def read(cls, reader: BinaryReader, is_asa: bool = False, **kwargs: t.Any) -> IntVector:
|
|
216
|
+
"""Read an IntVector from the archive."""
|
|
217
|
+
return cls(
|
|
218
|
+
x=reader.read_int32(),
|
|
219
|
+
y=reader.read_int32(),
|
|
220
|
+
z=reader.read_int32(),
|
|
221
|
+
)
|