Repository: MarkUnity/AssetAuditor
Branch: master
Commit: 6a34b5791429
Files: 36
Total size: 145.1 KB
Directory structure:
gitextract_7qfqj2k7/
├── .gitattributes
├── .gitignore
├── Assets/
│ ├── Editor/
│ │ ├── AssetAuditor/
│ │ │ ├── Audio/
│ │ │ │ └── DefaultAudio.wav.meta
│ │ │ ├── Audio.meta
│ │ │ ├── Models/
│ │ │ │ ├── DefaultAvatar.fbx
│ │ │ │ └── DefaultAvatar.fbx.meta
│ │ │ ├── Models.meta
│ │ │ ├── Scripts/
│ │ │ │ ├── AssetAuditTreeElement.cs
│ │ │ │ ├── AssetAuditTreeElement.cs.meta
│ │ │ │ ├── AssetAuditTreeView.cs
│ │ │ │ ├── AssetAuditTreeView.cs.meta
│ │ │ │ ├── AssetAuditor.cs
│ │ │ │ ├── AssetAuditor.cs.meta
│ │ │ │ ├── AssetAuditorNewRuleWindow.cs
│ │ │ │ ├── AssetAuditorNewRuleWindow.cs.meta
│ │ │ │ ├── AssetAuditorPreferences.cs
│ │ │ │ ├── AssetAuditorPreferences.cs.meta
│ │ │ │ ├── AssetAuditorUtilities.cs
│ │ │ │ ├── AssetAuditorUtilities.cs.meta
│ │ │ │ ├── AssetAuditorWindow.cs
│ │ │ │ ├── AssetAuditorWindow.cs.meta
│ │ │ │ ├── TreeElement.cs
│ │ │ │ ├── TreeElement.cs.meta
│ │ │ │ ├── TreeElementUtility.cs
│ │ │ │ ├── TreeElementUtility.cs.meta
│ │ │ │ ├── TreeModel.cs
│ │ │ │ ├── TreeModel.cs.meta
│ │ │ │ ├── TreeViewWithTreeModel.cs
│ │ │ │ └── TreeViewWithTreeModel.cs.meta
│ │ │ ├── Scripts.meta
│ │ │ ├── Texture/
│ │ │ │ └── DefaultTexture.jpg.meta
│ │ │ └── Texture.meta
│ │ └── AssetAuditor.meta
│ └── Editor.meta
├── LICENSE
└── README.md
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
# Auto detect text files and perform LF normalization
* text=auto
================================================
FILE: .gitignore
================================================
/[Ll]ibrary/
/[Tt]emp/
/[Oo]bj/
/[Bb]uild/
/[Bb]uilds/
/Assets/AssetStoreTools*
/Assets/Editor/AssetAuditor/ProxyAssets
.DS_Store
# Autogenerated VS/MD/Consulo solution and project files
ExportedObj/
.consulo/
*.csproj
*.unityproj
*.sln
*.suo
*.tmp
*.user
*.userprefs
*.pidb
*.booproj
*.svd
# Unity3D generated meta files
*.pidb.meta
# Unity3D Generated File On Crash Reports
sysinfo.txt
# Builds
*.apk
*.unitypackage
ProjectSettings/
Assets/Plugins\.meta
Assets/Plugins/Editor\.meta
Assets/Plugins/Editor/JetBrains\.meta
Assets/Plugins/Editor/JetBrains/RiderAssetPostprocessor\.cs
Assets/Plugins/Editor/JetBrains/RiderAssetPostprocessor\.cs\.meta
Assets/Plugins/Editor/JetBrains/RiderPlugin\.cs
Assets/Plugins/Editor/JetBrains/RiderPlugin\.cs\.meta
Assets/Plugins/Editor/JetBrains/Unity3DRider\.cs
Assets/Plugins/Editor/JetBrains/Unity3DRider\.cs\.meta
\.idea/\.idea\.AssetAuditor/riderModule\.iml
\.idea/\.idea\.AssetAuditor/\.idea/workspace\.xml
\.idea/\.idea\.AssetAuditor/\.idea/modules\.xml
\.idea/\.idea\.AssetAuditor/\.idea/contentModel\.xml
Assets/Editor/AssetAuditor/ProxyAssets\.meta
================================================
FILE: Assets/Editor/AssetAuditor/Audio/DefaultAudio.wav.meta
================================================
fileFormatVersion: 2
guid: d13848c7015ad4078abfd3076f74c106
timeCreated: 1502381708
licenseType: Pro
AudioImporter:
serializedVersion: 6
defaultSettings:
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
preloadAudioData: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Assets/Editor/AssetAuditor/Audio.meta
================================================
fileFormatVersion: 2
guid: fffabc88153284eda8f44478e35d6337
folderAsset: yes
timeCreated: 1502381697
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Assets/Editor/AssetAuditor/Models/DefaultAvatar.fbx.meta
================================================
fileFormatVersion: 2
guid: 6ca747ad81483413fa1665afa5a9c79a
timeCreated: 1502276181
licenseType: Pro
ModelImporter:
serializedVersion: 21
fileIDToRecycleName:
100000: Chest
100002: //RootNode
100004: Geo_grp
100006: Head
100008: Hips
100010: Jaw
100012: JawEND
100014: Le_Eye_Mesh
100016: LeftArm
100018: LeftCheek
100020: LeftEye
100022: LeftEyelidLower
100024: LeftEyelidUpper
100026: LeftFoot
100028: LeftForeArm
100030: LeftHand
100032: LeftHandIndex1
100034: LeftHandIndex2
100036: LeftHandIndex3
100038: LeftHandMiddle1
100040: LeftHandMiddle2
100042: LeftHandMiddle3
100044: LeftHandPinky1
100046: LeftHandPinky2
100048: LeftHandPinky3
100050: LeftHandRing1
100052: LeftHandRing2
100054: LeftHandRing3
100056: LeftHandThumb1
100058: LeftHandThumb2
100060: LeftHandThumb3
100062: LeftInnerBrow
100064: LeftIOuterBrow
100066: LeftLeg
100068: LeftLipCorner
100070: LeftLipLower
100072: LeftLipUpper
100074: LeftNostril
100076: LeftShoulder
100078: LeftToes
100080: LeftUpLeg
100082: Lw_Teeth_Mesh
100084: Neck
100086: Reference
100088: Ri_Eye_Mesh
100090: RightArm
100092: RightCheek
100094: RightEye
100096: RightEyelidLower
100098: RightEyelidUpper
100100: RightFoot
100102: RightForeArm
100104: RightHand
100106: RightHandIndex1
100108: RightHandIndex2
100110: RightHandIndex3
100112: RightHandMiddle1
100114: RightHandMiddle2
100116: RightHandMiddle3
100118: RightHandPinky1
100120: RightHandPinky2
100122: RightHandPinky3
100124: RightHandRing1
100126: RightHandRing2
100128: RightHandRing3
100130: RightHandThumb1
100132: RightHandThumb2
100134: RightHandThumb3
100136: RightInnerBrow
100138: RightIOuterBrow
100140: RightLeg
100142: RightLipCorner
100144: RightLipLower
100146: RightLipUpper
100148: RightNostril
100150: RightShoulder
100152: RightToes
100154: RightUpLeg
100156: Spine
100158: TongueBack
100160: TongueTip
100162: Tounge_Mesh
100164: Unity_Body_Mesh
100166: Up_Teeth_Mesh
400000: Chest
400002: //RootNode
400004: Geo_grp
400006: Head
400008: Hips
400010: Jaw
400012: JawEND
400014: Le_Eye_Mesh
400016: LeftArm
400018: LeftCheek
400020: LeftEye
400022: LeftEyelidLower
400024: LeftEyelidUpper
400026: LeftFoot
400028: LeftForeArm
400030: LeftHand
400032: LeftHandIndex1
400034: LeftHandIndex2
400036: LeftHandIndex3
400038: LeftHandMiddle1
400040: LeftHandMiddle2
400042: LeftHandMiddle3
400044: LeftHandPinky1
400046: LeftHandPinky2
400048: LeftHandPinky3
400050: LeftHandRing1
400052: LeftHandRing2
400054: LeftHandRing3
400056: LeftHandThumb1
400058: LeftHandThumb2
400060: LeftHandThumb3
400062: LeftInnerBrow
400064: LeftIOuterBrow
400066: LeftLeg
400068: LeftLipCorner
400070: LeftLipLower
400072: LeftLipUpper
400074: LeftNostril
400076: LeftShoulder
400078: LeftToes
400080: LeftUpLeg
400082: Lw_Teeth_Mesh
400084: Neck
400086: Reference
400088: Ri_Eye_Mesh
400090: RightArm
400092: RightCheek
400094: RightEye
400096: RightEyelidLower
400098: RightEyelidUpper
400100: RightFoot
400102: RightForeArm
400104: RightHand
400106: RightHandIndex1
400108: RightHandIndex2
400110: RightHandIndex3
400112: RightHandMiddle1
400114: RightHandMiddle2
400116: RightHandMiddle3
400118: RightHandPinky1
400120: RightHandPinky2
400122: RightHandPinky3
400124: RightHandRing1
400126: RightHandRing2
400128: RightHandRing3
400130: RightHandThumb1
400132: RightHandThumb2
400134: RightHandThumb3
400136: RightInnerBrow
400138: RightIOuterBrow
400140: RightLeg
400142: RightLipCorner
400144: RightLipLower
400146: RightLipUpper
400148: RightNostril
400150: RightShoulder
400152: RightToes
400154: RightUpLeg
400156: Spine
400158: TongueBack
400160: TongueTip
400162: Tounge_Mesh
400164: Unity_Body_Mesh
400166: Up_Teeth_Mesh
2300000: Le_Eye_Mesh
2300002: Ri_Eye_Mesh
3300000: Le_Eye_Mesh
3300002: Ri_Eye_Mesh
4300000: Le_Eye_Mesh
4300002: Ri_Eye_Mesh
4300004: Unity_Body_Mesh
4300006: Up_Teeth_Mesh
4300008: Lw_Teeth_Mesh
4300010: Tounge_Mesh
9500000: //RootNode
13700000: Lw_Teeth_Mesh
13700002: Tounge_Mesh
13700004: Unity_Body_Mesh
13700006: Up_Teeth_Mesh
materials:
importMaterials: 0
materialName: 0
materialSearch: 1
animations:
legacyGenerateAnimations: 4
bakeSimulation: 0
resampleCurves: 1
optimizeGameObjects: 0
motionNodeName:
rigImportErrors:
rigImportWarnings:
animationImportErrors:
animationImportWarnings:
animationRetargetingWarnings:
animationDoRetargetingWarnings: 0
animationCompression: 3
animationRotationError: 0.5
animationPositionError: 0.5
animationScaleError: 0.5
animationWrapMode: 0
extraExposedTransformPaths: []
extraUserProperties: []
clipAnimations: []
isReadable: 1
meshes:
lODScreenPercentages: []
globalScale: 1
meshCompression: 0
addColliders: 0
importVisibility: 1
importBlendShapes: 1
importCameras: 1
importLights: 1
swapUVChannels: 0
generateSecondaryUV: 0
useFileUnits: 1
optimizeMeshForGPU: 1
keepQuads: 0
weldVertices: 1
secondaryUVAngleDistortion: 8
secondaryUVAreaDistortion: 15.000001
secondaryUVHardAngle: 88
secondaryUVPackMargin: 4
useFileScale: 1
tangentSpace:
normalSmoothAngle: 60
normalImportMode: 0
tangentImportMode: 3
normalCalculationMode: 4
importAnimation: 1
copyAvatar: 0
humanDescription:
serializedVersion: 2
human:
- boneName: Hips
humanName: Hips
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: LeftUpLeg
humanName: LeftUpperLeg
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: RightUpLeg
humanName: RightUpperLeg
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: LeftLeg
humanName: LeftLowerLeg
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: RightLeg
humanName: RightLowerLeg
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: LeftFoot
humanName: LeftFoot
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: RightFoot
humanName: RightFoot
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: Spine
humanName: Spine
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: Chest
humanName: Chest
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: Neck
humanName: Neck
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: Head
humanName: Head
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: LeftShoulder
humanName: LeftShoulder
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: RightShoulder
humanName: RightShoulder
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: LeftArm
humanName: LeftUpperArm
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: RightArm
humanName: RightUpperArm
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: LeftForeArm
humanName: LeftLowerArm
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: RightForeArm
humanName: RightLowerArm
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: LeftHand
humanName: LeftHand
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: RightHand
humanName: RightHand
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: LeftToes
humanName: LeftToes
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: RightToes
humanName: RightToes
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: LeftEye
humanName: LeftEye
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: RightEye
humanName: RightEye
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: Jaw
humanName: Jaw
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: LeftHandThumb1
humanName: Left Thumb Proximal
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: LeftHandThumb2
humanName: Left Thumb Intermediate
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: LeftHandThumb3
humanName: Left Thumb Distal
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: LeftHandIndex1
humanName: Left Index Proximal
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: LeftHandIndex2
humanName: Left Index Intermediate
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: LeftHandIndex3
humanName: Left Index Distal
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: LeftHandMiddle1
humanName: Left Middle Proximal
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: LeftHandMiddle2
humanName: Left Middle Intermediate
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: LeftHandMiddle3
humanName: Left Middle Distal
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: LeftHandRing1
humanName: Left Ring Proximal
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: LeftHandRing2
humanName: Left Ring Intermediate
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: LeftHandRing3
humanName: Left Ring Distal
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: LeftHandPinky1
humanName: Left Little Proximal
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: LeftHandPinky2
humanName: Left Little Intermediate
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: LeftHandPinky3
humanName: Left Little Distal
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: RightHandThumb1
humanName: Right Thumb Proximal
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: RightHandThumb2
humanName: Right Thumb Intermediate
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: RightHandThumb3
humanName: Right Thumb Distal
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: RightHandIndex1
humanName: Right Index Proximal
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: RightHandIndex2
humanName: Right Index Intermediate
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: RightHandIndex3
humanName: Right Index Distal
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: RightHandMiddle1
humanName: Right Middle Proximal
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: RightHandMiddle2
humanName: Right Middle Intermediate
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: RightHandMiddle3
humanName: Right Middle Distal
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: RightHandRing1
humanName: Right Ring Proximal
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: RightHandRing2
humanName: Right Ring Intermediate
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: RightHandRing3
humanName: Right Ring Distal
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: RightHandPinky1
humanName: Right Little Proximal
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: RightHandPinky2
humanName: Right Little Intermediate
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
- boneName: RightHandPinky3
humanName: Right Little Distal
limit:
min: {x: 0, y: 0, z: 0}
max: {x: 0, y: 0, z: 0}
value: {x: 0, y: 0, z: 0}
length: 0
modified: 0
skeleton:
- name: DefaultAvatar(Clone)
parentName:
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: Geo_grp
parentName: DefaultAvatar(Clone)
position: {x: -0, y: 0, z: 0}
rotation: {x: 0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: Lw_Teeth_Mesh
parentName: Geo_grp
position: {x: -0, y: 0, z: 0}
rotation: {x: 0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: Tounge_Mesh
parentName: Geo_grp
position: {x: -0, y: 0, z: 0}
rotation: {x: 0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: Unity_Body_Mesh
parentName: Geo_grp
position: {x: -0, y: 0, z: 0}
rotation: {x: 0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: Up_Teeth_Mesh
parentName: Geo_grp
position: {x: -0, y: 0, z: 0}
rotation: {x: 0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: Reference
parentName: DefaultAvatar(Clone)
position: {x: -0, y: 0, z: 0}
rotation: {x: 0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: Hips
parentName: Reference
position: {x: -0, y: 0.963794, z: -0.023506777}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: Spine
parentName: Hips
position: {x: -0, y: 0.092263184, z: 0.015771331}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: Chest
parentName: Spine
position: {x: -0, y: 0.16254029, z: 0.021850722}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: Neck
parentName: Chest
position: {x: -0, y: 0.2357239, z: -0.032413255}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: Head
parentName: Neck
position: {x: -0, y: 0.1063558, z: 0.0113267815}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: LeftEye
parentName: Head
position: {x: -0.020848233, y: 0.0825027, z: 0.055427432}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: Le_Eye_Mesh
parentName: LeftEye
position: {x: -0.0016841149, y: 0.00040588377, z: 0.0053181886}
rotation: {x: 0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: RightEye
parentName: Head
position: {x: 0.020849999, y: 0.08250283, z: 0.0554274}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: Ri_Eye_Mesh
parentName: RightEye
position: {x: 0.0016618776, y: 0.00038345336, z: 0.0053166724}
rotation: {x: 0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: LeftLipUpper
parentName: Head
position: {x: -0.014501322, y: -0.005111811, z: 0.09461884}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: LeftNostril
parentName: Head
position: {x: -0.0179, y: 0.026312828, z: 0.0908674}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: LeftCheek
parentName: Head
position: {x: -0.054244027, y: 0.03370195, z: 0.0594304}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: LeftEyelidUpper
parentName: Head
position: {x: -0.034406897, y: 0.10060814, z: 0.08020531}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: LeftEyelidLower
parentName: Head
position: {x: -0.035618957, y: 0.06507366, z: 0.07623474}
rotation: {x: -0.0348995, y: -0, z: -0, w: 0.99939084}
scale: {x: 1, y: 1.0000005, z: 1.0000005}
- name: LeftInnerBrow
parentName: Head
position: {x: -0.012062691, y: 0.118765265, z: 0.093466826}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: LeftIOuterBrow
parentName: Head
position: {x: -0.05503987, y: 0.11482529, z: 0.061777398}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: RightInnerBrow
parentName: Head
position: {x: 0.012062687, y: 0.118765265, z: 0.093466826}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: RightIOuterBrow
parentName: Head
position: {x: 0.055040002, y: 0.11482283, z: 0.061777398}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: RightEyelidUpper
parentName: Head
position: {x: 0.03441, y: 0.10061283, z: 0.08020739}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: RightEyelidLower
parentName: Head
position: {x: 0.03562, y: 0.06507283, z: 0.0762374}
rotation: {x: -0.0348995, y: -0, z: -0, w: 0.99939084}
scale: {x: 1, y: 1.0000005, z: 1.0000005}
- name: RightCheek
parentName: Head
position: {x: 0.054239996, y: 0.033702828, z: 0.0594274}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: RightNostril
parentName: Head
position: {x: 0.0179, y: 0.026308905, z: 0.09087062}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: RightLipUpper
parentName: Head
position: {x: 0.014501322, y: -0.0051071714, z: 0.094617404}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: Jaw
parentName: Head
position: {x: -0, y: 0.0111267585, z: 0.010327543}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: LeftLipLower
parentName: Jaw
position: {x: -0.014250817, y: -0.02168876, z: 0.08224063}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: JawEND
parentName: Jaw
position: {x: -0, y: -0.04828876, z: 0.07185171}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: RightLipLower
parentName: Jaw
position: {x: 0.014250817, y: -0.02168876, z: 0.082238786}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: RightLipCorner
parentName: Jaw
position: {x: 0.03284, y: -0.01657876, z: 0.066118784}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: LeftLipCorner
parentName: Jaw
position: {x: -0.032843262, y: -0.01657876, z: 0.066121764}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: TongueBack
parentName: Jaw
position: {x: -0, y: -0.022869369, z: 0.010095409}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: TongueTip
parentName: TongueBack
position: {x: -0, y: -0.00040944412, z: 0.0282273}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: RightShoulder
parentName: Chest
position: {x: 0.03832851, y: 0.19217674, z: -0.017063085}
rotation: {x: 0.228672, y: 0.9715822, z: -0.014005679, w: -0.059507377}
scale: {x: 1.0000013, y: 1, z: 1.000001}
- name: RightArm
parentName: RightShoulder
position: {x: -0.08357552, y: 0.0360957, z: -0.000000051557407}
rotation: {x: -0.21105212, y: -0.97439414, z: 0.017311702, w: -0.07558775}
scale: {x: 1.0000001, y: 1.0000002, z: 1}
- name: RightForeArm
parentName: RightArm
position: {x: 0.25342825, y: 0.006011353, z: -0.016704524}
rotation: {x: -0.0006165215, y: 0.022078624, z: -0.01607026, w: 0.99962693}
scale: {x: 0.99999994, y: 0.99999976, z: 1.0000001}
- name: RightHand
parentName: RightForeArm
position: {x: 0.2453737, y: 0.021641772, z: 0.005550465}
rotation: {x: 8.1490714e-10, y: -0, z: 0.021413714, w: 0.99977076}
scale: {x: 1.0000001, y: 1.0000001, z: 1}
- name: RightHandThumb1
parentName: RightHand
position: {x: 0.014684916, y: -0.011104942, z: 0.025858095}
rotation: {x: -0.012817442, y: -0.0032555843, z: 0.031460524, w: 0.99941754}
scale: {x: 1.0000004, y: 1, z: 1}
- name: RightHandThumb2
parentName: RightHandThumb1
position: {x: 0.016374, y: -0.00529, z: 0.02349136}
rotation: {x: -0.026063675, y: -0.09668989, z: -0.003606537, w: 0.9949667}
scale: {x: 1.0000002, y: 1.0000001, z: 1}
- name: RightHandThumb3
parentName: RightHandThumb2
position: {x: 0.02546, y: -0.00764, z: 0.020833}
rotation: {x: 0.000000012019879, y: 9.3132235e-10, z: -0.00000000372546, w: 1}
scale: {x: 1.0000002, y: 0.9999999, z: 1}
- name: RightHandIndex1
parentName: RightHand
position: {x: 0.0747695, y: -0.0012430536, z: 0.034344498}
rotation: {x: -0.0021189174, y: 0.080257446, z: 0.017538162, w: 0.9966176}
scale: {x: 1, y: 0.99999994, z: 1.0000001}
- name: RightHandIndex2
parentName: RightHandIndex1
position: {x: 0.0370584, y: 0.00072612107, z: 0.014538894}
rotation: {x: -0.0033265573, y: 0.015931673, z: 0.060633723, w: 0.99802744}
scale: {x: 1.0000002, y: 1.0000002, z: 1}
- name: RightHandIndex3
parentName: RightHandIndex2
position: {x: 0.025225038, y: -0.0049664653, z: 0.011012146}
rotation: {x: -0, y: -0, z: -9.458742e-10, w: 1}
scale: {x: 1.0000001, y: 1.0000004, z: 1.0000001}
- name: RightHandMiddle1
parentName: RightHand
position: {x: 0.075647645, y: 0.0047914027, z: 0.011853182}
rotation: {x: -0.0007688713, y: 0.03332108, z: 0.020907532, w: 0.99922574}
scale: {x: 0.9999999, y: 0.99999994, z: 1}
- name: RightHandMiddle2
parentName: RightHandMiddle1
position: {x: 0.043809064, y: 0.00019418815, z: 0.006454936}
rotation: {x: -0.004130707, y: -0.033512067, z: 0.07612222, w: 0.99652666}
scale: {x: 1.0000001, y: 1, z: 0.99999994}
- name: RightHandMiddle3
parentName: RightHandMiddle2
position: {x: 0.03307247, y: -0.007547537, z: 0.0016898462}
rotation: {x: -0, y: -0, z: -0.0000000032414385, w: 1}
scale: {x: 1, y: 1.0000001, z: 1}
- name: RightHandRing1
parentName: RightHand
position: {x: 0.070598476, y: 0.0024570965, z: -0.009821458}
rotation: {x: 0.0007108786, y: -0.054342177, z: 0.03494465, w: 0.99791056}
scale: {x: 1.0000001, y: 0.99999994, z: 1}
- name: RightHandRing2
parentName: RightHandRing1
position: {x: 0.042887185, y: -0.0013753821, z: -0.004945858}
rotation: {x: 0.0004845856, y: -0.021289792, z: 0.06986199, w: 0.99732935}
scale: {x: 1.0000002, y: 1.0000001, z: 0.99999964}
- name: RightHandRing3
parentName: RightHandRing2
position: {x: 0.029500604, y: -0.0076929354, z: -0.004622256}
rotation: {x: -0, y: -0, z: 0.0000000013351378, w: 1}
scale: {x: 1, y: 0.9999999, z: 0.9999998}
- name: RightHandPinky1
parentName: RightHand
position: {x: 0.06680334, y: -0.0019941088, z: -0.030756146}
rotation: {x: 0.0031760908, y: -0.19200507, z: 0.0451148, w: 0.9803513}
scale: {x: 1.0000001, y: 1, z: 0.99999994}
- name: RightHandPinky2
parentName: RightHandPinky1
position: {x: 0.028530842, y: -0.001397143, z: -0.011623796}
rotation: {x: -0.00017062707, y: -0.009661323, z: -0.0053624124, w: 0.999939}
scale: {x: 1, y: 1.0000002, z: 1.0000001}
- name: RightHandPinky3
parentName: RightHandPinky2
position: {x: 0.02142686, y: -0.00055350893, z: -0.008516608}
rotation: {x: -0, y: 9.3132235e-10, z: -4.2518867e-11, w: 1}
scale: {x: 1, y: 1.0000002, z: 1.0000001}
- name: LeftShoulder
parentName: Chest
position: {x: -0.038243506, y: 0.19217809, z: -0.017063085}
rotation: {x: -0.01400671, y: -0.05950682, z: 0.22868991, w: 0.97157794}
scale: {x: 1, y: 0.99999994, z: 1}
- name: LeftArm
parentName: LeftShoulder
position: {x: -0.08357477, y: 0.036097575, z: 2.8865798e-17}
rotation: {x: 0.009464391, y: 0.043691695, z: -0.22304244, w: 0.97378314}
scale: {x: 1, y: 1.0000001, z: 0.9999998}
- name: LeftForeArm
parentName: LeftArm
position: {x: -0.2540493, y: 0, z: 0}
rotation: {x: -0.0006165216, y: 0.022078618, z: -0.016070211, w: 0.99962693}
scale: {x: 1, y: 1, z: 1.0000002}
- name: LeftHand
parentName: LeftForeArm
position: {x: -0.24638927, y: 0, z: 0}
rotation: {x: 0.0000000034924592, y: 0.0000000074505797, z: -0.02141356, w: 0.9997707}
scale: {x: 0.9999998, y: 1.0000002, z: 0.99999994}
- name: LeftHandThumb1
parentName: LeftHand
position: {x: -0.014231241, y: -0.012377825, z: 0.025531668}
rotation: {x: -0.012314987, y: -0.008526002, z: 0.012583703, w: 0.9998086}
scale: {x: 1.0000002, y: 0.99999994, z: 0.99999994}
- name: LeftHandThumb2
parentName: LeftHandThumb1
position: {x: -0.016374, y: -0.00529, z: 0.023491409}
rotation: {x: -0.026063059, y: 0.09668942, z: 0.0036069017, w: 0.9949668}
scale: {x: 1.0000004, y: 1.0000001, z: 0.9999999}
- name: LeftHandThumb3
parentName: LeftHandThumb2
position: {x: -0.02546, y: -0.00764, z: 0.020833}
rotation: {x: 0.000000042738975, y: 0.0000000037252903, z: 0.0000000018620199,
w: 1}
scale: {x: 1.0000001, y: 0.9999999, z: 0.9999999}
- name: LeftHandIndex1
parentName: LeftHand
position: {x: -0.0751258, y: -0.0078414045, z: 0.032652643}
rotation: {x: -0.0021189197, y: 0.08025745, z: 0.01753819, w: 0.9966176}
scale: {x: 1.0000002, y: 0.9999999, z: 1.0000004}
- name: LeftHandIndex2
parentName: LeftHandIndex1
position: {x: -0.03979728, y: 0.000049808405, z: 0.0011857504}
rotation: {x: 0.000501889, y: 0.015471162, z: 0.040411938, w: 0.99906325}
scale: {x: 1, y: 0.99999994, z: 0.99999976}
- name: LeftHandIndex3
parentName: LeftHandIndex2
position: {x: -0.027968477, y: -0.000000006281224, z: -0.00000005171866}
rotation: {x: -5.8207654e-11, y: -0, z: 0.000000002835804, w: 1}
scale: {x: 0.99999994, y: 1.0000001, z: 1.0000001}
- name: LeftHandMiddle1
parentName: LeftHand
position: {x: -0.076023825, y: -0.0018851344, z: 0.010141229}
rotation: {x: -0.00076887483, y: 0.033321086, z: 0.020907529, w: 0.9992257}
scale: {x: 1.0000001, y: 0.9999999, z: 1.0000001}
- name: LeftHandMiddle2
parentName: LeftHandMiddle1
position: {x: -0.044280436, y: 0.000004798874, z: -0.00042540013}
rotation: {x: -0.0013621139, y: -0.01915252, z: 0.037885293, w: 0.99909765}
scale: {x: 1.0000002, y: 1, z: 0.99999994}
- name: LeftHandMiddle3
parentName: LeftHandMiddle2
position: {x: -0.033964828, y: -0.000000012197929, z: 0.0000000037564827}
rotation: {x: -0, y: -0, z: 4.838512e-10, w: 1}
scale: {x: 1, y: 1.0000001, z: 1.0000001}
- name: LeftHandRing1
parentName: LeftHand
position: {x: -0.07030211, y: -0.0037453093, z: -0.011411792}
rotation: {x: -0.00032414307, y: 0.011598279, z: 0.024737397, w: 0.99962664}
scale: {x: 0.9999999, y: 0.9999998, z: 1.0000001}
- name: LeftHandRing2
parentName: LeftHandRing1
position: {x: -0.043135457, y: -0.000020882308, z: -0.0022351784}
rotation: {x: -0.0012033589, y: -0.023113519, z: 0.040983878, w: 0.9988918}
scale: {x: 0.99999994, y: 1.0000001, z: 0.99999994}
- name: LeftHandRing3
parentName: LeftHandRing2
position: {x: -0.030835565, y: 7.710497e-11, z: -0.00000001649327}
rotation: {x: -0, y: -0, z: 0.0000000013897075, w: 1}
scale: {x: 0.99999994, y: 1, z: 1}
- name: LeftHandPinky1
parentName: LeftHand
position: {x: -0.06565995, y: -0.007825106, z: -0.032251246}
rotation: {x: -0.00091239274, y: 0.012161445, z: 0.021224977, w: 0.9997003}
scale: {x: 1.0000001, y: 0.9999999, z: 1.0000002}
- name: LeftHandPinky2
parentName: LeftHandPinky1
position: {x: -0.030805448, y: -0.000030874573, z: -0.0014480775}
rotation: {x: -0.00017062433, y: -0.009661346, z: -0.00536237, w: 0.999939}
scale: {x: 0.99999994, y: 1.0000001, z: 1.0000001}
- name: LeftHandPinky3
parentName: LeftHandPinky2
position: {x: -0.023064027, y: -0.0000064025808, z: 0.000000018332095}
rotation: {x: -0, y: 9.3132235e-10, z: -1.9895191e-11, w: 1}
scale: {x: 0.9999999, y: 1, z: 0.9999999}
- name: RightUpLeg
parentName: Hips
position: {x: 0.075449534, y: -0.04566399, z: 0}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: RightLeg
parentName: RightUpLeg
position: {x: 0.020550467, y: -0.40913, z: 0.0071713654}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: RightFoot
parentName: RightLeg
position: {x: 0.0051529994, y: -0.4231559, z: -0.012032089}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: RightToes
parentName: RightFoot
position: {x: 0.007487, y: -0.0731673, z: 0.1454275}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: LeftUpLeg
parentName: Hips
position: {x: -0.0754495, y: -0.04566402, z: 0}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: LeftLeg
parentName: LeftUpLeg
position: {x: -0.020550499, y: -0.40912998, z: 0.0071713654}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: LeftFoot
parentName: LeftLeg
position: {x: -0.0051529994, y: -0.4231559, z: -0.012032089}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
- name: LeftToes
parentName: LeftFoot
position: {x: -0.007487, y: -0.0731673, z: 0.14542712}
rotation: {x: -0, y: -0, z: -0, w: 1}
scale: {x: 1, y: 1, z: 1}
armTwist: 0.5
foreArmTwist: 0.5
upperLegTwist: 0.5
legTwist: 0.5
armStretch: 0.05
legStretch: 0.05
feetSpacing: 0
rootMotionBoneName:
rootMotionBoneRotation: {x: 0, y: 0, z: 0, w: 1}
hasTranslationDoF: 0
hasExtraRoot: 1
skeletonHasParents: 1
lastHumanDescriptionAvatarSource: {instanceID: 0}
animationType: 3
humanoidOversampling: 1
additionalBone: 0
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Assets/Editor/AssetAuditor/Models.meta
================================================
fileFormatVersion: 2
guid: d1003e9744d57413fad5f07821ef2136
folderAsset: yes
timeCreated: 1502276220
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Assets/Editor/AssetAuditor/Scripts/AssetAuditTreeElement.cs
================================================
using System;
namespace UnityAssetAuditor
{
[Serializable]
public class AssetAuditTreeElement : TreeElement
{
public bool isAsset;
public string projectPath;
public AssetAuditor.AssetType assetType;
internal enum AssetType
{
Asset,
Directory
}
public bool conforms;
public AssetAuditTreeElement (string name,string _projectPath, int depth, int id, bool _isAsset, bool _conforms , AssetAuditor.AssetType _assetType) : base (name, depth, id)
{
isAsset = _isAsset;
projectPath = _projectPath;
conforms = _conforms;
assetType = _assetType;
}
}
}
================================================
FILE: Assets/Editor/AssetAuditor/Scripts/AssetAuditTreeElement.cs.meta
================================================
fileFormatVersion: 2
guid: f1bafad60d37c484dab3ce5b74c04a6a
timeCreated: 1472024032
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Assets/Editor/AssetAuditor/Scripts/AssetAuditTreeView.cs
================================================
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.IMGUI.Controls;
using UnityEngine;
using UnityEngine.Assertions;
namespace UnityAssetAuditor
{
public class AssetAuditTreeView : TreeViewWithTreeModel<AssetAuditTreeElement>
{
private readonly Action<AssetAuditTreeElement> _ruleFixEvent;
const float kRowHeights = 20f;
const float kIconWidth = 18f;
public bool showControls { get; set; }
// All columns
enum MyColumns
{
Name,
Conforms
}
public static void TreeToList(TreeViewItem root, IList<TreeViewItem> result)
{
if (root == null)
throw new NullReferenceException("root");
if (result == null)
throw new NullReferenceException("result");
result.Clear();
if (root.children == null)
return;
Stack<TreeViewItem> stack = new Stack<TreeViewItem>();
for (int i = root.children.Count - 1; i >= 0; i--)
stack.Push(root.children[i]);
while (stack.Count > 0)
{
TreeViewItem current = stack.Pop();
result.Add(current);
if (current.hasChildren && current.children[0] != null)
{
for (int i = current.children.Count - 1; i >= 0; i--)
{
stack.Push(current.children[i]);
}
}
}
}
public AssetAuditTreeView(TreeViewState state, MultiColumnHeader multicolumnHeader, TreeModel<AssetAuditTreeElement> model , Action<AssetAuditTreeElement> ruleFixEvent) : base(state, multicolumnHeader, model)
{
_ruleFixEvent = ruleFixEvent;
// Custom setup
rowHeight = kRowHeights;
columnIndexForTreeFoldouts = 0;
showAlternatingRowBackgrounds = true;
showBorder = true;
customFoldoutYOffset = (kRowHeights - EditorGUIUtility.singleLineHeight) * 0.5f; // center foldout in the row since we also center content. See RowGUI
extraSpaceBeforeIconAndLabel = kIconWidth;
Reload();
}
// Note we We only build the visible rows, only the backend has the full tree information.
// The treeview only creates info for the row list.
protected override IList<TreeViewItem> BuildRows(TreeViewItem root)
{
var rows = base.BuildRows(root);
return rows;
}
protected override void RowGUI(RowGUIArgs args)
{
var item = (TreeViewItem<AssetAuditTreeElement>)args.item;
for (int i = 0; i < args.GetNumVisibleColumns(); ++i)
{
CellGUI(args.GetCellRect(i), item, (MyColumns)args.GetColumn(i), ref args);
}
}
void CellGUI(Rect cellRect, TreeViewItem<AssetAuditTreeElement> item, MyColumns column, ref RowGUIArgs args)
{
// Center cell rect vertically (makes it easier to place controls, icons etc in the cells)
CenterRectUsingSingleLineHeight(ref cellRect);
switch (column)
{
case MyColumns.Name:
{
// Do toggle
Rect iconRect = cellRect;
iconRect.x += GetContentIndent(item);
iconRect.width = kIconWidth;
Texture2D iconTex = null;
/* if (item.data.isAsset)
{
if (!string.IsNullOrEmpty(item.data.projectPath))
{
iconTex = AssetPreview.GetMiniThumbnail(
AssetDatabase.LoadAssetAtPath<Texture2D>(
item.data.projectPath.Substring(Application.dataPath.Length - 6)));
}
}*/
switch (item.data.assetType)
{
case AssetAuditor.AssetType.Texture:
iconTex = AssetPreview.GetMiniThumbnail(
AssetDatabase.LoadAssetAtPath<Texture2D>(
item.data.projectPath));
break;
case AssetAuditor.AssetType.Model:
iconTex = EditorGUIUtility.FindTexture("PrefabModel Icon");
break;
case AssetAuditor.AssetType.Audio:
iconTex = EditorGUIUtility.FindTexture("AudioClip Icon");
break;
case AssetAuditor.AssetType.Folder:
iconTex = EditorGUIUtility.FindTexture("Folder Icon");
break;
default:
throw new ArgumentOutOfRangeException();
}
if (iconRect.xMax < cellRect.xMax)
{
GUI.DrawTexture(iconRect, iconTex);
}
// Default icon and label
args.rowRect = cellRect;
base.RowGUI(args);
}
break;
case MyColumns.Conforms:
var conforms = item.data.conforms;
if (item.data.isAsset)
{
if (conforms)
{
GUI.Label(cellRect , " Settings OK ");
}
else
{
if (GUI.Button(cellRect, "Fix"))
{
_ruleFixEvent.Invoke(item.data);
}
}
}
break;
}
}
// Misc
//--------
protected override bool CanMultiSelect(TreeViewItem item)
{
return true;
}
public static MultiColumnHeaderState CreateDefaultMultiColumnHeaderState(float treeViewWidth)
{
var columns = new[]
{
new MultiColumnHeaderState.Column
{
headerContent = new GUIContent("Name"),
headerTextAlignment = TextAlignment.Left,
width = 0, // adjusted below
minWidth = 60,
autoResize = true,
allowToggleVisibility = false,
canSort = false
},
new MultiColumnHeaderState.Column
{
headerContent = new GUIContent("Conforms"),
headerTextAlignment = TextAlignment.Left,
width = 150, // adjusted below
minWidth = 150,
autoResize = true,
allowToggleVisibility = false,
canSort = false
},
};
Assert.AreEqual(columns.Length, Enum.GetValues(typeof(MyColumns)).Length, "Number of columns should match number of enum values: You probably forgot to update one of them.");
// Set name column width (flexible)
int nameColumn = (int)MyColumns.Name;
columns[nameColumn].width = treeViewWidth - GUI.skin.verticalScrollbar.fixedWidth;
for (int i = 0; i < columns.Length; ++i)
if (i != nameColumn)
columns[nameColumn].width -= columns[i].width;
if (columns[nameColumn].width < 60f)
columns[nameColumn].width = 60f;
var state = new MultiColumnHeaderState(columns);
return state;
}
}
}
================================================
FILE: Assets/Editor/AssetAuditor/Scripts/AssetAuditTreeView.cs.meta
================================================
fileFormatVersion: 2
guid: e00d20ba7c1f4d446a34ea24d8b82c4e
timeCreated: 1464348051
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Assets/Editor/AssetAuditor/Scripts/AssetAuditor.cs
================================================
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEditor.IMGUI.Controls;
using UnityEngine;
using UnityEngine.Collections;
namespace UnityAssetAuditor
{
public delegate void OnQueueComplete();
public class AssetAuditor
{
public static IEnumerable<float> currentEnumerable;
public static IEnumerator<float> currentEnumerator;
public static Queue<IEnumerable<float>> enumerableQueue;
public static event OnQueueComplete queueComplete;
private static List<string> foundAssets;
public enum WildCardMatchType
{
NameContains,
Regex
}
public enum AssetType
{
Texture,
Model,
Audio,
Folder
}
[Serializable]
public struct AssetRule
{
public string RuleName;
public WildCardMatchType WildCardMatchType;
public string WildCard;
public string AssetGuid;
public AssetType assetType;
public bool SelectiveMode;
public List<string> SelectiveProperties;
}
static AssetAuditor()
{
EditorApplication.update += TickEnumerator;
enumerableQueue = new Queue<IEnumerable<float>>();
}
private static void TickEnumerator()
{
if (currentEnumerable == null)
{
return;
}
if (!currentEnumerator.MoveNext())
{
currentEnumerable = null;
currentEnumerator = null;
if (enumerableQueue.Count == 0)
{
if (queueComplete != null) queueComplete.Invoke();
}
else
{
currentEnumerable = enumerableQueue.Dequeue();
currentEnumerator = currentEnumerable.GetEnumerator();
}
}
}
public static float GetProgress()
{
return currentEnumerator != null ? currentEnumerator.Current : 0f;
}
public static void AddEnumerator(IEnumerable<float> enumerator)
{
enumerableQueue.Enqueue(enumerator);
if (currentEnumerable == null)
{
currentEnumerable = enumerableQueue.Dequeue();
currentEnumerator = currentEnumerable.GetEnumerator();
}
}
public static void ClearQueue()
{
enumerableQueue.Clear();
currentEnumerable = null;
currentEnumerator = null;
}
public static Type TypeFromAssetType(AssetType assetType)
{
switch (assetType)
{
case AssetType.Texture:
return typeof(Texture);
case AssetType.Model:
return typeof(GameObject);
case AssetType.Audio:
return typeof(AudioClip);
case AssetType.Folder:
return null;
default:
throw new ArgumentOutOfRangeException("assetType", assetType, null);
}
}
public static string[] GetAffectedAssets()
{
return foundAssets.ToArray();
}
public static void UpdateAffectedAssets(AssetRule assetRule)
{
foundAssets = new List<string>();
switch (assetRule.WildCardMatchType)
{
case WildCardMatchType.NameContains:
ClearQueue();
AddEnumerator(DoNameContainsSearch(foundAssets, assetRule));
break;
case WildCardMatchType.Regex:
ClearQueue();
AddEnumerator(DoRegexNameSearch(foundAssets, assetRule));
break;
default:
throw new ArgumentOutOfRangeException();
}
}
private static IEnumerable<float> DoRegexNameSearch(List<string> foundAssets, AssetRule assetRule)
{
string type = "";
switch (assetRule.assetType)
{
case AssetType.Texture:
type = "Texture";
break;
case AssetType.Model:
type = "GameObject";
break;
case AssetType.Audio:
type = "AudioClip";
break;
case AssetType.Folder:
break;
default:
throw new ArgumentOutOfRangeException();
}
foreach (var asset in AssetDatabase.FindAssets("t:" + type))
{
string guidToAssetPath = AssetDatabase.GUIDToAssetPath(asset);
if (guidToAssetPath.Contains(AssetAuditorPreferences.ProxyAssetsDirectory)) continue;
if (Regex.IsMatch(guidToAssetPath, assetRule.WildCard))
{
foundAssets.Add(guidToAssetPath);
}
}
AssetAuditor.foundAssets = foundAssets;
yield return 1f;
}
public static IEnumerable<float> DoNameContainsSearch(List<string> foundAssets, AssetRule assetRule)
{
string type = "";
switch (assetRule.assetType)
{
case AssetType.Texture:
type = "Texture";
break;
case AssetType.Model:
type = "GameObject";
break;
case AssetType.Audio:
type = "AudioClip";
break;
case AssetType.Folder:
break;
default:
throw new ArgumentOutOfRangeException();
}
foreach (string findAsset in AssetDatabase.FindAssets("t:" + type + " " + assetRule.WildCard))
{
string guidToAssetPath = AssetDatabase.GUIDToAssetPath(findAsset);
if(guidToAssetPath.Contains(AssetAuditorPreferences.ProxyAssetsDirectory))continue;
foundAssets.Add(guidToAssetPath);
}
AssetAuditor.foundAssets = foundAssets;
yield return 1f;
}
public static IEnumerable<float> GatherAssetRules(List<AssetRule> _assetRules , List<string> _assetRuleNames )
{
int progress = 0;
string[] foundAssets = AssetDatabase.FindAssets("", new[] {AssetAuditorPreferences.ProxyAssetsDirectory});
// get all assets in the proxyassets folder
foreach (string asset in foundAssets)
{
string guidToAssetPath = AssetDatabase.GUIDToAssetPath(asset);
AssetImporter assetImporter = AssetImporter.GetAtPath(guidToAssetPath);
AssetRule ar = new AssetRule();
ar = JsonUtility.FromJson<AssetRule>(assetImporter.userData);
_assetRules.Add(ar);
progress++;
yield return progress / (float)foundAssets.Length;
}
_assetRuleNames.Clear();
foreach (AssetRule assetRule in _assetRules)
{
_assetRuleNames.Add(assetRule.RuleName);
}
yield return 1f;
}
public static IEnumerable<float> GatherData(AssetRule assetRule , List<AssetAuditTreeElement> elements, int selectedSelective)
{
int id = -1;
// get the affected assets
string[] affectedAssets = GetAffectedAssets();
if(affectedAssets == null) Debug.Log(" null affected assets");
// build the directory tree from the affected assets
elements.Add(new AssetAuditTreeElement("Root", "", -1, 0, false, false, AssetType.Folder ));
// early out if there are no affected assets
if (affectedAssets.Length == 0)
{
Debug.Log("no affected assets ");
if (queueComplete != null) queueComplete.Invoke();
yield break;
}
AssetAuditTreeElement assetsFolder = new AssetAuditTreeElement("Assets", "Assets", 0, id++, false, false,
AssetType.Folder );
// add the project root "Assets" folder
elements.Add(assetsFolder);
if (assetsFolder.children == null) assetsFolder.children = new List<TreeElement>();
float progress = 0f;
foreach (var affectedAsset in affectedAssets)
{
// split the path
string path = affectedAsset.Substring(7);
var strings = path.Split(new[]{'/'}, StringSplitOptions.None);
string projectPath = "Assets";
// the first entries have lower depth
for(int i = 0 ; i < strings.Length ; i++)
{
projectPath += "/" + strings[i];
// the last element is the asset itself
if (i == strings.Length-1)
{
var result = CheckAffectedAsset(affectedAsset, assetRule, selectedSelective);
var element = new AssetAuditTreeElement(strings[i], projectPath, i + 1, id + 1, true, result,
assetRule.assetType);
elements.Add(element);
id++;
}
else if (!elements.Exists(element => element.name == strings[i] && element.projectPath == projectPath))
{
var assetAuditTreeElement = new AssetAuditTreeElement(strings[i], projectPath, i+1 , id+1, false, false, AssetType.Folder);
elements.Add(assetAuditTreeElement);
id++;
}
}
progress += 1f;
yield return progress / affectedAssets.Length;
}
}
private static bool CheckAffectedAsset(string affectedAsset, AssetRule assetRule, int selectedSelective)
{
SerializedObject assetImporterSO = null;
SerializedObject ruleImporterSO = null;
if (TypeFromAssetType(assetRule.assetType) == typeof(Texture))
{
TextureImporter assetimporter =
AssetImporter.GetAtPath(affectedAsset) as
TextureImporter;
// this may happen (e.g. render texture)
if (assetimporter == null)
return false;
TextureImporter ruleimporter =
AssetImporter.GetAtPath(AssetDatabase.GUIDToAssetPath(assetRule.AssetGuid)) as
TextureImporter;
if (assetimporter.GetInstanceID() == ruleimporter.GetInstanceID())
return false; // this shouldnt happen but is a nice failsafe
assetImporterSO = new SerializedObject(assetimporter);
ruleImporterSO = new SerializedObject(ruleimporter);
}
if (TypeFromAssetType(assetRule.assetType) == typeof(GameObject))
{
ModelImporter assetimporter =
AssetImporter.GetAtPath(affectedAsset) as
ModelImporter;
ModelImporter ruleimporter =
AssetImporter.GetAtPath(AssetDatabase.GUIDToAssetPath(assetRule.AssetGuid)) as
ModelImporter;
if (assetimporter.GetInstanceID() == ruleimporter.GetInstanceID())
return false; // this shouldnt happen but is a nice failsafe
assetImporterSO = new SerializedObject(assetimporter);
ruleImporterSO = new SerializedObject(ruleimporter);
}
if (TypeFromAssetType(assetRule.assetType) == typeof(AudioClip))
{
AudioImporter assetimporter =
AssetImporter.GetAtPath(affectedAsset) as
AudioImporter;
AudioImporter ruleimporter =
AssetImporter.GetAtPath(AssetDatabase.GUIDToAssetPath(assetRule.AssetGuid)) as
AudioImporter;
if (assetimporter.GetInstanceID() == ruleimporter.GetInstanceID())
return false; // this shouldnt happen but is a nice failsafe
assetImporterSO = new SerializedObject(assetimporter);
ruleImporterSO = new SerializedObject(ruleimporter);
}
if (assetImporterSO == null || ruleImporterSO == null) return false; // TODO log message here
if (!assetRule.SelectiveMode || assetRule.SelectiveProperties.Count <= 0)
{
return CompareSerializedObject(assetImporterSO, ruleImporterSO);
}
string property = assetRule.SelectiveProperties[selectedSelective];
string realname = GetPropertyNameFromDisplayName(assetImporterSO, property);
SerializedProperty foundAssetSP = assetImporterSO.FindProperty(realname);
SerializedProperty assetRuleSP = ruleImporterSO.FindProperty(realname);
return CompareSerializedProperty(foundAssetSP, assetRuleSP);
}
public static bool CompareSerializedProperty(SerializedProperty foundAssetSp, SerializedProperty assetRuleSp)
{
if (foundAssetSp.propertyPath == "m_FileIDToRecycleName" || foundAssetSp.propertyPath == "m_UserData") return true; // the file ids will always be different so we should skip over this. The user data is where the asset rule info is stored so we dont want to check that
switch (foundAssetSp.propertyType)
{
case SerializedPropertyType.Generic: // this eventually goes down through the data until we get a useable value to compare
SerializedProperty foundAssetsSPCopy = foundAssetSp.Copy();
SerializedProperty assetRuleSPCopy = assetRuleSp.Copy();
// we must get the next sibling SerializedProperties to know when to stop the comparison
SerializedProperty nextSiblingAssetSP = foundAssetSp.Copy ();
SerializedProperty nextSiblingRuleSP = assetRuleSp.Copy ();
nextSiblingAssetSP.NextVisible (false);
nextSiblingRuleSP.NextVisible (false);
bool asset, found;
do
{
if (assetRuleSPCopy.propertyType != foundAssetsSPCopy.propertyType)
{
return false; // mistmatch in types different serialisation
}
if (assetRuleSPCopy.propertyType != SerializedPropertyType.Generic)
{
if (!CompareSerializedProperty(foundAssetsSPCopy, assetRuleSPCopy))
{
return false;
}
}
asset = foundAssetsSPCopy.NextVisible(true);
found = assetRuleSPCopy.NextVisible(true);
} while (found && asset &&
!SerializedProperty.EqualContents (foundAssetsSPCopy, nextSiblingAssetSP) &&
!SerializedProperty.EqualContents (assetRuleSPCopy, nextSiblingRuleSP));
return true;
case SerializedPropertyType.Integer:
return foundAssetSp.intValue == assetRuleSp.intValue;
case SerializedPropertyType.Boolean:
return foundAssetSp.boolValue == assetRuleSp.boolValue;
case SerializedPropertyType.Float:
return foundAssetSp.floatValue == assetRuleSp.floatValue;
case SerializedPropertyType.String:
return foundAssetSp.stringValue == assetRuleSp.stringValue;
case SerializedPropertyType.Color:
return foundAssetSp.colorValue == assetRuleSp.colorValue;
case SerializedPropertyType.ObjectReference:
return true;// this is weird on models imports and needs a solution as the exposed transforms reference the model itself
case SerializedPropertyType.LayerMask:
break;
case SerializedPropertyType.Enum:
return foundAssetSp.enumValueIndex == assetRuleSp.enumValueIndex;
case SerializedPropertyType.Vector2:
return foundAssetSp.vector2Value == assetRuleSp.vector2Value;
case SerializedPropertyType.Vector3:
return foundAssetSp.vector3Value == assetRuleSp.vector3Value;
case SerializedPropertyType.Vector4:
return foundAssetSp.vector4Value == assetRuleSp.vector4Value;
case SerializedPropertyType.Rect:
return foundAssetSp.rectValue == assetRuleSp.rectValue;
case SerializedPropertyType.ArraySize:
if (foundAssetSp.isArray && assetRuleSp.isArray)
{
Debug.Log(foundAssetSp.arraySize + assetRuleSp.arraySize);
return foundAssetSp.arraySize == assetRuleSp.arraySize;
}
else
{
return foundAssetSp.intValue == assetRuleSp.intValue;
}
case SerializedPropertyType.Character:
break;
case SerializedPropertyType.AnimationCurve:
return foundAssetSp.animationCurveValue == assetRuleSp.animationCurveValue;
case SerializedPropertyType.Bounds:
return foundAssetSp.boundsValue == assetRuleSp.boundsValue;
case SerializedPropertyType.Gradient:
break;
case SerializedPropertyType.Quaternion:
return foundAssetSp.quaternionValue == assetRuleSp.quaternionValue;
case SerializedPropertyType.ExposedReference:
return foundAssetSp.exposedReferenceValue == assetRuleSp.exposedReferenceValue;
#if UNITY_2017_1_OR_NEWER
case SerializedPropertyType.FixedBufferSize:
break;
#endif
default:
throw new ArgumentOutOfRangeException();
}
return false;
}
public static bool CompareSerializedObject(SerializedObject rule, SerializedObject asset)
{
SerializedProperty ruleIter = rule.GetIterator();
SerializedProperty assetIter = asset.GetIterator();
assetIter.NextVisible(true);
ruleIter.NextVisible(true);
do
{
if (!CompareSerializedProperty(ruleIter, assetIter))
{
Debug.Log(" failied property " + ruleIter.propertyPath + " " + assetIter.displayName);
return false;
}
ruleIter.NextVisible(false);
} while (assetIter.NextVisible(false));
return true;
}
public static IEnumerable<float> FixAll(AssetAuditTreeView treeView , AssetRule assetRule)
{
List<AssetAuditTreeElement> list = new List<AssetAuditTreeElement>();
TreeElementUtility.TreeToList(treeView.treeModel.root, list);
float progress = 0f;
foreach (AssetAuditTreeElement assetAuditTreeElement in list)
{
if (assetAuditTreeElement.isAsset && !assetAuditTreeElement.conforms)
FixRule(assetAuditTreeElement, assetRule);
progress += 1f;
yield return progress / list.Count;
}
}
public static void FixRule(AssetAuditTreeElement data , AssetRule assetRule)
{
string ruleAssetPath = AssetDatabase.GUIDToAssetPath(assetRule.AssetGuid);
string affectedAssetPath = data.projectPath;
switch (data.assetType)
{
case AssetType.Texture:
TextureImporter ruleTexImporter = AssetImporter.GetAtPath(ruleAssetPath) as TextureImporter;
TextureImporter affectedAssetTexImporter = AssetImporter.GetAtPath(affectedAssetPath) as TextureImporter;
if (assetRule.SelectiveMode)
{
SerializedObject ruleImporterSO = new SerializedObject(ruleTexImporter);
SerializedObject affectedAssetImporterSO = new SerializedObject(affectedAssetTexImporter);
CopySelectiveProperties(affectedAssetImporterSO, ruleImporterSO, assetRule);
}
else
{
EditorUtility.CopySerialized(ruleTexImporter, affectedAssetTexImporter);
}
affectedAssetTexImporter.userData = "";
affectedAssetTexImporter.SaveAndReimport();
break;
case AssetType.Model:
ModelImporter ruleModelImporter = AssetImporter.GetAtPath(ruleAssetPath) as ModelImporter;
ModelImporter affectedAssetModelImporter = AssetImporter.GetAtPath(affectedAssetPath) as ModelImporter;
if (assetRule.SelectiveMode)
{
SerializedObject ruleImporterSO = new SerializedObject(ruleModelImporter);
SerializedObject affectedAssetImporterSO = new SerializedObject(affectedAssetModelImporter);
CopySelectiveProperties(affectedAssetImporterSO, ruleImporterSO, assetRule);
}
else
{
EditorUtility.CopySerialized(ruleModelImporter, affectedAssetModelImporter);
}
affectedAssetModelImporter.userData = "";
affectedAssetModelImporter.SaveAndReimport();
break;
case AssetType.Audio:
AudioImporter ruleAudioImporter = AssetImporter.GetAtPath(ruleAssetPath) as AudioImporter;
AudioImporter affectedAssetAudioImporter = AssetImporter.GetAtPath(affectedAssetPath) as AudioImporter;
if (assetRule.SelectiveMode)
{
SerializedObject ruleImporterSO = new SerializedObject(ruleAudioImporter);
SerializedObject affectedAssetImporterSO = new SerializedObject(affectedAssetAudioImporter);
CopySelectiveProperties(affectedAssetImporterSO, ruleImporterSO, assetRule);
}
else
{
EditorUtility.CopySerialized(ruleAudioImporter, affectedAssetAudioImporter);
}
affectedAssetAudioImporter.userData = "";
affectedAssetAudioImporter.SaveAndReimport();
break;
case AssetType.Folder:
break;
default:
throw new ArgumentOutOfRangeException();
}
data.conforms = true;
}
private static void CopySelectiveProperties(SerializedObject affectedAssetImporterSO, SerializedObject ruleImporterSO, AssetRule assetRule)
{
foreach (string property in assetRule.SelectiveProperties)
{
string realname = GetPropertyNameFromDisplayName(affectedAssetImporterSO, property);
SerializedProperty assetRuleSP = ruleImporterSO.FindProperty(realname);
affectedAssetImporterSO.CopyFromSerializedProperty(assetRuleSP);
bool applyModifiedProperties = affectedAssetImporterSO.ApplyModifiedProperties();
if (!applyModifiedProperties) Debug.Log(" copy failed ");
}
}
public static bool HaveEqualProperties<T>(T rhs, T lhs)
{
if (rhs != null && lhs != null)
{
Type type = typeof(T);
foreach (PropertyInfo pi in type.GetProperties(
BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly))
{
object rhsValue = type.GetProperty(pi.Name).GetValue(rhs, null);
object lhsValue = type.GetProperty(pi.Name).GetValue(lhs, null);
if (!rhsValue.Equals(lhsValue))
{
return false;
}
}
}
return true;
}
public static string GetPropertyNameFromDisplayName(SerializedObject so, string displayName)
{
SerializedProperty iter = so.GetIterator();
iter.NextVisible(true);
do
{
if (iter.displayName == displayName) return iter.name;
}
while (iter.NextVisible(false)) ;
return null;
}
public static string[] GetPropertyNames(SerializedObject so)
{
SerializedProperty soIter = so.GetIterator();
List<string> propNames = new List<string>();
soIter.NextVisible(true);
do
{
propNames.Add(soIter.displayName);
} while (soIter.NextVisible(false));
return propNames.ToArray();
}
public static void CreateProxyAudio(AssetRule newRule , ref string currentAsset)
{
string audioProxy = AssetAuditorPreferences.ProxyAudioPath;
string ext = audioProxy.Substring( audioProxy.LastIndexOf( '.' ) );
string newAssetPath = AssetAuditorPreferences.ProxyAssetsDirectory + Path.DirectorySeparatorChar + newRule.RuleName + ext;
if( !AssetDatabase.CopyAsset( audioProxy, newAssetPath ) )
{
Debug.LogWarning( "Failed to copy proxy asset from " + audioProxy );
return;
}
AssetDatabase.ImportAsset(newAssetPath);
WriteUserData(newAssetPath , newRule, ref currentAsset);
}
public static void CreateProxyModel(AssetRule newRule, ref string currentAsset)
{
string modelProxy = AssetAuditorPreferences.ProxyModelPath;
string ext = modelProxy.Substring( modelProxy.LastIndexOf( '.' ) );
string newAssetPath = AssetAuditorPreferences.ProxyAssetsDirectory + Path.DirectorySeparatorChar + newRule.RuleName + ext;
if( !AssetDatabase.CopyAsset( modelProxy, newAssetPath ) )
{
Debug.LogWarning( "Failed to copy proxy asset from " + modelProxy );
return;
}
AssetDatabase.ImportAsset(newAssetPath);
WriteUserData(newAssetPath , newRule, ref currentAsset);
}
public static void CreateProxyTexture(AssetRule newRule, ref string currentAsset)
{
string textureProxy = AssetAuditorPreferences.ProxyTexturePath;
string ext = textureProxy.Substring( textureProxy.LastIndexOf( '.' ) );
string newAssetPath = AssetAuditorPreferences.ProxyAssetsDirectory + Path.DirectorySeparatorChar + newRule.RuleName + ext;
if( !AssetDatabase.CopyAsset( textureProxy, newAssetPath ) )
{
Debug.LogWarning( "Failed to copy proxy asset from " + textureProxy );
return;
}
AssetDatabase.ImportAsset(newAssetPath);
WriteUserData(newAssetPath , newRule , ref currentAsset);
}
public static void WriteUserData(string path, AssetRule assetRule, ref string currentAsset)
{
AssetImporter assetImporter = AssetImporter.GetAtPath(path);
assetRule.AssetGuid = AssetDatabase.AssetPathToGUID(assetImporter.assetPath);
assetImporter.userData = JsonUtility.ToJson(assetRule);
EditorUtility.SetDirty(assetImporter);
AssetDatabase.WriteImportSettingsIfDirty(path);
AssetDatabase.SaveAssets();
currentAsset = assetRule.AssetGuid;
}
public static void WriteUserData(string path , AssetRule assetRule)
{
AssetImporter assetImporter = AssetImporter.GetAtPath(path);
assetRule.AssetGuid = AssetDatabase.AssetPathToGUID(assetImporter.assetPath);
assetImporter.userData = JsonUtility.ToJson(assetRule);
EditorUtility.SetDirty(assetImporter);
AssetDatabase.WriteImportSettingsIfDirty(path);
AssetDatabase.SaveAssets();
}
public static bool RuleExists(AssetRule assetRule)
{
if (!AssetDatabase.IsValidFolder(AssetAuditorPreferences.ProxyAssetsDirectory))
{
string folder = AssetAuditorPreferences.ProxyAssetsDirectory.Split(Path.DirectorySeparatorChar).Last();
string dir = AssetAuditorPreferences.ProxyAssetsDirectory.Substring(0,
AssetAuditorPreferences.ProxyAssetsDirectory.Length - folder.Length);
AssetDatabase.CreateFolder(dir, folder);
}
foreach (string asset in AssetDatabase.FindAssets("", new[] {AssetAuditorPreferences.ProxyAssetsDirectory}))
{
string guidToAssetPath = AssetDatabase.GUIDToAssetPath(asset);
AssetImporter assetImporter = AssetImporter.GetAtPath(guidToAssetPath);
AssetRule ar = new AssetRule();
ar = JsonUtility.FromJson<AssetRule>(assetImporter.userData);
if (ar.RuleName == assetRule.RuleName && ar.WildCard == assetRule.WildCard &&
ar.WildCardMatchType == assetRule.WildCardMatchType) return true;
}
return false;
}
}
}
================================================
FILE: Assets/Editor/AssetAuditor/Scripts/AssetAuditor.cs.meta
================================================
fileFormatVersion: 2
guid: 75cdde80fe406b14e816e78029e38d15
timeCreated: 1481588091
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Assets/Editor/AssetAuditor/Scripts/AssetAuditorNewRuleWindow.cs
================================================
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEditor.VersionControl;
using UnityEngine;
using Object = UnityEngine.Object;
namespace UnityAssetAuditor
{
public class AssetAuditorNewRuleWindow : EditorWindow
{
private static List<AssetAuditor.AssetRule> assetRules;
private static AssetAuditor.AssetRule newRule;
private static string currentAsset;
static int selected = -1;
private static string[] affectedAssets;
private static AssetAuditorNewRuleWindow window;
private static Vector2 scrollPosition;
[MenuItem("Asset Auditing/New Audit Rule")]
public static void ShowWindow()
{
window = GetWindow<AssetAuditorNewRuleWindow>();
window.Show();
window.titleContent = new GUIContent("Asset Auditor Creation");
if (!AssetDatabase.IsValidFolder(AssetAuditorPreferences.ProxyAssetsDirectory))
{
string folder = AssetAuditorPreferences.ProxyAssetsDirectory.Split(Path.DirectorySeparatorChar).Last();
string dir = AssetAuditorPreferences.ProxyAssetsDirectory.Substring(0,
AssetAuditorPreferences.ProxyAssetsDirectory.Length - folder.Length);
AssetDatabase.CreateFolder(dir, folder);
}
UpdateExistingRules();
scrollPosition = Vector2.zero;
AssetAuditor.queueComplete += AffectedAssetSearchComplete;
}
private static void AffectedAssetSearchComplete()
{
affectedAssets = AssetAuditor.GetAffectedAssets();
window.Repaint();
AssetAuditor.queueComplete -= AffectedAssetSearchComplete;
}
void OnGUI()
{
DoNewRuleGUI();
UpdateSelectedAsset();
UpdateExistingRules();
}
private static void UpdateSelectedAsset()
{
if (selected == -1) return;
Selection.activeObject =
AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(assetRules[selected].AssetGuid),
typeof(Object));
}
private static void UpdateExistingRules()
{
// clear current list
assetRules = new List<AssetAuditor.AssetRule>();
// get all assets in the proxyassets folder
foreach (var asset in AssetDatabase.FindAssets("", new[] {AssetAuditorPreferences.ProxyAssetsDirectory}))
{
var guidToAssetPath = AssetDatabase.GUIDToAssetPath(asset);
var assetImporter = AssetImporter.GetAtPath(guidToAssetPath);
AssetAuditor.AssetRule ar = new AssetAuditor.AssetRule();
ar = JsonUtility.FromJson<AssetAuditor.AssetRule>(assetImporter.userData);
assetRules.Add(ar);
}
int i = 0;
// make sure that the current asset is selected from assetRules
foreach (var assetRule in assetRules)
{
if (assetRule.AssetGuid == currentAsset)
{
selected = i;
return;
}
i++;
}
// if we get to here we couldnt find and asset to be the currently selected
// set it to -1 and ignore anything to be currently selected
selected = -1;
currentAsset = "";
}
//done
private static void DoNewRuleGUI()
{
newRule.RuleName = EditorGUILayout.TextField("Rule Name: ", newRule.RuleName);
EditorGUI.BeginChangeCheck();
newRule.WildCardMatchType =
(AssetAuditor.WildCardMatchType) EditorGUILayout.EnumPopup("Wild Card Matching Type: ",
newRule.WildCardMatchType);
if (EditorGUI.EndChangeCheck())
{
newRule.WildCard = "";
}
EditorGUI.BeginChangeCheck();
newRule.WildCard = EditorGUILayout.TextField("Wild Card: ", newRule.WildCard);
if (EditorGUI.EndChangeCheck())
{
AssetAuditor.queueComplete += AffectedAssetSearchComplete;
AssetAuditor.UpdateAffectedAssets(newRule);
}
newRule.SelectiveMode = EditorGUILayout.Toggle("Selective Mode", newRule.SelectiveMode);
if (newRule.SelectiveMode)
{
if(newRule.SelectiveProperties == null) newRule.SelectiveProperties = new List<string>();
SerializedObject so = GetSerializedObject(newRule.assetType);
var propertyNames = AssetAuditor.GetPropertyNames(so); // TODO need to cache this
// loop through all the selective properties
for (int i = 0 ; i < newRule.SelectiveProperties.Count ; i++)
{
EditorGUILayout.BeginHorizontal();
EditorGUI.BeginChangeCheck();
newRule.SelectiveProperties[i] = propertyNames[EditorGUILayout.Popup(SelectedFromList(propertyNames , newRule.SelectiveProperties[i]), propertyNames)];
if (EditorGUI.EndChangeCheck())
{
AssetAuditor.queueComplete += AffectedAssetSearchComplete;
AssetAuditor.UpdateAffectedAssets(newRule);
}
EditorGUILayout.EndHorizontal();
}
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("+", GUILayout.MaxWidth(20)))
{
AddNewSelectiveRule();
}
if (GUILayout.Button("-", GUILayout.MaxWidth(20)))
{
RemoveLastSelectiveRule();
}
EditorGUILayout.LabelField("Add and remove selective property overiding");
EditorGUILayout.EndHorizontal();
}
// drop down for type
EditorGUI.BeginChangeCheck();
newRule.assetType = (AssetAuditor.AssetType) EditorGUILayout.IntPopup("Rule Type: ", (int)newRule.assetType, new[]{"Texture", "Model","Audio"},new[]{0,1,2} );
if (EditorGUI.EndChangeCheck())
{
newRule.SelectiveProperties = new List<string>();
AssetAuditor.queueComplete += AffectedAssetSearchComplete;
AssetAuditor.UpdateAffectedAssets(newRule);
}
if (!AssetAuditor.RuleExists(newRule))
{
if (GUILayout.Button("Create New " + newRule.assetType + " Rule"))
{
switch (newRule.assetType)
{
case AssetAuditor.AssetType.Texture:
AssetAuditor.CreateProxyTexture(newRule , ref currentAsset);
break;
case AssetAuditor.AssetType.Audio:
AssetAuditor.CreateProxyAudio(newRule , ref currentAsset);
break;
case AssetAuditor.AssetType.Model:
AssetAuditor.CreateProxyModel(newRule, ref currentAsset);
break;
default:
throw new ArgumentOutOfRangeException();
}
UpdateExistingRules();
AssetAuditor.queueComplete += AffectedAssetSearchComplete;
AssetAuditor.UpdateAffectedAssets(assetRules[selected]);
}
}
else
{
GUILayout.Label("Rule already exists in the project cannot create duplicates");
}
GUILayout.Space(20);
GUILayout.Label("Affect Assets Preview");
GUILayout.Space(5);
Rect rt = GUILayoutUtility.GetRect(5, window ? window.position.width-10 : 100f, 18, 18);
EditorGUI.ProgressBar(rt,AssetAuditor.GetProgress(), "Affected Asset Search Progress " + (AssetAuditor.GetProgress() * 100f).ToString("0.00%"));
scrollPosition = GUILayout.BeginScrollView(scrollPosition);
if (affectedAssets != null)
{
foreach (string affectedAsset in affectedAssets)
{
EditorGUILayout.ObjectField(
AssetDatabase.LoadAssetAtPath(affectedAsset,
AssetAuditor.TypeFromAssetType(newRule.assetType)),
AssetAuditor.TypeFromAssetType(newRule.assetType), false);
}
}
GUILayout.EndScrollView();
if (GUILayout.Button("Open Audit View"))
{
AssetAuditorWindow.GetWindow();
}
}
private static SerializedObject GetSerializedObject(AssetAuditor.AssetType assetType)
{
SerializedObject so = null;
switch (assetType)
{
case AssetAuditor.AssetType.Texture:
so = new SerializedObject(TextureImporter.GetAtPath(AssetAuditorPreferences.ProxyTexturePath));
break;
case AssetAuditor.AssetType.Model:
so = new SerializedObject(ModelImporter.GetAtPath(AssetAuditorPreferences.ProxyModelPath));
break;
case AssetAuditor.AssetType.Audio:
so = new SerializedObject(AudioImporter.GetAtPath(AssetAuditorPreferences.ProxyAudioPath));
break;
case AssetAuditor.AssetType.Folder:
break;
default:
throw new ArgumentOutOfRangeException();
}
return so;
}
private static int SelectedFromList(string[] propertyNames , string current)
{
if (current == "") return 0; // hack to avoid the empty string problem
int i = 0;
while (propertyNames[i] != current)
{
i++;
}
return i;
}
private static void RemoveLastSelectiveRule()
{
newRule.SelectiveProperties.RemoveAt(newRule.SelectiveProperties.Count-1);
}
private static void AddNewSelectiveRule()
{
newRule.SelectiveProperties.Add(AssetAuditor.GetPropertyNames(GetSerializedObject(newRule.assetType))[0]);
}
}
}
================================================
FILE: Assets/Editor/AssetAuditor/Scripts/AssetAuditorNewRuleWindow.cs.meta
================================================
fileFormatVersion: 2
guid: 9cfdaaf847ee42a46bd18fa749076260
timeCreated: 1479436789
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Assets/Editor/AssetAuditor/Scripts/AssetAuditorPreferences.cs
================================================
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
namespace UnityAssetAuditor
{
public class AssetAuditorPreferences
{
private static string proxyAssetDir;
private const string proxyAssetDirKey = "ProxyAssetDirectory";
private const string proxyAssetDirDefault = "Assets/Editor/AssetAuditor/ProxyAssets";
private static string proxyTexturePath;
private const string proxyTexturePathKey = "ProxyTexturePath";
private const string proxyTexturePathDefault = "Assets/Editor/AssetAuditor/Texture/DefaultTexture.jpg";
private static string proxyModelPath;
private const string proxyModelPathKey = "ProxyModelPath";
private const string proxyModelPathDefault = "Assets/Editor/AssetAuditor/Models/DefaultAvatar.fbx";
private static string proxyAudioPath;
private const string proxyAudioPathKey = "ProxyAudioPath";
private const string proxyAudioPathDefault = "Assets/Editor/AssetAuditor/Audio/DefaultAudio.wav";
static AssetAuditorPreferences()
{
proxyAssetDir = EditorPrefs.GetString( proxyAssetDirKey, proxyAssetDirDefault );
proxyTexturePath = EditorPrefs.GetString( proxyTexturePathKey, proxyTexturePathDefault );
proxyModelPath = EditorPrefs.GetString( proxyModelPathKey, proxyModelPathDefault );
proxyAudioPath = EditorPrefs.GetString( proxyAudioPathKey, proxyAudioPathDefault );
}
public static string ProxyAssetsDirectory
{
get
{
createProxyAssetsDirectory();
return proxyAssetDir;
}
}
public static string ProxyTexturePath
{
get { return proxyTexturePath; }
}
public static string ProxyModelPath
{
get { return proxyModelPath; }
}
public static string ProxyAudioPath
{
get { return proxyAudioPath; }
}
private static void createProxyAssetsDirectory()
{
if( AssetDatabase.IsValidFolder( proxyAssetDir ) )
return;
AssetAuditorUtilities.CreatePath.Create( proxyAssetDir );
}
[PreferenceItem( "Asset Auditor" )]
public static void PreferencesGUI()
{
EditorGUILayout.LabelField( "Proxy Assets Directory", EditorStyles.boldLabel );
EditorGUILayout.BeginHorizontal();
proxyAssetDir = "Assets/" + EditorGUILayout.TextField( proxyAssetDir.Remove( 0, 7 ) );
if( GUILayout.Button( "Browse", EditorStyles.miniButton ) )
{
string path = EditorUtility.OpenFolderPanel( "Select Proxy Assets Directory", proxyAssetDir, "" );
if( !path.Contains( Application.dataPath ) )
{
Debug.LogError( "Selected path " + path + " is not a directory within the open project" );
}
else if( path.Length > 0 )
{
proxyAssetDir = path.Substring( Application.dataPath.Length - 6 );
;
EditorPrefs.SetString( proxyAssetDirKey, proxyAssetDir );
}
}
EditorGUILayout.EndHorizontal();
if( AssetDatabase.IsValidFolder( proxyAssetDir ) == false )
{
EditorGUILayout.HelpBox( "Folder does not exist at given path", MessageType.Warning );
if( GUILayout.Button( "Create Now", EditorStyles.miniButton ) )
{
createProxyAssetsDirectory();
}
}
EditorGUILayout.Space();
EditorGUILayout.Space();
EditorGUILayout.LabelField( "Proxy Asset Paths", EditorStyles.boldLabel );
EditorGUILayout.Space();
EditorGUILayout.LabelField( "Texture" );
EditorGUILayout.BeginHorizontal();
proxyTexturePath = "Assets/" + EditorGUILayout.TextField( proxyTexturePath.Remove( 0, 7 ) );
if( GUILayout.Button( "Browse", EditorStyles.miniButton ) )
{
string path = EditorUtility.OpenFilePanel( "Select Proxy Texture", proxyTexturePath, "jpg,png,bmp,tga" );
if( path.Length > 0 )
{
if( !path.Contains( Application.dataPath ) )
{
Debug.LogError( "Selected path <" + path + "> is not a directory within the open project" );
}
else
{
proxyTexturePath = path.Substring( Application.dataPath.Length - 6 );
EditorPrefs.SetString( proxyTexturePathKey, proxyTexturePath );
}
}
}
EditorGUILayout.EndHorizontal();
System.Type t = AssetDatabase.GetMainAssetTypeAtPath( proxyTexturePath );
if( t == null || t != typeof(Texture2D) )
EditorGUILayout.HelpBox( "Proxy Texture does not exist at given path", MessageType.Warning );
EditorGUILayout.Space();
EditorGUILayout.LabelField( "Model" );
EditorGUILayout.BeginHorizontal();
proxyModelPath = "Assets/" + EditorGUILayout.TextField( proxyModelPath.Remove( 0, 7 ) );
if( GUILayout.Button( "Browse", EditorStyles.miniButton ) )
{
string path = EditorUtility.OpenFilePanel( "Select Proxy Model", proxyModelPath, "fbx,obj,3ds" );
if( path.Length > 0 )
{
if( !path.Contains( Application.dataPath ) )
{
Debug.LogError( "Selected path <" + path + "> is not a directory within the open project" );
}
else
{
proxyModelPath = path.Substring( Application.dataPath.Length - 6 );
EditorPrefs.SetString( proxyModelPathKey, proxyModelPath );
}
}
}
EditorGUILayout.EndHorizontal();
t = AssetDatabase.GetMainAssetTypeAtPath( proxyModelPath );
if( t == null || t != typeof(GameObject) )
EditorGUILayout.HelpBox( "Proxy Texture does not exist at given path", MessageType.Warning );
EditorGUILayout.Space();
EditorGUILayout.LabelField( "Audio" );
EditorGUILayout.BeginHorizontal();
proxyAudioPath = "Assets/" + EditorGUILayout.TextField( proxyAudioPath.Remove( 0, 7 ) );
if( GUILayout.Button( "Browse", EditorStyles.miniButton ) )
{
string path = EditorUtility.OpenFilePanel( "Select Proxy Audio", proxyAudioPath, "wav,mp3,ogg" );
if( path.Length > 0 )
{
if( !path.Contains( Application.dataPath ) )
{
Debug.LogError( "Selected path <" + path + "> is not a directory within the open project" );
}
else
{
proxyAudioPath = path.Substring( Application.dataPath.Length - 6 );
EditorPrefs.SetString( proxyAudioPathKey, proxyAudioPath );
}
}
}
EditorGUILayout.EndHorizontal();
t = AssetDatabase.GetMainAssetTypeAtPath( proxyAudioPath );
if( t == null || t != typeof(AudioClip) )
EditorGUILayout.HelpBox( "Proxy AudioClip does not exist at given path", MessageType.Warning );
}
}
}
================================================
FILE: Assets/Editor/AssetAuditor/Scripts/AssetAuditorPreferences.cs.meta
================================================
fileFormatVersion: 2
guid: 940f261582124401db9376c57e2a48c8
timeCreated: 1505468470
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Assets/Editor/AssetAuditor/Scripts/AssetAuditorUtilities.cs
================================================
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.Assertions;
namespace UnityAssetAuditor
{
public class AssetAuditorUtilities
{
public class CreatePath : IEnumerable
{
private string[] m_Folders;
public CreatePath( string path )
{
Assert.IsTrue( path.StartsWith( "Assets/" ) );
m_Folders = path.Split( '/' );
}
public CreatePath( string[] folderList )
{
Assert.IsTrue( folderList.Length > 1 && folderList[0] == "Assets" );
m_Folders = new string[folderList.Length];
for( int i = 0; i < folderList.Length; i++ )
m_Folders[i] = folderList[i];
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public CreatePathEnumerator GetEnumerator()
{
return new CreatePathEnumerator( m_Folders );
}
public static string Create( string path )
{
CreatePathEnumerator e = new CreatePathEnumerator( path );
while( e.MoveNext() )
{
// Loop through each folder
}
return e.Current;
}
}
public class CreatePathEnumerator : IEnumerator
{
private string[] m_FolderNames;
private int m_Position = 0;
private string m_CurrentGuid;
private string m_CurrentPath;
public CreatePathEnumerator( string[] folderList )
{
m_FolderNames = folderList;
m_CurrentPath = m_FolderNames[0];
}
public CreatePathEnumerator( string path )
{
Debug.Log( path );
m_FolderNames = path.Split( '/' );
m_CurrentPath = m_FolderNames[0];
}
public bool MoveNext()
{
m_Position++;
if( m_Position < m_FolderNames.Length )
{
string nextPath = m_CurrentPath + "/" + m_FolderNames[m_Position];
if( AssetDatabase.IsValidFolder( nextPath ) )
m_CurrentGuid = string.Empty;
else
m_CurrentGuid = AssetDatabase.CreateFolder( m_CurrentPath, m_FolderNames[m_Position] );
m_CurrentPath = nextPath;
return true;
}
return false;
}
public void Reset()
{
m_Position = 0;
}
object IEnumerator.Current
{
get { return Current; }
}
public string Current
{
get { return m_CurrentGuid; }
}
}
}
}
================================================
FILE: Assets/Editor/AssetAuditor/Scripts/AssetAuditorUtilities.cs.meta
================================================
fileFormatVersion: 2
guid: 5e05911aedaeb4c9e9bd82b182deab1b
timeCreated: 1529319486
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Assets/Editor/AssetAuditor/Scripts/AssetAuditorWindow.cs
================================================
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEditor.IMGUI.Controls;
using UnityEngine;
namespace UnityAssetAuditor
{
public delegate void OnGatherAssetRulesComplete();
public delegate void OnGatherDataComplete();
class AssetAuditorWindow : EditorWindow
{
[SerializeField]
static TreeViewState m_TreeViewState; // Serialized in the window layout file so it survives assembly reloading
[SerializeField] MultiColumnHeaderState m_MultiColumnHeaderState;
static AssetAuditTreeView m_TreeView;
private static List<AssetAuditor.AssetRule> assetRules;
private List<string> assetRuleNames;
private static int selected = 0;
private static int selectedSelective = 0;
private static bool editSelective;
private static int editSelectiveProp = 0;
private string[] affectedAssets;
private Action<AssetAuditTreeElement> act;
private OnGatherAssetRulesComplete onGatherAssetRulesComplete;
private OnGatherDataComplete onGatherDataComplete;
private List<AssetAuditTreeElement> elements;
private bool gatherAssetsComplete;
private bool gatherDataComplete;
private List<AssetAuditTreeElement> tempElements;
private enum State
{
Uninitialized,
GatheringRules,
GatheringData,
Initialized,
NoAssetRules
}
[NonSerialized]
private State state = State.Uninitialized;
[MenuItem("Asset Auditing/Auditor View")]
public static AssetAuditorWindow GetWindow()
{
var window = GetWindow<AssetAuditorWindow>();
window.titleContent = new GUIContent("Audit");
return window;
}
Rect multiColumnTreeViewRect
{
get { return new Rect(20, 110, position.width - 40, position.height - 130); }
}
Rect toolbarRect
{
get { return new Rect(20f, 90f, position.width - 40f, 20f); }
}
Rect bottomToolbarRect
{
get { return new Rect(20f, position.height - 18f, position.width - 40f, 16f); }
}
Rect progressBarRect
{
get { return new Rect(20f, position.height - 36f, position.width - 40f, 16f); }
}
Rect ruleSelectRect
{
get { return new Rect(20f, 10f, position.width - 40, 15); }
}
Rect wildCardDisplayRect
{
get { return new Rect(20, 30, position.width - 40f, 15f); }
}
Rect SelectivePropRect
{
get { return new Rect(20, 50, position.width - 40f, 15f); }
}
Rect AddSelectivePropRect
{
get {return new Rect(20,70,18,18);}
}
Rect RemoveSelectivePropRect
{
get { return new Rect(40,70,18,18);}
}
Rect EditSelectedPropButtonRect
{
get {return new Rect(60,70, 40,18 );}
}
Rect EditSelectedPropDropDownRect
{
get {return new Rect(110,70, 400,18 );}
}
public AssetAuditTreeView treeView
{
get { return m_TreeView; }
}
private void FixRule(AssetAuditTreeElement assetAuditTreeElement)
{
AssetAuditor.FixRule(assetAuditTreeElement , assetRules[selected]);
elements = new List<AssetAuditTreeElement>();
AssetAuditor.queueComplete += OnGatherDataComplete;
AssetAuditor.AddEnumerator(AssetAuditor.GatherData(assetRules[selected], elements , selectedSelective));
}
void GatherAssetRules()
{
gatherAssetsComplete = false;
AssetAuditor.queueComplete += OnGatherAssetRulesComplete;
assetRules = new List<AssetAuditor.AssetRule>();
assetRuleNames = new List<string>();
AssetAuditor.ClearQueue();
AssetAuditor.AddEnumerator(AssetAuditor.GatherAssetRules(assetRules,assetRuleNames));
}
private void OnGatherAssetRulesComplete()
{
AssetAuditor.queueComplete -= OnGatherAssetRulesComplete;
if (assetRules.Count > 0)
{
gatherAssetsComplete = true;
}
else
{
gatherAssetsComplete = false;
state = State.NoAssetRules;
}
}
void GatherData()
{
gatherDataComplete = false;
AssetAuditor.queueComplete += OnGatherDataComplete;
elements = new List<AssetAuditTreeElement>();
AssetAuditor.ClearQueue();
AssetAuditor.UpdateAffectedAssets(assetRules[selected]);
AssetAuditor.AddEnumerator(AssetAuditor.GatherData(assetRules[selected],elements,selectedSelective));
}
private void OnGatherDataComplete()
{
AssetAuditor.queueComplete -= OnGatherDataComplete;
// Check if it already exists (deserialized from window layout file or scriptable object)
if (m_TreeViewState == null)
m_TreeViewState = new TreeViewState();
if (m_TreeView != null && elements.Count > 0)
{
m_TreeView.treeModel.SetData(elements);
m_TreeView.Reload();
}
gatherDataComplete = true;
}
void OnSelectionChange()
{
// if (!m_Initialized)
// return;
// m_TreeView.treeModel.SetData(GetData());
// m_TreeView.Reload();
}
private void OnFocus()
{
// this doesn't seem to be needed
/*if (m_Initialized)
{
GatherAssetRules();
m_TreeView.treeModel.SetData(GetData());
m_TreeView.Reload();
}*/
}
void OnGUI()
{
switch (state)
{
case State.Uninitialized:
act = FixRule;
GatherAssetRules();
state = State.GatheringRules;
break;
case State.GatheringRules:
if (gatherAssetsComplete)
{
GatherData();
state = State.GatheringData;
}
break;
case State.GatheringData:
if (gatherDataComplete)
{
// Check if it already exists (deserialized from window layout file or scriptable object)
if (m_TreeViewState == null)
m_TreeViewState = new TreeViewState();
var headerState =
AssetAuditTreeView.CreateDefaultMultiColumnHeaderState(multiColumnTreeViewRect.width);
if (MultiColumnHeaderState.CanOverwriteSerializedFields(m_MultiColumnHeaderState, headerState))
MultiColumnHeaderState.OverwriteSerializedFields(m_MultiColumnHeaderState, headerState);
m_MultiColumnHeaderState = headerState;
var multiColumnHeader = new MultiColumnHeader(headerState);
var treeModel = new TreeModel<AssetAuditTreeElement>(elements);
m_TreeView = new AssetAuditTreeView(m_TreeViewState, multiColumnHeader, treeModel, act);
GUILayout.Label(" no asset rules have been found in the project");
state = State.Initialized;
}
break;
case State.Initialized:
DoRuleSelectionGUI();
SearchBar(toolbarRect);
DoTreeView(multiColumnTreeViewRect);
BottomToolBar(bottomToolbarRect);
break;
case State.NoAssetRules:
DoNoAssetRuleGUI();
break;
}
DoProgressBar(progressBarRect);
}
private void DoNoAssetRuleGUI()
{
GUILayout.Label(" No Asset Rules Are Present In The Project ");
if (GUILayout.Button("Search Again For Assets ")) /// TODO add directory to string for proxy asset path
{
GatherAssetRules();
state = State.GatheringRules;
}
}
private void DoProgressBar(Rect rect)
{
var progress = AssetAuditor.GetProgress();
EditorGUI.ProgressBar(progressBarRect , progress, " Search Progress " + progress.ToString("0.00%"));
}
private void DoRuleSelectionGUI()
{
EditorGUI.BeginChangeCheck();
selected = EditorGUI.Popup(ruleSelectRect, "Rule Name", selected, assetRuleNames.ToArray());
if (EditorGUI.EndChangeCheck())
{
selectedSelective = 0;
GatherData();
}
// make wildcard editable and update selection from it
if (assetRules != null && selected != -1)// && !string.IsNullOrEmpty(assetRules[selected].WildCard))
{
AssetAuditor.AssetRule ar = assetRules[selected];
EditorGUI.BeginChangeCheck();
ar.WildCard = EditorGUI.TextField(wildCardDisplayRect, "WildCard ", ar.WildCard);
if (EditorGUI.EndChangeCheck())
{
assetRules[selected] = ar;
GatherData();
AssetAuditor.WriteUserData(AssetDatabase.GUIDToAssetPath(ar.AssetGuid), ar);
}
if (ar.SelectiveProperties != null && ar.SelectiveProperties.Count > 0)
{
selectedSelective = EditorGUI.Popup(SelectivePropRect, "Selective Properties", selectedSelective, ar.SelectiveProperties.ToArray());
}
else
{
EditorGUI.LabelField(SelectivePropRect , " No Selective Properties in the Asset Rule");
}
if (GUI.Button(AddSelectivePropRect, "+"))
{
// add a new selective property
if (ar.SelectiveProperties != null && !ar.SelectiveProperties.Contains("Unnasigned property")) ar.SelectiveProperties.Add("Unnasigned property");
assetRules[selected] = ar;
GatherData();
AssetAuditor.WriteUserData(AssetDatabase.GUIDToAssetPath(ar.AssetGuid), ar);
}
if (ar.SelectiveProperties != null && ar.SelectiveProperties.Count > 0)
{
if (GUI.Button(RemoveSelectivePropRect, "-"))
{
// remove last selective property
ar.SelectiveProperties.RemoveAt(ar.SelectiveProperties.Count - 1);
if (ar.SelectiveProperties.Count == 0)
ar.SelectiveMode = false;
assetRules[selected] = ar;
GatherData();
AssetAuditor.WriteUserData(AssetDatabase.GUIDToAssetPath(ar.AssetGuid), ar);
}
editSelective = GUI.Toggle(EditSelectedPropButtonRect, editSelective, "Edit", "Button");
if (editSelective)
{
SerializedObject so = new SerializedObject(
AssetImporter.GetAtPath(AssetDatabase.GUIDToAssetPath(ar.AssetGuid)));
EditorGUI.BeginChangeCheck();
editSelectiveProp = EditorGUI.Popup(EditSelectedPropDropDownRect, editSelectiveProp,
AssetAuditor.GetPropertyNames(so));
if (EditorGUI.EndChangeCheck())
{
ar.SelectiveProperties[selectedSelective] =
AssetAuditor.GetPropertyNames(so)[editSelectiveProp];
assetRules[selected] = ar;
GatherData();
AssetAuditor.WriteUserData(AssetDatabase.GUIDToAssetPath(ar.AssetGuid), ar);
}
}
}
}
}
void SearchBar(Rect rect)
{
if(treeView != null)
treeView.searchString = SearchField.OnGUI(rect, treeView.searchString);
}
void DoTreeView(Rect rect)
{
if(m_TreeView != null)
m_TreeView.OnGUI(rect);
}
void BottomToolBar(Rect rect)
{
var style = "miniButton";
if (GUI.Button(new Rect(rect.x, rect.y, rect.width / 3, rect.height), "Expand All", style))
{
treeView.ExpandAll();
}
if (GUI.Button(new Rect(rect.x + rect.width / 3, rect.y, rect.width / 3, rect.height), "Collapse All",
style))
{
treeView.CollapseAll();
}
if (GUI.Button(new Rect(rect.x + ((rect.width / 3) * 2), rect.y, rect.width / 3, rect.height), "Fix All",
style))
{
AssetAuditor.AddEnumerator(AssetAuditor.FixAll(m_TreeView , assetRules[selected]));
}
}
}
internal static class SearchField
{
static class Styles
{
public static GUIStyle searchField = "SearchTextField";
public static GUIStyle searchFieldCancelButton = "SearchCancelButton";
public static GUIStyle searchFieldCancelButtonEmpty = "SearchCancelButtonEmpty";
}
public static string OnGUI(Rect position, string text)
{
// Search field
Rect textRect = position;
textRect.width -= 15;
text = EditorGUI.TextField(textRect, GUIContent.none, text, Styles.searchField);
// Cancel button
Rect buttonRect = position;
buttonRect.x += position.width - 15;
buttonRect.width = 15;
if (GUI.Button(buttonRect, GUIContent.none,
text != "" ? Styles.searchFieldCancelButton : Styles.searchFieldCancelButtonEmpty) && text != "")
{
text = "";
GUIUtility.keyboardControl = 0;
}
return text;
}
}
}
================================================
FILE: Assets/Editor/AssetAuditor/Scripts/AssetAuditorWindow.cs.meta
================================================
fileFormatVersion: 2
guid: c3cf55b48c197bb40a09696dead1d7c2
timeCreated: 1467106475
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Assets/Editor/AssetAuditor/Scripts/TreeElement.cs
================================================
using System;
using System.Collections.Generic;
using UnityEngine;
namespace UnityAssetAuditor
{
[Serializable]
public class TreeElement
{
[SerializeField] int m_ID;
[SerializeField] string m_Name;
[SerializeField] int m_Depth;
[NonSerialized] TreeElement m_Parent;
[NonSerialized] List<TreeElement> m_Children;
public int depth
{
get { return m_Depth; }
set { m_Depth = value; }
}
public TreeElement parent
{
get { return m_Parent; }
set { m_Parent = value; }
}
public List<TreeElement> children
{
get { return m_Children; }
set { m_Children = value; }
}
public bool hasChildren
{
get { return children != null && children.Count > 0; }
}
public string name
{
get { return m_Name; } set { m_Name = value; }
}
public int id
{
get { return m_ID; } set { m_ID = value; }
}
public TreeElement ()
{
}
public TreeElement (string name, int depth, int id)
{
m_Name = name;
m_ID = id;
m_Depth = depth;
}
}
}
================================================
FILE: Assets/Editor/AssetAuditor/Scripts/TreeElement.cs.meta
================================================
fileFormatVersion: 2
guid: 69be32fe4d27dde489209c5885c1e5dc
timeCreated: 1472024155
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Assets/Editor/AssetAuditor/Scripts/TreeElementUtility.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using UnityEditor;
namespace UnityAssetAuditor
{
// TreeElementUtility and TreeElement are useful helper classes for backend tree data structures.
// See tests at the bottom for examples of how to use.
public static class TreeElementUtility
{
public static void TreeToList<T>(T root, IList<T> result) where T : TreeElement
{
if (result == null)
throw new NullReferenceException("The input 'IList<T> result' list is null");
result.Clear();
Stack<T> stack = new Stack<T>();
stack.Push(root);
while (stack.Count > 0)
{
T current = stack.Pop();
result.Add(current);
if (current.children != null && current.children.Count > 0)
{
for (int i = current.children.Count - 1; i >= 0; i--)
{
stack.Push((T)current.children[i]);
}
}
}
}
// Returns the root of the tree parsed from the list (always the first element).
// Important: the first item and is required to have a depth value of -1.
// The rest of the items should have depth >= 0.
public static T ListToTree<T>(IList<T> list) where T : TreeElement
{
// Validate input
ValidateDepthValues (list);
// Clear old states
foreach (var element in list)
{
element.parent = null;
element.children = null;
}
// Set child and parent references using depth info
for (int parentIndex = 0; parentIndex < list.Count; parentIndex++)
{
var parent = list[parentIndex];
bool alreadyHasValidChildren = parent.children != null;
if (alreadyHasValidChildren)
continue;
int parentDepth = parent.depth;
int childCount = 0;
// Count children based depth value, we are looking at children until it's the same depth as this object
for (int i = parentIndex + 1; i < list.Count; i++)
{
if (list[i].depth == parentDepth + 1)
childCount++;
if (list[i].depth <= parentDepth)
break;
}
// Fill child array
List<TreeElement> childList = null;
if (childCount != 0)
{
childList = new List<TreeElement>(childCount); // Allocate once
childCount = 0;
for (int i = parentIndex + 1; i < list.Count; i++)
{
if (list[i].depth == parentDepth + 1)
{
list[i].parent = parent;
childList.Add(list[i]);
childCount++;
}
if (list[i].depth <= parentDepth)
break;
}
}
parent.children = childList;
}
return list[0];
}
// Check state of input list
public static void ValidateDepthValues<T>(IList<T> list) where T : TreeElement
{
if (list.Count == 0)
throw new ArgumentException("list should have items, count is 0, check before calling ValidateDepthValues", "list");
if (list[0].depth != -1)
throw new ArgumentException("list item at index 0 should have a depth of -1 (since this should be the hidden root of the tree). Depth is: " + list[0].depth, "list");
for (int i = 0; i < list.Count - 1; i++)
{
int depth = list[i].depth;
int nextDepth = list[i + 1].depth;
if (nextDepth > depth && nextDepth - depth > 1)
throw new ArgumentException(string.Format("Invalid depth info in input list. Depth cannot increase more than 1 per row. Index {0} has depth {1} while index {2} has depth {3}", i, depth, i + 1, nextDepth));
}
for (int i = 1; i < list.Count; ++i)
if (list[i].depth < 0)
throw new ArgumentException("Invalid depth value for item at index " + i + ". Only the first item (the root) should have depth below 0.");
if (list.Count > 1 && list[1].depth != 0)
throw new ArgumentException("Input list item at index 1 is assumed to have a depth of 0", "list");
}
// For updating depth values below any given element e.g after reparenting elements
public static void UpdateDepthValues<T>(T root) where T : TreeElement
{
if (root == null)
throw new ArgumentNullException("root", "The root is null");
if (!root.hasChildren)
return;
Stack<TreeElement> stack = new Stack<TreeElement>();
stack.Push(root);
while (stack.Count > 0)
{
TreeElement current = stack.Pop();
if (current.children != null)
{
foreach (var child in current.children)
{
child.depth = current.depth + 1;
stack.Push(child);
}
}
}
}
// Returns true if there is an ancestor of child in the elements list
static bool IsChildOf<T>(T child, IList<T> elements) where T : TreeElement
{
while (child != null)
{
child = (T)child.parent;
if (elements.Contains(child))
return true;
}
return false;
}
public static IList<T> FindCommonAncestorsWithinList<T>(IList<T> elements) where T : TreeElement
{
if (elements.Count == 1)
return new List<T>(elements);
List<T> result = new List<T>(elements);
result.RemoveAll(g => IsChildOf(g, elements));
return result;
}
}
class TreeElementUtilityTests
{
class TestElement : TreeElement
{
public TestElement (string name, int depth)
{
this.name = name;
this.depth = depth;
}
}
#region Tests
[Test]
public static void TestTreeToListWorks()
{
// Arrange
TestElement root = new TestElement("root", -1);
root.children = new List<TreeElement>();
root.children.Add(new TestElement("A", 0));
root.children.Add(new TestElement("B", 0));
root.children.Add(new TestElement("C", 0));
root.children[1].children = new List<TreeElement>();
root.children[1].children.Add(new TestElement("Bchild", 1));
root.children[1].children[0].children = new List<TreeElement>();
root.children[1].children[0].children.Add(new TestElement("Bchildchild", 2));
// Test
List<TestElement> result = new List<TestElement>();
TreeElementUtility.TreeToList(root, result);
// Assert
string[] namesInCorrectOrder = { "root", "A", "B", "Bchild", "Bchildchild", "C" };
Assert.AreEqual(namesInCorrectOrder.Length, result.Count, "Result count is not match");
for (int i = 0; i < namesInCorrectOrder.Length; ++i)
{
Assert.AreEqual(namesInCorrectOrder[i], result[i].name);
}
TreeElementUtility.ValidateDepthValues(result);
}
[Test]
public static void TestListToTreeWorks()
{
// Arrange
var list = new List<TestElement>();
list.Add(new TestElement("root", -1));
list.Add(new TestElement("A", 0));
list.Add(new TestElement("B", 0));
list.Add(new TestElement("Bchild", 1));
list.Add(new TestElement("Bchildchild", 2));
list.Add(new TestElement("C", 0));
// Test
TestElement root = TreeElementUtility.ListToTree(list);
// Assert
Assert.AreEqual("root", root.name);
Assert.AreEqual(3, root.children.Count);
Assert.AreEqual("C", root.children[2].name);
Assert.AreEqual("Bchildchild", root.children[1].children[0].children[0].name);
}
[Test]
public static void TestListToTreeThrowsExceptionIfRootIsInvalidDepth()
{
// Arrange
var list = new List<TestElement>();
list.Add(new TestElement("root", 0));
list.Add(new TestElement("A", 1));
list.Add(new TestElement("B", 1));
list.Add(new TestElement("Bchild", 2));
// Test
bool catchedException = false;
try
{
TreeElementUtility.ListToTree(list);
}
catch (Exception)
{
catchedException = true;
}
// Assert
Assert.IsTrue(catchedException, "We require the root.depth to be -1, here it is: " + list[0].depth);
}
[Test]
public static void FindCommonAncestorsWithinListWorks()
{
// Arrange
var list = new List<TestElement>();
list.Add(new TestElement("root", -1));
list.Add(new TestElement("A", 0));
var b0 = new TestElement("B", 0);
var b1 = new TestElement("Bchild", 1);
var b2 = new TestElement("Bchildchild", 2);
list.Add(b0);
list.Add(b1);
list.Add(b2);
var c0 = new TestElement ("C", 0);
list.Add(c0);
var f0 = new TestElement("F", 0);
var f1 = new TestElement("Fchild", 1);
var f2 = new TestElement("Fchildchild", 2);
list.Add(f0);
list.Add(f1);
list.Add(f2);
// Init tree structure: set children and parent properties
TreeElementUtility.ListToTree(list);
// Single element
TestElement[] input = {b1};
TestElement[] expectedResult = {b1};
var result = TreeElementUtility.FindCommonAncestorsWithinList(input).ToArray();
Assert.IsTrue(ArrayUtility.ArrayEquals(expectedResult, result), "Single input should return single output");
// Single sub tree
input = new[] {b1, b2};
expectedResult = new[] {b1};
result = TreeElementUtility.FindCommonAncestorsWithinList (input).ToArray ();
Assert.IsTrue(ArrayUtility.ArrayEquals(expectedResult, result), "Common ancestor should only be b1 ");
// Multiple sub trees
input = new[] { b0, b2, f0, f2, c0 };
expectedResult = new[] { b0, f0, c0 };
result = TreeElementUtility.FindCommonAncestorsWithinList(input).ToArray();
Assert.IsTrue(ArrayUtility.ArrayEquals(expectedResult, result), "Common ancestor should only be b0, f0, c0");
}
#endregion
}
}
================================================
FILE: Assets/Editor/AssetAuditor/Scripts/TreeElementUtility.cs.meta
================================================
fileFormatVersion: 2
guid: fd65e8f324e17a344a97ddcf5a8d89d2
timeCreated: 1471616285
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Assets/Editor/AssetAuditor/Scripts/TreeModel.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
namespace UnityAssetAuditor
{
// The TreeModel is a utility class working on a list of serializable TreeElements where the order and the depth of each TreeElement define
// the tree structure. Note that the TreeModel itself is not serializable (in Unity we are currently limited to serializing lists/arrays) but the
// input list is.
// The tree representation (parent and children references) are then build internally using TreeElementUtility.ListToTree (using depth
// values of the elements).
// The first element of the input list is required to have depth == -1 (the hiddenroot) and the rest to have
// depth >= 0 (otherwise an exception will be thrown)
public class TreeModel<T> where T : TreeElement
{
IList<T> m_Data;
T m_Root;
int m_MaxID;
public T root { get { return m_Root; } set { m_Root = value; } }
public event Action modelChanged;
public int numberOfDataElements
{
get { return m_Data.Count; }
}
public TreeModel (IList<T> data)
{
SetData (data);
}
public T Find (int id)
{
return m_Data.FirstOrDefault (element => element.id == id);
}
public void SetData (IList<T> data)
{
Init (data);
}
void Init (IList<T> data)
{
if (data == null)
throw new ArgumentNullException("data", "Input data is null. Ensure input is a non-null list.");
m_Data = data;
if (m_Data.Count > 0)
m_Root = TreeElementUtility.ListToTree(data);
m_MaxID = m_Data.Max(e => e.id);
}
public int GenerateUniqueID ()
{
return ++m_MaxID;
}
public IList<int> GetAncestors (int id)
{
var parents = new List<int>();
TreeElement T = Find(id);
if (T != null)
{
while (T.parent != null)
{
parents.Add(T.parent.id);
T = T.parent;
}
}
return parents;
}
public IList<int> GetDescendantsThatHaveChildren (int id)
{
T searchFromThis = Find(id);
if (searchFromThis != null)
{
return GetParentsBelowStackBased(searchFromThis);
}
return new List<int>();
}
IList<int> GetParentsBelowStackBased(TreeElement searchFromThis)
{
Stack<TreeElement> stack = new Stack<TreeElement>();
stack.Push(searchFromThis);
var parentsBelow = new List<int>();
while (stack.Count > 0)
{
TreeElement current = stack.Pop();
if (current.hasChildren)
{
parentsBelow.Add(current.id);
foreach (var T in current.children)
{
stack.Push(T);
}
}
}
return parentsBelow;
}
public void RemoveElements (IList<int> elementIDs)
{
IList<T> elements = m_Data.Where (element => elementIDs.Contains (element.id)).ToArray ();
RemoveElements (elements);
}
public void RemoveElements (IList<T> elements)
{
foreach (var element in elements)
if (element == m_Root)
throw new ArgumentException("It is not allowed to remove the root element");
var commonAncestors = TreeElementUtility.FindCommonAncestorsWithinList (elements);
foreach (var element in commonAncestors)
{
element.parent.children.Remove (element);
element.parent = null;
}
TreeElementUtility.TreeToList(m_Root, m_Data);
Changed();
}
public void AddElements (IList<T> elements, TreeElement parent, int insertPosition)
{
if (elements == null)
throw new ArgumentNullException("elements", "elements is null");
if (elements.Count == 0)
throw new ArgumentNullException("elements", "elements Count is 0: nothing to add");
if (parent == null)
throw new ArgumentNullException("parent", "parent is null");
if (parent.children == null)
parent.children = new List<TreeElement>();
parent.children.InsertRange(insertPosition, elements.Cast<TreeElement> ());
foreach (var element in elements)
{
element.parent = parent;
element.depth = parent.depth + 1;
TreeElementUtility.UpdateDepthValues(element);
}
TreeElementUtility.TreeToList(m_Root, m_Data);
Changed();
}
public void AddRoot (T root)
{
if (root == null)
throw new ArgumentNullException("root", "root is null");
if (m_Data == null)
throw new InvalidOperationException("Internal Error: data list is null");
if (m_Data.Count != 0)
throw new InvalidOperationException("AddRoot is only allowed on empty data list");
root.id = GenerateUniqueID ();
root.depth = -1;
m_Data.Add (root);
}
public void AddElement (T element, TreeElement parent, int insertPosition)
{
if (element == null)
throw new ArgumentNullException("element", "element is null");
if (parent == null)
throw new ArgumentNullException("parent", "parent is null");
if (parent.children == null)
parent.children = new List<TreeElement> ();
parent.children.Insert (insertPosition, element);
element.parent = parent;
TreeElementUtility.UpdateDepthValues(parent);
TreeElementUtility.TreeToList(m_Root, m_Data);
Changed ();
}
public void MoveElements(TreeElement parentElement, int insertionIndex, List<TreeElement> elements)
{
if (insertionIndex < 0)
throw new ArgumentException("Invalid input: insertionIndex is -1, client needs to decide what index elements should be reparented at");
// Invalid reparenting input
if (parentElement == null)
return;
// We are moving items so we adjust the insertion index to accomodate that any items above the insertion index is removed before inserting
if (insertionIndex > 0)
insertionIndex -= parentElement.children.GetRange(0, insertionIndex).Count(elements.Contains);
// Remove draggedItems from their parents
foreach (var draggedItem in elements)
{
draggedItem.parent.children.Remove(draggedItem); // remove from old parent
draggedItem.parent = parentElement; // set new parent
}
if (parentElement.children == null)
parentElement.children = new List<TreeElement>();
// Insert dragged items under new parent
parentElement.children.InsertRange(insertionIndex, elements);
TreeElementUtility.UpdateDepthValues (root);
TreeElementUtility.TreeToList (m_Root, m_Data);
Changed ();
}
void Changed ()
{
if (modelChanged != null)
modelChanged ();
}
}
#region Tests
class TreeModelTests
{
[Test]
public static void TestTreeModelCanAddElements()
{
var root = new TreeElement {name = "Root", depth = -1};
var listOfElements = new List<TreeElement>();
listOfElements.Add(root);
var model = new TreeModel<TreeElement>(listOfElements);
model.AddElement(new TreeElement { name = "Element" }, root, 0);
model.AddElement(new TreeElement { name = "Element " + root.children.Count }, root, 0);
model.AddElement(new TreeElement { name = "Element " + root.children.Count }, root, 0);
model.AddElement(new TreeElement { name = "Sub Element" }, root.children[1], 0);
// Assert order is correct
string[] namesInCorrectOrder = { "Root", "Element 2", "Element 1", "Sub Element", "Element" };
Assert.AreEqual(namesInCorrectOrder.Length, listOfElements.Count, "Result count does not match");
for (int i = 0; i < namesInCorrectOrder.Length; ++i)
Assert.AreEqual(namesInCorrectOrder[i], listOfElements[i].name);
// Assert depths are valid
TreeElementUtility.ValidateDepthValues(listOfElements);
}
[Test]
public static void TestTreeModelCanRemoveElements()
{
var root = new TreeElement { name = "Root", depth = -1 };
var listOfElements = new List<TreeElement>();
listOfElements.Add(root);
var model = new TreeModel<TreeElement>(listOfElements);
model.AddElement(new TreeElement { name = "Element" }, root, 0);
model.AddElement(new TreeElement { name = "Element " + root.children.Count }, root, 0);
model.AddElement(new TreeElement { name = "Element " + root.children.Count }, root, 0);
model.AddElement(new TreeElement { name = "Sub Element" }, root.children[1], 0);
model.RemoveElements(new[] { root.children[1].children[0], root.children[1] });
// Assert order is correct
string[] namesInCorrectOrder = { "Root", "Element 2", "Element" };
Assert.AreEqual(namesInCorrectOrder.Length, listOfElements.Count, "Result count does not match");
for (int i = 0; i < namesInCorrectOrder.Length; ++i)
Assert.AreEqual(namesInCorrectOrder[i], listOfElements[i].name);
// Assert depths are valid
TreeElementUtility.ValidateDepthValues(listOfElements);
}
}
#endregion
}
================================================
FILE: Assets/Editor/AssetAuditor/Scripts/TreeModel.cs.meta
================================================
fileFormatVersion: 2
guid: 6f9fab1cf2636a6439c644bf08108abb
timeCreated: 1472122507
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Assets/Editor/AssetAuditor/Scripts/TreeViewWithTreeModel.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEditor.IMGUI.Controls;
using UnityEngine;
namespace UnityAssetAuditor
{
internal class TreeViewItem<T> : TreeViewItem where T : TreeElement
{
public T data { get; set; }
public TreeViewItem (int id, int depth, string displayName, T data) : base (id, depth, displayName)
{
this.data = data;
}
}
public class TreeViewWithTreeModel<T> : TreeView where T : TreeElement
{
TreeModel<T> m_TreeModel;
readonly List<TreeViewItem> m_Rows = new List<TreeViewItem>(100);
public event Action treeChanged;
public TreeModel<T> treeModel { get { return m_TreeModel; } }
public event Action<IList<TreeViewItem>> beforeDroppingDraggedItems;
public TreeViewWithTreeModel (TreeViewState state, TreeModel<T> model) : base (state)
{
Init (model);
}
public TreeViewWithTreeModel (TreeViewState state, MultiColumnHeader multiColumnHeader, TreeModel<T> model)
: base(state, multiColumnHeader)
{
Init (model);
}
void Init (TreeModel<T> model)
{
m_TreeModel = model;
m_TreeModel.modelChanged += ModelChanged;
}
void ModelChanged ()
{
if (treeChanged != null)
treeChanged ();
Reload ();
}
protected override TreeViewItem BuildRoot()
{
int depthForHiddenRoot = -1;
return new TreeViewItem(m_TreeModel.root.id, depthForHiddenRoot, m_TreeModel.root.name);
}
protected override IList<TreeViewItem> BuildRows (TreeViewItem root)
{
if (m_TreeModel.root == null)
{
Debug.LogError ("tree model root is null. did you call SetData()?");
}
m_Rows.Clear ();
if (!string.IsNullOrEmpty(searchString))
{
Search (m_TreeModel.root, searchString, m_Rows);
}
else
{
if (m_TreeModel.root.hasChildren)
AddChildrenRecursive(m_TreeModel.root, 0, m_Rows);
}
// We still need to setup the child parent information for the rows since this
// information is used by the TreeView internal logic (navigation, dragging etc)
SetupParentsAndChildrenFromDepths (root, m_Rows);
return m_Rows;
}
void AddChildrenRecursive (T parent, int depth, IList<TreeViewItem> newRows)
{
foreach (T child in parent.children)
{
var item = new TreeViewItem<T>(child.id, depth, child.name, child);
newRows.Add(item);
if (child.hasChildren)
{
if (IsExpanded(child.id))
{
AddChildrenRecursive (child, depth + 1, newRows);
}
else
{
item.children = CreateChildListForCollapsedParent();
}
}
}
}
void Search(T searchFromThis, string search, List<TreeViewItem> result)
{
if (string.IsNullOrEmpty(search))
throw new ArgumentException("Invalid search: cannot be null or empty", "search");
const int kItemDepth = 0; // tree is flattened when searching
Stack<T> stack = new Stack<T>();
foreach (var element in searchFromThis.children)
stack.Push((T)element);
while (stack.Count > 0)
{
T current = stack.Pop();
// Matches search?
if (current.name.IndexOf(search, StringComparison.OrdinalIgnoreCase) >= 0)
{
result.Add(new TreeViewItem<T>(current.id, kItemDepth, current.name, current));
}
if (current.children != null && current.children.Count > 0)
{
foreach (var element in current.children)
{
stack.Push((T)element);
}
}
}
SortSearchResult(result);
}
protected virtual void SortSearchResult (List<TreeViewItem> rows)
{
rows.Sort (); // sort by displayName by default, can be overriden for multicolumn solutions
}
protected override IList<int> GetAncestors (int id)
{
return m_TreeModel.GetAncestors(id);
}
protected override IList<int> GetDescendantsThatHaveChildren (int id)
{
return m_TreeModel.GetDescendantsThatHaveChildren(id);
}
// Dragging
//-----------
const string k_GenericDragID = "GenericDragColumnDragging";
protected override bool CanStartDrag (CanStartDragArgs args)
{
return true;
}
protected override void SetupDragAndDrop(SetupDragAndDropArgs args)
{
if (hasSearch)
return;
DragAndDrop.PrepareStartDrag();
var draggedRows = GetRows().Where(item => args.draggedItemIDs.Contains(item.id)).ToList();
DragAndDrop.SetGenericData(k_GenericDragID, draggedRows);
DragAndDrop.objectReferences = new UnityEngine.Object[] { }; // this IS required for dragging to work
string title = draggedRows.Count == 1 ? draggedRows[0].displayName : "< Multiple >";
DragAndDrop.StartDrag (title);
}
protected override DragAndDropVisualMode HandleDragAndDrop (DragAndDropArgs args)
{
// Check if we can handle the current drag data (could be dragged in from other areas/windows in the editor)
var draggedRows = DragAndDrop.GetGenericData(k_GenericDragID) as List<TreeViewItem>;
if (draggedRows == null)
return DragAndDropVisualMode.None;
// Parent item is null when dragging outside any tree view items.
switch (args.dragAndDropPosition)
{
case DragAndDropPosition.UponItem:
case DragAndDropPosition.BetweenItems:
{
bool validDrag = ValidDrag(args.parentItem, draggedRows);
if (args.performDrop && validDrag)
{
T parentData = ((TreeViewItem<T>)args.parentItem).data;
OnDropDraggedElementsAtIndex(draggedRows, parentData, args.insertAtIndex == -1 ? 0 : args.insertAtIndex);
}
return validDrag ? DragAndDropVisualMode.Move : DragAndDropVisualMode.None;
}
case DragAndDropPosition.OutsideItems:
{
if (args.performDrop)
OnDropDraggedElementsAtIndex(draggedRows, m_TreeModel.root, m_TreeModel.root.children.Count);
return DragAndDropVisualMode.Move;
}
default:
Debug.LogError("Unhandled enum " + args.dragAndDropPosition);
return DragAndDropVisualMode.None;
}
}
public virtual void OnDropDraggedElementsAtIndex (List<TreeViewItem> draggedRows, T parent, int insertIndex)
{
if (beforeDroppingDraggedItems != null)
beforeDroppingDraggedItems (draggedRows);
var draggedElements = new List<TreeElement> ();
foreach (var x in draggedRows)
draggedElements.Add (((TreeViewItem<T>) x).data);
var selectedIDs = draggedElements.Select (x => x.id).ToArray();
m_TreeModel.MoveElements (parent, insertIndex, draggedElements);
SetSelection(selectedIDs, TreeViewSelectionOptions.RevealAndFrame);
}
bool ValidDrag(TreeViewItem parent, List<TreeViewItem> draggedItems)
{
TreeViewItem currentParent = parent;
while (currentParent != null)
{
if (draggedItems.Contains(currentParent))
return false;
currentParent = currentParent.parent;
}
return true;
}
}
}
================================================
FILE: Assets/Editor/AssetAuditor/Scripts/TreeViewWithTreeModel.cs.meta
================================================
fileFormatVersion: 2
guid: 68fe63fd42552e7418aac450b41b8afb
timeCreated: 1472481611
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Assets/Editor/AssetAuditor/Scripts.meta
================================================
fileFormatVersion: 2
guid: d8004df83cf28884ab8e34a091ddd853
folderAsset: yes
timeCreated: 1481588073
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Assets/Editor/AssetAuditor/Texture/DefaultTexture.jpg.meta
================================================
fileFormatVersion: 2
guid: e762cc062d5c5411a9264437e5c9c09e
timeCreated: 1502701589
licenseType: Pro
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -1
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
spritePackingTag:
userData: '{"RuleName":"nromalmaps","WildCardMatchType":0,"WildCard":"nrm","AssetGuid":"0bc6347fd6d584af3ab1a06182982dad","assetType":0}'
assetBundleName:
assetBundleVariant:
================================================
FILE: Assets/Editor/AssetAuditor/Texture.meta
================================================
fileFormatVersion: 2
guid: 2e33a099c182b4826a46f527b242a2cd
folderAsset: yes
timeCreated: 1502705399
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Assets/Editor/AssetAuditor.meta
================================================
fileFormatVersion: 2
guid: 36d6f139a16b47a469947e0afd23b31d
folderAsset: yes
timeCreated: 1479437964
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: Assets/Editor.meta
================================================
fileFormatVersion: 2
guid: fa69737d10241b54391c55189b99b9c6
folderAsset: yes
timeCreated: 1440440842
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:
================================================
FILE: LICENSE
================================================
MIT X11
Copyright (C) 2017 Unity Technologies ApS
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL UNITY TECHNOLOGIES APS OR ANY OF ITS AFFILIATES (“UNITY”) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the “Unity” name/mark shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Unity.
================================================
FILE: README.md
================================================
# Asset Auditor
The asset auditor tool is designed to allow you to create sets of rules for the import settings for your assets in a Unity project and fix any assets that do not comply to those rules.
#### The new audit rule window.
This window allows you to create a new rule for you assets.
**Rule Name** - The first step is to give the rule a name. This can be whatever you desire it to be and will be name given to the proxy/dummy asset stored in the project. The reason for using a proxy/dummy assets is to provide a full inspector for the asset so that you modify the settings properties in a familiar manner to modify any other asset in
your project.
**Wild Card Matching Type** - The wild card matching type has two options.
**Name Contains** - Name contains works by matching the providing string to any of the asset names in the project that are of the same asset type as the asset rule. So If you set the name contains string to "nrm" on texture based rule. Any texture asset that has nrm in the name will be found by the rule when inspecting in audit view.
**Regex** - This work the same as name contains but uses full regex pattern matching. N.B. This is C# regex so there is no need for start and end /
**Wild Card** - This is the string that is used in the Wild Card Matching Type for finding assets that the rule should effect.
**Selective Mode** - This lets you create a rule that will only overwrite certain settings from a drop down The drop down enabling selective mode creates allows you to add as many selective element as you like and selectwhich rules you would like to override from it.
**Rule Type** - This determines what assets the rule should affect. Currently there are three supported asset types. Texture, for all your imported textures, Model, for all your imported models and Audio for the imported audio files.
During the creation of the rule new audit rule window will display a list of the assets that will be found by that rule so you can preview your results.
#### Audit View
The audit view allows you to see the assets that the rule wild card will cover and apply the desired import settings to if desired. It also allows for modification of the wildcard property in case of naming convention changes.
**Rule** - this is a drop down list of the available rules in the project.
**Wild Card** - This can be used to modify the wild card that has been supplied to original rule.
**Selective** - A drop down showing the properties that will be overriden.
**Search bar** - This allows for searching of the the assets that are in the tree view.
**Tree view** - This shows the subset of the project view that contains the assets that the rule has found through its search based on the wild card and wild card matching type.
**Tool Bar** - This contains three options
**Expand all** - This expands every element in the tree view
**Collapse all** - This collapses the entire tree view
**Fix all**- This fixes every asset that has been found to not match rules import settings.
## In Development
Improvements to selective mode.
UI improvements.
Folder level overrides.
gitextract_7qfqj2k7/ ├── .gitattributes ├── .gitignore ├── Assets/ │ ├── Editor/ │ │ ├── AssetAuditor/ │ │ │ ├── Audio/ │ │ │ │ └── DefaultAudio.wav.meta │ │ │ ├── Audio.meta │ │ │ ├── Models/ │ │ │ │ ├── DefaultAvatar.fbx │ │ │ │ └── DefaultAvatar.fbx.meta │ │ │ ├── Models.meta │ │ │ ├── Scripts/ │ │ │ │ ├── AssetAuditTreeElement.cs │ │ │ │ ├── AssetAuditTreeElement.cs.meta │ │ │ │ ├── AssetAuditTreeView.cs │ │ │ │ ├── AssetAuditTreeView.cs.meta │ │ │ │ ├── AssetAuditor.cs │ │ │ │ ├── AssetAuditor.cs.meta │ │ │ │ ├── AssetAuditorNewRuleWindow.cs │ │ │ │ ├── AssetAuditorNewRuleWindow.cs.meta │ │ │ │ ├── AssetAuditorPreferences.cs │ │ │ │ ├── AssetAuditorPreferences.cs.meta │ │ │ │ ├── AssetAuditorUtilities.cs │ │ │ │ ├── AssetAuditorUtilities.cs.meta │ │ │ │ ├── AssetAuditorWindow.cs │ │ │ │ ├── AssetAuditorWindow.cs.meta │ │ │ │ ├── TreeElement.cs │ │ │ │ ├── TreeElement.cs.meta │ │ │ │ ├── TreeElementUtility.cs │ │ │ │ ├── TreeElementUtility.cs.meta │ │ │ │ ├── TreeModel.cs │ │ │ │ ├── TreeModel.cs.meta │ │ │ │ ├── TreeViewWithTreeModel.cs │ │ │ │ └── TreeViewWithTreeModel.cs.meta │ │ │ ├── Scripts.meta │ │ │ ├── Texture/ │ │ │ │ └── DefaultTexture.jpg.meta │ │ │ └── Texture.meta │ │ └── AssetAuditor.meta │ └── Editor.meta ├── LICENSE └── README.md
SYMBOL INDEX (145 symbols across 11 files)
FILE: Assets/Editor/AssetAuditor/Scripts/AssetAuditTreeElement.cs
class AssetAuditTreeElement (line 5) | [Serializable]
type AssetType (line 12) | internal enum AssetType
method AssetAuditTreeElement (line 20) | public AssetAuditTreeElement (string name,string _projectPath, int dep...
FILE: Assets/Editor/AssetAuditor/Scripts/AssetAuditTreeView.cs
class AssetAuditTreeView (line 11) | public class AssetAuditTreeView : TreeViewWithTreeModel<AssetAuditTreeEl...
type MyColumns (line 19) | enum MyColumns
method TreeToList (line 26) | public static void TreeToList(TreeViewItem root, IList<TreeViewItem> r...
method AssetAuditTreeView (line 57) | public AssetAuditTreeView(TreeViewState state, MultiColumnHeader multi...
method BuildRows (line 74) | protected override IList<TreeViewItem> BuildRows(TreeViewItem root)
method RowGUI (line 81) | protected override void RowGUI(RowGUIArgs args)
method CellGUI (line 91) | void CellGUI(Rect cellRect, TreeViewItem<AssetAuditTreeElement> item, ...
method CanMultiSelect (line 168) | protected override bool CanMultiSelect(TreeViewItem item)
method CreateDefaultMultiColumnHeaderState (line 173) | public static MultiColumnHeaderState CreateDefaultMultiColumnHeaderSta...
FILE: Assets/Editor/AssetAuditor/Scripts/AssetAuditor.cs
class AssetAuditor (line 18) | public class AssetAuditor
type WildCardMatchType (line 26) | public enum WildCardMatchType
type AssetType (line 32) | public enum AssetType
type AssetRule (line 41) | [Serializable]
method AssetAuditor (line 54) | static AssetAuditor()
method TickEnumerator (line 61) | private static void TickEnumerator()
method GetProgress (line 86) | public static float GetProgress()
method AddEnumerator (line 92) | public static void AddEnumerator(IEnumerable<float> enumerator)
method ClearQueue (line 104) | public static void ClearQueue()
method TypeFromAssetType (line 113) | public static Type TypeFromAssetType(AssetType assetType)
method GetAffectedAssets (line 131) | public static string[] GetAffectedAssets()
method UpdateAffectedAssets (line 137) | public static void UpdateAffectedAssets(AssetRule assetRule)
method DoRegexNameSearch (line 157) | private static IEnumerable<float> DoRegexNameSearch(List<string> found...
method DoNameContainsSearch (line 194) | public static IEnumerable<float> DoNameContainsSearch(List<string> fou...
method GatherAssetRules (line 225) | public static IEnumerable<float> GatherAssetRules(List<AssetRule> _ass...
method GatherData (line 252) | public static IEnumerable<float> GatherData(AssetRule assetRule , List...
method CheckAffectedAsset (line 313) | private static bool CheckAffectedAsset(string affectedAsset, AssetRule...
method CompareSerializedProperty (line 389) | public static bool CompareSerializedProperty(SerializedProperty foundA...
method CompareSerializedObject (line 487) | public static bool CompareSerializedObject(SerializedObject rule, Seri...
method FixAll (line 509) | public static IEnumerable<float> FixAll(AssetAuditTreeView treeView , ...
method FixRule (line 527) | public static void FixRule(AssetAuditTreeElement data , AssetRule asse...
method CopySelectiveProperties (line 603) | private static void CopySelectiveProperties(SerializedObject affectedA...
method HaveEqualProperties (line 620) | public static bool HaveEqualProperties<T>(T rhs, T lhs)
method GetPropertyNameFromDisplayName (line 640) | public static string GetPropertyNameFromDisplayName(SerializedObject s...
method GetPropertyNames (line 656) | public static string[] GetPropertyNames(SerializedObject so)
method CreateProxyAudio (line 672) | public static void CreateProxyAudio(AssetRule newRule , ref string cur...
method CreateProxyModel (line 687) | public static void CreateProxyModel(AssetRule newRule, ref string curr...
method CreateProxyTexture (line 702) | public static void CreateProxyTexture(AssetRule newRule, ref string cu...
method WriteUserData (line 718) | public static void WriteUserData(string path, AssetRule assetRule, ref...
method WriteUserData (line 733) | public static void WriteUserData(string path , AssetRule assetRule)
method RuleExists (line 746) | public static bool RuleExists(AssetRule assetRule)
FILE: Assets/Editor/AssetAuditor/Scripts/AssetAuditorNewRuleWindow.cs
class AssetAuditorNewRuleWindow (line 13) | public class AssetAuditorNewRuleWindow : EditorWindow
method ShowWindow (line 26) | [MenuItem("Asset Auditing/New Audit Rule")]
method AffectedAssetSearchComplete (line 51) | private static void AffectedAssetSearchComplete()
method OnGUI (line 59) | void OnGUI()
method UpdateSelectedAsset (line 67) | private static void UpdateSelectedAsset()
method UpdateExistingRules (line 76) | private static void UpdateExistingRules()
method DoNewRuleGUI (line 110) | private static void DoNewRuleGUI()
method GetSerializedObject (line 239) | private static SerializedObject GetSerializedObject(AssetAuditor.Asset...
method SelectedFromList (line 261) | private static int SelectedFromList(string[] propertyNames , string cu...
method RemoveLastSelectiveRule (line 273) | private static void RemoveLastSelectiveRule()
method AddNewSelectiveRule (line 278) | private static void AddNewSelectiveRule()
FILE: Assets/Editor/AssetAuditor/Scripts/AssetAuditorPreferences.cs
class AssetAuditorPreferences (line 9) | public class AssetAuditorPreferences
method AssetAuditorPreferences (line 27) | static AssetAuditorPreferences()
method createProxyAssetsDirectory (line 59) | private static void createProxyAssetsDirectory()
method PreferencesGUI (line 67) | [PreferenceItem( "Asset Auditor" )]
FILE: Assets/Editor/AssetAuditor/Scripts/AssetAuditorUtilities.cs
class AssetAuditorUtilities (line 10) | public class AssetAuditorUtilities
class CreatePath (line 12) | public class CreatePath : IEnumerable
method CreatePath (line 16) | public CreatePath( string path )
method CreatePath (line 22) | public CreatePath( string[] folderList )
method GetEnumerator (line 31) | IEnumerator IEnumerable.GetEnumerator()
method GetEnumerator (line 36) | public CreatePathEnumerator GetEnumerator()
method Create (line 41) | public static string Create( string path )
class CreatePathEnumerator (line 53) | public class CreatePathEnumerator : IEnumerator
method CreatePathEnumerator (line 61) | public CreatePathEnumerator( string[] folderList )
method CreatePathEnumerator (line 67) | public CreatePathEnumerator( string path )
method MoveNext (line 74) | public bool MoveNext()
method Reset (line 93) | public void Reset()
FILE: Assets/Editor/AssetAuditor/Scripts/AssetAuditorWindow.cs
class AssetAuditorWindow (line 17) | class AssetAuditorWindow : EditorWindow
type State (line 41) | private enum State
method GetWindow (line 54) | [MenuItem("Asset Auditing/Auditor View")]
method FixRule (line 124) | private void FixRule(AssetAuditTreeElement assetAuditTreeElement)
method GatherAssetRules (line 134) | void GatherAssetRules()
method OnGatherAssetRulesComplete (line 147) | private void OnGatherAssetRulesComplete()
method GatherData (line 163) | void GatherData()
method OnGatherDataComplete (line 174) | private void OnGatherDataComplete()
method OnSelectionChange (line 192) | void OnSelectionChange()
method OnFocus (line 200) | private void OnFocus()
method OnGUI (line 211) | void OnGUI()
method DoNoAssetRuleGUI (line 267) | private void DoNoAssetRuleGUI()
method DoProgressBar (line 278) | private void DoProgressBar(Rect rect)
method DoRuleSelectionGUI (line 284) | private void DoRuleSelectionGUI()
method SearchBar (line 363) | void SearchBar(Rect rect)
method DoTreeView (line 369) | void DoTreeView(Rect rect)
method BottomToolBar (line 375) | void BottomToolBar(Rect rect)
class SearchField (line 396) | internal static class SearchField
class Styles (line 398) | static class Styles
method OnGUI (line 405) | public static string OnGUI(Rect position, string text)
FILE: Assets/Editor/AssetAuditor/Scripts/TreeElement.cs
class TreeElement (line 9) | [Serializable]
method TreeElement (line 52) | public TreeElement ()
method TreeElement (line 56) | public TreeElement (string name, int depth, int id)
FILE: Assets/Editor/AssetAuditor/Scripts/TreeElementUtility.cs
class TreeElementUtility (line 14) | public static class TreeElementUtility
method TreeToList (line 16) | public static void TreeToList<T>(T root, IList<T> result) where T : Tr...
method ListToTree (line 43) | public static T ListToTree<T>(IList<T> list) where T : TreeElement
method ValidateDepthValues (line 102) | public static void ValidateDepthValues<T>(IList<T> list) where T : Tre...
method UpdateDepthValues (line 128) | public static void UpdateDepthValues<T>(T root) where T : TreeElement
method IsChildOf (line 153) | static bool IsChildOf<T>(T child, IList<T> elements) where T : TreeEle...
method FindCommonAncestorsWithinList (line 164) | public static IList<T> FindCommonAncestorsWithinList<T>(IList<T> eleme...
class TreeElementUtilityTests (line 177) | class TreeElementUtilityTests
class TestElement (line 179) | class TestElement : TreeElement
method TestElement (line 181) | public TestElement (string name, int depth)
method TestTreeToListWorks (line 189) | [Test]
method TestListToTreeWorks (line 220) | [Test]
method TestListToTreeThrowsExceptionIfRootIsInvalidDepth (line 242) | [Test]
method FindCommonAncestorsWithinListWorks (line 268) | [Test]
FILE: Assets/Editor/AssetAuditor/Scripts/TreeModel.cs
class TreeModel (line 17) | public class TreeModel<T> where T : TreeElement
method TreeModel (line 30) | public TreeModel (IList<T> data)
method Find (line 35) | public T Find (int id)
method SetData (line 40) | public void SetData (IList<T> data)
method Init (line 45) | void Init (IList<T> data)
method GenerateUniqueID (line 57) | public int GenerateUniqueID ()
method GetAncestors (line 62) | public IList<int> GetAncestors (int id)
method GetDescendantsThatHaveChildren (line 77) | public IList<int> GetDescendantsThatHaveChildren (int id)
method GetParentsBelowStackBased (line 87) | IList<int> GetParentsBelowStackBased(TreeElement searchFromThis)
method RemoveElements (line 109) | public void RemoveElements (IList<int> elementIDs)
method RemoveElements (line 115) | public void RemoveElements (IList<T> elements)
method AddElements (line 134) | public void AddElements (IList<T> elements, TreeElement parent, int in...
method AddRoot (line 159) | public void AddRoot (T root)
method AddElement (line 175) | public void AddElement (T element, TreeElement parent, int insertPosit...
method MoveElements (line 194) | public void MoveElements(TreeElement parentElement, int insertionIndex...
method Changed (line 226) | void Changed ()
class TreeModelTests (line 235) | class TreeModelTests
method TestTreeModelCanAddElements (line 237) | [Test]
method TestTreeModelCanRemoveElements (line 260) | [Test]
FILE: Assets/Editor/AssetAuditor/Scripts/TreeViewWithTreeModel.cs
class TreeViewItem (line 12) | internal class TreeViewItem<T> : TreeViewItem where T : TreeElement
method TreeViewItem (line 16) | public TreeViewItem (int id, int depth, string displayName, T data) : ...
class TreeViewWithTreeModel (line 22) | public class TreeViewWithTreeModel<T> : TreeView where T : TreeElement
method TreeViewWithTreeModel (line 32) | public TreeViewWithTreeModel (TreeViewState state, TreeModel<T> model)...
method TreeViewWithTreeModel (line 37) | public TreeViewWithTreeModel (TreeViewState state, MultiColumnHeader m...
method Init (line 43) | void Init (TreeModel<T> model)
method ModelChanged (line 49) | void ModelChanged ()
method BuildRoot (line 57) | protected override TreeViewItem BuildRoot()
method BuildRows (line 63) | protected override IList<TreeViewItem> BuildRows (TreeViewItem root)
method AddChildrenRecursive (line 88) | void AddChildrenRecursive (T parent, int depth, IList<TreeViewItem> ne...
method Search (line 109) | void Search(T searchFromThis, string search, List<TreeViewItem> result)
method SortSearchResult (line 139) | protected virtual void SortSearchResult (List<TreeViewItem> rows)
method GetAncestors (line 144) | protected override IList<int> GetAncestors (int id)
method GetDescendantsThatHaveChildren (line 149) | protected override IList<int> GetDescendantsThatHaveChildren (int id)
method CanStartDrag (line 160) | protected override bool CanStartDrag (CanStartDragArgs args)
method SetupDragAndDrop (line 165) | protected override void SetupDragAndDrop(SetupDragAndDropArgs args)
method HandleDragAndDrop (line 178) | protected override DragAndDropVisualMode HandleDragAndDrop (DragAndDro...
method OnDropDraggedElementsAtIndex (line 213) | public virtual void OnDropDraggedElementsAtIndex (List<TreeViewItem> d...
method ValidDrag (line 228) | bool ValidDrag(TreeViewItem parent, List<TreeViewItem> draggedItems)
Condensed preview — 36 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (159K chars).
[
{
"path": ".gitattributes",
"chars": 65,
"preview": "# Auto detect text files and perform LF normalization\n* text=auto"
},
{
"path": ".gitignore",
"chars": 1115,
"preview": "/[Ll]ibrary/\n/[Tt]emp/\n/[Oo]bj/\n/[Bb]uild/\n/[Bb]uilds/\n/Assets/AssetStoreTools*\n/Assets/Editor/AssetAuditor/ProxyAssets\n"
},
{
"path": "Assets/Editor/AssetAuditor/Audio/DefaultAudio.wav.meta",
"chars": 477,
"preview": "fileFormatVersion: 2\nguid: d13848c7015ad4078abfd3076f74c106\ntimeCreated: 1502381708\nlicenseType: Pro\nAudioImporter:\n se"
},
{
"path": "Assets/Editor/AssetAuditor/Audio.meta",
"chars": 191,
"preview": "fileFormatVersion: 2\nguid: fffabc88153284eda8f44478e35d6337\nfolderAsset: yes\ntimeCreated: 1502381697\nlicenseType: Pro\nDe"
},
{
"path": "Assets/Editor/AssetAuditor/Models/DefaultAvatar.fbx.meta",
"chars": 35880,
"preview": "fileFormatVersion: 2\nguid: 6ca747ad81483413fa1665afa5a9c79a\ntimeCreated: 1502276181\nlicenseType: Pro\nModelImporter:\n se"
},
{
"path": "Assets/Editor/AssetAuditor/Models.meta",
"chars": 191,
"preview": "fileFormatVersion: 2\nguid: d1003e9744d57413fad5f07821ef2136\nfolderAsset: yes\ntimeCreated: 1502276220\nlicenseType: Pro\nDe"
},
{
"path": "Assets/Editor/AssetAuditor/Scripts/AssetAuditTreeElement.cs",
"chars": 637,
"preview": "using System;\n\nnamespace UnityAssetAuditor\n{\n\t[Serializable]\n\tpublic class AssetAuditTreeElement : TreeElement\n { \n\t\t"
},
{
"path": "Assets/Editor/AssetAuditor/Scripts/AssetAuditTreeElement.cs.meta",
"chars": 262,
"preview": "fileFormatVersion: 2\nguid: f1bafad60d37c484dab3ce5b74c04a6a\ntimeCreated: 1472024032\nlicenseType: Pro\nMonoImporter:\n ser"
},
{
"path": "Assets/Editor/AssetAuditor/Scripts/AssetAuditTreeView.cs",
"chars": 8106,
"preview": "using System;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEditor.IMGUI.Controls;\nusing UnityEngine;\n"
},
{
"path": "Assets/Editor/AssetAuditor/Scripts/AssetAuditTreeView.cs.meta",
"chars": 262,
"preview": "fileFormatVersion: 2\nguid: e00d20ba7c1f4d446a34ea24d8b82c4e\ntimeCreated: 1464348051\nlicenseType: Pro\nMonoImporter:\n ser"
},
{
"path": "Assets/Editor/AssetAuditor/Scripts/AssetAuditor.cs",
"chars": 31154,
"preview": "using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing Sys"
},
{
"path": "Assets/Editor/AssetAuditor/Scripts/AssetAuditor.cs.meta",
"chars": 262,
"preview": "fileFormatVersion: 2\nguid: 75cdde80fe406b14e816e78029e38d15\ntimeCreated: 1481588091\nlicenseType: Pro\nMonoImporter:\n ser"
},
{
"path": "Assets/Editor/AssetAuditor/Scripts/AssetAuditorNewRuleWindow.cs",
"chars": 10778,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.ComponentModel;\nusing System.IO;\nusing System.Linq;\nusing "
},
{
"path": "Assets/Editor/AssetAuditor/Scripts/AssetAuditorNewRuleWindow.cs.meta",
"chars": 262,
"preview": "fileFormatVersion: 2\nguid: 9cfdaaf847ee42a46bd18fa749076260\ntimeCreated: 1479436789\nlicenseType: Pro\nMonoImporter:\n ser"
},
{
"path": "Assets/Editor/AssetAuditor/Scripts/AssetAuditorPreferences.cs",
"chars": 7797,
"preview": "using System.Collections;\nusing System.Collections.Generic;\nusing System.IO;\nusing UnityEditor;\nusing UnityEngine;\n\nnam"
},
{
"path": "Assets/Editor/AssetAuditor/Scripts/AssetAuditorPreferences.cs.meta",
"chars": 262,
"preview": "fileFormatVersion: 2\nguid: 940f261582124401db9376c57e2a48c8\ntimeCreated: 1505468470\nlicenseType: Pro\nMonoImporter:\n ser"
},
{
"path": "Assets/Editor/AssetAuditor/Scripts/AssetAuditorUtilities.cs",
"chars": 2214,
"preview": "using System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing UnityEditor;\nusing UnityEngine;\nusing U"
},
{
"path": "Assets/Editor/AssetAuditor/Scripts/AssetAuditorUtilities.cs.meta",
"chars": 284,
"preview": "fileFormatVersion: 2\nguid: 5e05911aedaeb4c9e9bd82b182deab1b\ntimeCreated: 1529319486\nlicenseType: Pro\nMonoImporter:\n ext"
},
{
"path": "Assets/Editor/AssetAuditor/Scripts/AssetAuditorWindow.cs",
"chars": 14976,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.IO;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEditor"
},
{
"path": "Assets/Editor/AssetAuditor/Scripts/AssetAuditorWindow.cs.meta",
"chars": 262,
"preview": "fileFormatVersion: 2\nguid: c3cf55b48c197bb40a09696dead1d7c2\ntimeCreated: 1467106475\nlicenseType: Pro\nMonoImporter:\n ser"
},
{
"path": "Assets/Editor/AssetAuditor/Scripts/TreeElement.cs",
"chars": 1012,
"preview": "using System;\nusing System.Collections.Generic;\nusing UnityEngine;\n\n\nnamespace UnityAssetAuditor\n{\n\n\t[Serializable]\n\tpub"
},
{
"path": "Assets/Editor/AssetAuditor/Scripts/TreeElement.cs.meta",
"chars": 262,
"preview": "fileFormatVersion: 2\nguid: 69be32fe4d27dde489209c5885c1e5dc\ntimeCreated: 1472024155\nlicenseType: Pro\nMonoImporter:\n ser"
},
{
"path": "Assets/Editor/AssetAuditor/Scripts/TreeElementUtility.cs",
"chars": 9038,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing NUnit.Framework;\nusing UnityEditor;\n\n\nnamespace"
},
{
"path": "Assets/Editor/AssetAuditor/Scripts/TreeElementUtility.cs.meta",
"chars": 262,
"preview": "fileFormatVersion: 2\nguid: fd65e8f324e17a344a97ddcf5a8d89d2\ntimeCreated: 1471616285\nlicenseType: Pro\nMonoImporter:\n ser"
},
{
"path": "Assets/Editor/AssetAuditor/Scripts/TreeModel.cs",
"chars": 8441,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing NUnit.Framework;\n\n\nnamespace UnityAssetAuditor\n"
},
{
"path": "Assets/Editor/AssetAuditor/Scripts/TreeModel.cs.meta",
"chars": 262,
"preview": "fileFormatVersion: 2\nguid: 6f9fab1cf2636a6439c644bf08108abb\ntimeCreated: 1472122507\nlicenseType: Pro\nMonoImporter:\n ser"
},
{
"path": "Assets/Editor/AssetAuditor/Scripts/TreeViewWithTreeModel.cs",
"chars": 6689,
"preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing UnityEditor;\nusing UnityEditor.IMGUI.Controls;\n"
},
{
"path": "Assets/Editor/AssetAuditor/Scripts/TreeViewWithTreeModel.cs.meta",
"chars": 262,
"preview": "fileFormatVersion: 2\nguid: 68fe63fd42552e7418aac450b41b8afb\ntimeCreated: 1472481611\nlicenseType: Pro\nMonoImporter:\n ser"
},
{
"path": "Assets/Editor/AssetAuditor/Scripts.meta",
"chars": 191,
"preview": "fileFormatVersion: 2\nguid: d8004df83cf28884ab8e34a091ddd853\nfolderAsset: yes\ntimeCreated: 1481588073\nlicenseType: Pro\nDe"
},
{
"path": "Assets/Editor/AssetAuditor/Texture/DefaultTexture.jpg.meta",
"chars": 1736,
"preview": "fileFormatVersion: 2\nguid: e762cc062d5c5411a9264437e5c9c09e\ntimeCreated: 1502701589\nlicenseType: Pro\nTextureImporter:\n "
},
{
"path": "Assets/Editor/AssetAuditor/Texture.meta",
"chars": 191,
"preview": "fileFormatVersion: 2\nguid: 2e33a099c182b4826a46f527b242a2cd\nfolderAsset: yes\ntimeCreated: 1502705399\nlicenseType: Pro\nDe"
},
{
"path": "Assets/Editor/AssetAuditor.meta",
"chars": 191,
"preview": "fileFormatVersion: 2\nguid: 36d6f139a16b47a469947e0afd23b31d\nfolderAsset: yes\ntimeCreated: 1479437964\nlicenseType: Pro\nDe"
},
{
"path": "Assets/Editor.meta",
"chars": 191,
"preview": "fileFormatVersion: 2\nguid: fa69737d10241b54391c55189b99b9c6\nfolderAsset: yes\ntimeCreated: 1440440842\nlicenseType: Pro\nDe"
},
{
"path": "LICENSE",
"chars": 1313,
"preview": "MIT X11\n\nCopyright (C) 2017 Unity Technologies ApS\n\nPermission is hereby granted, free of charge, to any person obtainin"
},
{
"path": "README.md",
"chars": 3140,
"preview": "# Asset Auditor\n\nThe asset auditor tool is designed to allow you to create sets of rules for the import settings for you"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the MarkUnity/AssetAuditor GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 36 files (145.1 KB), approximately 41.1k tokens, and a symbol index with 145 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.