arkparse 0.5.1__tar.gz → 0.5.3__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.5.1 → arkparse-0.5.3}/.gitignore +3 -2
- {arkparse-0.5.1 → arkparse-0.5.3}/PKG-INFO +1 -1
- {arkparse-0.5.1 → arkparse-0.5.3}/pyproject.toml +1 -1
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/api/json_api.py +6 -1
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/logging/ark_save_logger.py +77 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/ark_game_object.py +24 -4
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/ark_archive.py +6 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/ark_property.py +94 -32
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_custom_item_data.py +24 -5
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/saves/save_connection.py +15 -5
- {arkparse-0.5.1 → arkparse-0.5.3}/LICENSE +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/README.md +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/__init__.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/api/__init__.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/api/base_api.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/api/dino_api.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/api/equipment_api.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/api/general_api.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/api/player_api.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/api/rcon_api.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/api/stackable_api.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/api/structure_api.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/ark_tribe.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/assets/ABERRATION.PNG +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/assets/LOST_COLONY.PNG +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/assets/RAGNAROK.PNG +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/assets/THE_ISLAND.PNG +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/assets/__init__.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/assets/heavy_inventory +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/assets/tamable_dinos.txt +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/assets/templates/equipment/armor +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/assets/templates/equipment/armor_bp +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/assets/templates/equipment/armor_bp_n.json +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/assets/templates/equipment/armor_n.json +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/assets/templates/equipment/saddle +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/assets/templates/equipment/saddle_bp +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/assets/templates/equipment/saddle_bp_n.json +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/assets/templates/equipment/saddle_n.json +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/assets/templates/equipment/shield +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/assets/templates/equipment/shield_bp +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/assets/templates/equipment/shield_bp_n.json +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/assets/templates/equipment/shield_n.json +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/assets/templates/equipment/weapon +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/assets/templates/equipment/weapon_bp +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/assets/templates/equipment/weapon_bp_n.json +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/assets/templates/equipment/weapon_n.json +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/assets/templates/inventory/with_item_n.json +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/assets/templates/stackable/stackable +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/assets/templates/stackable/stackable_n.json +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/assets/templates/trait/trait +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/assets/templates/trait/trait_n.json +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/classes/__init__.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/classes/consumables.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/classes/dinos.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/classes/equipment.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/classes/placed_structures.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/classes/player.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/classes/resources.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/classes/traits.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/enums/__init__.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/enums/ark_dino_trait.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/enums/ark_enum.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/enums/ark_equipment_stat.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/enums/ark_item_quality.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/enums/ark_map.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/enums/ark_stat.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/ftp/__init__.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/ftp/ark_ftp_client.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/helpers/dino/is_wild_tamed.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/logging/__init__.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/bases/base.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/cluster_data/ark_cluster_data.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/cluster_data/cluster_data_dino.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/cluster_data/cluster_data_item.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/cryopods/cryopod.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/dinos/__init__.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/dinos/baby.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/dinos/dino.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/dinos/dino_ai_controller.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/dinos/dino_id.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/dinos/pedigree.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/dinos/stats.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/dinos/tamed_baby.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/dinos/tamed_dino.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/equipment/__armor_defaults.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/equipment/__equipment.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/equipment/__equipment_with_armor.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/equipment/__equipment_with_durability.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/equipment/__init__.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/equipment/armor.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/equipment/saddle.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/equipment/shield.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/equipment/weapon.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/misc/__parsed_object_base.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/misc/dino_owner.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/misc/inventory.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/misc/inventory_item.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/misc/object_crafter.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/misc/object_owner.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/misc/trait.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/stackables/__init__.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/stackables/_stackable.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/stackables/ammo.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/stackables/resource.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/structures/__init__.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/structures/structure.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/object_model/structures/structure_with_inventory.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/__init__.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/_base_value_parser.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/_base_value_validator.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/_binary_reader_base.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/_byte_operator.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/_fast_shim.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/_legacy_parsing/__init__.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/_legacy_parsing/_property_insertor.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/_legacy_parsing/_property_parser.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/_legacy_parsing/_property_replacer.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/_legacy_parsing/ark_binary_parser.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/_legacy_parsing/ark_property.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/_legacy_parsing/struct/__init__.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/_legacy_parsing/struct/ark_dino_ancestor_entry.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/_legacy_parsing/struct/ark_item_net_id.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/_legacy_parsing/struct/ark_my_persistent_buff_datas.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/_legacy_parsing/struct/ark_object_property.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/_legacy_parsing/struct/ark_struct_type.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/_legacy_parsing/struct/ark_tracked_actor_id_category_pair_with_bool.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/_legacy_parsing/struct/ark_unique_net_id_repl.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/_legacy_parsing/struct/ark_vector.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/_legacy_parsing/struct/ark_vector_bool_pair.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/_property_insertor.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/_property_parser.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/_property_replacer.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/ark_binary_parser.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/ark_object.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/ark_property_container.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/ark_set.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/ark_value_type.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/array_property.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/game_object_reader_configuration.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/__init__.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/actor_transform.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_color.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_crafting_resource_requirement.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_dino_ancestor_entry.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_dino_order_id.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_gacha_resource_struct.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_gene_trait_struct.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_gigantoraptor_bonded_struct.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_int_point.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_item_craft_queue_entry.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_item_net_id.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_key_value_pair.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_linear_color.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_milestone_tree_level_and_index.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_my_persistent_buff_datas.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_object_property.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_painting_key_value.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_patrol_group_saved_data.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_player_death_reason.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_primal_saddle_structure.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_quat.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_rotator.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_server_custom_folder.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_struct_type.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_tracked_actor_id_category_pair.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_tracked_actor_id_category_pair_with_bool.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_tribe_alliance.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_tribe_rank_group.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_unique_net_id_repl.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_vector.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/ark_vector_bool_pair.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/object_reference.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/parsing/struct/unknown_struct.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/player/ark_character_config.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/player/ark_character_stats.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/player/ark_persistent_buff_data.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/player/ark_player.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/player/ark_tribute_item.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/saves/__init__.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/saves/asa_save.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/saves/header_location.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/saves/save_context.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/utils/__init__.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/utils/heatmap_visualization.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/utils/import_file.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/utils/json_utils.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/src/arkparse/utils/map_images.py +0 -0
- {arkparse-0.5.1 → arkparse-0.5.3}/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.5.
|
|
3
|
+
Version: 0.5.3
|
|
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>
|
|
@@ -455,7 +455,12 @@ class JsonApi:
|
|
|
455
455
|
try:
|
|
456
456
|
obj_uuid = SaveConnection.byte_array_to_uuid(row[0])
|
|
457
457
|
byte_buffer = ArkBinaryParser(row[1], self.save.save_context)
|
|
458
|
-
|
|
458
|
+
# Use the string-name-aware reader: some objects store their
|
|
459
|
+
# class as an inline string instead of a name-table id, which
|
|
460
|
+
# a raw read_name() can't resolve (raises when generate_unknown
|
|
461
|
+
# is off). Those are never items, so they fall through the
|
|
462
|
+
# filter below.
|
|
463
|
+
class_name, *_ = ArkGameObject.read_name(obj_uuid, byte_buffer)
|
|
459
464
|
|
|
460
465
|
if "/PrimalItemArmor_" not in class_name and \
|
|
461
466
|
"/PrimalItem_" not in class_name and \
|
|
@@ -52,6 +52,16 @@ class ArkSaveLogger:
|
|
|
52
52
|
# Use _get_struct_path() for thread-safe access
|
|
53
53
|
current_struct_path = []
|
|
54
54
|
_allow_invalid_objects = None
|
|
55
|
+
# Governs mod-namespace objects (not /Game/ or /Script/). Defaults to True
|
|
56
|
+
# (skip & continue) for backward compatibility; set to False to hard-fail.
|
|
57
|
+
_allow_invalid_mod_objects = None
|
|
58
|
+
# Optional callback invoked when an object fails to parse. Signature:
|
|
59
|
+
# (obj_uuid, class_name, byte_buffer, error) -> None
|
|
60
|
+
# Used by tooling (e.g. the testbench) to capture failing objects for debug.
|
|
61
|
+
_object_failure_handler = None
|
|
62
|
+
# Optional callback invoked on a (non-fatal) struct size mismatch. Signature:
|
|
63
|
+
# (struct_type, data_size, start_position, end_position, byte_buffer) -> None
|
|
64
|
+
_struct_mismatch_handler = None
|
|
55
65
|
_worker_logging_enabled = None # Whether logging is enabled in worker threads
|
|
56
66
|
_file = ""
|
|
57
67
|
_byte_buffer = None
|
|
@@ -140,10 +150,13 @@ class ArkSaveLogger:
|
|
|
140
150
|
}
|
|
141
151
|
ArkSaveLogger._file_viewer_enabled = True
|
|
142
152
|
ArkSaveLogger._worker_logging_enabled = False
|
|
153
|
+
ArkSaveLogger._allow_invalid_objects = True
|
|
154
|
+
ArkSaveLogger._allow_invalid_mod_objects = True
|
|
143
155
|
config = {
|
|
144
156
|
"levels": ArkSaveLogger._log_level_states,
|
|
145
157
|
"fve": False,
|
|
146
158
|
"allow_invalid": True,
|
|
159
|
+
"allow_invalid_mod": True,
|
|
147
160
|
"worker_logging": False
|
|
148
161
|
}
|
|
149
162
|
write_config_file(ArkSaveLogger.__LOG_CONFIG_FILE_NAME, config)
|
|
@@ -151,6 +164,7 @@ class ArkSaveLogger:
|
|
|
151
164
|
ArkSaveLogger._log_level_states = config["levels"]
|
|
152
165
|
ArkSaveLogger._file_viewer_enabled = config["fve"]
|
|
153
166
|
ArkSaveLogger._allow_invalid_objects = config["allow_invalid"]
|
|
167
|
+
ArkSaveLogger._allow_invalid_mod_objects = config.get("allow_invalid_mod", True)
|
|
154
168
|
ArkSaveLogger._worker_logging_enabled = config.get("worker_logging", False)
|
|
155
169
|
# Update cached parser_log state for fast checks
|
|
156
170
|
ArkSaveLogger._parser_log_enabled = (
|
|
@@ -220,6 +234,69 @@ class ArkSaveLogger:
|
|
|
220
234
|
global_config["allow_invalid"] = state
|
|
221
235
|
write_config_file(ArkSaveLogger.__LOG_CONFIG_FILE_NAME, global_config)
|
|
222
236
|
|
|
237
|
+
@staticmethod
|
|
238
|
+
def allow_invalid_mod_objects(state: bool = True, set_globally: bool = False):
|
|
239
|
+
"""Governs parsing failures for mod-namespace objects (anything whose
|
|
240
|
+
class is not under /Game/ or /Script/). When False, such failures are
|
|
241
|
+
reraised instead of skipped. Defaults to True (skip & continue)."""
|
|
242
|
+
if ArkSaveLogger._allow_invalid_mod_objects is None:
|
|
243
|
+
ArkSaveLogger.__init_config()
|
|
244
|
+
|
|
245
|
+
ArkSaveLogger._allow_invalid_mod_objects = state
|
|
246
|
+
|
|
247
|
+
if set_globally:
|
|
248
|
+
global_config = read_config_file(ArkSaveLogger.__LOG_CONFIG_FILE_NAME)
|
|
249
|
+
global_config["allow_invalid_mod"] = state
|
|
250
|
+
write_config_file(ArkSaveLogger.__LOG_CONFIG_FILE_NAME, global_config)
|
|
251
|
+
|
|
252
|
+
@staticmethod
|
|
253
|
+
def set_object_failure_handler(handler):
|
|
254
|
+
"""Register a callback invoked whenever an object fails to parse.
|
|
255
|
+
|
|
256
|
+
The handler receives ``(obj_uuid, class_name, byte_buffer, error)``. Pass
|
|
257
|
+
``None`` to clear it. Exceptions raised by the handler are swallowed so
|
|
258
|
+
debug tooling can never break parsing. Intended for capturing failing
|
|
259
|
+
objects (binary + structured dump) for offline debugging.
|
|
260
|
+
"""
|
|
261
|
+
ArkSaveLogger._object_failure_handler = handler
|
|
262
|
+
|
|
263
|
+
@staticmethod
|
|
264
|
+
def _notify_object_failure(obj_uuid, class_name, byte_buffer, error, **kwargs):
|
|
265
|
+
"""Forward a parse failure to the registered handler.
|
|
266
|
+
|
|
267
|
+
``kwargs`` carries optional context (e.g. ``kind`` of "game"/"archive" and
|
|
268
|
+
a ``reload_hint`` dict) so the handler can capture and reload different
|
|
269
|
+
object types appropriately. Handlers should accept ``**kwargs``.
|
|
270
|
+
"""
|
|
271
|
+
handler = ArkSaveLogger._object_failure_handler
|
|
272
|
+
if handler is None:
|
|
273
|
+
return
|
|
274
|
+
try:
|
|
275
|
+
handler(obj_uuid, class_name, byte_buffer, error, **kwargs)
|
|
276
|
+
except Exception as e: # never let debug tooling break parsing
|
|
277
|
+
ArkSaveLogger.warning_log(f"object_failure_handler raised: {e}")
|
|
278
|
+
|
|
279
|
+
@staticmethod
|
|
280
|
+
def set_struct_mismatch_handler(handler):
|
|
281
|
+
"""Register a callback invoked on a non-fatal struct size mismatch (a
|
|
282
|
+
struct parsed as a property list that didn't consume exactly data_size).
|
|
283
|
+
|
|
284
|
+
The handler receives ``(struct_type, data_size, start_position,
|
|
285
|
+
end_position, byte_buffer)``. Pass ``None`` to clear it. Exceptions are
|
|
286
|
+
swallowed. Intended for debug tooling to record under-/over-read structs.
|
|
287
|
+
"""
|
|
288
|
+
ArkSaveLogger._struct_mismatch_handler = handler
|
|
289
|
+
|
|
290
|
+
@staticmethod
|
|
291
|
+
def _notify_struct_mismatch(struct_type, data_size, start_position, end_position, byte_buffer):
|
|
292
|
+
handler = ArkSaveLogger._struct_mismatch_handler
|
|
293
|
+
if handler is None:
|
|
294
|
+
return
|
|
295
|
+
try:
|
|
296
|
+
handler(struct_type, data_size, start_position, end_position, byte_buffer)
|
|
297
|
+
except Exception as e: # never let debug tooling break parsing
|
|
298
|
+
ArkSaveLogger.warning_log(f"struct_mismatch_handler raised: {e}")
|
|
299
|
+
|
|
223
300
|
@staticmethod
|
|
224
301
|
def enable_worker_logging(state: bool = True, set_globally: bool = False):
|
|
225
302
|
"""Enable or disable logging in parallel worker threads.
|
|
@@ -45,6 +45,8 @@ class ArkGameObject(ArkPropertyContainer):
|
|
|
45
45
|
self.uuid = uuid
|
|
46
46
|
self.blueprint = blueprint
|
|
47
47
|
string_name = False
|
|
48
|
+
string_names: List[str] = []
|
|
49
|
+
string_name_offsets: List[int] = []
|
|
48
50
|
super().__init__()
|
|
49
51
|
if binary_reader:
|
|
50
52
|
ArkSaveLogger.set_file(binary_reader, "debug.bin")
|
|
@@ -55,7 +57,7 @@ class ArkGameObject(ArkPropertyContainer):
|
|
|
55
57
|
self.uuid2: UUID = None
|
|
56
58
|
binary_reader.set_position(0)
|
|
57
59
|
|
|
58
|
-
self.blueprint, string_name = ArkGameObject.read_name(uuid, binary_reader)
|
|
60
|
+
self.blueprint, string_name, string_names, string_name_offsets = ArkGameObject.read_name(uuid, binary_reader)
|
|
59
61
|
ArkSaveLogger.parser_log(f"Read Blueprint: {self.blueprint} (String name: {string_name})")
|
|
60
62
|
|
|
61
63
|
sContext : SaveContext = binary_reader.save_context
|
|
@@ -69,6 +71,14 @@ class ArkGameObject(ArkPropertyContainer):
|
|
|
69
71
|
binary_reader.validate_uint32(0)
|
|
70
72
|
if string_name:
|
|
71
73
|
binary_reader.read_uint16()
|
|
74
|
+
# Names embedded in a string-name header are stored as
|
|
75
|
+
# strings (never as name-table refs), mirroring what the
|
|
76
|
+
# regular names block below would produce.
|
|
77
|
+
self.names = string_names
|
|
78
|
+
self.name_metadata = [
|
|
79
|
+
_NameMetadata(name, offset, True)
|
|
80
|
+
for name, offset in zip(string_names, string_name_offsets)
|
|
81
|
+
]
|
|
72
82
|
|
|
73
83
|
try:
|
|
74
84
|
if not (no_header or string_name):
|
|
@@ -250,6 +260,8 @@ class ArkGameObject(ArkPropertyContainer):
|
|
|
250
260
|
def read_name(obj_uuid: UUID, reader: ArkBinaryParser) -> str:
|
|
251
261
|
reader.set_position(0)
|
|
252
262
|
string_name = False
|
|
263
|
+
extra_names: List[str] = []
|
|
264
|
+
extra_offsets: List[int] = []
|
|
253
265
|
|
|
254
266
|
try:
|
|
255
267
|
class_name = reader.read_name()
|
|
@@ -260,18 +272,26 @@ class ArkGameObject(ArkPropertyContainer):
|
|
|
260
272
|
try:
|
|
261
273
|
unknow_id = reader.read_uint32()
|
|
262
274
|
reader.validate_uint64(0)
|
|
263
|
-
reader.read_int()
|
|
275
|
+
name_count = reader.read_int()
|
|
264
276
|
class_name = reader.read_string()
|
|
265
277
|
# reader.validate_uint32(0)
|
|
266
278
|
string_name = True
|
|
279
|
+
# The string-name header carries a name count: the first string is
|
|
280
|
+
# the class, any further strings are the object's names (e.g. the
|
|
281
|
+
# instance name of a DeathItemCache) that the name-table format
|
|
282
|
+
# would store separately. Consume them so the trailing padding
|
|
283
|
+
# lines up (otherwise validate_uint32(0) hits the next length).
|
|
284
|
+
for _ in range(max(0, name_count - 1)):
|
|
285
|
+
extra_offsets.append(reader.position + 4)
|
|
286
|
+
extra_names.append(reader.read_string())
|
|
267
287
|
ArkSaveLogger.parser_log(f"Object {obj_uuid} has string class name {class_name} instead of name table reference")
|
|
268
288
|
except Exception as e:
|
|
269
289
|
ArkSaveLogger.error_log(f"Error reading class name for object {obj_uuid}: {e}")
|
|
270
290
|
reader.structured_print(to_default_file=True)
|
|
271
291
|
# input("Press Enter to continue...")
|
|
272
292
|
class_name = "UnknownClass"
|
|
273
|
-
|
|
274
|
-
return class_name, string_name
|
|
293
|
+
|
|
294
|
+
return class_name, string_name, extra_names, extra_offsets
|
|
275
295
|
|
|
276
296
|
def get_short_name(self) -> str:
|
|
277
297
|
to_strip_end = [
|
|
@@ -73,6 +73,12 @@ class ArkArchive:
|
|
|
73
73
|
except Exception as e:
|
|
74
74
|
ArkSaveLogger.error_log(f"Error reading properties for object \'{obj.class_name}\' at {self.data.get_position()}: {e}")
|
|
75
75
|
self.data.structured_print()
|
|
76
|
+
# Notify any registered debug handler (e.g. the testbench dumper).
|
|
77
|
+
# Archives reload from their raw bytes via ArkArchive(data, from_store).
|
|
78
|
+
ArkSaveLogger._notify_object_failure(
|
|
79
|
+
None, obj.class_name, self.data, e,
|
|
80
|
+
kind="archive", reload_hint={"from_store": from_store},
|
|
81
|
+
)
|
|
76
82
|
raise e
|
|
77
83
|
ArkSaveLogger.exit_struct()
|
|
78
84
|
|
|
@@ -173,7 +173,7 @@ class ArkProperty:
|
|
|
173
173
|
# Public API
|
|
174
174
|
# ---------------------------------------------------------------------------------------------
|
|
175
175
|
@staticmethod
|
|
176
|
-
def read_property(byte_buffer: "ArkBinaryParser", in_array: bool = False) -> Optional["ArkProperty"]:
|
|
176
|
+
def read_property(byte_buffer: "ArkBinaryParser", in_array: bool = False, struct_end: int = -1) -> Optional["ArkProperty"]:
|
|
177
177
|
name_position = byte_buffer.get_position()
|
|
178
178
|
value_position = 0
|
|
179
179
|
byte_buffer.save_context.generate_unknown = True
|
|
@@ -185,7 +185,12 @@ class ArkProperty:
|
|
|
185
185
|
ArkSaveLogger.parser_log("Exiting struct (None marker) (pos = " + str(byte_buffer.get_position()) + " (hex: " + hex(byte_buffer.get_position()) + "))")
|
|
186
186
|
ArkSaveLogger.exit_struct()
|
|
187
187
|
|
|
188
|
-
|
|
188
|
+
# Only skip the 4 trailing zeros if we haven't already reached the
|
|
189
|
+
# declared struct boundary. When struct_end is known and we're right
|
|
190
|
+
# at it, those zeros belong to the outer stream, not this struct.
|
|
191
|
+
if (struct_end == -1 or byte_buffer.position < struct_end) \
|
|
192
|
+
and byte_buffer.size() - byte_buffer.position >= 4 \
|
|
193
|
+
and byte_buffer.peek_int() == 0:
|
|
189
194
|
byte_buffer.skip_bytes(4)
|
|
190
195
|
return None
|
|
191
196
|
|
|
@@ -291,6 +296,18 @@ class ArkProperty:
|
|
|
291
296
|
if key_type == ArkValueType.Struct:
|
|
292
297
|
value_type = bb.read_name()
|
|
293
298
|
else:
|
|
299
|
+
if key_type == ArkValueType.Byte:
|
|
300
|
+
# Enum-keyed map (e.g. TMap<TEnumAsByte<EFoo>, ...>): the key's
|
|
301
|
+
# enum type is serialized as a descriptor block before the value
|
|
302
|
+
# type: [enum name][int][enum path][int]. Consume it so the value
|
|
303
|
+
# type is read from the correct offset.
|
|
304
|
+
enum_key_type = bb.read_name()
|
|
305
|
+
bb.read_int()
|
|
306
|
+
enum_key_path = bb.read_name()
|
|
307
|
+
bb.read_int()
|
|
308
|
+
ArkSaveLogger.parser_log(
|
|
309
|
+
f"Enum-keyed map: enum={enum_key_type} ({enum_key_path})"
|
|
310
|
+
)
|
|
294
311
|
value_type = bb.read_value_type_by_name()
|
|
295
312
|
struct_names = bb.read_int()
|
|
296
313
|
if struct_names > 0:
|
|
@@ -342,7 +359,13 @@ class ArkProperty:
|
|
|
342
359
|
@staticmethod
|
|
343
360
|
def read_struct_map(key_type: ArkValueType, bb: "ArkBinaryParser", map_name: str) -> "ArkProperty":
|
|
344
361
|
props: List[ArkProperty] = []
|
|
345
|
-
|
|
362
|
+
if key_type == ArkValueType.Byte:
|
|
363
|
+
# Enum-keyed map entry: the key is the enum value name (e.g.
|
|
364
|
+
# E_ActorType_AAT::NewEnumerator0), serialized as a name reference
|
|
365
|
+
# rather than a single byte.
|
|
366
|
+
key_name = bb.read_name()
|
|
367
|
+
else:
|
|
368
|
+
key_name = ArkProperty.read_property_value(key_type, bb)
|
|
346
369
|
with log_block(f"Map({key_name}:{map_name})"):
|
|
347
370
|
while bb.has_more():
|
|
348
371
|
p = ArkProperty.read_property(bb)
|
|
@@ -374,6 +397,16 @@ class ArkProperty:
|
|
|
374
397
|
|
|
375
398
|
return prop
|
|
376
399
|
|
|
400
|
+
@staticmethod
|
|
401
|
+
def _has_struct_reader(struct_type: str) -> bool:
|
|
402
|
+
"""Whether this struct type has a dedicated (fixed-layout) reader.
|
|
403
|
+
|
|
404
|
+
Types without one are read generically as a property list; see
|
|
405
|
+
``_read_struct_body`` and the guarded array backup in
|
|
406
|
+
``read_array_property``.
|
|
407
|
+
"""
|
|
408
|
+
return ArkStructType.from_type_name(struct_type) in _STRUCT_READERS
|
|
409
|
+
|
|
377
410
|
@staticmethod
|
|
378
411
|
def read_array_property(key: str, type_: str, position: int, bb: "ArkBinaryParser", data_size: int) -> Tuple["ArkProperty", int]:
|
|
379
412
|
# V14 no position in array
|
|
@@ -405,31 +438,51 @@ class ArkProperty:
|
|
|
405
438
|
bb.set_position(bb.position - 4)
|
|
406
439
|
|
|
407
440
|
array_items = bb.read_uint32()
|
|
441
|
+
array_end = data_start_position + data_size
|
|
408
442
|
|
|
409
|
-
#
|
|
410
|
-
#
|
|
443
|
+
# Structs without a dedicated reader are read generically as a property
|
|
444
|
+
# list (see _read_struct_body). That backup is reliable for well-formed,
|
|
445
|
+
# None-terminated property-list structs but can't be guaranteed for an
|
|
446
|
+
# arbitrary packed layout, so guard it: if a generic element read raises,
|
|
447
|
+
# recover by skipping to the array's known end and record the type for
|
|
448
|
+
# follow-up rather than failing the whole object. A dedicated reader
|
|
449
|
+
# raising is a real bug, so let that propagate.
|
|
450
|
+
has_reader = ArkProperty._has_struct_reader(array_content_type)
|
|
411
451
|
|
|
412
452
|
with log_block(f"Arr({array_content_type})"):
|
|
413
453
|
ArkSaveLogger.parser_log(
|
|
414
454
|
f"[STRUCT ARRAY: key='none'; nr_of_value={array_items}; type={array_content_type}; bin_length={data_size}]"
|
|
415
455
|
)
|
|
416
|
-
struct_array = [
|
|
417
|
-
|
|
418
|
-
for _ in range(array_items)
|
|
419
|
-
|
|
456
|
+
struct_array = []
|
|
457
|
+
try:
|
|
458
|
+
for _ in range(array_items):
|
|
459
|
+
struct_array.append(
|
|
460
|
+
ArkProperty.read_struct_property(bb, data_size, array_content_type, True)[0]
|
|
461
|
+
)
|
|
462
|
+
except Exception as exc:
|
|
463
|
+
if has_reader:
|
|
464
|
+
raise
|
|
465
|
+
ArkSaveLogger.warning_log(
|
|
466
|
+
f"Generic read of struct array '{array_content_type}' failed after "
|
|
467
|
+
f"{len(struct_array)}/{array_items} element(s): {exc}; skipping to end of array"
|
|
468
|
+
)
|
|
469
|
+
ArkSaveLogger._notify_struct_mismatch(
|
|
470
|
+
array_content_type, data_size, data_start_position, bb.position, bb
|
|
471
|
+
)
|
|
472
|
+
bb.set_position(array_end)
|
|
420
473
|
|
|
421
474
|
prop = ArkProperty(key, type_, position, 0, struct_array)
|
|
422
|
-
if bb.position !=
|
|
475
|
+
if bb.position != array_end:
|
|
476
|
+
# The read didn't consume exactly the declared size. Record the
|
|
477
|
+
# mismatch (the testbench captures these) and realign to the end.
|
|
423
478
|
ArkSaveLogger.warning_log(
|
|
424
|
-
f"Array
|
|
479
|
+
f"Array of struct '{array_content_type}' read incorrectly, "
|
|
480
|
+
f"bytes off: {array_end - bb.position}; realigning to end of array"
|
|
425
481
|
)
|
|
426
|
-
ArkSaveLogger.
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
# if array_content_type == "PrimalCharacterStatusValueModifier":
|
|
432
|
-
# ArkSaveLogger.set_log_level(ArkSaveLogger.LogTypes.PARSER, False)
|
|
482
|
+
ArkSaveLogger._notify_struct_mismatch(
|
|
483
|
+
array_content_type, data_size, data_start_position, bb.position, bb
|
|
484
|
+
)
|
|
485
|
+
bb.set_position(array_end)
|
|
433
486
|
|
|
434
487
|
return prop, start_values_pos
|
|
435
488
|
|
|
@@ -511,7 +564,12 @@ class ArkProperty:
|
|
|
511
564
|
ark_struct_type = ArkStructType.from_type_name(struct_type)
|
|
512
565
|
|
|
513
566
|
if (ark_struct_type is not None) or in_array:
|
|
514
|
-
|
|
567
|
+
# Known fixed-layout structs (LinearColor/Vector/Color/...) are packed
|
|
568
|
+
# primitives with no None terminator. In archive parsing there is no name
|
|
569
|
+
# table, so peek_name() falls back to read_string() and would mis-read their
|
|
570
|
+
# packed float bytes as a string length, overflowing the buffer. Skip the
|
|
571
|
+
# None probe for these and let the dedicated reader consume the exact bytes.
|
|
572
|
+
if in_array and ark_struct_type not in _STRUCT_READERS and bb.peek_name() == "None":
|
|
515
573
|
ArkSaveLogger.parser_log("Exiting struct (None marker)")
|
|
516
574
|
return bb.read_name()
|
|
517
575
|
if data_size <= 4:
|
|
@@ -521,34 +579,38 @@ class ArkProperty:
|
|
|
521
579
|
ArkSaveLogger.parser_log(f"Reading struct {struct_type} with data size {data_size}")
|
|
522
580
|
return _STRUCT_READERS[ark_struct_type](bb, data_size)
|
|
523
581
|
if in_array:
|
|
582
|
+
# No dedicated reader for this struct type. Fall through to the
|
|
583
|
+
# generic property-list read below — the designed backup for unknown
|
|
584
|
+
# structs in arrays. It reads cleanly for well-formed, None-terminated
|
|
585
|
+
# property-list structs, and read_array_property validates the array's
|
|
586
|
+
# total size and recovers from any type it can't fully consume, so
|
|
587
|
+
# this is not by itself an error. Record the type once (quietly) so it
|
|
588
|
+
# is discoverable without the noise of a per-type warning.
|
|
524
589
|
if struct_type not in UNSUPPORTED_STRUCTS:
|
|
525
|
-
ArkSaveLogger.
|
|
590
|
+
ArkSaveLogger.parser_log(
|
|
591
|
+
f"No dedicated reader for struct '{struct_type}' in array; "
|
|
592
|
+
f"reading generically as a property list"
|
|
593
|
+
)
|
|
526
594
|
UNSUPPORTED_STRUCTS.append(struct_type)
|
|
527
|
-
|
|
528
|
-
# uncomment the lines below if you want to make objects of unknown structs
|
|
529
|
-
# ArkSaveLogger.parser_log(f"Reading struct {struct_type} as array")
|
|
530
|
-
# bb.structured_print(to_default_file=True)
|
|
531
|
-
# bb.store()
|
|
532
|
-
# ArkSaveLogger.error_log(f"Unsupported struct type {struct_type} in array")
|
|
533
|
-
# ArkSaveLogger.open_hex_view(True)
|
|
534
|
-
# raise ValueError(f"Unsupported struct type {struct_type}")
|
|
535
595
|
|
|
536
596
|
ArkSaveLogger.parser_log(f"Reading struct {struct_type} with data size {data_size} as property list at position {bb.get_position()}")
|
|
537
597
|
# Fallback: struct as property list
|
|
538
598
|
position = bb.get_position()
|
|
539
|
-
props = ArkProperty.read_struct_properties(bb)
|
|
599
|
+
props = ArkProperty.read_struct_properties(bb, struct_end=position + data_size)
|
|
540
600
|
if bb.get_position() != position + data_size and not in_array:
|
|
541
601
|
ArkSaveLogger.warning_log(f"WARNING: Struct reading position mismatch for type {struct_type}")
|
|
542
602
|
ArkSaveLogger.warning_log(
|
|
543
603
|
f"StructType: {struct_type}, DataSize: {data_size}, Position: {position}, CurrentPosition: {bb.get_position()}"
|
|
544
604
|
)
|
|
605
|
+
# Notify any registered debug handler (e.g. the testbench recorder).
|
|
606
|
+
ArkSaveLogger._notify_struct_mismatch(struct_type, data_size, position, bb.get_position(), bb)
|
|
545
607
|
bb.set_position(position + data_size)
|
|
546
608
|
return props
|
|
547
609
|
|
|
548
610
|
@staticmethod
|
|
549
|
-
def read_struct_properties(bb: "ArkBinaryParser") -> ArkPropertyContainer:
|
|
611
|
+
def read_struct_properties(bb: "ArkBinaryParser", struct_end: int = -1) -> ArkPropertyContainer:
|
|
550
612
|
props: List[ArkProperty] = []
|
|
551
|
-
struct_property = ArkProperty.read_property(bb)
|
|
613
|
+
struct_property = ArkProperty.read_property(bb, struct_end=struct_end)
|
|
552
614
|
if struct_property is not None:
|
|
553
615
|
ArkSaveLogger.parser_log(
|
|
554
616
|
f"Struct properties: {struct_property.name} {struct_property.type} {struct_property.value}"
|
|
@@ -556,7 +618,7 @@ class ArkProperty:
|
|
|
556
618
|
while struct_property:
|
|
557
619
|
props.append(struct_property)
|
|
558
620
|
if bb.has_more():
|
|
559
|
-
struct_property = ArkProperty.read_property(bb)
|
|
621
|
+
struct_property = ArkProperty.read_property(bb, struct_end=struct_end)
|
|
560
622
|
if struct_property is not None:
|
|
561
623
|
ArkSaveLogger.parser_log(
|
|
562
624
|
f"Struct properties: {struct_property.name} {struct_property.type} {struct_property.value}"
|
|
@@ -92,7 +92,19 @@ class ArkCustomItemData:
|
|
|
92
92
|
# ark_binary_data.validate_uint32(0)
|
|
93
93
|
# self.skins.append([bp, shorthand])
|
|
94
94
|
|
|
95
|
-
ark_binary_data.validate_name("None")
|
|
95
|
+
ark_binary_data.validate_name("None")
|
|
96
|
+
|
|
97
|
+
# Some modded CustomItemData (e.g. the Cryopods mod) append extra empty
|
|
98
|
+
# trailing sections, each serialized as a [uint32 0][None] pair. Vanilla
|
|
99
|
+
# data has none of these, so this loop is a no-op there; the next array
|
|
100
|
+
# element starts with a real name ("CustomDataBytes") whose first 4 bytes
|
|
101
|
+
# are non-zero, which stops the loop.
|
|
102
|
+
while (ark_binary_data.size() - ark_binary_data.position) >= 12 \
|
|
103
|
+
and ark_binary_data.peek_int() == 0 \
|
|
104
|
+
and ark_binary_data.peek_name(4) == "None":
|
|
105
|
+
ark_binary_data.read_uint32() # 0
|
|
106
|
+
ark_binary_data.read_name() # None
|
|
107
|
+
ArkSaveLogger.parser_log("Consumed trailing [0][None] padding in CustomItemData")
|
|
96
108
|
|
|
97
109
|
ArkSaveLogger.parser_log(f"CustomItemData of type {self.custom_data_name} read successfully, total size: {total_size} bytes")
|
|
98
110
|
for string in self.strings:
|
|
@@ -335,10 +347,17 @@ class ArkCustomItemData:
|
|
|
335
347
|
nr_of_items = ark_binary_data.read_uint32()
|
|
336
348
|
soft_classes = []
|
|
337
349
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
350
|
+
# Each soft-class entry is an FSoftObjectPath.
|
|
351
|
+
# - With name table (game saves): single FName (name_id + always_zero) + SubPathString.
|
|
352
|
+
# - Without name table (archives, UE 5.5): FTopLevelAssetPath — PackageName string
|
|
353
|
+
# + AssetName string — followed by SubPathString.
|
|
354
|
+
has_name_table = ark_binary_data.save_context.has_name_table()
|
|
355
|
+
for _ in range(nr_of_items):
|
|
356
|
+
pkg_name = ark_binary_data.read_name() # PackageName (or full path when name table)
|
|
357
|
+
if not has_name_table:
|
|
358
|
+
ark_binary_data.read_name() # AssetName (archives only)
|
|
359
|
+
ark_binary_data.read_string() # SubPathString (usually empty)
|
|
360
|
+
soft_classes.append(pkg_name)
|
|
342
361
|
|
|
343
362
|
return soft_classes
|
|
344
363
|
|
|
@@ -182,7 +182,7 @@ class SaveConnection:
|
|
|
182
182
|
obj_uuid = _fast_uuid_from_bytes(key_bytes)
|
|
183
183
|
try:
|
|
184
184
|
reader = ArkBinaryParser(value_bytes, self.save_context)
|
|
185
|
-
class_name, _ = ArkGameObject.read_name(obj_uuid, reader)
|
|
185
|
+
class_name, *_ = ArkGameObject.read_name(obj_uuid, reader)
|
|
186
186
|
self._class_cache[obj_uuid] = class_name
|
|
187
187
|
except Exception:
|
|
188
188
|
pass
|
|
@@ -192,7 +192,7 @@ class SaveConnection:
|
|
|
192
192
|
return self._class_cache[obj_uuid]
|
|
193
193
|
bin = self.get_game_obj_binary(obj_uuid)
|
|
194
194
|
reader = ArkBinaryParser(bin, self.save_context)
|
|
195
|
-
class_name,
|
|
195
|
+
class_name, *_ = ArkGameObject.read_name(obj_uuid, reader)
|
|
196
196
|
self._class_cache[obj_uuid] = class_name
|
|
197
197
|
return class_name
|
|
198
198
|
|
|
@@ -402,7 +402,10 @@ class SaveConnection:
|
|
|
402
402
|
cursor = conn.execute(query)
|
|
403
403
|
for row in cursor:
|
|
404
404
|
byte_buffer = ArkBinaryParser(row[0], self.save_context)
|
|
405
|
-
|
|
405
|
+
# String-name-aware read: some objects store their class as an
|
|
406
|
+
# inline string instead of a name-table id, which a raw
|
|
407
|
+
# read_name() can't resolve (raises when generate_unknown is off).
|
|
408
|
+
class_name, *_ = ArkGameObject.read_name(None, byte_buffer)
|
|
406
409
|
if class_name not in classes:
|
|
407
410
|
classes.append(class_name)
|
|
408
411
|
return classes
|
|
@@ -452,7 +455,7 @@ class SaveConnection:
|
|
|
452
455
|
bin = self.get_game_obj_binary(obj_uuid)
|
|
453
456
|
reader = ArkBinaryParser(bin, self.save_context)
|
|
454
457
|
|
|
455
|
-
class_name,
|
|
458
|
+
class_name, *_ = ArkGameObject.read_name(obj_uuid, reader)
|
|
456
459
|
|
|
457
460
|
obj = SaveConnection.parse_as_predefined_object(obj_uuid, class_name, reader)
|
|
458
461
|
|
|
@@ -488,7 +491,7 @@ class SaveConnection:
|
|
|
488
491
|
continue
|
|
489
492
|
|
|
490
493
|
byte_buffer = ArkBinaryParser(binary_data, self.save_context)
|
|
491
|
-
class_name, _ = ArkGameObject.read_name(obj_uuid, byte_buffer)
|
|
494
|
+
class_name, *_ = ArkGameObject.read_name(obj_uuid, byte_buffer)
|
|
492
495
|
|
|
493
496
|
if reader_config.blueprint_name_filter and not reader_config.blueprint_name_filter(class_name):
|
|
494
497
|
continue
|
|
@@ -609,10 +612,17 @@ class SaveConnection:
|
|
|
609
612
|
ArkSaveLogger.warning_log(f"Error parsing object {obj_uuid} of type {class_name}, skipping...")
|
|
610
613
|
else:
|
|
611
614
|
byte_buffer.structured_print(to_default_file=True)
|
|
615
|
+
if ArkSaveLogger._allow_invalid_mod_objects is False:
|
|
616
|
+
byte_buffer.find_names(type=2)
|
|
617
|
+
ArkSaveLogger.error_log(f"Error parsing mod object {obj_uuid} of type {class_name}: {e}")
|
|
618
|
+
reraise = True
|
|
612
619
|
ArkSaveLogger.warning_log(f"Error parsing non-standard object of type {class_name}")
|
|
613
620
|
|
|
614
621
|
# input("Press Enter to continue...")
|
|
615
622
|
|
|
623
|
+
# Notify any registered debug handler (e.g. the testbench dumper).
|
|
624
|
+
ArkSaveLogger._notify_object_failure(obj_uuid, class_name, byte_buffer, e, kind="game")
|
|
625
|
+
|
|
616
626
|
SaveConnection.failed_parses[class_name] = SaveConnection.failed_parses.get(class_name, 0) + 1
|
|
617
627
|
ArkSaveLogger.warning_log(f"Failed parses for this class: {SaveConnection.failed_parses[class_name]}")
|
|
618
628
|
|
|
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
|