Last active
January 12, 2023 15:11
-
-
Save amatiasq/356644b8ca76e55ca7568810380fe857 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Example : MonoBehaviour { | |
// Assets only | |
[AssetsOnly] | |
public GameObject SomePrefab; | |
[AssetsOnly] | |
public List<GameObject> OnlyPrefabs; | |
// SceneObjectsOnly | |
[SceneObjectsOnly] | |
public GameObject SomeSceneObject; | |
[SceneObjectsOnly] | |
public List<GameObject> OnlySceneObjects; | |
// CustomValueDrawer | |
[CustomValueDrawer("MyCustomDrawerStatic")] | |
public float CustomDrawerStatic; | |
private static float MyCustomDrawerStatic(float value, GUIContent label) | |
=> EditorGUILayout.Slider(label, value, 0f, 10f); | |
// Delayed / DelayedProperty | |
// Debounces the calls to `OnValueChanged()` | |
[OnValueChanged("OnValueChanged"), Delayed] | |
public int DelayedField; | |
[ShowInInspector] | |
[OnValueChanged("OnValueChanged"), DelayedProperty] | |
public string DelayedProperty { get; set; } | |
private void OnValueChanged() => Debug.Log("Value changed!"); | |
// EnableGUI | |
// Forces disabled properties to be enabled | |
[ShowInInspector, EnableGUI] | |
public int GUIEnabledProperty => 10; | |
// GUIColor | |
[GUIColor(0.3f, 0.8f, 0.8f, 1f)] | |
public int ColoredInt1; | |
[Button(ButtonSizes.Large)] | |
[GUIColor("GetButtonColor")] | |
private void Apply() { } | |
private static Color GetButtonColor() | |
{ | |
Sirenix.Utilities.Editor.GUIHelper.RequestRepaint(); | |
var time = (float)UnityEditor.EditorApplication.timeSinceStartup | |
return Color.HSVToRGB(Mathf.Cos(time + 1f) * 0.225f + 0.325f, 1, 1); | |
} | |
// HideLabel | |
[HideLabel] | |
[Title("Latex")] | |
public string Latex; | |
// PropertyOrder | |
[PropertyOrder(1)] | |
public int Second; | |
[PropertyOrder(-1)] | |
public int First; | |
// Space / PropertySpace | |
[Space] | |
public int Space; | |
[ShowInInspector, PropertySpace] | |
public string Property { get; set; } | |
[PropertySpace(SpaceBefore = 0, SpaceAfter = 60), PropertyOrder(2)] | |
public int BeforeAndAfter; | |
[ReadOnly] public string MyString = "This is displayed as text"; | |
// Searchable | |
// Check the docs, this is huge | |
[Searchable] | |
public List<Perk> Perks; | |
// ShowInInspector | |
// this does not serialize the field / property | |
[ShowInInspector] | |
private int myPrivateInt; | |
[ShowInInspector] | |
public int MyPropertyInt { get; set; } | |
[ShowInInspector] | |
public int ReadOnlyProperty => this.myPrivateInt; | |
[ShowInInspector] | |
public static bool StaticProperty { get; set; } | |
// Title | |
public string MyTitle = "My Dynamic Title"; | |
public string MySubtitle => MyTitle.Replace("Title", "Subtitle") | |
[Title("Static title")] | |
public int A; | |
[Title("$MyTitle", "$MySubtitle", | |
horizontalLine: false, bold: false, | |
titleAlignment: TitleAlignments.Centered | |
)] | |
public int B; | |
[Title("@DateTime.Now.ToString(\"dd:MM:yyyy\")", "@DateTime.Now.ToString(\"HH:mm:ss\")")] | |
public int C; | |
// TypeFilter | |
[TypeFilter("GetFilteredTypeList")] | |
public BaseClass A; | |
[TypeFilter("GetFilteredTypeList")] | |
public BaseClass[] Array = new BaseClass[3]; | |
public IEnumerable<Type> GetFilteredTypeList() | |
{ | |
var q = typeof(BaseClass).Assembly.GetTypes() | |
// Exclude BaseClass | |
.Where(x => !x.IsAbstract) | |
// Excludes C1<> | |
.Where(x => !x.IsGenericTypeDefinition) | |
// Excludes classes not inheriting from BaseClass | |
.Where(x => typeof(BaseClass).IsAssignableFrom(x)); | |
// Adds various C1<T> type variants. | |
q = q.AppendWith(typeof(C1<>).MakeGenericType(typeof(AnimationCurve))); | |
q = q.AppendWith(typeof(C1<>).MakeGenericType(typeof(List<float>))); | |
return q; | |
} | |
public abstract class BaseClass {} | |
public class A1 : BaseClass { public int a1; } | |
public class A2 : A1 { public int a2; } | |
public class B1 : BaseClass { public int b1; } | |
public class B2 : B1 { public int b2; } | |
public class B3 : B2 { public int b3; } | |
public class C1<T> : BaseClass { public T c; } | |
// TypeInfoBox | |
public MyType MyObject = new MyType(); | |
[Serializable] | |
[TypeInfoBox("The TypeInfoBox attribute can be put on type definitions and will result in an InfoBox being drawn at the top of a property.")] | |
public class MyType { public int Value; } | |
// ValueDropdown | |
[ValueDropdown("TextureSizes")] | |
public int SomeSize1; | |
private static int[] TextureSizes = new int[] { 256, 512, 1024 }; | |
[ValueDropdown("FriendlyTextureSizes", ExpandAllMenuItems = true | |
AppendNextDrawer = true, DisableGUIInAppendedDrawer = true)] | |
public int SomeSize2; | |
private static IEnumerable FriendlyTextureSizes = new ValueDropdownList<int>() | |
{ | |
{ "Small / Very Small", 128 }, | |
{ "Small", 256 }, | |
{ "Medium", 512 }, | |
{ "Large", 1024 }, | |
}; | |
[ValueDropdown("GetListOfMonoBehaviours", | |
IsUniqueList = true, DropdownTitle = "Select Scene Object", | |
DrawDropdownForListElements = false, ExcludeExistingValuesInList = true)] | |
public List<GameObject> UniqueGameobjectList; | |
private IEnumerable<MonoBehaviour> GetListOfMonoBehaviours() => return GameObject.FindObjectsOfType<MonoBehaviour>(); | |
/*********** | |
* BUTTONS * | |
***********/ | |
// Button | |
private bool toggle = false; | |
[Button("Name of button")] | |
private void NamedButton() { } | |
[Button("$ButtonName")] | |
private void DefaultSizedButton() { } | |
[Button(90)] | |
private void CustomSizedButton() { } | |
[DisableIf("toggle")] | |
[HorizontalGroup("Split", 0.5f)] | |
[Button(ButtonSizes.Large), GUIColor(0.4f, 0.8f, 1)] | |
private void FanzyButton1() { } | |
[HideIf("toggle")] | |
[VerticalGroup("Split/right")] | |
[Button(ButtonSizes.Large), GUIColor(0, 1, 0)] | |
private void FanzyButton2() { } | |
[ShowIf("toggle")] | |
[VerticalGroup("Split/right")] | |
[Button(ButtonSizes.Large), GUIColor(1, 0.2f, 0)] | |
private void FanzyButton3() { } | |
[Button(Icon = SdfIconType.Dice1Fill, IconAlignment = IconAlignment.LeftOfText)] | |
private void IconButton() { } | |
// ButtonGroup | |
public IconButtonGroupExamples iconButtonGroupExamples; | |
[ButtonGroup] | |
private void A() { } | |
[ButtonGroup] | |
private void B() { } | |
[Button(ButtonSizes.Large)] | |
[ButtonGroup("My Button Group")] | |
private void C() { } | |
[GUIColor(0, 1, 0)] | |
[ButtonGroup("My Button Group")] | |
private void D() { } | |
[Serializable, HideLabel] | |
public struct IconButtonGroupExamples | |
{ | |
[ButtonGroup(ButtonHeight = 25), Button(SdfIconType.ArrowsMove, "")] | |
void ArrowsMove() { } | |
[ButtonGroup, Button(SdfIconType.Crop, "")] | |
void Crop() { } | |
} | |
// ResponsiveButonGroup | |
[ResponsiveButtonGroup] public void Foo() { } | |
[ResponsiveButtonGroup] public void Bar() { } | |
[ResponsiveButtonGroup] public void Baz() { } | |
// EnumPaging | |
// Dropdown with navigation arrorws | |
[EnumPaging] | |
public SomeEnum SomeEnumField; | |
public enum SomeEnum { A, B, C } | |
// EnumToggleButtons | |
// Enums as button group, supports [Flags] | |
[EnumToggleButtons] | |
public SomeEnum SomeEnumField; | |
[EnumToggleButtons] | |
public SomeBitmaskEnum BitmaskEnumField; | |
public enum SomeEnum { First, Second, Third } | |
[System.Flags] | |
public enum SomeBitmaskEnum { A = 1 << 1, B = 1 << 2, C = 1 << 3, All = A | B | C } | |
// InlineButton | |
// Place a button next to the property drawer | |
[InlineButton("A")] | |
[InlineButton("B", SdfIconType.Dice6Fill, "Custom Button Name")] | |
public int ChainedButtons; | |
private void A() { } | |
private void B() { } | |
/*************** | |
* COLLECTIONS * | |
***************/ | |
// DictionaryDrawerSettings | |
class DictionaryExamples : SerializedMonoBehaviour { | |
public Dictionary<int, Material> IntMaterialLookup; | |
[DictionaryDrawerSettings( | |
DisplayMode = DictionaryDisplayOptions.ExpandedFoldout, | |
KeyLabel = "Custom Key Label", ValueLabel = "Custom Value Label")] | |
public Dictionary<SomeEnum, List<int>> StringStringDictionary; | |
public enum SomeEnum { First, Second, Third, Fourth, AndSoOn } | |
} | |
// ListDrawerSettings | |
// Range applies to all float entries | |
[Range(0, 1)] | |
public List<float> FloatList; | |
[ReadOnly] | |
public int[] ReadOnlyArray2 = new int[] { 1, 2, 3 }; | |
// | |
[ListDrawerSettings(ShowIndexLabels = true, ListElementLabelName = "SomeString", NumberOfItemsPerPage = 5)] | |
public SomeStruct[] IndexLabels; | |
// | |
[ListDrawerSettings(DraggableItems = false, Expanded = false, ShowIndexLabels = true, ShowPaging = false, | |
ShowItemCount = false, HideRemoveButton = true)] | |
public int[] MoreListSettings = new int[] { 1, 2, 3 }; | |
// | |
[ListDrawerSettings(OnBeginListElementGUI = "BeginDrawListElement", OnEndListElementGUI = "EndDrawListElement")] | |
public SomeStruct[] InjectListElementGUI; | |
private void BeginDrawListElement(int index) | |
=> SirenixEditorGUI.BeginBox(this.InjectListElementGUI[index].SomeString); | |
private void EndDrawListElement(int index) | |
=> SirenixEditorGUI.EndBox(); | |
// | |
[ListDrawerSettings(CustomAddFunction = "CustomAddFunction")] | |
public List<int> CustomAddBehaviour; | |
private int CustomAddFunction() => CustomAddBehaviour.Count; | |
[ListDrawerSettings(OnTitleBarGUI = "DrawRefreshButton")] | |
public List<int> CustomButtons; | |
private void DrawRefreshButton() | |
{ | |
if (SirenixEditorGUI.ToolbarButton(EditorIcons.Refresh)) | |
Debug.Log(this.CustomButtons.Count.ToString()); | |
} | |
// TableColumWidth | |
[TableList] | |
public List<MyItem> List = new List<MyItem>(); | |
[Serializable] | |
public class MyItem | |
{ | |
[TableColumnWidth(30, Resizable = false)] | |
public Texture2D Icon; | |
[TableColumnWidth(60)] | |
public int ID; | |
public string Name; | |
} | |
// TableList | |
[TableList(ShowIndexLabels = true, ShowPaging = true, AlwaysExpanded = true)] | |
public List<MyClass> TableListWithIndexLabels = new List<MyClass>(); | |
[TableList(DrawScrollView = true, MaxScrollViewHeight = 200, MinScrollViewHeight = 100)] | |
public List<MyClass> MinMaxScrollViewTable = new List<MyClass>(); | |
// TableMatrix | |
[TableMatrix(HorizontalTitle = "X axis", VerticalTitle = "Y axis")] | |
public int[,] ReadOnlyMatrix = new int[5, 5]; | |
[TableMatrix(HorizontalTitle = "Square Celled Matrix", SquareCells = true)] | |
public Texture2D[,] SquareCelledMatrix = new Texture2D[2,2]; | |
// | |
[TableMatrix(HorizontalTitle = "Custom Cell Drawing", DrawElementMethod = "DrawCell", | |
ResizableColumns = false, RowHeight = 16)] | |
public bool[,] CustomCellDrawing; | |
[ShowInInspector, DoNotDrawAsReference] | |
[TableMatrix(HorizontalTitle = "Transposed Custom Cell Drawing", DrawElementMethod = "DrawCell", | |
ResizableColumns = false, RowHeight = 16, Transpose = true)] | |
public bool[,] Transposed { get => CustomCellDrawing; set => CustomCellDrawing = value; } | |
private static bool DrawCell(Rect rect, bool value) | |
{ | |
if (Event.current.type == EventType.MouseDown && rect.Contains(Event.current.mousePosition)) | |
{ | |
value = !value; | |
GUI.changed = true; | |
Event.current.Use(); | |
} | |
var color = value ? new Color(0.1f, 0.8f, 0.2f) : new Color(0, 0, 0, 0.5f); | |
UnityEditor.EditorGUI.DrawRect(rect.Padding(1), color); | |
return value; | |
} | |
/**************** | |
* CONDITIONALS * | |
****************/ | |
// EnableIf | |
[EnableIf("IsToggled")] | |
public int EnableIfToggled; | |
public bool IsToggled; | |
[EnableIf("SomeEnum", InfoMessageType.Info)] | |
public Vector2 Info; | |
public InfoMessageType SomeEnum = InfoMessageType.Info; | |
[EnableIf("SomeObject")] | |
public Vector3 EnabledWhenHasReference; | |
public UnityEngine.Object SomeObject; | |
[EnableIf("@this.IsToggled && this.SomeObject != null || this.SomeEnum == InfoMessageType.Error")] | |
public int EnableWithExpression; | |
// DisableIf | |
// Same usage as EnableIf | |
[DisableIf("@true")] | |
public int DisableIfToggled; | |
// EnableIn | |
[EnableIn(PrefabKind.PrefabAsset)] | |
public string PrefabAsset = "Prefab assets and prefab variant assets"; | |
// DisableIn | |
[DisableIn(PrefabKind.PrefabAsset)] | |
public string PrefabAsset = "Prefab assets and prefab variant assets"; | |
// DisableInEditorMode | |
// Only editable in play mode | |
[DisableInEditorMode] | |
public GameObject A; | |
// HideInEditorMode | |
// Only visible in play mode | |
[HideInEditorMode] | |
public int C; | |
// ShowInInlineEditors | |
[InlineEditor(Expanded = true)] | |
public MyClass InlineObject; | |
[Serializable] class MyClass { | |
[ShowInInlineEditors] public int A; | |
} | |
// DisableInInlineEditors | |
[InlineEditor(Expanded = true)] | |
public MyClass InlineObject; | |
[Serializable] class MyClass { | |
[DisableInInlineEditors] public int A; | |
} | |
[DisableInPlayMode] public int A; | |
[HideInPlayMode] public int A; | |
// ShowIf | |
// Same usage as EnableIf | |
[ShowIf("@false")] | |
public int A; | |
// HideIf | |
// Same usage as EnableIf | |
[HideIf("@true")] | |
public int A; | |
// ShowIfGroup | |
// Or more aproppiately "ShowGroupIf" | |
// Same usage as EnableIf | |
[ShowIfGroup("Toggle")] | |
[BoxGroup("Toggle/Shown Box")] | |
public int A, B; | |
// HideIfGroup | |
// Or more aproppiately "HideGroupIf" | |
// Same usage as EnableIf | |
[HideIfGroup("@true")] | |
[BoxGroup("Toggle/Shown Box")] | |
public int A, B; | |
// ShowIn | |
[ShowIn(PrefabKind.PrefabAsset)] | |
public string PrefabAsset = "Prefab assets and prefab variant assets"; | |
// HideIn | |
[HideIn(PrefabKind.PrefabAsset)] | |
public string PrefabAsset = "Prefab assets and prefab variant assets"; | |
// Toggle | |
[Toggle("Enabled")] | |
public MyToggleable Toggler = new MyToggleable(); | |
public ToggleableClass Toggleable = new ToggleableClass(); | |
// You can also use the Toggle attribute directly on a class definition. | |
[Serializable, Toggle("Enabled")] | |
public class MyToggleable | |
{ | |
public bool Enabled; | |
public int MyValue; | |
} | |
// ToggleLeft | |
// Draws the checkbox before the label | |
[ToggleLeft] | |
public bool LeftToggled; | |
/********** | |
* GROUPS * | |
**********/ | |
// BoxGroup | |
[BoxGroup] | |
public string A; | |
[BoxGroup("Centered Title", centerLabel: true)] | |
public string B; | |
[BoxGroup("Centered Title"] | |
public string C; | |
// A named box group without a title. | |
[BoxGroup("NoTitle", false)] | |
public string D; | |
[BoxGroup("NoTitle")] | |
public string E; | |
// FoldoutGroup | |
[FoldoutGroup("Group 1")] | |
public int A; | |
[FoldoutGroup("Group 1")] | |
public int B; | |
[FoldoutGroup("Expanded group", expanded: true)] | |
public int C; | |
[FoldoutGroup("Expanded group")] | |
public int D; | |
// HorizontalGroup | |
[HorizontalGroup] | |
public int A; | |
[HideLabel, LabelWidth(150)] | |
[HorizontalGroup(150)] | |
public LayerMask B; | |
// LabelWidth can be helpfull when dealing with HorizontalGroups. | |
[HorizontalGroup("Group 1", LabelWidth = 20)] | |
public int C; | |
[HorizontalGroup("Group 1")] | |
public int D; | |
// Having multiple properties in a column can be achived using multiple groups | |
[HorizontalGroup("Split", 0.5f, LabelWidth = 20)] | |
[BoxGroup("Split/Left")] public int E; | |
[BoxGroup("Split/Right")] public int F; | |
[BoxGroup("Split/Left")] public int G; | |
[BoxGroup("Split/Right")] public int H; | |
// Horizontal Group also has supprot for: | |
// Title, MarginLeft, MarginRight, PaddingLeft, PaddingRight, MinWidth and MaxWidth. | |
[HorizontalGroup("MyButton", MarginLeft = 0.25f, MarginRight = 0.25f)] | |
public void SomeButton() {} | |
// TabGroup | |
[TabGroup("Tab A")] public int One; | |
[TabGroup("Tab A")] public int Two; | |
[TabGroup("Tab B")] public string MyString; | |
[HideLabel] | |
[TabGroup("Tab C")] public MyTabObject TabC; | |
[Serializable] | |
public class MyTabObject { public int A, B, C; } | |
// TitleGroup | |
[TitleGroup("Ints")] | |
public int SomeInt1; | |
[TitleGroup("$SomeString1", "Optional subtitle")] | |
public string SomeString1; | |
[TitleGroup("Vectors", "Optional subtitle", | |
alignment: TitleAlignments.Centered, horizontalLine: true, boldTitle: true, indent: false)] | |
public Vector2 SomeVector1; | |
// ToggleGroup | |
// Simple Toggle Group | |
[ToggleGroup("MyToggle", "$MyGroupTitle")] | |
public bool MyToggle; | |
[ToggleGroup("MyToggle")] | |
public float MyGroupTitle; | |
// Toggle for individual objects. | |
[Toggle("Enabled")] | |
public MyToggleObject Three = new MyToggleObject(); | |
[Serializable] | |
public class MyToggleObject | |
{ | |
public bool Enabled; | |
public int A; | |
} | |
// Toggle items individually | |
public MyToggleItem[] ToggleList = new MyToggleItem[]; | |
[Serializable] | |
public class MyToggleItem | |
{ | |
[ToggleGroup("Enabled", "@A.ToString()")] | |
public bool Enabled; | |
public int A; | |
} | |
// VerticalGroup | |
[HorizontalGroup("Split")] | |
[VerticalGroup("Split/Left")] public InfoMessageType First; | |
[VerticalGroup("Split/Left")] public InfoMessageType Second; | |
[HideLabel] [VerticalGroup("Split/Right")] public int A; | |
[HideLabel] [VerticalGroup("Split/Right")] public int B; | |
/*********** | |
* NUMBERS * | |
***********/ | |
// MinValue | |
[MinValue(0)] public int IntMinValue0; | |
[MinValue(0)] public Vector3 Vector3MinValue0; | |
// MaxValue | |
[MaxValue(0)] public int IntMaxValue0; | |
[MaxValue(0)] public Vector3 Vector3MaxValue0; | |
// MinMaxSlider | |
[MinMaxSlider(-10, 10)] | |
public Vector2 MinMaxValueSlider = new Vector2(-7, -2); | |
[MinMaxSlider(-10, 10, true)] | |
public Vector2 WithFields = new Vector2(-3, 4); | |
[MinMaxSlider("DynamicRange", true)] | |
public Vector2 DynamicMinMax = new Vector2(25, 50); | |
public Vector2 DynamicRange = new Vector2(0, 50); | |
[MinMaxSlider("@DynamicRange.x", "@DynamicRange.y * 10f", true)] | |
public Vector2 Expressive = new Vector2(0, 450); | |
// ProgressBar | |
[ProgressBar(0, 100)] | |
public int ProgressBar = 50; | |
[HideLabel, ProgressBar(-100, 100, r: 1, g: 1, b: 1, Height = 30)] | |
public short BigColoredProgressBar = 50; | |
[ProgressBar(0, 10, 0, 1, 0, Segmented = true)] | |
public int SegmentedColoredBar = 5; | |
[ProgressBar(0, 100, ColorGetter = "GetHealthBarColor")] | |
public float DynamicHealthBarColor = 50; | |
private Color GetHealthBarColor(float value) => Color.Lerp(Color.red, Color.green, Mathf.Pow(value / 100f, 2)); | |
[ProgressBar("Min", "Max")] | |
public float DynamicProgressBar = 50; | |
public float Min; | |
public float Max = 100; | |
// | |
[HideLabel, ShowInInspector] | |
[ProgressBar(0, 100, ColorGetter = "GetStackedHealthColor", BackgroundColorGetter = "GetStackHealthBackgroundColor", DrawValueLabel = false)] | |
[BoxGroup("Stacked Health")] | |
private float StackedHealthProgressBar => this.StackedHealth % 100.01f; | |
private Color GetStackedHealthColor() => | |
StackedHealth > 200 ? Color.white : | |
StackedHealth > 100 ? Color.green : | |
Color.red; | |
private Color GetStackHealthBackgroundColor() => | |
StackedHealth > 200 ? Color.green : | |
StackedHealth > 100 ? Color.red : | |
new Color(0.16f, 0.16f, 0.16f, 1f); | |
// Range / PropertyRange | |
[Range(0, 10)] | |
public int Field = 2; | |
[ShowInInspector, PropertyRange(0, 10)] | |
public int Property { get; set; } | |
// Wrap | |
[Wrap(0f, 360)] public float AngleWrap; | |
[Wrap(0f, Mathf.PI * 2)] public float RadianWrap; | |
/****************** | |
* TYPE SPECIFICS * | |
******************/ | |
// AssetList | |
[AssetList] | |
[PreviewField(70, ObjectFieldAlignment.Center)] | |
public Texture2D SingleObject; | |
[AssetList(Path = "Plugins/Sirenix/")] | |
public ScriptableObject SirenixAsset; | |
[AssetList(Path = "/Plugins/Sirenix/")] | |
public List<ScriptableObject> AssetList; | |
// | |
[AssetList(AutoPopulate = true, Path = "Plugins/Sirenix/")] | |
[FoldoutGroup("Filtered Odin ScriptableObjects", expanded: false)] | |
public List<ScriptableObject> AutoPopulatedWhenInspected; | |
// | |
[AssetList(LayerNames = "MyLayerName")] | |
public GameObject[] AllPrefabsWithLayerName; | |
[AssetList(AssetNamePrefix = "Rock")] | |
public List<GameObject> PrefabsStartingWithRock; | |
[AssetList(Tags = "MyTagA, MyTabB", Path = "/Plugins/Sirenix/")] | |
public List<GameObject> GameObjectsWithTag; | |
[AssetList(CustomFilterMethod = "HasRigidbodyComponent")] | |
public List<GameObject> MyRigidbodyPrefabs; | |
private bool HasRigidbodyComponent(GameObject obj) => obj.GetComponent<Rigidbody>() != null; | |
// AssetSelector | |
[AssetSelector] | |
public Material AnyAllMaterials; | |
[AssetSelector] | |
public Material[] ListOfAllMaterials; | |
[AssetSelector(FlattenTreeView = true)] | |
public PhysicMaterial NoTreeView; | |
[AssetSelector(Paths = "Assets/MyScriptableObjects")] | |
public ScriptableObject ScriptableObjectsFromFolder; | |
[AssetSelector(Paths = "Assets/MyScriptableObjects|Assets/Other/MyScriptableObjects")] | |
public Material ScriptableObjectsFromMultipleFolders; | |
[AssetSelector(Filter = "name t:type l:label")] | |
public UnityEngine.Object AssetDatabaseSearchFilters; | |
[AssetSelector(DrawDropdownForListElements = false)] | |
public List<GameObject> DisableListElementBehaviour; | |
[AssetSelector(ExcludeExistingValuesInList = false)] | |
public List<GameObject> ExcludeExistingValuesInList; | |
[AssetSelector(IsUniqueList = false)] | |
public List<GameObject> DisableUniqueListBehaviour; | |
[AssetSelector(ExpandAllMenuItems = true)] | |
public List<GameObject> ExpandAllMenuItems; | |
[AssetSelector(DropdownTitle = "Custom Dropdown Title")] | |
public List<GameObject> CustomDropdownTitle; | |
// ColorPalette | |
[ColorPalette] | |
public Color ColorOptions; | |
[ColorPalette("Underwater")] | |
public Color UnderwaterColor; | |
[ColorPalette("$DynamicPaletteName")] | |
public Color DynamicPaletteColor; | |
public string DynamicPaletteName = "Clovers"; | |
[ColorPalette("Fall"), HideLabel] | |
public Color WideColorPalette; | |
[ColorPalette("Clovers")] | |
public Color[] ColorArray; | |
// DisplayAsString | |
[DisplayAsString] | |
public Color SomeColor; | |
[DisplayAsString] | |
public string SomeText = "Lorem Ipsum"; | |
[DisplayAsString(false)] | |
public string DisplayAllOfIt = "A very very very very very very very very long string that has been configured to not wrap into lines."; | |
// HideInTables | |
public MyItem Item = new MyItem(); | |
[TableList] | |
public List<MyItem> Table = new List<MyItem>(); | |
[Serializable] public class MyItem { [HideInTables] public int Hidden; } | |
// HideMonoScript | |
// Removes the read-only "Script" field in inspector | |
[HideMonoScript] class MyComponent : MonoBehaviour {} | |
// HideNetworkBehaviourFields | |
[HideNetworkBehaviourFields] class MyComponent : NetworkBehaviour {} | |
// HideReferenceObjectPicker | |
[HideReferenceObjectPicker] | |
public MyCustomReferenceType OdinSerializedProperty1 = new MyCustomReferenceType(); | |
// Protip: You can also put the HideInInspector attribute on the class definition itself to hide it globally for all members. | |
// [HideReferenceObjectPicker] | |
public class MyCustomReferenceType { public int A; } | |
[InlineEditor] | |
public MyScriptable InlineComponent; | |
[InlineEditor(InlineEditorModes.FullEditor)] | |
public Material FullInlineEditor; | |
// You can also use the InlineEditor attribute directly on a class definition itself! | |
[InlineEditor] | |
public class MyScriptable : ScriptableObject { public Vector3 Position; } | |
// Multiline / MultilineProperty | |
[Multiline(10)] | |
public string UnityMultilineField = ""; | |
[MultiLineProperty(10)] | |
public string WideMultilineTextField = ""; | |
[ShowInInspector] | |
[MultiLineProperty(10)] | |
public string OdinMultilineProperty { get; set; } | |
// PreviewField | |
[PreviewField] | |
public Object RegularPreviewField; | |
[PreviewField(50, ObjectFieldAlignment.Right)] | |
public Object D; | |
/************** | |
* VALIDATION * | |
**************/ | |
[Required] public GameObject MyGameObject; | |
// RequiredIn | |
[RequiredIn(PrefabKind.PrefabAsset)] | |
public string PrefabAsset = "Prefab assets and prefab variant assets"; | |
[RequiredIn(PrefabKind.InstanceInScene, | |
ErrorMessage = "Error messages can be customized. Odin expressions is supported.")] | |
public string InstanceInScene = "Instances of prefabs in scenes"; | |
// AssetsOnly | |
[AssetsOnly] | |
public List<GameObject> OnlyPrefabs; | |
[AssetsOnly] | |
public GameObject SomePrefab; | |
// SceneObjectsOnly | |
[SceneObjectsOnly] | |
public List<GameObject> OnlySceneObjects; | |
[SceneObjectsOnly] | |
public GameObject SomeSceneObject; | |
// ChildGameObjectsOnly | |
[ChildGameObjectsOnly] | |
public Transform ChildOrSelfTransform; | |
[ChildGameObjectsOnly] | |
public GameObject ChildGameObject; | |
[ChildGameObjectsOnly(IncludeSelf = false)] | |
public Light[] Lights; | |
// FilePath | |
[FilePath] | |
public string UnityProjectPath; | |
// Using parent path, FilePath can also provide a path relative to a resources folder. | |
[FilePath(ParentFolder = "Assets/Resources")] | |
public string ResourcePath; | |
[FilePath(Extensions = "cs")] | |
public string ScriptFiles; | |
[FilePath(AbsolutePath = true, RequireExistingPath = true, UseBackslashes = true)] | |
public string ExistingPath; | |
[FilePath(ParentFolder = "Assets/Plugins/Sirenix/Demos/Odin Inspector")] | |
public string[] ListOfFiles; | |
// | |
[FilePath(ParentFolder = "$DynamicParent", Extensions = "$DynamicExtensions")] | |
public string DynamicFilePath; | |
public string DynamicParent = "Assets/Plugins/Sirenix"; | |
public string DynamicExtensions = "cs, unity, jpg"; | |
// FolderPath | |
[FolderPath] | |
public string UnityProjectPath; | |
[FolderPath(ParentFolder = "Assets/Resources")] | |
public string ResourcePath; | |
[FolderPath(AbsolutePath = true, RequireExistingPath = true, UseBackslashes = true)] | |
public string ExistingPath; | |
[FolderPath(ParentFolder = "Assets/Plugins/Sirenix")] | |
public string[] ListOfFolders; | |
[FolderPath(ParentFolder = "$DynamicParent")] | |
public string DynamicFolderPath; | |
public string DynamicParent = "Assets/Plugins/Sirenix"; | |
// ValidateInput | |
[ValidateInput("MustBeNull", "This field should be null.")] | |
public Transform DefaultMessage; | |
private bool MustBeNull(Transform scripty) => scripty == null; | |
[ValidateInput("AlwaysFalse", "$Message", InfoMessageType.Warning)] | |
public string Message = "Dynamic ValidateInput message"; | |
private bool AlwaysFalse(GameObject gameObject, ref string errorMessage, ref InfoMessageType? messageType) | |
{ | |
errorMessage = "\"" + gameObject.name + "\" should have a MeshRenderer component"; | |
messageType = this.MessageType; | |
return false; | |
} | |
/******** | |
* MISC * | |
********/ | |
// CustomContextMenu | |
[CustomContextMenu("Say Hello/Twice", "SayHello")] | |
public int MyProperty; | |
private void SayHello() => Debug.Log("Hello Twice"); | |
// DisableContextMenu | |
[DisableContextMenu] | |
public int NoRightClickField = 19; | |
[DisableContextMenu(disableForMember: false, disableCollectionElements: true)] | |
public int[] NoRightClickListOnListElements = new int[] { 7, 11 }; | |
// DrawWithUnity | |
// For when Odio gets in the way | |
[DrawWithUnity] | |
public GameObject ObjectDrawnWithUnity; | |
public GameObject ObjectDrawnWithOdin; | |
// HideDuplicateReferenceBox | |
// Prevents inspector recursion... I think | |
[HideDuplicateReferenceBox] | |
public ReferenceTypeClass withoutReferenceBox; | |
public class ReferenceTypeClass | |
{ | |
[HideDuplicateReferenceBox] | |
public ReferenceTypeClass recursiveReference; | |
} | |
// Indent | |
[Indent] | |
public int A; | |
[Indent(2)] | |
public int B; | |
[Indent(3)] | |
public int C; | |
[Indent(-1)] | |
public int D; | |
// InfoBox | |
[InfoBox("Default info box.")] | |
public int A; | |
[InfoBox("Warning info box.", InfoMessageType.Warning, "IsInEditMode")] | |
public int B; | |
private static bool IsInEditMode() => !Application.isPlaying; | |
[InfoBox("$InfoBoxMessage")] | |
[InfoBox("@\"Time: \" + DateTime.Now.ToString(\"HH:mm:ss\")")] | |
public string InfoBoxMessage = "My dynamic info box message"; | |
// DetailedInfoBox | |
[DetailedInfoBox("Click the DetailedInfoBox...", "... to reveal me.")] | |
public int Field; | |
// InlineProperty | |
// Displays the content of this file horizontally instead of foldout | |
[InlineProperty(LabelWidth = 13)] | |
public Vector2Int MyVector2Int; | |
// or add it to the class | |
[InlineProperty(LabelWidth = 13)] | |
[Serializable] | |
public struct Vector2Int | |
{ | |
[HorizontalGroup] public int X; | |
[HorizontalGroup] public int Y; | |
} | |
// LabelText | |
[LabelText("1")] | |
public int MyInt1 = 1; | |
[LabelText("$MyInt1", SdfIconType.HeartFill)] | |
public string LabelText = "The label is taken from the number 3 above"; | |
[LabelText("@DateTime.Now.ToString(\"HH:mm:ss\")")] | |
public string DateTimeLabel; | |
// LabelWidth | |
[LabelWidth(50)] | |
public int Thin; | |
/********** | |
* EVENTS * | |
**********/ | |
// OnCollectionChanged | |
[OnCollectionChanged("Before", "After")] | |
public List<string> list = new List<string>() { "str1", "str2", "str3" }; | |
public void Before(CollectionChangeInfo info, object value) {} | |
public void After(CollectionChangeInfo info, object value) {} | |
// OnInspectorGUI | |
[OnInspectorGUI] | |
private void OnInspectorGUI() {} | |
[OnInspectorGUI("DrawPreview", append: true)] | |
public Texture2D Texture; | |
private void DrawPreview() | |
{ | |
GUILayout.BeginVertical(GUI.skin.box); | |
GUILayout.Label(this.Texture); | |
GUILayout.EndVertical(); | |
} | |
// OnInspectorInit | |
// Runs code first time inspector is created | |
[OnInspectorInit("@TimeWhenExampleWasOpened = DateTime.Now.ToString()")] | |
public string TimeWhenExampleWasOpened; | |
// this OnInspectorInit attribute won't execute until the foldout is expanded. | |
[FoldoutGroup("Delayed Initialization", Expanded = false, HideWhenChildrenAreInvisible = false)] | |
[OnInspectorInit("@TimeFoldoutWasOpened = DateTime.Now.ToString()")] | |
public string TimeFoldoutWasOpened; | |
// OnInspectorDispose | |
// Dispose the un-selected value before it's changed | |
[OnInspectorDispose("@UnityEngine.Debug.Log(\"Dispose event invoked!\")")] | |
public MyClass A; | |
// OnStateUpdate | |
[OnStateUpdate("@#(list).State.Expanded = $value")] | |
public bool ExpandList; | |
public List<string> list; | |
// OnValueChanged | |
[OnValueChanged("CreateMaterial")] | |
public Shader Shader; | |
private void CreateMaterial() {} | |
// Tooltip / PropertyTooltip | |
[PropertyTooltip("This is tooltip on an int property.")] | |
public int MyInt; | |
[PropertyTooltip("$Tooltip")] | |
public string Tooltip = "Dynamic tooltip."; | |
[Button] | |
[PropertyTooltip("Button Tooltip")] | |
private void ButtonWithTooltip() {} | |
// SuffixLabel | |
[SuffixLabel("Prefab")] | |
public GameObject GameObject; | |
// Draw inside the input box | |
[SuffixLabel("radians", Overlay = true)] | |
public float Angle; | |
[SuffixLabel("@DateTime.Now.ToString(\"HH:mm:ss\")", SdfIconType.HeartFill, Overlay = true)] | |
public string Expression; | |
[SuffixLabel(SdfIconType.HeartFill, Overlay = true)] | |
public string OnlyIcon2; | |
// SuppressInvalidAttributeError | |
[SuppressInvalidAttributeError] | |
[Range(0, 10)] | |
public string SuppressedError = "The error has been suppressed on this field, and thus no error box will appear."; | |
/********* | |
* DEBUG * | |
*********/ | |
// ShowDrawerChain | |
[ShowDrawerChain] | |
[HideIf("ToggleHideIf")] | |
public GameObject SomeObject; | |
[Range(0, 10)] | |
[ShowDrawerChain] | |
public float SomeRange; | |
// ShowPropertyResolver | |
[ShowPropertyResolver] | |
public string MyString; | |
[ShowPropertyResolver] | |
public List<int> MyList; | |
[ShowPropertyResolver] | |
public Dictionary<int, Vector3> MyDictionary; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment