main
55
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"files.exclude":
|
||||
{
|
||||
"**/.DS_Store":true,
|
||||
"**/.git":true,
|
||||
"**/.gitmodules":true,
|
||||
"**/*.booproj":true,
|
||||
"**/*.pidb":true,
|
||||
"**/*.suo":true,
|
||||
"**/*.user":true,
|
||||
"**/*.userprefs":true,
|
||||
"**/*.unityproj":true,
|
||||
"**/*.dll":true,
|
||||
"**/*.exe":true,
|
||||
"**/*.pdf":true,
|
||||
"**/*.mid":true,
|
||||
"**/*.midi":true,
|
||||
"**/*.wav":true,
|
||||
"**/*.gif":true,
|
||||
"**/*.ico":true,
|
||||
"**/*.jpg":true,
|
||||
"**/*.jpeg":true,
|
||||
"**/*.png":true,
|
||||
"**/*.psd":true,
|
||||
"**/*.tga":true,
|
||||
"**/*.tif":true,
|
||||
"**/*.tiff":true,
|
||||
"**/*.3ds":true,
|
||||
"**/*.3DS":true,
|
||||
"**/*.fbx":true,
|
||||
"**/*.FBX":true,
|
||||
"**/*.lxo":true,
|
||||
"**/*.LXO":true,
|
||||
"**/*.ma":true,
|
||||
"**/*.MA":true,
|
||||
"**/*.obj":true,
|
||||
"**/*.OBJ":true,
|
||||
"**/*.asset":true,
|
||||
"**/*.cubemap":true,
|
||||
"**/*.flare":true,
|
||||
"**/*.mat":true,
|
||||
"**/*.meta":true,
|
||||
"**/*.prefab":true,
|
||||
"**/*.unity":true,
|
||||
"build/":true,
|
||||
"Build/":true,
|
||||
"Library/":true,
|
||||
"library/":true,
|
||||
"obj/":true,
|
||||
"Obj/":true,
|
||||
"ProjectSettings/":true,
|
||||
"temp/":true,
|
||||
"Temp/":true
|
||||
}
|
||||
}
|
||||
6
.vsconfig
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"version": "1.0",
|
||||
"components": [
|
||||
"Microsoft.VisualStudio.Workload.ManagedGame"
|
||||
]
|
||||
}
|
||||
8
Assets/Asset Cleaner.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b22dfca284c7bd54b8c2d60926037322
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
15
Assets/Asset Cleaner/AssetCleaner.asmdef
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "AssetCleaner",
|
||||
"references": [],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
7
Assets/Asset Cleaner/AssetCleaner.asmdef.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de141fd48bce7594e9474fe440f5ea10
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1236
Assets/Asset Cleaner/CleanerStyle.asset
Normal file
8
Assets/Asset Cleaner/CleanerStyle.asset.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7f4dfe9d348c0ff4cb525a0b2c48fc34
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Asset Cleaner/Content.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f45f9c9770a8371428fce5031e1c7c5c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/Asset Cleaner/Content/ac_back1.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
110
Assets/Asset Cleaner/Content/ac_back1.png.meta
Normal file
@@ -0,0 +1,110 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bfec65de7ee2e114199f83507d375a6f
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 9
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
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
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -100
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 2
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 2
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- serializedVersion: 2
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 2
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- serializedVersion: 2
|
||||
buildTarget: Android
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 2
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/Asset Cleaner/Content/ac_delete_asset.png
Normal file
|
After Width: | Height: | Size: 991 B |
110
Assets/Asset Cleaner/Content/ac_delete_asset.png.meta
Normal file
@@ -0,0 +1,110 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f4b3e5a29ec20194a8ba1d6cf7b1b037
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 9
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
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
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -100
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 2
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 2
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- serializedVersion: 2
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 2
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- serializedVersion: 2
|
||||
buildTarget: Android
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 2
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/Asset Cleaner/Content/ac_delete_scene_asset.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
110
Assets/Asset Cleaner/Content/ac_delete_scene_asset.png.meta
Normal file
@@ -0,0 +1,110 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3fec3bf4c4f5e2d48835dbe2f21aa7d0
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 9
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
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
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -100
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 2
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 2
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- serializedVersion: 2
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 2
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- serializedVersion: 2
|
||||
buildTarget: Android
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 2
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/Asset Cleaner/Content/ac_forward1.png
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
110
Assets/Asset Cleaner/Content/ac_forward1.png.meta
Normal file
@@ -0,0 +1,110 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 07bb28c80f378c64194dd46c34b2d6c1
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 9
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
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
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -100
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 2
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 2
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- serializedVersion: 2
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 2
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- serializedVersion: 2
|
||||
buildTarget: Android
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 2
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/Asset Cleaner/Content/ac_lock.png
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
110
Assets/Asset Cleaner/Content/ac_lock.png.meta
Normal file
@@ -0,0 +1,110 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c5fd88366c67daf4585631953fa79779
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 9
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
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
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -100
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 2
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 2
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- serializedVersion: 2
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 2
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- serializedVersion: 2
|
||||
buildTarget: Android
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 2
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/Asset Cleaner/Content/ac_multiselect.png
Normal file
|
After Width: | Height: | Size: 282 B |
110
Assets/Asset Cleaner/Content/ac_multiselect.png.meta
Normal file
@@ -0,0 +1,110 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e0208e3a37267be46ba2d10fad510cef
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 9
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
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
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -100
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 2
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- serializedVersion: 2
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- serializedVersion: 2
|
||||
buildTarget: Android
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/Asset Cleaner/Content/ac_unlock.png
Normal file
|
After Width: | Height: | Size: 7.4 KiB |
110
Assets/Asset Cleaner/Content/ac_unlock.png.meta
Normal file
@@ -0,0 +1,110 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e755b5ef4cb427f469ba580ae9956237
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 9
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
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
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -100
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 2
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 2
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- serializedVersion: 2
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 2
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- serializedVersion: 2
|
||||
buildTarget: Android
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 2
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Asset Cleaner/Data.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4848aa5846cd6264c984dcc6cd9d72af
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
82
Assets/Asset Cleaner/Data/AufSerializableData.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
[Serializable]
|
||||
class AufSerializableData {
|
||||
public const int CurrentVersion = 1;
|
||||
public int Version;
|
||||
public bool MarkRed;
|
||||
public int RebuildCacheOnDemand;
|
||||
public int UpdateUnusedAssetsOnDemand;
|
||||
public bool ShowInfoBox;
|
||||
public string IgnorePathContainsCombined;
|
||||
public bool IgnoreMaterial;
|
||||
public bool IgnoreScriptable;
|
||||
public bool IgnoreSprite;
|
||||
|
||||
static int BoolToInt(bool val) {
|
||||
return val ? 2 : 1;
|
||||
}
|
||||
|
||||
static bool IntToBool(int val, bool defaultVal) {
|
||||
switch (val) {
|
||||
case 2:
|
||||
return true;
|
||||
case 1:
|
||||
return false;
|
||||
default:
|
||||
return defaultVal;
|
||||
}
|
||||
}
|
||||
|
||||
public static AufSerializableData Default() {
|
||||
return new AufSerializableData {
|
||||
Version = CurrentVersion,
|
||||
MarkRed = true,
|
||||
ShowInfoBox = true,
|
||||
IgnorePathContainsCombined = "Gizmos;Resources;Editor;Asset Cleaner;Asset Usage Finder;",
|
||||
IgnoreMaterial = false,
|
||||
IgnoreScriptable = true,
|
||||
IgnoreSprite = false,
|
||||
RebuildCacheOnDemand = 2,
|
||||
UpdateUnusedAssetsOnDemand = 2,
|
||||
};
|
||||
}
|
||||
|
||||
public static void OnSerialize(in Config src, out AufSerializableData result) {
|
||||
result = new AufSerializableData();
|
||||
result.Version = CurrentVersion;
|
||||
result.MarkRed = src.MarkRed;
|
||||
result.ShowInfoBox = src.ShowInfoBox;
|
||||
result.IgnorePathContainsCombined = src.IgnorePathContainsCombined;
|
||||
result.IgnoreMaterial = src.IgnoreMaterial;
|
||||
result.IgnoreScriptable = src.IgnoreScriptable;
|
||||
result.IgnoreSprite = src.IgnoreSprite;
|
||||
result.RebuildCacheOnDemand = BoolToInt(src.RebuildCacheOnDemand);
|
||||
result.UpdateUnusedAssetsOnDemand = BoolToInt(src.UpdateUnusedAssetsOnDemand);
|
||||
}
|
||||
|
||||
public static void OnDeserialize(in AufSerializableData src, ref Config result) {
|
||||
var def = Default();
|
||||
|
||||
result.MarkRed = src.MarkRed;
|
||||
result.IgnorePathContainsCombined = src.IgnorePathContainsCombined;
|
||||
result.ShowInfoBox = src.ShowInfoBox;
|
||||
result.IgnorePathContains = result.IgnorePathContainsCombined
|
||||
.Split(';')
|
||||
.Select(s => s.Trim())
|
||||
.Where(s => !string.IsNullOrWhiteSpace(s))
|
||||
.ToArray();
|
||||
result.IgnoreMaterial = src.IgnoreMaterial;
|
||||
result.IgnoreScriptable = src.IgnoreScriptable;
|
||||
result.IgnoreSprite = src.IgnoreSprite;
|
||||
result.RebuildCacheOnDemand = IntToBool(src.RebuildCacheOnDemand, def.RebuildCacheOnDemand == 2);
|
||||
result.UpdateUnusedAssetsOnDemand = IntToBool(src.UpdateUnusedAssetsOnDemand, def.UpdateUnusedAssetsOnDemand == 2);
|
||||
}
|
||||
|
||||
public bool Valid() {
|
||||
return Version == CurrentVersion || IgnorePathContainsCombined == null;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Asset Cleaner/Data/AufSerializableData.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 14980ecc573d44c59b5f9323603c7bdf
|
||||
timeCreated: 1588518687
|
||||
105
Assets/Asset Cleaner/Data/CleanerStyleAsset.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
#pragma warning disable 649
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
class CleanerStyleAsset : ScriptableObject {
|
||||
[Serializable]
|
||||
public class Style {
|
||||
public Color RedHighlight = new Color(1, 0, 0, 1f);
|
||||
|
||||
public GUIContent Lock;
|
||||
public GUIStyle LockBtn = new GUIStyle();
|
||||
public GUIStyle SampleBtn = new GUIStyle();
|
||||
|
||||
public GUIContent Unlock;
|
||||
public GUIStyle UnlockBtn = new GUIStyle();
|
||||
|
||||
public GUIContent RemoveFile;
|
||||
public GUIContent RemoveScene;
|
||||
|
||||
public GUIStyle RowMainAssetBtn = new GUIStyle();
|
||||
public GUIStyle RemoveUnusedBtn = new GUIStyle();
|
||||
|
||||
public GUIStyle CurrentBtn = new GUIStyle();
|
||||
|
||||
public GUIContent ArrowL;
|
||||
public GUIContent ArrowR;
|
||||
public GUIStyle ArrowBtn = new GUIStyle();
|
||||
|
||||
public float SceneIndent1 = 20f;
|
||||
public float SceneIndent2 = 20f;
|
||||
public GUIStyle ProjectViewCounterLabel;
|
||||
|
||||
public GUIContent MultiSelect;
|
||||
|
||||
public static bool TryFindSelf(out Style value) {
|
||||
const string typeName = nameof(CleanerStyleAsset);
|
||||
|
||||
var guids = AssetDatabase.FindAssets($"t:{typeName}");
|
||||
if (!guids.Any()) {
|
||||
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
|
||||
}
|
||||
|
||||
Asr.IsTrue(guids.Length > 0, $"No '{typeName}' assets found");
|
||||
var res = guids.Select(AssetDatabase.GUIDToAssetPath).Select(t => (CleanerStyleAsset) AssetDatabase.LoadAssetAtPath(t, typeof(CleanerStyleAsset))).FirstOrDefault();
|
||||
if (res == null) {
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
value = EditorGUIUtility.isProSkin ? res.Pro : res.Personal;
|
||||
return value != null;
|
||||
}
|
||||
}
|
||||
#pragma warning disable 0649
|
||||
public Style Pro;
|
||||
public Style Personal;
|
||||
#pragma warning restore
|
||||
|
||||
[CustomEditor(typeof(CleanerStyleAsset))]
|
||||
class Editor : UnityEditor.Editor {
|
||||
public override void OnInspectorGUI() {
|
||||
#if false
|
||||
if (GUILayout.Button("Update Btn backgrounds")) {
|
||||
var targ = (CleanerStyleAsset) target;
|
||||
Set(targ.Pro);
|
||||
}
|
||||
#endif
|
||||
EditorGUI.BeginChangeCheck();
|
||||
base.OnInspectorGUI();
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
|
||||
}
|
||||
|
||||
#if false
|
||||
static void Set(Style style) {
|
||||
var st = style;
|
||||
var sample = st.SampleBtn;
|
||||
|
||||
foreach (var btn in new[] {
|
||||
st.LockBtn,
|
||||
st.UnlockBtn,
|
||||
st.RowMainAssetBtn,
|
||||
st.RemoveUnusedBtn,
|
||||
st.CurrentBtn,
|
||||
st.ArrowBtn,
|
||||
}) {
|
||||
btn.normal = sample.normal;
|
||||
btn.hover = sample.hover;
|
||||
btn.active = sample.active;
|
||||
btn.focused = sample.focused;
|
||||
btn.onNormal = sample.onNormal;
|
||||
btn.onHover = sample.onHover;
|
||||
btn.onActive = sample.onActive;
|
||||
btn.onFocused = sample.onFocused;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Asset Cleaner/Data/CleanerStyleAsset.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 16578cbec6a24ac4d951b5f328a970ca
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Asset Cleaner/Data/FindModeEnum.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Asset_Cleaner {
|
||||
enum FindModeEnum {
|
||||
None = 0,
|
||||
File = 1,
|
||||
Scene = 2,
|
||||
Stage = 3,
|
||||
}
|
||||
}
|
||||
11
Assets/Asset Cleaner/Data/FindModeEnum.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 34e14d6333c649f4fb74ccdb6c86d8b6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
3
Assets/Asset Cleaner/Data/Globals.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f94bcb0962724eeea17b007a6ddfd885
|
||||
timeCreated: 1596213773
|
||||
284
Assets/Asset Cleaner/Data/Globals/BacklinkStore.cs
Normal file
@@ -0,0 +1,284 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditorInternal;
|
||||
using Debug = UnityEngine.Debug;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
class BacklinkStore {
|
||||
public bool Initialized { get; private set; }
|
||||
|
||||
public Dictionary<string, long> UnusedFiles { get; private set; }
|
||||
public Dictionary<string, long> UnusedScenes { get; private set; }
|
||||
public Dictionary<string, BwMeta> Backward { get; private set; }
|
||||
public Dictionary<string, UnusedQty> FoldersWithQty { get; private set; }
|
||||
|
||||
Dictionary<string, FwMeta> _forward;
|
||||
List<string> Folders { get; set; }
|
||||
|
||||
|
||||
public void Init() {
|
||||
FoldersWithQty = new Dictionary<string, UnusedQty>();
|
||||
_forward = new Dictionary<string, FwMeta>();
|
||||
Backward = new Dictionary<string, BwMeta>();
|
||||
|
||||
var defaultAss = typeof(DefaultAsset);
|
||||
var asmdefAss = typeof(AssemblyDefinitionAsset);
|
||||
|
||||
var paths = AssetDatabase.GetAllAssetPaths()
|
||||
.Distinct()
|
||||
.Where(s => s.StartsWith("Assets") || s.StartsWith("ProjectSettings"))
|
||||
.Where(p => {
|
||||
var t = AssetDatabase.GetMainAssetTypeAtPath(p);
|
||||
return !t.IsAssignableFromInverse(defaultAss) && !t.IsAssignableFromInverse(asmdefAss);
|
||||
})
|
||||
.ToArray();
|
||||
|
||||
var i = 0f;
|
||||
var total = (float) paths.Length;
|
||||
foreach (var path in paths) {
|
||||
_FillFwAndBacklinks(path);
|
||||
var percent = i * 100f / total;
|
||||
if (Math.Abs(percent % 5f) < 0.01f) {
|
||||
if (EditorUtility.DisplayCancelableProgressBar(
|
||||
"Please wait...",
|
||||
"Building the cache...", percent))
|
||||
Debug.LogError("Cache build aborted");
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
EditorUtility.ClearProgressBar();
|
||||
|
||||
// FillFoldersWithQtyByPaths
|
||||
List<string> foldersAll = new List<string>();
|
||||
foreach (var path in paths) {
|
||||
var folders = GetAllFoldersFromPath(path);
|
||||
foldersAll.AddRange(folders);
|
||||
}
|
||||
|
||||
Folders = foldersAll.Distinct().OrderBy(p => p).ToList();
|
||||
UpdateUnusedAssets();
|
||||
Initialized = true;
|
||||
}
|
||||
|
||||
void _FillFwAndBacklinks(string path) {
|
||||
var dependencies = _Dependencies(path);
|
||||
var hs = new FwMeta {Dependencies = new HashSet<string>(dependencies)};
|
||||
_forward.Add(path, hs);
|
||||
foreach (var backPath in dependencies) {
|
||||
if (!Backward.TryGetValue(backPath, out var val)) {
|
||||
val = new BwMeta();
|
||||
val.Lookup = new HashSet<string>();
|
||||
Backward.Add(backPath, val);
|
||||
}
|
||||
|
||||
val.Lookup.Add(path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void UpdateFoldersWithQtyByPath(string path) {
|
||||
var folders = GetAllFoldersFromPath(path);
|
||||
foreach (var folder in folders) {
|
||||
if (!Folders.Exists(p => p == folder))
|
||||
Folders.Add(folder);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static List<string> GetAllFoldersFromPath(string p) {
|
||||
var result = new List<string>();
|
||||
var i = p.IndexOf('/', 0);
|
||||
while (i > 0) {
|
||||
var item = p.Substring(0, i);
|
||||
result.Add(item);
|
||||
i = p.IndexOf('/', i + 1);
|
||||
}
|
||||
|
||||
return result.Distinct().ToList();
|
||||
}
|
||||
|
||||
public void UpdateUnusedAssets() {
|
||||
var all = new HashSet<string>(_forward.Keys);
|
||||
var withBacklinks =
|
||||
new HashSet<string>(Backward.Where(kv => kv.Value.Lookup.Count > 0).Select(kv => kv.Key));
|
||||
|
||||
all.ExceptWith(withBacklinks);
|
||||
all.RemoveWhere(SearchUtils.IsFileIgrnoredBySettings);
|
||||
|
||||
var unusedAssets = all;
|
||||
|
||||
var scenes = unusedAssets.Where(s =>
|
||||
AssetDatabase.GetMainAssetTypeAtPath(s).IsAssignableFromInverse(typeof(SceneAsset))).ToArray();
|
||||
|
||||
unusedAssets.ExceptWith(scenes);
|
||||
var files = unusedAssets;
|
||||
UnusedFiles = new Dictionary<string, long>();
|
||||
foreach (var file in files) UnusedFiles[file] = new FileInfo(file).Length;
|
||||
|
||||
UnusedScenes = new Dictionary<string, long>();
|
||||
foreach (var scene in scenes) UnusedScenes[scene] = new FileInfo(scene).Length;
|
||||
|
||||
// UpdateFoldersWithQty();
|
||||
foreach (var folder in Folders) {
|
||||
var unusedFilesQty = UnusedFiles.Count(p => p.Key.StartsWith(folder));
|
||||
var unusedScenesQty = UnusedScenes.Count(p => p.Key.StartsWith(folder));
|
||||
long size = 0;
|
||||
size = UnusedFiles.Where((p => p.Key.StartsWith(folder))).Sum(p => p.Value);
|
||||
size += UnusedScenes.Where(p => p.Key.StartsWith(folder)).Sum(p => p.Value);
|
||||
|
||||
FoldersWithQty.TryGetValue(folder, out var folderWithQty);
|
||||
if (folderWithQty == null) {
|
||||
FoldersWithQty.Add(folder, new UnusedQty(unusedFilesQty, unusedScenesQty, size));
|
||||
}
|
||||
else {
|
||||
folderWithQty.UnusedFilesQty = unusedFilesQty;
|
||||
folderWithQty.UnusedScenesQty = unusedScenesQty;
|
||||
folderWithQty.UnusedSize = size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void Remove(string path) {
|
||||
if (!_forward.TryGetValue(path, out var fwMeta))
|
||||
return;
|
||||
|
||||
foreach (var dependency in fwMeta.Dependencies) {
|
||||
if (!Backward.TryGetValue(dependency, out var dep)) continue;
|
||||
|
||||
dep.Lookup.Remove(path);
|
||||
}
|
||||
|
||||
_forward.Remove(path);
|
||||
UpdateFoldersWithQtyByPath(path);
|
||||
}
|
||||
|
||||
public void Replace(string src, string dest) {
|
||||
_Upd(_forward);
|
||||
_Upd(Backward);
|
||||
UpdateFoldersWithQtyByPath(dest);
|
||||
|
||||
void _Upd<T>(Dictionary<string, T> dic) {
|
||||
if (!dic.TryGetValue(src, out var refs)) return;
|
||||
|
||||
dic.Remove(src);
|
||||
dic.Add(dest, refs);
|
||||
}
|
||||
}
|
||||
|
||||
public void RebuildFor(string path, bool remove) {
|
||||
if (!_forward.TryGetValue(path, out var fwMeta)) {
|
||||
fwMeta = new FwMeta();
|
||||
_forward.Add(path, fwMeta);
|
||||
}
|
||||
else if (remove) {
|
||||
foreach (var dependency in fwMeta.Dependencies) {
|
||||
if (!Backward.TryGetValue(dependency, out var backDep)) continue;
|
||||
|
||||
backDep.Lookup.Remove(path);
|
||||
}
|
||||
|
||||
fwMeta.Dependencies = null;
|
||||
}
|
||||
|
||||
var dependencies = _Dependencies(path);
|
||||
fwMeta.Dependencies = new HashSet<string>(dependencies);
|
||||
|
||||
foreach (var backPath in dependencies) {
|
||||
if (!Backward.TryGetValue(backPath, out var bwMeta)) {
|
||||
bwMeta = new BwMeta {Lookup = new HashSet<string>()};
|
||||
Backward.Add(backPath, bwMeta);
|
||||
}
|
||||
else if (remove)
|
||||
bwMeta.Lookup.Remove(path);
|
||||
|
||||
bwMeta.Lookup.Add(path);
|
||||
}
|
||||
|
||||
if (!remove) {
|
||||
UpdateFoldersWithQtyByPath(path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static string[] _Dependencies(string s) {
|
||||
if (s[0] == 'A')
|
||||
return AssetDatabase.GetDependencies(s, false);
|
||||
var obj = LoadAllOrMain(s)[0];
|
||||
return GetDependenciesManualPaths().ToArray();
|
||||
|
||||
Object[] LoadAllOrMain(string assetPath) {
|
||||
// prevents error "Do not use readobjectthreaded on scene objects!"
|
||||
return typeof(SceneAsset) == AssetDatabase.GetMainAssetTypeAtPath(assetPath)
|
||||
? new[] {AssetDatabase.LoadMainAssetAtPath(assetPath)}
|
||||
: AssetDatabase.LoadAllAssetsAtPath(assetPath);
|
||||
}
|
||||
|
||||
IEnumerable<string> GetDependenciesManualPaths() {
|
||||
if (obj is EditorBuildSettings) {
|
||||
foreach (var scene in EditorBuildSettings.scenes)
|
||||
yield return scene.path;
|
||||
}
|
||||
|
||||
using (var so = new SerializedObject(obj)) {
|
||||
var props = so.GetIterator();
|
||||
while (props.Next(true)) {
|
||||
switch (props.propertyType) {
|
||||
case SerializedPropertyType.ObjectReference:
|
||||
var propsObjectReferenceValue = props.objectReferenceValue;
|
||||
if (!propsObjectReferenceValue) continue;
|
||||
|
||||
var assetPath = AssetDatabase.GetAssetPath(propsObjectReferenceValue);
|
||||
yield return assetPath;
|
||||
break;
|
||||
#if later
|
||||
case SerializedPropertyType.Generic:
|
||||
case SerializedPropertyType.ExposedReference:
|
||||
case SerializedPropertyType.ManagedReference:
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class FwMeta {
|
||||
public HashSet<string> Dependencies;
|
||||
}
|
||||
|
||||
public class BwMeta {
|
||||
public HashSet<string> Lookup;
|
||||
}
|
||||
|
||||
public class UnusedQty {
|
||||
public int UnusedFilesQty;
|
||||
public int UnusedScenesQty;
|
||||
|
||||
public long UnusedSize;
|
||||
|
||||
public UnusedQty() {
|
||||
Init(0, 0, 0);
|
||||
}
|
||||
|
||||
public UnusedQty(int unusedFilesQty, int unusedScenesQty, long unusedSize) {
|
||||
Init(unusedFilesQty, unusedScenesQty, unusedSize);
|
||||
}
|
||||
|
||||
private void Init(int unusedFilesQty, int unusedScenesQty, long unusedSize) {
|
||||
UnusedFilesQty = unusedFilesQty;
|
||||
UnusedScenesQty = unusedScenesQty;
|
||||
UnusedSize = unusedSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Asset Cleaner/Data/Globals/BacklinkStore.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 004e5680782f4e679ae93027d2d40023
|
||||
timeCreated: 1577106223
|
||||
23
Assets/Asset Cleaner/Data/Globals/Config.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace Asset_Cleaner {
|
||||
class Config {
|
||||
// serialized
|
||||
public bool MarkRed;
|
||||
public string IgnorePathContainsCombined;
|
||||
public bool ShowInfoBox;
|
||||
public bool RebuildCacheOnDemand;
|
||||
public bool UpdateUnusedAssetsOnDemand;
|
||||
|
||||
// todo make type array
|
||||
public bool IgnoreMaterial;
|
||||
public bool IgnoreScriptable;
|
||||
public bool IgnoreSprite;
|
||||
|
||||
// serialized only while window is opened
|
||||
public bool Locked;
|
||||
|
||||
// non-serialized
|
||||
public string[] IgnorePathContains;
|
||||
public string InitializationTime;
|
||||
public bool PendingUpdateUnusedAssets;
|
||||
}
|
||||
}
|
||||
3
Assets/Asset Cleaner/Data/Globals/Config.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a6ff796e4dab4324887a303cba29eed4
|
||||
timeCreated: 1577117228
|
||||
15
Assets/Asset Cleaner/Data/Globals/PersistentUndoRedoState.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
[Serializable]
|
||||
class PersistentUndoRedoState {
|
||||
public List<SelectionEntry> History = new List<SelectionEntry>();
|
||||
public int Id;
|
||||
|
||||
public void Deconstruct(out List<SelectionEntry> list, out int id) {
|
||||
id = Id;
|
||||
list = History;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5414db21dfea4d7eaff8ce4c8f106c8d
|
||||
timeCreated: 1596213717
|
||||
6
Assets/Asset Cleaner/Data/Globals/UndoRedoState.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Asset_Cleaner {
|
||||
class UndoRedoState {
|
||||
public bool UndoEnabled;
|
||||
public bool RedoEnabled;
|
||||
}
|
||||
}
|
||||
3
Assets/Asset Cleaner/Data/Globals/UndoRedoState.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c3ac9efa32c8491aa8a11749f8020d96
|
||||
timeCreated: 1596213776
|
||||
14
Assets/Asset Cleaner/Data/Globals/WindowData.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
class WindowData {
|
||||
public bool ExpandFiles;
|
||||
public bool ExpandScenes;
|
||||
public Vector2 ScrollPos;
|
||||
public CleanerStyleAsset.Style Style;
|
||||
public GUIContent SceneFoldout;
|
||||
public PrevClick Click;
|
||||
public AufWindow Window;
|
||||
public FindModeEnum FindFrom;
|
||||
}
|
||||
}
|
||||
3
Assets/Asset Cleaner/Data/Globals/WindowData.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8481f043b2414c08a45957dcd6035fbe
|
||||
timeCreated: 1575305740
|
||||
11
Assets/Asset Cleaner/Data/InSceneResult.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Leopotam.Ecs;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
class InSceneResult : IEcsAutoReset {
|
||||
public string ScenePath;
|
||||
|
||||
public void Reset() {
|
||||
ScenePath = default;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Asset Cleaner/Data/InSceneResult.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 013577ffef1140109e8367f2a5f75fa6
|
||||
timeCreated: 1577269723
|
||||
18
Assets/Asset Cleaner/Data/PrevClick.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
public struct PrevClick {
|
||||
const float DoubleClickTime = 0.5f;
|
||||
Object _target;
|
||||
float _timeClicked;
|
||||
|
||||
public PrevClick(Object target) {
|
||||
_target = target;
|
||||
_timeClicked = Time.realtimeSinceStartup;
|
||||
}
|
||||
|
||||
public bool IsDoubleClick(Object o) {
|
||||
return _target == o && Time.realtimeSinceStartup - _timeClicked < DoubleClickTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Asset Cleaner/Data/PrevClick.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 31c0f204d1b044caaa02a0726f11a270
|
||||
timeCreated: 1576087327
|
||||
19
Assets/Asset Cleaner/Data/Result.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Leopotam.Ecs;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
class Result : IEcsAutoReset {
|
||||
public string FilePath;
|
||||
public Object File;
|
||||
public Object MainFile;
|
||||
public GameObject RootGo;
|
||||
|
||||
public void Reset() {
|
||||
FilePath = default;
|
||||
File = default;
|
||||
MainFile = default;
|
||||
RootGo = default;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Asset Cleaner/Data/Result.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 46f4fd24243adc749b377209f744d628
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
20
Assets/Asset Cleaner/Data/SceneDetails.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using Leopotam.Ecs;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
class SceneDetails : IEcsAutoReset {
|
||||
public string Path;
|
||||
public Scene Scene;
|
||||
public bool SearchRequested;
|
||||
public bool SearchDone;
|
||||
public bool WasOpened;
|
||||
|
||||
public void Reset() {
|
||||
Path = default;
|
||||
Scene = default;
|
||||
SearchRequested = default;
|
||||
SearchDone = default;
|
||||
WasOpened = default;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Asset Cleaner/Data/SceneDetails.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 14749f86c2c14febb592442508f8c23a
|
||||
timeCreated: 1577266613
|
||||
11
Assets/Asset Cleaner/Data/SceneResult.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Leopotam.Ecs;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
class SceneResult : IEcsAutoReset {
|
||||
public string PathNicified;
|
||||
|
||||
public void Reset() {
|
||||
PathNicified = default;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Asset Cleaner/Data/SceneResult.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 338e9e86c9274f91808429753a912d4b
|
||||
timeCreated: 1576083610
|
||||
26
Assets/Asset Cleaner/Data/SearchArg.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System.Collections.Generic;
|
||||
using Leopotam.Ecs;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
class SearchArg : IEcsAutoReset {
|
||||
public Object Target;
|
||||
public Object Main;
|
||||
public string FilePath;
|
||||
public Option<Object[]> SubAssets;
|
||||
public Scene Scene;
|
||||
public List<string> UnusedAssetsFiltered;
|
||||
public List<string> UnusedScenesFiltered;
|
||||
|
||||
public void Reset() {
|
||||
UnusedAssetsFiltered = default;
|
||||
UnusedScenesFiltered = default;
|
||||
Target = default;
|
||||
Main = default;
|
||||
SubAssets = default;
|
||||
Scene = default;
|
||||
FilePath = default;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Asset Cleaner/Data/SearchArg.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4a6b25ca9296c9e41affadc9ccecb1f1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
32
Assets/Asset Cleaner/Data/SearchResultGui.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System.Collections.Generic;
|
||||
using Leopotam.Ecs;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
class SearchResultGui : IEcsAutoReset {
|
||||
public SerializedObject SerializedObject;
|
||||
public List<PropertyData> Properties;
|
||||
public GUIContent Label;
|
||||
public string TransformPath;
|
||||
|
||||
public void Reset() {
|
||||
SerializedObject?.Dispose();
|
||||
SerializedObject = default;
|
||||
|
||||
if (Properties != default)
|
||||
foreach (var propertyData in Properties) {
|
||||
propertyData.Property.Dispose();
|
||||
}
|
||||
|
||||
Properties = default;
|
||||
Label = default;
|
||||
TransformPath = default;
|
||||
}
|
||||
|
||||
public class PropertyData {
|
||||
public SerializedProperty Property;
|
||||
public GUIContent Content;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Asset Cleaner/Data/SearchResultGui.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 14f26ff078c04c5685fdbb3ec3f92382
|
||||
timeCreated: 1576168925
|
||||
17
Assets/Asset Cleaner/Data/SelectionChanged.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using Leopotam.Ecs;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
class SelectionChanged : IEcsAutoReset {
|
||||
public Object Target;
|
||||
public Scene Scene;
|
||||
public FindModeEnum From;
|
||||
|
||||
public void Reset() {
|
||||
Target = default;
|
||||
Scene = default;
|
||||
From = default;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Asset Cleaner/Data/SelectionChanged.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1d0dc4d007bb4ebbbeea6626197d17b9
|
||||
timeCreated: 1575365553
|
||||
31
Assets/Asset Cleaner/Data/SelectionEntry.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
[Serializable]
|
||||
class SelectionEntry {
|
||||
public bool IsGuids;
|
||||
public string[] Guids;
|
||||
|
||||
public Object[] SceneObjects;
|
||||
|
||||
public bool Valid() {
|
||||
if (IsGuids) {
|
||||
foreach (var guid in Guids) {
|
||||
var path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var sceneObject in SceneObjects)
|
||||
if (sceneObject)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Asset Cleaner/Data/SelectionEntry.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2b4476be23474ea4b20262c0ee59983c
|
||||
timeCreated: 1596139978
|
||||
41
Assets/Asset Cleaner/IgnoreTypes.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
static class IgnoreTypes {
|
||||
public static bool Check(string path, out Type type) {
|
||||
type = AssetDatabase.GetMainAssetTypeAtPath(path);
|
||||
if (type == null) return false;
|
||||
var conf = Globals<Config>.Value;
|
||||
if (conf == null) return false;
|
||||
|
||||
if (type.IsAssignableFromInverse(typeof(MonoScript))) return true;
|
||||
if (type.IsAssignableFromInverse(typeof(DefaultAsset))) return true;
|
||||
if (conf.IgnoreScriptable && type.IsAssignableFromInverse(typeof(ScriptableObject))) return true;
|
||||
|
||||
if (type.IsAssignableFromInverse(typeof(Shader))) return true;
|
||||
if (type.IsAssignableFromInverse(typeof(ComputeShader))) return true;
|
||||
if (type.IsAssignableFromInverse(typeof(ShaderVariantCollection))) return true;
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
if (type.IsAssignableFromInverse(typeof(UnityEngine.Experimental.Rendering.RayTracingShader))) return true; // todo: track of Experimental namespace
|
||||
#endif
|
||||
|
||||
if (type.IsAssignableFromInverse(typeof(TextAsset))) return true;
|
||||
if (type.IsAssignableFromInverse(typeof(AssemblyDefinitionAsset))) return true;
|
||||
|
||||
if (type.IsAssignableFromInverse(typeof(UnityEngine.U2D.SpriteAtlas))) return true;
|
||||
|
||||
if (conf.IgnoreMaterial && type.IsAssignableFromInverse(typeof(Material))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (conf.IgnoreSprite && type.Name.Contains("Texture2D")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Asset Cleaner/IgnoreTypes.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 34f1d98d6e464e5ebee0df9de721af39
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
3
Assets/Asset Cleaner/Systems.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4b15d89b453047218955641734d4ec9e
|
||||
timeCreated: 1596213484
|
||||
3
Assets/Asset Cleaner/Systems/External.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cbedea52d931409a8b62256873637225
|
||||
timeCreated: 1596214557
|
||||
103
Assets/Asset Cleaner/Systems/External/AufWindow.cs
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
using System.Diagnostics;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Debug = UnityEngine.Debug;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
class AufWindow : EditorWindow {
|
||||
[SerializeField] PersistentUndoRedoState _persistentUndo;
|
||||
|
||||
[MenuItem("Window/- Asset Cleaner %L")]
|
||||
static void OpenActiveWindow() {
|
||||
GetWindow<AufWindow>();
|
||||
}
|
||||
|
||||
// restore window state after recompilation
|
||||
void OnEnable() {
|
||||
var wd = Globals<WindowData>.Value = new WindowData();
|
||||
wd.Window = this;
|
||||
wd.Window.titleContent = new GUIContent("Asset Cleaner v1.26");
|
||||
|
||||
var firstTime = _persistentUndo == null;
|
||||
Globals<PersistentUndoRedoState>.Value = _persistentUndo ?? new PersistentUndoRedoState();
|
||||
Globals<BacklinkStore>.Value = new BacklinkStore();
|
||||
var config = Globals<Config>.Value = new Config();
|
||||
PersistenceUtils.Load(ref config);
|
||||
|
||||
if (firstTime || !config.RebuildCacheOnDemand)
|
||||
Globals<BacklinkStore>.Value.Init();
|
||||
|
||||
EditorApplication.update += Upd;
|
||||
EditorApplication.projectWindowItemOnGUI += ProjectViewGui.OnProjectWindowItemOnGui;
|
||||
|
||||
AufCtx.TryInitWorld();
|
||||
|
||||
// need to close window in case of Asset Cleaner uninstalled
|
||||
if (!CleanerStyleAsset.Style.TryFindSelf(out wd.Style))
|
||||
ForceClose();
|
||||
}
|
||||
|
||||
void OnGUI() {
|
||||
var store = Globals<BacklinkStore>.Value;
|
||||
if (!store.Initialized) {
|
||||
// prevent further window GUI rendering
|
||||
var config = Globals<Config>.Value;
|
||||
if (!GUILayout.Button("Initialize Cache")) return;
|
||||
|
||||
var stopwatch = new Stopwatch();
|
||||
stopwatch.Start();
|
||||
store.Init();
|
||||
stopwatch.Stop();
|
||||
config.InitializationTime = $"Initialized in {stopwatch.Elapsed.TotalSeconds:N} s";
|
||||
AufCtx.World.NewEntityWith(out RequestRepaintEvt _);
|
||||
}
|
||||
|
||||
if (Globals<Config>.Value.PendingUpdateUnusedAssets && GUILayout.Button ("Update unused assets")) {
|
||||
ProcessAllAssets.ForceUpdateUnusedAssets ();
|
||||
}
|
||||
|
||||
AufCtx.OnGuiGroup.Run();
|
||||
}
|
||||
|
||||
static void Upd() {
|
||||
if (AufCtx.World == null) {
|
||||
AufCtx.DestroyWorld();
|
||||
return;
|
||||
}
|
||||
|
||||
AufCtx.UndoGroup.Run();
|
||||
if (!Globals<BacklinkStore>.Value.Initialized) return;
|
||||
AufCtx.UpdateGroup.Run();
|
||||
}
|
||||
|
||||
bool _closing;
|
||||
|
||||
void ForceClose() {
|
||||
if (_closing) return;
|
||||
_closing = true;
|
||||
Close();
|
||||
EditorWindow.DestroyImmediate(this);
|
||||
}
|
||||
|
||||
void OnDisable() {
|
||||
if (!AufCtx.Destroyed) {
|
||||
AufCtx.UndoGroup.Destroy();
|
||||
AufCtx.UpdateGroup.Destroy();
|
||||
AufCtx.OnGuiGroup.Destroy();
|
||||
AufCtx.DestroyWorld();
|
||||
}
|
||||
_persistentUndo = Globals<PersistentUndoRedoState>.Value;
|
||||
|
||||
Globals<Config>.Value = default;
|
||||
Globals<PersistentUndoRedoState>.Value = default;
|
||||
Globals<WindowData>.Value = default;
|
||||
|
||||
EditorApplication.update -= Upd;
|
||||
EditorApplication.projectWindowItemOnGUI -= ProjectViewGui.OnProjectWindowItemOnGui;
|
||||
|
||||
// need to close window in case of Asset Cleaner uninstalled
|
||||
if (!CleanerStyleAsset.Style.TryFindSelf(out _))
|
||||
ForceClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Asset Cleaner/Systems/External/AufWindow.cs.meta
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 44ebd7bbb2bb41b4ba0187901e8d583f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
39
Assets/Asset Cleaner/Systems/External/ProcessAllAssets.cs
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
using UnityEditor;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
class ProcessAllAssets : AssetPostprocessor {
|
||||
static void OnPostprocessAllAssets (string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) {
|
||||
if (!AufCtx.InitStarted) return;
|
||||
if (!Globals<BacklinkStore>.Value.Initialized) return;
|
||||
|
||||
var store = Globals<BacklinkStore>.Value;
|
||||
if (store == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var length = movedAssets.Length;
|
||||
for (var i = 0; i < length; i++)
|
||||
store.Replace (movedFromAssetPaths[i], movedAssets[i]);
|
||||
|
||||
foreach (var path in deletedAssets)
|
||||
store.Remove (path);
|
||||
|
||||
foreach (var path in importedAssets)
|
||||
store.RebuildFor (path, true);
|
||||
|
||||
var config = Globals<Config>.Value;
|
||||
if (config.UpdateUnusedAssetsOnDemand) {
|
||||
config.PendingUpdateUnusedAssets = true;
|
||||
}
|
||||
else {
|
||||
ForceUpdateUnusedAssets ();
|
||||
}
|
||||
}
|
||||
|
||||
public static void ForceUpdateUnusedAssets () {
|
||||
Globals<Config>.Value.PendingUpdateUnusedAssets = false;
|
||||
var store = Globals<BacklinkStore>.Value;
|
||||
store.UpdateUnusedAssets ();
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Asset Cleaner/Systems/External/ProcessAllAssets.cs.meta
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 17c1f845fa88d38448c4cf65e9745f30
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
47
Assets/Asset Cleaner/Systems/External/ProjectViewGui.cs
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
static class ProjectViewGui {
|
||||
static CleanerStyleAsset.Style _style = Globals<WindowData>.Value.Style;
|
||||
|
||||
public static void OnProjectWindowItemOnGui(string guid, Rect rect) {
|
||||
if (!Globals<Config>.Value.MarkRed) return;
|
||||
|
||||
var store = Globals<BacklinkStore>.Value;
|
||||
if (!store.Initialized) return;
|
||||
|
||||
var path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
ShowRowQuantity(rect, path, store);
|
||||
|
||||
long size = 0;
|
||||
var _ = store.UnusedFiles.TryGetValue(path, out size) || store.UnusedScenes.TryGetValue(path, out size);
|
||||
|
||||
if (SearchUtils.IsUnused(path)) {
|
||||
var buf = GUI.color;
|
||||
{
|
||||
GUI.color = _style.RedHighlight;
|
||||
GUI.Box(rect, string.Empty);
|
||||
}
|
||||
GUI.color = buf;
|
||||
GUI.Label(rect, CommonUtils.BytesToString(size), _style.ProjectViewCounterLabel);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ShowRowQuantity(Rect rect, string path, BacklinkStore backlinkStore) {
|
||||
if (!AssetDatabase.IsValidFolder(path))
|
||||
return;
|
||||
|
||||
backlinkStore.FoldersWithQty.TryGetValue(path, out var folderWithQty);
|
||||
|
||||
var cntFiles = folderWithQty?.UnusedFilesQty ?? 0;
|
||||
var cntScenes = folderWithQty?.UnusedScenesQty ?? 0;
|
||||
long size = folderWithQty?.UnusedSize ?? 0;
|
||||
|
||||
if (cntFiles == 0 && cntScenes == 0) return;
|
||||
var countStr = cntFiles + cntScenes > 0 ? $"{cntFiles} | {cntScenes} ({CommonUtils.BytesToString(size)})" : "";
|
||||
GUI.Label(rect, countStr, _style.ProjectViewCounterLabel);
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Asset Cleaner/Systems/External/ProjectViewGui.cs.meta
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a17718cc645348b0bc4ed6d7e514ab30
|
||||
timeCreated: 1589032770
|
||||
56
Assets/Asset Cleaner/Systems/SysProcessSearch.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using Leopotam.Ecs;
|
||||
using UnityEngine;
|
||||
using static Asset_Cleaner.AufCtx;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
class SysProcessSearch : IEcsRunSystem {
|
||||
EcsFilter<SelectionChanged> _from = null;
|
||||
|
||||
EcsFilter<Result, SearchResultGui, InSceneResult> SceneResultRows = null;
|
||||
EcsFilter<SceneResult, SceneDetails> ScenePaths = null;
|
||||
EcsFilter<SearchArg>.Exclude<InSceneResult> SearchArgMain = null;
|
||||
EcsFilter<Result, SearchResultGui, FileResultTag> FileResultRows = null;
|
||||
|
||||
public void Run() {
|
||||
if (_from.IsEmpty())
|
||||
return;
|
||||
|
||||
SearchArgMain.AllDestroy();
|
||||
ScenePaths.AllDestroy();
|
||||
FileResultRows.AllDestroy();
|
||||
SceneResultRows.AllDestroy();
|
||||
|
||||
var wd = Globals<WindowData>.Value;
|
||||
if (wd.Window)
|
||||
wd.Window.Repaint();
|
||||
|
||||
foreach (var i in _from.Out(out var get1, out _)) {
|
||||
var t1 = get1[i];
|
||||
if (!t1.Target) continue;
|
||||
wd.FindFrom = t1.From;
|
||||
|
||||
try {
|
||||
switch (t1.From) {
|
||||
case FindModeEnum.Scene:
|
||||
World.NewEntityWith(out SearchArg st);
|
||||
SearchUtils.Init(st, t1.Target, t1.Scene);
|
||||
SearchUtils.InScene(st, t1.Scene);
|
||||
break;
|
||||
case FindModeEnum.File:
|
||||
World.NewEntityWith(out SearchArg arg);
|
||||
SearchUtils.Init(arg, t1.Target);
|
||||
SearchUtils.FilesThatReference(arg);
|
||||
SearchUtils.ScenesThatContain(t1.Target);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
Debug.LogException(e);
|
||||
}
|
||||
}
|
||||
|
||||
_from.AllUnset<SelectionChanged>();
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Asset Cleaner/Systems/SysProcessSearch.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: afd561b0c1384bcc82976f2624afa895
|
||||
timeCreated: 1577287503
|
||||
29
Assets/Asset Cleaner/Systems/SysRepaintWindow.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using Leopotam.Ecs;
|
||||
using UnityEditor;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
class RequestRepaintEvt { }
|
||||
|
||||
class SysRepaintWindow : IEcsRunSystem, IEcsInitSystem {
|
||||
EcsFilter<RequestRepaintEvt> Repaint = null;
|
||||
|
||||
public void Init() {
|
||||
var wd = Globals<WindowData>.Value;
|
||||
wd.SceneFoldout = new GUIContent(AssetPreview.GetMiniTypeThumbnail(typeof(SceneAsset)));
|
||||
wd.ExpandScenes = true;
|
||||
wd.ExpandFiles = true;
|
||||
wd.ScrollPos = Vector2.zero;
|
||||
}
|
||||
|
||||
public void Run() {
|
||||
var wd = Globals<WindowData>.Value;
|
||||
|
||||
if (Repaint.IsEmpty()) return;
|
||||
wd.Window.Repaint();
|
||||
InternalEditorUtility.RepaintAllViews();
|
||||
Repaint.AllDestroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Asset Cleaner/Systems/SysRepaintWindow.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 673a2486762b4e3da784f1657b90bb93
|
||||
timeCreated: 1577288020
|
||||
44
Assets/Asset Cleaner/Systems/SysSceneCleanup.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using Leopotam.Ecs;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
class SceneToClose : IEcsAutoReset {
|
||||
public Scene Scene;
|
||||
public int SelectionId;
|
||||
public bool ForceClose;
|
||||
|
||||
public void Reset() {
|
||||
ForceClose = default;
|
||||
Scene = default;
|
||||
SelectionId = default;
|
||||
}
|
||||
}
|
||||
|
||||
class SysSceneCleanup : IEcsRunSystem, IEcsDestroySystem {
|
||||
EcsFilter<SceneToClose> ScenesToClose = default;
|
||||
|
||||
public void Run() {
|
||||
if (ScenesToClose.IsEmpty()) return;
|
||||
|
||||
var selectionId = Globals<PersistentUndoRedoState>.Value.Id;
|
||||
|
||||
foreach (var i in ScenesToClose.Out(out var g1, out var entities)) {
|
||||
var s = g1[i].Scene;
|
||||
if (g1[i].SelectionId == selectionId && !g1[i].ForceClose) continue;
|
||||
if (Selection.activeGameObject && Selection.activeGameObject.scene == s) continue;
|
||||
if (s.isLoaded) EditorSceneManager.CloseScene(s, removeScene: true);
|
||||
entities[i].Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
// close scenes on window close
|
||||
public void Destroy() {
|
||||
foreach (var i in ScenesToClose.Out(out var g1, out _)) {
|
||||
var s = g1[i].Scene;
|
||||
if (s.isLoaded) EditorSceneManager.CloseScene(s, removeScene: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Asset Cleaner/Systems/SysSceneCleanup.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d42cae4aa3ff4500948ddd623a270120
|
||||
timeCreated: 1596142629
|
||||
191
Assets/Asset Cleaner/Systems/SysUndoRedoSelection.cs
Normal file
@@ -0,0 +1,191 @@
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using Leopotam.Ecs;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using static Asset_Cleaner.AufCtx;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
class CleanupPrevArg { }
|
||||
|
||||
class UndoEvt { }
|
||||
|
||||
class RedoEvt { }
|
||||
|
||||
class SysUndoRedoSelection : IEcsRunSystem, IEcsInitSystem, IEcsDestroySystem {
|
||||
EcsFilter<UndoEvt> UndoEvt = default;
|
||||
EcsFilter<RedoEvt> RedoEvt = default;
|
||||
|
||||
bool _preventHistoryInsert;
|
||||
bool _preventSelectionSet;
|
||||
|
||||
public void Init() {
|
||||
Undo.undoRedoPerformed += OnUndoRedoPerformed;
|
||||
Selection.selectionChanged += OnSelectionChanged;
|
||||
Globals<UndoRedoState>.Value = new UndoRedoState();
|
||||
if (Globals<PersistentUndoRedoState>.Value.History.Count > 0)
|
||||
_preventHistoryInsert = true;
|
||||
OnSelectionChanged(); //init selection
|
||||
}
|
||||
|
||||
public void Destroy() {
|
||||
Undo.undoRedoPerformed -= OnUndoRedoPerformed;
|
||||
Selection.selectionChanged -= OnSelectionChanged;
|
||||
Globals<UndoRedoState>.Value = default;
|
||||
}
|
||||
|
||||
public void Run() {
|
||||
MouseInput();
|
||||
|
||||
if (UndoEvt.IsEmpty() && RedoEvt.IsEmpty()) return;
|
||||
Counters(undo: !UndoEvt.IsEmpty(), redo: !RedoEvt.IsEmpty(), false);
|
||||
_preventHistoryInsert = true;
|
||||
if (!_preventSelectionSet) {
|
||||
(var history, var id) = Globals<PersistentUndoRedoState>.Value;
|
||||
SelectionEntry entry = history[id];
|
||||
if (entry.Valid())
|
||||
Selection.objects = entry.IsGuids
|
||||
? entry.Guids.Select(AssetDatabase.GUIDToAssetPath).Select(AssetDatabase.LoadAssetAtPath<Object>).Where(obj => obj).ToArray()
|
||||
: entry.SceneObjects;
|
||||
}
|
||||
|
||||
_preventSelectionSet = false;
|
||||
|
||||
UndoEvt.AllDestroy();
|
||||
RedoEvt.AllDestroy();
|
||||
}
|
||||
|
||||
|
||||
static void Counters(bool undo, bool redo, bool insertToHistory) {
|
||||
var state = Globals<PersistentUndoRedoState>.Value;
|
||||
World.NewEntityWith(out RequestRepaintEvt _);
|
||||
|
||||
const int MinId = 0;
|
||||
if (insertToHistory) {
|
||||
var entry = new SelectionEntry();
|
||||
|
||||
var count = state.History.Count - 1 - state.Id;
|
||||
if (count > 0)
|
||||
state.History.RemoveRange(state.Id + 1, count);
|
||||
|
||||
state.History.Add(entry);
|
||||
state.Id = MaxId();
|
||||
|
||||
if (Selection.assetGUIDs.Length > 0) {
|
||||
entry.IsGuids = true;
|
||||
entry.Guids = Selection.assetGUIDs;
|
||||
}
|
||||
else {
|
||||
entry.SceneObjects = Selection.objects;
|
||||
}
|
||||
}
|
||||
|
||||
if (undo) {
|
||||
// loop to skip invalid
|
||||
while (true) {
|
||||
state.Id -= 1;
|
||||
if (state.Id < MinId) break;
|
||||
if (state.History[state.Id].Valid()) break;
|
||||
}
|
||||
}
|
||||
|
||||
if (redo) {
|
||||
// loop to skip invalid
|
||||
while (true) {
|
||||
state.Id += 1;
|
||||
if (state.Id > MaxId()) break;
|
||||
if (state.History[state.Id].Valid()) break;
|
||||
}
|
||||
}
|
||||
|
||||
state.Id = Mathf.Clamp(state.Id, MinId, MaxId());
|
||||
|
||||
var undoRedoState = Globals<UndoRedoState>.Value;
|
||||
undoRedoState.UndoEnabled = state.Id != MinId;
|
||||
undoRedoState.RedoEnabled = state.Id != MaxId();
|
||||
|
||||
int MaxId() => Mathf.Max(0, state.History.Count - 1);
|
||||
}
|
||||
|
||||
void OnSelectionChanged() {
|
||||
World.NewEntityWith(out RequestRepaintEvt _);
|
||||
if (Globals<Config>.Value == null || Globals<Config>.Value.Locked) return;
|
||||
Counters(undo: false, redo: false, insertToHistory: !_preventHistoryInsert);
|
||||
_preventHistoryInsert = false;
|
||||
|
||||
World.NewEntityWith(out SelectionChanged comp);
|
||||
World.NewEntityWith(out CleanupPrevArg _);
|
||||
var go = Selection.activeGameObject;
|
||||
if (go && go.scene.IsValid()) {
|
||||
comp.From = FindModeEnum.Scene;
|
||||
comp.Target = go;
|
||||
comp.Scene = go.scene;
|
||||
}
|
||||
else {
|
||||
var guids = Selection.assetGUIDs;
|
||||
// comp.Guids = Selection.assetGUIDs;
|
||||
bool any = guids != null && guids.Length > 0;
|
||||
if (any) {
|
||||
comp.From = FindModeEnum.File;
|
||||
var path = AssetDatabase.GUIDToAssetPath(guids[0]);
|
||||
comp.Target = AssetDatabase.LoadAssetAtPath<Object>(path);
|
||||
}
|
||||
else {
|
||||
comp.From = FindModeEnum.None;
|
||||
comp.Target = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// prevents selection history flooding
|
||||
void OnUndoRedoPerformed() {
|
||||
// below is a hackish way to catch Undo/Redo from editor
|
||||
//if (AufCtx.Destroyed) return;
|
||||
if (!Undo.GetCurrentGroupName().Equals("Selection Change")) return;
|
||||
var evt = Event.current;
|
||||
if (evt == null) return;
|
||||
if (evt.rawType != EventType.KeyDown) return;
|
||||
|
||||
switch (evt.keyCode) {
|
||||
case KeyCode.Z:
|
||||
World.NewEntityWith(out UndoEvt _);
|
||||
_preventSelectionSet = true; // prevent manual Selection set
|
||||
break;
|
||||
case KeyCode.Y:
|
||||
World.NewEntityWith(out RedoEvt _);
|
||||
_preventSelectionSet = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MouseInput() {
|
||||
if (_nextClick > EditorApplication.timeSinceStartup) return;
|
||||
|
||||
var any = false;
|
||||
if (Pressed(0x5)) {
|
||||
World.NewEntityWith(out UndoEvt _);
|
||||
any = true;
|
||||
}
|
||||
|
||||
if (Pressed(0x6)) {
|
||||
World.NewEntityWith(out RedoEvt _);
|
||||
any = true;
|
||||
}
|
||||
|
||||
if (any)
|
||||
_nextClick = EditorApplication.timeSinceStartup + 0.25;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR_WIN
|
||||
[DllImport("USER32.dll")]
|
||||
static extern short GetKeyState(int keycode);
|
||||
#else
|
||||
static short GetKeyState(int keycode) => 0;
|
||||
#endif
|
||||
|
||||
double _nextClick;
|
||||
|
||||
// 5 back, 6 fw
|
||||
static bool Pressed(int keyCode) => (GetKeyState(keyCode) & 0x100) != 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6e6a2f49ce174cabbc560ea8e3e9975c
|
||||
timeCreated: 1596008857
|
||||
978
Assets/Asset Cleaner/Systems/SysWindowGui.cs
Normal file
@@ -0,0 +1,978 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Leopotam.Ecs;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
class FileResultTag { }
|
||||
|
||||
enum TargetTypeEnum {
|
||||
File = 0,
|
||||
Directory = 1,
|
||||
Scene = 2,
|
||||
ObjectInScene = 3,
|
||||
ObjectInStage = 4
|
||||
}
|
||||
|
||||
class SysWindowGui : IEcsRunSystem, IEcsInitSystem {
|
||||
EcsFilter<Result, SearchResultGui, InSceneResult> SceneResultRows = null;
|
||||
EcsFilter<SceneResult, SceneDetails> ScenePaths = null;
|
||||
EcsFilter<SearchArg>.Exclude<InSceneResult> SearchArgMain = null;
|
||||
EcsFilter<Result, SearchResultGui, FileResultTag> FileResultRows = null;
|
||||
|
||||
public void Init() {
|
||||
BacklinkStoreDirty(true);
|
||||
VisualSettingDirty(true);
|
||||
}
|
||||
|
||||
public void Run() {
|
||||
var windowData = Globals<WindowData>.Value;
|
||||
|
||||
_toolbarSelection = GUILayout.Toolbar(_toolbarSelection, _toolbarStrings, GUILayout.ExpandWidth(false));
|
||||
var conf = Globals<Config>.Value;
|
||||
switch (_toolbarSelection) {
|
||||
case 0: {
|
||||
ShowTabMain(conf, windowData);
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
ShowTabSettings(conf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string[] _toolbarStrings = {"Main", "Settings"};
|
||||
|
||||
const int _progressBarShowFromLevel = 10;
|
||||
int _toolbarSelection = 0;
|
||||
|
||||
int _settingIgnoredPathsHash1;
|
||||
|
||||
bool BacklinkStoreDirty(bool set) {
|
||||
var res = Hash() != _settingIgnoredPathsHash1;
|
||||
if (set) _settingIgnoredPathsHash1 = Hash();
|
||||
return res;
|
||||
|
||||
int Hash() {
|
||||
var conf = Globals<Config>.Value;
|
||||
return DirtyUtils.HashCode(conf.IgnorePathContainsCombined,
|
||||
conf.IgnoreMaterial,
|
||||
conf.IgnoreScriptable,
|
||||
conf.IgnoreSprite);
|
||||
}
|
||||
}
|
||||
|
||||
int _settingCodeHash1;
|
||||
|
||||
bool VisualSettingDirty(bool set) {
|
||||
var res = Hash() != _settingCodeHash1;
|
||||
if (set) _settingCodeHash1 = Hash();
|
||||
return res;
|
||||
|
||||
int Hash() {
|
||||
var conf = Globals<Config>.Value;
|
||||
return DirtyUtils.HashCode(
|
||||
conf.MarkRed,
|
||||
conf.ShowInfoBox,
|
||||
conf.RebuildCacheOnDemand,
|
||||
conf.UpdateUnusedAssetsOnDemand);
|
||||
}
|
||||
}
|
||||
|
||||
void ShowTabSettings(Config conf) {
|
||||
using (new EditorGUILayout.VerticalScope()) {
|
||||
EditorGUILayout.Space();
|
||||
|
||||
var enabled = GUI.enabled;
|
||||
GUI.enabled = true;
|
||||
|
||||
|
||||
using (new EditorGUILayout.VerticalScope()) {
|
||||
conf.MarkRed = GUILayout.Toggle(conf.MarkRed, "Display counters and red overlay in Project View");
|
||||
conf.ShowInfoBox = GUILayout.Toggle(conf.ShowInfoBox, "Help suggestions");
|
||||
conf.RebuildCacheOnDemand = GUILayout.Toggle(conf.RebuildCacheOnDemand, "Rebuild cache on demand (when scripts are updated often)");
|
||||
conf.UpdateUnusedAssetsOnDemand = GUILayout.Toggle(conf.UpdateUnusedAssetsOnDemand, "Update unused assets on demand");
|
||||
EditorGUILayout.Space();
|
||||
conf.IgnoreMaterial = GUILayout.Toggle(conf.IgnoreMaterial, "Skip Materials");
|
||||
conf.IgnoreScriptable = GUILayout.Toggle(conf.IgnoreScriptable, "Skip ScriptableObjects");
|
||||
conf.IgnoreSprite = GUILayout.Toggle(conf.IgnoreSprite, "Skip Sprites");
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
GUI.enabled = enabled;
|
||||
|
||||
EditorGUILayout.LabelField("Skip Path(s) contains:");
|
||||
|
||||
conf.IgnorePathContainsCombined = GUILayout.TextArea(conf.IgnorePathContainsCombined);
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope(GUILayout.ExpandWidth(false))) {
|
||||
EditorGUILayout.Space();
|
||||
|
||||
var previous = GUI.enabled;
|
||||
|
||||
GUI.enabled = BacklinkStoreDirty(false) || VisualSettingDirty(false);
|
||||
if (GUILayout.Button("Apply")) {
|
||||
conf.IgnorePathContains = conf.IgnorePathContainsCombined.Split(';')
|
||||
.Where(s => !string.IsNullOrWhiteSpace(s)).ToArray();
|
||||
Apply();
|
||||
}
|
||||
|
||||
GUI.enabled = previous;
|
||||
|
||||
var selectedGuids = Selection.assetGUIDs;
|
||||
var assetPaths = new List<string>();
|
||||
if (selectedGuids.Length > 0) {
|
||||
foreach (var guid in selectedGuids) {
|
||||
var realAssetPath = AssetDatabase.GUIDToAssetPath(guid);
|
||||
var obj = AssetDatabase.LoadAssetAtPath<Object>(realAssetPath);
|
||||
var assetPath = realAssetPath.Replace("Assets/", string.Empty);
|
||||
if (obj is DefaultAsset &&
|
||||
!conf.IgnorePathContains.Any(p => (StringComparer.Ordinal.Equals(p, assetPath)))) {
|
||||
assetPaths.Add(assetPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GUI.enabled = (assetPaths.Count > 0);
|
||||
var foldersList = string.Join(", ", assetPaths);
|
||||
if (GUILayout.Button("Add Selected Path")) {
|
||||
var choice = EditorUtility.DisplayDialog(
|
||||
title: "Asset Cleaner",
|
||||
message:
|
||||
$"Do you really want to add these folder(s) to ignored list: \"{foldersList}\"?",
|
||||
ok: "Ignore",
|
||||
cancel: "Cancel");
|
||||
if (choice) {
|
||||
conf.IgnorePathContainsCombined += $"{foldersList};";
|
||||
conf.IgnorePathContains = conf.IgnorePathContainsCombined.Split(';')
|
||||
.Where(s => !string.IsNullOrWhiteSpace(s)).ToArray();
|
||||
Apply();
|
||||
}
|
||||
}
|
||||
|
||||
GUI.enabled = true;
|
||||
if (GUILayout.Button("Reset")) {
|
||||
var choice = EditorUtility.DisplayDialog(
|
||||
title: "Asset Cleaner",
|
||||
message:
|
||||
$"Do you really want to reset to the factory settings?",
|
||||
ok: "Reset",
|
||||
cancel: "Cancel");
|
||||
if (choice) {
|
||||
var serializable = AufSerializableData.Default();
|
||||
AufSerializableData.OnDeserialize(in serializable, ref conf);
|
||||
Apply();
|
||||
}
|
||||
}
|
||||
|
||||
GUI.enabled = previous;
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField(conf.InitializationTime);
|
||||
|
||||
var buf = GUI.enabled;
|
||||
GUI.enabled = Selection.objects.Length > 0;
|
||||
if (GUILayout.Button("Reserialize selected assets", GUILayout.ExpandWidth(false))) {
|
||||
var paths = Selection.objects.Select(AssetDatabase.GetAssetPath);
|
||||
AssetDatabase.ForceReserializeAssets(paths);
|
||||
EditorApplication.ExecuteMenuItem("File/Save Project");
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
GUI.enabled = buf;
|
||||
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
|
||||
void Apply() {
|
||||
var rebuild = BacklinkStoreDirty(true);
|
||||
VisualSettingDirty(true);
|
||||
PersistenceUtils.Save(in conf);
|
||||
AufCtx.World.NewEntityWith(out RequestRepaintEvt _);
|
||||
if (rebuild)
|
||||
Globals<BacklinkStore>.Value.UpdateUnusedAssets();
|
||||
InternalEditorUtility.RepaintAllViews();
|
||||
}
|
||||
}
|
||||
|
||||
void ShowTabMain(Config conf, WindowData windowData) {
|
||||
var store = Globals<BacklinkStore>.Value;
|
||||
EditorGUIUtility.labelWidth = windowData.Window.position.width * .7f;
|
||||
|
||||
int Hash() => DirtyUtils.HashCode(conf.Locked);
|
||||
var active = SearchArgMain.Get1[0];
|
||||
if (conf.Locked && (windowData.FindFrom == FindModeEnum.File &&
|
||||
(active == null || active.Main == null || !AssetDatabase.Contains(active.Main)))) {
|
||||
conf.Locked = false;
|
||||
AufCtx.World.NewEntityWith(out RequestRepaintEvt _);
|
||||
}
|
||||
|
||||
var style = windowData.Style;
|
||||
var hash = Hash();
|
||||
if (hash != Hash()) {
|
||||
PersistenceUtils.Save(in conf);
|
||||
AufCtx.World.NewEntityWith(out RequestRepaintEvt _);
|
||||
}
|
||||
|
||||
// if (Globals<WindowData>.Get() == null) return;
|
||||
EditorGUILayout.Space();
|
||||
|
||||
SearchArg arg = default;
|
||||
foreach (var i in SearchArgMain) {
|
||||
arg = SearchArgMain.Get1[i];
|
||||
if (arg != null && arg.Main != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (arg == default) {
|
||||
GUI.enabled = false;
|
||||
GUILayout.TextArea("No items selected. Select an item in a scene or project.");
|
||||
GUI.enabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var targetTypeEnum = GetTargetType(windowData, arg?.Main);
|
||||
BacklinkStore.UnusedQty unusedQty = new BacklinkStore.UnusedQty(0, 0, 0);
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope()) {
|
||||
var enabledBuf = GUI.enabled;
|
||||
var selectedGuids = Selection.assetGUIDs;
|
||||
|
||||
var undoRedoState = Globals<UndoRedoState>.Value;
|
||||
|
||||
GUI.enabled = selectedGuids != null && !conf.Locked && undoRedoState.UndoEnabled;
|
||||
if (GUILayout.Button(style.ArrowL, style.ArrowBtn)) {
|
||||
AufCtx.World.NewEntityWith(out UndoEvt _);
|
||||
}
|
||||
|
||||
GUI.enabled = selectedGuids != null && !conf.Locked && undoRedoState.RedoEnabled;
|
||||
if (GUILayout.Button(style.ArrowR, style.ArrowBtn)) {
|
||||
AufCtx.World.NewEntityWith(out RedoEvt _);
|
||||
}
|
||||
|
||||
GUI.enabled = enabledBuf;
|
||||
|
||||
if (conf.Locked) {
|
||||
if (GUILayout.Button(style.Lock, style.LockBtn)) {
|
||||
AufCtx.World.NewEntityWith(out SelectionChanged selectionChanged);
|
||||
conf.Locked = false;
|
||||
if (Selection.activeObject != arg.Target) {
|
||||
selectionChanged.From = FindModeEnum.Scene;
|
||||
selectionChanged.Scene = SceneManager.GetActiveScene();
|
||||
selectionChanged.Target = Selection.activeObject;
|
||||
}
|
||||
else if (Selection.assetGUIDs is string[] guids) {
|
||||
// todo show info box multiple selection is unsupported
|
||||
if (guids.Length > 0) {
|
||||
var path = AssetDatabase.GUIDToAssetPath(guids[0]);
|
||||
selectionChanged.Target = AssetDatabase.LoadAssetAtPath<Object>(path);
|
||||
switch (Selection.selectionChanged.Target) {
|
||||
case DefaultAsset _:
|
||||
selectionChanged.From = FindModeEnum.File;
|
||||
break;
|
||||
case GameObject go when go.scene.isLoaded:
|
||||
selectionChanged.From = FindModeEnum.Scene;
|
||||
selectionChanged.Scene = SceneManager.GetActiveScene();
|
||||
break;
|
||||
default:
|
||||
selectionChanged.From = FindModeEnum.File;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (Selection.activeObject is GameObject go && go.scene.isLoaded) {
|
||||
selectionChanged.From = FindModeEnum.Scene;
|
||||
selectionChanged.Target = Selection.activeObject;
|
||||
selectionChanged.Scene = SceneManager.GetActiveScene();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
var enabled = GUI.enabled;
|
||||
GUI.enabled = selectedGuids != null && selectedGuids.Length == 1;
|
||||
if (GUILayout.Button(style.Unlock, style.UnlockBtn)) {
|
||||
conf.Locked = true;
|
||||
}
|
||||
|
||||
GUI.enabled = enabled;
|
||||
}
|
||||
|
||||
unusedQty = ShowObjectName(store, windowData, targetTypeEnum, arg, selectedGuids);
|
||||
}
|
||||
|
||||
bool isMultiSelect = Selection.assetGUIDs != null && Selection.assetGUIDs.Length > 1;
|
||||
|
||||
if (conf.ShowInfoBox) {
|
||||
if (isMultiSelect && (unusedQty.UnusedFilesQty + unusedQty.UnusedScenesQty > 0)) {
|
||||
var msgUnusedFiles = (unusedQty.UnusedFilesQty > 0)
|
||||
? $"unused files ({unusedQty.UnusedFilesQty}),"
|
||||
: "";
|
||||
var msgUnusedScenes = (unusedQty.UnusedScenesQty > 0)
|
||||
? $"unused scenes ({unusedQty.UnusedScenesQty}),"
|
||||
: "";
|
||||
var msgMultiSelect = $"This multi-selection contains: " +
|
||||
msgUnusedFiles + msgUnusedScenes +
|
||||
$"\nYou could delete them pressing corresponding button to the right.";
|
||||
EditorGUILayout.HelpBox(msgMultiSelect, MessageType.Info);
|
||||
}
|
||||
else if (TryGetHelpInfo(arg, out var msg, out var msgType)) {
|
||||
EditorGUILayout.HelpBox(msg, msgType);
|
||||
}
|
||||
}
|
||||
|
||||
if (targetTypeEnum != TargetTypeEnum.Directory && !isMultiSelect) {
|
||||
var windowData2 = Globals<WindowData>.Value;
|
||||
|
||||
EditorGUILayout.BeginVertical();
|
||||
{
|
||||
windowData2.ScrollPos = EditorGUILayout.BeginScrollView(windowData2.ScrollPos);
|
||||
{
|
||||
RenderRows(windowData2);
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
EditorGUILayout.EndScrollView();
|
||||
}
|
||||
EditorGUILayout.EndVertical();
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool TryGetHelpInfo(SearchArg arg, out string msg, out MessageType msgType) {
|
||||
msgType = MessageType.Info;
|
||||
if (arg == null) {
|
||||
msg = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
var path = arg.FilePath;
|
||||
if (string.IsNullOrEmpty(path)) {
|
||||
msg = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SearchUtils.IgnoredPaths(path, out var subPath)) {
|
||||
msg = $"Paths containing '{subPath}' are ignored. You could add or remove it in Settings tab";
|
||||
return true;
|
||||
}
|
||||
|
||||
if (SearchUtils.IgnoredNonAssets(path) && !path.Eq("Assets")) {
|
||||
msg = $"Asset is outside of Assets folder";
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IgnoreTypes.Check(path, out var type)) {
|
||||
if (AssetDatabase.IsValidFolder(path)) {
|
||||
var scenes = arg.UnusedScenesFiltered?.Count;
|
||||
var files = arg.UnusedAssetsFiltered?.Count;
|
||||
if (scenes == 0 && files == 0) {
|
||||
msg = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
var b = new StringBuilder();
|
||||
b.Append("This directory contains: ");
|
||||
var any = false;
|
||||
|
||||
if (files > 0) {
|
||||
any = true;
|
||||
|
||||
b.Append($"unused files ({files})");
|
||||
}
|
||||
|
||||
if (scenes > 0) {
|
||||
if (any)
|
||||
b.Append(", ");
|
||||
b.Append($"unused scenes ({scenes})");
|
||||
}
|
||||
|
||||
b.Append(
|
||||
".\nYou could delete them pressing corresponding button to the right.\nIf you don't want it to be inspected, please add it to Ignore list in the Settings tab");
|
||||
msg = b.ToString();
|
||||
return true;
|
||||
}
|
||||
|
||||
msg = $"Assets of type '{type.Name}' are ignored. Please contact support if you need to change it";
|
||||
return true;
|
||||
}
|
||||
|
||||
// if (Filters.ScenePaths.GetEntitiesCount() == 0 && Filters.FileResultRows.GetEntitiesCount() == 0) {
|
||||
if (SearchUtils.IsUnused(path)) {
|
||||
type = AssetDatabase.GetMainAssetTypeAtPath(path);
|
||||
var name = type.IsAssignableFromInverse(typeof(SceneAsset)) ? "scene" : "file";
|
||||
msg =
|
||||
$"This {name} has no explicit serialized usages and potentially could be removed. If you don't want it to be inspected, please add the containing folder to ignore list";
|
||||
return true;
|
||||
}
|
||||
|
||||
msgType = default;
|
||||
msg = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
static TargetTypeEnum GetTargetType(WindowData windowData1, Object obj) {
|
||||
if (obj == null) return TargetTypeEnum.File;
|
||||
var targetTypeEnum = TargetTypeEnum.Directory;
|
||||
var path = AssetDatabase.GetAssetPath(obj);
|
||||
switch (windowData1.FindFrom) {
|
||||
case FindModeEnum.File when obj is DefaultAsset:
|
||||
targetTypeEnum = TargetTypeEnum.Directory;
|
||||
break;
|
||||
case FindModeEnum.File when path.LastIndexOf(".unity", StringComparison.Ordinal) != -1:
|
||||
targetTypeEnum = TargetTypeEnum.Scene;
|
||||
break;
|
||||
case FindModeEnum.File:
|
||||
targetTypeEnum = TargetTypeEnum.File;
|
||||
break;
|
||||
case FindModeEnum.Scene:
|
||||
targetTypeEnum = TargetTypeEnum.ObjectInScene;
|
||||
break;
|
||||
case FindModeEnum.Stage:
|
||||
targetTypeEnum = TargetTypeEnum.ObjectInStage;
|
||||
break;
|
||||
}
|
||||
|
||||
return targetTypeEnum;
|
||||
}
|
||||
|
||||
GUIContent _contentBuf = new GUIContent();
|
||||
GUIContent _buf2 = new GUIContent();
|
||||
|
||||
BacklinkStore.UnusedQty ShowObjectName(BacklinkStore store, WindowData windowData, TargetTypeEnum targetTypeEnum, SearchArg arg, string[] selectedGuids) {
|
||||
float TextWidth() {
|
||||
_buf2.text = _contentBuf.text;
|
||||
return 20f + GUI.skin.button.CalcSize(_buf2).x;
|
||||
}
|
||||
|
||||
if (arg == null || arg.Main == null) return new BacklinkStore.UnusedQty();
|
||||
|
||||
bool isMultiSelect = selectedGuids != null && selectedGuids.Length > 1;
|
||||
|
||||
if (_contentBuf == null) {
|
||||
_contentBuf = new GUIContent {tooltip = $"Click to ping"};
|
||||
}
|
||||
|
||||
_contentBuf.image = isMultiSelect
|
||||
? windowData.Style.MultiSelect.image
|
||||
: AssetPreview.GetMiniThumbnail(arg.Target);
|
||||
_contentBuf.text = string.Empty;
|
||||
_contentBuf.tooltip = string.Empty;
|
||||
|
||||
if (!isMultiSelect) {
|
||||
switch (targetTypeEnum) {
|
||||
case TargetTypeEnum.Directory:
|
||||
if (!SearchArgMain.IsEmpty()) {
|
||||
_contentBuf.text = $"{arg.Main.name} (Folder)";
|
||||
if (GUILayout.Button(_contentBuf, windowData.Style.CurrentBtn,
|
||||
GUILayout.MinWidth(TextWidth()))) {
|
||||
EditorGUIUtility.PingObject(arg.Main);
|
||||
}
|
||||
|
||||
if (AskDeleteUnusedFiles(arg, arg.UnusedAssetsFiltered, windowData))
|
||||
return new BacklinkStore.UnusedQty();
|
||||
|
||||
if (AskDeleteUnusedScenes(arg, arg.UnusedScenesFiltered, windowData))
|
||||
return new BacklinkStore.UnusedQty();
|
||||
}
|
||||
|
||||
break;
|
||||
case TargetTypeEnum.File:
|
||||
_contentBuf.text = $"{arg.Main.name} (File Asset)";
|
||||
if (GUILayout.Button(_contentBuf, windowData.Style.CurrentBtn,
|
||||
GUILayout.MinWidth(TextWidth()))) {
|
||||
EditorGUIUtility.PingObject(arg.Main);
|
||||
}
|
||||
|
||||
bool hasUnusedFile = SearchUtils.IsUnused(arg.FilePath);
|
||||
var previous = GUI.enabled;
|
||||
GUI.enabled = hasUnusedFile;
|
||||
|
||||
if (GUILayout.Button(windowData.Style.RemoveFile,
|
||||
windowData.Style.RemoveUnusedBtn)) {
|
||||
var choice = EditorUtility.DisplayDialog(
|
||||
title: "Asset Cleaner",
|
||||
message:
|
||||
$"Do you really want to remove file: \"{arg.Main.name}\"?",
|
||||
ok: "Remove",
|
||||
cancel: "Cancel");
|
||||
if (choice) {
|
||||
EditorApplication.ExecuteMenuItem("File/Save Project");
|
||||
DeleteWithMeta(arg.FilePath);
|
||||
AssetDatabase.Refresh();
|
||||
SearchUtils.Upd(arg);
|
||||
}
|
||||
}
|
||||
|
||||
GUI.enabled = previous;
|
||||
|
||||
break;
|
||||
case TargetTypeEnum.Scene:
|
||||
_contentBuf.text = $"{arg.Main.name} (Scene)";
|
||||
if (GUILayout.Button(_contentBuf, windowData.Style.CurrentBtn,
|
||||
GUILayout.MinWidth(TextWidth()))) {
|
||||
EditorGUIUtility.PingObject(arg.Main);
|
||||
}
|
||||
|
||||
bool hasUnusedScene = SearchUtils.IsUnused(arg.FilePath);
|
||||
previous = GUI.enabled;
|
||||
GUI.enabled = hasUnusedScene;
|
||||
|
||||
if (GUILayout.Button(windowData.Style.RemoveScene,
|
||||
windowData.Style.RemoveUnusedBtn)) {
|
||||
var choice = EditorUtility.DisplayDialog(
|
||||
title: "Asset Cleaner",
|
||||
message:
|
||||
$"Do you really want to remove scene: {arg.Main.name}?",
|
||||
ok: "Remove",
|
||||
cancel: "Cancel");
|
||||
if (choice) {
|
||||
EditorApplication.ExecuteMenuItem("File/Save Project");
|
||||
DeleteWithMeta(arg.FilePath);
|
||||
AssetDatabase.Refresh();
|
||||
SearchUtils.Upd(arg);
|
||||
}
|
||||
}
|
||||
|
||||
GUI.enabled = previous;
|
||||
break;
|
||||
case TargetTypeEnum.ObjectInScene:
|
||||
_contentBuf.text = $"{arg.Main.name} (Object in Scene)";
|
||||
|
||||
if (GUILayout.Button(_contentBuf, windowData.Style.CurrentBtn,
|
||||
GUILayout.MinWidth(TextWidth()))) {
|
||||
EditorGUIUtility.PingObject(arg.Main);
|
||||
}
|
||||
|
||||
break;
|
||||
case TargetTypeEnum.ObjectInStage:
|
||||
_contentBuf.image = AssetPreview.GetMiniThumbnail(arg.Target);
|
||||
_contentBuf.text = $"{arg.Main.name} (Object in Staging)";
|
||||
|
||||
if (GUILayout.Button(_contentBuf,
|
||||
windowData.Style.RemoveUnusedBtn)) {
|
||||
EditorGUIUtility.PingObject(arg.Main);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
if (GUILayout.Button($"{arg.Main.name} (Unknown Object Type)",
|
||||
windowData.Style.RemoveUnusedBtn)) {
|
||||
EditorGUIUtility.PingObject(arg.Main);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
var unusedAssets = new List<string>();
|
||||
var unusedScenes = new List<string>();
|
||||
|
||||
foreach (var guid in selectedGuids) {
|
||||
var path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
|
||||
if (store.UnusedFiles.TryGetValue(path, out _))
|
||||
unusedAssets.Add(path);
|
||||
|
||||
else if (store.UnusedScenes.TryGetValue(path, out _))
|
||||
unusedScenes.Add(path);
|
||||
|
||||
if (store.FoldersWithQty.TryGetValue(path, out _)) {
|
||||
SearchArg searchArg = new SearchArg() {
|
||||
FilePath = path,
|
||||
Target = AssetDatabase.LoadAssetAtPath<DefaultAsset>(path),
|
||||
Main = AssetDatabase.LoadAssetAtPath<DefaultAsset>(path)
|
||||
};
|
||||
SearchUtils.Upd(searchArg);
|
||||
|
||||
foreach (var unusedAssetPath in searchArg.UnusedAssetsFiltered)
|
||||
if (store.UnusedFiles.TryGetValue(unusedAssetPath, out _))
|
||||
unusedAssets.Add(unusedAssetPath);
|
||||
|
||||
foreach (var unusedScenePath in searchArg.UnusedScenesFiltered)
|
||||
if (store.UnusedScenes.TryGetValue(unusedScenePath, out _))
|
||||
unusedScenes.Add(unusedScenePath);
|
||||
}
|
||||
}
|
||||
|
||||
unusedAssets = unusedAssets.Distinct().ToList();
|
||||
unusedScenes = unusedScenes.Distinct().ToList();
|
||||
|
||||
var assetSize = unusedAssets.Sum(p => new FileInfo(p).Length);
|
||||
var sceneSize = unusedScenes.Sum(p => new FileInfo(p).Length);
|
||||
|
||||
_contentBuf.text =
|
||||
$"Assets: {unusedAssets.Count} ({CommonUtils.BytesToString(assetSize)}), Scenes: {unusedScenes.Count} ({CommonUtils.BytesToString(sceneSize)})";
|
||||
;
|
||||
|
||||
GUILayout.Button(_contentBuf, windowData.Style.CurrentBtn, GUILayout.MinWidth(TextWidth()));
|
||||
|
||||
if (AskDeleteUnusedFiles(arg, unusedAssets, windowData))
|
||||
return new BacklinkStore.UnusedQty();
|
||||
|
||||
if (AskDeleteUnusedScenes(arg, unusedScenes, windowData))
|
||||
return new BacklinkStore.UnusedQty();
|
||||
|
||||
return new BacklinkStore.UnusedQty(unusedAssets.Count, unusedScenes.Count, assetSize + sceneSize);
|
||||
}
|
||||
|
||||
return new BacklinkStore.UnusedQty();
|
||||
}
|
||||
|
||||
static bool AskDeleteUnusedFiles(SearchArg arg, List<string> unusedAssets, WindowData windowData) {
|
||||
if (arg == null || unusedAssets == null) return false;
|
||||
var hasUnusedAssets = unusedAssets.Count > 0;
|
||||
var previous = GUI.enabled;
|
||||
GUI.enabled = hasUnusedAssets;
|
||||
|
||||
var guiContentRemoveAssets = windowData.Style.RemoveFile;
|
||||
|
||||
if (GUILayout.Button(guiContentRemoveAssets,
|
||||
windowData.Style.RemoveUnusedBtn)) {
|
||||
var choice = EditorUtility.DisplayDialog(
|
||||
title: "Asset Cleaner",
|
||||
message:
|
||||
$"Do you really want to remove {unusedAssets.Count} asset(s)?",
|
||||
ok: "Remove",
|
||||
cancel: "Cancel");
|
||||
if (choice) {
|
||||
EditorApplication.ExecuteMenuItem("File/Save Project");
|
||||
|
||||
var i = 0f;
|
||||
var total = (float) unusedAssets.Count;
|
||||
|
||||
foreach (var f in unusedAssets) {
|
||||
var path = Application.dataPath.Replace("Assets", f);
|
||||
DeleteWithMeta(path);
|
||||
|
||||
var percent = i * 100 / total;
|
||||
if (total >= _progressBarShowFromLevel) {
|
||||
if (Math.Abs(percent % 5f) < 0.01f) {
|
||||
if (EditorUtility.DisplayCancelableProgressBar(
|
||||
"Please wait...",
|
||||
"Deleting assets...", percent))
|
||||
throw new Exception("Deleting aborted");
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (total >= _progressBarShowFromLevel) {
|
||||
EditorUtility.ClearProgressBar();
|
||||
}
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
SearchUtils.Upd(arg);
|
||||
}
|
||||
|
||||
GUI.enabled = previous;
|
||||
return true;
|
||||
}
|
||||
|
||||
GUI.enabled = previous;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void DeleteWithMeta(string path) {
|
||||
FileUtil.DeleteFileOrDirectory(path);
|
||||
var metaPath = AssetDatabase.GetTextMetaFilePathFromAssetPath(path);
|
||||
if (!string.IsNullOrEmpty(metaPath))
|
||||
FileUtil.DeleteFileOrDirectory(metaPath);
|
||||
}
|
||||
|
||||
static bool AskDeleteUnusedScenes(SearchArg arg, List<string> unusedScenes, WindowData windowData) {
|
||||
if (arg == null || unusedScenes == null) return false;
|
||||
var hasUnusedScenes = unusedScenes.Count > 0;
|
||||
var previous = GUI.enabled;
|
||||
GUI.enabled = hasUnusedScenes;
|
||||
|
||||
var guiContentRemoveScenes = windowData.Style.RemoveScene;
|
||||
|
||||
if (GUILayout.Button(guiContentRemoveScenes,
|
||||
windowData.Style.RemoveUnusedBtn)) {
|
||||
var choice = EditorUtility.DisplayDialog(
|
||||
title: "Asset Cleaner",
|
||||
message:
|
||||
$"Do you really want to remove {unusedScenes.Count} scene(s)?",
|
||||
ok: "Remove",
|
||||
cancel: "Cancel");
|
||||
if (choice) {
|
||||
EditorApplication.ExecuteMenuItem("File/Save Project");
|
||||
|
||||
var i = 0f;
|
||||
var total = (float) unusedScenes.Count;
|
||||
|
||||
foreach (var scene in unusedScenes) {
|
||||
var path = Application.dataPath.Replace("Assets", scene);
|
||||
DeleteWithMeta(path);
|
||||
|
||||
if (total >= _progressBarShowFromLevel) {
|
||||
var percent = i * 100 / total;
|
||||
if (Math.Abs(percent % 5f) < 0.01f) {
|
||||
if (EditorUtility.DisplayCancelableProgressBar(
|
||||
"Please wait...",
|
||||
"Deleting scenes...", percent))
|
||||
throw new Exception("Deleting aborted");
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (total >= _progressBarShowFromLevel) {
|
||||
EditorUtility.ClearProgressBar();
|
||||
}
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
SearchUtils.Upd(arg);
|
||||
}
|
||||
|
||||
GUI.enabled = previous;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
GUI.enabled = previous;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void RenderRows(WindowData windowData) {
|
||||
// todo show spinner until scene is loaded,
|
||||
|
||||
if (FileResultRows.GetEntitiesCount() > 0) {
|
||||
windowData.ExpandFiles =
|
||||
EditorGUILayout.Foldout(windowData.ExpandFiles,
|
||||
$"Usages in Project: {FileResultRows.GetEntitiesCount()}");
|
||||
}
|
||||
|
||||
if (SearchArgMain.IsEmpty())
|
||||
return;
|
||||
|
||||
if (windowData.ExpandFiles && windowData.FindFrom == FindModeEnum.File)
|
||||
foreach (var i in FileResultRows.Out(out var get1, out var get2, out _, out _))
|
||||
DrawRowFile(get1[i], get2[i], windowData);
|
||||
|
||||
|
||||
var sceneMessage = $"Usages in Scenes: {ScenePaths.GetEntitiesCount()}";
|
||||
if (ScenePaths.GetEntitiesCount() > 0) {
|
||||
windowData.ExpandScenes =
|
||||
EditorGUILayout.Foldout(windowData.ExpandScenes, sceneMessage);
|
||||
}
|
||||
|
||||
|
||||
if (!windowData.ExpandScenes) return;
|
||||
|
||||
if (windowData.ExpandScenes && windowData.FindFrom == FindModeEnum.Scene) {
|
||||
foreach (var (grp, indices) in SceneResultRows.Out(out _, out var get2, out _, out _)
|
||||
.GroupBy1(ResultComp.Instance)) {
|
||||
using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) {
|
||||
var count = 0;
|
||||
foreach (var i in indices) {
|
||||
if (count++ == 0)
|
||||
if (GUILayout.Button(get2[i].Label, windowData.Style.RowMainAssetBtn)) {
|
||||
if (windowData.Click.IsDoubleClick(grp.RootGo)) {
|
||||
// _selectionChangedByArrows = false;
|
||||
Selection.activeObject = grp.RootGo;
|
||||
}
|
||||
else
|
||||
EditorGUIUtility.PingObject(grp.RootGo);
|
||||
|
||||
windowData.Click = new PrevClick(grp.RootGo);
|
||||
}
|
||||
|
||||
DrawRowScene(get2[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using (new GUILayout.HorizontalScope()) {
|
||||
GUILayout.Space(windowData.Style.SceneIndent1);
|
||||
using (new EditorGUILayout.VerticalScope()) {
|
||||
foreach (var i1 in ScenePaths.Out(out var get1, out var get2, out _)) {
|
||||
windowData.SceneFoldout.text = get1[i1].PathNicified;
|
||||
var details = get2[i1];
|
||||
|
||||
details.SearchRequested = details.Scene.isLoaded;
|
||||
details.SearchRequested = EditorGUILayout.Foldout(details.SearchRequested,
|
||||
windowData.SceneFoldout, EditorStyles.foldout);
|
||||
if (details.SearchRequested && details.Scene.isLoaded && !details.SearchDone) {
|
||||
var mainArg = SearchArgMain.GetSingle();
|
||||
|
||||
mainArg.Scene = SceneManager.GetSceneByPath(details.Scene.path);
|
||||
|
||||
SearchUtils.InScene(mainArg, details.Scene);
|
||||
details.SearchDone = true;
|
||||
}
|
||||
|
||||
if (!details.SearchRequested) {
|
||||
if (!details.Scene.isLoaded) continue;
|
||||
if (!details.WasOpened) {
|
||||
// to clean up on selection change
|
||||
AufCtx.World.NewEntityWith(out SceneToClose comp);
|
||||
comp.Scene = details.Scene;
|
||||
comp.ForceClose = true;
|
||||
}
|
||||
|
||||
foreach (var row in SceneResultRows.Out(out _, out _, out var get3, out var entities)) {
|
||||
if (!get3[row].ScenePath.Eq(details.Path))
|
||||
continue;
|
||||
|
||||
entities[row].Destroy();
|
||||
}
|
||||
|
||||
details.SearchDone = false;
|
||||
}
|
||||
else {
|
||||
if (!details.Scene.isLoaded) {
|
||||
details.Scene = EditorSceneManager.OpenScene(details.Path, OpenSceneMode.Additive);
|
||||
|
||||
// to clean up on selection change
|
||||
AufCtx.World.NewEntityWith(out SceneToClose comp);
|
||||
comp.Scene = details.Scene;
|
||||
comp.SelectionId = Globals<PersistentUndoRedoState>.Value.Id;
|
||||
|
||||
|
||||
#if UNITY_2019_1_OR_NEWER
|
||||
EditorSceneManager.SetSceneCullingMask(details.Scene, 0);
|
||||
#endif
|
||||
details.SearchRequested = true;
|
||||
// todo Scope component
|
||||
#if later
|
||||
if (details.Scene.isLoaded)
|
||||
EditorSceneManager.CloseScene(details.Scene, false);
|
||||
#endif
|
||||
}
|
||||
else if (SceneResultRows.IsEmpty())
|
||||
EditorGUILayout.LabelField("No in-scene dependencies found.");
|
||||
else
|
||||
using (new GUILayout.HorizontalScope()) {
|
||||
GUILayout.Space(windowData.Style.SceneIndent2);
|
||||
using (new EditorGUILayout.VerticalScope())
|
||||
foreach (var (grp, indices) in SceneResultRows
|
||||
.Out(out var g1, out var g2, out var g3, out _)
|
||||
.GroupBy1(ResultComp.Instance)) {
|
||||
var any = false;
|
||||
foreach (var i3 in indices) {
|
||||
if (!g3[i3].ScenePath.Eq(details.Path))
|
||||
continue;
|
||||
any = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!any)
|
||||
continue;
|
||||
|
||||
using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) {
|
||||
var count = 0;
|
||||
foreach (var i2 in indices) {
|
||||
if (!g3[i2].ScenePath.Eq(details.Path))
|
||||
continue;
|
||||
|
||||
if (count++ == 0) {
|
||||
Result comp = g1[i2];
|
||||
if (GUILayout.Button(g2[i2].Label,
|
||||
windowData.Style.RowMainAssetBtn)) {
|
||||
if (windowData.Click.IsDoubleClick(grp.RootGo)) {
|
||||
// _selectionChangedByArrows = false;
|
||||
Selection.activeObject = comp.RootGo;
|
||||
}
|
||||
else
|
||||
EditorGUIUtility.PingObject(comp.RootGo);
|
||||
|
||||
windowData.Click = new PrevClick(comp.RootGo);
|
||||
}
|
||||
}
|
||||
|
||||
DrawRowScene(g2[i2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ResultComp : IEqualityComparer<Result> {
|
||||
public static ResultComp Instance { get; } = new ResultComp();
|
||||
public bool Equals(Result x, Result y) => GetHashCode(x) == GetHashCode(y);
|
||||
public int GetHashCode(Result obj) => obj.RootGo.GetInstanceID();
|
||||
}
|
||||
|
||||
static void DrawRowScene(SearchResultGui gui) {
|
||||
EditorGUI.BeginChangeCheck();
|
||||
// if (data.TargetGo || data.TargetComponent)
|
||||
foreach (var prop in gui.Properties) {
|
||||
{
|
||||
var locked = prop.Property.objectReferenceValue is MonoScript;
|
||||
var f = GUI.enabled;
|
||||
|
||||
if (locked) GUI.enabled = false;
|
||||
|
||||
EditorGUILayout.PropertyField(prop.Property, prop.Content, false);
|
||||
|
||||
if (locked) GUI.enabled = f;
|
||||
}
|
||||
}
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
gui.SerializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
|
||||
static void DrawRowFile(Result data, SearchResultGui gui, WindowData windowData) {
|
||||
using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) {
|
||||
var buf = GUI.color;
|
||||
var pingGo = data.MainFile == null ? data.RootGo : data.MainFile;
|
||||
if (GUILayout.Button(gui.Label, windowData.Style.RowMainAssetBtn)) {
|
||||
if (windowData.Click.IsDoubleClick(pingGo)) {
|
||||
// _selectionChangedByArrows = false;
|
||||
Selection.activeObject = pingGo;
|
||||
}
|
||||
else {
|
||||
EditorGUIUtility.PingObject(pingGo);
|
||||
}
|
||||
|
||||
windowData.Click = new PrevClick(pingGo);
|
||||
}
|
||||
|
||||
GUI.color = buf;
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
if (data.File) {
|
||||
foreach (var prop in gui.Properties) {
|
||||
using (new EditorGUILayout.HorizontalScope()) {
|
||||
var locked = prop.Property.objectReferenceValue is MonoScript;
|
||||
var f = GUI.enabled;
|
||||
if (locked) GUI.enabled = false;
|
||||
EditorGUILayout.PropertyField(prop.Property, prop.Content, false);
|
||||
if (locked) GUI.enabled = f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (EditorGUI.EndChangeCheck()) {
|
||||
gui.SerializedObject.ApplyModifiedProperties();
|
||||
// dependency.SerializedObject.Update();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Asset Cleaner/Systems/SysWindowGui.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 87ac41283aa347c4aece096c90076c7f
|
||||
timeCreated: 1596213420
|
||||
10
Assets/Asset Cleaner/Third-Party Notices.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
Asset Cleaner PRO - Clean | Find References
|
||||
Third-Party Notices
|
||||
|
||||
This asset is governed by the Asset Store EULA; however, the following components are governed by the licenses indicated below:
|
||||
A. [LeoECS] [MIT License] [license and copyright/accreditation details below]
|
||||
|
||||
Copyright (c) 2017 - 2020 Leopotam leopotam@gmail.com
|
||||
|
||||
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 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 THE AUTHORS OR COPYRIGHT HOLDERS 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.
|
||||
7
Assets/Asset Cleaner/Third-Party Notices.txt.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1f955e95e9069b4439aa4fc90e0ee0ab
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Asset Cleaner/Utils.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8f9623ba76cbf214994b7b865c65f362
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
34
Assets/Asset Cleaner/Utils/Asr.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System.Diagnostics;
|
||||
using UnityEngine.Assertions;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
static class FLAGS {
|
||||
// cleanup in release
|
||||
public const string DEBUG = "DEBUG1";
|
||||
public const string M_DISABLE_POOLING = "M_DISABLE_POOLING";
|
||||
}
|
||||
|
||||
static class Asr {
|
||||
#line hidden
|
||||
[Conditional(FLAGS.DEBUG)]
|
||||
public static void AreEqual(int a, int b) {
|
||||
Assert.AreEqual(a, b);
|
||||
}
|
||||
|
||||
[Conditional(FLAGS.DEBUG)]
|
||||
public static void IsTrue(bool b, string format = null) {
|
||||
Assert.IsTrue(b, format);
|
||||
}
|
||||
|
||||
[Conditional(FLAGS.DEBUG)]
|
||||
public static void IsFalse(bool b, string format = null) {
|
||||
Assert.IsFalse(b, format);
|
||||
}
|
||||
|
||||
[Conditional(FLAGS.DEBUG)]
|
||||
public static void IsNotNull(object target, string format = null) {
|
||||
Assert.IsNotNull(target, format);
|
||||
}
|
||||
#line default
|
||||
}
|
||||
}
|
||||
3
Assets/Asset Cleaner/Utils/Asr.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 53c5eeeb89d541a5b26f906f93ffe650
|
||||
timeCreated: 1581424097
|
||||
41
Assets/Asset Cleaner/Utils/AufCtx.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using Leopotam.Ecs;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
static class AufCtx {
|
||||
public static EcsWorld World;
|
||||
|
||||
public static EcsSystems UndoGroup;
|
||||
public static EcsSystems UpdateGroup;
|
||||
public static EcsSystems OnGuiGroup;
|
||||
|
||||
internal static bool InitStarted { get; private set; }
|
||||
internal static bool Destroyed { get; private set; }
|
||||
|
||||
internal static void TryInitWorld() {
|
||||
if (InitStarted) return;
|
||||
InitStarted = true;
|
||||
|
||||
World = new EcsWorld();
|
||||
|
||||
(OnGuiGroup = new EcsSystems(World)
|
||||
.Add(new SysWindowGui())).Init();
|
||||
|
||||
(UndoGroup = new EcsSystems(World)
|
||||
.Add(new SysUndoRedoSelection())
|
||||
).Init();
|
||||
|
||||
(UpdateGroup = new EcsSystems(World)
|
||||
.Add(new SysRepaintWindow())
|
||||
.Add(new SysProcessSearch())
|
||||
.Add(new SysSceneCleanup())
|
||||
).Init();
|
||||
}
|
||||
|
||||
internal static void DestroyWorld() {
|
||||
if (!InitStarted) return;
|
||||
InitStarted = false;
|
||||
Destroyed = true;
|
||||
Asr.IsFalse(__GlobalsCounter.HasAnyValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Asset Cleaner/Utils/AufCtx.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 999cc1329c8dd5743b39fe17eb02a7aa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
23
Assets/Asset Cleaner/Utils/CommonUtils.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
public static class CommonUtils {
|
||||
static string[] _suffix = {"B", "KB", "MB", "GB", "TB"};
|
||||
|
||||
public static string BytesToString(long byteCount) {
|
||||
if (byteCount == 0)
|
||||
return $"0 {_suffix[0]}";
|
||||
|
||||
var bytes = Math.Abs(byteCount);
|
||||
var place = Convert.ToInt32(Math.Floor(Math.Log(bytes, 1024)));
|
||||
double num;
|
||||
if (place == 0 || place == 1) { // display B, KB in MB
|
||||
num = Math.Round(bytes / Math.Pow(1024, 2), 4);
|
||||
return $"{Math.Sign(byteCount) * num:N} {_suffix[2]}";
|
||||
}
|
||||
|
||||
num = Math.Round(bytes / Math.Pow(1024, place), 1);
|
||||
return $"{Math.Sign(byteCount) * num:F0} {_suffix[place]}";
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Asset Cleaner/Utils/CommonUtils.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4a0fa79cb05e495a8dc80a251a33970c
|
||||
timeCreated: 1595072385
|
||||
46
Assets/Asset Cleaner/Utils/DirtyUtils.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
static class DirtyUtils {
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int HashCode<T1>(in T1 v1) {
|
||||
var hash = v1.GetHashCode();
|
||||
hash = (hash * 397);
|
||||
return hash;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int HashCode<T1, T2>(in T1 v1, in T2 v2) {
|
||||
var hash = v1.GetHashCode();
|
||||
hash = (hash * 397) ^ v2.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int HashCode<T1, T2, T3>(in T1 v1, in T2 v2, in T3 v3) {
|
||||
var hash = v1.GetHashCode();
|
||||
hash = (hash * 397) ^ v2.GetHashCode();
|
||||
hash = (hash * 397) ^ v3.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int HashCode<T1, T2, T3, T4>(in T1 v1, in T2 v2, in T3 v3, in T4 v4) {
|
||||
var hash = v1.GetHashCode();
|
||||
hash = (hash * 397) ^ v2.GetHashCode();
|
||||
hash = (hash * 397) ^ v3.GetHashCode();
|
||||
hash = (hash * 397) ^ v4.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int HashCode<T1, T2, T3, T4, T5>(in T1 v1, in T2 v2, in T3 v3, in T4 v4, in T5 v5) {
|
||||
var hash = v1.GetHashCode();
|
||||
hash = (hash * 397) ^ v2.GetHashCode();
|
||||
hash = (hash * 397) ^ v3.GetHashCode();
|
||||
hash = (hash * 397) ^ v4.GetHashCode();
|
||||
hash = (hash * 397) ^ v5.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Asset Cleaner/Utils/DirtyUtils.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3fd8e20db38143e3a3c51ea733bd0bab
|
||||
timeCreated: 1577270369
|
||||
56
Assets/Asset Cleaner/Utils/EcsUtils.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Leopotam.Ecs;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
static class EcsUtils {
|
||||
public static IEnumerable<(T Group, IEnumerable<int> Indices)> GroupBy1<T, T1, T2>(this EcsFilter<T, T1, T2> f, IEqualityComparer<T> comp)
|
||||
where T : class
|
||||
where T1 : class
|
||||
where T2 : class {
|
||||
foreach (var group in Inner().GroupBy(tuple => tuple.Group, comp))
|
||||
yield return (group.Key, group.Select(g => g.EcsIndex));
|
||||
|
||||
IEnumerable<(T Group, int EcsIndex)> Inner() {
|
||||
var get1 = f.Get1;
|
||||
foreach (var i in f) yield return (get1[i], i);
|
||||
}
|
||||
}
|
||||
|
||||
public static EcsFilter<T> Out<T>(this EcsFilter<T> filter, out T[] get1, out EcsEntity[] entities) where T : class {
|
||||
get1 = filter.Get1;
|
||||
entities = filter.Entities;
|
||||
return filter;
|
||||
}
|
||||
|
||||
public static EcsFilter<T1, T2> Out<T1, T2>(this EcsFilter<T1, T2> filter, out T1[] get1, out T2[] get2, out EcsEntity[] entities)
|
||||
where T1 : class where T2 : class {
|
||||
get1 = filter.Get1;
|
||||
get2 = filter.Get2;
|
||||
entities = filter.Entities;
|
||||
return filter;
|
||||
}
|
||||
|
||||
public static EcsFilter<T1, T2, T3> Out<T1, T2, T3>(this EcsFilter<T1, T2, T3> filter, out T1[] get1, out T2[] get2, out T3[] get3, out EcsEntity[] entities)
|
||||
where T1 : class where T2 : class where T3 : class {
|
||||
get1 = filter.Get1;
|
||||
get2 = filter.Get2;
|
||||
get3 = filter.Get3;
|
||||
entities = filter.Entities;
|
||||
return filter;
|
||||
}
|
||||
|
||||
public static void AllDestroy(this EcsFilter f) {
|
||||
var ecsEntities = f.Entities;
|
||||
foreach (var i in f)
|
||||
ecsEntities[i].Destroy();
|
||||
}
|
||||
|
||||
public static void AllUnset<T>(this EcsFilter f) where T : class {
|
||||
var e = f.Entities;
|
||||
foreach (var i in f)
|
||||
e[i].Unset<T>();
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Asset Cleaner/Utils/EcsUtils.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3d81e9bb0744bc4448ddb9bbd93bffd3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
17
Assets/Asset Cleaner/Utils/Ext.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using Leopotam.Ecs;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
static class Ext {
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool Eq(this string s1, string s2) => (s1 == s2);
|
||||
// public static bool Eq(this string s1, string s2) => StringComparer.Ordinal.Equals(s1, s2);
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T GetSingle<T>(this EcsFilter<T> f) where T : class {
|
||||
Asr.AreEqual(f.GetEntitiesCount(), 1);
|
||||
return f.Get1[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Asset Cleaner/Utils/Ext.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 66f6b6922016ea04797deac8d082bc80
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
29
Assets/Asset Cleaner/Utils/Globals.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
namespace Asset_Cleaner {
|
||||
static class Globals<T> where T : class {
|
||||
static T _instance;
|
||||
|
||||
public static T Value {
|
||||
get {
|
||||
Asr.IsFalse(_instance == null);
|
||||
return _instance;
|
||||
}
|
||||
set {
|
||||
var was = HasValue();
|
||||
_instance = value;
|
||||
|
||||
// keep counter to check during deinitialization if all Globals are cleared
|
||||
if (was && !HasValue())
|
||||
__GlobalsCounter.Counter -= 1;
|
||||
if (!was && HasValue())
|
||||
__GlobalsCounter.Counter += 1;
|
||||
|
||||
bool HasValue() => _instance != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class __GlobalsCounter {
|
||||
internal static int Counter;
|
||||
public static bool HasAnyValue() => Counter > 0;
|
||||
}
|
||||
}
|
||||
3
Assets/Asset Cleaner/Utils/Globals.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd0464bfdb1b4253ba131c7140510c81
|
||||
timeCreated: 1596137163
|
||||
124
Assets/Asset Cleaner/Utils/Option.cs
Normal file
@@ -0,0 +1,124 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
readonly struct Option<T> : IEquatable<Option<T>>, IComparable<Option<T>> {
|
||||
// ReSharper disable once StaticMemberInGenericType
|
||||
static readonly bool IsValueType;
|
||||
|
||||
public bool HasValue { get; }
|
||||
|
||||
T Value { get; }
|
||||
|
||||
public static implicit operator Option<T>(T arg) {
|
||||
if (!IsValueType) return ReferenceEquals(arg, null) ? new Option<T>() : new Option<T>(arg, true);
|
||||
#if M_WARN
|
||||
if (arg.Equals(default(T)))
|
||||
Warn.Warning($"{arg} has default value");
|
||||
#endif
|
||||
return new Option<T>(arg, true);
|
||||
}
|
||||
|
||||
static Option() {
|
||||
IsValueType = typeof(T).IsValueType;
|
||||
}
|
||||
|
||||
public void GetOrFail(out T value) {
|
||||
if (!TryGet(out value))
|
||||
Fail($"Option<{typeof(T).Name}> has no value");
|
||||
}
|
||||
|
||||
public T GetOrFail() {
|
||||
if (!TryGet(out var value))
|
||||
Fail($"Option<{typeof(T).Name}> has no value");
|
||||
return value;
|
||||
}
|
||||
|
||||
[Conditional("DEBUG1")]
|
||||
static void Fail(string format = null) {
|
||||
throw new Exception(format);
|
||||
}
|
||||
|
||||
public bool TryGet(out T value) {
|
||||
if (!HasValue) {
|
||||
value = default(T);
|
||||
return false;
|
||||
}
|
||||
|
||||
value = Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
internal Option(T value, bool hasValue) {
|
||||
Value = value;
|
||||
HasValue = hasValue;
|
||||
}
|
||||
|
||||
public T ValueOr(T alternative) {
|
||||
return HasValue ? Value : alternative;
|
||||
}
|
||||
|
||||
// for debug purposes
|
||||
public override string ToString() {
|
||||
if (!HasValue) return "None";
|
||||
|
||||
return Value == null ? "Some(null)" : $"Some({Value})";
|
||||
}
|
||||
|
||||
#region eq comparers boilerplate
|
||||
|
||||
public bool Equals(Option<T> other) {
|
||||
if (!HasValue && !other.HasValue)
|
||||
return true;
|
||||
|
||||
if (HasValue && other.HasValue)
|
||||
return EqualityComparer<T>.Default.Equals(Value, other.Value);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj) {
|
||||
return obj is Option<T> && Equals((Option<T>) obj);
|
||||
}
|
||||
|
||||
public static bool operator ==(Option<T> left, Option<T> right) {
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(Option<T> left, Option<T> right) {
|
||||
return !left.Equals(right);
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
if (!HasValue) return 0;
|
||||
|
||||
return IsValueType || Value != null ? Value.GetHashCode() : 1;
|
||||
}
|
||||
|
||||
public int CompareTo(Option<T> other) {
|
||||
if (HasValue && !other.HasValue) return 1;
|
||||
if (!HasValue && other.HasValue) return -1;
|
||||
|
||||
return Comparer<T>.Default.Compare(Value, other.Value);
|
||||
}
|
||||
|
||||
public static bool operator <(Option<T> left, Option<T> right) {
|
||||
return left.CompareTo(right) < 0;
|
||||
}
|
||||
|
||||
public static bool operator <=(Option<T> left, Option<T> right) {
|
||||
return left.CompareTo(right) <= 0;
|
||||
}
|
||||
|
||||
public static bool operator >(Option<T> left, Option<T> right) {
|
||||
return left.CompareTo(right) > 0;
|
||||
}
|
||||
|
||||
public static bool operator >=(Option<T> left, Option<T> right) {
|
||||
return left.CompareTo(right) >= 0;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
3
Assets/Asset Cleaner/Utils/Option.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 098c45ccebe14f5caa28635386021c94
|
||||
timeCreated: 1591801098
|
||||
57
Assets/Asset Cleaner/Utils/PersistenceUtils.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
static class PersistenceUtils {
|
||||
public static void Load(ref Config result) {
|
||||
var serializable = Deserialize();
|
||||
AufSerializableData.OnDeserialize(in serializable, ref result);
|
||||
}
|
||||
|
||||
public static void Save(in Config src) {
|
||||
AufSerializableData.OnSerialize(in src, out var serializable);
|
||||
var json = JsonUtility.ToJson(serializable);
|
||||
File.WriteAllText(Path, json);
|
||||
}
|
||||
|
||||
static AufSerializableData Deserialize() {
|
||||
AufSerializableData serializableData;
|
||||
string json;
|
||||
|
||||
if (!File.Exists(Path)) {
|
||||
// not exists - write new
|
||||
serializableData = AufSerializableData.Default();
|
||||
json = JsonUtility.ToJson(serializableData);
|
||||
File.WriteAllText(Path, json);
|
||||
}
|
||||
else {
|
||||
// exists
|
||||
json = File.ReadAllText(Path);
|
||||
|
||||
if (string.IsNullOrEmpty(json)) {
|
||||
// but corrupted - overwrite with new
|
||||
serializableData = AufSerializableData.Default();
|
||||
json = JsonUtility.ToJson(serializableData);
|
||||
File.WriteAllText(Path, json);
|
||||
}
|
||||
|
||||
serializableData = JsonUtility.FromJson<AufSerializableData>(json);
|
||||
if (serializableData.Valid())
|
||||
return serializableData;
|
||||
|
||||
serializableData = AufSerializableData.Default();
|
||||
json = JsonUtility.ToJson(serializableData);
|
||||
File.WriteAllText(Path, json);
|
||||
}
|
||||
|
||||
return serializableData;
|
||||
}
|
||||
|
||||
static string Path => $"{Application.temporaryCachePath}/AssetCleaner_{AufSerializableData.CurrentVersion}.json";
|
||||
|
||||
// [MenuItem("Tools/LogPath")]
|
||||
static void Log() {
|
||||
Debug.Log(Application.temporaryCachePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Asset Cleaner/Utils/PersistenceUtils.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 764a6ef52ca2456eb7c276bbcd0929f0
|
||||
timeCreated: 1589466213
|
||||
81
Assets/Asset Cleaner/Utils/Pool.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
class Pool<T> : IDisposable where T : class {
|
||||
Func<T> _ctor;
|
||||
readonly Stack<T> _stack;
|
||||
|
||||
// todo place asserts on app quit
|
||||
Action<T> _reset;
|
||||
Action<T> _destroy;
|
||||
|
||||
static Action<T> Empty = _ => { };
|
||||
|
||||
public Pool(Func<T> ctor, Action<T> reset, Action<T> destroy = null) {
|
||||
_ctor = ctor;
|
||||
#if !M_DISABLE_POOLING
|
||||
_destroy = destroy ?? Empty;
|
||||
_reset = reset;
|
||||
_stack = new Stack<T>();
|
||||
#endif
|
||||
}
|
||||
|
||||
public T Get() {
|
||||
#if M_DISABLE_POOLING
|
||||
return _ctor.Invoke();
|
||||
#else
|
||||
T element;
|
||||
if (_stack.Count == 0) {
|
||||
element = _ctor();
|
||||
}
|
||||
else {
|
||||
element = _stack.Pop();
|
||||
}
|
||||
|
||||
return element;
|
||||
#endif
|
||||
}
|
||||
|
||||
public void Release(ref T element) {
|
||||
#if !M_DISABLE_POOLING
|
||||
Asr.IsFalse(_stack.Count > 0 && ReferenceEquals(_stack.Peek(), element),
|
||||
"Internal error. Trying to release object that is already released to pool. ");
|
||||
|
||||
_reset.Invoke(element);
|
||||
_stack.Push(element);
|
||||
#endif
|
||||
|
||||
element = null;
|
||||
}
|
||||
|
||||
|
||||
public void Dispose() {
|
||||
#if !M_DISABLE_POOLING
|
||||
while (_stack.Count > 0) {
|
||||
var t = _stack.Pop();
|
||||
_destroy.Invoke(t);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public _Scope GetScoped(out T tmp) {
|
||||
tmp = Get();
|
||||
return new _Scope(this, ref tmp);
|
||||
}
|
||||
|
||||
public struct _Scope : IDisposable {
|
||||
Pool<T> _pool;
|
||||
T _val;
|
||||
|
||||
internal _Scope(Pool<T> pool, ref T val) {
|
||||
_pool = pool;
|
||||
_val = val;
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
_pool.Release(ref _val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||