mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
171 lines
4.6 KiB
Python
171 lines
4.6 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Pipeline tools for OpenPype Houdini integration."""
|
|
import os
|
|
import logging
|
|
from operator import attrgetter
|
|
|
|
import json
|
|
|
|
from openpype.host import HostBase, IWorkfileHost, ILoadHost, INewPublisher
|
|
import pyblish.api
|
|
from openpype.pipeline import (
|
|
register_creator_plugin_path,
|
|
register_loader_plugin_path,
|
|
AVALON_CONTAINER_ID,
|
|
)
|
|
from openpype.hosts.max.api.menu import OpenPypeMenu
|
|
from openpype.hosts.max.api import lib
|
|
from openpype.hosts.max import MAX_HOST_DIR
|
|
|
|
from pymxs import runtime as rt # noqa
|
|
|
|
log = logging.getLogger("openpype.hosts.max")
|
|
|
|
PLUGINS_DIR = os.path.join(MAX_HOST_DIR, "plugins")
|
|
PUBLISH_PATH = os.path.join(PLUGINS_DIR, "publish")
|
|
LOAD_PATH = os.path.join(PLUGINS_DIR, "load")
|
|
CREATE_PATH = os.path.join(PLUGINS_DIR, "create")
|
|
INVENTORY_PATH = os.path.join(PLUGINS_DIR, "inventory")
|
|
|
|
|
|
class MaxHost(HostBase, IWorkfileHost, ILoadHost, INewPublisher):
|
|
|
|
name = "max"
|
|
menu = None
|
|
|
|
def __init__(self):
|
|
super(MaxHost, self).__init__()
|
|
self._op_events = {}
|
|
self._has_been_setup = False
|
|
|
|
def install(self):
|
|
pyblish.api.register_host("max")
|
|
|
|
pyblish.api.register_plugin_path(PUBLISH_PATH)
|
|
register_loader_plugin_path(LOAD_PATH)
|
|
register_creator_plugin_path(CREATE_PATH)
|
|
|
|
# self._register_callbacks()
|
|
self.menu = OpenPypeMenu()
|
|
|
|
self._has_been_setup = True
|
|
|
|
def context_setting():
|
|
return lib.set_context_setting()
|
|
rt.callbacks.addScript(rt.Name('systemPostNew'),
|
|
context_setting)
|
|
|
|
def has_unsaved_changes(self):
|
|
# TODO: how to get it from 3dsmax?
|
|
return True
|
|
|
|
def get_workfile_extensions(self):
|
|
return [".max"]
|
|
|
|
def save_workfile(self, dst_path=None):
|
|
rt.saveMaxFile(dst_path)
|
|
return dst_path
|
|
|
|
def open_workfile(self, filepath):
|
|
rt.checkForSave()
|
|
rt.loadMaxFile(filepath)
|
|
return filepath
|
|
|
|
def get_current_workfile(self):
|
|
return os.path.join(rt.maxFilePath, rt.maxFileName)
|
|
|
|
def get_containers(self):
|
|
return ls()
|
|
|
|
def _register_callbacks(self):
|
|
rt.callbacks.removeScripts(id=rt.name("OpenPypeCallbacks"))
|
|
|
|
rt.callbacks.addScript(
|
|
rt.Name("postLoadingMenus"),
|
|
self._deferred_menu_creation, id=rt.Name('OpenPypeCallbacks'))
|
|
|
|
def _deferred_menu_creation(self):
|
|
self.log.info("Building menu ...")
|
|
self.menu = OpenPypeMenu()
|
|
|
|
@staticmethod
|
|
def create_context_node():
|
|
"""Helper for creating context holding node."""
|
|
|
|
root_scene = rt.rootScene
|
|
|
|
create_attr_script = ("""
|
|
attributes "OpenPypeContext"
|
|
(
|
|
parameters main rollout:params
|
|
(
|
|
context type: #string
|
|
)
|
|
|
|
rollout params "OpenPype Parameters"
|
|
(
|
|
editText editTextContext "Context" type: #string
|
|
)
|
|
)
|
|
""")
|
|
|
|
attr = rt.execute(create_attr_script)
|
|
rt.custAttributes.add(root_scene, attr)
|
|
|
|
return root_scene.OpenPypeContext.context
|
|
|
|
def update_context_data(self, data, changes):
|
|
try:
|
|
_ = rt.rootScene.OpenPypeContext.context
|
|
except AttributeError:
|
|
# context node doesn't exists
|
|
self.create_context_node()
|
|
|
|
rt.rootScene.OpenPypeContext.context = json.dumps(data)
|
|
|
|
def get_context_data(self):
|
|
try:
|
|
context = rt.rootScene.OpenPypeContext.context
|
|
except AttributeError:
|
|
# context node doesn't exists
|
|
context = self.create_context_node()
|
|
if not context:
|
|
context = "{}"
|
|
return json.loads(context)
|
|
|
|
def save_file(self, dst_path=None):
|
|
# Force forwards slashes to avoid segfault
|
|
dst_path = dst_path.replace("\\", "/")
|
|
rt.saveMaxFile(dst_path)
|
|
|
|
|
|
def ls() -> list:
|
|
"""Get all OpenPype instances."""
|
|
objs = rt.objects
|
|
containers = [
|
|
obj for obj in objs
|
|
if rt.getUserProp(obj, "id") == AVALON_CONTAINER_ID
|
|
]
|
|
|
|
for container in sorted(containers, key=attrgetter("name")):
|
|
yield lib.read(container)
|
|
|
|
|
|
def containerise(name: str, nodes: list, context, loader=None, suffix="_CON"):
|
|
data = {
|
|
"schema": "openpype:container-2.0",
|
|
"id": AVALON_CONTAINER_ID,
|
|
"name": name,
|
|
"namespace": "",
|
|
"loader": loader,
|
|
"representation": context["representation"]["_id"],
|
|
}
|
|
|
|
container_name = f"{name}{suffix}"
|
|
container = rt.container(name=container_name)
|
|
for node in nodes:
|
|
node.Parent = container
|
|
|
|
if not lib.imprint(container_name, data):
|
|
print(f"imprinting of {container_name} failed.")
|
|
return container
|