redo adaptation
This commit is contained in:
@@ -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:
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|||||||
30
__init__.py
30
__init__.py
@@ -11,7 +11,33 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# 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()
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ schema_version = "1.0.0"
|
|||||||
|
|
||||||
# Example of manifest file for a Blender extension
|
# Example of manifest file for a Blender extension
|
||||||
# Change the values according to your extension
|
# Change the values according to your extension
|
||||||
id = "dynamic-link-manager"
|
id = "dynamiclinkmanager"
|
||||||
version = "1.0.0"
|
version = "0.0.1"
|
||||||
name = "Dynamic-link-manager"
|
name = "Dynamic Link Manager"
|
||||||
tagline = "This is another extension"
|
tagline = "Replace linked assets and characters with ease"
|
||||||
maintainer = "RaincloudTheDragon"
|
maintainer = "Nathan Lindsay"
|
||||||
# Supported types: "add-on", "theme"
|
# Supported types: "add-on", "theme"
|
||||||
type = "add-on"
|
type = "add-on"
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ type = "add-on"
|
|||||||
|
|
||||||
# Optional list defined by Blender and server, see:
|
# Optional list defined by Blender and server, see:
|
||||||
# https://docs.blender.org/manual/en/dev/advanced/extensions/tags.html
|
# 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"
|
blender_version_min = "4.2.0"
|
||||||
# # Optional: Blender version that the extension does not support, earlier versions are supported.
|
# # Optional: Blender version that the extension does not support, earlier versions are supported.
|
||||||
|
|||||||
78
operators.py
Normal file
78
operators.py
Normal 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
75
ui.py
Normal 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)
|
||||||
Reference in New Issue
Block a user