Files
2025-09-29 00:52:08 +02:00

2279 lines
83 KiB
Plaintext
Executable File

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