arkparse 0.4.4__tar.gz → 0.5.1__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.
- {arkparse-0.4.4 → arkparse-0.5.1}/.gitignore +5 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/PKG-INFO +38 -5
- {arkparse-0.4.4 → arkparse-0.5.1}/README.md +35 -4
- {arkparse-0.4.4 → arkparse-0.5.1}/pyproject.toml +4 -1
- arkparse-0.5.1/src/arkparse/__init__.py +3 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/api/base_api.py +2 -2
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/api/dino_api.py +159 -76
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/api/equipment_api.py +7 -4
- arkparse-0.5.1/src/arkparse/api/general_api.py +106 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/api/stackable_api.py +2 -2
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/api/structure_api.py +104 -33
- arkparse-0.5.1/src/arkparse/assets/templates/trait/trait +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/classes/dinos.py +9 -3
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/classes/equipment.py +4 -2
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/ftp/ark_ftp_client.py +57 -2
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/logging/ark_save_logger.py +109 -28
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/ark_game_object.py +13 -4
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/bases/base.py +5 -1
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/cryopods/cryopod.py +3 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/dinos/baby.py +9 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/dinos/dino.py +50 -2
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/dinos/stats.py +14 -2
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/dinos/tamed_dino.py +15 -3
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/equipment/__armor_defaults.py +40 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/equipment/__equipment.py +11 -1
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/equipment/__equipment_with_armor.py +4 -4
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/equipment/__equipment_with_durability.py +1 -1
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/equipment/weapon.py +1 -1
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/misc/__parsed_object_base.py +11 -2
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/misc/inventory.py +14 -10
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/structures/structure.py +7 -1
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/structures/structure_with_inventory.py +9 -1
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/_base_value_parser.py +60 -4
- arkparse-0.5.1/src/arkparse/parsing/_fast_shim.py +224 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/_legacy_parsing/ark_binary_parser.py +2 -2
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/ark_binary_parser.py +28 -4
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/ark_property.py +3 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/ark_property_container.py +63 -7
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/ark_value_type.py +5 -4
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/actor_transform.py +25 -17
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_custom_item_data.py +3 -4
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/player/ark_player.py +2 -1
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/saves/asa_save.py +23 -3
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/saves/save_connection.py +164 -50
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/saves/save_context.py +8 -1
- arkparse-0.4.4/src/arkparse/__init__.py +0 -3
- arkparse-0.4.4/src/arkparse/api/general_api.py +0 -56
- {arkparse-0.4.4 → arkparse-0.5.1}/LICENSE +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/api/__init__.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/api/json_api.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/api/player_api.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/api/rcon_api.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/ark_tribe.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/assets/ABERRATION.PNG +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/assets/LOST_COLONY.PNG +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/assets/RAGNAROK.PNG +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/assets/THE_ISLAND.PNG +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/assets/__init__.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/assets/heavy_inventory +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/assets/tamable_dinos.txt +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/assets/templates/equipment/armor +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/assets/templates/equipment/armor_bp +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/assets/templates/equipment/armor_bp_n.json +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/assets/templates/equipment/armor_n.json +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/assets/templates/equipment/saddle +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/assets/templates/equipment/saddle_bp +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/assets/templates/equipment/saddle_bp_n.json +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/assets/templates/equipment/saddle_n.json +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/assets/templates/equipment/shield +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/assets/templates/equipment/shield_bp +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/assets/templates/equipment/shield_bp_n.json +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/assets/templates/equipment/shield_n.json +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/assets/templates/equipment/weapon +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/assets/templates/equipment/weapon_bp +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/assets/templates/equipment/weapon_bp_n.json +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/assets/templates/equipment/weapon_n.json +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/assets/templates/inventory/with_item_n.json +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/assets/templates/stackable/stackable +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/assets/templates/stackable/stackable_n.json +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/assets/templates/trait/trait_n.json +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/classes/__init__.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/classes/consumables.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/classes/placed_structures.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/classes/player.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/classes/resources.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/classes/traits.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/enums/__init__.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/enums/ark_dino_trait.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/enums/ark_enum.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/enums/ark_equipment_stat.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/enums/ark_item_quality.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/enums/ark_map.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/enums/ark_stat.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/ftp/__init__.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/helpers/dino/is_wild_tamed.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/logging/__init__.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/cluster_data/ark_cluster_data.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/cluster_data/cluster_data_dino.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/cluster_data/cluster_data_item.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/dinos/__init__.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/dinos/dino_ai_controller.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/dinos/dino_id.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/dinos/pedigree.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/dinos/tamed_baby.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/equipment/__init__.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/equipment/armor.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/equipment/saddle.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/equipment/shield.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/misc/dino_owner.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/misc/inventory_item.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/misc/object_crafter.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/misc/object_owner.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/misc/trait.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/stackables/__init__.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/stackables/_stackable.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/stackables/ammo.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/stackables/resource.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/object_model/structures/__init__.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/__init__.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/_base_value_validator.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/_binary_reader_base.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/_byte_operator.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/_legacy_parsing/__init__.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/_legacy_parsing/_property_insertor.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/_legacy_parsing/_property_parser.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/_legacy_parsing/_property_replacer.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/_legacy_parsing/ark_property.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/_legacy_parsing/struct/__init__.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/_legacy_parsing/struct/ark_dino_ancestor_entry.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/_legacy_parsing/struct/ark_item_net_id.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/_legacy_parsing/struct/ark_my_persistent_buff_datas.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/_legacy_parsing/struct/ark_object_property.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/_legacy_parsing/struct/ark_struct_type.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/_legacy_parsing/struct/ark_tracked_actor_id_category_pair_with_bool.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/_legacy_parsing/struct/ark_unique_net_id_repl.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/_legacy_parsing/struct/ark_vector.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/_legacy_parsing/struct/ark_vector_bool_pair.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/_property_insertor.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/_property_parser.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/_property_replacer.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/ark_archive.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/ark_object.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/ark_set.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/array_property.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/game_object_reader_configuration.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/__init__.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_color.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_crafting_resource_requirement.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_dino_ancestor_entry.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_dino_order_id.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_gacha_resource_struct.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_gene_trait_struct.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_gigantoraptor_bonded_struct.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_int_point.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_item_craft_queue_entry.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_item_net_id.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_key_value_pair.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_linear_color.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_milestone_tree_level_and_index.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_my_persistent_buff_datas.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_object_property.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_painting_key_value.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_patrol_group_saved_data.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_player_death_reason.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_primal_saddle_structure.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_quat.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_rotator.py +2 -2
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_server_custom_folder.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_struct_type.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_tracked_actor_id_category_pair.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_tracked_actor_id_category_pair_with_bool.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_tribe_alliance.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_tribe_rank_group.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_unique_net_id_repl.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_vector.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/ark_vector_bool_pair.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/object_reference.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/parsing/struct/unknown_struct.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/player/ark_character_config.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/player/ark_character_stats.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/player/ark_persistent_buff_data.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/player/ark_tribute_item.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/saves/__init__.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/saves/header_location.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/utils/__init__.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/utils/heatmap_visualization.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/utils/import_file.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/utils/json_utils.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/utils/map_images.py +0 -0
- {arkparse-0.4.4 → arkparse-0.5.1}/src/arkparse/utils/tm_files.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: arkparse
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.1
|
|
4
4
|
Summary: A package to parse and modify ark save files
|
|
5
5
|
Project-URL: Homepage, https://github.com/VincentHenauGithub/ark-save-parser
|
|
6
6
|
Author-email: Vincent Henau <vincent.henau.github@gmail.com>
|
|
@@ -11,6 +11,8 @@ Requires-Dist: matplotlib>=3.10.3
|
|
|
11
11
|
Requires-Dist: numpy>=2.3.2
|
|
12
12
|
Requires-Dist: pandas>=2.3.1
|
|
13
13
|
Requires-Dist: rcon>=2.4.9
|
|
14
|
+
Provides-Extra: fast
|
|
15
|
+
Requires-Dist: arkparse-fast-core; extra == 'fast'
|
|
14
16
|
Description-Content-Type: text/markdown
|
|
15
17
|
|
|
16
18
|
# ArkParse: A Python Library for Reading and Modifying ARK Save Files
|
|
@@ -33,7 +35,6 @@ I mainly use this package for server management tasks. Some highlights include:
|
|
|
33
35
|
- Sending random stats of the server to the chat
|
|
34
36
|
- Monitoring player activity like when people log off and on and such
|
|
35
37
|
- Randomly spawning bases with random loot for my friends to raid; probably my favorite feature (and the most complicated)
|
|
36
|
-
If you're curious or want to explore the features yourself, you can find the project here: [ark-server-manager](https://github.com/VincentHenauGithub/ark-server-manager).
|
|
37
38
|
|
|
38
39
|
Hope you find it useful or inspiring or both! 😊
|
|
39
40
|
|
|
@@ -63,17 +64,49 @@ I just hope it's usefull for someone!
|
|
|
63
64
|
---
|
|
64
65
|
## Installation
|
|
65
66
|
|
|
67
|
+
### Standard Installation
|
|
68
|
+
|
|
66
69
|
Install via pip:
|
|
67
70
|
|
|
68
71
|
```bash
|
|
69
72
|
pip install arkparse
|
|
70
73
|
```
|
|
71
74
|
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
For faster parsing, install with the optional Rust accelerator (requires pre-built wheels to be available on PyPI):
|
|
76
|
+
|
|
77
|
+
Current available wheels: MacOS, Windows and Linux; Python 3.9, 3.10, 3.11, 3.12, 3.13, 3.14 (3.13t and 3.14t)
|
|
74
78
|
```bash
|
|
79
|
+
pip install arkparse[fast]
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Recommended python version: Free-Threaded Python (~40% speedup)
|
|
83
|
+
|
|
84
|
+
ArkParse supports Python 3.13+ free-threaded builds (no-GIL), which provides additional performance benefits through parallel workloads. In my benchmarks this provides over **40% increased performance**, so I would highly recommend it!
|
|
85
|
+
|
|
86
|
+
ArkParse automatically detects if you are using free-threaded Python and parallelizes intensive tasks accordingly — no code changes required on your end.
|
|
87
|
+
|
|
88
|
+
Since free-threaded python is experimental I would advise using a virtual environment.
|
|
89
|
+
|
|
90
|
+
### Development Installation
|
|
91
|
+
|
|
92
|
+
For local development, clone and install in editable mode:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
git clone https://github.com/VincentHenauGithub/ark-save-parser.git
|
|
96
|
+
cd ark-save-parser
|
|
75
97
|
pip install -e .
|
|
76
98
|
```
|
|
99
|
+
|
|
100
|
+
**Optional: Rust Accelerator (up to ~20% increased performance single threaded mode and ~5% in free threaded mode)**
|
|
101
|
+
|
|
102
|
+
The Rust accelerator is something I started and is still very much not finished, it currently provides some decent performance benefits but I would like to see this become a much larger benefit. I will update that package in the future.
|
|
103
|
+
|
|
104
|
+
Requires [Rust](https://rustup.rs/) and [maturin](https://www.maturin.rs/):
|
|
105
|
+
```bash
|
|
106
|
+
git clone https://github.com/VincentHenauGithub/arkparse-fast-core.git
|
|
107
|
+
cd arkparse-fast-core && pip install maturin && maturin develop --release
|
|
108
|
+
```
|
|
109
|
+
|
|
77
110
|
---
|
|
78
111
|
|
|
79
112
|
### 4. **Quickstart**
|
|
@@ -233,7 +266,7 @@ This project is licensed under the MIT License. See the [LICENSE](LICENSE) file
|
|
|
233
266
|
## Feedback & Support
|
|
234
267
|
|
|
235
268
|
- **Issues or Feature Requests**: Open an issue on the repo!
|
|
236
|
-
- **Help**: If you need help for something specific, you can always
|
|
269
|
+
- **Help**: If you need help for something specific, you can always message me, I will try to help you out
|
|
237
270
|
|
|
238
271
|
## Donation
|
|
239
272
|
|
|
@@ -18,7 +18,6 @@ I mainly use this package for server management tasks. Some highlights include:
|
|
|
18
18
|
- Sending random stats of the server to the chat
|
|
19
19
|
- Monitoring player activity like when people log off and on and such
|
|
20
20
|
- Randomly spawning bases with random loot for my friends to raid; probably my favorite feature (and the most complicated)
|
|
21
|
-
If you're curious or want to explore the features yourself, you can find the project here: [ark-server-manager](https://github.com/VincentHenauGithub/ark-server-manager).
|
|
22
21
|
|
|
23
22
|
Hope you find it useful or inspiring or both! 😊
|
|
24
23
|
|
|
@@ -48,17 +47,49 @@ I just hope it's usefull for someone!
|
|
|
48
47
|
---
|
|
49
48
|
## Installation
|
|
50
49
|
|
|
50
|
+
### Standard Installation
|
|
51
|
+
|
|
51
52
|
Install via pip:
|
|
52
53
|
|
|
53
54
|
```bash
|
|
54
55
|
pip install arkparse
|
|
55
56
|
```
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
For faster parsing, install with the optional Rust accelerator (requires pre-built wheels to be available on PyPI):
|
|
59
|
+
|
|
60
|
+
Current available wheels: MacOS, Windows and Linux; Python 3.9, 3.10, 3.11, 3.12, 3.13, 3.14 (3.13t and 3.14t)
|
|
59
61
|
```bash
|
|
62
|
+
pip install arkparse[fast]
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Recommended python version: Free-Threaded Python (~40% speedup)
|
|
66
|
+
|
|
67
|
+
ArkParse supports Python 3.13+ free-threaded builds (no-GIL), which provides additional performance benefits through parallel workloads. In my benchmarks this provides over **40% increased performance**, so I would highly recommend it!
|
|
68
|
+
|
|
69
|
+
ArkParse automatically detects if you are using free-threaded Python and parallelizes intensive tasks accordingly — no code changes required on your end.
|
|
70
|
+
|
|
71
|
+
Since free-threaded python is experimental I would advise using a virtual environment.
|
|
72
|
+
|
|
73
|
+
### Development Installation
|
|
74
|
+
|
|
75
|
+
For local development, clone and install in editable mode:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
git clone https://github.com/VincentHenauGithub/ark-save-parser.git
|
|
79
|
+
cd ark-save-parser
|
|
60
80
|
pip install -e .
|
|
61
81
|
```
|
|
82
|
+
|
|
83
|
+
**Optional: Rust Accelerator (up to ~20% increased performance single threaded mode and ~5% in free threaded mode)**
|
|
84
|
+
|
|
85
|
+
The Rust accelerator is something I started and is still very much not finished, it currently provides some decent performance benefits but I would like to see this become a much larger benefit. I will update that package in the future.
|
|
86
|
+
|
|
87
|
+
Requires [Rust](https://rustup.rs/) and [maturin](https://www.maturin.rs/):
|
|
88
|
+
```bash
|
|
89
|
+
git clone https://github.com/VincentHenauGithub/arkparse-fast-core.git
|
|
90
|
+
cd arkparse-fast-core && pip install maturin && maturin develop --release
|
|
91
|
+
```
|
|
92
|
+
|
|
62
93
|
---
|
|
63
94
|
|
|
64
95
|
### 4. **Quickstart**
|
|
@@ -218,7 +249,7 @@ This project is licensed under the MIT License. See the [LICENSE](LICENSE) file
|
|
|
218
249
|
## Feedback & Support
|
|
219
250
|
|
|
220
251
|
- **Issues or Feature Requests**: Open an issue on the repo!
|
|
221
|
-
- **Help**: If you need help for something specific, you can always
|
|
252
|
+
- **Help**: If you need help for something specific, you can always message me, I will try to help you out
|
|
222
253
|
|
|
223
254
|
## Donation
|
|
224
255
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "arkparse"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.5.1"
|
|
8
8
|
dependencies = [
|
|
9
9
|
"rcon>=2.4.9",
|
|
10
10
|
"numpy>=2.3.2",
|
|
@@ -22,6 +22,9 @@ classifiers = [
|
|
|
22
22
|
# Add additional classifiers as needed
|
|
23
23
|
]
|
|
24
24
|
|
|
25
|
+
[project.optional-dependencies]
|
|
26
|
+
fast = ["arkparse-fast-core"]
|
|
27
|
+
|
|
25
28
|
[project.urls]
|
|
26
29
|
Homepage = "https://github.com/VincentHenauGithub/ark-save-parser"
|
|
27
30
|
|
|
@@ -18,9 +18,9 @@ from arkparse.utils import ImportFile
|
|
|
18
18
|
from arkparse.logging import ArkSaveLogger
|
|
19
19
|
|
|
20
20
|
class BaseApi(StructureApi):
|
|
21
|
-
def __init__(self, save, map: ArkMap):
|
|
21
|
+
def __init__(self, save, map: ArkMap = None):
|
|
22
22
|
super().__init__(save)
|
|
23
|
-
self.map = map
|
|
23
|
+
self.map = map if map is not None else self.save.map
|
|
24
24
|
|
|
25
25
|
def __get_closest_to(self, structures: Dict[UUID, Structure], coords: MapCoords):
|
|
26
26
|
closest = None
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
from typing import Dict, List, Optional
|
|
1
|
+
from typing import Dict, List, Optional, Tuple
|
|
2
2
|
from uuid import UUID, uuid4
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
import os
|
|
5
|
+
import sys
|
|
6
|
+
import threading
|
|
7
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
5
8
|
|
|
6
9
|
from arkparse.object_model.cryopods.cryopod import Cryopod
|
|
7
10
|
from arkparse.object_model.dinos.dino import Dino, DinoStats, DinoId
|
|
@@ -23,13 +26,26 @@ from arkparse.classes.dinos import Dinos
|
|
|
23
26
|
from arkparse.object_model.misc.inventory import Inventory
|
|
24
27
|
from arkparse.object_model.misc.inventory_item import InventoryItem
|
|
25
28
|
from arkparse.object_model.dinos.pedigree import Pedigree
|
|
29
|
+
from arkparse.logging.ark_save_logger import mark_as_worker_thread
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _is_parallel_enabled() -> bool:
|
|
33
|
+
"""Check if parallel parsing should be enabled (GIL is disabled)."""
|
|
34
|
+
if hasattr(sys, '_is_gil_enabled'):
|
|
35
|
+
return not sys._is_gil_enabled()
|
|
36
|
+
return False
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
_PARALLEL_ENABLED = _is_parallel_enabled()
|
|
40
|
+
|
|
26
41
|
|
|
27
42
|
class DinoApi:
|
|
28
43
|
_DEFAULT_CONFIG = GameObjectReaderConfiguration(
|
|
29
44
|
blueprint_name_filter=lambda name: \
|
|
30
45
|
name is not None and \
|
|
31
|
-
(("Dinos/" in name and "_Character_" in name) or \
|
|
32
|
-
("
|
|
46
|
+
(((("/Creatures/" in name) or ("/Dinos/" in name) or ("/SDinoVariants/" in name)) and "_Character_" in name) or \
|
|
47
|
+
("DinoCharacterStatusComponent" in name) or \
|
|
48
|
+
("PrimalItem_WeaponEmptyCryopod" in name or "PrimalItem_SCSCryopod" in name or "ItemDinoball.ItemDinoball_C" in name)))
|
|
33
49
|
|
|
34
50
|
def __init__(self, save: AsaSave):
|
|
35
51
|
self.save = save
|
|
@@ -37,6 +53,13 @@ class DinoApi:
|
|
|
37
53
|
self.parsed_dinos: Dict[UUID, Dino] = {}
|
|
38
54
|
self.parsed_cryopods: Dict[UUID, Cryopod] = {}
|
|
39
55
|
|
|
56
|
+
@staticmethod
|
|
57
|
+
def _create_dino(uuid: UUID, save: AsaSave, is_tamed: bool, is_baby: bool, bypass_inventory: bool = True) -> Dino:
|
|
58
|
+
if is_tamed:
|
|
59
|
+
return TamedBaby(uuid, save=save) if is_baby else TamedDino(uuid, save=save, bypass_inventory=bypass_inventory)
|
|
60
|
+
else:
|
|
61
|
+
return Baby(uuid, save=save) if is_baby else Dino(uuid, save=save)
|
|
62
|
+
|
|
40
63
|
@staticmethod
|
|
41
64
|
def is_applicable_bp(blueprint: str) -> bool:
|
|
42
65
|
return DinoApi._DEFAULT_CONFIG.blueprint_name_filter(blueprint)
|
|
@@ -66,99 +89,159 @@ class DinoApi:
|
|
|
66
89
|
|
|
67
90
|
dino = None
|
|
68
91
|
if "Dinos/" in object.blueprint and "_Character_" in object.blueprint:
|
|
69
|
-
is_tamed = object.get_property_value("TamedTimeStamp") is not None
|
|
70
|
-
|
|
71
92
|
if uuid in self.parsed_dinos:
|
|
72
93
|
dino = self.parsed_dinos[uuid]
|
|
73
94
|
else:
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
dino = Dino(uuid, self.save)
|
|
95
|
+
is_tamed = object.get_property_value("TamedTimeStamp") is not None
|
|
96
|
+
is_baby = object.get_property_value("bIsBaby", False)
|
|
97
|
+
dino = DinoApi._create_dino(uuid, self.save, is_tamed, is_baby)
|
|
78
98
|
self.parsed_dinos[uuid] = dino
|
|
79
99
|
|
|
80
100
|
return dino
|
|
81
101
|
|
|
82
|
-
def get_all(self, config = None, include_cryos: bool = True, include_wild: bool = True, include_tamed: bool = True, include_babies: bool = True, only_cryopodded: bool = False) -> Dict[UUID, Dino]:
|
|
102
|
+
def get_all(self, config = None, include_cryos: bool = True, include_wild: bool = True, include_tamed: bool = True, include_babies: bool = True, only_cryopodded: bool = False, max_workers: int = 6, bypass_inventory: bool = True) -> Dict[UUID, Dino]:
|
|
83
103
|
ArkSaveLogger.api_log("Retrieving all dinos from save...")
|
|
84
104
|
|
|
85
105
|
objects = self.get_all_objects(config)
|
|
106
|
+
|
|
86
107
|
dinos = {}
|
|
87
108
|
|
|
88
109
|
if self.all_objects and len(objects) != len(self.all_objects):
|
|
89
110
|
ArkSaveLogger.api_log(f"Found {len(objects)} dinos, parsing them... (and retrieving inventories)")
|
|
90
111
|
|
|
112
|
+
# Classify objects into categories for parallel processing
|
|
113
|
+
dino_objects_to_parse: List[Tuple[UUID, ArkGameObject, bool, bool]] = [] # (uuid, obj, is_tamed, is_baby)
|
|
114
|
+
cryopod_objects_to_parse: List[Tuple[UUID, ArkGameObject]] = [] # (uuid, obj)
|
|
115
|
+
|
|
91
116
|
for key, obj in objects.items():
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
dino = Baby(obj.uuid, save=self.save)
|
|
118
|
-
else:
|
|
119
|
-
dino = Dino(obj.uuid, save=self.save)
|
|
120
|
-
self.parsed_dinos[obj.uuid] = dino
|
|
121
|
-
|
|
122
|
-
elif ("PrimalItem_SCSCryopod" in obj.blueprint or "PrimalItem_WeaponEmptyCryopod" in obj.blueprint) and include_cryos and include_tamed:
|
|
123
|
-
if not obj.get_property_value("bIsEngram", default=False) and obj.get_property_value("CustomItemDatas") is not None:
|
|
124
|
-
if obj.uuid in self.parsed_cryopods:
|
|
125
|
-
is_baby = self.parsed_cryopods[obj.uuid].dino is not None and isinstance(self.parsed_cryopods[obj.uuid].dino, TamedBaby)
|
|
126
|
-
if is_baby and include_babies:
|
|
127
|
-
dino = self.parsed_cryopods[obj.uuid].dino
|
|
128
|
-
else:
|
|
129
|
-
dino = self.parsed_cryopods[obj.uuid].dino
|
|
130
|
-
if dino is not None:
|
|
131
|
-
self.parsed_dinos[dino.uuid] = dino
|
|
132
|
-
else:
|
|
133
|
-
try:
|
|
134
|
-
cryopod = Cryopod(obj.uuid, save=self.save)
|
|
135
|
-
self.parsed_cryopods[obj.uuid] = cryopod
|
|
136
|
-
if cryopod.dino is not None:
|
|
137
|
-
dino = cryopod.dino
|
|
138
|
-
dino.is_cryopodded = True
|
|
139
|
-
except Exception as e:
|
|
140
|
-
if "Unsupported embedded data version" in str(e):
|
|
141
|
-
ArkSaveLogger.warning_log(f"Skipping cryopod {obj.uuid} due to unsupported embedded data version (pre Unreal 5.5)")
|
|
142
|
-
continue
|
|
143
|
-
ArkSaveLogger.set_log_level(ArkSaveLogger.LogTypes.PARSER, True)
|
|
144
|
-
cryopod = Cryopod(obj.uuid, save=self.save)
|
|
145
|
-
ArkSaveLogger.set_log_level(ArkSaveLogger.LogTypes.PARSER, False)
|
|
146
|
-
ArkSaveLogger.error_log(f"Error parsing cryopod {obj.uuid}: {e}")
|
|
147
|
-
raise e
|
|
148
|
-
finally:
|
|
149
|
-
ArkSaveLogger.set_log_level(ArkSaveLogger.LogTypes.PARSER, False)
|
|
150
|
-
if dino is not None:
|
|
151
|
-
dinos[key] = dino
|
|
152
|
-
except Exception as e:
|
|
153
|
-
if ArkSaveLogger._allow_invalid_objects:
|
|
154
|
-
ArkSaveLogger.error_log(f"Failed to parse dino {obj.uuid}: {e}")
|
|
155
|
-
else:
|
|
156
|
-
raise e
|
|
117
|
+
if not only_cryopodded and "Dinos/" in obj.blueprint and "_Character_" in obj.blueprint:
|
|
118
|
+
is_tamed = obj.get_property_value("TamedTimeStamp") is not None
|
|
119
|
+
is_baby = obj.get_property_value("bIsBaby", False)
|
|
120
|
+
|
|
121
|
+
if obj.uuid in self.parsed_dinos:
|
|
122
|
+
if (is_tamed and include_tamed) or (not is_tamed and include_wild):
|
|
123
|
+
dinos[key] = self.parsed_dinos[obj.uuid]
|
|
124
|
+
elif (is_tamed and include_tamed) or (not is_tamed and include_wild):
|
|
125
|
+
if not is_baby or include_babies:
|
|
126
|
+
dino_objects_to_parse.append((key, obj, is_tamed, is_baby))
|
|
127
|
+
|
|
128
|
+
elif ("PrimalItem_SCSCryopod" in obj.blueprint or "PrimalItem_WeaponEmptyCryopod" in obj.blueprint or "ItemDinoball.ItemDinoball_C" in obj.blueprint) and include_cryos and include_tamed:
|
|
129
|
+
if not obj.get_property_value("bIsEngram", default=False) and obj.get_property_value("CustomItemDatas") is not None:
|
|
130
|
+
if obj.uuid in self.parsed_cryopods:
|
|
131
|
+
self._collect_cached_cryopod(self.parsed_cryopods[obj.uuid], key, dinos, include_babies)
|
|
132
|
+
else:
|
|
133
|
+
cryopod_objects_to_parse.append((key, obj))
|
|
134
|
+
|
|
135
|
+
# Parse dinos - parallel when GIL is disabled
|
|
136
|
+
if dino_objects_to_parse:
|
|
137
|
+
self._parse_dinos_batch(dino_objects_to_parse, dinos, max_workers, bypass_inventory)
|
|
138
|
+
|
|
139
|
+
# Parse cryopods - parallel when GIL is disabled
|
|
140
|
+
if cryopod_objects_to_parse:
|
|
141
|
+
self._parse_cryopods_batch(cryopod_objects_to_parse, dinos, include_babies, max_workers)
|
|
157
142
|
|
|
158
143
|
ArkSaveLogger.api_log(f"Parsed {len(dinos)} dinos")
|
|
159
144
|
|
|
160
145
|
return dinos
|
|
161
|
-
|
|
146
|
+
|
|
147
|
+
def _collect_cached_cryopod(self, cryopod: Cryopod, key: UUID, dinos: Dict[UUID, Dino], include_babies: bool):
|
|
148
|
+
if cryopod.dino is not None:
|
|
149
|
+
is_baby = isinstance(cryopod.dino, TamedBaby)
|
|
150
|
+
if include_babies or not is_baby:
|
|
151
|
+
dinos[key] = cryopod.dino
|
|
152
|
+
self.parsed_dinos[cryopod.dino.uuid] = cryopod.dino
|
|
153
|
+
|
|
154
|
+
def _collect_parsed_cryopod(self, cryopod: Cryopod, key: UUID, dinos: Dict[UUID, Dino], include_babies: bool):
|
|
155
|
+
self.parsed_cryopods[cryopod.uuid] = cryopod
|
|
156
|
+
if cryopod.dino is not None:
|
|
157
|
+
cryopod.dino.is_cryopodded = True
|
|
158
|
+
is_baby = isinstance(cryopod.dino, TamedBaby)
|
|
159
|
+
if include_babies or not is_baby:
|
|
160
|
+
dinos[key] = cryopod.dino
|
|
161
|
+
self.parsed_dinos[cryopod.dino.uuid] = cryopod.dino
|
|
162
|
+
|
|
163
|
+
def _parse_dinos_batch(self, dino_objects_to_parse: List[Tuple[UUID, ArkGameObject, bool, bool]], dinos: Dict[UUID, Dino], max_workers: int, bypass_inventory: bool = True):
|
|
164
|
+
if _PARALLEL_ENABLED and max_workers > 1:
|
|
165
|
+
ArkSaveLogger.api_log(f"Parsing {len(dino_objects_to_parse)} dinos with {max_workers} workers...")
|
|
166
|
+
save = self.save
|
|
167
|
+
_worker_initialized = threading.local()
|
|
168
|
+
error_count = [0]
|
|
169
|
+
|
|
170
|
+
def parse_single_dino(item):
|
|
171
|
+
if not getattr(_worker_initialized, 'done', False):
|
|
172
|
+
mark_as_worker_thread()
|
|
173
|
+
_worker_initialized.done = True
|
|
174
|
+
key, obj, is_tamed, is_baby = item
|
|
175
|
+
try:
|
|
176
|
+
return (key, DinoApi._create_dino(obj.uuid, save, is_tamed, is_baby, bypass_inventory))
|
|
177
|
+
except Exception as e:
|
|
178
|
+
error_count[0] += 1
|
|
179
|
+
if error_count[0] <= 3:
|
|
180
|
+
ArkSaveLogger.error_log(f"Parallel dino parse error #{error_count[0]}: {type(e).__name__}: {e}")
|
|
181
|
+
return (key, None)
|
|
182
|
+
|
|
183
|
+
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
|
184
|
+
results = list(executor.map(parse_single_dino, dino_objects_to_parse))
|
|
185
|
+
|
|
186
|
+
for key, dino in results:
|
|
187
|
+
if dino is not None:
|
|
188
|
+
dinos[key] = dino
|
|
189
|
+
self.parsed_dinos[dino.uuid] = dino
|
|
190
|
+
else:
|
|
191
|
+
for key, obj, is_tamed, is_baby in dino_objects_to_parse:
|
|
192
|
+
try:
|
|
193
|
+
dino = DinoApi._create_dino(obj.uuid, self.save, is_tamed, is_baby, bypass_inventory)
|
|
194
|
+
dinos[key] = dino
|
|
195
|
+
self.parsed_dinos[dino.uuid] = dino
|
|
196
|
+
except Exception as e:
|
|
197
|
+
if ArkSaveLogger._allow_invalid_objects:
|
|
198
|
+
ArkSaveLogger.error_log(f"Failed to parse dino {obj.uuid}: {e}")
|
|
199
|
+
else:
|
|
200
|
+
raise e
|
|
201
|
+
|
|
202
|
+
def _parse_cryopods_batch(self, cryopod_objects_to_parse: List[Tuple[UUID, ArkGameObject]], dinos: Dict[UUID, Dino], include_babies: bool, max_workers: int):
|
|
203
|
+
if _PARALLEL_ENABLED and max_workers > 1:
|
|
204
|
+
ArkSaveLogger.api_log(f"Parsing {len(cryopod_objects_to_parse)} cryopods with {max_workers} workers...")
|
|
205
|
+
save = self.save
|
|
206
|
+
_worker_initialized = threading.local()
|
|
207
|
+
|
|
208
|
+
def parse_single_cryopod(item):
|
|
209
|
+
if not getattr(_worker_initialized, 'done', False):
|
|
210
|
+
mark_as_worker_thread()
|
|
211
|
+
_worker_initialized.done = True
|
|
212
|
+
key, obj = item
|
|
213
|
+
try:
|
|
214
|
+
return (key, Cryopod(obj.uuid, save=save), None)
|
|
215
|
+
except Exception as e:
|
|
216
|
+
if "Unsupported embedded data version" in str(e):
|
|
217
|
+
return (key, None, "unsupported_version")
|
|
218
|
+
return (key, None, str(e))
|
|
219
|
+
|
|
220
|
+
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
|
221
|
+
cryo_results = list(executor.map(parse_single_cryopod, cryopod_objects_to_parse))
|
|
222
|
+
|
|
223
|
+
for key, cryopod, error in cryo_results:
|
|
224
|
+
if cryopod is not None:
|
|
225
|
+
self._collect_parsed_cryopod(cryopod, key, dinos, include_babies)
|
|
226
|
+
elif error == "unsupported_version":
|
|
227
|
+
ArkSaveLogger.warning_log(f"Skipping cryopod due to unsupported embedded data version (pre Unreal 5.5)")
|
|
228
|
+
elif error is not None:
|
|
229
|
+
ArkSaveLogger.error_log(f"Error parsing cryopod: {error}")
|
|
230
|
+
if not ArkSaveLogger._allow_invalid_objects:
|
|
231
|
+
raise RuntimeError(f"Cryopod parse error: {error}")
|
|
232
|
+
else:
|
|
233
|
+
for key, obj in cryopod_objects_to_parse:
|
|
234
|
+
try:
|
|
235
|
+
cryopod = Cryopod(obj.uuid, save=self.save)
|
|
236
|
+
self._collect_parsed_cryopod(cryopod, key, dinos, include_babies)
|
|
237
|
+
except Exception as e:
|
|
238
|
+
if "Unsupported embedded data version" in str(e):
|
|
239
|
+
ArkSaveLogger.warning_log(f"Skipping cryopod {obj.uuid} due to unsupported embedded data version (pre Unreal 5.5)")
|
|
240
|
+
continue
|
|
241
|
+
ArkSaveLogger.error_log(f"Error parsing cryopod {obj.uuid}: {e}")
|
|
242
|
+
if not ArkSaveLogger._allow_invalid_objects:
|
|
243
|
+
raise e
|
|
244
|
+
|
|
162
245
|
def get_at_location(self, map: ArkMap, coords: MapCoords, radius: float = 0.3, tamed: bool = True, untamed: bool = True) -> Dict[UUID, Dino]:
|
|
163
246
|
dinos = self.get_all()
|
|
164
247
|
|
|
@@ -82,20 +82,23 @@ class EquipmentApi(GeneralApi):
|
|
|
82
82
|
else:
|
|
83
83
|
return None
|
|
84
84
|
|
|
85
|
-
def get_all(self, cls: "EquipmentApi.Classes", config: GameObjectReaderConfiguration = None) -> Dict[UUID, Equipment]:
|
|
85
|
+
def get_all(self, cls: "EquipmentApi.Classes", config: GameObjectReaderConfiguration = None, max_workers: int = 6) -> Dict[UUID, Equipment]:
|
|
86
86
|
def is_valid(obj: ArkGameObject):
|
|
87
87
|
is_engram = obj.get_property_value("bIsEngram")
|
|
88
88
|
return not is_engram
|
|
89
89
|
|
|
90
|
+
allowed = set(self.__get_cls_filter(cls))
|
|
90
91
|
_config = GameObjectReaderConfiguration(
|
|
91
|
-
blueprint_name_filter=lambda name: (True if config is None else config.blueprint_name_filter(name)) and name in
|
|
92
|
+
blueprint_name_filter=lambda name: (True if config is None else config.blueprint_name_filter(name)) and name in allowed
|
|
92
93
|
)
|
|
93
94
|
|
|
94
|
-
return super().get_all(cls, valid_filter=is_valid, config=_config)
|
|
95
|
+
return super().get_all(cls, valid_filter=is_valid, config=_config, max_workers=max_workers)
|
|
95
96
|
|
|
96
97
|
def get_by_class(self, cls: "EquipmentApi.Classes", classes: List[str]) -> Dict[UUID, Equipment]:
|
|
98
|
+
allowed = set(self.__get_cls_filter(cls))
|
|
99
|
+
classes_set = set(classes)
|
|
97
100
|
config = GameObjectReaderConfiguration(
|
|
98
|
-
blueprint_name_filter=lambda name: name is not None and name in
|
|
101
|
+
blueprint_name_filter=lambda name: name is not None and name in classes_set and name in allowed
|
|
99
102
|
)
|
|
100
103
|
|
|
101
104
|
return self.get_all(cls, config)
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
from typing import Dict, List, Tuple
|
|
2
|
+
from uuid import UUID
|
|
3
|
+
import sys
|
|
4
|
+
import threading
|
|
5
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
6
|
+
|
|
7
|
+
from arkparse.logging.ark_save_logger import ArkSaveLogger, mark_as_worker_thread
|
|
8
|
+
from arkparse.object_model.ark_game_object import ArkGameObject
|
|
9
|
+
from arkparse.parsing import ArkBinaryParser
|
|
10
|
+
from arkparse.saves.asa_save import AsaSave
|
|
11
|
+
from arkparse.parsing import GameObjectReaderConfiguration
|
|
12
|
+
from arkparse.object_model.misc.__parsed_object_base import ParsedObjectBase
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _is_parallel_enabled() -> bool:
|
|
16
|
+
if hasattr(sys, '_is_gil_enabled'):
|
|
17
|
+
return not sys._is_gil_enabled()
|
|
18
|
+
return False
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
_PARALLEL_ENABLED = _is_parallel_enabled()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class GeneralApi:
|
|
25
|
+
def __init__(self, save: AsaSave, config: GameObjectReaderConfiguration= GameObjectReaderConfiguration()):
|
|
26
|
+
self.save = save
|
|
27
|
+
self.config = config
|
|
28
|
+
self.all_objects = None
|
|
29
|
+
self.parsed_objects: Dict[UUID, ParsedObjectBase] = {}
|
|
30
|
+
|
|
31
|
+
def get_all_objects(self, config: GameObjectReaderConfiguration = None) -> Dict[UUID, ArkGameObject]:
|
|
32
|
+
reuse = False
|
|
33
|
+
if config is None:
|
|
34
|
+
reuse = True
|
|
35
|
+
if self.all_objects is not None:
|
|
36
|
+
return self.all_objects
|
|
37
|
+
|
|
38
|
+
config = self.config
|
|
39
|
+
|
|
40
|
+
objects = self.save.get_game_objects(config)
|
|
41
|
+
|
|
42
|
+
if reuse:
|
|
43
|
+
self.all_objects = objects
|
|
44
|
+
|
|
45
|
+
return objects
|
|
46
|
+
|
|
47
|
+
def get_all(self, constructor, valid_filter = None, config = None, max_workers: int = 4) -> Dict[UUID, object]:
|
|
48
|
+
objects = self.get_all_objects(config)
|
|
49
|
+
|
|
50
|
+
parsed = {}
|
|
51
|
+
to_parse: List[Tuple[UUID, ArkGameObject]] = []
|
|
52
|
+
|
|
53
|
+
for key, obj in objects.items():
|
|
54
|
+
if valid_filter and not valid_filter(obj):
|
|
55
|
+
continue
|
|
56
|
+
|
|
57
|
+
if key in self.parsed_objects:
|
|
58
|
+
parsed[key] = self.parsed_objects[key]
|
|
59
|
+
else:
|
|
60
|
+
to_parse.append((key, obj))
|
|
61
|
+
|
|
62
|
+
self._parse_batch(to_parse, parsed, constructor, max_workers)
|
|
63
|
+
|
|
64
|
+
return parsed
|
|
65
|
+
|
|
66
|
+
def _parse_batch(self, to_parse: List[Tuple[UUID, ArkGameObject]], parsed: Dict, constructor, max_workers: int):
|
|
67
|
+
if _PARALLEL_ENABLED and max_workers > 1 and len(to_parse) > 0:
|
|
68
|
+
ArkSaveLogger.api_log(f"Parsing {len(to_parse)} objects with {max_workers} workers...")
|
|
69
|
+
save = self.save
|
|
70
|
+
_worker_initialized = threading.local()
|
|
71
|
+
error_count = [0]
|
|
72
|
+
|
|
73
|
+
def parse_single(item):
|
|
74
|
+
if not getattr(_worker_initialized, 'done', False):
|
|
75
|
+
mark_as_worker_thread()
|
|
76
|
+
_worker_initialized.done = True
|
|
77
|
+
key, obj = item
|
|
78
|
+
try:
|
|
79
|
+
return (key, constructor(obj.uuid, save), None)
|
|
80
|
+
except Exception as e:
|
|
81
|
+
error_count[0] += 1
|
|
82
|
+
if error_count[0] <= 3:
|
|
83
|
+
ArkSaveLogger.error_log(f"Parallel parse error #{error_count[0]}: {type(e).__name__}: {e}")
|
|
84
|
+
return (key, None, str(e))
|
|
85
|
+
|
|
86
|
+
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
|
87
|
+
results = list(executor.map(parse_single, to_parse))
|
|
88
|
+
|
|
89
|
+
for key, obj, error in results:
|
|
90
|
+
if obj is not None:
|
|
91
|
+
parsed[key] = obj
|
|
92
|
+
self.parsed_objects[key] = obj
|
|
93
|
+
elif error is not None:
|
|
94
|
+
if not ArkSaveLogger._allow_invalid_objects:
|
|
95
|
+
raise RuntimeError(f"Parse error for {key}: {error}")
|
|
96
|
+
else:
|
|
97
|
+
for key, obj in to_parse:
|
|
98
|
+
try:
|
|
99
|
+
parsed[key] = constructor(obj.uuid, self.save)
|
|
100
|
+
self.parsed_objects[key] = parsed[key]
|
|
101
|
+
except Exception as e:
|
|
102
|
+
if ArkSaveLogger._allow_invalid_objects:
|
|
103
|
+
ArkSaveLogger.error_log(f"Failed to parse object {obj.uuid}: {e}")
|
|
104
|
+
else:
|
|
105
|
+
raise e
|
|
106
|
+
|
|
@@ -25,13 +25,13 @@ class StackableApi(GeneralApi):
|
|
|
25
25
|
config = StackableApi._DEFAULT_CONFIG
|
|
26
26
|
super().__init__(save, config)
|
|
27
27
|
|
|
28
|
-
def get_all(self, cls: "StackableApi.Classes", config = None) -> Dict[UUID, InventoryItem]:
|
|
28
|
+
def get_all(self, cls: "StackableApi.Classes", config = None, max_workers: int = 4) -> Dict[UUID, InventoryItem]:
|
|
29
29
|
def is_valid(obj: ArkGameObject):
|
|
30
30
|
is_bp = obj.get_property_value("bIsBlueprint")
|
|
31
31
|
is_engram = obj.get_property_value("bIsEngram")
|
|
32
32
|
return not (is_bp or is_engram)
|
|
33
33
|
|
|
34
|
-
return super().get_all(cls, valid_filter=is_valid, config=config)
|
|
34
|
+
return super().get_all(cls, valid_filter=is_valid, config=config, max_workers=max_workers)
|
|
35
35
|
|
|
36
36
|
def get_by_class(self, cls: "StackableApi.Classes", classes: List[str]) -> Dict[UUID, InventoryItem]:
|
|
37
37
|
config = GameObjectReaderConfiguration(
|