Add: English docs

This commit is contained in:
AnnulusGames 2024-02-20 14:49:47 +09:00
parent 5daec8d69e
commit 1da3074c9f
61 changed files with 1535 additions and 7 deletions

View File

@ -0,0 +1,9 @@
# Alchemy Overview
![header](../../images/header.png)
Alchemy is a library that provides a rich set of editor extensions for Unity. By integrating Alchemy, over 30 attributes are added to easily extend the Inspector. Additionally, by utilizing the Unity.Serialization package and a dedicated Source Generator, it becomes possible to serialize and edit types not normally serializable in Unity (`Dictionary`, `HashSet`, `Nullable`, `ValueTuple`, etc.) directly from the Inspector.
![img](../../images/img-v2.0.png)
Furthermore, version 2.0 introduces new features such as EditorWindow extensions and Hierarchy extensions. These enable the easy creation of tools to streamline the development workflow within the editor.

View File

@ -0,0 +1,53 @@
# AlchemyEditorWindow
By inheriting from `AlchemyEditorWindow` instead of `EditorWindow`, you can create editor windows using Alchemy attributes.
```cs
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
using Alchemy.Editor;
using Alchemy.Inspector;
public class EditorWindowExample : AlchemyEditorWindow
{
[MenuItem("Window/Example")]
static void Open()
{
var window = GetWindow<EditorWindowExample>("Example");
window.Show();
}
[Serializable]
[HorizontalGroup]
public class DatabaseItem
{
[LabelWidth(30f)]
public float foo;
[LabelWidth(30f)]
public Vector3 bar;
[LabelWidth(30f)]
public GameObject baz;
}
[ListViewSettings(ShowAlternatingRowBackgrounds = AlternatingRowBackground.All, ShowFoldoutHeader = false)]
public List<DatabaseItem> items;
[Button, HorizontalGroup]
public void Button1() { }
[Button, HorizontalGroup]
public void Button2() { }
[Button, HorizontalGroup]
public void Button3() { }
}
```
![img](../../images/img-editor-window.png)
Data from windows created by inheriting `AlchemyEditorWindow` is saved in JSON format in the ProjectSettings folder of the project. For more details, refer to the [Saving Editor Window Data](saving-editor-window-data.md) page.

View File

@ -0,0 +1,80 @@
# Alchemy Serialization Process
In Alchemy, by adding the `[AlchemySerialize]` attribute to the target type, a dedicated Source Generator automatically implements `ISerializationCallbackReceiver`. Within this process, all fields annotated with `[AlchemySerializeField]` are gathered, and using the Unity.Serialization package, they are converted to JSON format. However, fields of type `UnityEngine.Object` cannot be handled in JSON format, so their instances are saved in a single list, and only their indices are written to JSON.
For example, consider the following class:
```cs
using System;
using System.Collections.Generic;
using UnityEngine;
using Alchemy.Serialization;
[AlchemySerialize]
public partial class AlchemySerializationExample : MonoBehaviour
{
[AlchemySerializeField, NonSerialized]
public Dictionary<string, GameObject> dictionary = new();
}
```
Alchemy generates code similar to the following:
```cs
partial class AlchemySerializationExample : global::UnityEngine.ISerializationCallbackReceiver
{
[global::System.Serializable]
sealed class AlchemySerializationData
{
[global::System.Serializable]
public sealed class Item
{
[global::UnityEngine.HideInInspector] public bool isCreated;
[global::UnityEngine.TextArea] public string data;
}
public Item dictionary = new();
[global::UnityEngine.SerializeField] private global::System.Collections.Generic.List<UnityEngine.Object> unityObjectReferences = new();
public global::System.Collections.Generic.IList<UnityEngine.Object> UnityObjectReferences => unityObjectReferences;
}
[global::UnityEngine.HideInInspector, global::UnityEngine.SerializeField] private AlchemySerializationData alchemySerializationData = new();
void global::UnityEngine.ISerializationCallbackReceiver.OnBeforeSerialize()
{
if (this is global::Alchemy.Serialization.IAlchemySerializationCallbackReceiver receiver) receiver.OnBeforeSerialize();
alchemySerializationData.UnityObjectReferences.Clear();
try
{
alchemySerializationData.dictionary.data = global::Alchemy.Serialization.Internal.SerializationHelper.ToJson(this.dictionary , alchemySerializationData.UnityObjectReferences);
alchemySerializationData.dictionary.isCreated = true;
}
catch (global::System.Exception ex)
{
global::UnityEngine.Debug.LogException(ex);
}
}
void global::UnityEngine.ISerializationCallbackReceiver.OnAfterDeserialize()
{
try
{
if (alchemySerializationData.dictionary.isCreated)
{
this.dictionary = global::Alchemy.Serialization.Internal.SerializationHelper.FromJson<System.Collections.Generic.Dictionary<string, UnityEngine.GameObject>>(alchemySerializationData.dictionary.data, alchemySerializationData.UnityObjectReferences);
}
}
catch (global::System.Exception ex)
{
global::UnityEngine.Debug.LogException(ex);
}
if (this is global::Alchemy.Serialization.IAlchemySerializationCallbackReceiver receiver) receiver.OnAfterDeserialize();
}
}
```
Using `[AlchemySerializeField]` increases the processing load for serialization and deserialization. Therefore, it is recommended to avoid using `[AlchemySerializeField]` whenever possible.

View File

@ -0,0 +1,13 @@
# Assets Only Attribute
Limits the reference that can be entered into an object field to assets only.
![img](../../../images/img-attribute-assets-only.png)
```cs
[AssetsOnly]
public Object asset1;
[AssetsOnly]
public GameObject asset2;
```

View File

@ -0,0 +1,14 @@
# Blockquote Attribute
Displays a quotation in the Inspector.
![img](../../../images/img-attribute-blockquote.png)
```cs
[Blockquote("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.")]
public float foo;
```
| Parameter | Description |
| - | - |
| Text | The text to display in the quotation |

View File

@ -0,0 +1,29 @@
# Box Group Attribute
Creates a group that wraps multiple members in a box for display.
![img](../../../images/img-attribute-box-group.png)
```cs
[BoxGroup("Group1")]
public float foo;
[BoxGroup("Group1")]
public Vector3 bar;
[BoxGroup("Group1")]
public GameObject baz;
[BoxGroup("Group1/Group2")]
public float alpha;
[BoxGroup("Group1/Group2")]
public Vector3 beta;
[BoxGroup("Group1/Group2")]
public GameObject gamma;
```
| Parameter | Description |
| - | - |
| GroupPath | Specifies the path of the group. Groups can be nested by separating them with `/`. |

View File

@ -0,0 +1,30 @@
# Button Attribute
Displays a button in the Inspector that can execute a method. If the method has parameters, input fields for those parameters will be added.
![img](../../../images/img-attribute-button.png)
```cs
[Button]
public void Foo()
{
Debug.Log("Foo");
}
[Button]
public void Foo(int parameter)
{
Debug.Log("Foo: " + parameter);
}
[Button]
public void Foo(SampleClass parameter)
{
var builder = new StringBuilder();
builder.AppendLine();
builder.Append("foo = ").AppendLine(parameter.foo.ToString());
builder.Append("bar = ").AppendLine(parameter.bar.ToString());
builder.Append("baz = ").Append(parameter.baz == null ? "Null" : parameter.baz.ToString());
Debug.Log("Foo: " + builder.ToString());
}
```

View File

@ -0,0 +1,15 @@
# Disable Alchemy Editor Attribute
Disables the AlchemyEditor for the target class and uses the default Inspector for rendering. When this attribute is added to a field, only that field will be rendered using the default PropertyField.
![img](../../../images/img-attribute-disable-alchemy-editor.png)
```cs
[DisableAlchemyEditor]
public class DisableAlchemyEditorExample : MonoBehaviour
{
public float foo;
public Vector3 bar;
public GameObject baz;
}
```

View File

@ -0,0 +1,27 @@
# Disable If Attribute
If the boolean value of the target member is true, the field becomes disabled.
![img](../../../images/img-attribute-disable-if-false.png)
![img](../../../images/img-attribute-disable-if-true.png)
```cs
public bool isDisabled;
public bool IsDisabled => isDisabled;
public bool IsDisabledMethod() => isDisabled;
[DisableIf("isDisabled")]
public int disableIfField;
[DisableIf("IsDisabled")]
public int disableIfProperty;
[DisableIf("IsDisabledMethod")]
public int disableIfMethod;
```
| Parameter | Description |
| - | - |
| Condition | The name of the field, property, or method used for condition evaluation. |

View File

@ -0,0 +1,12 @@
# Disable In Edit Mode Attribute
During Edit Mode, the field becomes disabled.
![img](../../../images/img-attribute-disable-in-edit-mode-editor.png)
![img](../../../images/img-attribute-disable-in-edit-mode-player.png)
```cs
[DisableInEditMode]
public float foo;
```

View File

@ -0,0 +1,12 @@
# Disable In Play Mode Attribute
During Play Mode, the field becomes disabled.
![img](../../../images/img-attribute-disable-in-play-mode-editor.png)
![img](../../../images/img-attribute-disable-in-play-mode-player.png)
```cs
[DisableInPlayMode]
public float foo;
```

View File

@ -0,0 +1,27 @@
# Enable If Attribute
The field becomes editable only if the boolean value of the target member is true.
![img](../../../images/img-attribute-enable-if-false.png)
![img](../../../images/img-attribute-enable-if-true.png)
```cs
public bool isEnabled;
public bool IsEnabled => isEnabled;
public bool IsEnabledMethod() => isEnabled;
[EnableIf("isEnabled")]
public int enableIfField;
[EnableIf("IsEnabled")]
public int enableIfProperty;
[EnableIf("IsEnabledMethod")]
public int enableIfMethod;
```
| Parameter | Description |
| - | - |
| Condition | The name of the field, property, or method used for condition evaluation |

View File

@ -0,0 +1,29 @@
# Foldout Group Attribute
Creates collapsible groups for multiple members.
![img](../../../images/img-attribute-foldout-group.png)
```cs
[FoldoutGroup("Group1")]
public float foo;
[FoldoutGroup("Group1")]
public Vector3 bar;
[FoldoutGroup("Group1")]
public GameObject baz;
[FoldoutGroup("Group2")]
public float alpha;
[FoldoutGroup("Group2")]
public Vector3 beta;
[FoldoutGroup("Group2")]
public GameObject gamma;
```
| Parameter | Description |
| - | - |
| GroupPath | Specifies the path of the group. Groups can be nested using `/`. |

View File

@ -0,0 +1,29 @@
# Group Attribute
Creates a group to display multiple members together.
![img](../../../images/img-attribute-group.png)
```cs
[Group("Group1")]
public float foo;
[Group("Group1")]
public Vector3 bar;
[Group("Group1")]
public GameObject baz;
[Group("Group2")]
public float alpha;
[Group("Group2")]
public Vector3 beta;
[Group("Group2")]
public GameObject gamma;
```
| Parameter | Description |
| - | - |
| GroupPath | Specifies the path of the group. Groups can be nested using `/`. |

View File

@ -0,0 +1,21 @@
# Help Box Attribute
Adds a note or warning above a field.
![img](../../../images/img-attribute-help-box.png)
```cs
[HelpBox("Custom Info")]
public float foo;
[HelpBox("Custom Warning", HelpBoxMessageType.Warning)]
public Vector2 bar;
[HelpBox("Custom Error", HelpBoxMessageType.Error)]
public GameObject baz;
```
| Parameter | Description |
| - | - |
| Message | The text to display inside the box. |
| MessageType | The type of message. |

View File

@ -0,0 +1,27 @@
# Hide If Attribute
Hides the member in the Inspector if the boolean value is true.
![img](../../../images/img-attribute-hide-if-false.png)
![img](../../../images/img-attribute-hide-if-true.png)
```cs
public bool hide;
public bool Hide => hide;
public bool IsHideTrue() => hide;
[HideIf("hide")]
public int hideIfField;
[HideIf("Hide")]
public int hideIfProperty;
[HideIf("IsHideTrue")]
public int hideIfMethod;
```
| Parameter | Description |
| - | - |
| Condition | The name of the field, property, or method used for the condition evaluation. |

View File

@ -0,0 +1,12 @@
# Hide In Edit Mode Attribute
Hides the field while in Edit Mode.
![img](../../../images/img-attribute-hide-in-edit-mode-editor.png)
![img](../../../images/img-attribute-hide-in-edit-mode-player.png)
```cs
[HideInEditMode]
public float foo;
```

View File

@ -0,0 +1,12 @@
# Hide In Play Mode Attribute
Hides the field while in Play Mode.
![img](../../../images/img-attribute-hide-in-play-mode-editor.png)
![img](../../../images/img-attribute-hide-in-play-mode-player.png)
```cs
[HideInPlayMode]
public float foo;
```

View File

@ -0,0 +1,16 @@
# Hide Label Attribute
Hides the label of the field.
![img](../../../images/img-attribute-hide-label.png)
```cs
[HideLabel]
public float foo;
[HideLabel]
public Vector3 bar;
[HideLabel]
public GameObject baz;
```

View File

@ -0,0 +1,15 @@
# Hide Script Field Attribute
Hides the target script field.
![img](../../../images/img-attribute-hide-script-field.png)
```cs
[HideScriptField]
public class HideScriptFieldSample : MonoBehaviour
{
public float foo;
public Vector3 bar;
public GameObject baz;
}
```

View File

@ -0,0 +1,44 @@
# Horizontal Attribute
Creates a group that displays multiple members horizontally.
![img](../../../images/img-attribute-horizontal-group.png)
```cs
[HorizontalGroup("Group1")]
public int a;
[HorizontalGroup("Group1")]
public int b;
[HorizontalGroup("Group1")]
public int c;
[HorizontalGroup("Group2")]
[BoxGroup("Group2/Box1")]
public float foo;
[HorizontalGroup("Group2")]
[BoxGroup("Group2/Box1")]
public Vector3 bar;
[HorizontalGroup("Group2")]
[BoxGroup("Group2/Box1")]
public GameObject baz;
[HorizontalGroup("Group2")]
[BoxGroup("Group2/Box2")]
public float alpha;
[HorizontalGroup("Group2")]
[BoxGroup("Group2/Box2")]
public Vector3 beta;
[HorizontalGroup("Group2")]
[BoxGroup("Group2/Box2")]
public GameObject gamma;
```
| Parameter | Description |
| - | - |
| GroupPath | Specifies the path of the group. Groups can be nested using `/`. |

View File

@ -0,0 +1,23 @@
# Horizontal Line Attribute
Adds a horizontal line to the Inspector.
![img](../../../images/img-attribute-horizontal-line.png)
```cs
[HorizontalLine]
public float foo;
[HorizontalLine(1f, 0f, 0f)]
public Vector2 bar;
[HorizontalLine(1f, 0.5f, 0f, 0.5f)]
public GameObject baz;
```
| Parameter | Description |
| - | - |
| r | Red component of the line color |
| g | Green component of the line color |
| b | Blue component of the line color |
| a | Alpha value of the line color |

View File

@ -0,0 +1,20 @@
# Indent Attribute
Adds an indent to the field in the Inspector.
![img](../../../images/img-attribute-indent.png)
```cs
[Indent]
public float foo;
[Indent(2)]
public Vector2 bar;
[Indent(3)]
public GameObject baz;
```
| Parameter | Description |
| - | - |
| Indent | Number of indents |

View File

@ -0,0 +1,10 @@
# Inline Editor Attribute
Displays the Inspector of the target ScriptableObject or component inline, allowing for editing.
![img](../../../images/img-attribute-inline-editor.png)
```cs
[InlineEditor]
public SampleScriptableObject sample;
```

View File

@ -0,0 +1,30 @@
# Label Text Attribute
Overrides the label text of the field.
![img](../../../images/img-attribute-label-text.png)
```cs
[LabelText("FOO!")]
public float foo;
[LabelText("BAR!")]
public Vector3 bar;
[LabelText("BAZ!")]
public GameObject baz;
[Space]
[LabelText("α")]
public float alpha;
[LabelText("β")]
public Vector3 beta;
[LabelText("γ")]
public GameObject gamma;
```
| Parameter | Description |
| - | - |
| Text | The text to display on the field label |

View File

@ -0,0 +1,28 @@
# List View Settings Attribute
Changes the display settings for collections. This attribute allows you to enhance the readability of rows, and create arrays where the element count/order cannot be changed from the Inspector.
![img](../../../images/img-attribute-list-view-settings.png)
```cs
[ListViewSettings(ShowAlternatingRowBackgrounds = AlternatingRowBackground.All, ShowFoldoutHeader = false)]
public int[] array1;
[ListViewSettings(Reorderable = false, ShowAddRemoveFooter = false, ShowBorder = false, ShowBoundCollectionSize = false)]
public Vector3[] array2 = new Vector3[]
{
Vector3.zero,
Vector3.one
};
```
| Parameter | Description |
| - | - |
| ShowAddRemoveFooter | Whether to display the footer for adding/removing elements |
| ShowAlternatingRowBackgrounds | Whether to change the background color for every other row |
| ShowBorder | Whether to display borders |
| ShowBoundCollectionSize | Whether to display the field for changing the number of elements |
| ShowFoldoutHeader | Whether to display the foldout header |
| SelectionType | Selection settings for elements |
| Reorderable | Whether elements can be reordered |
| ReorderMode | Settings for displaying reordering |

View File

@ -0,0 +1,11 @@
# On Inspector Destroy Attribute
Executes a method when the Inspector is destroyed.
```cs
[OnInspectorDestroy]
void OnInspectorDestroy()
{
Debug.Log("Destroy");
}
```

View File

@ -0,0 +1,11 @@
# On Inspector Disable Attribute
Executes a method when the Inspector is disabled.
```cs
[OnInspectorDisable]
void OnInspectorDisable()
{
Debug.Log("Disable");
}
```

View File

@ -0,0 +1,11 @@
# On Inspector Enable Attribute
Executes a method when the Inspector is enabled.
```cs
[OnInspectorEnable]
void OnInspectorEnable()
{
Debug.Log("Enable");
}
```

View File

@ -0,0 +1,17 @@
# On Value Changed Attribute
Executes a method with the specified name when the value of the field changes.
```cs
[OnValueChanged("OnValueChanged")]
public int foo;
void OnValueChanged(int value)
{
Debug.Log(value);
}
```
| Parameter | Description |
| - | - |
| MethodName | The name of the method to be called when the value changes. |

View File

@ -0,0 +1,20 @@
# Order Attribute
Changes the display order of the field. The default value of order is 0, and members are displayed in ascending order.
![img](../../../images/img-attribute-order.png)
```cs
[Order(2)]
public float foo;
[Order(1)]
public Vector3 bar;
[Order(0)]
public GameObject baz;
```
| Parameter | Description |
| - | - |
| Order | The display order of the member. |

View File

@ -0,0 +1,19 @@
# Read Only Attribute
Makes the field uneditable.
![img](../../../images/img-attribute-read-only.png)
```cs
[ReadOnly]
public float field = 2.5f;
[ReadOnly]
public int[] array = new int[5];
[ReadOnly]
public SampleClass classField;
[ReadOnly]
public SampleClass[] classArray = new SampleClass[3];
```

View File

@ -0,0 +1,17 @@
# Required Attribute
Displays a warning if the field does not have an object reference assigned.
![img](../../../images/img-attribute-required.png)
```cs
[Required]
public GameObject requiredField1;
[Required("Custom message")]
public Material requiredField2;
```
| Parameter | Description |
| - | - |
| Message | Text to display in the warning |

View File

@ -0,0 +1,27 @@
# Show If Attribute
Displays in the Inspector only if the boolean value of the target member is true.
![img](../../../images/img-attribute-show-if-false.png)
![img](../../../images/img-attribute-show-if-true.png)
```cs
public bool show;
public bool Show => show;
public bool IsShowTrue() => show;
[ShowIf("show")]
public int showIfField;
[ShowIf("Show")]
public int showIfProperty;
[ShowIf("IsShowTrue")]
public int showIfMethod;
```
| Parameter | Description |
| - | - |
| Condition | The name of the field, property, or method used for condition checking |

View File

@ -0,0 +1,19 @@
# Show In Inspector Attribute
Allows non-serialized fields or properties to be edited in the Inspector. Note that these values are not serialized, and changes are not saved.
![img](../../../images/img-attribute-show-in-inspector.png)
```cs
[NonSerialized, ShowInInspector]
public int field;
[NonSerialized, ShowInInspector]
public SampleClass classField = new();
[ShowInInspector]
public int Getter => 10;
[field: NonSerialized, ShowInInspector]
public string Property { get; set; } = string.Empty;
```

View File

@ -0,0 +1,30 @@
# Tab Group Attribute
Creates a group that divides multiple members into tabs.
![img](../../../images/img-attribute-tab-group.png)
```cs
[TabGroup("Group1", "Tab1")]
public float foo;
[TabGroup("Group1", "Tab2")]
public Vector3 bar;
[TabGroup("Group1", "Tab3")]
public GameObject baz;
[TabGroup("Group1", "Tab1")]
public float alpha;
[TabGroup("Group1", "Tab2")]
public Vector3 beta;
[TabGroup("Group1", "Tab3")]
public GameObject gamma;
```
| Parameter | Description |
| - | - |
| GroupPath | Specifies the path of the group. Groups can be nested using `/`. |
| TabName | Specifies the name of the tab to which the member belongs. |

View File

@ -0,0 +1,22 @@
# Title Attribute
Displays a header with a separator line in the Inspector.
![img](../../../images/img-attribute-title.png)
```cs
[Title("Title1")]
public float foo;
public Vector3 bar;
public GameObject baz;
[Title("Title2", "Subtitle")]
public float alpha;
public Vector3 beta;
public GameObject gamma;
```
| Parameter | Description |
| - | - |
| Title | Text to display in the header. |
| Subtitle | Text displayed below the title in smaller font. |

View File

@ -0,0 +1,28 @@
# Validate Input Attribute
Displays a warning if the value of the specified member is false.
![img](../../../images/img-attribute-validate-input.png)
```cs
[ValidateInput("IsNotNull")]
public GameObject obj;
[ValidateInput("IsZeroOrGreater", "foo must be 0 or greater.")]
public int foo = -1;
static bool IsNotNull(GameObject go)
{
return go != null;
}
static bool IsZeroOrGreater(int a)
{
return a >= 0;
}
```
| Parameter | Description |
| - | - |
| Condition | Name of the field, property, or method used for validation. |
| Message | Text displayed in the warning. |

View File

@ -0,0 +1,45 @@
# Button Attribute
By adding the `[Button]` attribute to a method, you can display a button in the Inspector to execute the method.
```cs
using System;
using UnityEngine;
using Alchemy.Inspector;
[Serializable]
public sealed class Example
{
public float foo;
public Vector3 bar;
public GameObject baz;
}
public class ButtonAttributeExample : MonoBehaviour
{
[Button]
public void Foo()
{
Debug.Log("Foo");
}
[Button]
public void Foo(int parameter)
{
Debug.Log("Foo: " + parameter);
}
[Button]
public void Foo(Example parameter)
{
var builder = new StringBuilder();
builder.AppendLine();
builder.Append("foo = ").AppendLine(parameter.foo.ToString());
builder.Append("bar = ").AppendLine(parameter.bar.ToString());
builder.Append("baz = ").Append(parameter.baz == null ? "Null" : parameter.baz.ToString());
Debug.Log("Foo: " + builder.ToString());
}
}
```
![img](../../images/img-button.png)

View File

@ -0,0 +1,15 @@
# Comparison with Other Libraries
Alchemy offers features equivalent to or surpassing those of other assets/libraries for editor extensions. Here's a comparison of Alchemy's features with other assets/libraries:
| | Alchemy | [Odin Inspector & Serializer](https://odininspector.com/) | [NaughtyAttributes](https://github.com/dbrizov/NaughtyAttributes) | [Tri Inspector](https://github.com/codewriter-packages/Tri-Inspector) | [Unity Editor Toolbox](https://github.com/arimger/Unity-Editor-Toolbox) |
| - | - | - | - | - | - |
| Open Source | ✔︎ | ❌ | ✔︎ | ✔︎ | ✔︎ |
| Grouping Attributes | ✔︎ | ✔︎ | ✔︎ | ✔︎ | ✔︎ |
| Button Attribute | ✔︎ | ✔︎ | ✔︎ <br>(without arguments) | ✔︎ | ✔︎ <br>(without arguments) |
| Editing NonSerialized Members | ✔︎ | ✔︎ | ❌ | ✔︎ | ❌ |
| SerializeReference Support | ✔︎ | ✔︎ | ❌ | ✔︎ | ✔︎ |
| Serialization Extension | ✔︎ <br>(requires partial) | ✔︎ <br>(inherit from dedicated types) | ❌ | ❌ | ❌ <br>(provides serializable types) |
| UI Toolkit Support | ✔︎ | ✔︎ | ❌ | ✔︎ | ❌ |
| EditorWindow Extensions | ✔︎ | ✔︎ | ❌ | ❌ | ❌ |
| Hierarchy Extensions | ✔︎ | ❌ | ❌ | ❌ | ✔︎ |

View File

@ -0,0 +1,48 @@
# Creating Custom Attributes
By using `AlchemyAttributeDrawer`, it is possible to create custom attributes that work within Alchemy. Here is an example demonstrating the implementation of `HelpBoxAttribute` and its corresponding drawer.
First, define the attribute to be added to fields or properties.
```cs
using System;
using UnityEngine.UIElements;
public sealed class HelpBoxAttribute : Attribute
{
public HelpBoxAttribute(string message, HelpBoxMessageType messageType = HelpBoxMessageType.Info)
{
Message = message;
MessageType = messageType;
}
public string Message { get; }
public HelpBoxMessageType MessageType { get; }
}
```
Next, create the drawer corresponding to the defined attribute. Drawer scripts should be placed within the Editor folder.
```cs
using UnityEngine.UIElements;
using Alchemy.Editor;
[CustomAttributeDrawer(typeof(HelpBoxAttribute))]
public sealed class HelpBoxDrawer : AlchemyAttributeDrawer
{
HelpBox helpBox;
public override void OnCreateElement()
{
var att = (HelpBoxAttribute)Attribute;
helpBox = new HelpBox(att.Message, att.MessageType);
var parent = TargetElement.parent;
parent.Insert(parent.IndexOf(TargetElement), helpBox);
}
}
```
Implement the `OnCreateElement()` method to add processing when creating the corresponding VisualElement for the member. Unlike regular `PropertyDrawer`s that override the drawing process, here we're adding post-processing after the creation of the Visual Element. This mechanism allows Alchemy to combine multiple drawers.
Additionally, make sure to add the `CustomAttributeDrawer` attribute to the defined drawer, with the type of the defined attribute as an argument. Alchemy uses this attribute to search for the necessary drawers for element rendering.

View File

@ -0,0 +1,41 @@
# Creating Custom Group Attributes
By using `AlchemyGroupDrawer`, it is possible to create custom attributes for grouping fields. Here is an example demonstrating the implementation of `FoldoutGroupAttribute` and its corresponding drawer. (Some parts of the actual implementation have been omitted for the sake of explanation.)
First, define the attribute to be used for defining groups. This attribute must inherit from `PropertyGroupAttribute`.
```cs
using Alchemy.Inspector;
public sealed class FoldoutGroupAttribute : PropertyGroupAttribute
{
public FoldoutGroupAttribute() : base() { }
public FoldoutGroupAttribute(string groupPath) : base(groupPath) { }
}
```
Next, create the drawer corresponding to the defined attribute. Drawer scripts should be placed within the Editor folder.
```cs
using UnityEngine.UIElements;
using Alchemy.Editor;
[CustomGroupDrawer(typeof(FoldoutGroupAttribute))]
public sealed class FoldoutGroupDrawer : AlchemyGroupDrawer
{
public override VisualElement CreateRootElement(string label)
{
var foldout = new Foldout()
{
style = {
width = Length.Percent(100f)
},
text = label
};
return foldout;
}
}
```
Implement the `CreateRootElement(string label)` method to create the root VisualElement for each group. Additionally, make sure to add the `CustomGroupDrawer` attribute to the defined drawer, with the type of the defined attribute as an argument. Alchemy uses this attribute to search for the necessary drawers for group rendering.

View File

@ -0,0 +1,20 @@
# Debugging Serialized Data
By adding the `[ShowAlchemySerializationData]` attribute along with `[AlchemySerialize]`, you can inspect serialized data from the Inspector.
```cs
using System;
using System.Collections.Generic;
using UnityEngine;
using Alchemy.Serialization;
[AlchemySerialize]
[ShowAlchemySerializationData]
public partial class AlchemySerializationExample : MonoBehaviour
{
[AlchemySerializeField, NonSerialized]
public Dictionary<string, GameObject> dictionary = new();
}
```
![img](../../images/img-show-serialization-data.png)

View File

@ -0,0 +1,19 @@
# Decorating Hierarchy
Alchemy allows you to decorate the Hierarchy by adding headers and separators, making it more visually appealing and easier to navigate.
![img](../../images/img-hierarchy.png)
To add headers and separators, navigate to the Hierarchy and click the "+" button, then choose `Alchemy > Header/Separator`.
![img](../../images/img-create-hierarchy-object.png)
These objects used for decoration in the Hierarchy are called `HierarchyObjects` in Alchemy. They are excluded from the build process. If any child objects exist, they will be detached using `transform.DetachChildren()` before deletion.
You can configure the handling of `HierarchyObjects` in the Alchemy settings under `Project Settings > Alchemy`.
![img](../../images/img-project-settings.png)
For individual `HierarchyObjects`, you can adjust their settings from the Inspector.
![img](../../images/img-hierarchy-header-inspector.png)

View File

@ -0,0 +1,5 @@
# Disabling the Default Editor
By default, Alchemy uses its own editor class to handle the drawing of all types. However, to avoid conflicts with other libraries or assets, you can disable this behavior.
To disable the default editor, add `ALCHEMY_DISABLE_DEFAULT_EDITOR` to the `Scripting Define Symbols` field in `Project Settings > Player`. If you want to use Alchemy's features while this option is enabled, you'll need to define your own editor class that inherits from `AlchemyEditor`.

View File

@ -0,0 +1,21 @@
# Extending AlchemyEditor
If a MonoBehaviour or ScriptableObject has its own custom editor class, Alchemy attributes won't work by default.
To combine your custom editor extension with Alchemy, you need to inherit from `AlchemyEditor` class instead of the regular `Editor` class.
```cs
using UnityEditor;
using Alchemy.Editor;
[CustomEditor(typeof(Example))]
public class EditorExample : AlchemyEditor
{
public override VisualElement CreateInspectorGUI()
{
// Always call the base CreateInspectorGUI
base.CreateInspectorGUI();
// Add your custom logic here
}
}
```

View File

@ -0,0 +1,85 @@
# Group Attributes
Alchemy provides attributes to group fields together.
```cs
using UnityEngine;
using Alchemy.Inspector;
public class GroupAttributesExample : MonoBehaviour
{
[FoldoutGroup("Foldout")]
public int a;
[FoldoutGroup("Foldout")]
public int b;
[FoldoutGroup("Foldout")]
public int c;
[TabGroup("Tab", "Tab1")]
public int x;
[TabGroup("Tab", "Tab2")]
public string y;
[TabGroup("Tab", "Tab3")]
public Vector3 z;
}
```
![img](../../images/img-group-1.png)
Each group can be nested by using slashes.
```cs
using UnityEngine;
using Alchemy.Inspector;
public class GroupAttributesExample : MonoBehaviour
{
[HorizontalGroup("Horizontal"), BoxGroup("Horizontal/Box1")]
public float foo;
[HorizontalGroup("Horizontal"), BoxGroup("Horizontal/Box1")]
public Vector3 bar;
[HorizontalGroup("Horizontal"), BoxGroup("Horizontal/Box1")]
public GameObject baz;
[HorizontalGroup("Horizontal"), BoxGroup("Horizontal/Box2")]
public float alpha;
[HorizontalGroup("Horizontal"), BoxGroup("Horizontal/Box2")]
public Vector3 beta;
[HorizontalGroup("Horizontal"), BoxGroup("Horizontal/Box2")]
public GameObject gamma;
}
```
![img](../../images/img-group-2.png)
Additionally, you can add group attributes to a defined Serializable class to change how its members are displayed within corresponding groups.
```cs
using System;
using UnityEngine;
using Alchemy.Inspector;
[Serializable]
[BoxGroup]
public sealed class Example
{
public float foo;
public Vector3 bar;
public GameObject baz;
}
public class GroupAttributeExample : MonoBehaviour
{
public Example example;
}
```
![img](../../images/img-group-3.png)

View File

@ -0,0 +1,9 @@
# Toggles and Icons
By integrating Alchemy, you can add toggles to the Hierarchy to switch objects between active and inactive states, as well as icons for each component.
![gif](../../images/gif-hierarchy-toggle.gif)
These features are disabled by default. You can configure Hierarchy display settings in `Project Settings > Alchemy`.
![img](../../images/img-project-settings.png)

View File

@ -0,0 +1,28 @@
# Inspector Extension with Attributes
Alchemy allows you to extend the Inspector using attributes. To customize the display in the Inspector, you can add attributes to the fields of your class.
```cs
using UnityEngine;
using UnityEngine.UIElements;
using Alchemy.Inspector; // Add Alchemy.Inspector namespace
public class AttributesExample : MonoBehaviour
{
[LabelText("Custom Label")]
public float foo;
[HideLabel]
public Vector3 bar;
[AssetsOnly]
public GameObject baz;
[Title("Title")]
[HelpBox("HelpBox", HelpBoxMessageType.Info)]
[ReadOnly]
public string message = "Read Only";
}
```
![img](../../images/img-attributes-example.png)

View File

@ -0,0 +1,40 @@
# Installation
Let's install Alchemy into your project to start using it.
### Requirements
* Unity 2021.2 or later (Unity 2022.1 or later recommended for serialization extensions)
* Serialization 2.0 or later (if using serialization extensions)
### Install via Package Manager (Recommended)
You can install Alchemy via the Package Manager.
1. Open the Package Manager by navigating to Window > Package Manager.
2. Click the "+" button and choose "Add package from git URL".
3. Enter the following URL:
```text
https://github.com/AnnulusGames/Alchemy.git?path=/Alchemy/Assets/Alchemy
```
![img1](../../images/img-setup-1.png)
Alternatively, you can add the following line to the dependencies block in your Packages/manifest.json file:
```json
{
"dependencies": {
"com.annulusgames.alchemy": "https://github.com/AnnulusGames/Alchemy.git?path=/Alchemy/Assets/Alchemy"
}
}
```
### Install from unitypackage
You can also install Alchemy from a unitypackage file.
1. Go to Releases and navigate to the latest release.
2. Download the unitypackage file.
3. Open the file and import it into your project.

View File

@ -0,0 +1,39 @@
# Saving EditorWindow Data
The data of an editor window created by inheriting from `AlchemyEditorWindow` is automatically saved in JSON format within the ProjectSettings folder of your project.
You can customize the saving/loading process and the destination path by overriding the `SaveWindowData()`, `LoadWindowData()`, and `GetWindowDataPath()` methods.
```cs
using UnityEditor;
using UnityEngine;
using Alchemy.Editor;
public class EditorWindowExample : AlchemyEditorWindow
{
[MenuItem("Window/Example")]
static void Open()
{
var window = GetWindow<EditorWindowExample>("Example");
window.Show();
}
protected override string GetWindowDataPath()
{
// Return the path where the data will be saved
return ...
}
protected override void LoadWindowData(string dataPath)
{
// Write the loading process here
...
}
protected override void SaveWindowData(string dataPath)
{
// Write the saving process here
...
}
}
```

View File

@ -0,0 +1,21 @@
# Serialization Callbacks
When using the `[AlchemySerialize]` attribute, the Source Generator automatically implements `ISerializationCallbackReceiver`. Therefore, you cannot use `ISerializationCallbackReceiver` to add callbacks.
Instead, Alchemy provides an alternative interface called `IAlchemySerializationCallbackReceiver`. Please use this interface instead of `ISerializationCallbackReceiver` when using `[AlchemySerialize]`.
```cs
[AlchemySerialize]
public partial class AlchemySerializationSample : MonoBehaviour, IAlchemySerializationCallbackReceiver
{
public void OnAfterDeserialize()
{
Debug.Log("OnAfterDeserialize");
}
public void OnBeforeSerialize()
{
Debug.Log("OnBeforeSerialize");
}
}
```

View File

@ -0,0 +1,49 @@
# Serialization Extension
If you want to edit types that Unity cannot serialize normally, such as Dictionary, you can serialize them using the `[AlchemySerialize]` attribute.
To use serialization extension, you need the [Unity.Serialization](https://docs.unity3d.com/Packages/com.unity.serialization@3.1/manual/index.html) package. Also, please note that reflection-based Unity.Serialization serialization may not work in AOT environments prior to Unity 2022.1. Please refer to the package manual for details.
Here is a sample using Alchemy's serialization extension to serialize various types and make them editable in the Inspector:
```cs
using System;
using System.Collections.Generic;
using UnityEngine;
using Alchemy.Serialization; // Add Alchemy.Serialization namespace
[AlchemySerialize]
public partial class AlchemySerializationExample : MonoBehaviour
{
// Add the [AlchemySerializeField] and [NonSerialized] attributes to the target field.
[AlchemySerializeField, NonSerialized]
public HashSet<GameObject> hashSet = new();
[AlchemySerializeField, NonSerialized]
public Dictionary<string, GameObject> dictionary = new();
[AlchemySerializeField, NonSerialized]
public (int, int) tuple;
[AlchemySerializeField, NonSerialized]
public Vector3? nullable = null;
}
```
![img](../../images/img-serialization-sample.png)
Currently, the following types can be edited in the Inspector:
- Primitive types
- UnityEngine.Object
- AnimationCurve
- Gradient
- Array
- List<>
- HashSet<>
- Dictionary<,>
- ValueTuple<>
- Nullable<>
- class/struct consisting of the above types
For technical details on serialization, please refer to [Alchemy's Serialization Process](alchemy-serialization-process.md).

View File

@ -0,0 +1,40 @@
# SerializeReference
Alchemy supports Unity's `[SerializeReference]`. By adding the `[SerializeReference]` attribute, you can edit interfaces or abstract classes in the Inspector.
```cs
using System;
using UnityEngine;
public interface IExample { }
[Serializable]
public sealed class ExampleA : IExample
{
public float alpha;
}
[Serializable]
public sealed class ExampleB : IExample
{
public Vector3 beta;
}
[Serializable]
public sealed class ExampleC : IExample
{
public GameObject gamma;
}
public class SerializeReferenceExample : MonoBehaviour
{
[SerializeReference] public IExample example;
[SerializeReference] public IExample[] exampleArray;
}
```
![img](../../images/img-serialize-reference.png)
Interfaces and abstract classes are displayed as shown above, and you can select and create subclasses from the dropdown.
For more information about SerializeReference serialization, please refer to [Unity's official documentation](https://docs.unity3d.com/2020.3/ScriptReference/SerializeReference.html).

134
docs/articles/en/toc.yml Normal file
View File

@ -0,0 +1,134 @@
- name: Get Started
- name: Alchemy Overview
href: about.md
- name: Installation
href: installation.md
- name: Inspector
- name: Inspector Extension with Attributes
href: inspector-extension-with-attributes.md
- name: Group Attributes
href: group-attributes.md
- name: Button Attribute
href: button-attribute.md
- name: SerializeReference
href: serialize-reference.md
- name: Attribute List
items:
- name: General
- name: Assets Only
href: attributes/assets-only.md
- name: Button
href: attributes/button.md
- name: Disable Alchemy Editor
href: attributes/disable-alchemy-editor.md
- name: Hide Script Field
href: attributes/hide-script-field.md
- name: Indent
href: attributes/indent.md
- name: Inline Editor
href: attributes/inline-editor.md
- name: List View Settings
href: attributes/list-view-settings.md
- name: Order
href: attributes/order.md
- name: Read Only
href: attributes/read-only.md
- name: Show In Inspector
href: attributes/show-in-inspector.md
- name: Conditionals
- name: Disable If
href: attributes/disable-if.md
- name: Disable In Edit Mode
href: attributes/disable-in-edit-mode.md
- name: Disable In Play Mode
href: attributes/disable-in-play-mode.md
- name: Enable If
href: attributes/enable-if.md
- name: Hide If
href: attributes/hide-if.md
- name: Hide In Edit Mode
href: attributes/hide-in-edit-mode.md
- name: Hide In Play Mode
href: attributes/hide-in-play-mode.md
- name: Show If
href: attributes/show-if.md
- name: Decoration
- name: Blockquote
href: attributes/blockquote.md
- name: Help Box
href: attributes/help-box.md
- name: Hide Label
href: attributes/hide-label.md
- name: Horizontal Line
href: attributes/horizontal-line.md
- name: Label Text
href: attributes/label-text.md
- name: Title
href: attributes/title.md
- name: Validation
- name: Required
href: attributes/required.md
- name: Validate Input
href: attributes/validate-input.md
- name: Events
- name: On Inspector Destroy
href: attributes/on-inspector-destroy.md
- name: On Inspector Disable
href: attributes/on-inspector-disable.md
- name: On Inspector Enable
href: attributes/on-inspector-enable.md
- name: On Value Changed
href: attributes/on-value-changed.md
- name: Groups
- name: Box Group
href: attributes/box-group.md
- name: Foldout Group
href: attributes/foldout-group.md
- name: Group
href: attributes/group.md
- name: Horizontal Group
href: attributes/horizontal-group.md
- name: Tab Group
href: attributes/tab-group.md
- name: Hierarchy
- name: Toggles and Icons
href: hierarchy-toggles-and-icons.md
- name: Decorating Hierarchy
href: decorating-hierarchy.md
- name: Editor Window
- name: AlchemyEditorWindow
href: alchemy-editor-window.md
- name: Saving Editor Window Data
href: saving-editor-window-data.md
- name: Serialization
- name: Serialization Extension
href: serialization-extension.md
- name: Alchemy Serialization Process
href: alchemy-serialization-process.md
- name: Debugging Serialized Data
href: debugging-serialized-data.md
- name: Serialization Callback
href: serialization-callback.md
- name: Extensions
- name: Extending Alchemy Editor
href: extending-alchemy-editor.md
- name: Creating Custom Attribute
href: creating-custom-attribute.md
- name: Creating Custom Group Attribute
href: creating-custom-group-attribute.md
- name: Others
- name: Disable Default Editor
href: disable-default-editor.md
- name: Comparison with Other Libraries
href: comparison-with-other-libraries.md

View File

@ -6,7 +6,7 @@
- name: Inspector
- name: 属性を用いたInspector拡張
href: inspector-extension-using-attributes.md
href: inspector-extension-with-attributes.md
- name: グループ属性
href: group-attributes.md
- name: Button属性
@ -76,12 +76,12 @@
href: attributes/validate-input.md
- name: Events
- name: On Inspector Enable
href: attributes/on-inspector-enable.md
- name: On Inspector Destroy
href: attributes/on-inspector-destroy.md
- name: On Inspector Disable
href: attributes/on-inspector-disable.md
- name: On Inspector Enable
href: attributes/on-inspector-enable.md
- name: On Value Changed
href: attributes/on-value-changed.md
@ -101,7 +101,7 @@
- name: トグルとアイコン
href: hierarchy-toggles-and-icons.md
- name: Hierarchyの装飾
href: hierarchy-decoration.md
href: decorating-hierarchy.md
- name: Editor Window
- name: AlchemyEditorWindow
@ -123,9 +123,9 @@
- name: AlchemyEditorを拡張する
href: extending-alchemy-editor.md
- name: カスタム属性を作成する
href: create-custom-attribute.md
href: creating-custom-attribute.md
- name: カスタムグループ属性を作成する
href: create-custom-group-attribute.md
href: creating-custom-group-attribute.md
- name: Others
- name: デフォルトのエディタを無効化する