Skip to content

Instantly share code, notes, and snippets.

@amatiasq
Last active January 12, 2023 15:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save amatiasq/356644b8ca76e55ca7568810380fe857 to your computer and use it in GitHub Desktop.
Save amatiasq/356644b8ca76e55ca7568810380fe857 to your computer and use it in GitHub Desktop.
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