Files
NexusLauncher/plugins/maya.py
2025-11-23 20:41:50 +08:00

246 lines
9.0 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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()