fivefury 0.2.4__tar.gz → 0.2.5__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 (301) hide show
  1. {fivefury-0.2.4 → fivefury-0.2.5}/PKG-INFO +2 -2
  2. {fivefury-0.2.4 → fivefury-0.2.5}/README.md +1 -1
  3. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/__init__.py +160 -2
  4. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/assets/yft.py +3 -0
  5. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/bounds/geometry.py +5 -23
  6. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/bounds/model.py +157 -6
  7. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cache/assets.py +18 -9
  8. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cache/core.py +1 -0
  9. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cache/io.py +4 -2
  10. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cache/scan.py +1 -1
  11. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cache/views.py +18 -9
  12. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/dlc/model.py +2 -2
  13. fivefury-0.2.5/fivefury/dlc/xml.py +51 -0
  14. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/gtxd.py +44 -14
  15. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/pso/__init__.py +2 -0
  16. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/pso/codec.py +7 -1
  17. fivefury-0.2.5/fivefury/rbf.py +197 -0
  18. fivefury-0.2.5/fivefury/vector.py +150 -0
  19. {fivefury-0.2.4/fivefury/dlc → fivefury-0.2.5/fivefury}/xml.py +107 -17
  20. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/prepare.py +10 -32
  21. fivefury-0.2.5/fivefury/yft/__init__.py +91 -0
  22. fivefury-0.2.5/fivefury/yft/constants.py +47 -0
  23. fivefury-0.2.5/fivefury/yft/corpus.py +66 -0
  24. fivefury-0.2.5/fivefury/yft/drawable_reader.py +48 -0
  25. fivefury-0.2.5/fivefury/yft/drawables.py +26 -0
  26. fivefury-0.2.5/fivefury/yft/fields_reader.py +84 -0
  27. fivefury-0.2.5/fivefury/yft/fragment.py +309 -0
  28. fivefury-0.2.5/fivefury/yft/io_helpers.py +91 -0
  29. fivefury-0.2.5/fivefury/yft/model.py +66 -0
  30. fivefury-0.2.5/fivefury/yft/physics.py +805 -0
  31. fivefury-0.2.5/fivefury/yft/physics_authoring.py +259 -0
  32. fivefury-0.2.5/fivefury/yft/physics_reader.py +680 -0
  33. fivefury-0.2.5/fivefury/yft/physics_writer.py +407 -0
  34. fivefury-0.2.5/fivefury/yft/pointers.py +66 -0
  35. fivefury-0.2.5/fivefury/yft/reader.py +175 -0
  36. fivefury-0.2.5/fivefury/yft/stats.py +20 -0
  37. fivefury-0.2.5/fivefury/yft/validation.py +331 -0
  38. fivefury-0.2.5/fivefury/yft/writer.py +406 -0
  39. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ymap/timecycle.py +6 -13
  40. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ymap/utils.py +4 -24
  41. fivefury-0.2.5/fivefury/ymf/__init__.py +47 -0
  42. fivefury-0.2.5/fivefury/ymf/builder.py +284 -0
  43. fivefury-0.2.5/fivefury/ymf/enums.py +45 -0
  44. fivefury-0.2.5/fivefury/ymf/model.py +440 -0
  45. fivefury-0.2.5/fivefury/ymf/pso.py +269 -0
  46. fivefury-0.2.5/fivefury/ymf/resource.py +114 -0
  47. fivefury-0.2.5/fivefury/ymf/schema.py +119 -0
  48. fivefury-0.2.5/fivefury/ymf/utils.py +60 -0
  49. fivefury-0.2.5/fivefury/ymt/__init__.py +328 -0
  50. fivefury-0.2.5/fivefury/ymt/ped_metadata.py +131 -0
  51. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ymt/ped_variation.py +37 -18
  52. fivefury-0.2.5/fivefury/ymt/scenario.py +139 -0
  53. fivefury-0.2.5/fivefury/ymt/streaming.py +133 -0
  54. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ynd/model.py +2 -2
  55. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ytyp/lod.py +2 -7
  56. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury.egg-info/PKG-INFO +2 -2
  57. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury.egg-info/SOURCES.txt +34 -0
  58. {fivefury-0.2.4 → fivefury-0.2.5}/pyproject.toml +1 -1
  59. fivefury-0.2.5/tests/test_gtxd.py +252 -0
  60. {fivefury-0.2.4 → fivefury-0.2.5}/tests/test_pso.py +6 -0
  61. {fivefury-0.2.4 → fivefury-0.2.5}/tests/test_ybn.py +25 -0
  62. fivefury-0.2.5/tests/test_yft.py +412 -0
  63. fivefury-0.2.5/tests/test_ymf.py +175 -0
  64. {fivefury-0.2.4 → fivefury-0.2.5}/tests/test_ymt_ped_variation.py +40 -0
  65. fivefury-0.2.4/fivefury/ymf/__init__.py +0 -24
  66. fivefury-0.2.4/fivefury/ymt/__init__.py +0 -44
  67. {fivefury-0.2.4 → fivefury-0.2.5}/MANIFEST.in +0 -0
  68. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/_native.py +0 -0
  69. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/assets/__init__.py +0 -0
  70. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/assets/base.py +0 -0
  71. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/assets/ydd.py +0 -0
  72. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/assets/ydr.py +0 -0
  73. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/assets/ypt.py +0 -0
  74. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/awc/__init__.py +0 -0
  75. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/awc/audio.py +0 -0
  76. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/awc/constants.py +0 -0
  77. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/awc/conversion.py +0 -0
  78. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/awc/crypto.py +0 -0
  79. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/awc/io.py +0 -0
  80. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/awc/structures.py +0 -0
  81. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/binary.py +0 -0
  82. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/bounds/__init__.py +0 -0
  83. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/bounds/materials.py +0 -0
  84. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/bounds/reader.py +0 -0
  85. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/bounds/writer.py +0 -0
  86. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cache/__init__.py +0 -0
  87. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cache/kinds.py +0 -0
  88. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cache/paths.py +0 -0
  89. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/colors.py +0 -0
  90. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/common.py +0 -0
  91. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/crypto/__init__.py +0 -0
  92. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/crypto/backends.py +0 -0
  93. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/crypto/keys.py +0 -0
  94. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cut/__init__.py +0 -0
  95. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cut/analysis.py +0 -0
  96. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cut/dsl.py +0 -0
  97. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cut/events.py +0 -0
  98. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cut/flags.py +0 -0
  99. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cut/lights.py +0 -0
  100. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cut/model.py +0 -0
  101. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cut/names.py +0 -0
  102. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cut/payloads.py +0 -0
  103. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cut/pso.py +0 -0
  104. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cut/scene/__init__.py +0 -0
  105. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cut/scene/base.py +0 -0
  106. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cut/scene/bindings.py +0 -0
  107. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cut/scene/core.py +0 -0
  108. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cut/scene/event_api.py +0 -0
  109. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cut/scene/io.py +0 -0
  110. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cut/scene/shared.py +0 -0
  111. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cut/scene/subtitles.py +0 -0
  112. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cut/scene/timeline.py +0 -0
  113. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cut/scene/validation.py +0 -0
  114. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cut/schema.py +0 -0
  115. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cut/write.py +0 -0
  116. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/cut/xml.py +0 -0
  117. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/data/lut.dat +0 -0
  118. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/data/magic.dat +0 -0
  119. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/data/ng.dat +0 -0
  120. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/dlc/__init__.py +0 -0
  121. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/dlc/enums.py +0 -0
  122. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/dlc/highlevel.py +0 -0
  123. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/game_target.py +0 -0
  124. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/gamefile.py +0 -0
  125. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/gxt2.py +0 -0
  126. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/hashing.py +0 -0
  127. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/meta/__init__.py +0 -0
  128. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/meta/backed.py +0 -0
  129. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/meta/builder.py +0 -0
  130. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/meta/defs.py +0 -0
  131. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/meta/read.py +0 -0
  132. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/meta/resource.py +0 -0
  133. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/meta/utils.py +0 -0
  134. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/metahash.py +0 -0
  135. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/pso/model.py +0 -0
  136. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/pso/reader.py +0 -0
  137. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/pso/schema.py +0 -0
  138. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/pso/writer.py +0 -0
  139. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/rel/__init__.py +0 -0
  140. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/rel/enums.py +0 -0
  141. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/rel/io.py +0 -0
  142. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/rel/model.py +0 -0
  143. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/resolver.py +0 -0
  144. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/resource.py +0 -0
  145. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/resource_textures.py +0 -0
  146. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/rpf/__init__.py +0 -0
  147. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/rpf/convert.py +0 -0
  148. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/rpf/entries.py +0 -0
  149. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/rpf/utils.py +0 -0
  150. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/texture.py +0 -0
  151. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ybn/__init__.py +0 -0
  152. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ycd/__init__.py +0 -0
  153. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ycd/cutscene.py +0 -0
  154. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ycd/model.py +0 -0
  155. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ycd/reader.py +0 -0
  156. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ycd/sequence_channels.py +0 -0
  157. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ycd/sequence_codec.py +0 -0
  158. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ycd/sequence_tracks.py +0 -0
  159. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ycd/sequences.py +0 -0
  160. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ycd/write.py +0 -0
  161. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydd/__init__.py +0 -0
  162. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydd/model.py +0 -0
  163. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydd/reader.py +0 -0
  164. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydd/rigging.py +0 -0
  165. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydd/writer.py +0 -0
  166. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/Shaders.xml +0 -0
  167. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/ShadersGen9Conversion.xml +0 -0
  168. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/__init__.py +0 -0
  169. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/_helpers.py +0 -0
  170. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/assimp.py +0 -0
  171. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/build_types.py +0 -0
  172. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/builder.py +0 -0
  173. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/collision.py +0 -0
  174. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/defs.py +0 -0
  175. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/gen9.py +0 -0
  176. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/gen9_shader_enums.py +0 -0
  177. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/gen9_shader_info.py +0 -0
  178. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/materials.py +0 -0
  179. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/model.py +0 -0
  180. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/read_joints.py +0 -0
  181. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/read_lights.py +0 -0
  182. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/read_materials.py +0 -0
  183. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/read_skeleton.py +0 -0
  184. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/reader.py +0 -0
  185. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/rigging.py +0 -0
  186. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/shader_enums.py +0 -0
  187. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/shader_info.py +0 -0
  188. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/shaders.py +0 -0
  189. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/write_buffers.py +0 -0
  190. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/write_drawable.py +0 -0
  191. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/write_geometry.py +0 -0
  192. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/write_joints.py +0 -0
  193. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/write_lights.py +0 -0
  194. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/write_materials.py +0 -0
  195. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/write_models.py +0 -0
  196. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ydr/write_skeleton.py +0 -0
  197. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/yed/__init__.py +0 -0
  198. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/yed/audit.py +0 -0
  199. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/yed/constants.py +0 -0
  200. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/yed/enums.py +0 -0
  201. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/yed/instructions.py +0 -0
  202. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/yed/model.py +0 -0
  203. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/yed/ped.py +0 -0
  204. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/yed/reader.py +0 -0
  205. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/yed/writer.py +0 -0
  206. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ymap/__init__.py +0 -0
  207. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ymap/base.py +0 -0
  208. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ymap/blocks.py +0 -0
  209. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ymap/cargens.py +0 -0
  210. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ymap/defs.py +0 -0
  211. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ymap/entities.py +0 -0
  212. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ymap/enums.py +0 -0
  213. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ymap/extension_defs.py +0 -0
  214. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ymap/extensions.py +0 -0
  215. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ymap/grass.py +0 -0
  216. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ymap/io.py +0 -0
  217. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ymap/lights.py +0 -0
  218. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ymap/model.py +0 -0
  219. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ymap/occluders.py +0 -0
  220. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ymap/packing.py +0 -0
  221. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ymap/surfaces.py +0 -0
  222. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ynd/__init__.py +0 -0
  223. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ynd/heightmaps.py +0 -0
  224. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ynd/network.py +0 -0
  225. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ynd/reader.py +0 -0
  226. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ynd/regions.py +0 -0
  227. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ynd/writer.py +0 -0
  228. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ynv/__init__.py +0 -0
  229. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ynv/assimp.py +0 -0
  230. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ynv/model.py +0 -0
  231. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ynv/reader.py +0 -0
  232. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ynv/writer.py +0 -0
  233. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ytd/__init__.py +0 -0
  234. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ytd/defs.py +0 -0
  235. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ytd/model.py +0 -0
  236. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ytyp/__init__.py +0 -0
  237. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ytyp/archetypes.py +0 -0
  238. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ytyp/asset_types.py +0 -0
  239. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ytyp/base_archetype.py +0 -0
  240. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ytyp/defs.py +0 -0
  241. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ytyp/extension_defs.py +0 -0
  242. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ytyp/extensions.py +0 -0
  243. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ytyp/flags.py +0 -0
  244. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ytyp/helpers.py +0 -0
  245. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ytyp/mlo.py +0 -0
  246. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ytyp/model.py +0 -0
  247. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury/ytyp/timed_archetype.py +0 -0
  248. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury.egg-info/dependency_links.txt +0 -0
  249. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury.egg-info/requires.txt +0 -0
  250. {fivefury-0.2.4 → fivefury-0.2.5}/fivefury.egg-info/top_level.txt +0 -0
  251. {fivefury-0.2.4 → fivefury-0.2.5}/native/bounds_algorithms.cpp +0 -0
  252. {fivefury-0.2.4 → fivefury-0.2.5}/native/bounds_algorithms.h +0 -0
  253. {fivefury-0.2.4 → fivefury-0.2.5}/native/bounds_python.cpp +0 -0
  254. {fivefury-0.2.4 → fivefury-0.2.5}/native/bounds_python.h +0 -0
  255. {fivefury-0.2.4 → fivefury-0.2.5}/native/bounds_types.h +0 -0
  256. {fivefury-0.2.4 → fivefury-0.2.5}/native/crypto_magic.cpp +0 -0
  257. {fivefury-0.2.4 → fivefury-0.2.5}/native/crypto_magic.h +0 -0
  258. {fivefury-0.2.4 → fivefury-0.2.5}/native/py_bindings.cpp +0 -0
  259. {fivefury-0.2.4 → fivefury-0.2.5}/native/py_bindings.h +0 -0
  260. {fivefury-0.2.4 → fivefury-0.2.5}/native/py_bounds.cpp +0 -0
  261. {fivefury-0.2.4 → fivefury-0.2.5}/native/py_crypto.cpp +0 -0
  262. {fivefury-0.2.4 → fivefury-0.2.5}/native/py_index.cpp +0 -0
  263. {fivefury-0.2.4 → fivefury-0.2.5}/native/py_module.cpp +0 -0
  264. {fivefury-0.2.4 → fivefury-0.2.5}/native/py_resource.cpp +0 -0
  265. {fivefury-0.2.4 → fivefury-0.2.5}/native/py_rpf.cpp +0 -0
  266. {fivefury-0.2.4 → fivefury-0.2.5}/native/resource_layout.cpp +0 -0
  267. {fivefury-0.2.4 → fivefury-0.2.5}/native/resource_layout.h +0 -0
  268. {fivefury-0.2.4 → fivefury-0.2.5}/native/rpf_archive.cpp +0 -0
  269. {fivefury-0.2.4 → fivefury-0.2.5}/native/rpf_archive.h +0 -0
  270. {fivefury-0.2.4 → fivefury-0.2.5}/native/rpf_crypto.cpp +0 -0
  271. {fivefury-0.2.4 → fivefury-0.2.5}/native/rpf_index.cpp +0 -0
  272. {fivefury-0.2.4 → fivefury-0.2.5}/native/rpf_index.h +0 -0
  273. {fivefury-0.2.4 → fivefury-0.2.5}/native/rpf_read.cpp +0 -0
  274. {fivefury-0.2.4 → fivefury-0.2.5}/native/rpf_scan.cpp +0 -0
  275. {fivefury-0.2.4 → fivefury-0.2.5}/native/rpf_scan.h +0 -0
  276. {fivefury-0.2.4 → fivefury-0.2.5}/setup.cfg +0 -0
  277. {fivefury-0.2.4 → fivefury-0.2.5}/setup.py +0 -0
  278. {fivefury-0.2.4 → fivefury-0.2.5}/tests/test_awc.py +0 -0
  279. {fivefury-0.2.4 → fivefury-0.2.5}/tests/test_cut.py +0 -0
  280. {fivefury-0.2.4 → fivefury-0.2.5}/tests/test_cut_dsl.py +0 -0
  281. {fivefury-0.2.4 → fivefury-0.2.5}/tests/test_cut_no_template.py +0 -0
  282. {fivefury-0.2.4 → fivefury-0.2.5}/tests/test_cut_ycd.py +0 -0
  283. {fivefury-0.2.4 → fivefury-0.2.5}/tests/test_dlc.py +0 -0
  284. {fivefury-0.2.4 → fivefury-0.2.5}/tests/test_gxt2.py +0 -0
  285. {fivefury-0.2.4 → fivefury-0.2.5}/tests/test_hashing.py +0 -0
  286. {fivefury-0.2.4 → fivefury-0.2.5}/tests/test_high_level_api_consistency.py +0 -0
  287. {fivefury-0.2.4 → fivefury-0.2.5}/tests/test_meta_rpf_contracts.py +0 -0
  288. {fivefury-0.2.4 → fivefury-0.2.5}/tests/test_rel.py +0 -0
  289. {fivefury-0.2.4 → fivefury-0.2.5}/tests/test_ycd.py +0 -0
  290. {fivefury-0.2.4 → fivefury-0.2.5}/tests/test_ycd_cutscene_builder.py +0 -0
  291. {fivefury-0.2.4 → fivefury-0.2.5}/tests/test_ydd.py +0 -0
  292. {fivefury-0.2.4 → fivefury-0.2.5}/tests/test_ydr.py +0 -0
  293. {fivefury-0.2.4 → fivefury-0.2.5}/tests/test_ydr_builder.py +0 -0
  294. {fivefury-0.2.4 → fivefury-0.2.5}/tests/test_ydr_rigging.py +0 -0
  295. {fivefury-0.2.4 → fivefury-0.2.5}/tests/test_ydr_shaders.py +0 -0
  296. {fivefury-0.2.4 → fivefury-0.2.5}/tests/test_yed.py +0 -0
  297. {fivefury-0.2.4 → fivefury-0.2.5}/tests/test_ymt_ymf.py +0 -0
  298. {fivefury-0.2.4 → fivefury-0.2.5}/tests/test_ynd.py +0 -0
  299. {fivefury-0.2.4 → fivefury-0.2.5}/tests/test_ynv.py +0 -0
  300. {fivefury-0.2.4 → fivefury-0.2.5}/tests/test_ynv_assimp.py +0 -0
  301. {fivefury-0.2.4 → fivefury-0.2.5}/tests/test_ytyp_flags.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fivefury
3
- Version: 0.2.4
3
+ Version: 0.2.5
4
4
  Summary: Python library for GTA V asset workflows including YMAP, YTYP, RPF, YTD and GameFileCache utilities.
5
5
  Author: Codex
6
6
  License-Expression: MIT
@@ -77,7 +77,7 @@ Support levels:
77
77
 
78
78
  | Format | Current behavior |
79
79
  | --- | --- |
80
- | `YFT` | Resource texture dictionaries can be discovered/extracted from fragments, but full fragment authoring is not implemented. |
80
+ | `YFT` | Fragment reading/writing for common, damaged, extra and cloth drawables, including geometry, materials, LOD meshes, bounding sphere metadata, fragment flags, physics LODs, physics groups, physics children, child entity drawables, per-child breaking/inertia data, damping constants, damping archetypes, articulated body metadata, link attachments, group and child event references, editable composite bounds, mass/inertia helpers, glass/cloth/vehicle semantic queries, corpus scanning, validation, declarative physics helpers, geometry summaries and embedded texture dictionaries. |
81
81
  | `YPT` | Resource texture dictionaries can be discovered/extracted from particle dictionaries, but full particle authoring is not implemented. |
82
82
  | `AWC` | Audio wave containers can be read/written structurally, opened through `GameFileCache`, exported back to WAV for PCM/ADPCM streams, and built from mono or multichannel 16-bit PCM inputs decoded through `miniaudio` (`.wav`, `.mp3`, `.ogg`, `.flac`). Playback metadata lives in `.rel` banks. |
83
83
  | `REL` | Audio metadata banks can be read/written structurally, opened through `GameFileCache`, and round-tripped with unknown entries preserved. `dat10.rel` modular synth presets/synths, `dat16.rel` curves, `dat22.rel` categories, and common `dat54.rel` sound graph entries have typed models, including simple AWC-backed sounds, wrappers, sequential/multitrack/streaming child lists, randomized variations, modular synth sounds, automation/MIDI sounds, note maps, variable-curve and conditional routing, directional/kinetic routing, variable blocks, math operations, parameter transforms, fluctuators, external streams, sound sets, sound-set lists, and sound-hash lists. Other REL item families currently stay as raw entries. |
@@ -67,7 +67,7 @@ Support levels:
67
67
 
68
68
  | Format | Current behavior |
69
69
  | --- | --- |
70
- | `YFT` | Resource texture dictionaries can be discovered/extracted from fragments, but full fragment authoring is not implemented. |
70
+ | `YFT` | Fragment reading/writing for common, damaged, extra and cloth drawables, including geometry, materials, LOD meshes, bounding sphere metadata, fragment flags, physics LODs, physics groups, physics children, child entity drawables, per-child breaking/inertia data, damping constants, damping archetypes, articulated body metadata, link attachments, group and child event references, editable composite bounds, mass/inertia helpers, glass/cloth/vehicle semantic queries, corpus scanning, validation, declarative physics helpers, geometry summaries and embedded texture dictionaries. |
71
71
  | `YPT` | Resource texture dictionaries can be discovered/extracted from particle dictionaries, but full particle authoring is not implemented. |
72
72
  | `AWC` | Audio wave containers can be read/written structurally, opened through `GameFileCache`, exported back to WAV for PCM/ADPCM streams, and built from mono or multichannel 16-bit PCM inputs decoded through `miniaudio` (`.wav`, `.mp3`, `.ogg`, `.flac`). Playback metadata lives in `.rel` banks. |
73
73
  | `REL` | Audio metadata banks can be read/written structurally, opened through `GameFileCache`, and round-tripped with unknown entries preserved. `dat10.rel` modular synth presets/synths, `dat16.rel` curves, `dat22.rel` categories, and common `dat54.rel` sound graph entries have typed models, including simple AWC-backed sounds, wrappers, sequential/multitrack/streaming child lists, randomized variations, modular synth sounds, automation/MIDI sounds, note maps, variable-curve and conditional routing, directional/kinetic routing, variable blocks, math operations, parameter transforms, fluctuators, external streams, sound sets, sound-set lists, and sound-hash lists. Other REL item families currently stay as raw entries. |
@@ -280,7 +280,7 @@ from .gxt2 import (
280
280
  save_gxt2,
281
281
  save_gxt2_text,
282
282
  )
283
- from .gtxd import Gtxd, TxdRelationship, create_gtxd, read_gtxd, save_gtxd
283
+ from .gtxd import Gtxd, TxdRelationship, create_gtxd, is_gtxd_rbf, read_gtxd, read_gtxd_bytes, save_gtxd
284
284
  from .hashing import jenk_hash
285
285
  from .metahash import HashString, MetaHash
286
286
  from .meta import Meta, read_meta
@@ -476,6 +476,52 @@ from .ydd import (
476
476
  rig_ydd_to_bones_radially,
477
477
  save_ydd,
478
478
  )
479
+ from .yft import (
480
+ Yft,
481
+ YftArticulatedBodyType,
482
+ YftDrawable,
483
+ YftDrawableMatch,
484
+ YftFragmentFlag,
485
+ YftFragmentPointers,
486
+ YftFragmentState,
487
+ YftGeometryStats,
488
+ YftCorpusEntry,
489
+ DEFAULT_DAMPING_CONSTANTS,
490
+ IDENTITY_MATRIX34,
491
+ YftPhysicsChild,
492
+ YftPhysicsChildFlag,
493
+ YftPhysicsDampArchetype,
494
+ YftPhysicsDamping,
495
+ YftPhysicsDampingKind,
496
+ YftPhysicsEntity,
497
+ YftPhysicsEventRefs,
498
+ YftPhysicsGroup,
499
+ YftPhysicsGroupEventRefs,
500
+ YftPhysicsGroupFlag,
501
+ YftPhysicsInertia,
502
+ YftPhysicsJointType,
503
+ YftPhysicsLod,
504
+ YftPhysicsLodPointers,
505
+ YftPhysicsReference,
506
+ YftRawField,
507
+ YftValidationIssue,
508
+ YftValidationSeverity,
509
+ assert_valid_yft,
510
+ bound_inertia,
511
+ bound_mass,
512
+ box_inertia,
513
+ build_yft_bytes,
514
+ create_yft,
515
+ default_articulated_body_type,
516
+ default_damp_archetype,
517
+ iter_yft_paths,
518
+ normalize_physics_lod,
519
+ read_yft,
520
+ save_yft,
521
+ scan_yft_corpus,
522
+ simple_physics_bound,
523
+ validate_yft,
524
+ )
479
525
  from .ymap import (
480
526
  AngleMode,
481
527
  Block,
@@ -646,11 +692,44 @@ from .yed import (
646
692
  validate_yed,
647
693
  )
648
694
  from .ytd import Texture, TextureFormat, Ytd, read_ytd, save_ytd
649
- from .ymf import Ymf, read_ymf, save_ymf
695
+ from .ymf import (
696
+ HdTxdAssetBinding,
697
+ ImapDependencies,
698
+ ImapDependency,
699
+ InteriorBoundsFile,
700
+ ItypDependencies,
701
+ ManifestFlags,
702
+ MapDataGroup,
703
+ PackFileMetaData,
704
+ PackFileMetaDataAssetType,
705
+ PackFileMetaDataImapGroupType,
706
+ Ymf,
707
+ YmfRelationship,
708
+ YmfRelationshipType,
709
+ build_ymf_for_ymaps,
710
+ build_ymf_manifest_for_ymaps,
711
+ build_ymf,
712
+ create_ymf_for_ymaps,
713
+ iter_ymf_relationships,
714
+ read_ymf,
715
+ read_ymf_xml,
716
+ save_ymf,
717
+ )
650
718
  from .ymt import (
651
719
  PedComponent,
652
720
  PedDrawableVariation,
653
721
  Ymt,
722
+ YmtAabb,
723
+ YmtContentType,
724
+ YmtFormat,
725
+ YmtPedInitData,
726
+ YmtPedMetadata,
727
+ YmtScenarioPointGroup,
728
+ YmtScenarioPointManifest,
729
+ YmtScenarioPointRegionDef,
730
+ YmtStreamingRequestCommonSet,
731
+ YmtStreamingRequestFrame,
732
+ YmtStreamingRequestRecord,
654
733
  coerce_ped_component,
655
734
  iter_ped_drawables,
656
735
  ped_drawable_file_stem,
@@ -1187,6 +1266,50 @@ __all__ = [
1187
1266
  "YedTrackFormat",
1188
1267
  "YedPedExpressionBinding",
1189
1268
  "YedValidationIssue",
1269
+ "Yft",
1270
+ "YftArticulatedBodyType",
1271
+ "YftDrawable",
1272
+ "YftDrawableMatch",
1273
+ "YftFragmentFlag",
1274
+ "YftFragmentPointers",
1275
+ "YftFragmentState",
1276
+ "YftGeometryStats",
1277
+ "YftCorpusEntry",
1278
+ "DEFAULT_DAMPING_CONSTANTS",
1279
+ "IDENTITY_MATRIX34",
1280
+ "YftPhysicsChild",
1281
+ "YftPhysicsChildFlag",
1282
+ "YftPhysicsDampArchetype",
1283
+ "YftPhysicsDamping",
1284
+ "YftPhysicsDampingKind",
1285
+ "YftPhysicsEntity",
1286
+ "YftPhysicsEventRefs",
1287
+ "YftPhysicsGroup",
1288
+ "YftPhysicsGroupEventRefs",
1289
+ "YftPhysicsGroupFlag",
1290
+ "YftPhysicsInertia",
1291
+ "YftPhysicsJointType",
1292
+ "YftPhysicsLod",
1293
+ "YftPhysicsLodPointers",
1294
+ "YftPhysicsReference",
1295
+ "YftRawField",
1296
+ "YftValidationIssue",
1297
+ "YftValidationSeverity",
1298
+ "assert_valid_yft",
1299
+ "bound_inertia",
1300
+ "bound_mass",
1301
+ "box_inertia",
1302
+ "build_yft_bytes",
1303
+ "create_yft",
1304
+ "default_articulated_body_type",
1305
+ "default_damp_archetype",
1306
+ "iter_yft_paths",
1307
+ "normalize_physics_lod",
1308
+ "read_yft",
1309
+ "save_yft",
1310
+ "scan_yft_corpus",
1311
+ "simple_physics_bound",
1312
+ "validate_yft",
1190
1313
  "assimp_to_ynvs",
1191
1314
  "build_junction_heightmap",
1192
1315
  "get_ynd_area_bounds",
@@ -1206,8 +1329,29 @@ __all__ = [
1206
1329
  "YmapLodLightType",
1207
1330
  "YmapMloInstanceFlags",
1208
1331
  "YmapPriorityLevel",
1332
+ "HdTxdAssetBinding",
1333
+ "ImapDependencies",
1334
+ "ImapDependency",
1335
+ "InteriorBoundsFile",
1336
+ "ItypDependencies",
1337
+ "ManifestFlags",
1338
+ "MapDataGroup",
1339
+ "PackFileMetaData",
1340
+ "PackFileMetaDataAssetType",
1341
+ "PackFileMetaDataImapGroupType",
1209
1342
  "Ymf",
1343
+ "YmfRelationship",
1344
+ "YmfRelationshipType",
1210
1345
  "Ymt",
1346
+ "YmtAabb",
1347
+ "YmtPedInitData",
1348
+ "YmtPedMetadata",
1349
+ "YmtScenarioPointGroup",
1350
+ "YmtScenarioPointManifest",
1351
+ "YmtScenarioPointRegionDef",
1352
+ "YmtStreamingRequestCommonSet",
1353
+ "YmtStreamingRequestFrame",
1354
+ "YmtStreamingRequestRecord",
1211
1355
  "ContainerLodDef",
1212
1356
  "YddAsset",
1213
1357
  "Ytd",
@@ -1229,6 +1373,9 @@ __all__ = [
1229
1373
  "build_dlc_extra_title_update_data_xml",
1230
1374
  "build_dlc_list_xml",
1231
1375
  "build_dlc_setup_xml",
1376
+ "build_ymf",
1377
+ "build_ymf_for_ymaps",
1378
+ "build_ymf_manifest_for_ymaps",
1232
1379
  "create_dlc_folder_metadata",
1233
1380
  "create_dlc_list_for_packs",
1234
1381
  "create_dlc_patch_manifest",
@@ -1238,6 +1385,7 @@ __all__ = [
1238
1385
  "clear_hash_resolver",
1239
1386
  "clear_game_crypto",
1240
1387
  "create_rpf",
1388
+ "create_ymf_for_ymaps",
1241
1389
  "create_ydd",
1242
1390
  "create_ydr",
1243
1391
  "convert_audio_to_awc",
@@ -1282,7 +1430,9 @@ __all__ = [
1282
1430
  "read_dlc_list",
1283
1431
  "read_dlc_pack",
1284
1432
  "read_dlc_setup",
1433
+ "is_gtxd_rbf",
1285
1434
  "read_gtxd",
1435
+ "read_gtxd_bytes",
1286
1436
  "read_gxt2",
1287
1437
  "read_gxt2_text",
1288
1438
  "read_ycd",
@@ -1291,6 +1441,8 @@ __all__ = [
1291
1441
  "read_yed",
1292
1442
  "read_shader_library",
1293
1443
  "read_ydr",
1444
+ "read_yft",
1445
+ "save_yft",
1294
1446
  "rig_body_folder_jiggle_bones",
1295
1447
  "rig_mesh_to_bones_radially",
1296
1448
  "rig_ydd_to_bones_radially",
@@ -1314,11 +1466,15 @@ __all__ = [
1314
1466
  "read_ynv",
1315
1467
  "read_ymap",
1316
1468
  "read_ymf",
1469
+ "read_ymf_xml",
1317
1470
  "read_ymt",
1318
1471
  "read_ytd",
1319
1472
  "read_ytyp",
1473
+ "YmtContentType",
1474
+ "YmtFormat",
1320
1475
  "infer_dlc_content_from_folder",
1321
1476
  "iter_ped_drawables",
1477
+ "iter_ymf_relationships",
1322
1478
  "iter_dlc_content_candidates",
1323
1479
  "register_name",
1324
1480
  "register_names",
@@ -1381,4 +1537,6 @@ __all__ = [
1381
1537
  "create_ycd_uv_clip",
1382
1538
  "get_ycd_track_format",
1383
1539
  "parse_ycd_uv_clip_binding",
1540
+ "assert_valid_yft",
1541
+ "validate_yft",
1384
1542
  ]
@@ -29,6 +29,9 @@ class YftAsset(ResourceTextureAsset):
29
29
  main_drawable_pointer = _u64(self.system_data, 0x30)
30
30
  yield from emit("drawable", main_drawable_pointer)
31
31
 
32
+ damaged_drawable_pointer = _u64(self.system_data, 0x50)
33
+ yield from emit("damaged", damaged_drawable_pointer)
34
+
32
35
  drawable_array_pointer = _u64(self.system_data, 0x38)
33
36
  drawable_array_count = _u32(self.system_data, 0x48)
34
37
  for index, drawable_pointer in enumerate(
@@ -1,9 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import dataclasses
4
- from math import sqrt
5
-
6
4
  from .. import _native as _native_backend
5
+ from ..vector import aabb_center, aabb_from_points, vec_cross, vec_length, vec_sub
7
6
  from .model import (
8
7
  BoundAabb,
9
8
  BoundBVH,
@@ -35,14 +34,7 @@ class BoundTriangleChunk:
35
34
 
36
35
 
37
36
  def _triangle_area_python(vertex0: Vector3, vertex1: Vector3, vertex2: Vector3) -> float:
38
- edge1 = (vertex1[0] - vertex0[0], vertex1[1] - vertex0[1], vertex1[2] - vertex0[2])
39
- edge2 = (vertex2[0] - vertex0[0], vertex2[1] - vertex0[1], vertex2[2] - vertex0[2])
40
- cross = (
41
- (edge1[1] * edge2[2]) - (edge1[2] * edge2[1]),
42
- (edge1[2] * edge2[0]) - (edge1[0] * edge2[2]),
43
- (edge1[0] * edge2[1]) - (edge1[1] * edge2[0]),
44
- )
45
- return 0.5 * sqrt((cross[0] * cross[0]) + (cross[1] * cross[1]) + (cross[2] * cross[2]))
37
+ return 0.5 * vec_length(vec_cross(vec_sub(vertex1, vertex0), vec_sub(vertex2, vertex0)))
46
38
 
47
39
 
48
40
  def triangle_area(vertex0: Vector3, vertex1: Vector3, vertex2: Vector3) -> float:
@@ -54,10 +46,7 @@ def triangle_area(vertex0: Vector3, vertex1: Vector3, vertex2: Vector3) -> float
54
46
  def _bounds_from_vertices_python(vertices: list[Vector3]) -> tuple[Vector3, Vector3]:
55
47
  if not vertices:
56
48
  raise ValueError("At least one vertex is required")
57
- return (
58
- (min(vertex[0] for vertex in vertices), min(vertex[1] for vertex in vertices), min(vertex[2] for vertex in vertices)),
59
- (max(vertex[0] for vertex in vertices), max(vertex[1] for vertex in vertices), max(vertex[2] for vertex in vertices)),
60
- )
49
+ return aabb_from_points(vertices)
61
50
 
62
51
 
63
52
  def bounds_from_vertices(vertices: list[Vector3]) -> tuple[Vector3, Vector3]:
@@ -67,19 +56,12 @@ def bounds_from_vertices(vertices: list[Vector3]) -> tuple[Vector3, Vector3]:
67
56
 
68
57
 
69
58
  def center_from_bounds(minimum: Vector3, maximum: Vector3) -> Vector3:
70
- return ((minimum[0] + maximum[0]) * 0.5, (minimum[1] + maximum[1]) * 0.5, (minimum[2] + maximum[2]) * 0.5)
59
+ return aabb_center(minimum, maximum)
71
60
 
72
61
 
73
62
  def _sphere_radius_from_vertices_python(center: Vector3, vertices: list[Vector3]) -> float:
74
63
  return max(
75
- (
76
- sqrt(
77
- ((vertex[0] - center[0]) ** 2)
78
- + ((vertex[1] - center[1]) ** 2)
79
- + ((vertex[2] - center[2]) ** 2)
80
- )
81
- for vertex in vertices
82
- ),
64
+ (vec_length(vec_sub(vertex, center)) for vertex in vertices),
83
65
  default=0.0,
84
66
  )
85
67
 
@@ -8,6 +8,7 @@ from typing import Iterator
8
8
 
9
9
  from .. import _native as _native_backend
10
10
  from ..resource import ResourcePagesInfo
11
+ from ..vector import aabb_center, aabb_from_center_size, vec_add, vec_scale, vec_sub
11
12
  from .materials import BoundMaterialType, coerce_bound_material_index, get_bound_material_type
12
13
 
13
14
 
@@ -57,9 +58,7 @@ def _merge_bounds(bounds: list[BoundAabb], fallback: BoundAabb) -> BoundAabb:
57
58
 
58
59
 
59
60
  def _aabb_from_center_size(center: tuple[float, float, float], size: tuple[float, float, float]) -> BoundAabb:
60
- half_size = tuple(float(value) * 0.5 for value in size)
61
- minimum = tuple(float(center[axis]) - half_size[axis] for axis in range(3))
62
- maximum = tuple(float(center[axis]) + half_size[axis] for axis in range(3))
61
+ minimum, maximum = aabb_from_center_size(center, size)
63
62
  return BoundAabb(minimum, maximum)
64
63
 
65
64
 
@@ -159,6 +158,46 @@ def _sphere_radius_from_bounds(bounds: BoundAabb, center: tuple[float, float, fl
159
158
  )
160
159
 
161
160
 
161
+ def _box_volume_distribution(size: tuple[float, float, float]) -> tuple[float, float, float]:
162
+ x, y, z = (abs(float(axis)) for axis in size)
163
+ return (((y * y) + (z * z)) / 12.0, ((x * x) + (z * z)) / 12.0, ((x * x) + (y * y)) / 12.0)
164
+
165
+
166
+ def _sphere_volume_distribution(radius: float) -> tuple[float, float, float]:
167
+ value = 0.4 * float(radius) * float(radius)
168
+ return (value, value, value)
169
+
170
+
171
+ def _cylinder_volume_distribution(radius: float, length: float) -> tuple[float, float, float]:
172
+ radius2 = float(radius) * float(radius)
173
+ central = (radius2 * 0.25) + ((float(length) * float(length)) / 12.0)
174
+ radial = radius2 * 0.5
175
+ return (central, radial, central)
176
+
177
+
178
+ def _capsule_volume_distribution(radius: float, length: float) -> tuple[float, float, float]:
179
+ radius = float(radius)
180
+ length = float(length)
181
+ denominator = length + (4.0 / 3.0) * radius
182
+ if denominator <= 0.0:
183
+ return (0.0, 0.0, 0.0)
184
+ inverse = 1.0 / denominator
185
+ radius2 = radius * radius
186
+ radial = 0.5 * radius2 * (length + 1.0666666666667 * radius) * inverse
187
+ length2 = length * length
188
+ central = (
189
+ (1.0 / 3.0)
190
+ * (
191
+ 0.25 * length * length2
192
+ + radius * length2
193
+ + 2.25 * length * radius2
194
+ + 1.6 * radius * radius2
195
+ )
196
+ * inverse
197
+ )
198
+ return (central, radial, central)
199
+
200
+
162
201
  @dataclasses.dataclass(slots=True)
163
202
  class BoundCompositeFlags:
164
203
  flags1: BoundCompositeFlag = BoundCompositeFlag.NONE
@@ -629,19 +668,37 @@ class Bound:
629
668
  def geometry_count(self) -> int:
630
669
  return len(self.geometries)
631
670
 
632
- @property
671
+ @property
633
672
  def leaf_bounds(self) -> list[Bound]:
634
673
  return [bound for bound in self.walk() if not isinstance(bound, BoundComposite)]
635
674
 
675
+ def compute_volume(self) -> float:
676
+ if self.volume > 0.0 and math.isfinite(self.volume):
677
+ return float(self.volume)
678
+ return abs(self.width * self.depth * self.height)
679
+
680
+ def compute_volume_distribution(self) -> tuple[float, float, float]:
681
+ if any(abs(value) > 0.0 for value in self.angular_inertia):
682
+ return tuple(float(value) for value in self.angular_inertia)
683
+ return _box_volume_distribution(self.dimensions)
684
+
685
+ def compute_angular_inertia(self, mass: float) -> tuple[float, float, float]:
686
+ distribution = self.compute_volume_distribution()
687
+ return tuple(float(value) * float(mass) for value in distribution)
688
+
636
689
  def build(self) -> "Bound":
637
690
  normalized = _normalize_aabb(self.bounds)
638
691
  self.box_min = normalized.minimum
639
692
  self.box_max = normalized.maximum
640
693
  self.box_center = tuple((normalized.minimum[axis] + normalized.maximum[axis]) * 0.5 for axis in range(3))
694
+ if self.sphere_center == (0.0, 0.0, 0.0) and self.box_center != (0.0, 0.0, 0.0):
695
+ self.sphere_center = self.box_center
641
696
  self.flags = BoundFlag(int(self.flags))
642
697
  self.part_index = int(self.part_index) & 0xFFFF
643
698
  self.material_index = coerce_bound_material_index(self.material_index)
644
699
  self.ref_count = int(self.ref_count)
700
+ self.volume = self.compute_volume()
701
+ self.angular_inertia = self.compute_volume_distribution()
645
702
  return self
646
703
 
647
704
  def validate(self) -> list[str]:
@@ -699,9 +756,18 @@ class BoundSphere(Bound):
699
756
  def diameter(self) -> float:
700
757
  return self.radius * 2.0
701
758
 
759
+ def compute_volume(self) -> float:
760
+ return (4.0 / 3.0) * math.pi * (self.radius ** 3)
761
+
762
+ def compute_volume_distribution(self) -> tuple[float, float, float]:
763
+ return _sphere_volume_distribution(self.radius)
764
+
702
765
 
703
766
  @dataclasses.dataclass(slots=True)
704
767
  class BoundBox(Bound):
768
+ def compute_volume_distribution(self) -> tuple[float, float, float]:
769
+ return _box_volume_distribution(self.dimensions)
770
+
705
771
  @classmethod
706
772
  def from_bounds(
707
773
  cls,
@@ -777,6 +843,13 @@ class BoundCapsule(Bound):
777
843
  def total_height(self) -> float:
778
844
  return self.shaft_length + (self.radius * 2.0)
779
845
 
846
+ def compute_volume(self) -> float:
847
+ radius = self.radius
848
+ return math.pi * radius * radius * (self.shaft_length + (4.0 / 3.0) * radius)
849
+
850
+ def compute_volume_distribution(self) -> tuple[float, float, float]:
851
+ return _capsule_volume_distribution(self.radius, self.shaft_length)
852
+
780
853
 
781
854
  @dataclasses.dataclass(slots=True)
782
855
  class BoundDisc(Bound):
@@ -846,6 +919,12 @@ class BoundDisc(Bound):
846
919
  def thickness(self) -> float:
847
920
  return self.half_thickness * 2.0
848
921
 
922
+ def compute_volume(self) -> float:
923
+ return math.pi * self.radius * self.radius * self.thickness
924
+
925
+ def compute_volume_distribution(self) -> tuple[float, float, float]:
926
+ return _cylinder_volume_distribution(self.radius, self.thickness)
927
+
849
928
 
850
929
  @dataclasses.dataclass(slots=True)
851
930
  class BoundCylinder(Bound):
@@ -910,6 +989,12 @@ class BoundCylinder(Bound):
910
989
  def height(self) -> float:
911
990
  return self.half_height * 2.0
912
991
 
992
+ def compute_volume(self) -> float:
993
+ return math.pi * self.radius * self.radius * self.height
994
+
995
+ def compute_volume_distribution(self) -> tuple[float, float, float]:
996
+ return _cylinder_volume_distribution(self.radius, self.height)
997
+
913
998
 
914
999
  @dataclasses.dataclass(slots=True)
915
1000
  class BoundCloth(Bound):
@@ -1121,6 +1206,70 @@ class BoundComposite(Bound):
1121
1206
  self.children.append(child)
1122
1207
  return child
1123
1208
 
1209
+ def compute_volume(self) -> float:
1210
+ if self.children:
1211
+ return sum(child.bound.compute_volume() for child in self.children)
1212
+ return super().compute_volume()
1213
+
1214
+ def compute_center_of_gravity(
1215
+ self,
1216
+ masses: list[float] | tuple[float, ...] | None = None,
1217
+ ) -> tuple[float, float, float]:
1218
+ weighted = (0.0, 0.0, 0.0)
1219
+ total_weight = 0.0
1220
+ for index, child in enumerate(self.children):
1221
+ weight = (
1222
+ float(masses[index])
1223
+ if masses is not None and index < len(masses)
1224
+ else child.bound.compute_volume()
1225
+ )
1226
+ if weight <= 0.0:
1227
+ continue
1228
+ child_center = _transform_point(child.bound.sphere_center, child.transform)
1229
+ weighted = vec_add(weighted, vec_scale(child_center, weight))
1230
+ total_weight += weight
1231
+ return vec_scale(weighted, 1.0 / total_weight) if total_weight > 0.0 else (0.0, 0.0, 0.0)
1232
+
1233
+ def compute_composite_angular_inertia(
1234
+ self,
1235
+ mass: float,
1236
+ *,
1237
+ masses: list[float] | tuple[float, ...] | None = None,
1238
+ inertias: list[tuple[float, float, float]] | tuple[tuple[float, float, float], ...] | None = None,
1239
+ ) -> tuple[float, float, float]:
1240
+ total_mass = float(mass)
1241
+ total_volume = self.compute_volume()
1242
+ density = total_mass / total_volume if total_volume > 0.0 else 0.0
1243
+ center_of_gravity = self.compute_center_of_gravity(masses)
1244
+ total = (0.0, 0.0, 0.0)
1245
+ for index, child in enumerate(self.children):
1246
+ part_mass = (
1247
+ float(masses[index])
1248
+ if masses is not None and index < len(masses)
1249
+ else density * child.bound.compute_volume()
1250
+ )
1251
+ if inertias is not None and index < len(inertias):
1252
+ part_inertia = inertias[index]
1253
+ else:
1254
+ part_inertia = child.bound.compute_angular_inertia(part_mass)
1255
+ offset = vec_sub(_transform_point(child.bound.sphere_center, child.transform), center_of_gravity)
1256
+ parallel_axis = (
1257
+ part_mass * ((offset[1] * offset[1]) + (offset[2] * offset[2])),
1258
+ part_mass * ((offset[0] * offset[0]) + (offset[2] * offset[2])),
1259
+ part_mass * ((offset[0] * offset[0]) + (offset[1] * offset[1])),
1260
+ )
1261
+ total = vec_add(total, vec_add(part_inertia, parallel_axis))
1262
+ return total
1263
+
1264
+ def compute_volume_distribution(self) -> tuple[float, float, float]:
1265
+ volume = self.compute_volume()
1266
+ if volume <= 0.0:
1267
+ return (0.0, 0.0, 0.0)
1268
+ return vec_scale(self.compute_composite_angular_inertia(volume), 1.0 / volume)
1269
+
1270
+ def compute_angular_inertia(self, mass: float) -> tuple[float, float, float]:
1271
+ return self.compute_composite_angular_inertia(mass)
1272
+
1124
1273
  def build(self) -> "BoundComposite":
1125
1274
  super().build()
1126
1275
  for child in self.children:
@@ -1133,12 +1282,14 @@ class BoundComposite(Bound):
1133
1282
  for child in self.children
1134
1283
  ]
1135
1284
  overall = _merge_bounds(transformed_bounds, self.bounds)
1136
- center = tuple((overall.minimum[axis] + overall.maximum[axis]) * 0.5 for axis in range(3))
1285
+ center = aabb_center(overall.minimum, overall.maximum)
1137
1286
  self.box_min = overall.minimum
1138
1287
  self.box_max = overall.maximum
1139
1288
  self.box_center = center
1140
- self.sphere_center = center
1289
+ self.sphere_center = self.compute_center_of_gravity()
1141
1290
  self.sphere_radius = _sphere_radius_from_bounds(overall, center)
1291
+ self.volume = self.compute_volume()
1292
+ self.angular_inertia = self.compute_volume_distribution()
1142
1293
  if len(self.children) <= 5:
1143
1294
  self.bvh = None
1144
1295
  else:
@@ -154,11 +154,11 @@ class GameFileCacheAssetMixin:
154
154
  def list_ymap_entity_assets(self, query: Any, *, include_supporting: bool = True) -> list["AssetRecord"]:
155
155
  return list(self.iter_ymap_entity_assets(query, include_supporting=include_supporting))
156
156
 
157
- def extract_ymap_assets(
158
- self,
159
- query: Any,
160
- destination: str | Path,
161
- *,
157
+ def extract_ymap_assets(
158
+ self,
159
+ query: Any,
160
+ destination: str | Path,
161
+ *,
162
162
  include_supporting: bool = True,
163
163
  logical: bool = False,
164
164
  ) -> list[Path]:
@@ -168,10 +168,19 @@ class GameFileCacheAssetMixin:
168
168
  for asset in self.iter_ymap_entity_assets(query, include_supporting=include_supporting):
169
169
  result = self.extract_asset(asset, output_dir / asset.name, logical=logical)
170
170
  if result is not None:
171
- extracted.append(result)
172
- return extracted
173
-
174
- def _coerce_ytd(self, value: Any) -> Ytd | None:
171
+ extracted.append(result)
172
+ return extracted
173
+
174
+ def create_ymf_for_ymaps(self, ymaps: Any | None = None, **kwargs: Any) -> Any:
175
+ from ..ymf import create_ymf_for_ymaps
176
+
177
+ sources = None if ymaps is None else (ymaps if isinstance(ymaps, (list, tuple, set)) else [ymaps])
178
+ return create_ymf_for_ymaps(sources, cache=self, **kwargs)
179
+
180
+ def build_ymf_for_ymaps(self, ymaps: Any | None = None, **kwargs: Any) -> Any:
181
+ return self.create_ymf_for_ymaps(ymaps, **kwargs)
182
+
183
+ def _coerce_ytd(self, value: Any) -> Ytd | None:
175
184
  if isinstance(value, Ytd):
176
185
  return value
177
186
  if hasattr(value, "textures") and hasattr(value, "to_bytes"):
@@ -513,6 +513,7 @@ _KIND_DICT_TYPES: dict[str, GameFileType] = {
513
513
  "YwrDict": GameFileType.YWR,
514
514
  "YvrDict": GameFileType.YVR,
515
515
  "Gxt2Dict": GameFileType.GXT2,
516
+ "GtxdDict": GameFileType.GTXD,
516
517
  "AwcDict": GameFileType.AWC,
517
518
  "YedDict": GameFileType.YED,
518
519
  }
@@ -21,6 +21,7 @@ from ..ybn import read_ybn
21
21
  from ..ydd import read_ydd
22
22
  from ..yed import read_yed
23
23
  from ..ydr import read_ydr
24
+ from ..yft import read_yft
24
25
  from ..ynd import read_ynd
25
26
  from ..ynv import read_ynv
26
27
  from ..ytd import read_ytd
@@ -70,6 +71,7 @@ def _decode_payload(path: str, data: bytes, *, raw: bytes | None = None) -> tupl
70
71
  resource_decoders = {
71
72
  ".ydr": (GameFileType.YDR, lambda payload: read_ydr(payload, path=path)),
72
73
  ".ydd": (GameFileType.YDD, lambda payload: read_ydd(payload, path=path)),
74
+ ".yft": (GameFileType.YFT, lambda payload: read_yft(payload, path=path)),
73
75
  ".ytd": (GameFileType.YTD, read_ytd),
74
76
  ".ycd": (GameFileType.YCD, lambda payload: read_ycd(payload, path=path)),
75
77
  ".yed": (GameFileType.YED, lambda payload: read_yed(payload, path=path)),
@@ -225,7 +227,7 @@ class GameFileCacheIOMixin:
225
227
  self._log(f"read file {asset.path}")
226
228
  logical_native = self._logical_archive_bytes_from_standalone(asset, standalone_native)
227
229
  ext = Path(asset.path).suffix.lower()
228
- raw_source = standalone_native if ext in {".ytd", ".ydr", ".ydd", ".ycd", ".yed", ".ybn", ".ynd", ".ynv"} else stored_native
230
+ raw_source = standalone_native if ext in {".ytd", ".ydr", ".ydd", ".yft", ".ycd", ".yed", ".ybn", ".ynd", ".ynv"} else stored_native
229
231
  parsed, kind = _decode_payload(asset.path, logical_native, raw=raw_source)
230
232
  entry = asset.entry if isinstance(asset.entry, RpfFileEntry) else None
231
233
  archive = asset.archive if isinstance(asset.archive, RpfArchive) else None
@@ -249,7 +251,7 @@ class GameFileCacheIOMixin:
249
251
  stored = entry.read(logical=False)
250
252
  logical = entry.read(logical=True)
251
253
  raw_source = None
252
- if asset.path.lower().endswith((".ytd", ".ydr", ".ydd", ".ycd", ".yed", ".ybn", ".ynd", ".ynv")):
254
+ if asset.path.lower().endswith((".ytd", ".ydr", ".ydd", ".yft", ".ycd", ".yed", ".ybn", ".ynd", ".ynv")):
253
255
  raw_source = entry._archive.read_entry_standalone(entry)
254
256
  parsed, kind = _decode_payload(asset.path, logical, raw=raw_source)
255
257
  game_file = GameFile(