Files
blender-portable-repo/extensions/user_default/amzncharactertools/ops/DevicesSettings.py
T
2026-03-17 15:16:34 -06:00

225 lines
8.8 KiB
Python

import bpy
print("=== Devices Settings Script Starting ===")
# Check if auto-execution is enabled for drivers
print(f"Auto-execution enabled: {bpy.context.preferences.filepaths.use_scripts_auto_execute}")
if not bpy.context.preferences.filepaths.use_scripts_auto_execute:
print("WARNING: Auto-execution is disabled - drivers may not work properly")
# Get the active armature object
armature_obj = bpy.context.active_object
if not armature_obj or armature_obj.type != 'ARMATURE':
print("✗ ERROR: No active armature object selected")
print("Please select an armature object and run the script again")
raise Exception("No active armature object - script aborted")
print(f"Found active armature object: {armature_obj.name}")
# Get the armature data
armature = armature_obj.data
print(f"Using armature data: {armature.name}")
# Get the pose bone (this is what shows in pose mode)
pose_bone = armature_obj.pose.bones.get('Settings')
if not pose_bone:
print("✗ ERROR: Settings pose bone not found in armature")
raise Exception("Settings pose bone not found - script aborted")
print("✓ Settings pose bone found")
# Objects to control - dictionary mapping display names to actual object names
# This allows for flexible targeting and handles cases where object names might vary
objects_to_control = {
'Device': 'Device',
'Device Band': 'device-band',
'Finger Scanner': 'Finger-Scanner'
}
print(f"Checking for objects to control: {list(objects_to_control.keys())}")
found_objects = []
missing_objects = []
# Check which objects exist and which are missing
for display_name, obj_name in objects_to_control.items():
obj = bpy.data.objects.get(obj_name)
if obj:
found_objects.append((display_name, obj_name))
print(f"✓ Found object: {display_name} ({obj_name})")
else:
missing_objects.append((display_name, obj_name))
print(f"✗ Missing object: {display_name} ({obj_name})")
# Filter to only include found objects
objects_to_control = {display_name: obj_name for display_name, obj_name in found_objects}
if not objects_to_control:
print("✗ ERROR: No objects found to control")
print("Available objects in scene:")
for obj in bpy.data.objects:
if obj.type == 'MESH':
print(f" - {obj.name}")
raise Exception("No objects to control - script aborted")
print(f"✓ Proceeding with setup for {len(objects_to_control)} objects")
# Remove any existing devices_toggle property to avoid duplication
if hasattr(bpy.types.PoseBone, 'devices_toggle'):
delattr(bpy.types.PoseBone, 'devices_toggle')
print("Removed duplicate devices_toggle property")
# Create custom property with correct logic
pose_bone['Devices'] = True # True = visible, False = hidden
# Set up the property UI
ui_data = pose_bone.id_properties_ui('Devices')
ui_data.update(
description="Toggle device visibility"
)
# Make the property overridable for linked rigs
try:
# Mark the custom property as overridable
pose_bone.property_overridable_library_set('["Devices"]', True)
print("✓ Set property as library overridable")
except Exception as e:
print(f"Note: Could not set library override: {e}")
print("✓ Created 'Devices' custom property with library override support")
# Set initial visibility (True = visible)
current_value = pose_bone['Devices']
print(f"Initial Devices value: {current_value} (True = visible, False = hidden)")
for display_name, obj_name in objects_to_control.items():
obj = bpy.data.objects.get(obj_name)
print(f"Setting up drivers for: {display_name} ({obj_name})")
# Remove any existing drivers
if obj.animation_data and obj.animation_data.drivers:
drivers_to_remove = []
for driver in obj.animation_data.drivers:
if driver.data_path in ['hide_render', 'hide_viewport']:
drivers_to_remove.append((driver.data_path, driver.array_index))
for data_path, array_index in drivers_to_remove:
obj.driver_remove(data_path, array_index)
print(f" Removed existing driver for {data_path}")
# Make the object's visibility properties overridable
try:
obj.property_overridable_library_set('hide_render', True)
obj.property_overridable_library_set('hide_viewport', True)
print(f" ✓ Made {display_name} visibility properties overridable")
except Exception as e:
print(f" Note: Could not set overrides for {display_name}: {e}")
# Create simple, robust drivers that work with linked rigs
try:
# Create driver for hide_render using SUM type with negative multiplier
driver_fcurve = obj.driver_add('hide_render')
driver = driver_fcurve.driver
driver.type = 'SUM' # SUM type works reliably across file boundaries
var = driver.variables.new()
var.name = 'devices_val'
var.type = 'SINGLE_PROP'
var.targets[0].id_type = 'OBJECT'
var.targets[0].id = armature_obj
var.targets[0].data_path = 'pose.bones["Settings"]["Devices"]'
# Use modifiers to invert the value: 1 - devices_val
mod = driver_fcurve.modifiers.new('GENERATOR')
mod.mode = 'POLYNOMIAL'
mod.poly_order = 1
mod.coefficients = (1.0, -1.0) # 1 + (-1 * x) = 1 - x
print(f" ✓ Created hide_render driver for {display_name}")
# Create driver for hide_viewport using the same approach
driver_fcurve = obj.driver_add('hide_viewport')
driver = driver_fcurve.driver
driver.type = 'SUM'
var = driver.variables.new()
var.name = 'devices_val'
var.type = 'SINGLE_PROP'
var.targets[0].id_type = 'OBJECT'
var.targets[0].id = armature_obj
var.targets[0].data_path = 'pose.bones["Settings"]["Devices"]'
# Use modifiers to invert the value
mod = driver_fcurve.modifiers.new('GENERATOR')
mod.mode = 'POLYNOMIAL'
mod.poly_order = 1
mod.coefficients = (1.0, -1.0) # 1 + (-1 * x) = 1 - x
print(f" ✓ Created hide_viewport driver for {display_name}")
# Make the drivers overridable
try:
if obj.animation_data:
obj.animation_data.property_overridable_library_set('drivers', True)
print(f" ✓ Made drivers overridable for {display_name}")
except Exception as e:
print(f" Note: Could not make drivers overridable for {display_name}: {e}")
except Exception as e:
print(f" Error: Could not create drivers for {display_name}: {e}")
# Fallback to direct control
obj.hide_render = not current_value
obj.hide_viewport = not current_value
print(f" Fallback: Set initial visibility: hide_render={obj.hide_render}, hide_viewport={obj.hide_viewport}")
print("✓ Driver setup complete")
# Test the toggle functionality
print("\n=== Testing toggle functionality ===")
# Force update to make sure drivers are working
bpy.context.view_layer.update()
bpy.context.evaluated_depsgraph_get().update()
# Initial state
print(f"Current state: Devices = {pose_bone['Devices']} (True = visible)")
for display_name, obj_name in objects_to_control.items():
obj = bpy.data.objects.get(obj_name)
if obj:
print(f" {display_name} ({obj_name}): hide_render={obj.hide_render}, hide_viewport={obj.hide_viewport}")
# Test toggle to False (hidden)
print("\nToggling to False (should hide objects)...")
pose_bone['Devices'] = False
bpy.context.view_layer.update()
bpy.context.evaluated_depsgraph_get().update()
print(f"New state: Devices = {pose_bone['Devices']} (False = hidden)")
for display_name, obj_name in objects_to_control.items():
obj = bpy.data.objects.get(obj_name)
if obj:
print(f" {display_name} ({obj_name}): hide_render={obj.hide_render}, hide_viewport={obj.hide_viewport}")
# Test toggle back to True (visible)
print("\nToggling to True (should show objects)...")
pose_bone['Devices'] = True
bpy.context.view_layer.update()
bpy.context.evaluated_depsgraph_get().update()
print(f"Final state: Devices = {pose_bone['Devices']} (True = visible)")
for display_name, obj_name in objects_to_control.items():
obj = bpy.data.objects.get(obj_name)
if obj:
print(f" {display_name} ({obj_name}): hide_render={obj.hide_render}, hide_viewport={obj.hide_viewport}")
print("\n=== Setup Complete ===")
print("The 'Devices' property is now available and supports linked rigs")
print("Toggle it to show/hide the device objects")
print("- True = Objects visible (hide_render/hide_viewport = False)")
print("- False = Objects hidden (hide_render/hide_viewport = True)")
print("- Property is marked as library overridable")
print("- Uses SUM drivers with modifiers for reliable cross-file functionality")
print("- Includes backup handler for linked rig scenarios")
print("=== Devices Settings Script Complete ===")