def refresh(self): self.list_families.clear() has_families = False project_name = self.dbcon.Session.get("AVALON_PROJECT") if not project_name: return settings = get_project_settings(project_name) sp_settings = settings.get('standalonepublisher', {}) for key, creator_data in sp_settings.get("create", {}).items(): creator = type(key, (Creator, ), creator_data) label = creator.label or creator.family item = QtWidgets.QListWidgetItem(label) item.setData(QtCore.Qt.ItemIsEnabled, True) item.setData(HelpRole, creator.help or "") item.setData(FamilyRole, creator.family) item.setData(PluginRole, creator) item.setData(PluginKeyRole, key) item.setData(ExistsRole, False) self.list_families.addItem(item) has_families = True if not has_families: item = QtWidgets.QListWidgetItem("No registered families") item.setData(QtCore.Qt.ItemIsEnabled, False) self.list_families.addItem(item) self.list_families.setCurrentItem(self.list_families.item(0))
def load(self, context, name, namespace, options): import maya.cmds as cmds import avalon.maya.lib as lib from avalon.maya.pipeline import containerise import mtoa.ui.arnoldmenu import pymel.core as pm version = context['version'] version_data = version.get("data", {}) self.log.info("version_data: {}\n".format(version_data)) frameStart = version_data.get("frameStart", None) asset = context['asset']['name'] namespace = namespace or lib.unique_namespace( asset + "_", prefix="_" if asset[0].isdigit() else "", suffix="_", ) # cmds.loadPlugin("gpuCache", quiet=True) # Root group label = "{}:{}".format(namespace, name) root = pm.group(name=label, empty=True) settings = get_project_settings(os.environ['AVALON_PROJECT']) colors = settings['maya']['load']['colors'] c = colors.get('ass') if c is not None: cmds.setAttr(root + ".useOutlinerColor", 1) cmds.setAttr(root + ".outlinerColor", c[0], c[1], c[2]) # Create transform with shape transform_name = label + "_ASS" # transform = pm.createNode("transform", name=transform_name, # parent=root) standinShape = pm.PyNode(mtoa.ui.arnoldmenu.createStandIn()) standin = standinShape.getParent() standin.rename(transform_name) pm.parent(standin, root) # Set the standin filepath standinShape.dso.set(self.fname) if frameStart is not None: standinShape.useFrameExtension.set(1) nodes = [root, standin] self[:] = nodes return containerise(name=name, namespace=namespace, nodes=nodes, context=context, loader=self.__class__.__name__)
def launch(self, session, entities, event): # Get project entity project_entity = self.get_project_from_entity(entities[0]) # Load settings for project project_name = project_entity["full_name"] project_settings = get_project_settings(project_name) project_folder_structure = ( project_settings["global"]["project_folder_structure"]) if not project_folder_structure: return { "success": False, "message": "Project structure is not set." } try: # Get paths based on presets basic_paths = self.get_path_items(project_folder_structure) self.create_folders(basic_paths, project_entity) self.create_ftrack_entities(basic_paths, project_entity) except Exception as exc: self.log.warning("Creating of structure crashed.", exc_info=True) session.rollback() return {"success": False, "message": str(exc)} return True
def load(self, context, name=None, namespace=None, data=None): try: family = context["representation"]["context"]["family"] except ValueError: family = "yeticache" # Build namespace asset = context["asset"] if namespace is None: namespace = self.create_namespace(asset["name"]) # Ensure Yeti is loaded if not cmds.pluginInfo("pgYetiMaya", query=True, loaded=True): cmds.loadPlugin("pgYetiMaya", quiet=True) # Get JSON fbase = re.search(r'^(.+)\.(\d+|#+)\.fur', self.fname) if not fbase: raise RuntimeError('Cannot determine fursettings file path') settings_fname = "{}.fursettings".format(fbase.group(1)) with open(settings_fname, "r") as fp: fursettings = json.load(fp) # Check if resources map exists # Get node name from JSON if "nodes" not in fursettings: raise RuntimeError("Encountered invalid data, expect 'nodes' in " "fursettings.") node_data = fursettings["nodes"] nodes = self.create_nodes(namespace, node_data) group_name = "{}:{}".format(namespace, name) group_node = cmds.group(nodes, name=group_name) settings = get_project_settings(os.environ['AVALON_PROJECT']) colors = settings['maya']['load']['colors'] c = colors.get(family) if c is not None: cmds.setAttr(group_name + ".useOutlinerColor", 1) cmds.setAttr(group_name + ".outlinerColor", c[0], c[1], c[2]) nodes.append(group_node) self[:] = nodes return pipeline.containerise(name=name, namespace=namespace, nodes=nodes, context=context, loader=self.__class__.__name__)
def ftrack_status_change(self, session, entity, project_name): project_settings = get_project_settings(project_name) status_update = project_settings["ftrack"]["events"]["status_update"] if not status_update["enabled"]: self.log.debug( "Status changes are disabled for project \"{}\"".format( project_name)) return status_mapping = status_update["mapping"] if not status_mapping: self.log.warning( "Project \"{}\" does not have set status changes.".format( project_name)) return actual_status = entity["status"]["name"].lower() already_tested = set() ent_path = "/".join([ent["name"] for ent in entity["link"]]) while True: next_status_name = None for key, value in status_mapping.items(): if key in already_tested: continue if actual_status in value or "__any__" in value: if key != "__ignore__": next_status_name = key already_tested.add(key) break already_tested.add(key) if next_status_name is None: break try: query = "Status where name is \"{}\"".format(next_status_name) status = session.query(query).one() entity["status"] = status session.commit() self.log.debug("Changing status to \"{}\" <{}>".format( next_status_name, ent_path)) break except Exception: session.rollback() msg = ("Status \"{}\" in presets wasn't found" " on Ftrack entity type \"{}\"").format( next_status_name, entity.entity_type) self.log.warning(msg)
def load(self, context, name, namespace, data): import maya.cmds as cmds import avalon.maya.lib as lib from avalon.maya.pipeline import containerise asset = context['asset']['name'] namespace = namespace or lib.unique_namespace( asset + "_", prefix="_" if asset[0].isdigit() else "", suffix="_", ) cmds.loadPlugin("gpuCache", quiet=True) # Root group label = "{}:{}".format(namespace, name) root = cmds.group(name=label, empty=True) settings = get_project_settings(os.environ['AVALON_PROJECT']) colors = settings['maya']['load']['colors'] c = colors.get('model') if c is not None: cmds.setAttr(root + ".useOutlinerColor", 1) cmds.setAttr(root + ".outlinerColor", c[0], c[1], c[2]) # Create transform with shape transform_name = label + "_GPU" transform = cmds.createNode("transform", name=transform_name, parent=root) cache = cmds.createNode("gpuCache", parent=transform, name="{0}Shape".format(transform_name)) # Set the cache filepath cmds.setAttr(cache + '.cacheFileName', self.fname, type="string") cmds.setAttr(cache + '.cacheGeomPath', "|", type="string") # root # Lock parenting of the transform and cache cmds.lockNode([transform, cache], lock=True) nodes = [root, transform, cache] self[:] = nodes return containerise(name=name, namespace=namespace, nodes=nodes, context=context, loader=self.__class__.__name__)
def load(self, context, name, namespace, data): from avalon.maya.pipeline import containerise from openpype.hosts.maya.api.lib import namespaced try: family = context["representation"]["context"]["family"] except ValueError: family = "vrayproxy" asset_name = context['asset']["name"] namespace = namespace or lib.unique_namespace( asset_name + "_", prefix="_" if asset_name[0].isdigit() else "", suffix="_", ) # Ensure V-Ray for Maya is loaded. cmds.loadPlugin("vrayformaya", quiet=True) with lib.maintained_selection(): cmds.namespace(addNamespace=namespace) with namespaced(namespace, new=False): nodes, group_node = self.create_vray_proxy(name, filename=self.fname) self[:] = nodes if not nodes: return # colour the group node settings = get_project_settings(os.environ['AVALON_PROJECT']) colors = settings['maya']['load']['colors'] c = colors.get(family) if c is not None: cmds.setAttr("{0}.useOutlinerColor".format(group_node), 1) cmds.setAttr("{0}.outlinerColor".format(group_node), c[0], c[1], c[2]) return containerise(name=name, namespace=namespace, nodes=nodes, context=context, loader=self.__class__.__name__)
def presets_by_hosts(self): # Get global filters as base presets = get_project_settings(os.environ['AVALON_PROJECT']) or {} if not presets: return {} result = presets.get("global", {}).get("filters", {}) hosts = pyblish.api.registered_hosts() for host in hosts: host_presets = presets.get(host, {}).get("filters") if not host_presets: continue for key, value in host_presets.items(): if value is None: if key in result: result.pop(key) continue result[key] = value return result
def process_reference(self, context, name, namespace, options): import maya.cmds as cmds from avalon import maya import pymel.core as pm try: family = context["representation"]["context"]["family"] except ValueError: family = "model" with maya.maintained_selection(): groupName = "{}:{}".format(namespace, name) cmds.loadPlugin("AbcImport.mll", quiet=True) nodes = cmds.file(self.fname, namespace=namespace, sharedReferenceFile=False, groupReference=True, groupName="{}:{}".format(namespace, name), reference=True, returnNewNodes=True) # namespace = cmds.referenceQuery(nodes[0], namespace=True) shapes = cmds.ls(nodes, shapes=True, long=True) newNodes = (list(set(nodes) - set(shapes))) current_namespace = pm.namespaceInfo(currentNamespace=True) if current_namespace != ":": groupName = current_namespace + ":" + groupName groupNode = pm.PyNode(groupName) roots = set() for node in newNodes: try: roots.add(pm.PyNode(node).getAllParents()[-2]) except: # noqa: E722 pass if family not in ["layout", "setdress", "mayaAscii"]: for root in roots: root.setParent(world=True) groupNode.zeroTransformPivots() for root in roots: root.setParent(groupNode) cmds.setAttr(groupName + ".displayHandle", 1) settings = get_project_settings(os.environ['AVALON_PROJECT']) colors = settings['maya']['load']['colors'] c = colors.get(family) if c is not None: groupNode.useOutlinerColor.set(1) groupNode.outlinerColor.set(c[0], c[1], c[2]) self[:] = newNodes cmds.setAttr(groupName + ".displayHandle", 1) # get bounding box bbox = cmds.exactWorldBoundingBox(groupName) # get pivot position on world space pivot = cmds.xform(groupName, q=True, sp=True, ws=True) # center of bounding box cx = (bbox[0] + bbox[3]) / 2 cy = (bbox[1] + bbox[4]) / 2 cz = (bbox[2] + bbox[5]) / 2 # add pivot position to calculate offset cx = cx + pivot[0] cy = cy + pivot[1] cz = cz + pivot[2] # set selection handle offset to center of bounding box cmds.setAttr(groupName + ".selectHandleX", cx) cmds.setAttr(groupName + ".selectHandleY", cy) cmds.setAttr(groupName + ".selectHandleZ", cz) if family == "rig": self._post_process_rig(name, namespace, context, options) else: if "translate" in options: cmds.setAttr(groupName + ".t", *options["translate"]) return newNodes
def launch(self, session, event): if not event.get("data"): return entities_info = event["data"].get("entities") if not entities_info: return # load shell scripts presets tmp_by_project_name = {} for entity_info in entities_info: if entity_info.get('entity_type') != 'Appointment': continue task_entity, user_entity = self._get_task_and_user( session, entity_info.get('action'), entity_info.get('changes')) if not task_entity or not user_entity: self.log.error("Task or User was not found.") continue # format directories to pass to shell script project_name = task_entity["project"]["full_name"] project_data = tmp_by_project_name.get(project_name) or {} if "scripts_by_action" not in project_data: project_settings = get_project_settings(project_name) _settings = ( project_settings["ftrack"]["events"]["user_assignment"]) project_data["scripts_by_action"] = _settings.get("scripts") tmp_by_project_name[project_name] = project_data scripts_by_action = project_data["scripts_by_action"] if not scripts_by_action: continue if "anatomy" not in project_data: project_data["anatomy"] = Anatomy(project_name) tmp_by_project_name[project_name] = project_data anatomy = project_data["anatomy"] data = self._get_template_data(task_entity) anatomy_filled = anatomy.format(data) # formatting work dir is easiest part as we can use whole path work_dir = anatomy_filled["work"]["folder"] # we also need publish but not whole anatomy_filled.strict = False publish = anatomy_filled["publish"]["folder"] # now find path to {asset} m = re.search("(^.+?{})".format(data["asset"]), publish) if not m: msg = 'Cannot get part of publish path {}'.format(publish) self.log.error(msg) return {'success': False, 'message': msg} publish_dir = m.group(1) username = user_entity["username"] event_entity_action = entity_info["action"] for script in scripts_by_action.get(event_entity_action): self.log.info(("[{}] : running script for user {}").format( event_entity_action, username)) self._run_script(script, [username, work_dir, publish_dir]) return True
def process_reference(self, context, name=None, namespace=None, options=None): import maya.cmds as cmds from avalon import maya # get roots of selected hierarchies selected_roots = [] for sel in cmds.ls(sl=True, long=True): selected_roots.append(sel.split("|")[1]) # get all objects under those roots selected_hierarchy = [] for root in selected_roots: selected_hierarchy.append( cmds.listRelatives(root, allDescendents=True) or []) # flatten the list and filter only shapes shapes_flat = [] for root in selected_hierarchy: shapes = cmds.ls(root, long=True, type="mesh") or [] for shape in shapes: shapes_flat.append(shape) # create dictionary of cbId and shape nodes scene_lookup = defaultdict(list) for node in shapes_flat: cb_id = lib.get_id(node) scene_lookup[cb_id] = node # load rig with maya.maintained_selection(): nodes = cmds.file(self.fname, namespace=namespace, reference=True, returnNewNodes=True, groupReference=True, groupName="{}:{}".format(namespace, name)) # for every shape node we've just loaded find matching shape by its # cbId in selection. If found outMesh of scene shape will connect to # inMesh of loaded shape. for destination_node in nodes: source_node = scene_lookup[lib.get_id(destination_node)] if source_node: self.log.info("found: {}".format(source_node)) self.log.info( "creating connection to {}".format(destination_node)) cmds.connectAttr("{}.outMesh".format(source_node), "{}.inMesh".format(destination_node), force=True) groupName = "{}:{}".format(namespace, name) settings = get_project_settings(os.environ['AVALON_PROJECT']) colors = settings['maya']['load']['colors'] c = colors.get('yetiRig') if c is not None: cmds.setAttr(groupName + ".useOutlinerColor", 1) cmds.setAttr(groupName + ".outlinerColor", c[0], c[1], c[2]) self[:] = nodes return nodes
import os from openpype.api import get_project_settings import openpype.hosts.maya.api.lib as mlib from maya import cmds print("starting OpenPype usersetup") # build a shelf settings = get_project_settings(os.environ['AVALON_PROJECT']) shelf_preset = settings['maya'].get('project_shelf') if shelf_preset: project = os.environ["AVALON_PROJECT"] icon_path = os.path.join(os.environ['OPENPYPE_PROJECT_SCRIPTS'], project, "icons") icon_path = os.path.abspath(icon_path) for i in shelf_preset['imports']: import_string = "from {} import {}".format(project, i) print(import_string) exec(import_string) cmds.evalDeferred( "mlib.shelf(name=shelf_preset['name'], iconPath=icon_path, preset=shelf_preset)" ) print("finished OpenPype usersetup")
def create_unreal_project(project_name: str, ue_version: str, pr_dir: str, engine_path: str, dev_mode: bool = False) -> None: """ This will create `.uproject` file at specified location. As there is no way I know to create project via command line, this is easiest option. Unreal project file is basically JSON file. If we find `AVALON_UNREAL_PLUGIN` environment variable we assume this is location of Avalon Integration Plugin and we copy its content to project folder and enable this plugin. :param project_name: project name :type project_name: str :param ue_version: unreal engine version (like 4.23) :type ue_version: str :param pr_dir: path to directory where project will be created :type pr_dir: str :param engine_path: Path to Unreal Engine installation :type engine_path: str :param dev_mode: Flag to trigger C++ style Unreal project needing Visual Studio and other tools to compile plugins from sources. This will trigger automatically if `Binaries` directory is not found in plugin folders as this indicates this is only source distribution of the plugin. Dev mode is also set by preset file `unreal/project_setup.json` in **OPENPYPE_CONFIG**. :type dev_mode: bool :returns: None """ preset = get_project_settings(project_name)["unreal"]["project_setup"] if os.path.isdir(os.environ.get("AVALON_UNREAL_PLUGIN", "")): # copy plugin to correct path under project plugins_path = os.path.join(pr_dir, "Plugins") avalon_plugin_path = os.path.join(plugins_path, "Avalon") if not os.path.isdir(avalon_plugin_path): os.makedirs(avalon_plugin_path, exist_ok=True) dir_util._path_created = {} dir_util.copy_tree(os.environ.get("AVALON_UNREAL_PLUGIN"), avalon_plugin_path) if (not os.path.isdir(os.path.join(avalon_plugin_path, "Binaries")) or not os.path.join(avalon_plugin_path, "Intermediate")): dev_mode = True # data for project file data = { "FileVersion": 3, "EngineAssociation": ue_version, "Category": "", "Description": "", "Plugins": [{ "Name": "PythonScriptPlugin", "Enabled": True }, { "Name": "EditorScriptingUtilities", "Enabled": True }, { "Name": "Avalon", "Enabled": True }] } if preset["install_unreal_python_engine"]: # If `OPENPYPE_UNREAL_ENGINE_PYTHON_PLUGIN` is set, copy it from there # to support offline installation. # Otherwise clone UnrealEnginePython to Plugins directory # https://github.com/20tab/UnrealEnginePython.git uep_path = os.path.join(plugins_path, "UnrealEnginePython") if os.environ.get("OPENPYPE_UNREAL_ENGINE_PYTHON_PLUGIN"): os.makedirs(uep_path, exist_ok=True) dir_util._path_created = {} dir_util.copy_tree( os.environ.get("OPENPYPE_UNREAL_ENGINE_PYTHON_PLUGIN"), uep_path) else: # WARNING: this will trigger dev_mode, because we need to compile # this plugin. dev_mode = True import git git.Repo.clone_from( "https://github.com/20tab/UnrealEnginePython.git", uep_path) data["Plugins"].append({"Name": "UnrealEnginePython", "Enabled": True}) if (not os.path.isdir(os.path.join(uep_path, "Binaries")) or not os.path.join(uep_path, "Intermediate")): dev_mode = True if dev_mode or preset["dev_mode"]: # this will add project module and necessary source file to make it # C++ project and to (hopefully) make Unreal Editor to compile all # sources at start data["Modules"] = [{ "Name": project_name, "Type": "Runtime", "LoadingPhase": "Default", "AdditionalDependencies": ["Engine"], }] if preset["install_unreal_python_engine"]: # now we need to fix python path in: # `UnrealEnginePython.Build.cs` # to point to our python with open(os.path.join(uep_path, "Source", "UnrealEnginePython", "UnrealEnginePython.Build.cs"), mode="r") as f: build_file = f.read() fix = build_file.replace( 'private string pythonHome = "";', 'private string pythonHome = "{}";'.format( sys.base_prefix.replace("\\", "/"))) with open(os.path.join(uep_path, "Source", "UnrealEnginePython", "UnrealEnginePython.Build.cs"), mode="w") as f: f.write(fix) # write project file project_file = os.path.join(pr_dir, "{}.uproject".format(project_name)) with open(project_file, mode="w") as pf: json.dump(data, pf, indent=4) # UE < 4.26 have Python2 by default, so we need PySide # but we will not need it in 4.26 and up if int(ue_version.split(".")[1]) < 26: # ensure we have PySide installed in engine # TODO: make it work for other platforms � � if platform.system().lower() == "windows": python_path = os.path.join(engine_path, "Engine", "Binaries", "ThirdParty", "Python", "Win64", "python.exe") subprocess.run([python_path, "-m", "pip", "install", "pyside"]) if dev_mode or preset["dev_mode"]: _prepare_cpp_project(project_file, engine_path)
def process_reference(self, context, name, namespace, options): import maya.cmds as cmds from avalon import maya import pymel.core as pm version = context['version'] version_data = version.get("data", {}) self.log.info("version_data: {}\n".format(version_data)) frameStart = version_data.get("frameStart", None) try: family = context["representation"]["context"]["family"] except ValueError: family = "ass" with maya.maintained_selection(): groupName = "{}:{}".format(namespace, name) path = self.fname proxyPath_base = os.path.splitext(path)[0] if frameStart is not None: proxyPath_base = os.path.splitext(proxyPath_base)[0] publish_folder = os.path.split(path)[0] files_in_folder = os.listdir(publish_folder) collections, remainder = clique.assemble(files_in_folder) if collections: hashes = collections[0].padding * '#' coll = collections[0].format('{head}[index]{tail}') filename = coll.replace('[index]', hashes) path = os.path.join(publish_folder, filename) proxyPath = proxyPath_base + ".ma" self.log.info nodes = cmds.file(proxyPath, namespace=namespace, reference=True, returnNewNodes=True, groupReference=True, groupName=groupName) cmds.makeIdentity(groupName, apply=False, rotate=True, translate=True, scale=True) # Set attributes proxyShape = pm.ls(nodes, type="mesh")[0] proxyShape.aiTranslator.set('procedural') proxyShape.dso.set(path) proxyShape.aiOverrideShaders.set(0) settings = get_project_settings(os.environ['AVALON_PROJECT']) colors = settings['maya']['load']['colors'] c = colors.get(family) if c is not None: cmds.setAttr(groupName + ".useOutlinerColor", 1) cmds.setAttr(groupName + ".outlinerColor", c[0], c[1], c[2]) self[:] = nodes return nodes
def load(self, context, name=None, namespace=None, data=None): from maya import cmds import avalon.maya.lib as lib from avalon.maya.pipeline import containerise try: family = context["representation"]["context"]["family"] except ValueError: family = "vdbcache" # Check if the plugin for redshift is available on the pc try: cmds.loadPlugin("redshift4maya", quiet=True) except Exception as exc: self.log.error("Encountered exception:\n%s" % exc) return # Check if viewport drawing engine is Open GL Core (compat) render_engine = None compatible = "OpenGL" if cmds.optionVar(exists="vp2RenderingEngine"): render_engine = cmds.optionVar(query="vp2RenderingEngine") if not render_engine or not render_engine.startswith(compatible): raise RuntimeError("Current scene's settings are incompatible." "See Preferences > Display > Viewport 2.0 to " "set the render engine to '%s<type>'" % compatible) asset = context['asset'] asset_name = asset["name"] namespace = namespace or lib.unique_namespace( asset_name + "_", prefix="_" if asset_name[0].isdigit() else "", suffix="_", ) # Root group label = "{}:{}".format(namespace, name) root = cmds.group(name=label, empty=True) settings = get_project_settings(os.environ['AVALON_PROJECT']) colors = settings['maya']['load']['colors'] c = colors.get(family) if c is not None: cmds.setAttr(root + ".useOutlinerColor", 1) cmds.setAttr(root + ".outlinerColor", c[0], c[1], c[2]) # Create VR volume_node = cmds.createNode("RedshiftVolumeShape", name="{}RVSShape".format(label), parent=root) cmds.setAttr("{}.fileName".format(volume_node), self.fname, type="string") nodes = [root, volume_node] self[:] = nodes return containerise(name=name, namespace=namespace, nodes=nodes, context=context, loader=self.__class__.__name__)