# -*- coding: utf-8 -*-
"""
The rig_module provides the base class, ART_Component, from which all rig modules are derived.
When creating a new rig module, here is a list of common attributes and functions you will want or need to override.
+------------+------------------------+----------------------------------------------------------------------------+
| Type | Name | Description |
+============+========================+============================================================================+
| attribute | nice_name | The string nice name of the module (as it will appear in UIs) |
+------------+------------------------+----------------------------------------------------------------------------+
| attribute | base_name | The string base name of the module. This is a simple string used to |
| | | identify the module type and append onto nodes created by the module. |
| | | For example, on a leg module, the base_name is simply: "leg" |
+------------+------------------------+----------------------------------------------------------------------------+
| attribute | has_sides | Boolean for whether or not the module supports different sides, like a leg |
| | | or arm do. |
+------------+------------------------+----------------------------------------------------------------------------+
| attribute | joint_mover_file | The relative path from the ARTv2 directory to the joint mover file of the |
| | | module. For example, self.joint_mover_file = |
| | | "resources/rigging_guides/root.ma" |
+------------+------------------------+----------------------------------------------------------------------------+
| function | _add_metadata | This method adds attributes you want to keep track of that are unique to |
| | | your module. Make sure that you still call on the base class's |
| | | _add_metadata method to setup the required attributes. |
+------------+------------------------+----------------------------------------------------------------------------+
"""
import inspect
import os
from abc import abstractmethod, ABCMeta
import maya.cmds as cmds
import pymel.core as pm
import artv2_utilities.error_utilities as errors
import artv2_utilities.general_utilities as utils
import artv2_utilities.rig_module_utilities as module_utils
from joint_mover import JointMover
reload(module_utils)
reload(utils)
# noinspection PyPep8Naming
[docs]class ART_Component(object):
"""
Base class for defining a rig module in ARTv2. All rig modules should inherit from this class.
"""
__metaclass__ = ABCMeta
nice_name = ""
base_name = None
has_sides = False
up = cmds.upAxis(q=True, ax=True)
joint_mover_file = "replace_me_with_valid_path.ma"
@abstractmethod
def __init__(self, prefix="", suffix="", network_node=None):
prefix = module_utils.validate_prefix(network_node, prefix)
suffix = module_utils.validate_suffix(network_node, suffix)
if network_node is None:
self._unique_name = prefix + self.base_name + suffix
self._create_component(prefix, suffix)
self.joint_mover = JointMover(self.joint_mover_file, self.network_node)
self.joint_mover.add_joint_mover()
else:
if cmds.objExists(network_node):
prefix = cmds.getAttr(network_node + ".prefix")
suffix = cmds.getAttr(network_node + ".suffix")
self._unique_name = prefix + self.base_name + suffix
self.joint_mover = JointMover(self.joint_mover_file, network_node)
self.prefix = prefix
self.suffix = suffix
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def _create_component(self, prefix, suffix):
"""
Method for adding the module to the Maya scene. Calls on various functions to accomplish.
"""
character_node = module_utils.get_rig_asset_node()
network_node = self._create_network_node()
self._add_metadata(network_node, prefix, suffix)
cmds.connectAttr(character_node + ".rigModules", network_node + ".asset")
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
@abstractmethod
def _add_metadata(self, network_node, prefix, suffix):
"""
Method for adding metadata attributes to the network node that are important for the module. The ones created
by the base class are necessary for all modules.
:param (str) network_node: module's network node name to add attributes to.
:param (str) prefix: the module's (optional) prefix.
:param (str) suffix: the module's (optional) suffix.
"""
cmds.lockNode(network_node, lock=False)
cmds.addAttr(network_node, ln="asset", at="message")
cmds.addAttr(network_node, ln="modulePath", dt="string", keyable=False)
module_path = os.path.splitext(inspect.getfile(self.__class__).split("artv2_source")[1])[0]
module_path = module_path.replace("\\", ".")
module_path = module_path.partition(".")[2]
cmds.setAttr(network_node + ".modulePath", module_path, type="string", lock=True)
cmds.addAttr(network_node, ln="className", dt="string", keyable=False)
cmds.setAttr(network_node + ".className", self.__class__.__name__, type="string", lock=True)
cmds.addAttr(network_node, ln="moduleName", dt="string", keyable=False)
cmds.setAttr(network_node + ".moduleName", self._unique_name, type="string", lock=True)
cmds.addAttr(network_node, ln="baseName", dt="string", keyable=False)
cmds.setAttr(network_node + ".baseName", self.base_name, type="string", lock=True)
cmds.addAttr(network_node, ln="prefix", dt="string", keyable=False)
cmds.setAttr(network_node + ".prefix", prefix, type="string", lock=True)
cmds.addAttr(network_node, ln="suffix", dt="string", keyable=False)
cmds.setAttr(network_node + ".suffix", suffix, type="string", lock=True)
cmds.addAttr(network_node, ln="parentModuleBone", dt="string", keyable=False)
cmds.addAttr(network_node, ln="mirrorModule", dt="string", keyable=False)
cmds.addAttr(network_node, ln="pinned", at="bool", keyable=False)
cmds.setAttr(network_node + ".pinned", False, lock=True)
cmds.addAttr(network_node, ln="global_movers", at="message")
cmds.addAttr(network_node, ln="offset_movers", at="message")
cmds.addAttr(network_node, ln="geo_movers", at="message")
cmds.addAttr(network_node, ln="lra_movers", at="message")
cmds.addAttr(network_node, ln="mover_grp", at="message")
cmds.lockNode(network_node, lock=True)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def _create_network_node(self):
existing_nodes = module_utils.return_all_components()
for node in existing_nodes:
if cmds.getAttr(node + ".moduleName") == self._unique_name:
errors.raise_error("This module instance has already been created! Aborting.")
return
network_node = cmds.shadingNode("network", name=self._unique_name + "_metadata", asUtility=True)
cmds.lockNode(network_node, lock=True)
return network_node
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
@property
def parent(self):
"""
This property holds the joint name of the parent of this module.
"""
return cmds.getAttr(self.network_node + ".parentModuleBone")
@parent.setter
def parent(self, new_parent):
all_joints = module_utils.get_all_created_joints()
if new_parent in all_joints:
utils.set_attribute(self.network_node, "parentModuleBone", new_parent, "string")
self.joint_mover.set_mover_parent(new_parent)
else:
errors.raise_error("Invalid parent: {0}! No module creates such a joint.".format(new_parent))
return
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
@property
def prefix(self):
return cmds.getAttr(self.network_node + ".prefix")
@prefix.setter
def prefix(self, new_prefix):
valid_prefix = module_utils.validate_prefix(self.network_node, new_prefix)
if valid_prefix is not False:
old_prefix = self.prefix
suffix = self.suffix
utils.set_attribute(self.network_node, "prefix", valid_prefix, "string")
utils.set_attribute(self.network_node, "moduleName", valid_prefix + self.base_name + suffix, "string")
self._unique_name = valid_prefix + self.base_name + suffix
pynode = pm.PyNode(self.network_node)
utils.rename_object(pynode, self._unique_name + "_metadata")
self.joint_mover.metanode = self._unique_name + "_metadata"
self.joint_mover.rename_movers(old_prefix, self.suffix)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
@property
def suffix(self):
return cmds.getAttr(self.network_node + ".suffix")
@suffix.setter
def suffix(self, new_suffix):
valid_suffix = module_utils.validate_suffix(self.network_node, new_suffix)
if valid_suffix is not False:
old_suffix = self.suffix
prefix = self.prefix
utils.set_attribute(self.network_node, "suffix", valid_suffix, "string")
utils.set_attribute(self.network_node, "moduleName", prefix + self.base_name + valid_suffix, "string")
self._unique_name = prefix + self.base_name + valid_suffix
pynode = pm.PyNode(self.network_node)
utils.rename_object(pynode, self._unique_name + "_metadata")
self.joint_mover.metanode = self._unique_name + "_metadata"
self.joint_mover.rename_movers(self.prefix, old_suffix)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
@property
def network_node(self):
"""
This property holds the network node that contains this module's metadata.
"""
return_node = None
rig_modules = module_utils.return_all_components()
for module in rig_modules:
if cmds.getAttr(module + ".moduleName") == self._unique_name:
return_node = module
break
if return_node is None:
errors.raise_error("ART_Component.network_node: No network node found.")
return
return return_node