2026-02-16

This commit is contained in:
2026-03-17 15:25:32 -06:00
parent d5dd373de0
commit 60100fbab2
560 changed files with 33397 additions and 20776 deletions
@@ -0,0 +1,18 @@
"""
Utility modules for Remove Static FCurves extension
"""
# Handle module reloading
if "bpy" in locals():
import importlib
if "compat" in locals():
importlib.reload(compat)
if "version" in locals():
importlib.reload(version)
else:
from . import compat
from . import version
import bpy
__all__ = ["compat", "version"]
@@ -0,0 +1,144 @@
"""
API compatibility functions for handling differences between Blender versions.
"""
import bpy
from bpy_extras import anim_utils
from . import version
def get_action_fcurves(action):
"""
Get the fcurves collection from an action, handling version differences.
In Blender 4.x: action.fcurves
In Blender 5.0+: Uses channelbag.fcurves via action slots
Args:
action: The action object
Returns:
Collection of fcurves, or None if not available
"""
if version.is_version_at_least(5, 0, 0):
# Blender 5.0+ uses channelbags and slots
# Try to get fcurves from all slots in the action
all_fcurves = []
# Iterate through all slots in the action
if hasattr(action, 'slots') and action.slots:
for slot in action.slots:
try:
channelbag = anim_utils.action_get_channelbag_for_slot(
action, slot)
if channelbag and hasattr(channelbag, 'fcurves'):
all_fcurves.extend(channelbag.fcurves)
except (AttributeError, RuntimeError):
continue
return all_fcurves if all_fcurves else None
else:
# Blender 4.x uses direct fcurves attribute
if hasattr(action, 'fcurves'):
return action.fcurves
return None
def get_fcurves_from_object(obj):
"""
Get FCurves from an object's animation data, handling version differences.
Args:
obj: The object with animation data
Returns:
List of (action, fcurve, slot) tuples, or empty list
"""
if not obj.animation_data or not obj.animation_data.action:
return []
action = obj.animation_data.action
fcurves_list = []
if version.is_version_at_least(5, 0, 0):
# Blender 5.0+: Get the channelbag for the object's current action slot
if hasattr(obj.animation_data, 'action_slot') and obj.animation_data.action_slot:
try:
channelbag = anim_utils.action_get_channelbag_for_slot(
action,
obj.animation_data.action_slot
)
if channelbag and hasattr(channelbag, 'fcurves'):
for fcurve in channelbag.fcurves:
fcurves_list.append(
(action, fcurve, obj.animation_data.action_slot))
except (AttributeError, RuntimeError) as e:
print(f"Error getting channelbag for {obj.name}: {e}")
else:
# Fallback: try all slots if no specific slot is set
if hasattr(action, 'slots') and action.slots:
for slot in action.slots:
try:
channelbag = anim_utils.action_get_channelbag_for_slot(
action, slot)
if channelbag and hasattr(channelbag, 'fcurves'):
for fcurve in channelbag.fcurves:
fcurves_list.append((action, fcurve, slot))
except (AttributeError, RuntimeError):
continue
else:
# Blender 4.x: Direct access to fcurves
if hasattr(action, 'fcurves'):
for fcurve in action.fcurves:
fcurves_list.append((action, fcurve, None))
return fcurves_list
def remove_action_fcurve(action, fcurve, slot=None):
"""
Remove an fcurve from an action, handling version differences.
Args:
action: The action object
fcurve: The fcurve to remove
slot: (Blender 5.0+) The action slot containing the fcurve
Returns:
bool: True if removal succeeded, False otherwise
"""
if version.is_version_at_least(5, 0, 0):
# Blender 5.0+: Need to remove from the channelbag
if slot is None:
# Try to find which slot contains this fcurve
if hasattr(action, 'slots'):
for try_slot in action.slots:
try:
channelbag = anim_utils.action_get_channelbag_for_slot(
action, try_slot)
if channelbag and hasattr(channelbag, 'fcurves'):
if fcurve in channelbag.fcurves:
channelbag.fcurves.remove(fcurve)
return True
except (ValueError, AttributeError, RuntimeError):
continue
else:
# We know which slot to use
try:
channelbag = anim_utils.action_get_channelbag_for_slot(
action, slot)
if channelbag and hasattr(channelbag, 'fcurves'):
channelbag.fcurves.remove(fcurve)
return True
except (ValueError, AttributeError, RuntimeError) as e:
print(f"Error removing fcurve: {e}")
else:
# Blender 4.x: Direct removal
if hasattr(action, 'fcurves'):
try:
action.fcurves.remove(fcurve)
return True
except (ValueError, AttributeError):
pass
return False
@@ -0,0 +1,70 @@
"""
Version detection and comparison utilities for multi-version Blender support.
"""
import bpy
def get_blender_version():
"""
Returns the current Blender version as a tuple (major, minor, patch).
Returns:
tuple: (major, minor, patch) version numbers
"""
return bpy.app.version
def get_version_string():
"""
Returns the current Blender version as a string (e.g., "4.2.0").
Returns:
str: Version string in format "major.minor.patch"
"""
version = get_blender_version()
return f"{version[0]}.{version[1]}.{version[2]}"
def is_version_at_least(major, minor=0, patch=0):
"""
Check if the current Blender version is at least the specified version.
Args:
major (int): Major version number
minor (int): Minor version number (default: 0)
patch (int): Patch version number (default: 0)
Returns:
bool: True if current version >= specified version
"""
current = get_blender_version()
target = (major, minor, patch)
if current[0] != target[0]:
return current[0] > target[0]
if current[1] != target[1]:
return current[1] > target[1]
return current[2] >= target[2]
def is_version_less_than(major, minor=0, patch=0):
"""
Check if the current Blender version is less than the specified version.
Args:
major (int): Major version number
minor (int): Minor version number (default: 0)
patch (int): Patch version number (default: 0)
Returns:
bool: True if current version < specified version
"""
return not is_version_at_least(major, minor, patch)
def is_version_5_0():
"""Check if running Blender 5.0 or later."""
return is_version_at_least(5, 0, 0)