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

601 lines
22 KiB
Plaintext
Executable File

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 <compName>_<seqNum>_<racialTag>
if isGeo do
(
if (matchPattern passedName pattern:"p_*") then seqNum = (filterString passedName "_ ")[3]
else seqNum = (filterString passedName "_ ")[2]
)
-- Texture names have pattern <compName>_<mapName>_<seqNum>_<racialTag>, 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()
)
)