arkparser 0.1.8__tar.gz → 0.1.11__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.8 → arkparser-0.1.11}/PKG-INFO +1 -1
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/__init__.py +1 -1
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/export.py +99 -15
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/files/world_save.py +17 -21
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/game_objects/container.py +79 -13
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser.egg-info/PKG-INFO +1 -1
- {arkparser-0.1.8 → arkparser-0.1.11}/pyproject.toml +1 -1
- {arkparser-0.1.8 → arkparser-0.1.11}/LICENSE +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/README.md +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/common/__init__.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/common/binary_reader.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/common/exceptions.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/common/map_config.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/common/normalization.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/common/types.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/common/version_detection.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/data_models.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/files/__init__.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/files/base.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/files/cloud_inventory.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/files/profile.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/files/tribe.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/game_objects/__init__.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/game_objects/game_object.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/game_objects/location.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/models/__init__.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/models/character.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/models/creature.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/models/item.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/models/player.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/models/stats.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/models/structure.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/models/tribe.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/properties/__init__.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/properties/base.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/properties/byte_property.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/properties/compound.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/properties/primitives.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/properties/registry.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/structs/__init__.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/structs/base.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/structs/colors.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/structs/misc.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/structs/property_list.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/structs/registry.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser/structs/vectors.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser.egg-info/SOURCES.txt +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser.egg-info/dependency_links.txt +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser.egg-info/requires.txt +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/arkparser.egg-info/top_level.txt +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/setup.cfg +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/tests/test_binary_reader.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/tests/test_cloud_inventory.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/tests/test_data_models.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/tests/test_export.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/tests/test_game_objects.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/tests/test_models.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/tests/test_profile.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/tests/test_tribe.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/tests/test_version_detection.py +0 -0
- {arkparser-0.1.8 → arkparser-0.1.11}/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)):
|
|
@@ -500,9 +560,18 @@ def _get_worldsave_objects(save: t.Any, getter_name: str, legacy_attr: str) -> l
|
|
|
500
560
|
|
|
501
561
|
|
|
502
562
|
def _resolve_reference(ref: t.Any, lookup: dict[t.Any, t.Any]) -> t.Any:
|
|
503
|
-
"""Resolve an object reference
|
|
563
|
+
"""Resolve an object reference to a game object.
|
|
564
|
+
|
|
565
|
+
Handles three reference forms:
|
|
566
|
+
- int or str: direct lookup (ASE object IDs, GUID strings, name strings)
|
|
567
|
+
- (type_tag, value) tuple: array-property format where type_tag is "id",
|
|
568
|
+
"name", or "path" and value is the actual lookup key
|
|
569
|
+
"""
|
|
504
570
|
if ref is None:
|
|
505
571
|
return None
|
|
572
|
+
if isinstance(ref, tuple) and len(ref) == 2:
|
|
573
|
+
_, key = ref
|
|
574
|
+
return lookup.get(key)
|
|
506
575
|
return lookup.get(ref)
|
|
507
576
|
|
|
508
577
|
|
|
@@ -598,14 +667,29 @@ def _find_status_component(obj: t.Any, lookup: dict[t.Any, t.Any]) -> t.Any:
|
|
|
598
667
|
|
|
599
668
|
|
|
600
669
|
def _get_inventory_items(obj: t.Any, lookup: dict[t.Any, t.Any]) -> list[dict[str, t.Any]]:
|
|
601
|
-
"""Get inventory items for a creature.
|
|
670
|
+
"""Get inventory items for a game object (creature or structure).
|
|
671
|
+
|
|
672
|
+
Tries two strategies in order:
|
|
673
|
+
1. MyInventoryComponent property + reference lookup (works for ASE and some ASA objects).
|
|
674
|
+
2. Iterate obj.components to find the first component whose class_name contains
|
|
675
|
+
"Inventory" (fallback for ASA, where the property may be absent).
|
|
676
|
+
"""
|
|
602
677
|
items: list[dict[str, t.Any]] = []
|
|
603
678
|
|
|
604
|
-
|
|
679
|
+
inv_obj = None
|
|
680
|
+
|
|
681
|
+
# Strategy 1: property reference
|
|
605
682
|
if hasattr(obj, "get_property_value"):
|
|
606
683
|
inv_ref = obj.get_property_value("MyInventoryComponent", default=None)
|
|
607
|
-
|
|
608
|
-
|
|
684
|
+
if inv_ref is not None:
|
|
685
|
+
inv_obj = _resolve_reference(inv_ref, lookup)
|
|
686
|
+
|
|
687
|
+
# Strategy 2: component dict (ASA or when property is absent)
|
|
688
|
+
if inv_obj is None and hasattr(obj, "components"):
|
|
689
|
+
for comp in obj.components.values():
|
|
690
|
+
if "Inventory" in getattr(comp, "class_name", ""):
|
|
691
|
+
inv_obj = comp
|
|
692
|
+
break
|
|
609
693
|
|
|
610
694
|
if inv_obj is None:
|
|
611
695
|
return items
|
|
@@ -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
|
|
File without changes
|