Below is an example demonstrating how to obtain a list of products in the database used by an object in the scene.
// DAZ Studio version 4.9.2.27 // Define an anonymous function; // serves as our main loop, // limits the scope of variables (function( aArgs ){ // Initialize 'static' variables that hold modifier key state var s_bShiftPressed = false; var s_bControlPressed = false; var s_bAltPressed = false; var s_bMetaPressed = false; // If the "Action" global transient is defined, and its the correct type if( typeof( Action ) != "undefined" && Action.inherits( "DzScriptAction" ) ){ // If the current key sequence for the action is not pressed if( !App.isKeySequenceDown( Action.shortcut ) ){ updateModifierKeyState(); } // If the "Action" global transient is not defined } else if( typeof( Action ) == "undefined" ) { updateModifierKeyState(); } /*********************************************************************/ // void : A function for updating the keyboard modifier state function updateModifierKeyState() { // Get the current modifier key state var nModifierState = App.modifierKeyState(); // Update variables that hold modifier key state s_bShiftPressed = (nModifierState & 0x02000000) != 0; s_bControlPressed = (nModifierState & 0x04000000) != 0; s_bAltPressed = (nModifierState & 0x08000000) != 0; s_bMetaPressed = (nModifierState & 0x10000000) != 0; }; /*********************************************************************/ // void : A function for printing only if debugging function debug() { // If we are not debugging if( !s_bAltPressed ){ // We are done... return; } // Convert the arguments object into an array var aArguments = [].slice.call( arguments ); // Print the array print( aArguments.join(" ") ); }; /*********************************************************************/ // String : A function for retrieving a translation if one exists function text( sText ) { // If the version of the application supports qsTr() if( typeof( qsTr ) != "undefined" ){ // Return the translated (if any) text return qsTr( sText ); } // Return the original text return sText; }; /*********************************************************************/ // Boolean : A function for testing whether or not a QObject instance // inherits one of a list of types function inheritsType( oObject, aTypeNames ) { // If the object does not define the 'inherits' function if( !oObject || typeof( oObject.inherits ) != "function" ){ // We are done... it is not a QObject return false; } // Iterate over the list of type names for( var i = 0, nTypes = aTypeNames.length; i < nTypes; i += 1 ){ // If the object does not inherit the 'current' type if( !oObject.inherits( aTypeNames[i] ) ){ // Next!! continue; } // Return the result return true; } // Return the result return false; }; /*********************************************************************/ // String : A function for converting an ECMA Object to a JSON string function getStringified( oObject ) { return JSON.stringify( oObject, null, "\t" ); }; /*********************************************************************/ // Array : A function for getting the keys of an ECMA Object function getKeys( oObject ) { return Object.keys( oObject ); }; /*********************************************************************/ // Array : A function for getting the values of an ECMA Object function getValues( oObject ) { return getKeys( oObject ) .map( function( sProperty ){ return oObject[ sProperty ]; } ); }; /*********************************************************************/ // Object : A function for creating a deep copy of an ECMA Object function deepCopy( oObject ) { // Initialize depending on whether or not it is an array var oCopy = (Array.isArray( oObject ) ? [] : {}); // Iterate over each property of the object for( var sProperty in oObject ){ // If the property holds an object if( typeof( oObject[ sProperty ] ) === "object" ){ // Recurse oCopy[ sProperty ] = deepCopy( oObject[ sProperty ] ); // Otherwise } else { // Copy the value oCopy[ sProperty ] = oObject[ sProperty ]; } } // Return the copy return oCopy; }; /*********************************************************************/ // String : A function for getting a file error string function getFileErrorString( oFile ) { // Initialize var aResult = []; // Based on the error type switch( oFile.error() ){ case DzFile.NoError: break; case DzFile.ReadError: aResult.push( "Read Error" ); break; case DzFile.WriteError: aResult.push( "Write Error" ); break; case DzFile.FatalError: aResult.push( "Fatal Error" ); break; case DzFile.ResourceError: aResult.push( "Resource Error" ); break; case DzFile.OpenError: aResult.push( "Open Error" ); break; case DzFile.AbortError: aResult.push( "Abort Error" ); break; case DzFile.TimeOutError: aResult.push( "TimeOut Error" ); break; case DzFile.UnspecifiedError: aResult.push( "Unspecified Error" ); break; case DzFile.RemoveError: aResult.push( "Remove Error" ); break; case DzFile.RenameError: aResult.push( "Rename Error" ); break; case DzFile.PositionError: aResult.push( "Position Error" ); break; case DzFile.ResizeError: aResult.push( "Resize Error" ); break; case DzFile.PermissionsError: aResult.push( "Permissions Error" ); break; case DzFile.CopyError: aResult.push( "Copy Error" ); break; } // Append the error string aResult.push( oFile.errorString() ); // Return the result string return aResult.length > 0 ? aResult.join( ": " ) : ""; }; /*********************************************************************/ // String : A function for writing data to file function writeToFile( sFilename, vData, nMode ) { // If we do not have a file path if( sFilename.isEmpty() ){ // Return failure return "Empty filename."; } // Create a new file object var oFile = new DzFile( sFilename ); // If the file is already open if( oFile.isOpen() ){ // Return failure return sFilename + " is already open."; } // Open the file if( !oFile.open( nMode ) ){ // Return failure return sFilename + " could not be opened. " + getFileErrorString( oFile ); } // Initialize var nBytes = 0; // Based on the type of the data switch( typeof( vData ) ){ case "string": // If we have data to write if( !vData.isEmpty() ){ // Write the data to the file nBytes = oFile.write( vData ); } break; case "object": // If we have a ByteArray if( inheritsType( vData, ["QByteArrayWrapper"] ) && vData.length > 0 ){ // Write the data to the file nBytes = oFile.writeBytes( vData ); } break; } // Close the file oFile.close(); // Initialize var sError = ""; // If an error occured if( nBytes < 0 ){ // Provide feedback sError = getFileErrorString( oFile ); } // If bytes were not written if( nBytes < 1 ){ // Return failure return "No bytes written."; } // Return result return sError; }; /*********************************************************************/ // String : A function for opening the application log function openApplicationLog() { // Cause any data in the log buffer to be written to file App.flushLogBuffer(); // Cause the log file to be shown App.showURL( App.getLogFilename() ); }; /*********************************************************************/ // String : A function for getting a contextual label for a node function getContextualNodeLabel( oNode ) { // If we do not have a node if( !oNode || !inheritsType( oNode, ["DzNode"] )){ // Return an empty string return ""; } // Declare working variable var oSkeleton; // If we have a bone if( inheritsType( oNode, ["DzBone"] ) ){ // Get the skeleton oSkeleton = getRootNode( oNode ); // Return the label that provides enough context return oSkeleton.getLabel() + ":" + oNode.getLabel(); // If we have any other kind of node } else { // Return the node label return oNode.getLabel(); } }; /*********************************************************************/ // DzNode : A function for getting the root of a node function getRootNode( oNode ) { // If we have a node and it is a bone if( oNode && inheritsType( oNode, ["DzBone"] ) ){ // We want the skeleton return oNode.getSkeleton(); } // Return the original node return oNode; }; /*********************************************************************/ // DzObject : A function for getting the object for a node function getObjectForNode( oNode, bRoot ) { // Get the node var oContextNode = bRoot ? getRootNode( oNode ) : oNode; // If we do not have a root node if( !oContextNode ){ // We are done... return null; } // Get the object of the root node var oObject = oContextNode.getObject(); // If we do not have an object if( !oObject ){ // We are done... return null; } // Return the object return oObject; }; /*********************************************************************/ // DzShape : A function for getting the shape for a node function getShapeForNode( oNode, bRoot ) { // Get the object of the node var oObject = getObjectForNode( oNode, bRoot ); // If we do not have an object if( !oObject ){ // We are done... return null; } // Get the shape of the root node var oShape = oObject.getCurrentShape(); // If we do not have a shape if( !oShape ){ // We are done... return null; } // Return the shape return oShape; }; /*********************************************************************/ // DzGeometry : A function for getting the geometry for the root of a node function getGeometryForNode( oNode, bRoot, bCached ) { // Get the shape of the root node var oShape = getShapeForNode( oNode, bRoot ); // If we do not have a shape if( !oShape ){ // We are done... return null; } // If we are getting the cached geometry if( bCached ){ // Update the working mesh //oShape.invalidateWorkingMesh(); // Get the object of the root node var oObject = getObjectForNode( oNode, bRoot ); // Return the geometry return oObject.getCachedGeom(); } // Get the geometry of the root node var oGeometry = oShape.getGeometry(); // If we do not have a geometry if( !oGeometry ){ // We are done... return null; } // Return the geometry return oGeometry; }; /*********************************************************************/ // Array<DzNode> : A function for getting the followers of a node function getFollowNodes( oNode ) { // If we do not have a node if( !oNode ){ // Return an empty list return []; } // If we have a bone if( inheritsType( oNode, ["DzBone"] ) ){ // Get the root node oNode = getRootNode( oNode ); } // If we have a skeleton if( inheritsType( oNode, ["DzSkeleton"] ) ){ // Get the number of skeletons following this one var nFollowers = oNode.getNumFollowSkeletons(); // Pre-size the results array var aResult = new Array( nNodes ); // Iterate over the followers for( var i = 0; i < nFollowers; i += 1 ){ // Get the 'current' follower oFollower = oNode.getFollowSkeleton( i ); // Assign the node to the result aResult[i] = oFollower; } // Return the list return aResult; } // Return an empty list return []; }; /*********************************************************************/ // Array<DzNode> : A function for getting the nodes parented to a node function getNodeChildren( oNode, bRecurse ) { // If we have a node if( oNode && inheritsType( oNode, ["DzNode"] ) ){ // Return a list of the node children return oNode.getNodeChildren( bRecurse ); } // Return an empty list return []; }; /*********************************************************************/ // Array<DzNode> : A function for extracting unique nodes function getUniqueNodes( aNodes, bRoots, bFollowers, bParented, bRecursive ) { // If we do not have an array if( typeof( aNodes ) != "object" || !Array.isArray( aNodes ) ){ // We are done... return []; } // Get the number of nodes in the list var nNodes = aNodes.length; // Declare working variables var oNode; var aSubNodes; // If we are processing followers or parented nodes if( bFollowers || bParented ){ // Iterate over the nodes for( var i = 0; i < nNodes; i += 1 ){ // Get the 'current' node oNode = aNodes[ i ]; // If we are interested in followers if( bFollowers ){ // Get the followers aSubNodes = getFollowNodes( oNode ); // If we are recursing if( bRecursive ){ // Get the unique nodes of the followers aSubNodes = getUniqueNodes( aSubNodes, false, bFollowers, bParented, bRecursive ); } // Append the nodes aNodes = aNodes.concat( aSubNodes ); } // If we are interested in parented nodes if( bParented ){ // If we are interested in roots, recursively if( bRoots && bRecursive ){ // Get the nodes in the hierarchy of the root aSubNodes = getNodeChildren( getRootNode( oNode ), true ); // If we are not interested in roots } else { // Get the parented nodes aSubNodes = getNodeChildren( oNode, bRecursive ); } // Append the nodes aNodes = aNodes.concat( aSubNodes ); } } } // Update the number of nodes nNodes = aNodes.length; // Pre-size the results array var aResult = new Array( nNodes ); // Declare working variable var nNodeId; // Initialize var oNodeIds = {}; var nIdx = 0; // Iterate over the list of nodes for( var i = 0; i < nNodes; i += 1 ){ // Get the 'current' node oNode = aNodes[ i ]; // If we do not have a node if( !oNode || !inheritsType( oNode, ["DzNode"] ) ){ // Next!! continue; } // If we are interested in root nodes if( bRoots ){ // Get the root for the node oNode = getRootNode( oNode ); } // Get the element ID for the node nNodeId = oNode.elementID; // If we already have that ID if( oNodeIds[ nNodeId ] ){ // Next!! continue; } // Record the node for the ID oNodeIds[ nNodeId ] = oNode; // Assign the node to the result aResult[ nIdx ] = oNode; // Increment our index nIdx += 1; } // Return the list, without any empty/invalid values return aResult.filter( Boolean ); }; /*********************************************************************/ // Array<DzProperty> : A function for getting a list of the properties in a group function getGroupProperties( oGroup, bTraverse, bRecurse ) { // Declare an array to hold properties var aProperties = []; // If a group is not passed in if( !oGroup ){ // We are done, return an empty array return aProperties; } // Get the number of proeprties in the group var nProperties = oGroup.getNumProperties(); // Pre-size the properties array aProperties = new Array( nProperties ); // Iterate over the properties, setting each element in the array for( var i = 0; i < nProperties; i += 1 ){ // Assign the property to the position in the array aProperties[ i ] = oGroup.getProperty( i ); } // If we are recursing if( bRecurse ){ // Concatenate the properties array from child groups aProperties = aProperties.concat( getGroupProperties( oGroup.getFirstChild(), true, bRecurse ) ); } // If we are traversing if( bTraverse ){ // Concatenate the properties array from sibling groups aProperties = aProperties.concat( getGroupProperties( oGroup.getNextSibling(), bTraverse, bRecurse ) ); } // Return the array of properties return aProperties; }; /*********************************************************************/ // Array<DzProperty> : A function for getting the list properties for an element function getElementProperties( oElement, bTraverse, bRecurse ) { // Get the property group tree for the element var oPropertyGroupTree = oElement.getPropertyGroups(); // If the application version is 4.9.4.101 or newer and we want all properties if( App.version64 >= 0x0004000900040065 && bTraverse && bRecurse ){ // Return the properties for the element return oPropertyGroupTree.getAllProperties(); } // Get the first group in the tree var oPropertyGroup = oPropertyGroupTree.getFirstChild(); // Return the properties for the element return getGroupProperties( oPropertyGroup, bTraverse, bRecurse ); }; /*********************************************************************/ // Boolean : A function for testing whether an object is a scene asset function isSceneAsset( oObject ) { // Return the result return inheritsType( oObject, [ "DzSceneAsset" ] ); }; /*********************************************************************/ // Boolean : A function for testing whether a modifier is controlled by // a property function isPropertyControlledModifier( oModifier ) { // Define the list of modifier types that are controlled by a property var aTypes = [ "DzDFormModifier", "DzConditionalGraftModifier", "DzMeshSmoothModifier", "DzMorph", "DzPushModifier" ]; // Return the result return inheritsType( oModifier, aTypes ); }; /*********************************************************************/ // Boolean : A function for testing whether a property's default value is on function isPropertyDefaultOn( oProperty ) { // If the property is not of the types we need if( !inheritsType( oProperty, [ "DzFloatProperty", "DzIntProperty" ] ) ){ // We are done... return false; } // Return whether or not the default value is non-zero return Math.abs( oProperty.getDefaultValue() ) > 0; }; /*********************************************************************/ // Boolean : A function for testing whether a modifier's default value is on function isModifierDefaultOn( oModifier ) { // If the object is not a modifier if( !inheritsType( oModifier, [ "DzModifier" ] ) ){ // We are done... return false; } // Declare working variable var oProperty; // If the modifier has the getValueControl() function if( typeof( oModifier.getValueControl ) == "function" ){ // Get the value control property oProperty = oModifier.getValueControl(); // If the modifier has the getValueChannel() function } else if( typeof( oModifier.getValueChannel ) == "function" ){ // Get the value control property oProperty = oModifier.getValueChannel(); // If the modifier has the getEnableSmoothingControl() function } else if( typeof( oModifier.getEnableSmoothingControl ) == "function" ){ // Get the value control property oProperty = oModifier.getEnableSmoothingControl(); } // If we do not have a property if( !oProperty ){ // We are done... return false; } // Return whether or not the default value is non-zero return isPropertyDefaultOn( oProperty ); }; /*********************************************************************/ // void : A function for collecting product information from a local absolute path function captureAssetPathProductInfo( sPath, bIsRelative ) { // If the path is empty if( sPath.isEmpty() ){ // We are done... return; } // Declare working variables var oContentMgr; var sRelPath; // If the path is relative if( bIsRelative ){ // Update our variable sRelPath = sPath; // If the path is absolute } else { // Get the content manager oContentMgr = App.getContentMgr(); // If we do not have a content manager if( !oContentMgr ){ // We are done... return; } // Get the relative path of the file sRelPath = oContentMgr.getRelativePath( DzContentMgr.AllDirsAndCloud, sPath ); // If the path is not relative if( sRelPath == sPath ){ // We are done... (not mapped) return; } } // Get the asset manager var oAssetMgr = App.getAssetMgr(); // If we do not have a asset manager if( !oAssetMgr ){ // We are done... return; } // Get the products that this relative path is in var aProducts = oAssetMgr.findProductsForFile( sRelPath ); // Declare working variables var oProduct; var sGuid; var aPaths; // Iterate over the products for( var i = 0, nProducts = aProducts.length; i < nProducts; i += 1 ){ // Get the 'current' product oProduct = aProducts[ i ]; // Get the GUID sGuid = oProduct.guid; // If the product does not have a GUID; // this "should" not happen, but it has // so we need to handle the case if( sGuid.isEmpty() ){ // Use the store id and token, separated by a // character that is not valid in a GUID so // that we can detect the case in a later step sGuid = oProduct.store + "," + oProduct.token; } // Get the list of relative paths aPaths = s_oProductsMap[ sGuid ]; // If the list does not exist if( !Array.isArray( aPaths ) ){ // Initialize the list with the 'current' path aPaths = [ sRelPath ]; // If the list does exist } else { // Assign the next item in the list aPaths[ aPaths.length ] = sRelPath; } // Update the products map s_oProductsMap[ sGuid ] = aPaths; } }; /*********************************************************************/ // void : A function for collecting product information from an asset URI function captureUriProductInfo( oUri, sDebug ) { // If we do not have a DzUri if( !oUri || !inheritsType( oUri, [ "DzUri" ] ) ){ // We are done... return; } // If the URI is empty if( oUri.isEmpty() ){ // Provide feedback debug( "Empty URI:", sDebug ); // We are done... return; } // Get the file path portion of the URI var sRelPath = oUri.filePath; // If we do not have a local file if( sRelPath.isEmpty() ){ // Provide feedback debug( "File not found:", sDebug, "~", oUri.toString() ); // We are done... return; } // Capture product info from the path captureAssetPathProductInfo( sRelPath, true ); }; /*********************************************************************/ // void : A function for collecting product information for a scene asset function captureSceneAssetInfo( oObject, sDebug ) { // If we do not have a scene asset if( !oObject || !isSceneAsset( oObject ) ){ // We are done... return; } // Capture product info from the URI captureUriProductInfo( oObject.assetUri, "URI - " + sDebug ); // Capture product info from the source URI (if any) captureUriProductInfo( oObject.assetSource, "Source - " + sDebug ); }; /*********************************************************************/ // void : A function for collecting product information for a property function capturePropertyProductInfo( oProperty, oOwner ) { // If we do not have a property or an owner if( !oProperty || !oOwner ){ // We are done... return; } // If the owner is a modifier that provides the scene asset API if( inheritsType( oOwner, [ "DzModifier" ] ) && isSceneAsset( oOwner ) ){ // Capture product info from the modifier captureSceneAssetInfo( oOwner, "Modifier: " + oOwner.assetId + " : " + oOwner.getName() ); // Otherwise } else { // Capture product info from the property captureSceneAssetInfo( oProperty, "Property: " + oProperty.assetId + " : " + oProperty.getLabel() ); } //Declare working variable var oDeltas; // If the owner is a morph if( inheritsType( oOwner, [ "DzMorph" ] ) ){ // Get the deltas for the morph oDeltas = oOwner.getDeltas(); // If we have deltas if( oDeltas ){ // Capture product info from the HD asset captureUriProductInfo( oDeltas.getHDUrl(), "Morph HD: " + oOwner.assetId + " : " + oOwner.getName() ); } } // If the property is not an alias if( !oProperty.isAlias() ){ // We are done... return; } // Get the target property of the alias var oTargetProperty = oProperty.getAliasTarget(); // Get the owner of the target property oTargetOwner = oTargetProperty.getOwner(); // Capture product info from the target property capturePropertyProductInfo( oTargetProperty, oTargetOwner ); }; /*********************************************************************/ // void : A function for collecting product information for active // properties associated with an element function capturePropertiesProductInfo( oElement ) { // If we do not have an element if( !oElement ){ // We are done... return; } // Declare working variables var oProperty, oOwner; var sTmpPath; var nType; // Get the properties available to the user by way of the selected node var aProperties = getElementProperties( oElement, true, true ); // Iterate over all properties for( var i = 0, n = aProperties.length; i < n; i += 1 ){ // Get the 'current' property oProperty = aProperties[ i ]; // If we have a numeric property if( inheritsType( oProperty, [ "DzNumericProperty" ] ) ){ // Capture product info from the map value (if mappable/mapped) captureTextureProductInfo( oProperty.getMapValue() ); // If we have an image property } else if( inheritsType( oProperty, [ "DzImageProperty" ] ) ){ // Capture product info from the value (if any) captureTextureProductInfo( oProperty.getValue() ); // If we have a file property } else if( inheritsType( oProperty, [ "DzFileProperty" ] ) ){ // Get the value of the property sTmpPath = oProperty.getValue(); // Get the type of the property nType = oProperty.getType(); // If the property is configured for consuming (open/load) a file and has a value if( nType != DzFileProperty.FileSave && nType != DzFileProperty.Dir && !sTmpPath.isEmpty() ){ // Capture product info from the value captureAssetPathProductInfo( sTmpPath, sTmpPath != oProperty.getAbsolutePath( sTmpPath ) ); } } // Get the owner of the property oOwner = oProperty.getOwner(); // If the owner is not a material if( !inheritsType( oOwner, [ "DzMaterial" ] ) ){ // If the property's current value and raw value are the same as // the definition, and the property is not animated, and the // owner is not a modifier that is on by default if( oProperty.currentValueIsDefinitionValue() && oProperty.rawValueIsDefinitionValue() && oProperty.getNumKeys() < 2 && !isModifierDefaultOn( oOwner ) ){ // Next!! continue; } /* // If the property is hidden if( oProperty.isHidden() || oProperty.isDynamicallyHidden() ){ // Next!! continue; } */ } // Capture product info from the property capturePropertyProductInfo( oProperty, oOwner ); } }; /*********************************************************************/ // void : A function for collecting product information from a UV set function captureUVSetProductInfo( oMap ) { // If we do not have a map or it is not a UV Set if( !oMap || !inheritsType( oMap, [ "DzUVSet" ] ) ){ // We are done... return; } // Capture product info from the UV set captureSceneAssetInfo( oMap, "UV Set: " + oMap.assetId + " : " + oMap.getLabel() ); }; /*********************************************************************/ // void : A function for collecting product information from a geometry function captureFacetMeshProductInfo( oGeometry ) { // If we do not have a geometry or it is not a facet mesh if( !oGeometry || !inheritsType( oGeometry, [ "DzFacetMesh" ] ) ){ // We are done... return; } // Capture product info from the geometry captureSceneAssetInfo( oGeometry, "Mesh: " + oGeometry.assetId + " : " + oGeometry.getName() ); // Get the active UVs var oActiveUVs = oGeometry.getUVs(); // Capture product info for the active UVs captureUVSetProductInfo( oActiveUVs ); // Get the number of UV sets var nUVSets = oGeometry.getNumUVSets(); // If we only have one UV set, or the active one is the default if( nUVSets == 1 || oActiveUVs.name == "default" ){ // We are done... return; } // Declare working variable var oUVs; // Iterate over the UV sets for( var i = 0; i < nUVSets; i += 1 ){ // Get the 'current' UV set oUVs = oGeometry.getUVSet( i ); // If it is not the default if( oUVs.name != "default" ){ // Next!! continue; } // Capture product info for the UV set captureUVSetProductInfo( oUVs ); // We are done... break; } }; /*********************************************************************/ // void : A function for collecting product information from a layered texture function captureLayeredTextureProductInfo( oTexture ) { // If we do not have a texture or it is not a layered texture if( !oTexture || !inheritsType( oTexture, [ "DzLayeredTexture" ] ) ){ // We are done... return; } // Declare working variables var oLayer; var oMask; // Iterate over the layers for( var i = 0, n = oTexture.getNumLayers(); i < n; i += 1 ){ // Get the 'current' layer oLayer = oTexture.getLayer( i ); // Capture product info from the image path captureAssetPathProductInfo( oLayer.imageFile, false ); // Get the mask for the layer oMask = oLayer.getMask(); // If we have a mask if( oMask ){ // Capture product info from the image path captureAssetPathProductInfo( oMask.imageFile, false ); } } }; /*********************************************************************/ // void : A function for collecting product information from a texture function captureTextureProductInfo( oTexture ) { // If we do not have a texture if( !oTexture ){ // We are done... return; } // Get the content manager var oContentMgr = App.getContentMgr(); // Get the path of the file var sAbsPath = oTexture.getFilename(); // Get the relative path of the file; so that we can resolve // the original casing of assets installed via Daz Connect var sRelPath = oContentMgr.getRelativePath( DzContentMgr.AllDirsAndCloud, sAbsPath ); // Get the (absolute) asset URI var oUri = oContentMgr.getAbsoluteUri( DzContentMgr.AllDirsAndCloud, sRelPath ); // Get the (relative) file path portion of the asset URI sRelPath = oUri.filePath; // If the texture is not of a type that provides the scene asset API if( !isSceneAsset( oTexture ) ){ // If we do not have a local file if( sRelPath.isEmpty() ){ // Provide feedback debug( "Path not relative -", "Texture: " + sAbsPath ); // Capture product info from the absolute path captureAssetPathProductInfo( sAbsPath, false ); // We are done... return; } // Capture product info from the asset path captureAssetPathProductInfo( sRelPath, true ); // We are done... return; } // If we do not have a local file if( sRelPath.isEmpty() ){ // Provide feedback debug( "File not found -", "Texture: " + oTexture.assetId, ":", sAbsPath ); // We are done... return; } // Capture product info from the file assigned to the texture captureAssetPathProductInfo( sRelPath, true ); // Capture product info from the texture object captureSceneAssetInfo( oTexture, "Texture: " + oTexture.assetId + " : " + sRelPath ); // Capture product info for the layers in a layered texture captureLayeredTextureProductInfo( oTexture ); }; /*********************************************************************/ // void : A function for collecting product information from materials function captureMaterialsProductInfo( oShape ) { // If we do not have a shape if( !oShape ){ // We are done... return; } // Declare working variables var oMaterial; var aMaps; // Get the materials on the current shape var aMaterials = oShape.getAllMaterials(); // Iterate over the materials for( var i = 0, nMaterials = aMaterials.length; i < nMaterials; i += 1 ){ // Get the 'current' material oMaterial = aMaterials[ i ]; // Capture product info from the active UV set captureUVSetProductInfo( oMaterial.getActiveUVSet( oShape ) ); // Get all the maps used by the material aMaps = oMaterial.getAllMaps(); // Iterate over the maps for( var j = 0, nMaps = aMaps.length; j < nMaps; j += 1 ){ // Capture product info from the map captureTextureProductInfo( aMaps[ j ] ); } // Capture product info from the material captureSceneAssetInfo( oMaterial, "Material: " + oMaterial.assetId + " : " + oMaterial.getLabel() ); // We do not need to do this because it is already being handled // by the textures and a material's properties reside in the same // asset as the material // Capture product info from properties on the material //capturePropertiesProductInfo( oMaterial ); } // Declare working variables var oProvider; // Get the list of simulation settings provider names var aSimProviderNames = oShape.getSimulationProviderNames(); // Iterate over the simulation provider names for( var i = 0, nProviders = aSimProviderNames.length; i < nProviders; i += 1 ){ // Get the 'current' simulation settings provider oProvider = oShape.findSimulationSettingsProvider( aSimProviderNames[ i ] ); // Capture product info from the simulation settings provider captureSceneAssetInfo( oProvider, "Provider: " + oProvider.assetId + " : " + oProvider.getName() ); // Capture product info from properties on the provider capturePropertiesProductInfo( oProvider ); } }; /*********************************************************************/ // void : A function for collecting product information from modifiers function captureModifiersProductInfo( oObject ) { // If we do not have a object if( !oObject ){ // We are done... return; } // Declare working variable var oModifier; // Iterate over the modifiers for( var i = 0, nModifiers = oObject.getNumModifiers(); i < nModifiers; i += 1 ){ // Get the 'current' modifier oModifier = oObject.getModifier( i ); // If the modifier is not of a type that provides the scene asset API if( !isSceneAsset( oModifier ) ){ // Next!! continue; } // If the modifier is of a type that is controlled by a property if( isPropertyControlledModifier( oModifier ) ){ // Next!! continue; } // Capture product info from the modifier captureSceneAssetInfo( oModifier, "Modifier: " + oModifier.assetId + " : " + oModifier.getName() ); // We do not need to do this because it is already being handled // by the properties being handled by the node // Capture product info from properties on the modifier //capturePropertiesProductInfo( oModifier ); } }; /*********************************************************************/ // void : A function for collecting product information from a node function captureNodeProductInfo( oNode ) { // Get the asset manager var oAssetMgr = App.getAssetMgr(); // If we do not have an asset manager if( !oAssetMgr ){ // We are done... return; } // Get the asset URI path for the node var sUri = oAssetMgr.getAssetUriForNode( oNode ); // Create a URI from the path var oUri = new DzUri( sUri ); // Get the file path portion of the asset URI var sRelPath = oUri.filePath; // If the path is empty if( !sRelPath.isEmpty() ){ // Capture product info from the asset path captureAssetPathProductInfo( sRelPath, true ); } // Capture product info from properties on the node capturePropertiesProductInfo( oNode ); }; /*********************************************************************/ // Object : A function for getting products information function getProductsInfo( bUnified ) { // Initialize var oProducts = {}; // Get the asset manager var oAssetMgr = App.getAssetMgr(); // If we do not have an asset manager if( !oAssetMgr ){ // We are done... return oProducts; } // Declare working variables var oProduct, oProductInfo; var aGuids, aPaths; var sGuid, sStore, sToken; var nIdx; // Get the list of product GUIDs var aGuids = getKeys( s_oProductsMap ); // Iterate over the list of GUIDs for( var i = 0, nGuids = aGuids.length; i < nGuids; i += 1 ){ // Get the 'current' GUID sGuid = aGuids[ i ]; // Check whether or not we have a real GUID; // comma is not a valid GUID character, so if // we find one, we assume that what we really // have is a store ID and product token nIdx = sGuid.indexOf( "," ); // If we have a valid GUID; we did not find a comma if( nIdx < 0 ){ // Get the product for the GUID oProduct = oAssetMgr.findProductByGuid( sGuid ); // If we do not have a valid GUID; we found a comma } else { // Get the store ID sStore = sGuid.substring( 0, nIdx ); // Get product token sToken = sGuid.substring( nIdx + 1 ); // Get the product for the store ID and token combination oProduct = oAssetMgr.findProductByStoreToken( sStore, sToken ); } // If no product was found if( !oProduct ){ // Provide feedback print( "Product", sGuid, "could not be found." ); // Next!! continue; } // Initialize; capture the title oProductInfo = { "title" : oProduct.title }; // If this is not the 'LOCAL_USER' product if( !oProduct.isLocalUser ){ // Capture the store oProductInfo[ "store" ] = oProduct.store; // Capture the token - SKU, id, etc oProductInfo[ "token" ] = oProduct.token; } //If we are unifying the results if( bUnified ){ // Capture the product GUID oProductInfo[ "guid" ] = sGuid; } // Get the list of paths aPaths = s_oProductsMap[ sGuid ]; // Sort and remove duplicates aPaths = aPaths.sort().filter( function( sValue, nIdx, aList ){ return !nIdx || sValue != aList[ nIdx - 1 ]; }); // Capture the paths oProductInfo[ "files" ] = aPaths; // Capture the product info oProducts[ sGuid ] = oProductInfo; } // Return the result return oProducts; }; /*********************************************************************/ // Object : A function for getting products information for a node function getNodeProductsMap( oNode, bUnified ) { // Declare working variable var oProductsMap; // If we are unifying the results and there is something to copy if( bUnified && getKeys( s_oProductsMap ).length > 0 ){ // Copy the current products map oProductsMap = deepCopy( s_oProductsMap ); } // Initialize for this node s_oProductsMap = {}; // Capture product information captureNodeProductInfo( oNode ); // We do not need to do this because it is already being handled // by the properties being handled by the node // Get the object var oObject = getObjectForNode( oNode, false ); // If we have an object if( oObject ){ // Capture product information captureModifiersProductInfo( oObject ); } // Get the current shape var oShape = getShapeForNode( oNode, false ); // If we have a shape if( oShape ){ // Capture product information captureMaterialsProductInfo( oShape ); } // Get the geometry var oGeometry = getGeometryForNode( oNode, false, false ); // If we have a geometry if( oGeometry ){ // Capture product information captureFacetMeshProductInfo( oGeometry ); } // Get the product GUIDs var aGuids = getKeys( s_oProductsMap ); // Declare working variables var sGuid; var aMapFiles, aNodeFiles; var bHasMapFiles, bHasNodeFiles; // If we have a stored products map if( oProductsMap ){ // Iterate over the product GUIDs for( var i = 0, nGuids = aGuids.length; i < nGuids; i += 1 ){ // Get the 'current' GUID sGuid = aGuids[ i ]; // Get the stored map file list aMapFiles = oProductsMap[ sGuid ]; bHasMapFiles = Array.isArray( aMapFiles ); // Get the node file list aNodeFiles = s_oProductsMap[ sGuid ]; bHasNodeFiles = Array.isArray( aNodeFiles ); // If we have lists to merge if( bHasMapFiles && bHasNodeFiles ){ // Append this node files to the map aMapFiles = aMapFiles.concat( aNodeFiles ); // Update the map oProductsMap[ sGuid ] = aMapFiles; // If we only have node files } else if( bHasNodeFiles ){ // Update the map oProductsMap[ sGuid ] = aNodeFiles; } } // Update the product map s_oProductsMap = deepCopy( oProductsMap ); } // If we are unifying the results if( bUnified ){ // Return the product GUIDs return aGuids; } // Initialize var oNodeInfo = {}; // Capture the node label oNodeInfo[ "node" ] = getContextualNodeLabel( oNode ); // Capture the products used by the node oNodeInfo[ "products" ] = getProductsInfo( bUnified ); // Return the node products information return oNodeInfo; }; /*********************************************************************/ // Object : A function for getting unified products information function getUnifiedProductsMap( oNodeGuidMap ) { // Get the products information var oProductsMap = getProductsInfo( true ); // Declare working variables var sNodeID, sNodeLabel, sGuid; var oNodeInfo, oInfo; var aGuids, aNodes; // Get the node IDs var aNodeIDs = getKeys( oNodeGuidMap ); // Iterate over the node IDs for( var i = 0, nNodeIDs = aNodeIDs.length; i < nNodeIDs; i += 1 ){ // Get the 'current' node ID sNodeID = aNodeIDs[ i ]; // Get the node info oNodeInfo = oNodeGuidMap[ sNodeID ]; // Get the node label sNodeLabel = oNodeInfo[ "label" ]; // Get the product GUIDs aGuids = oNodeInfo[ "guids" ]; // Iterate over the GUIDs for( var j = 0, nGuids = aGuids.length; j < nGuids; j += 1 ){ // Get the 'current' GUID sGuid = aGuids[ j ]; // Get the product info oInfo = oProductsMap[ sGuid ]; // Get the list of nodes aNodes = oInfo[ "nodes" ]; // If the list does not exist if( !Array.isArray( aNodes ) ){ // Initialize the list aNodes = [ sNodeLabel ]; // If the list does exist } else { // Assign the next item in the list aNodes[ aNodes.length ] = sNodeLabel; } // Update the list of nodes oInfo[ "nodes" ] = aNodes; // Update the product info oProductsMap[ sGuid ] = oInfo; } } // Return the unified return oProductsMap; }; /*********************************************************************/ // Construct the message var sMessage = text( "This script accepts exactly 1 argument - an ECMA Object. " + "This Object may define five (5) optional members, named 'target_path', " + "'unify_products', 'selected_only', 'open_results' and 'run_silent'. The " + "values of the 'unify_products', 'selected_only', 'open_results' and 'run_silent' " + "members must be of the Boolean type. The 'unify_products' member is used " + "to control whether or not results are presented in the context of products " + "(true), or the context of nodes (false). The 'selected_only' member is used " + "to control whether or not only the selected nodes will be evaluated (true), " + "or whether the entire scene is evaluated (false). The 'open_results' member " + "is used to control whether or not results should be opened upon completion - " + "when 'target_path' is defined. The 'run_silent' member is used to control " + "whether or not modal messages to the user are supressed.\n\n" + "Example:\n" + "{\n" + "\t\"target_path\": \"C:/Temp/ProductsUsed.json\",\n" + "\t\"unify_products\": true,\n" + "\t\"selected_only\": false,\n" + "\t\"open_results\": false,\n" + "\t\"run_silent\": false\n" + "}" ); var sTitle = text( "Usage" ); var sOk = text( "&OK" ); // Define the psth of the results file var sFile = ""; // Define whether or not we want to unify (combine) // the node product result(s) in a single product map var bUnifyProducts = true; // Define whether or not to limit which nodes are processed var bSelectedNodes = false; // Define whether or not to open the results var bOpenResults = false; // Define whether or not to suppress modal prompting var bSilent = false; // Declare working variables var vArg0; var vFile; var vUnifyProducts; var vSelectedOnly; var vOpenResults; var vSilent; // If this script was executed remotely if( aArgs.length > 0 ){ // Get the first argument vArg0 = aArgs[0]; // If it is an ECMA Object if( typeof( vArg0 ) == "object" ){ // If it has a member named "target_path" if( vArg0.hasOwnProperty( "target_path" ) ){ // Get the "target_path" value vFile = vArg0[ "target_path" ]; // If "target_path" is not a string if( typeof( vFile ) != "string" ){ // Inform the user MessageBox.information( text( sMessage ), text( sTitle ), sOk ); // We are done... return; } // Capture the value sFile = vFile; // If the value does not end with ".json" if( !sFile.endsWith( ".json" ) ){ // Inform the user MessageBox.information( text( sMessage ), text( sTitle ), sOk ); // We are done... return; } } // If it has a member named "unify_products" if( vArg0.hasOwnProperty( "unify_products" ) ){ // Get the "unify_products" value vUnifyProducts = vArg0[ "unify_products" ]; // If "unify_products" is not a Boolean if( typeof( vUnifyProducts ) != "boolean" ){ // Inform the user MessageBox.information( text( sMessage ), text( sTitle ), sOk ); // We are done... return; } // Capture the value bUnifyProducts = vUnifyProducts; } // If it has a member named "selected_only" if( vArg0.hasOwnProperty( "selected_only" ) ){ // Get the "selected_only" value vSelectedOnly = vArg0[ "selected_only" ]; // If "selected_only" is not a Boolean if( typeof( vSelectedOnly ) != "boolean" ){ // Inform the user MessageBox.information( text( sMessage ), text( sTitle ), sOk ); // We are done... return; } // Capture the value bSelectedNodes = vSelectedOnly; } // If it has a member named "open_results" if( vArg0.hasOwnProperty( "open_results" ) ){ // Get the "open_results" value vOpenResults = vArg0[ "open_results" ]; // If "open_results" is not a Boolean if( typeof( vOpenResults ) != "boolean" ){ // Inform the user MessageBox.information( text( sMessage ), text( sTitle ), sOk ); // We are done... return; } // Capture the value bOpenResults = vOpenResults; } // If it has a member named "run_silent" if( vArg0.hasOwnProperty( "run_silent" ) ){ // Get the "run_silent" value vSilent = vArg0[ "run_silent" ]; // If "run_silent" is not a Boolean if( typeof( vSilent ) != "boolean" ){ // Inform the user MessageBox.information( text( sMessage ), text( sTitle ), sOk ); // We are done... return; } // Capture the value bSilent = vSilent; } } } // Declare working variables var oNode; var aNodes; // Define a 'static' variable to collect product data var s_oProductsMap = {}; // Define how to handle selection var bRoots = true; var bFollowers = true; var bParented = true; var bRecursive = true; // If we are processing the selected nodes only if( bSelectedNodes ){ // Get the primary selection oNode = Scene.getPrimarySelection(); // If nothing is selected if( !oNode ){ // Define the message sTitle = text( "Selection Error" ); sMessage = text( "A node in the scene must be selected to continue." ); // If prompts are not being supressed if( !bSilent && App.showPrompts() ){ // Inform the user MessageBox.information( sMessage, sTitle, sOk ); // If the application is not showing prompts } else { // Provide feedback print( sTitle, ":", sMessage ); // If we are opening the result if( bOpenResults ){ // Cause the log file to be shown openApplicationLog(); } } // We are done.. return; } // Get the list of unique selected nodes aNodes = getUniqueNodes( Scene.getSelectedNodeList(), bRoots, bFollowers, bParented, bRecursive ); // If we are processing all nodes in the scene } else { // Get the list of unique nodes; // if bRoots is true, bones of a skeleton are // not independently evaluated - they are promoted // to the owning skeleton; if bRoots is false, all // nodes in the scene are independently considered aNodes = getUniqueNodes( Scene.getNodeList(), bRoots, false, false, false ); } // Let the user know we are busy setBusyCursor(); // Declare working variable var oNodeInfo; var sData; // Get the number of nodes var nNodes = aNodes.length; // Define an array for capturing non-unified results; pre-size var aNonUnified = bUnifyProducts ? new Array( nNodes ) : []; // Initialize var oNodeGuidMap = {}; // Iterate over the root nodes for( var i = 0; i < nNodes; i += 1 ){ // Get the 'current' node oNode = aNodes[ i ]; // Get the product information for the node oNodeInfo = getNodeProductsMap( oNode, bUnifyProducts ); // If we are not unifying results if( !bUnifyProducts ){ // Capture the info aNonUnified[i] = oNodeInfo; // Next!! continue; } // Get the list of product GUIDs oNodeGuidMap[ oNode.elementID ] = { "label" : getContextualNodeLabel( oNode ), "guids" : oNodeInfo }; } // Declare working variable var oUnifiedMap; // If we are unifying results if( bUnifyProducts ){ // Get the unified products map oUnifiedMap = getUnifiedProductsMap( oNodeGuidMap ); // Get a stringified version of the info sData = getStringified( getValues( oUnifiedMap ) ); // If we are not unifying results } else { // Remove any empty entries aNonUnified = aNonUnified.filter( Boolean ); // Get a stringified version of the info sData = getStringified( aNonUnified ); } // Declare working variable var sError; // If we have a path for a file to write to if( !sFile.isEmpty() ){ // Write the data to file sError = writeToFile( sFile, sData, DzFile.WriteOnly ); // If we do not have any errors if( sError.isEmpty() ){ // If we are opening the result if( bOpenResults ){ // Cause the file to be shown App.showURL( sFile ); // If prompts are not being supressed } else if( !bSilent && App.showPrompts() ){ // sTitle = text( "Data Saved" ); sMessage = text( "Saved product data to:" ) + "\"" + sFile + "\""; // Inform the user switch( MessageBox.information( sMessage, sTitle, sOk, !bOpenResults ? text( "Open" ): "", !bOpenResults ? text( "Show" ): "" ) ){ case 1: // Cause the file to be opened App.showURL( sFile ); break; case 2: // Cause the OS file browser to be opened App.showInNativeBrowser( sFile ); break; default: break } } // If prompts are not being supressed } else if( !bSilent && App.showPrompts() ){ // Inform the user MessageBox.warning( sError, text( "Save Error" ), sOk, "" ); // If we are opening the result } else if( bOpenResults ){ // Provide feedback print( sError ); // Cause the log file to be shown openApplicationLog(); } // If we are not writing to file } else { // Provide feedback print( sData ); // If we are opening the result if( bOpenResults ){ // Cause the log file to be shown openApplicationLog(); } } // Let the user know we are done clearBusyCursor(); // Finalize the function and invoke })( getArguments() );