Updated Operations and Properties

- Updated Operations and Properties with tpying and logging.

I have not updated translation files, this is because i want to gut MMD Tools system and replace it with our own, however I want to make MMD Tools more simple and ajust it to our needs only. This is going to take a while and my aim for this is Alpha 4, also the MMD Translation system hurt my head....

- Fixes a couple of bugs as well, with quick access and the PMX importer.
This commit is contained in:
Yusarina
2025-04-23 00:43:38 +01:00
parent 61e4269764
commit cfe760e8df
21 changed files with 689 additions and 347 deletions
+38 -24
View File
@@ -6,7 +6,7 @@
# MMD Tools is licensed under the terms of the GNU General Public License version 3 (GPLv3) same as Avatar Toolkit.
import math
from typing import Dict, Optional, Tuple, cast
from typing import Dict, Optional, Tuple, cast, Set, List, Any, Union, Generator
import bpy
from mathutils import Euler, Vector
@@ -16,6 +16,7 @@ from ..bpyutils import FnContext, Props
from ..core import rigid_body
from ..core.model import FnModel, Model
from ..core.rigid_body import FnRigidBody
from ...logging_setup import logger
class SelectRigidBody(bpy.types.Operator):
@@ -43,15 +44,15 @@ class SelectRigidBody(bpy.types.Operator):
default=False,
)
def invoke(self, context, event):
def invoke(self, context: bpy.types.Context, event: Any) -> Set[str]:
vm = context.window_manager
return vm.invoke_props_dialog(self)
@classmethod
def poll(cls, context):
def poll(cls, context: bpy.types.Context) -> bool:
return FnModel.is_rigid_body_object(context.active_object)
def execute(self, context):
def execute(self, context: bpy.types.Context) -> Set[str]:
obj = context.active_object
root = FnModel.find_root_object(obj)
if root is None:
@@ -173,7 +174,7 @@ class AddRigidBody(bpy.types.Operator):
default=0.1,
)
def __add_rigid_body(self, context: bpy.types.Context, root_object: bpy.types.Object, pose_bone: Optional[bpy.types.PoseBone] = None):
def __add_rigid_body(self, context: bpy.types.Context, root_object: bpy.types.Object, pose_bone: Optional[bpy.types.PoseBone] = None) -> bpy.types.Object:
name_j: str = self.name_j
name_e: str = self.name_e
size = self.size.copy()
@@ -226,7 +227,7 @@ class AddRigidBody(bpy.types.Operator):
)
@classmethod
def poll(cls, context):
def poll(cls, context: bpy.types.Context) -> bool:
root_object = FnModel.find_root_object(context.active_object)
if root_object is None:
return False
@@ -237,7 +238,7 @@ class AddRigidBody(bpy.types.Operator):
return True
def execute(self, context):
def execute(self, context: bpy.types.Context) -> Set[str]:
active_object = context.active_object
root_object = cast(bpy.types.Object, FnModel.find_root_object(active_object))
@@ -254,15 +255,17 @@ class AddRigidBody(bpy.types.Operator):
armature_object.select_set(False)
if len(selected_pose_bones) > 0:
logger.info(f"Adding rigid bodies to {len(selected_pose_bones)} selected bones")
for pose_bone in selected_pose_bones:
rigid = self.__add_rigid_body(context, root_object, pose_bone)
rigid.select_set(True)
else:
logger.info("Adding a single rigid body without bone attachment")
rigid = self.__add_rigid_body(context, root_object)
rigid.select_set(True)
return {"FINISHED"}
def invoke(self, context, event):
def invoke(self, context: bpy.types.Context, event: Any) -> Set[str]:
no_bone = True
if context.selected_bones and len(context.selected_bones) > 0:
no_bone = False
@@ -288,12 +291,13 @@ class RemoveRigidBody(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
def poll(cls, context: bpy.types.Context) -> bool:
return FnModel.is_rigid_body_object(context.active_object)
def execute(self, context):
def execute(self, context: bpy.types.Context) -> Set[str]:
obj = context.active_object
root = FnModel.find_root_object(obj)
logger.info(f"Removing rigid body: {obj.name}")
utils.selectAObject(obj) # ensure this is the only one object select
bpy.ops.object.delete(use_global=True)
if root:
@@ -306,7 +310,8 @@ class RigidBodyBake(bpy.types.Operator):
bl_label = "Bake"
bl_options = {"REGISTER", "UNDO", "INTERNAL"}
def execute(self, context: bpy.types.Context):
def execute(self, context: bpy.types.Context) -> Set[str]:
logger.info("Baking rigid body simulation")
with context.temp_override(scene=context.scene, point_cache=context.scene.rigidbody_world.point_cache):
bpy.ops.ptcache.bake("INVOKE_DEFAULT", bake=True)
@@ -318,7 +323,8 @@ class RigidBodyDeleteBake(bpy.types.Operator):
bl_label = "Delete Bake"
bl_options = {"REGISTER", "UNDO", "INTERNAL"}
def execute(self, context: bpy.types.Context):
def execute(self, context: bpy.types.Context) -> Set[str]:
logger.info("Deleting rigid body simulation bake")
with context.temp_override(scene=context.scene, point_cache=context.scene.rigidbody_world.point_cache):
bpy.ops.ptcache.free_bake("INVOKE_DEFAULT")
@@ -381,7 +387,7 @@ class AddJoint(bpy.types.Operator):
min=0,
)
def __enumerate_rigid_pair(self, bone_map: Dict[bpy.types.Object, Optional[bpy.types.Bone]]):
def __enumerate_rigid_pair(self, bone_map: Dict[bpy.types.Object, Optional[bpy.types.Bone]]) -> Generator[Tuple[bpy.types.Object, bpy.types.Object], None, None]:
obj_seq = tuple(bone_map.keys())
for rigid_a, bone_a in bone_map.items():
for rigid_b, bone_b in bone_map.items():
@@ -394,7 +400,7 @@ class AddJoint(bpy.types.Operator):
else:
yield obj_seq
def __add_joint(self, context: bpy.types.Context, root_object: bpy.types.Object, rigid_pair: Tuple[bpy.types.Object, bpy.types.Object], bone_map):
def __add_joint(self, context: bpy.types.Context, root_object: bpy.types.Object, rigid_pair: Tuple[bpy.types.Object, bpy.types.Object], bone_map: Dict[bpy.types.Object, Optional[bpy.types.Bone]]) -> bpy.types.Object:
loc: Optional[Vector] = None
rot = Euler((0.0, 0.0, 0.0))
rigid_a, rigid_b = rigid_pair
@@ -432,7 +438,7 @@ class AddJoint(bpy.types.Operator):
)
@classmethod
def poll(cls, context):
def poll(cls, context: bpy.types.Context) -> bool:
root_object = FnModel.find_root_object(context.active_object)
if root_object is None:
return False
@@ -443,7 +449,7 @@ class AddJoint(bpy.types.Operator):
return True
def execute(self, context):
def execute(self, context: bpy.types.Context) -> Set[str]:
active_object = context.active_object
root_object = cast(bpy.types.Object, FnModel.find_root_object(active_object))
armature_object = cast(bpy.types.Object, FnModel.find_armature_object(root_object))
@@ -456,15 +462,19 @@ class AddJoint(bpy.types.Operator):
FnContext.select_single_object(context, root_object).select_set(False)
if context.scene.rigidbody_world is None:
logger.info("Creating rigid body world")
bpy.ops.rigidbody.world_add()
joint_count = 0
for pair in self.__enumerate_rigid_pair(bone_map):
joint = self.__add_joint(context, root_object, pair, bone_map)
joint.select_set(True)
joint_count += 1
logger.info(f"Added {joint_count} joints between rigid bodies")
return {"FINISHED"}
def invoke(self, context, event):
def invoke(self, context: bpy.types.Context, event: Any) -> Set[str]:
vm = context.window_manager
return vm.invoke_props_dialog(self)
@@ -476,12 +486,13 @@ class RemoveJoint(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
def poll(cls, context: bpy.types.Context) -> bool:
return FnModel.is_joint_object(context.active_object)
def execute(self, context):
def execute(self, context: bpy.types.Context) -> Set[str]:
obj = context.active_object
root = FnModel.find_root_object(obj)
logger.info(f"Removing joint: {obj.name}")
utils.selectAObject(obj) # ensure this is the only one object select
bpy.ops.object.delete(use_global=True)
if root:
@@ -496,7 +507,7 @@ class UpdateRigidBodyWorld(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
@staticmethod
def __get_rigid_body_world_objects():
def __get_rigid_body_world_objects() -> Tuple[bpy.types.Collection, bpy.types.Collection]:
rigid_body.setRigidBodyWorldEnabled(True)
rbw = bpy.context.scene.rigidbody_world
if not rbw.collection:
@@ -511,12 +522,12 @@ class UpdateRigidBodyWorld(bpy.types.Operator):
return rbw.collection.objects, rbw.constraints.objects
def execute(self, context):
def execute(self, context: bpy.types.Context) -> Set[str]:
scene = context.scene
scene_objs = set(scene.objects)
scene_objs.union(o for x in scene.objects if x.instance_type == "COLLECTION" and x.instance_collection for o in x.instance_collection.objects)
def _update_group(obj, group):
def _update_group(obj: bpy.types.Object, group: bpy.types.Collection) -> bool:
if obj in scene_objs:
if obj not in group.values():
group.link(obj)
@@ -525,7 +536,7 @@ class UpdateRigidBodyWorld(bpy.types.Operator):
group.unlink(obj)
return False
def _references(obj):
def _references(obj: bpy.types.Object) -> Generator[bpy.types.Object, None, None]:
yield obj
if getattr(obj, "proxy", None):
yield from _references(obj.proxy)
@@ -542,6 +553,7 @@ class UpdateRigidBodyWorld(bpy.types.Operator):
# Object.rigid_body are removed,
# but Object.rigid_body_constraint are retained.
# Therefore, it must be checked with Object.mmd_type.
logger.info("Updating rigid body world objects")
for i in (x for x in objects if x.mmd_type == "RIGID_BODY"):
if not _update_group(i, rb_objs):
continue
@@ -556,6 +568,7 @@ class UpdateRigidBodyWorld(bpy.types.Operator):
# TODO Modify mmd_rigid to allow recovery of the remaining rigidbody parameters.
# mass, friction, restitution, linear_dumping, angular_dumping
logger.info("Updating rigid body constraints")
for i in (x for x in objects if x.rigid_body_constraint):
if not _update_group(i, rbc_objs):
continue
@@ -566,6 +579,7 @@ class UpdateRigidBodyWorld(bpy.types.Operator):
rbc.object2 = rb_map.get(rbc.object2, rbc.object2)
if need_rebuild_physics:
logger.info("Rebuilding physics for models")
for root_object in scene.objects:
if root_object.mmd_type != "ROOT":
continue