fix MigBoneConst not migrating properties/targets of constraints
This commit is contained in:
@@ -13884,3 +13884,572 @@ _**User**_
|
||||
|
||||
---
|
||||
|
||||
_**Agent (model default, mode Agent)**_
|
||||
|
||||
<think><details><summary>Thought Process</summary>
|
||||
|
||||
The user says AnimLayers is still being detected improperly. They're suggesting I grep how the animation layers addon works. The addon might be installed in Blender's addons folder - I should search for it. Common locations would be:
|
||||
- C:\Program Files\Blender Foundation\Blender 5.0\5.0\scripts\addons
|
||||
- Or a user addon path
|
||||
- The terminal mentioned "animation_layers_updater addon" - so there might be a folder like "animation_layers" or "animation_layers_updater"
|
||||
|
||||
Let me search the user's system for the animation layers addon so we can see how it stores the "turn on" / layer state. I'll search in common Blender addon paths and also in the workspace.
|
||||
</details></think>
|
||||
|
||||
---
|
||||
|
||||
|
||||
Searching for the Animation Layers addon to see how it stores its state:
|
||||
|
||||
|
||||
---
|
||||
|
||||
<tool-use data-tool-type="generic" data-tool-name="glob_file_search">
|
||||
<details>
|
||||
<summary>Tool use: **glob_file_search** • Searched codebase "undefined" • **16** results in **1** directory</summary>
|
||||
|
||||
Directory: **C:\Program Files\Blender Foundation\Blender 5.0** (16 files)
|
||||
|
||||
| File |
|
||||
|------|
|
||||
| `../C:\Program Files\Blender Foundation\Blender 5.0\portable\scripts\addons\Animation_Layers\animation_layers_updater\Animation_Layers_updater_status.json` |
|
||||
| `../C:\Program Files\Blender Foundation\Blender 5.0\portable\scripts\addons\Animation_Layers\multikey.py` |
|
||||
| `../C:\Program Files\Blender Foundation\Blender 5.0\portable\scripts\addons\Animation_Layers\subscriptions.py` |
|
||||
| `../C:\Program Files\Blender Foundation\Blender 5.0\portable\scripts\addons\Animation_Layers\anim_layers.py` |
|
||||
| `../C:\Program Files\Blender Foundation\Blender 5.0\portable\scripts\addons\Animation_Layers\bake_ops.py` |
|
||||
| `../C:\Program Files\Blender Foundation\Blender 5.0\portable\scripts\addons\Animation_Layers\addon_updater_ops.py` |
|
||||
| `../C:\Program Files\Blender Foundation\Blender 5.0\portable\scripts\addons\Animation_Layers\addon_updater.py` |
|
||||
| `../C:\Program Files\Blender Foundation\Blender 5.0\portable\scripts\addons\Animation_Layers\__init__.py` |
|
||||
| `../C:\Program Files\Blender Foundation\Blender 5.0\portable\scripts\addons\Animation_Layers\animation_layers_updater\backup\animation_layers_updater\Animation_Layers_updater_status.json` |
|
||||
| `../C:\Program Files\Blender Foundation\Blender 5.0\portable\scripts\addons\Animation_Layers\animation_layers_updater\backup\subscriptions.py` |
|
||||
| `../C:\Program Files\Blender Foundation\Blender 5.0\portable\scripts\addons\Animation_Layers\animation_layers_updater\backup\__init__.py` |
|
||||
| `../C:\Program Files\Blender Foundation\Blender 5.0\portable\scripts\addons\Animation_Layers\animation_layers_updater\backup\anim_layers.py` |
|
||||
| `../C:\Program Files\Blender Foundation\Blender 5.0\portable\scripts\addons\Animation_Layers\animation_layers_updater\backup\bake_ops.py` |
|
||||
| `../C:\Program Files\Blender Foundation\Blender 5.0\portable\scripts\addons\Animation_Layers\animation_layers_updater\backup\multikey.py` |
|
||||
| `../C:\Program Files\Blender Foundation\Blender 5.0\portable\scripts\addons\Animation_Layers\animation_layers_updater\backup\addon_updater.py` |
|
||||
| `../C:\Program Files\Blender Foundation\Blender 5.0\portable\scripts\addons\Animation_Layers\animation_layers_updater\backup\addon_updater_ops.py` |
|
||||
|
||||
</details>
|
||||
</tool-use>
|
||||
|
||||
---
|
||||
|
||||
<tool-use data-tool-type="unknown" data-tool-name="ripgrep_raw_search">
|
||||
<details>
|
||||
<summary>Tool use: **ripgrep_raw_search**</summary>
|
||||
|
||||
|
||||
Parameters:
|
||||
|
||||
```json
|
||||
{
|
||||
"pattern": "turn_on|als\\.|animation.layer",
|
||||
"path": "C:\\Program Files\\Blender Foundation\\Blender 5.0",
|
||||
"glob": "*.py",
|
||||
"outputMode": "content",
|
||||
"contextBefore": 0,
|
||||
"contextAfter": 0,
|
||||
"caseInsensitive": false
|
||||
}
|
||||
```
|
||||
Additional data:
|
||||
|
||||
```json
|
||||
{
|
||||
"isPruned": true,
|
||||
"pattern": "turn_on|als\\.|animation.layer",
|
||||
"path": "C:\\Program Files\\Blender Foundation\\Blender 5.0",
|
||||
"outputMode": "content",
|
||||
"totalFiles": 457,
|
||||
"totalMatches": 2148,
|
||||
"topFiles": [
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\extensions\\.local\\lib\\python3.11\\site-packages\\typing_extensions.py",
|
||||
"matchCount": 8
|
||||
},
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\extensions\\.local\\lib\\python3.11\\site-packages\\regex\\test_regex.py",
|
||||
"matchCount": 1
|
||||
},
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\extensions\\.local\\lib\\python3.11\\site-packages\\regex\\regex.py",
|
||||
"matchCount": 1
|
||||
},
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\extensions\\.local\\lib\\python3.11\\site-packages\\regex\\_regex_core.py",
|
||||
"matchCount": 3
|
||||
},
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\extensions\\.local\\lib\\python3.11\\site-packages\\rdflib\\xsd_datetime.py",
|
||||
"matchCount": 1
|
||||
},
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\extensions\\.local\\lib\\python3.11\\site-packages\\rdflib\\term.py",
|
||||
"matchCount": 2
|
||||
},
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\extensions\\.local\\lib\\python3.11\\site-packages\\rdflib\\plugins\\parsers\\notation3.py",
|
||||
"matchCount": 1
|
||||
},
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\extensions\\.local\\lib\\python3.11\\site-packages\\rdflib\\namespace\\_TIME.py",
|
||||
"matchCount": 2
|
||||
},
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\extensions\\.local\\lib\\python3.11\\site-packages\\rdflib\\namespace\\_SH.py",
|
||||
"matchCount": 3
|
||||
},
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\extensions\\.local\\lib\\python3.11\\site-packages\\rdflib\\namespace\\_SDO.py",
|
||||
"matchCount": 8
|
||||
},
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\extensions\\.local\\lib\\python3.11\\site-packages\\rdflib\\namespace\\_PROV.py",
|
||||
"matchCount": 1
|
||||
},
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\extensions\\.local\\lib\\python3.11\\site-packages\\rdflib\\namespace\\_OWL.py",
|
||||
"matchCount": 5
|
||||
},
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\extensions\\.local\\lib\\python3.11\\site-packages\\dateutil\\rrule.py",
|
||||
"matchCount": 5
|
||||
},
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\extensions\\.local\\lib\\python3.11\\site-packages\\jsonschema\\_keywords.py",
|
||||
"matchCount": 1
|
||||
},
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\extensions\\.local\\lib\\python3.11\\site-packages\\joblib\\test\\test_parallel.py",
|
||||
"matchCount": 2
|
||||
},
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\extensions\\.local\\lib\\python3.11\\site-packages\\joblib\\test\\test_module.py",
|
||||
"matchCount": 1
|
||||
},
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\extensions\\.local\\lib\\python3.11\\site-packages\\joblib\\test\\test_memmapping.py",
|
||||
"matchCount": 2
|
||||
},
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\extensions\\.local\\lib\\python3.11\\site-packages\\joblib\\externals\\loky\\backend\\resource_tracker.py",
|
||||
"matchCount": 1
|
||||
},
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\extensions\\.local\\lib\\python3.11\\site-packages\\joblib\\externals\\loky\\backend\\reduction.py",
|
||||
"matchCount": 1
|
||||
},
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\extensions\\.local\\lib\\python3.11\\site-packages\\joblib\\externals\\loky\\backend\\popen_loky_win32.py",
|
||||
"matchCount": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
Status: **completed**
|
||||
|
||||
|
||||
</details>
|
||||
</tool-use>
|
||||
|
||||
---
|
||||
|
||||
<think><details><summary>Thought Process</summary>
|
||||
|
||||
The grep hit a lot of unrelated files. Let me search specifically inside the Animation_Layers addon folder for turn_on, als, nla, layer state, etc.
|
||||
</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": "turn_on|als\\.|\\[.als|animation_data|nla_tracks",
|
||||
"path": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\scripts\\addons\\Animation_Layers",
|
||||
"glob": "*.py",
|
||||
"caseInsensitive": false
|
||||
}
|
||||
```
|
||||
Additional data:
|
||||
|
||||
```json
|
||||
{
|
||||
"isPruned": true,
|
||||
"pattern": "turn_on|als\\.|\\[.als|animation_data|nla_tracks",
|
||||
"path": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\scripts\\addons\\Animation_Layers",
|
||||
"outputMode": "content",
|
||||
"totalFiles": 10,
|
||||
"totalMatches": 997,
|
||||
"topFiles": [
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\scripts\\addons\\Animation_Layers\\subscriptions.py",
|
||||
"matchCount": 70
|
||||
},
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\scripts\\addons\\Animation_Layers\\multikey.py",
|
||||
"matchCount": 13
|
||||
},
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\scripts\\addons\\Animation_Layers\\bake_ops.py",
|
||||
"matchCount": 105
|
||||
},
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\scripts\\addons\\Animation_Layers\\anim_layers.py",
|
||||
"matchCount": 310
|
||||
},
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\scripts\\addons\\Animation_Layers\\__init__.py",
|
||||
"matchCount": 1
|
||||
},
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\scripts\\addons\\Animation_Layers\\animation_layers_updater\\backup\\__init__.py",
|
||||
"matchCount": 1
|
||||
},
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\scripts\\addons\\Animation_Layers\\animation_layers_updater\\backup\\subscriptions.py",
|
||||
"matchCount": 70
|
||||
},
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\scripts\\addons\\Animation_Layers\\animation_layers_updater\\backup\\multikey.py",
|
||||
"matchCount": 13
|
||||
},
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\scripts\\addons\\Animation_Layers\\animation_layers_updater\\backup\\bake_ops.py",
|
||||
"matchCount": 105
|
||||
},
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\scripts\\addons\\Animation_Layers\\animation_layers_updater\\backup\\anim_layers.py",
|
||||
"matchCount": 309
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
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: C:\Program Files\Blender Foundation\Blender 5.0\portable\scripts\addons\Animation_Layers\anim_layers.py</summary>
|
||||
|
||||
</details>
|
||||
</tool-use>
|
||||
|
||||
---
|
||||
|
||||
<think><details><summary>Thought Process</summary>
|
||||
|
||||
I found it. The addon uses **obj.als.turn_on** - so `als` is an **RNA property** (a PropertyGroup on the object), not an id property. So we're checking `key in orig` (id props) but the addon stores it as **orig.als** which is a PropertyGroup with a **turn_on** attribute. So we need to check `getattr(orig, 'als', None)` and then `getattr(orig.als, 'turn_on', None)` or similar. Let me look at how they register the property.
|
||||
</details></think>
|
||||
|
||||
---
|
||||
|
||||
|
||||
Checking how the addon registers `als` and `Anim_Layers`:
|
||||
|
||||
|
||||
---
|
||||
|
||||
<tool-use data-tool-type="unknown" data-tool-name="ripgrep_raw_search">
|
||||
<details>
|
||||
<summary>Tool use: **ripgrep_raw_search**</summary>
|
||||
|
||||
|
||||
Parameters:
|
||||
|
||||
```json
|
||||
{
|
||||
"pattern": "als\\.|Anim_Layers|PropertyGroup|BoolProperty.*turn_on",
|
||||
"path": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\scripts\\addons\\Animation_Layers",
|
||||
"glob": "*.py",
|
||||
"outputMode": "content",
|
||||
"contextBefore": 0,
|
||||
"contextAfter": 0,
|
||||
"caseInsensitive": false
|
||||
}
|
||||
```
|
||||
Additional data:
|
||||
|
||||
```json
|
||||
{
|
||||
"isPruned": true,
|
||||
"pattern": "als\\.|Anim_Layers|PropertyGroup|BoolProperty.*turn_on",
|
||||
"path": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\scripts\\addons\\Animation_Layers",
|
||||
"outputMode": "content",
|
||||
"totalFiles": 3,
|
||||
"totalMatches": 699,
|
||||
"topFiles": [
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\scripts\\addons\\Animation_Layers\\subscriptions.py",
|
||||
"matchCount": 54
|
||||
},
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\scripts\\addons\\Animation_Layers\\multikey.py",
|
||||
"matchCount": 2
|
||||
},
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\scripts\\addons\\Animation_Layers\\anim_layers.py",
|
||||
"matchCount": 24
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
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: C:\Program Files\Blender Foundation\Blender 5.0\portable\scripts\addons\Animation_Layers\__init__.py</summary>
|
||||
|
||||
</details>
|
||||
</tool-use>
|
||||
|
||||
---
|
||||
|
||||
<think><details><summary>Thought Process</summary>
|
||||
|
||||
Found it. In __init__.py:
|
||||
- **AnimLayersSettings** is a PropertyGroup with **turn_on: bpy.props.BoolProperty**
|
||||
- It's registered on the **Object** type as **als** (need to find where they register it)
|
||||
|
||||
So the addon uses **obj.als** (RNA PropertyGroup on Object) with **obj.als.turn_on**. So we must check **getattr(orig, 'als', None)** and then **getattr(orig.als, 'turn_on', None)**. It's not in orig.keys() at all - it's an RNA property. Let me find where they register it on Object.
|
||||
</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": "als|Anim_Layers|register_class|Object\\.|bpy\\.types\\.Object",
|
||||
"path": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\scripts\\addons\\Animation_Layers\\__init__.py",
|
||||
"caseInsensitive": false
|
||||
}
|
||||
```
|
||||
Additional data:
|
||||
|
||||
```json
|
||||
{
|
||||
"isPruned": true,
|
||||
"pattern": "als|Anim_Layers|register_class|Object\\.|bpy\\.types\\.Object",
|
||||
"path": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\scripts\\addons\\Animation_Layers\\__init__.py",
|
||||
"outputMode": "content",
|
||||
"totalFiles": 1,
|
||||
"totalMatches": 39,
|
||||
"topFiles": [
|
||||
{
|
||||
"uri": "C:\\Program Files\\Blender Foundation\\Blender 5.0\\portable\\scripts\\addons\\Animation_Layers\\__init__.py",
|
||||
"matchCount": 39
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
Status: **completed**
|
||||
|
||||
|
||||
</details>
|
||||
</tool-use>
|
||||
|
||||
---
|
||||
|
||||
<think><details><summary>Thought Process</summary>
|
||||
|
||||
Perfect. So:
|
||||
- **bpy.types.Object.als** = PointerProperty(type=AnimLayersSettings)
|
||||
- So **obj.als** is an RNA property (PropertyGroup) on the **Object**, and **obj.als.turn_on** is the boolean.
|
||||
|
||||
So we need to:
|
||||
1. Detect Animation Layers by checking **getattr(orig, 'als', None)** and then **getattr(orig.als, 'turn_on', None)** - if the addon is loaded, every Object has .als; we consider "has Animation Layers" when orig has NLA tracks (we already have has_nla) OR when we want to report that we migrated the toggle. Actually the message is "Animation Layer attributes migrated" when we find als - so we need has_als to be True when **orig.als exists and we copied turn_on**. So detection should be: has_als = getattr(orig, 'als', None) is not None (and optionally orig.als.turn_on is True or we have nla - but actually we should consider "Animation Layers found" when the Object has the als property group, which it will if the addon is loaded). So simply: has_als = getattr(orig, 'als', None) is not None.
|
||||
|
||||
2. Mirror: we need to copy **orig.als.turn_on** to **rep.als.turn_on** (and possibly other writable properties of the als group like layer_index). So in _mirror_als_turn_on we do:
|
||||
- If getattr(orig, 'als', None) and getattr(rep, 'als', None):
|
||||
rep.als.turn_on = orig.als.turn_on
|
||||
And for detection: has_als = getattr(orig, 'als', None) is not None (and maybe rep has als too).
|
||||
</details></think>
|
||||
|
||||
---
|
||||
|
||||
|
||||
Identifying the addon: it registers `bpy.types.Object.als` (RNA PropertyGroup), so the toggle is `obj.als.turn_on`, not an id prop. Updating detection and mirroring to use `orig.als` / `rep.als`.
|
||||
|
||||
|
||||
---
|
||||
|
||||
The string to replace was not found in the file.
|
||||
|
||||
---
|
||||
|
||||
<think><details><summary>Thought Process</summary>
|
||||
|
||||
I had a typo in the replace - "except Exception:\n pass" vs "except Exception:\n pass" in the bone loop I wrote "except Exception:\n pass" but with wrong indentation (only 4 spaces before pass in one place). Let me do the replace in two smaller chunks: first _has_als_anywhere, then _mirror_als_turn_on.
|
||||
</details></think>
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
<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>
|
||||
|
||||
---
|
||||
|
||||
<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>
|
||||
|
||||
Both edits applied. Adding RNA check to _debug_als_lookup so the debug output shows that obj.als exists when the addon is loaded.
|
||||
</details></think>
|
||||
|
||||
---
|
||||
|
||||
|
||||
Adding an RNA check to the debug output so we log when `obj.als` exists:
|
||||
|
||||
|
||||
---
|
||||
|
||||
<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. Let me verify there are no linter errors.
|
||||
</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>
|
||||
|
||||
All good. Summarize for the user.
|
||||
</details></think>
|
||||
|
||||
---
|
||||
|
||||
|
||||
Summary of what changed:
|
||||
|
||||
**Cause:** The Animation Layers addon uses **RNA**, not id properties: it registers `bpy.types.Object.als` (a `PointerProperty` to `AnimLayersSettings`) and stores the toggle as **`obj.als.turn_on`**. The migrator was only checking id props (`"als.turn_on"` in `orig.keys()`, etc.), so it never saw that.
|
||||
|
||||
**Updates in `ops/migrator.py`:**
|
||||
|
||||
1. **`_has_als_anywhere(orig)`**
|
||||
- First checks **`getattr(orig, "als", None) is not None`** (RNA).
|
||||
- If that’s true, it returns True so “Animation Layer attributes migrated” is reported.
|
||||
- Id-property checks are kept as a fallback.
|
||||
|
||||
2. **`_mirror_als_turn_on(orig, rep)`**
|
||||
- First copies via RNA: if both `orig.als` and `rep.als` exist, sets **`rep.als.turn_on = orig.als.turn_on`**.
|
||||
- Then runs the existing id-property mirroring as fallback.
|
||||
|
||||
3. **`_debug_als_lookup(orig)`**
|
||||
- Now prints **`orig.als` (RNA)** and **`orig.als.turn_on`** so you can confirm the addon’s state in the console.
|
||||
|
||||
With the Animation Layers addon enabled, any armature object has the `als` RNA property. So when the original has Animation Layers turned on (`orig.als.turn_on`), detection should succeed and the report should say “Animation Layer attributes migrated” after Mig NLA. Reload the addon and run Mig NLA again to confirm.
|
||||
|
||||
---
|
||||
|
||||
_**User**_
|
||||
|
||||
Good.
|
||||
|
||||
MigBoneConst is copying the constraints, but it's not copying their properties, specifically the targets. I like to run bpy.ops.pose.copy_pose_con(), but that's context-dependent on pose mode.
|
||||
|
||||
---
|
||||
|
||||
|
||||
+59
-18
@@ -356,8 +356,65 @@ def run_mig_cust_props(orig, rep):
|
||||
print(f"[DLM MigCustProps] Settings[{k!r}] = {v!r}")
|
||||
|
||||
|
||||
def _retarget_id(ob, orig, rep, orig_to_rep):
|
||||
"""Return rep, orig_to_rep[ob], or ob so constraint targets point to replacement when appropriate."""
|
||||
if ob is None:
|
||||
return None
|
||||
if ob == orig:
|
||||
return rep
|
||||
return orig_to_rep.get(ob, ob)
|
||||
|
||||
|
||||
def _copy_constraint_props(c, nc, orig, rep, orig_to_rep):
|
||||
"""Copy all copyable RNA properties from c to nc, retargeting object/armature pointers."""
|
||||
for rna_prop in c.bl_rna.properties:
|
||||
if rna_prop.is_readonly or rna_prop.identifier in ("name", "type"):
|
||||
continue
|
||||
if not hasattr(nc, rna_prop.identifier):
|
||||
continue
|
||||
try:
|
||||
val = getattr(c, rna_prop.identifier)
|
||||
except Exception:
|
||||
continue
|
||||
rna_type = getattr(rna_prop, "type", None)
|
||||
if rna_type == "POINTER":
|
||||
setattr(nc, rna_prop.identifier, _retarget_id(val, orig, rep, orig_to_rep))
|
||||
elif rna_type == "COLLECTION":
|
||||
# e.g. ArmatureConstraint.targets: ensure count then copy item props (target, subtarget, weight)
|
||||
try:
|
||||
dst_coll = getattr(nc, rna_prop.identifier)
|
||||
src_coll = getattr(c, rna_prop.identifier)
|
||||
add_fn = getattr(dst_coll, "add", None) or getattr(dst_coll, "new", None)
|
||||
for i in range(len(src_coll)):
|
||||
if i >= len(dst_coll) and add_fn:
|
||||
add_fn()
|
||||
for i, src_item in enumerate(src_coll):
|
||||
if i >= len(dst_coll):
|
||||
break
|
||||
dst_item = dst_coll[i]
|
||||
for p in dst_item.bl_rna.properties:
|
||||
if p.is_readonly or p.identifier == "name":
|
||||
continue
|
||||
if not hasattr(dst_item, p.identifier):
|
||||
continue
|
||||
try:
|
||||
v = getattr(src_item, p.identifier)
|
||||
if getattr(p, "type", None) == "POINTER":
|
||||
v = _retarget_id(v, orig, rep, orig_to_rep)
|
||||
setattr(dst_item, p.identifier, v)
|
||||
except Exception:
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
setattr(nc, rna_prop.identifier, val)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def run_mig_bone_const(orig, rep, orig_to_rep):
|
||||
"""Bone constraints: remove stale on rep, copy from orig with retarget, trim duplicates."""
|
||||
"""Bone constraints: remove stale on rep, copy from orig with full props (targets, etc.) and retarget, trim duplicates."""
|
||||
other_originals = [o for o in orig_to_rep if o != orig]
|
||||
for pb in rep.pose.bones:
|
||||
to_remove = [c for c in pb.constraints if getattr(c, "target", None) in other_originals]
|
||||
@@ -368,25 +425,9 @@ def run_mig_bone_const(orig, rep, orig_to_rep):
|
||||
continue
|
||||
rbone = rep.pose.bones[pbone.name]
|
||||
for c in pbone.constraints:
|
||||
if getattr(c, "target", None) == orig:
|
||||
continue
|
||||
nc = rbone.constraints.new(type=c.type)
|
||||
nc.name = c.name
|
||||
nc.mute = c.mute
|
||||
nc.influence = c.influence
|
||||
t = getattr(c, "target", None)
|
||||
if t is not None and t in orig_to_rep:
|
||||
nc.target = orig_to_rep[t]
|
||||
elif getattr(nc, "target", None) is not None and t:
|
||||
nc.target = t
|
||||
if hasattr(c, "subtarget") and c.subtarget:
|
||||
nc.subtarget = c.subtarget
|
||||
for prop in ("head_tail", "use_bone_object", "invert_x", "invert_y", "invert_z"):
|
||||
if hasattr(c, prop):
|
||||
try:
|
||||
setattr(nc, prop, getattr(c, prop))
|
||||
except Exception:
|
||||
pass
|
||||
_copy_constraint_props(c, nc, orig, rep, orig_to_rep)
|
||||
for pb in orig.pose.bones:
|
||||
if pb.name not in rep.pose.bones:
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user