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
|
||||
# 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
|
||||
# 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
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