refactor: overhaul armature validation system to be opt-in by default
- Change default validation mode from STRICT to NONE (disabled) - Move validation from automatic panel draw to explicit "Validate Now" button - Hide validation results when mode is changed to NONE - Fix PMX/MMD model detection to check mmd_type value, not just attribute existence - Add new validation result collapsible sections - Improve UI presentation with better visual hierarchy - Add translation strings for new validation UI elements
This commit is contained in:
@@ -63,6 +63,6 @@ def get_addon_preferences(context):
|
||||
# Initialize preferences if the file doesn't exist
|
||||
if not os.path.exists(PREFERENCES_FILE):
|
||||
save_preference("language", 0) # Set default language to 0 (auto)
|
||||
save_preference("validation_mode", "STRICT") # Set default validation mode
|
||||
save_preference("validation_mode", "NONE") # Set default validation mode to NONE (off by default)
|
||||
save_preference("enable_logging", False) # Set default logging mode
|
||||
save_preference("highlight_problem_bones", True) # Set default bone highlighting
|
||||
|
||||
@@ -15,6 +15,26 @@ from ..core.dictionaries import (
|
||||
)
|
||||
from ..core.logging_setup import logger
|
||||
|
||||
def is_pmx_model(armature: Object) -> bool:
|
||||
"""
|
||||
Check if the armature is a PMX/MMD model.
|
||||
PMX models have an mmd_type attribute set to 'ROOT' on the root object.
|
||||
"""
|
||||
if not armature:
|
||||
return False
|
||||
|
||||
# Check if armature itself has mmd_type set to ROOT
|
||||
if hasattr(armature, 'mmd_type') and armature.mmd_type == 'ROOT':
|
||||
return True
|
||||
|
||||
# Check if parent has mmd_type set to ROOT (parent container model)
|
||||
if hasattr(armature, 'parent') and armature.parent:
|
||||
parent = armature.parent
|
||||
if hasattr(parent, 'mmd_type') and parent.mmd_type == 'ROOT':
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def validate_armature(armature: Object, detailed_messages: bool = False, override_mode: Optional[str] = None) -> Union[Tuple[bool, List[str], bool], Tuple[bool, List[str], bool, List[str], List[str], List[str]]]:
|
||||
"""
|
||||
Validates armature and returns validation results
|
||||
@@ -27,9 +47,8 @@ def validate_armature(armature: Object, detailed_messages: bool = False, overrid
|
||||
scale_messages: List[str] = []
|
||||
|
||||
# Check if this is a PMX model
|
||||
is_pmx_model = False
|
||||
if armature and hasattr(armature, 'mmd_type') or (hasattr(armature, 'parent') and armature.parent and hasattr(armature.parent, 'mmd_type')):
|
||||
is_pmx_model = True
|
||||
pmx_model = is_pmx_model(armature)
|
||||
if pmx_model:
|
||||
logger.debug("Detected PMX model, using specialized validation")
|
||||
|
||||
if validation_mode == 'NONE':
|
||||
@@ -157,7 +176,7 @@ def validate_armature(armature: Object, detailed_messages: bool = False, overrid
|
||||
non_standard_messages.append(t("Armature.validation.standardize_note.line3"))
|
||||
|
||||
# Special handling for PMX models
|
||||
if is_pmx_model:
|
||||
if pmx_model:
|
||||
logger.info("PMX model detected, applying specialized validation")
|
||||
# For PMX models, we'll be more lenient with validation
|
||||
# and provide specific guidance for these models
|
||||
@@ -783,3 +802,44 @@ class AvatarToolkit_OT_ClearBoneHighlighting(Operator):
|
||||
logger.info("Bone highlighting cleared")
|
||||
self.report({'INFO'}, t("Validation.highlighting_cleared"))
|
||||
return {'FINISHED'}
|
||||
|
||||
class AvatarToolkit_OT_ValidateArmatureManual(Operator):
|
||||
"""Manually validate armature and show results"""
|
||||
bl_idname = "avatar_toolkit.validate_armature_manual"
|
||||
bl_label = t("Validation.validate_now", "Validate Armature Now")
|
||||
bl_description = t("Validation.validate_now_desc", "Run armature validation and display detailed results")
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return get_active_armature(context) is not None
|
||||
|
||||
def execute(self, context):
|
||||
armature = get_active_armature(context)
|
||||
if not armature:
|
||||
logger.warning("No active armature found for validation")
|
||||
self.report({'ERROR'}, t("Validation.no_armature"))
|
||||
return {'CANCELLED'}
|
||||
|
||||
logger.info(f"Running manual validation for armature: {armature.name}")
|
||||
|
||||
# Clear the validation cache to force a refresh
|
||||
from ..ui.quick_access_panel import clear_armature_caches
|
||||
clear_armature_caches()
|
||||
|
||||
# Toggle the show_validation_results flag to display results
|
||||
props = context.scene.avatar_toolkit
|
||||
props.show_validation_results = True
|
||||
|
||||
# Run validation
|
||||
is_valid, messages, is_acceptable = validate_armature(armature, detailed_messages=False)
|
||||
|
||||
if is_valid:
|
||||
if is_acceptable:
|
||||
self.report({'INFO'}, t("Armature.validation.acceptable_standard.success"))
|
||||
else:
|
||||
self.report({'INFO'}, t("QuickAccess.valid_armature"))
|
||||
else:
|
||||
self.report({'WARNING'}, t("Validation.status.failed"))
|
||||
|
||||
logger.info("Manual validation complete")
|
||||
return {'FINISHED'}
|
||||
|
||||
+12
-1
@@ -34,6 +34,11 @@ def update_validation_mode(self: PropertyGroup, context: Context) -> None:
|
||||
"""Updates validation mode and saves preference"""
|
||||
logger.info(f"Updating validation mode to: {self.validation_mode}")
|
||||
save_preference("validation_mode", self.validation_mode)
|
||||
|
||||
# Hide validation results if mode is set to NONE
|
||||
if self.validation_mode == 'NONE':
|
||||
self.show_validation_results = False
|
||||
logger.debug("Validation mode set to NONE, hiding validation results")
|
||||
|
||||
|
||||
def update_logging_state(self: PropertyGroup, context: Context) -> None:
|
||||
@@ -153,6 +158,12 @@ class AvatarToolkitSceneProperties(PropertyGroup):
|
||||
default=False
|
||||
)
|
||||
|
||||
show_validation_results: BoolProperty(
|
||||
name="Show Validation Results",
|
||||
default=False,
|
||||
description="Show the validation results section"
|
||||
)
|
||||
|
||||
material_search_filter: StringProperty(
|
||||
name=t("TextureAtlas.search_materials"),
|
||||
description=t("TextureAtlas.search_materials_desc"),
|
||||
@@ -283,7 +294,7 @@ class AvatarToolkitSceneProperties(PropertyGroup):
|
||||
('BASIC', t("Settings.validation_mode.basic"), t("Settings.validation_mode.basic_desc")),
|
||||
('NONE', t("Settings.validation_mode.none"), t("Settings.validation_mode.none_desc"))
|
||||
],
|
||||
default=get_preference("validation_mode", "STRICT"),
|
||||
default=get_preference("validation_mode", "NONE"),
|
||||
update=update_validation_mode
|
||||
)
|
||||
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ GITHUB_REPO = "teamneoneko/Avatar-Toolkit"
|
||||
# Define which version series this installation can update to
|
||||
# For example: ["0.1"] means only look for 0.1.x updates
|
||||
# ["0.2", "0.3"] would look for both 0.2.x and 0.3.x
|
||||
ALLOWED_ = ["0.5"]
|
||||
ALLOWED_ = ["0.6"]
|
||||
|
||||
is_checking_for_update: bool = False
|
||||
update_needed: bool = False
|
||||
|
||||
Reference in New Issue
Block a user