diff --git a/.gitignore b/.gitignore
index d93bfaf..5d2a4aa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,32 +1,36 @@
-/[Ll]ibrary/
-/[Tt]emp/
-/[Oo]bj/
-/[Bb]uild/
-/[Bb]uilds/
-/[Ll]ogs/
-/[Uu]ser[Ss]ettings/
+*/[Ll]ibrary/
+*/[Tt]emp/
+*/[Oo]bj/
+*/[Bb]uild/
+*/[Bb]uilds/
+*/[Ll]ogs/
+*/[Uu]ser[Ss]ettings/
+
+# FieldSearchConfigs
+**/[Ff]ield[Ss]earch[Cc]onfigs/
+[Ff]ield[Ss]earch[Cc]onfigs.meta
# MemoryCaptures can get excessive in size.
# They also could contain extremely sensitive data
-/[Mm]emoryCaptures/
+*/[Mm]emoryCaptures/
# Recordings can get excessive in size
-/[Rr]ecordings/
+*/[Rr]ecordings/
# Uncomment this line if you wish to ignore the asset store tools plugin
# /[Aa]ssets/AssetStoreTools*
# Autogenerated Jetbrains Rider plugin
-/[Aa]ssets/Plugins/Editor/JetBrains*
+*/[Aa]ssets/Plugins/Editor/JetBrains*
# Visual Studio cache directory
-.vs/
+*/.vs/
# Gradle cache directory
.gradle/
# Autogenerated VS/MD/Consulo solution and project files
-ExportedObj/
+*/ExportedObj/
.consulo/
*.csproj
*.unityproj
@@ -61,8 +65,8 @@ sysinfo.txt
crashlytics-build.properties
# Packed Addressables
-/[Aa]ssets/[Aa]ddressable[Aa]ssets[Dd]ata/*/*.bin*
+*/[Aa]ssets/[Aa]ddressable[Aa]ssets[Dd]ata/*/*.bin*
# Temporary auto-generated Android Assets
-/[Aa]ssets/[Ss]treamingAssets/aa.meta
-/[Aa]ssets/[Ss]treamingAssets/aa/*
+*/[Aa]ssets/[Ss]treamingAssets/aa.meta
+*/[Aa]ssets/[Ss]treamingAssets/aa/*
diff --git a/.vsconfig b/FieldSearch/.vsconfig
similarity index 100%
rename from .vsconfig
rename to FieldSearch/.vsconfig
diff --git a/Assets/Scenes/SampleScene.unity.meta b/FieldSearch/Assembly-CSharp-Editor.csproj.meta
similarity index 74%
rename from Assets/Scenes/SampleScene.unity.meta
rename to FieldSearch/Assembly-CSharp-Editor.csproj.meta
index 952bd1e..b310c0a 100644
--- a/Assets/Scenes/SampleScene.unity.meta
+++ b/FieldSearch/Assembly-CSharp-Editor.csproj.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: 9fc0d4010bbf28b4594072e72b8655ab
+guid: df81f64228e728b4591d166693a332fe
DefaultImporter:
externalObjects: {}
userData:
diff --git a/FieldSearch/Assembly-CSharp.csproj.meta b/FieldSearch/Assembly-CSharp.csproj.meta
new file mode 100644
index 0000000..3d940a1
--- /dev/null
+++ b/FieldSearch/Assembly-CSharp.csproj.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: b497a7d581725ab418986f65a9ff4359
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scenes.meta b/FieldSearch/Assets.meta
similarity index 77%
rename from Assets/Scenes.meta
rename to FieldSearch/Assets.meta
index 3857cc0..400b388 100644
--- a/Assets/Scenes.meta
+++ b/FieldSearch/Assets.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: 9c038b0cd688df34ea3a8ff8c005064b
+guid: 28b673a302768244cab28881f7564792
folderAsset: yes
DefaultImporter:
externalObjects: {}
diff --git a/FieldSearch/Assets/FieldSearch.meta b/FieldSearch/Assets/FieldSearch.meta
new file mode 100644
index 0000000..bf5603e
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 2d71eac1bf9fb7040b03a2d4d377cc11
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Attributes.meta b/FieldSearch/Assets/FieldSearch/Attributes.meta
new file mode 100644
index 0000000..e3462ac
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Attributes.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 831f3712ba7401645ae6331c5a5292ca
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Attributes/Drawers.meta b/FieldSearch/Assets/FieldSearch/Attributes/Drawers.meta
new file mode 100644
index 0000000..08ea529
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Attributes/Drawers.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 87540d1e2bbd07b4ebc94aa881573f3e
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Attributes/Drawers/TypeRefDropdownAttributeDrawer.cs b/FieldSearch/Assets/FieldSearch/Attributes/Drawers/TypeRefDropdownAttributeDrawer.cs
new file mode 100644
index 0000000..83ba6d8
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Attributes/Drawers/TypeRefDropdownAttributeDrawer.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Linq;
+using UnityEditor;
+using UnityEngine;
+
+namespace FieldSearch.Attributes.Drawers
+{
+ ///
+ /// Drawer for
+ ///
+ [CustomPropertyDrawer(typeof(TypeRefDropdownAttribute))]
+ public class TypeRefDropdownAttributeDrawer : PropertyDrawer
+ {
+ TypeRefDropdownAttribute target;
+
+ int currentTypeIndex;
+ GUIContent[] displayedOptions;
+
+ public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
+ {
+ if (target == null)
+ {
+ Init(property);
+ return;
+ }
+
+ EditorGUI.BeginProperty(position, label, property);
+ ShowDropDownTypeList(position, property, label);
+ EditorGUI.EndProperty();
+ }
+
+ private void ShowDropDownTypeList(Rect position, SerializedProperty property, GUIContent label)
+ {
+ EditorGUI.BeginChangeCheck();
+ currentTypeIndex = EditorGUI.Popup(position, label, currentTypeIndex, displayedOptions);
+ if (EditorGUI.EndChangeCheck())
+ {
+ property.stringValue = target.InheritedTypeNameArray[currentTypeIndex];
+ property.serializedObject.ApplyModifiedProperties();
+ property.serializedObject.Update();
+ }
+ }
+
+ ///
+ /// First Init call
+ ///
+ ///
+ private void Init(SerializedProperty property)
+ {
+ target = attribute as TypeRefDropdownAttribute;
+ currentTypeIndex = Array.IndexOf(target.InheritedTypeNameArray, property.stringValue);
+
+ if (currentTypeIndex < 0)
+ {
+ Debug.LogWarning($"Type Index can't found for {property.displayName}");
+ currentTypeIndex = 0;
+ }
+
+ displayedOptions = target.ShortInheritedTypeNameArray.Select(x => new GUIContent(x)).ToArray();
+ }
+ }
+}
diff --git a/FieldSearch/Assets/FieldSearch/Attributes/Drawers/TypeRefDropdownAttributeDrawer.cs.meta b/FieldSearch/Assets/FieldSearch/Attributes/Drawers/TypeRefDropdownAttributeDrawer.cs.meta
new file mode 100644
index 0000000..5d199dc
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Attributes/Drawers/TypeRefDropdownAttributeDrawer.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: db7a6219cd8c9314590516432001e9f7
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Attributes/FieldSearch.Attributes.asmdef b/FieldSearch/Assets/FieldSearch/Attributes/FieldSearch.Attributes.asmdef
new file mode 100644
index 0000000..50d4b1e
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Attributes/FieldSearch.Attributes.asmdef
@@ -0,0 +1,14 @@
+{
+ "name": "FieldSearch.Attributes",
+ "references": [],
+ "optionalUnityReferences": [],
+ "includePlatforms": [
+ "Editor"
+ ],
+ "excludePlatforms": [],
+ "allowUnsafeCode": false,
+ "overrideReferences": false,
+ "precompiledReferences": [],
+ "autoReferenced": true,
+ "defineConstraints": []
+}
\ No newline at end of file
diff --git a/FieldSearch/Assets/FieldSearch/Attributes/FieldSearch.Attributes.asmdef.meta b/FieldSearch/Assets/FieldSearch/Attributes/FieldSearch.Attributes.asmdef.meta
new file mode 100644
index 0000000..7b835b3
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Attributes/FieldSearch.Attributes.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 00729d9f1fa97cf48b2359e703ae52b7
+AssemblyDefinitionImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Attributes/TypeComparer.cs b/FieldSearch/Assets/FieldSearch/Attributes/TypeComparer.cs
new file mode 100644
index 0000000..dc7a3d3
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Attributes/TypeComparer.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+
+namespace FieldSearch.Attributes
+{
+ ///
+ /// Type comparer.
+ /// Used in
+ ///
+ public class TypeComparer : IComparer
+ {
+ public int Compare(Type x, Type y)
+ {
+ return x.Name.CompareTo(y.Name);
+ }
+ }
+}
diff --git a/FieldSearch/Assets/FieldSearch/Attributes/TypeComparer.cs.meta b/FieldSearch/Assets/FieldSearch/Attributes/TypeComparer.cs.meta
new file mode 100644
index 0000000..dad446b
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Attributes/TypeComparer.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ef62c18eef9b06948a8d50a59e3785f1
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Attributes/TypeRefDropdownAttribute.cs b/FieldSearch/Assets/FieldSearch/Attributes/TypeRefDropdownAttribute.cs
new file mode 100644
index 0000000..addf415
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Attributes/TypeRefDropdownAttribute.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using UnityEngine;
+
+namespace FieldSearch.Attributes
+{
+ ///
+ /// Dropdown list attribute for type, inherited from BaseType
+ ///
+ [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
+ public class TypeRefDropdownAttribute : PropertyAttribute
+ {
+ public TypeRefDropdownAttribute(Type baseType, params string[] ignoredNamespaces)
+ {
+ BaseType = baseType;
+ Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
+ var types = GetInheritedTypes(BaseType, assemblies)
+ .Where(x => !x.IsAbstract
+ && !ignoredNamespaces.Contains(x.Namespace));
+
+ InheritedTypeNameArray = types.Select(x => x.AssemblyQualifiedName).ToArray();
+ ShortInheritedTypeNameArray = types.Select(x => x.Name).ToArray();
+ }
+
+ ///
+ /// Base type
+ ///
+ public Type BaseType { get; private set; }
+
+ ///
+ /// Array with Type.AssemblyQualifiedName
+ ///
+ public string[] InheritedTypeNameArray { get; private set; }
+
+ ///
+ /// Array with Type.Name
+ ///
+ public string[] ShortInheritedTypeNameArray { get; private set; }
+
+ ///
+ /// Get all Inherited from Types
+ ///
+ ///
+ ///
+ ///
+ public static List GetInheritedTypes(Type baseType, params Assembly[] assemblies)
+ {
+ List types = new List();
+ foreach (Type type in
+ assemblies.SelectMany(x => x.GetTypes())
+ .Where(x => x.IsSubclassOf(baseType)
+ && x.IsClass))
+ {
+ types.Add(type);
+ }
+ types.Sort(new TypeComparer());
+
+ return types;
+ }
+ }
+}
diff --git a/FieldSearch/Assets/FieldSearch/Attributes/TypeRefDropdownAttribute.cs.meta b/FieldSearch/Assets/FieldSearch/Attributes/TypeRefDropdownAttribute.cs.meta
new file mode 100644
index 0000000..cfd581d
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Attributes/TypeRefDropdownAttribute.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 0fee3066f382e624987ad2fa844c8e1e
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/CodeGeneration.meta b/FieldSearch/Assets/FieldSearch/CodeGeneration.meta
new file mode 100644
index 0000000..d5d83e0
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/CodeGeneration.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 58fe3382b57df0144a464342436ae017
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/CodeGeneration/Base.meta b/FieldSearch/Assets/FieldSearch/CodeGeneration/Base.meta
new file mode 100644
index 0000000..da5b14f
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/CodeGeneration/Base.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 442157033b3a65342910a05e4afb93f3
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/CodeGeneration/Base/BaseCodeGenerator.cs b/FieldSearch/Assets/FieldSearch/CodeGeneration/Base/BaseCodeGenerator.cs
new file mode 100644
index 0000000..4a6bc1e
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/CodeGeneration/Base/BaseCodeGenerator.cs
@@ -0,0 +1,28 @@
+using System;
+using UnityEngine;
+
+namespace CodeGeneration.Base
+{
+ ///
+ /// Base class for custom CodeGenerator
+ ///
+ ///
+ public abstract class BaseCodeGenerator where T : BaseScriptTemplate
+ {
+ protected BaseCodeGenerator(BaseCodeGeneratorSettings settings)
+ {
+ _settings = settings;
+ }
+
+ [SerializeField]
+ protected BaseCodeGeneratorSettings _settings;
+
+ ///
+ /// Create scripts using
+ ///
+ ///
+ ///
+ ///
+ public abstract void CreateScripts(T scriptTemplate, bool refresh = true, params Type[] inputTypes);
+ }
+}
diff --git a/FieldSearch/Assets/FieldSearch/CodeGeneration/Base/BaseCodeGenerator.cs.meta b/FieldSearch/Assets/FieldSearch/CodeGeneration/Base/BaseCodeGenerator.cs.meta
new file mode 100644
index 0000000..172f494
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/CodeGeneration/Base/BaseCodeGenerator.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 24eaf8cdb2cc4c14c8fcc38e962c7e61
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/CodeGeneration/Base/BaseCodeGeneratorSettings.cs b/FieldSearch/Assets/FieldSearch/CodeGeneration/Base/BaseCodeGeneratorSettings.cs
new file mode 100644
index 0000000..d635b8a
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/CodeGeneration/Base/BaseCodeGeneratorSettings.cs
@@ -0,0 +1,58 @@
+using System;
+using System.IO;
+using UnityEngine;
+
+namespace CodeGeneration.Base
+{
+ ///
+ /// Base settings object for
+ ///
+ public abstract class BaseCodeGeneratorSettings : ScriptableObject where T : BaseScriptTemplate
+ {
+ ///
+ /// Default script template, used in
+ ///
+ public T DefaultScriptTemplate => _defaultScriptTemplate;
+
+ ///
+ /// Folder for generated files
+ ///
+ public string DefaultFileFolder =>
+ Path.Combine(Environment.CurrentDirectory, _defaultFileFolder);
+
+ ///
+ /// CodeGenerator type name
+ ///
+ protected abstract string CodeGeneratorTypeName { get; }
+
+ ///
+ /// Get CodeGeneratorType using
+ ///
+ protected Type CodeGeneratorType => Type.GetType(CodeGeneratorTypeName);
+
+ [Tooltip("Default relative folder path")]
+ [SerializeField]
+ protected string _defaultFileFolder;
+ [SerializeField]
+ protected T _defaultScriptTemplate;
+
+ ///
+ /// Full folder path with
+ ///
+ ///
+ ///
+ public string FullFileFolder(string relativePath) =>
+ Path.Combine(Environment.CurrentDirectory, relativePath);
+
+ ///
+ /// Create new instance
+ /// using
+ ///
+ ///
+ public BaseCodeGenerator CreateGeneratorInstance()
+ {
+ return (BaseCodeGenerator)Activator
+ .CreateInstance(CodeGeneratorType, args: this);
+ }
+ }
+}
diff --git a/FieldSearch/Assets/FieldSearch/CodeGeneration/Base/BaseCodeGeneratorSettings.cs.meta b/FieldSearch/Assets/FieldSearch/CodeGeneration/Base/BaseCodeGeneratorSettings.cs.meta
new file mode 100644
index 0000000..80fbefa
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/CodeGeneration/Base/BaseCodeGeneratorSettings.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 2180cefbe0decc840b745c64ad940079
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/CodeGeneration/Base/BaseScriptTemplate.cs b/FieldSearch/Assets/FieldSearch/CodeGeneration/Base/BaseScriptTemplate.cs
new file mode 100644
index 0000000..cc2a254
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/CodeGeneration/Base/BaseScriptTemplate.cs
@@ -0,0 +1,33 @@
+using CodeGeneration.Data;
+using System;
+using UnityEngine;
+
+namespace CodeGeneration.Base
+{
+ ///
+ /// Base script template object
+ ///
+ public abstract class BaseScriptTemplate : ScriptableObject
+ {
+ ///
+ /// File name format string
+ ///
+ [SerializeField]
+ protected string _scriptNameFormatString;
+
+ ///
+ /// Script format string
+ ///
+ [TextArea(10, 70)]
+ [SerializeField]
+ protected string _scriptFormatString;
+
+ ///
+ /// Create script with args using
+ ///
+ ///
+ ///
+ ///
+ public abstract GeneratedScript CreateScript(Type type, params object[] args);
+ }
+}
diff --git a/FieldSearch/Assets/FieldSearch/CodeGeneration/Base/BaseScriptTemplate.cs.meta b/FieldSearch/Assets/FieldSearch/CodeGeneration/Base/BaseScriptTemplate.cs.meta
new file mode 100644
index 0000000..ad9fbf0
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/CodeGeneration/Base/BaseScriptTemplate.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 0137375e51f9ac749bf32cb9a26c5d7b
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/CodeGeneration/CodeGeneration.asmdef b/FieldSearch/Assets/FieldSearch/CodeGeneration/CodeGeneration.asmdef
new file mode 100644
index 0000000..ccc617c
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/CodeGeneration/CodeGeneration.asmdef
@@ -0,0 +1,16 @@
+{
+ "name": "CodeGenerator",
+ "references": [
+ "FieldSearch.Attributes"
+ ],
+ "optionalUnityReferences": [],
+ "includePlatforms": [
+ "Editor"
+ ],
+ "excludePlatforms": [],
+ "allowUnsafeCode": false,
+ "overrideReferences": false,
+ "precompiledReferences": [],
+ "autoReferenced": true,
+ "defineConstraints": []
+}
\ No newline at end of file
diff --git a/FieldSearch/Assets/FieldSearch/CodeGeneration/CodeGeneration.asmdef.meta b/FieldSearch/Assets/FieldSearch/CodeGeneration/CodeGeneration.asmdef.meta
new file mode 100644
index 0000000..b5da954
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/CodeGeneration/CodeGeneration.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: a547b51c9dad9054b97bdcd5f5eaea9d
+AssemblyDefinitionImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/CodeGeneration/CodeGenerationUtils.cs b/FieldSearch/Assets/FieldSearch/CodeGeneration/CodeGenerationUtils.cs
new file mode 100644
index 0000000..7f0fbed
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/CodeGeneration/CodeGenerationUtils.cs
@@ -0,0 +1,156 @@
+using CodeGeneration.Data;
+using System;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using UnityEngine;
+
+namespace CodeGeneration
+{
+ ///
+ /// Utils for CodeGeneration
+ ///
+ public class CodeGenerationUtils
+ {
+ ///
+ /// Get all types.
+ /// Excluding default or sample types.
+ ///
+ ///
+ public static Type[] GetAllAvailableEditorTypes()
+ {
+ var types = GetAllInheritedTypes(typeof(UnityEditor.Editor),
+ ValidateNamespaceFunc: (name) =>
+ {
+ if (name == null)
+ {
+ return false;
+ }
+
+ // Dev debug lines
+ if (new DirectoryInfo(Environment.CurrentDirectory).Name == nameof(FieldSearch)
+ && name.StartsWith("FieldSearch.Samples"))
+ {
+ return true;
+ }
+
+ // Default exclude namespaces
+ if (name.Contains(nameof(UnityEditor))
+ || name.Contains(nameof(UnityEngine))
+ || name.Contains(nameof(FieldSearch))
+ || name.Contains("TMP"))
+ {
+ return false;
+ }
+
+ return true;
+ });
+ return types;
+ }
+
+ ///
+ /// Get all inherited types for
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static Type[] GetAllInheritedTypes(Type baseType, Assembly[] assemblies = default,
+ Func ValidateNamespaceFunc = default)
+ {
+ if(assemblies == default)
+ {
+ assemblies = AppDomain.CurrentDomain.GetAssemblies();
+ }
+
+ if(ValidateNamespaceFunc == default)
+ {
+ ValidateNamespaceFunc = (name) => true;
+ }
+
+ var types =
+ assemblies
+ .SelectMany(x => x
+ .GetTypes()
+ .Where(type =>
+ type.IsPublic
+ && type.IsClass
+ && !type.IsAbstract
+ && type.IsSubclassOf(baseType)
+ && ValidateNamespaceFunc(type.Namespace)));
+ return types.ToArray();
+ }
+
+ ///
+ /// Get first FieldInfo for by
+ ///
+ ///
+ ///
+ ///
+ public static FieldInfo GetAttributeFieldByName(Attribute attribute, string fieldName)
+ {
+ var field = attribute.GetType()
+ .GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
+ ?.FirstOrDefault(x => x.Name == fieldName);
+ return field;
+ }
+
+ ///
+ /// Get first FieldInfo for by type of
+ ///
+ ///
+ ///
+ ///
+ public static FieldInfo GetFirstAttributeFieldByType(Attribute attribute) where T : Type
+ {
+ var field = attribute.GetType()
+ .GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
+ ?.FirstOrDefault(x => x.GetValue(attribute) is T);
+ return field;
+ }
+
+ ///
+ /// Get first class attribute
+ ///
+ ///
+ ///
+ ///
+ public static T GetFirstClassAttribute(Type type) where T : Attribute
+ {
+ var attribute = type.GetCustomAttributes(typeof(T), true)
+ ?.FirstOrDefault() as T;
+ return attribute;
+ }
+
+ ///
+ /// Save to folder with
+ ///
+ ///
+ ///
+ ///
+ public static bool SaveToFile(string folderPath, GeneratedScript generatedScript)
+ {
+ try
+ {
+ if(generatedScript?.fileName == null)
+ {
+ return false;
+ }
+
+ if (!Directory.Exists(folderPath))
+ {
+ Directory.CreateDirectory(folderPath);
+ }
+
+ var path = Path.Combine(folderPath, generatedScript.fileName);
+ File.WriteAllText(path, generatedScript.scriptStr);
+ return true;
+ }
+ catch (Exception e)
+ {
+ Debug.LogError(e);
+ return false;
+ }
+ }
+ }
+}
diff --git a/FieldSearch/Assets/FieldSearch/CodeGeneration/CodeGenerationUtils.cs.meta b/FieldSearch/Assets/FieldSearch/CodeGeneration/CodeGenerationUtils.cs.meta
new file mode 100644
index 0000000..812cd51
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/CodeGeneration/CodeGenerationUtils.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: aeefdaeaa85e98f4a8f25fec9afa5342
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/CodeGeneration/GeneratedScript.cs b/FieldSearch/Assets/FieldSearch/CodeGeneration/GeneratedScript.cs
new file mode 100644
index 0000000..0757772
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/CodeGeneration/GeneratedScript.cs
@@ -0,0 +1,17 @@
+namespace CodeGeneration.Data
+{
+ ///
+ /// Data class for Generated Script
+ ///
+ public class GeneratedScript
+ {
+ public GeneratedScript(string fileName, string scriptStr)
+ {
+ this.fileName = fileName;
+ this.scriptStr = scriptStr;
+ }
+
+ public string fileName;
+ public string scriptStr;
+ }
+}
diff --git a/FieldSearch/Assets/FieldSearch/CodeGeneration/GeneratedScript.cs.meta b/FieldSearch/Assets/FieldSearch/CodeGeneration/GeneratedScript.cs.meta
new file mode 100644
index 0000000..0a91fe2
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/CodeGeneration/GeneratedScript.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c0006f583f57d5b4480ac99676acb32c
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Core.meta b/FieldSearch/Assets/FieldSearch/Core.meta
new file mode 100644
index 0000000..351e806
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 3c78cfd4cb95460489a1436eb4691e63
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Core/BaseSearch.cs b/FieldSearch/Assets/FieldSearch/Core/BaseSearch.cs
new file mode 100644
index 0000000..31ebc91
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/BaseSearch.cs
@@ -0,0 +1,54 @@
+using FieldSearch.Core.Data.Criteria.Base;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace FieldSearch.Core.Base
+{
+ ///
+ /// Base search class with filter implementation
+ ///
+ public abstract class BaseSearch
+ {
+ [System.Flags]
+ public enum SearchFilter
+ {
+ None = 0,
+ StartWith = 1,
+ IgnoreCase = 2,
+ ByFieldName = 4,
+ ByObjName = 8
+ }
+
+ public BaseSearch(SearchFilter currentFlags)
+ {
+ baseSearchCriteria = new List();
+ CreateCriteria(currentFlags);
+ }
+
+ private List baseSearchCriteria;
+
+ public void UpdateCriteria(SearchFilter currentFlags)
+ {
+ ClearCriteria();
+ CreateCriteria(currentFlags);
+ }
+
+ protected abstract bool CreateCriteria(SearchFilter currentFlags);
+
+ public bool GetResult(SearchFilter currentFlags, bool any = false, params object[] input)
+ {
+ return any ? baseSearchCriteria.Any(x => x.HasResult(currentFlags, input))
+ : baseSearchCriteria.All(x => x.HasResult(currentFlags, input));
+ }
+
+ protected void AddCriterion(BaseSearchCriterion baseSearchCriterion)
+ {
+ baseSearchCriteria.Add(baseSearchCriterion);
+ }
+
+ public void ClearCriteria()
+ {
+ baseSearchCriteria.Clear();
+ }
+ }
+}
diff --git a/FieldSearch/Assets/FieldSearch/Core/BaseSearch.cs.meta b/FieldSearch/Assets/FieldSearch/Core/BaseSearch.cs.meta
new file mode 100644
index 0000000..f116c48
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/BaseSearch.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 1aaa67165ec09fa408989e9e81dabe6c
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Core/Data.meta b/FieldSearch/Assets/FieldSearch/Core/Data.meta
new file mode 100644
index 0000000..f21d2d0
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/Data.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 72f1590abc64bc54eba2d56f6cdb0d3a
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Core/Data/Criteria.meta b/FieldSearch/Assets/FieldSearch/Core/Data/Criteria.meta
new file mode 100644
index 0000000..85c415c
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/Data/Criteria.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 9e213de3ac6c10249a011a3f332f3e87
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Core/Data/Criteria/BaseSearchCriterion.cs b/FieldSearch/Assets/FieldSearch/Core/Data/Criteria/BaseSearchCriterion.cs
new file mode 100644
index 0000000..7347201
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/Data/Criteria/BaseSearchCriterion.cs
@@ -0,0 +1,72 @@
+using FieldSearch.Helpers.StringFormatter;
+using static FieldSearch.Core.Base.BaseSearch;
+
+namespace FieldSearch.Core.Data.Criteria.Base
+{
+ ///
+ /// Base search criterion for
+ ///
+ public abstract class BaseSearchCriterion
+ {
+ public BaseSearchCriterion()
+ {
+ Init();
+ }
+
+ ///
+ /// Criterion flag
+ ///
+ protected SearchFilter criterionFilter;
+
+ ///
+ /// Check results
+ ///
+ ///
+ ///
+ ///
+ ///
+ public abstract bool HasResult(SearchFilter currentFlags, params T[] input);
+
+ ///
+ /// Get Criterion flag
+ ///
+ ///
+ protected abstract SearchFilter GetCriterionSearchFilter();
+
+ ///
+ /// Compare result with search text
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected bool Compare(string name, string rawSearchText, SearchFilter currentSearchFilter)
+ {
+ var finalString = SearchStringFormatter.GetFinalString(name, currentSearchFilter);
+ var finalSearchText = SearchStringFormatter.GetFinalString(rawSearchText, currentSearchFilter);
+
+ var startWith = criterionFilter.HasFlag(SearchFilter.StartWith);
+ return startWith ?
+ finalString.StartsWith(finalSearchText)
+ : finalString.Contains(finalSearchText);
+ }
+
+ ///
+ /// If criterion is active for current search flag
+ ///
+ ///
+ ///
+ protected virtual bool IsActive(SearchFilter currentFlags)
+ {
+ return currentFlags.HasFlag(criterionFilter);
+ }
+
+ ///
+ /// Init method with base logic
+ ///
+ protected virtual void Init()
+ {
+ this.criterionFilter = GetCriterionSearchFilter();
+ }
+ }
+}
diff --git a/FieldSearch/Assets/FieldSearch/Core/Data/Criteria/BaseSearchCriterion.cs.meta b/FieldSearch/Assets/FieldSearch/Core/Data/Criteria/BaseSearchCriterion.cs.meta
new file mode 100644
index 0000000..cabd584
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/Data/Criteria/BaseSearchCriterion.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: adf5a4e997f920a4e9aa7dabdac0c57e
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Core/Data/Criteria/ByFieldNameSearchCriterion.cs b/FieldSearch/Assets/FieldSearch/Core/Data/Criteria/ByFieldNameSearchCriterion.cs
new file mode 100644
index 0000000..0c8ed76
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/Data/Criteria/ByFieldNameSearchCriterion.cs
@@ -0,0 +1,42 @@
+using FieldSearch.Core.Data.Criteria.Base;
+using UnityEditor;
+using static FieldSearch.Core.Base.BaseSearch;
+
+namespace FieldSearch.Core.Data.Criteria
+{
+ ///
+ /// ByFieldName search criterion
+ /// for
+ ///
+ public class ByFieldNameSearchCriterion : BaseSearchCriterion
+ {
+ public const SearchFilter CRITERION_SEARCH_FILTER = SearchFilter.ByFieldName;
+
+ public ByFieldNameSearchCriterion() : base() { }
+
+ protected override SearchFilter GetCriterionSearchFilter() => CRITERION_SEARCH_FILTER;
+
+ public override bool HasResult(SearchFilter currentFlags, params T[] input)
+ {
+ if (!IsActive(currentFlags))
+ {
+ return false;
+ }
+
+ var rawSearchText = input[0] as string;
+ if(rawSearchText is null)
+ {
+ return false;
+ }
+
+ var serializedProperty = input[1] as SerializedProperty;
+
+ if (serializedProperty == null)
+ {
+ return false;
+ }
+
+ return Compare(serializedProperty.displayName, rawSearchText, currentFlags);
+ }
+ }
+}
diff --git a/FieldSearch/Assets/FieldSearch/Core/Data/Criteria/ByFieldNameSearchCriterion.cs.meta b/FieldSearch/Assets/FieldSearch/Core/Data/Criteria/ByFieldNameSearchCriterion.cs.meta
new file mode 100644
index 0000000..fb555f2
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/Data/Criteria/ByFieldNameSearchCriterion.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 7fe17efc89925144081efbd3877ee320
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Core/Data/Criteria/ByObjNameSearchCriterion.cs b/FieldSearch/Assets/FieldSearch/Core/Data/Criteria/ByObjNameSearchCriterion.cs
new file mode 100644
index 0000000..6bff8e0
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/Data/Criteria/ByObjNameSearchCriterion.cs
@@ -0,0 +1,62 @@
+using FieldSearch.Core.Data.Criteria.Base;
+using UnityEditor;
+using static FieldSearch.Core.Base.BaseSearch;
+
+namespace FieldSearch.Core.Data.Criteria
+{
+ ///
+ /// ByObjName search criterion
+ /// for
+ ///
+ public class ByObjNameSearchCriterion : BaseSearchCriterion
+ {
+ public const SearchFilter CRITERION_SEARCH_FILTER = SearchFilter.ByObjName;
+
+ public ByObjNameSearchCriterion() : base() { }
+
+ protected override SearchFilter GetCriterionSearchFilter() => CRITERION_SEARCH_FILTER;
+
+ public override bool HasResult(SearchFilter currentFlags, params T[] input)
+ {
+ if (!IsActive(currentFlags))
+ {
+ return false;
+ }
+
+ if (input.Length < 2)
+ {
+ return false;
+ }
+
+ var rawSearchText = input[0] as string;
+ if (rawSearchText is null)
+ {
+ return false;
+ }
+
+ try
+ {
+ if (input[1] is SerializedProperty == false)
+ {
+ return false;
+ }
+
+ var serializedProperty = input[1] as SerializedProperty;
+
+ if(serializedProperty == null
+ || serializedProperty.propertyType != SerializedPropertyType.ObjectReference)
+ {
+ return false;
+ }
+
+ return Compare(serializedProperty.objectReferenceValue.name, rawSearchText, currentFlags);
+ }
+ catch
+ {
+ // TODO: check SerializedProperty pptr error && update logic
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/FieldSearch/Assets/FieldSearch/Core/Data/Criteria/ByObjNameSearchCriterion.cs.meta b/FieldSearch/Assets/FieldSearch/Core/Data/Criteria/ByObjNameSearchCriterion.cs.meta
new file mode 100644
index 0000000..4bd6e39
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/Data/Criteria/ByObjNameSearchCriterion.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 77f0b3b4d459a4b488633f24d4ff6350
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Core/FieldSearch.Core.asmdef b/FieldSearch/Assets/FieldSearch/Core/FieldSearch.Core.asmdef
new file mode 100644
index 0000000..fa57ace
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/FieldSearch.Core.asmdef
@@ -0,0 +1,16 @@
+{
+ "name": "FieldSearch.Core",
+ "references": [
+ "FieldSearch.Attributes"
+ ],
+ "optionalUnityReferences": [],
+ "includePlatforms": [
+ "Editor"
+ ],
+ "excludePlatforms": [],
+ "allowUnsafeCode": false,
+ "overrideReferences": false,
+ "precompiledReferences": [],
+ "autoReferenced": true,
+ "defineConstraints": []
+}
\ No newline at end of file
diff --git a/FieldSearch/Assets/FieldSearch/Core/FieldSearch.Core.asmdef.meta b/FieldSearch/Assets/FieldSearch/Core/FieldSearch.Core.asmdef.meta
new file mode 100644
index 0000000..2a6730f
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/FieldSearch.Core.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 95622f21ee9c7944dba4c2dd0aa941ae
+AssemblyDefinitionImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Core/GlobalEditor.meta b/FieldSearch/Assets/FieldSearch/Core/GlobalEditor.meta
new file mode 100644
index 0000000..b8b148e
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/GlobalEditor.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 59ef36d1f2d22a7459579d9425fb7efb
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Core/GlobalEditor/Editor.meta b/FieldSearch/Assets/FieldSearch/Core/GlobalEditor/Editor.meta
new file mode 100644
index 0000000..bb068a3
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/GlobalEditor/Editor.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 2680ab051550ab645ae963a2fae37cb8
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Core/GlobalEditor/Editor/BaseFieldSearchGlobalEditor.cs b/FieldSearch/Assets/FieldSearch/Core/GlobalEditor/Editor/BaseFieldSearchGlobalEditor.cs
new file mode 100644
index 0000000..d4de457
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/GlobalEditor/Editor/BaseFieldSearchGlobalEditor.cs
@@ -0,0 +1,12 @@
+using UnityEditor;
+
+namespace FieldSearch.Core.GlobalEditor
+{
+ ///
+ /// Base FieldSearchGlobalEditor class
+ ///
+ public abstract class BaseFieldSearchGlobalEditor : Editor
+ {
+
+ }
+}
diff --git a/FieldSearch/Assets/FieldSearch/Core/GlobalEditor/Editor/BaseFieldSearchGlobalEditor.cs.meta b/FieldSearch/Assets/FieldSearch/Core/GlobalEditor/Editor/BaseFieldSearchGlobalEditor.cs.meta
new file mode 100644
index 0000000..6d86e91
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/GlobalEditor/Editor/BaseFieldSearchGlobalEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e1b2042a83304094d9f2a386bb4576c2
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Core/GlobalEditor/Editor/DefaultFieldSearchGlobalEditor.cs b/FieldSearch/Assets/FieldSearch/Core/GlobalEditor/Editor/DefaultFieldSearchGlobalEditor.cs
new file mode 100644
index 0000000..8548080
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/GlobalEditor/Editor/DefaultFieldSearchGlobalEditor.cs
@@ -0,0 +1,82 @@
+using FieldSearch.Settings.Base;
+using System;
+using System.Reflection;
+using UnityEditor;
+using UnityEngine;
+
+namespace FieldSearch.Core.GlobalEditor
+{
+ ///
+ /// Default implementation
+ ///
+ [CustomEditor(typeof(MonoBehaviour), true, isFallback = true)]
+ public class DefaultFieldSearchGlobalEditor : BaseFieldSearchGlobalEditor
+ {
+ protected virtual BaseFieldSearchSettings Settings => BaseFieldSearchSettings.Instance;
+ protected virtual Type SearchLayerInspectorType => Settings.SearchLayerInspectorType;
+ protected virtual bool IsActive => Settings?.ApplyToAll ?? false;
+
+ protected Editor searchLayerInspector;
+
+ private void OnEnable()
+ {
+ if (IsActive)
+ {
+ searchLayerInspector = CreateEditor(target, SearchLayerInspectorType);
+ }
+ }
+
+ private void OnDisable()
+ {
+ if (IsActive)
+ {
+ DestroyImmediate(searchLayerInspector);
+ }
+ }
+
+ public override void OnInspectorGUI()
+ {
+ if (IsActive)
+ {
+ searchLayerInspector?.OnInspectorGUI();
+ }
+ else
+ {
+ base.OnInspectorGUI();
+ }
+ }
+ }
+
+ ///
+ /// Abstract to save default Inspector
+ ///
+ /// Default inspector
+ public abstract class DefaultFieldSearchGlobalEditor : BaseFieldSearchGlobalEditor where T : Editor
+ {
+ protected Editor searchableGlobalEditor;
+ protected Editor defaultEditor;
+
+ private void OnEnable()
+ {
+ //Try invoke baase OnEnable method
+ typeof(T)
+ .GetMethod(nameof(OnEnable),
+ BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
+ ?.Invoke(this, null);
+
+ InitSearchableInspector();
+ }
+
+ protected virtual void InitSearchableInspector()
+ {
+ searchableGlobalEditor = CreateEditor(target, typeof(DefaultFieldSearchGlobalEditor));
+ defaultEditor = CreateEditor(target, typeof(T));
+ }
+
+ public override void OnInspectorGUI()
+ {
+ searchableGlobalEditor?.OnInspectorGUI();
+ defaultEditor?.OnInspectorGUI();
+ }
+ }
+}
diff --git a/FieldSearch/Assets/FieldSearch/Core/GlobalEditor/Editor/DefaultFieldSearchGlobalEditor.cs.meta b/FieldSearch/Assets/FieldSearch/Core/GlobalEditor/Editor/DefaultFieldSearchGlobalEditor.cs.meta
new file mode 100644
index 0000000..6c0ffa0
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/GlobalEditor/Editor/DefaultFieldSearchGlobalEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 0e6cd06e24f19e4488b388c9ced5a85f
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Core/GlobalEditor/FieldSearch.Core.GlobalEditor.asmdef b/FieldSearch/Assets/FieldSearch/Core/GlobalEditor/FieldSearch.Core.GlobalEditor.asmdef
new file mode 100644
index 0000000..1d91b39
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/GlobalEditor/FieldSearch.Core.GlobalEditor.asmdef
@@ -0,0 +1,16 @@
+{
+ "name": "FieldSearch.Core.GlobalEditor",
+ "references": [
+ "FieldSearch.Core"
+ ],
+ "optionalUnityReferences": [],
+ "includePlatforms": [
+ "Editor"
+ ],
+ "excludePlatforms": [],
+ "allowUnsafeCode": false,
+ "overrideReferences": false,
+ "precompiledReferences": [],
+ "autoReferenced": true,
+ "defineConstraints": []
+}
\ No newline at end of file
diff --git a/FieldSearch/Assets/FieldSearch/Core/GlobalEditor/FieldSearch.Core.GlobalEditor.asmdef.meta b/FieldSearch/Assets/FieldSearch/Core/GlobalEditor/FieldSearch.Core.GlobalEditor.asmdef.meta
new file mode 100644
index 0000000..16bd522
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/GlobalEditor/FieldSearch.Core.GlobalEditor.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 367cfe07efa90014a9815765b08a7da9
+AssemblyDefinitionImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Core/Helpers.meta b/FieldSearch/Assets/FieldSearch/Core/Helpers.meta
new file mode 100644
index 0000000..9a7d9e7
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/Helpers.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: c148cba6d19b18c4aa2241d094f7244f
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Core/Helpers/Cache.meta b/FieldSearch/Assets/FieldSearch/Core/Helpers/Cache.meta
new file mode 100644
index 0000000..b070de6
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/Helpers/Cache.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 953da1ed0347977489c28ee94a07ea7b
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Core/Helpers/Cache/Data.meta b/FieldSearch/Assets/FieldSearch/Core/Helpers/Cache/Data.meta
new file mode 100644
index 0000000..5f2c175
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/Helpers/Cache/Data.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 3609556c73a95d14ba9a2c8cc938e316
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Core/Helpers/Cache/Data/SearchCacheJson.cs b/FieldSearch/Assets/FieldSearch/Core/Helpers/Cache/Data/SearchCacheJson.cs
new file mode 100644
index 0000000..de472c3
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/Helpers/Cache/Data/SearchCacheJson.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace FieldSearch.Helpers.Cache.Data
+{
+ ///
+ /// Container for
+ ///
+ [Serializable]
+ public struct SearchCacheJson
+ {
+ public SearchCacheJson(ConcurrentDictionary dict)
+ {
+ objects = dict.Select(x => x.Value).ToList();
+ }
+
+ public SearchCacheJson(Dictionary dict)
+ {
+ objects = dict.Select(x => x.Value).ToList();
+ }
+
+ public List objects;
+
+ public Dictionary ToDictionary()
+ {
+ return objects.ToDictionary(x => x.id);
+ }
+
+ public ConcurrentDictionary ToConcurrentDictionary()
+ {
+ return new ConcurrentDictionary(ToDictionary());
+ }
+ }
+}
\ No newline at end of file
diff --git a/FieldSearch/Assets/FieldSearch/Core/Helpers/Cache/Data/SearchCacheJson.cs.meta b/FieldSearch/Assets/FieldSearch/Core/Helpers/Cache/Data/SearchCacheJson.cs.meta
new file mode 100644
index 0000000..92c6947
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/Helpers/Cache/Data/SearchCacheJson.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8e02ff6fbb1a87644b1a326166966b5f
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Core/Helpers/Cache/Data/SearchCacheObj.cs b/FieldSearch/Assets/FieldSearch/Core/Helpers/Cache/Data/SearchCacheObj.cs
new file mode 100644
index 0000000..2bc8e8d
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/Helpers/Cache/Data/SearchCacheObj.cs
@@ -0,0 +1,22 @@
+using System;
+
+namespace FieldSearch.Helpers.Cache.Data
+{
+ ///
+ /// Stored SearchCache struct
+ ///
+ [Serializable]
+ public struct SearchCacheObj
+ {
+ public SearchCacheObj(int id, string searchText, int flags)
+ {
+ this.id = id;
+ this.searchText = searchText;
+ this.flags = flags;
+ }
+
+ public int id;
+ public string searchText;
+ public int flags;
+ }
+}
diff --git a/FieldSearch/Assets/FieldSearch/Core/Helpers/Cache/Data/SearchCacheObj.cs.meta b/FieldSearch/Assets/FieldSearch/Core/Helpers/Cache/Data/SearchCacheObj.cs.meta
new file mode 100644
index 0000000..4179092
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/Helpers/Cache/Data/SearchCacheObj.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d5a6ed6de1c2df244a89c1f535d22599
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Core/Helpers/Cache/SearchInspectorCache.cs b/FieldSearch/Assets/FieldSearch/Core/Helpers/Cache/SearchInspectorCache.cs
new file mode 100644
index 0000000..aedee1e
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/Helpers/Cache/SearchInspectorCache.cs
@@ -0,0 +1,154 @@
+using FieldSearch.Helpers.Cache.Data;
+using FieldSearch.Settings.Base;
+using System.Collections.Concurrent;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using UnityEditor;
+using UnityEngine;
+
+namespace FieldSearch.Helpers.Cache
+{
+ ///
+ /// SearchCache inspector controller.
+ /// With InitializeOnLoad logic
+ ///
+ [InitializeOnLoad]
+ public class SearchInspectorCache
+ {
+ static SearchInspectorCache()
+ {
+ ReadCacheFromDisk();
+ AssemblyReloadEvents.beforeAssemblyReload += AssemblyReloadEvents_beforeAssemblyReload;
+ EditorApplication.quitting += EditorApplication_quitting;
+ }
+
+ private static void EditorApplication_quitting()
+ {
+ EditorApplication.quitting -= EditorApplication_quitting;
+ SaveCacheToDisk();
+ }
+
+ private static void AssemblyReloadEvents_beforeAssemblyReload()
+ {
+ AssemblyReloadEvents.beforeAssemblyReload -= AssemblyReloadEvents_beforeAssemblyReload;
+ SaveCacheToDisk();
+ }
+
+ public const string FILE_NAME = "SearchInspectorCache.txt";
+
+ public static string FilePath => $"{Application.temporaryCachePath}/{FILE_NAME}";
+
+ public static float GetCurrentSize() => inspectorsDict.Sum(x => Marshal.SizeOf(x.Value));
+
+ protected static ConcurrentDictionary inspectorsDict
+ = new ConcurrentDictionary();
+
+ protected static BaseFieldSearchSettings Settings => BaseFieldSearchSettings.Instance;
+
+ public static bool TryAddValue(SearchCacheObj val)
+ {
+ if (!HasFreeMemorySlots())
+ {
+ TryRemoveFirstValue();
+ }
+
+ var id = val.id;
+
+ if (inspectorsDict.ContainsKey(id))
+ {
+ inspectorsDict[id] = val;
+ return true;
+ }
+ else
+ {
+ return inspectorsDict.TryAdd(id, val);
+ }
+ }
+
+ public static bool TryRemoveValue(int id)
+ {
+ if (inspectorsDict.ContainsKey(id))
+ {
+ SearchCacheObj obj;
+ return inspectorsDict.TryRemove(id, out obj);
+ }
+ return false;
+ }
+
+ public static bool TryGetValue(int id, out SearchCacheObj obj)
+ {
+ return inspectorsDict.TryGetValue(id, out obj);
+ }
+
+ private static bool TryRemoveFirstValue()
+ {
+ return TryRemoveValue(inspectorsDict.Keys.First());
+ }
+
+ private static bool HasFreeMemorySlots()
+ {
+ if(Settings == null)
+ {
+ return true;
+ }
+
+ var currentSizeInMb = ConvertByteToMb(GetCurrentSize());
+ return currentSizeInMb < Settings.MemoryLimitInMb;
+ }
+
+ private static double ConvertByteToMb(float byteCount)
+ {
+ return (byteCount / (double)Mathf.Pow(1024, 2));
+ }
+
+ private static void SaveCacheToDisk()
+ {
+ using (StreamWriter sw = File.CreateText(FilePath))
+ {
+ var obj = new SearchCacheJson(inspectorsDict);
+ var json = JsonUtility.ToJson(obj);
+ sw.Write(json);
+ }
+ }
+
+ private static void ReadCacheFromDisk()
+ {
+ if (!File.Exists(FilePath))
+ {
+ return;
+ }
+
+ using (StreamReader sw = File.OpenText(FilePath))
+ {
+ var str = sw.ReadToEnd();
+ if(string.IsNullOrEmpty(str)
+ || string.IsNullOrWhiteSpace(str))
+ {
+ return;
+ }
+
+ var obj = JsonUtility.FromJson(str);
+ inspectorsDict = obj.ToConcurrentDictionary();
+ }
+ }
+
+ public static void ClearCache(bool fromDisk = true, bool fromMemory = true)
+ {
+ if (fromDisk)
+ {
+ using (StreamWriter sw = File.CreateText(FilePath))
+ {
+ var obj = new SearchCacheJson(inspectorsDict);
+ var json = JsonUtility.ToJson(obj);
+ sw.Write("");
+ }
+ }
+
+ if (fromMemory)
+ {
+ inspectorsDict.Clear();
+ }
+ }
+ }
+}
diff --git a/FieldSearch/Assets/FieldSearch/Core/Helpers/Cache/SearchInspectorCache.cs.meta b/FieldSearch/Assets/FieldSearch/Core/Helpers/Cache/SearchInspectorCache.cs.meta
new file mode 100644
index 0000000..7ff88c1
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/Helpers/Cache/SearchInspectorCache.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e6f3993b2047d75428927b96a117475d
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Core/Helpers/StringFormatter.meta b/FieldSearch/Assets/FieldSearch/Core/Helpers/StringFormatter.meta
new file mode 100644
index 0000000..f643f6c
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/Helpers/StringFormatter.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 62d6dcaee4b4a2e42bc12b8f4ecfae61
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Core/Helpers/StringFormatter/SearchStringFormatter.cs b/FieldSearch/Assets/FieldSearch/Core/Helpers/StringFormatter/SearchStringFormatter.cs
new file mode 100644
index 0000000..75611d4
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/Helpers/StringFormatter/SearchStringFormatter.cs
@@ -0,0 +1,27 @@
+using static FieldSearch.Core.Base.BaseSearch;
+
+namespace FieldSearch.Helpers.StringFormatter
+{
+ ///
+ /// Helper formatter class for strings.
+ /// Used in
+ ///
+ public class SearchStringFormatter
+ {
+ public static string GetFinalString(string str, bool ignoreCase = false)
+ {
+ return ignoreCase ? str.ToLower() : str;
+ }
+
+ public static string GetFinalString(string str, SearchFilter searchFilter = default)
+ {
+ var ignoreCase = false;
+ if (searchFilter != default)
+ {
+ ignoreCase = searchFilter.HasFlag(SearchFilter.IgnoreCase); ;
+ }
+
+ return ignoreCase ? str.ToLower() : str;
+ }
+ }
+}
diff --git a/FieldSearch/Assets/FieldSearch/Core/Helpers/StringFormatter/SearchStringFormatter.cs.meta b/FieldSearch/Assets/FieldSearch/Core/Helpers/StringFormatter/SearchStringFormatter.cs.meta
new file mode 100644
index 0000000..541ab3d
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/Helpers/StringFormatter/SearchStringFormatter.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4ca60406e350f604eb30b354c59c94a2
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Core/Inspectors.meta b/FieldSearch/Assets/FieldSearch/Core/Inspectors.meta
new file mode 100644
index 0000000..aba9e1a
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/Inspectors.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 53a418dff2d6e284b9deef9a6ac040b7
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Core/Inspectors/BaseSearchLayerInspector.cs b/FieldSearch/Assets/FieldSearch/Core/Inspectors/BaseSearchLayerInspector.cs
new file mode 100644
index 0000000..bf40d3f
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/Inspectors/BaseSearchLayerInspector.cs
@@ -0,0 +1,10 @@
+namespace FieldSearch.Core.Inspectors.Base
+{
+ ///
+ /// Base SearchLayerInspector class
+ ///
+ public abstract class BaseSearchLayerInspector : UnityEditor.Editor
+ {
+
+ }
+}
diff --git a/FieldSearch/Assets/FieldSearch/Core/Inspectors/BaseSearchLayerInspector.cs.meta b/FieldSearch/Assets/FieldSearch/Core/Inspectors/BaseSearchLayerInspector.cs.meta
new file mode 100644
index 0000000..d47d9ca
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/Inspectors/BaseSearchLayerInspector.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 410c04ddccd304241b7a808f164d6301
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Core/Inspectors/Controllers.meta b/FieldSearch/Assets/FieldSearch/Core/Inspectors/Controllers.meta
new file mode 100644
index 0000000..642dd0c
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/Inspectors/Controllers.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 651d2e8fc22499e418a9735da264db05
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Core/Inspectors/Controllers/SearchInspectorService.cs b/FieldSearch/Assets/FieldSearch/Core/Inspectors/Controllers/SearchInspectorService.cs
new file mode 100644
index 0000000..f1803c2
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/Inspectors/Controllers/SearchInspectorService.cs
@@ -0,0 +1,298 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using UnityEditor;
+using UnityEngine;
+using static FieldSearch.Core.Base.BaseSearch;
+
+namespace FieldSearch.Core.Inspectors.Controllers
+{
+ ///
+ /// Default Search Service for Inspectors.
+ /// Using
+ ///
+ public class SearchInspectorService
+ {
+ public SearchInspectorService(SerializedObject serializedObject)
+ {
+ searchFilters =
+ SearchFilter.IgnoreCase |
+ SearchFilter.ByFieldName |
+ SearchFilter.ByObjName;
+
+ search = new SearchWithFilters(searchFilters);
+ this.serializedObject = serializedObject;
+ }
+
+ public SerializedObject SerializedObject
+ {
+ get => serializedObject;
+ set => serializedObject = value;
+ }
+
+ ///
+ /// Search status is inactive
+ ///
+ public bool IsNullOrNone => string.IsNullOrEmpty(searchText) || searchFilters.Equals(SearchFilter.None);
+
+ ///
+ /// Current target object
+ ///
+ private object TargetObject => serializedObject?.targetObject;
+
+ private SearchWithFilters search;
+ private SerializedObject serializedObject;
+ readonly string searchLabel = "Field Search:";
+
+ private string searchText;
+ private SearchFilter searchFilters;
+
+ ///
+ /// Get current search data
+ /// with &
+ ///
+ ///
+ public (string searchText, int flags) GetData()
+ {
+ return (searchText, (int)searchFilters);
+ }
+
+ ///
+ /// Update current search data
+ ///
+ ///
+ ///
+ public void UpdateData(string searchText, SearchFilter searchFilters)
+ {
+ if (!string.IsNullOrEmpty(searchText))
+ {
+ this.searchText = searchText;
+ }
+
+ this.searchFilters = searchFilters;
+ search.UpdateCriteria(this.searchFilters);
+
+ serializedObject?.ApplyModifiedProperties();
+ }
+
+ ///
+ /// Try show full inspector search layer
+ ///
+ ///
+ public bool ShowInspectorLayer()
+ {
+ if (!ShowSearchTextArea())
+ {
+ return false;
+ }
+
+ return ShowSearchObjectsLayer();
+ }
+
+ ///
+ /// Try show only search layer
+ ///
+ ///
+ public bool ShowSearchTextArea()
+ {
+ try
+ {
+ if (SerializedObject == null)
+ {
+ return false;
+ }
+
+ EditorGUILayout.BeginVertical(EditorStyles.helpBox);
+
+ if (!ShowSearchFields())
+ {
+ EndVertical();
+ return false;
+ }
+
+ EndVertical();
+ return true;
+ }
+ catch (Exception e)
+ {
+ Debug.LogError($"Fail with SearchArea: {e}");
+ return false;
+ }
+ }
+
+ ///
+ /// Try show only search result layer
+ ///
+ ///
+ public bool ShowSearchObjectsLayer()
+ {
+ if (IsNullOrNone)
+ {
+ return false;
+ }
+
+ var rawProperties = GetFieldInfoRecursive(TargetObject.GetType())
+ .Where(x => x.GetCustomAttributes(typeof(SerializeField), false) != null)
+ .Select(x => serializedObject.FindProperty(x.Name))
+ .Where(x => x != null);
+
+ var properties = new List();
+ foreach (var prop in rawProperties)
+ {
+ if (prop.isArray)
+ {
+ var childProps = GetSerializedPropertyRecursive(prop,
+ x => search.GetResult(searchFilters, true, searchText, x));
+
+ properties.AddRange(childProps);
+ continue;
+ }
+
+ if (!prop.isArray && search.GetResult(searchFilters, true, searchText, prop))
+ {
+ properties.Add(prop);
+ continue;
+ }
+ }
+
+ if (properties == null || !properties.Any())
+ {
+ return false;
+ }
+
+ EditorGUILayout.BeginVertical(EditorStyles.helpBox);
+ EditorGUILayout.Space();
+
+ foreach (var prop in properties)
+ {
+ EditorGUILayout.PropertyField(prop, true);
+ }
+
+ EndVertical();
+ return true;
+ }
+
+ ///
+ /// Get all based on
+ /// with inherited objs
+ ///
+ ///
+ ///
+ ///
+ private List GetSerializedPropertyRecursive(SerializedProperty property,
+ Func validateFunc)
+ {
+ var result = new List();
+
+ if (validateFunc(property))
+ {
+ result.Add(property);
+ return result;
+ }
+
+ for (int i = 0; i < property.arraySize; i++)
+ {
+ var prop = property.GetArrayElementAtIndex(i);
+
+ if (prop.isArray)
+ {
+ var arrayProps = GetSerializedPropertyRecursive(prop, validateFunc);
+ if (arrayProps.Count != 0)
+ {
+ result.Add(prop);
+ }
+ continue;
+ }
+ else
+ {
+ if (validateFunc(prop))
+ {
+ result.Add(prop);
+ }
+ continue;
+ }
+ }
+
+ return result;
+ }
+
+ ///
+ /// Get all for
+ /// with inherited objs
+ ///
+ ///
+ ///
+ ///
+ private List GetFieldInfoRecursive(Type type)
+ {
+ var result =
+ type
+ .GetFields(
+ BindingFlags.NonPublic
+ | BindingFlags.Public
+ | BindingFlags.Instance)
+
+ .ToList();
+
+ if(type.BaseType != null)
+ {
+ result.AddRange(GetFieldInfoRecursive(type.BaseType));
+ }
+
+ return result;
+ }
+
+ ///
+ /// Just show search layer
+ ///
+ ///
+ private bool ShowSearchFields()
+ {
+ var searchTextChanged =
+ ActionWithChangeCheck(() => searchText = EditorGUILayout.TextField(searchLabel, searchText));
+ var searchFiltersChanged =
+ ActionWithChangeCheck(() => searchFilters = (SearchFilter)EditorGUILayout.EnumFlagsField(searchFilters));
+
+ if (searchFiltersChanged)
+ {
+ serializedObject?.ApplyModifiedProperties();
+ search.UpdateCriteria(searchFilters);
+ }
+
+ if (searchTextChanged || string.IsNullOrEmpty(searchText))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Method to call GUI action that returns state of change
+ ///
+ ///
+ ///
+ private bool ActionWithChangeCheck(Action action)
+ {
+ EditorGUI.BeginChangeCheck();
+ action.Invoke();
+ if (EditorGUI.EndChangeCheck())
+ {
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ /// Default call with extra actions
+ ///
+ ///
+ private bool EndVertical()
+ {
+ serializedObject?.ApplyModifiedProperties();
+ EditorGUILayout.EndVertical();
+ return false;
+ }
+ }
+}
diff --git a/FieldSearch/Assets/FieldSearch/Core/Inspectors/Controllers/SearchInspectorService.cs.meta b/FieldSearch/Assets/FieldSearch/Core/Inspectors/Controllers/SearchInspectorService.cs.meta
new file mode 100644
index 0000000..1198dce
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/Inspectors/Controllers/SearchInspectorService.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 5524f0a239ac6a34bb8dedae898064bd
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/FieldSearch/Assets/FieldSearch/Core/Inspectors/DefaultSearchLayerInspector.cs b/FieldSearch/Assets/FieldSearch/Core/Inspectors/DefaultSearchLayerInspector.cs
new file mode 100644
index 0000000..2b6c2b0
--- /dev/null
+++ b/FieldSearch/Assets/FieldSearch/Core/Inspectors/DefaultSearchLayerInspector.cs
@@ -0,0 +1,62 @@
+using FieldSearch.Core.Inspectors.Base;
+using FieldSearch.Core.Inspectors.Controllers;
+using FieldSearch.Helpers.Cache;
+using FieldSearch.Helpers.Cache.Data;
+using System;
+using UnityEditor;
+using UnityEngine;
+using static FieldSearch.Core.Base.BaseSearch;
+using Object = UnityEngine.Object;
+
+namespace FieldSearch.Core.Inspectors
+{
+ ///
+ /// Default implementation
+ ///
+ public class DefaultSearchLayerInspector : BaseSearchLayerInspector
+ {
+ ///
+ /// Func to get Id of current target Object
+ ///
+ protected Func