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

View File

@@ -0,0 +1,318 @@
#!/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()