Skip to content

Commit

Permalink
:recyce: move maya addon
Browse files Browse the repository at this point in the history
  • Loading branch information
antirotor committed May 23, 2024
1 parent 01203f7 commit ca40abe
Show file tree
Hide file tree
Showing 297 changed files with 40,953 additions and 1 deletion.
10 changes: 10 additions & 0 deletions client/ayon_maya/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from .addon import (
MayaAddon,
MAYA_ROOT_DIR,
)


__all__ = (
"MayaAddon",
"MAYA_ROOT_DIR",
)
46 changes: 46 additions & 0 deletions client/ayon_maya/addon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import os
from ayon_core.addon import AYONAddon, IHostAddon

MAYA_ROOT_DIR = os.path.dirname(os.path.abspath(__file__))


class MayaAddon(AYONAddon, IHostAddon):
name = "maya"
host_name = "maya"

def add_implementation_envs(self, env, _app):
# Add requirements to PYTHONPATH
new_python_paths = [
os.path.join(MAYA_ROOT_DIR, "startup")
]
old_python_path = env.get("PYTHONPATH") or ""
for path in old_python_path.split(os.pathsep):
if not path:
continue

norm_path = os.path.normpath(path)
if norm_path not in new_python_paths:
new_python_paths.append(norm_path)

# add vendor path
new_python_paths.append(
os.path.join(MAYA_ROOT_DIR, "vendor", "python")
)
env["PYTHONPATH"] = os.pathsep.join(new_python_paths)

# Set default environments
envs = {
"AYON_LOG_NO_COLORS": "1",
}
for key, value in envs.items():
env[key] = value

def get_launch_hook_paths(self, app):
if app.host_name != self.host_name:
return []
return [
os.path.join(MAYA_ROOT_DIR, "hooks")
]

def get_workfile_extensions(self):
return [".ma", ".mb"]
74 changes: 74 additions & 0 deletions client/ayon_maya/api/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
"""Public API
Anything that isn't defined here is INTERNAL and unreliable for external use.
"""

from .pipeline import (
uninstall,

ls,
containerise,
MayaHost,
)
from .plugin import (
Creator,
Loader
)

from .workio import (
open_file,
save_file,
current_file,
has_unsaved_changes,
file_extensions,
work_root
)

from .lib import (
lsattr,
lsattrs,
read,

apply_shaders,
maintained_selection,
suspended_refresh,

unique_namespace,
)


__all__ = [
"uninstall",

"ls",
"containerise",
"MayaHost",

"Creator",
"Loader",

# Workfiles API
"open_file",
"save_file",
"current_file",
"has_unsaved_changes",
"file_extensions",
"work_root",

# Utility functions
"lsattr",
"lsattrs",
"read",

"unique_namespace",

"apply_shaders",
"maintained_selection",
"suspended_refresh",

]

# Backwards API compatibility
open = open_file
save = save_file
146 changes: 146 additions & 0 deletions client/ayon_maya/api/action.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# absolute_import is needed to counter the `module has no cmds error` in Maya
from __future__ import absolute_import

import pyblish.api
import ayon_api

from ayon_core.pipeline.publish import (
get_errored_instances_from_context,
get_errored_plugins_from_context
)


class GenerateUUIDsOnInvalidAction(pyblish.api.Action):
"""Generate UUIDs on the invalid nodes in the instance.
Invalid nodes are those returned by the plugin's `get_invalid` method.
As such it is the plug-in's responsibility to ensure the nodes that
receive new UUIDs are actually invalid.
Requires:
- instance.data["folderPath"]
"""

label = "Regenerate UUIDs"
on = "failed" # This action is only available on a failed plug-in
icon = "wrench" # Icon from Awesome Icon

def process(self, context, plugin):

from maya import cmds

self.log.info("Finding bad nodes..")

errored_instances = get_errored_instances_from_context(context)

# Apply pyblish logic to get the instances for the plug-in
instances = pyblish.api.instances_by_plugin(errored_instances, plugin)

# Get the nodes from the all instances that ran through this plug-in
all_invalid = []
for instance in instances:
invalid = plugin.get_invalid(instance)

# Don't allow referenced nodes to get their ids regenerated to
# avoid loaded content getting messed up with reference edits
if invalid:
referenced = {node for node in invalid if
cmds.referenceQuery(node, isNodeReferenced=True)}
if referenced:
self.log.warning("Skipping UUID generation on referenced "
"nodes: {}".format(list(referenced)))
invalid = [node for node in invalid
if node not in referenced]

if invalid:

self.log.info("Fixing instance {}".format(instance.name))
self._update_id_attribute(instance, invalid)

all_invalid.extend(invalid)

if not all_invalid:
self.log.info("No invalid nodes found.")
return

all_invalid = list(set(all_invalid))
self.log.info("Generated ids on nodes: {0}".format(all_invalid))

def _update_id_attribute(self, instance, nodes):
"""Delete the id attribute
Args:
instance: The instance we're fixing for
nodes (list): all nodes to regenerate ids on
"""

from . import lib

# Expecting this is called on validators in which case 'folderEntity'
# should be always available, but kept a way to query it by name.
folder_entity = instance.data.get("folderEntity")
if not folder_entity:
folder_path = instance.data["folderPath"]
project_name = instance.context.data["projectName"]
self.log.info((
"Folder is not stored on instance."
" Querying by path \"{}\" from project \"{}\""
).format(folder_path, project_name))
folder_entity = ayon_api.get_folder_by_path(
project_name, folder_path, fields={"id"}
)

for node, _id in lib.generate_ids(
nodes, folder_id=folder_entity["id"]
):
lib.set_id(node, _id, overwrite=True)


class SelectInvalidAction(pyblish.api.Action):
"""Select invalid nodes in Maya when plug-in failed.
To retrieve the invalid nodes this assumes a static `get_invalid()`
method is available on the plugin.
"""
label = "Select invalid"
on = "failed" # This action is only available on a failed plug-in
icon = "search" # Icon from Awesome Icon

def process(self, context, plugin):

try:
from maya import cmds
except ImportError:
raise ImportError("Current host is not Maya")

# Get the invalid nodes for the plug-ins
self.log.info("Finding invalid nodes..")
invalid = list()
if issubclass(plugin, pyblish.api.ContextPlugin):
errored_plugins = get_errored_plugins_from_context(context)
if plugin in errored_plugins:
invalid = plugin.get_invalid(context)
else:
errored_instances = get_errored_instances_from_context(
context, plugin=plugin
)
for instance in errored_instances:
invalid_nodes = plugin.get_invalid(instance)
if invalid_nodes:
if isinstance(invalid_nodes, (list, tuple)):
invalid.extend(invalid_nodes)
else:
self.log.warning("Plug-in returned to be invalid, "
"but has no selectable nodes.")

# Ensure unique (process each node only once)
invalid = list(set(invalid))

if invalid:
self.log.info("Selecting invalid nodes: %s" % ", ".join(invalid))
cmds.select(invalid, replace=True, noExpand=True)
else:
self.log.info("No invalid nodes found.")
cmds.select(deselect=True)
Loading

0 comments on commit ca40abe

Please sign in to comment.