RSTA_LoadCommonFunction #("FN_RSTA_rageMat.ms") struct struct_PedValidationTool ( private _targetPed = undefined, _validComponentNames = #("head", "hair", "hand", "uppr", "lowr", "feet", "jbib", "accs", "berd", "task", "teef", "decl", "p_head", "p_eyes", "p_ears", "p_lwrist", "p_rwrist"), _validPedPresets = #("ped.sps", "ped_nopeddamagedecals.sps", "ped_alpha.sps", "ped_decal.sps", "ped_decal_decoration.sps", "ped_hair_cutout_alpha.sps", "ped_hair_spiked.sps", "ped_emissive.sps", "ped_fur.sps"), _validRacialTags = #("whi", "ita", "chi", "lat" , "jam", "bla", "ara", "pak", "bal", "kor"), _normalSpecExceptionPresets = #("ped_decal.sps", "ped_decal_decoration.sps", "ped_fur.sps"), _validationReport = "", _geoValidationReport_Arr = #(), _textureValidationReport_Arr = #(), _materialValidationReport_Arr = #(), -- Scaling Validation fn fn_ValidateScale = ( local currentScale = #(this._targetPed.scale.x, this._targetPed.scale.y, this._targetPed.scale.z) local idealScale = 1.0 -- If the scale is not ideal, add an Xform modifier and collapse local modifiedScale_arr = for scaleVal in currentScale where scaleVal != idealScale collect scaleVal if modifiedScale_arr.count > 0 do ( -- Reset Xform resetXform this._targetPed deleteModifier this._targetPed 1 -- Check if the scale is negative local isScaleNegative = false for scaleVal in currentScale do ( if scaleVal < 0 do isScaleNegative = true break ) -- If negative, flip the normals if isScaleNegative then ( addModifier this._targetPed (Normalmodifier flip:true) append this._geoValidationReport_Arr "\nNegative scale found. Xform has been applied and flipped normals reversed." ) else ( append this._geoValidationReport_Arr "\nScaling issues found. Xform has been applied." ) ) ), -- Extracts the component name from the passed name fn fn_GetComponentName passedName = ( if passedName == "" do return undefined local compName = undefined if matchPattern passedName pattern:"p_*" then ( -- Prop naming starts with "p_" so join the first and second item to form the name local nameElements = filterString passedName "_" compName = nameElements[1] + "_" + nameElements[2] ) else ( -- Get the first element in the name string compName = (filterString passedName "_")[1] ) return compName ), -- Get tne suffix from a geo name fn fn_GetSuffix passedName = ( local nameElems = filterString passedName "_" local nameSuffix = undefined if matchPattern passedName pattern:"p_*" then nameSuffix = nameElems[4] else nameSuffix = nameElems[3] return nameSuffix ), fn fn_GetSequenceNum passedName isGeo:false isTex:false = ( if passedName == "" do return undefined local seqNum = undefined -- Geo names have pattern __ if isGeo do ( if (matchPattern passedName pattern:"p_*") then seqNum = (filterString passedName "_ ")[3] else seqNum = (filterString passedName "_ ")[2] ) -- Texture names have pattern ___, so +1 element if isTex do ( if (matchPattern passedName pattern:"p_*") then seqNum = (filterString passedName "_")[4] else seqNum = (filterString passedName "_")[3] ) return (seqNum as integer) ), fn fn_GetRacialTag passedName isGeo:false isTex:false = ( if passedName == "" do return undefined if (matchPattern passedName pattern:"p_*") do return undefined -- Since props have no race tag local racialTag = undefined if isGeo do racialTag = (filterString passedName "_ ")[3] if isTex do racialTag = (filterString passedName "_")[5] return racialTag ), -- Check that the naming of assets is consistent with set standards fn fn_ValidateComponentName = ( -- Get all child meshes of selection local childGeo = for child in this._targetPed.children where (superClassOf child == GeometryClass) collect child local namingIssues = #() for geo in childGeo do ( local componentName = this.fn_GetComponentName geo.name if (findItem this._validComponentNames (toLower componentName) == 0) do appendIfUnique namingIssues ("\nGeo component naming issue found: " + geo.name) ) -- Add any possile issues to the global report arrays if namingIssues.count > 0 do ( for issue in namingIssues do ( appendIfUnique this._geoValidationReport_Arr issue ) ) ), -- Compares 2 strings (Used for sorting) fn fn_CompareStrings string1 string2 = ( stricmp string1 string2 ), -- Validates Component sequence, Eg: jbib_000_*, jbib_001_*, jbib_0002_*, etc. fn fn_ValidateComponentSequence = ( -- Get all child meshes of selection local childGeoNames = for child in this._targetPed.children where (superClassOf child == GeometryClass) collect child.name local seqIssues = #() for cgName in childGeoNames do ( cgName_Main = (filterString cgName " ")[1] -- Disregard string data after the space in name local componentName = this.fn_GetComponentName cgName_Main local compNamePattern = componentName + "_*" -- Using the component name pattern, get other geoNames that have the same prefix local seqGeoNames = #() for refName in childGeoNames do ( --refName = (filterString refName " ")[1] -- remove whats after the space refName_elems = filterString refName "_" refName_toConsider = refName_elems[1] + "_" + refName_elems[2] -- only considering component name + component number, eg. accs_001 if matchPattern refName_toConsider pattern:compNamePattern do appendIfUnique seqGeoNames (toLower refName_toConsider) ) -- If we find matches if seqGeoNames.count > 1 do ( -- Sort the names qSort seqGeoNames this.fn_CompareStrings -- Start from 0 and keep checking for a consistent sequence in the matched geos local seqErrorFound = false local counterNum = 0 for geoName in seqGeoNames while not seqErrorFound do ( local expectedSeqNum = formattedPrint counterNum format:"03d" -- Get the sequence number from the geo name local seqNum = -1 if (matchPattern geoName pattern:"p_*") then seqNum = (filterString geoName "_")[3] else seqNum = (filterString geoName "_")[2] -- Check if the seqNum matches what we expect if seqNum == expectedSeqNum then counterNum += 1 else ( appendIfUnique seqIssues ("\nSequencing issue found: " + geoName) seqErrorFound = true ) ) ) ) -- Add any possile issues to the global report arrays if seqIssues.count > 0 do ( for issue in seqIssues do ( appendIfUnique this._geoValidationReport_Arr issue ) ) ), -- Validates Mateials and Textures fn fn_ValidateMatsAndTex = ( -- Get all child meshes of selection local childGeo = for child in this._targetPed.children where (superClassOf child == GeometryClass) collect child local materialIssues = #() for geo in childGeo do ( local isEditMesh = false -- If the base object is an Editable Mesh, add an edit-poly mod on top, then clear it later if classOf geo == Editable_mesh do ( isEditMesh = True addModifier geo (Edit_Poly ()) ) local geoLinkedMats = this.fn_GetLinkedMeshMats geo for currentMaterial in geoLinkedMats do ( if currentMaterial != undefined then ( if (rsta_rageMat.isRageMat currentMaterial) then ( this.fn_SingleMatTextureCheck currentMaterial geo this.fn_ValidateTextureNaming geo currentMaterial ) -- If currentMaterial is not a Rage_Shader, then it is invalid else ( append materialIssues ("\nNot a valid rageMat: " + currentMaterial.name) ) ) else ( append materialIssues ("\nUndefined materials in " + geo.name) ) ) -- Clear the temporary Edit_Poly modifier if it was added in if isEditMesh do deleteModifier geo geo.modifiers[1] ) -- Add any possile tex/mat issues to the global report arrays if materialIssues.count > 0 do ( for issue in materialIssues do ( appendIfUnique this._materialValidationReport_Arr issue ) ) ), -- Works in conjunction with fn_ValidateMatsAndTex, to check the Diff/Norm/Spec textures for a single material fn fn_SingleMatTextureCheck currentMaterial currentGeo = ( local materialIssues = #() local textureIssues = #() local currPreset = rsta_rageMat.getShaderType currentMaterial -- Check if material preset is valid if (findItem _validPedPresets currPreset == 0) do append materialIssues ("\nInvalid Rage Preset: " + currentGeo.name + ", " + (currPreset as string)) -- Check Diff local diffMapPath = rsta_rageMat.getDiffuse currentMaterial if (diffMapPath != "") and (doesFileExist diffMapPath) then ( local textureDimCheck = this.fn_TextureDimensionCheck diffMapPath 512 -- If check fails, add texPath to issue report if textureDimCheck == false do appendIfUnique textureIssues ("\nDiffuse texture size mismatch: " + diffMapPath + "(" + currentMaterial.name + ")" ) ) else ( if((diffMapPath == undefined) or (diffMapPath == "")) then ( appendIfUnique textureIssues ("\nMissing diffuse texture in " + currentMaterial.name) ) -- If the path exists but the file is not on disk else if ((diffMapPath != "") and (not doesFileExist diffMapPath)) do ( appendIfUnique textureIssues ("\nTexture not found on disk: " + diffMapPath) ) ) -- Check Normal local normalMapPath = rsta_rageMat.getBump currentMaterial if (normalMapPath != undefined) and (doesFileExist normalMapPath) then ( local textureDimCheck = this.fn_TextureDimensionCheck normalMapPath 512 -- If check fails, add texPath to issue report if textureDimCheck == false do appendIfUnique textureIssues ("\nMormal texture size mismatch: " + normalMapPath + "(" + currentMaterial.name + ")") ) else ( if (normalMapPath == undefined) or (normalMapPath == "") then ( -- Check if preset is within exception list if not (findItem _normalSpecExceptionPresets currPreset > 0) do ( appendIfUnique textureIssues ("\nMissing normal texture in " + currentMaterial.name) ) ) -- If the path exists but the file is not on disk else if ((normalMapPath != "") and (not doesFileExist normalMapPath)) do ( appendIfUnique textureIssues ("\nTexture not found on disk: " + normalMapPath) ) ) -- Check Spec local specMapPath = rsta_rageMat.getSpec currentMaterial if (specMapPath != undefined) and (doesFileExist specMapPath) then ( local textureDimCheck = this.fn_TextureDimensionCheck specMapPath 256 -- If check fails, add texPath to issue report if textureDimCheck == false do appendIfUnique textureIssues ("\nSpec texture size mismatch: " + specMapPath + "(" + currentMaterial.name + ")") ) else ( if (specMapPath == undefined) or (specMapPath == "") then ( -- Check if preset is within exception list if not (findItem _normalSpecExceptionPresets currPreset > 0) do ( appendIfUnique textureIssues ("\nMissing specular texture in " + currentMaterial.name) ) ) -- If the path exists but the file is not on disk else if ((specMapPath != "") and (not doesFileExist specMapPath)) do ( appendIfUnique textureIssues ("\nTexture not found on disk: " + specMapPath) ) ) -- CHECK IF ALL TEXTURES ARE IN THE PROPER TEXTURE DIRECTORY local currFileTexDir = pathConfig.appendPath maxFilePath "Textures\\HighRes\\" local thisMatTextures = rsta_ragemat.getAllTextures currentMaterial for tex in thisMatTextures do ( local texPath = "" if (tex != "") do (texPath = getFileNamePath tex) -- If the texture path is wrong, but not empty if (stricmp texPath currFileTexDir != 0) and (texPath != "") do ( format "\ncurrFileTexDir: %" currFileTexDir format "\ntexPath: %" texPath append textureIssues ("\nTexture not in project dir: " + tex + "(" + currentMaterial.name + ")") ) ) -- Add any possile issues to the global report arrays if textureIssues.count > 0 do ( for issue in textureIssues do ( appendIfUnique this._textureValidationReport_Arr issue ) ) if materialIssues.count > 0 do ( for issue in materialIssues do ( appendIfUnique this._materialValidationReport_Arr issue ) ) ), -- Works in conjunction with fn_ValidateMatsAndTex, to open bitmap textures, check against their ideal size and returns false if size mismatch occurs fn fn_TextureDimensionCheck texPath idealTexSize = ( -- Open the bitmap local texBitmap = openBitmap texPath -- Compare texture w/h against ideal w/h if (texBitmap.width > idealTexSize) or (texBitmap.height > idealTexSize) then ( close texBitmap return false ) else ( close texBitmap return true ) ), -- Get all mats associated with a passed material byiterating through the faces fn fn_GetLinkedMeshMats passedMesh = ( local linkedMatArr = #() local matIndicesArr = #() local materialIssues = #() for face in passedMesh.faces do ( -- If some faces have undefined materials local facemat = polyOp.getFaceMatID passedMesh face.index if facemat != undefined then ( appendIfUnique matIndicesArr facemat ) else ( append materialIssues ("\nUndefined materials in " + passedMesh.name) ) ) -- If it is a multimaterial if (classOf passedMesh.material == Multimaterial) then ( for matIndex in matIndicesArr do append linkedMatArr passedMesh.material[matIndex] ) -- Else if it is a single mat else append matIndicesArr passedMesh.material -- Add any possile mat issues to the global report arrays if materialIssues.count > 0 do ( for issue in materialIssues do ( appendIfUnique this._materialValidationReport_Arr issue ) ) return linkedMatArr ), -- Validate texture naming per-geo fn fn_ValidateTextureNaming geo mat = ( local texNamingIssues = #() local diffMapPath = rsta_rageMat.getDiffuse mat local normalMapPath = rsta_rageMat.getBump mat local specMapPath = rsta_rageMat.getSpec mat -- Get texture names local diffMapName = "" local normalMapName = "" local specMapName = "" if (diffMapPath != undefined) do diffMapName = getFileNameFile diffMapPath if (normalMapPath != undefined) do normalMapName = getFileNameFile normalMapPath if (specMapPath != undefined) do specMapName = getFileNameFile specMapPath local mapNamesArr = #(diffMapName, normalMapName, specMapName) -- COMPONENT NAME CHECK local geo_componentName = this.fn_GetComponentName geo.name for mapName in mapNamesArr do ( if (mapName != "") do ( local mapCompName = this.fn_GetComponentName mapName --if mapCompName != geo_componentName do append texNamingIssues ("\nTexture component mismatch with geo: " + mapName + ", " + geo.name) if (stricmp mapCompName geo_componentName != 0) do append texNamingIssues ("\nTexture component mismatch with geo: " + mapName + ", " + geo.name) ) ) -- RACIAL TAG CHECK -- Note: We only check diffuse map for racial tags local geo_racialTag = this.fn_GetRacialTag geo.name isGeo:true if (diffMapName != "") do ( local tex_racialTag = this.fn_GetRacialTag diffMapName isTex:true if geo_racialTag == "u" do ( if tex_racialTag != "uni" do append texNamingIssues ("\nTexture racial tag mismatch with geo: " + diffMapName + ", " + geo.name) ) if geo_racialTag == "r" do ( if (findItem this._validRacialTags tex_racialTag == 0) do append texNamingIssues ("\nInvalid racial tag: " + diffMapName + ", " + geo.name) ) ) -- SEQ NUM CHECK local geo_seqNum_Padded = formattedPrint (this.fn_GetSequenceNum geo.name isGeo:true) format:"03d" if geo_seqNum_Padded != undefined do ( for mapName in mapNamesArr do ( if (mapName != "") do ( local tex_seqNum_Padded = formattedPrint (this.fn_GetSequenceNum mapName isTex:true) format:"03d" if (tex_seqNum_Padded != geo_seqNum_Padded) do append texNamingIssues ("\nTexture sequence mismatch with geo: " + mapName + ", " + geo.name ) ) ) ) -- Add any possile issues to the global report arrays if texNamingIssues.count > 0 do ( for issue in texNamingIssues do ( appendIfUnique this._textureValidationReport_Arr issue ) ) ), -- Prints out the validation report fn fn_PrintValidationReport = ( for issue in this._geoValidationReport_Arr do ( this._validationReport += issue ) for issue in this._materialValidationReport_Arr do ( this._validationReport += issue ) for issue in this._textureValidationReport_Arr do ( this._validationReport += issue ) if (this._geoValidationReport_Arr.count + this._materialValidationReport_Arr.count + this._textureValidationReport_Arr.count == 0) do this._validationReport = "ALL CLEAR!" format "\n----------------------------\n" format " VALIDATION REPORT" format "\n----------------------------\n" format "% \n" this._validationReport format "\n----------------------------\n" if this._validationReport != "ALL CLEAR!" then ( this.fn_AddErrorsToULog this._validationReport ) else ( this.fn_AddMessageToULog this._validationReport ) ), fn fn_AddErrorsToULog validationReport = ( gRsUlog.LogError(validationReport) gRsUlog.Validate() ), fn fn_AddMessageToULog message = ( gRsUlog.LogMessage(message) gRsUlog.Validate() gRsUlog.ShowDialog() ), public fn fn_BeginValidation = ( -- Initialize this._validationReport = "" -- Set the model to validate this._targetPed = (selection as array)[1] if this._targetPed == undefined do ( format "Please select a valid ped." return false ) -- Check for model scaling issues this.fn_ValidateScale() -- Check for model naming issues this.fn_ValidateComponentName() -- Check for sequencing issues in name this.fn_ValidateComponentSequence() -- texture size checks this.fn_ValidateMatsAndTex() -- Print out validation report this.fn_PrintValidationReport() ) )