fix action slot not applying to shapekey
This commit is contained in:
@@ -15132,7 +15132,161 @@ I see. Currently `run_retarg_relatives` builds candidates as:
|
||||
3. objects that have a constraint targeting orig
|
||||
|
||||
So it's retargeting both (a) objects in rep's hierarchy and (b) objects that point to orig (parent or constraint). The user says: objects that are within OrigChar's hierarchy (starting from linked collection) should NOT have their relations retargeted. So we should exclude from candidates any object that is in the original character's hierarchy. So:
|
||||
- candidates = rep_descendants only? No - we also add objects whose parent is orig and objects with constraint targeting orig. So we might be retargeting an object that is parented to orig - that object could be in the "original" linked </details></think>
|
||||
- candidates = rep_descendants only? No - we also add objects whose parent is orig and objects with constraint targeting orig. So we might be retargeting an object that is parented to orig - that object could be in the "original" linked collection (a child of orig). So when we retarget ob.parent = rep for such an object, we're moving it from orig to rep. The user says objects in OrigChar's hierarchy should NOT be retargeted. So we should NOT change parent/constraint/modifier for any object that is a descendant of orig (or in orig's linked collection). So the fix: only retarget relations for objects that are NOT in orig's hierarchy. So we need to compute orig_descendants (or "orig hierarchy") and exclude those from candidates. So candidates = (rep_descendants | objects with parent orig | objects with constraint target orig) MINUS orig_descendants. Actually wait - if an object's parent is orig, it IS in orig's hierarchy. So we're currently retargeting it to rep (making it a child of rep). The user says don't retarget objects in OrigChar's hierarchy. So we should exclude objects that are in orig's hierarchy. So: orig_descendants = descendants(orig) or something that includes orig itself and everything under it. Then candidates = current_candidates - orig_descendants. So we only retarget objects that are outside orig's hierarchy. That way, objects that are children of orig (in the linked collection) stay as-is (parent stays orig, constraints stay targeting orig). And objects that are in rep's hierarchy (rep_descendants) get retargeted - but wait, rep_descendants are already descendants of rep, so they're not descendants of orig. So rep_descendants ∩ orig_descendants would be empty typically. The case we're excluding is: objects that have parent==orig or constraint target==orig but are themselves in orig's hierarchy. So e.g. a mesh that is parented to orig - that mesh is in orig's hierarchy. Currently we add it to candidates and set ob.parent = rep. The user says don't do that - leave it parented to orig. So we need to add orig and all its descendants to an "exclude" set, and only retarget objects that are not in that set. So: exclude = {orig} | set(descendants(orig)) # or descendants already returns a set? Let me check. candidates = (rep_descendants | objects with parent orig | objects with constraint target orig) - exclude So we only retarget objects that (1) are in the candidate set and (2) are not in orig's hierarchy. Let me read the descendants function.
|
||||
</details></think>
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
<tool-use data-tool-type="unknown" data-tool-name="ripgrep_raw_search">
|
||||
<details>
|
||||
<summary>Tool use: **ripgrep_raw_search**</summary>
|
||||
|
||||
|
||||
Parameters:
|
||||
|
||||
```json
|
||||
{
|
||||
"pattern": "^def descendants",
|
||||
"path": "T:\\Dynamic-Link-Manager",
|
||||
"contextAfter": 15,
|
||||
"caseInsensitive": false
|
||||
}
|
||||
```
|
||||
Additional data:
|
||||
|
||||
```json
|
||||
{
|
||||
"isPruned": true,
|
||||
"pattern": "^def descendants",
|
||||
"path": "T:\\Dynamic-Link-Manager",
|
||||
"outputMode": "content",
|
||||
"totalFiles": 1,
|
||||
"totalMatches": 1,
|
||||
"topFiles": [
|
||||
{
|
||||
"uri": "utils/__init__.py",
|
||||
"matchCount": 16
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
Status: **completed**
|
||||
|
||||
|
||||
</details>
|
||||
</tool-use>
|
||||
|
||||
---
|
||||
|
||||
<tool-use data-tool-type="read" data-tool-name="read_file_v2">
|
||||
<details><summary>Tool use: **read_file_v2** • Read file: T:\Dynamic-Link-Manager\ops\migrator.py</summary>
|
||||
|
||||
</details>
|
||||
</tool-use>
|
||||
|
||||
---
|
||||
|
||||
<think><details><summary>Thought Process</summary>
|
||||
|
||||
So descendants(orig) gives all objects whose parent chain leads to orig. That's "orig's hierarchy". The user wants: do NOT retarget relations for objects that are in orig's hierarchy. So we should exclude orig and its descendants from the set of objects we modify. So:
|
||||
|
||||
orig_hierarchy = {orig} | descendants(orig)
|
||||
candidates = (rep_descendants | objects with parent orig | objects with constraint target orig) - orig_hierarchy
|
||||
|
||||
Then only iterate over candidates for the actual retargeting. That way any object that is under orig (linked collection) is left alone.
|
||||
</details></think>
|
||||
|
||||
---
|
||||
|
||||
|
||||
Excluding objects in the original character's hierarchy from retargeting. Applying the change.
|
||||
|
||||
|
||||
---
|
||||
|
||||
<tool-use data-tool-type="write" data-tool-name="edit_file_v2">
|
||||
|
||||
<details><summary>Tool use: **edit_file_v2** • Edit file: T:\Dynamic-Link-Manager\ops\migrator.py</summary>
|
||||
|
||||
</details>
|
||||
|
||||
</tool-use>
|
||||
|
||||
---
|
||||
|
||||
<think><details><summary>Thought Process</summary>
|
||||
|
||||
Good. So now any object that is orig itself or a descendant of orig (parent chain leads to orig) will not be retargeted. Only objects that are in the candidate set and outside orig's hierarchy get their parent/constraint/modifier updated to point to rep.
|
||||
</details></think>
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
<tool-use data-tool-type="unknown" data-tool-name="read_lints">
|
||||
<details>
|
||||
<summary>Tool use: **read_lints**</summary>
|
||||
|
||||
|
||||
Parameters:
|
||||
|
||||
```json
|
||||
{
|
||||
"paths": [
|
||||
"T:\\Dynamic-Link-Manager\\ops\\migrator.py"
|
||||
]
|
||||
}
|
||||
```
|
||||
Result:
|
||||
|
||||
```json
|
||||
{
|
||||
"linterErrorsByFile": [
|
||||
{
|
||||
"relativeWorkspacePath": "T:\\Dynamic-Link-Manager\\ops\\migrator.py"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
Status: **completed**
|
||||
|
||||
|
||||
</details>
|
||||
</tool-use>
|
||||
|
||||
---
|
||||
|
||||
<think><details><summary>Thought Process</summary>
|
||||
|
||||
Done. Summary for user.
|
||||
</details></think>
|
||||
|
||||
---
|
||||
|
||||
|
||||
Update made in `run_retarg_relatives`:
|
||||
|
||||
- **`orig_hierarchy`** = `{orig}` ∪ `descendants(orig)` (the original armature and every object whose parent chain leads to it, i.e. the linked character hierarchy).
|
||||
- **`candidates`** is built as before (rep descendants + objects that parent or constrain to orig), then **`candidates -= orig_hierarchy`** so we never retarget objects in orig’s hierarchy.
|
||||
- Only objects in **`candidates`** have their parent, constraint targets, or Armature modifier object changed to `rep`.
|
||||
|
||||
So anything under the original character (linked collection) keeps pointing at the original; only objects outside that hierarchy (e.g. rep’s hierarchy or other scene objects that referenced orig) get retargeted to the replacement.
|
||||
|
||||
---
|
||||
|
||||
_**User**_
|
||||
|
||||
migbbody shapekeys apparently is experiencing the same issue where the action slot is not applied.
|
||||
|
||||
---
|
||||
|
||||
|
||||
+24
-1
@@ -596,6 +596,15 @@ def run_mig_bbody_shapekeys(orig, rep, rep_descendants, context=None):
|
||||
print(f"[DLM step6] {ob.name} orig base body has no shape_keys")
|
||||
if not ob.data.shape_keys.animation_data:
|
||||
ob.data.shape_keys.animation_data_create()
|
||||
sk_ad = ob.data.shape_keys.animation_data
|
||||
# Prefer action (and slot) from original base body; fallback to name lookup.
|
||||
orig_sk_ad = None
|
||||
if orig_base and orig_base.data.shape_keys:
|
||||
orig_sk_ad = orig_base.data.shape_keys.animation_data
|
||||
action = None
|
||||
if orig_sk_ad and getattr(orig_sk_ad, "action", None):
|
||||
action = orig_sk_ad.action
|
||||
if action is None:
|
||||
body_name = ob.name
|
||||
action = (
|
||||
bpy.data.actions.get(body_name + "Action")
|
||||
@@ -603,7 +612,21 @@ def run_mig_bbody_shapekeys(orig, rep, rep_descendants, context=None):
|
||||
or bpy.data.actions.get(body_name + "Action.001")
|
||||
)
|
||||
if action:
|
||||
ob.data.shape_keys.animation_data.action = action
|
||||
# Copy slot-related props before action so slot is applied (Blender 4.4+).
|
||||
if orig_sk_ad and hasattr(sk_ad, "last_slot_identifier") and hasattr(orig_sk_ad, "last_slot_identifier") and orig_sk_ad.last_slot_identifier:
|
||||
sk_ad.last_slot_identifier = orig_sk_ad.last_slot_identifier
|
||||
sk_ad.action = action
|
||||
if orig_sk_ad and getattr(orig_sk_ad, "action_slot", None) and getattr(sk_ad, "action_slot", None):
|
||||
try:
|
||||
sk_ad.action_slot = orig_sk_ad.action_slot
|
||||
except Exception:
|
||||
pass
|
||||
for prop in ("action_blend_type", "action_extrapolation", "action_influence"):
|
||||
if orig_sk_ad and hasattr(orig_sk_ad, prop) and hasattr(sk_ad, prop):
|
||||
try:
|
||||
setattr(sk_ad, prop, getattr(orig_sk_ad, prop))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def run_full_migration(context):
|
||||
|
||||
Reference in New Issue
Block a user