Skip to content

Programmable Resource Check Tool

The goal we sought to fulfill when designing it was to provide some set functions, which users could combine to tackle various resource checks. Every project team has its own understanding of what makes a resource good, and good resources should have something in common. Project teams can share their check rules with each other.

Usage

Please open from the console

sac.exe [Project Path] Run resource checks with default rules

sac.exe D:\game\Assets


-s [Project Path] Specify a project path

-r [Rule Path] Check with custom rules

sac.exe -s D:\game\Assets -r myrule.yaml

Syntax:

Try to keep the syntax similar to Python, and follow the rules of YAML

WhitePath:  # Whitelist. It takes regular expressions. Each of the following paths is matched with a regular expression   If there’s no Whitelist, also annotate this line
    - ".*prefab"
    - "*.obj"
    # Used globally if not written here
BlackPath:  # Blacklist    If there’s no Blacklist, also annotate this line
    - ".*.prefab"
    # - "*.obj"
    # No Blacklist if you don’t write it

# Configure each rule according to the Path Whitelist and Blacklist
# You can describe which rules apply on which paths here
PathRule:
  - Rules: 
      - Material_GPUInstance
      - Material_lit
      - Prefab1
    White:  # Whitelist. It takes regular expressions. Each of the following paths is matched with a regular expression   If there’s no Whitelist, also annotate this line
      - .*mat
    Black: # Blacklist    If there’s no Blacklist, also annotate this line
      - '.*'
    Enable: True #Means use this rule  This line is used by default if you don’t write it

  - Rules:
    - Material_URP
    - Material_workFlow
    White:
      - .*mat
    # If there is both a Blacklist and a Whitelist, both need to be satisfied 

###############################
# Register your custom rules here
Material:
- Material_lit
- Material_GPUInstance
Prefab:
- Prefab_layer

###############################
# Below is the custom rule

# If ShaderName is Universal Render Pipeline/Lit 
# You must select AlphaClipping If the self-glow color is black, the glow map cannot be bound
Material_lit:
  - shaderName = GetShaderName()
  - if shaderName == "Universal Render Pipeline/Lit":
    - WriteWithPath("Shouldn’t use Lit type shader")

# If shader is Universal Render Pipeline/Lit, Universal Render Pipeline/FX/ADDAphaBlend_Decal, Universal Render Pipeline/SpeedTree8 
# You must start GPUInstance
Material_GPUInstance:  
  - shaderName = GetShaderName()
  - if shaderName:
    - if Any(shaderName,"Universal Render Pipeline/Lit","Universal Render Pipeline/FX/ADDAphaBlend_Decal","Universal Render Pipeline/SpeedTree8"):
      - if GetEnableGPUInstance() == 0:
        - WriteWithPath("GPUInstance unstarted")

# If a Prefab contains other Prefabs, and if there are collider components, and Layer is Default, you need to set Layer as GroundTerrain
Prefab_layer:
- if IsIncludeAnotherPrefab():
    - if IsColliderExist():
      - if GetRootLayer() == 0:
        - WriteWithPath("If a nested Prefab contains colliders, and Layer is Default, you need to set Layer as GroundTerrain")

Texture:  # Means the following rules will apply on resources of the Prefab type  When a Prefab type resource is parsed, this rule will auto apply to it 
 - if AttributeIsTarget("mipMapMode",0):
    - WriteWithPath("mipMapMpde_is_zero")

Material means this type will apply on the Material type resources. When the program loads a Material, it will find and run this rule.

As shown above, it checks which Materials use the Lit type shader and saves the path to the output result. The result should be as follows: :

- D:SRP_Run\Assets\Meterial\m1.mat: Shouldn’t use Lit type shader
- D:SRP_Run\Assets\Meterial\m2.mat: Shouldn’t use Lit type shader

Key Function

The string should be quoted in double quotation marks.

View “mipMapMode”, “mipMaps” and other attribute names in the resource file

General Function

A general function is a function that all types can use

Function Name Usage
GetSubAttribute(x,"mipMapMode") Obtains the target attribute from the given dictionary X, recursively looking down
GetAttributeByName("mimaps") Obtains the target attribute
GetSize() Size of the obtained resource (kb)
GetGUID() Obtain GUID
GetPath() Return Path
Call("ruleName",guid) Call other resource check, e.g.check a certain Texture of the current Prefab
WriteWithPath("xxxxx",...) Save “xxxxx” and output it to the local directory. This function supports limitless parameters but the string should not contain spaces
Print("xxxx",....) Outputs “xxxxx”. Supports limitless parameters
AttributeIsTarget("attribute",1) If Attribute is the target, return True
Any(p1,p2,p3....) If there is any True and non-zero value, return True
AnyCount(p1,p2.....) Number of True, non-zero values returned
AnyEqual(p1,p2,p3...) If P1 equals any of the following values, return True
AnyEqualCount(p1,p2,p3....) Return the number of following values equalling P1
if else for > = < == != not and Same as Python, for if, None, False or 0 are False, others are True
in ,not in Same as Python, can be used to operate strings, arrays, "a" in "abc" --> True
+ - * / Same as Python, elementary arithmetic
len(a) Same as Python, returns array length but cannot create arrays. Arrays are the return values of system functions.
continue break

Don’t use arithmetic operators in succession on the same line, e.g., a=1+2+3. Write it as a=1+(2+3)

Exclusive Functions

Texture

Texture refers to files of the following formats:

('.bmp', '.gif', '.hdr','.iff', '.jpg', '.jpeg','.pict', '.png', '.psd','.tga', '.tiff', '.tif','.exr')
Function Name Usage
GetTextureType() Return the Texture type: please consult TextureType for the meaning of the return value
GetTextureShape() Return the Texture shape: please consult TextureShape for the meaning of the return value
GetSizeForDefault() Return its default size
GetSizeForAndroid() Return its size on Android
GetSizeForStandalone() Return its size under Standalone
GetResizeAlgorithmForDefault() Return its default compression algorithm: 0 for Mitchell, 1 for Billinear
GetResizeAlgorithmForAndroid() Return its compression algorithm on Android: 0 for Mitchell, 1 for Billinear
GetResizeAlgorithmForStandalone() Return its compression algorithm under Standalone: 0 for Mitchell, 1 for Billinear
GetCompressionForDefault Return its default compression level. 0: None, 1: Normal Quality, 2: High, 3: Low
GetCompressionForAndroid Return the Android compression level
GetCompressionForStandalone Return the Standalone compression level
GetFormatForDefault Default format. Please consult TextureFormat for the meaning of the return value
GetFormatForStandalone Format under Standalone
GetFormatForAndroid Format on Android
GetSRGBAttribute() Acquire whether it is SRGB: 0 for No, 1 for Yes
GetAlphaSource() Acquire its AlphaSource: please contact AlphaSouce for the meaning of the return values
GetAlphaIsTransparency() If Alpha is transparent: 0 for No, 1 for Yes
GetIgnorePngGramma() If you selected to ignore pngGramma:0,1
GetReadWriteEnable() Readable and writable:0,1
GetStreamingMipmaps() 0,1
GetVirtualTextureOnly() 0,1
GetWrapU() 0:Repect, 1:Clamp, 2:Mirror, 3:MirrorOnce
GetWrapV() Same as above
GetWrapW() Same as above
GetAnsioLevel()
GetMipMapFiltering() 0: Box, 1:Kaiser
GetBorderMipMaps() 0,1
GetFadeoutMipMaps() 0,1
GetMipMapsPreserveCoverage() 0,1
GetAlphaCutoffValue() Value

Return Types Cross Reference:


TextureType :

  • 0 : Default
  • 1 : NormalMap
  • 2 : EditorGUIandLegacyGUI
  • 4: Cookie
  • 6 : lightMap
  • 7 : Cursor
  • 8 : Sprite(2D and ui)
  • 10 : SingleChannel
  • 11: ShadowMask
  • 12: DirectionalLightmap

TextureShape :

  • 1: 2D
  • 2: Cube
  • 4: 2D Array
  • 8: 3D

AlphaSource

  • 0: None
  • 1: Input Texture Alpha
  • 2: From Gray Scale

TextureFormat

  • -1: Automatic
  • 4: RGBA32
  • 7: RGB16
  • 3: RGB24
  • 63: R8
  • 9: R16
  • 1: Alpha8

Material

Material refers to files of the following format:

('.mat', )
Function Name Usage
GetShaderName() Return the name of shader it owns, e.g. “Unlit/custom"
GetTextureByName("name") Acquire the Texture; This function should not be used currently and its return value should be used in conjunction with GetSubAttribute
GetTextureGuidByName("name") Acquire its Texture GUID; If there is none, return 0. You can judge from this whether a map is bound
ColorEqual("tar",1,1,1,1) Whether the color tar’s RGBA equals the parameters behind. If yes, return False. If the parameter is -1, this item will not be compared
GetEnableGPUInstance() Return whether GPUInstance is on, 0: No, 1: Yes
GetDoubleSideGI() Whether DoubleSidedGlobalIIIumination is on, 0 No, 1: Yes
GetTextureNameInShader() Acquire Texture names referenced in Shader
GetTextureNameInMaterial() Acquire Texture names referenced in Material

For Material: If you want to get a variable on the panel called Threshold, it is Float or int:

GetAttributeByName("Threshold") # The function will return the value of the threshold

For color types on the panel:

ColorEqual("tar",1,1,1,1)   # This function will compare the target color with the following four values, respectively RGBA. True will be returned if they all equal. If any of the four is not to be compared, set it as -1.
# If you want a higher level of color customization 
x = GetAttributeByName("tar")   # This function will return the color’s original stats
r = GetSubAttribute(x,'r')      # Thus, you will get detailed stats 
g = GetSubAttribute(x,'g')
b = GetSubAttribute(x,'b')
a = GetSubAttribute(x,'a')

Prefab


Prefab refers to files of the following format:

('.prefab')
Function Name Usage
IsComponentExist("Transfrom") Whether the target component is there. Search through the Prefab
IsGameObjectHasComponent("GameObjName","ComName") Whether there are the target components in the target GameObject
GetAllComponentByGameObjectName("GameObejctName") Return all components’ names according to GameObject
GetComponentByGameObject("GameObjectName","ComponentName") Return target GameObject’s target component. The return value is a dictionary
GetComponentByName('ComponentName') Return the first component found. This is a dictionary
GetGameObjectByName("Name") Get the target GameObject. The return value is a dictionary and should be processed with GetSubAttribute
GetRootLayer() Get the Layer of Prefab’s root GameObject
GetLayerByName("GameObjName") Get the Layer of the target GameObject. It should 1, 2, 3 or 4
GetRootTag() Return the tag of the root GameObject
GetTagByName("GameObjName") Return the tag of the target GameObject. The result is a string
GetRootName() Return the name of the root GameObject
IsColliderExist() Whether there is a Collider inside
IsIncludeAnotherPrefab() Whether there is another Prefab inside (Whether this is a nested Prefab)
GetNameByFileID(fileID) Get the name of components, or of GameObject according to file ID
GetSubGameObjectName("Name") Return the name of a first-level sub-object of the target GameObject
GetGameObjectNameByComponentID(fileID) Return the component’s file ID and the name of the GameObject it belongs to
GetGameObjectByName
IsTransformPositionEqual(Transform,0,0,0) Determine if the Position of Transform is equal to the latter. -1 means the bit is not involved in comparison. Transform is the Component acquired in the last step
IsTransformScaleEqual(Transform,1,1,-1) Same as above
IsTransformRotationEqual(Transform,1,1,1,-1) Same as above. Note that Rotation has four bits, with the last by default 1, i.e. when not rotating, it is (0,0,0,1)

Prefab is a rather complex type. For most demands, use

GetAllComponentByGameObjectName()

GetComponentByName()

These two functions are enough to handle most cases

Note that GetComponentByName() returns a dictionary. For the time being you can only process this return value with GetSubAttribute()

a = GetComponentByName("Sphere","MeshRenderer")

x = GetSubAttribute(a,"m_CastShadows")

For the time being, you can only find the attribute name m_CastShadows in .prefab files. m_CastShadow corresponds to CastShadow in the attribute panel.

A mapping table will then be created internally, enabling you to use the attribute names you see on the attribute panel.

Animation

Animation refers to the files of the following format:

('.anim')

None. General functions can be used if and AttributeIsTarget are enough for most tasks

Video

Video refers to the files of the following formats:

('.webm','.mpg','.mp2','.mpeg','.mpe','.mpv','.ogg','.mp4','.m4p','.m4v','.avi','.wmv','mov','.qt','.flv','.swf')
Function Name Usage
GetSRGB() Whether SRGB is on: 0, 1
GetTranscodeForDefault() Whether Transcode is on on the default platform: 0, 1
GetTranscodeForStandalone() Whether Transcode is on on PC/Standalone: 0, 1
getTranscodeForAndroid() Whether Transcode is on on Android: 0, 1
GetBitRateModeForDefault() Default Bitrate mode: 0: Low, 1: Medium, 2: High
GetBitRateModeForStandalone() Same as above
GetBitRateModeForAndroid() Same as above
GetCodecForDefault() Coding mode on the default platform: consult Codec for the meaning of the return value
GetCodecForStandalone() Same as above
GetCodecForAndroid() Same as above
GetDimensionsForDefault() Dimensions attributes on the default platform: consult Dimensions for the meaning of the return value
GetDimensionsForStandalone() Same as above
GetDimensionsForAndroid() Same as above
GetAspectRatioForDefault() AspectRatio attributes on the default platform: 0 for No Scaling, 5 for Stretch
GetAspectRatioForStandalone() Same as above
GetAspectRatioForAndroid() Same as above
GetWidthForDefault() Width under default, only makes sense when Dimensions are CustomSize
GetWidthForStandalone() Same as above
GetWidthForAndroid() Same as above
GetHeightForDefault() Height under default, only makes sense when Dimensions are CustomSize
GetHeightForStandalone() Same as above
GetHeightForAndroid() Same as above
GetSpatialQualityForDefault() SpatialQuality Grade under default. Consult SpatialQuality for the meaning of the return value
GetSpatialQualityForStandalone() Same as above
GetSpatialQualityForAndroid() Same as above
GetFlipHorizontally() Get whether Flip Horizontally is selected
GetFlipVertical() Get whether Flip Vertically is selected
GetDeinteriace() Get Deinterlace: 0: off, 1: even, 2: odd
GetImportAudio() Get whether ImportAudio is selected

Codec

  • 0: Auto
  • 1: H264
  • 2: VP8
  • 3: H265

Dimensions

  • 0: Original Size
  • 1: ThreeQuarterRes
  • 2: HalfRes
  • 3: QuarterRes
  • 4: Square1024
  • 5: Square512
  • 6: Square256
  • 7: CustomSize

SpatialQuality

  • 0: Low Spatial Quality
  • 1: Medium Spatial Quality
  • 2: High Spatial Quality

Audio

Audio refers to the files of the following formats:

('.mp3','.ogg','.wav','.aiff','.aif','.mod','.it','.s3m','.xm')
Function Name Usage
GetForceToMono Whether ForceToMono is selected. Return 0, 1
GetLoadInBackGround Whether LoadInBackGround is selected. Return 0, 1
GetAmbisonic Whether Ambisonic is selected. Return 0, 1
GetNormalize Whether Normalize is selected. Return 0, 1
GetPreloadAudioData Whether Preload Audio Data is selected. Return 0, 1
GetLoadTypeForDefault LoadType on the default platform. Please consult LoadType for the meaning of the return value
GetLoadTypeForStandalone Same as above
GetLoadTypeForAndroid Same as above
GetCompressionFormatForDefault CompressionFormat on the default platform. Please consult CompressionFormat for the meaning of the return value
GetCompressionFormatForStandalone Same as above
GetCompressionFormatForAndroid Same as above
GetQualityForDefault Return the quality under default, only makes sense when CompressionFormat is Vorbis
GetQualityForStandalone Same as above
GetQualityForAndroid Same as above
GetSampleRateSettingForDefault SampleRateSetting under default. Please consult SampleRateSetting for the meaning of the return value
GetSampleRateSettingForStandalone Same as above
GetSampleRateSettingForAndroid Same as above
GetSampleRateForDefault SampleRate under default, only makes sense when SampleRateSetting is OverrideSampleRate
GetSampleRateForStandalone Same as above
GetSampleRateForAndroid Same as above

LoadType

  • 0: Decompress On Load
  • 1: Compressed In Memory
  • 2: Streaming

CompressionFormat

  • 0: PCM
  • 1: Vorbis
  • 2: ADPCM

SampleRateSetting

  • 0: PreserveSampleRate
  • 1: OptimizeSampleRate
  • 2: OverrideSampleRate

Model

!!Please read this first!! For unknown reasons, the number of vertices and triangles for a model in the Unity engine does not match what other model-editable software shows, so offline resource check tools cannot get the vertex number in Unity. We are analyzing the Unity source code to try to understand how Unity processes models and we believe this feature will be available soon.


Model refers to the files of the following formats:

('.dae','.3ds','.dxf','.obj','.max','.blend','.lxo')
Function Usage
GetMeshCompression() Compression level, 0: Off, 1: Low, 2: Medium, 3: High
GetReadWriteEnable Return whether it is readable and writable: 0, 1
GetImportVisibility Return if import Visibility is selected: 0, 1
GetImportCameras Return if Import Cameras is selected: 0, 1
GetImportLights Return if ImportLights is selected: 0, 1
GetImportBlendShape Return if ImportBlendShape is selected
GetBakeAxisConversion Return if BakeAxisConversion is selected
GetScaleFactor Return ScaleFactor
GetSortHierarchyByName Return if SortHierarchyByName is selected
GetGenerateColliders Return if GenerateColliders is selected
GetOptimizeMesh Consult OptimizeMesh for the meaning of the return value
GetKeepQuads Return if keepQuads is selected
GetWeldVertices Return if WeldVertices is selected
GetIndexFormat Return if IndexFormat is selected
GetLegacyBlendShapeNormals Return if LegacyBlendShapeNormals is selected
GetNormals Consult Normals for the meaning of the return value
GetBlendShapeNormals Meaning of the return value is the same as Normals
GetNormalsMode Consult NormalsMode for the meaning of the return value
GetSmoothnessSource Consult SmoothnessSource
GetSmoothingAngle Return SmoothingAngle
GetTangents Consult Tangents for the meaning of the return value
GetSwapUVs Return if SwapUV is selected
GetSubMeshCount Return SubMesh number
GetVertexCount Return vertices number

OptimizeMesh

  • 0: Nothing
  • 1: PolygonOrder
  • 2: VertexOrder
  • 3: PolygonOrder & VertexOrder
  • 2147483647: EveryThing

Normals

  • 0: Import
  • 1: Calculate
  • 2: None

NormalsMode

  • 0: Unweighted(legacy)
  • 1: Unweighted
  • 2: AreaWeighted
  • 3: AngleWeighted
  • 4: AreaAndAngleWeighted

SmoothnessSource

  • 0: PreferSmoothingGroup
  • 1: FromSmoothingGroup
  • 2: FromAngle
  • 3: None

Tangents

  • 0: Import
  • 1: CalculateLegacy
  • 2: None
  • 3: CalculateMikktspace
  • 4: CalculateLegacyWithSplitTangent