This commit is contained in:
2025-11-23 20:41:50 +08:00
commit f7d5b7be07
65 changed files with 14986 additions and 0 deletions

245
plugins/maya.py Normal file
View File

@@ -0,0 +1,245 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Maya 插件启动模块
负责检测 Maya 版本并设置正确的插件路径
"""
import os
import re
import subprocess
from typing import Dict, Optional, Tuple, List
# 尝试导入 Qt使用 Qt.py 模块实现跨版本兼容
try:
from .Qt import QtWidgets
QMessageBox = QtWidgets.QMessageBox
HAS_QT = True
except ImportError:
HAS_QT = False
QMessageBox = None
class MayaLauncher:
"""Maya 启动器"""
def __init__(self, maya_exe_path: str, plugin_base_path: str):
"""
初始化 Maya 启动器
Args:
maya_exe_path: Maya 可执行文件路径
plugin_base_path: 插件基础路径(不含版本号)
"""
self.maya_exe_path = maya_exe_path
self.plugin_base_path = plugin_base_path
self.maya_version = self._detect_maya_version()
def _detect_maya_version(self) -> Optional[str]:
"""从 Maya 路径中检测版本号
支持的格式:
- Maya2023 -> 2023
- Maya2023.2 -> 2023
- Maya2025.0.1 -> 2025
Returns:
主版本号字符串,如 "2023", "2025" 等,如果检测失败返回 None
"""
# 从路径中提取版本号(支持 Maya2023, Maya2023.2, Maya2025.0.1 等格式)
match = re.search(r'Maya(\d{4})(?:\.\d+)*', self.maya_exe_path, re.IGNORECASE)
if match:
version = match.group(1) # 只取主版本号
print(f"[INFO] Detected Maya major version: {version}")
return version
print(f"[WARNING] Could not detect Maya version from path: {self.maya_exe_path}")
return None
def _get_available_plugin_versions(self) -> List[str]:
"""获取所有可用的插件版本
Returns:
可用版本列表,如 ['2023', '2024', '2025']
"""
if not os.path.exists(self.plugin_base_path):
return []
versions = []
try:
for item in os.listdir(self.plugin_base_path):
item_path = os.path.join(self.plugin_base_path, item)
# 检查是否是目录且名称是4位数字版本号
if os.path.isdir(item_path) and re.match(r'^\d{4}$', item):
versions.append(item)
except Exception as e:
print(f"[WARNING] Error scanning plugin versions: {e}")
return sorted(versions)
def _get_versioned_plugin_path(self) -> Tuple[Optional[str], Optional[str]]:
"""获取带版本号的插件路径
Returns:
(插件路径, 错误消息) 元组
- 如果成功: (路径, None)
- 如果失败: (None, 错误消息)
"""
if not self.maya_version:
return None, "无法检测 Maya 版本号"
# 拼接版本号路径
versioned_path = os.path.join(self.plugin_base_path, self.maya_version)
# 检查路径是否存在
if not os.path.exists(versioned_path):
# 获取所有可用版本
available_versions = self._get_available_plugin_versions()
if not available_versions:
error_msg = (
f"插件目录不存在:\n{self.plugin_base_path}\n\n"
f"未找到任何可用的插件版本。"
)
else:
error_msg = (
f"Maya 版本: {self.maya_version}\n"
f"插件版本不匹配!\n\n"
f"当前 Maya 版本: {self.maya_version}\n"
f"可用插件版本: {', '.join(available_versions)}\n\n"
f"插件将不会被加载。\n"
f"请检查 Maya 软件版本或安装对应版本的插件。"
)
return None, error_msg
print(f"[INFO] Using plugin path: {versioned_path}")
return versioned_path, None
def _setup_environment(self) -> Tuple[Dict[str, str], Optional[str]]:
"""设置 Maya 环境变量
Returns:
(环境变量字典, 错误消息) 元组
"""
env = os.environ.copy()
# 获取带版本号的插件路径
plugin_path, error_msg = self._get_versioned_plugin_path()
if not plugin_path:
return env, error_msg
# 设置 Maya 环境变量
shelves_path = os.path.join(plugin_path, "shelves")
scripts_path = os.path.join(plugin_path, "scripts")
plugins_path = os.path.join(plugin_path, "plug-ins")
icons_path = os.path.join(plugin_path, "icons")
# MAYA_SHELF_PATH - 工具架路径(追加到现有路径)
if os.path.exists(shelves_path):
existing_shelf_path = env.get("MAYA_SHELF_PATH", "")
if existing_shelf_path:
env["MAYA_SHELF_PATH"] = f"{shelves_path};{existing_shelf_path}"
else:
env["MAYA_SHELF_PATH"] = shelves_path
print(f"[OK] Set MAYA_SHELF_PATH: {shelves_path}")
# MAYA_SCRIPT_PATH - MEL/Python 脚本路径(追加到现有路径)
if os.path.exists(scripts_path):
existing_script_path = env.get("MAYA_SCRIPT_PATH", "")
if existing_script_path:
env["MAYA_SCRIPT_PATH"] = f"{scripts_path};{existing_script_path}"
else:
env["MAYA_SCRIPT_PATH"] = scripts_path
print(f"[OK] Set MAYA_SCRIPT_PATH: {scripts_path}")
# PYTHONPATH - Python 模块路径
if os.path.exists(scripts_path):
existing_pythonpath = env.get("PYTHONPATH", "")
if existing_pythonpath:
env["PYTHONPATH"] = f"{scripts_path};{existing_pythonpath}"
else:
env["PYTHONPATH"] = scripts_path
print(f"[OK] Set PYTHONPATH: {scripts_path}")
# MAYA_PLUG_IN_PATH - 插件路径(追加到现有路径)
if os.path.exists(plugins_path):
existing_plugin_path = env.get("MAYA_PLUG_IN_PATH", "")
if existing_plugin_path:
env["MAYA_PLUG_IN_PATH"] = f"{plugins_path};{existing_plugin_path}"
else:
env["MAYA_PLUG_IN_PATH"] = plugins_path
print(f"[OK] Set MAYA_PLUG_IN_PATH: {plugins_path}")
# XBMLANGPATH - 图标路径(追加到现有路径)
if os.path.exists(icons_path):
existing_icon_path = env.get("XBMLANGPATH", "")
if existing_icon_path:
env["XBMLANGPATH"] = f"{icons_path};{existing_icon_path}"
else:
env["XBMLANGPATH"] = icons_path
print(f"[OK] Set XBMLANGPATH: {icons_path}")
return env, None
def launch(self, show_error_dialog: bool = True) -> bool:
"""启动 Maya
Args:
show_error_dialog: 是否显示错误对话框
Returns:
是否成功启动
"""
try:
# 检查 Maya 可执行文件是否存在
if not os.path.exists(self.maya_exe_path):
error_msg = f"Maya 可执行文件不存在:\n{self.maya_exe_path}"
print(f"[ERROR] {error_msg}")
if show_error_dialog and HAS_QT:
QMessageBox.critical(None, "Maya 启动失败", error_msg)
return False
# 设置环境变量
env, error_msg = self._setup_environment()
# 如果有错误消息,显示警告但继续启动(不加载插件)
if error_msg:
print(f"[WARNING] {error_msg}")
if show_error_dialog and HAS_QT:
QMessageBox.warning(
None,
"插件版本不匹配",
error_msg + "\n\nMaya 将在不加载插件的情况下启动。"
)
# 启动 Maya
print(f"[INFO] Launching Maya: {self.maya_exe_path}")
subprocess.Popen([self.maya_exe_path], env=env)
if error_msg:
print(f"[OK] Maya launched without plugins")
else:
print(f"[OK] Maya launched successfully with plugins")
return True
except Exception as e:
error_msg = f"启动 Maya 时发生错误:\n{str(e)}"
print(f"[ERROR] {error_msg}")
if show_error_dialog and HAS_QT:
QMessageBox.critical(None, "Maya 启动失败", error_msg)
return False
def launch_maya(maya_exe_path: str, plugin_base_path: str) -> bool:
"""启动 Maya 的便捷函数
Args:
maya_exe_path: Maya 可执行文件路径
plugin_base_path: 插件基础路径(不含版本号)
Returns:
是否成功启动
"""
launcher = MayaLauncher(maya_exe_path, plugin_base_path)
return launcher.launch()