MigNLA: now makes repchar active before activating animlayers to avoid requirement for manual activation
This commit is contained in:
@@ -3286,3 +3286,870 @@ _**Agent (composer-2-fast)**_
|
||||
<summary>Tool use: **edit_file_v2**</summary>
|
||||
|
||||
</details></tool-use>
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
<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/utils/remove_original.py</summary>
|
||||
|
||||
</details>
|
||||
|
||||
</tool-use>
|
||||
|
||||
<tool-use data-tool-type="write" data-tool-name="edit_file_v2"><details>
|
||||
<summary>Tool use: **edit_file_v2**</summary>
|
||||
|
||||
</details></tool-use>
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
<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/ui/operators.py</summary>
|
||||
|
||||
</details>
|
||||
</tool-use>
|
||||
|
||||
<tool-use data-tool-type="read" data-tool-name="read_file_v2"><details>
|
||||
<summary>Tool use: **read_file_v2**</summary>
|
||||
|
||||
</details></tool-use>
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
<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/ui/operators.py</summary>
|
||||
|
||||
</details>
|
||||
</tool-use>
|
||||
|
||||
<tool-use data-tool-type="read" data-tool-name="read_file_v2"><details>
|
||||
<summary>Tool use: **read_file_v2**</summary>
|
||||
|
||||
</details></tool-use>
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
<tool-use data-tool-type="unknown" data-tool-name="ripgrep_raw_search">
|
||||
<details>
|
||||
<summary>Tool use: **ripgrep_raw_search**</summary>
|
||||
|
||||
|
||||
Parameters:
|
||||
|
||||
```json
|
||||
{
|
||||
"caseInsensitive": false,
|
||||
"path": "T:/Dynamic-Link-Manager/ui/operators.py",
|
||||
"pattern": "collection_containing_armature"
|
||||
}
|
||||
```
|
||||
Additional data:
|
||||
|
||||
```json
|
||||
{
|
||||
"isPruned": true,
|
||||
"outputMode": "content",
|
||||
"path": "T:/Dynamic-Link-Manager/ui/operators.py",
|
||||
"pattern": "collection_containing_armature",
|
||||
"topFiles": [
|
||||
{
|
||||
"matchCount": 2,
|
||||
"uri": "ui/operators.py"
|
||||
}
|
||||
],
|
||||
"totalFiles": 1,
|
||||
"totalMatches": 2
|
||||
}
|
||||
```
|
||||
Status: **completed**
|
||||
|
||||
|
||||
</details>
|
||||
</tool-use>
|
||||
|
||||
<tool-use data-tool-type="unknown" data-tool-name="ripgrep_raw_search"><details>
|
||||
<summary>Tool use: **ripgrep_raw_search**</summary>
|
||||
|
||||
</details></tool-use>
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
<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/ui/operators.py</summary>
|
||||
|
||||
</details>
|
||||
|
||||
</tool-use>
|
||||
|
||||
<tool-use data-tool-type="write" data-tool-name="edit_file_v2"><details>
|
||||
<summary>Tool use: **edit_file_v2**</summary>
|
||||
|
||||
</details></tool-use>
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
<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/ui/operators.py</summary>
|
||||
|
||||
</details>
|
||||
|
||||
</tool-use>
|
||||
|
||||
<tool-use data-tool-type="write" data-tool-name="edit_file_v2"><details>
|
||||
<summary>Tool use: **edit_file_v2**</summary>
|
||||
|
||||
</details></tool-use>
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
<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/ui/properties.py",
|
||||
"T:/Dynamic-Link-Manager/ui/panels.py",
|
||||
"T:/Dynamic-Link-Manager/ui/operators.py",
|
||||
"T:/Dynamic-Link-Manager/utils/remove_original.py"
|
||||
]
|
||||
}
|
||||
```
|
||||
Result:
|
||||
|
||||
```json
|
||||
{
|
||||
"linterErrorsByFile": [
|
||||
{
|
||||
"relativeWorkspacePath": "T:/Dynamic-Link-Manager/ui/properties.py"
|
||||
},
|
||||
{
|
||||
"relativeWorkspacePath": "T:/Dynamic-Link-Manager/ui/panels.py"
|
||||
},
|
||||
{
|
||||
"relativeWorkspacePath": "T:/Dynamic-Link-Manager/ui/operators.py"
|
||||
},
|
||||
{
|
||||
"relativeWorkspacePath": "T:/Dynamic-Link-Manager/utils/remove_original.py"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
Status: **completed**
|
||||
|
||||
|
||||
</details>
|
||||
</tool-use>
|
||||
|
||||
<tool-use data-tool-type="unknown" data-tool-name="read_lints"><details>
|
||||
<summary>Tool use: **read_lints**</summary>
|
||||
|
||||
</details></tool-use>
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
<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/__init__.py</summary>
|
||||
|
||||
</details>
|
||||
</tool-use>
|
||||
|
||||
<tool-use data-tool-type="read" data-tool-name="read_file_v2"><details>
|
||||
<summary>Tool use: **read_file_v2**</summary>
|
||||
|
||||
</details></tool-use>
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
<tool-use data-tool-type="unknown" data-tool-name="todo_write">
|
||||
<details>
|
||||
<summary>Tool use: **todo_write**</summary>
|
||||
|
||||
|
||||
Parameters:
|
||||
|
||||
```json
|
||||
{
|
||||
"merge": true
|
||||
}
|
||||
```
|
||||
Result:
|
||||
|
||||
```json
|
||||
{
|
||||
"finalTodos": [
|
||||
{
|
||||
"content": "Add migrator_rig_family EnumProperty and draw at top of CharMig box in panels.py",
|
||||
"id": "enum-prop-ui",
|
||||
"status": "completed"
|
||||
},
|
||||
{
|
||||
"content": "Implement resolve_collection_for_remove_original(orig, rig_family) with linked/override hierarchy walk + safe fallback",
|
||||
"id": "collection-resolver",
|
||||
"status": "completed"
|
||||
},
|
||||
{
|
||||
"content": "Refactor DLM_OT_migrator_remove_original to use resolver; keep action purge/rename logic",
|
||||
"id": "wire-remove-original",
|
||||
"status": "completed"
|
||||
}
|
||||
],
|
||||
"initialTodos": [
|
||||
{
|
||||
"content": "Add migrator_rig_family EnumProperty and draw at top of CharMig box in panels.py",
|
||||
"id": "enum-prop-ui",
|
||||
"status": "completed"
|
||||
},
|
||||
{
|
||||
"content": "Implement resolve_collection_for_remove_original(orig, rig_family) with linked/override hierarchy walk + safe fallback",
|
||||
"id": "collection-resolver",
|
||||
"status": "in_progress"
|
||||
},
|
||||
{
|
||||
"content": "Refactor DLM_OT_migrator_remove_original to use resolver; keep action purge/rename logic",
|
||||
"id": "wire-remove-original",
|
||||
"status": "pending"
|
||||
}
|
||||
],
|
||||
"success": true,
|
||||
"wasMerge": true
|
||||
}
|
||||
```
|
||||
Status: **completed**
|
||||
|
||||
|
||||
</details>
|
||||
</tool-use>
|
||||
|
||||
<tool-use data-tool-type="unknown" data-tool-name="todo_write"><details>
|
||||
<summary>Tool use: **todo_write**</summary>
|
||||
|
||||
</details></tool-use>
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
|
||||
Here’s what was implemented:
|
||||
|
||||
### 1. Rig family selector ([`ui/properties.py`](ui/properties.py), [`ui/panels.py`](ui/panels.py))
|
||||
- Added `migrator_rig_family` **`EnumProperty`**: **Rigify** | **ARP** (default Rigify).
|
||||
- First row under “Character Migrator” uses **`expand=True`** for the two buttons.
|
||||
|
||||
### 2. Collection resolver ([`utils/remove_original.py`](utils/remove_original.py))
|
||||
- **`resolve_collection_for_remove_original(orig, rig_family, scene)`**:
|
||||
- Picks the **deepest** `users_collection` entry (most nested).
|
||||
- Walks **up** to `scene.collection` via **`_parent_collection`**.
|
||||
- Chooses the remove target:
|
||||
- **Linked armature:** outermost collection in that chain whose **`library.filepath`** matches **`orig.library`**.
|
||||
- **Override:** outermost collection with **`override_library`** set when **`orig.override_library`** is set.
|
||||
- **Rigify:** optional name match (`_Rigify`, base name) on the way **down** from the top of the chain.
|
||||
- **ARP:** no `_Rigify` stripping; hierarchy + defaults rule.
|
||||
- Default: **`chain[-1]`** (top of the branch under the scene).
|
||||
|
||||
### 3. Remove Original ([`ui/operators.py`](ui/operators.py))
|
||||
- Imports **`resolve_collection_for_remove_original`** (replaces **`collection_containing_armature`** for this operator).
|
||||
- Reads **`migrator_rig_family`** from scene props.
|
||||
- Tries **`bpy.data.collections.remove()`**; on failure, **warns** and falls back to **`bpy.data.objects.remove(orig, do_unlink=True)`**.
|
||||
- If the resolver returns **None**, removes the object only (unchanged idea).
|
||||
- **Action purge and `.rep` rename** on the replacement are unchanged.
|
||||
|
||||
`collection_containing_armature` in [`utils/__init__.py`](utils/__init__.py) is unchanged for **MigBBody** and other callers.
|
||||
|
||||
---
|
||||
|
||||
_**User**_
|
||||
|
||||
So far, CopyAttr and MigNLA need no rig type-specific behavior; current behavior is sufficient for both.
|
||||
|
||||
MigNLA needs to do one special thing: It needs to select the RepChar before activating animlayers.
|
||||
|
||||
---
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
<tool-use data-tool-type="unknown" data-tool-name="ripgrep_raw_search">
|
||||
<details>
|
||||
<summary>Tool use: **ripgrep_raw_search**</summary>
|
||||
|
||||
|
||||
Parameters:
|
||||
|
||||
```json
|
||||
{
|
||||
"caseInsensitive": false,
|
||||
"path": "T:/Dynamic-Link-Manager/ops/migrator.py",
|
||||
"pattern": "als|AnimLayer|run_mig_nla|mirror_als"
|
||||
}
|
||||
```
|
||||
Additional data:
|
||||
|
||||
```json
|
||||
{
|
||||
"isPruned": true,
|
||||
"outputMode": "content",
|
||||
"path": "T:/Dynamic-Link-Manager/ops/migrator.py",
|
||||
"pattern": "als|AnimLayer|run_mig_nla|mirror_als",
|
||||
"topFiles": [
|
||||
{
|
||||
"matchCount": 71,
|
||||
"uri": "ops/migrator.py"
|
||||
}
|
||||
],
|
||||
"totalFiles": 1,
|
||||
"totalMatches": 71
|
||||
}
|
||||
```
|
||||
Status: **completed**
|
||||
|
||||
|
||||
</details>
|
||||
</tool-use>
|
||||
|
||||
<tool-use data-tool-type="unknown" data-tool-name="ripgrep_raw_search"><details>
|
||||
<summary>Tool use: **ripgrep_raw_search**</summary>
|
||||
|
||||
</details></tool-use>
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
<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>
|
||||
|
||||
<tool-use data-tool-type="read" data-tool-name="read_file_v2"><details>
|
||||
<summary>Tool use: **read_file_v2**</summary>
|
||||
|
||||
</details></tool-use>
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
<tool-use data-tool-type="unknown" data-tool-name="ripgrep_raw_search">
|
||||
<details>
|
||||
<summary>Tool use: **ripgrep_raw_search**</summary>
|
||||
|
||||
|
||||
Parameters:
|
||||
|
||||
```json
|
||||
{
|
||||
"caseInsensitive": false,
|
||||
"path": "T:/Dynamic-Link-Manager",
|
||||
"pattern": "run_mig_nla"
|
||||
}
|
||||
```
|
||||
Additional data:
|
||||
|
||||
```json
|
||||
{
|
||||
"isPruned": true,
|
||||
"outputMode": "content",
|
||||
"path": "T:/Dynamic-Link-Manager",
|
||||
"pattern": "run_mig_nla",
|
||||
"topFiles": [
|
||||
{
|
||||
"matchCount": 4,
|
||||
"uri": ".specstory/history/2026-03-10_16-22-17Z-dlm_ot_migrator_remove_original-class-implementation.md"
|
||||
},
|
||||
{
|
||||
"matchCount": 2,
|
||||
"uri": ".specstory/history/2026-03-10_16-25Z-collection-removal-error-handling.md"
|
||||
},
|
||||
{
|
||||
"matchCount": 2,
|
||||
"uri": ".specstory/history/2026-03-10_16-07-46Z-operators.py-file-content.md"
|
||||
},
|
||||
{
|
||||
"matchCount": 2,
|
||||
"uri": ".specstory/history/2026-03-10_16-07Z-operators-py-file-content.md"
|
||||
},
|
||||
{
|
||||
"matchCount": 2,
|
||||
"uri": ".specstory/history/2026-03-10_16-19Z-removal-of-run-migration-command.md"
|
||||
},
|
||||
{
|
||||
"matchCount": 2,
|
||||
"uri": ".specstory/history/2026-03-10_16-19-09Z-removal-of-run-migration-command.md"
|
||||
},
|
||||
{
|
||||
"matchCount": 2,
|
||||
"uri": ".specstory/history/2026-03-10_17-03-21Z-operator-update-for-dlm_ot_migrator_remove_original.md"
|
||||
},
|
||||
{
|
||||
"matchCount": 4,
|
||||
"uri": ".specstory/history/2026-03-10_16-22Z-dlm-ot-migrator-remove-original-class-implementation.md"
|
||||
},
|
||||
{
|
||||
"matchCount": 2,
|
||||
"uri": "ui/operators.py"
|
||||
},
|
||||
{
|
||||
"matchCount": 2,
|
||||
"uri": ".specstory/history/2026-03-10_16-23Z-dlm-ot-migrator-remove-original-class-update.md"
|
||||
},
|
||||
{
|
||||
"matchCount": 2,
|
||||
"uri": ".specstory/history/2026-03-10_17-03Z-operator-update-for-dlm-ot-migrator-remove-original.md"
|
||||
},
|
||||
{
|
||||
"matchCount": 2,
|
||||
"uri": "ops/migrator.py"
|
||||
},
|
||||
{
|
||||
"matchCount": 2,
|
||||
"uri": ".specstory/history/2026-03-10_16-25-51Z-collection-removal-error-handling.md"
|
||||
},
|
||||
{
|
||||
"matchCount": 2,
|
||||
"uri": ".specstory/history/2026-03-10_16-23-09Z-dlm_ot_migrator_remove_original-class-update.md"
|
||||
},
|
||||
{
|
||||
"matchCount": 2,
|
||||
"uri": ".specstory/history/2026-02-18_23-39-18Z-character-migrator-workflow-integration.md"
|
||||
},
|
||||
{
|
||||
"matchCount": 3,
|
||||
"uri": ".specstory/history/2026-02-18_23-39Z-character-migrator-workflow-integration.md"
|
||||
},
|
||||
{
|
||||
"matchCount": 2,
|
||||
"uri": "ui\\operators.py"
|
||||
}
|
||||
],
|
||||
"totalFiles": 17,
|
||||
"totalMatches": 39
|
||||
}
|
||||
```
|
||||
Status: **completed**
|
||||
|
||||
|
||||
</details>
|
||||
</tool-use>
|
||||
|
||||
<tool-use data-tool-type="unknown" data-tool-name="ripgrep_raw_search"><details>
|
||||
<summary>Tool use: **ripgrep_raw_search**</summary>
|
||||
|
||||
</details></tool-use>
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
<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>
|
||||
|
||||
<tool-use data-tool-type="read" data-tool-name="read_file_v2"><details>
|
||||
<summary>Tool use: **read_file_v2**</summary>
|
||||
|
||||
</details></tool-use>
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
<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/ui/operators.py</summary>
|
||||
|
||||
</details>
|
||||
</tool-use>
|
||||
|
||||
<tool-use data-tool-type="read" data-tool-name="read_file_v2"><details>
|
||||
<summary>Tool use: **read_file_v2**</summary>
|
||||
|
||||
</details></tool-use>
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
<think><details><summary>Thought Process</summary>
|
||||
**Updating migration function**
|
||||
|
||||
I'm adding `context=None` parameter to `run_mig_nla()` and creating a helper `_activate_rep_for_animlayers()` to manage active object state. </details></think>
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
<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>
|
||||
|
||||
<tool-use data-tool-type="read" data-tool-name="read_file_v2"><details>
|
||||
<summary>Tool use: **read_file_v2**</summary>
|
||||
|
||||
</details></tool-use>
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
|
||||
Selecting the replacement armature as active before `_mirror_als_turn_on` so the Animation Layers addon receives the correct active object. Adding a context manager and passing `context` through `run_mig_nla`.
|
||||
|
||||
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
<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**</summary>
|
||||
|
||||
</details></tool-use>
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
<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**</summary>
|
||||
|
||||
</details></tool-use>
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
<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**</summary>
|
||||
|
||||
</details></tool-use>
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
<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**</summary>
|
||||
|
||||
</details></tool-use>
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
<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**</summary>
|
||||
|
||||
</details></tool-use>
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
<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/ui/operators.py</summary>
|
||||
|
||||
</details>
|
||||
|
||||
</tool-use>
|
||||
|
||||
<tool-use data-tool-type="write" data-tool-name="edit_file_v2"><details>
|
||||
<summary>Tool use: **edit_file_v2**</summary>
|
||||
|
||||
</details></tool-use>
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
<tool-use data-tool-type="unknown" data-tool-name="ripgrep_raw_search">
|
||||
<details>
|
||||
<summary>Tool use: **ripgrep_raw_search**</summary>
|
||||
|
||||
|
||||
Parameters:
|
||||
|
||||
```json
|
||||
{
|
||||
"caseInsensitive": false,
|
||||
"glob": "*.py",
|
||||
"path": "T:/Dynamic-Link-Manager",
|
||||
"pattern": "run_mig_nla\\("
|
||||
}
|
||||
```
|
||||
Additional data:
|
||||
|
||||
```json
|
||||
{
|
||||
"isPruned": true,
|
||||
"outputMode": "content",
|
||||
"path": "T:/Dynamic-Link-Manager",
|
||||
"pattern": "run_mig_nla\\(",
|
||||
"topFiles": [
|
||||
{
|
||||
"matchCount": 1,
|
||||
"uri": "ui/operators.py"
|
||||
},
|
||||
{
|
||||
"matchCount": 2,
|
||||
"uri": "ops/migrator.py"
|
||||
},
|
||||
{
|
||||
"matchCount": 1,
|
||||
"uri": "ui\\operators.py"
|
||||
},
|
||||
{
|
||||
"matchCount": 2,
|
||||
"uri": "ops\\migrator.py"
|
||||
}
|
||||
],
|
||||
"totalFiles": 4,
|
||||
"totalMatches": 6
|
||||
}
|
||||
```
|
||||
Status: **completed**
|
||||
|
||||
|
||||
</details>
|
||||
</tool-use>
|
||||
|
||||
<tool-use data-tool-type="unknown" data-tool-name="ripgrep_raw_search"><details>
|
||||
<summary>Tool use: **ripgrep_raw_search**</summary>
|
||||
|
||||
</details></tool-use>
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
<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",
|
||||
"T:/Dynamic-Link-Manager/ui/operators.py"
|
||||
]
|
||||
}
|
||||
```
|
||||
Result:
|
||||
|
||||
```json
|
||||
{
|
||||
"linterErrorsByFile": [
|
||||
{
|
||||
"relativeWorkspacePath": "T:/Dynamic-Link-Manager/ops/migrator.py"
|
||||
},
|
||||
{
|
||||
"relativeWorkspacePath": "T:/Dynamic-Link-Manager/ui/operators.py"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
Status: **completed**
|
||||
|
||||
|
||||
</details>
|
||||
</tool-use>
|
||||
|
||||
<tool-use data-tool-type="unknown" data-tool-name="read_lints"><details>
|
||||
<summary>Tool use: **read_lints**</summary>
|
||||
|
||||
</details></tool-use>
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
|
||||
Here’s what changed:
|
||||
|
||||
### `run_mig_nla` + Animation Layers active object
|
||||
- Added **`_rep_active_for_animlayers(context, rep)`** (`contextlib.contextmanager`): sets **`context.view_layer.objects.active = rep`** before AnimLayers handling, then restores the previous active object if it still exists.
|
||||
- **`run_mig_nla(orig, rep, report=None, context=None)`** wraps both **`_mirror_als_turn_on(orig, rep)`** calls (no‑NLA path and NLA path) in that context manager.
|
||||
- **`run_full_migration`** now calls **`run_mig_nla(orig, rep, context=context)`**.
|
||||
- **`DLM_OT_migrator_migrate_nla`** passes **`context=context`** into **`run_mig_nla`**.
|
||||
|
||||
If **`context` is omitted** (e.g. scripts), behavior is unchanged and AnimLayers mirroring runs without forcing selection.
|
||||
|
||||
---
|
||||
|
||||
_**User**_
|
||||
|
||||
@c:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\terminals\3.txt doesn't work; if I select origchar, repchar is not selected first. the reason I'm trying to do this is because if repchar is not active when mignla is ran, animlayers will not be activated on repchar and the user must select repchar and activate animlayers again.
|
||||
|
||||
---
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
<think><details><summary>Thought Process</summary>
|
||||
**Checking terminal output**
|
||||
|
||||
I'm reading the terminal file to identify any errors causing the repchar activation issue. </details></think>
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
<tool-use data-tool-type="read" data-tool-name="read_file_v2">
|
||||
<details><summary>Tool use: **read_file_v2** • Read file: c:\Users\Nathan\.cursor\projects\t-Dynamic-Link-Manager\terminals\3.txt</summary>
|
||||
|
||||
</details>
|
||||
</tool-use>
|
||||
|
||||
<tool-use data-tool-type="read" data-tool-name="read_file_v2"><details>
|
||||
<summary>Tool use: **read_file_v2**</summary>
|
||||
|
||||
</details></tool-use>
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
<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>
|
||||
|
||||
<tool-use data-tool-type="read" data-tool-name="read_file_v2"><details>
|
||||
<summary>Tool use: **read_file_v2**</summary>
|
||||
|
||||
</details></tool-use>
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
<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>
|
||||
|
||||
<tool-use data-tool-type="read" data-tool-name="read_file_v2"><details>
|
||||
<summary>Tool use: **read_file_v2**</summary>
|
||||
|
||||
</details></tool-use>
|
||||
|
||||
_**Agent (composer-2-fast)**_
|
||||
|
||||
<think><details><summary>Thought Process</summary>
|
||||
**Investigating restore issue**
|
||||
|
||||
The issue may be that we're restoring the original active object too early in the `finally` block, before animation layers can process it. The addon likely needs the replacement object to remain active during AnimLayers processing, not the original object. I'll leave `rep` as the active object after MigNLA completes to keep AnimLayers UI active on the replacement object. I'll set rep as active before `_mirror_als_turn_on` and avoid restoring previous active object.
|
||||
|
||||
**Testing object activation**
|
||||
|
||||
I'm testing if `vl.objects.active = rep` works when rep is hidden or obscured. I need to ensure `rep` is in the current view layer and not hidden or excluded from selection. I'm checking if `rep` needs to be selected explicitly with `Object.select_set(True)` to become active. Setting `view_layer.objects.active = obj` requires `obj.select_set(True)` and object to be in view layer.
|
||||
|
||||
**Setting object selection**
|
||||
|
||||
I'm using the view layer API to properly deselect all objects before setting the active object. I'm switching to object mode before selecting the replacement object to ensure compatibility across modes. I'm setting the replacement object as active before entering object mode to ensure proper selection.
|
||||
|
||||
**Handling mode switching**
|
||||
|
||||
I need to switch modes before setting the replacement object as active to avoid conflicts with armature parenting. I need to ensure proper mode switching before setting the replacement object as active to avoid armature parenting conflicts. I'm implementing robust activation logic that ensures proper mode switching before setting the replacement object as active. I'm refining the object selection logic to properly set the active object in Blender. I'm optimizing object selection by using `bpy.ops.object.select_all` instead of looping through objects. I'm switching to OBJECT mode from POSE mode and deselecting all objects before selecting the replacement object.
|
||||
|
||||
I'm updating the `_rep_active_for_animlayers` function to enter OBJECT mode, select the replacement object, and skip restoring the active object afterward. I'm implementing the selection restoration logic with try/except for `select_all` and using `context.temp_override` for proper window context. </details></think>
|
||||
|
||||
@@ -226,13 +226,13 @@
|
||||
"last_updated": "2026-03-25T20:22:34Z"
|
||||
},
|
||||
"f09112e7-3ddb-4e4e-b91a-418e38b881bf": {
|
||||
"user_message_count": 14,
|
||||
"agent_message_count": 199,
|
||||
"user_message_count": 16,
|
||||
"agent_message_count": 243,
|
||||
"start_timestamp": "2026-03-13T14:29:12-06:00",
|
||||
"end_timestamp": "2026-03-13T14:29:12-06:00",
|
||||
"markdown_size_bytes": 230631,
|
||||
"markdown_size_bytes": 253227,
|
||||
"provider": "cursoride",
|
||||
"last_updated": "2026-03-25T20:28:01Z"
|
||||
"last_updated": "2026-03-25T20:37:28Z"
|
||||
},
|
||||
"f1bb25c5-e5d4-4aad-88a3-f562ab877040": {
|
||||
"user_message_count": 1,
|
||||
|
||||
+68
-5
@@ -5,11 +5,71 @@
|
||||
|
||||
"""Character migrator: migrate animation, constraints, relations from original to replacement armature."""
|
||||
|
||||
from contextlib import contextmanager
|
||||
|
||||
import bpy
|
||||
|
||||
from ..utils import descendants, collection_containing_armature
|
||||
|
||||
|
||||
def _first_view3d_area(context):
|
||||
win = getattr(context, "window", None)
|
||||
if not win or not getattr(win, "screen", None):
|
||||
return None, None
|
||||
for area in win.screen.areas:
|
||||
if area.type == "VIEW_3D":
|
||||
return win, area
|
||||
return None, None
|
||||
|
||||
|
||||
@contextmanager
|
||||
def _rep_active_for_animlayers(context, rep):
|
||||
"""Make rep the only selected active object in Object mode so Animation Layers (als.turn_on) applies to rep.
|
||||
|
||||
Does not restore the previous selection: Anim Layers and the UI expect rep to stay active after MigNLA.
|
||||
"""
|
||||
if context is None or rep is None:
|
||||
yield
|
||||
return
|
||||
vl = context.view_layer
|
||||
win, area = _first_view3d_area(context)
|
||||
# Ops need a VIEW_3D context; selection/active still use view_layer.
|
||||
if win and area:
|
||||
with context.temp_override(window=win, area=area):
|
||||
if context.mode != "OBJECT":
|
||||
try:
|
||||
bpy.ops.object.mode_set(mode="OBJECT")
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
bpy.ops.object.select_all(action="DESELECT")
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
if context.mode != "OBJECT":
|
||||
try:
|
||||
bpy.ops.object.mode_set(mode="OBJECT")
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
bpy.ops.object.select_all(action="DESELECT")
|
||||
except Exception:
|
||||
pass
|
||||
for ob in vl.objects:
|
||||
try:
|
||||
ob.select_set(False)
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
rep.select_set(True)
|
||||
except Exception:
|
||||
pass
|
||||
vl.objects.active = rep
|
||||
if bpy.context.view_layer == vl:
|
||||
bpy.context.view_layer.objects.active = rep
|
||||
yield
|
||||
|
||||
|
||||
def get_pair_manual(context):
|
||||
"""Return (orig_armature, rep_armature) from scene props, or (None, None)."""
|
||||
props = getattr(context.scene, "dynamic_link_manager", None)
|
||||
@@ -202,9 +262,10 @@ def _duplicate_action(src_action, suffix=".rep"):
|
||||
return new_action
|
||||
|
||||
|
||||
def run_mig_nla(orig, rep, report=None):
|
||||
def run_mig_nla(orig, rep, report=None, context=None):
|
||||
"""Migrate NLA: copy tracks and strips to replacement; or mirror action slot when no NLA (MigNLA).
|
||||
Actions are duplicated so repchar has independent copies."""
|
||||
Actions are duplicated so repchar has independent copies.
|
||||
Pass context so Animation Layers mirroring runs with rep as active object."""
|
||||
if not orig.animation_data:
|
||||
return
|
||||
ad = orig.animation_data
|
||||
@@ -249,7 +310,8 @@ def run_mig_nla(orig, rep, report=None):
|
||||
setattr(rad, prop, getattr(ad, prop))
|
||||
print(f"[DLM MigNLA] set rep {prop}={getattr(ad, prop)!r}")
|
||||
_slot_debug("Rep (after)", rad)
|
||||
_mirror_als_turn_on(orig, rep)
|
||||
with _rep_active_for_animlayers(context, rep):
|
||||
_mirror_als_turn_on(orig, rep)
|
||||
if report:
|
||||
report({"INFO"}, "No NLA detected, active action (duplicated) and slot copied to Replacement Armature.")
|
||||
return
|
||||
@@ -296,7 +358,8 @@ def run_mig_nla(orig, rep, report=None):
|
||||
new_strip.use_animated_time_cyclic = strip.use_animated_time_cyclic
|
||||
new_strip.use_sync_length = strip.use_sync_length
|
||||
prev_track = new_track
|
||||
_mirror_als_turn_on(orig, rep)
|
||||
with _rep_active_for_animlayers(context, rep):
|
||||
_mirror_als_turn_on(orig, rep)
|
||||
if report:
|
||||
_debug_als_lookup(orig)
|
||||
has_als = _has_als_anywhere(orig)
|
||||
@@ -703,7 +766,7 @@ def run_full_migration(context):
|
||||
|
||||
try:
|
||||
run_copy_attr(orig, rep)
|
||||
run_mig_nla(orig, rep)
|
||||
run_mig_nla(orig, rep, context=context)
|
||||
run_mig_cust_props(orig, rep)
|
||||
run_mig_bone_const(orig, rep, orig_to_rep)
|
||||
run_retarg_relatives(orig, rep, rep_descendants, orig_to_rep)
|
||||
|
||||
+1
-1
@@ -305,7 +305,7 @@ class DLM_OT_migrator_migrate_nla(Operator):
|
||||
return {"CANCELLED"}
|
||||
try:
|
||||
from ..ops.migrator import run_mig_nla
|
||||
run_mig_nla(orig, rep, report=self.report)
|
||||
run_mig_nla(orig, rep, report=self.report, context=context)
|
||||
return {"FINISHED"}
|
||||
except Exception as e:
|
||||
self.report({"ERROR"}, str(e))
|
||||
|
||||
Reference in New Issue
Block a user