arkparser 0.1.9__tar.gz → 0.1.12__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.1.9 → arkparser-0.1.12}/PKG-INFO +1 -1
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/__init__.py +1 -1
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/export.py +70 -10
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/files/tribe.py +23 -2
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/files/world_save.py +17 -21
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/game_objects/container.py +79 -13
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser.egg-info/PKG-INFO +1 -1
- {arkparser-0.1.9 → arkparser-0.1.12}/pyproject.toml +1 -1
- {arkparser-0.1.9 → arkparser-0.1.12}/LICENSE +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/README.md +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/common/__init__.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/common/binary_reader.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/common/exceptions.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/common/map_config.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/common/normalization.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/common/types.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/common/version_detection.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/data_models.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/files/__init__.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/files/base.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/files/cloud_inventory.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/files/profile.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/game_objects/__init__.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/game_objects/game_object.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/game_objects/location.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/models/__init__.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/models/character.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/models/creature.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/models/item.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/models/player.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/models/stats.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/models/structure.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/models/tribe.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/properties/__init__.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/properties/base.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/properties/byte_property.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/properties/compound.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/properties/primitives.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/properties/registry.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/structs/__init__.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/structs/base.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/structs/colors.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/structs/misc.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/structs/property_list.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/structs/registry.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser/structs/vectors.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser.egg-info/SOURCES.txt +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser.egg-info/dependency_links.txt +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser.egg-info/requires.txt +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/arkparser.egg-info/top_level.txt +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/setup.cfg +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/tests/test_binary_reader.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/tests/test_cloud_inventory.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/tests/test_data_models.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/tests/test_export.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/tests/test_game_objects.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/tests/test_models.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/tests/test_profile.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/tests/test_tribe.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/tests/test_version_detection.py +0 -0
- {arkparser-0.1.9 → arkparser-0.1.12}/tests/test_world_save.py +0 -0
|
@@ -351,27 +351,84 @@ def export_tribe_logs(
|
|
|
351
351
|
|
|
352
352
|
|
|
353
353
|
# -------------------------------------------------------------------------
|
|
354
|
-
# Map Structures (ASV_MapStructures):
|
|
354
|
+
# Map Structures (ASV_MapStructures): untribed environmental map elements
|
|
355
355
|
# -------------------------------------------------------------------------
|
|
356
356
|
|
|
357
|
+
# Canonical match rules. Mirrors C# ContentContainer.cs:846.
|
|
358
|
+
# (pattern, label, match_kind) where match_kind is "startswith" or "contains".
|
|
359
|
+
# Order matters: first match wins.
|
|
360
|
+
_MAP_STRUCT_RULES: tuple[tuple[str, str, str], ...] = (
|
|
361
|
+
("TributeTerminal_", "ASV_Terminal", "startswith"),
|
|
362
|
+
("CityTerminal_", "ASV_Terminal", "contains"),
|
|
363
|
+
("PowerNodeCharge", "ASV_ChargeNode", "startswith"),
|
|
364
|
+
("BeaverDam_C", "ASV_BeaverDam", "startswith"),
|
|
365
|
+
("DeinonychusNest_C", "ASV_DeinoNest", "startswith"),
|
|
366
|
+
("RockDrakeNest_C", "ASV_DrakeNest", "startswith"),
|
|
367
|
+
("CherufeNest_C", "ASV_MagmaNest", "startswith"),
|
|
368
|
+
("WyvernNest_", "ASV_WyvernNest", "startswith"),
|
|
369
|
+
("OilVein_", "ASV_OilVein", "startswith"),
|
|
370
|
+
("WaterVein_", "ASV_WaterVein", "startswith"),
|
|
371
|
+
("GasVein_", "ASV_GasVein", "startswith"),
|
|
372
|
+
("ArtifactCrate_", "ASV_Artifact", "startswith"),
|
|
373
|
+
# PlantSpeciesZ_Wild_C is in the C# prefix list but legacy doesn't actually
|
|
374
|
+
# emit them — only player-grown plants are surfaced.
|
|
375
|
+
("Structure_PlantSpeciesZ_PlayerGrown", "ASV_PlantSpeciesZ", "startswith"),
|
|
376
|
+
("BeeHive_C", "ASV_BeeHive", "startswith"),
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
def _asv_map_struct_label(class_name: str) -> str | None:
|
|
381
|
+
for pattern, label, kind in _MAP_STRUCT_RULES:
|
|
382
|
+
if kind == "startswith":
|
|
383
|
+
if class_name.startswith(pattern):
|
|
384
|
+
return label
|
|
385
|
+
elif pattern in class_name:
|
|
386
|
+
return label
|
|
387
|
+
return None
|
|
388
|
+
|
|
357
389
|
|
|
358
390
|
def export_map_structures(
|
|
359
391
|
save: t.Any,
|
|
360
392
|
map_config: MapConfig | None = None,
|
|
361
393
|
) -> list[dict[str, t.Any]]:
|
|
362
394
|
"""
|
|
363
|
-
Export
|
|
364
|
-
|
|
365
|
-
Same as ASV_Structures but intended for map visualisation with GPS coords.
|
|
395
|
+
Export environmental map elements in ASV_MapStructures format.
|
|
366
396
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
397
|
+
Mirrors C# ContentContainer.cs:846 filter:
|
|
398
|
+
* has a Location
|
|
399
|
+
* TargetingTeam is null
|
|
400
|
+
* class_name starts with one of the canonical map-element prefixes.
|
|
370
401
|
|
|
371
|
-
|
|
372
|
-
List of structure dictionaries with GPS coordinates.
|
|
402
|
+
Does NOT include player structures.
|
|
373
403
|
"""
|
|
374
|
-
|
|
404
|
+
assert hasattr(save, "objects"), "save must expose .objects"
|
|
405
|
+
objects = save.objects if hasattr(save, "objects") else {}
|
|
406
|
+
obj_lookup = _build_lookup(objects)
|
|
407
|
+
all_objs = list(objects.values()) if isinstance(objects, dict) else list(objects)
|
|
408
|
+
|
|
409
|
+
results: list[dict[str, t.Any]] = []
|
|
410
|
+
bound = len(all_objs) + 1
|
|
411
|
+
for i, obj in enumerate(all_objs):
|
|
412
|
+
assert i < bound
|
|
413
|
+
cn = getattr(obj, "class_name", "") or ""
|
|
414
|
+
label = _asv_map_struct_label(cn)
|
|
415
|
+
if label is None:
|
|
416
|
+
continue
|
|
417
|
+
loc = getattr(obj, "location", None)
|
|
418
|
+
if loc is None:
|
|
419
|
+
continue
|
|
420
|
+
if obj.get_property_value("TargetingTeam") is not None:
|
|
421
|
+
continue
|
|
422
|
+
ccc = f"{loc.x} {loc.y} {loc.z}"
|
|
423
|
+
data: dict[str, t.Any] = {"struct": label, "ccc": ccc}
|
|
424
|
+
if map_config is not None:
|
|
425
|
+
data["lat"] = map_config.ue_to_lat(loc.y)
|
|
426
|
+
data["lon"] = map_config.ue_to_lon(loc.x)
|
|
427
|
+
data["inventory"] = _get_inventory_items(obj, obj_lookup)
|
|
428
|
+
results.append(data)
|
|
429
|
+
|
|
430
|
+
assert isinstance(results, list)
|
|
431
|
+
return results
|
|
375
432
|
|
|
376
433
|
|
|
377
434
|
# -------------------------------------------------------------------------
|
|
@@ -478,6 +535,9 @@ def _get_collection(source: t.Any, attr_name: str, parser_type: type[t.Any]) ->
|
|
|
478
535
|
"""Normalize a parser collection or single parser instance to a list."""
|
|
479
536
|
if isinstance(source, parser_type):
|
|
480
537
|
return [source]
|
|
538
|
+
# source may already be a list of parser objects
|
|
539
|
+
if isinstance(source, (list, tuple)):
|
|
540
|
+
return list(source)
|
|
481
541
|
|
|
482
542
|
values = getattr(source, attr_name, None)
|
|
483
543
|
if isinstance(values, (list, tuple)):
|
|
@@ -115,8 +115,29 @@ class Tribe(ArkFile):
|
|
|
115
115
|
|
|
116
116
|
@property
|
|
117
117
|
def alliance_ids(self) -> list[int]:
|
|
118
|
-
"""Get IDs of allied tribes.
|
|
119
|
-
|
|
118
|
+
"""Get IDs of allied tribes.
|
|
119
|
+
|
|
120
|
+
TribeAlliances normally serializes as a list of AllianceData structs
|
|
121
|
+
(dicts with ``AllianceID``, ``AllianceName``, ``MembersTribeIDs``,
|
|
122
|
+
etc.). Older / Prim+ / corrupted saves sometimes emit a flat list of
|
|
123
|
+
ints instead. Accept both forms and skip entries we cannot coerce.
|
|
124
|
+
"""
|
|
125
|
+
out: list[int] = []
|
|
126
|
+
for entry in normalize_indexed_list(self._tribe_data.get("TribeAlliances")):
|
|
127
|
+
if isinstance(entry, dict):
|
|
128
|
+
aid = entry.get("AllianceID")
|
|
129
|
+
if aid is None:
|
|
130
|
+
continue
|
|
131
|
+
try:
|
|
132
|
+
out.append(int(aid))
|
|
133
|
+
except (TypeError, ValueError):
|
|
134
|
+
continue
|
|
135
|
+
else:
|
|
136
|
+
try:
|
|
137
|
+
out.append(int(entry))
|
|
138
|
+
except (TypeError, ValueError):
|
|
139
|
+
continue
|
|
140
|
+
return out
|
|
120
141
|
|
|
121
142
|
@property
|
|
122
143
|
def government_type(self) -> int:
|
|
@@ -217,31 +217,23 @@ class WorldSave:
|
|
|
217
217
|
"""Return all objects whose ``class_name`` contains *class_name*."""
|
|
218
218
|
return self.container.find_by_class_pattern(class_name)
|
|
219
219
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
"TamedOnServerName",
|
|
226
|
-
"UploadedFromServerName",
|
|
227
|
-
"ImprinterName",
|
|
228
|
-
"ImprinterPlayerDataID",
|
|
229
|
-
)
|
|
220
|
+
# TargetingTeam threshold: the C# reference (TeamType.cs) uses 50_000 as the
|
|
221
|
+
# boundary between non-player (wild/AI) and player-owned teams.
|
|
222
|
+
_PLAYER_TEAM_THRESHOLD: t.ClassVar[int] = 50_000
|
|
223
|
+
# Unclaimed babies use 2_000_000_000 as a sentinel; still tamed.
|
|
224
|
+
_BREEDING_SENTINEL: t.ClassVar[int] = 2_000_000_000
|
|
230
225
|
|
|
231
226
|
def _is_tamed_creature(self, obj: GameObject) -> bool:
|
|
232
|
-
"""Return ``True`` if a creature
|
|
233
|
-
taming_team = obj.get_property_value("TamingTeamID")
|
|
234
|
-
if isinstance(taming_team, (int, float)) and taming_team > 0:
|
|
235
|
-
return True
|
|
227
|
+
"""Return ``True`` if a creature is player-owned.
|
|
236
228
|
|
|
229
|
+
Mirrors C# GameObjectExtensions.IsTamed: targeting_team >= 50_000.
|
|
230
|
+
The breeding sentinel (2_000_000_000) is also considered tamed.
|
|
231
|
+
"""
|
|
237
232
|
targeting_team = obj.get_property_value("TargetingTeam")
|
|
238
|
-
if isinstance(targeting_team, (int, float))
|
|
239
|
-
return
|
|
240
|
-
|
|
241
|
-
return
|
|
242
|
-
obj.get_property_value(prop_name) not in (None, "", 0, 0.0, False)
|
|
243
|
-
for prop_name in self._TAMED_MARKER_PROPERTIES
|
|
244
|
-
)
|
|
233
|
+
if not isinstance(targeting_team, (int, float)):
|
|
234
|
+
return False
|
|
235
|
+
team = int(targeting_team)
|
|
236
|
+
return team >= self._PLAYER_TEAM_THRESHOLD
|
|
245
237
|
|
|
246
238
|
def get_creatures(self) -> list[GameObject]:
|
|
247
239
|
"""Return all creature objects (tamed **and** wild)."""
|
|
@@ -283,6 +275,10 @@ class WorldSave:
|
|
|
283
275
|
"""Return engine-placed resource / vein / node objects."""
|
|
284
276
|
return self.container.get_map_resources()
|
|
285
277
|
|
|
278
|
+
def get_nests(self) -> list[GameObject]:
|
|
279
|
+
"""Return creature nest objects (wyvern, drake, etc.)."""
|
|
280
|
+
return self.container.get_nests()
|
|
281
|
+
|
|
286
282
|
# ------------------------------------------------------------------
|
|
287
283
|
# Properties
|
|
288
284
|
# ------------------------------------------------------------------
|
|
@@ -121,14 +121,35 @@ class GameObjectContainer:
|
|
|
121
121
|
"DinoDropInventory",
|
|
122
122
|
)
|
|
123
123
|
|
|
124
|
+
# Vehicles that carry DinoID1/bServerInitializedDino but are not creatures.
|
|
125
|
+
# Source: C# GameObjectExtensions.IsCreature (SavegameToolkitAdditions).
|
|
126
|
+
_VEHICLE_CLASS_NAMES: t.ClassVar[frozenset[str]] = frozenset({
|
|
127
|
+
"MotorRaft_BP_C",
|
|
128
|
+
"Raft_BP_C",
|
|
129
|
+
"TekHoverSkiff_Character_BP_C",
|
|
130
|
+
"CogRaft_BP_C",
|
|
131
|
+
"DingyRaft_BP_C",
|
|
132
|
+
"LongshipRaft_BP_C",
|
|
133
|
+
"SRaft_BP_C",
|
|
134
|
+
})
|
|
135
|
+
|
|
124
136
|
def _is_creature_object(self, obj: GameObject) -> bool:
|
|
125
|
-
"""Return ``True`` for top-level creature actors only.
|
|
126
|
-
class_name = obj.class_name
|
|
127
|
-
if not class_name or obj.is_item:
|
|
128
|
-
return False
|
|
137
|
+
"""Return ``True`` for top-level creature actors only.
|
|
129
138
|
|
|
130
|
-
|
|
131
|
-
|
|
139
|
+
Primary check mirrors C# GameObjectExtensions.IsCreature: presence of
|
|
140
|
+
``bServerInitializedDino`` AND not a vehicle. Falls back to class name
|
|
141
|
+
patterns for unit tests and edge cases where properties are absent.
|
|
142
|
+
"""
|
|
143
|
+
if obj.is_item:
|
|
144
|
+
return False
|
|
145
|
+
if obj.class_name in self._VEHICLE_CLASS_NAMES:
|
|
146
|
+
return False
|
|
147
|
+
if obj.get_property_value("bServerInitializedDino") is not None:
|
|
148
|
+
return True
|
|
149
|
+
# Class-name fallback for minimal test objects or pre-property-load pass.
|
|
150
|
+
cn = obj.class_name
|
|
151
|
+
is_character = "_Character_" in cn or "DinoCharacter" in cn
|
|
152
|
+
return is_character and "StatusComponent" not in cn and "Inventory" not in cn
|
|
132
153
|
|
|
133
154
|
def get_creatures(self) -> list[GameObject]:
|
|
134
155
|
"""Get all creature objects (tamed and wild)."""
|
|
@@ -138,8 +159,48 @@ class GameObjectContainer:
|
|
|
138
159
|
"""Get all item objects."""
|
|
139
160
|
return [obj for obj in self.objects if obj.is_item]
|
|
140
161
|
|
|
162
|
+
# Class-name substrings for environmental map elements that should NOT
|
|
163
|
+
# appear in get_structures() (they go through get_terminals/get_nests/etc).
|
|
164
|
+
_MAP_ELEMENT_PATTERNS: t.ClassVar[tuple[str, ...]] = (
|
|
165
|
+
"TributeTerminal",
|
|
166
|
+
"CityTerminal",
|
|
167
|
+
"ArtifactCrate",
|
|
168
|
+
"OilVein",
|
|
169
|
+
"WaterVein",
|
|
170
|
+
"GasVein",
|
|
171
|
+
"ChargeNode",
|
|
172
|
+
"ElementVein",
|
|
173
|
+
"BeaverDam",
|
|
174
|
+
"Nest",
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
def _is_structure(self, obj: GameObject) -> bool:
|
|
178
|
+
"""Return ``True`` if the object is a structure per the C# IsStructure rule.
|
|
179
|
+
|
|
180
|
+
Mirrors C# GameObjectExtensions.IsStructure: has OwnerName OR
|
|
181
|
+
bHasResetDecayTime OR is one of the known vehicle/special class names;
|
|
182
|
+
excludes the Structure_LoadoutDummy_Hotbar_C, cryo-pinned objects,
|
|
183
|
+
DeathItemCache_ entries, and environmental map elements (which belong
|
|
184
|
+
in map_structures, not player structures).
|
|
185
|
+
"""
|
|
186
|
+
cn = obj.class_name
|
|
187
|
+
if cn == "Structure_LoadoutDummy_Hotbar_C":
|
|
188
|
+
return False
|
|
189
|
+
if cn.startswith("DeathItemCache_"):
|
|
190
|
+
return False
|
|
191
|
+
if obj.get_property_value("IsInCryo"):
|
|
192
|
+
return False
|
|
193
|
+
# CherufeNest_C is explicitly a structure per the C# rule.
|
|
194
|
+
if cn != "CherufeNest_C" and any(p in cn for p in self._MAP_ELEMENT_PATTERNS):
|
|
195
|
+
return False
|
|
196
|
+
if obj.get_property_value("OwnerName") is not None:
|
|
197
|
+
return True
|
|
198
|
+
if obj.get_property_value("bHasResetDecayTime") is not None:
|
|
199
|
+
return True
|
|
200
|
+
return cn == "CherufeNest_C" or cn in self._VEHICLE_CLASS_NAMES
|
|
201
|
+
|
|
141
202
|
def get_structures(self) -> list[GameObject]:
|
|
142
|
-
"""Get all
|
|
203
|
+
"""Get all placed structures.
|
|
143
204
|
|
|
144
205
|
ASE saves include the same actor in both the main level and sub-levels,
|
|
145
206
|
producing duplicate entries with identical Names[0]. Deduplicating by
|
|
@@ -149,12 +210,7 @@ class GameObjectContainer:
|
|
|
149
210
|
seen_names: set[str] = set()
|
|
150
211
|
results: list[GameObject] = []
|
|
151
212
|
for obj in self.objects:
|
|
152
|
-
|
|
153
|
-
if obj.get_property_value("TargetingTeam") is None:
|
|
154
|
-
continue
|
|
155
|
-
if obj.get_property_value("DinoID1") is not None:
|
|
156
|
-
continue
|
|
157
|
-
if any(pat in cn for pat in self._NON_STRUCTURE_PATTERNS):
|
|
213
|
+
if not self._is_structure(obj):
|
|
158
214
|
continue
|
|
159
215
|
name = obj.primary_name
|
|
160
216
|
if name is not None:
|
|
@@ -226,6 +282,16 @@ class GameObjectContainer:
|
|
|
226
282
|
and not obj.is_item
|
|
227
283
|
]
|
|
228
284
|
|
|
285
|
+
def get_nests(self) -> list[GameObject]:
|
|
286
|
+
"""Get creature nest objects (wyvern, drake, etc.). Inventory excluded."""
|
|
287
|
+
return [
|
|
288
|
+
obj
|
|
289
|
+
for obj in self.objects
|
|
290
|
+
if "Nest" in obj.class_name
|
|
291
|
+
and "Inventory" not in obj.class_name
|
|
292
|
+
and not obj.is_item
|
|
293
|
+
]
|
|
294
|
+
|
|
229
295
|
def get_players(self) -> list[GameObject]:
|
|
230
296
|
"""Get all player data objects."""
|
|
231
297
|
return self.get_by_class("PrimalPlayerData") + self.find_by_class_pattern("PlayerPawnTest")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|