Update
This commit is contained in:
@@ -7,7 +7,7 @@
|
|||||||
## 📁 目录结构说明
|
## 📁 目录结构说明
|
||||||
|
|
||||||
```
|
```
|
||||||
template/plugins/maya/2023/
|
template_plugins/maya/2023/
|
||||||
├── shelves/ # 工具架文件(.mel 格式)
|
├── shelves/ # 工具架文件(.mel 格式)
|
||||||
├── scripts/ # Python/MEL 脚本
|
├── scripts/ # Python/MEL 脚本
|
||||||
├── plug-ins/ # Maya 插件文件(.py 或 .mll)
|
├── plug-ins/ # Maya 插件文件(.py 或 .mll)
|
||||||
|
|||||||
@@ -54,6 +54,11 @@
|
|||||||
- 智能清理机制(退出时自动清理)
|
- 智能清理机制(退出时自动清理)
|
||||||
- 支持多版本 Maya(2023、2025+)
|
- 支持多版本 Maya(2023、2025+)
|
||||||
- 工具架重载脚本(开发调试用)
|
- 工具架重载脚本(开发调试用)
|
||||||
|
- **Nexus 插件包**
|
||||||
|
- 完整的 Maya 插件模板
|
||||||
|
- 三个专业工具架(Modeling、Rigging、Animation)
|
||||||
|
- 模块化工具包结构
|
||||||
|
- 批量挤出工具(Batch Extrusion)
|
||||||
- **Substance Painter 插件支持**
|
- **Substance Painter 插件支持**
|
||||||
- **可扩展架构**(BasePlugin 基类)
|
- **可扩展架构**(BasePlugin 基类)
|
||||||
|
|
||||||
@@ -226,8 +231,7 @@ NexusLauncher 为 Maya 提供了完整的插件集成系统:
|
|||||||
{
|
{
|
||||||
"app_plugins": {
|
"app_plugins": {
|
||||||
"C:/Program Files/Autodesk/Maya2023/bin/maya.exe": {
|
"C:/Program Files/Autodesk/Maya2023/bin/maya.exe": {
|
||||||
"maya_plugin_path": "E:/NexusLauncher/template/plugins/maya/2023/plug-ins",
|
"maya_plugin_path": "E:/NexusLauncher/template_plugins/maya"
|
||||||
"maya_shelf_path": "E:/NexusLauncher/template/plugins/maya/2023/shelves"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -236,19 +240,16 @@ NexusLauncher 为 Maya 提供了完整的插件集成系统:
|
|||||||
### 插件目录结构
|
### 插件目录结构
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
template/plugins/maya/
|
template_plugins/maya/
|
||||||
├── 2023/
|
└── 2023/
|
||||||
│ ├── scripts/
|
├── scripts/
|
||||||
│ │ └── userSetup.py # Maya 启动脚本
|
│ └── userSetup.py # Maya 启动脚本
|
||||||
│ ├── shelves/
|
├── shelves/
|
||||||
│ │ └── shelf_NexusLauncher.mel # 工具架定义
|
│ └── shelf_*.mel # 工具架定义
|
||||||
│ ├── plug-ins/
|
├── plug-ins/
|
||||||
│ │ └── nexus_example_plugin.py # 示例插件
|
│ └── *.py # 插件文件
|
||||||
│ ├── icons/
|
└── icons/
|
||||||
│ │ └── *.png # 工具架图标
|
└── *.png # 工具架图标
|
||||||
│ └── RELOAD_SHELF.py # 工具架重载脚本(开发用)
|
|
||||||
└── 2025/
|
|
||||||
└── (相同结构)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 开发调试
|
### 开发调试
|
||||||
@@ -256,14 +257,11 @@ template/plugins/maya/
|
|||||||
在 Maya Script Editor 中运行重载脚本:
|
在 Maya Script Editor 中运行重载脚本:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# 方法 1: 导入并运行
|
|
||||||
import sys
|
import sys
|
||||||
sys.path.append("E:/NexusLauncher/template/plugins/maya/2023")
|
sys.path.append("E:/NexusLauncher/template_plugins/maya/2023")
|
||||||
import RELOAD_SHELF
|
import RELOAD_SHELF
|
||||||
|
reload(RELOAD_SHELF)
|
||||||
RELOAD_SHELF.reload_shelf()
|
RELOAD_SHELF.reload_shelf()
|
||||||
|
|
||||||
# 方法 2: 直接执行
|
|
||||||
exec(open("E:/NexusLauncher/template/plugins/maya/2023/RELOAD_SHELF.py").read())
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 工作原理
|
### 工作原理
|
||||||
@@ -339,6 +337,15 @@ NexusLauncher/
|
|||||||
│ ├── task_panel.py # 任务面板
|
│ ├── task_panel.py # 任务面板
|
||||||
│ ├── node.py # 节点类
|
│ ├── node.py # 节点类
|
||||||
│ └── subfolder_editor.py # 子文件夹编辑器
|
│ └── subfolder_editor.py # 子文件夹编辑器
|
||||||
|
├── plugins/ # 插件系统
|
||||||
|
│ ├── __init__.py
|
||||||
|
│ ├── base_plugin.py # 插件基类
|
||||||
|
│ ├── plugin_manager.py # 插件管理器
|
||||||
|
│ ├── maya_plugin.py # Maya 插件
|
||||||
|
│ └── substance_painter_plugin.py # SP 插件
|
||||||
|
├── template_plugins/ # 插件模板
|
||||||
|
│ └── maya/ # Maya 插件模板
|
||||||
|
│ └── 2023/
|
||||||
├── icons/ # 图标资源
|
├── icons/ # 图标资源
|
||||||
│ ├── NexusLauncher.ico # 应用图标
|
│ ├── NexusLauncher.ico # 应用图标
|
||||||
│ └── *.png # 预设图标
|
│ └── *.png # 预设图标
|
||||||
@@ -428,6 +435,22 @@ A: 请查看以下文档:
|
|||||||
|
|
||||||
## 更新日志
|
## 更新日志
|
||||||
|
|
||||||
|
### v2.2.0 (2025-11-23) - 当前版本 ⭐
|
||||||
|
- 🎨 **Nexus 插件包**: 全新的 Maya 插件模板
|
||||||
|
- 三个专业工具架(Nexus_Modeling、Nexus_Rigging、Nexus_Animation)
|
||||||
|
- 模块化工具包结构(modeling_tools、rigging_tools、animation_tools)
|
||||||
|
- 批量挤出工具(Batch Extrusion)集成
|
||||||
|
- 完整的插件系统(nexus_plugin.py)
|
||||||
|
- 详细的文档和重载脚本
|
||||||
|
- 🔧 **插件系统增强**:
|
||||||
|
- 支持多插件包共存
|
||||||
|
- 统一的环境变量配置
|
||||||
|
- 改进的工具架加载机制
|
||||||
|
- 📝 **文档更新**:
|
||||||
|
- 更新 README.md 添加 Nexus 插件包说明
|
||||||
|
- 完善插件配置方法
|
||||||
|
- 添加开发调试指南
|
||||||
|
|
||||||
### v2.1.0 (2025-11-22)
|
### v2.1.0 (2025-11-22)
|
||||||
- 🔌 **Maya 插件系统**: 完整的 Maya 插件集成
|
- 🔌 **Maya 插件系统**: 完整的 Maya 插件集成
|
||||||
- 自动设置环境变量(MAYA_SHELF_PATH、MAYA_PLUG_IN_PATH、XBMLANGPATH 等)
|
- 自动设置环境变量(MAYA_SHELF_PATH、MAYA_PLUG_IN_PATH、XBMLANGPATH 等)
|
||||||
|
|||||||
42
template_plugins/maya/2023/README.md
Normal file
42
template_plugins/maya/2023/README.md
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
# Maya 2023 Plugin Directory Structure
|
||||||
|
|
||||||
|
## Directory Description
|
||||||
|
|
||||||
|
- **shelves/** - Shelf files (.mel format)
|
||||||
|
- shelf_NexusLauncher.mel - NexusLauncher shelf
|
||||||
|
|
||||||
|
- **scripts/** - Python/MEL scripts
|
||||||
|
- userSetup.py - Automatically executed when Maya starts
|
||||||
|
- nexus_test.py - Test script
|
||||||
|
|
||||||
|
- **plug-ins/** - Maya plugin files (.py or .mll)
|
||||||
|
- Place Maya plugin files here
|
||||||
|
|
||||||
|
- **icons/** - Tool icons
|
||||||
|
- Place icon files used by shelf buttons here
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
1. Configure in NexusLauncher's config.json:
|
||||||
|
```json
|
||||||
|
"maya_plugin_path": "E:/Zoroot/Dev/NexusLauncher/template/plugins/maya"
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Start Maya 2023, the system will automatically:
|
||||||
|
- Load NexusLauncher shelf
|
||||||
|
- Execute userSetup.py
|
||||||
|
- Set correct environment variables
|
||||||
|
|
||||||
|
3. Testing:
|
||||||
|
- Check if "NexusLauncher" shelf appears
|
||||||
|
- Click the "Test" button
|
||||||
|
- A confirmation dialog should appear
|
||||||
|
|
||||||
|
## Environment Variables
|
||||||
|
|
||||||
|
Automatically set on startup:
|
||||||
|
- MAYA_SHELF_PATH - Points to shelves directory
|
||||||
|
- MAYA_SCRIPT_PATH - Points to scripts directory
|
||||||
|
- PYTHONPATH - Points to scripts directory
|
||||||
|
- MAYA_PLUG_IN_PATH - Points to plug-ins directory
|
||||||
|
- XBMLANGPATH - Points to icons directory
|
||||||
117
template_plugins/maya/2023/RELOAD_SHELF.py
Normal file
117
template_plugins/maya/2023/RELOAD_SHELF.py
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Shelf Reload Script
|
||||||
|
Run this script in Maya Script Editor to reload NexusLauncher shelf
|
||||||
|
"""
|
||||||
|
import maya.cmds as cmds
|
||||||
|
import maya.mel as mel
|
||||||
|
|
||||||
|
|
||||||
|
def reload_shelf():
|
||||||
|
"""Reload NexusLauncher shelf"""
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("Reloading NexusLauncher Shelf")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
# 1. Delete old shelf
|
||||||
|
if cmds.shelfLayout('NexusLauncher', exists=True):
|
||||||
|
old_buttons = cmds.shelfLayout('NexusLauncher', query=True, childArray=True) or []
|
||||||
|
print(f"[1/4] Deleting old shelf (had {len(old_buttons)} button(s))...")
|
||||||
|
cmds.deleteUI('NexusLauncher', layout=True)
|
||||||
|
print(" ✓ Old shelf deleted")
|
||||||
|
else:
|
||||||
|
print("[1/4] No existing shelf found")
|
||||||
|
|
||||||
|
# 2. Reload shelf (using new method)
|
||||||
|
import os
|
||||||
|
shelf_paths = os.environ.get('MAYA_SHELF_PATH', '')
|
||||||
|
|
||||||
|
# Find shelf file
|
||||||
|
shelf_file_found = None
|
||||||
|
if shelf_paths:
|
||||||
|
path_separator = ';' if os.name == 'nt' else ':'
|
||||||
|
for shelf_path in shelf_paths.split(path_separator):
|
||||||
|
shelf_file = os.path.join(shelf_path.strip(), "shelf_NexusLauncher.mel")
|
||||||
|
if os.path.exists(shelf_file):
|
||||||
|
shelf_file_found = shelf_file.replace("\\", "/")
|
||||||
|
break
|
||||||
|
|
||||||
|
if not shelf_file_found:
|
||||||
|
print("[2/4] ✗ Could not find shelf_NexusLauncher.mel in MAYA_SHELF_PATH")
|
||||||
|
return False
|
||||||
|
|
||||||
|
print(f"[2/4] Loading shelf from: {shelf_file_found}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Disable auto-save
|
||||||
|
mel.eval('optionVar -intValue "saveLastLoadedShelf" 0;')
|
||||||
|
|
||||||
|
# Create shelf layout
|
||||||
|
mel.eval('''
|
||||||
|
global string $gShelfTopLevel;
|
||||||
|
setParent $gShelfTopLevel;
|
||||||
|
shelfLayout -cellWidth 35 -cellHeight 34 NexusLauncher;
|
||||||
|
''')
|
||||||
|
|
||||||
|
# Set parent and execute shelf script
|
||||||
|
mel.eval('setParent NexusLauncher;')
|
||||||
|
mel.eval(f'source "{shelf_file_found}";')
|
||||||
|
mel.eval('shelf_NexusLauncher();')
|
||||||
|
|
||||||
|
print(" ✓ Shelf loaded (temporary, won't be saved)")
|
||||||
|
except Exception as e:
|
||||||
|
print(f" ✗ Failed to load shelf: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 3. Verify shelf
|
||||||
|
if cmds.shelfLayout('NexusLauncher', exists=True):
|
||||||
|
print("[3/4] Verifying shelf...")
|
||||||
|
buttons = cmds.shelfLayout('NexusLauncher', query=True, childArray=True) or []
|
||||||
|
|
||||||
|
if buttons:
|
||||||
|
print(f" ✓ Shelf has {len(buttons)} button(s)")
|
||||||
|
|
||||||
|
# Display button details
|
||||||
|
for i, btn in enumerate(buttons, 1):
|
||||||
|
try:
|
||||||
|
label = cmds.shelfButton(btn, query=True, label=True)
|
||||||
|
annotation = cmds.shelfButton(btn, query=True, annotation=True)
|
||||||
|
source_type = cmds.shelfButton(btn, query=True, sourceType=True)
|
||||||
|
print(f" Button {i}: {label} ({source_type})")
|
||||||
|
print(f" {annotation}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f" ✗ Error querying button {i}: {e}")
|
||||||
|
else:
|
||||||
|
print(" ⚠ Warning: Shelf exists but has no buttons!")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
print("[3/4] ✗ Shelf not found after loading!")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 4. Test button command
|
||||||
|
print("[4/4] Testing button command...")
|
||||||
|
try:
|
||||||
|
import nexus_test
|
||||||
|
print(" ✓ nexus_test module imported")
|
||||||
|
|
||||||
|
# Run test
|
||||||
|
print(" Running test...")
|
||||||
|
nexus_test.run_test()
|
||||||
|
print(" ✓ Test executed successfully!")
|
||||||
|
except Exception as e:
|
||||||
|
print(f" ✗ Test failed: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
return False
|
||||||
|
|
||||||
|
print("=" * 60)
|
||||||
|
print("✓ Shelf reload complete!")
|
||||||
|
print("=" * 60 + "\n")
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
reload_shelf()
|
||||||
BIN
template_plugins/maya/2023/icons/.alg_meta/batchextrusion.png
Normal file
BIN
template_plugins/maya/2023/icons/.alg_meta/batchextrusion.png
Normal file
Binary file not shown.
BIN
template_plugins/maya/2023/icons/.alg_meta/nexus_test.png
Normal file
BIN
template_plugins/maya/2023/icons/.alg_meta/nexus_test.png
Normal file
Binary file not shown.
BIN
template_plugins/maya/2023/icons/batchextrusion.png
Normal file
BIN
template_plugins/maya/2023/icons/batchextrusion.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
BIN
template_plugins/maya/2023/icons/nexus_test.png
Normal file
BIN
template_plugins/maya/2023/icons/nexus_test.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
55
template_plugins/maya/2023/plug-ins/nexus_example_plugin.py
Normal file
55
template_plugins/maya/2023/plug-ins/nexus_example_plugin.py
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
'''
|
||||||
|
NexusLauncher Example Plugin
|
||||||
|
Example plugin - demonstrates how to create a Maya plugin
|
||||||
|
'''
|
||||||
|
import sys
|
||||||
|
import maya.api.OpenMaya as om
|
||||||
|
|
||||||
|
|
||||||
|
def maya_useNewAPI():
|
||||||
|
'''Tell Maya to use Maya Python API 2.0'''
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class NexusExampleCmd(om.MPxCommand):
|
||||||
|
'''Example command'''
|
||||||
|
|
||||||
|
kPluginCmdName = 'nexusExample'
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
om.MPxCommand.__init__(self)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def cmdCreator():
|
||||||
|
return NexusExampleCmd()
|
||||||
|
|
||||||
|
def doIt(self, args):
|
||||||
|
print('[NexusLauncher] Example plugin command executed!')
|
||||||
|
om.MGlobal.displayInfo('NexusLauncher Example Plugin is working!')
|
||||||
|
|
||||||
|
|
||||||
|
def initializePlugin(plugin):
|
||||||
|
'''Initialize plugin'''
|
||||||
|
pluginFn = om.MFnPlugin(plugin, 'NexusLauncher', '1.0', 'Any')
|
||||||
|
try:
|
||||||
|
pluginFn.registerCommand(
|
||||||
|
NexusExampleCmd.kPluginCmdName,
|
||||||
|
NexusExampleCmd.cmdCreator
|
||||||
|
)
|
||||||
|
print('[NexusLauncher] Example plugin loaded successfully')
|
||||||
|
except:
|
||||||
|
sys.stderr.write(f'Failed to register command: {NexusExampleCmd.kPluginCmdName}')
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
def uninitializePlugin(plugin):
|
||||||
|
'''Uninitialize plugin'''
|
||||||
|
pluginFn = om.MFnPlugin(plugin)
|
||||||
|
try:
|
||||||
|
pluginFn.deregisterCommand(NexusExampleCmd.kPluginCmdName)
|
||||||
|
print('[NexusLauncher] Example plugin unloaded')
|
||||||
|
except:
|
||||||
|
sys.stderr.write(f'Failed to deregister command: {NexusExampleCmd.kPluginCmdName}')
|
||||||
|
raise
|
||||||
30
template_plugins/maya/2023/scripts/nexus_test.py
Normal file
30
template_plugins/maya/2023/scripts/nexus_test.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
NexusLauncher Test Script
|
||||||
|
Test script - verify plugin system is working properly
|
||||||
|
"""
|
||||||
|
import maya.cmds as cmds
|
||||||
|
|
||||||
|
|
||||||
|
def run_test():
|
||||||
|
"""Run test"""
|
||||||
|
result = cmds.confirmDialog(
|
||||||
|
title='NexusLauncher Test',
|
||||||
|
message='NexusLauncher plugin system is working!\n\nPlugin system is running normally!',
|
||||||
|
button=['OK'],
|
||||||
|
defaultButton='OK',
|
||||||
|
cancelButton='OK',
|
||||||
|
dismissString='OK'
|
||||||
|
)
|
||||||
|
|
||||||
|
print("=" * 50)
|
||||||
|
print("[NexusLauncher] Test executed successfully!")
|
||||||
|
print("[NexusLauncher] Test executed successfully!")
|
||||||
|
print("=" * 50)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
run_test()
|
||||||
222
template_plugins/maya/2023/scripts/userSetup.py
Normal file
222
template_plugins/maya/2023/scripts/userSetup.py
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Maya Startup Script
|
||||||
|
Automatically executed when Maya starts
|
||||||
|
"""
|
||||||
|
import maya.cmds as cmds
|
||||||
|
import maya.mel as mel
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def load_nexus_shelf():
|
||||||
|
"""Load NexusLauncher shelf (force refresh)"""
|
||||||
|
try:
|
||||||
|
# Get shelf path from environment variable (may contain multiple paths separated by semicolons)
|
||||||
|
shelf_paths = os.environ.get('MAYA_SHELF_PATH', '')
|
||||||
|
|
||||||
|
if not shelf_paths:
|
||||||
|
print("[NexusLauncher] MAYA_SHELF_PATH not set, trying alternative method...")
|
||||||
|
# Fallback method: infer from current script directory
|
||||||
|
try:
|
||||||
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
shelf_paths = os.path.join(os.path.dirname(script_dir), "shelves")
|
||||||
|
except:
|
||||||
|
print("[NexusLauncher] Could not determine shelf path, skipping shelf load")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Split multiple paths (Windows uses semicolon, Unix uses colon)
|
||||||
|
path_separator = ';' if os.name == 'nt' else ':'
|
||||||
|
shelf_path_list = shelf_paths.split(path_separator)
|
||||||
|
|
||||||
|
# First check if shelf file exists
|
||||||
|
shelf_file_found = None
|
||||||
|
for shelf_path in shelf_path_list:
|
||||||
|
shelf_path = shelf_path.strip()
|
||||||
|
if not shelf_path:
|
||||||
|
continue
|
||||||
|
|
||||||
|
shelf_file = os.path.join(shelf_path, "shelf_NexusLauncher.mel")
|
||||||
|
shelf_file = shelf_file.replace("\\", "/")
|
||||||
|
|
||||||
|
print(f"[NexusLauncher] Checking: {shelf_file}")
|
||||||
|
|
||||||
|
if os.path.exists(shelf_file):
|
||||||
|
shelf_file_found = shelf_file
|
||||||
|
print(f"[NexusLauncher] ✓ Found shelf file: {shelf_file}")
|
||||||
|
break
|
||||||
|
|
||||||
|
# If shelf file not found, skip loading
|
||||||
|
if not shelf_file_found:
|
||||||
|
print("[NexusLauncher] ✗ Could not find shelf_NexusLauncher.mel in any MAYA_SHELF_PATH")
|
||||||
|
print("[NexusLauncher] Skipping shelf load (no file found)")
|
||||||
|
return
|
||||||
|
|
||||||
|
# After finding shelf file, delete old one before loading new one
|
||||||
|
# Note: loadNewShelf does not automatically delete shelf with same name, must delete manually
|
||||||
|
existing_shelves = cmds.lsUI(type='shelfLayout') or []
|
||||||
|
if 'NexusLauncher' in existing_shelves:
|
||||||
|
print("[NexusLauncher] Removing existing shelf before reload...")
|
||||||
|
try:
|
||||||
|
cmds.deleteUI('NexusLauncher', layout=True)
|
||||||
|
print("[NexusLauncher] ✓ Removed old shelf")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[NexusLauncher] Warning: Could not remove old shelf: {e}")
|
||||||
|
|
||||||
|
# Key: Use custom method to load shelf, avoid loadNewShelf auto-save
|
||||||
|
print(f"[NexusLauncher] Loading shelf from: {shelf_file_found}")
|
||||||
|
|
||||||
|
# Method: Use mel.eval to execute shelf file, then immediately delete saved config
|
||||||
|
try:
|
||||||
|
# 1. First disable auto-save (attempt)
|
||||||
|
mel.eval('optionVar -intValue "saveLastLoadedShelf" 0;')
|
||||||
|
|
||||||
|
# 2. Create shelf layout
|
||||||
|
mel.eval('''
|
||||||
|
global string $gShelfTopLevel;
|
||||||
|
if (`shelfLayout -exists NexusLauncher`) {
|
||||||
|
deleteUI -layout NexusLauncher;
|
||||||
|
}
|
||||||
|
setParent $gShelfTopLevel;
|
||||||
|
shelfLayout -cellWidth 35 -cellHeight 34 NexusLauncher;
|
||||||
|
''')
|
||||||
|
print(f"[NexusLauncher] ✓ Created shelf layout")
|
||||||
|
|
||||||
|
# 3. Set parent to shelf, then execute shelf file to create buttons
|
||||||
|
mel.eval('setParent NexusLauncher;')
|
||||||
|
mel.eval(f'source "{shelf_file_found}";')
|
||||||
|
mel.eval('shelf_NexusLauncher();')
|
||||||
|
print(f"[NexusLauncher] ✓ Executed shelf script")
|
||||||
|
|
||||||
|
# 4. Verify shelf
|
||||||
|
if cmds.shelfLayout('NexusLauncher', exists=True):
|
||||||
|
new_buttons = cmds.shelfLayout('NexusLauncher', query=True, childArray=True) or []
|
||||||
|
if new_buttons:
|
||||||
|
print(f"[NexusLauncher] ✓ Shelf loaded successfully with {len(new_buttons)} button(s)")
|
||||||
|
|
||||||
|
# 5. Ensure no config file is saved
|
||||||
|
try:
|
||||||
|
maya_version = cmds.about(version=True).split()[0]
|
||||||
|
maya_app_dir = os.environ.get('MAYA_APP_DIR', '')
|
||||||
|
if maya_app_dir:
|
||||||
|
shelf_config = os.path.join(maya_app_dir, maya_version, "prefs", "shelves", "shelf_NexusLauncher.mel")
|
||||||
|
if os.path.exists(shelf_config):
|
||||||
|
os.remove(shelf_config)
|
||||||
|
print(f"[NexusLauncher] ✓ Removed auto-saved config")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[NexusLauncher] Warning: {e}")
|
||||||
|
|
||||||
|
print(f"[NexusLauncher] ✓ Shelf is temporary (won't be saved)")
|
||||||
|
else:
|
||||||
|
print("[NexusLauncher] ⚠ Warning: Shelf has no buttons!")
|
||||||
|
else:
|
||||||
|
print("[NexusLauncher] ✗ Error: Shelf failed to load")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[NexusLauncher] Error loading shelf: {e}")
|
||||||
|
import traceback
|
||||||
|
print(traceback.format_exc())
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
import traceback
|
||||||
|
print(f"[NexusLauncher] Failed to load shelf: {e}")
|
||||||
|
print(traceback.format_exc())
|
||||||
|
|
||||||
|
|
||||||
|
def load_nexus_plugins():
|
||||||
|
"""Load NexusLauncher plugins"""
|
||||||
|
try:
|
||||||
|
# Get plugin path
|
||||||
|
plugin_path = os.environ.get('MAYA_PLUG_IN_PATH', '')
|
||||||
|
|
||||||
|
if not plugin_path:
|
||||||
|
print("[NexusLauncher] MAYA_PLUG_IN_PATH not set, skipping plugin load")
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"[NexusLauncher] MAYA_PLUG_IN_PATH: {plugin_path}")
|
||||||
|
|
||||||
|
# Load example plugin
|
||||||
|
plugin_file = "nexus_example_plugin.py"
|
||||||
|
|
||||||
|
if cmds.pluginInfo(plugin_file, query=True, loaded=True):
|
||||||
|
print(f"[NexusLauncher] Plugin already loaded: {plugin_file}")
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
cmds.loadPlugin(plugin_file)
|
||||||
|
print(f"[NexusLauncher] ✓ Loaded plugin: {plugin_file}")
|
||||||
|
|
||||||
|
# Set to auto-load
|
||||||
|
cmds.pluginInfo(plugin_file, edit=True, autoload=True)
|
||||||
|
print(f"[NexusLauncher] ✓ Set plugin to auto-load")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[NexusLauncher] Failed to load plugin {plugin_file}: {e}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[NexusLauncher] Error loading plugins: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
def print_environment():
|
||||||
|
"""Print environment variables (for debugging)"""
|
||||||
|
print("=" * 60)
|
||||||
|
print("[NexusLauncher] Environment Variables:")
|
||||||
|
print(f" MAYA_SHELF_PATH: {os.environ.get('MAYA_SHELF_PATH', 'Not set')}")
|
||||||
|
print(f" MAYA_SCRIPT_PATH: {os.environ.get('MAYA_SCRIPT_PATH', 'Not set')}")
|
||||||
|
print(f" PYTHONPATH: {os.environ.get('PYTHONPATH', 'Not set')}")
|
||||||
|
print(f" MAYA_PLUG_IN_PATH: {os.environ.get('MAYA_PLUG_IN_PATH', 'Not set')}")
|
||||||
|
print(f" XBMLANGPATH: {os.environ.get('XBMLANGPATH', 'Not set')}")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
|
||||||
|
def cleanup_on_exit():
|
||||||
|
"""Clean up NexusLauncher shelf config file when Maya exits"""
|
||||||
|
try:
|
||||||
|
# Check if launched by NexusLauncher
|
||||||
|
shelf_paths = os.environ.get('MAYA_SHELF_PATH', '')
|
||||||
|
|
||||||
|
is_nexus_launcher = False
|
||||||
|
if shelf_paths:
|
||||||
|
path_separator = ';' if os.name == 'nt' else ':'
|
||||||
|
for shelf_path in shelf_paths.split(path_separator):
|
||||||
|
shelf_file = os.path.join(shelf_path.strip(), "shelf_NexusLauncher.mel")
|
||||||
|
if os.path.exists(shelf_file):
|
||||||
|
is_nexus_launcher = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not is_nexus_launcher:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Delete config file (if exists)
|
||||||
|
try:
|
||||||
|
maya_version = cmds.about(version=True).split()[0]
|
||||||
|
maya_app_dir = os.environ.get('MAYA_APP_DIR', '')
|
||||||
|
|
||||||
|
if maya_app_dir:
|
||||||
|
shelf_config = os.path.join(maya_app_dir, maya_version, "prefs", "shelves", "shelf_NexusLauncher.mel")
|
||||||
|
if os.path.exists(shelf_config):
|
||||||
|
os.remove(shelf_config)
|
||||||
|
print(f"[NexusLauncher] ✓ Cleaned up shelf config on exit")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[NexusLauncher] Warning: Could not clean up shelf config: {e}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[NexusLauncher] Error during cleanup: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
def register_exit_callback():
|
||||||
|
"""Register cleanup callback on exit"""
|
||||||
|
try:
|
||||||
|
# Use scriptJob to execute cleanup when Maya exits
|
||||||
|
cmds.scriptJob(event=["quitApplication", cleanup_on_exit], protected=True)
|
||||||
|
print("[NexusLauncher] ✓ Registered exit cleanup callback")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[NexusLauncher] Warning: Could not register exit callback: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
# Execute after Maya startup completes
|
||||||
|
cmds.evalDeferred(load_nexus_shelf)
|
||||||
|
cmds.evalDeferred(load_nexus_plugins)
|
||||||
|
cmds.evalDeferred(print_environment)
|
||||||
|
cmds.evalDeferred(register_exit_callback)
|
||||||
|
|
||||||
|
print("[NexusLauncher] userSetup.py executed")
|
||||||
78
template_plugins/maya/2023/shelves/shelf_NexusLauncher.mel
Normal file
78
template_plugins/maya/2023/shelves/shelf_NexusLauncher.mel
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
global proc shelf_NexusLauncher () {
|
||||||
|
global string $gBuffStr;
|
||||||
|
global string $gBuffStr0;
|
||||||
|
global string $gBuffStr1;
|
||||||
|
|
||||||
|
|
||||||
|
shelfButton
|
||||||
|
-enableCommandRepeat 1
|
||||||
|
-flexibleWidthType 3
|
||||||
|
-flexibleWidthValue 32
|
||||||
|
-enable 1
|
||||||
|
-width 35
|
||||||
|
-height 34
|
||||||
|
-manage 1
|
||||||
|
-visible 1
|
||||||
|
-preventOverride 0
|
||||||
|
-annotation "NexusLauncher Test - Click to verify plugin system"
|
||||||
|
-enableBackground 0
|
||||||
|
-backgroundColor 0 0 0
|
||||||
|
-highlightColor 0.321569 0.521569 0.65098
|
||||||
|
-align "center"
|
||||||
|
-label "NL"
|
||||||
|
-labelOffset 0
|
||||||
|
-rotation 0
|
||||||
|
-flipX 0
|
||||||
|
-flipY 0
|
||||||
|
-useAlpha 1
|
||||||
|
-font "boldLabelFont"
|
||||||
|
-imageOverlayLabel "NL"
|
||||||
|
-overlayLabelColor 1 1 1
|
||||||
|
-overlayLabelBackColor 0.2 0.5 0.8 0.9
|
||||||
|
-image "nexus_test.png"
|
||||||
|
-image1 "nexus_test.png"
|
||||||
|
-style "iconOnly"
|
||||||
|
-marginWidth 0
|
||||||
|
-marginHeight 1
|
||||||
|
-command "import nexus_test\nnexus_test.run_test()"
|
||||||
|
-sourceType "python"
|
||||||
|
-commandRepeatable 1
|
||||||
|
-flat 1
|
||||||
|
;
|
||||||
|
shelfButton
|
||||||
|
-enableCommandRepeat 1
|
||||||
|
-flexibleWidthType 3
|
||||||
|
-flexibleWidthValue 32
|
||||||
|
-enable 1
|
||||||
|
-width 35
|
||||||
|
-height 34
|
||||||
|
-manage 1
|
||||||
|
-visible 1
|
||||||
|
-preventOverride 0
|
||||||
|
-annotation "Batch Extrusion - Create shell mesh layers with vertex colors"
|
||||||
|
-enableBackground 0
|
||||||
|
-backgroundColor 0 0 0
|
||||||
|
-highlightColor 0.321569 0.521569 0.65098
|
||||||
|
-align "center"
|
||||||
|
-label "BE"
|
||||||
|
-labelOffset 0
|
||||||
|
-rotation 0
|
||||||
|
-flipX 0
|
||||||
|
-flipY 0
|
||||||
|
-useAlpha 1
|
||||||
|
-font "boldLabelFont"
|
||||||
|
-imageOverlayLabel "BE"
|
||||||
|
-overlayLabelColor 1 1 1
|
||||||
|
-overlayLabelBackColor 0.8 0.4 0.2 0.9
|
||||||
|
-image "batchextrusion.png"
|
||||||
|
-image1 "batchextrusion.png"
|
||||||
|
-style "iconOnly"
|
||||||
|
-marginWidth 0
|
||||||
|
-marginHeight 1
|
||||||
|
-command "import batchextrusion\nbatchextrusion.show_batch_extrusion_ui()"
|
||||||
|
-sourceType "python"
|
||||||
|
-commandRepeatable 1
|
||||||
|
-flat 1
|
||||||
|
;
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user