diff --git a/core/templates.yml b/core/templates.yml index d60f302ec..3b98a53d3 100644 --- a/core/templates.yml +++ b/core/templates.yml @@ -427,6 +427,42 @@ paths: sequence_asset_publish_standin: '@sequence_asset_publish_area_scene/standin/@geom_subdirs/@sequence_asset_version_name.{maya.std.ext}' shot_asset_publish_standin: '@shot_asset_publish_area_scene/standin/@geom_subdirs/@shot_asset_version_name.{maya.std.ext}' + # XGEN FILES + project_publish_xgen_file: '@project_publish_area_scene/@project_version_name_xgen_file.xgen' + sequence_publish_xgen_file: '@sequence_publish_area_scene/@sequence_version_name_xgen_file.xgen' + shot_publish_xgen_file: '@shot_publish_area_scene/@shot_version_name_xgen_file.xgen' + + project_asset_publish_xgen_file: '@project_asset_publish_area_scene/@project_asset_version_name_xgen_file.xgen' + sequence_asset_publish_xgen_file: '@sequence_asset_publish_area_scene/@sequence_asset_version_name_xgen_file.xgen' + shot_asset_publish_xgen_file: '@shot_asset_publish_area_scene/@shot_asset_version_name_xgen_file.xgen' + + # XGEN PATCHES + project_publish_xgen_patch: '@project_publish_area_scene/@project_version_name_xgen_file.abc' + sequence_publish_xgen_patch: '@sequence_publish_area_scene/@sequence_version_name_xgen_file.abc' + shot_publish_xgen_patch: '@shot_publish_area_scene/@shot_version_name_xgen_file.abc' + + project_asset_publish_xgen_patch: '@project_asset_publish_area_scene/@project_asset_version_name_xgen_file.abc' + sequence_asset_publish_xgen_patch: '@sequence_asset_publish_area_scene/@sequence_asset_version_name_xgen_file.abc' + shot_asset_publish_xgen_patch: '@shot_asset_publish_area_scene/@shot_asset_version_name_xgen_file.abc' + + # XGEN COLLECTION + project_publish_xgen_collection: '@project_publish_area_scene/xgen/collections/@project_version_name[/{palette_name}]' + sequence_publish_xgen_collection: '@sequence_publish_area_scene/xgen/collections/@sequence_version_name[/{palette_name}]' + shot_publish_xgen_collection: '@shot_publish_area_scene/xgen/collections/@shot_version_name[/{palette_name}]' + + project_asset_publish_xgen_collection: '@project_asset_publish_area_scene/xgen/collections/@project_asset_version_name[/{palette_name}]' + sequence_asset_publish_xgen_collection: '@sequence_asset_publish_area_scene/xgen/collections/@sequence_asset_version_name[/{palette_name}]' + shot_asset_publish_xgen_collection: '@shot_asset_publish_area_scene/xgen/collections/@shot_asset_version_name[/{palette_name}]' + + # 3DPAINTTEXTURES FILES + project_publish_3dPaintTextures: '@project_publish_area_scene/@3dPaintTextures_subdir/@project_version_name' + sequence_publish_3dPaintTextures: '@sequence_publish_area_scene/@3dPaintTextures_subdir/@sequence_version_name' + shot_publish_3dPaintTextures: '@shot_publish_area_scene/@3dPaintTextures_subdir/@shot_version_name' + + project_asset_publish_3dPaintTextures: '@project_asset_publish_area_scene/@3dPaintTextures_subdir/@project_asset_version_name' + sequence_asset_publish_3dPaintTextures: '@sequence_asset_publish_area_scene/@3dPaintTextures_subdir/@sequence_asset_version_name' + shot_asset_publish_3dPaintTextures: '@shot_asset_publish_area_scene/@3dPaintTextures_subdir/@shot_asset_version_name' + # REFERENCE CAMERA project_publish_ref_cam: '@project_publish_area_model/ref_cam/@geom_subdirs/@project_version_name.abc' sequence_publish_ref_cam: '@sequence_publish_area_model/ref_cam/@geom_subdirs/@sequence_version_name.abc' @@ -573,6 +609,8 @@ strings: 2k_subdirs: '{name}/v{version}/2K' geom_subdirs: '{name}/v{version}[/{node}]' texture_subdirs: '{name}/v{version}[/{node}]/{channel}[/{layer}]' + xgen_collection_subdirs: 'xgen/collections[/{palette_name}]' + 3dPaintTextures_subdir: 'sourceimages/3dPaintTextures' # SCENE PUBLISH NAMES project_publish_name: '{Step}_{name}[-{node}]' @@ -594,6 +632,18 @@ strings: sequence_asset_version_name: '@sequence_asset_publish_name.v{version}' shot_asset_version_name: '@shot_asset_publish_name.v{version}' + # ASSET XGEN VERSION NAMES: + project_asset_version_name_xgen_file: '@project_asset_publish_name.v{version}__[{palette_name}]' + sequence_asset_version_name_xgen_file: '@sequence_asset_publish_name.v{version}__[{palette_name}]' + shot_asset_version_name_xgen_file: '@shot_asset_publish_name.v{version}__[{palette_name}]' + + # SCENE XGEN VERSION NAMES + project_version_name_xgen_file: '@project_publish_name.v{version}__[{palette_name}]' + sequence_version_name_xgen_file: '@sequence_publish_name.v{version}__[{palette_name}]' + shot_version_name_xgen_file: '@shot_publish_name.v{version}__[{palette_name}]' + + + diff --git a/core/templates/maya.yml b/core/templates/maya.yml index 7548a3020..a0b25a644 100644 --- a/core/templates/maya.yml +++ b/core/templates/maya.yml @@ -23,6 +23,19 @@ keys: ass: Arnold (.ass) default: ass + palette_name: + type: str + filter_by: '^[a-zA-Z](\w+)?[a-zA-Z0-9]$' + + description_name: + type: str + filter_by: '^[a-zA-Z](\w+)?[a-zA-Z0-9]$' + + patch_name: + type: str + filter_by: '^[a-zA-Z](\w+)?[a-zA-Z0-9]$' + + paths: # WORK AREAS @@ -129,6 +142,42 @@ paths: tk-maya_sequence_asset_work_standin: '@tk-maya_sequence_asset_work_area/cache/standin/@geom_subdirs/@sequence_asset_version_name.{maya.std.ext}' tk-maya_shot_asset_work_standin: '@tk-maya_shot_asset_work_area/cache/standin/@geom_subdirs/@shot_asset_version_name.{maya.std.ext}' + # XGEN FILES + tk-maya_project_work_xgen_file: '@tk-maya_project_work_area/scenes/@project_version_name_xgen_file.xgen' + tk-maya_sequence_work_xgen_file: '@tk-maya_sequence_work_area/scenes/@sequence_version_name_xgen_file.xgen' + tk-maya_shot_work_xgen_file: '@tk-maya_shot_work_area/scenes/@shot_version_name_xgen_file.xgen' + + tk-maya_project_asset_work_xgen_file: '@tk-maya_project_asset_work_area/scenes/@project_asset_version_name_xgen_file.xgen' + tk-maya_sequence_asset_work_xgen_file: '@tk-maya_sequence_asset_work_area/scenes/@sequence_asset_version_name_xgen_file.xgen' + tk-maya_shot_asset_work_xgen_file: '@tk-maya_shot_asset_work_area/scenes/@shot_asset_version_name_xgen_file.xgen' + + # XGEN Patches + tk-maya_project_work_xgen_patch: '@tk-maya_project_work_area/scenes/@project_version_name_xgen_file.abc' + tk-maya_sequence_work_xgen_patch: '@tk-maya_sequence_work_area/scenes/@sequence_version_name_xgen_file.abc' + tk-maya_shot_work_xgen_patch: '@tk-maya_shot_work_area/scenes/@shot_version_name_xgen_file.abc' + + tk-maya_project_asset_work_xgen_patch: '@tk-maya_project_asset_work_area/scenes/@project_asset_version_name_xgen_file.abc' + tk-maya_sequence_asset_work_xgen_patch: '@tk-maya_sequence_asset_work_area/scenes/@sequence_asset_version_name_xgen_file.abc' + tk-maya_shot_asset_work_xgen_patch: '@tk-maya_shot_asset_work_area/scenes/@shot_asset_version_name_xgen_file.abc' + + # XGEN COLLECTIONS + tk-maya_project_work_xgen_collection: '@tk-maya_project_work_area/@xgen_collection_subdirs' + tk-maya_sequence_work_xgen_collection: '@tk-maya_sequence_work_area/@xgen_collection_subdirs' + tk-maya_shot_work_xgen_collection: '@tk-maya_shot_work_area/@xgen_collection_subdirs' + + tk-maya_project_asset_work_xgen_collection: '@tk-maya_project_asset_work_area/@xgen_collection_subdirs' + tk-maya_sequence_asset_work_xgen_collection: '@tk-maya_sequence_asset_work_area/@xgen_collection_subdirs' + tk-maya_shot_asset_work_xgen_collection: '@tk-maya_shot_asset_work_area/@xgen_collection_subdirs' + + # 3dPaintTextures FILES + tk-maya_project_work_3dPaintTextures: '@tk-maya_project_work_area/@3dPaintTextures_subdir/@project_version_name' + tk-maya_sequence_work_3dPaintTextures: '@tk-maya_sequence_work_area/@3dPaintTextures_subdir/@sequence_version_name' + tk-maya_shot_work_3dPaintTextures: '@tk-maya_shot_work_area/@3dPaintTextures_subdir/@shot_version_name' + + tk-maya_project_asset_work_3dPaintTextures: '@tk-maya_project_asset_work_area/@3dPaintTextures_subdir/@project_asset_version_name' + tk-maya_sequence_asset_work_3dPaintTextures: '@tk-maya_sequence_asset_work_area/@3dPaintTextures_subdir/@sequence_asset_version_name' + tk-maya_shot_asset_work_3dPaintTextures: '@tk-maya_shot_asset_work_area/@3dPaintTextures_subdir/@shot_asset_version_name' + aliases: # PUBLISH AREAS diff --git a/hooks/tk-multi-publish2/maya/collector_xgen_dependencies.py b/hooks/tk-multi-publish2/maya/collector_xgen_dependencies.py new file mode 100644 index 000000000..2d8fcecfd --- /dev/null +++ b/hooks/tk-multi-publish2/maya/collector_xgen_dependencies.py @@ -0,0 +1,348 @@ +# Copyright (c) 2017 Shotgun Software Inc. +# +# CONFIDENTIAL AND PROPRIETARY +# +# This work is provided "AS IS" and subject to the Shotgun Pipeline Toolkit +# Source Code License included in this distribution package. See LICENSE. +# By accessing, using, copying or modifying this work you indicate your +# agreement to the Shotgun Pipeline Toolkit Source Code License. All rights +# not expressly granted therein are reserved by Shotgun Software Inc. + +import glob +import copy +import traceback +import os + +import maya.cmds as cmds +import sgtk +from sgtk import TankError +from sgtk.templatekey import SequenceKey +from maya_xgen_handle import MayaXgenHandle + +HookBaseClass = sgtk.get_hook_baseclass() + + +# This is a dictionary of file type info that allows the basic collector to +# identify common production file types and associate them with a display name, +# item type, and config icon. +MAYA_SESSION_ITEM_TYPES = { + "maya.session": { + "icon_path": "{self}/hooks/icons/maya.png", + "type_display": "Maya Session" + }, + "maya.geometry": { + "icon_path": "{self}/hooks/icons/geometry.png", + "type_display": "Geometry" + } +} + + +class MayaSessionCollector(HookBaseClass): + """ + Collector that operates on the current maya session. Should + inherit from the basic collector hook. + """ + def __init__(self, parent, **kwargs): + """ + Construction + """ + # call base init + super(MayaSessionCollector, self).__init__(parent, **kwargs) + + # cache the workfiles app + self.__workfiles_app = self.parent.engine.apps.get("tk-multi-workfiles2") + + @property + def settings_schema(self): + """ + Dictionary defining the settings that this collector expects to receive + through the settings parameter in the process_current_session and + process_file methods. + + A dictionary on the following form:: + + { + "Settings Name": { + "type": "settings_type", + "default_value": "default_value", + "description": "One line description of the setting" + } + + The type string should be one of the data types that toolkit accepts as + part of its environment configuration. + """ + schema = super(MayaSessionCollector, self).settings_schema + schema["Item Types"]["default_value"].update(MAYA_SESSION_ITEM_TYPES) + schema["Work File Templates"] = { + "type": "list", + "values": { + "type": "template", + "description": "", + "fields": "context, *" + }, + "default_value": [], + "allows_empty": True, + "description": "A list of templates to use to search for work files." + } + + # Schema for Xgen file + schema["file.xgen"] = { + "type": "list", + "description": "List of xgen file publish settings.", + "skip_validation": "True", + "values": { + "type": "dict", + "description": "", + "items": { + "extensions": { + "type": "str" + }, + "publish_type": { + "type": "str" + }, + "publish_path_template": { + "type": "template", + "default": {}, + "description": "Xgen file publish path template" + } + } + }, + } + + # Schema for Xgen patch cache + schema["file.xgen.patch"] = { + "type": "list", + "description": "List of xgen file patch publish settings.", + "skip_validation": "True", + "values": { + "type": "dict", + "description": "", + "items": { + "extensions": { + "type": "str" + }, + "publish_type": { + "type": "str" + }, + "publish_path_template": { + "type": "template", + "default": {}, + "description": "Xgen file patch publish path template" + } + } + }, + } + # Schema for Xgen collection folder + schema["file.xgen.collection"] = { + "type": "list", + "description": "List of xgen collection publish settings.", + "skip_validation": "True", + "values": { + "type": "dict", + "description": "", + "items": { + "extensions": { + "type": "str" + }, + "publish_type": { + "type": "str" + }, + "publish_path_template": { + "type": "template", + "default": {}, + "description": "Xgen collection publish path template" + } + } + }, + } + # Schema for 3dPaintTextures + schema["file.3dPaintTextures"] = { + "type": "list", + "description": "List of 3dPaintTextures publish settings.", + "skip_validation": "True", + "values": { + "type": "dict", + "description": "", + "items": { + "extensions": { + "type": "str" + }, + "publish_type": { + "type": "str" + }, + "publish_path_template": { + "type": "template", + "default": {}, + "description": "3dPaintTextures publish path template" + } + } + }, + } + return schema + + def process_current_session(self, settings, parent_item): + """ + Analyzes the current session open in Maya and parents a + subtree of items under the parent_item passed in. + + :param dict settings: Configured settings for this collector + :param parent_item: Root item instance + """ + items = super(MayaSessionCollector, self).process_current_session(settings, parent_item) + + session_item = None + for item in items: + if item.type_spec == "maya.session": + session_item = item + break + # Adding xgen dependencies as session item properties + self.collect_xgen_dependencies(settings, session_item) + + # Collecting 3dPainteTextures + self.collect_paint_textures(settings, session_item) + + return items + + def collect_paint_textures(self, settings, parent_item): + """ + Collect 3dPainteTextures as session item + properties attribute with name "paint_textures" + + The reason for collecting entire folder instated + of individual files is then we need to crate really + long dictionary of work_files and publish_files and run + a long loop. Unless there is a way to publish dir + could be same for multiple dependency files. + + :param settings: + :param parent_item: + :return: + """ + # Get maya scene name + scene_name = os.path.basename(cmds.file(q=True, sceneName=True)) + # Removing scene name extension + scene_name = os.path.splitext(scene_name)[0] + + workspace_path = cmds.workspace(q=True, rootDirectory=True) + + paintTextures_dir = os.path.join(workspace_path, 'sourceimages', '3dPaintTextures', scene_name) + + # Adding 3dPaintTextures folder in collector + if os.path.isdir(paintTextures_dir): + dict_values = dict() + dict_values.update(self.resolve_custom_path_template( + settings, parent_item, 'file.3dPaintTextures', paintTextures_dir)) + self.logger.info(" Collected file.3dPaintTextures: '%s'" % (paintTextures_dir)) + + parent_item.properties.paint_textures = dict_values + + return None + + def collect_xgen_dependencies(self, settings, parent_item): + """ + Collect live palettes dependencies as session item + properties attribute with name "xgen_dependencies" + + :param settings: + :param parent_item: session item + :return: + """ + + # Instance of maya xgen handle + xgen_handle = MayaXgenHandle() + + # Collecting all available live palettes information + palette_info = xgen_handle.get_live_palette_info() + + if palette_info: + xgen_dependencies = dict() + for palette in palette_info.iterkeys(): + + dict_values = dict() + + # Adding xgen file in collector + xgFileName = palette_info[palette]['xgFileName'] + if os.path.isfile(xgFileName): + dict_values.update( + self.resolve_custom_path_template( + settings, parent_item, 'file.xgen', str(xgFileName))) + self.logger.info(" Collected file.xgen: '%s'" % (os.path.basename(xgFileName))) + else: + error_msg = "Collect Xgen Dependencies failed. " \ + "Missing xgen file: '{}'".format(xgFileName) + self.logger.error(error_msg) + raise Exception(error_msg) + + # Adding xgen data path in collector + xgDataPath = palette_info[palette]['xgDataPath'] + if os.path.isdir(xgDataPath): + dict_values.update(self.resolve_custom_path_template( + settings, parent_item, 'file.xgen.collection', xgDataPath)) + self.logger.info(" Collected file.xgen.collection: '%s'" % (xgDataPath)) + else: + error_msg = "Collect Xgen Dependencies failed. " \ + "Missing xgen data path: '{}'".format(xgDataPath) + self.logger.error(error_msg) + raise Exception(error_msg) + + # Adding xgen data path in collector + xgPatchCache = palette_info[palette]['xgPatchCache'] + if os.path.isfile(xgPatchCache): + dict_values.update(self.resolve_custom_path_template( + settings, parent_item, 'file.xgen.patch', xgPatchCache)) + self.logger.info(" Collected file.xgen.patch: '%s'" % (os.path.basename(xgPatchCache))) + else: + error_msg = "Collect Xgen Dependencies failed. " \ + "Missing xgen patch caches: '{}'".format(xgPatchCache) + self.logger.error(error_msg) + raise Exception(error_msg) + + xgen_dependencies[str(palette)] = dict_values + parent_item.properties.xgen_dependencies = xgen_dependencies + return None + + def resolve_custom_path_template(self, settings, parent_item, item_key, work_path): + """ + Resolve custom work and publish path_template from the given work_path for the + specified item. + + :param settings: collector settings + :param parent_item: parent item + :param item_key: valid settings item key + :param work_path: source work path to resolve publish type and publish path + :return: Resolved values in dict format: {publish_type:{work_path:, publish_path:}} + """ + + resolved_values = dict() + + work_tmpl = self.sgtk.template_from_path(work_path) + fields = work_tmpl.get_fields(work_path) + + if item_key == 'file.xgen.collection': + """ + By default xgen collection doesn't maintain versions + and link with source maya file. So to resolve this issue, + We are collecting session item fields and passing the + missing values to xgen collections publish template + fields which creates the folder with session file name + and publishes collections inside. + """ + # Resolve session work path template + session_work_path = parent_item.properties.path + session_work_template = self.sgtk.template_from_path(session_work_path) + session_item_fields = session_work_template.get_fields(session_work_path) + + # Adding required session name fields + fields['Step'] = session_item_fields['Step'] + fields['name'] = session_item_fields['name'] + fields['version'] = session_item_fields['version'] + + publish_tmp_name = settings[item_key]['publish_path_template'].value + publish_tmp_obj = self.sgtk.templates[publish_tmp_name] + publish_path = publish_tmp_obj.apply_fields(fields) + publish_type = settings[item_key]['publish_type'].value + + resolved_values[publish_type] = {'work_path': str(work_path), 'publish_path': str(publish_path)} + + return resolved_values + diff --git a/hooks/tk-multi-publish2/maya/publish_session_xgen.py b/hooks/tk-multi-publish2/maya/publish_session_xgen.py new file mode 100644 index 000000000..685ab0742 --- /dev/null +++ b/hooks/tk-multi-publish2/maya/publish_session_xgen.py @@ -0,0 +1,303 @@ +# Copyright (c) 2017 Shotgun Software Inc. +# +# CONFIDENTIAL AND PROPRIETARY +# +# This work is provided "AS IS" and subject to the Shotgun Pipeline Toolkit +# Source Code License included in this distribution package. See LICENSE. +# By accessing, using, copying or modifying this work you indicate your +# agreement to the Shotgun Pipeline Toolkit Source Code License. All rights +# not expressly granted therein are reserved by Shotgun Software Inc. + +import sgtk +from sgtk.util import filesystem +import os +import xgenm as xg +import maya.cmds as cmds +import pprint +from maya_xgen_handle import MayaXgenHandle + +HookBaseClass = sgtk.get_hook_baseclass() + +class MayaPublishSessionGroomPlugin(HookBaseClass): + """ + Inherits from MayaPublishSessionPlugin + Modified to export xgen palettes and groom_set if its available in scene. + """ + + def publish_files(self, task_settings, item, publish_path, work_path=None, publish_type=None, palette=None): + """ + This method publishes (copies) the item's path property to the publish location. + + :param task_settings: Dictionary of Settings. The keys are strings, matching + the keys returned in the settings property. The values are `Setting` + instances. + :param item: Item to process + :param publish_path: The output path to publish files to + """ + publisher = self.parent + path = item.properties.get("path") + if not path: + raise KeyError("Base class implementation of publish_files() method requires a 'path' property.") + + # Determine if we should seal the copied files or not + seal_files = item.properties.get("seal_files", True) + + xgen_handle = MayaXgenHandle() + + if publish_type == "Xgen Collection": + publisher.util.copy_folder([work_path], publish_path, seal_folder=seal_files) + self.logger.info("Published Xgen Collection: {}".format(publish_path)) + + elif publish_type == 'Xgen Patch File': + publisher.util.copy_files([work_path], publish_path, seal_files=seal_files, is_sequence=False) + self.logger.info("Published Xgen Patch File: {}".format(publish_path)) + + elif publish_type == "Xgen Files": + # Exporting temporary remapped palettes to publish path + xg.exportPalette(palette, publish_path) + self.logger.info("Published Xgen File: {}".format(publish_path)) + if seal_files: + filesystem.seal_file(publish_path) + + elif publish_type == '3dPaintTextures': + publisher.util.copy_folder([work_path], publish_path, seal_folder=seal_files) + self.logger.info("Published 3dPaintTextures: {}".format(publish_path)) + + else: + """ + Proceed and publish Maya session item + - We also need to remap 3dPaintTexture maps from publish dir. + Problem with adding this under 3dPaintTextures publish type is + Maya creates default texture directory on server before session item publish. + - Secondly if xgen dependencies are exist in scene then + """ + work_path = path + + self.remap_paint_textures_from_target(item, xgen_handle, target='publish_path') + + if item.get_property("xgen_dependencies"): + """ + If xgen dependencies are exists in the scene then perform predefine nodes + export action instead of coping entire session file. + """ + + # Re-mapping xgen file name from publish path + xgen_dependencies = item.properties.xgen_dependencies + + for palette in xgen_dependencies.iterkeys(): + self.logger.info("Mapping Xgen Palettes from Publish Path...") + xgen_handle.set_cur_xgen_file( + palette, xgen_dependencies[palette]['Xgen Files']['publish_path'], check_existence=False) + + # Get predefined publish objects for grooming team + cmds.select(self.get_publish_objects(), noExpand=True) + publish_path = os.path.splitext(publish_path)[0] + + # EXPORT PUBLISH OBJECTS IF XGEN IS AVAILABLE IN SCENE + self.logger.info("Exporting Session item to Publish Path...") + published_path = cmds.file( + publish_path, exportSelected=True, force=True, options="v=0;", type='mayaAscii') + cmds.select(clear=True) + + filesystem.seal_file(published_path) + self.logger.info("Mapping Xgen Palettes from Workspace...") + xgen_handle.set_palettes_from_workspace() + + else: + """ + If xgen dependencies doesn't exists in the scene then perform copy session item file. + """ + publisher.util.copy_files([work_path], publish_path, seal_files=seal_files, is_sequence=False) + + self.remap_paint_textures_from_target(item, xgen_handle, target='work_path') + + return publish_path + + @staticmethod + def remap_paint_textures_from_target(item, xgen_handle, target=None): + """ + Remap 3dPaintTextures from given target value. + :param item: session item + :param target: "publish_path" OR "work_path" + :return: + """ + if item.get_property("paint_textures"): + """ + Re map 3dPaintTextures from target path to avoid map creations in shared location. + """ + + paint_textures = item.properties.paint_textures + + for key in paint_textures.keys(): + xgen_handle.re_map_source_images(str(paint_textures[key][target])) + + def publish(self, task_settings, item): + """ + Executes the publish logic for the given item and task_settings. + + :param task_settings: Dictionary of Settings. The keys are strings, matching + the keys returned in the task_settings property. The values are `Setting` + instances. + :param item: Item to process + """ + sg_fields = {} + additional_fields = task_settings.get("additional_publish_fields").value or {} + for template_key, sg_field in additional_fields.iteritems(): + if template_key in item.get_property("fields"): + sg_fields[sg_field] = item.get_property("fields")[template_key] + + publish_name = item.get_property("publish_name") + publish_version = item.get_property("publish_version") + publish_user = item.get_property("publish_user", default_value=None) + + if item.get_property("xgen_dependencies"): + item.properties["xgen_publish_ids"] = [] + + # Instantiate Maya xgen handle + xgen_handle = MayaXgenHandle() + + xgen_dependencies = item.properties.xgen_dependencies + self.logger.info("Processing on xgen dependencies...") + + for palette, values in xgen_dependencies.items(): + publish_xgen_file = xgen_dependencies[palette]['Xgen Files']['publish_path'] + publish_dir = os.path.dirname(publish_xgen_file) + publish_collection_dir = xgen_dependencies[palette]['Xgen Collection']['publish_path'] + + # Parsing xgen file from publish path + self.logger.info( + "Re mapping paths for '{}' from publish path {} ".format(palette, publish_dir)) + xgen_handle.set_palette_from_target(palette, publish_dir, publish_collection_dir, check_existence=False) + + for key in values.iterkeys(): + publish_type = key + work_path = values[key]['work_path'] + publish_path = values[key]['publish_path'] + + self.publish_files(task_settings, item, publish_path, work_path, publish_type, palette) + self._create_published_file_entity(task_settings, item, publish_path, publish_name, publish_user, + publish_version, publish_type, sg_fields) + + if item.get_property("paint_textures"): + item.properties["3dPaintTextures_publish_ids"] = [] + + paint_textures = item.properties.paint_textures + self.logger.info("Processing on 3dPaintTextures...") + + for key in paint_textures.keys(): + publish_type = key + work_path = paint_textures[key]['work_path'] + publish_path = paint_textures[key]['publish_path'] + + self.publish_files(task_settings, item, publish_path, work_path, publish_type) + self._create_published_file_entity(task_settings, item, publish_path, publish_name, publish_user, + publish_version, publish_type, sg_fields) + + # publish maya file + super(MayaPublishSessionGroomPlugin, self).publish(task_settings, item) + + def _create_published_file_entity(self, task_settings, item, publish_path, publish_name, publish_user, + publish_version, publish_type, sg_fields): + publish_data = { + "tk": self.parent.sgtk, + "context": item.context, + "comment": item.description, + "path": publish_path, + "name": publish_name, + "created_by": publish_user, + "version_number": publish_version, + "thumbnail_path": item.get_thumbnail_as_path() or "", + "published_file_type": publish_type, + "dependency_ids": [], + "dependency_paths": [], + "sg_fields": sg_fields + } + + self.logger.debug( + "Populated Publish data...", + extra={ + "action_show_more_info": { + "label": "Publish Data", + "tooltip": "Show the complete Publish data dictionary", + "text": "
%s" % (pprint.pformat(publish_data),) + } + } + ) + + exception = None + sg_publish_data = None + # create the publish and stash it in the item properties for other + # plugins to use. + try: + sg_publish_data = sgtk.util.register_publish(**publish_data) + self.logger.info("Publish registered!") + self.logger.debug( + "Shotgun Publish data...", + extra={ + "action_show_more_info": { + "label": "Shotgun Publish Data", + "tooltip": "Show the complete Shotgun Publish Entity dictionary", + "text": "
%s" % (pprint.pformat(sg_publish_data),) + } + } + ) + except Exception as e: + import traceback + exception = e + self.logger.error( + "Couldn't register Publish for %s" % item.name, + extra={ + "action_show_more_info": { + "label": "Show Error Log", + "tooltip": "Show the error log", + "text": traceback.format_exc() + } + } + ) + + if not sg_publish_data: + self.undo(task_settings, item) + else: + item.properties.xgen_publish_ids.append(sg_publish_data["id"]) + + item.properties.setdefault("sg_publish_data_list", []) + item.local_properties.setdefault("sg_publish_data_list", []) + + # add the publish data to local and global item properties + item.local_properties.sg_publish_data_list.append(sg_publish_data) + item.properties.sg_publish_data_list.append(sg_publish_data) + + if exception: + raise exception + + def _get_dependency_ids(self, task_settings, item): + """ + Extend dependency ids for additional items that has been added as item properties. + :param task_settings: + :param item: + :return: + """ + dependency_ids = super(MayaPublishSessionGroomPlugin, self)._get_dependency_ids(task_settings, item) + if item.get_property("xgen_dependencies"): + dependency_ids.extend(item.get_property("xgen_publish_ids")) + if item.get_property("paint_textures"): + dependency_ids.extend(item.get_property("3dPaintTextures_publish_ids")) + return dependency_ids + + @staticmethod + def get_publish_objects(): + """ + To export xgen palettes, groom_set and associated node and pass as publish item file path + to make sure only required data get published. + :return: If session has xgen palettes then exported file path else the same input path. + """ + publish_dependencies = [] + + # Select all palettes available in scene. + publish_dependencies.extend([x for x in xg.palettes()]) + # Select object set with name 'groom_set' to export with publish data. + if cmds.objExists('groom_set') and cmds.nodeType('groom_set') == 'objectSet': + publish_dependencies.append('groom_set') + + return publish_dependencies +