Add main mesh fixes
This commit is contained in:
parent
c89f326c37
commit
989424e659
8
Assets/Asset Cleaner.meta
Normal file
8
Assets/Asset Cleaner.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3b69e6d6a63f3f74e8ea14c2dc3f7812
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
15
Assets/Asset Cleaner/AssetCleaner.asmdef
Normal file
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
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
1236
Assets/Asset Cleaner/CleanerStyle.asset
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 40a73520157b85a4199ff8fa3f867660
|
||||
guid: 7f4dfe9d348c0ff4cb525a0b2c48fc34
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 112000000
|
||||
mainObjectFileID: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/Asset Cleaner/Content.meta
Normal file
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
(Stored with Git LFS)
Normal file
BIN
Assets/Asset Cleaner/Content/ac_back1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
110
Assets/Asset Cleaner/Content/ac_back1.png.meta
Normal file
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
(Stored with Git LFS)
Normal file
BIN
Assets/Asset Cleaner/Content/ac_delete_asset.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -1,12 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 111dd15a59f754d46a87913104dbb489
|
||||
guid: f4b3e5a29ec20194a8ba1d6cf7b1b037
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
serializedVersion: 9
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
@ -21,9 +21,8 @@ TextureImporter:
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 1
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
@ -32,13 +31,13 @@ TextureImporter:
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 3
|
||||
mipBias: 0
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -100
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 1
|
||||
wrapW: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
@ -49,23 +48,41 @@ TextureImporter:
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 0
|
||||
alphaIsTransparency: 0
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 6
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
- serializedVersion: 2
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
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
|
||||
@ -74,7 +91,6 @@ TextureImporter:
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
@ -82,12 +98,10 @@ TextureImporter:
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
BIN
Assets/Asset Cleaner/Content/ac_delete_scene_asset.png
(Stored with Git LFS)
Normal file
BIN
Assets/Asset Cleaner/Content/ac_delete_scene_asset.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -1,12 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6d18636b5c1d2ad49869d53de6329a8a
|
||||
guid: 3fec3bf4c4f5e2d48835dbe2f21aa7d0
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
serializedVersion: 9
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
@ -21,9 +21,8 @@ TextureImporter:
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 1
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
@ -32,13 +31,13 @@ TextureImporter:
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 3
|
||||
mipBias: 0
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -100
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 1
|
||||
wrapW: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
@ -49,23 +48,41 @@ TextureImporter:
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 0
|
||||
alphaIsTransparency: 0
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 6
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
- serializedVersion: 2
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
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
|
||||
@ -74,7 +91,6 @@ TextureImporter:
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
@ -82,12 +98,10 @@ TextureImporter:
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
BIN
Assets/Asset Cleaner/Content/ac_forward1.png
(Stored with Git LFS)
Normal file
BIN
Assets/Asset Cleaner/Content/ac_forward1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
110
Assets/Asset Cleaner/Content/ac_forward1.png.meta
Normal file
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
(Stored with Git LFS)
Normal file
BIN
Assets/Asset Cleaner/Content/ac_lock.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -1,12 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a5ade20c3b0640c4aa089c87345bf1b9
|
||||
guid: c5fd88366c67daf4585631953fa79779
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
serializedVersion: 9
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
@ -21,9 +21,8 @@ TextureImporter:
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 1
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
@ -32,13 +31,13 @@ TextureImporter:
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 3
|
||||
mipBias: 0
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -100
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 1
|
||||
wrapW: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
@ -49,23 +48,41 @@ TextureImporter:
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 0
|
||||
alphaIsTransparency: 0
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 6
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
- serializedVersion: 2
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
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
|
||||
@ -74,7 +91,6 @@ TextureImporter:
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
@ -82,12 +98,10 @@ TextureImporter:
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
BIN
Assets/Asset Cleaner/Content/ac_multiselect.png
(Stored with Git LFS)
Normal file
BIN
Assets/Asset Cleaner/Content/ac_multiselect.png
(Stored with Git LFS)
Normal file
Binary file not shown.
110
Assets/Asset Cleaner/Content/ac_multiselect.png.meta
Normal file
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
(Stored with Git LFS)
Normal file
BIN
Assets/Asset Cleaner/Content/ac_unlock.png
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -1,12 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7f2cb3f82f1849348bd89908a38ba764
|
||||
guid: e755b5ef4cb427f469ba580ae9956237
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
serializedVersion: 9
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
@ -21,9 +21,8 @@ TextureImporter:
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 1
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
@ -32,13 +31,13 @@ TextureImporter:
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 3
|
||||
mipBias: 0
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -100
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 1
|
||||
wrapW: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
@ -49,23 +48,41 @@ TextureImporter:
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 0
|
||||
alphaIsTransparency: 0
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 6
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
- serializedVersion: 2
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
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
|
||||
@ -74,7 +91,6 @@ TextureImporter:
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
@ -82,12 +98,10 @@ TextureImporter:
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
8
Assets/Asset Cleaner/Data.meta
Normal file
8
Assets/Asset Cleaner/Data.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4848aa5846cd6264c984dcc6cd9d72af
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
74
Assets/Asset Cleaner/Data/AufSerializableData.cs
Normal file
74
Assets/Asset Cleaner/Data/AufSerializableData.cs
Normal file
@ -0,0 +1,74 @@
|
||||
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 bool ShowInfoBox;
|
||||
public string IgnorePathContainsCombined;
|
||||
public bool IgnoreMaterial;
|
||||
public bool IgnoreScriptable;
|
||||
|
||||
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,
|
||||
RebuildCacheOnDemand = 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.RebuildCacheOnDemand = BoolToInt(src.RebuildCacheOnDemand);
|
||||
}
|
||||
|
||||
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.RebuildCacheOnDemand = IntToBool(src.RebuildCacheOnDemand, def.RebuildCacheOnDemand == 2);
|
||||
}
|
||||
|
||||
public bool Valid() {
|
||||
return Version == CurrentVersion || IgnorePathContainsCombined == null;
|
||||
}
|
||||
}
|
||||
}
|
3
Assets/Asset Cleaner/Data/AufSerializableData.cs.meta
Normal file
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
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
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
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
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
3
Assets/Asset Cleaner/Data/Globals.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f94bcb0962724eeea17b007a6ddfd885
|
||||
timeCreated: 1596213773
|
286
Assets/Asset Cleaner/Data/Globals/BacklinkStore.cs
Normal file
286
Assets/Asset Cleaner/Data/Globals/BacklinkStore.cs
Normal file
@ -0,0 +1,286 @@
|
||||
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] = CommonUtils.Size(file);
|
||||
|
||||
UnusedScenes = new Dictionary<string, long>();
|
||||
foreach (var scene in scenes) UnusedScenes[scene] = CommonUtils.Size(scene);
|
||||
|
||||
// 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
3
Assets/Asset Cleaner/Data/Globals/BacklinkStore.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 004e5680782f4e679ae93027d2d40023
|
||||
timeCreated: 1577106223
|
20
Assets/Asset Cleaner/Data/Globals/Config.cs
Normal file
20
Assets/Asset Cleaner/Data/Globals/Config.cs
Normal file
@ -0,0 +1,20 @@
|
||||
namespace Asset_Cleaner {
|
||||
class Config {
|
||||
// serialized
|
||||
public bool MarkRed;
|
||||
public string IgnorePathContainsCombined;
|
||||
public bool ShowInfoBox;
|
||||
public bool RebuildCacheOnDemand;
|
||||
|
||||
// todo make type array
|
||||
public bool IgnoreMaterial;
|
||||
public bool IgnoreScriptable;
|
||||
|
||||
// serialized only while window is opened
|
||||
public bool Locked;
|
||||
|
||||
// non-serialized
|
||||
public string[] IgnorePathContains;
|
||||
public string InitializationTime;
|
||||
}
|
||||
}
|
3
Assets/Asset Cleaner/Data/Globals/Config.cs.meta
Normal file
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
3
Assets/Asset Cleaner/Data/SelectionEntry.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2b4476be23474ea4b20262c0ee59983c
|
||||
timeCreated: 1596139978
|
34
Assets/Asset Cleaner/IgnoreTypes.cs
Normal file
34
Assets/Asset Cleaner/IgnoreTypes.cs
Normal file
@ -0,0 +1,34 @@
|
||||
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 (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;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Asset Cleaner/IgnoreTypes.cs.meta
Normal file
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
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
3
Assets/Asset Cleaner/Systems/External.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cbedea52d931409a8b62256873637225
|
||||
timeCreated: 1596214557
|
94
Assets/Asset Cleaner/Systems/External/AufWindow.cs
vendored
Normal file
94
Assets/Asset Cleaner/Systems/External/AufWindow.cs
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
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;
|
||||
|
||||
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
|
||||
if (!GUILayout.Button("Initialize Cache")) return;
|
||||
var stopwatch = new Stopwatch();
|
||||
stopwatch.Start();
|
||||
store.Init();
|
||||
stopwatch.Stop();
|
||||
Globals<Config>.Value.InitializationTime = $"Initialized in {stopwatch.Elapsed.TotalSeconds:N} s";
|
||||
AufCtx.World.NewEntityWith(out RequestRepaintEvt _);
|
||||
}
|
||||
|
||||
AufCtx.OnGuiGroup.Run();
|
||||
}
|
||||
|
||||
static void Upd() {
|
||||
if (AufCtx.World == null) {
|
||||
AufCtx.DestroyWorld();
|
||||
return;
|
||||
}
|
||||
|
||||
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) return;
|
||||
_persistentUndo = Globals<PersistentUndoRedoState>.Value;
|
||||
|
||||
AufCtx.UpdateGroup.Destroy();
|
||||
AufCtx.OnGuiGroup.Destroy();
|
||||
AufCtx.DestroyWorld();
|
||||
|
||||
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
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:
|
23
Assets/Asset Cleaner/Systems/External/ProcessAllAssets.cs
vendored
Normal file
23
Assets/Asset Cleaner/Systems/External/ProcessAllAssets.cs
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
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;
|
||||
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);
|
||||
|
||||
store.UpdateUnusedAssets();
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Asset Cleaner/Systems/External/ProcessAllAssets.cs.meta
vendored
Normal file
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
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
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
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
3
Assets/Asset Cleaner/Systems/SysProcessSearch.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: afd561b0c1384bcc82976f2624afa895
|
||||
timeCreated: 1577287503
|
30
Assets/Asset Cleaner/Systems/SysRepaintWindow.cs
Normal file
30
Assets/Asset Cleaner/Systems/SysRepaintWindow.cs
Normal file
@ -0,0 +1,30 @@
|
||||
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;
|
||||
wd.Window.titleContent = new GUIContent("Asset Cleaner v1.0");
|
||||
}
|
||||
|
||||
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
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
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
3
Assets/Asset Cleaner/Systems/SysSceneCleanup.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d42cae4aa3ff4500948ddd623a270120
|
||||
timeCreated: 1596142629
|
190
Assets/Asset Cleaner/Systems/SysUndoRedoSelection.cs
Normal file
190
Assets/Asset Cleaner/Systems/SysUndoRedoSelection.cs
Normal file
@ -0,0 +1,190 @@
|
||||
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.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 (!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
|
970
Assets/Asset Cleaner/Systems/SysWindowGui.cs
Normal file
970
Assets/Asset Cleaner/Systems/SysWindowGui.cs
Normal file
@ -0,0 +1,970 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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)");
|
||||
EditorGUILayout.Space();
|
||||
conf.IgnoreMaterial = GUILayout.Toggle(conf.IgnoreMaterial, "Ignore Materials");
|
||||
conf.IgnoreScriptable = GUILayout.Toggle(conf.IgnoreScriptable, "Ignore ScriptableObjects");
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
GUI.enabled = enabled;
|
||||
|
||||
EditorGUILayout.LabelField("Ignore 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)
|
||||
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); //TODO?
|
||||
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(CommonUtils.Size);
|
||||
var sceneSize = unusedScenes.Sum(CommonUtils.Size);
|
||||
|
||||
_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
3
Assets/Asset Cleaner/Systems/SysWindowGui.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 87ac41283aa347c4aece096c90076c7f
|
||||
timeCreated: 1596213420
|
8
Assets/Asset Cleaner/Utils.meta
Normal file
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
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
3
Assets/Asset Cleaner/Utils/Asr.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 53c5eeeb89d541a5b26f906f93ffe650
|
||||
timeCreated: 1581424097
|
37
Assets/Asset Cleaner/Utils/AufCtx.cs
Normal file
37
Assets/Asset Cleaner/Utils/AufCtx.cs
Normal file
@ -0,0 +1,37 @@
|
||||
using Leopotam.Ecs;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
static class AufCtx {
|
||||
public static EcsWorld World;
|
||||
|
||||
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();
|
||||
|
||||
(UpdateGroup = new EcsSystems(World)
|
||||
.Add(new SysRepaintWindow())
|
||||
.Add(new SysUndoRedoSelection())
|
||||
.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
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:
|
40
Assets/Asset Cleaner/Utils/CommonUtils.cs
Normal file
40
Assets/Asset Cleaner/Utils/CommonUtils.cs
Normal file
@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
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]}";
|
||||
}
|
||||
|
||||
// todo
|
||||
public static long Size(string path) {
|
||||
return TryGetSize(path, out var res) ? res : 0L;
|
||||
}
|
||||
|
||||
public static bool TryGetSize(string path, out long result) {
|
||||
if (!File.Exists(path)) {
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
var fi = new FileInfo(path);
|
||||
result = fi.Length;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
3
Assets/Asset Cleaner/Utils/CommonUtils.cs.meta
Normal file
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
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
3
Assets/Asset Cleaner/Utils/DirtyUtils.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3fd8e20db38143e3a3c51ea733bd0bab
|
||||
timeCreated: 1577270369
|
55
Assets/Asset Cleaner/Utils/EcsUtils.cs
Normal file
55
Assets/Asset Cleaner/Utils/EcsUtils.cs
Normal file
@ -0,0 +1,55 @@
|
||||
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
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
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
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
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
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
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
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
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
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
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
3
Assets/Asset Cleaner/Utils/Pool.cs.meta
Normal file
3
Assets/Asset Cleaner/Utils/Pool.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b5a618b193c34a5cba77e7cc0df122f1
|
||||
timeCreated: 1591254176
|
458
Assets/Asset Cleaner/Utils/SearchUtils.cs
Normal file
458
Assets/Asset Cleaner/Utils/SearchUtils.cs
Normal file
@ -0,0 +1,458 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Leopotam.Ecs;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Animations;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using static Asset_Cleaner.AufCtx;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Asset_Cleaner {
|
||||
static class SearchUtils {
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsAssignableFromInverse(this Type lhs, Type rhs) {
|
||||
if (lhs == null || rhs == null)
|
||||
return false;
|
||||
|
||||
return rhs.IsAssignableFrom(lhs);
|
||||
}
|
||||
|
||||
static Queue<SerializedProperty> _tmp = new Queue<SerializedProperty>();
|
||||
|
||||
public static void Upd(SearchArg arg) {
|
||||
if (arg.Target is DefaultAsset folder) {
|
||||
var path = AssetDatabase.GetAssetPath(folder);
|
||||
var store = Globals<BacklinkStore>.Value;
|
||||
arg.UnusedAssetsFiltered = store.UnusedFiles.Where(p => p.Key.StartsWith(path)).Select(p => p.Key).ToList();
|
||||
arg.UnusedScenesFiltered = store.UnusedScenes.Where(p => p.Key.StartsWith(path)).Select(p => p.Key).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public static void Init(SearchArg arg, Object target, Scene scene = default) {
|
||||
Asr.IsNotNull(target, "Asset you're trying to search is corrupted");
|
||||
|
||||
arg.Target = target;
|
||||
|
||||
arg.FilePath = AssetDatabase.GetAssetPath(arg.Target);
|
||||
if (!scene.IsValid()) {
|
||||
Upd(arg);
|
||||
|
||||
arg.Main = AssetDatabase.LoadMainAssetAtPath(arg.FilePath);
|
||||
if (AssetDatabase.IsSubAsset(arg.Target)) { }
|
||||
else {
|
||||
switch (target) {
|
||||
case SceneAsset _:
|
||||
// todo support cross-scene references?
|
||||
// nested = all assets
|
||||
break;
|
||||
default:
|
||||
// AssetDatabase.IsMainAssetAtPathLoaded()
|
||||
var subAssets = AssetDatabase.LoadAllAssetsAtPath(arg.FilePath).Where(Predicate).ToArray();
|
||||
arg.SubAssets = subAssets.Length == 0 ? default(Option<Object[]>) : subAssets;
|
||||
|
||||
bool Predicate(Object s) {
|
||||
if (!s)
|
||||
return false;
|
||||
return s.GetInstanceID() != arg.Target.GetInstanceID();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (arg.Target) {
|
||||
case GameObject gg:
|
||||
arg.Main = gg;
|
||||
arg.Scene = scene;
|
||||
arg.SubAssets = gg.GetComponents<Component>().OfType<Object>().ToArray();
|
||||
break;
|
||||
case Component component: {
|
||||
// treat like subAsset
|
||||
arg.Main = component.gameObject;
|
||||
arg.Scene = scene;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// project asset such as Material
|
||||
arg.Main = arg.Target;
|
||||
arg.Scene = scene;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool SearchInChildProperties(SearchArg arg, Object suspect, bool scene, out EcsEntity entity) {
|
||||
if (IsTargetOrNested(arg, suspect)) {
|
||||
entity = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!suspect) {
|
||||
entity = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
var so = new SerializedObject(suspect);
|
||||
_tmp.Clear();
|
||||
var queue = _tmp;
|
||||
var propIterator = so.GetIterator();
|
||||
|
||||
var prefabInstance = false;
|
||||
|
||||
if (scene && !string.IsNullOrEmpty(arg.FilePath) && PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(suspect) == arg.FilePath) {
|
||||
prefabInstance = true;
|
||||
while (propIterator.NextVisible(true)) {
|
||||
if (propIterator.propertyType != SerializedPropertyType.ObjectReference)
|
||||
continue;
|
||||
if (!IsTargetOrNested(arg, propIterator.objectReferenceValue))
|
||||
continue;
|
||||
|
||||
queue.Enqueue(propIterator.Copy());
|
||||
}
|
||||
}
|
||||
else {
|
||||
while (propIterator.Next(true)) {
|
||||
if (propIterator.propertyType != SerializedPropertyType.ObjectReference)
|
||||
continue;
|
||||
if (!IsTargetOrNested(arg, propIterator.objectReferenceValue))
|
||||
continue;
|
||||
|
||||
queue.Enqueue(propIterator.Copy());
|
||||
}
|
||||
}
|
||||
|
||||
if (queue.Count == 0 && !prefabInstance) {
|
||||
entity = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
entity = World.NewEntityWith(out Result data);
|
||||
|
||||
var gui = entity.Set<SearchResultGui>();
|
||||
gui.Properties = new List<SearchResultGui.PropertyData>();
|
||||
gui.SerializedObject = so;
|
||||
gui.Label = new GUIContent();
|
||||
|
||||
// init header
|
||||
Texture2D miniTypeThumbnail = null;
|
||||
if (scene) {
|
||||
switch (suspect) {
|
||||
case Component component:
|
||||
data.RootGo = component.gameObject;
|
||||
gui.TransformPath = AnimationUtility.CalculateTransformPath(component.transform, null);
|
||||
gui.Label.image = AssetPreview.GetMiniThumbnail(data.RootGo);
|
||||
gui.Label.text = gui.TransformPath;
|
||||
break;
|
||||
case GameObject go:
|
||||
data.RootGo = go;
|
||||
gui.Label.image = AssetPreview.GetMiniThumbnail(data.RootGo);
|
||||
gui.TransformPath = AnimationUtility.CalculateTransformPath(go.transform, null);
|
||||
gui.Label.text = gui.TransformPath;
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
miniTypeThumbnail = data.RootGo.GetInstanceID() == suspect.GetInstanceID()
|
||||
? null
|
||||
: AssetPreview.GetMiniThumbnail(suspect);
|
||||
}
|
||||
else {
|
||||
data.File = suspect;
|
||||
data.FilePath = AssetDatabase.GetAssetPath(data.File);
|
||||
data.MainFile = AssetDatabase.LoadMainAssetAtPath(data.FilePath);
|
||||
|
||||
// todo
|
||||
var prefabInstanceStatus = PrefabUtility.GetPrefabInstanceStatus(data.MainFile);
|
||||
switch (prefabInstanceStatus) {
|
||||
case PrefabInstanceStatus.Connected:
|
||||
case PrefabInstanceStatus.Disconnected:
|
||||
switch (data.File) {
|
||||
case Component comp:
|
||||
// transformPath = $"{AnimationUtility.CalculateTransformPath(comp.transform, null)}/".Replace("/", "/\n");
|
||||
gui.TransformPath =
|
||||
$"{AnimationUtility.CalculateTransformPath(comp.transform, null)}";
|
||||
break;
|
||||
case GameObject go:
|
||||
// transformPath = $"{AnimationUtility.CalculateTransformPath(go.transform, null)}/".Replace("/", "/\n");
|
||||
gui.TransformPath =
|
||||
$"{AnimationUtility.CalculateTransformPath(go.transform, null)}";
|
||||
break;
|
||||
default:
|
||||
// Assert.Fail("Not a component"); //todo
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case PrefabInstanceStatus.NotAPrefab:
|
||||
case PrefabInstanceStatus.MissingAsset:
|
||||
if (!AssetDatabase.IsMainAsset(data.File)) {
|
||||
// {row.Main.name}
|
||||
gui.TransformPath = $"/{data.File.name}";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
gui.Label.text = data.FilePath.Replace(AssetsRootPath, string.Empty);
|
||||
gui.Label.image = AssetDatabase.GetCachedIcon(data.FilePath);
|
||||
}
|
||||
|
||||
gui.Label.tooltip = gui.TransformPath;
|
||||
|
||||
|
||||
// init properties (footer)
|
||||
while (queue.Count > 0) {
|
||||
var prop = queue.Dequeue();
|
||||
var targetObject = prop.serializedObject.targetObject;
|
||||
var item = new SearchResultGui.PropertyData {
|
||||
Property = prop,
|
||||
Content = new GUIContent()
|
||||
};
|
||||
item.Content.image = miniTypeThumbnail;
|
||||
item.Content.text = Nicify(prop, targetObject, gui.TransformPath);
|
||||
item.Content.tooltip = gui.TransformPath;
|
||||
var typeName = targetObject.GetType().Name;
|
||||
if (StringComparer.Ordinal.Equals(typeName, targetObject.name))
|
||||
item.Content.tooltip = $"{gui.TransformPath}.{prop.propertyPath}";
|
||||
else
|
||||
item.Content.tooltip = $"{gui.TransformPath}({typeName}).{prop.propertyPath}";
|
||||
gui.Properties.Add(item: item);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool IsFileIgrnoredBySettings(string path) {
|
||||
if (IgnoreTypes.Check(path, out _)) return true;
|
||||
if (IgnoredNonAssets(path)) return true;
|
||||
if (IgnoredPaths(path, out _)) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IgnoredPaths(string path, out string str) {
|
||||
var conf = Globals<Config>.Value;
|
||||
foreach (var substr in conf.IgnorePathContains) {
|
||||
Asr.IsNotNull(path);
|
||||
Asr.IsNotNull(substr);
|
||||
if (!path.Contains(substr)) continue;
|
||||
str = substr;
|
||||
return true;
|
||||
}
|
||||
|
||||
str = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IgnoredNonAssets(string path) {
|
||||
return !path.Contains("Assets/");
|
||||
}
|
||||
|
||||
#region Project
|
||||
|
||||
public static bool IsUnused(string path) {
|
||||
if (IsFileIgrnoredBySettings(path))
|
||||
return false;
|
||||
return !AnyDependencies(path);
|
||||
}
|
||||
|
||||
static bool AnyDependencies(string path) {
|
||||
var store = Globals<BacklinkStore>.Value;
|
||||
if (store.UnusedFiles.Select(p => p.Key).Contains(path))
|
||||
return false;
|
||||
if (store.UnusedScenes.Select(p => p.Key).Contains(path))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void FilesThatReference(SearchArg arg) {
|
||||
var store = Globals<BacklinkStore>.Value;
|
||||
var path1 = AssetDatabase.GetAssetPath(arg.Target);
|
||||
|
||||
if (!store.Backward.TryGetValue(path1, out var dep))
|
||||
return;
|
||||
|
||||
foreach (var path in dep.Lookup) {
|
||||
var mainAsset = AssetDatabase.GetMainAssetTypeAtPath(path);
|
||||
if (mainAsset.IsAssignableFromInverse(typeof(SceneAsset)))
|
||||
continue;
|
||||
|
||||
var any = false;
|
||||
if (mainAsset.IsAssignableFromInverse(typeof(GameObject))) { }
|
||||
else {
|
||||
var allAssetsAtPath = AssetDatabase.LoadAllAssetsAtPath(path);
|
||||
foreach (var suspect in allAssetsAtPath) {
|
||||
if (suspect is DefaultAsset || suspect is Transform || !suspect) continue;
|
||||
|
||||
if (!SearchInChildProperties(arg, suspect, false, out var entity))
|
||||
continue;
|
||||
|
||||
entity.Set<FileResultTag>();
|
||||
any = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (any) continue;
|
||||
|
||||
// failed to find any property - just show main asset
|
||||
var e = World.NewEntity();
|
||||
var gui = e.Set<SearchResultGui>();
|
||||
gui.Properties = new List<SearchResultGui.PropertyData>();
|
||||
var main = AssetDatabase.LoadMainAssetAtPath(path);
|
||||
gui.Label = new GUIContent() {
|
||||
image = AssetPreview.GetMiniThumbnail(main),
|
||||
text = path.Replace(AssetsRootPath, string.Empty)
|
||||
};
|
||||
var res = e.Set<Result>();
|
||||
res.MainFile = main;
|
||||
e.Set<FileResultTag>();
|
||||
}
|
||||
}
|
||||
|
||||
public static void ScenesThatContain(Object activeObject) {
|
||||
var store = Globals<BacklinkStore>.Value;
|
||||
var path1 = AssetDatabase.GetAssetPath(activeObject);
|
||||
if (!store.Backward.TryGetValue(path1, out var dep))
|
||||
return;
|
||||
|
||||
foreach (var path in dep.Lookup) {
|
||||
if (!AssetDatabase.GetMainAssetTypeAtPath(path).IsAssignableFromInverse(typeof(SceneAsset)))
|
||||
continue;
|
||||
|
||||
World.NewEntityWith(out SceneResult sp, out SceneDetails sceneDetails);
|
||||
sp.PathNicified = path.Replace("Assets/", string.Empty);
|
||||
|
||||
// heavy
|
||||
sceneDetails.Path = path;
|
||||
var alreadyOpened = false;
|
||||
for (var i = 0; i < EditorSceneManager.loadedSceneCount; i++) {
|
||||
var cur = SceneManager.GetSceneAt(i);
|
||||
if (!cur.path.Eq(sceneDetails.Path)) continue;
|
||||
alreadyOpened = true;
|
||||
sceneDetails.Scene = cur;
|
||||
}
|
||||
|
||||
sceneDetails.WasOpened = alreadyOpened;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Scene
|
||||
|
||||
static Pool<List<Component>> ComponentListPool = new Pool<List<Component>>(() => new List<Component>(), list => list.Clear());
|
||||
|
||||
// todo provide explicit scene arg
|
||||
public static void InScene(SearchArg arg, Scene currentScene) {
|
||||
var rootGameObjects = currentScene.GetRootGameObjects();
|
||||
|
||||
foreach (var suspect in Traverse(rootGameObjects)) {
|
||||
if (!SearchInChildProperties(arg, suspect, scene: true, out var entity))
|
||||
continue;
|
||||
var s = entity.Set<InSceneResult>();
|
||||
s.ScenePath = arg.Scene.path;
|
||||
}
|
||||
|
||||
IEnumerable<Object> Traverse(GameObject[] roots) {
|
||||
foreach (var rootGo in roots)
|
||||
foreach (var comp in GoAndChildComps(rootGo)) {
|
||||
yield return comp;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerable<Object> GoAndChildComps(GameObject rr) {
|
||||
using (ComponentListPool.GetScoped(out var pooled)) {
|
||||
rr.GetComponents(pooled);
|
||||
foreach (var component in pooled) {
|
||||
if (component is Transform)
|
||||
continue;
|
||||
yield return component;
|
||||
}
|
||||
}
|
||||
|
||||
var transform = rr.transform;
|
||||
var childCount = transform.childCount;
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
var g = transform.GetChild(i).gameObject;
|
||||
foreach (var res in GoAndChildComps(g))
|
||||
yield return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
#if backup
|
||||
static void InScene(SearchArg arg, Scene currentScene) {
|
||||
var allObjects = currentScene
|
||||
.GetRootGameObjects()
|
||||
.SelectMany(g => g.GetComponentsInChildren<Component>(true)
|
||||
.Where(c => c && !(c is Transform))
|
||||
.Union(Enumerable.Repeat(g as Object, 1))
|
||||
)
|
||||
.ToArray();
|
||||
|
||||
var total = allObjects.Length;
|
||||
for (var i = 0; i < total; i++) {
|
||||
var suspect = allObjects[i];
|
||||
|
||||
if (SearchInChildProperties(arg, suspect, true, out var entity)) {
|
||||
var s = entity.Set<InSceneResult>();
|
||||
s.ScenePath = arg.Scene.path;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool IsTargetOrNested(SearchArg target, Object suspect) {
|
||||
if (!suspect)
|
||||
return false;
|
||||
|
||||
if (target.Target.GetInstanceID() == suspect.GetInstanceID() || target.Main.GetInstanceID() == (suspect).GetInstanceID())
|
||||
return true;
|
||||
|
||||
if (target.SubAssets.TryGet(out var subassets))
|
||||
foreach (var asset in subassets) {
|
||||
if (asset.GetInstanceID() == (suspect).GetInstanceID())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static string Nicify(SerializedProperty sp, Object o, string transformPath) {
|
||||
// return sp.propertyPath;
|
||||
|
||||
string nice;
|
||||
switch (o) {
|
||||
case AnimatorState animatorState:
|
||||
return animatorState.name;
|
||||
case Material material:
|
||||
nice = material.name;
|
||||
break;
|
||||
default: {
|
||||
nice = sp.propertyPath.Replace(".Array.data", string.Empty);
|
||||
if (nice.IndexOf(".m_PersistentCalls.m_Calls", StringComparison.Ordinal) > 0) {
|
||||
nice = nice.Replace(".m_PersistentCalls.m_Calls", string.Empty)
|
||||
.Replace(".m_Target", string.Empty);
|
||||
}
|
||||
|
||||
nice = nice.Split('.').Select(t => ObjectNames.NicifyVariableName(t).Replace(" ", string.Empty))
|
||||
.Aggregate((a, b) => a + "." + b);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// nice = $"{transformPath}({o.GetType().Name}).{nice}";
|
||||
nice = $"({o.GetType().Name}).{nice}";
|
||||
return nice;
|
||||
}
|
||||
|
||||
const string AssetsRootPath = "Assets/";
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
3
Assets/Asset Cleaner/Utils/SearchUtils.cs.meta
Normal file
3
Assets/Asset Cleaner/Utils/SearchUtils.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 66f3f357bedc44e2907d7e5f48de45d3
|
||||
timeCreated: 1576134438
|
8
Assets/Asset Cleaner/com.leopotam.ecs.meta
Normal file
8
Assets/Asset Cleaner/com.leopotam.ecs.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cf3dfe88eca681d449c3f24f79d64b4c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user