@volter/blender-engine 0.1.148 → 0.1.149

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 (245) hide show
  1. package/LICENSE +16 -0
  2. package/README.md +4 -11
  3. package/browser/addons/vrm/LICENSE_(OPTION1)_MIT.txt +22 -0
  4. package/browser/addons/vrm/LICENSE_(OPTION2)_GPL-3_0.txt +674 -0
  5. package/browser/addons/vrm/LICENSE_MAIN.txt +1 -0
  6. package/browser/addons/vrm/README.txt +3 -0
  7. package/browser/addons/vrm/__init__.py +41 -0
  8. package/browser/addons/vrm/blender_manifest.toml +16 -0
  9. package/browser/addons/vrm/common/__init__.py +1 -0
  10. package/browser/addons/vrm/common/animation.py +58 -0
  11. package/browser/addons/vrm/common/blender_manifest.py +82 -0
  12. package/browser/addons/vrm/common/char.py +16 -0
  13. package/browser/addons/vrm/common/convert.py +287 -0
  14. package/browser/addons/vrm/common/convert_any.py +48 -0
  15. package/browser/addons/vrm/common/debug.py +40 -0
  16. package/browser/addons/vrm/common/deep.py +162 -0
  17. package/browser/addons/vrm/common/error_dialog.py +274 -0
  18. package/browser/addons/vrm/common/fs.py +71 -0
  19. package/browser/addons/vrm/common/gl.py +20 -0
  20. package/browser/addons/vrm/common/gltf.py +1149 -0
  21. package/browser/addons/vrm/common/human_bone_mapper/__init__.py +1 -0
  22. package/browser/addons/vrm/common/human_bone_mapper/biped_mapping.py +84 -0
  23. package/browser/addons/vrm/common/human_bone_mapper/cats_blender_plugin_fix_model_mapping.py +63 -0
  24. package/browser/addons/vrm/common/human_bone_mapper/human_bone_mapper.py +203 -0
  25. package/browser/addons/vrm/common/human_bone_mapper/microsoft_rocketbox_mapping.py +69 -0
  26. package/browser/addons/vrm/common/human_bone_mapper/mixamo_mapping.py +62 -0
  27. package/browser/addons/vrm/common/human_bone_mapper/mmd_mapping.py +115 -0
  28. package/browser/addons/vrm/common/human_bone_mapper/mpfb_mapping.py +120 -0
  29. package/browser/addons/vrm/common/human_bone_mapper/ready_player_me_mapping.py +65 -0
  30. package/browser/addons/vrm/common/human_bone_mapper/reallusion_mapping.py +94 -0
  31. package/browser/addons/vrm/common/human_bone_mapper/rigify_meta_rig_mapping.py +65 -0
  32. package/browser/addons/vrm/common/human_bone_mapper/structure_based_mapping.py +891 -0
  33. package/browser/addons/vrm/common/human_bone_mapper/unreal_mapping.py +62 -0
  34. package/browser/addons/vrm/common/human_bone_mapper/vrm_addon_mapping.py +112 -0
  35. package/browser/addons/vrm/common/human_bone_mapper/vroid_mapping.py +89 -0
  36. package/browser/addons/vrm/common/legacy_gltf.py +16 -0
  37. package/browser/addons/vrm/common/logger.py +84 -0
  38. package/browser/addons/vrm/common/mtoon0.blend +0 -0
  39. package/browser/addons/vrm/common/mtoon1.blend +0 -0
  40. package/browser/addons/vrm/common/mtoon1_outline.blend +0 -0
  41. package/browser/addons/vrm/common/mtoon_auto_setup.blend +0 -0
  42. package/browser/addons/vrm/common/mtoon_unversioned.py +62 -0
  43. package/browser/addons/vrm/common/ops/__init__.py +10 -0
  44. package/browser/addons/vrm/common/ops/export_scene.py +67 -0
  45. package/browser/addons/vrm/common/ops/icyp.py +53 -0
  46. package/browser/addons/vrm/common/ops/import_scene.py +57 -0
  47. package/browser/addons/vrm/common/ops/vrm.py +2380 -0
  48. package/browser/addons/vrm/common/ops/wm.py +167 -0
  49. package/browser/addons/vrm/common/preferences.py +362 -0
  50. package/browser/addons/vrm/common/progress.py +87 -0
  51. package/browser/addons/vrm/common/rotation.py +89 -0
  52. package/browser/addons/vrm/common/safe_removal.py +46 -0
  53. package/browser/addons/vrm/common/scene_watcher.py +230 -0
  54. package/browser/addons/vrm/common/shader.py +2243 -0
  55. package/browser/addons/vrm/common/shape_key_mapper/__init__.py +1 -0
  56. package/browser/addons/vrm/common/shape_key_mapper/arkit_mapping.py +168 -0
  57. package/browser/addons/vrm/common/shape_key_mapper/mmd_mapping.py +62 -0
  58. package/browser/addons/vrm/common/shape_key_mapper/ready_player_me_mapping.py +52 -0
  59. package/browser/addons/vrm/common/shape_key_mapper/vrchat_mapping.py +17 -0
  60. package/browser/addons/vrm/common/third_party_user_extension.py +214 -0
  61. package/browser/addons/vrm/common/transparent_z_write.blend +0 -0
  62. package/browser/addons/vrm/common/version.py +161 -0
  63. package/browser/addons/vrm/common/vrm0/__init__.py +1 -0
  64. package/browser/addons/vrm/common/vrm0/human_bone.py +662 -0
  65. package/browser/addons/vrm/common/vrm0/material_property.py +346 -0
  66. package/browser/addons/vrm/common/vrm1/__init__.py +1 -0
  67. package/browser/addons/vrm/common/vrm1/expression_preset.py +207 -0
  68. package/browser/addons/vrm/common/vrm1/human_bone.py +822 -0
  69. package/browser/addons/vrm/common/workspace.py +227 -0
  70. package/browser/addons/vrm/common/writable_context.py +77 -0
  71. package/browser/addons/vrm/documentation/en-us/animation/index.md +63 -0
  72. package/browser/addons/vrm/documentation/en-us/create-humanoid-vrm-from-scratch/index.md +131 -0
  73. package/browser/addons/vrm/documentation/en-us/create-simple-vrm-from-scratch/index.md +30 -0
  74. package/browser/addons/vrm/documentation/en-us/development/index.md +136 -0
  75. package/browser/addons/vrm/documentation/en-us/index.md +41 -0
  76. package/browser/addons/vrm/documentation/en-us/installation/index.md +152 -0
  77. package/browser/addons/vrm/documentation/en-us/material-mtoon/index.md +122 -0
  78. package/browser/addons/vrm/documentation/en-us/material-pbr/index.md +94 -0
  79. package/browser/addons/vrm/documentation/en-us/scripting-api/index.md +391 -0
  80. package/browser/addons/vrm/documentation/en-us/ui/export_scene.vrm/index.md +57 -0
  81. package/browser/addons/vrm/documentation/en-us/ui/export_scene.vrma/index.md +17 -0
  82. package/browser/addons/vrm/documentation/en-us/ui/import_scene.vrm/index.md +61 -0
  83. package/browser/addons/vrm/documentation/en-us/ui/import_scene.vrma/index.md +13 -0
  84. package/browser/addons/vrm/documentation/ja-jp/animation/index.md +57 -0
  85. package/browser/addons/vrm/documentation/ja-jp/create-humanoid-vrm-from-scratch/index.md +129 -0
  86. package/browser/addons/vrm/documentation/ja-jp/create-simple-vrm-from-scratch/index.md +29 -0
  87. package/browser/addons/vrm/documentation/ja-jp/development/index.md +137 -0
  88. package/browser/addons/vrm/documentation/ja-jp/index.md +37 -0
  89. package/browser/addons/vrm/documentation/ja-jp/installation/index.md +150 -0
  90. package/browser/addons/vrm/documentation/ja-jp/material-mtoon/index.md +113 -0
  91. package/browser/addons/vrm/documentation/ja-jp/material-pbr/index.md +90 -0
  92. package/browser/addons/vrm/documentation/ja-jp/scripting-api/index.md +389 -0
  93. package/browser/addons/vrm/documentation/ja-jp/ui/export_scene.vrm/index.md +55 -0
  94. package/browser/addons/vrm/documentation/ja-jp/ui/export_scene.vrma/index.md +19 -0
  95. package/browser/addons/vrm/documentation/ja-jp/ui/import_scene.vrm/index.md +56 -0
  96. package/browser/addons/vrm/documentation/ja-jp/ui/import_scene.vrma/index.md +14 -0
  97. package/browser/addons/vrm/editor/__init__.py +1 -0
  98. package/browser/addons/vrm/editor/extension.py +425 -0
  99. package/browser/addons/vrm/editor/extension_accessor.py +75 -0
  100. package/browser/addons/vrm/editor/handler.py +84 -0
  101. package/browser/addons/vrm/editor/khr_character/__init__.py +1 -0
  102. package/browser/addons/vrm/editor/khr_character/panel.py +69 -0
  103. package/browser/addons/vrm/editor/khr_character/property_group.py +27 -0
  104. package/browser/addons/vrm/editor/khr_xmp_json_ld/__init__.py +1 -0
  105. package/browser/addons/vrm/editor/khr_xmp_json_ld/ops.py +464 -0
  106. package/browser/addons/vrm/editor/khr_xmp_json_ld/panel.py +136 -0
  107. package/browser/addons/vrm/editor/khr_xmp_json_ld/property_group.py +83 -0
  108. package/browser/addons/vrm/editor/khr_xmp_json_ld/ui_list.py +198 -0
  109. package/browser/addons/vrm/editor/make_armature.py +709 -0
  110. package/browser/addons/vrm/editor/menu.py +147 -0
  111. package/browser/addons/vrm/editor/migration.py +297 -0
  112. package/browser/addons/vrm/editor/mtoon1/__init__.py +1 -0
  113. package/browser/addons/vrm/editor/mtoon1/handler.py +20 -0
  114. package/browser/addons/vrm/editor/mtoon1/migration.py +536 -0
  115. package/browser/addons/vrm/editor/mtoon1/ops.py +304 -0
  116. package/browser/addons/vrm/editor/mtoon1/panel.py +442 -0
  117. package/browser/addons/vrm/editor/mtoon1/property_group.py +4977 -0
  118. package/browser/addons/vrm/editor/mtoon1/scene_watcher.py +381 -0
  119. package/browser/addons/vrm/editor/node_constraint1/__init__.py +1 -0
  120. package/browser/addons/vrm/editor/node_constraint1/panel.py +317 -0
  121. package/browser/addons/vrm/editor/node_constraint1/property_group.py +25 -0
  122. package/browser/addons/vrm/editor/ops.py +471 -0
  123. package/browser/addons/vrm/editor/panel.py +315 -0
  124. package/browser/addons/vrm/editor/property_group.py +888 -0
  125. package/browser/addons/vrm/editor/search.py +682 -0
  126. package/browser/addons/vrm/editor/spring_bone1/__init__.py +1 -0
  127. package/browser/addons/vrm/editor/spring_bone1/handler.py +994 -0
  128. package/browser/addons/vrm/editor/spring_bone1/menu.py +246 -0
  129. package/browser/addons/vrm/editor/spring_bone1/migration.py +86 -0
  130. package/browser/addons/vrm/editor/spring_bone1/ops.py +1679 -0
  131. package/browser/addons/vrm/editor/spring_bone1/panel.py +605 -0
  132. package/browser/addons/vrm/editor/spring_bone1/property_group.py +1457 -0
  133. package/browser/addons/vrm/editor/spring_bone1/ui_list.py +408 -0
  134. package/browser/addons/vrm/editor/subscription.py +123 -0
  135. package/browser/addons/vrm/editor/t_pose.py +713 -0
  136. package/browser/addons/vrm/editor/validation.py +1271 -0
  137. package/browser/addons/vrm/editor/vrm0/__init__.py +1 -0
  138. package/browser/addons/vrm/editor/vrm0/gizmo_group.py +63 -0
  139. package/browser/addons/vrm/editor/vrm0/handler.py +23 -0
  140. package/browser/addons/vrm/editor/vrm0/menu.py +145 -0
  141. package/browser/addons/vrm/editor/vrm0/migration.py +761 -0
  142. package/browser/addons/vrm/editor/vrm0/ops.py +2145 -0
  143. package/browser/addons/vrm/editor/vrm0/panel.py +1333 -0
  144. package/browser/addons/vrm/editor/vrm0/property_group.py +1818 -0
  145. package/browser/addons/vrm/editor/vrm0/ui_list.py +688 -0
  146. package/browser/addons/vrm/editor/vrm1/__init__.py +1 -0
  147. package/browser/addons/vrm/editor/vrm1/handler.py +28 -0
  148. package/browser/addons/vrm/editor/vrm1/menu.py +76 -0
  149. package/browser/addons/vrm/editor/vrm1/migration.py +321 -0
  150. package/browser/addons/vrm/editor/vrm1/ops.py +2679 -0
  151. package/browser/addons/vrm/editor/vrm1/panel.py +1243 -0
  152. package/browser/addons/vrm/editor/vrm1/property_group.py +2087 -0
  153. package/browser/addons/vrm/editor/vrm1/scene_watcher.py +90 -0
  154. package/browser/addons/vrm/editor/vrm1/ui_list.py +533 -0
  155. package/browser/addons/vrm/exporter/__init__.py +1 -0
  156. package/browser/addons/vrm/exporter/abstract_base_vrm_exporter.py +628 -0
  157. package/browser/addons/vrm/exporter/export_scene.py +930 -0
  158. package/browser/addons/vrm/exporter/gltf2_export_user_extension.py +45 -0
  159. package/browser/addons/vrm/exporter/khr_character_exporter.py +34 -0
  160. package/browser/addons/vrm/exporter/vrm0_exporter.py +4020 -0
  161. package/browser/addons/vrm/exporter/vrm1_exporter.py +3682 -0
  162. package/browser/addons/vrm/exporter/vrm_animation_exporter.py +1035 -0
  163. package/browser/addons/vrm/external/__init__.py +1 -0
  164. package/browser/addons/vrm/external/auto_rig_pro_support.py +3 -0
  165. package/browser/addons/vrm/external/io_scene_gltf2_support.py +418 -0
  166. package/browser/addons/vrm/external/rigify_support.py +1 -0
  167. package/browser/addons/vrm/importer/__init__.py +1 -0
  168. package/browser/addons/vrm/importer/abstract_base_vrm_importer.py +1548 -0
  169. package/browser/addons/vrm/importer/file_handler.py +34 -0
  170. package/browser/addons/vrm/importer/gltf2_import_user_extension.py +268 -0
  171. package/browser/addons/vrm/importer/import_scene.py +646 -0
  172. package/browser/addons/vrm/importer/license_validation.py +198 -0
  173. package/browser/addons/vrm/importer/vrm0_importer.py +1723 -0
  174. package/browser/addons/vrm/importer/vrm1_importer.py +2014 -0
  175. package/browser/addons/vrm/importer/vrm_animation_importer.py +763 -0
  176. package/browser/addons/vrm/importer/vrm_diff.py +316 -0
  177. package/browser/addons/vrm/locale/__init__.py +1 -0
  178. package/browser/addons/vrm/locale/ja_jp.py +826 -0
  179. package/browser/addons/vrm/locale/ruff.toml +8 -0
  180. package/browser/addons/vrm/locale/translation_dictionary.py +10 -0
  181. package/browser/addons/vrm/locale/zh_hans.py +928 -0
  182. package/browser/addons/vrm/registration.py +670 -0
  183. package/browser/addons/vrm.json +18 -0
  184. package/browser/blender-emscripten-engine.mts +60 -128
  185. package/browser/blender-engine.mts +20 -186
  186. package/browser/blender-wali-engine.mts +35 -81
  187. package/browser/describe-thrown.mts +3 -6
  188. package/browser/document-chunks.mts +4 -16
  189. package/browser/gltf_export.py +3161 -0
  190. package/browser/heap-growth.mts +23 -0
  191. package/browser/index.ts +2 -0
  192. package/browser/protocol.ts +119 -35
  193. package/browser/pull-job.mts +2 -10
  194. package/browser/rna.ts +190 -73
  195. package/browser/runtime.ts +197 -82
  196. package/browser/session-addons.mts +33 -0
  197. package/browser/session-frame.mts +5 -24
  198. package/browser/session.py +1338 -1427
  199. package/browser/three/attach-presenter.ts +11 -39
  200. package/browser/three/blender-base64.ts +1 -36
  201. package/browser/three/blender-corner-normals.ts +1 -23
  202. package/browser/three/blender-display-shaders.json +1 -1
  203. package/browser/three/blender-display-shaders.lut +0 -0
  204. package/browser/three/blender-display-transform.ts +2 -1
  205. package/browser/three/blender-frame-columns.ts +5 -13
  206. package/browser/three/blender-graph-material.ts +18 -3
  207. package/browser/three/blender-node-graph.ts +10 -34
  208. package/browser/three/blender-physical-material.ts +2 -31
  209. package/browser/three/blender-runtime-armature.ts +7 -60
  210. package/browser/three/blender-runtime-frame.ts +9 -23
  211. package/browser/three/blender-runtime-geometry.ts +22 -26
  212. package/browser/three/blender-runtime-lighting.ts +48 -178
  213. package/browser/three/blender-runtime-shadows.ts +187 -1
  214. package/browser/three/blender-runtime-skeleton.ts +53 -1
  215. package/browser/three/blender-runtime-view.ts +505 -283
  216. package/browser/three/blender-runtime-weights.ts +9 -72
  217. package/browser/three/blender-sky.ts +13 -33
  218. package/browser/three/blender-triangulate.ts +7 -35
  219. package/browser/three/blender-viewport-sampling.ts +235 -0
  220. package/browser/three/blender-workbench-material.ts +25 -29
  221. package/browser/three/blender-workbench-outline.ts +199 -0
  222. package/browser/three/blender-world-volume.ts +62 -10
  223. package/browser/three/presenter.ts +10 -26
  224. package/browser/three/release.ts +5 -21
  225. package/browser/three/sky-precompute-worker.ts +1 -18
  226. package/browser/three/sky-worker.ts +5 -23
  227. package/browser/three/world-field-sampler.ts +12 -26
  228. package/browser/volter_three.py +9 -105
  229. package/browser/worker.ts +156 -151
  230. package/package.json +5 -2
  231. package/wasm/BUNDLE.json +17 -17
  232. package/wasm/DEPENDENCY-LICENSES.txt +14 -0
  233. package/wasm/blender_browser.data.br +0 -0
  234. package/wasm/blender_browser.js +1 -1
  235. package/wasm/blender_browser.wasm.br +0 -0
  236. package/browser/frame-transfer.mts +0 -19
  237. package/browser/three/agx-base-srgb.lut +0 -0
  238. package/browser/three/agx-look-medium-high-contrast.lut +0 -0
  239. package/browser/three/agx-look-punchy.lut +0 -0
  240. package/browser/three/blender-agx.ts +0 -235
  241. package/browser/three/blender-display-lut.ts +0 -145
  242. package/browser/three/blender-filmic.ts +0 -49
  243. package/browser/three/blender-standard.ts +0 -68
  244. package/browser/three/blender-world-visibility.ts +0 -278
  245. package/browser/three/filmic-srgb.lut +0 -0
@@ -0,0 +1,1679 @@
1
+ # SPDX-License-Identifier: MIT OR GPL-3.0-or-later
2
+ import uuid
3
+ from collections import deque
4
+ from sys import float_info
5
+ from typing import TYPE_CHECKING, ClassVar, Optional
6
+
7
+ from bpy.props import BoolProperty, FloatProperty, IntProperty, StringProperty
8
+ from bpy.types import Armature, Bone, ChildOfConstraint, Context, Object, Operator
9
+ from mathutils import Vector
10
+
11
+ from ...common import safe_removal
12
+ from ...common.logger import get_logger
13
+ from ..extension_accessor import get_armature_extension
14
+ from .handler import reset_state, update_pose_bone_rotations
15
+ from .property_group import (
16
+ SpringBone1ColliderGroupReferencePropertyGroup,
17
+ SpringBone1ColliderReferencePropertyGroup,
18
+ )
19
+
20
+ logger = get_logger(__name__)
21
+
22
+
23
+ class VRM_OT_add_spring_bone1_collider(Operator):
24
+ bl_idname = "vrm.add_spring_bone1_collider"
25
+ bl_label = "Add Collider"
26
+ bl_description = "Add VRM 1.0 Collider"
27
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
28
+
29
+ armature_object_name: StringProperty( # type: ignore[valid-type]
30
+ options={"HIDDEN"},
31
+ )
32
+
33
+ def execute(self, context: Context) -> set[str]:
34
+ armature = context.blend_data.objects.get(self.armature_object_name)
35
+ if armature is None or armature.type != "ARMATURE":
36
+ return {"CANCELLED"}
37
+ armature_data = armature.data
38
+ if not isinstance(armature_data, Armature):
39
+ return {"CANCELLED"}
40
+ spring_bone1 = get_armature_extension(armature_data).spring_bone1
41
+ spring_bone1.add_collider(context, armature)
42
+ return {"FINISHED"}
43
+
44
+ if TYPE_CHECKING:
45
+ # This code is auto generated.
46
+ # To regenerate, run the `uv run tools/property_typing.py` command.
47
+ armature_object_name: str # type: ignore[no-redef]
48
+
49
+
50
+ class VRM_OT_remove_spring_bone1_collider(Operator):
51
+ bl_idname = "vrm.remove_spring_bone1_collider"
52
+ bl_label = "Remove Collider"
53
+ bl_description = "Remove VRM 0.x Collider"
54
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
55
+
56
+ armature_object_name: StringProperty( # type: ignore[valid-type]
57
+ options={"HIDDEN"},
58
+ )
59
+
60
+ collider_index: IntProperty( # type: ignore[valid-type]
61
+ options={"HIDDEN"},
62
+ min=0,
63
+ )
64
+
65
+ def execute(self, context: Context) -> set[str]:
66
+ armature = context.blend_data.objects.get(self.armature_object_name)
67
+ if armature is None or armature.type != "ARMATURE":
68
+ return {"CANCELLED"}
69
+ armature_data = armature.data
70
+ if not isinstance(armature_data, Armature):
71
+ return {"CANCELLED"}
72
+ spring_bone = get_armature_extension(armature_data).spring_bone1
73
+ if len(spring_bone.colliders) <= self.collider_index:
74
+ return {"CANCELLED"}
75
+
76
+ collider = spring_bone.colliders[self.collider_index]
77
+ bpy_object = collider.bpy_object
78
+ if bpy_object:
79
+ collider.bpy_object = None
80
+ for unnecessary_object in (*bpy_object.children, bpy_object):
81
+ if not safe_removal.remove_object(context, unnecessary_object):
82
+ logger.warning(
83
+ 'Failed to remove "%s" with %d users'
84
+ " while removing spring bone collider object",
85
+ unnecessary_object.name,
86
+ unnecessary_object.users,
87
+ )
88
+ bpy_object = None
89
+
90
+ collider_uuid = spring_bone.colliders[self.collider_index].uuid
91
+ for collider_group in spring_bone.collider_groups:
92
+ for index in reversed(range(len(collider_group.colliders))):
93
+ if not (0 <= index < len(collider_group.colliders)):
94
+ continue
95
+ collider_reference = collider_group.colliders[index]
96
+ if collider_reference.collider_uuid == collider_uuid:
97
+ collider_group.colliders.remove(index)
98
+ collider_group.active_collider_index = min(
99
+ collider_group.active_collider_index,
100
+ max(0, len(collider_group.colliders) - 1),
101
+ )
102
+
103
+ spring_bone.colliders.remove(self.collider_index)
104
+
105
+ spring_bone.active_collider_index = min(
106
+ spring_bone.active_collider_index,
107
+ max(0, len(spring_bone.colliders) - 1),
108
+ )
109
+
110
+ return {"FINISHED"}
111
+
112
+ if TYPE_CHECKING:
113
+ # This code is auto generated.
114
+ # To regenerate, run the `uv run tools/property_typing.py` command.
115
+ armature_object_name: str # type: ignore[no-redef]
116
+ collider_index: int # type: ignore[no-redef]
117
+
118
+
119
+ class VRM_OT_move_up_spring_bone1_collider_group(Operator):
120
+ bl_idname = "vrm.move_up_spring_bone1_collider_group"
121
+ bl_label = "Move Up Collider Group"
122
+ bl_description = "Move Up VRM 1.0 Collider Group"
123
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
124
+
125
+ armature_object_name: StringProperty( # type: ignore[valid-type]
126
+ options={"HIDDEN"},
127
+ )
128
+
129
+ collider_group_index: IntProperty( # type: ignore[valid-type]
130
+ options={"HIDDEN"},
131
+ min=0,
132
+ )
133
+
134
+ def execute(self, context: Context) -> set[str]:
135
+ armature = context.blend_data.objects.get(self.armature_object_name)
136
+ if armature is None or armature.type != "ARMATURE":
137
+ return {"CANCELLED"}
138
+ armature_data = armature.data
139
+ if not isinstance(armature_data, Armature):
140
+ return {"CANCELLED"}
141
+ spring_bone = get_armature_extension(armature_data).spring_bone1
142
+ if len(spring_bone.collider_groups) <= self.collider_group_index:
143
+ return {"CANCELLED"}
144
+ new_index = (self.collider_group_index - 1) % len(spring_bone.collider_groups)
145
+ spring_bone.collider_groups.move(self.collider_group_index, new_index)
146
+ spring_bone.active_collider_group_index = new_index
147
+ return {"FINISHED"}
148
+
149
+ if TYPE_CHECKING:
150
+ # This code is auto generated.
151
+ # To regenerate, run the `uv run tools/property_typing.py` command.
152
+ armature_object_name: str # type: ignore[no-redef]
153
+ collider_group_index: int # type: ignore[no-redef]
154
+
155
+
156
+ class VRM_OT_move_down_spring_bone1_collider_group(Operator):
157
+ bl_idname = "vrm.move_down_spring_bone1_collider_group"
158
+ bl_label = "Move Down Collider Group"
159
+ bl_description = "Move Down VRM 1.0 Collider Group"
160
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
161
+
162
+ armature_object_name: StringProperty( # type: ignore[valid-type]
163
+ options={"HIDDEN"},
164
+ )
165
+
166
+ collider_group_index: IntProperty( # type: ignore[valid-type]
167
+ options={"HIDDEN"},
168
+ min=0,
169
+ )
170
+
171
+ def execute(self, context: Context) -> set[str]:
172
+ armature = context.blend_data.objects.get(self.armature_object_name)
173
+ if armature is None or armature.type != "ARMATURE":
174
+ return {"CANCELLED"}
175
+ armature_data = armature.data
176
+ if not isinstance(armature_data, Armature):
177
+ return {"CANCELLED"}
178
+ spring_bone = get_armature_extension(armature_data).spring_bone1
179
+ if len(spring_bone.collider_groups) <= self.collider_group_index:
180
+ return {"CANCELLED"}
181
+ new_index = (self.collider_group_index + 1) % len(spring_bone.collider_groups)
182
+ spring_bone.collider_groups.move(self.collider_group_index, new_index)
183
+ spring_bone.active_collider_group_index = new_index
184
+ return {"FINISHED"}
185
+
186
+ if TYPE_CHECKING:
187
+ # This code is auto generated.
188
+ # To regenerate, run the `uv run tools/property_typing.py` command.
189
+ armature_object_name: str # type: ignore[no-redef]
190
+ collider_group_index: int # type: ignore[no-redef]
191
+
192
+
193
+ class VRM_OT_add_spring_bone1_spring(Operator):
194
+ bl_idname = "vrm.add_spring_bone1_spring"
195
+ bl_label = "Add Spring"
196
+ bl_description = "Add VRM 1.0 Spring"
197
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
198
+
199
+ armature_object_name: StringProperty( # type: ignore[valid-type]
200
+ options={"HIDDEN"},
201
+ )
202
+
203
+ def execute(self, context: Context) -> set[str]:
204
+ armature = context.blend_data.objects.get(self.armature_object_name)
205
+ if armature is None or armature.type != "ARMATURE":
206
+ return {"CANCELLED"}
207
+ armature_data = armature.data
208
+ if not isinstance(armature_data, Armature):
209
+ return {"CANCELLED"}
210
+ spring_bone1 = get_armature_extension(armature_data).spring_bone1
211
+ spring_bone1.add_spring()
212
+ return {"FINISHED"}
213
+
214
+ if TYPE_CHECKING:
215
+ # This code is auto generated.
216
+ # To regenerate, run the `uv run tools/property_typing.py` command.
217
+ armature_object_name: str # type: ignore[no-redef]
218
+
219
+
220
+ class VRM_OT_remove_spring_bone1_spring(Operator):
221
+ bl_idname = "vrm.remove_spring_bone1_spring"
222
+ bl_label = "Remove Spring"
223
+ bl_description = "Remove VRM 1.0 Spring"
224
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
225
+
226
+ armature_object_name: StringProperty( # type: ignore[valid-type]
227
+ options={"HIDDEN"},
228
+ )
229
+
230
+ spring_index: IntProperty( # type: ignore[valid-type]
231
+ options={"HIDDEN"},
232
+ min=0,
233
+ )
234
+
235
+ def execute(self, context: Context) -> set[str]:
236
+ armature = context.blend_data.objects.get(self.armature_object_name)
237
+ if armature is None or armature.type != "ARMATURE":
238
+ return {"CANCELLED"}
239
+ armature_data = armature.data
240
+ if not isinstance(armature_data, Armature):
241
+ return {"CANCELLED"}
242
+ spring_bone1 = get_armature_extension(armature_data).spring_bone1
243
+ if len(spring_bone1.springs) <= self.spring_index:
244
+ return {"CANCELLED"}
245
+ spring_bone1.springs.remove(self.spring_index)
246
+ spring_bone1.active_spring_index = min(
247
+ spring_bone1.active_spring_index, max(0, len(spring_bone1.springs) - 1)
248
+ )
249
+
250
+ return {"FINISHED"}
251
+
252
+ if TYPE_CHECKING:
253
+ # This code is auto generated.
254
+ # To regenerate, run the `uv run tools/property_typing.py` command.
255
+ armature_object_name: str # type: ignore[no-redef]
256
+ spring_index: int # type: ignore[no-redef]
257
+
258
+
259
+ class VRM_OT_move_up_spring_bone1_spring(Operator):
260
+ bl_idname = "vrm.move_up_spring_bone1_spring"
261
+ bl_label = "Move Up Spring"
262
+ bl_description = "Move Up VRM 1.0 Spring"
263
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
264
+
265
+ armature_object_name: StringProperty( # type: ignore[valid-type]
266
+ options={"HIDDEN"},
267
+ )
268
+
269
+ spring_index: IntProperty( # type: ignore[valid-type]
270
+ options={"HIDDEN"},
271
+ min=0,
272
+ )
273
+
274
+ def execute(self, context: Context) -> set[str]:
275
+ armature = context.blend_data.objects.get(self.armature_object_name)
276
+ if armature is None or armature.type != "ARMATURE":
277
+ return {"CANCELLED"}
278
+ armature_data = armature.data
279
+ if not isinstance(armature_data, Armature):
280
+ return {"CANCELLED"}
281
+ spring_bone1 = get_armature_extension(armature_data).spring_bone1
282
+ springs = spring_bone1.springs
283
+ if len(springs) <= self.spring_index:
284
+ return {"CANCELLED"}
285
+ new_spring_index = (self.spring_index - 1) % len(springs)
286
+ springs.move(self.spring_index, new_spring_index)
287
+ spring_bone1.active_spring_index = new_spring_index
288
+ return {"FINISHED"}
289
+
290
+ if TYPE_CHECKING:
291
+ # This code is auto generated.
292
+ # To regenerate, run the `uv run tools/property_typing.py` command.
293
+ armature_object_name: str # type: ignore[no-redef]
294
+ spring_index: int # type: ignore[no-redef]
295
+
296
+
297
+ class VRM_OT_move_down_spring_bone1_spring(Operator):
298
+ bl_idname = "vrm.move_down_spring_bone1_spring"
299
+ bl_label = "Move Down Spring"
300
+ bl_description = "Move Down VRM 1.0 Spring"
301
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
302
+
303
+ armature_object_name: StringProperty( # type: ignore[valid-type]
304
+ options={"HIDDEN"},
305
+ )
306
+
307
+ spring_index: IntProperty( # type: ignore[valid-type]
308
+ options={"HIDDEN"},
309
+ min=0,
310
+ )
311
+
312
+ def execute(self, context: Context) -> set[str]:
313
+ armature = context.blend_data.objects.get(self.armature_object_name)
314
+ if armature is None or armature.type != "ARMATURE":
315
+ return {"CANCELLED"}
316
+ armature_data = armature.data
317
+ if not isinstance(armature_data, Armature):
318
+ return {"CANCELLED"}
319
+ spring_bone1 = get_armature_extension(armature_data).spring_bone1
320
+ springs = spring_bone1.springs
321
+ if len(springs) <= self.spring_index:
322
+ return {"CANCELLED"}
323
+ new_spring_index = (self.spring_index + 1) % len(springs)
324
+ springs.move(self.spring_index, new_spring_index)
325
+ spring_bone1.active_spring_index = new_spring_index
326
+ return {"FINISHED"}
327
+
328
+ if TYPE_CHECKING:
329
+ # This code is auto generated.
330
+ # To regenerate, run the `uv run tools/property_typing.py` command.
331
+ armature_object_name: str # type: ignore[no-redef]
332
+ spring_index: int # type: ignore[no-redef]
333
+
334
+
335
+ class VRM_OT_add_spring_bone1_collider_group(Operator):
336
+ bl_idname = "vrm.add_spring_bone1_collider_group"
337
+ bl_label = "Add Collider Group"
338
+ bl_description = "Add VRM 1.0 Spring Bone Collider Group"
339
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
340
+
341
+ armature_object_name: StringProperty( # type: ignore[valid-type]
342
+ options={"HIDDEN"},
343
+ )
344
+
345
+ def execute(self, context: Context) -> set[str]:
346
+ armature = context.blend_data.objects.get(self.armature_object_name)
347
+ if armature is None or armature.type != "ARMATURE":
348
+ return {"CANCELLED"}
349
+ armature_data = armature.data
350
+ if not isinstance(armature_data, Armature):
351
+ return {"CANCELLED"}
352
+ spring_bone = get_armature_extension(armature_data).spring_bone1
353
+ spring_bone.add_collider_group()
354
+ return {"FINISHED"}
355
+
356
+ if TYPE_CHECKING:
357
+ # This code is auto generated.
358
+ # To regenerate, run the `uv run tools/property_typing.py` command.
359
+ armature_object_name: str # type: ignore[no-redef]
360
+
361
+
362
+ class VRM_OT_remove_spring_bone1_collider_group(Operator):
363
+ bl_idname = "vrm.remove_spring_bone1_collider_group"
364
+ bl_label = "Remove Collider Group"
365
+ bl_description = "Remove VRM 1.0 Spring Bone Collider Group"
366
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
367
+
368
+ armature_object_name: StringProperty( # type: ignore[valid-type]
369
+ options={"HIDDEN"},
370
+ )
371
+
372
+ collider_group_index: IntProperty( # type: ignore[valid-type]
373
+ options={"HIDDEN"},
374
+ min=0,
375
+ )
376
+
377
+ def execute(self, context: Context) -> set[str]:
378
+ armature = context.blend_data.objects.get(self.armature_object_name)
379
+ if armature is None or armature.type != "ARMATURE":
380
+ return {"CANCELLED"}
381
+ armature_data = armature.data
382
+ if not isinstance(armature_data, Armature):
383
+ return {"CANCELLED"}
384
+ spring_bone = get_armature_extension(armature_data).spring_bone1
385
+ collider_groups = spring_bone.collider_groups
386
+ if len(collider_groups) <= self.collider_group_index:
387
+ return {"CANCELLED"}
388
+
389
+ collider_group_uuid = collider_groups[self.collider_group_index].uuid
390
+ for spring in spring_bone.springs:
391
+ for index in reversed(range(len(spring.collider_groups))):
392
+ if not (0 <= index < len(spring.collider_groups)):
393
+ continue
394
+ collider_group_reference = spring.collider_groups[index]
395
+ if collider_group_reference.collider_group_uuid == collider_group_uuid:
396
+ spring.collider_groups.remove(index)
397
+ spring.active_collider_group_index = min(
398
+ spring.active_collider_group_index,
399
+ max(0, len(spring.collider_groups) - 1),
400
+ )
401
+
402
+ collider_groups.remove(self.collider_group_index)
403
+
404
+ spring_bone.active_collider_group_index = min(
405
+ spring_bone.active_collider_group_index,
406
+ max(0, len(spring_bone.collider_groups) - 1),
407
+ )
408
+
409
+ return {"FINISHED"}
410
+
411
+ if TYPE_CHECKING:
412
+ # This code is auto generated.
413
+ # To regenerate, run the `uv run tools/property_typing.py` command.
414
+ armature_object_name: str # type: ignore[no-redef]
415
+ collider_group_index: int # type: ignore[no-redef]
416
+
417
+
418
+ class VRM_OT_move_up_spring_bone1_collider(Operator):
419
+ bl_idname = "vrm.move_up_spring_bone1_collider"
420
+ bl_label = "Move Up Collider"
421
+ bl_description = "Move Up VRM 1.0 Collider"
422
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
423
+
424
+ armature_object_name: StringProperty( # type: ignore[valid-type]
425
+ options={"HIDDEN"},
426
+ )
427
+
428
+ collider_index: IntProperty( # type: ignore[valid-type]
429
+ options={"HIDDEN"},
430
+ min=0,
431
+ )
432
+
433
+ def execute(self, context: Context) -> set[str]:
434
+ armature = context.blend_data.objects.get(self.armature_object_name)
435
+ if armature is None or armature.type != "ARMATURE":
436
+ return {"CANCELLED"}
437
+ armature_data = armature.data
438
+ if not isinstance(armature_data, Armature):
439
+ return {"CANCELLED"}
440
+ spring_bone1 = get_armature_extension(armature_data).spring_bone1
441
+ colliders = spring_bone1.colliders
442
+ if len(colliders) <= self.collider_index:
443
+ return {"CANCELLED"}
444
+ new_collider_index = (self.collider_index - 1) % len(colliders)
445
+ colliders.move(self.collider_index, new_collider_index)
446
+ spring_bone1.active_collider_index = new_collider_index
447
+ return {"FINISHED"}
448
+
449
+ if TYPE_CHECKING:
450
+ # This code is auto generated.
451
+ # To regenerate, run the `uv run tools/property_typing.py` command.
452
+ armature_object_name: str # type: ignore[no-redef]
453
+ collider_index: int # type: ignore[no-redef]
454
+
455
+
456
+ class VRM_OT_move_down_spring_bone1_collider(Operator):
457
+ bl_idname = "vrm.move_down_spring_bone1_collider"
458
+ bl_label = "Move Down Collider"
459
+ bl_description = "Move Down VRM 1.0 Collider"
460
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
461
+
462
+ armature_object_name: StringProperty( # type: ignore[valid-type]
463
+ options={"HIDDEN"},
464
+ )
465
+
466
+ collider_index: IntProperty( # type: ignore[valid-type]
467
+ options={"HIDDEN"},
468
+ min=0,
469
+ )
470
+
471
+ def execute(self, context: Context) -> set[str]:
472
+ armature = context.blend_data.objects.get(self.armature_object_name)
473
+ if armature is None or armature.type != "ARMATURE":
474
+ return {"CANCELLED"}
475
+ armature_data = armature.data
476
+ if not isinstance(armature_data, Armature):
477
+ return {"CANCELLED"}
478
+ spring_bone1 = get_armature_extension(armature_data).spring_bone1
479
+ colliders = spring_bone1.colliders
480
+ if len(colliders) <= self.collider_index:
481
+ return {"CANCELLED"}
482
+ new_collider_index = (self.collider_index + 1) % len(colliders)
483
+ colliders.move(self.collider_index, new_collider_index)
484
+ spring_bone1.active_collider_index = new_collider_index
485
+ return {"FINISHED"}
486
+
487
+ if TYPE_CHECKING:
488
+ # This code is auto generated.
489
+ # To regenerate, run the `uv run tools/property_typing.py` command.
490
+ armature_object_name: str # type: ignore[no-redef]
491
+ collider_index: int # type: ignore[no-redef]
492
+
493
+
494
+ class VRM_OT_add_spring_bone1_collider_group_collider(Operator):
495
+ bl_idname = "vrm.add_spring_bone1_collider_group_collider"
496
+ bl_label = "Add Collider"
497
+ bl_description = "Add VRM 1.0 Spring Bone Collider Group Collider"
498
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
499
+
500
+ armature_object_name: StringProperty( # type: ignore[valid-type]
501
+ options={"HIDDEN"},
502
+ )
503
+
504
+ collider_group_index: IntProperty( # type: ignore[valid-type]
505
+ options={"HIDDEN"},
506
+ min=0,
507
+ )
508
+
509
+ def execute(self, context: Context) -> set[str]:
510
+ armature = context.blend_data.objects.get(self.armature_object_name)
511
+ if armature is None or armature.type != "ARMATURE":
512
+ return {"CANCELLED"}
513
+ armature_data = armature.data
514
+ if not isinstance(armature_data, Armature):
515
+ return {"CANCELLED"}
516
+ collider_groups = get_armature_extension(
517
+ armature_data
518
+ ).spring_bone1.collider_groups
519
+ if len(collider_groups) <= self.collider_group_index:
520
+ return {"CANCELLED"}
521
+ collider_group = collider_groups[self.collider_group_index]
522
+ collider_group.add_collider()
523
+ return {"FINISHED"}
524
+
525
+ if TYPE_CHECKING:
526
+ # This code is auto generated.
527
+ # To regenerate, run the `uv run tools/property_typing.py` command.
528
+ armature_object_name: str # type: ignore[no-redef]
529
+ collider_group_index: int # type: ignore[no-redef]
530
+
531
+
532
+ class VRM_OT_assign_spring_bone1_collider_group_collider(Operator):
533
+ bl_idname = "vrm.assign_spring_bone1_collider_group_collider"
534
+ bl_label = "Assign Collider"
535
+ bl_description = "Assign VRM 1.0 Spring Bone Collider Group Collider"
536
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
537
+
538
+ armature_data_name: StringProperty( # type: ignore[valid-type]
539
+ options={"HIDDEN"},
540
+ )
541
+ collider_reference_path: StringProperty( # type: ignore[valid-type]
542
+ options={"HIDDEN"},
543
+ )
544
+ collider_uuid: StringProperty( # type: ignore[valid-type]
545
+ options={"HIDDEN"},
546
+ )
547
+
548
+ def execute(self, context: Context) -> set[str]:
549
+ armature_data = context.blend_data.armatures.get(self.armature_data_name)
550
+ if not isinstance(armature_data, Armature):
551
+ return {"CANCELLED"}
552
+
553
+ collider_reference = armature_data.path_resolve(
554
+ self.collider_reference_path,
555
+ False,
556
+ )
557
+ if not isinstance(
558
+ collider_reference, SpringBone1ColliderReferencePropertyGroup
559
+ ):
560
+ return {"CANCELLED"}
561
+
562
+ if not self.collider_uuid:
563
+ collider_reference.collider_uuid = ""
564
+ return {"FINISHED"}
565
+
566
+ spring_bone1 = get_armature_extension(armature_data).spring_bone1
567
+ for collider in spring_bone1.colliders:
568
+ if collider.uuid != self.collider_uuid:
569
+ continue
570
+ collider_reference.collider_uuid = collider.uuid
571
+ return {"FINISHED"}
572
+
573
+ return {"CANCELLED"}
574
+
575
+ if TYPE_CHECKING:
576
+ # This code is auto generated.
577
+ # To regenerate, run the `uv run tools/property_typing.py` command.
578
+ armature_data_name: str # type: ignore[no-redef]
579
+ collider_reference_path: str # type: ignore[no-redef]
580
+ collider_uuid: str # type: ignore[no-redef]
581
+
582
+
583
+ class VRM_OT_unassign_spring_bone1_collider_group_collider(Operator):
584
+ bl_idname = "vrm.unassign_spring_bone1_collider_group_collider"
585
+ bl_label = "Unassign Collider"
586
+ bl_description = "Unassign VRM 1.0 Spring Bone Collider Group Collider"
587
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
588
+
589
+ armature_data_name: StringProperty( # type: ignore[valid-type]
590
+ options={"HIDDEN"},
591
+ )
592
+ collider_reference_path: StringProperty( # type: ignore[valid-type]
593
+ options={"HIDDEN"},
594
+ )
595
+
596
+ def execute(self, context: Context) -> set[str]:
597
+ armature_data = context.blend_data.armatures.get(self.armature_data_name)
598
+ if not isinstance(armature_data, Armature):
599
+ return {"CANCELLED"}
600
+
601
+ collider_reference = armature_data.path_resolve(
602
+ self.collider_reference_path,
603
+ False,
604
+ )
605
+ if not isinstance(
606
+ collider_reference, SpringBone1ColliderReferencePropertyGroup
607
+ ):
608
+ return {"CANCELLED"}
609
+
610
+ collider_reference.collider_uuid = ""
611
+ return {"FINISHED"}
612
+
613
+ if TYPE_CHECKING:
614
+ # This code is auto generated.
615
+ # To regenerate, run the `uv run tools/property_typing.py` command.
616
+ armature_data_name: str # type: ignore[no-redef]
617
+ collider_reference_path: str # type: ignore[no-redef]
618
+
619
+
620
+ class VRM_OT_remove_spring_bone1_collider_group_collider(Operator):
621
+ bl_idname = "vrm.remove_spring_bone1_collider_group_collider"
622
+ bl_label = "Remove Collider"
623
+ bl_description = "Remove VRM 1.0 Spring Bone Collider Group Collider"
624
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
625
+
626
+ armature_object_name: StringProperty( # type: ignore[valid-type]
627
+ options={"HIDDEN"},
628
+ )
629
+
630
+ collider_group_index: IntProperty( # type: ignore[valid-type]
631
+ options={"HIDDEN"},
632
+ min=0,
633
+ )
634
+ collider_index: IntProperty( # type: ignore[valid-type]
635
+ options={"HIDDEN"},
636
+ min=0,
637
+ )
638
+
639
+ def execute(self, context: Context) -> set[str]:
640
+ armature = context.blend_data.objects.get(self.armature_object_name)
641
+ if armature is None or armature.type != "ARMATURE":
642
+ return {"CANCELLED"}
643
+ armature_data = armature.data
644
+ if not isinstance(armature_data, Armature):
645
+ return {"CANCELLED"}
646
+ collider_groups = get_armature_extension(
647
+ armature_data
648
+ ).spring_bone1.collider_groups
649
+ if len(collider_groups) <= self.collider_group_index:
650
+ return {"CANCELLED"}
651
+ collider_group = collider_groups[self.collider_group_index]
652
+ if len(collider_group.colliders) <= self.collider_index:
653
+ return {"CANCELLED"}
654
+ collider_group.colliders.remove(self.collider_index)
655
+ collider_group.active_collider_index = min(
656
+ collider_group.active_collider_index,
657
+ max(0, len(collider_group.colliders) - 1),
658
+ )
659
+ return {"FINISHED"}
660
+
661
+ if TYPE_CHECKING:
662
+ # This code is auto generated.
663
+ # To regenerate, run the `uv run tools/property_typing.py` command.
664
+ armature_object_name: str # type: ignore[no-redef]
665
+ collider_group_index: int # type: ignore[no-redef]
666
+ collider_index: int # type: ignore[no-redef]
667
+
668
+
669
+ class VRM_OT_move_up_spring_bone1_collider_group_collider(Operator):
670
+ bl_idname = "vrm.move_up_spring_bone1_collider_group_collider"
671
+ bl_label = "Move Up Collider"
672
+ bl_description = "Move Up VRM 1.0 Collider Group Collider"
673
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
674
+
675
+ armature_object_name: StringProperty( # type: ignore[valid-type]
676
+ options={"HIDDEN"},
677
+ )
678
+
679
+ collider_group_index: IntProperty( # type: ignore[valid-type]
680
+ options={"HIDDEN"},
681
+ min=0,
682
+ )
683
+ collider_index: IntProperty( # type: ignore[valid-type]
684
+ options={"HIDDEN"},
685
+ min=0,
686
+ )
687
+
688
+ def execute(self, context: Context) -> set[str]:
689
+ armature = context.blend_data.objects.get(self.armature_object_name)
690
+ if armature is None or armature.type != "ARMATURE":
691
+ return {"CANCELLED"}
692
+ armature_data = armature.data
693
+ if not isinstance(armature_data, Armature):
694
+ return {"CANCELLED"}
695
+ spring_bone1 = get_armature_extension(armature_data).spring_bone1
696
+ if len(spring_bone1.collider_groups) <= self.collider_group_index:
697
+ return {"CANCELLED"}
698
+ collider_group = spring_bone1.collider_groups[self.collider_group_index]
699
+ if len(collider_group.colliders) <= self.collider_index:
700
+ return {"CANCELLED"}
701
+ new_collider_index = (self.collider_index - 1) % len(collider_group.colliders)
702
+ collider_group.colliders.move(self.collider_index, new_collider_index)
703
+ collider_group.active_collider_index = new_collider_index
704
+ return {"FINISHED"}
705
+
706
+ if TYPE_CHECKING:
707
+ # This code is auto generated.
708
+ # To regenerate, run the `uv run tools/property_typing.py` command.
709
+ armature_object_name: str # type: ignore[no-redef]
710
+ collider_group_index: int # type: ignore[no-redef]
711
+ collider_index: int # type: ignore[no-redef]
712
+
713
+
714
+ class VRM_OT_move_down_spring_bone1_collider_group_collider(Operator):
715
+ bl_idname = "vrm.move_down_spring_bone1_collider_group_collider"
716
+ bl_label = "Move Down Collider"
717
+ bl_description = "Move Down VRM 1.0 Collider Group Collider"
718
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
719
+
720
+ armature_object_name: StringProperty( # type: ignore[valid-type]
721
+ options={"HIDDEN"},
722
+ )
723
+
724
+ collider_group_index: IntProperty( # type: ignore[valid-type]
725
+ options={"HIDDEN"},
726
+ min=0,
727
+ )
728
+ collider_index: IntProperty( # type: ignore[valid-type]
729
+ options={"HIDDEN"},
730
+ min=0,
731
+ )
732
+
733
+ def execute(self, context: Context) -> set[str]:
734
+ armature = context.blend_data.objects.get(self.armature_object_name)
735
+ if armature is None or armature.type != "ARMATURE":
736
+ return {"CANCELLED"}
737
+ armature_data = armature.data
738
+ if not isinstance(armature_data, Armature):
739
+ return {"CANCELLED"}
740
+ spring_bone1 = get_armature_extension(armature_data).spring_bone1
741
+ if len(spring_bone1.collider_groups) <= self.collider_group_index:
742
+ return {"CANCELLED"}
743
+ collider_group = spring_bone1.collider_groups[self.collider_group_index]
744
+ if len(collider_group.colliders) <= self.collider_index:
745
+ return {"CANCELLED"}
746
+ new_collider_index = (self.collider_index + 1) % len(collider_group.colliders)
747
+ collider_group.colliders.move(self.collider_index, new_collider_index)
748
+ collider_group.active_collider_index = new_collider_index
749
+ return {"FINISHED"}
750
+
751
+ if TYPE_CHECKING:
752
+ # This code is auto generated.
753
+ # To regenerate, run the `uv run tools/property_typing.py` command.
754
+ armature_object_name: str # type: ignore[no-redef]
755
+ collider_group_index: int # type: ignore[no-redef]
756
+ collider_index: int # type: ignore[no-redef]
757
+
758
+
759
+ class VRM_OT_add_spring_bone1_spring_collider_group(Operator):
760
+ bl_idname = "vrm.add_spring_bone1_spring_collider_group"
761
+ bl_label = "Add Collider Group"
762
+ bl_description = "Add VRM 1.0 Spring Bone Spring Collider Group"
763
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
764
+
765
+ armature_object_name: StringProperty( # type: ignore[valid-type]
766
+ options={"HIDDEN"},
767
+ )
768
+
769
+ spring_index: IntProperty( # type: ignore[valid-type]
770
+ options={"HIDDEN"},
771
+ min=0,
772
+ )
773
+
774
+ def execute(self, context: Context) -> set[str]:
775
+ armature = context.blend_data.objects.get(self.armature_object_name)
776
+ if armature is None or armature.type != "ARMATURE":
777
+ return {"CANCELLED"}
778
+ armature_data = armature.data
779
+ if not isinstance(armature_data, Armature):
780
+ return {"CANCELLED"}
781
+ springs = get_armature_extension(armature_data).spring_bone1.springs
782
+ if len(springs) <= self.spring_index:
783
+ return {"CANCELLED"}
784
+ spring = springs[self.spring_index]
785
+ spring.add_collider_group()
786
+ return {"FINISHED"}
787
+
788
+ if TYPE_CHECKING:
789
+ # This code is auto generated.
790
+ # To regenerate, run the `uv run tools/property_typing.py` command.
791
+ armature_object_name: str # type: ignore[no-redef]
792
+ spring_index: int # type: ignore[no-redef]
793
+
794
+
795
+ class VRM_OT_assign_spring_bone1_spring_collider_group(Operator):
796
+ bl_idname = "vrm.assign_spring_bone1_spring_collider_group"
797
+ bl_label = "Assign Collider Group"
798
+ bl_description = "Assign VRM 1.0 Spring Bone Spring Collider Group"
799
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
800
+
801
+ armature_data_name: StringProperty( # type: ignore[valid-type]
802
+ options={"HIDDEN"},
803
+ )
804
+ collider_group_reference_path: StringProperty( # type: ignore[valid-type]
805
+ options={"HIDDEN"},
806
+ )
807
+ collider_group_uuid: StringProperty( # type: ignore[valid-type]
808
+ options={"HIDDEN"},
809
+ )
810
+
811
+ def execute(self, context: Context) -> set[str]:
812
+ armature_data = context.blend_data.armatures.get(self.armature_data_name)
813
+ if not isinstance(armature_data, Armature):
814
+ return {"CANCELLED"}
815
+
816
+ collider_group_reference = armature_data.path_resolve(
817
+ self.collider_group_reference_path,
818
+ False,
819
+ )
820
+ if not isinstance(
821
+ collider_group_reference,
822
+ SpringBone1ColliderGroupReferencePropertyGroup,
823
+ ):
824
+ return {"CANCELLED"}
825
+
826
+ if not self.collider_group_uuid:
827
+ collider_group_reference.collider_group_uuid = ""
828
+ return {"FINISHED"}
829
+
830
+ spring_bone1 = get_armature_extension(armature_data).spring_bone1
831
+ for collider_group in spring_bone1.collider_groups:
832
+ if collider_group.uuid != self.collider_group_uuid:
833
+ continue
834
+ collider_group_reference.collider_group_uuid = collider_group.uuid
835
+ return {"FINISHED"}
836
+
837
+ return {"CANCELLED"}
838
+
839
+ if TYPE_CHECKING:
840
+ # This code is auto generated.
841
+ # To regenerate, run the `uv run tools/property_typing.py` command.
842
+ armature_data_name: str # type: ignore[no-redef]
843
+ collider_group_reference_path: str # type: ignore[no-redef]
844
+ collider_group_uuid: str # type: ignore[no-redef]
845
+
846
+
847
+ class VRM_OT_unassign_spring_bone1_spring_collider_group(Operator):
848
+ bl_idname = "vrm.unassign_spring_bone1_spring_collider_group"
849
+ bl_label = "Unassign Collider Group"
850
+ bl_description = "Unassign VRM 1.0 Spring Bone Spring Collider Group"
851
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
852
+
853
+ armature_data_name: StringProperty( # type: ignore[valid-type]
854
+ options={"HIDDEN"},
855
+ )
856
+ collider_group_reference_path: StringProperty( # type: ignore[valid-type]
857
+ options={"HIDDEN"},
858
+ )
859
+
860
+ def execute(self, context: Context) -> set[str]:
861
+ armature_data = context.blend_data.armatures.get(self.armature_data_name)
862
+ if not isinstance(armature_data, Armature):
863
+ return {"CANCELLED"}
864
+
865
+ collider_group_reference = armature_data.path_resolve(
866
+ self.collider_group_reference_path,
867
+ False,
868
+ )
869
+ if not isinstance(
870
+ collider_group_reference,
871
+ SpringBone1ColliderGroupReferencePropertyGroup,
872
+ ):
873
+ return {"CANCELLED"}
874
+
875
+ collider_group_reference.collider_group_uuid = ""
876
+ return {"FINISHED"}
877
+
878
+ if TYPE_CHECKING:
879
+ # This code is auto generated.
880
+ # To regenerate, run the `uv run tools/property_typing.py` command.
881
+ armature_data_name: str # type: ignore[no-redef]
882
+ collider_group_reference_path: str # type: ignore[no-redef]
883
+
884
+
885
+ class VRM_OT_remove_spring_bone1_spring_collider_group(Operator):
886
+ bl_idname = "vrm.remove_spring_bone1_spring_collider_group"
887
+ bl_label = "Remove Collider Group"
888
+ bl_description = "Remove VRM 1.0 Spring Bone Spring Collider Group"
889
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
890
+
891
+ armature_object_name: StringProperty( # type: ignore[valid-type]
892
+ options={"HIDDEN"},
893
+ )
894
+
895
+ spring_index: IntProperty( # type: ignore[valid-type]
896
+ options={"HIDDEN"},
897
+ min=0,
898
+ )
899
+ collider_group_index: IntProperty( # type: ignore[valid-type]
900
+ options={"HIDDEN"},
901
+ min=0,
902
+ )
903
+
904
+ def execute(self, context: Context) -> set[str]:
905
+ armature = context.blend_data.objects.get(self.armature_object_name)
906
+ if armature is None or armature.type != "ARMATURE":
907
+ return {"CANCELLED"}
908
+ armature_data = armature.data
909
+ if not isinstance(armature_data, Armature):
910
+ return {"CANCELLED"}
911
+ springs = get_armature_extension(armature_data).spring_bone1.springs
912
+ if len(springs) <= self.spring_index:
913
+ return {"CANCELLED"}
914
+ spring = springs[self.spring_index]
915
+ if len(spring.collider_groups) <= self.collider_group_index:
916
+ return {"CANCELLED"}
917
+ spring.collider_groups.remove(self.collider_group_index)
918
+ spring.active_collider_group_index = min(
919
+ spring.active_collider_group_index, max(0, len(spring.collider_groups) - 1)
920
+ )
921
+ return {"FINISHED"}
922
+
923
+ if TYPE_CHECKING:
924
+ # This code is auto generated.
925
+ # To regenerate, run the `uv run tools/property_typing.py` command.
926
+ armature_object_name: str # type: ignore[no-redef]
927
+ spring_index: int # type: ignore[no-redef]
928
+ collider_group_index: int # type: ignore[no-redef]
929
+
930
+
931
+ class VRM_OT_move_up_spring_bone1_spring_collider_group(Operator):
932
+ bl_idname = "vrm.move_up_spring_bone1_spring_collider_group"
933
+ bl_label = "Move Up Collider Group"
934
+ bl_description = "Move Up VRM 1.0 Spring Collider Group"
935
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
936
+
937
+ armature_object_name: StringProperty( # type: ignore[valid-type]
938
+ options={"HIDDEN"},
939
+ )
940
+
941
+ spring_index: IntProperty( # type: ignore[valid-type]
942
+ options={"HIDDEN"},
943
+ min=0,
944
+ )
945
+ collider_group_index: IntProperty( # type: ignore[valid-type]
946
+ options={"HIDDEN"},
947
+ min=0,
948
+ )
949
+
950
+ def execute(self, context: Context) -> set[str]:
951
+ armature = context.blend_data.objects.get(self.armature_object_name)
952
+ if armature is None or armature.type != "ARMATURE":
953
+ return {"CANCELLED"}
954
+ armature_data = armature.data
955
+ if not isinstance(armature_data, Armature):
956
+ return {"CANCELLED"}
957
+ spring_bone1 = get_armature_extension(armature_data).spring_bone1
958
+ springs = spring_bone1.springs
959
+ if len(springs) <= self.spring_index:
960
+ return {"CANCELLED"}
961
+ spring = springs[self.spring_index]
962
+ if len(spring.collider_groups) <= self.collider_group_index:
963
+ return {"CANCELLED"}
964
+ new_collider_group_index = (self.collider_group_index - 1) % len(
965
+ spring.collider_groups
966
+ )
967
+ spring.collider_groups.move(self.collider_group_index, new_collider_group_index)
968
+ spring.active_collider_group_index = new_collider_group_index
969
+ return {"FINISHED"}
970
+
971
+ if TYPE_CHECKING:
972
+ # This code is auto generated.
973
+ # To regenerate, run the `uv run tools/property_typing.py` command.
974
+ armature_object_name: str # type: ignore[no-redef]
975
+ spring_index: int # type: ignore[no-redef]
976
+ collider_group_index: int # type: ignore[no-redef]
977
+
978
+
979
+ class VRM_OT_move_down_spring_bone1_spring_collider_group(Operator):
980
+ bl_idname = "vrm.move_down_spring_bone1_spring_collider_group"
981
+ bl_label = "Move Down Collider Group"
982
+ bl_description = "Move Down VRM 1.0 Spring Collider Group"
983
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
984
+
985
+ armature_object_name: StringProperty( # type: ignore[valid-type]
986
+ options={"HIDDEN"},
987
+ )
988
+
989
+ spring_index: IntProperty( # type: ignore[valid-type]
990
+ options={"HIDDEN"},
991
+ min=0,
992
+ )
993
+ collider_group_index: IntProperty( # type: ignore[valid-type]
994
+ options={"HIDDEN"},
995
+ min=0,
996
+ )
997
+
998
+ def execute(self, context: Context) -> set[str]:
999
+ armature = context.blend_data.objects.get(self.armature_object_name)
1000
+ if armature is None or armature.type != "ARMATURE":
1001
+ return {"CANCELLED"}
1002
+ armature_data = armature.data
1003
+ if not isinstance(armature_data, Armature):
1004
+ return {"CANCELLED"}
1005
+ spring_bone1 = get_armature_extension(armature_data).spring_bone1
1006
+ springs = spring_bone1.springs
1007
+ if len(springs) <= self.spring_index:
1008
+ return {"CANCELLED"}
1009
+ spring = springs[self.spring_index]
1010
+ if len(spring.collider_groups) <= self.collider_group_index:
1011
+ return {"CANCELLED"}
1012
+ new_collider_group_index = (self.collider_group_index + 1) % len(
1013
+ spring.collider_groups
1014
+ )
1015
+ spring.collider_groups.move(self.collider_group_index, new_collider_group_index)
1016
+ spring.active_collider_group_index = new_collider_group_index
1017
+ return {"FINISHED"}
1018
+
1019
+ if TYPE_CHECKING:
1020
+ # This code is auto generated.
1021
+ # To regenerate, run the `uv run tools/property_typing.py` command.
1022
+ armature_object_name: str # type: ignore[no-redef]
1023
+ spring_index: int # type: ignore[no-redef]
1024
+ collider_group_index: int # type: ignore[no-redef]
1025
+
1026
+
1027
+ class VRM_OT_add_spring_bone1_joint(Operator):
1028
+ bl_idname = "vrm.add_spring_bone1_spring_joint"
1029
+ bl_label = "Add Joint"
1030
+ bl_description = "Add VRM 1.0 Spring Bone Spring Joint"
1031
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
1032
+
1033
+ armature_object_name: StringProperty( # type: ignore[valid-type]
1034
+ options={"HIDDEN"},
1035
+ )
1036
+
1037
+ spring_index: IntProperty( # type: ignore[valid-type]
1038
+ options={"HIDDEN"},
1039
+ min=0,
1040
+ )
1041
+ guess_properties: BoolProperty( # type: ignore[valid-type]
1042
+ options={"HIDDEN"},
1043
+ )
1044
+
1045
+ def execute(self, context: Context) -> set[str]:
1046
+ armature = context.blend_data.objects.get(self.armature_object_name)
1047
+ if armature is None or armature.type != "ARMATURE":
1048
+ return {"CANCELLED"}
1049
+ armature_data = armature.data
1050
+ if not isinstance(armature_data, Armature):
1051
+ return {"CANCELLED"}
1052
+ springs = get_armature_extension(armature_data).spring_bone1.springs
1053
+ if len(springs) <= self.spring_index:
1054
+ return {"CANCELLED"}
1055
+ spring = springs[self.spring_index]
1056
+ spring.add_joint()
1057
+ if not self.guess_properties:
1058
+ return {"FINISHED"}
1059
+
1060
+ if len(spring.joints) < 2:
1061
+ return {"FINISHED"}
1062
+ parent_joint, joint = spring.joints[-2:]
1063
+ parent_bone = armature_data.bones.get(parent_joint.node.bone_name)
1064
+ if parent_bone and parent_bone.children:
1065
+ joint.node.bone_name = parent_bone.children[0].name
1066
+ joint.hit_radius = parent_joint.hit_radius
1067
+ joint.stiffness = parent_joint.stiffness
1068
+ joint.gravity_power = parent_joint.gravity_power
1069
+ joint.gravity_dir = list(parent_joint.gravity_dir)
1070
+ joint.drag_force = parent_joint.drag_force
1071
+ return {"FINISHED"}
1072
+
1073
+ if TYPE_CHECKING:
1074
+ # This code is auto generated.
1075
+ # To regenerate, run the `uv run tools/property_typing.py` command.
1076
+ armature_object_name: str # type: ignore[no-redef]
1077
+ spring_index: int # type: ignore[no-redef]
1078
+ guess_properties: bool # type: ignore[no-redef]
1079
+
1080
+
1081
+ class VRM_OT_remove_spring_bone1_joint(Operator):
1082
+ bl_idname = "vrm.remove_spring_bone1_spring_joint"
1083
+ bl_label = "Remove Joint"
1084
+ bl_description = "Remove VRM 1.0 Spring Bone Spring Joint"
1085
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
1086
+
1087
+ armature_object_name: StringProperty( # type: ignore[valid-type]
1088
+ options={"HIDDEN"},
1089
+ )
1090
+
1091
+ spring_index: IntProperty( # type: ignore[valid-type]
1092
+ options={"HIDDEN"},
1093
+ min=0,
1094
+ )
1095
+ joint_index: IntProperty( # type: ignore[valid-type]
1096
+ options={"HIDDEN"},
1097
+ min=0,
1098
+ )
1099
+
1100
+ def execute(self, context: Context) -> set[str]:
1101
+ armature = context.blend_data.objects.get(self.armature_object_name)
1102
+ if armature is None or armature.type != "ARMATURE":
1103
+ return {"CANCELLED"}
1104
+ armature_data = armature.data
1105
+ if not isinstance(armature_data, Armature):
1106
+ return {"CANCELLED"}
1107
+ springs = get_armature_extension(armature_data).spring_bone1.springs
1108
+ if len(springs) <= self.spring_index:
1109
+ return {"CANCELLED"}
1110
+ spring = springs[self.spring_index]
1111
+ if len(spring.joints) <= self.joint_index:
1112
+ return {"CANCELLED"}
1113
+ spring.joints.remove(self.joint_index)
1114
+ spring.active_joint_index = min(
1115
+ spring.active_joint_index, max(0, len(spring.joints) - 1)
1116
+ )
1117
+ return {"FINISHED"}
1118
+
1119
+ if TYPE_CHECKING:
1120
+ # This code is auto generated.
1121
+ # To regenerate, run the `uv run tools/property_typing.py` command.
1122
+ armature_object_name: str # type: ignore[no-redef]
1123
+ spring_index: int # type: ignore[no-redef]
1124
+ joint_index: int # type: ignore[no-redef]
1125
+
1126
+
1127
+ class VRM_OT_move_up_spring_bone1_joint(Operator):
1128
+ bl_idname = "vrm.move_up_spring_bone1_joint"
1129
+ bl_label = "Move Up Joint"
1130
+ bl_description = "Move Up VRM 1.0 Joint"
1131
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
1132
+
1133
+ armature_object_name: StringProperty( # type: ignore[valid-type]
1134
+ options={"HIDDEN"},
1135
+ )
1136
+
1137
+ spring_index: IntProperty( # type: ignore[valid-type]
1138
+ options={"HIDDEN"},
1139
+ min=0,
1140
+ )
1141
+ joint_index: IntProperty( # type: ignore[valid-type]
1142
+ options={"HIDDEN"},
1143
+ min=0,
1144
+ )
1145
+
1146
+ def execute(self, context: Context) -> set[str]:
1147
+ armature = context.blend_data.objects.get(self.armature_object_name)
1148
+ if armature is None or armature.type != "ARMATURE":
1149
+ return {"CANCELLED"}
1150
+ armature_data = armature.data
1151
+ if not isinstance(armature_data, Armature):
1152
+ return {"CANCELLED"}
1153
+ spring_bone1 = get_armature_extension(armature_data).spring_bone1
1154
+ springs = spring_bone1.springs
1155
+ if len(springs) <= self.spring_index:
1156
+ return {"CANCELLED"}
1157
+ spring = springs[self.spring_index]
1158
+ if len(spring.joints) <= self.joint_index:
1159
+ return {"CANCELLED"}
1160
+ new_joint_index = (self.joint_index - 1) % len(spring.joints)
1161
+ spring.joints.move(self.joint_index, new_joint_index)
1162
+ spring.active_joint_index = new_joint_index
1163
+ return {"FINISHED"}
1164
+
1165
+ if TYPE_CHECKING:
1166
+ # This code is auto generated.
1167
+ # To regenerate, run the `uv run tools/property_typing.py` command.
1168
+ armature_object_name: str # type: ignore[no-redef]
1169
+ spring_index: int # type: ignore[no-redef]
1170
+ joint_index: int # type: ignore[no-redef]
1171
+
1172
+
1173
+ class VRM_OT_move_down_spring_bone1_joint(Operator):
1174
+ bl_idname = "vrm.move_down_spring_bone1_joint"
1175
+ bl_label = "Move Down Joint"
1176
+ bl_description = "Move Down VRM 1.0 Joint"
1177
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
1178
+
1179
+ armature_object_name: StringProperty( # type: ignore[valid-type]
1180
+ options={"HIDDEN"},
1181
+ )
1182
+
1183
+ spring_index: IntProperty( # type: ignore[valid-type]
1184
+ options={"HIDDEN"},
1185
+ min=0,
1186
+ )
1187
+ joint_index: IntProperty( # type: ignore[valid-type]
1188
+ options={"HIDDEN"},
1189
+ min=0,
1190
+ )
1191
+
1192
+ def execute(self, context: Context) -> set[str]:
1193
+ armature = context.blend_data.objects.get(self.armature_object_name)
1194
+ if armature is None or armature.type != "ARMATURE":
1195
+ return {"CANCELLED"}
1196
+ armature_data = armature.data
1197
+ if not isinstance(armature_data, Armature):
1198
+ return {"CANCELLED"}
1199
+ spring_bone1 = get_armature_extension(armature_data).spring_bone1
1200
+ springs = spring_bone1.springs
1201
+ if len(springs) <= self.spring_index:
1202
+ return {"CANCELLED"}
1203
+ spring = springs[self.spring_index]
1204
+ if len(spring.joints) <= self.joint_index:
1205
+ return {"CANCELLED"}
1206
+ new_joint_index = (self.joint_index + 1) % len(spring.joints)
1207
+ spring.joints.move(self.joint_index, new_joint_index)
1208
+ spring.active_joint_index = new_joint_index
1209
+ return {"FINISHED"}
1210
+
1211
+ if TYPE_CHECKING:
1212
+ # This code is auto generated.
1213
+ # To regenerate, run the `uv run tools/property_typing.py` command.
1214
+ armature_object_name: str # type: ignore[no-redef]
1215
+ spring_index: int # type: ignore[no-redef]
1216
+ joint_index: int # type: ignore[no-redef]
1217
+
1218
+
1219
+ class VRM_OT_reset_spring_bone1_animation_state(Operator):
1220
+ bl_idname = "vrm.reset_spring_bone1_animation_state"
1221
+ bl_label = "Reset SpringBone Animation State"
1222
+ bl_description = "Reset SpringBone Animation State"
1223
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
1224
+
1225
+ armature_object_name: StringProperty( # type: ignore[valid-type]
1226
+ options={"HIDDEN"},
1227
+ )
1228
+
1229
+ def execute(self, context: Context) -> set[str]:
1230
+ armature = context.blend_data.objects.get(self.armature_object_name)
1231
+ if armature is None or armature.type != "ARMATURE":
1232
+ return {"CANCELLED"}
1233
+ armature_data = armature.data
1234
+ if not isinstance(armature_data, Armature):
1235
+ return {"CANCELLED"}
1236
+ for spring in get_armature_extension(armature_data).spring_bone1.springs:
1237
+ for joint in spring.joints:
1238
+ joint.animation_state.initialized_as_tail = False
1239
+ reset_state(context)
1240
+ return {"FINISHED"}
1241
+
1242
+ if TYPE_CHECKING:
1243
+ # This code is auto generated.
1244
+ # To regenerate, run the `uv run tools/property_typing.py` command.
1245
+ armature_object_name: str # type: ignore[no-redef]
1246
+
1247
+
1248
+ class VRM_OT_update_spring_bone1_animation(Operator):
1249
+ bl_idname = "vrm.update_spring_bone1_animation"
1250
+ bl_label = "Update SpringBone Animation"
1251
+ bl_description = "Update SpringBone Animation"
1252
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
1253
+
1254
+ delta_time: FloatProperty( # type: ignore[valid-type]
1255
+ options={"HIDDEN"},
1256
+ )
1257
+
1258
+ def execute(self, context: Context) -> set[str]:
1259
+ delta_time = self.delta_time
1260
+ if abs(delta_time) < float_info.epsilon:
1261
+ delta_time = context.scene.render.fps_base / float(context.scene.render.fps)
1262
+ update_pose_bone_rotations(context, delta_time)
1263
+ return {"FINISHED"}
1264
+
1265
+ if TYPE_CHECKING:
1266
+ # This code is auto generated.
1267
+ # To regenerate, run the `uv run tools/property_typing.py` command.
1268
+ delta_time: float # type: ignore[no-redef]
1269
+
1270
+
1271
+ def _assign_spring_bone1_from_vrm0(
1272
+ context: Context,
1273
+ armature_object_name: str,
1274
+ ) -> set[str]:
1275
+ armature = context.blend_data.objects.get(armature_object_name)
1276
+ if armature is None or armature.type != "ARMATURE":
1277
+ return {"CANCELLED"}
1278
+ armature_data = armature.data
1279
+ if not isinstance(armature_data, Armature):
1280
+ return {"CANCELLED"}
1281
+
1282
+ ext = get_armature_extension(armature_data)
1283
+ vrm0_secondary_animation = ext.vrm0.secondary_animation
1284
+ spring_bone1 = ext.spring_bone1
1285
+
1286
+ if (
1287
+ not vrm0_secondary_animation.collider_groups
1288
+ and not vrm0_secondary_animation.bone_groups
1289
+ ):
1290
+ return {"FINISHED"}
1291
+
1292
+ if spring_bone1.colliders or spring_bone1.springs:
1293
+ return {"FINISHED"}
1294
+
1295
+ vrm0_collider_group_uuid_to_collider_group_uuid: dict[str, str] = {}
1296
+ for vrm0_collider_group in vrm0_secondary_animation.collider_groups:
1297
+ if not vrm0_collider_group.uuid:
1298
+ continue
1299
+ collider_group = spring_bone1.add_collider_group()
1300
+ vrm0_collider_group_uuid_to_collider_group_uuid[vrm0_collider_group.uuid] = (
1301
+ collider_group.uuid
1302
+ )
1303
+ collider_group_name = vrm0_collider_group.node.bone_name
1304
+ if collider_group_name:
1305
+ collider_group_name += "-"
1306
+ collider_group_name += vrm0_collider_group.uuid
1307
+ collider_group.vrm_name = collider_group_name
1308
+ for vrm0_collider in vrm0_collider_group.colliders:
1309
+ vrm0_collider_bpy_object = vrm0_collider.bpy_object
1310
+ if not vrm0_collider_bpy_object:
1311
+ continue
1312
+
1313
+ collider = spring_bone1.add_collider(context, armature)
1314
+ collider.node.bone_name = vrm0_collider_group.node.bone_name
1315
+ collider.shape_type = collider.SHAPE_TYPE_SPHERE.identifier
1316
+ collider_bpy_object = collider.bpy_object
1317
+ if collider_bpy_object:
1318
+ collider_bpy_object.name = vrm0_collider_bpy_object.name + ".1"
1319
+ collider_bpy_object.matrix_world = vrm0_collider_bpy_object.matrix_world
1320
+ vrm0_scale = vrm0_collider_bpy_object.scale
1321
+ vrm0_mean_abs_scale = (
1322
+ abs(vrm0_scale[0]) + abs(vrm0_scale[1]) + abs(vrm0_scale[2])
1323
+ ) / 3.0
1324
+ effective_radius = (
1325
+ vrm0_collider_bpy_object.empty_display_size * vrm0_mean_abs_scale
1326
+ )
1327
+ collider.shape.sphere.radius = effective_radius
1328
+
1329
+ collider_group_collider = collider_group.add_collider()
1330
+ collider_group_collider.collider_uuid = collider.uuid
1331
+
1332
+ assigned_bone_names: set[str] = set()
1333
+ for vrm0_bone_group in vrm0_secondary_animation.bone_groups:
1334
+ root_bones: list[Bone] = []
1335
+ for vrm0_bone_group_bone in vrm0_bone_group.bones:
1336
+ bone_name = vrm0_bone_group_bone.bone_name
1337
+ if not bone_name:
1338
+ continue
1339
+ bone = armature_data.bones.get(bone_name)
1340
+ if not bone:
1341
+ continue
1342
+ if bone.name in assigned_bone_names:
1343
+ continue
1344
+ traversing_bone = bone
1345
+ while traversing_bone:
1346
+ if traversing_bone in root_bones:
1347
+ break
1348
+ traversing_bone = traversing_bone.parent
1349
+ if traversing_bone:
1350
+ continue
1351
+
1352
+ children = list(bone.children)
1353
+ while children:
1354
+ child_bone = children.pop()
1355
+ if child_bone in root_bones:
1356
+ root_bones.remove(child_bone)
1357
+ children.extend(child_bone.children)
1358
+
1359
+ root_bones.append(bone)
1360
+
1361
+ bone_chains: list[list[str]] = []
1362
+
1363
+ start_bones = deque[Bone](root_bones)
1364
+ while start_bones:
1365
+ start_bone = start_bones.popleft()
1366
+ bone_chain = [start_bone.name]
1367
+ child_bones = deque[Bone](start_bone.children)
1368
+ while child_bones:
1369
+ first_child_bone = child_bones.popleft()
1370
+ bone_chain.append(first_child_bone.name)
1371
+ start_bones.extend(child_bones)
1372
+ child_bones = deque[Bone](first_child_bone.children)
1373
+ bone_chains.append(bone_chain)
1374
+
1375
+ assigned_bone_names.update(
1376
+ bone_name for bone_chain in bone_chains for bone_name in bone_chain
1377
+ )
1378
+
1379
+ for bone_chain in bone_chains:
1380
+ spring = spring_bone1.add_spring()
1381
+ spring_vrm_name = vrm0_bone_group.comment
1382
+ if not spring_vrm_name:
1383
+ spring_vrm_name = "Spring"
1384
+ spring_vrm_name += "-" + uuid.uuid4().hex
1385
+ spring.vrm_name = spring_vrm_name
1386
+ spring.center.bone_name = vrm0_bone_group.center.bone_name
1387
+
1388
+ for bone_name in bone_chain:
1389
+ joint = spring.add_joint()
1390
+ joint.node.bone_name = bone_name
1391
+ joint.stiffness = vrm0_bone_group.stiffiness
1392
+ joint.gravity_power = vrm0_bone_group.gravity_power
1393
+ joint.gravity_dir = list(vrm0_bone_group.gravity_dir)
1394
+ joint.drag_force = vrm0_bone_group.drag_force
1395
+ joint.hit_radius = vrm0_bone_group.hit_radius
1396
+
1397
+ for vrm0_bone_group_collider_group in vrm0_bone_group.collider_groups:
1398
+ vrm0_collider_group_uuid = (
1399
+ vrm0_bone_group_collider_group.collider_group_uuid
1400
+ )
1401
+ if not vrm0_collider_group_uuid:
1402
+ continue
1403
+ collider_group_uuid = (
1404
+ vrm0_collider_group_uuid_to_collider_group_uuid.get(
1405
+ vrm0_collider_group_uuid
1406
+ )
1407
+ )
1408
+ if not collider_group_uuid:
1409
+ continue
1410
+ spring_collider_group = spring.add_collider_group()
1411
+ spring_collider_group.collider_group_uuid = collider_group_uuid
1412
+ return {"FINISHED"}
1413
+
1414
+
1415
+ class VRM_OT_assign_spring_bone1_from_vrm0(Operator):
1416
+ bl_idname = "vrm.assign_spring_bone1_from_vrm0"
1417
+ bl_label = "Assign VRM 0.0 Spring Bones"
1418
+ bl_description = "Copy VRM 0.0 Spring Bone data to VRM 1.0 Spring Bone"
1419
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
1420
+
1421
+ armature_object_name: StringProperty( # type: ignore[valid-type]
1422
+ options={"HIDDEN"},
1423
+ )
1424
+
1425
+ def execute(self, context: Context) -> set[str]:
1426
+ return _assign_spring_bone1_from_vrm0(context, self.armature_object_name)
1427
+
1428
+ if TYPE_CHECKING:
1429
+ # This code is auto generated.
1430
+ # To regenerate, run the `uv run tools/property_typing.py` command.
1431
+ armature_object_name: str # type: ignore[no-redef]
1432
+
1433
+
1434
+ def _assign_spring_bone1_from_mmd(
1435
+ context: Context,
1436
+ armature_object_name: str,
1437
+ ) -> set[str]:
1438
+ armature = context.blend_data.objects.get(armature_object_name)
1439
+ if armature is None or armature.type != "ARMATURE":
1440
+ return {"CANCELLED"}
1441
+
1442
+ armature_data = armature.data
1443
+ if not isinstance(armature_data, Armature):
1444
+ return {"CANCELLED"}
1445
+
1446
+ ext = get_armature_extension(armature_data)
1447
+ spring_bone1 = ext.spring_bone1
1448
+ if spring_bone1.colliders or spring_bone1.springs:
1449
+ return {"FINISHED"}
1450
+
1451
+ # Collect MMD rigid bodies associated with this armature.
1452
+ # mmd_rigid.type: '0' = kinematic (collider), '1' or '2' = dynamic (springy bone).
1453
+ # https://github.com/MMD-Blender/blender_mmd_tools/blob/v4.5.9/mmd_tools/core/rigid_body.py
1454
+ # https://github.com/MMD-Blender/blender_mmd_tools/blob/v4.5.9/mmd_tools/properties/rigid_body.py
1455
+ static_rigid_bodies: list[tuple[str, Object]] = []
1456
+ dynamic_rigid_bone_names: list[str] = []
1457
+
1458
+ for obj in context.blend_data.objects:
1459
+ mmd_type: object = getattr(obj, "mmd_type", None)
1460
+ if mmd_type != "RIGID_BODY":
1461
+ continue
1462
+
1463
+ mmd_rigid: object = getattr(obj, "mmd_rigid", None)
1464
+ if mmd_rigid is None:
1465
+ continue
1466
+
1467
+ # The bone linkage is stored in a 'mmd_tools_rigid_parent' CHILD_OF constraint.
1468
+ rigid_parent_constraint = obj.constraints.get("mmd_tools_rigid_parent")
1469
+ if not isinstance(rigid_parent_constraint, ChildOfConstraint):
1470
+ continue
1471
+
1472
+ if rigid_parent_constraint.target != armature:
1473
+ continue
1474
+
1475
+ bone_name = rigid_parent_constraint.subtarget
1476
+ if not bone_name:
1477
+ continue
1478
+
1479
+ if bone_name not in armature_data.bones:
1480
+ continue
1481
+
1482
+ rigid_type: object = getattr(mmd_rigid, "type", None)
1483
+ if rigid_type == "0":
1484
+ # MODE_STATIC
1485
+ static_rigid_bodies.append((bone_name, obj))
1486
+ elif rigid_type in {"1", "2"} and bone_name not in dynamic_rigid_bone_names:
1487
+ # MODE_DYNAMIC, MODE_DYNAMIC_BONE
1488
+ dynamic_rigid_bone_names.append(bone_name)
1489
+
1490
+ if not dynamic_rigid_bone_names:
1491
+ return {"FINISHED"}
1492
+
1493
+ # Preserve every kinematic body, including multiple bodies on one bone.
1494
+ static_rigid_bone_to_collider_group_uuid: dict[str, str] = {}
1495
+ for bone_name, mmd_obj in static_rigid_bodies:
1496
+ collider = spring_bone1.add_collider(context, armature)
1497
+ collider.node.bone_name = bone_name
1498
+
1499
+ mmd_rigid = getattr(mmd_obj, "mmd_rigid", None)
1500
+ shape: object = getattr(mmd_rigid, "shape", None)
1501
+ # MMD capsule geometry is centered on local Z. Read local bounds so
1502
+ # object scale is applied exactly once by the body-to-bone transform.
1503
+ bounds = mmd_obj.bound_box
1504
+ dimensions = Vector(
1505
+ tuple(
1506
+ max(v[i] for v in bounds) - min(v[i] for v in bounds) for i in range(3)
1507
+ )
1508
+ )
1509
+ bone_world = armature.matrix_world @ armature.pose.bones[bone_name].matrix
1510
+ body_to_bone = bone_world.inverted_safe() @ mmd_obj.matrix_world
1511
+ # Approximate nonuniform scale with the largest body-to-bone scale.
1512
+ radius_scale = max(abs(value) for value in body_to_bone.to_scale())
1513
+
1514
+ if shape == "CAPSULE":
1515
+ collider.shape_type = collider.SHAPE_TYPE_CAPSULE.identifier
1516
+ radius = max(dimensions.x, dimensions.y) / 2
1517
+ half_height = max(dimensions.z - radius * 2, 0.0) / 2
1518
+ collider.shape.capsule.offset = body_to_bone @ Vector((0, 0, -half_height))
1519
+ collider.shape.capsule.tail = body_to_bone @ Vector((0, 0, half_height))
1520
+ collider.shape.capsule.radius = max(radius * radius_scale, 0.0001)
1521
+ else:
1522
+ collider.shape_type = collider.SHAPE_TYPE_SPHERE.identifier
1523
+ collider.shape.sphere.offset = body_to_bone.translation
1524
+ collider.shape.sphere.radius = max(
1525
+ max(dimensions) * radius_scale / 2, 0.0001
1526
+ )
1527
+
1528
+ # Do not overwrite matrix_world with the source body's center: the
1529
+ # capsule object is its first endpoint, and its child is the second.
1530
+ group_uuid = static_rigid_bone_to_collider_group_uuid.get(bone_name)
1531
+ collider_group = next(
1532
+ (
1533
+ group
1534
+ for group in spring_bone1.collider_groups
1535
+ if group.uuid == group_uuid
1536
+ ),
1537
+ None,
1538
+ )
1539
+ if collider_group is None:
1540
+ collider_group = spring_bone1.add_collider_group()
1541
+ collider_group.vrm_name = bone_name + "-mmd-colliders"
1542
+ static_rigid_bone_to_collider_group_uuid[bone_name] = collider_group.uuid
1543
+ collider_group_collider = collider_group.add_collider()
1544
+ collider_group_collider.collider_uuid = collider.uuid
1545
+
1546
+ # Build bone chains from physics bones.
1547
+ # Root physics bones are those whose direct bone parent is NOT a physics bone.
1548
+ root_physics_bones: list[Bone] = []
1549
+ for bone_name in dynamic_rigid_bone_names:
1550
+ bone = armature_data.bones.get(bone_name)
1551
+ if not bone:
1552
+ continue
1553
+ parent = bone.parent
1554
+ if parent is None or parent.name not in dynamic_rigid_bone_names:
1555
+ root_physics_bones.append(bone)
1556
+
1557
+ assigned_bone_names: set[str] = set()
1558
+ bone_chains: list[list[str]] = []
1559
+
1560
+ start_bones = deque[Bone](root_physics_bones)
1561
+ while start_bones:
1562
+ start_bone = start_bones.popleft()
1563
+ if start_bone.name in assigned_bone_names:
1564
+ continue
1565
+ bone_chain = [start_bone.name]
1566
+ child_bones = deque[Bone](
1567
+ child
1568
+ for child in start_bone.children
1569
+ if child.name in dynamic_rigid_bone_names
1570
+ )
1571
+ while child_bones:
1572
+ first_child_bone = child_bones.popleft()
1573
+ bone_chain.append(first_child_bone.name)
1574
+ start_bones.extend(child_bones)
1575
+ child_bones = deque[Bone](
1576
+ child
1577
+ for child in first_child_bone.children
1578
+ if child.name in dynamic_rigid_bone_names
1579
+ )
1580
+ bone_chains.append(bone_chain)
1581
+ assigned_bone_names.update(bone_chain)
1582
+
1583
+ for bone_chain in bone_chains:
1584
+ if not bone_chain:
1585
+ continue
1586
+ first_bone_name = bone_chain[0]
1587
+
1588
+ spring = spring_bone1.add_spring()
1589
+
1590
+ spring_vrm_name = ""
1591
+ root_pose_bone = armature.pose.bones.get(first_bone_name)
1592
+ if root_pose_bone is not None:
1593
+ mmd_bone: object = getattr(root_pose_bone, "mmd_bone", None)
1594
+ if mmd_bone is not None:
1595
+ name_j = getattr(mmd_bone, "name_j", None)
1596
+ if isinstance(name_j, str) and name_j:
1597
+ spring_vrm_name = name_j
1598
+ if not spring_vrm_name:
1599
+ spring_vrm_name = first_bone_name
1600
+ spring.vrm_name = spring_vrm_name + "-" + uuid.uuid4().hex
1601
+
1602
+ for bone_name in bone_chain:
1603
+ joint = spring.add_joint()
1604
+ joint.node.bone_name = bone_name
1605
+
1606
+ # Associate collider groups whose bone is an ancestor of the root physics bone.
1607
+ root_bone = armature_data.bones.get(first_bone_name)
1608
+ if root_bone:
1609
+ traversing: Optional[Bone] = root_bone.parent
1610
+ while traversing:
1611
+ collider_group_uuid = static_rigid_bone_to_collider_group_uuid.get(
1612
+ traversing.name
1613
+ )
1614
+ if collider_group_uuid:
1615
+ spring_collider_group = spring.add_collider_group()
1616
+ spring_collider_group.collider_group_uuid = collider_group_uuid
1617
+ traversing = traversing.parent
1618
+
1619
+ return {"FINISHED"}
1620
+
1621
+
1622
+ class VRM_OT_assign_spring_bone1_from_mmd(Operator):
1623
+ bl_idname = "vrm.assign_spring_bone1_from_mmd"
1624
+ bl_label = "Assign MMD Spring Bones"
1625
+ bl_description = "Copy MMD spring bone data to VRM 1.0 Spring Bone"
1626
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
1627
+
1628
+ armature_object_name: StringProperty( # type: ignore[valid-type]
1629
+ options={"HIDDEN"},
1630
+ )
1631
+
1632
+ def execute(self, context: Context) -> set[str]:
1633
+ return _assign_spring_bone1_from_mmd(context, self.armature_object_name)
1634
+
1635
+ if TYPE_CHECKING:
1636
+ # This code is auto generated.
1637
+ # To regenerate, run the `uv run tools/property_typing.py` command.
1638
+ armature_object_name: str # type: ignore[no-redef]
1639
+
1640
+
1641
+ def assign_spring_bone1_automatically(
1642
+ context: Context, armature_object_name: str
1643
+ ) -> set[str]:
1644
+ armature = context.blend_data.objects.get(armature_object_name)
1645
+ if armature is None or armature.type != "ARMATURE":
1646
+ return {"CANCELLED"}
1647
+ armature_data = armature.data
1648
+ if not isinstance(armature_data, Armature):
1649
+ return {"CANCELLED"}
1650
+
1651
+ ext = get_armature_extension(armature_data)
1652
+ spring_bone1 = ext.spring_bone1
1653
+
1654
+ if spring_bone1.colliders or spring_bone1.springs:
1655
+ return {"FINISHED"}
1656
+
1657
+ _assign_spring_bone1_from_vrm0(context, armature_object_name)
1658
+ _assign_spring_bone1_from_mmd(context, armature_object_name)
1659
+
1660
+ return {"FINISHED"}
1661
+
1662
+
1663
+ class VRM_OT_assign_spring_bone1_automatically(Operator):
1664
+ bl_idname = "vrm.assign_spring_bone1_automatically"
1665
+ bl_label = "Assign Auto-Detected Spring Bones"
1666
+ bl_description = "Assign Spring Bones automatically"
1667
+ bl_options: ClassVar = {"REGISTER", "UNDO"}
1668
+
1669
+ armature_object_name: StringProperty( # type: ignore[valid-type]
1670
+ options={"HIDDEN"},
1671
+ )
1672
+
1673
+ def execute(self, context: Context) -> set[str]:
1674
+ return assign_spring_bone1_automatically(context, self.armature_object_name)
1675
+
1676
+ if TYPE_CHECKING:
1677
+ # This code is auto generated.
1678
+ # To regenerate, run the `uv run tools/property_typing.py` command.
1679
+ armature_object_name: str # type: ignore[no-redef]