{"id":117,"date":"2008-08-11T23:42:42","date_gmt":"2008-08-12T06:42:42","guid":{"rendered":"http:\/\/www.rodgreen.com\/wordpress\/?p=117"},"modified":"2008-08-11T23:42:42","modified_gmt":"2008-08-12T06:42:42","slug":"renaming-objects-in-maya-advanced","status":"publish","type":"post","link":"https:\/\/www.rodgreen.com\/?p=117","title":{"rendered":"Renaming objects in Maya (advanced)"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" alt=\"\" height=\"283\" src=\"https:\/\/www.rodgreen.com\/wp-content\/uploads\/image\/Icons\/rename_advanced.png\" width=\"308\" \/><\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"https:\/\/www.rodgreen.com\/scripts\/mel\/renameAdvanced.mel\" onclick=\"window.open(this.href,'renameIntermediate','resizable=yes,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,fullscreen=no,dependent=no,status'); return false\">[Download Script]<\/a><\/p>\n<p>&nbsp;<\/p>\n<p>This is the third part to a three part tutorial on renaming objects in Maya.&nbsp; In the <a href=\"https:\/\/www.rodgreen.com\/wordpress\/?p=23\">first installment<\/a> we established a collection of procedures and a simple UI that allows multiple objects to be renamed. In the <a href=\"https:\/\/www.rodgreen.com\/wordpress\/?p=80\">second installment<\/a> we evolved this tool to utilize an custom sorting method and improved the UI.<\/p>\n<p>The previous system for sorting while functional limited our ability to do more sophisticated renaming. We&#39;re going to address these issues and introduce a neat system for managing object lists:<\/p>\n<ul>\n<li>Ultimately we want to support an extended set of rename options (Prefix, Suffix, Find &amp; Replace, exclusions) along with the standard rename and numeric incrementation<\/li>\n<\/ul>\n<p><!--more--><\/p>\n<h3>What&#39;s the goal exactly?<\/h3>\n<p>We need to advance the existing tool to support the following:<\/p>\n<ul>\n<li>Stronger method for tracking objects and name changes through some form of &#39;object pointer list&#39;<\/li>\n<li>Remove the need to sort objects<\/li>\n<li>Improve UI<\/li>\n<\/ul>\n<h3>What could go wrong?<\/h3>\n<ul>\n<li>Filtering objects can be tricky mainly due to the inherited nature of objects (i.e. mesh object is also a shape object)<\/li>\n<li>Handling shape objects; Should shape objects be skipped? should the rename operation be set to ignore shapes?<\/li>\n<\/ul>\n<h2>&nbsp;<\/h2>\n<h2>Lets get started&#8230;<\/h2>\n<hr \/>\n<h3>Utility procedures<\/h3>\n<h4 style=\"margin-left: 40px;\">&nbsp;<\/h4>\n<h4 style=\"margin-left: 40px;\">padInt (Unchanged)<\/h4>\n<pre style=\"margin-left: 80px;\">global proc string padInt(int $inputInt, int $length)\n{\n    string $returnString = $inputInt;\n\n&nbsp;&nbsp; &nbsp;for($i = size($returnString); $i &lt; $length; $i++) $returnString = (&quot;0&quot; + $returnString);\n\n&nbsp;&nbsp; &nbsp;return $returnString;\n}\n<\/pre>\n<p style=\"margin-left: 40px;\">Description:<\/p>\n<p style=\"margin-left: 40px;\">This will take the input integer value and pad it with preceding zeros so that it fills a certain text length.<\/p>\n<p style=\"margin-left: 40px;\">&nbsp;<\/p>\n<p style=\"margin-left: 40px;\">Details:<\/p>\n<p style=\"margin-left: 40px;\">If the $inputInt is longer in string length then the specific $length it will return the original int as a string.<\/p>\n<p style=\"margin-left: 40px;\">&nbsp;<\/p>\n<p style=\"margin-left: 40px;\">&nbsp;<\/p>\n<h4 style=\"margin-left: 40px;\">getSelection (Unchanged)<\/h4>\n<pre style=\"margin-left: 80px;\">global proc string[] getSelection()\n{\n\treturn (ls(&quot;-selection&quot;, &quot;-long&quot;, &quot;-flatten&quot;));\n}\n<\/pre>\n<p style=\"margin-left: 40px;\">Description:<\/p>\n<p style=\"margin-left: 40px;\">While none of my core or utility procedures rely on switching and querying selection I do a lot of interfacing with the user through their selection. So a unified selection query procedure is important. The long and flatten flags returns the objects with long paths and flattened individualized list respectively.<\/p>\n<p style=\"margin-left: 40px;\">i.e.<\/p>\n<blockquote><p>&nbsp;<\/p><\/blockquote>\n<blockquote>\n<pre style=\"margin-left: 40px;\">{&quot;locator1&quot;, &quot;pCube1.uv[0:2]&quot;}<\/pre>\n<\/blockquote>\n<blockquote><p>&nbsp;<\/p><\/blockquote>\n<p style=\"margin-left: 40px;\">would return as<\/p>\n<blockquote><p>&nbsp;<\/p><\/blockquote>\n<blockquote>\n<pre style=\"margin-left: 40px;\">{&quot;|pCube1|pCube2|locator1&quot;, &quot;|pCube1.uv[0]&quot;, &quot;|pCube1.uv[1]&quot;, &quot;|pCube1.uv[2]&quot;}<\/pre>\n<\/blockquote>\n<p style=\"margin-left: 40px;\">&nbsp;<\/p>\n<p style=\"margin-left: 40px;\">&nbsp;<\/p>\n<h4 style=\"margin-left: 40px;\">renameLong (Unchanged)<\/h4>\n<pre style=\"margin-left: 80px;\">global proc string renameLong(string $object, string $newName)\n{\n\treturn longNameOf(rename($object, $newName));\n}\n<\/pre>\n<p style=\"margin-left: 40px;\">Description:<\/p>\n<p style=\"margin-left: 40px;\">Renames and object and returns the long form result.<\/p>\n<p style=\"margin-left: 40px;\">&nbsp;<\/p>\n<p style=\"margin-left: 40px;\">Details:<\/p>\n<p style=\"margin-left: 40px;\">As the default rename procedure doesn&#39;t always return the long version of the object we&#39;ll create this wrapper procedure to ensure it does.<\/p>\n<p style=\"margin-left: 40px;\">&nbsp;<\/p>\n<p style=\"margin-left: 40px;\">&nbsp;<\/p>\n<h4 style=\"margin-left: 40px;\">newTransform<\/h4>\n<pre style=\"margin-left: 80px;\">global proc string newTransform(string $name)\n    {\n&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;string $transformObj = createNode(&quot;-skipSelect&quot;, &quot;-name&quot;, $name, &quot;transform&quot;);\n&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;refresh; <strong>\/\/ This is needed to finalize the createNode operation to stop the proc from becoming out of sync<\/strong>\n&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return $transformObj;\n&nbsp;&nbsp; &nbsp;}\n<\/pre>\n<p style=\"margin-left: 40px;\">Description:<\/p>\n<p style=\"margin-left: 40px;\">&nbsp;Creates a new transform object with the given name.<\/p>\n<p style=\"margin-left: 40px;\">&nbsp;<\/p>\n<p style=\"margin-left: 40px;\">Details:<\/p>\n<p style=\"margin-left: 40px;\">&nbsp;I really, really, really (is that enough reallys?) dislike operations that change the selection (unless the operation is specifically intended to change the selection i.e. &#39;selectAllAnimatedObjects&#39;). So I created this script to create a blank transform node with the &#39;-skipSelect&#39; option set to true.&nbsp; This replaces the more common &#39;group -empty&#39; command.<\/p>\n<p style=\"margin-left: 40px;\">\n\tThere seems to be some kind of sync bug however &#8211;&nbsp; I&#39;m guessing it has something to do with Maya spawning this operation off onto a seperate thread.&nbsp; In anycase we need to add a &#39;refresh&#39; call here to make sure Maya updates the scene before we continue.<\/p>\n<p style=\"margin-left: 40px;\">\n\tTry commenting out the refresh and see what results you get from the script.&nbsp; You&#39;ll find the objects rename correctly however the resulting object list returned from the core renameObjects function is blank??!&nbsp; Some voodoo that&#39;s for sure, if anyone can shed some light on this I&#39;d be very interested to hear.<\/p>\n<p style=\"margin-left: 40px;\">&nbsp;<\/p>\n<h4 style=\"margin-left: 40px;\">cleanStringArray<\/h4>\n<pre style=\"margin-left: 80px;\">global proc cleanStringArray(string $inputStringArray[])\n    {\n        string $cleanArray[] = {};\n        for($eachItem in $inputStringArray)\n        {\n&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if($eachItem != &quot;&quot;) $cleanArray[size($cleanArray)] = $eachItem;\n&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}\n\n&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;$inputStringArray = $cleanArray;\n&nbsp;&nbsp; &nbsp;}\n<\/pre>\n<p style=\"margin-left: 40px;\">Description:<\/p>\n<p style=\"margin-left: 40px;\">Pretty quick and simple procedure that will step through a string array and remove any blank entries.<\/p>\n<p style=\"margin-left: 40px;\">&nbsp;<\/p>\n<h4 style=\"margin-left: 40px;\">niceNameOf<\/h4>\n<pre style=\"margin-left: 80px;\">global proc string niceNameOf(string $inputObj)\n    {\n        return(match(&quot;[^|]*$&quot;,$inputObj));\n    }\n\n<\/pre>\n<p style=\"margin-left: 40px;\">Description:<\/p>\n<p style=\"margin-left: 40px;\">Returns the last component of a object name string (everything after the last pipe &quot;|&quot; character).<\/p>\n<p style=\"margin-left: 40px;\">&nbsp;<\/p>\n<p style=\"margin-left: 40px;\">Details:<\/p>\n<p style=\"margin-left: 40px;\">Previously I was utilizing the &#39;shortNameOf&#39; embedded script function however I found that this will return a long form name of an object if there are duplicately named objects in the scene.<br \/>\n\tSo we really wanted the nice name version of the object in anycase.&nbsp; This little match trick will give the result intended.<\/p>\n<p style=\"margin-left: 40px;\">&nbsp;<\/p>\n<h4 style=\"margin-left: 40px;\">cullTrailingInts<\/h4>\n<pre style=\"margin-left: 80px;\">global proc string cullTrailingInts(string $inputString)\n{\n&nbsp;&nbsp;&nbsp; int $intCount = size(match(&quot;[0-9]*$&quot;, $inputString));\n\n&nbsp;&nbsp;&nbsp; return (substring($inputString, 1, size($inputString) - $intCount ));\n\n}\n<\/pre>\n<p style=\"margin-left: 40px;\">Description:<\/p>\n<p style=\"margin-left: 40px;\">&nbsp;Again another simple procedure that will just remove the trailing numeric characters (0 to 9) from a string.<br \/>\n\t&nbsp;&nbsp; &nbsp;i.e. &quot;pCube33&quot; becomes &quot;pCube&quot;&nbsp;<\/p>\n<p style=\"margin-left: 40px;\">&nbsp;<\/p>\n<h4 style=\"margin-left: 40px;\">adjustString<\/h4>\n<pre style=\"margin-left: 80px;\">global proc string adjustString( string $baseString, string $prefix, string $suffix, string $find, string $replace)\n{\n&nbsp;&nbsp;&nbsp; if($find == &quot;&quot;) return ($prefix + $baseString + $suffix);\n&nbsp;&nbsp;&nbsp; return ($prefix + substituteAllString($baseString, $find, $replace) + $suffix);\n}\n<\/pre>\n<p style=\"margin-left: 40px;\">Description:<\/p>\n<p style=\"margin-left: 40px;\">A procedure that processes a list of string inputs into a resulting string.<\/p>\n<p style=\"margin-left: 40px;\">&nbsp;<\/p>\n<p style=\"margin-left: 40px;\">Details:<\/p>\n<p style=\"margin-left: 40px;\">This is a pretty key procedure that allows us to process all the base, prefix, suffix and find\/replace options.<\/p>\n<p style=\"margin-left: 40px;\">&nbsp;<\/p>\n<h4 style=\"margin-left: 40px;\">filterObjectsByTypes<\/h4>\n<pre style=\"margin-left: 80px;\">global proc string[] filterObjectsByTypes(string $objects[], string $types[], int $evalShapeChildren)\n{\n    string $returnObjects[] = {};\n    if(size($objects) == 0 || size($types) == 0) return $objects;\n    for($eachObj in $objects)\n    {\n        int $matches = 0;\n        for($eachType in $types)\n        {\n            $eachType = strip($eachType);\n&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(objectType(&quot;-isAType&quot;, $eachType, $eachObj))\n&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {\n&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; $matches = 1;\n&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;\n&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }\n&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <strong>\/\/ This loop will be called if the evaluate shape children option is true<\/strong>\n&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <strong>\/\/ This way we&#39;re able to distinguish a transforms &#39;shape&#39; type and process as needed<\/strong>\n&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if($evalShapeChildren)\n&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {\n&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; string $shapeChildren[] = listRelatives(&quot;-fullPath&quot;, &quot;-shapes&quot;, $eachObj);\n&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;\n&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for($eachShape in $shapeChildren)\n&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {\n&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;\n&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(objectType(&quot;-isAType&quot;, $eachType, $eachShape))\n&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {\n&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; $matches = 1;\n&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;\n&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;\n&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }\n&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }\n&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }\n&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if(!$matches) $returnObjects[size($returnObjects)] = $eachObj;\n&nbsp;&nbsp;&nbsp; }\n&nbsp;&nbsp;&nbsp; return $returnObjects;\n}\n<\/pre>\n<p style=\"margin-left: 40px;\">Description:<\/p>\n<p style=\"margin-left: 40px;\">&nbsp;Filters through a given list of objects and removes objects matching the types found in $types.&nbsp; If $evalShapeChildren then each objects shape children are also evaluated for the filter even if they weren&#39;t directly selected.<\/p>\n<p style=\"margin-left: 40px;\">&nbsp;<\/p>\n<p style=\"margin-left: 40px;\">Details:<\/p>\n<p style=\"margin-left: 40px;\">This one is a little more tricky.&nbsp; Here we&#39;re quering types of objects and their children to establish a desired list of objects. <br \/>\n\tThe main reason it&#39;s tricky is that nodes inherit from other nodes and so you can get caught when an transform node&#39;s shape is a shape but also another type.<\/p>\n<p style=\"margin-left: 80px;\">\n\ti.e. most objects are built by a shape object (i.e. camera, mesh, locator) parented to a transform and so if you just filtered out all transforms with shapes you would filter out most objects.<\/p>\n<p style=\"margin-left: 40px;\">\n\tSo through the $evalShapeChildres I can distinguish between directly included shape objects and those needing to be derived to establish the actual node type.<\/p>\n<p>&nbsp;<\/p>\n<h3>Utility: Object Pointer System<\/h3>\n<h4 style=\"margin-left: 40px;\">attrSize<\/h4>\n<pre style=\"margin-left: 80px;\">global proc int attrSize( string $baseObject, string $attributeName)\n\t{\n\t\treturn getAttr(&quot;-size&quot;, ($baseObject + &quot;.&quot; + $attributeName));\n\t}<\/pre>\n<p style=\"margin-left: 40px;\">Description:<\/p>\n<p style=\"margin-left: 40px;\">Gets the size of the given attribute<\/p>\n<p style=\"margin-left: 40px;\">&nbsp;<\/p>\n<h4 style=\"margin-left: 40px;\">createObjectPointer<\/h4>\n<pre style=\"margin-left: 80px;\">global proc string createObjectPointer()\n\t{\n\t\tglobal string $pointerObjString;\n\t\tstring $groupObj = newTransform(&quot;__objPointer__&quot;);\n\t\taddAttr -ln $pointerObjString  -multi -at &quot;message&quot; $groupObj;\n\t\treturn $groupObj;\n\t}<\/pre>\n<p style=\"margin-left: 40px;\">Description:<\/p>\n<p style=\"margin-left: 40px;\">This creates a new transform object, assigns it a temp name &quot;__objPointer__&quot; and add the multi message attribute we&#39;re going to use to connect the objects to.<\/p>\n<p>&nbsp;<\/p>\n<h4 style=\"margin-left: 40px;\">addObjectsToPointer<\/h4>\n<pre style=\"margin-left: 80px;\">global proc addObjectsToPointer(string $objects[], string $pointer)\n\t{\n\t\tif (size($objects) == 0 || $pointer == &quot;&quot;) return;\n\t\tglobal string $pointerObjString;\n\n\t\tfor($i = 0; $i &lt; size($objects); $i++)\n\t\t{\n\t\t\tconnectAttr -f ($objects[$i] + &quot;.message&quot;) ($pointer + &quot;.&quot; + $pointerObjString + &quot;[&quot; + $i + &quot;]&quot;);\n\t\t}\n\t}<\/pre>\n<p style=\"margin-left: 40px;\">Description:<\/p>\n<p style=\"margin-left: 40px;\">Loops over the specified objects and one by one add them to the $pointer objects mutli message attribute.<\/p>\n<p style=\"margin-left: 40px;\">&nbsp;<\/p>\n<p style=\"margin-left: 40px;\">Details:<\/p>\n<p style=\"margin-left: 40px;\">Here we have the core method to maintaining the updated object list. This connects the &#39;message&#39; attribute of each object to the multi message (message array) of another.<br \/>\n\tThis connection is automatically updated whenever an object is deleted or renamed because the connection is an actual &#39;link&#39; to the object rather then just a string containing the objects name.<\/p>\n<p style=\"margin-left: 40px;\">&nbsp;<\/p>\n<h4 style=\"margin-left: 40px;\">getObjectFromPointer<\/h4>\n<pre style=\"margin-left: 80px;\">global proc string getObjectFromPointer(string $pointer, int $index)\n\t{\n\t\tglobal string $pointerObjString;\n\t\t$pointer = longNameOf($pointer);\n\t\tstring $returnObject = &quot;&quot;;\n\t\tif (!attributeExists($pointerObjString, $pointer)) return $returnObject; \/\/ Attribute doesn&#39;t exist so return nothing\n\t\tstring $listConnectionsResult[] = listConnections(&quot;-shapes&quot;, 1, &quot;-connections&quot;, 1,\n\t\t\t\t\t\t\t\t\t($pointer + &quot;.&quot;+ $pointerObjString + &quot;[&quot; + $index + &quot;]&quot;));\n\t\treturn longNameOf($listConnectionsResult[1]);\n\t}<\/pre>\n<p style=\"margin-left: 40px;\">Description:<\/p>\n<p style=\"margin-left: 40px;\">Basic procedure to fetch an object from a specific index in the given $pointer objects multi message attribute<\/p>\n<p>&nbsp;<\/p>\n<h4 style=\"margin-left: 40px;\">getObjectsFromPointer<\/h4>\n<pre style=\"margin-left: 80px;\">global proc string[] getObjectsFromPointer(string $pointer)\n\t{\n\t\tglobal string $pointerObjString;\n\t\t$pointer = longNameOf($pointer);\n\t\t\tstring $returnObjects[] = {};\n\t\t\tif (!attributeExists($pointerObjString, $pointer)) return $returnObjects; \/\/ Attribute doesn&#39;t exist so return nothing\n\t\t\tint $attrSize = attrSize($pointer, $pointerObjString);\n\n\t\t\t\/\/ Scan attribute for all connected objects\n\t\t\tfor($i = 0; $i &lt; $attrSize; $i++)\n\t\t\t{\n\t\t\t\tstring $listConnectionsResult[] = listConnections(&quot;-connections&quot;, 1,\n\t\t\t\t\t\t\t\t\t\t\t($pointer + &quot;.&quot;+ $pointerObjString + &quot;[&quot; + $i + &quot;]&quot;));\n\t\t\t\n\t\t\t\tif ($listConnectionsResult[0] != &quot;&quot;) \/\/ Skip blank entries\n\t\t\t\t{\n\t\t\t\t\t$returnObjects[size($returnObjects)] = longNameOf($listConnectionsResult[1]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn $returnObjects;\n\t}<\/pre>\n<p style=\"margin-left: 40px;\">Description:<\/p>\n<p style=\"margin-left: 40px;\">This iterates over the $pointer objects multi message attribute and collects all connected objects.<\/p>\n<p>&nbsp;<\/p>\n<h3>Core procedures<\/h3>\n<h4 style=\"padding-left: 30px;\">&nbsp;renameObjects (Modified!)<\/h4>\n<pre style=\"margin-left: 80px;\">global proc string[] renameObjects(\tstring $objects[], string $newName, string $prefix, string $suffix,\n\t\t\t\t\t\tstring $find, string $replace, string $typeMask, int $padding, int $cullTrailingInts)\n\t{\n\t\t\n\t\tstring $filterTypes[] = {};\n\t\ttokenize($typeMask, &quot;,; :\/\\|.-&quot;, $filterTypes);\n\t\tcleanStringArray($filterTypes);\n\t\t\n\t\tstring $filteredObjects[] = $objects;\n\n\t\t$filteredObjects = filterObjectsByTypes($filteredObjects, {&quot;shape&quot;}, 0);\n\n\t\t$filteredObjects = filterObjectsByTypes($filteredObjects, $filterTypes, 1);\n\n\t\tstring $pointerObj = createObjectPointer();\n\t\taddObjectsToPointer($filteredObjects, $pointerObj);\n\t\tstring $newNames[] = {};\n\t\tstring $originalNames[] = {};\n\n\n\n\t\tfor($i = 0; $i &lt; size($filteredObjects); $i++)\n\t\t{\n\n\t\t\t\/\/ Set object names to &quot;__tempName__&quot;\n\t\t\t$originalNames[$i] = niceNameOf($filteredObjects[$i]);\n\t\t\trenameLong(getObjectFromPointer($pointerObj, $i), &quot;__tempName__&quot;);\n\n\t\t\t\n\t\t\t\/\/ Establish base name\n\t\t\tstring $baseString = $originalNames[$i];\n\t\t\tif($cullTrailingInts) $baseString = cullTrailingInts($baseString);\n\t\t\tif($newName != &quot;&quot;) $baseString = $newName;\n\t\t\tint $offsetIndex = 0;\n\n\n\t\t\tint $maxLoopCount = size(ls());\n\n\n\t\t\t\/\/ Generate new name from options\n\t\t\t\/\/ If padding is used then loop over name until a unique name is found\n\t\t\t\/\/ $maxLoopCount is used to detect a Infinate loop\n\t\t\tstring $eachName = (adjustString($baseString, $prefix, $suffix, $find, $replace) \n\t\t\t\t\t\t+ padInt($i, $padding));\n\t\t\twhile(objExists($eachName) &amp;&amp; $padding &gt; 0)\n\t\t\t{\n\t\t\t\t$offsetIndex++;\n\t\t\t\tif ($offsetIndex &gt; $maxLoopCount)\n\t\t\t\t{\n\t\t\t\t\tprint (&quot;Attempting to Undo..n&quot;);\n\t\t\t\t\tundo();\n\t\t\t\t\tdelete $pointerObj;\n\t\t\t\t\twarning &quot;Renamed failed! - Infinite loop detected!&quot;;\n\t\t\t\t\treturn {};\n\t\t\t\t}\n\t\t\t\t$eachName = (adjustString($baseString, $prefix, $suffix, $find, $replace)\n\t\t\t\t\t\t+ padInt(($offsetIndex + $i), $padding));\n\t\t\t}\n\n\t\t\t$newNames[$i] = $eachName;\n\t\t}\n\n\n\t\t\/\/ Finally exectue the rename operations\n\t\tfor($i = 0; $i &lt; size($filteredObjects); $i++)\n\t\t{\n\t\t\tstring $objectToRename = getObjectFromPointer($pointerObj, $i);\n\t\t\trenameLong($objectToRename, $newNames[$i]);\n\t\t}\n\n\n\n\t\tstring $renamedObjects[] = getObjectsFromPointer($pointerObj);\n\t\t\n\n\t\tdelete $pointerObj;\n\n\t\tprint (&quot;\/\/ ----------- Rename detailsn&quot;);\n\n\t\tfor($i = 0; $i &lt; size($filteredObjects); $i++)\n\t\t{\n\t\t\tprint (&quot;t&quot; + $filteredObjects[$i] + &quot;ntt-&gt; &quot; + $renamedObjects[$i] + &quot;nn&quot;);\n\t\t}\n\n\t\tprint (&quot;\/\/ ----------- Success! Renamed &quot; + size($renamedObjects) + &quot; Objectsn&quot;);\n\n\t\treturn $renamedObjects;\n\n\t}<\/pre>\n<p style=\"margin-left: 40px;\">Description:<\/p>\n<p style=\"margin-left: 40px;\">As before this is the entry point for the rename routine and so it handles the main iteration over the specified objects processing them and renaming as needed.<\/p>\n<p style=\"margin-left: 40px;\">&nbsp;<\/p>\n<p style=\"margin-left: 40px;\">Details:<\/p>\n<p style=\"margin-left: 40px;\">Because of the new object message link system we don&#39;t need to keep track of or sort objects anymore. Without that worry we can process the given objects in the order they were passed to the procedure. While the method it self is a little more indirect the result is the increased simplicity of the rename operations.<\/p>\n<p style=\"margin-left: 40px;\">However as you can see the procedure and it&#39;s arguments have become quite lengthy with all the added features and so becomes even more reliant on a solid UI to utilize the tool.<\/p>\n<pre style=\"margin-left: 80px;\">global proc string[] renameObjects(string $objects[], string $newName, string $prefix, string $suffix,\n\t\t\t\tstring $find, string $replace, string $typeMask, int $padding, int $cullTrailingInts)\n<\/pre>\n<p style=\"margin-left: 40px;\">First off we have to parse the $typeMask string and break it up into each delinated type. The string will be &#39;tokenized&#39; or seperated by each character found in the string &quot;,; :\/\\|.-&quot;. So whereever there&#39;s one of those characters the tokenize function will create a new string element in the $filterTypes string array.<\/p>\n<pre style=\"margin-left: 80px;\">tokenize($typeMask, &quot;,; :\/\\|.-&quot;, $filterTypes);<\/pre>\n<p style=\"margin-left: 40px;\">We then clean this array to remove any strings that are blank<\/p>\n<pre style=\"margin-left: 80px;\">cleanStringArray($filterTypes);<\/pre>\n<p style=\"margin-left: 40px;\">We dont want the script to attempt to rename the shape nodes of a transform as renaming the transform will update the shape node names automatically.<br \/>\n\tSo we remove all shape nodes i<span id=\"1218522610511E\" style=\"display: none;\">&nbsp;<\/span>ncluded in the object list.<\/p>\n<pre style=\"margin-left: 80px;\">string $filteredObjects[] = $objects;\n        $filteredObjects = filterObjectsByTypes($filteredObjects, {&quot;shape&quot;}, 0);<\/pre>\n<p style=\"margin-left: 40px;\">Then we remove all user specified &#39;types&#39; from the list of objects<\/p>\n<pre style=\"margin-left: 80px;\">$filteredObjects = filterObjectsByTypes($filteredObjects, $filterTypes, 1);<\/pre>\n<p style=\"margin-left: 40px;\">Now we&#39;ve got a clean array of objects lets create the pointer holder object and add the objects to it<\/p>\n<pre style=\"margin-left: 80px;\">string $pointerObj = createObjectPointer();\n        addObjectsToPointer($filteredObjects, $pointerObj);<\/pre>\n<p style=\"margin-left: 40px;\">The inital part of the first loop is used to reset the names of the objects we plan to rename to something that wont clash with the specified new names.&nbsp; We need to rename the objects to some kind of temp name before we do the actual final rename so we can &#39;reuse&#39; object names that might already be assigned to objects in the current target list of objects.<\/p>\n<pre style=\"margin-left: 80px;\">renameLong(getObjectFromPointer($pointerObj, $i), &quot;__tempName__&quot;);<\/pre>\n<p style=\"margin-left: 40px;\">So without this if you had a list of objects:<\/p>\n<pre style=\"margin-left: 80px;\">{&quot;pCube03&quot;, &quot;pCube01&quot;, &quot;pCube04&quot;}<\/pre>\n<p style=\"margin-left: 40px;\">and you attempt to rename them to the base name of &quot;pCube&quot; with a padding of 2 you&#39;ll &#39;clash&#39; with the existing objects.<\/p>\n<p style=\"margin-left: 40px;\">So as a result you&#39;d get something like:<\/p>\n<pre style=\"margin-left: 80px;\">{&quot;pCube02&quot;, &quot;pCube05&quot;, &quot;pCube06&quot;}<\/pre>\n<p style=\"margin-left: 40px;\">Rather then the desired:<\/p>\n<pre style=\"margin-left: 80px;\">{&quot;pCube01&quot;, &quot;pCube02&quot;, &quot;pCube03&quot;}<\/pre>\n<p style=\"margin-left: 40px;\">Note: I&#39;m using the &#39;getObjectFromPointer&#39; procedure here rather then just quering the $filteredObjects array.&nbsp; This is because as soon as any rename or delete operations are executed on the objects the $filteredObjects array, which is uses full paths to the objects, will become invalid.<\/p>\n<p style=\"margin-left: 40px;\">After safely assigning new names to these objects the next step is to find the best fit unique object name for each object. If padding is set it will loop until it finds a unique scene name if not it&#39;ll just assign the new name and let Maya&#39;s internal name clashing systems handle incrementation.<\/p>\n<p style=\"margin-left: 40px;\">There&#39;s a safty mechanism built into the while loop to detect an infinate loop.&nbsp; Allthough this method is pretty safe it&#39;s still helpful to have some form of infinate loop protection &#8211; espicially when you&#39;re writing and debugging the script.<\/p>\n<p style=\"margin-left: 40px;\">This $maxLoopCount is set to the total number of nodes in the scene &#8211; a slighty arbitary metric but accurate measure of an infinate loop in this while instance.<\/p>\n<pre style=\"margin-left: 80px;\">int $maxLoopCount = size(ls());<\/pre>\n<p style=\"margin-left: 40px;\">Therefore we can test if the loop count becomes greater then the total number of nodes in the scene and bail out of the rest of the script with an error letting the user know it failed.<\/p>\n<pre style=\"margin-left: 80px;\">if ($offsetIndex &gt; $maxLoopCount)\n            {\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print (&quot;Attempting to Undo..n&quot;);\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; undo();\n                delete $pointerObj;\n                warning &quot;Renamed failed! - Infinite loop detected!&quot;;\n                return {};\n            }<\/pre>\n<p style=\"margin-left: 40px;\">The second loop will complete the actual rename operation.<\/p>\n<pre style=\"margin-left: 80px;\">for($i = 0; $i &lt; size($filteredObjects); $i++)\n            {\n                string $objectToRename = getObjectFromPointer($pointerObj, $i);\n                renameLong($objectToRename, $newNames[$i]);\n            }<\/pre>\n<p style=\"margin-left: 40px;\">Now the rename operations are all completed we can update the $renamedObjects variable with the new full path object strings<\/p>\n<pre style=\"margin-left: 80px;\">string $renamedObjects[] = getObjectsFromPointer($pointerObj);<\/pre>\n<p style=\"margin-left: 40px;\">After some cleanup and debug print statements we return the new list of objects<\/p>\n<pre style=\"margin-left: 80px;\">return $renamedObjects;\n <\/pre>\n<p style=\"margin-left: 40px;\">&nbsp;&nbsp;<\/p>\n<h3>UI procedures<\/h3>\n<h4 style=\"padding-left: 30px;\">&nbsp;renameObjectsUI (Modified!)<\/h4>\n<pre style=\"margin-left: 40px;\">global proc renameObjectsUI()\n\t{\n\n\n\t\tglobal string $renameObjectsWindow;\n\t\tif (window(&quot;-exists&quot;, $renameObjectsWindow)) deleteUI -window $renameObjectsWindow;\n\t\t$renameObjectsWindow = window(\n\t\t\t\t\t\t&quot;-widthHeight&quot;, 306, 281,\n\t\t\t\t\t\t&quot;-resizeToFitChildren&quot;, 1,\n\t\t\t\t\t\t&quot;-sizeable&quot;, 0,\n\t\t\t\t\t\t&quot;-title&quot;, &quot;Rename Objects Advanced&quot;,\n\t\t\t\t\t\t&quot;renameObjectsWindow&quot;);\n\t\t\n\t\t\tcolumnLayout;\n\n\t\t\t\t\trowColumnLayout -width 308 -numberOfRows 9;\n\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\tstring $prefixCtrl = textFieldGrp(\n\t\t\t\t\t\t\t\t\t\t&quot;-label&quot;, &quot;Prefix&quot;,\n\n\t\t\t\t\t\t\t\t\t\t&quot;-ann&quot;, &quot;Prefix to final object names&quot;,\n\t\t\t\t\t\t\t\t\t\t&quot;-cw&quot;, 1, 90,\n\t\t\t\t\t\t\t\t\t\t&quot;-cw&quot;, 2, 208,\n\t\t\t\t\t\t\t\t\t\t&quot;-text&quot;, &quot;&quot;);\n\n\t\t\t\t\t\tstring $newNameCtrl = textFieldGrp(\n\t\t\t\t\t\t\t\t\t\t&quot;-label&quot;, &quot;New Name&quot;,\n\t\t\t\t\t\t\t\t\t\t&quot;-ann&quot;, &quot;Override existing names with this string&quot;,\n\t\t\t\t\t\t\t\t\t\t&quot;-cw&quot;, 1, 90,\n\t\t\t\t\t\t\t\t\t\t&quot;-cw&quot;, 2, 208,\n\t\t\t\t\t\t\t\t\t\t&quot;-text&quot;, &quot;&quot;);\n\n\t\t\t\t\t\tstring $suffixCtrl = textFieldGrp(\n\t\t\t\t\t\t\t\t\t\t&quot;-label&quot;, &quot;Suffix&quot;,\n\t\t\t\t\t\t\t\t\t\t&quot;-ann&quot;, &quot;Suffix to final object names&quot;,\n\t\t\t\t\t\t\t\t\t\t&quot;-cw&quot;, 1, 90,\n\t\t\t\t\t\t\t\t\t\t&quot;-cw&quot;, 2, 208,\n\t\t\t\t\t\t\t\t\t\t&quot;-text&quot;, &quot;&quot;);\n\t\t\t\t\t\tstring $findCtrl = textFieldGrp(\n\t\t\t\t\t\t\t\t\t\t&quot;-label&quot;, &quot;Find&quot;,\n\t\t\t\t\t\t\t\t\t\t&quot;-ann&quot;, &quot;String to search for an replace&quot;,\n\t\t\t\t\t\t\t\t\t\t&quot;-cw&quot;, 1, 90,\n\t\t\t\t\t\t\t\t\t\t&quot;-cw&quot;, 2, 208,\n\t\t\t\t\t\t\t\t\t\t&quot;-text&quot;, &quot;&quot;);\n\t\t\t\t\t\tstring $replaceCtrl = textFieldGrp(\n\t\t\t\t\t\t\t\t\t\t&quot;-label&quot;, &quot;Replace&quot;,\n\t\t\t\t\t\t\t\t\t\t&quot;-ann&quot;, &quot;What to replace the &#39;found&#39; string with&quot;,\n\t\t\t\t\t\t\t\t\t\t&quot;-cw&quot;, 1, 90,\n\t\t\t\t\t\t\t\t\t\t&quot;-cw&quot;, 2, 208,\n\t\t\t\t\t\t\t\t\t\t&quot;-text&quot;, &quot;&quot;);\n\t\t\t\t\t\tstring $typeMaskCtrl = textFieldGrp(\n\t\t\t\t\t\t\t\t\t\t&quot;-label&quot;, &quot;Exclude Types&quot;,\n\t\t\t\t\t\t\t\t\t\t&quot;-ann&quot;, &quot;Enter types of objects to exclude seperated by commas: i.e. camera, locator&quot;,\n\t\t\t\t\t\t\t\t\t\t&quot;-cw&quot;, 1, 90,\n\t\t\t\t\t\t\t\t\t\t&quot;-cw&quot;, 2, 208,\n\t\t\t\t\t\t\t\t\t\t&quot;-text&quot;, &quot;&quot;);\n\t\t\t\t\t\tstring $paddingCtrl = intFieldGrp(\n\t\t\t\t\t\t\t\t\t\t&quot;-numberOfFields&quot;, 1,\n\t\t\t\t\t\t\t\t\t\t&quot;-label&quot;, &quot;Padding&quot;,\n\t\t\t\t\t\t\t\t\t\t&quot;-ann&quot;, &quot;How much to pad integer suffix. 0 relies on Maya&#39;s default incrementing&quot;,\n\t\t\t\t\t\t\t\t\t\t&quot;-cw&quot;, 1, 90,\n\t\t\t\t\t\t\t\t\t\t&quot;-cw&quot;, 2, 30,\n\t\t\t\t\t\t\t\t\t\t&quot;-value1&quot;, 0);\n\t\t\t\t\t\tstring $cullIntsCtrl = checkBoxGrp(\n\t\t\t\t\t\t\t\t\t\t&quot;-numberOfCheckBoxes&quot;, 1,\n\t\t\t\t\t\t\t\t\t\t&quot;-cw&quot;, 1, 90,\n\t\t\t\t\t\t\t\t\t\t&quot;-value1&quot;, 0,\n\t\t\t\t\t\t\t\t\t\t&quot;-ann&quot;, &quot;Delete trailing integers at the end of objects before renaming&quot;,\n\t\t\t\t\t\t\t\t\t\t&quot;-label&quot;, &quot;Clean Ints&quot;);\n\n\n\t\t\t\t\tsetParent..;\n\n\n\n\t\t\t\t\trowColumnLayout -numberOfColumns 2\n\t\t\t\t\t-columnWidth 1 150\n\t\t\t\t\t-columnWidth 2 150;\n\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\tbutton -l &quot;Cancel&quot; -c &quot;deleteUI -window $renameObjectsWindow;&quot;;\n\t\t\t\t\t\tbutton -l &quot;Defaults&quot; -c &quot;renameObjectsUI();&quot;\n\t\t\t\t\t\t\t-ann &quot;Reset settings to defaults&quot;;\n\t\t\t\t\tsetParent..;\n\n\t\t\t\t\trowColumnLayout -numberOfColumns 1\n\t\t\t\t\t-columnWidth 1 300;\n\n\t\t\t\t\t\tbutton -l &quot;Apply (Selection)&quot;\t-c (\t&quot;renameObjects(&quot;\n\t\t\t\t\t\t\t\t\t\t\t+\t&quot;getSelection(),&quot;\n\t\t\t\t\t\t\t\t\t\t\t+\t&quot;(&quot;&quot; + textFieldGrp(&quot;-q&quot;, &quot;-text&quot;, &quot;&quot; + $newNameCtrl +&quot;&quot;)), &quot;\n\t\t\t\t\t\t\t\t\t\t\t+\t&quot;(&quot;&quot; + textFieldGrp(&quot;-q&quot;, &quot;-text&quot;, &quot;&quot; + $prefixCtrl +&quot;&quot;)), &quot;\n\t\t\t\t\t\t\t\t\t\t\t+\t&quot;(&quot;&quot; + textFieldGrp(&quot;-q&quot;, &quot;-text&quot;, &quot;&quot; + $suffixCtrl +&quot;&quot;)), &quot;\n\t\t\t\t\t\t\t\t\t\t\t+\t&quot;(&quot;&quot; + textFieldGrp(&quot;-q&quot;, &quot;-text&quot;, &quot;&quot; + $findCtrl +&quot;&quot;)), &quot;\n\t\t\t\t\t\t\t\t\t\t\t+\t&quot;(&quot;&quot; + textFieldGrp(&quot;-q&quot;, &quot;-text&quot;, &quot;&quot; + $replaceCtrl +&quot;&quot;)), &quot;\n\t\t\t\t\t\t\t\t\t\t\t+\t&quot;(&quot;&quot; + textFieldGrp(&quot;-q&quot;, &quot;-text&quot;, &quot;&quot; + $typeMaskCtrl +&quot;&quot;)), &quot;\n\t\t\t\t\t\t\t\t\t\t\t+\t&quot;(intFieldGrp(&quot;-q&quot;, &quot;-value1&quot;, &quot;&quot; + $paddingCtrl + &quot;&quot;)), &quot;\n\t\t\t\t\t\t\t\t\t\t\t+\t&quot;(checkBoxGrp(&quot;-q&quot;, &quot;-value1&quot;, &quot;&quot; + $cullIntsCtrl  + &quot;&quot;))&quot;\n\t\t\t\t\t\t\t\t\t\t\t+&quot;);&quot;)\n\t\t\t\t\t\t\t\t\t\t\t-ann\t&quot;Do rename!&quot;;\n\n\t\t\t\t\tsetParent..;\n\t\t\t\t\tstring $form = formLayout(&quot;-numberOfDivisions&quot;, 100);\n\t\t\t\t\tstring $website = text(\n\t\t\t\t\t\t\t\t&quot;-width&quot;, 300,\n\t\t\t\t\t\t\t\t&quot;-enable&quot;, false,\n\t\t\t\t\t\t\t\t&quot;-font&quot;, &quot;smallFixedWidthFont&quot;,\n\t\t\t\t\t\t\t\t&quot;-bgc&quot;, 0.1, 0.2, 0.3,\n\t\t\t\t\t\t\t\t&quot;-align&quot;, &quot;center&quot;,\n\t\t\t\t\t\t\t\t&quot;-label&quot;, &quot;www.rodgreen.com&quot;);\n\n\t\t\t\t\tformLayout -edit\n\t\t\t\t\t    -attachForm     $website     &quot;top&quot;    -4\n\t\t\t\t\t$form;\n\n\t\tshowWindow $renameObjectsWindow;\n\n\t}<\/pre>\n<p style=\"margin-left: 40px;\">Description:<\/p>\n<p style=\"margin-left: 40px;\">Front end for the rename objects tool.<\/p>\n<p style=\"margin-left: 40px;\">&nbsp;<\/p>\n<p style=\"margin-left: 40px;\">Details:<\/p>\n<p style=\"margin-left: 40px;\">Most of this is pretty standard UI stuff &#8211; built of and extended on the previous UI procedure. The thing to note is the assigning of the controls to a variable so that we can include them in the &#39;Apply&#39; button&#39;s command.<\/p>\n<p style=\"margin-left: 40px;\">It&#39;s also important to stress that because this UI is the only real intuitive way to use the rename tool it needs to be clean and fast.&nbsp; The use of annotation strings (&quot;-ann&quot;) give a extra little bit of help to users confused about the usage of certain options.<\/p>\n<p>&nbsp;<\/p>\n<h4>Thats it!<\/h4>\n<p>&nbsp;<a href=\"https:\/\/www.rodgreen.com\/scripts\/mel\/renameAdvanced.mel\" onclick=\"window.open(this.href,'renameIntermediate','resizable=yes,location=no,menubar=no,scrollbars=yes,status=no,toolbar=no,fullscreen=no,dependent=no,status'); return false\">[Download Script]<\/a><\/p>\n<h3>Conclusions \/ next steps?<\/h3>\n<p>&nbsp;<\/p>\n<ul>\n<li>Improving the script beyond this would involve adding more and more features to the rename options and UI (i.e. saving common or user specified rename options) however the underlying system would support any arbitrary object name change.<\/li>\n<li>The method of utilizing a transform node&#39;s message array attribute can help in many other tools not just renaming.&nbsp; This could also be used to maintain connections within rigs (i.e. for dynamic constraints), give more explicit connections for exporting to a game engine, manage dynamic systems like destruction, etc.<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p>I hope you found this informative and at the very least gave you some alternative ways to think about how to handle objects and their names in Maya.<\/p>\n<p>\tThanks for reading!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>&nbsp; [Download Script] &nbsp; This is the third part to a three part tutorial on renaming objects in Maya.&nbsp; In the first installment we established a collection of procedures and a simple UI that allows multiple objects to be renamed. In the second installment we evolved this tool to utilize an custom sorting method and [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[18,2,4,6,7,11,15],"tags":[54,42,44,56,47],"class_list":["post-117","post","type-post","status-publish","format-standard","hentry","category-animation","category-art","category-development","category-games","category-maya-art","category-technical-art","category-tutorials","tag-maya-art","tag-rename","tag-scripting","tag-technical-art","tag-tutorial"],"_links":{"self":[{"href":"https:\/\/www.rodgreen.com\/index.php?rest_route=\/wp\/v2\/posts\/117","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.rodgreen.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.rodgreen.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.rodgreen.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.rodgreen.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=117"}],"version-history":[{"count":0,"href":"https:\/\/www.rodgreen.com\/index.php?rest_route=\/wp\/v2\/posts\/117\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.rodgreen.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=117"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.rodgreen.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=117"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.rodgreen.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=117"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}