319 lines
13 KiB
Python
319 lines
13 KiB
Python
#!/usr/bin/env python
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
Substance Painter API 插件
|
||
通过 Python API 自动添加项目库
|
||
|
||
此文件会被复制到临时目录,在 SP 启动时自动执行
|
||
"""
|
||
|
||
import os
|
||
import sys
|
||
|
||
|
||
def setup_project_library_via_registry(library_name, library_path):
|
||
"""通过注册表设置项目库(Windows)
|
||
|
||
Args:
|
||
library_name: 库名称
|
||
library_path: 库路径
|
||
|
||
Returns:
|
||
bool: 是否成功
|
||
"""
|
||
try:
|
||
import winreg
|
||
import re
|
||
|
||
# SP 库名称规则:只能包含小写字母、数字、下划线和连字符
|
||
safe_library_name = library_name.lower().replace(' ', '_')
|
||
safe_library_name = re.sub(r'[^a-z0-9_-]', '', safe_library_name)
|
||
|
||
print(f"[NexusLauncher] Setting up library via registry: {library_name}")
|
||
if safe_library_name != library_name:
|
||
print(f"[NexusLauncher] Normalized name: {safe_library_name}")
|
||
print(f"[NexusLauncher] Path: {library_path}")
|
||
|
||
# 检查路径是否存在
|
||
if not os.path.exists(library_path):
|
||
print(f"[NexusLauncher] Error: Library path does not exist: {library_path}")
|
||
return False
|
||
|
||
# 规范化路径
|
||
normalized_path = library_path.replace('\\', '/')
|
||
|
||
# 注册表路径
|
||
registry_key_name = r"SOFTWARE\Adobe\Adobe Substance 3D Painter\Shelf\pathInfos"
|
||
|
||
# 连接到注册表
|
||
reg_connection = winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER)
|
||
|
||
try:
|
||
# 打开父键
|
||
key = winreg.OpenKey(reg_connection, registry_key_name, 0, winreg.KEY_READ)
|
||
except FileNotFoundError:
|
||
print(f"[NexusLauncher] Registry key not found. Please open SP settings once to create it.")
|
||
return False
|
||
|
||
# 检查是否已存在同名库
|
||
sub_key_count = winreg.QueryInfoKey(key)[0]
|
||
shelf_exists = False
|
||
shelf_number = 0
|
||
|
||
for x in range(sub_key_count):
|
||
sub_key_name = winreg.EnumKey(key, x)
|
||
shelf_number = max(shelf_number, int(sub_key_name))
|
||
|
||
sub_key = winreg.OpenKey(reg_connection, registry_key_name + "\\" + sub_key_name, 0, winreg.KEY_READ)
|
||
try:
|
||
existing_name = winreg.QueryValueEx(sub_key, "name")[0]
|
||
existing_path = winreg.QueryValueEx(sub_key, "path")[0]
|
||
|
||
if existing_name == safe_library_name:
|
||
print(f"[NexusLauncher] Library already exists: {existing_name} at {existing_path}")
|
||
shelf_exists = True
|
||
winreg.CloseKey(sub_key)
|
||
break
|
||
finally:
|
||
winreg.CloseKey(sub_key)
|
||
|
||
if not shelf_exists:
|
||
# 添加新库
|
||
shelf_number += 1
|
||
print(f"[NexusLauncher] Adding new library with ID: {shelf_number}")
|
||
|
||
# 创建新键
|
||
new_key = winreg.CreateKey(key, str(shelf_number))
|
||
winreg.SetValueEx(new_key, "disabled", 0, winreg.REG_SZ, "false")
|
||
winreg.SetValueEx(new_key, "name", 0, winreg.REG_SZ, safe_library_name)
|
||
winreg.SetValueEx(new_key, "path", 0, winreg.REG_SZ, normalized_path)
|
||
winreg.CloseKey(new_key)
|
||
|
||
# 更新计数
|
||
try:
|
||
count = winreg.QueryValueEx(key, "size")[0]
|
||
new_count = count + 1
|
||
except:
|
||
# 如果读取失败,使用当前最大的 shelf_number + 1
|
||
new_count = shelf_number + 1
|
||
|
||
winreg.CloseKey(key)
|
||
|
||
key = winreg.OpenKeyEx(reg_connection, registry_key_name, 0, winreg.KEY_SET_VALUE)
|
||
winreg.SetValueEx(key, "size", 0, winreg.REG_DWORD, new_count)
|
||
print(f"[NexusLauncher] Updated size to: {new_count}")
|
||
|
||
print(f"[NexusLauncher] ✓ Library added to registry successfully")
|
||
|
||
# 设置为默认库(writableShelf)
|
||
try:
|
||
shelf_key = r"SOFTWARE\Adobe\Adobe Substance 3D Painter\Shelf"
|
||
default_key = winreg.OpenKeyEx(reg_connection, shelf_key, 0, winreg.KEY_SET_VALUE)
|
||
winreg.SetValueEx(default_key, "writableShelf", 0, winreg.REG_SZ, safe_library_name)
|
||
winreg.CloseKey(default_key)
|
||
print(f"[NexusLauncher] ✓ Set as default library (writableShelf)")
|
||
except Exception as e:
|
||
print(f"[NexusLauncher] Warning: Could not set as default: {e}")
|
||
|
||
winreg.CloseKey(key)
|
||
else:
|
||
winreg.CloseKey(key)
|
||
|
||
print(f"[NexusLauncher] ========================================")
|
||
print(f"[NexusLauncher] ✓ Library setup complete")
|
||
print(f"[NexusLauncher] Note: Restart SP to see the changes")
|
||
print(f"[NexusLauncher] ========================================")
|
||
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"[NexusLauncher] Error: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
return False
|
||
|
||
|
||
def setup_project_library(library_name, library_path, set_as_default=True):
|
||
"""设置项目库
|
||
|
||
Args:
|
||
library_name: 库名称
|
||
library_path: 库路径
|
||
set_as_default: 是否设置为默认库
|
||
|
||
Returns:
|
||
bool: 是否成功
|
||
"""
|
||
try:
|
||
# 延迟导入,因为只有在 SP 中才能导入
|
||
import substance_painter.resource
|
||
|
||
# SP 库名称规则:只能包含小写字母、数字、下划线和连字符
|
||
# 将名称转换为小写并替换无效字符
|
||
safe_library_name = library_name.lower().replace(' ', '_')
|
||
# 移除其他无效字符
|
||
import re
|
||
safe_library_name = re.sub(r'[^a-z0-9_-]', '', safe_library_name)
|
||
|
||
print(f"[NexusLauncher] Setting up library: {library_name}")
|
||
if safe_library_name != library_name:
|
||
print(f"[NexusLauncher] Normalized name: {safe_library_name} (SP naming rules)")
|
||
print(f"[NexusLauncher] Path: {library_path}")
|
||
|
||
# 检查路径是否存在
|
||
if not os.path.exists(library_path):
|
||
print(f"[NexusLauncher] Error: Library path does not exist: {library_path}")
|
||
return False
|
||
|
||
# 获取所有现有的 Shelf
|
||
existing_shelves = substance_painter.resource.Shelves.all()
|
||
print(f"[NexusLauncher] Found {len(existing_shelves)} existing shelves")
|
||
|
||
# 检查是否已存在同名或同路径的库
|
||
shelf_exists = False
|
||
for shelf in existing_shelves:
|
||
shelf_name = shelf.name()
|
||
shelf_path = shelf.path()
|
||
print(f"[NexusLauncher] Existing shelf: {shelf_name} -> {shelf_path}")
|
||
|
||
# 规范化路径进行比较
|
||
from os.path import normpath
|
||
normalized_shelf_path = normpath(shelf_path).lower()
|
||
normalized_library_path = normpath(library_path).lower()
|
||
|
||
if shelf_name == safe_library_name or normalized_shelf_path == normalized_library_path:
|
||
print(f"[NexusLauncher] Library already exists: {shelf_name} at {shelf_path}")
|
||
shelf_exists = True
|
||
existing_shelf = shelf
|
||
break
|
||
|
||
if not shelf_exists:
|
||
# 添加新库
|
||
print(f"[NexusLauncher] Adding new library...")
|
||
try:
|
||
# 探索可用的 API 方法
|
||
print(f"[NexusLauncher] Available Shelf methods: {[m for m in dir(substance_painter.resource.Shelf) if not m.startswith('_')]}")
|
||
print(f"[NexusLauncher] Available Shelves methods: {[m for m in dir(substance_painter.resource.Shelves) if not m.startswith('_')]}")
|
||
|
||
# 检查是否有项目打开(添加库需要关闭项目)
|
||
try:
|
||
import substance_painter.project
|
||
if substance_painter.project.is_open():
|
||
print(f"[NexusLauncher] ERROR: A project is currently open!")
|
||
print(f"[NexusLauncher] According to SP API docs, no project should be open when adding shelves")
|
||
print(f"[NexusLauncher] Please close the project and try again")
|
||
print(f"[NexusLauncher] Or add the library manually: Edit -> Settings -> Libraries")
|
||
return False
|
||
else:
|
||
print(f"[NexusLauncher] ✓ No project is open, safe to add shelf")
|
||
except Exception as e:
|
||
print(f"[NexusLauncher] Warning: Could not check project status: {e}")
|
||
|
||
# 规范化路径为正斜杠格式(SP 可能需要这个)
|
||
normalized_path = library_path.replace('\\', '/')
|
||
print(f"[NexusLauncher] Normalized path: {normalized_path}")
|
||
|
||
# 使用 Shelves.add 方法(使用规范化的名称)
|
||
print(f"[NexusLauncher] Calling Shelves.add('{safe_library_name}', '{normalized_path}')")
|
||
new_shelf = substance_painter.resource.Shelves.add(safe_library_name, normalized_path)
|
||
print(f"[NexusLauncher] ✓ Library added successfully")
|
||
|
||
# 刷新资源
|
||
substance_painter.resource.Shelves.refresh_all()
|
||
print(f"[NexusLauncher] ✓ Resources refreshed")
|
||
|
||
except Exception as e:
|
||
print(f"[NexusLauncher] Error adding library: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
return False
|
||
else:
|
||
print(f"[NexusLauncher] Library already configured")
|
||
|
||
# 设置为默认库(如果需要)
|
||
if set_as_default:
|
||
# 注意:SP API 可能没有直接设置默认库的方法
|
||
# 这需要通过修改配置文件来实现
|
||
print(f"[NexusLauncher] Note: Default library setting may require manual configuration")
|
||
|
||
print(f"[NexusLauncher] ========================================")
|
||
print(f"[NexusLauncher] ✓ Library setup complete")
|
||
print(f"[NexusLauncher] ========================================")
|
||
|
||
return True
|
||
|
||
except ImportError as e:
|
||
print(f"[NexusLauncher] Error: Cannot import substance_painter module")
|
||
print(f"[NexusLauncher] This script must be run inside Substance Painter")
|
||
return False
|
||
except Exception as e:
|
||
print(f"[NexusLauncher] Error: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
return False
|
||
|
||
|
||
def get_library_info_from_env():
|
||
"""从环境变量获取库信息
|
||
|
||
Returns:
|
||
tuple: (library_name, library_path) 或 (None, None)
|
||
"""
|
||
# NexusLauncher 会设置这些环境变量
|
||
library_name = os.environ.get('NEXUS_SP_LIBRARY_NAME')
|
||
library_path = os.environ.get('NEXUS_SP_LIBRARY_PATH')
|
||
|
||
if library_name and library_path:
|
||
return library_name, library_path
|
||
|
||
return None, None
|
||
|
||
|
||
def main():
|
||
"""主函数"""
|
||
print(f"[NexusLauncher] ========================================")
|
||
print(f"[NexusLauncher] Substance Painter Library Setup Plugin")
|
||
print(f"[NexusLauncher] ========================================")
|
||
print(f"[NexusLauncher] Plugin loaded from: {__file__}")
|
||
print(f"[NexusLauncher] Python version: {sys.version}")
|
||
|
||
# 检查环境变量
|
||
print(f"[NexusLauncher] Checking environment variables...")
|
||
library_name = os.environ.get('NEXUS_SP_LIBRARY_NAME')
|
||
library_path = os.environ.get('NEXUS_SP_LIBRARY_PATH')
|
||
print(f"[NexusLauncher] NEXUS_SP_LIBRARY_NAME: {library_name}")
|
||
print(f"[NexusLauncher] NEXUS_SP_LIBRARY_PATH: {library_path}")
|
||
|
||
if not library_name or not library_path:
|
||
print(f"[NexusLauncher] Error: Library info not found in environment variables")
|
||
print(f"[NexusLauncher] Please launch SP through NexusLauncher")
|
||
return False
|
||
|
||
# 优先使用注册表方法(更可靠)
|
||
print(f"[NexusLauncher] Method 1: Using Windows Registry...")
|
||
success = setup_project_library_via_registry(library_name, library_path)
|
||
|
||
if not success:
|
||
print(f"[NexusLauncher] Method 2: Using Python API...")
|
||
success = setup_project_library(library_name, library_path, set_as_default=True)
|
||
|
||
return success
|
||
|
||
|
||
# SP 插件入口点
|
||
def start_plugin():
|
||
"""SP 插件启动入口点"""
|
||
main()
|
||
|
||
def close_plugin():
|
||
"""SP 插件关闭入口点"""
|
||
pass
|
||
|
||
# 如果作为插件运行
|
||
if __name__ == "__plugin__":
|
||
start_plugin()
|
||
|
||
# 如果作为脚本运行
|
||
elif __name__ == "__main__":
|
||
main()
|