SkinLayerStudio

FAQ.4 — Maya 无法连接时,请发送检查日志

下载 Markdown

概述

如果 Maya 无法连接到 SkinLayer Studio,请运行下面的检查脚本,并把全部输出用邮件发给我们。
脚本只读取信息。它不会安装、不会删除文件,也不会启动连接器。

请发送到 contact@otakusolutions.com

如果现在需要继续工作,可以先用 FAQ.3 — 强制启动 打开连接器。要确认原因,仍然需要这份日志。


请在邮件里写上

  1. SkinLayer Studio 版本(Help → About)
  2. Maya 版本
  3. 安装连接器后,是否已完全退出 Maya 再打开
  4. 下面脚本的全部输出,包括最后的 VERDICT
  5. 如果可以,请附上 SkinLayer Studio 顶部 DCC 一栏的截图

请不要发送场景文件和许可证密钥。

请不要手动创建 sessions 文件夹。这个文件夹会在连接器启动时出现。空文件夹不会完成连接。

运行方法

  1. 在 Maya 中打开 Windows → General Editors → Script Editor。
  2. 选择下方输入区的 Python 标签。不是 MEL。
  3. 把下面的脚本全部粘贴进去。
  4. 取消所有选中后,按 Ctrl + Enter 执行。如果只选中其中一段,可能会出现 Invalid Code Fragment。
  5. 把全部输出复制到邮件里。

请不要在 SkinLayer Studio 的 `` 窗口里运行。

from __future__ import print_function

# SkinLayer Studio - Maya connection check
# Windows > General Editors > Script Editor > Python tab > paste all > Execute.
# Do not run this inside the SkinLayer Studio window.
# Read-only: it does not install, delete, or start the connector.

import json
import os
import sys
import time
import traceback

BEGIN = "# === SLS_MAYA_CONNECTOR_BLOCK_BEGIN ==="
END = "# === SLS_MAYA_CONNECTOR_BLOCK_END ==="
PKG = "os_skinLayerStudio_connector"
LEGACY_NAMES = (
    "sls_maya_connector",
    "sls_protocol",
    "os_sls_protocol",
    "sls_maya_connector.meta.json",
)

def say(status, message):
    print("%-8s %s" % (status, message))

def read_text(path):
    handle = open(path, "rb")
    try:
        data = handle.read()
    finally:
        handle.close()
    for enc in ("utf-8-sig", "utf-8", "cp949"):
        try:
            return data.decode(enc)
        except UnicodeDecodeError:
            pass
    return data.decode("utf-8", "replace")

def pid_alive(pid):
    if os.name != "nt":
        return None
    try:
        import ctypes
        kernel = ctypes.windll.kernel32
        access = 0x1000
        still = 259
        handle = kernel.OpenProcess(access, 0, int(pid))
        if not handle:
            err = int(kernel.GetLastError())
            if err == 5:
                return True
            return False
        code = ctypes.c_ulong()
        try:
            ok = kernel.GetExitCodeProcess(handle, ctypes.byref(code))
            if not ok:
                return None
            return int(code.value) == still
        finally:
            kernel.CloseHandle(handle)
    except Exception:
        return None

def load_json(path):
    try:
        return json.loads(read_text(path))
    except Exception as exc:
        say("FAIL", "json %s (%s)" % (os.path.basename(path), exc))
        return None

def main():
    print("=" * 64)
    print("SkinLayer Studio  Maya connection check")
    print("=" * 64)

    try:
        import maya.cmds as cmds
    except Exception as exc:
        say("FAIL", "NOT_IN_MAYA")
        print("Open Maya, then run this in Script Editor on the Python tab.")
        print(exc)
        return

    say("OK", "maya=%s  python=%d.%d.%d  pid=%s" % (
        cmds.about(version=True),
        sys.version_info[0], sys.version_info[1], sys.version_info[2],
        os.getpid(),
    ))

    scripts = cmds.internalVar(userScriptDir=True) or ""
    scripts = os.path.normpath(scripts)
    say("INFO", "scripts=%s" % scripts)
    app_dir = os.environ.get("MAYA_APP_DIR", "")
    if app_dir:
        say("INFO", "MAYA_APP_DIR=%s" % app_dir)

    user_setup = os.path.join(scripts, "userSetup.py")
    begin_n = 0
    end_n = 0
    has_setup = os.path.isfile(user_setup)
    if not has_setup:
        say("MISSING", "userSetup.py")
    else:
        text = read_text(user_setup)
        begin_n = text.count(BEGIN)
        end_n = text.count(END)
        if begin_n == 1 and end_n == 1:
            say("OK", "userSetup sentinel")
        else:
            say("FAIL", "userSetup sentinel begin=%d end=%d" % (begin_n, end_n))

    pkg = os.path.join(scripts, PKG)
    has_pkg = os.path.isdir(pkg)
    names = (
        "__init__.py",
        "units.py",
        "import_weights.py",
        os.path.join("os_sls_protocol", "__init__.py"),
        os.path.join("os_sls_protocol", "safe_fs.py"),
        "meta.json",
    )
    present = {}
    if not has_pkg:
        say("MISSING", "folder %s" % PKG)
        for name in names:
            present[name] = False
    else:
        say("OK", "folder %s" % pkg)
        for name in names:
            path = os.path.join(pkg, name)
            present[name] = os.path.isfile(path)
            if present[name]:
                say("OK", name)
            else:
                say("MISSING", name)
        meta = load_json(os.path.join(pkg, "meta.json")) if present["meta.json"] else None
        if isinstance(meta, dict):
            say("INFO", "meta connector=%s  for_maya=%s  installed_at=%s" % (
                meta.get("connector_version", "?"),
                meta.get("maya_version", "?"),
                meta.get("installed_at", "?"),
            ))

    if os.path.isdir(scripts):
        for name in LEGACY_NAMES:
            path = os.path.join(scripts, name)
            if os.path.exists(path):
                say("WARN", "old leftover %s" % path)

    imported = False
    proto_loaded = False
    units_mod = False
    server_on = False
    port = 0
    mod = None
    try:
        import os_skinLayerStudio_connector as mod
        imported = True
    except Exception:
        say("FAIL", "import os_skinLayerStudio_connector")
        traceback.print_exc()

    if mod is not None:
        ver = getattr(mod, "_CONNECTOR_VERSION", "?")
        proto_loaded = bool(getattr(mod, "_SLS_PROTO_LOADED", False))
        units_mod = getattr(mod, "_sls_maya_units", None) is not None
        server = getattr(mod, "_SERVER", None)
        say("INFO", "loaded version=%s  protocol=%s  units=%s" % (
            ver, "yes" if proto_loaded else "no", "yes" if units_mod else "no",
        ))
        if server is None:
            say("MISSING", "connector server (this Maya session has not booted it)")
        else:
            port = int(getattr(server, "_port", 0) or 0)
            server_on = port > 0
            if server_on:
                say("OK", "server port=%d" % port)
            else:
                say("FAIL", "server object without a port")

    base = os.environ.get("LOCALAPPDATA")
    if not base:
        base = os.path.join(os.path.expanduser("~"), "AppData", "Local")
    sessions = os.path.join(base, "SkinLayerStudio", "sessions")
    say("INFO", "sessions=%s" % sessions)
    lock_name = "maya_%d.json" % os.getpid()
    lock_path = os.path.join(sessions, lock_name)
    has_session = os.path.isfile(lock_path)
    session_port = None
    if not os.path.isdir(sessions):
        say("MISSING", "sessions folder")
    elif not has_session:
        say("MISSING", lock_name)
    else:
        payload = load_json(lock_path)
        if isinstance(payload, dict):
            session_port = int(payload.get("port") or 0)
            scene = payload.get("scene_file") or ""
            scene_name = os.path.basename(scene) if scene else ""
            started = payload.get("started_at")
            started_s = "?"
            if isinstance(started, int):
                started_s = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(started))
            say("OK", "session port=%s connector=%s protocol=%s started=%s scene=%s" % (
                session_port,
                payload.get("connector_version", "?"),
                payload.get("protocol_version", "?"),
                started_s,
                scene_name or "-",
            ))
            if server_on and session_port != port:
                say("FAIL", "session port %s != server port %s" % (session_port, port))
        others = []
        try:
            listed = os.listdir(sessions)
        except OSError as exc:
            say("FAIL", "cannot list sessions (%s)" % exc)
            listed = []
        for name in listed:
            if name.startswith("maya_") and name.endswith(".json") and name != lock_name:
                others.append(name)
        others.sort()
        if not others:
            say("INFO", "no other maya session files")
        shown = others[:8]
        for name in shown:
            other = load_json(os.path.join(sessions, name))
            other_pid = "?"
            other_port = "?"
            other_ver = "?"
            alive = "?"
            if isinstance(other, dict):
                other_pid = other.get("pid", "?")
                other_port = other.get("port", "?")
                other_ver = other.get("connector_version", "?")
                state = pid_alive(other_pid)
                if state is True:
                    alive = "running"
                elif state is False:
                    alive = "not-running"
            say("INFO", "other %s pid=%s port=%s connector=%s %s" % (
                name, other_pid, other_port, other_ver, alive,
            ))
        if len(others) > 8:
            say("INFO", "%d more session files not listed" % (len(others) - 8))

    proto_name = os.path.join("os_sls_protocol", "__init__.py")
    if not has_pkg:
        code = "NO_PACKAGE"
    elif (not has_setup) or begin_n == 0:
        code = "NO_SENTINEL"
    elif begin_n != 1 or end_n != 1:
        code = "SENTINEL_BROKEN"
    elif (not present.get(proto_name)) or (imported and not proto_loaded):
        code = "NO_PROTOCOL"
    elif not imported:
        code = "IMPORT_FAIL"
    elif not server_on:
        code = "NOT_BOOTED"
    elif not has_session:
        code = "NO_SESSION_FILE"
    elif session_port != port:
        code = "PORT_MISMATCH"
    else:
        code = "READY"

    meaning = {
        "READY": "Maya is waiting. SkinLayer Studio should be able to see this session.",
        "NO_SENTINEL": "This Maya does not auto-start the connector. Install Connector for this Maya version, fully quit Maya, then open it again.",
        "SENTINEL_BROKEN": "userSetup.py markers are not in a pair. Install Connector again.",
        "NO_PACKAGE": "The connector folder is not in this Maya scripts directory. Install Connector for this Maya version.",
        "NO_PROTOCOL": "os_sls_protocol is missing, so the connector refuses to start. Install Connector again.",
        "IMPORT_FAIL": "The connector module did not import. Send this whole output.",
        "NOT_BOOTED": "The files are there, but this Maya session did not start the connector. Fully quit Maya and open it again. If the Script Editor shows red text, send that too.",
        "NO_SESSION_FILE": "The connector is running, but the session file Studio uses to find Maya was not written.",
        "PORT_MISMATCH": "The session file port does not match the port Maya is listening on.",
    }
    print("-" * 64)
    print("VERDICT: %s" % code)
    print(meaning[code])
    units_file = present.get("units.py", False)
    if has_pkg and ((not units_file) or (imported and not units_mod)):
        print("NOTE: NO_UNITS - units.py is missing. Connecting may still work, but bone positions will fail. Install Connector again.")
    print("-" * 64)

main()

需要更多帮助?

联系支持