After feedback patch 1
This commit is contained in:
parent
adc1e94b00
commit
2c851159d6
24
Assets/ForcedArabic.cs
Normal file
24
Assets/ForcedArabic.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using UnityEngine;
|
||||
using TMPro;
|
||||
using ArabicSupport; // Make sure this script is in your project
|
||||
|
||||
[RequireComponent(typeof(TextMeshProUGUI))]
|
||||
public class ForcedArabic : MonoBehaviour
|
||||
{
|
||||
[TextArea(2, 5)]
|
||||
public string rawArabicInput = "العربية"; // You can paste Arabic here
|
||||
|
||||
public bool showTashkeel = true;
|
||||
public bool useHinduNumbers = true;
|
||||
|
||||
private TextMeshProUGUI textMeshPro;
|
||||
|
||||
void Start()
|
||||
{
|
||||
textMeshPro = GetComponent<TextMeshProUGUI>();
|
||||
// textMeshPro.isRightToLeftText = true;
|
||||
|
||||
string fixedText = ArabicFixer.Fix(rawArabicInput, showTashkeel, useHinduNumbers);
|
||||
textMeshPro.text = fixedText;
|
||||
}
|
||||
}
|
11
Assets/ForcedArabic.cs.meta
Normal file
11
Assets/ForcedArabic.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cc004b44880e9b0438fdcabff26b08d8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -140,46 +140,46 @@ MonoBehaviour:
|
||||
english: All of the above
|
||||
arabic: "\u0643\u0644 \u0645\u0627 \u0633\u0628\u0642"
|
||||
- key: whatwerethecluessummary
|
||||
english: "\U0001F4CC Typos & Spelling Errors The email had spelling mistakes
|
||||
or odd grammar \u2014 a common phishing sign. \U0001F4CC Urgency & Pressure
|
||||
It used urgent language to pressure you into acting quickly. \U0001F4CC Link
|
||||
Inspection The link preview didn\u2019t match the real website \u2014 inspect
|
||||
links before clicking. \U0001F4CC Unfamiliar or Unexpected Content The email
|
||||
seemed unrelated to your work \u2014 phishing often comes out of nowhere.
|
||||
\U0001F4CC Generic Greetings It used a generic greeting like Dear user instead
|
||||
of your name. \U0001F4CC Unusual Requests It asked for sensitive info like
|
||||
passwords \u2014 companies don\u2019t do this by email."
|
||||
arabic: "\U0001F4CC \u0623\u062E\u0637\u0627\u0621 \u0625\u0645\u0644\u0627\u0626\u064A\u0629
|
||||
\u0648\u0646\u062D\u0648\u064A\u0629 \u062A\u0636\u0645\u0651\u0646 \u0627\u0644\u0628\u0631\u064A\u062F
|
||||
\u0623\u062E\u0637\u0627\u0621 \u0641\u064A \u0627\u0644\u062A\u0647\u062C\u0626\u0629
|
||||
\u0623\u0648 \u0642\u0648\u0627\u0639\u062F \u0644\u063A\u0648\u064A\u0629
|
||||
\u063A\u0631\u064A\u0628\u0629 \u2014 \u0648\u0647\u0630\u0627 \u0645\u0646
|
||||
\u0639\u0644\u0627\u0645\u0627\u062A \u0627\u0644\u062A\u0635\u064A\u0651\u062F
|
||||
\u0627\u0644\u0634\u0627\u0626\u0639\u0629. \U0001F4CC \u0627\u0644\u0627\u0633\u062A\u0639\u062C\u0627\u0644
|
||||
\u0648\u0627\u0644\u0636\u063A\u0637 \u0627\u0633\u062A\u062E\u062F\u0645 \u0644\u063A\u0629
|
||||
\u0645\u0644\u062D\u0651\u0629 \u0644\u0644\u0636\u063A\u0637 \u0639\u0644\u064A\u0643
|
||||
\u0643\u064A \u062A\u062A\u0635\u0631\u0641 \u0628\u0633\u0631\u0639\u0629.
|
||||
\U0001F4CC \u0641\u062D\u0635 \u0627\u0644\u0631\u0627\u0628\u0637 \u0644\u0645
|
||||
\u064A\u062A\u0637\u0627\u0628\u0642 \u0645\u0639\u0627\u064A\u0646\u0629 \u0627\u0644\u0631\u0627\u0628\u0637
|
||||
english: "Typos & Spelling Errors The email had spelling mistakes or odd grammar
|
||||
\u2014 a common phishing sign. Urgency & Pressure It used urgent language
|
||||
to pressure you into acting quickly. Link Inspection The link preview didn\u2019t
|
||||
match the real website \u2014 inspect links before clicking. Unfamiliar or
|
||||
Unexpected Content The email seemed unrelated to your work \u2014 phishing
|
||||
often comes out of nowhere. Generic Greetings It used a generic greeting like
|
||||
Dear user instead of your name. Unusual Requests It asked for sensitive info
|
||||
like passwords \u2014 companies don\u2019t do this by email.email."
|
||||
arabic: "\u0623\u062E\u0637\u0627\u0621 \u0625\u0645\u0644\u0627\u0626\u064A\u0629
|
||||
\u0648\u0646\u062D\u0648\u064A\u0629 \u0627\u062D\u062A\u0648\u0649 \u0627\u0644\u0628\u0631\u064A\u062F
|
||||
\u0627\u0644\u0625\u0644\u0643\u062A\u0631\u0648\u0646\u064A \u0639\u0644\u0649
|
||||
\u0623\u062E\u0637\u0627\u0621 \u0625\u0645\u0644\u0627\u0626\u064A\u0629 \u0623\u0648
|
||||
\u0646\u062D\u0648\u064A\u0629 \u063A\u0631\u064A\u0628\u0629 \u2014 \u0648\u0647\u064A
|
||||
\u0639\u0644\u0627\u0645\u0629 \u0634\u0627\u0626\u0639\u0629 \u0639\u0644\u0649
|
||||
\u0627\u0644\u062A\u0635\u064A\u062F \u0627\u0644\u0627\u062D\u062A\u064A\u0627\u0644\u064A.
|
||||
\u0627\u0644\u0627\u0633\u062A\u0639\u062C\u0627\u0644 \u0648\u0627\u0644\u0636\u063A\u0637
|
||||
\u0627\u0633\u062A\u062E\u062F\u0645 \u0644\u063A\u0629 \u0639\u0627\u062C\u0644\u0629
|
||||
\u0644\u0644\u0636\u063A\u0637 \u0639\u0644\u064A\u0643 \u0645\u0646 \u0623\u062C\u0644
|
||||
\u0627\u0644\u062A\u0635\u0631\u0641 \u0628\u0633\u0631\u0639\u0629. \u0641\u062D\u0635
|
||||
\u0627\u0644\u0631\u0648\u0627\u0628\u0637 \u0645\u0639\u0627\u064A\u0646\u0629
|
||||
\u0627\u0644\u0631\u0627\u0628\u0637 \u0644\u0645 \u062A\u062A\u0637\u0627\u0628\u0642
|
||||
\u0645\u0639 \u0627\u0644\u0645\u0648\u0642\u0639 \u0627\u0644\u062D\u0642\u064A\u0642\u064A
|
||||
\u2014 \u0627\u0641\u062D\u0635 \u0627\u0644\u0631\u0648\u0627\u0628\u0637
|
||||
\u0642\u0628\u0644 \u0627\u0644\u0646\u0642\u0631 \u0639\u0644\u064A\u0647\u0627.
|
||||
\U0001F4CC \u0645\u062D\u062A\u0648\u0649 \u063A\u064A\u0631 \u0645\u0623\u0644\u0648\u0641
|
||||
\u0623\u0648 \u063A\u064A\u0631 \u0645\u062A\u0648\u0642\u0639 \u0628\u062F\u0627
|
||||
\u0627\u0644\u0628\u0631\u064A\u062F \u063A\u064A\u0631 \u0645\u0631\u062A\u0628\u0637
|
||||
\u0628\u0639\u0645\u0644\u0643 \u2014 \u0641\u0627\u0644\u062A\u0635\u064A\u0651\u062F
|
||||
\u063A\u0627\u0644\u0628\u0627\u064B \u0645\u0627 \u064A\u0623\u062A\u064A
|
||||
\u0645\u0646 \u0645\u0635\u062F\u0631 \u063A\u064A\u0631 \u0645\u062A\u0648\u0642\u0639.
|
||||
\U0001F4CC \u062A\u062D\u064A\u0629 \u0639\u0627\u0645\u0629 \u0627\u0633\u062A\u062E\u062F\u0645
|
||||
\u062A\u062D\u064A\u0629 \u0639\u0627\u0645\u0629 \u0645\u062B\u0644 \"\u0639\u0632\u064A\u0632\u064A
|
||||
\u0645\u062D\u062A\u0648\u0649 \u063A\u064A\u0631 \u0645\u0623\u0644\u0648\u0641
|
||||
\u0623\u0648 \u063A\u064A\u0631 \u0645\u062A\u0648\u0642\u0639 \u0628\u062F\u0649
|
||||
\u0627\u0644\u0628\u0631\u064A\u062F \u0627\u0644\u0625\u0644\u0643\u062A\u0631\u0648\u0646\u064A
|
||||
\u063A\u064A\u0631 \u0645\u0631\u062A\u0628\u0637 \u0628\u0639\u0645\u0644\u0643
|
||||
\u2014 \u063A\u0627\u0644\u0628\u064B\u0627 \u0645\u0627 \u064A\u0623\u062A\u064A
|
||||
\u0627\u0644\u062A\u0635\u064A\u062F \u0627\u0644\u0627\u062D\u062A\u064A\u0627\u0644\u064A
|
||||
\u0628\u0634\u0643\u0644 \u0645\u0641\u0627\u062C\u0626. \u062A\u062D\u064A\u0627\u062A
|
||||
\u0639\u0627\u0645\u0629 \u0627\u0633\u062A\u062E\u062F\u0645 \u062A\u062D\u064A\u0629
|
||||
\u0639\u0627\u0645\u0629 \u0645\u062B\u0644 \"\u0639\u0632\u064A\u0632\u064A
|
||||
\u0627\u0644\u0645\u0633\u062A\u062E\u062F\u0645\" \u0628\u062F\u0644\u0627\u064B
|
||||
\u0645\u0646 \u0627\u0633\u0645\u0643 \u0627\u0644\u062D\u0642\u064A\u0642\u064A.
|
||||
\U0001F4CC \u0637\u0644\u0628\u0627\u062A \u063A\u064A\u0631 \u0645\u0639\u062A\u0627\u062F\u0629
|
||||
\u0637\u0644\u0628 \u0645\u0639\u0644\u0648\u0645\u0627\u062A \u062D\u0633\u0627\u0633\u0629
|
||||
\u0645\u062B\u0644 \u0643\u0644\u0645\u0627\u062A \u0627\u0644\u0645\u0631\u0648\u0631
|
||||
\u2014 \u0627\u0644\u0634\u0631\u0643\u0627\u062A \u0644\u0627 \u062A\u0637\u0644\u0628
|
||||
\u0630\u0644\u0643 \u0639\u0628\u0631 \u0627\u0644\u0628\u0631\u064A\u062F
|
||||
\u0627\u0644\u0625\u0644\u0643\u062A\u0631\u0648\u0646\u064A. "
|
||||
\u0645\u0646 \u0627\u0633\u0645\u0643. \u0637\u0644\u0628\u0627\u062A \u063A\u064A\u0631
|
||||
\u0645\u0639\u062A\u0627\u062F\u0629 \u0637\u0644\u0628 \u0645\u0639\u0644\u0648\u0645\u0627\u062A
|
||||
\u062D\u0633\u0627\u0633\u0629 \u0645\u062B\u0644 \u0643\u0644\u0645\u0627\u062A
|
||||
\u0627\u0644\u0645\u0631\u0648\u0631 \u2014 \u0627\u0644\u0634\u0631\u0643\u0627\u062A
|
||||
\u0644\u0627 \u062A\u0641\u0639\u0644 \u0630\u0644\u0643 \u0639\u0628\u0631
|
||||
\u0627\u0644\u0628\u0631\u064A\u062F \u0627\u0644\u0625\u0644\u0643\u062A\u0631\u0648\u0646\u064A.\u0648\u0646\u064A. "
|
||||
- key: howtobesafesummary
|
||||
english: "\u2022 <b>Verify the sender\u2019s email address carefully</b> Phishing
|
||||
emails often use addresses that look legit but contain subtle misspellings.
|
||||
|
9
Assets/Plugins/AssetUsageDetector.meta
Normal file
9
Assets/Plugins/AssetUsageDetector.meta
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c1764d69117881843b761dc14ca276d4
|
||||
folderAsset: yes
|
||||
timeCreated: 1561225368
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
9
Assets/Plugins/AssetUsageDetector/Editor.meta
Normal file
9
Assets/Plugins/AssetUsageDetector/Editor.meta
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 19f677a9eb83d3942af6d4c5fa8dbeee
|
||||
folderAsset: yes
|
||||
timeCreated: 1520032274
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "AssetUsageDetector.Editor",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"Unity.Addressables"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [
|
||||
{
|
||||
"name": "com.unity.addressables",
|
||||
"expression": "0.0.0",
|
||||
"define": "ASSET_USAGE_ADDRESSABLES"
|
||||
},
|
||||
{
|
||||
"name": "com.unity.visualeffectgraph",
|
||||
"expression": "0.0.0",
|
||||
"define": "ASSET_USAGE_VFX_GRAPH"
|
||||
}
|
||||
],
|
||||
"noEngineReferences": false
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8579ab42c9ab63d4bac5fb07bd390b46
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
1398
Assets/Plugins/AssetUsageDetector/Editor/AssetUsageDetector.cs
Normal file
1398
Assets/Plugins/AssetUsageDetector/Editor/AssetUsageDetector.cs
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2c0dea52dcdb16e4e9b13f8dacc1590f
|
||||
timeCreated: 1520032279
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,207 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace AssetUsageDetectorNamespace
|
||||
{
|
||||
public partial class AssetUsageDetector
|
||||
{
|
||||
#region Helper Classes
|
||||
private class CacheEntry
|
||||
{
|
||||
public enum Result { Unknown = 0, No = 1, Yes = 2 };
|
||||
|
||||
public string hash;
|
||||
public string[] dependencies;
|
||||
public long[] fileSizes;
|
||||
|
||||
public bool verified;
|
||||
public Result searchResult;
|
||||
|
||||
public CacheEntry( string path )
|
||||
{
|
||||
Verify( path );
|
||||
}
|
||||
|
||||
public CacheEntry( string hash, string[] dependencies, long[] fileSizes )
|
||||
{
|
||||
this.hash = hash;
|
||||
this.dependencies = dependencies;
|
||||
this.fileSizes = fileSizes;
|
||||
}
|
||||
|
||||
public void Verify( string path )
|
||||
{
|
||||
string hash = AssetDatabase.GetAssetDependencyHash( path ).ToString();
|
||||
if( this.hash != hash )
|
||||
{
|
||||
this.hash = hash;
|
||||
Refresh( path );
|
||||
}
|
||||
|
||||
verified = true;
|
||||
}
|
||||
|
||||
public void Refresh( string path )
|
||||
{
|
||||
dependencies = AssetDatabase.GetDependencies( path, false );
|
||||
if( fileSizes == null || fileSizes.Length != dependencies.Length )
|
||||
fileSizes = new long[dependencies.Length];
|
||||
|
||||
int length = dependencies.Length;
|
||||
for( int i = 0; i < length; i++ )
|
||||
{
|
||||
if( !string.IsNullOrEmpty( dependencies[i] ) )
|
||||
{
|
||||
FileInfo assetFile = new FileInfo( dependencies[i] );
|
||||
fileSizes[i] = assetFile.Exists ? assetFile.Length : 0L;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This dependency is empty which causes issues when passed to FileInfo constructor
|
||||
// Find a non-empty dependency and move it to this index
|
||||
for( int j = length - 1; j > i; j--, length-- )
|
||||
{
|
||||
if( !string.IsNullOrEmpty( dependencies[j] ) )
|
||||
{
|
||||
dependencies[i--] = dependencies[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
length--;
|
||||
}
|
||||
}
|
||||
|
||||
if( length != fileSizes.Length )
|
||||
{
|
||||
Array.Resize( ref dependencies, length );
|
||||
Array.Resize( ref fileSizes, length );
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
// An optimization to fetch the dependencies of an asset only once (key is the path of the asset)
|
||||
private Dictionary<string, CacheEntry> assetDependencyCache;
|
||||
private CacheEntry lastRefreshedCacheEntry;
|
||||
|
||||
private string CachePath { get { return Application.dataPath + "/../Library/AssetUsageDetector.cache"; } } // Path of the cache file
|
||||
|
||||
public void SaveCache()
|
||||
{
|
||||
if( assetDependencyCache == null )
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
using( FileStream stream = new FileStream( CachePath, FileMode.Create ) )
|
||||
using( BinaryWriter writer = new BinaryWriter( stream ) )
|
||||
{
|
||||
writer.Write( assetDependencyCache.Count );
|
||||
|
||||
foreach( var keyValuePair in assetDependencyCache )
|
||||
{
|
||||
CacheEntry cacheEntry = keyValuePair.Value;
|
||||
string[] dependencies = cacheEntry.dependencies;
|
||||
long[] fileSizes = cacheEntry.fileSizes;
|
||||
|
||||
writer.Write( keyValuePair.Key );
|
||||
writer.Write( cacheEntry.hash );
|
||||
writer.Write( dependencies.Length );
|
||||
|
||||
for( int i = 0; i < dependencies.Length; i++ )
|
||||
{
|
||||
writer.Write( dependencies[i] );
|
||||
writer.Write( fileSizes[i] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
Debug.LogException( e );
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadCache()
|
||||
{
|
||||
if( File.Exists( CachePath ) )
|
||||
{
|
||||
using( FileStream stream = new FileStream( CachePath, FileMode.Open, FileAccess.Read ) )
|
||||
using( BinaryReader reader = new BinaryReader( stream ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
int cacheSize = reader.ReadInt32();
|
||||
assetDependencyCache = new Dictionary<string, CacheEntry>( cacheSize );
|
||||
|
||||
for( int i = 0; i < cacheSize; i++ )
|
||||
{
|
||||
string assetPath = reader.ReadString();
|
||||
string hash = reader.ReadString();
|
||||
|
||||
int dependenciesLength = reader.ReadInt32();
|
||||
string[] dependencies = new string[dependenciesLength];
|
||||
long[] fileSizes = new long[dependenciesLength];
|
||||
for( int j = 0; j < dependenciesLength; j++ )
|
||||
{
|
||||
dependencies[j] = reader.ReadString();
|
||||
fileSizes[j] = reader.ReadInt64();
|
||||
}
|
||||
|
||||
assetDependencyCache[assetPath] = new CacheEntry( hash, dependencies, fileSizes );
|
||||
}
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
assetDependencyCache = null;
|
||||
Debug.LogWarning( "Couldn't load cache (probably cache format has changed in an update), will regenerate cache.\n" + e.ToString() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate cache for all assets for the first time
|
||||
if( assetDependencyCache == null )
|
||||
{
|
||||
assetDependencyCache = new Dictionary<string, CacheEntry>( 1024 * 8 );
|
||||
|
||||
string[] allAssets = AssetDatabase.GetAllAssetPaths();
|
||||
if( allAssets.Length > 0 )
|
||||
{
|
||||
double startTime = EditorApplication.timeSinceStartup;
|
||||
|
||||
try
|
||||
{
|
||||
for( int i = 0; i < allAssets.Length; i++ )
|
||||
{
|
||||
if( i % 30 == 0 && EditorUtility.DisplayCancelableProgressBar( "Please wait...", "Generating cache for the first time (optional)", (float) i / allAssets.Length ) )
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
Debug.LogWarning( "Initial cache generation cancelled, cache will be generated on the fly as more and more assets are searched." );
|
||||
break;
|
||||
}
|
||||
|
||||
assetDependencyCache[allAssets[i]] = new CacheEntry( allAssets[i] );
|
||||
}
|
||||
|
||||
EditorUtility.ClearProgressBar();
|
||||
|
||||
Debug.Log( "Cache generated in " + ( EditorApplication.timeSinceStartup - startTime ).ToString( "F2" ) + " seconds" );
|
||||
Debug.Log( "You can always reset the cache by deleting " + Path.GetFullPath( CachePath ) );
|
||||
|
||||
SaveCache();
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
Debug.LogException( e );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 71ea9a3fd0b82594d8130d882dbfc844
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 93aaae685d4c3db44baeb91a0296855e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,298 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AssetUsageDetectorNamespace
|
||||
{
|
||||
public static class AssetUsageDetectorSettings
|
||||
{
|
||||
private static readonly GUILayoutOption GL_WIDTH_60 = GUILayout.Width( 60f );
|
||||
|
||||
#region Colors
|
||||
private static Color? m_settingsHeaderColor = null;
|
||||
public static Color SettingsHeaderColor
|
||||
{
|
||||
get { if( m_settingsHeaderColor == null ) m_settingsHeaderColor = GetColor( "AUD_SettingsHeaderTint", Color.cyan ); return m_settingsHeaderColor.Value; }
|
||||
set { if( m_settingsHeaderColor == value ) return; m_settingsHeaderColor = value; SetColor( "AUD_SettingsHeaderTint", value ); }
|
||||
}
|
||||
|
||||
private static Color? m_searchResultGroupHeaderColor = null;
|
||||
public static Color SearchResultGroupHeaderColor
|
||||
{
|
||||
get { if( m_searchResultGroupHeaderColor == null ) m_searchResultGroupHeaderColor = GetColor( "AUD_ResultGroupHeaderTint", Color.cyan ); return m_searchResultGroupHeaderColor.Value; }
|
||||
set { if( m_searchResultGroupHeaderColor == value ) return; m_searchResultGroupHeaderColor = value; SetColor( "AUD_ResultGroupHeaderTint", value ); }
|
||||
}
|
||||
|
||||
private static Color? m_rootRowsBackgroundColor = null;
|
||||
public static Color RootRowsBackgroundColor
|
||||
{
|
||||
get { if( m_rootRowsBackgroundColor == null ) m_rootRowsBackgroundColor = GetColor( "AUD_RootRowsTint", EditorGUIUtility.isProSkin ? new Color( 0f, 1f, 1f, 0.15f ) : new Color( 0f, 1f, 1f, 0.25f ) ); return m_rootRowsBackgroundColor.Value; }
|
||||
set { if( m_rootRowsBackgroundColor == value ) return; m_rootRowsBackgroundColor = value; SetColor( "AUD_RootRowsTint", value ); }
|
||||
}
|
||||
|
||||
private static Color? m_rootRowsBorderColor = null;
|
||||
public static Color RootRowsBorderColor
|
||||
{
|
||||
get { if( m_rootRowsBorderColor == null ) m_rootRowsBorderColor = GetColor( "AUD_RootRowsBorderColor", EditorGUIUtility.isProSkin ? new Color( 0.15f, 0.15f, 0.15f, 1f ) : new Color( 0.375f, 0.375f, 0.375f, 1f ) ); return m_rootRowsBorderColor.Value; }
|
||||
set { if( m_rootRowsBorderColor == value ) return; m_rootRowsBorderColor = value; SetColor( "AUD_RootRowsBorderColor", value ); }
|
||||
}
|
||||
|
||||
private static Color? m_mainReferencesBackgroundColor = null;
|
||||
public static Color MainReferencesBackgroundColor
|
||||
{
|
||||
get { if( m_mainReferencesBackgroundColor == null ) m_mainReferencesBackgroundColor = GetColor( "AUD_MainRefRowsTint", EditorGUIUtility.isProSkin ? new Color( 0f, 0.35f, 0f, 1f ) : new Color( 0.25f, 0.75f, 0.25f, 1f ) ); return m_mainReferencesBackgroundColor.Value; }
|
||||
set { if( m_mainReferencesBackgroundColor == value ) return; m_mainReferencesBackgroundColor = value; SetColor( "AUD_MainRefRowsTint", value ); }
|
||||
}
|
||||
|
||||
private static Color? m_selectedRowsParentTint = null;
|
||||
public static Color SelectedRowParentsTint
|
||||
{
|
||||
get { if( m_selectedRowsParentTint == null ) m_selectedRowsParentTint = GetColor( "AUD_SelectedRowParentsTint", EditorGUIUtility.isProSkin ? new Color( 0.36f, 0.36f, 0.18f, 1f ) : new Color( 0.825f, 0.825f, 0.55f, 1f ) ); return m_selectedRowsParentTint.Value; }
|
||||
set { if( m_selectedRowsParentTint == value ) return; m_selectedRowsParentTint = value; SetColor( "AUD_SelectedRowParentsTint", value ); }
|
||||
}
|
||||
|
||||
private static Color? m_selectedRowOccurrencesColor = null;
|
||||
public static Color SelectedRowOccurrencesColor
|
||||
{
|
||||
get { if( m_selectedRowOccurrencesColor == null ) m_selectedRowOccurrencesColor = GetColor( "AUD_SelectedRowOccurrencesTint", EditorGUIUtility.isProSkin ? new Color( 0f, 0.3f, 0.75f, 1f ) : new Color( 0.25f, 0.75f, 1f, 1f ) ); return m_selectedRowOccurrencesColor.Value; }
|
||||
set { if( m_selectedRowOccurrencesColor == value ) return; m_selectedRowOccurrencesColor = value; SetColor( "AUD_SelectedRowOccurrencesTint", value ); }
|
||||
}
|
||||
|
||||
private static Color? m_treeLinesColor = null;
|
||||
public static Color TreeLinesColor
|
||||
{
|
||||
get { if( m_treeLinesColor == null ) m_treeLinesColor = GetColor( "AUD_TreeLinesColor", EditorGUIUtility.isProSkin ? new Color( 0.65f, 0.65f, 0.65f, 1f ) : new Color( 0.375f, 0.375f, 0.375f, 1f ) ); return m_treeLinesColor.Value; }
|
||||
set { if( m_treeLinesColor == value ) return; m_treeLinesColor = value; SetColor( "AUD_TreeLinesColor", value ); }
|
||||
}
|
||||
|
||||
private static Color? m_highlightedTreeLinesColor = null;
|
||||
public static Color HighlightedTreeLinesColor
|
||||
{
|
||||
get { if( m_highlightedTreeLinesColor == null ) m_highlightedTreeLinesColor = GetColor( "AUD_HighlightTreeLinesColor", Color.cyan ); return m_highlightedTreeLinesColor.Value; }
|
||||
set { if( m_highlightedTreeLinesColor == value ) return; m_highlightedTreeLinesColor = value; SetColor( "AUD_HighlightTreeLinesColor", value ); }
|
||||
}
|
||||
|
||||
private static Color? m_searchMatchingTextColor = null;
|
||||
public static Color SearchMatchingTextColor
|
||||
{
|
||||
get { if( m_searchMatchingTextColor == null ) m_searchMatchingTextColor = GetColor( "AUD_SearchTextColor", Color.red ); return m_searchMatchingTextColor.Value; }
|
||||
set { if( m_searchMatchingTextColor == value ) return; m_searchMatchingTextColor = value; SetColor( "AUD_SearchTextColor", value ); ForEachAssetUsageDetectorWindow( ( window ) => window.OnSettingsChanged( highlightedSearchTextColorChanged: true ) ); }
|
||||
}
|
||||
|
||||
private static Color? m_tooltipDescriptionTextColor = null;
|
||||
public static Color TooltipDescriptionTextColor
|
||||
{
|
||||
get { if( m_tooltipDescriptionTextColor == null ) m_tooltipDescriptionTextColor = GetColor( "AUD_TooltipUsageTextColor", EditorGUIUtility.isProSkin ? new Color( 0f, 0.9f, 0.9f, 1f ) : new Color( 0.9f, 0f, 0f, 1f ) ); return m_tooltipDescriptionTextColor.Value; }
|
||||
set { if( m_tooltipDescriptionTextColor == value ) return; m_tooltipDescriptionTextColor = value; SetColor( "AUD_TooltipUsageTextColor", value ); ForEachAssetUsageDetectorWindow( ( window ) => window.OnSettingsChanged( tooltipDescriptionsColorChanged: true ) ); }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Size Adjustments
|
||||
private static float? m_extraRowHeight = null;
|
||||
public static float ExtraRowHeight
|
||||
{
|
||||
get { if( m_extraRowHeight == null ) m_extraRowHeight = EditorPrefs.GetFloat( "AUD_ExtraRowHeight", 0f ); return m_extraRowHeight.Value; }
|
||||
set { if( m_extraRowHeight == value ) return; m_extraRowHeight = value; EditorPrefs.SetFloat( "AUD_ExtraRowHeight", value ); ForEachAssetUsageDetectorWindow( ( window ) => window.OnSettingsChanged() ); }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Other Settings
|
||||
private static bool? m_showRootAssetName = null;
|
||||
public static bool ShowRootAssetName
|
||||
{
|
||||
get { if( m_showRootAssetName == null ) m_showRootAssetName = EditorPrefs.GetBool( "AUD_ShowRootAssetName", true ); return m_showRootAssetName.Value; }
|
||||
set { if( m_showRootAssetName == value ) return; m_showRootAssetName = value; EditorPrefs.SetBool( "AUD_ShowRootAssetName", value ); }
|
||||
}
|
||||
|
||||
private static bool? m_pingClickedObjects = null;
|
||||
public static bool PingClickedObjects
|
||||
{
|
||||
get { if( m_pingClickedObjects == null ) m_pingClickedObjects = EditorPrefs.GetBool( "AUD_PingClickedObj", true ); return m_pingClickedObjects.Value; }
|
||||
set { if( m_pingClickedObjects == value ) return; m_pingClickedObjects = value; EditorPrefs.SetBool( "AUD_PingClickedObj", value ); }
|
||||
}
|
||||
|
||||
private static bool? m_selectClickedObjects = null;
|
||||
public static bool SelectClickedObjects
|
||||
{
|
||||
get { if( m_selectClickedObjects == null ) m_selectClickedObjects = EditorPrefs.GetBool( "AUD_SelectClickedObj", false ); return m_selectClickedObjects.Value; }
|
||||
set { if( m_selectClickedObjects == value ) return; m_selectClickedObjects = value; EditorPrefs.SetBool( "AUD_SelectClickedObj", value ); }
|
||||
}
|
||||
|
||||
private static bool? m_selectDoubleClickedObjects = null;
|
||||
public static bool SelectDoubleClickedObjects
|
||||
{
|
||||
get { if( m_selectDoubleClickedObjects == null ) m_selectDoubleClickedObjects = EditorPrefs.GetBool( "AUD_SelectDoubleClickedObj", true ); return m_selectDoubleClickedObjects.Value; }
|
||||
set { if( m_selectDoubleClickedObjects == value ) return; m_selectDoubleClickedObjects = value; EditorPrefs.SetBool( "AUD_SelectDoubleClickedObj", value ); }
|
||||
}
|
||||
|
||||
private static bool? m_markUsedAssetsSubAssetsAsUsed = null;
|
||||
public static bool MarkUsedAssetsSubAssetsAsUsed
|
||||
{
|
||||
get { if( m_markUsedAssetsSubAssetsAsUsed == null ) m_markUsedAssetsSubAssetsAsUsed = EditorPrefs.GetBool( "AUD_MarkUsedAssetsSubAssetsAsUsed", true ); return m_markUsedAssetsSubAssetsAsUsed.Value; }
|
||||
set { if( m_markUsedAssetsSubAssetsAsUsed == value ) return; m_markUsedAssetsSubAssetsAsUsed = value; EditorPrefs.SetBool( "AUD_MarkUsedAssetsSubAssetsAsUsed", value ); }
|
||||
}
|
||||
|
||||
private static bool? m_showUnityTooltip = null;
|
||||
public static bool ShowUnityTooltip
|
||||
{
|
||||
get { if( m_showUnityTooltip == null ) m_showUnityTooltip = EditorPrefs.GetBool( "AUD_ShowUnityTooltip", false ); return m_showUnityTooltip.Value; }
|
||||
set { if( m_showUnityTooltip == value ) return; m_showUnityTooltip = value; EditorPrefs.SetBool( "AUD_ShowUnityTooltip", value ); }
|
||||
}
|
||||
|
||||
private static bool? m_showCustomTooltip = null;
|
||||
public static bool ShowCustomTooltip
|
||||
{
|
||||
get { if( m_showCustomTooltip == null ) m_showCustomTooltip = EditorPrefs.GetBool( "AUD_ShowCustomTooltip", true ); return m_showCustomTooltip.Value; }
|
||||
set { if( m_showCustomTooltip == value ) return; m_showCustomTooltip = value; EditorPrefs.SetBool( "AUD_ShowCustomTooltip", value ); ForEachAssetUsageDetectorWindow( ( window ) => window.OnSettingsChanged() ); }
|
||||
}
|
||||
|
||||
private static float? m_customTooltipDelay = null;
|
||||
public static float CustomTooltipDelay
|
||||
{
|
||||
get { if( m_customTooltipDelay == null ) m_customTooltipDelay = EditorPrefs.GetFloat( "AUD_CustomTooltipDelay", 0.7f ); return m_customTooltipDelay.Value; }
|
||||
set { if( m_customTooltipDelay == value ) return; m_customTooltipDelay = value; EditorPrefs.SetFloat( "AUD_CustomTooltipDelay", value ); }
|
||||
}
|
||||
|
||||
private static bool? m_showTreeLines = null;
|
||||
public static bool ShowTreeLines
|
||||
{
|
||||
get { if( m_showTreeLines == null ) m_showTreeLines = EditorPrefs.GetBool( "AUD_ShowTreeLines", true ); return m_showTreeLines.Value; }
|
||||
set { if( m_showTreeLines == value ) return; m_showTreeLines = value; EditorPrefs.SetBool( "AUD_ShowTreeLines", value ); }
|
||||
}
|
||||
|
||||
private static bool? m_applySelectedRowParentsTintToRootRows = null;
|
||||
public static bool ApplySelectedRowParentsTintToRootRows
|
||||
{
|
||||
get { if( m_applySelectedRowParentsTintToRootRows == null ) m_applySelectedRowParentsTintToRootRows = EditorPrefs.GetBool( "AUD_SelectedRowParentsTintAtRoot", true ); return m_applySelectedRowParentsTintToRootRows.Value; }
|
||||
set { if( m_applySelectedRowParentsTintToRootRows == value ) return; m_applySelectedRowParentsTintToRootRows = value; EditorPrefs.SetBool( "AUD_SelectedRowParentsTintAtRoot", value ); }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
[SettingsProvider]
|
||||
public static SettingsProvider CreatePreferencesGUI()
|
||||
{
|
||||
return new SettingsProvider( "Project/yasirkula/Asset Usage Detector", SettingsScope.Project )
|
||||
{
|
||||
guiHandler = ( searchContext ) => PreferencesGUI(),
|
||||
keywords = new System.Collections.Generic.HashSet<string>() { "Asset", "Usage", "Detector" }
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !UNITY_2018_3_OR_NEWER
|
||||
[PreferenceItem( "Asset Usage Detector" )]
|
||||
#endif
|
||||
public static void PreferencesGUI()
|
||||
{
|
||||
float labelWidth = EditorGUIUtility.labelWidth;
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
EditorGUIUtility.labelWidth += 60f;
|
||||
#else
|
||||
EditorGUIUtility.labelWidth += 20f;
|
||||
#endif
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
ShowRootAssetName = AssetUsageDetectorWindow.WordWrappingToggleLeft( "Show Root Asset's Name For Sub-Assets (Requires Refresh)", ShowRootAssetName );
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
PingClickedObjects = AssetUsageDetectorWindow.WordWrappingToggleLeft( "Ping Clicked Objects", PingClickedObjects );
|
||||
SelectClickedObjects = AssetUsageDetectorWindow.WordWrappingToggleLeft( "Select Clicked Objects", SelectClickedObjects );
|
||||
SelectDoubleClickedObjects = AssetUsageDetectorWindow.WordWrappingToggleLeft( "Select Double Clicked Objects", SelectDoubleClickedObjects );
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
MarkUsedAssetsSubAssetsAsUsed = AssetUsageDetectorWindow.WordWrappingToggleLeft( "Hide unused sub-assets in \"Unused Objects\" list if their parent assets are used (Requires Refresh)", MarkUsedAssetsSubAssetsAsUsed );
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
ShowUnityTooltip = AssetUsageDetectorWindow.WordWrappingToggleLeft( "Show Unity Tooltip", ShowUnityTooltip );
|
||||
ShowCustomTooltip = AssetUsageDetectorWindow.WordWrappingToggleLeft( "Show Custom Tooltip", ShowCustomTooltip );
|
||||
EditorGUI.indentLevel++;
|
||||
CustomTooltipDelay = FloatField( "Delay", CustomTooltipDelay, 0.7f );
|
||||
EditorGUI.indentLevel--;
|
||||
TooltipDescriptionTextColor = ColorField( "Tooltip Descriptions Text Color", TooltipDescriptionTextColor, EditorGUIUtility.isProSkin ? new Color( 0f, 0.9f, 0.9f, 1f ) : new Color( 0.9f, 0f, 0f, 1f ) );
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
ExtraRowHeight = Mathf.Max( 0f, FloatField( "Extra Row Height", ExtraRowHeight, 0f ) );
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
SettingsHeaderColor = ColorField( "Settings Header Color", SettingsHeaderColor, Color.cyan );
|
||||
SearchResultGroupHeaderColor = ColorField( "Group Header Color", SearchResultGroupHeaderColor, Color.cyan );
|
||||
RootRowsBackgroundColor = ColorField( "Root Rows Background Color", RootRowsBackgroundColor, EditorGUIUtility.isProSkin ? new Color( 0f, 1f, 1f, 0.15f ) : new Color( 0f, 1f, 1f, 0.25f ) );
|
||||
RootRowsBorderColor = ColorField( "Root Rows Border Color", RootRowsBorderColor, EditorGUIUtility.isProSkin ? new Color( 0.15f, 0.15f, 0.15f, 1f ) : new Color( 0.375f, 0.375f, 0.375f, 1f ) );
|
||||
MainReferencesBackgroundColor = ColorField( "Main References Background Color", MainReferencesBackgroundColor, EditorGUIUtility.isProSkin ? new Color( 0f, 0.35f, 0f, 1f ) : new Color( 0.25f, 0.75f, 0.25f, 1f ) );
|
||||
SelectedRowParentsTint = ColorField( "Selected Row Parents Tint", SelectedRowParentsTint, EditorGUIUtility.isProSkin ? new Color( 0.36f, 0.36f, 0.18f, 1f ) : new Color( 0.825f, 0.825f, 0.55f, 1f ) );
|
||||
EditorGUI.indentLevel++;
|
||||
ApplySelectedRowParentsTintToRootRows = !EditorGUILayout.Toggle( "Ignore Root Rows", !ApplySelectedRowParentsTintToRootRows );
|
||||
EditorGUI.indentLevel--;
|
||||
SelectedRowOccurrencesColor = ColorField( "Selected Row All Occurrences Tint", SelectedRowOccurrencesColor, EditorGUIUtility.isProSkin ? new Color( 0f, 0.3f, 0.75f, 1f ) : new Color( 0.25f, 0.75f, 1f, 1f ) );
|
||||
SearchMatchingTextColor = ColorField( "Matching Search Text Color", SearchMatchingTextColor, Color.red );
|
||||
|
||||
ShowTreeLines = AssetUsageDetectorWindow.WordWrappingToggleLeft( "Show Tree Lines", ShowTreeLines );
|
||||
EditorGUI.indentLevel++;
|
||||
TreeLinesColor = ColorField( "Normal Color", TreeLinesColor, EditorGUIUtility.isProSkin ? new Color( 0.65f, 0.65f, 0.65f, 1f ) : new Color( 0.375f, 0.375f, 0.375f, 1f ) );
|
||||
HighlightedTreeLinesColor = ColorField( "Highlighted Color", HighlightedTreeLinesColor, Color.cyan );
|
||||
EditorGUI.indentLevel--;
|
||||
|
||||
EditorGUIUtility.labelWidth = labelWidth;
|
||||
|
||||
if( EditorGUI.EndChangeCheck() )
|
||||
ForEachAssetUsageDetectorWindow( ( window ) => window.Repaint() );
|
||||
}
|
||||
|
||||
private static Color ColorField( string label, Color value, Color defaultValue )
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
Color result = EditorGUILayout.ColorField( label, value );
|
||||
if( GUILayout.Button( "Reset", GL_WIDTH_60 ) )
|
||||
result = defaultValue;
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static float FloatField( string label, float value, float defaultValue )
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
float result = EditorGUILayout.FloatField( label, value );
|
||||
if( GUILayout.Button( "Reset", GL_WIDTH_60 ) )
|
||||
result = defaultValue;
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Color GetColor( string pref, Color defaultColor )
|
||||
{
|
||||
if( EditorGUIUtility.isProSkin )
|
||||
pref += "_Pro";
|
||||
|
||||
if( !EditorPrefs.HasKey( pref ) )
|
||||
return defaultColor;
|
||||
|
||||
string[] parts = EditorPrefs.GetString( pref ).Split( ';' );
|
||||
return new Color32( byte.Parse( parts[0] ), byte.Parse( parts[1] ), byte.Parse( parts[2] ), byte.Parse( parts[3] ) );
|
||||
}
|
||||
|
||||
private static void SetColor( string pref, Color32 value )
|
||||
{
|
||||
if( EditorGUIUtility.isProSkin )
|
||||
pref += "_Pro";
|
||||
|
||||
EditorPrefs.SetString( pref, string.Concat( value.r.ToString(), ";", value.g.ToString(), ";", value.b.ToString(), ";", value.a.ToString() ) );
|
||||
}
|
||||
|
||||
private static void ForEachAssetUsageDetectorWindow( System.Action<AssetUsageDetectorWindow> action )
|
||||
{
|
||||
foreach( AssetUsageDetectorWindow window in Resources.FindObjectsOfTypeAll<AssetUsageDetectorWindow>() )
|
||||
{
|
||||
if( window )
|
||||
action( window );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 13295073724765e45aa3b77486e515f4
|
||||
timeCreated: 1639982865
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,812 @@
|
||||
// Asset Usage Detector - by Suleyman Yasir KULA (yasirkula@gmail.com)
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Object = UnityEngine.Object;
|
||||
#if UNITY_2021_2_OR_NEWER
|
||||
using PrefabStage = UnityEditor.SceneManagement.PrefabStage;
|
||||
using PrefabStageUtility = UnityEditor.SceneManagement.PrefabStageUtility;
|
||||
#elif UNITY_2018_3_OR_NEWER
|
||||
using PrefabStage = UnityEditor.Experimental.SceneManagement.PrefabStage;
|
||||
using PrefabStageUtility = UnityEditor.Experimental.SceneManagement.PrefabStageUtility;
|
||||
#endif
|
||||
|
||||
namespace AssetUsageDetectorNamespace
|
||||
{
|
||||
public enum Phase { Setup, Processing, Complete };
|
||||
|
||||
public class AssetUsageDetectorWindow : EditorWindow, IHasCustomMenu
|
||||
{
|
||||
private enum WindowFilter { AlwaysReturnActive, ReturnActiveIfNotLocked, AlwaysReturnNew };
|
||||
|
||||
private const string PREFS_SEARCH_SCENES = "AUD_SceneSearch";
|
||||
private const string PREFS_SEARCH_SCENE_LIGHTING_SETTINGS = "AUD_LightingSettingsSearch";
|
||||
private const string PREFS_SEARCH_ASSETS = "AUD_AssetsSearch";
|
||||
private const string PREFS_SEARCH_PROJECT_SETTINGS = "AUD_ProjectSettingsSearch";
|
||||
private const string PREFS_DONT_SEARCH_SOURCE_ASSETS = "AUD_AssetsExcludeSrc";
|
||||
private const string PREFS_SEARCH_DEPTH_LIMIT = "AUD_Depth";
|
||||
private const string PREFS_SEARCH_FIELDS = "AUD_Fields";
|
||||
private const string PREFS_SEARCH_PROPERTIES = "AUD_Properties";
|
||||
private const string PREFS_SEARCH_NON_SERIALIZABLES = "AUD_NonSerializables";
|
||||
private const string PREFS_SEARCH_UNUSED_MATERIAL_PROPERTIES = "AUD_SearchUnusedMaterialProps";
|
||||
private const string PREFS_LAZY_SCENE_SEARCH = "AUD_LazySceneSearch";
|
||||
private const string PREFS_ADDRESSABLES_SUPPORT = "AUD_AddressablesSupport";
|
||||
private const string PREFS_CALCULATE_UNUSED_OBJECTS = "AUD_FindUnusedObjs";
|
||||
private const string PREFS_HIDE_DUPLICATE_ROWS = "AUD_HideDuplicates";
|
||||
private const string PREFS_HIDE_REDUNDANT_PREFAB_VARIANT_LINKS = "AUD_HideRedundantPVariantLinks";
|
||||
private const string PREFS_SHOW_PROGRESS = "AUD_Progress";
|
||||
|
||||
private static readonly GUIContent windowTitle = new GUIContent( "Asset Usage Detector" );
|
||||
private static readonly Vector2 windowMinSize = new Vector2( 325f, 220f );
|
||||
|
||||
private static readonly GUILayoutOption GL_WIDTH_12 = GUILayout.Width( 12f );
|
||||
|
||||
private GUIStyle lockButtonStyle;
|
||||
|
||||
private readonly AssetUsageDetector core = new AssetUsageDetector();
|
||||
private SearchResult searchResult; // Overall search results
|
||||
|
||||
// This isn't readonly so that it can be serialized
|
||||
private List<ObjectToSearch> objectsToSearch = new List<ObjectToSearch>() { new ObjectToSearch( null ) };
|
||||
|
||||
#pragma warning disable 0649
|
||||
[SerializeField] // Since titleContent persists between Editor sessions, so should the IsLocked property because otherwise, "[L]" in title becomes confusing when the EditorWindow isn't actually locked
|
||||
private bool m_isLocked;
|
||||
private bool IsLocked
|
||||
{
|
||||
get { return m_isLocked; }
|
||||
set
|
||||
{
|
||||
if( m_isLocked != value )
|
||||
{
|
||||
m_isLocked = value;
|
||||
titleContent = value ? new GUIContent( "[L] " + windowTitle.text, EditorGUIUtility.IconContent( "InspectorLock" ).image ) : windowTitle;
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore 0649
|
||||
|
||||
private Phase currentPhase = Phase.Setup;
|
||||
|
||||
private bool searchInOpenScenes = true; // Scenes currently open in Hierarchy view
|
||||
private bool searchInScenesInBuild = true; // Scenes in build
|
||||
private bool searchInScenesInBuildTickedOnly = true; // Scenes in build (ticked only or not)
|
||||
private bool searchInAllScenes = true; // All scenes (including scenes that are not in build)
|
||||
private bool searchInSceneLightingSettings = true; // Window-Rendering-Lighting settings
|
||||
private bool searchInAssetsFolder = true; // Assets in Project window
|
||||
private bool dontSearchInSourceAssets = true; // objectsToSearch won't be searched for internal references
|
||||
private bool searchInProjectSettings = true; // Player Settings, Graphics Settings etc.
|
||||
|
||||
private List<Object> searchInAssetsSubset = new List<Object>() { null }; // If not empty, only these assets are searched for references
|
||||
private List<Object> excludedAssets = new List<Object>() { null }; // These assets won't be searched for references
|
||||
private List<Object> excludedScenes = new List<Object>() { null }; // These scenes won't be searched for references
|
||||
|
||||
private int searchDepthLimit = 4; // Depth limit for recursively searching variables of objects
|
||||
|
||||
private bool lazySceneSearch = true;
|
||||
#if ASSET_USAGE_ADDRESSABLES
|
||||
private bool addressablesSupport = false;
|
||||
#endif
|
||||
private bool searchNonSerializableVariables = true;
|
||||
private bool searchUnusedMaterialProperties = true;
|
||||
private bool calculateUnusedObjects = false;
|
||||
private bool hideDuplicateRows = true;
|
||||
private bool hideReduntantPrefabVariantLinks = true;
|
||||
private bool noAssetDatabaseChanges = false;
|
||||
private bool showDetailedProgressBar = true;
|
||||
|
||||
private BindingFlags fieldModifiers, propertyModifiers;
|
||||
|
||||
private SearchRefactoring searchRefactoring = null; // Its value can be assigned via ShowAndSearch
|
||||
|
||||
private readonly ObjectToSearchListDrawer objectsToSearchDrawer = new ObjectToSearchListDrawer();
|
||||
private readonly ObjectListDrawer searchInAssetsSubsetDrawer = new ObjectListDrawer( "Search following asset(s) only:", false );
|
||||
private readonly ObjectListDrawer excludedAssetsDrawer = new ObjectListDrawer( "Don't search following asset(s):", false );
|
||||
private readonly ObjectListDrawer excludedScenesDrawer = new ObjectListDrawer( "Don't search in following scene(s):", false );
|
||||
|
||||
private bool drawObjectsToSearchSection = true;
|
||||
|
||||
private Vector2 scrollPosition = Vector2.zero;
|
||||
|
||||
private bool shouldRepositionSelf;
|
||||
private Rect windowTargetPosition;
|
||||
|
||||
void IHasCustomMenu.AddItemsToMenu( GenericMenu contextMenu )
|
||||
{
|
||||
contextMenu.AddItem( new GUIContent( "Lock" ), IsLocked, () => IsLocked = !IsLocked );
|
||||
contextMenu.AddSeparator( "" );
|
||||
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
contextMenu.AddItem( new GUIContent( "Settings" ), false, () => SettingsService.OpenProjectSettings( "Project/yasirkula/Asset Usage Detector" ) );
|
||||
#else
|
||||
contextMenu.AddItem( new GUIContent( "Settings" ), false, () =>
|
||||
{
|
||||
System.Type preferencesWindowType = typeof( EditorWindow ).Assembly.GetType( "UnityEditor.PreferencesWindow" );
|
||||
preferencesWindowType.GetMethod( "ShowPreferencesWindow", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static ).Invoke( null, null );
|
||||
|
||||
EditorWindow preferencesWindow = GetWindow( preferencesWindowType );
|
||||
if( (bool) preferencesWindowType.GetField( "m_RefreshCustomPreferences", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance ).GetValue( preferencesWindow ) )
|
||||
{
|
||||
preferencesWindowType.GetMethod( "AddCustomSections", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance ).Invoke( preferencesWindow, null );
|
||||
preferencesWindowType.GetField( "m_RefreshCustomPreferences", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance ).SetValue( preferencesWindow, false );
|
||||
}
|
||||
|
||||
int targetSectionIndex = -1;
|
||||
System.Collections.IList sections = (System.Collections.IList) preferencesWindowType.GetField( "m_Sections", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance ).GetValue( preferencesWindow );
|
||||
for( int i = 0; i < sections.Count; i++ )
|
||||
{
|
||||
if( ( (GUIContent) sections[i].GetType().GetField( "content", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance ).GetValue( sections[i] ) ).text == "Asset Usage Detector" )
|
||||
{
|
||||
targetSectionIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( targetSectionIndex >= 0 )
|
||||
preferencesWindowType.GetProperty( "selectedSectionIndex", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance ).SetValue( preferencesWindow, targetSectionIndex, null );
|
||||
} );
|
||||
#endif
|
||||
|
||||
if( currentPhase == Phase.Setup )
|
||||
{
|
||||
contextMenu.AddSeparator( "" );
|
||||
contextMenu.AddItem( new GUIContent( "Refresh Sub-Assets of Searched Objects" ), false, () =>
|
||||
{
|
||||
for( int i = objectsToSearch.Count - 1; i >= 0; i-- )
|
||||
objectsToSearch[i].RefreshSubAssets();
|
||||
} );
|
||||
}
|
||||
else if( currentPhase == Phase.Complete )
|
||||
{
|
||||
if( searchResult != null && searchResult.NumberOfGroups > 0 )
|
||||
{
|
||||
contextMenu.AddSeparator( "" );
|
||||
contextMenu.AddItem( new GUIContent( "Collapse All" ), false, searchResult.CollapseAllSearchResultGroups );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Shows lock button at the top-right corner
|
||||
// Credit: http://leahayes.co.uk/2013/04/30/adding-the-little-padlock-button-to-your-editorwindow.html
|
||||
private void ShowButton( Rect position )
|
||||
{
|
||||
if( lockButtonStyle == null )
|
||||
lockButtonStyle = "IN LockButton";
|
||||
|
||||
IsLocked = GUI.Toggle( position, IsLocked, GUIContent.none, lockButtonStyle );
|
||||
}
|
||||
|
||||
private static AssetUsageDetectorWindow GetWindow( WindowFilter filter )
|
||||
{
|
||||
AssetUsageDetectorWindow[] windows = Resources.FindObjectsOfTypeAll<AssetUsageDetectorWindow>();
|
||||
AssetUsageDetectorWindow window = System.Array.Find( windows, ( w ) => w && !w.IsLocked );
|
||||
if( !window )
|
||||
window = System.Array.Find( windows, ( w ) => w );
|
||||
|
||||
if( window && ( filter == WindowFilter.AlwaysReturnActive || ( !window.IsLocked && filter == WindowFilter.ReturnActiveIfNotLocked ) ) )
|
||||
{
|
||||
window.Show();
|
||||
window.Focus();
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
Rect? windowTargetPosition = null;
|
||||
if( window )
|
||||
{
|
||||
Rect position = window.position;
|
||||
position.position += new Vector2( 50f, 50f );
|
||||
windowTargetPosition = position;
|
||||
}
|
||||
|
||||
window = CreateInstance<AssetUsageDetectorWindow>();
|
||||
window.titleContent = windowTitle;
|
||||
window.minSize = windowMinSize;
|
||||
|
||||
if( windowTargetPosition.HasValue )
|
||||
{
|
||||
window.shouldRepositionSelf = true;
|
||||
window.windowTargetPosition = windowTargetPosition.Value;
|
||||
}
|
||||
|
||||
window.Show( true );
|
||||
window.Focus();
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
[MenuItem( "Window/Asset Usage Detector/Active Window" )]
|
||||
private static void OpenActiveWindow()
|
||||
{
|
||||
GetWindow( WindowFilter.AlwaysReturnActive );
|
||||
}
|
||||
|
||||
[MenuItem( "Window/Asset Usage Detector/New Window" )]
|
||||
private static void OpenNewWindow()
|
||||
{
|
||||
GetWindow( WindowFilter.AlwaysReturnNew );
|
||||
}
|
||||
|
||||
// Quickly initiate search for the selected assets
|
||||
[MenuItem( "GameObject/Search for References/This Object Only", priority = 49 )]
|
||||
[MenuItem( "Assets/Search for References", priority = 1000 )]
|
||||
private static void SearchSelectedAssetReferences( MenuCommand command )
|
||||
{
|
||||
// This happens when this button is clicked via hierarchy's right click context menu
|
||||
// and is called once for each object in the selection. We don't want that, we want
|
||||
// the function to be called only once
|
||||
if( command.context )
|
||||
{
|
||||
EditorApplication.update -= CallSearchSelectedAssetReferencesOnce;
|
||||
EditorApplication.update += CallSearchSelectedAssetReferencesOnce;
|
||||
}
|
||||
else
|
||||
ShowAndSearch( Selection.objects );
|
||||
}
|
||||
|
||||
[MenuItem( "GameObject/Search for References/Include Children", priority = 49 )]
|
||||
private static void SearchSelectedAssetReferencesWithChildren( MenuCommand command )
|
||||
{
|
||||
if( command.context )
|
||||
{
|
||||
EditorApplication.update -= CallSearchSelectedAssetReferencesWithChildrenOnce;
|
||||
EditorApplication.update += CallSearchSelectedAssetReferencesWithChildrenOnce;
|
||||
}
|
||||
else
|
||||
ShowAndSearch( Selection.objects, true );
|
||||
}
|
||||
|
||||
// Show the menu item only if there is a selection in the Editor
|
||||
[MenuItem( "GameObject/Search for References/This Object Only", validate = true )]
|
||||
[MenuItem( "GameObject/Search for References/Include Children", validate = true )]
|
||||
[MenuItem( "Assets/Search for References", validate = true )]
|
||||
private static bool SearchSelectedAssetReferencesValidate( MenuCommand command )
|
||||
{
|
||||
return Selection.objects.Length > 0;
|
||||
}
|
||||
|
||||
// Quickly show the AssetUsageDetector window and initiate a search
|
||||
public static void ShowAndSearch( IEnumerable<Object> searchObjects, bool? shouldSearchChildren = null )
|
||||
{
|
||||
GetWindow( WindowFilter.ReturnActiveIfNotLocked ).ShowAndSearchInternal( searchObjects, null, shouldSearchChildren );
|
||||
}
|
||||
|
||||
// Quickly show the AssetUsageDetector window and initiate a search
|
||||
public static void ShowAndSearch( AssetUsageDetector.Parameters searchParameters, bool? shouldSearchChildren = null )
|
||||
{
|
||||
if( searchParameters == null )
|
||||
{
|
||||
Debug.LogError( "searchParameters can't be null!" );
|
||||
return;
|
||||
}
|
||||
|
||||
GetWindow( WindowFilter.ReturnActiveIfNotLocked ).ShowAndSearchInternal( searchParameters.objectsToSearch, searchParameters, shouldSearchChildren );
|
||||
}
|
||||
|
||||
private static void CallSearchSelectedAssetReferencesOnce()
|
||||
{
|
||||
EditorApplication.update -= CallSearchSelectedAssetReferencesOnce;
|
||||
SearchSelectedAssetReferences( new MenuCommand( null ) );
|
||||
}
|
||||
|
||||
private static void CallSearchSelectedAssetReferencesWithChildrenOnce()
|
||||
{
|
||||
EditorApplication.update -= CallSearchSelectedAssetReferencesWithChildrenOnce;
|
||||
SearchSelectedAssetReferencesWithChildren( new MenuCommand( null ) );
|
||||
}
|
||||
|
||||
private void ShowAndSearchInternal( IEnumerable<Object> searchObjects, AssetUsageDetector.Parameters searchParameters, bool? shouldSearchChildren )
|
||||
{
|
||||
if( !ReturnToSetupPhase() )
|
||||
{
|
||||
Debug.LogError( "Need to reset the previous search first!" );
|
||||
return;
|
||||
}
|
||||
|
||||
objectsToSearch.Clear();
|
||||
if( searchObjects != null )
|
||||
{
|
||||
foreach( Object obj in searchObjects )
|
||||
objectsToSearch.Add( new ObjectToSearch( obj, shouldSearchChildren ) );
|
||||
}
|
||||
|
||||
if( searchParameters != null )
|
||||
{
|
||||
ParseSceneSearchMode( searchParameters.searchInScenes );
|
||||
searchInSceneLightingSettings = searchParameters.searchInSceneLightingSettings;
|
||||
searchInAssetsFolder = searchParameters.searchInAssetsFolder;
|
||||
dontSearchInSourceAssets = searchParameters.dontSearchInSourceAssets;
|
||||
searchInProjectSettings = searchParameters.searchInProjectSettings;
|
||||
searchDepthLimit = searchParameters.searchDepthLimit;
|
||||
fieldModifiers = searchParameters.fieldModifiers;
|
||||
propertyModifiers = searchParameters.propertyModifiers;
|
||||
searchNonSerializableVariables = searchParameters.searchNonSerializableVariables;
|
||||
searchUnusedMaterialProperties = searchParameters.searchUnusedMaterialProperties;
|
||||
searchRefactoring = searchParameters.searchRefactoring;
|
||||
lazySceneSearch = searchParameters.lazySceneSearch;
|
||||
#if ASSET_USAGE_ADDRESSABLES
|
||||
addressablesSupport = searchParameters.addressablesSupport;
|
||||
#endif
|
||||
calculateUnusedObjects = searchParameters.calculateUnusedObjects;
|
||||
hideDuplicateRows = searchParameters.hideDuplicateRows;
|
||||
hideReduntantPrefabVariantLinks = searchParameters.hideReduntantPrefabVariantLinks;
|
||||
noAssetDatabaseChanges = searchParameters.noAssetDatabaseChanges;
|
||||
showDetailedProgressBar = searchParameters.showDetailedProgressBar;
|
||||
|
||||
searchInAssetsSubset.Clear();
|
||||
if( searchParameters.searchInAssetsSubset != null )
|
||||
{
|
||||
foreach( Object obj in searchParameters.searchInAssetsSubset )
|
||||
searchInAssetsSubset.Add( obj );
|
||||
}
|
||||
|
||||
excludedAssets.Clear();
|
||||
if( searchParameters.excludedAssetsFromSearch != null )
|
||||
{
|
||||
foreach( Object obj in searchParameters.excludedAssetsFromSearch )
|
||||
excludedAssets.Add( obj );
|
||||
}
|
||||
|
||||
excludedScenes.Clear();
|
||||
if( searchParameters.excludedScenesFromSearch != null )
|
||||
{
|
||||
foreach( Object obj in searchParameters.excludedScenesFromSearch )
|
||||
excludedScenes.Add( obj );
|
||||
}
|
||||
}
|
||||
|
||||
InitiateSearch();
|
||||
Repaint();
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
LoadPrefs();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if( currentPhase == Phase.Complete && AssetUsageDetectorSettings.ShowCustomTooltip )
|
||||
wantsMouseMove = wantsMouseEnterLeaveWindow = true; // These values aren't preserved during domain reload on Unity 2020.3.0f1
|
||||
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
PrefabStage.prefabStageClosing -= ReplacePrefabStageObjectsWithAssets;
|
||||
PrefabStage.prefabStageClosing += ReplacePrefabStageObjectsWithAssets;
|
||||
#endif
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
PrefabStage.prefabStageClosing -= ReplacePrefabStageObjectsWithAssets;
|
||||
#endif
|
||||
SearchResultTooltip.Hide();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if( core != null )
|
||||
core.SaveCache();
|
||||
|
||||
SavePrefs();
|
||||
|
||||
if( searchResult != null && currentPhase == Phase.Complete )
|
||||
searchResult.RestoreInitialSceneSetup();
|
||||
}
|
||||
|
||||
private void SavePrefs()
|
||||
{
|
||||
EditorPrefs.SetInt( PREFS_SEARCH_SCENES, (int) GetSceneSearchMode( false ) );
|
||||
EditorPrefs.SetBool( PREFS_SEARCH_SCENE_LIGHTING_SETTINGS, searchInSceneLightingSettings );
|
||||
EditorPrefs.SetBool( PREFS_SEARCH_ASSETS, searchInAssetsFolder );
|
||||
EditorPrefs.SetBool( PREFS_DONT_SEARCH_SOURCE_ASSETS, dontSearchInSourceAssets );
|
||||
EditorPrefs.SetBool( PREFS_SEARCH_PROJECT_SETTINGS, searchInProjectSettings );
|
||||
EditorPrefs.SetInt( PREFS_SEARCH_DEPTH_LIMIT, searchDepthLimit );
|
||||
EditorPrefs.SetInt( PREFS_SEARCH_FIELDS, (int) fieldModifiers );
|
||||
EditorPrefs.SetInt( PREFS_SEARCH_PROPERTIES, (int) propertyModifiers );
|
||||
EditorPrefs.SetBool( PREFS_SEARCH_NON_SERIALIZABLES, searchNonSerializableVariables );
|
||||
EditorPrefs.SetBool( PREFS_SEARCH_UNUSED_MATERIAL_PROPERTIES, searchUnusedMaterialProperties );
|
||||
EditorPrefs.SetBool( PREFS_LAZY_SCENE_SEARCH, lazySceneSearch );
|
||||
#if ASSET_USAGE_ADDRESSABLES
|
||||
EditorPrefs.SetBool( PREFS_ADDRESSABLES_SUPPORT, addressablesSupport );
|
||||
#endif
|
||||
EditorPrefs.SetBool( PREFS_CALCULATE_UNUSED_OBJECTS, calculateUnusedObjects );
|
||||
EditorPrefs.SetBool( PREFS_HIDE_DUPLICATE_ROWS, hideDuplicateRows );
|
||||
EditorPrefs.SetBool( PREFS_HIDE_REDUNDANT_PREFAB_VARIANT_LINKS, hideReduntantPrefabVariantLinks );
|
||||
EditorPrefs.SetBool( PREFS_SHOW_PROGRESS, showDetailedProgressBar );
|
||||
}
|
||||
|
||||
private void LoadPrefs()
|
||||
{
|
||||
ParseSceneSearchMode( (SceneSearchMode) EditorPrefs.GetInt( PREFS_SEARCH_SCENES, (int) ( SceneSearchMode.OpenScenes | SceneSearchMode.ScenesInBuildSettingsTickedOnly | SceneSearchMode.AllScenes ) ) );
|
||||
searchInSceneLightingSettings = EditorPrefs.GetBool( PREFS_SEARCH_SCENE_LIGHTING_SETTINGS, true );
|
||||
searchInAssetsFolder = EditorPrefs.GetBool( PREFS_SEARCH_ASSETS, true );
|
||||
dontSearchInSourceAssets = EditorPrefs.GetBool( PREFS_DONT_SEARCH_SOURCE_ASSETS, true );
|
||||
searchInProjectSettings = EditorPrefs.GetBool( PREFS_SEARCH_PROJECT_SETTINGS, true );
|
||||
searchDepthLimit = EditorPrefs.GetInt( PREFS_SEARCH_DEPTH_LIMIT, 4 );
|
||||
fieldModifiers = (BindingFlags) EditorPrefs.GetInt( PREFS_SEARCH_FIELDS, (int) ( BindingFlags.Public | BindingFlags.NonPublic ) );
|
||||
propertyModifiers = (BindingFlags) EditorPrefs.GetInt( PREFS_SEARCH_PROPERTIES, (int) ( BindingFlags.Public | BindingFlags.NonPublic ) );
|
||||
searchNonSerializableVariables = EditorPrefs.GetBool( PREFS_SEARCH_NON_SERIALIZABLES, true );
|
||||
searchUnusedMaterialProperties = EditorPrefs.GetBool( PREFS_SEARCH_UNUSED_MATERIAL_PROPERTIES, true );
|
||||
lazySceneSearch = EditorPrefs.GetBool( PREFS_LAZY_SCENE_SEARCH, true );
|
||||
#if ASSET_USAGE_ADDRESSABLES
|
||||
addressablesSupport = EditorPrefs.GetBool( PREFS_ADDRESSABLES_SUPPORT, false );
|
||||
#endif
|
||||
calculateUnusedObjects = EditorPrefs.GetBool( PREFS_CALCULATE_UNUSED_OBJECTS, false );
|
||||
hideDuplicateRows = EditorPrefs.GetBool( PREFS_HIDE_DUPLICATE_ROWS, true );
|
||||
hideReduntantPrefabVariantLinks = EditorPrefs.GetBool( PREFS_HIDE_REDUNDANT_PREFAB_VARIANT_LINKS, true );
|
||||
showDetailedProgressBar = EditorPrefs.GetBool( PREFS_SHOW_PROGRESS, true );
|
||||
}
|
||||
|
||||
private SceneSearchMode GetSceneSearchMode( bool hideOptionsInPlayMode )
|
||||
{
|
||||
SceneSearchMode sceneSearchMode = SceneSearchMode.None;
|
||||
if( searchInOpenScenes )
|
||||
sceneSearchMode |= SceneSearchMode.OpenScenes;
|
||||
if( !hideOptionsInPlayMode || !EditorApplication.isPlaying )
|
||||
{
|
||||
if( searchInScenesInBuild )
|
||||
sceneSearchMode |= searchInScenesInBuildTickedOnly ? SceneSearchMode.ScenesInBuildSettingsTickedOnly : SceneSearchMode.ScenesInBuildSettingsAll;
|
||||
if( searchInAllScenes )
|
||||
sceneSearchMode |= SceneSearchMode.AllScenes;
|
||||
}
|
||||
|
||||
return sceneSearchMode;
|
||||
}
|
||||
|
||||
private void ParseSceneSearchMode( SceneSearchMode sceneSearchMode )
|
||||
{
|
||||
searchInOpenScenes = ( sceneSearchMode & SceneSearchMode.OpenScenes ) == SceneSearchMode.OpenScenes;
|
||||
searchInScenesInBuild = ( sceneSearchMode & SceneSearchMode.ScenesInBuildSettingsAll ) == SceneSearchMode.ScenesInBuildSettingsAll || ( sceneSearchMode & SceneSearchMode.ScenesInBuildSettingsTickedOnly ) == SceneSearchMode.ScenesInBuildSettingsTickedOnly;
|
||||
searchInScenesInBuildTickedOnly = ( sceneSearchMode & SceneSearchMode.ScenesInBuildSettingsAll ) != SceneSearchMode.ScenesInBuildSettingsAll;
|
||||
searchInAllScenes = ( sceneSearchMode & SceneSearchMode.AllScenes ) == SceneSearchMode.AllScenes;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if( shouldRepositionSelf )
|
||||
{
|
||||
shouldRepositionSelf = false;
|
||||
position = windowTargetPosition;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
// Make the window scrollable
|
||||
scrollPosition = EditorGUILayout.BeginScrollView( scrollPosition, Utilities.GL_EXPAND_WIDTH, Utilities.GL_EXPAND_HEIGHT );
|
||||
|
||||
GUILayout.BeginVertical();
|
||||
|
||||
if( currentPhase == Phase.Processing )
|
||||
{
|
||||
// If we are stuck at this phase, then we have encountered an exception
|
||||
GUILayout.Label( ". . . Search in progress or something went wrong (check console) . . ." );
|
||||
|
||||
if( GUILayout.Button( "RETURN", Utilities.GL_HEIGHT_30 ) )
|
||||
{
|
||||
ReturnToSetupPhase();
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
}
|
||||
else if( currentPhase == Phase.Setup )
|
||||
{
|
||||
DrawObjectsToSearchSection();
|
||||
|
||||
GUILayout.Space( 10f );
|
||||
|
||||
Color c = GUI.backgroundColor;
|
||||
GUI.backgroundColor = AssetUsageDetectorSettings.SettingsHeaderColor;
|
||||
GUILayout.Box( "<b>SEARCH IN</b>", Utilities.BoxGUIStyle, Utilities.GL_EXPAND_WIDTH );
|
||||
GUI.backgroundColor = c;
|
||||
|
||||
searchInAssetsFolder = WordWrappingToggleLeft( "Project window (Assets folder)", searchInAssetsFolder );
|
||||
|
||||
if( searchInAssetsFolder )
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space( 35f );
|
||||
GUILayout.BeginVertical();
|
||||
|
||||
searchInAssetsSubsetDrawer.Draw( searchInAssetsSubset );
|
||||
excludedAssetsDrawer.Draw( excludedAssets );
|
||||
|
||||
GUILayout.EndVertical();
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
GUILayout.Space( 5f );
|
||||
|
||||
dontSearchInSourceAssets = WordWrappingToggleLeft( "Don't search \"SEARCHED OBJECTS\" themselves for references", dontSearchInSourceAssets );
|
||||
searchUnusedMaterialProperties = WordWrappingToggleLeft( "Search unused material properties (e.g. normal map of a material that no longer uses normal mapping)", searchUnusedMaterialProperties );
|
||||
|
||||
Utilities.DrawSeparatorLine();
|
||||
|
||||
if( searchInAllScenes && !EditorApplication.isPlaying )
|
||||
GUI.enabled = false;
|
||||
|
||||
searchInOpenScenes = WordWrappingToggleLeft( "Currently open (loaded) scene(s)", searchInOpenScenes );
|
||||
|
||||
if( !EditorApplication.isPlaying )
|
||||
{
|
||||
searchInScenesInBuild = WordWrappingToggleLeft( "Scenes in Build Settings", searchInScenesInBuild );
|
||||
|
||||
if( searchInScenesInBuild )
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space( 35f );
|
||||
|
||||
searchInScenesInBuildTickedOnly = EditorGUILayout.ToggleLeft( "Ticked only", searchInScenesInBuildTickedOnly, Utilities.GL_WIDTH_100 );
|
||||
searchInScenesInBuildTickedOnly = !EditorGUILayout.ToggleLeft( "All", !searchInScenesInBuildTickedOnly, Utilities.GL_WIDTH_100 );
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
GUI.enabled = true;
|
||||
|
||||
searchInAllScenes = WordWrappingToggleLeft( "All scenes in the project", searchInAllScenes );
|
||||
}
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space( 35f );
|
||||
GUILayout.BeginVertical();
|
||||
|
||||
excludedScenesDrawer.Draw( excludedScenes );
|
||||
|
||||
GUILayout.EndVertical();
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
EditorGUI.BeginDisabledGroup( !searchInOpenScenes && !searchInScenesInBuild && !searchInAllScenes );
|
||||
searchInSceneLightingSettings = WordWrappingToggleLeft( "Scene Lighting Settings (WARNING: This may change the active scene during search)", searchInSceneLightingSettings );
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
Utilities.DrawSeparatorLine();
|
||||
|
||||
searchInProjectSettings = WordWrappingToggleLeft( "Project Settings (Player Settings, Graphics Settings etc.)", searchInProjectSettings );
|
||||
|
||||
GUILayout.Space( 10f );
|
||||
|
||||
GUI.backgroundColor = AssetUsageDetectorSettings.SettingsHeaderColor;
|
||||
GUILayout.Box( "<b>SETTINGS</b>", Utilities.BoxGUIStyle, Utilities.GL_EXPAND_WIDTH );
|
||||
GUI.backgroundColor = c;
|
||||
|
||||
#if ASSET_USAGE_ADDRESSABLES
|
||||
EditorGUI.BeginDisabledGroup( addressablesSupport );
|
||||
#endif
|
||||
lazySceneSearch = WordWrappingToggleLeft( "Lazy scene search: scenes are searched in detail only when they are manually refreshed (faster search)", lazySceneSearch );
|
||||
#if ASSET_USAGE_ADDRESSABLES
|
||||
EditorGUI.EndDisabledGroup();
|
||||
addressablesSupport = WordWrappingToggleLeft( "Addressables support (Experimental) (WARNING: 'Lazy scene search' will be disabled) (slower search)", addressablesSupport );
|
||||
#endif
|
||||
calculateUnusedObjects = WordWrappingToggleLeft( "Calculate unused objects", calculateUnusedObjects );
|
||||
hideDuplicateRows = WordWrappingToggleLeft( "Hide duplicate rows in search results", hideDuplicateRows );
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
hideReduntantPrefabVariantLinks = WordWrappingToggleLeft( "Hide redundant prefab variant links (when the same value is assigned to the same Component of a prefab and its variant(s))", hideReduntantPrefabVariantLinks );
|
||||
#endif
|
||||
noAssetDatabaseChanges = WordWrappingToggleLeft( "I haven't modified any assets/scenes since the last search (faster search)", noAssetDatabaseChanges );
|
||||
showDetailedProgressBar = WordWrappingToggleLeft( "Update search progress bar more often (cancelable search) (slower search)", showDetailedProgressBar );
|
||||
|
||||
GUILayout.Space( 10f );
|
||||
|
||||
// Don't let the user press the GO button without any valid search location
|
||||
if( !searchInAllScenes && !searchInOpenScenes && !searchInScenesInBuild && !searchInAssetsFolder && !searchInProjectSettings )
|
||||
GUI.enabled = false;
|
||||
|
||||
if( GUILayout.Button( "GO!", Utilities.GL_HEIGHT_30 ) )
|
||||
{
|
||||
InitiateSearch();
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
|
||||
GUILayout.Space( 5f );
|
||||
}
|
||||
else if( currentPhase == Phase.Complete )
|
||||
{
|
||||
// Draw the results of the search
|
||||
GUI.enabled = false;
|
||||
|
||||
DrawObjectsToSearchSection();
|
||||
|
||||
if( drawObjectsToSearchSection )
|
||||
GUILayout.Space( 10f );
|
||||
|
||||
GUI.enabled = true;
|
||||
|
||||
if( GUILayout.Button( "Reset Search", Utilities.GL_HEIGHT_30 ) )
|
||||
{
|
||||
ReturnToSetupPhase();
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
|
||||
if( searchResult == null )
|
||||
{
|
||||
EditorGUILayout.HelpBox( "ERROR: searchResult is null", MessageType.Error );
|
||||
return;
|
||||
}
|
||||
else if( !searchResult.SearchCompletedSuccessfully )
|
||||
EditorGUILayout.HelpBox( "ERROR: search was interrupted, check the logs for more info", MessageType.Error );
|
||||
|
||||
if( searchResult.NumberOfGroups == 0 )
|
||||
{
|
||||
GUILayout.Space( 10f );
|
||||
GUILayout.Box( "No references found...", Utilities.BoxGUIStyle, Utilities.GL_EXPAND_WIDTH );
|
||||
}
|
||||
else
|
||||
{
|
||||
noAssetDatabaseChanges = WordWrappingToggleLeft( "I haven't modified any assets/scenes since the last search (faster Refresh)", noAssetDatabaseChanges );
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
scrollPosition.y = searchResult.DrawOnGUI( this, scrollPosition.y, noAssetDatabaseChanges );
|
||||
}
|
||||
}
|
||||
|
||||
if( Event.current.type == EventType.MouseLeaveWindow )
|
||||
{
|
||||
SearchResultTooltip.Hide();
|
||||
|
||||
if( searchResult != null )
|
||||
searchResult.CancelDelayedTreeViewTooltip();
|
||||
}
|
||||
|
||||
GUILayout.EndVertical();
|
||||
|
||||
EditorGUILayout.EndScrollView();
|
||||
}
|
||||
|
||||
private void DrawObjectsToSearchSection()
|
||||
{
|
||||
Color c = GUI.backgroundColor;
|
||||
GUI.backgroundColor = AssetUsageDetectorSettings.SettingsHeaderColor;
|
||||
GUILayout.Box( "<b>SEARCHED OBJECTS</b>", Utilities.BoxGUIStyle, Utilities.GL_EXPAND_WIDTH );
|
||||
GUI.backgroundColor = c;
|
||||
|
||||
Rect searchedObjectsHeaderRect = GUILayoutUtility.GetLastRect();
|
||||
searchedObjectsHeaderRect.x += 5f;
|
||||
searchedObjectsHeaderRect.yMin += ( searchedObjectsHeaderRect.height - EditorGUIUtility.singleLineHeight ) * 0.5f;
|
||||
searchedObjectsHeaderRect.height = EditorGUIUtility.singleLineHeight;
|
||||
|
||||
drawObjectsToSearchSection = EditorGUI.Foldout( searchedObjectsHeaderRect, drawObjectsToSearchSection, GUIContent.none, true );
|
||||
|
||||
if( drawObjectsToSearchSection )
|
||||
objectsToSearchDrawer.Draw( objectsToSearch );
|
||||
}
|
||||
|
||||
public static bool WordWrappingToggleLeft( string label, bool value )
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
bool result = EditorGUILayout.ToggleLeft( GUIContent.none, value, GL_WIDTH_12 );
|
||||
if( GUILayout.Button( label, EditorStyles.wordWrappedLabel ) )
|
||||
{
|
||||
GUI.FocusControl( null );
|
||||
result = !value;
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void InitiateSearch()
|
||||
{
|
||||
currentPhase = Phase.Processing;
|
||||
|
||||
SavePrefs();
|
||||
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
ReplacePrefabStageObjectsWithAssets( PrefabStageUtility.GetCurrentPrefabStage() );
|
||||
#endif
|
||||
|
||||
// Start searching
|
||||
searchResult = core.Run( new AssetUsageDetector.Parameters()
|
||||
{
|
||||
objectsToSearch = !objectsToSearch.IsEmpty() ? new ObjectToSearchEnumerator( objectsToSearch ).ToArray() : null,
|
||||
searchInScenes = GetSceneSearchMode( true ),
|
||||
searchInSceneLightingSettings = searchInSceneLightingSettings,
|
||||
searchInAssetsFolder = searchInAssetsFolder,
|
||||
searchInAssetsSubset = !searchInAssetsSubset.IsEmpty() ? searchInAssetsSubset.ToArray() : null,
|
||||
excludedAssetsFromSearch = !excludedAssets.IsEmpty() ? excludedAssets.ToArray() : null,
|
||||
dontSearchInSourceAssets = dontSearchInSourceAssets,
|
||||
excludedScenesFromSearch = !excludedScenes.IsEmpty() ? excludedScenes.ToArray() : null,
|
||||
searchInProjectSettings = searchInProjectSettings,
|
||||
//fieldModifiers = fieldModifiers,
|
||||
//propertyModifiers = propertyModifiers,
|
||||
//searchDepthLimit = searchDepthLimit,
|
||||
//searchNonSerializableVariables = searchNonSerializableVariables,
|
||||
searchUnusedMaterialProperties = searchUnusedMaterialProperties,
|
||||
searchRefactoring = searchRefactoring,
|
||||
#if ASSET_USAGE_ADDRESSABLES
|
||||
lazySceneSearch = lazySceneSearch && !addressablesSupport,
|
||||
addressablesSupport = addressablesSupport,
|
||||
#else
|
||||
lazySceneSearch = lazySceneSearch,
|
||||
#endif
|
||||
calculateUnusedObjects = calculateUnusedObjects,
|
||||
hideDuplicateRows = hideDuplicateRows,
|
||||
hideReduntantPrefabVariantLinks = hideReduntantPrefabVariantLinks,
|
||||
noAssetDatabaseChanges = noAssetDatabaseChanges,
|
||||
showDetailedProgressBar = showDetailedProgressBar
|
||||
} );
|
||||
|
||||
currentPhase = Phase.Complete;
|
||||
|
||||
// We really don't want SearchRefactoring to affect next searches unless the search is initiated via ShowAndSearch again
|
||||
searchRefactoring = null;
|
||||
|
||||
if( AssetUsageDetectorSettings.ShowCustomTooltip )
|
||||
wantsMouseMove = wantsMouseEnterLeaveWindow = true;
|
||||
}
|
||||
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
// Try replacing searched objects who are part of currently open prefab stage with their corresponding prefab assets
|
||||
public void ReplacePrefabStageObjectsWithAssets( PrefabStage prefabStage )
|
||||
{
|
||||
if( prefabStage == null || !prefabStage.stageHandle.IsValid() )
|
||||
return;
|
||||
|
||||
#if UNITY_2020_1_OR_NEWER
|
||||
GameObject prefabAsset = AssetDatabase.LoadAssetAtPath<GameObject>( prefabStage.assetPath );
|
||||
#else
|
||||
GameObject prefabAsset = AssetDatabase.LoadAssetAtPath<GameObject>( prefabStage.prefabAssetPath );
|
||||
#endif
|
||||
if( prefabAsset == null || prefabAsset.Equals( null ) )
|
||||
return;
|
||||
|
||||
for( int i = 0; i < objectsToSearch.Count; i++ )
|
||||
{
|
||||
Object obj = objectsToSearch[i].obj;
|
||||
if( obj != null && !obj.Equals( null ) && obj is GameObject && prefabStage.IsPartOfPrefabContents( (GameObject) obj ) )
|
||||
{
|
||||
GameObject prefabStageObjectSource = ( (GameObject) obj ).FollowSymmetricHierarchy( prefabStage.prefabContentsRoot, prefabAsset );
|
||||
if( prefabStageObjectSource != null )
|
||||
objectsToSearch[i].obj = prefabStageObjectSource;
|
||||
|
||||
List<ObjectToSearch.SubAsset> subAssets = objectsToSearch[i].subAssets;
|
||||
for( int j = 0; j < subAssets.Count; j++ )
|
||||
{
|
||||
obj = subAssets[j].subAsset;
|
||||
if( obj != null && !obj.Equals( null ) && obj is GameObject && prefabStage.IsPartOfPrefabContents( (GameObject) obj ) )
|
||||
{
|
||||
prefabStageObjectSource = ( (GameObject) obj ).FollowSymmetricHierarchy( prefabStage.prefabContentsRoot, prefabAsset );
|
||||
if( prefabStageObjectSource != null )
|
||||
subAssets[j].subAsset = prefabStageObjectSource;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private bool ReturnToSetupPhase()
|
||||
{
|
||||
if( searchResult != null && !EditorApplication.isPlaying && !searchResult.RestoreInitialSceneSetup() )
|
||||
return false;
|
||||
|
||||
searchResult = null;
|
||||
currentPhase = Phase.Setup;
|
||||
wantsMouseMove = wantsMouseEnterLeaveWindow = false;
|
||||
|
||||
SearchResultTooltip.Hide();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
internal void OnSettingsChanged( bool highlightedSearchTextColorChanged = false, bool tooltipDescriptionsColorChanged = false )
|
||||
{
|
||||
if( searchResult == null )
|
||||
return;
|
||||
|
||||
wantsMouseMove = wantsMouseEnterLeaveWindow = AssetUsageDetectorSettings.ShowCustomTooltip;
|
||||
|
||||
for( int i = searchResult.NumberOfGroups - 1; i >= 0; i-- )
|
||||
{
|
||||
if( searchResult[i].treeView != null )
|
||||
{
|
||||
searchResult[i].treeView.rowHeight = EditorGUIUtility.singleLineHeight + AssetUsageDetectorSettings.ExtraRowHeight;
|
||||
searchResult[i].treeView.OnSettingsChanged( highlightedSearchTextColorChanged, tooltipDescriptionsColorChanged );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 271a22c69c3d96c4dbdd04cca415a840
|
||||
timeCreated: 1520032279
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
130
Assets/Plugins/AssetUsageDetector/Editor/Enumerators.cs
Normal file
130
Assets/Plugins/AssetUsageDetector/Editor/Enumerators.cs
Normal file
@ -0,0 +1,130 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AssetUsageDetectorNamespace
|
||||
{
|
||||
public class EmptyEnumerator<T> : IEnumerable<T>, IEnumerator<T>
|
||||
{
|
||||
public T Current { get { return default( T ); } }
|
||||
object IEnumerator.Current { get { return Current; } }
|
||||
|
||||
public void Dispose() { }
|
||||
public void Reset() { }
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public class ObjectToSearchEnumerator : IEnumerable<Object>
|
||||
{
|
||||
public class Enumerator : IEnumerator<Object>
|
||||
{
|
||||
public Object Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if( subAssetIndex < 0 )
|
||||
return source[index].obj;
|
||||
|
||||
return source[index].subAssets[subAssetIndex].subAsset;
|
||||
}
|
||||
}
|
||||
|
||||
object IEnumerator.Current { get { return Current; } }
|
||||
|
||||
private List<ObjectToSearch> source;
|
||||
private int index;
|
||||
private int subAssetIndex;
|
||||
|
||||
public Enumerator( List<ObjectToSearch> source )
|
||||
{
|
||||
this.source = source;
|
||||
Reset();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
source = null;
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if( subAssetIndex < -1 )
|
||||
{
|
||||
subAssetIndex = -1;
|
||||
|
||||
if( ++index >= source.Count )
|
||||
return false;
|
||||
|
||||
// Skip folder assets in the enumeration, AssetUsageDetector expands encountered folders automatically
|
||||
// and we don't want that to happen as source[index].subAssets already contains the folder's contents
|
||||
if( !source[index].obj.IsFolder() )
|
||||
return true;
|
||||
}
|
||||
|
||||
List<ObjectToSearch.SubAsset> subAssets = source[index].subAssets;
|
||||
if( subAssets != null )
|
||||
{
|
||||
while( ++subAssetIndex < subAssets.Count && !subAssets[subAssetIndex].shouldSearch )
|
||||
continue;
|
||||
|
||||
if( subAssetIndex < subAssets.Count )
|
||||
return true;
|
||||
}
|
||||
|
||||
subAssetIndex = -2;
|
||||
return MoveNext();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
index = -1;
|
||||
subAssetIndex = -2;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly List<ObjectToSearch> source;
|
||||
|
||||
public ObjectToSearchEnumerator( List<ObjectToSearch> source )
|
||||
{
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public IEnumerator<Object> GetEnumerator()
|
||||
{
|
||||
return new Enumerator( source );
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public Object[] ToArray()
|
||||
{
|
||||
int count = 0;
|
||||
foreach( Object obj in this )
|
||||
count++;
|
||||
|
||||
Object[] result = new Object[count];
|
||||
int index = 0;
|
||||
foreach( Object obj in this )
|
||||
result[index++] = obj;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Plugins/AssetUsageDetector/Editor/Enumerators.cs.meta
Normal file
12
Assets/Plugins/AssetUsageDetector/Editor/Enumerators.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 894047c47ce45cf40939dae24afcc72b
|
||||
timeCreated: 1562079461
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
252
Assets/Plugins/AssetUsageDetector/Editor/ListDrawer.cs
Normal file
252
Assets/Plugins/AssetUsageDetector/Editor/ListDrawer.cs
Normal file
@ -0,0 +1,252 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AssetUsageDetectorNamespace
|
||||
{
|
||||
public abstract class ListDrawer<T>
|
||||
{
|
||||
private readonly string label;
|
||||
private readonly bool acceptSceneObjects;
|
||||
|
||||
protected ListDrawer( string label, bool acceptSceneObjects )
|
||||
{
|
||||
this.label = label;
|
||||
this.acceptSceneObjects = acceptSceneObjects;
|
||||
}
|
||||
|
||||
// Exposes a list on GUI
|
||||
public bool Draw( List<T> list )
|
||||
{
|
||||
bool hasChanged = false;
|
||||
bool guiEnabled = GUI.enabled;
|
||||
|
||||
Event ev = Event.current;
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
|
||||
GUILayout.Label( label );
|
||||
|
||||
if( guiEnabled )
|
||||
{
|
||||
// Handle drag & drop references to array
|
||||
// Credit: https://answers.unity.com/answers/657877/view.html
|
||||
if( ( ev.type == EventType.DragPerform || ev.type == EventType.DragUpdated ) && GUILayoutUtility.GetLastRect().Contains( ev.mousePosition ) )
|
||||
{
|
||||
DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
|
||||
if( ev.type == EventType.DragPerform )
|
||||
{
|
||||
DragAndDrop.AcceptDrag();
|
||||
|
||||
Object[] draggedObjects = DragAndDrop.objectReferences;
|
||||
if( draggedObjects.Length > 0 )
|
||||
{
|
||||
for( int i = 0; i < draggedObjects.Length; i++ )
|
||||
{
|
||||
if( draggedObjects[i] != null && !draggedObjects[i].Equals( null ) )
|
||||
{
|
||||
bool replacedNullElement = false;
|
||||
for( int j = 0; j < list.Count; j++ )
|
||||
{
|
||||
if( IsElementNull( list[j] ) )
|
||||
{
|
||||
list[j] = CreateElement( draggedObjects[i] );
|
||||
|
||||
replacedNullElement = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( !replacedNullElement )
|
||||
list.Add( CreateElement( draggedObjects[i] ) );
|
||||
|
||||
hasChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ev.Use();
|
||||
}
|
||||
else if( ev.type == EventType.ContextClick && GUILayoutUtility.GetLastRect().Contains( ev.mousePosition ) )
|
||||
{
|
||||
GenericMenu contextMenu = new GenericMenu();
|
||||
contextMenu.AddItem( new GUIContent( "Clear" ), false, () =>
|
||||
{
|
||||
list.Clear();
|
||||
list.Add( CreateElement( null ) );
|
||||
} );
|
||||
contextMenu.ShowAsContext();
|
||||
|
||||
ev.Use();
|
||||
}
|
||||
|
||||
if( GUILayout.Button( "+", Utilities.GL_WIDTH_25 ) )
|
||||
list.Insert( 0, CreateElement( null ) );
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
for( int i = 0; i < list.Count; i++ )
|
||||
{
|
||||
T element = list[i];
|
||||
|
||||
GUI.changed = false;
|
||||
GUILayout.BeginHorizontal();
|
||||
|
||||
Object prevObject = GetObjectFromElement( element );
|
||||
Object newObject = EditorGUILayout.ObjectField( "", prevObject, typeof( Object ), acceptSceneObjects );
|
||||
|
||||
if( GUI.changed )
|
||||
{
|
||||
hasChanged = true;
|
||||
SetObjectOfElement( list, i, newObject );
|
||||
}
|
||||
|
||||
if( guiEnabled )
|
||||
{
|
||||
if( GUILayout.Button( "+", Utilities.GL_WIDTH_25 ) )
|
||||
list.Insert( i + 1, CreateElement( null ) );
|
||||
|
||||
if( GUILayout.Button( "-", Utilities.GL_WIDTH_25 ) )
|
||||
{
|
||||
if( element != null && !element.Equals( null ) )
|
||||
hasChanged = true;
|
||||
|
||||
// Lists with no elements look ugly, always keep a dummy null variable
|
||||
if( list.Count > 1 )
|
||||
list.RemoveAt( i-- );
|
||||
else
|
||||
list[0] = CreateElement( null );
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
PostElementDrawer( element );
|
||||
}
|
||||
|
||||
return hasChanged;
|
||||
}
|
||||
|
||||
protected abstract T CreateElement( Object source );
|
||||
protected abstract Object GetObjectFromElement( T element );
|
||||
protected abstract void SetObjectOfElement( List<T> list, int index, Object value );
|
||||
protected abstract bool IsElementNull( T element );
|
||||
protected abstract void PostElementDrawer( T element );
|
||||
}
|
||||
|
||||
public class ObjectListDrawer : ListDrawer<Object>
|
||||
{
|
||||
public ObjectListDrawer( string label, bool acceptSceneObjects ) : base( label, acceptSceneObjects )
|
||||
{
|
||||
}
|
||||
|
||||
protected override Object CreateElement( Object source )
|
||||
{
|
||||
return source;
|
||||
}
|
||||
|
||||
protected override Object GetObjectFromElement( Object element )
|
||||
{
|
||||
return element;
|
||||
}
|
||||
|
||||
protected override void SetObjectOfElement( List<Object> list, int index, Object value )
|
||||
{
|
||||
list[index] = value;
|
||||
}
|
||||
|
||||
protected override bool IsElementNull( Object element )
|
||||
{
|
||||
return element == null || element.Equals( null );
|
||||
}
|
||||
|
||||
protected override void PostElementDrawer( Object element )
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class ObjectToSearchListDrawer : ListDrawer<ObjectToSearch>
|
||||
{
|
||||
public ObjectToSearchListDrawer() : base( "Find references of:", true )
|
||||
{
|
||||
}
|
||||
|
||||
protected override ObjectToSearch CreateElement( Object source )
|
||||
{
|
||||
return new ObjectToSearch( source );
|
||||
}
|
||||
|
||||
protected override Object GetObjectFromElement( ObjectToSearch element )
|
||||
{
|
||||
return element.obj;
|
||||
}
|
||||
|
||||
protected override void SetObjectOfElement( List<ObjectToSearch> list, int index, Object value )
|
||||
{
|
||||
list[index].obj = value;
|
||||
list[index].RefreshSubAssets();
|
||||
}
|
||||
|
||||
protected override bool IsElementNull( ObjectToSearch element )
|
||||
{
|
||||
return element == null || element.obj == null || element.obj.Equals( null );
|
||||
}
|
||||
|
||||
protected override void PostElementDrawer( ObjectToSearch element )
|
||||
{
|
||||
List<ObjectToSearch.SubAsset> subAssetsToSearch = element.subAssets;
|
||||
if( subAssetsToSearch.Count > 0 )
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
|
||||
// 0-> all toggles off, 1-> mixed, 2-> all toggles on
|
||||
bool toggleAllSubAssets = subAssetsToSearch[0].shouldSearch;
|
||||
bool mixedToggle = false;
|
||||
for( int j = 1; j < subAssetsToSearch.Count; j++ )
|
||||
{
|
||||
if( subAssetsToSearch[j].shouldSearch != toggleAllSubAssets )
|
||||
{
|
||||
mixedToggle = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( mixedToggle )
|
||||
EditorGUI.showMixedValue = true;
|
||||
|
||||
GUI.changed = false;
|
||||
toggleAllSubAssets = EditorGUILayout.Toggle( toggleAllSubAssets, Utilities.GL_WIDTH_25 );
|
||||
if( GUI.changed )
|
||||
{
|
||||
for( int j = 0; j < subAssetsToSearch.Count; j++ )
|
||||
subAssetsToSearch[j].shouldSearch = toggleAllSubAssets;
|
||||
}
|
||||
|
||||
EditorGUI.showMixedValue = false;
|
||||
|
||||
element.showSubAssetsFoldout = EditorGUILayout.Foldout( element.showSubAssetsFoldout, "Include sub-assets in search:", true );
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
if( element.showSubAssetsFoldout )
|
||||
{
|
||||
for( int j = 0; j < subAssetsToSearch.Count; j++ )
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
|
||||
subAssetsToSearch[j].shouldSearch = EditorGUILayout.Toggle( subAssetsToSearch[j].shouldSearch, Utilities.GL_WIDTH_25 );
|
||||
|
||||
bool guiEnabled = GUI.enabled;
|
||||
GUI.enabled = false;
|
||||
EditorGUILayout.ObjectField( string.Empty, subAssetsToSearch[j].subAsset, typeof( Object ), true );
|
||||
GUI.enabled = guiEnabled;
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Plugins/AssetUsageDetector/Editor/ListDrawer.cs.meta
Normal file
12
Assets/Plugins/AssetUsageDetector/Editor/ListDrawer.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 88a4a4e861026b2498a437ce1e12b054
|
||||
timeCreated: 1568758673
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
120
Assets/Plugins/AssetUsageDetector/Editor/ObjectToSearch.cs
Normal file
120
Assets/Plugins/AssetUsageDetector/Editor/ObjectToSearch.cs
Normal file
@ -0,0 +1,120 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace AssetUsageDetectorNamespace
|
||||
{
|
||||
[Serializable]
|
||||
public class ObjectToSearch
|
||||
{
|
||||
[Serializable]
|
||||
public class SubAsset
|
||||
{
|
||||
public Object subAsset;
|
||||
public bool shouldSearch;
|
||||
|
||||
public SubAsset( Object subAsset, bool shouldSearch )
|
||||
{
|
||||
this.subAsset = subAsset;
|
||||
this.shouldSearch = shouldSearch;
|
||||
}
|
||||
}
|
||||
|
||||
public Object obj;
|
||||
public List<SubAsset> subAssets;
|
||||
public bool showSubAssetsFoldout;
|
||||
|
||||
private static HashSet<Object> currentSubAssets;
|
||||
|
||||
public ObjectToSearch( Object obj, bool? shouldSearchChildren = null )
|
||||
{
|
||||
this.obj = obj;
|
||||
RefreshSubAssets( shouldSearchChildren );
|
||||
}
|
||||
|
||||
public void RefreshSubAssets( bool? shouldSearchChildren = null )
|
||||
{
|
||||
if( subAssets == null )
|
||||
subAssets = new List<SubAsset>();
|
||||
else
|
||||
subAssets.Clear();
|
||||
|
||||
if( currentSubAssets == null )
|
||||
currentSubAssets = new HashSet<Object>();
|
||||
else
|
||||
currentSubAssets.Clear();
|
||||
|
||||
AddSubAssets( obj, false, shouldSearchChildren );
|
||||
currentSubAssets.Clear();
|
||||
}
|
||||
|
||||
private void AddSubAssets( Object target, bool includeTarget, bool? shouldSearchChildren )
|
||||
{
|
||||
if( target == null || target.Equals( null ) )
|
||||
return;
|
||||
|
||||
if( !target.IsAsset() )
|
||||
{
|
||||
GameObject go = target as GameObject;
|
||||
if( !go || !go.scene.IsValid() )
|
||||
return;
|
||||
|
||||
// If this is a scene object, add its child objects to the sub-assets list
|
||||
// but don't include them in the search by default
|
||||
Transform goTransform = go.transform;
|
||||
Transform[] children = go.GetComponentsInChildren<Transform>( true );
|
||||
for( int i = 0; i < children.Length; i++ )
|
||||
{
|
||||
if( ReferenceEquals( children[i], goTransform ) )
|
||||
continue;
|
||||
|
||||
subAssets.Add( new SubAsset( children[i].gameObject, shouldSearchChildren ?? false ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !AssetDatabase.IsMainAsset( target ) || target is SceneAsset )
|
||||
return;
|
||||
|
||||
if( includeTarget )
|
||||
{
|
||||
if( currentSubAssets.Add( target ) )
|
||||
subAssets.Add( new SubAsset( target, shouldSearchChildren ?? true ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// If asset is a directory, add all of its contents as sub-assets recursively
|
||||
if( target.IsFolder() )
|
||||
{
|
||||
foreach( string filePath in Utilities.EnumerateFolderContents( target ) )
|
||||
AddSubAssets( AssetDatabase.LoadAssetAtPath<Object>( filePath ), true, shouldSearchChildren );
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Find sub-asset(s) of the asset (if any)
|
||||
Object[] assets = AssetDatabase.LoadAllAssetsAtPath( AssetDatabase.GetAssetPath( target ) );
|
||||
for( int i = 0; i < assets.Length; i++ )
|
||||
{
|
||||
Object asset = assets[i];
|
||||
if( asset == null || asset.Equals( null ) || asset is Component || asset == target )
|
||||
continue;
|
||||
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
// Nested prefabs in prefab assets add an additional native object of type 'UnityEngine.PrefabInstance' to the prefab. Managed type of that native type
|
||||
// is UnityEngine.Object (i.e. GetType() returns UnityEngine.Object, not UnityEngine.PrefabInstance). There are no possible references to these native
|
||||
// objects so skip them (we're checking for UnityEngine.Prefab because it includes other native types like UnityEngine.PrefabCreation, as well)
|
||||
if( target is GameObject && asset.GetType() == typeof( Object ) && asset.ToString().Contains( "(UnityEngine.Prefab" ) )
|
||||
continue;
|
||||
#endif
|
||||
|
||||
if( currentSubAssets.Add( asset ) )
|
||||
subAssets.Add( new SubAsset( asset, shouldSearchChildren ?? true ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 66d5a144a723fea40945afc069d4231d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
382
Assets/Plugins/AssetUsageDetector/Editor/SearchRefactoring.cs
Normal file
382
Assets/Plugins/AssetUsageDetector/Editor/SearchRefactoring.cs
Normal file
@ -0,0 +1,382 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace AssetUsageDetectorNamespace
|
||||
{
|
||||
public delegate void SearchRefactoring( SearchMatch match );
|
||||
|
||||
public abstract class SearchMatch
|
||||
{
|
||||
public readonly object Source;
|
||||
public readonly Object Context; // Almost always equal to Source. This is the Object that needs to be dirtied (if not null) to notify Unity of changes to Value
|
||||
public Object Value { get; private set; }
|
||||
|
||||
protected SearchMatch( object source, Object value )
|
||||
{
|
||||
Source = source;
|
||||
Context = source as Object;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
protected SearchMatch( object source, Object value, Object context ) : this( source, value )
|
||||
{
|
||||
Context = context;
|
||||
}
|
||||
|
||||
public void ChangeValue( Object newValue )
|
||||
{
|
||||
if( newValue == Value )
|
||||
return;
|
||||
|
||||
if( Context && ( Context.hideFlags & HideFlags.NotEditable ) == HideFlags.NotEditable )
|
||||
{
|
||||
Debug.LogWarning( "Can't change value of read-only Object: " + Context, Context );
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
bool setContextDirty;
|
||||
if( ChangeValue( newValue, out setContextDirty ) )
|
||||
OnValueChanged( newValue, setContextDirty );
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
Debug.LogException( e );
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract bool ChangeValue( Object newValue, out bool setContextDirty );
|
||||
|
||||
public void OnValueChanged( Object newValue, bool setContextDirty = true )
|
||||
{
|
||||
Value = newValue;
|
||||
|
||||
if( setContextDirty )
|
||||
{
|
||||
if( Context )
|
||||
{
|
||||
if( AssetDatabase.Contains( Context ) )
|
||||
EditorUtility.SetDirty( Context );
|
||||
else if( !EditorApplication.isPlaying )
|
||||
{
|
||||
EditorUtility.SetDirty( Context );
|
||||
|
||||
if( Context is Component )
|
||||
EditorSceneManager.MarkSceneDirty( ( (Component) Context ).gameObject.scene );
|
||||
else if( Context is GameObject )
|
||||
EditorSceneManager.MarkSceneDirty( ( (GameObject) Context ).scene );
|
||||
else
|
||||
EditorSceneManager.MarkAllScenesDirty();
|
||||
}
|
||||
}
|
||||
else if( !EditorApplication.isPlaying )
|
||||
EditorSceneManager.MarkAllScenesDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class GenericSearchMatch : SearchMatch
|
||||
{
|
||||
public delegate void SetterFunction( Object newValue );
|
||||
|
||||
public readonly SetterFunction Setter;
|
||||
|
||||
internal GenericSearchMatch( object source, Object value, SetterFunction setter ) : base( source, value ) { Setter = setter; }
|
||||
internal GenericSearchMatch( object source, Object value, Object context, SetterFunction setter ) : base( source, value, context ) { Setter = setter; }
|
||||
|
||||
protected override bool ChangeValue( Object newValue, out bool setContextDirty )
|
||||
{
|
||||
Setter( newValue );
|
||||
|
||||
setContextDirty = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class ReadOnlySearchMatch : SearchMatch
|
||||
{
|
||||
internal ReadOnlySearchMatch( object source, Object value ) : base( source, value ) { }
|
||||
|
||||
protected override bool ChangeValue( Object newValue, out bool setContextDirty )
|
||||
{
|
||||
Debug.LogWarning( "Can't change value of " + GetType().Name );
|
||||
|
||||
setContextDirty = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// - Source: Object whose SerializedProperty points to Value
|
||||
/// - Value: Referenced object
|
||||
/// - SerializedProperty: The SerializedProperty that points to Value
|
||||
/// </summary>
|
||||
public class SerializedPropertyMatch : SearchMatch
|
||||
{
|
||||
public readonly SerializedProperty SerializedProperty; // Next or NextVisible mustn't be called with this SerializedProperty
|
||||
|
||||
internal SerializedPropertyMatch( Object source, Object value, SerializedProperty property ) : base( source, value ) { SerializedProperty = property; }
|
||||
|
||||
protected override bool ChangeValue( Object newValue, out bool setContextDirty )
|
||||
{
|
||||
setContextDirty = true;
|
||||
|
||||
switch( SerializedProperty.propertyType )
|
||||
{
|
||||
case SerializedPropertyType.ObjectReference:
|
||||
SerializedProperty.objectReferenceValue = newValue;
|
||||
if( SerializedProperty.objectReferenceValue != newValue )
|
||||
{
|
||||
Debug.LogWarning( "Couldn't cast " + newValue.GetType() + " to " + SerializedProperty.type );
|
||||
SerializedProperty.objectReferenceValue = Value;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
case SerializedPropertyType.ExposedReference:
|
||||
SerializedProperty.exposedReferenceValue = newValue;
|
||||
if( SerializedProperty.exposedReferenceValue != newValue )
|
||||
{
|
||||
Debug.LogWarning( "Couldn't cast " + newValue.GetType() + " to " + SerializedProperty.type );
|
||||
SerializedProperty.exposedReferenceValue = Value;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
case SerializedPropertyType.ManagedReference: SerializedProperty.managedReferenceValue = newValue; break;
|
||||
#endif
|
||||
}
|
||||
|
||||
SerializedProperty.serializedObject.ApplyModifiedPropertiesWithoutUndo();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// - Source: Object whose variable points to Value
|
||||
/// - Value: Referenced object
|
||||
/// - Variable: FieldInfo, PropertyInfo or IEnumerable (ChangeValue may not work for all IEnumerables)
|
||||
/// </summary>
|
||||
public class ReflectionMatch : SearchMatch
|
||||
{
|
||||
public readonly object Variable;
|
||||
|
||||
internal ReflectionMatch( object source, Object value, object variable ) : base( source, value ) { Variable = variable; }
|
||||
|
||||
protected override bool ChangeValue( Object newValue, out bool setContextDirty )
|
||||
{
|
||||
setContextDirty = true;
|
||||
|
||||
if( Variable is FieldInfo )
|
||||
( (FieldInfo) Variable ).SetValue( Source, newValue );
|
||||
else if( Variable is PropertyInfo )
|
||||
{
|
||||
PropertyInfo property = (PropertyInfo) Variable;
|
||||
if( !property.CanWrite )
|
||||
{
|
||||
Debug.LogWarning( "Property is read-only: " + property.DeclaringType.FullName + "." + property.Name );
|
||||
return false;
|
||||
}
|
||||
|
||||
property.SetValue( Source, newValue, null );
|
||||
}
|
||||
else if( Variable is IList )
|
||||
{
|
||||
IList list = (IList) Variable;
|
||||
for( int i = list.Count - 1; i >= 0; i-- )
|
||||
{
|
||||
if( ReferenceEquals( list[i], Value ) )
|
||||
list[i] = newValue;
|
||||
}
|
||||
}
|
||||
else if( Variable is IDictionary )
|
||||
{
|
||||
IDictionary dictionary = (IDictionary) Variable;
|
||||
bool dictionaryModified;
|
||||
do
|
||||
{
|
||||
dictionaryModified = false;
|
||||
foreach( object dictKey in dictionary.Keys )
|
||||
{
|
||||
object dictValue = dictionary[dictKey];
|
||||
if( ReferenceEquals( dictKey, Value ) )
|
||||
{
|
||||
dictionary.Remove( dictKey );
|
||||
if( newValue )
|
||||
dictionary[newValue] = dictValue;
|
||||
|
||||
dictionaryModified = true;
|
||||
break;
|
||||
}
|
||||
else if( ReferenceEquals( dictValue, Value ) )
|
||||
{
|
||||
dictionary[dictKey] = newValue;
|
||||
dictionaryModified = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while( dictionaryModified );
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning( "Can't change value of " + Variable.GetType().Name );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// - Source: MonoImporter (for scripts) or ShaderImporter
|
||||
/// - Value: Default value assigned to Source's specified variable in the Inspector
|
||||
/// - Variable: The variable of Source that Value is assigned to as default value
|
||||
/// - MonoScriptAllVariables: All variables of Source script if it's MonoImporter
|
||||
/// </summary>
|
||||
public class AssetImporterDefaultValueMatch : SearchMatch
|
||||
{
|
||||
public readonly string Variable;
|
||||
public readonly VariableGetterHolder[] MonoScriptAllVariables;
|
||||
|
||||
internal AssetImporterDefaultValueMatch( Object source, Object value, string variable, VariableGetterHolder[] monoScriptAllVariables ) : base( source, value )
|
||||
{
|
||||
Variable = variable;
|
||||
MonoScriptAllVariables = monoScriptAllVariables;
|
||||
}
|
||||
|
||||
protected override bool ChangeValue( Object newValue, out bool setContextDirty )
|
||||
{
|
||||
setContextDirty = false;
|
||||
|
||||
if( Source is MonoImporter )
|
||||
{
|
||||
MonoImporter monoImporter = (MonoImporter) Source;
|
||||
|
||||
List<string> variableNames = new List<string>( 8 );
|
||||
List<Object> variableValues = new List<Object>( 8 );
|
||||
|
||||
for( int i = 0; i < MonoScriptAllVariables.Length; i++ )
|
||||
{
|
||||
if( MonoScriptAllVariables[i].isSerializable && !MonoScriptAllVariables[i].IsProperty )
|
||||
{
|
||||
Object variableDefaultValue = monoImporter.GetDefaultReference( MonoScriptAllVariables[i].Name );
|
||||
if( variableDefaultValue == Value && MonoScriptAllVariables[i].Name == Variable )
|
||||
variableDefaultValue = newValue;
|
||||
|
||||
variableNames.Add( MonoScriptAllVariables[i].Name );
|
||||
variableValues.Add( variableDefaultValue );
|
||||
}
|
||||
}
|
||||
|
||||
monoImporter.SetDefaultReferences( variableNames.ToArray(), variableValues.ToArray() );
|
||||
EditorApplication.delayCall += () => AssetDatabase.ImportAsset( monoImporter.assetPath ); // If code recompiles during search, it will break the search. Give it a 1 frame delay
|
||||
}
|
||||
else if( Source is ShaderImporter )
|
||||
{
|
||||
ShaderImporter shaderImporter = (ShaderImporter) Source;
|
||||
Shader shader = shaderImporter.GetShader();
|
||||
|
||||
List<string> textureNames = new List<string>( 16 );
|
||||
List<Texture> textureValues = new List<Texture>( 16 );
|
||||
#if UNITY_2018_1_OR_NEWER
|
||||
List<string> nonModifiableTextureNames = new List<string>( 16 );
|
||||
List<Texture> nonModifiableTextureValues = new List<Texture>( 16 );
|
||||
#endif
|
||||
|
||||
int shaderPropertyCount = ShaderUtil.GetPropertyCount( shader );
|
||||
for( int i = 0; i < shaderPropertyCount; i++ )
|
||||
{
|
||||
if( ShaderUtil.GetPropertyType( shader, i ) != ShaderUtil.ShaderPropertyType.TexEnv )
|
||||
continue;
|
||||
|
||||
string propertyName = ShaderUtil.GetPropertyName( shader, i );
|
||||
#if UNITY_2018_1_OR_NEWER
|
||||
if( ShaderUtil.IsShaderPropertyNonModifiableTexureProperty( shader, i ) )
|
||||
{
|
||||
Texture propertyDefaultValue = shaderImporter.GetNonModifiableTexture( propertyName );
|
||||
if( propertyDefaultValue == Value && propertyName == Variable )
|
||||
propertyDefaultValue = (Texture) newValue;
|
||||
|
||||
nonModifiableTextureNames.Add( propertyName );
|
||||
nonModifiableTextureValues.Add( propertyDefaultValue );
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
Texture propertyDefaultValue = shaderImporter.GetDefaultTexture( propertyName );
|
||||
if( propertyDefaultValue == Value && propertyName == Variable )
|
||||
propertyDefaultValue = (Texture) newValue;
|
||||
|
||||
textureNames.Add( propertyName );
|
||||
textureValues.Add( propertyDefaultValue );
|
||||
}
|
||||
}
|
||||
|
||||
shaderImporter.SetDefaultTextures( textureNames.ToArray(), textureValues.ToArray() );
|
||||
#if UNITY_2018_1_OR_NEWER
|
||||
shaderImporter.SetNonModifiableTextures( nonModifiableTextureNames.ToArray(), nonModifiableTextureValues.ToArray() );
|
||||
#endif
|
||||
AssetDatabase.ImportAsset( shaderImporter.assetPath );
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning( "Can't change default value of: " + Source.GetType() );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// - Source: Animation, Animator, AnimatorStateMachine, AnimatorState, AnimatorControllerLayer, BlendTree, PlayableDirector* or AnimationClip*
|
||||
/// - Context: If Source is AnimatorControllerLayer, then its RuntimeAnimatorController. Otherwise, equal to Source
|
||||
/// - Value: AnimationClip, AnimatorController or AvatarMask used in Source (*for PlayableDirector and AnimationClip, it can be any Object value)
|
||||
/// </summary>
|
||||
public class AnimationSystemMatch : GenericSearchMatch
|
||||
{
|
||||
internal AnimationSystemMatch( object source, Object value, SetterFunction setter ) : base( source, value, setter ) { }
|
||||
internal AnimationSystemMatch( object source, Object value, Object context, SetterFunction setter ) : base( source, value, context, setter ) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// - Source: GameObject, AnimatorStateMachine or AnimatorState
|
||||
/// - Value: The attached behaviour's source script (C# script or DLL, i.e. MonoScript)
|
||||
/// - Behaviour: The attached behaviour (MonoBehaviour or StateMachineBehaviour)
|
||||
/// </summary>
|
||||
public class BehaviourUsageMatch : ReadOnlySearchMatch
|
||||
{
|
||||
public readonly Object Behaviour;
|
||||
|
||||
internal BehaviourUsageMatch( Object source, MonoScript value, Object behaviour ) : base( source, value ) { Behaviour = behaviour; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// - Source: GameObject Instance
|
||||
/// - Value: Prefab of that GameObject
|
||||
/// </summary>
|
||||
public class PrefabMatch : ReadOnlySearchMatch
|
||||
{
|
||||
internal PrefabMatch( Object source, Object value ) : base( source, value ) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// - Source: Object that references Value
|
||||
/// - Value: Matched object
|
||||
/// </summary>
|
||||
public class OtherSearchMatch : GenericSearchMatch
|
||||
{
|
||||
internal OtherSearchMatch( object source, Object value, SetterFunction setter ) : base( source, value, setter ) { }
|
||||
internal OtherSearchMatch( object source, Object value, Object context, SetterFunction setter ) : base( source, value, context, setter ) { }
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3d15ef8bd8f7c7c4e8d228c99713b7eb
|
||||
timeCreated: 1641132238
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
1395
Assets/Plugins/AssetUsageDetector/Editor/SearchResult.cs
Normal file
1395
Assets/Plugins/AssetUsageDetector/Editor/SearchResult.cs
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ca236e4f3c5a9f447be89f0e61e485fa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,91 @@
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AssetUsageDetectorNamespace
|
||||
{
|
||||
public class SearchResultTooltip : EditorWindow
|
||||
{
|
||||
private static SearchResultTooltip mainWindow;
|
||||
private static string tooltip;
|
||||
|
||||
private static GUIStyle m_style;
|
||||
internal static GUIStyle Style
|
||||
{
|
||||
get
|
||||
{
|
||||
if( m_style == null )
|
||||
{
|
||||
m_style = (GUIStyle) typeof( EditorStyles ).GetProperty( "tooltip", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static ).GetValue( null, null );
|
||||
m_style.richText = true;
|
||||
}
|
||||
|
||||
return m_style;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Show( Rect sourcePosition, string tooltip )
|
||||
{
|
||||
Vector2 preferredSize = Style.CalcSize( new GUIContent( tooltip ) ) + Style.contentOffset + new Vector2( Style.padding.horizontal + Style.margin.horizontal, Style.padding.vertical + Style.margin.vertical );
|
||||
Rect preferredPosition;
|
||||
|
||||
Rect positionLeft = new Rect( sourcePosition.position - new Vector2( preferredSize.x, 0f ), preferredSize );
|
||||
Rect screenFittedPositionLeft = Utilities.GetScreenFittedRect( positionLeft );
|
||||
|
||||
Vector2 positionOffset = positionLeft.position - screenFittedPositionLeft.position;
|
||||
Vector2 sizeOffset = positionLeft.size - screenFittedPositionLeft.size;
|
||||
if( positionOffset.sqrMagnitude <= 400f && sizeOffset.sqrMagnitude <= 400f )
|
||||
preferredPosition = screenFittedPositionLeft;
|
||||
else
|
||||
{
|
||||
Rect positionRight = new Rect( sourcePosition.position + new Vector2( sourcePosition.width, 0f ), preferredSize );
|
||||
Rect screenFittedPositionRight = Utilities.GetScreenFittedRect( positionRight );
|
||||
|
||||
Vector2 positionOffset2 = positionRight.position - screenFittedPositionRight.position;
|
||||
Vector2 sizeOffset2 = positionRight.size - screenFittedPositionRight.size;
|
||||
if( positionOffset2.magnitude + sizeOffset2.magnitude < positionOffset.magnitude + sizeOffset.magnitude )
|
||||
preferredPosition = screenFittedPositionRight;
|
||||
else
|
||||
preferredPosition = screenFittedPositionLeft;
|
||||
}
|
||||
|
||||
// Don't lose focus to the previous window
|
||||
EditorWindow prevFocusedWindow = focusedWindow;
|
||||
|
||||
if( !mainWindow )
|
||||
{
|
||||
mainWindow = CreateInstance<SearchResultTooltip>();
|
||||
mainWindow.ShowPopup();
|
||||
}
|
||||
|
||||
SearchResultTooltip.tooltip = tooltip;
|
||||
mainWindow.minSize = preferredPosition.size;
|
||||
mainWindow.position = preferredPosition;
|
||||
mainWindow.Repaint();
|
||||
|
||||
if( prevFocusedWindow )
|
||||
prevFocusedWindow.Focus();
|
||||
}
|
||||
|
||||
public static void Hide()
|
||||
{
|
||||
if( mainWindow )
|
||||
{
|
||||
mainWindow.Close();
|
||||
mainWindow = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
// If somehow the tooltip isn't automatically closed, allow closing it by clicking on it
|
||||
if( Event.current.type == EventType.MouseDown )
|
||||
{
|
||||
Hide();
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
|
||||
GUI.Label( new Rect( Vector2.zero, position.size ), tooltip, Style );
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c8bd4351b5024324ca5974ebcad1dde3
|
||||
timeCreated: 1639247551
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
1353
Assets/Plugins/AssetUsageDetector/Editor/SearchResultTreeView.cs
Normal file
1353
Assets/Plugins/AssetUsageDetector/Editor/SearchResultTreeView.cs
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b3903f1d3149e9b4990e49206f8255c8
|
||||
timeCreated: 1638690728
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
565
Assets/Plugins/AssetUsageDetector/Editor/Utilities.cs
Normal file
565
Assets/Plugins/AssetUsageDetector/Editor/Utilities.cs
Normal file
@ -0,0 +1,565 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
#if UNITY_2018_1_OR_NEWER
|
||||
using Unity.Collections;
|
||||
#endif
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using Object = UnityEngine.Object;
|
||||
#if UNITY_2018_3_OR_NEWER && !UNITY_2021_2_OR_NEWER
|
||||
using PrefabStage = UnityEditor.Experimental.SceneManagement.PrefabStage;
|
||||
using PrefabStageUtility = UnityEditor.Experimental.SceneManagement.PrefabStageUtility;
|
||||
#endif
|
||||
|
||||
namespace AssetUsageDetectorNamespace
|
||||
{
|
||||
public static class Utilities
|
||||
{
|
||||
// A set of commonly used Unity types
|
||||
private static readonly HashSet<Type> primitiveUnityTypes = new HashSet<Type>()
|
||||
{
|
||||
typeof( string ), typeof( Vector4 ), typeof( Vector3 ), typeof( Vector2 ), typeof( Rect ),
|
||||
typeof( Quaternion ), typeof( Color ), typeof( Color32 ), typeof( LayerMask ), typeof( Bounds ),
|
||||
typeof( Matrix4x4 ), typeof( AnimationCurve ), typeof( Gradient ), typeof( RectOffset ),
|
||||
typeof( bool[] ), typeof( byte[] ), typeof( sbyte[] ), typeof( char[] ), typeof( decimal[] ),
|
||||
typeof( double[] ), typeof( float[] ), typeof( int[] ), typeof( uint[] ), typeof( long[] ),
|
||||
typeof( ulong[] ), typeof( short[] ), typeof( ushort[] ), typeof( string[] ),
|
||||
typeof( Vector4[] ), typeof( Vector3[] ), typeof( Vector2[] ), typeof( Rect[] ),
|
||||
typeof( Quaternion[] ), typeof( Color[] ), typeof( Color32[] ), typeof( LayerMask[] ), typeof( Bounds[] ),
|
||||
typeof( Matrix4x4[] ), typeof( AnimationCurve[] ), typeof( Gradient[] ), typeof( RectOffset[] ),
|
||||
typeof( List<bool> ), typeof( List<byte> ), typeof( List<sbyte> ), typeof( List<char> ), typeof( List<decimal> ),
|
||||
typeof( List<double> ), typeof( List<float> ), typeof( List<int> ), typeof( List<uint> ), typeof( List<long> ),
|
||||
typeof( List<ulong> ), typeof( List<short> ), typeof( List<ushort> ), typeof( List<string> ),
|
||||
typeof( List<Vector4> ), typeof( List<Vector3> ), typeof( List<Vector2> ), typeof( List<Rect> ),
|
||||
typeof( List<Quaternion> ), typeof( List<Color> ), typeof( List<Color32> ), typeof( List<LayerMask> ), typeof( List<Bounds> ),
|
||||
typeof( List<Matrix4x4> ), typeof( List<AnimationCurve> ), typeof( List<Gradient> ), typeof( List<RectOffset> ),
|
||||
#if UNITY_2017_2_OR_NEWER
|
||||
typeof( Vector3Int ), typeof( Vector2Int ), typeof( RectInt ), typeof( BoundsInt ),
|
||||
typeof( Vector3Int[] ), typeof( Vector2Int[] ), typeof( RectInt[] ), typeof( BoundsInt[] ),
|
||||
typeof( List<Vector3Int> ), typeof( List<Vector2Int> ), typeof( List<RectInt> ), typeof( List<BoundsInt> )
|
||||
#endif
|
||||
};
|
||||
|
||||
private static readonly string reflectionNamespace = typeof( Assembly ).Namespace;
|
||||
#if UNITY_2018_1_OR_NEWER
|
||||
private static readonly string nativeCollectionsNamespace = typeof( NativeArray<int> ).Namespace;
|
||||
#endif
|
||||
|
||||
private static MethodInfo screenFittedRectGetter;
|
||||
|
||||
private static readonly HashSet<string> folderContentsSet = new HashSet<string>();
|
||||
|
||||
internal static readonly StringBuilder stringBuilder = new StringBuilder( 400 );
|
||||
|
||||
public static readonly GUILayoutOption GL_EXPAND_WIDTH = GUILayout.ExpandWidth( true );
|
||||
public static readonly GUILayoutOption GL_EXPAND_HEIGHT = GUILayout.ExpandHeight( true );
|
||||
public static readonly GUILayoutOption GL_WIDTH_25 = GUILayout.Width( 25 );
|
||||
public static readonly GUILayoutOption GL_WIDTH_100 = GUILayout.Width( 100 );
|
||||
public static readonly GUILayoutOption GL_WIDTH_250 = GUILayout.Width( 250 );
|
||||
public static readonly GUILayoutOption GL_HEIGHT_0 = GUILayout.Height( 0 );
|
||||
public static readonly GUILayoutOption GL_HEIGHT_2 = GUILayout.Height( 2 );
|
||||
public static readonly GUILayoutOption GL_HEIGHT_30 = GUILayout.Height( 30 );
|
||||
public static readonly GUILayoutOption GL_HEIGHT_35 = GUILayout.Height( 35 );
|
||||
public static readonly GUILayoutOption GL_HEIGHT_40 = GUILayout.Height( 40 );
|
||||
|
||||
private static GUIStyle m_boxGUIStyle; // GUIStyle used to draw the results of the search
|
||||
public static GUIStyle BoxGUIStyle
|
||||
{
|
||||
get
|
||||
{
|
||||
if( m_boxGUIStyle == null )
|
||||
{
|
||||
m_boxGUIStyle = new GUIStyle( EditorStyles.helpBox )
|
||||
{
|
||||
alignment = TextAnchor.MiddleCenter,
|
||||
font = EditorStyles.label.font,
|
||||
richText = true
|
||||
};
|
||||
|
||||
Color textColor = GUI.skin.button.normal.textColor;
|
||||
m_boxGUIStyle.normal.textColor = textColor;
|
||||
m_boxGUIStyle.hover.textColor = textColor;
|
||||
m_boxGUIStyle.focused.textColor = textColor;
|
||||
m_boxGUIStyle.active.textColor = textColor;
|
||||
|
||||
#if !UNITY_2019_1_OR_NEWER || UNITY_2019_3_OR_NEWER
|
||||
// On 2019.1 and 2019.2 versions, GUI.skin.button.fontSize returns 0 on some devices
|
||||
// https://forum.unity.com/threads/asset-usage-detector-find-references-to-an-asset-object-open-source.408134/page-3#post-7285954
|
||||
m_boxGUIStyle.fontSize = ( m_boxGUIStyle.fontSize + GUI.skin.button.fontSize ) / 2;
|
||||
#endif
|
||||
}
|
||||
|
||||
return m_boxGUIStyle;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if object is an asset or a Scene object
|
||||
public static bool IsAsset( this object obj )
|
||||
{
|
||||
return obj is Object && AssetDatabase.Contains( (Object) obj );
|
||||
}
|
||||
|
||||
public static bool IsAsset( this Object obj )
|
||||
{
|
||||
return AssetDatabase.Contains( obj );
|
||||
}
|
||||
|
||||
// Check if object is a folder asset
|
||||
public static bool IsFolder( this Object obj )
|
||||
{
|
||||
return obj is DefaultAsset && AssetDatabase.IsValidFolder( AssetDatabase.GetAssetPath( obj ) );
|
||||
}
|
||||
|
||||
// Returns an enumerator to iterate through all asset paths in the folder
|
||||
public static IEnumerable<string> EnumerateFolderContents( Object folderAsset )
|
||||
{
|
||||
string[] folderContents = AssetDatabase.FindAssets( "", new string[] { AssetDatabase.GetAssetPath( folderAsset ) } );
|
||||
if( folderContents == null )
|
||||
return new EmptyEnumerator<string>();
|
||||
|
||||
folderContentsSet.Clear();
|
||||
for( int i = 0; i < folderContents.Length; i++ )
|
||||
{
|
||||
string filePath = AssetDatabase.GUIDToAssetPath( folderContents[i] );
|
||||
if( !string.IsNullOrEmpty( filePath ) && !AssetDatabase.IsValidFolder( filePath ) )
|
||||
folderContentsSet.Add( filePath );
|
||||
}
|
||||
|
||||
return folderContentsSet;
|
||||
}
|
||||
|
||||
public static void GetObjectsToSelectAndPing( this Object obj, out Object selection, out Object pingTarget )
|
||||
{
|
||||
if( obj == null || obj.Equals( null ) )
|
||||
{
|
||||
selection = pingTarget = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if( obj is Component )
|
||||
obj = ( (Component) obj ).gameObject;
|
||||
|
||||
selection = pingTarget = obj;
|
||||
|
||||
if( obj.IsAsset() )
|
||||
{
|
||||
if( obj is GameObject )
|
||||
{
|
||||
// Pinging a prefab only works if the pinged object is the root of the prefab or a direct child of it. Pinging any grandchildren
|
||||
// of the prefab doesn't work; in which case, traverse the parent hierarchy until a pingable parent is reached
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
Transform objTR = ( (GameObject) obj ).transform.root;
|
||||
|
||||
PrefabAssetType prefabAssetType = PrefabUtility.GetPrefabAssetType( objTR.gameObject );
|
||||
if( prefabAssetType == PrefabAssetType.Regular || prefabAssetType == PrefabAssetType.Variant )
|
||||
{
|
||||
string assetPath = AssetDatabase.GetAssetPath( objTR.gameObject );
|
||||
PrefabStage openPrefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
#if UNITY_2020_1_OR_NEWER
|
||||
if( openPrefabStage != null && openPrefabStage.stageHandle.IsValid() && assetPath == openPrefabStage.assetPath )
|
||||
#else
|
||||
if( openPrefabStage != null && openPrefabStage.stageHandle.IsValid() && assetPath == openPrefabStage.prefabAssetPath )
|
||||
#endif
|
||||
{
|
||||
GameObject prefabStageGO = FollowSymmetricHierarchy( (GameObject) obj, ( (GameObject) obj ).transform.root.gameObject, openPrefabStage.prefabContentsRoot );
|
||||
if( prefabStageGO != null )
|
||||
{
|
||||
objTR = prefabStageGO.transform;
|
||||
selection = objTR.gameObject;
|
||||
}
|
||||
}
|
||||
#if UNITY_2019_1_OR_NEWER
|
||||
else if( obj != objTR.gameObject )
|
||||
selection = objTR.gameObject;
|
||||
#endif
|
||||
}
|
||||
else if( prefabAssetType == PrefabAssetType.Model )
|
||||
{
|
||||
objTR = ( (GameObject) obj ).transform;
|
||||
while( objTR.parent != null && objTR.parent.parent != null )
|
||||
objTR = objTR.parent;
|
||||
}
|
||||
#else
|
||||
Transform objTR = ( (GameObject) obj ).transform;
|
||||
while( objTR.parent != null && objTR.parent.parent != null )
|
||||
objTR = objTR.parent;
|
||||
#endif
|
||||
|
||||
pingTarget = objTR.gameObject;
|
||||
}
|
||||
else if( ( obj.hideFlags & ( HideFlags.HideInInspector | HideFlags.HideInHierarchy ) ) != HideFlags.None )
|
||||
{
|
||||
// Can't ping assets that are hidden from Project window (e.g. animator states of AnimatorController), ping the main asset at that path instead
|
||||
pingTarget = AssetDatabase.LoadMainAssetAtPath( AssetDatabase.GetAssetPath( obj ) );
|
||||
}
|
||||
else if( !AssetDatabase.IsMainAsset( obj ) && Array.IndexOf( AssetDatabase.LoadAllAssetRepresentationsAtPath( AssetDatabase.GetAssetPath( obj ) ), obj ) < 0 )
|
||||
{
|
||||
// VFX Graph assets' nodes are serialized as part of the graph but they are invisible in the Project window even though their hideFlags is None (I don't know how)
|
||||
pingTarget = AssetDatabase.LoadMainAssetAtPath( AssetDatabase.GetAssetPath( obj ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We are passing "go"s root Transform to thisRoot parameter. If we use go.transform.root instead, when we are in prefab mode on
|
||||
// newer Unity versions, it points to the preview scene at the root of the prefab stage instead of pointing to the actual root of "go"
|
||||
public static GameObject FollowSymmetricHierarchy( this GameObject go, GameObject thisRoot, GameObject symmetricRoot )
|
||||
{
|
||||
Transform target = go.transform;
|
||||
Transform root1 = thisRoot.transform;
|
||||
Transform root2 = symmetricRoot.transform;
|
||||
while( root1 != target )
|
||||
{
|
||||
Transform temp = target;
|
||||
while( temp.parent != root1 )
|
||||
temp = temp.parent;
|
||||
|
||||
Transform newRoot2;
|
||||
int siblingIndex = temp.GetSiblingIndex();
|
||||
if( siblingIndex < root2.childCount )
|
||||
{
|
||||
newRoot2 = root2.GetChild( siblingIndex );
|
||||
if( newRoot2.name != temp.name )
|
||||
newRoot2 = root2.Find( temp.name );
|
||||
}
|
||||
else
|
||||
newRoot2 = root2.Find( temp.name );
|
||||
|
||||
if( newRoot2 == null )
|
||||
return null;
|
||||
|
||||
root2 = newRoot2;
|
||||
root1 = temp;
|
||||
}
|
||||
|
||||
return root2.gameObject;
|
||||
}
|
||||
|
||||
// Returns -1 if t1 is above t2 in Hierarchy, 1 if t1 is below t2 in Hierarchy and 0 if they are the same object
|
||||
public static int CompareHierarchySiblingIndices( Transform t1, Transform t2 )
|
||||
{
|
||||
Transform parent1 = t1.parent;
|
||||
Transform parent2 = t2.parent;
|
||||
|
||||
if( parent1 == parent2 )
|
||||
return t1.GetSiblingIndex() - t2.GetSiblingIndex();
|
||||
|
||||
int deltaHierarchyDepth = 0;
|
||||
for( ; parent1; parent1 = parent1.parent )
|
||||
deltaHierarchyDepth++;
|
||||
for( ; parent2; parent2 = parent2.parent )
|
||||
deltaHierarchyDepth--;
|
||||
|
||||
for( ; deltaHierarchyDepth > 0; deltaHierarchyDepth-- )
|
||||
{
|
||||
t1 = t1.parent;
|
||||
if( t1 == t2 )
|
||||
return 1;
|
||||
}
|
||||
for( ; deltaHierarchyDepth < 0; deltaHierarchyDepth++ )
|
||||
{
|
||||
t2 = t2.parent;
|
||||
if( t1 == t2 )
|
||||
return -1;
|
||||
}
|
||||
|
||||
while( t1.parent != t2.parent )
|
||||
{
|
||||
t1 = t1.parent;
|
||||
t2 = t2.parent;
|
||||
}
|
||||
|
||||
return t1.GetSiblingIndex() - t2.GetSiblingIndex();
|
||||
}
|
||||
|
||||
// Check if the field is serializable
|
||||
public static bool IsSerializable( this FieldInfo fieldInfo )
|
||||
{
|
||||
// See Serialization Rules: https://docs.unity3d.com/Manual/script-Serialization.html
|
||||
if( fieldInfo.IsInitOnly )
|
||||
return false;
|
||||
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
// SerializeReference makes even System.Object fields serializable
|
||||
if( Attribute.IsDefined( fieldInfo, typeof( SerializeReference ) ) )
|
||||
return true;
|
||||
#endif
|
||||
|
||||
if( ( !fieldInfo.IsPublic || fieldInfo.IsNotSerialized ) && !Attribute.IsDefined( fieldInfo, typeof( SerializeField ) ) )
|
||||
return false;
|
||||
|
||||
return IsTypeSerializable( fieldInfo.FieldType );
|
||||
}
|
||||
|
||||
// Check if the property is serializable
|
||||
public static bool IsSerializable( this PropertyInfo propertyInfo )
|
||||
{
|
||||
return IsTypeSerializable( propertyInfo.PropertyType );
|
||||
}
|
||||
|
||||
// Check if type is serializable
|
||||
private static bool IsTypeSerializable( Type type )
|
||||
{
|
||||
// see Serialization Rules: https://docs.unity3d.com/Manual/script-Serialization.html
|
||||
if( typeof( Object ).IsAssignableFrom( type ) )
|
||||
return true;
|
||||
|
||||
if( type.IsArray )
|
||||
{
|
||||
if( type.GetArrayRank() != 1 )
|
||||
return false;
|
||||
|
||||
type = type.GetElementType();
|
||||
|
||||
if( typeof( Object ).IsAssignableFrom( type ) )
|
||||
return true;
|
||||
}
|
||||
else if( type.IsGenericType )
|
||||
{
|
||||
// Generic types are allowed on 2020.1 and later
|
||||
#if UNITY_2020_1_OR_NEWER
|
||||
if( type.GetGenericTypeDefinition() == typeof( List<> ) )
|
||||
{
|
||||
type = type.GetGenericArguments()[0];
|
||||
|
||||
if( typeof( Object ).IsAssignableFrom( type ) )
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
if( type.GetGenericTypeDefinition() != typeof( List<> ) )
|
||||
return false;
|
||||
|
||||
type = type.GetGenericArguments()[0];
|
||||
|
||||
if( typeof( Object ).IsAssignableFrom( type ) )
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !UNITY_2020_1_OR_NEWER
|
||||
if( type.IsGenericType )
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return Attribute.IsDefined( type, typeof( SerializableAttribute ), false );
|
||||
}
|
||||
|
||||
// Check if instances of this type should be searched for references
|
||||
public static bool IsIgnoredUnityType( this Type type )
|
||||
{
|
||||
if( type.IsPrimitive || primitiveUnityTypes.Contains( type ) || type.IsEnum )
|
||||
return true;
|
||||
|
||||
#if UNITY_2018_1_OR_NEWER
|
||||
// Searching NativeArrays for reference can throw InvalidOperationException if the collection is disposed
|
||||
if( type.Namespace == nativeCollectionsNamespace )
|
||||
return true;
|
||||
#endif
|
||||
|
||||
// Searching assembly variables for reference throws InvalidCastException on .NET 4.0 runtime
|
||||
if( typeof( Type ).IsAssignableFrom( type ) || type.Namespace == reflectionNamespace )
|
||||
return true;
|
||||
|
||||
// Searching pointers or ref variables for reference throws ArgumentException
|
||||
if( type.IsPointer || type.IsByRef )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get <get> function for a field
|
||||
public static VariableGetVal CreateGetter( this FieldInfo fieldInfo, Type type )
|
||||
{
|
||||
// Commented the IL generator code below because it might actually be slower than simply using reflection
|
||||
// Credit: https://www.codeproject.com/Articles/14560/Fast-Dynamic-Property-Field-Accessors
|
||||
//DynamicMethod dm = new DynamicMethod( "Get" + fieldInfo.Name, fieldInfo.FieldType, new Type[] { typeof( object ) }, type );
|
||||
//ILGenerator il = dm.GetILGenerator();
|
||||
//// Load the instance of the object (argument 0) onto the stack
|
||||
//il.Emit( OpCodes.Ldarg_0 );
|
||||
//// Load the value of the object's field (fi) onto the stack
|
||||
//il.Emit( OpCodes.Ldfld, fieldInfo );
|
||||
//// return the value on the top of the stack
|
||||
//il.Emit( OpCodes.Ret );
|
||||
|
||||
//return (VariableGetVal) dm.CreateDelegate( typeof( VariableGetVal ) );
|
||||
|
||||
return fieldInfo.GetValue;
|
||||
}
|
||||
|
||||
// Get <get> function for a property
|
||||
public static VariableGetVal CreateGetter( this PropertyInfo propertyInfo )
|
||||
{
|
||||
// Can't use PropertyWrapper (which uses CreateDelegate) for property getters of structs
|
||||
if( propertyInfo.DeclaringType.IsValueType )
|
||||
{
|
||||
return !propertyInfo.CanRead ? (VariableGetVal) null : ( obj ) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return propertyInfo.GetValue( obj, null );
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Property getters may return various kinds of exceptions if their backing fields are not initialized (yet)
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Type GenType = typeof( PropertyWrapper<,> ).MakeGenericType( propertyInfo.DeclaringType, propertyInfo.PropertyType );
|
||||
return ( (IPropertyAccessor) Activator.CreateInstance( GenType, propertyInfo.GetGetMethod( true ) ) ).GetValue;
|
||||
}
|
||||
|
||||
// Check if all open scenes are saved (not dirty)
|
||||
public static bool AreScenesSaved()
|
||||
{
|
||||
for( int i = 0; i < SceneManager.sceneCount; i++ )
|
||||
{
|
||||
Scene scene = SceneManager.GetSceneAt( i );
|
||||
if( scene.isDirty || string.IsNullOrEmpty( scene.path ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns file extension in lowercase (period not included)
|
||||
public static string GetFileExtension( string path )
|
||||
{
|
||||
int extensionIndex = path.LastIndexOf( '.' );
|
||||
if( extensionIndex < 0 || extensionIndex >= path.Length - 1 )
|
||||
return "";
|
||||
|
||||
stringBuilder.Length = 0;
|
||||
for( extensionIndex++; extensionIndex < path.Length; extensionIndex++ )
|
||||
{
|
||||
char ch = path[extensionIndex];
|
||||
if( ch >= 65 && ch <= 90 ) // A-Z
|
||||
ch += (char) 32; // Converted to a-z
|
||||
|
||||
stringBuilder.Append( ch );
|
||||
}
|
||||
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
// Draw horizontal line inside OnGUI
|
||||
public static void DrawSeparatorLine()
|
||||
{
|
||||
GUILayout.Space( 4f );
|
||||
GUILayout.Box( "", GL_HEIGHT_2, GL_EXPAND_WIDTH );
|
||||
GUILayout.Space( 4f );
|
||||
}
|
||||
|
||||
// Restricts the given Rect within the screen's bounds
|
||||
public static Rect GetScreenFittedRect( Rect originalRect )
|
||||
{
|
||||
if( screenFittedRectGetter == null )
|
||||
screenFittedRectGetter = typeof( EditorWindow ).Assembly.GetType( "UnityEditor.ContainerWindow" ).GetMethod( "FitRectToScreen", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static );
|
||||
|
||||
return (Rect) screenFittedRectGetter.Invoke( null, new object[3] { originalRect, true, true } );
|
||||
}
|
||||
|
||||
// Check if all the objects inside the list are null
|
||||
public static bool IsEmpty( this List<ObjectToSearch> objectsToSearch )
|
||||
{
|
||||
if( objectsToSearch == null )
|
||||
return true;
|
||||
|
||||
for( int i = 0; i < objectsToSearch.Count; i++ )
|
||||
{
|
||||
if( objectsToSearch[i].obj != null && !objectsToSearch[i].obj.Equals( null ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if all the objects inside the list are null
|
||||
public static bool IsEmpty( this List<Object> objects )
|
||||
{
|
||||
if( objects == null )
|
||||
return true;
|
||||
|
||||
for( int i = 0; i < objects.Count; i++ )
|
||||
{
|
||||
if( objects[i] != null && !objects[i].Equals( null ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if all the objects that are enumerated are null
|
||||
public static bool IsEmpty( this IEnumerable<Object> objects )
|
||||
{
|
||||
if( objects == null )
|
||||
return true;
|
||||
|
||||
using( IEnumerator<Object> enumerator = objects.GetEnumerator() )
|
||||
{
|
||||
while( enumerator.MoveNext() )
|
||||
{
|
||||
if( enumerator.Current != null && !enumerator.Current.Equals( null ) )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns true is str starts with prefix
|
||||
public static bool StartsWithFast( this string str, string prefix )
|
||||
{
|
||||
int aLen = str.Length;
|
||||
int bLen = prefix.Length;
|
||||
int ap = 0; int bp = 0;
|
||||
while( ap < aLen && bp < bLen && str[ap] == prefix[bp] )
|
||||
{
|
||||
ap++;
|
||||
bp++;
|
||||
}
|
||||
|
||||
return bp == bLen;
|
||||
}
|
||||
|
||||
// Returns true is str ends with postfix
|
||||
public static bool EndsWithFast( this string str, string postfix )
|
||||
{
|
||||
int ap = str.Length - 1;
|
||||
int bp = postfix.Length - 1;
|
||||
while( ap >= 0 && bp >= 0 && str[ap] == postfix[bp] )
|
||||
{
|
||||
ap--;
|
||||
bp--;
|
||||
}
|
||||
|
||||
return bp < 0;
|
||||
}
|
||||
|
||||
public static bool ContainsFast<T>( this List<T> list, T element )
|
||||
{
|
||||
if( !( element is ValueType ) )
|
||||
{
|
||||
for( int i = list.Count - 1; i >= 0; i-- )
|
||||
{
|
||||
if( ReferenceEquals( list[i], element ) )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( int i = list.Count - 1; i >= 0; i-- )
|
||||
{
|
||||
if( element.Equals( list[i] ) )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Plugins/AssetUsageDetector/Editor/Utilities.cs.meta
Normal file
11
Assets/Plugins/AssetUsageDetector/Editor/Utilities.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 52b272b7591fb90499916205261524e0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
83
Assets/Plugins/AssetUsageDetector/Editor/VariableGetter.cs
Normal file
83
Assets/Plugins/AssetUsageDetector/Editor/VariableGetter.cs
Normal file
@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AssetUsageDetectorNamespace
|
||||
{
|
||||
// Delegate to get the value of a variable (either field or property)
|
||||
public delegate object VariableGetVal( object obj );
|
||||
|
||||
// Custom struct to hold a variable, its important properties and its getter function
|
||||
public struct VariableGetterHolder
|
||||
{
|
||||
public readonly MemberInfo variable;
|
||||
public readonly bool isSerializable;
|
||||
private readonly VariableGetVal getter;
|
||||
|
||||
public string Name { get { return variable.Name; } }
|
||||
public bool IsProperty { get { return variable is PropertyInfo; } }
|
||||
|
||||
public VariableGetterHolder( FieldInfo fieldInfo, VariableGetVal getter, bool isSerializable )
|
||||
{
|
||||
this.variable = fieldInfo;
|
||||
this.isSerializable = isSerializable;
|
||||
this.getter = getter;
|
||||
}
|
||||
|
||||
public VariableGetterHolder( PropertyInfo propertyInfo, VariableGetVal getter, bool isSerializable )
|
||||
{
|
||||
this.variable = propertyInfo;
|
||||
this.isSerializable = isSerializable;
|
||||
this.getter = getter;
|
||||
}
|
||||
|
||||
public object Get( object obj )
|
||||
{
|
||||
try
|
||||
{
|
||||
return getter( obj );
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
StringBuilder sb = Utilities.stringBuilder;
|
||||
sb.Length = 0;
|
||||
sb.Append( "Error while getting the value of (" ).Append( IsProperty ? ( (PropertyInfo) variable ).PropertyType : ( (FieldInfo) variable ).FieldType ).Append( ") " )
|
||||
.Append( variable.DeclaringType ).Append( "." ).Append( Name ).Append( ": " ).Append( e );
|
||||
|
||||
Debug.LogError( sb.ToString() );
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Credit: http://stackoverflow.com/questions/724143/how-do-i-create-a-delegate-for-a-net-property
|
||||
public interface IPropertyAccessor
|
||||
{
|
||||
object GetValue( object source );
|
||||
}
|
||||
|
||||
// A wrapper class for properties to get their values more efficiently
|
||||
public class PropertyWrapper<TObject, TValue> : IPropertyAccessor where TObject : class
|
||||
{
|
||||
private readonly Func<TObject, TValue> getter;
|
||||
|
||||
public PropertyWrapper( MethodInfo getterMethod )
|
||||
{
|
||||
getter = (Func<TObject, TValue>) Delegate.CreateDelegate( typeof( Func<TObject, TValue> ), getterMethod );
|
||||
}
|
||||
|
||||
public object GetValue( object obj )
|
||||
{
|
||||
try
|
||||
{
|
||||
return getter( (TObject) obj );
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Property getters may return various kinds of exceptions if their backing fields are not initialized (yet)
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9e94c83e8b850514ca0217aeff1491a6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
4
Assets/Plugins/AssetUsageDetector/README.txt
Normal file
4
Assets/Plugins/AssetUsageDetector/README.txt
Normal file
@ -0,0 +1,4 @@
|
||||
= Asset Usage Detector (v2.5.3) =
|
||||
|
||||
Documentation: https://github.com/yasirkula/UnityAssetUsageDetector
|
||||
E-mail: yasirkula@gmail.com
|
8
Assets/Plugins/AssetUsageDetector/README.txt.meta
Normal file
8
Assets/Plugins/AssetUsageDetector/README.txt.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ac528f1751f33a647a45caeff6a9344b
|
||||
timeCreated: 1520032521
|
||||
licenseType: Store
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -7749,7 +7749,7 @@ GameObject:
|
||||
- component: {fileID: 109379979}
|
||||
- component: {fileID: 109379978}
|
||||
m_Layer: 5
|
||||
m_Name: Button (1)
|
||||
m_Name: EnglishButton
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
@ -7770,11 +7770,11 @@ RectTransform:
|
||||
- {fileID: 2033966157}
|
||||
m_Father: {fileID: 2079626611}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0}
|
||||
m_AnchorMax: {x: 0.5, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 20.2}
|
||||
m_SizeDelta: {x: 295.7585, y: 55.4547}
|
||||
m_Pivot: {x: 0.5, y: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: -90}
|
||||
m_SizeDelta: {x: 295.7585, y: 55.454712}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &109379978
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -7831,7 +7831,7 @@ MonoBehaviour:
|
||||
m_StringArgument:
|
||||
m_BoolArgument: 0
|
||||
m_CallState: 2
|
||||
- m_Target: {fileID: 1568526660}
|
||||
- m_Target: {fileID: 2079626610}
|
||||
m_TargetAssemblyTypeName: UnityEngine.GameObject, UnityEngine
|
||||
m_MethodName: SetActive
|
||||
m_Mode: 6
|
||||
@ -7843,6 +7843,18 @@ MonoBehaviour:
|
||||
m_StringArgument:
|
||||
m_BoolArgument: 0
|
||||
m_CallState: 2
|
||||
- m_Target: {fileID: 401603026}
|
||||
m_TargetAssemblyTypeName: LanguageManager, Assembly-CSharp
|
||||
m_MethodName: SetLanguage
|
||||
m_Mode: 5
|
||||
m_Arguments:
|
||||
m_ObjectArgument: {fileID: 0}
|
||||
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
|
||||
m_IntArgument: 0
|
||||
m_FloatArgument: 0
|
||||
m_StringArgument: English
|
||||
m_BoolArgument: 0
|
||||
m_CallState: 2
|
||||
--- !u!114 &109379979
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -17402,7 +17414,7 @@ GameObject:
|
||||
- component: {fileID: 236729269}
|
||||
- component: {fileID: 236729268}
|
||||
m_Layer: 5
|
||||
m_Name: Button
|
||||
m_Name: ArabicButton
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
@ -17423,11 +17435,11 @@ RectTransform:
|
||||
- {fileID: 1029186221}
|
||||
m_Father: {fileID: 2079626611}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0}
|
||||
m_AnchorMax: {x: 0.5, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 107.4}
|
||||
m_SizeDelta: {x: 295.7585, y: 55.4547}
|
||||
m_Pivot: {x: 0.5, y: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 295.7585, y: 55.454712}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &236729268
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -17474,7 +17486,31 @@ MonoBehaviour:
|
||||
m_Calls:
|
||||
- m_Target: {fileID: 401603026}
|
||||
m_TargetAssemblyTypeName: LanguageManager, Assembly-CSharp
|
||||
m_MethodName: ToggleLanguage
|
||||
m_MethodName: SetLanguage
|
||||
m_Mode: 5
|
||||
m_Arguments:
|
||||
m_ObjectArgument: {fileID: 0}
|
||||
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
|
||||
m_IntArgument: 0
|
||||
m_FloatArgument: 0
|
||||
m_StringArgument: Arabic
|
||||
m_BoolArgument: 0
|
||||
m_CallState: 2
|
||||
- m_Target: {fileID: 2079626610}
|
||||
m_TargetAssemblyTypeName: UnityEngine.GameObject, UnityEngine
|
||||
m_MethodName: SetActive
|
||||
m_Mode: 6
|
||||
m_Arguments:
|
||||
m_ObjectArgument: {fileID: 0}
|
||||
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
|
||||
m_IntArgument: 0
|
||||
m_FloatArgument: 0
|
||||
m_StringArgument:
|
||||
m_BoolArgument: 0
|
||||
m_CallState: 2
|
||||
- m_Target: {fileID: 1809986913}
|
||||
m_TargetAssemblyTypeName: CharacterMovement, Assembly-CSharp
|
||||
m_MethodName: AnimationStarter
|
||||
m_Mode: 1
|
||||
m_Arguments:
|
||||
m_ObjectArgument: {fileID: 0}
|
||||
@ -28154,7 +28190,7 @@ Transform:
|
||||
m_GameObject: {fileID: 390376883}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0.000000030434517, y: 0.7071067, z: -0.00000003795118, w: 0.7071068}
|
||||
m_LocalPosition: {x: -1.5892, y: 1.4498, z: -0.0239}
|
||||
m_LocalPosition: {x: -1.719, y: 1.4498, z: -0.024}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
@ -29326,6 +29362,7 @@ MonoBehaviour:
|
||||
fontEnglish: {fileID: 11400000, guid: 9f7cb4b53799717478f208258f1af701, type: 2}
|
||||
fontArabic: {fileID: 11400000, guid: 5d7d7d6271e9ff04b99c8a2c50c4f464, type: 2}
|
||||
languageLabel: {fileID: 694310787}
|
||||
languageSetBool: 0
|
||||
--- !u!4 &401603027
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -50588,7 +50625,7 @@ GameObject:
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
m_IsActive: 0
|
||||
--- !u!224 &694310786
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -52215,7 +52252,7 @@ GameObject:
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &718829149
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -64478,6 +64515,140 @@ Transform:
|
||||
m_CorrespondingSourceObject: {fileID: 4837329652793204, guid: 88498815dea432045b6eaa9875ec268a, type: 3}
|
||||
m_PrefabInstance: {fileID: 1225554677}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
--- !u!1 &885259529
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 885259530}
|
||||
- component: {fileID: 885259532}
|
||||
- component: {fileID: 885259531}
|
||||
m_Layer: 5
|
||||
m_Name: Promo
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &885259530
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 885259529}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1568526664}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 1, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 170.5492, y: 50}
|
||||
m_Pivot: {x: 1, y: 0}
|
||||
--- !u!114 &885259531
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 885259529}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text: Powered by CyberCompanion
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 9f7cb4b53799717478f208258f1af701, type: 2}
|
||||
m_sharedMaterial: {fileID: -7900421164380424285, guid: 9f7cb4b53799717478f208258f1af701, type: 2}
|
||||
m_fontSharedMaterials: []
|
||||
m_fontMaterial: {fileID: 0}
|
||||
m_fontMaterials: []
|
||||
m_fontColor32:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_enableVertexGradient: 0
|
||||
m_colorMode: 3
|
||||
m_fontColorGradient:
|
||||
topLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
topRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_fontColorGradientPreset: {fileID: 0}
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: -1183493901
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 21.3
|
||||
m_fontSizeBase: 36
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 1
|
||||
m_fontSizeMin: 18
|
||||
m_fontSizeMax: 72
|
||||
m_fontStyle: 0
|
||||
m_HorizontalAlignment: 1
|
||||
m_VerticalAlignment: 256
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_wordSpacing: 0
|
||||
m_lineSpacing: 0
|
||||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_enableWordWrapping: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 1
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 1
|
||||
m_isCullingEnabled: 0
|
||||
m_horizontalMapping: 0
|
||||
m_verticalMapping: 0
|
||||
m_uvLineOffset: 0
|
||||
m_geometrySortingOrder: 0
|
||||
m_IsTextObjectScaleStatic: 0
|
||||
m_VertexBufferAutoSizeReduction: 0
|
||||
m_useMaxVisibleDescender: 1
|
||||
m_pageToDisplay: 1
|
||||
m_margin: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_isUsingLegacyAnimationComponent: 0
|
||||
m_isVolumetricText: 0
|
||||
m_hasFontAssetChanged: 0
|
||||
m_baseMaterial: {fileID: 0}
|
||||
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
|
||||
--- !u!222 &885259532
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 885259529}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!4 &885475623 stripped
|
||||
Transform:
|
||||
m_CorrespondingSourceObject: {fileID: 4156121308509644, guid: 911d4c5eaa0b3b84b83995d2433ebf94, type: 3}
|
||||
@ -65126,7 +65297,7 @@ GameObject:
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &893706589
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -75428,6 +75599,7 @@ GameObject:
|
||||
- component: {fileID: 1029186221}
|
||||
- component: {fileID: 1029186223}
|
||||
- component: {fileID: 1029186222}
|
||||
- component: {fileID: 1029186224}
|
||||
m_Layer: 5
|
||||
m_Name: Text (TMP)
|
||||
m_TagString: Untagged
|
||||
@ -75474,10 +75646,10 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text: Switch
|
||||
m_text: "\u201C\u0627\u0644\u0639\u0631\u0628\u064A\u0629\u201D"
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 8fb9d20fb5f90a34c9e3810c210f5f8c, type: 2}
|
||||
m_sharedMaterial: {fileID: -5830505048132788728, guid: 8fb9d20fb5f90a34c9e3810c210f5f8c, type: 2}
|
||||
m_fontAsset: {fileID: 11400000, guid: 5d7d7d6271e9ff04b99c8a2c50c4f464, type: 2}
|
||||
m_sharedMaterial: {fileID: -4076715752635496019, guid: 5d7d7d6271e9ff04b99c8a2c50c4f464, type: 2}
|
||||
m_fontSharedMaterials: []
|
||||
m_fontMaterial: {fileID: 0}
|
||||
m_fontMaterials: []
|
||||
@ -75501,7 +75673,7 @@ MonoBehaviour:
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 47.3
|
||||
m_fontSize: 55.45
|
||||
m_fontSizeBase: 24
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 1
|
||||
@ -75551,6 +75723,21 @@ CanvasRenderer:
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1029186220}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &1029186224
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1029186220}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: cc004b44880e9b0438fdcabff26b08d8, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
rawArabicInput: "\u0627\u0644\u0639\u0631\u0628\u064A\u0629"
|
||||
showTashkeel: 1
|
||||
useHinduNumbers: 1
|
||||
--- !u!4 &1029194909 stripped
|
||||
Transform:
|
||||
m_CorrespondingSourceObject: {fileID: 4194271709752040, guid: acb8028c6738c8642b20c2f467061501, type: 3}
|
||||
@ -83843,6 +84030,8 @@ GameObject:
|
||||
- component: {fileID: 1165035729}
|
||||
- component: {fileID: 1165035728}
|
||||
- component: {fileID: 1165035727}
|
||||
- component: {fileID: 1165035730}
|
||||
- component: {fileID: 1165035731}
|
||||
m_Layer: 0
|
||||
m_Name: NewEmail
|
||||
m_TagString: Untagged
|
||||
@ -83962,7 +84151,7 @@ MonoBehaviour:
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Material: {fileID: 1614071849}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
@ -83988,6 +84177,38 @@ CanvasRenderer:
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1165035725}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &1165035730
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1165035725}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: ee158225ee1e59f4791627785501d950, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
shaderTypes: 0
|
||||
normalStrength: 5
|
||||
normalSmoothing: 1
|
||||
computingNormal: 0
|
||||
--- !u!114 &1165035731
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1165035725}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: dfeee82aa0b6bf24381f7c432ba35115, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
targetMaterial: {fileID: 1614071849}
|
||||
minZoom: 0.95
|
||||
maxZoom: 1.25
|
||||
speed: 3
|
||||
--- !u!1001 &1165265475
|
||||
PrefabInstance:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -92879,7 +93100,7 @@ GameObject:
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
m_IsActive: 0
|
||||
--- !u!224 &1289299255
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -95149,15 +95370,14 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text: "\U0001F4CC Typos & Spelling Errors\nThe email had spelling mistakes or
|
||||
odd grammar \u2014 a common phishing sign.\n\n\U0001F4CC Urgency & Pressure\nIt
|
||||
used urgent language to pressure you into acting quickly.\n\n\U0001F4CC Link
|
||||
Inspection\nThe link preview didn\u2019t match the real website \u2014 inspect
|
||||
links before clicking.\n\n\U0001F4CC Unfamiliar or Unexpected Content\nThe email
|
||||
seemed unrelated to your work \u2014 phishing often comes out of nowhere.\n\n\U0001F4CC
|
||||
Generic Greetings\nIt used a generic greeting like Dear user instead of your
|
||||
name.\n\n\U0001F4CC Unusual Requests\nIt asked for sensitive info like passwords
|
||||
\u2014 companies don\u2019t do this by email."
|
||||
m_text: "Typos & Spelling Errors\nThe email had spelling mistakes or odd grammar
|
||||
\u2014 a common phishing sign.\n\nUrgency & Pressure\nIt used urgent language
|
||||
to pressure you into acting quickly.\n\nLink Inspection\nThe link preview didn\u2019t
|
||||
match the real website \u2014 inspect links before clicking.\n\nUnfamiliar or
|
||||
Unexpected Content\nThe email seemed unrelated to your work \u2014 phishing often
|
||||
comes out of nowhere.\n\nGeneric Greetings\nIt used a generic greeting like Dear
|
||||
user instead of your name.\n\nUnusual Requests\nIt asked for sensitive info like
|
||||
passwords \u2014 companies don\u2019t do this by email."
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 1b7bc6f8d1e1a594ea77f76cabc9a9be, type: 2}
|
||||
m_sharedMaterial: {fileID: 4094059608530178792, guid: 1b7bc6f8d1e1a594ea77f76cabc9a9be, type: 2}
|
||||
@ -111921,7 +112141,7 @@ GameObject:
|
||||
- component: {fileID: 1568526662}
|
||||
- component: {fileID: 1568526661}
|
||||
m_Layer: 5
|
||||
m_Name: Canvas
|
||||
m_Name: ScreenCanvas
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
@ -112003,6 +112223,7 @@ RectTransform:
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 2079626611}
|
||||
- {fileID: 885259530}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
@ -115433,6 +115654,242 @@ PrefabInstance:
|
||||
m_AddedGameObjects: []
|
||||
m_AddedComponents: []
|
||||
m_SourcePrefab: {fileID: 100100000, guid: fdfb9caedb76de945869ccf8157e4122, type: 3}
|
||||
--- !u!21 &1614071849
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: AllIn1SpriteShader/AllIn1SpriteShader
|
||||
m_Shader: {fileID: 4800000, guid: a36b7719ff0465b42ab1407d67672c5f, type: 3}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords:
|
||||
- ZOOMUV_ON
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: 3000
|
||||
stringTagMap: {}
|
||||
disabledShaderPasses: []
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _ColorRampTex:
|
||||
m_Texture: {fileID: 2800000, guid: 279657edc397ece4b8029c727adf6ddc, type: 3}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _ColorRampTexGradient:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _ColorSwapTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DistortTex:
|
||||
m_Texture: {fileID: 2800000, guid: 7aad8c583ef292e48b06af0d1f2fab97, type: 3}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _FadeBurnTex:
|
||||
m_Texture: {fileID: 2800000, guid: 677cca399782dea41aedc1d292ecb67d, type: 3}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _FadeTex:
|
||||
m_Texture: {fileID: 2800000, guid: 7aad8c583ef292e48b06af0d1f2fab97, type: 3}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _GlowTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _OutlineDistortTex:
|
||||
m_Texture: {fileID: 2800000, guid: 7aad8c583ef292e48b06af0d1f2fab97, type: 3}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _OutlineTex:
|
||||
m_Texture: {fileID: 2800000, guid: 74087f6d03f233e4a8a142fa01f9e5cf, type: 3}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _OverlayTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _ShineMask:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _Alpha: 1
|
||||
- _AlphaCutoffValue: 0.25
|
||||
- _AlphaOutlineBlend: 1
|
||||
- _AlphaOutlineGlow: 5
|
||||
- _AlphaOutlineMinAlpha: 0
|
||||
- _AlphaOutlinePower: 1
|
||||
- _AlphaRoundThreshold: 0.5
|
||||
- _BillboardY: 0
|
||||
- _BlurHD: 0
|
||||
- _BlurIntensity: 10
|
||||
- _Brightness: 0
|
||||
- _ChromAberrAlpha: 0.4
|
||||
- _ChromAberrAmount: 1
|
||||
- _ClipUvDown: 0
|
||||
- _ClipUvLeft: 0
|
||||
- _ClipUvRight: 0
|
||||
- _ClipUvUp: 0
|
||||
- _ColorChangeLuminosity: 0
|
||||
- _ColorChangeTolerance: 0.25
|
||||
- _ColorChangeTolerance2: 0.25
|
||||
- _ColorChangeTolerance3: 0.25
|
||||
- _ColorRampBlend: 1
|
||||
- _ColorRampLuminosity: 0
|
||||
- _ColorRampOutline: 0
|
||||
- _ColorSwapBlend: 1
|
||||
- _ColorSwapBlueLuminosity: 0.5
|
||||
- _ColorSwapGreenLuminosity: 0.5
|
||||
- _ColorSwapRedLuminosity: 0.5
|
||||
- _Contrast: 1
|
||||
- _CullingOption: 0
|
||||
- _DistortAmount: 0.5
|
||||
- _DistortTexXSpeed: 5
|
||||
- _DistortTexYSpeed: 5
|
||||
- _EditorDrawers: 6
|
||||
- _FadeAmount: -0.1
|
||||
- _FadeBurnGlow: 2
|
||||
- _FadeBurnTransition: 0.075
|
||||
- _FadeBurnWidth: 0.025
|
||||
- _FishEyeUvAmount: 0.35
|
||||
- _FlickerAlpha: 0
|
||||
- _FlickerFreq: 0.2
|
||||
- _FlickerPercent: 0.05
|
||||
- _GhostBlend: 1
|
||||
- _GhostColorBoost: 1
|
||||
- _GhostTransparency: 0
|
||||
- _GlitchAmount: 3
|
||||
- _GlitchSize: 1
|
||||
- _Glow: 10
|
||||
- _GlowGlobal: 1
|
||||
- _GradBlend: 1
|
||||
- _GradBoostX: 1.2
|
||||
- _GradBoostY: 1.2
|
||||
- _GradIsRadial: 0
|
||||
- _GrassManualAnim: 1
|
||||
- _GrassManualToggle: 0
|
||||
- _GrassRadialBend: 0.1
|
||||
- _GrassSpeed: 2
|
||||
- _GrassWind: 20
|
||||
- _GreyscaleBlend: 1
|
||||
- _GreyscaleLuminosity: 0
|
||||
- _GreyscaleOutline: 0
|
||||
- _HandDrawnAmount: 10
|
||||
- _HandDrawnSpeed: 5
|
||||
- _HitEffectBlend: 1
|
||||
- _HitEffectGlow: 5
|
||||
- _HologramBlend: 1
|
||||
- _HologramMaxAlpha: 0.75
|
||||
- _HologramMinAlpha: 0.1
|
||||
- _HologramStripesAmount: 0.1
|
||||
- _HologramStripesSpeed: 4.5
|
||||
- _HologramUnmodAmount: 0
|
||||
- _HsvBright: 1
|
||||
- _HsvSaturation: 1
|
||||
- _HsvShift: 180
|
||||
- _InnerOutlineAlpha: 1
|
||||
- _InnerOutlineGlow: 4
|
||||
- _InnerOutlineThickness: 1
|
||||
- _MaxXUV: 1
|
||||
- _MaxYUV: 1
|
||||
- _MinXUV: 0
|
||||
- _MinYUV: 0
|
||||
- _MotionBlurAngle: 0.1
|
||||
- _MotionBlurDist: 1.25
|
||||
- _MyDstMode: 10
|
||||
- _MySrcMode: 5
|
||||
- _NegativeAmount: 1
|
||||
- _OffsetUvX: 0
|
||||
- _OffsetUvY: 0
|
||||
- _OnlyInnerOutline: 0
|
||||
- _OnlyOutline: 0
|
||||
- _OutlineAlpha: 1
|
||||
- _OutlineDistortAmount: 0.5
|
||||
- _OutlineDistortTexXSpeed: 5
|
||||
- _OutlineDistortTexYSpeed: 5
|
||||
- _OutlineGlow: 1.5
|
||||
- _OutlinePixelWidth: 1
|
||||
- _OutlineTexXSpeed: 10
|
||||
- _OutlineTexYSpeed: 0
|
||||
- _OutlineWidth: 0.004
|
||||
- _OverlayBlend: 1
|
||||
- _OverlayGlow: 1
|
||||
- _PinchUvAmount: 0
|
||||
- _PixelateSize: 32
|
||||
- _PosterizeGamma: 0.75
|
||||
- _PosterizeNumColors: 8
|
||||
- _PosterizeOutline: 0
|
||||
- _RandomSeed: 0
|
||||
- _RectSize: 1
|
||||
- _RotateUvAmount: 0
|
||||
- _RoundWaveSpeed: 2
|
||||
- _RoundWaveStrength: 0.7
|
||||
- _ShadowAlpha: 0.5
|
||||
- _ShadowX: 0.1
|
||||
- _ShadowY: -0.05
|
||||
- _ShakeUvSpeed: 2.5
|
||||
- _ShakeUvX: 1.5
|
||||
- _ShakeUvY: 1
|
||||
- _ShineGlow: 1
|
||||
- _ShineLocation: 0.5
|
||||
- _ShineRotate: 0
|
||||
- _ShineWidth: 0.1
|
||||
- _TextureScrollXSpeed: 1
|
||||
- _TextureScrollYSpeed: 0
|
||||
- _TwistUvAmount: 1
|
||||
- _TwistUvPosX: 0.5
|
||||
- _TwistUvPosY: 0.5
|
||||
- _TwistUvRadius: 0.75
|
||||
- _WaveAmount: 7
|
||||
- _WaveSpeed: 10
|
||||
- _WaveStrength: 7.5
|
||||
- _WaveX: 0
|
||||
- _WaveY: 0.5
|
||||
- _ZTestMode: 4
|
||||
- _ZWrite: 0
|
||||
- _ZoomUvAmount: 1.22
|
||||
m_Colors:
|
||||
- _AlphaOutlineColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _ColorChangeNewCol: {r: 1, g: 1, b: 0, a: 1}
|
||||
- _ColorChangeNewCol2: {r: 1, g: 1, b: 0, a: 1}
|
||||
- _ColorChangeNewCol3: {r: 1, g: 1, b: 0, a: 1}
|
||||
- _ColorChangeTarget: {r: 1, g: 0, b: 0, a: 1}
|
||||
- _ColorChangeTarget2: {r: 1, g: 0, b: 0, a: 1}
|
||||
- _ColorChangeTarget3: {r: 1, g: 0, b: 0, a: 1}
|
||||
- _ColorSwapBlue: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _ColorSwapGreen: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _ColorSwapRed: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _FadeBurnColor: {r: 1, g: 1, b: 0, a: 1}
|
||||
- _GlowColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _GradBotLeftCol: {r: 0, g: 0, b: 1, a: 1}
|
||||
- _GradBotRightCol: {r: 0, g: 1, b: 0, a: 1}
|
||||
- _GradTopLeftCol: {r: 1, g: 0, b: 0, a: 1}
|
||||
- _GradTopRightCol: {r: 1, g: 1, b: 0, a: 1}
|
||||
- _GreyscaleTintColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _HitEffectColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _HologramStripeColor: {r: 0, g: 1, b: 1, a: 1}
|
||||
- _InnerOutlineColor: {r: 1, g: 0, b: 0, a: 1}
|
||||
- _OutlineColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _OverlayColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _ShadowColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
- _ShineColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_BuildTextureStacks: []
|
||||
--- !u!1001 &1614491339
|
||||
PrefabInstance:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -142747,9 +143204,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text: 'Start
|
||||
|
||||
'
|
||||
m_text: English
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 8fb9d20fb5f90a34c9e3810c210f5f8c, type: 2}
|
||||
m_sharedMaterial: {fileID: -5830505048132788728, guid: 8fb9d20fb5f90a34c9e3810c210f5f8c, type: 2}
|
||||
@ -146974,7 +147429,7 @@ GameObject:
|
||||
- component: {fileID: 2079626613}
|
||||
- component: {fileID: 2079626612}
|
||||
m_Layer: 5
|
||||
m_Name: BG
|
||||
m_Name: LanguageUI
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
@ -147001,7 +147456,7 @@ RectTransform:
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 447.2637, y: 447.2637}
|
||||
m_SizeDelta: {x: 350, y: 350}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &2079626612
|
||||
MonoBehaviour:
|
||||
@ -147016,14 +147471,14 @@ MonoBehaviour:
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_Color: {r: 0.16078432, g: 0.18823531, b: 0.23137257, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 21300000, guid: 8464d7c9cdc4af04c9ef3874898fff0f, type: 3}
|
||||
m_Sprite: {fileID: 0}
|
||||
m_Type: 0
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
|
35
Assets/Scripts/ArabicFixerHelper.cs
Normal file
35
Assets/Scripts/ArabicFixerHelper.cs
Normal file
@ -0,0 +1,35 @@
|
||||
using ArabicSupport;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
public static class ArabicFixerHelper
|
||||
{
|
||||
public static string FixPreservingTags(string rawText)
|
||||
{
|
||||
// Match <link=...>…</link> and preserve it
|
||||
var regex = new Regex(@"<link=.*?</link>", RegexOptions.IgnoreCase);
|
||||
var matches = regex.Matches(rawText);
|
||||
|
||||
string fixedText = rawText;
|
||||
|
||||
foreach (Match match in matches)
|
||||
{
|
||||
string tag = match.Value;
|
||||
string placeholder = $"[[LINK{match.Index}]]";
|
||||
|
||||
fixedText = fixedText.Replace(tag, placeholder);
|
||||
}
|
||||
|
||||
// Apply ArabicFixer to the full string with placeholders
|
||||
fixedText = ArabicFixer.Fix(fixedText);
|
||||
|
||||
// Replace placeholders back with original tags
|
||||
foreach (Match match in matches)
|
||||
{
|
||||
string tag = match.Value;
|
||||
string placeholder = ArabicFixer.Fix($"[[LINK{match.Index}]]");
|
||||
fixedText = fixedText.Replace(placeholder, tag);
|
||||
}
|
||||
|
||||
return fixedText;
|
||||
}
|
||||
}
|
11
Assets/Scripts/ArabicFixerHelper.cs.meta
Normal file
11
Assets/Scripts/ArabicFixerHelper.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e51b8a1eaffd39f42a4cf34953bf3b94
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,13 +1,15 @@
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections;
|
||||
public class EmailLoader : MonoBehaviour
|
||||
{
|
||||
public Transform contentParent;
|
||||
public GameObject emailItemPrefab;
|
||||
public EmailData[] emails;
|
||||
void Start()
|
||||
IEnumerator Start()
|
||||
{
|
||||
yield return new WaitUntil(() => LanguageManager.Instance != null && LanguageManager.Instance.languageSetBool == true);
|
||||
LoadEmails();
|
||||
}
|
||||
|
||||
|
@ -61,14 +61,26 @@ public class EmailOpenPanel : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
//void LocalizeTMP(TextMeshProUGUI tmp, string english, string arabic)
|
||||
//{
|
||||
// if (tmp == null) return;
|
||||
|
||||
// bool isArabic = LanguageManager.Instance != null && LanguageManager.Instance.currentLanguage == "Arabic";
|
||||
// tmp.text = isArabic ? ArabicFixer.Fix(arabic) : english;
|
||||
// tmp.font = LanguageManager.Instance?.GetCurrentFont();
|
||||
// //tmp.isRightToLeftText = isArabic;
|
||||
// //tmp.alignment = isArabic ? TextAlignmentOptions.Right : TextAlignmentOptions.Left;
|
||||
//}
|
||||
void LocalizeTMP(TextMeshProUGUI tmp, string english, string arabic)
|
||||
{
|
||||
if (tmp == null) return;
|
||||
|
||||
bool isArabic = LanguageManager.Instance != null && LanguageManager.Instance.currentLanguage == "Arabic";
|
||||
tmp.text = isArabic ? ArabicFixer.Fix(arabic) : english;
|
||||
tmp.font = LanguageManager.Instance?.GetCurrentFont();
|
||||
//tmp.isRightToLeftText = isArabic;
|
||||
bool isArabic = LanguageManager.Instance.currentLanguage == "Arabic";
|
||||
|
||||
tmp.text = isArabic ? ArabicFixerHelper.FixPreservingTags(arabic) : english;
|
||||
tmp.font = LanguageManager.Instance.GetCurrentFont();
|
||||
// tmp.isRightToLeftText = isArabic;
|
||||
//tmp.alignment = isArabic ? TextAlignmentOptions.Right : TextAlignmentOptions.Left;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ public class LanguageManager : MonoBehaviour
|
||||
public TMP_FontAsset fontEnglish;
|
||||
public TMP_FontAsset fontArabic;
|
||||
public TextMeshProUGUI languageLabel;
|
||||
public bool languageSetBool = false;
|
||||
public TMP_FontAsset GetCurrentFont()
|
||||
{
|
||||
return currentLanguage == "Arabic" ? fontArabic : fontEnglish;
|
||||
@ -72,6 +73,20 @@ public class LanguageManager : MonoBehaviour
|
||||
{
|
||||
return languageDB.GetText(key, currentLanguage);
|
||||
}
|
||||
public void SetLanguage(string language)
|
||||
{
|
||||
languageSetBool = true;
|
||||
if (language == currentLanguage) return;
|
||||
|
||||
if (language == "English" || language == "Arabic")
|
||||
{
|
||||
currentLanguage = language;
|
||||
PlayerPrefs.SetString("AppLang", currentLanguage);
|
||||
UpdateLanguageLabel();
|
||||
UpdateAllTexts();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void UpdateAllTexts()
|
||||
{
|
||||
|
@ -1,7 +1,7 @@
|
||||
using UnityEngine;
|
||||
using TMPro;
|
||||
using ArabicSupport;
|
||||
|
||||
using System.Linq;
|
||||
[RequireComponent(typeof(TextMeshProUGUI))]
|
||||
public class LocalizedTextComponent : MonoBehaviour
|
||||
{
|
||||
@ -29,6 +29,23 @@ public class LocalizedTextComponent : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
//public void UpdateText()
|
||||
//{
|
||||
// if (LanguageManager.Instance == null)
|
||||
// {
|
||||
// Debug.LogWarning($"LanguageManager not available when updating text for {gameObject.name}");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// bool isArabic = LanguageManager.Instance.currentLanguage == "Arabic";
|
||||
// string rawText = LanguageManager.Instance.GetLocalizedText(localizationKey);
|
||||
|
||||
// tmp.text = isArabic ? ArabicFixer.Fix(rawText) : rawText;
|
||||
// tmp.font = LanguageManager.Instance.GetCurrentFont();
|
||||
// //tmp.isRightToLeftText = isArabic;
|
||||
// //tmp.alignment = isArabic ? TextAlignmentOptions.Right : TextAlignmentOptions.Left;
|
||||
//}
|
||||
|
||||
public void UpdateText()
|
||||
{
|
||||
if (LanguageManager.Instance == null)
|
||||
@ -40,9 +57,19 @@ public class LocalizedTextComponent : MonoBehaviour
|
||||
bool isArabic = LanguageManager.Instance.currentLanguage == "Arabic";
|
||||
string rawText = LanguageManager.Instance.GetLocalizedText(localizationKey);
|
||||
|
||||
tmp.text = isArabic ? ArabicFixer.Fix(rawText) : rawText;
|
||||
if (isArabic)
|
||||
{
|
||||
// Split by \n and fix each line
|
||||
string[] lines = rawText.Split(new[] { "\\n", "\n" }, System.StringSplitOptions.None);
|
||||
tmp.text = string.Join("\n", lines.Select(ArabicFixer.Fix));
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp.text = rawText.Replace("\\n", "\n"); // Handle escaped newline
|
||||
}
|
||||
|
||||
tmp.font = LanguageManager.Instance.GetCurrentFont();
|
||||
//tmp.isRightToLeftText = isArabic;
|
||||
//tmp.alignment = isArabic ? TextAlignmentOptions.Right : TextAlignmentOptions.Left;
|
||||
tmp.ForceMeshUpdate();
|
||||
}
|
||||
|
||||
}
|
||||
|
6537
Assets/TextMesh Pro/Fonts/Cairo-Black SDF.asset
Normal file
6537
Assets/TextMesh Pro/Fonts/Cairo-Black SDF.asset
Normal file
File diff suppressed because one or more lines are too long
8
Assets/TextMesh Pro/Fonts/Cairo-Black SDF.asset.meta
Normal file
8
Assets/TextMesh Pro/Fonts/Cairo-Black SDF.asset.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 975a612d4bf0d22479c1d2bb28530d18
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
BIN
Assets/TextMesh Pro/Fonts/Cairo-Black.ttf
Normal file
BIN
Assets/TextMesh Pro/Fonts/Cairo-Black.ttf
Normal file
Binary file not shown.
21
Assets/TextMesh Pro/Fonts/Cairo-Black.ttf.meta
Normal file
21
Assets/TextMesh Pro/Fonts/Cairo-Black.ttf.meta
Normal file
@ -0,0 +1,21 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 97826a7901e1ce9418ca23b0b6b4ec7e
|
||||
TrueTypeFontImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
fontSize: 16
|
||||
forceTextureCase: -2
|
||||
characterSpacing: 0
|
||||
characterPadding: 1
|
||||
includeFontData: 1
|
||||
fontNames:
|
||||
- Cairo
|
||||
fallbackFontReferences: []
|
||||
customCharacters:
|
||||
fontRenderingMode: 0
|
||||
ascentCalculationMode: 1
|
||||
useLegacyBoundsCalculation: 0
|
||||
shouldRoundAdvanceValue: 1
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
28
Assets/ZoomTween.cs
Normal file
28
Assets/ZoomTween.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using DG.Tweening;
|
||||
using UnityEngine;
|
||||
|
||||
public class ZoomTween : MonoBehaviour
|
||||
{
|
||||
[Header("Material and Property")]
|
||||
public Material targetMaterial;
|
||||
[Tooltip("Zoom range e.g., from 0.1 (zoomed in) to 5 (zoomed out)")]
|
||||
public float minZoom = 0.1f;
|
||||
public float maxZoom = 2f;
|
||||
public float speed = 1f;
|
||||
|
||||
[Tooltip("Name of the shader property (must match _ZoomUvAmount)")]
|
||||
private readonly string zoomProperty = "_ZoomUvAmount";
|
||||
|
||||
private float t;
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (!targetMaterial) return;
|
||||
|
||||
t += Time.deltaTime * speed;
|
||||
|
||||
// Animate using ping-pong
|
||||
float zoom = Mathf.Lerp(minZoom, maxZoom, Mathf.PingPong(t, 1f));
|
||||
targetMaterial.SetFloat(zoomProperty, zoom);
|
||||
}
|
||||
}
|
11
Assets/ZoomTween.cs.meta
Normal file
11
Assets/ZoomTween.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dfeee82aa0b6bf24381f7c432ba35115
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
x
Reference in New Issue
Block a user