redo adaptation

This commit is contained in:
Nathan
2025-08-20 17:07:03 -06:00
parent a48b871f8b
commit 2addfc4e02
5 changed files with 302 additions and 8 deletions

View File

@@ -1073,3 +1073,118 @@ The extension is ready to be installed in Blender 4.5.0+ and should appear in th
---
_**User**_
alright, let's simplify. I restarted by using this blender development vscode addon. We should be able to build off this structure.
---
_**Assistant**_
Great idea! Using the Blender development VSCode addon will give us a much better development experience. Let me check what structure we have now and see how we can build on it.
---
<details>
<summary>Listed current directory • **6** results</summary>
| Name |
|-------|
| 📁 `.git` |
| 📄 `.gitignore` |
| 📄 `blender_manifest.toml` |
| 📄 `__init__.py` |
| 📄 `.cursorindexingignore` |
| 📁 `.specstory` |
</details>
---
Perfect! I can see you have the basic structure with the VSCode addon. Let me check what's in the `__init__.py` to see what the addon generated:
---
Read file: __init__.py
---
Great! The VSCode addon has given us a clean starting point. Now let me check the manifest to see what it generated:
---
Read file: blender_manifest.toml
---
Excellent! The VSCode addon has given us a much cleaner and more modern structure. Now let me update the manifest with your specific details and then build the core functionality. Let me start by updating the manifest:
---
<details><summary>Edit file: blender_manifest.toml</summary>
undefined
**Chunk 1**
Lines added: 5, lines removed: 5
```diff
@@ -3,9 +3,9 @@
# Example of manifest file for a Blender extension
# Change the values according to your extension
- id = "dynamic-link-manager"
- version = "1.0.0"
- name = "Dynamic-link-manager"
- tagline = "This is another extension"
- maintainer = "RaincloudTheDragon"
+ id = "dynamiclinkmanager"
+ version = "0.5.1"
+ name = "Dynamic Link Manager"
+ tagline = "Replace linked assets and characters with ease"
+ maintainer = "Nathan Lindsay"
# Supported types: "add-on", "theme"
type = "add-on"
```
</details>
---
<details><summary>Edit file: blender_manifest.toml</summary>
undefined
**Chunk 1**
Lines added: 1, lines removed: 1
```diff
@@ -16,5 +16,5 @@
# Optional list defined by Blender and server, see:
# https://docs.blender.org/manual/en/dev/advanced/extensions/tags.html
- tags = ["Animation", "Sequencer"]
+ tags = ["3D View", "Import-Export"]
blender_version_min = "4.2.0"
```
</details>
---
Now let me update the `__init__.py` with the proper addon structure:
---
---
---

View File

@@ -11,7 +11,33 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
def register(): ...
bl_info = {
"name": "Dynamic Link Manager",
"author": "Nathan Lindsay",
"version": (0, 0, 1),
"blender": (4, 5, 0),
"location": "View3D > Sidebar > Dynamic Link Manager",
"description": "Replace linked assets and characters with ease",
"warning": "",
"doc_url": "",
"category": "Import-Export",
}
import bpy
from bpy.props import StringProperty, BoolProperty, EnumProperty
from bpy.types import Panel, Operator, PropertyGroup
def unregister(): ...
# Import local modules
from . import operators
from . import ui
def register():
operators.register()
ui.register()
def unregister():
ui.unregister()
operators.unregister()
if __name__ == "__main__":
register()

View File

@@ -2,11 +2,11 @@ schema_version = "1.0.0"
# Example of manifest file for a Blender extension
# Change the values according to your extension
id = "dynamic-link-manager"
version = "1.0.0"
name = "Dynamic-link-manager"
tagline = "This is another extension"
maintainer = "RaincloudTheDragon"
id = "dynamiclinkmanager"
version = "0.0.1"
name = "Dynamic Link Manager"
tagline = "Replace linked assets and characters with ease"
maintainer = "Nathan Lindsay"
# Supported types: "add-on", "theme"
type = "add-on"
@@ -15,7 +15,7 @@ type = "add-on"
# Optional list defined by Blender and server, see:
# https://docs.blender.org/manual/en/dev/advanced/extensions/tags.html
tags = ["Animation", "Sequencer"]
tags = ["3D View", "Import-Export"]
blender_version_min = "4.2.0"
# # Optional: Blender version that the extension does not support, earlier versions are supported.

78
operators.py Normal file
View File

@@ -0,0 +1,78 @@
import bpy
import os
from bpy.types import Operator
from bpy.props import StringProperty, BoolProperty, EnumProperty
class DYNAMICLINK_OT_replace_linked_asset(Operator):
"""Replace a linked asset with a new file"""
bl_idname = "dynamiclink.replace_linked_asset"
bl_label = "Replace Linked Asset"
bl_options = {'REGISTER', 'UNDO'}
filepath: StringProperty(
name="File Path",
description="Path to the new asset file",
subtype='FILE_PATH'
)
def execute(self, context):
obj = context.active_object
if not obj:
self.report({'ERROR'}, "No object selected")
return {'CANCELLED'}
if not obj.data or not obj.data.library:
self.report({'ERROR'}, "Selected object is not linked")
return {'CANCELLED'}
try:
# Implementation will go here
self.report({'INFO'}, f"Replaced linked asset: {obj.name}")
return {'FINISHED'}
except Exception as e:
self.report({'ERROR'}, f"Failed to replace asset: {str(e)}")
return {'CANCELLED'}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'}
class DYNAMICLINK_OT_scan_linked_assets(Operator):
"""Scan scene for all linked assets"""
bl_idname = "dynamiclink.scan_linked_assets"
bl_label = "Scan Linked Assets"
def execute(self, context):
linked_assets = []
# Scan objects
for obj in bpy.data.objects:
if obj.library:
linked_assets.append({
'type': 'OBJECT',
'name': obj.name,
'library': obj.library.filepath
})
# Scan meshes
for mesh in bpy.data.meshes:
if mesh.library:
linked_assets.append({
'type': 'MESH',
'name': mesh.name,
'library': mesh.library.filepath
})
# Store results in scene properties
context.scene.dynamic_link_manager.linked_assets_count = len(linked_assets)
self.report({'INFO'}, f"Found {len(linked_assets)} linked assets")
return {'FINISHED'}
def register():
bpy.utils.register_class(DYNAMICLINK_OT_replace_linked_asset)
bpy.utils.register_class(DYNAMICLINK_OT_scan_linked_assets)
def unregister():
bpy.utils.unregister_class(DYNAMICLINK_OT_scan_linked_assets)
bpy.utils.unregister_class(DYNAMICLINK_OT_replace_linked_asset)

75
ui.py Normal file
View File

@@ -0,0 +1,75 @@
import bpy
from bpy.types import Panel, PropertyGroup
from bpy.props import IntProperty, StringProperty
class DynamicLinkManagerProperties(PropertyGroup):
linked_assets_count: IntProperty(
name="Linked Assets Count",
description="Number of linked assets found in scene",
default=0
)
selected_asset_path: StringProperty(
name="Selected Asset Path",
description="Path to the currently selected asset",
default=""
)
class DYNAMICLINK_PT_main_panel(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = 'Dynamic Link Manager'
bl_label = "Asset Replacement"
def draw(self, context):
layout = self.layout
props = context.scene.dynamic_link_manager
# Scan section
box = layout.box()
box.label(text="Scene Analysis")
row = box.row()
row.operator("dynamiclink.scan_linked_assets", text="Scan Linked Assets")
row.label(text=f"Found: {props.linked_assets_count}")
# Asset replacement section
box = layout.box()
box.label(text="Asset Replacement")
obj = context.active_object
if obj:
box.label(text=f"Selected: {obj.name}")
if obj.library:
box.label(text=f"Linked from: {obj.library.filepath}")
row = box.row()
row.operator("dynamiclink.replace_linked_asset", text="Replace Asset")
else:
box.label(text="Not a linked asset")
else:
box.label(text="No object selected")
# Batch operations section
box = layout.box()
box.label(text="Batch Operations")
row = box.row()
row.operator("dynamiclink.scan_linked_assets", text="Refresh Scan")
# Settings section
box = layout.box()
box.label(text="Settings")
row = box.row()
row.prop(props, "selected_asset_path", text="Asset Path")
def register():
bpy.utils.register_class(DynamicLinkManagerProperties)
bpy.utils.register_class(DYNAMICLINK_PT_main_panel)
# Register properties to scene
bpy.types.Scene.dynamic_link_manager = bpy.props.PointerProperty(type=DynamicLinkManagerProperties)
def unregister():
# Unregister properties from scene
del bpy.types.Scene.dynamic_link_manager
bpy.utils.unregister_class(DYNAMICLINK_PT_main_panel)
bpy.utils.unregister_class(DynamicLinkManagerProperties)