theProjectRoot = RsConfigGetProjRootDir() theProject = RSConfigGetProjectName() theWildWest = RsConfigGetWildWestDir() theProjectConfig = RsConfigGetProjBinConfigDir() ------------------------------------------------------------------------------------------------------------------------- filein (RsConfigGetWildWestDir() + "script/3dsmax/_config_files/wildwest_header.ms") ------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------- --Ped Validation functions ------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------- filein "pipeline/util/RsUniversalLogViewer.ms" filein "pipeline/util/RsUniversalLog.ms" sRsULog() ------------------------------------------------------------------------------------------------------------------------- global theProjectName = undefined /* -- HACK theProjectName = case theproject of ( "rdr3" : "bob" "gta5":"gta5" ) --filein (pathToConfigFiles + "project_config_"+theProjectName+".ms") */ dotnet.LoadAssembly "System.Xml.XPath.dll" ------------------------------------------------------------------------------------------------------------------------- -- Setup globals ------------------------------------------------------------------------------------------------------------------------- global gPedValidationLogFile = ( RsConfigGetLogDir() + "pedValidation.ulog" ) global gRsPedValidationULog = sRsULog() global pedValidation_Floater global RsPedValidation = undefined ------------------------------------------------------------------------------------------------------------------------- struct RsPedValidationStruct ( configFile=undefined, nmFile=undefined, typeFile=undefined, metaFile=undefined, namelengthMaxFile = undefined, textureXMaxFile = undefined, textureYMaxFile = undefined, pedSuffixFile = undefined, pedConfigData = undefined, pedNodeError = undefined, pedLodError = undefined, fn genPedConfigFile = (configFile=pathToConfigFiles + "characters/ped_data_config.xml"), fn genPedNmFile = (nmFile=RsConfigGetToolsDir() + "etc\\config\\characters\\nm.xml"), fn genPedTypeFile = (typeFile=theProjectConfig + "characters/ped_type_list.xml"), fn genPedMetaFile = (metaFile=RsConfigGetProjRootDir()+ "build\\dev\\common\\data\\peds.meta"), fn createPedNodeError = (pedNodeError = true), fn createpedLodError = (pedLodError = true), pedConfigFile = genPedConfigFile(), pedNmFile = genPedNmFile(), pedTypeFile = genPedTypeFile(), pedMetaFile = genPedMetaFile(), --========================================================================= -- fn getPedConfigData = --========================================================================= -- Description: gets all the ped config data from ped_data_config.xml --========================================================================= fn getPedConfigData = ( local dataFileName = pedConfigFile if (doesfileexist dataFileName) == true then ( local xmlDoc = dotnetobject "System.XML.XMLDocument" xmlDoc.load dataFileName local pedConfigArray = #() ( -- get Racial identifiers local itemIter = (xmlDoc.selectnodes "//pedData/pedcomponenttextures/pedraces/item").GetEnumerator() local theCountEnum = (xmlDoc.selectnodes "//pedData/pedcomponenttextures/pedraces").GetEnumerator() local pedRaceId = #() theCountEnum.MoveNext() local theCount = theCountEnum.current.Childnodes.count for sufIndx in 1 to theCount do ( itemIter.MoveNext() local thepedRaceId = (tolower (itemIter.current.innertext)) append pedRaceId thepedRaceId ) append pedConfigArray pedRaceId ) ( -- get ped suffix array local itemIter = (xmlDoc.selectnodes "//pedData/pedcomponenttypes/item/pedcomponentsuffix/item").GetEnumerator() local pedSuffixArray = #() for sufIndx in 1 to 3 do ( itemIter.MoveNext() local thepedsuffix = (tolower (itemIter.current.innertext)) append pedSuffixArray thepedsuffix ) append pedConfigArray pedSuffixArray ) ( -- get max name length local itemIter = (xmlDoc.selectnodes "//pedData/ped_global_variables/ped_modelnamelength").GetEnumerator() itemIter.MoveNext() local maxnamelength = (itemIter.current.attributes.GetNamedItem "value").value as number append pedConfigArray maxnamelength ) ( -- get max texture width local itemIter = (xmlDoc.selectnodes "//pedData/pedcomponenttextures/texturemaxx").GetEnumerator() itemIter.MoveNext() local xValue = (itemIter.current.attributes.GetNamedItem "value").value as number append pedConfigArray xValue ) ( -- get max texture height local itemIter = (xmlDoc.selectnodes "//pedData/pedcomponenttextures/texturemaxy").GetEnumerator() itemIter.MoveNext() local yValue = (itemIter.current.attributes.GetNamedItem "value").value as number append pedConfigArray yValue ) ( -- get texture types local itemIter = (xmlDoc.selectnodes "//pedData/pedcomponenttextures/texturetypes/item").GetEnumerator() local theCountEnum = (xmlDoc.selectnodes "//pedData/pedcomponenttextures/texturetypes").GetEnumerator() local textureTypeArray = #() theCountEnum.MoveNext() local theCount = theCountEnum.current.Childnodes.count for texIter in 1 to theCount do ( itemIter.MoveNext() local theTextureType = (tolower (itemIter.current.innertext)) append textureTypeArray theTextureType ) append pedConfigArray textureTypeArray ) pedConfigArray ) else ( local msg = "Could not find ped config file" gRsPedValidationULog.LogError msg appendToFile:false ) ), PedConfigData = getPedConfigData(), --=============================================================-- ------ Reads XML attribute -- selectedSet = dotNet xml document navigator selection set, attributeName = Case sensitive XML attribute name --=============================================================-- fn getXMLAttribute selectedSet attributeName = ( -- use the passed in set of nodes to search for our attribute local attributeIterator = selectedSet.Current.Select("@" + attributeName) local returnValue = attributeIterator.Current.Value if attributeIterator.Count > 0 then ( attributeIterator.MoveNext() returnValue = attributeIterator.Current.Value ) returnValue ), --=============================================================-- -- loadSettingsXML fileXML selSetXML attributeArra = ------ Loads in the required XML, returns array of arrays holding the type and values -- ARGS: -- fileXML = XML file to search -- selSetXML = selection to search -- attributeArray = attributes to search for --=============================================================-- fn loadSettingsXML fileXML selSetXML attributeArray = ( local settingsFilePath = fileXML -- create an xml instance local settingsXML = XmlDocument() settingsXML.init() settingsXML.Load settingsFilePath -- now create a XML document instance to read from local settingsDocument = settingsXML.Document -- create our navigator which we use to survey the xml document local settingsNavigator = settingsDocument.CreateNavigator() settingsNavigator.MoveToRoot() -- find all of the specific nodes we are looking for local settingsSelectionSet = settingsNavigator.Select(settingsNavigator.Compile(selSetXML)) local settingsFileFormatted = #() -- lets loop through all of the found nodes and then search for each attribute we are looking for, compiling it in an array of values while (settingsSelectionSet.MoveNext()) do ( local settingsArray = #() for attrIndx= 1 to attributeArray.count do ( local nameAttribute = RsPedValidation.getXMLAttribute settingsSelectionSet attributeArray[attrIndx] append settingsArray nameAttribute ) append settingsFileFormatted settingsArray ) settingsFileFormatted ), --========================================================================= -- fn filterObjNameToArray theName = --========================================================================= -- Description: filters the obj name to its component parts as an array -- ARGS: -- thename = The obj name we are testing --========================================================================= fn filterObjNameToArray theName = ( if theName != undefined then ( local nameLowerCase = tolower theName local removeAppendedName = filterstring nameLowerCase " " local appendedName = "" local prefixName = "" local objNameArray = #() local objNameArrayMain = #() local filteredNameArray = #() for nameItr in 2 to removeAppendedName.count do ( append appendedName removeAppendedName[nameItr] if nameItr != removeAppendedName.count then append appendedName " " ) objNameArray = filterstring removeAppendedName[1] "_" if objNameArray[1].count < 2 then ( objName = (objNameArray[1]+"_"+objNameArray[2]) append filteredNameArray objName for objIter in 3 to 3 do ( append filteredNameArray objNameArray[objIter] ) if objNameArray[4] != undefined then append filteredNameArray objNameArray[4] else append filteredNameArray "" )else ( for objIter in 1 to 2 do ( append filteredNameArray objNameArray[objIter] ) if objNameArray[3] != undefined then append filteredNameArray objNameArray[3] else append filteredNameArray "" ) append filteredNameArray appendedName filteredNameArray ) ), --========================================================================= -- fn doesObjHaveDamageBake theObj = --========================================================================= -- Description: Does the obj have mapping on map id 2 for damage UVs and id 11 for default vert bake -- ARGS: -- theObj = The mesh we are testing --========================================================================= fn doesObjHaveDamageBake theObj = ( -- get the class of theObj if theObj != undefined and superclassof theObj == GeometryClass then ( if classof theObj == Editable_mesh then ( local testForID2 = meshop.getMapSupport theObj 2-- if mesh local testForID11 = meshop.getMapSupport theObj 11-- if mesh ) else if classof theObj == PolyMeshObject or classof theObj == Editable_Poly then ( local testForID2 = polyop.getMapSupport theObj 2-- if poly local testForID11 = polyop.getMapSupport theObj 11-- if poly ) if testForID2 != true then ( if (tolower (substring theObj.name 1 2)) != "p_" and (tolower (substring theObj.name 1 5)) != "hair_" then ( if (tolower (substring theObj.name 1 5)) != "accs_" then ( local msg = ( "\""+theObj.name+"\" does not have damage UVs") gRsPedValidationULog.LogWarning msg appendToFile:false ) ) ) if testForID11 != true then ( local msg = ( "\""+theObj.name+"\" does not have default vert bake") gRsPedValidationULog.LogWarning msg appendToFile:false ) ) ), --========================================================================= -- fn isMaterialUsed theObj theMatID = --========================================================================= -- Description: checks the mesh matID to see if the material in a multisub is using it -- ARGS: -- theObj = The mesh we are testing -- theMatID = the Material ID to search for --========================================================================= fn isMaterialUsed theObj theMatID = ( local usedVal = 0 -- test value -- get the class of theObj if theObj != undefined and superclassof theObj == GeometryClass then ( if classof theObj == Editable_mesh then ( local faceGetter = getFaceMatID -- if mesh ) else if classof theObj == PolyMeshObject or classof theObj == Editable_Poly then ( local faceGetter = polyop.getFaceMatID -- if poly ) try -- making sure theObj will work with getnumfaces ( local numFaces = getNumFaces theObj for faceIdx = 1 to numFaces do ( local getUsedMats = facegetter theObj faceIdx if getUsedMats == theMatID then usedVal = usedVal +1 ) if usedVal > 0 then return true else return false ) catch (Print "Not Poly or Ed Mesh ") ) ), --========================================================================= -- fn testRageShaderDiffuse shaderToTest MeshName = --========================================================================= -- Description: Checks the Rage Shader to verify it has a diffuse texture -- ARGS: -- shaderToTest = The shader we are testing --========================================================================= fn testRageShaderDiffuse shaderToTest = ( local returnArray = #(0,0) -- returnArray[1] = does diffuse texture exist, returnArray[2] = is texture a race texture -- identify Diffuse Texture withing Rage Shader Variables local rageShaderVariables = #() local rageShaderVariableCount = RstGetVariableCount shaderToTest for variableIndx in 1 to rageShaderVariableCount do ( append rageShaderVariables (RstGetVariableName shaderToTest variableIndx) ) local rageShdrDiffuseTexture = finditem rageShaderVariables "Diffuse Texture" -- check a texture is being used local hasDiffuseTexture = RstGetVariable shaderToTest rageShdrDiffuseTexture if hasDiffuseTexture == "" then ( returnArray[1]= 0 -- texture does not exist ) else ( returnArray[1]= 1 -- texture exists local raceArray = rspedvalidation.pedConfigData[1] local textureName = tolower (getFileNameFile hasDiffuseTexture) -- gets texture name local hasRaceTextureName = filterstring textureName "_ " -- filters name for chckRace in 1 to raceArray.count do ( local hasRaceTexture = finditem hasRaceTextureName raceArray[chckRace] if hasRaceTexture > 0 then returnArray[2] = 1 -- is race texture ) ) returnArray ), --========================================================================= -- fn testMaterialProperties theMesh theMat theMatId= --========================================================================= -- Description: Checks the Rage Shader to verify it has a diffuse texture -- ARGS: -- theMesh = The mesh we are testing -- theMat = The shader we are looking for -- theMatId = The material id on the mesh --========================================================================= fn testMaterialProperties theMesh theMat theMatId= ( -- check for rage shaders local isRageShader = classof theMat if isRageShader != Rage_Shader then ( gRsUlog.logWarning ( "\""+theMesh.name+"\" has a material that is not a Rage Shader") context:"shader" ) else ( local objUsesThisShader = RsPedValidation.isMaterialUsed theMesh theMatId -- checks if mesh uses this material if objUsesThisShader == true then ( -- check for diffuse texture local testDiffTexture = RsPedValidation.testRageShaderDiffuse theMat if testDiffTexture[1]==0 then ( local msg = ( "\""+theMesh.name+"\" has a material with no diffuse texture") gRsPedValidationULog.LogWarning msg appendToFile:false context:"texture" ) else ( -- check if it's a racial texture if testDiffTexture[2] > 0 then ( local findRacial = filterstring (tolower theMesh.name) "_ " local HasRacial = finditem findRacial rspedvalidation.pedConfigData[2][1] if HasRacial == 0 then HasRacial = finditem findRacial rspedvalidation.pedConfigData[2][3] if HasRacial == 0 then ( local msg = ( "\""+theMesh.name+"\" uses race textures but does not have \"_R\" or \"_U\" race identifier") gRsPedValidationULog.LogWarning msg appendToFile:false context:"texture" ) ) ) ) ) ), --========================================================================= -- fn shaderErrorChecks mainMesh = --========================================================================= -- Description: Uses the passed in meshes to perform various checks relating to -- shader requirements -- ARGS: -- mainMesh = Mesh we are working on actively --========================================================================= fn shaderErrorChecks mainMesh = ( if mainMesh != undefined and mainMesh.material != undefined then ( -- get the material assigned to the mesh local meshMaterial = mainMesh.material if classof meshMaterial == Multimaterial then ( for materialIndx in 1 to meshMaterial.count do ( RsPedValidation.testMaterialProperties mainMesh meshMaterial[materialIndx] materialIndx ) ) else ( RsPedValidation.testMaterialProperties mainMesh meshMaterial 0 ) ) ), --========================================================================= -- fn nameLengthCheck itemName = --========================================================================= -- Description: Uses the passed in string to check the name length -- is within character limit -- ARGS: -- itemName = String we are working with --========================================================================= fn nameLengthCheck itemName = ( -- find the max name length local maxNameLength = rspedvalidation.pedConfigData[3] --Ped model name should be within the character limit. if classof itemName == String then ( local nameLengthFiltered = (filterstring itemName " ") if nameLengthFiltered[1].count > maxNameLength then ( local msg =("\""+itemName+"\" name is too long. More than "+ ( maxNameLength as string) + " characters") gRsPedValidationULog.LogWarning msg appendToFile:false context:"model" ) ) else "Not a string!" ), --========================================================================= -- fn skinningErrorChecks mainMesh = --========================================================================= -- Description: Uses the passed in meshes to perform various checks relating to -- skinning requirements -- ARGS: -- mainMesh = Mesh we are working on actively --========================================================================= fn skinningErrorChecks mainMesh = ( if mainMesh != undefined then ( -- check for skinning local skinLocation = 0 local allModifiersOnMesh = mainMesh.modifiers for meshIndx in 1 to allModifiersOnMesh.count do --search modifier array for skin modifier ( if classof allModifiersOnMesh[meshIndx] == Skin then ( skinLocation = meshIndx ) ) if skinLocation != 0 then -- Has skin modifier ( skinModifier = allModifiersOnMesh[skinLocation] InstanceMgr.MakeModifiersUnique mainMesh skinModifier 1 modPanel.setCurrentObject allModifiersOnMesh[skinLocation] ui:true ---- Skinning is enabled if skinModifier.enabled == false then ( local msg =( "\""+mainMesh.name+"\" skin modifier not enabled") gRsPedValidationULog.LogWarning msg appendToFile:false context:"model" ) ---- skinned objects have a limit of 4 effective bones if skinModifier.bonelimit > 4 then ( local msg =( "\""+mainMesh.name+"\" has more than the 4 bone per vertex limit") gRsPedValidationULog.LogWarning msg appendToFile:false context:"model" ) ---- No prop meshes "P_" should have skin if (tolower (substring mainMesh.name 1 2)) == "p_" then ( local msg =( "\""+mainMesh.name+"\" is prop mesh, but has skin modifier") gRsPedValidationULog.LogWarning msg appendToFile:false context:"model" ) ---- no verts skinned to unused bones, ---- unused bones being secondary movement bones/attachment bones ( local Vertexfound = 0 local bonesInSkin = skinOps.GetNumberBones skinModifier local boneNameArray = #() local badBoneNameArray = #() for boneIndx in 1 to bonesInSkin do ( local boneName = (skinOps.GetBoneName skinModifier boneIndx 0) if (substring boneName 1 5) != "SKEL_" and (substring boneName 1 3) != "RB_"then append badBoneNameArray boneName if (substring boneName 1 5) == "SKEL_" then append boneNameArray boneName ) local skinnedVertices = skinOps.GetNumberVertices skinModifier if Vertexfound == 0 then for vertexIndx in 1 to skinnedVertices do ( influenceBones =skinOps.GetVertexWeightCount skinModifier vertexIndx for boneIndx in 1 to influenceBones do ( local influenceBoneID = skinOps.GetVertexWeightBoneID skinModifier vertexIndx boneIndx local influenceBoneName = (skinOps.GetBoneName skinModifier influenceBoneID 0) local influenceBoneinBoneList = finditem badBoneNameArray influenceBoneName if influenceBoneinBoneList > 0 then ( if Vertexfound == 0 then ( local msg = ("\""+mainMesh.name+"\" has vertices influenced by an unused bone") gRsPedValidationULog.LogWarning msg appendToFile:false context:"model" ) Vertexfound = (Vertexfound + 1) ) ) ) ) -- *********************** WANT TO MAKE SURE BONE NUBS COUNT ******************* -- currently this does not flag if Skel_ NUBs are not in skin. Need to find out if this is correct -- -- if we want to flag nubs change findAllSkelBones = 1 to findAllSkelBones = 0 ---- all "skel_" joint should be in the skin of the head mesh if (substring mainMesh.name 1 5) == "head_" then ( local MissingBones = 0 local skelBoneNameArray = for o in $SKEL_* collect o.name -- collect all bones named "Skel_" for boneIndx in 1 to skelBoneNameArray.count do -- check each skelbone is in modifier ( local findAllSkelBones = finditem boneNameArray skelBoneNameArray[boneIndx] local nubCheck = (filterstring skelBoneNameArray[boneIndx] "_") if (tolower (nubCheck[nubCheck.count])) == "nub" then findAllSkelBones = 1 if findAllSkelBones == 0 and MissingBones == 0 then ( local msg = ("\""+mainMesh.name+"\"is a head mesh and is missing some SKEL_ bones from the skin modifier" ) gRsPedValidationULog.LogWarning msg appendToFile:false context:"model" MissingBones = (MissingBones + 1) ) ) ) ) else -- does not have skin modifier ( if (tolower (substring mainMesh.name 1 2)) != "p_" then ( local msg = ("mesh \""+mainMesh.name+"\" does not have valid skin modifier") gRsPedValidationULog.LogWarning msg appendToFile:false context:"model" ) ) ) OutputStringStream ), --========================================================================= -- fn checkMeshErrors mainMesh = --========================================================================= -- Description: Uses the passed in meshes to perform various checks relating to -- mesh requirements -- ARGS: -- mainMesh = Mesh we are working on actively --========================================================================= fn checkMeshErrors mainMesh = ( if mainMesh != undefined and (tolower (substring mainMesh.name 1 2)) != "p_" then ( local meshToMatIdArray =ped_fullComponentNamesByID for meshMatIndx in 1 to meshToMatIdArray.count do ( local meshNameinArray = RsPedValidation.searchFilteredString mainMesh.name "_ " meshToMatIdArray[meshMatIndx] if meshNameinArray == true then ( local meshMatIdEqualsName = RsPedValidation.isMaterialUsed mainMesh meshMatIndx if meshMatIdEqualsName != true then ( local msg = ("mesh \""+mainMesh.name+"\" does not have correct Mat ID") gRsPedValidationULog.LogWarning msg appendToFile:false context:"model" ) ) ) -- check for scaling local theMeshScale = mainMesh.scale return theMeshScale if theMeshScale != [1,1,1] then ( local msg = ( "\""+mainMesh.name+"\" has a scale applied") gRsPedValidationULog.LogWarning msg appendToFile:false context:"model" ) ) ), --========================================================================= -- fn searchFilteredString theString theFilter theSearch = --========================================================================= -- Description: tests string for arg. Uses tolower to remove case from search -- returns true or false -- ARGS: -- theString = the string we are searching -- theFilter = how we will filter the string -- theSearch = the string to look for --========================================================================= fn searchFilteredString theString theFilter theSearch = ( if theString != undefined and classof theString == String then -- check string exists and is a string ( local filteredArray = filterString theString theFilter -- filter theString with theFilter local loweredArray = #() -- create an array for the lower case strings for stringIndx in 1 to filteredArray.count do append loweredArray (tolower filteredArray[stringIndx]) -- append lower case strings to array local findString = finditem loweredArray (tolower theSearch) -- lower case array for lower case theSearch if findString == 0 then return false else return true ) ), --========================================================================= -- fn checkRaceIDName mainMesh = --========================================================================= -- Description: Uses the passed in meshes to check there is a race identifier -- in the mesh name -- ARGS: -- mainMesh = Mesh we are working on actively --========================================================================= fn checkRaceIDName mainMesh = ( if mainMesh != undefined then ( -- check for correct racial identifier naming if (tolower (substring mainMesh.name 1 2)) != "p_" then -- makes sure the mesh isnt a prop ( local filterName = (RSPedValidation.filterObjNameToArray mainMesh.name) local raceIdent = filterName[3] local raceIdentFound = 0 local identifierArray = rspedvalidation.pedConfigData[2] local hasIdentifierRoot = finditem identifierArray raceIdent if hasIdentifierRoot == 0 then ( local msg = ( "\""+mainMesh.name+"\" does not have a racial identifier") gRsPedValidationULog.LogWarning msg appendToFile:false context:"model" )else ( raceIdentFound = 1 local texSearchName = (filterName[1]+"_diff_"+filterName[2]) local texArray = getFiles ( maxfilepath+"Textures\\HighRes\\"+texSearchName+"*") for textureIter in 1 to texArray.count do ( local filterTexID = filterstring (getfilenamefile texArray[textureIter]) "_." local raceTexID = (tolower filterTexID[filterTexID.count]) local compareID = finditem rspedvalidation.pedConfigData[1] raceTexID if compareID != 0 then ( local theRaceID = rspedvalidation.pedConfigData[1][finditem rspedvalidation.pedConfigData[1] raceTexID] if theRaceID != "uni" then ( if raceIdent != "r" then ( local msg = ( "\""+mainMesh.name+"\" uses race textures, but does not use racial identifier naming, \"_r\"") gRsPedValidationULog.LogWarning msg appendToFile:false context:"model" ) ) ) ) ) ) ) ), --========================================================================= -- fn findNumeric theString = --========================================================================= -- Description: Tests for integers within a filtered string -- ARGS: -- theString = the string to test --========================================================================= fn findNumeric theString = ( local seperateString = filterString theString "_" for stringIndx in 1 to seperateString.count do ( local isNum = seperateString[stringIndx] as number if classof isNum == integer then return isNum ) ), --========================================================================= -- fn checkNodeNamesAreSequential theArray = --========================================================================= -- Description: Collects the nodes in the scene and finds out if the nodes are -- named sequentially -- ARGS: -- theArray = the array of Meshes to look for similar names --========================================================================= fn checkNodeNamesAreSequential theArray = ( if theArray != undefined then ( local checkTheNode = undefined local findSiblings = undefined local siblingArray = #() local siblingNameArray = #() for arrayIndx in 1 to theArray.count do ( checkTheNode = RSPedValidation.filterObjNameToArray theArray[arrayIndx].name findSiblings = checkTheNode[1] siblingArray = (execute ("$"+findSiblings+"* as array")) for siblingIter in 1 to siblingArray.count do ( local filterSibLingNameParts = RSPedValidation.filterObjNameToArray siblingArray[siblingIter].name local filterSibLingName = filterSibLingNameParts[2] local isInArray = finditem siblingNameArray filterSibLingName if isInArray == 0 and filterSibLingName != undefined then append siblingNameArray filterSibLingName ) local sortedArray = sort siblingNameArray for numIter in 1 to sortedArray.count do ( local checkNumber = (sortedArray[numIter] as integer + 1) if checkNumber != numIter then ( local msg = ("\""+findSiblings+"\" not named sequentially") gRsPedValidationULog.LogWarning msg appendToFile:false context:"model" --print msg ) ) ) ) siblingNameArray ), --========================================================================= -- fn getFilesRecursive root pattern = --========================================================================= -- Description: Recurses through selected folder to find pattern -- ARGS: -- root = The root folder to search in -- pattern = The pattern to search for --========================================================================= fn getFilesRecursive root pattern = ( local dir_array = GetDirectories (root+"/*") for d in dir_array do join dir_array (GetDirectories (d+"/*")) local my_files = #() for f in dir_array do join my_files (getFiles (f + pattern)) my_files ), --========================================================================= --fn highLowCheck Mainmesh = --========================================================================= -- Description: Tests to see if mesh has a lod and if so, then if they has same shader -- ARGS: -- Mainmesh = The mesh to perform check on --========================================================================= fn highLowCheck Mainmesh = ( local lodSets = execute ("$"+(getfilenamefile maxfilename)+"* as array") -- collect all node sets if lodSets.count < 2 then ( if pedLodError == undefined then ( createpedLodError() local msg = "Could not find Lod collection. It either does not exist or is named incorrectly." gRsPedValidationULog.LogWarning msg appendToFile:false context:"model" ) )else ( for setIndx in 1 to lodSets.count do ( if lodSets[setIndx] != (getnodebyname (getfilenamefile maxfilename)) then -- does not check the non LOD set ( local whichLod = filterString lodSets[setIndx].name "-" -- filters the LOD identifier local LodName = "" if whichLod[2] == "L" then LodName = " LOD" else if whichLod[2] == "l2" then LodName = " LOD2" --- High and Low LOD have the same shader if (tolower (substring Mainmesh.name 1 2)) != "p_" then ( if LodName == " LOD2" then ( local lod2Items = #("head","uppr","lowr") local lod2Check = filterstring Mainmesh.name "_ " itemIsLod2 = (finditem lod2Items (tolower lod2Check[1])) if itemIsLod2 > 0 then ( ( local hasLowMesh = getnodebyname (Mainmesh.name+LodName) -- Selects the LOD if hasLowMesh != undefined then ( local hasSameShader = Mainmesh.material == hasLowMesh.material -- Compares the shaders if hasSameShader != true then ( ( local msg = ("\""+mainMesh.name+"\" and LOD mesh do not use same shader") gRsPedValidationULog.LogWarning msg appendToFile:false context:"model" ) ) ) else ( local msg = ("\""+mainMesh.name+"\" has no"+LodName+ " mesh") gRsPedValidationULog.LogWarning msg appendToFile:false context:"model" ) ) ) ) ) ) ) ) ), --========================================================================= -- fn countTexturesInFile = --========================================================================= -- Description: Collects all the texutures used in the scene and returns an array of them --========================================================================= fn countTexturesInFile = ( local texturesInFile = #() local origAssets = for assetIndx = 1 to AssetManager.GetNumAssets() collect (AssetManager.GetAssetByIndex assetIndx) for assetIndx in origAssets do ( local AType = assetIndx.getType() if AType == #bitmap then ( local AFile = (tolower (assetIndx.getfilename())) if substring AFile 1 1 == "x" then ( local filterHiRes = filterstring (getFilenamePath AFile) "\\" if filterHiRes[filterHiRes.count] == "highres" then append texturesInFile AFile ) ) ) texturesInFile ), --========================================================================= -- fn textureChecks = --========================================================================= -- Description: Makes sure scen is using textures relating to -- texture requirements --========================================================================= fn textureChecks = ( --get all .tga files from the maxfilepath+Textures\ConsoleRes and all its subfolders: local checkForHighResDir = doesfileexist (maxfilepath+"Textures\\HighRes") if checkForHighResDir == true then ( local texturesInFolder = getFiles (maxfilepath+"Textures\\HighRes\\*.tga") -- check all textures in HighRes folder are right dimensions for texIndx in 1 to texturesInFolder.count do ( size = getBitmapInfo texturesInFolder[texIndx] if size[3] > rspedvalidation.pedConfigData[4] or size[4] > rspedvalidation.pedConfigData[5] then ( local msg = ((filenameFromPath texturesInFolder[texIndx])+" is larger than recommended. It is "+ (size[3] as string)+"x"+(size[4] as string)+".") gRsPedValidationULog.LogWarning msg appendToFile:false context:"texture" ) ) -- check all textures in HighRes folder are used for texIndx in 1 to texturesInFolder.count do ( local objNameFromTex = (filterstring (getfilenamefile texturesInFolder[texIndx]) "_") local objExistsArray = execute ("$"+objNameFromTex[1]+"* as array") if objExistsArray.count == 0 then ( local msg =("\""+(getfilenamefile texturesInFolder[texIndx]) + "\" texture in the \"HighRes\" folder, is not used in this ped file") gRsPedValidationULog.LogWarning msg appendToFile:false context:"texture" ) ) /* -- local texturesInFile = RsPedValidation.countTexturesInFile() if texturesInFolder.count > texturesInFile.count then ( local texuredetails = 0 if texuredetails == 0 then ( local msg =("There are unused textures in the \"HighRes\" folder") gRsPedValidationULog.LogWarning msg appendToFile:false context:"texture" ) else ( for texIter in 1 to texturesInFolder.count do ( local isInFile = findItem texturesInFile texturesInFolder[texIter] if isInFile == 0 then ( theTexFileName = getFilenameFile texturesInFolder[texIter] local msg =("There are unused textures in the \"HighRes\" folder") local msg =(theTexFileName + " in the \"HighRes\" folder, is not used in this Max file") gRsPedValidationULog.LogWarning msg appendToFile:false context:"texture" ) ) ) ) */ ) else ( local msg =("No \"HighRes\" texture folder found") gRsPedValidationULog.LogError msg appendToFile:false context:"texture" ) ), --========================================================================= -- fn findXMLValue theXml theItem = --========================================================================= -- Description: find stated item in XML file -- ARGS: -- theXml = The xml to search -- theItem = The item to search for the value --========================================================================= fn findXMLValue theXml theItem= ( local dataFileName = theXml if (doesfileexist dataFileName) == true then ( local xmlDoc = dotnetobject "System.XML.XMLDocument" xmlDoc.load dataFileName local itemIter = (xmlDoc.selectnodes theItem).GetEnumerator() local theArray = #() while (itemIter.MoveNext()) do ( if itemIter.current.IsEmpty == true then ( -- print "true" append theArray (itemIter.current.GetAttribute "value") ) if itemIter.current.IsEmpty == false then ( -- print "false" append theArray itemIter.current.InnerText ) ) ) theArray ), --========================================================================= -- fn checkSkeletonIsValid = --========================================================================= -- Description: checks that skeleton in file is the same as latest skeleton --========================================================================= fn checkSkeletonIsValid = ( if maxfilename != "" then ( --- make sure skeletons are up to date in perforce local p4Checks = RsPerforce() -- perforce fns local skelLocation = (RsConfigGetProjRootDir()+"art\\peds\\Skeletons\\") local checklFileInP4 = (p4Checks.exists #((skelLocation+"Male Skeleton.max"),(skelLocation+"Female Skeleton.max"),(skelLocation+"Female Skeleton Heels.max"))) local compareSkels = false local genderSkeleton = undefined if checklFileInP4.count > 0 then ( -- check gender of ped local theGenderFilname = filterstring (getfilenamefile maxfilename) "_" local theGender = theGenderFilname[2] if theGender == "M" then genderSkeleton = (RsConfigGetProjRootDir()+"art\\peds\\Skeletons\\Male Skeleton.max") if theGender == "F" then genderSkeleton = (RsConfigGetProjRootDir()+"art\\peds\\Skeletons\\Female Skeleton.max") if genderSkeleton != undefined then ( if doesfileexist genderSkeleton != false then ( local getXref =xrefs.addNewXRefFile genderSkeleton -- collect skeleton nodes local skelInFile = for obj in $dummy01 collect obj local skelInXref = for obj in getXref.tree.children[1] collect obj local skelInfoArray = #(#(),#(),#()) local skelInfoArrayXref = #(#(),#(),#()) sliderTime = 0f -- time to zero in case there is animation on file -- collect file skeleton info for skelIndx in 1 to skelInFile.count do ( if (tolower (substring skelInFile[skelIndx].name 1 5)) == "skel_" then ( append skelInfoArray[1] skelInFile[skelIndx].name append skelInfoArray[2] skelInFile[skelIndx].transform if skelInFile[skelIndx].parent != undefined then append skelInfoArray[3] skelInFile[skelIndx].parent.name else append skelInfoArray[3] "" ) ) -- collect xref skeleton info for skelIndx in 1 to skelInXref.count do ( if (tolower (substring skelInXref[skelIndx].name 1 5)) == "skel_" then ( append skelInfoArrayXref[1] skelInXref[skelIndx].name append skelInfoArrayXref[2] skelInXref[skelIndx].transform if skelInXref[skelIndx].parent != undefined then append skelInfoArrayXref[3] skelInXref[skelIndx].parent.name else append skelInfoArrayXref[3] "" ) ) --compare transforms between file and xref skeletons if skelInfoArray[2].count == skelInfoArrayXref[2].count then ( for trsfrmIndx in 1 to skelInfoArray[2].count do ( for pnt3Indx in 1 to 4 do ( local point3Variable = skelInfoArray[2][trsfrmIndx][pnt3Indx] local areCloseEnough = assert_point3_equal skelInfoArrayXref[2][trsfrmIndx][pnt3Indx] point3Variable tolerance:0.1 if areCloseEnough == true then skelInfoArrayXref[2][trsfrmIndx] = skelInfoArray[2][trsfrmIndx] ) ) )else ( -- THIS IS JUST FOR DEBUG TO COMPARE SKELETONS IF THEY DONT MATCH -- /* global ss = stringstream "" format "File = XREF\n" to:ss for i in 1 to skelInfoArray[1].count do format "% = %\n" skelInfoArray[1][i] skelInfoArrayXref[1][i] to:ss ns = newscript() format (ss as string) to:ns */ ) -- compare everything compareSkels = with PrintAllElements on skelInfoArray as string == skelInfoArrayXref as string xrefs.deleteAllXRefs() if compareSkels != true then ( local msg ="this skeleton does not match the current skeleton in perforce" gRsPedValidationULog.LogError msg appendToFile:false context:"model" ) )else( local msg ="you do not have the latest skeletons" gRsPedValidationULog.LogError msg appendToFile:false context:"model" ) )else ( local msg ="could not determine gender of ped. check file naming." gRsPedValidationULog.LogError msg appendToFile:false context:"model" ) )else ( local msg ="you do not have the latest skeletons in perforce" gRsPedValidationULog.LogError msg appendToFile:false context:"model" ) ) compareSkels ), --========================================================================= -- fn generatePedList = --========================================================================= -- Description: creates a list of ped names in ped_type_list.xml file. --========================================================================= fn generatePedList = ( local pedTypeArray = #("//PedTypes/streamedpeds/file","//PedTypes/componentpeds/file","//PedTypes/cutspeds/file") local fileNameArray = #() for pedIndx in 1 to pedTypeArray.count do ( local xmlFileArray = RsPedValidation.findXMLValue RsPedValidation.pedConfigFile pedTypeArray[pedIndx] local subfileNameArray = #() for fileIndx in 1 to xmlFileArray.count do ( append subfileNameArray (tolower (getfilenamefile xmlFileArray[fileIndx])) ) append fileNameArray subfileNameArray ) fileNameArray ), --========================================================================= -- fn createPedMetaNameList = --========================================================================= -- Description: creates a list of all ped names in peds.meta file. --========================================================================= fn createPedMetaNameList = ( local dataFileName = RsPedValidation.pedMetaFile if (doesfileexist dataFileName) == true then ( local fileNameArray = #() ( local subfileNameArray = #() local xmlFileArray = RsPedValidation.findXMLValue dataFileName "//CPedModelInfo__InitDataList/InitDatas/Item/Name" for fileIndx in 1 to xmlFileArray.count do ( append subfileNameArray (tolower (getfilenamefile xmlFileArray[fileIndx])) ) append fileNameArray subfileNameArray ) ( local subfileNameArray = #() local xmlFileArray = RsPedValidation.findXMLValue dataFileName "//CPedModelInfo__InitDataList/InitDatas/Item/IsStreamedGfx" for fileIndx in 1 to xmlFileArray.count do ( append subfileNameArray (tolower (getfilenamefile xmlFileArray[fileIndx])) ) append fileNameArray subfileNameArray ) ) fileNameArray ), --========================================================================= --fn comparePedtexToFile theFile = --========================================================================= -- Description: Tests to see racial indentifiers in pedtex file compare to meshes -- ARGS: -- theFile = The file to compare --========================================================================= fn comparePedtexToFile theFile = ( if doesfileexist theFile == true then ( local theFileArray = #() -- Array for file strings local theFileStream = openFile theFile seek theFileStream 0 -- Go to beginning of filestream for stringIndx in 1 to 10000 while (eof theFileStream == false ) do ( append theFileArray (readLine theFileStream) -- append file strings to array ) local filteredArray = #() -- array to contain file strings filtering out uneeded name text for stringIndx in 1 to theFileArray.count do ( local theFileName = (tolower (getFilenameFile theFileArray[stringIndx])) local textureFileName = (theFileName + (tolower (getFilenameType theFileArray[stringIndx])) ) local filteredName = filterstring theFileName "_ ." local removeArray =#("diff","normal","spec","a","b","c","d","e","f","g","h") local pedTextureTypes = rspedvalidation.pedconfigdata[6] for txtrIndx in 1 to pedTextureTypes.count do -- checks against the texturestypes array in the project config max script ( append removeArray (substring pedTextureTypes[txtrIndx] 3 100) ) for nameIndx in 1 to removeArray.count do -- remove unwanted strings ( local hasString = finditem filteredName removeArray[nameIndx] if hasString > 0 then deleteitem filteredName hasstring ) hasString = finditem filteredName rspedvalidation.pedconfigdata[1][1] if hasString > 0 then filteredName[hasstring] = "u" -- if true add identifier to name local filterRaces = rspedvalidation.pedconfigdata[1] for i in 2 to filterRaces.count do ( e hasString = finditem filteredName filterRaces[i] if hasString > 0 then filteredName[hasstring] = "r" -- if true add identifier to name ) local createName = "" -- empty string to create node name for arrayIndx in 1 to filteredName.count do ( append createName filteredName[arrayIndx] if arrayIndx != filteredName.count do append createName "_" -- create node name ) append filteredArray createName -- add node name to filtered array ) local nodesInScene = RsPedValidation.createMeshList () -- creates a list of nodes local filteredNodes = #() -- array for filtered node names local objName = "" if nodesInScene.count != 0 then ( for nodeIndx in 1 to nodesInScene.count do ( local nameToArray = RsPedValidation.filterObjNameToArray nodesInScene[nodeIndx].name objName = (nameToArray[1]+"_"+nameToArray[2]) if nameToArray[3].count > 0 then append objName ("_"+nameToArray[3]) append filteredNodes objName-- append filtered name ) for nodeIndx in 1 to filteredArray.count do -- compare filtered node array to generated node name array ( local findNode = finditem filteredNodes filteredArray[nodeIndx] if findNode == 0 then -- if node in file cannot be found then send error ( ( local msg =("\"" +(getFilenameFile theFileArray[nodeIndx]) + ".tga\" in pedtex file but \""+filteredArray[nodeIndx] + "\" mesh does not exist") gRsPedValidationULog.LogWarning msg appendToFile:false context:"texture" ) ) ) ) ) --print filteredArray --print "----------------" --print filteredNodes ), --========================================================================= -- fn doFileChecks = --========================================================================= -- Description: Runs through all the ped validation external file checks --========================================================================= fn doFileChecks = ( -- check that the character is in the nm.xml file local characterXMLarray = RsPedValidation.loadSettingsXML RsPedValidation.pedNmFile "/xmlmatchs/xmlmatch" #("source") local filteredCharacterXMLarray = #() for arrayIndx = 1 to characterXMLarray.count do append filteredCharacterXMLarray (tolower ((filterstring characterXMLarray[arrayIndx][1] "/.")[1])) local isPedInArray = finditem filteredCharacterXMLarray (tolower (getFileNameFile maxfilename)) if isPedInArray == 0 then gRsUlog.logError "this ped is not in nm.xml. check ped name." -- check that the character is in thepeds.meta file local pedMetaNameList = RsPedValidation.createPedMetaNameList() local isPedInArray = finditem pedMetaNameList[1] (tolower (getFileNameFile maxfilename)) local streamedPedData = RsPedValidation.generatePedList() -- generates a list of ped data from ped_type_list.xml if isPedInArray == 0 then gRsUlog.logError "this ped is not in peds.meta. check ped name." else ( local checkStreamGroup = finditem streamedPedData[2] (tolower (getFileNameFile maxfilename)) if checkStreamGroup != 0 then ( if pedMetaNameList[2][isPedInArray] != "false " then ( local msg = "this ped is in the component ped list in \"ped_type_list.xml\", but is not flagged \"IsStreamedGfx=false\" in \"peds.meta\" " gRsPedValidationULog.LogWarning msg appendToFile:false context:"model" ) ) ) --check maps in .pedtex have a mesh in max file if maxFileName != "" then RsPedValidation.comparePedtexToFile (maxfilepath+(getfilenamefile maxfilename)+".pedtex") ), --========================================================================= -- fn checkAllInP4 = --========================================================================= -- Description: checks that all the files are in perforce and up to date --========================================================================= fn checkAllInP4 = ( -- create array with max file string and pedtex string, file based off of filename local doesMaxfileExist = doesFileExist (maxfilepath+maxFileName) if doesMaxfileExist == true then ( local p4Checks = RsPerforce() -- perforce fns global allFilesToCheck = #((maxfilepath+maxFileName), (maxfilepath+(getFilenameFile maxFileName)+".pedtex")) local theGenderFilname = filterstring (getfilenamefile maxfilename) "_" local genderSkeleton = undefined local theGender = theGenderFilname[2] if theGender == "M" then genderSkeleton = (RsConfigGetProjRootDir()+"art\\peds\\Skeletons\\Male Skeleton.max") if theGender == "F" then genderSkeleton = (RsConfigGetProjRootDir()+"art\\peds\\Skeletons\\Female Skeleton.max") if genderSkeleton != undefined then append allFilesToCheck genderSkeleton -- add texture file strings to to array local checkForHighResDir = doesfileexist (maxfilepath+"Textures\\HighRes") if checkForHighResDir == true then ( local texturesInFolder = getFiles (maxfilepath+"Textures\\HighRes\\*.tga") for fileIndx in 1 to texturesInFolder.count do ( append allFilesToCheck texturesInFolder[fileIndx] ) ) -- check that all files are in perforce and up to date global checkAllFilesInP4 = (p4Checks.exists allFilesToCheck as array) -- if the returned value is not the same as the string array then recurse and find which files are not in perforce if checkAllFilesInP4.count != allFilesToCheck.count then ( for comparefiles in 1 to allFilesToCheck.count do ( local inArray = finditem checkAllFilesInP4 comparefiles if inArray == 0 then ( ( local msg = ("\""+allFilesToCheck[comparefiles]+"\" not in perforce or file not latest") gRsPedValidationULog.LogError msg appendToFile:false context:"model" ) ) ) ) ) else ( local msg = "The max file has not been saved or does not exist" gRsPedValidationULog.LogError msg appendToFile:false context:"model" ) ), --========================================================================= -- fn createMeshList = --========================================================================= -- Description: checks that the root node and the file name match then collects nodes --========================================================================= fn createMeshList = ( -- Check to see that the character root node name matches the filename local NodeMatchesFilename = getNodeByName (getFilenameFile maxFileName) if NodeMatchesFilename == undefined then ( ( local msg = "the character node does not match the max filename or does not exist" gRsPedValidationULog.LogError msg appendToFile:false context:"model" ) return #() ) else ( local characterNodeMeshes = for obj in NodeMatchesFilename collect obj --Collect the nodes deleteItem characterNodeMeshes 1 -- Remove Parent Dummy node if characterNodeMeshes.count == 0 then ( if rsPedValidation.pedNodeError == undefined then ( createPedNodeError() local msg = "the ped node has no children, or is not set up correctly" gRsPedValidationULog.LogError msg appendToFile:false context:"model" ) characterNodeMeshes )else ( characterNodeMeshes ) ) ), --========================================================================= -- fn validatePed = --========================================================================= -- Description: Runs through all the ped validation check functions for a pre rigged ped --========================================================================= fn validatePedPreRig = ( RsPedValidation.dofileChecks() -- run through all the file checks RsPedValidation.textureChecks() -- run through all the texture checks local theMeshlist = RsPedValidation.createMeshList() if theMeshlist.count > 0 then ( for meshIndx in 1 to theMeshlist.count do ( RsPedValidation.nameLengthCheck theMeshlist[meshIndx].name -- check node name length RsPedValidation.checkMeshErrors theMeshlist[meshIndx] -- run through mesh error checks RsPedValidation.checkRaceIDName theMeshlist[meshIndx] -- checks race identifiers RsPedValidation.shaderErrorChecks theMeshlist[meshIndx] -- run through shader error checks RsPedValidation.highLowCheck theMeshlist[meshIndx] -- run through high and low mesh error checks RsPedValidation.doesObjHaveDamageBake theMeshlist[meshIndx] -- check mesh for damage UV's ) RsPedValidation.checkNodeNamesAreSequential theMeshlist -- check that all similar meshes are numbered sequentially -- if gRsUlog.HasNewErrorsWarnings() == true then ShowRsUlogDialog() ) return theMeshlist ), --========================================================================= -- fn validatePedPostRig = --========================================================================= -- Description: Runs through all the ped validation check functions for a rigged ped --========================================================================= fn validatePedPostRig = ( local theMeshlist = RsPedValidation.validatePedPreRig() local isSkeletonValid = RsPedValidation.checkSkeletonIsValid() if isSkeletonValid == true then ( if theMeshlist.count > 0 then ( max modify mode undo on ( with redraw off for meshIndx in 1 to theMeshlist.count do ( select theMeshlist[meshIndx] -- select node RsPedValidation.skinningErrorChecks theMeshlist[meshIndx] -- run through skinning error checks ) ) max undo ) -- if gRsUlog.HasNewErrorsWarnings() == true then ShowRsUlogDialog() ) ), --========================================================================= -- fn validatePedPostExprt = --========================================================================= -- Description: checks data is in perforce --========================================================================= fn validatePedPostExprt= ( RsPedValidation.checkAllInP4() ), --========================================================================= -- fn RsTa_checkIfBonesSkinned = --========================================================================= -- Description: checks if verts are skinned to fingers and toe bones --========================================================================= fn RsTa_checkIfBonesSkinned obj fingerString toeString &fingersFlag &toesFlag= ( max modify mode select obj local numVerts = obj.numVerts local theSkin = obj.modifiers[#Skin] local fingerCheck = false local toeCheck = false if(theSkin != undefined) then ( modPanel.setCurrentObject theSkin for theVert = 1 to numVerts do ( local numBones = skinOps.GetVertexWeightCount theSkin theVert for theBone = 1 to numBones do ( local theBoneID = skinOps.GetVertexWeightBoneID theSkin theVert theBone local theBoneName = skinOps.GetBoneName theSkin theBoneID 1 local stringTest = findString theBoneName fingerString if (stringTest != undefined) then ( local theWeight = skinOps.GetVertexWeight theSkin theVert theBone if (theWeight > 0.25) then fingerCheck = true ) else ( stringTest = findString theBoneName toeString if (stringTest != undefined) then ( local theWeight = skinOps.GetVertexWeight theSkin theVert theBone if (theWeight > 0.25) then toeCheck = true ) ) ) ) ) if (fingerCheck == true) then fingersFlag += 1 else if (toeCheck == true) then toesFlag += 1 ), --========================================================================= -- fn RsTa_validateFingerToes = --========================================================================= -- Description: validates finger and toe bone skinning --========================================================================= fn RsTa_validateFingerToes= ( local theSelection = getCurrentSelection() local theCount = theSelection.count local fingersFlag = 0 local toesFlag = 0 if (theCount != 0) then for obj in theSelection do RsPedValidation.RsTa_checkIfBonesSkinned obj "Finger" "Toe" &fingersFlag &toesFlag if (fingersFlag == 0 and toesFlag == 0) then ( local msg ="Fingers and toes are not skinned." gRsPedValidationULog.LogWarning msg appendToFile:false context:"model" ) else if (fingersFlag == 0) then ( local msg ="Fingers are not skinned." gRsPedValidationULog.LogWarning msg appendToFile:false context:"model" ) else if (toesFlag == 0) then ( local msg ="Toes are not skinned." gRsPedValidationULog.LogWarning msg appendToFile:false context:"model" ) ), --========================================================================= -- fn RsTa_findSkinnedObjects = --========================================================================= -- Description: Finds objects that are either skinned but not parented for export, or not skinned --========================================================================= fn RsTa_findSkinnedObjects= ( local unparentedArray = #() local unskinnedArray = #() for obj in objects where (classof obj.baseObject == Editable_poly or classOf obj.BaseObject == Editable_mesh) do ( if (obj.modifiers[#Skin] != undefined) then ( if (obj.parent == undefined) then append unparentedArray obj.name ) else if (obj.modifiers[#Skin] == undefined) then ( local lowerCaseName = toLower obj.name if (findString lowerCaseName "mover" == undefined and findString lowerCaseName "p_" == undefined) then append unskinnedArray obj.name ) ) if (unparentedArray.count != 0) then ( for str in unparentedArray do ( local msg =("\""+str+"\" is skinned but not parented to the export dummy.") gRsPedValidationULog.LogWarning msg appendToFile:false context:"model" ) ) if (unskinnedArray.count != 0) then ( for str in unskinnedArray do ( local msg =("\""+str+"\" is not skinned.") gRsPedValidationULog.LogWarning msg appendToFile:false context:"model" ) ) ), --========================================================================= -- fn RsTa_findExportObjects = --========================================================================= -- Description: Finds the file's export dummy, gets exporting objects from it --========================================================================= fn RsTa_findExportObjects= ( clearSelection() local fileName = filterString maxFileName "." fileName = fileName[1] local exportDummy = getNodeByName fileName if (exportDummy != undefined) then ( select exportDummy.children ) else ( local msg ="Could not find the export dummy. Please check the dummy exists and is named properly." gRsPedValidationULog.LogWarning msg appendToFile:false context:"model" ) ), --========================================================================= -- fn RsTa_confirmNullsExist = --========================================================================= -- Description: Validates PH, IK etc nodes exist in scene --========================================================================= fn RsTa_confirmNullsExist= ( local missingObjs = #() local findNameList = #("Dummy01", "IK_Head", "IK_L_Foot", "IK_L_Hand", "IK_R_Foot", "IK_R_Hand", "IK_Root", "PH_L_Foot", "PH_L_Hand", "PH_R_Foot", "PH_R_Hand") for x in findNameList do if (getNodeByName x == undefined) then append missingObjs x if (missingObjs.count != 0) then ( for str in missingObjs do ( local msg =("\""+str+"\" is missing from the scene.") gRsPedValidationULog.LogWarning msg appendToFile:false context:"model" ) ) ), --========================================================================= -- fn RsTa_traverseXmlTree = --========================================================================= -- Description: Checks bone tag XML and compares to tags on facial nodes --========================================================================= fn RsTa_traverseXmlTree ele objList= ( local noTagObjList = #() local theCheck = true for obj in objList do ( for i = 0 to ele.childNodes.count-1 do ( local bName = (ele.ChildNodes.itemOf[i].GetAttributeNode "name").value local bTag = (ele.ChildNodes.itemOf[i].GetAttributeNode "id").value if (findString obj.name bName != undefined) then ( local uPropTag = getUserProp obj "tag" if (findString obj.name "root" != undefined and findString bName "root" != undefined) then ( if (uPropTag != bTag) then append noTagObjList obj.name ) else if (findString obj.name "root" == undefined) then ( if (uPropTag != bTag) then append noTagObjList obj.name ) --format "obj: %\t bTag: %\tuPropTag: %\n" obj bTag uPropTag ) ) ) if (noTagObjList.count != 0) then ( local msgString = "" for str in noTagObjList do ( local msg =("\""+str+"\" has missing or incorrect bone tag.") gRsPedValidationULog.LogWarning msg appendToFile:false context:"model" ) ) ), --========================================================================= -- fn RsTa_validateBoneTag = --========================================================================= -- Description: Opens bone tag XML file, compares tags on facial nodes to the XML --========================================================================= fn RsTa_validateBoneTag= ( local facialNodes = #() for obj in objects do ( if (findString obj.name "FB_" != undefined) then append facialNodes obj else if (findString obj.name "FACIAL_" != undefined) then append facialNodes obj else if (findString obj.name "facialRoot_" != undefined) then append facialNodes obj else if (findString obj.name "FaceRoot_" != undefined) then append facialNodes obj ) theCount = facialNodes.count if (theCount != 0) then ( xmlPath = (RsConfigGetToolsDir() + "etc/content/animconfig/bone_tags.xml") --Load the xml assembly dotNet.loadAssembly "system.xml" --Create an xml document object. xmlDoc=dotNetObject "system.xml.xmlDocument" if doesFileExist xmlPath then ( --Load the XML file. xmlDoc.load xmlPath --Check to make sure the xmlDoc has a root element. docEle=xmlDoc.documentElement --If the root element exists continue. if (docEle!=undefined and docEle.name=="boneids") then ( local subTree = undefined for j = 0 to docEle.childNodes.count-1 do ( if (docEle.ChildNodes.itemOf[j].name == "peds") then subTree = docEle.ChildNodes.itemOf[j] ) if (subTree != undefined) then ( for j = 0 to subTree.childNodes.count-1 do ( if (subTree.ChildNodes.itemOf[j].name == "boneids") then subTree = subTree.ChildNodes.itemOf[j] ) --Traverse the XML tree. if (subTree.name == "boneids") then RsTa_traverseXmlTree subTree facialNodes ) ) ) ) else ( local msg ="No facial rig nodes found." gRsPedValidationULog.LogWarning msg appendToFile:false context:"model" ) ), --========================================================================= -- fn RsTa_validateSingleSkeleton = --========================================================================= -- Description: Checks if more than one dummy01 exists --========================================================================= fn RsTa_validateSingleSkeleton= ( local dummyCount = 0 for o in objects do ( if ((toLower o.name) == "dummy01") then dummyCount += 1 ) if dummyCount > 1 then ( local msg ="More than one Dummy01 found. May be more than one skeleton in file." gRsPedValidationULog.LogWarning msg appendToFile:false context:"model" ) ), --========================================================================= -- fn RsTa_validateHeels = --========================================================================= -- Description: Looks for heel height slider --========================================================================= fn RsTa_validateHeels= ( if (getNodeByName "HeelHeight" == undefined) then ( local msg ="HeelHeight slider is missing. If it isn't required then ignore this." gRsPedValidationULog.LogWarning msg appendToFile:false context:"model" ) ), --========================================================================= -- fn RsTa_addTexture = --========================================================================= -- Description: Adds scene texture to an array pointer --========================================================================= fn RsTa_addTexture textureFile &textureList= ( local index = finditem textureList textureFile if index == 0 do append textureList textureFile ), --========================================================================= -- fn RsTa_checkTexP4Status = --========================================================================= -- Description: Checks all scene textures to see if they exist in P4 --========================================================================= fn RsTa_checkTexP4Status= ( local textureList = #() local missingList = #() enumerateFiles RsTa_addTexture &textureList for i = 1 to textureList.count do textureList[i] = toLower textureList[i] local isCheckedIn = gRsPerforce.exists textureList silent:false for i = 1 to textureList.count do ( if (isCheckedIn[i] == false) then append missingList textureList[i] ) if (missingList.count > 0) then ( local msgString = "" for str in missingList do ( local msg =("\""+str+"\" : texture is not in perforce, or a file is outside of the client view.") gRsPedValidationULog.LogWarning msg appendToFile:false context:"model" ) ) ) ) RsPedValidation = RsPedValidationStruct() ------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------- --3L functions ------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------- --a function to delete old physic collision bounds and contraints. should be obsolete in almost all scenes fn tidyPhysics = ( try ( clearSelection() select $collis* max delete ) catch () try ( clearSelection() select $constraint* max delete ) catch () ) -- Take an object and apply/remove an stl check fn stlChecker meshObj stlSetValue = ( select meshObj -- If true, then add and activate the STL check if stlSetValue == true then ( max modify mode addmodifier meshObj (STL_Check ()) ui:on $.modifiers[#STL_Check].Check_Now = 1 --actionMan.executeAction 0 "281" -- Tools: Hide Unselected --max tool zoomextents ) -- If false then remove the STL check if stlSetValue == false then ( modPanel.setCurrentObject $.modifiers[#STL_Check] STLmod = $.modifiers[#STL_Check] if STLmod != undefined then deleteModifier $ STLmod ) ) -- We have 2 required named components for rigging. fn CheckComponentNames = ( allgood = true clearSelection() selectByWildcard "head_000" curSel = getCurrentSelection() if curSel.count < 1 then ( messagebox "Could not find an object named as a head" allgood = false ) else ( splitname = filterstring $.name " " if splitname[1].count != 10 then ( messagebox "Could not find an object named head_000_R - probably almost correct though" allgood = false ) ) clearSelection() selectByWildcard "teef_000" curSel = getCurrentSelection() if curSel.count < 1 then ( messagebox "Could not find an object named as teef" allgood = false ) else ( splitname = filterstring $.name " " if splitname[1].count != 10 then ( messagebox "Could not find an object named teef_000_R - probably almost correct though" allgood = false ) ) clearSelection() if allgood == true then messagebox "Components seem good" ) ------------------------------------------------------------------------------------------------------------------------- --UI ------------------------------------------------------------------------------------------------------------------------- ( global pedValidationTools try (cui.UnRegisterDialogBar pedValidationTools)catch() try(destroyDialog pedValidationTools)catch() local LastSubRollout = 1 ------------------------------------------------------------------------------------------------------------------------- rollout pedValidation "Ped Validation Tools" ( ------------------------------------------------------------------------------------------------------------------------- on pedValidation open do ( gRsPedValidationULog.Init "ped validation" appendToFile:false forceLogFile:gPedValidationLogFile -- initialize Universal Log pedValidationTools.height = 270 ) group "Validate:" ( label lblPBar "Validation Result:" align:#center offset:[-10, 0] progressbar pBarValStatus color:green offset:[108, -18] width:20 button btn_valPreRig "Pre Rig" width:150 button btn_valPostRig "Post Rig" width:150 button btn_valPostExp "Post Export" width:150 button btn_valPreRes "Pre Resource" width:150 ) button btn_toggleErrorLog "Toggle Error Log" width:150 ------------------------------------------------------------------------------------------------------------------------- /* Pre-Resource Validation functions */ on btn_valPreRes pressed do ( if queryBox "Does this character have a 3Lateral setup?" beep:true title:"3L Query" do ( filein (theWildwest + "/script/3dsMax/Characters/Rigging/3Lateral/RSTA_fixThreeLateralAlphAGuiShaders.ms") filein (theWildwest + "/script/3dsMax/Characters/Rigging/3Lateral/reconnectWrinkleMaps.ms") ) gRsPedValidationULog.ClearLogDirectory() --clear the uLog pBarValStatus.value = 0--reset the progress bar start = timeStamp() RsPedValidation.RsTa_findExportObjects() RsPedValidation.RsTa_validateFingerToes() RsPedValidation.RsTa_findSkinnedObjects() RsPedValidation.RsTa_confirmNullsExist() RsPedValidation.RsTa_validateBoneTag() RsPedValidation.RsTa_validateSingleSkeleton() RsPedValidation.RsTa_validateHeels() RsPedValidation.RsTa_checkTexP4Status() end = timeStamp() local valErrors = gRsPedValidationULog.HasNewErrorsWarnings() if (valErrors == true) then ( pBarValStatus.color = orange--make the progress bar colour red pBarValStatus.value = 100--set the progress bar to full ShowRsUlogDialog()--show the ulog ) else ( pBarValStatus.color = green--make the progress bar colour green pBarValStatus.value = 100 ) format "Processing took % seconds\n" ((end - start) / 1000.0) ) on btn_valPreRig pressed do --Validate - Pre Rig ( pBarValStatus.value = 0--reset the progress bar gRsPedValidationULog.Init "" appendToFile:false RsPedValidation.validatePedPreRig() local valErrors = gRsPedValidationULog.HasNewErrorsWarnings() if valErrors == true then ( pBarValStatus.color = red--make the progress bar colour red pBarValStatus.value = 100--set the progress bar to full ShowRsUlogDialog()--show the ulog ) else--if the validation completed without errors ( pBarValStatus.color = green--make the progress bar colour green pBarValStatus.value = 100 ) ) on btn_valPostRig pressed do --Validate - Post Rig ( pBarValStatus.value = 0--reset the progress bar gRsPedValidationULog.Init "" appendToFile:false RsPedValidation.validatePedPostRig() local valErrors = gRsPedValidationULog.HasNewErrorsWarnings() if valErrors == true then ( pBarValStatus.color = red pBarValStatus.value = 100 ShowRsUlogDialog() ) else ( pBarValStatus.color = green pBarValStatus.value = 100 ) ) on btn_valPostExp pressed do --Validate Post Export ( pBarValStatus.value = 0--reset the progress bar gRsPedValidationULog.Init "" appendToFile:false RsPedValidation.validatePedPostExprt() local valErrors = gRsPedValidationULog.HasNewErrorsWarnings() if valErrors == true then ( pBarValStatus.color = red pBarValStatus.value = 100 ShowRsUlogDialog() ) else ( pBarValStatus.color = green pBarValStatus.value = 100 ) ) on btn_toggleErrorLog pressed do --show the ulog window ( case of ( (gRsUlogDialog.isvisible == false): ShowRsUlogDialog()--if the ulog is closed show it (gRsUlogDialog.isvisible == true): gRsUlogDialog.close()--if the ulog is open close it ) ) )--end pedValidation rollout ------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------- rollout threeLValidation "3L Validation Tools" ( ------------------------------------------------------------------------------------------------------------------------- button btnCheckComponentNames "Check Component Names" width:160 height:25 button btnCheckTeef "Check Teef" width:160 height:25 button btnSTLCheckOn "Add STL Checks" width:160 height:25 button btnSTLCheckOff "Remove STL Checks" width:160 height:25 --button btntidyPhysics "Remove Collision Constraints" width:160 height:25 button btnCheckForSkeleton "Check For Skeleton" width:160 height:25 button btnCheckForSkin "Check For Skin" width:160 height:25 button btnHideNonMesh "Hide Bones/Helpers" width:160 height:25 button btnFinalViews "Final Views" width:160 height:25 button btnExportHeadOBJ "Export Head OBJ" width:160 height:25 ------------------------------------------------------------------------------------------------------------------------- on threeLValidation open do ( sliderTime = 0f pedValidationTools.theSubRollout.height = 565 pedValidationTools.height = 370 ) on btnCheckComponentNames pressed do CheckComponentNames() on btnSTLCheckOn pressed do ( selectByWildcard "head_000_R" headmesh = getcurrentSelection() selectByWildcard "teef_000_U" teethmesh = getcurrentSelection() stlChecker headmesh true stlChecker teethmesh true select headmesh selectmore teethmesh ) on btnCheckTeef pressed do ( DefaultTeefValue = 1000 try ( selectByWildcard "teef_000_U" teethmesh = getcurrentSelection() teethmesh = teethmesh[1] theVertCount = getNumVerts teethmesh if theVertCount > DefaultTeefValue do ( messageBox "Teef ok" ) if theVertCount < DefaultTeefValue do ( messageBox "You should check the teef" ) ) catch (messageBox "no teef object") ) on btnSTLCheckOff pressed do ( selectByWildcard "head_000_R" headmesh = getcurrentSelection() selectByWildcard "teef_000_U" teethmesh = getcurrentSelection() stlChecker headmesh false stlChecker teethmesh false ) on btntidyPhysics pressed do (tidyPhysics())--redundant button, added to hide bones/helpers on btnCheckForSkeleton pressed do ( clearSelection() select ped_rootbone for thebone in selection do ( try (selectmore thebone.children) catch () ) selectedbones = $ if selectedbones.count < 70 then (messagebox ("Skeleton seems wrong, found " + (selectedbones.count as string)+ ", expected at least 70")) else (messagebox "Skeleton seems to be OK") ) on btnCheckForSkin pressed do ( selectByWildcard "uppr_000_" uppermesh = getcurrentSelection() skinmod = $.modifiers[#Skin] if skinmod == undefined then (messagebox "Couldn't find a skin on the upper, assuming no skinning in scene") else (messagebox "Found a skin on the upper, assuming there is skinning in scene - but double check") ) on btnHideNonMesh pressed do ( tidyPhysics() hideByCategory.all() hideByCategory.geometry = false try ( select $mover max hide selection ) catch() ) on btnFinalViews pressed do ( max vpt front max tool zoomextents ) on btnExportHeadOBJ pressed do ( clearSelection() selectByWildcard "head_000" OBJOutputPath = "c:/temp/headOBJs" makeDir (OBJOutputPath) OBJOutputName = OBJOutputPath + "/" + (getFilenameFile maxFileName) exportClasses =exporterPlugin.classes --find the obj index objExpIndex = undefined for exportclassIndex = 1 to exportClasses.count do ( ec = exportClasses[exportclassIndex] if (uppercase (substring (ec as string) 1 3 )) == "OBJ" then objExpIndex = exportclassIndex ) -- Export the the obj exportFile (OBJOutputName) using:exportClasses[objExpIndex] selectedOnly:true ) ------------------------------------------------------------------------------------------------------------------------- )--end threeLValidation rollout ------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------- pedValidationTools_Rollouts = #(#("Ped Validation",#(pedValidation)), #("3L Validation",#(threeLValidation))) ------------------------------------------------------------------------------------------------------------------------- rollout pedValidationTools "Ped Validation Toolkit" ( dotNetControl rsBannerPanel "Panel" pos:[0,0] height:32 width:pedValidationTools.width local banner = makeRsBanner dn_Panel:rsBannerPanel wiki:"Ped_Validation_Toolkit" doOutline:false filename:(getThisScriptFilename()) dotNetControl dn_tabs "System.Windows.Forms.TabControl" height:20 width:155 align:#left subRollout theSubRollout width:185 height:285 align:#center on dn_tabs Selected itm do ( if LastSubRollout != (itm.TabPageIndex+1) do --do not update if the same tab clicked twice ( for subroll in pedValidationTools_Rollouts[LastSubRollout][2] do removeSubRollout theSubRollout subroll for subroll in pedValidationTools_Rollouts[LastSubRollout = itm.TabPageIndex+1][2] do addSubRollout theSubRollout subroll ) )--end tabs clicked ------------------------------------------------------------------------------------------------------------------------- on pedValidationTools open do ( rs_dialogPosition "get" pedValidationTools --load the ui position banner.setup() for aTab in pedValidationTools_Rollouts do (dn_tabs.TabPages.add aTab[1]) for subroll in pedValidationTools_Rollouts[1][2] do addSubRollout theSubRollout subroll ) --------------------------------------------------------- on pedValidationTools close do ( rs_dialogPosition "set" pedValidationTools --store the ui position ) ) ) createDialog pedValidationTools 185 280