arkparse 0.5.2__tar.gz → 0.5.4__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.
Files changed (193) hide show
  1. {arkparse-0.5.2 → arkparse-0.5.4}/PKG-INFO +1 -1
  2. {arkparse-0.5.2 → arkparse-0.5.4}/pyproject.toml +1 -1
  3. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/api/json_api.py +6 -1
  4. arkparse-0.5.4/src/arkparse/assets/GENESIS_Ocean.png +0 -0
  5. arkparse-0.5.4/src/arkparse/assets/GENESIS_OtherBiomes.png +0 -0
  6. arkparse-0.5.4/src/arkparse/assets/make_composite.py +171 -0
  7. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/classes/dinos.py +10 -3
  8. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/classes/placed_structures.py +5 -2
  9. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/enums/ark_map.py +9 -1
  10. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/ark_game_object.py +24 -4
  11. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/dinos/dino.py +1 -1
  12. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/_base_value_parser.py +2 -1
  13. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/ark_property.py +58 -24
  14. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/__init__.py +1 -0
  15. arkparse-0.5.4/src/arkparse/parsing/struct/actor_transform.py +423 -0
  16. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_struct_type.py +3 -0
  17. arkparse-0.5.4/src/arkparse/parsing/struct/ark_vector2d.py +38 -0
  18. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/saves/save_connection.py +8 -5
  19. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/utils/heatmap_visualization.py +4 -3
  20. arkparse-0.5.2/src/arkparse/parsing/struct/actor_transform.py +0 -412
  21. {arkparse-0.5.2 → arkparse-0.5.4}/.gitignore +0 -0
  22. {arkparse-0.5.2 → arkparse-0.5.4}/LICENSE +0 -0
  23. {arkparse-0.5.2 → arkparse-0.5.4}/README.md +0 -0
  24. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/__init__.py +0 -0
  25. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/api/__init__.py +0 -0
  26. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/api/base_api.py +0 -0
  27. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/api/dino_api.py +0 -0
  28. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/api/equipment_api.py +0 -0
  29. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/api/general_api.py +0 -0
  30. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/api/player_api.py +0 -0
  31. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/api/rcon_api.py +0 -0
  32. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/api/stackable_api.py +0 -0
  33. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/api/structure_api.py +0 -0
  34. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/ark_tribe.py +0 -0
  35. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/assets/ABERRATION.PNG +0 -0
  36. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/assets/LOST_COLONY.PNG +0 -0
  37. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/assets/RAGNAROK.PNG +0 -0
  38. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/assets/THE_ISLAND.PNG +0 -0
  39. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/assets/__init__.py +0 -0
  40. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/assets/heavy_inventory +0 -0
  41. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/assets/tamable_dinos.txt +0 -0
  42. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/assets/templates/equipment/armor +0 -0
  43. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/assets/templates/equipment/armor_bp +0 -0
  44. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/assets/templates/equipment/armor_bp_n.json +0 -0
  45. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/assets/templates/equipment/armor_n.json +0 -0
  46. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/assets/templates/equipment/saddle +0 -0
  47. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/assets/templates/equipment/saddle_bp +0 -0
  48. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/assets/templates/equipment/saddle_bp_n.json +0 -0
  49. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/assets/templates/equipment/saddle_n.json +0 -0
  50. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/assets/templates/equipment/shield +0 -0
  51. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/assets/templates/equipment/shield_bp +0 -0
  52. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/assets/templates/equipment/shield_bp_n.json +0 -0
  53. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/assets/templates/equipment/shield_n.json +0 -0
  54. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/assets/templates/equipment/weapon +0 -0
  55. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/assets/templates/equipment/weapon_bp +0 -0
  56. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/assets/templates/equipment/weapon_bp_n.json +0 -0
  57. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/assets/templates/equipment/weapon_n.json +0 -0
  58. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/assets/templates/inventory/with_item_n.json +0 -0
  59. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/assets/templates/stackable/stackable +0 -0
  60. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/assets/templates/stackable/stackable_n.json +0 -0
  61. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/assets/templates/trait/trait +0 -0
  62. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/assets/templates/trait/trait_n.json +0 -0
  63. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/classes/__init__.py +0 -0
  64. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/classes/consumables.py +0 -0
  65. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/classes/equipment.py +0 -0
  66. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/classes/player.py +0 -0
  67. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/classes/resources.py +0 -0
  68. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/classes/traits.py +0 -0
  69. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/enums/__init__.py +0 -0
  70. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/enums/ark_dino_trait.py +0 -0
  71. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/enums/ark_enum.py +0 -0
  72. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/enums/ark_equipment_stat.py +0 -0
  73. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/enums/ark_item_quality.py +0 -0
  74. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/enums/ark_stat.py +0 -0
  75. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/ftp/__init__.py +0 -0
  76. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/ftp/ark_ftp_client.py +0 -0
  77. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/helpers/dino/is_wild_tamed.py +0 -0
  78. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/logging/__init__.py +0 -0
  79. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/logging/ark_save_logger.py +0 -0
  80. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/bases/base.py +0 -0
  81. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/cluster_data/ark_cluster_data.py +0 -0
  82. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/cluster_data/cluster_data_dino.py +0 -0
  83. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/cluster_data/cluster_data_item.py +0 -0
  84. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/cryopods/cryopod.py +0 -0
  85. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/dinos/__init__.py +0 -0
  86. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/dinos/baby.py +0 -0
  87. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/dinos/dino_ai_controller.py +0 -0
  88. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/dinos/dino_id.py +0 -0
  89. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/dinos/pedigree.py +0 -0
  90. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/dinos/stats.py +0 -0
  91. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/dinos/tamed_baby.py +0 -0
  92. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/dinos/tamed_dino.py +0 -0
  93. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/equipment/__armor_defaults.py +0 -0
  94. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/equipment/__equipment.py +0 -0
  95. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/equipment/__equipment_with_armor.py +0 -0
  96. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/equipment/__equipment_with_durability.py +0 -0
  97. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/equipment/__init__.py +0 -0
  98. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/equipment/armor.py +0 -0
  99. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/equipment/saddle.py +0 -0
  100. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/equipment/shield.py +0 -0
  101. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/equipment/weapon.py +0 -0
  102. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/misc/__parsed_object_base.py +0 -0
  103. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/misc/dino_owner.py +0 -0
  104. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/misc/inventory.py +0 -0
  105. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/misc/inventory_item.py +0 -0
  106. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/misc/object_crafter.py +0 -0
  107. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/misc/object_owner.py +0 -0
  108. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/misc/trait.py +0 -0
  109. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/stackables/__init__.py +0 -0
  110. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/stackables/_stackable.py +0 -0
  111. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/stackables/ammo.py +0 -0
  112. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/stackables/resource.py +0 -0
  113. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/structures/__init__.py +0 -0
  114. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/structures/structure.py +0 -0
  115. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/object_model/structures/structure_with_inventory.py +0 -0
  116. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/__init__.py +0 -0
  117. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/_base_value_validator.py +0 -0
  118. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/_binary_reader_base.py +0 -0
  119. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/_byte_operator.py +0 -0
  120. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/_fast_shim.py +0 -0
  121. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/_legacy_parsing/__init__.py +0 -0
  122. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/_legacy_parsing/_property_insertor.py +0 -0
  123. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/_legacy_parsing/_property_parser.py +0 -0
  124. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/_legacy_parsing/_property_replacer.py +0 -0
  125. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/_legacy_parsing/ark_binary_parser.py +0 -0
  126. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/_legacy_parsing/ark_property.py +0 -0
  127. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/_legacy_parsing/struct/__init__.py +0 -0
  128. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/_legacy_parsing/struct/ark_dino_ancestor_entry.py +0 -0
  129. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/_legacy_parsing/struct/ark_item_net_id.py +0 -0
  130. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/_legacy_parsing/struct/ark_my_persistent_buff_datas.py +0 -0
  131. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/_legacy_parsing/struct/ark_object_property.py +0 -0
  132. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/_legacy_parsing/struct/ark_struct_type.py +0 -0
  133. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/_legacy_parsing/struct/ark_tracked_actor_id_category_pair_with_bool.py +0 -0
  134. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/_legacy_parsing/struct/ark_unique_net_id_repl.py +0 -0
  135. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/_legacy_parsing/struct/ark_vector.py +0 -0
  136. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/_legacy_parsing/struct/ark_vector_bool_pair.py +0 -0
  137. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/_property_insertor.py +0 -0
  138. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/_property_parser.py +0 -0
  139. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/_property_replacer.py +0 -0
  140. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/ark_archive.py +0 -0
  141. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/ark_binary_parser.py +0 -0
  142. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/ark_object.py +0 -0
  143. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/ark_property_container.py +0 -0
  144. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/ark_set.py +0 -0
  145. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/ark_value_type.py +0 -0
  146. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/array_property.py +0 -0
  147. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/game_object_reader_configuration.py +0 -0
  148. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_color.py +0 -0
  149. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_crafting_resource_requirement.py +0 -0
  150. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_custom_item_data.py +0 -0
  151. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_dino_ancestor_entry.py +0 -0
  152. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_dino_order_id.py +0 -0
  153. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_gacha_resource_struct.py +0 -0
  154. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_gene_trait_struct.py +0 -0
  155. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_gigantoraptor_bonded_struct.py +0 -0
  156. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_int_point.py +0 -0
  157. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_item_craft_queue_entry.py +0 -0
  158. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_item_net_id.py +0 -0
  159. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_key_value_pair.py +0 -0
  160. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_linear_color.py +0 -0
  161. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_milestone_tree_level_and_index.py +0 -0
  162. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_my_persistent_buff_datas.py +0 -0
  163. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_object_property.py +0 -0
  164. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_painting_key_value.py +0 -0
  165. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_patrol_group_saved_data.py +0 -0
  166. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_player_death_reason.py +0 -0
  167. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_primal_saddle_structure.py +0 -0
  168. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_quat.py +0 -0
  169. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_rotator.py +0 -0
  170. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_server_custom_folder.py +0 -0
  171. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_tracked_actor_id_category_pair.py +0 -0
  172. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_tracked_actor_id_category_pair_with_bool.py +0 -0
  173. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_tribe_alliance.py +0 -0
  174. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_tribe_rank_group.py +0 -0
  175. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_unique_net_id_repl.py +0 -0
  176. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_vector.py +0 -0
  177. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/ark_vector_bool_pair.py +0 -0
  178. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/object_reference.py +0 -0
  179. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/parsing/struct/unknown_struct.py +0 -0
  180. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/player/ark_character_config.py +0 -0
  181. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/player/ark_character_stats.py +0 -0
  182. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/player/ark_persistent_buff_data.py +0 -0
  183. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/player/ark_player.py +0 -0
  184. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/player/ark_tribute_item.py +0 -0
  185. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/saves/__init__.py +0 -0
  186. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/saves/asa_save.py +0 -0
  187. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/saves/header_location.py +0 -0
  188. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/saves/save_context.py +0 -0
  189. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/utils/__init__.py +0 -0
  190. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/utils/import_file.py +0 -0
  191. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/utils/json_utils.py +0 -0
  192. {arkparse-0.5.2 → arkparse-0.5.4}/src/arkparse/utils/map_images.py +0 -0
  193. {arkparse-0.5.2 → arkparse-0.5.4}/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.2
3
+ Version: 0.5.4
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>
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "arkparse"
7
- version = "0.5.2"
7
+ version = "0.5.4"
8
8
  dependencies = [
9
9
  "rcon>=2.4.9",
10
10
  "numpy>=2.3.2",
@@ -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
- class_name = byte_buffer.read_name()
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 \
@@ -0,0 +1,171 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ make_composite.py
4
+
5
+ Downloads map tiles from a tile server and composites them into a single image.
6
+ Auto-detects grid size using binary search.
7
+
8
+ Requires: Pillow (PIL)
9
+ pip install pillow
10
+ """
11
+ from __future__ import annotations
12
+
13
+ import io
14
+ import os
15
+ import sys
16
+ from typing import List
17
+ from urllib.request import urlopen, Request
18
+ from urllib.error import HTTPError
19
+ from pathlib import Path
20
+
21
+ try:
22
+ from PIL import Image
23
+ except Exception as e:
24
+ print("Pillow is required: pip install pillow", file=sys.stderr)
25
+ raise
26
+
27
+ # Headers to mimic a browser request
28
+ HEADERS = {
29
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
30
+ "Accept": "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8",
31
+ "Referer": "https://wikily.gg/",
32
+ }
33
+
34
+ TILE_SIZE = 256
35
+
36
+
37
+ def tile_exists(base_url: str, zoom: int, x: int, y: int) -> bool:
38
+ """Check if a tile exists at the given coordinates."""
39
+ url = f"{base_url}/{zoom}/{x}/{y}.png"
40
+ try:
41
+ req = Request(url, headers=HEADERS, method='HEAD')
42
+ with urlopen(req, timeout=10) as resp:
43
+ return resp.status == 200
44
+ except HTTPError:
45
+ return False
46
+ except Exception:
47
+ # Try GET as fallback (some servers don't support HEAD)
48
+ try:
49
+ req = Request(url, headers=HEADERS)
50
+ with urlopen(req, timeout=10) as resp:
51
+ return resp.status == 200
52
+ except:
53
+ return False
54
+
55
+
56
+ def find_grid_size(base_url: str, zoom: int) -> int:
57
+ """
58
+ Binary search to find the grid size (number of tiles per side).
59
+ Assumes square grid starting at 0,0.
60
+ """
61
+ print(f"Detecting grid size for zoom {zoom}...")
62
+
63
+ # First, verify tile 0,0 exists
64
+ if not tile_exists(base_url, zoom, 0, 0):
65
+ raise SystemExit(f"Tile 0,0 does not exist at {base_url}/{zoom}/")
66
+
67
+ # Binary search for max coordinate
68
+ low, high = 1, 256 # reasonable upper bound
69
+
70
+ # First find an upper bound that doesn't exist
71
+ while tile_exists(base_url, zoom, high - 1, 0):
72
+ high *= 2
73
+ if high > 1024:
74
+ raise SystemExit("Grid size exceeds reasonable limit (1024)")
75
+
76
+ # Binary search
77
+ while low < high:
78
+ mid = (low + high) // 2
79
+ if tile_exists(base_url, zoom, mid, 0):
80
+ low = mid + 1
81
+ else:
82
+ high = mid
83
+
84
+ grid_size = low
85
+ print(f"Detected grid size: {grid_size}x{grid_size} tiles")
86
+ return grid_size
87
+
88
+
89
+ def download_image(url: str) -> Image.Image:
90
+ """Download an image from URL and return as PIL Image."""
91
+ req = Request(url, headers=HEADERS)
92
+ with urlopen(req, timeout=30) as resp:
93
+ data = resp.read()
94
+ return Image.open(io.BytesIO(data)).convert("RGBA")
95
+
96
+
97
+ def compose_map(base_url: str, zoom: int, out_path: str) -> None:
98
+ """Download all tiles for a zoom level and compose into single image."""
99
+ grid_size = find_grid_size(base_url, zoom)
100
+
101
+ width = grid_size * TILE_SIZE
102
+ height = grid_size * TILE_SIZE
103
+ total_tiles = grid_size * grid_size
104
+
105
+ print(f"Canvas size: {width}x{height} ({total_tiles} tiles)")
106
+
107
+ canvas = Image.new("RGBA", (width, height), (0, 0, 0, 0))
108
+
109
+ downloaded = 0
110
+ failed = 0
111
+
112
+ for y in range(grid_size):
113
+ for x in range(grid_size):
114
+ tile_num = y * grid_size + x + 1
115
+ url = f"{base_url}/{zoom}/{x}/{y}.png"
116
+ print(f"Downloading tile {tile_num}/{total_tiles}: {zoom}/{x}/{y}.png", end="")
117
+
118
+ try:
119
+ img = download_image(url)
120
+ if img.size != (TILE_SIZE, TILE_SIZE):
121
+ img = img.resize((TILE_SIZE, TILE_SIZE))
122
+
123
+ paste_x = x * TILE_SIZE
124
+ paste_y = y * TILE_SIZE
125
+ canvas.paste(img, (paste_x, paste_y))
126
+ downloaded += 1
127
+ print(" OK")
128
+ except Exception as e:
129
+ print(f" FAILED: {e}")
130
+ failed += 1
131
+
132
+ print(f"\nDownloaded: {downloaded}, Failed: {failed}")
133
+
134
+ # Save
135
+ os.makedirs(os.path.dirname(out_path) or ".", exist_ok=True)
136
+ canvas.convert("RGB").save(out_path, format="PNG")
137
+ print(f"Saved -> {out_path}")
138
+
139
+
140
+ def main() -> None:
141
+ # Configuration
142
+ output_dir = Path(__file__).parent
143
+ zoom = 5
144
+
145
+ # List of maps to download: (base_url, output_name)
146
+ maps: List[tuple[str, str]] = [
147
+ ("https://r2.wikily.gg/images/ark/maps/lost_colony_tiles", "LOST_COLONY.png"),
148
+ ("https://r2.wikily.gg/images/ark/maps/valguero_tiles", "VALGUERO.png"),
149
+ ("https://r2.wikily.gg/images/ark/maps/aberration_tiles", "ABERRATION.png"),
150
+ ("https://r2.wikily.gg/images/ark/maps/ragnarok_tiles", "RAGNAROK.png"),
151
+ ("https://r2.wikily.gg/images/ark/maps/the_island_tiles", "THE_ISLAND.png"),
152
+ ("https://r2.wikily.gg/images/ark/maps/genesis_tiles", "GENESIS_BIOMES.png"),
153
+ ("https://r2.wikily.gg/images/ark/maps/genesisocean_tiles", "GENESIS_OCEAN.png"),
154
+ ]
155
+
156
+ for base_url, output_name in maps:
157
+ print(f"\n{'='*60}")
158
+ print(f"Processing: {output_name}")
159
+ print(f"Base URL: {base_url}")
160
+ print(f"Zoom: {zoom}")
161
+ print('='*60)
162
+
163
+ out_path = os.path.join(output_dir, output_name)
164
+ try:
165
+ compose_map(base_url, zoom, out_path)
166
+ except Exception as e:
167
+ print(f"ERROR processing {output_name}: {e}", file=sys.stderr)
168
+
169
+
170
+ if __name__ == "__main__":
171
+ main()
@@ -139,7 +139,11 @@ class DlcDinos:
139
139
  malwyn = "/Game/LostColony/Dinos/SnowDragon/SnowDragon_Character_BP.SnowDragon_Character_BP_C"
140
140
  ossidon = "/Game/LostColony/Dinos/SnowMonster/SnowMonster_Character_BP.SnowMonster_Character_BP_C"
141
141
  gloon = "/Game/LostColony/Dinos/LostChargePet/LostCharge_LanternPet_Char_BP.LostCharge_LanternPet_Char_BP_C"
142
- all_bps = [firemane, archelon, dread_mare, oasisaur, train, helper_bot, zeppelin, doggo, veilwyn, elderclaw, solwyn, malwyn, ossidon, gloon]
142
+ lumina = "/Game/Dragontopia/Dragons/Eclipsar/Lumina/Lumina_Character_BP.Lumina_Character_BP_C"
143
+ umbra = "/Game/Dragontopia/Dragons/Eclipsar/Umbra/Umbra_Character_BP.Umbra_Character_BP_C"
144
+ brig_ship = "/Game/Water/Vessels/Brig/BrigShipBP.BrigShipBP_C"
145
+ sloop_ship = "/Game/Water/Vessels/Sloop/SloopShipBP.SloopShipBP_C"
146
+ all_bps = [firemane, archelon, dread_mare, oasisaur, train, helper_bot, zeppelin, doggo, veilwyn, elderclaw, solwyn, malwyn, ossidon, gloon, lumina, umbra, brig_ship, sloop_ship]
143
147
 
144
148
  class ShoulderPets:
145
149
  glowtail = "/Game/Aberration/Dinos/LanternLizard/LanternLizard_Character_BP.LanternLizard_Character_BP_C"
@@ -223,6 +227,8 @@ class NonTameable:
223
227
  tek_giga = "/Game/PrimalEarth/Dinos/Giganotosaurus/BionicGigant_Character_BP.BionicGigant_Character_BP_C"
224
228
  leedsichthys = "/Game/PrimalEarth/Dinos/Leedsichthys/Leedsichthys_Character_BP.Leedsichthys_Character_BP_C"
225
229
  yeti = "/Game/PrimalEarth/Dinos/Bigfoot/Yeti_Character_BP.Yeti_Character_BP_C"
230
+ insect_swarm = "/Game/Genesis/Dinos/Swarms/InsectSwarmChar_BP.InsectSwarmChar_BP_C"
231
+ microbe_swarm = "/Game/Genesis/Dinos/Swarms/MicrobeSwarmChar_BP.MicrobeSwarmChar_BP_C"
226
232
  corrupted = Corrupted()
227
233
  alpha = Alphas()
228
234
  event = event()
@@ -233,7 +239,7 @@ class NonTameable:
233
239
  coelacanth_ocean, leech, leech_diseased, piranha,
234
240
  sabertooth_salmon, trilobite, death_worm, jugbug_oil, jugbug_water,
235
241
  enforcer, scout, defence_unit, polar_bear, iceworm, tek_giga,
236
- leedsichthys, yeti
242
+ leedsichthys, yeti, insect_swarm, microbe_swarm
237
243
  ] + corrupted.all_bps + alpha.all_bps + event.all_bps
238
244
 
239
245
  class Paleo:
@@ -382,6 +388,7 @@ class Dinos:
382
388
  helicoprion = "/Game/ASA/Dinos/Helicoprion/Helicoprion_Character_BP.Helicoprion_Character_BP_C"
383
389
  acrocanthosaurus = "/Game/ASA/Dinos/Acrocanthosaurus/Acrocanthosaurus_Character_BP.Acrocanthosaurus_Character_BP_C"
384
390
  cryolophosaurus = "/Game/ASA/Dinos/Cryolophosaurus/Cryolophosaurus_Character_BP.Cryolophosaurus_Character_BP_C"
391
+ magmasaur = "/Game/Genesis/Dinos/Cherufe/Cherufe_Character_BP"
385
392
 
386
393
  abberant = Abberant()
387
394
  paleo = Paleo()
@@ -416,7 +423,7 @@ class Dinos:
416
423
  dreadnoughtus, maelizard, shastasaurus, gacha, gasbag,
417
424
  managarmr, tek_raptor, tek_rex, tek_stego,
418
425
  velonosaur, yutyrannus, tek_parasaur, queen_bee,
419
- rubble_golem, helicoprion, acrocanthosaurus, cryolophosaurus
426
+ rubble_golem, helicoprion, acrocanthosaurus, cryolophosaurus, magmasaur
420
427
  ] + abberant.all_bps + flyers.all_bps + \
421
428
  dlc_dinos.all_bps + shoulder_pets.all_bps + non_tameable.all_bps + \
422
429
  paleo.all_bps
@@ -96,8 +96,9 @@ class Crafting:
96
96
  cooking_pot = "/Game/PrimalEarth/Structures/CookingPot.CookingPot_C"
97
97
  grill = "/Game/PrimalEarth/Structures/Grill.Grill_C"
98
98
  chembench = "/Game/PrimalEarth/Structures/StorageBox_ChemBench.StorageBox_ChemBench_C"
99
+ blood_forge = "/Game/LostColony/Structures/Bloodforge/Inventory/InventoryComponent_Bloodforge.InventoryComponent_Bloodforge_C"
99
100
 
100
- all_bps = [forge, mortar_and_pestle, compost_bin, campfire, cooking_pot, grill, chembench]
101
+ all_bps = [forge, mortar_and_pestle, compost_bin, campfire, cooking_pot, grill, chembench, blood_forge]
101
102
 
102
103
  class Utility:
103
104
  simple_bed = "/Game/PrimalEarth/Structures/SimpleBed.SimpleBed_C"
@@ -112,9 +113,11 @@ class Utility:
112
113
  toilet = "/Game/PrimalEarth/Structures/Furniture/StructureBP_Toilet.StructureBP_Toilet_C"
113
114
  cryofridge = "/Game/Extinction/Structures/Cryofridge/CryoFridge.CryoFridge_C"
114
115
  deathitemcache = "/Game/PrimalEarth/Structures/DeathItemCache.DeathItemCache_C"
116
+ cryo_hospital = "/Game/LostColony/Structures/CryoHospital/Inventory/InventoryComponent_CryoHospital.InventoryComponent_CryoHospital_C"
117
+ medical_stand = "/Game/LostColony/Structures/MedicalStand/Inventories/InventoryComponent_MedicalStand.InventoryComponent_MedicalStand_C"
115
118
 
116
119
  all_bps = [simple_bed, sleeping_bag, anvil_bench, small_storage_box, large_bear_trap, large_storage_box,
117
- bunk_bed, vault, sleeping_pod, toilet, cryofridge, deathitemcache]
120
+ bunk_bed, vault, sleeping_pod, toilet, cryofridge, deathitemcache, cryo_hospital, medical_stand]
118
121
 
119
122
  class TributeTerminals:
120
123
  tribute_terminal_purple = "/Game/PrimalEarth/Structures/TributeTerminal_Purple.TributeTerminal_Purple_C"
@@ -15,10 +15,18 @@ class ArkMap(Enum):
15
15
  SVARTALFHEIM = 11
16
16
  CLUB_ARK = 12
17
17
  LOST_COLONY = 13
18
+ GENESIS1 = 14
18
19
 
19
20
  def to_file_name(self) -> str:
20
21
  """
21
22
  Converts the enum value to a file name.
22
23
  :return: The file name of the map.
23
24
  """
24
- return self.name.replace('_', ' ').title().replace(' ', '')
25
+ return self.name.replace('_', ' ').title().replace(' ', '')
26
+
27
+ class SubMap(Enum):
28
+ pass
29
+
30
+ class GenesisSubMap(Enum):
31
+ BIOMES = "OtherBiomes"
32
+ OCEAN = "Ocean"
@@ -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 = [
@@ -267,7 +267,7 @@ class Dino(ParsedObjectBase):
267
267
 
268
268
  # Grab gene traits if they exists
269
269
  if self.gene_traits is not None:
270
- json_obj["GeneTraits"] = self.gene_traits
270
+ json_obj["GeneTraits"] = [str(t) for t in self.gene_traits]
271
271
 
272
272
  # Grab colors if they exists
273
273
  color_set_indices = self.get_color_set_indices()
@@ -1,6 +1,6 @@
1
1
  import struct
2
2
  from typing import List
3
- from uuid import UUID
3
+ from uuid import UUID, SafeUUID
4
4
 
5
5
  from ._binary_reader_base import BinaryReaderBase
6
6
  from arkparse.logging import ArkSaveLogger
@@ -24,6 +24,7 @@ def _fast_uuid_from_bytes(b: bytes) -> UUID:
24
24
  # This is ~3-4x faster than UUID(bytes=b)
25
25
  u = object.__new__(UUID)
26
26
  object.__setattr__(u, 'int', int.from_bytes(b, 'big'))
27
+ object.__setattr__(u, 'is_safe', SafeUUID.unknown)
27
28
  return u
28
29
 
29
30
  class BaseValueParser(BinaryReaderBase):
@@ -11,6 +11,7 @@ from arkparse.parsing.struct.ark_linear_color import ArkLinearColor
11
11
  from arkparse.parsing.struct.ark_quat import ArkQuat
12
12
  from arkparse.parsing.struct.ark_rotator import ArkRotator
13
13
  from arkparse.parsing.struct.ark_vector import ArkVector
14
+ from arkparse.parsing.struct.ark_vector2d import ArkVector2D
14
15
  from arkparse.parsing.struct.ark_unique_net_id_repl import ArkUniqueNetIdRepl
15
16
  from arkparse.parsing.struct.ark_vector_bool_pair import ArkVectorBoolPair
16
17
  from arkparse.parsing.struct.ark_server_custom_folder import ArkServerCustomFolder
@@ -83,6 +84,7 @@ _STRUCT_READERS: Dict[ArkStructType, Callable[["ArkBinaryParser", int], Any]] =
83
84
  ArkStructType.Quat: lambda bb, ds: ArkQuat(bb),
84
85
  ArkStructType.Rotator: lambda bb, ds: ArkRotator(bb),
85
86
  ArkStructType.Vector: lambda bb, ds: ArkVector(bb),
87
+ ArkStructType.Vector2D: lambda bb, ds: ArkVector2D(bb, ds),
86
88
  ArkStructType.UniqueNetIdRepl: lambda bb, ds: ArkUniqueNetIdRepl(bb),
87
89
  ArkStructType.VectorBoolPair: lambda bb, ds: ArkVectorBoolPair(bb),
88
90
  ArkStructType.ArkTrackedActorIdCategoryPairWithBool: lambda bb, ds: ArkTrackedActorIdCategoryPairWithBool(bb),
@@ -397,6 +399,16 @@ class ArkProperty:
397
399
 
398
400
  return prop
399
401
 
402
+ @staticmethod
403
+ def _has_struct_reader(struct_type: str) -> bool:
404
+ """Whether this struct type has a dedicated (fixed-layout) reader.
405
+
406
+ Types without one are read generically as a property list; see
407
+ ``_read_struct_body`` and the guarded array backup in
408
+ ``read_array_property``.
409
+ """
410
+ return ArkStructType.from_type_name(struct_type) in _STRUCT_READERS
411
+
400
412
  @staticmethod
401
413
  def read_array_property(key: str, type_: str, position: int, bb: "ArkBinaryParser", data_size: int) -> Tuple["ArkProperty", int]:
402
414
  # V14 no position in array
@@ -428,31 +440,51 @@ class ArkProperty:
428
440
  bb.set_position(bb.position - 4)
429
441
 
430
442
  array_items = bb.read_uint32()
443
+ array_end = data_start_position + data_size
431
444
 
432
- # if array_content_type == "PrimalCharacterStatusValueModifier":
433
- # ArkSaveLogger.set_log_level(ArkSaveLogger.LogTypes.PARSER, True)
445
+ # Structs without a dedicated reader are read generically as a property
446
+ # list (see _read_struct_body). That backup is reliable for well-formed,
447
+ # None-terminated property-list structs but can't be guaranteed for an
448
+ # arbitrary packed layout, so guard it: if a generic element read raises,
449
+ # recover by skipping to the array's known end and record the type for
450
+ # follow-up rather than failing the whole object. A dedicated reader
451
+ # raising is a real bug, so let that propagate.
452
+ has_reader = ArkProperty._has_struct_reader(array_content_type)
434
453
 
435
454
  with log_block(f"Arr({array_content_type})"):
436
455
  ArkSaveLogger.parser_log(
437
456
  f"[STRUCT ARRAY: key='none'; nr_of_value={array_items}; type={array_content_type}; bin_length={data_size}]"
438
457
  )
439
- struct_array = [
440
- ArkProperty.read_struct_property(bb, data_size, array_content_type, True)[0]
441
- for _ in range(array_items)
442
- ]
458
+ struct_array = []
459
+ try:
460
+ for _ in range(array_items):
461
+ struct_array.append(
462
+ ArkProperty.read_struct_property(bb, data_size, array_content_type, True)[0]
463
+ )
464
+ except Exception as exc:
465
+ if has_reader:
466
+ raise
467
+ ArkSaveLogger.warning_log(
468
+ f"Generic read of struct array '{array_content_type}' failed after "
469
+ f"{len(struct_array)}/{array_items} element(s): {exc}; skipping to end of array"
470
+ )
471
+ ArkSaveLogger._notify_struct_mismatch(
472
+ array_content_type, data_size, data_start_position, bb.position, bb
473
+ )
474
+ bb.set_position(array_end)
443
475
 
444
476
  prop = ArkProperty(key, type_, position, 0, struct_array)
445
- if bb.position != data_start_position + data_size:
477
+ if bb.position != array_end:
478
+ # The read didn't consume exactly the declared size. Record the
479
+ # mismatch (the testbench captures these) and realign to the end.
446
480
  ArkSaveLogger.warning_log(
447
- f"Array read incorrectly, bytes left to read: {data_start_position + data_size - bb.position}, current position: {bb.position}"
481
+ f"Array of struct '{array_content_type}' read incorrectly, "
482
+ f"bytes off: {array_end - bb.position}; realigning to end of array"
448
483
  )
449
- ArkSaveLogger.warning_log(f"Skipping to the end of the struct, type: {array_content_type}")
450
- bb.set_position(data_start_position + data_size)
451
- bb.structured_print(to_default_file=True)
452
- ArkSaveLogger.open_hex_view(True)
453
-
454
- # if array_content_type == "PrimalCharacterStatusValueModifier":
455
- # ArkSaveLogger.set_log_level(ArkSaveLogger.LogTypes.PARSER, False)
484
+ ArkSaveLogger._notify_struct_mismatch(
485
+ array_content_type, data_size, data_start_position, bb.position, bb
486
+ )
487
+ bb.set_position(array_end)
456
488
 
457
489
  return prop, start_values_pos
458
490
 
@@ -549,17 +581,19 @@ class ArkProperty:
549
581
  ArkSaveLogger.parser_log(f"Reading struct {struct_type} with data size {data_size}")
550
582
  return _STRUCT_READERS[ark_struct_type](bb, data_size)
551
583
  if in_array:
584
+ # No dedicated reader for this struct type. Fall through to the
585
+ # generic property-list read below — the designed backup for unknown
586
+ # structs in arrays. It reads cleanly for well-formed, None-terminated
587
+ # property-list structs, and read_array_property validates the array's
588
+ # total size and recovers from any type it can't fully consume, so
589
+ # this is not by itself an error. Record the type once (quietly) so it
590
+ # is discoverable without the noise of a per-type warning.
552
591
  if struct_type not in UNSUPPORTED_STRUCTS:
553
- ArkSaveLogger.warning_log(f"Unsupported struct type {struct_type} in array")
592
+ ArkSaveLogger.parser_log(
593
+ f"No dedicated reader for struct '{struct_type}' in array; "
594
+ f"reading generically as a property list"
595
+ )
554
596
  UNSUPPORTED_STRUCTS.append(struct_type)
555
-
556
- # uncomment the lines below if you want to make objects of unknown structs
557
- # ArkSaveLogger.parser_log(f"Reading struct {struct_type} as array")
558
- # bb.structured_print(to_default_file=True)
559
- # bb.store()
560
- # ArkSaveLogger.error_log(f"Unsupported struct type {struct_type} in array")
561
- # ArkSaveLogger.open_hex_view(True)
562
- # raise ValueError(f"Unsupported struct type {struct_type}")
563
597
 
564
598
  ArkSaveLogger.parser_log(f"Reading struct {struct_type} with data size {data_size} as property list at position {bb.get_position()}")
565
599
  # Fallback: struct as property list
@@ -11,6 +11,7 @@ from .ark_tracked_actor_id_category_pair import ArkTrackedActorIdCategoryPair
11
11
  from .ark_unique_net_id_repl import ArkUniqueNetIdRepl
12
12
  from .ark_vector_bool_pair import ArkVectorBoolPair
13
13
  from .ark_vector import ArkVector
14
+ from .ark_vector2d import ArkVector2D
14
15
  from .object_reference import ObjectReference, get_uuid_reference_bytes
15
16
  from .unknown_struct import UnknownStruct
16
17
  from .ark_custom_item_data import ArkCustomItemData