```c#
[Serializable]
public abstract class TraitBase
{
public bool enabled;
public virtual void Update() {}
}
///
/// Inherited classes from TraitBase (Hunger, Health, Energy)
///
```
3.
IArtifice_Persistence: In case you need to add persistency to your editor scripts, you can use this interface and implement its methods to support any persisted information.
4. 4.
Artifice_SCR_CommonResourcesHolder: ArtificeToolkit uses icons which are publicly exposed even for other editor tools to utilize.
5.
UIBuilder: Dynamically rebuild visual elements using the UIBuilder to have dynamic DOM updates.
6. A plethora of specifalized Artifice_SerializedPropertyExtensions.
7. A plethora of Visual Elements like:
- Artifice_VisualElement_ToggleButton
- Artifice_VisualElement_FoldoutGroup
- Artifice_VisualElement_InfoBox
7. You can selectively choose to ignore any C# type by using the "Ignore List" found in the MenuItem "ArtificeToolkit". From there you can search a type and append it into the ignored list. This will cause ArtificeToolkit to fallback to the Unity default rendering system for the specific property. Therefore this feature is for cases where you are experiencing problems with a specific type (e.g. LocalizedString has shown some issues in the past).
8. The ArtificeToolkit now providers the InspectorHeader, a simple utility header to help manage crowded inspectors by providing a searchbar, filtering and collapse/expand all components. It can be toggled on and off through Menu > ArtificeToolkit > Toggle Inspector Header.
# Artifice Validator
The best way to solve bugs, is to avoid creating them. Assertions are one of the most powerful ways to do this and it is considered one of the best programming practices. Using the Artifice Validator, you can apply assertions in your serialized properties.

The Validator works with attributes which inherit from the ValidatorAttribute class. Such attributes have an additional implementation explaining what they are supposed to be asserting. The most common use case the [Required](#required) attribute, to make sure the property has been assigned with a reference.
## Validator in CI or Build scripts
The Artifice_Validator provides the `RunSynchronousValidation` method which returns a List of `ValidatorLog`. This method, will open all scenes contained within the Validator Config file and run the main Validation coroutine on them to gather and return potential logs.
## Creating new CustomAttributes for your own Validations
Creating your own validations is simple. You need to:
1. **Create a Custom Attribute**
Define a custom attribute by inheriting from `ValidatorAttribute`. This attribute encapsulates the logic for what needs to be validated. For example, you might want to ensure a property is required or falls within a specific range.
**NOTE**: By default, when a CustomAttribute is used on an Array or a List, the attribute is injected to the children of the array/list. If you intend your attribute to be applied to he array/list it self, add the `IArtifice_ArrayAppliedAttribute` interface to the attribute in question.
2. **Implement an Artifice_CustomAttributeDrawer_Validator**
Create a drawer class inheriting from `Artifice_CustomAttributeDrawer_Validator_BASE`. This class will define how the validation is performed and how any validation errors or warnings are displayed in the Unity Inspector.
### Example: Required Attribute
Below is an example of how to implement a "Required" attribute to ensure that a property has been assigned a reference.
```csharp
[Artifice_CustomAttributeDrawer(typeof(RequiredAttribute))]
public class Artifice_CustomAttributeDrawer_RequiredAttribute : Artifice_CustomAttributeDrawer_Validator_BASE
{
public override string LogMessage { get; } = "Property is required.";
public override Sprite LogSprite { get; } = Artifice_SCR_CommonResourcesHolder.instance.ErrorIcon;
public override LogType LogType { get; } = LogType.Error;
// Determine if this validator applies to the given property
protected override bool IsApplicableToProperty(SerializedProperty property)
{
return property.propertyType == SerializedPropertyType.ObjectReference;
}
// Validate the property
public override bool IsValid(SerializedProperty property)
{
return property.objectReferenceValue != null;
}
}
```
# Artifice Drawer
The ArtificeDrawer is what renders everything when the Artifice Inspector is enabled. The ArtificeDrawer can receive a SerializedObject or SerializedProperty and returns a VisualElement of the rendered result. It essentially parses the SerializedObject or SerializedProperty and renders either the default result or the enhanced result if CustomAttributes have been used on that property.
This section will only interest you if you want to learn the underlying secrets of how the ArtificeToolkit works at its core and learn how to extend it with your own CustomAttributes and tools. Knowledge regarding CustomEditors, CustomPropertyDrawers etc will be needed.
## ArtificeDrawer GUI Steps
When a property directly uses a CustomAttribute, the drawer will access the respective [CustomAttributeDrawer](#custom-attribute-drawer) and call its GUI steps in order
1. Pre GUI: Appends a VisualElement before the property.
2. On GUI: Replaces the property with the result of this method. Only applies with IsReplacingProperty is set on true.
3. Post GUI: Appends a VisualElement after the property.
4. Wrap GUI: Returns a new VisualElement which adds the VisualElements from the previous steps inside of it.
5. On Bound Property GUI: Executes code when the OnGUI VisualElement is attached in the inspector.
## Creating New CustomAttributes
To create a new `CustomAttribute`, follow these steps:
1. **YourCustomAttribute**: Create your custom attribute by inheriting from `System.Attribute`. This should be placed in a **runtime** folder so it can be applied to your components or ScriptableObjects.
2. **Artifice_CustomAttributeDrawer_YourAttribute**: Create a custom attribute drawer by inheriting from `Artifice_CustomAttributeDrawer`. This drawer class must be placed inside an **Editor** folder.
To link the attribute with its drawer, mark the drawer class with `[CustomPropertyDrawer(typeof(YourAttribute))]`.
### Example: `TitleAttribute`
In this example, we create a custom `TitleAttribute` that adds a styled header to serialized fields in the Unity Inspector.
### Step 1: Create the `TitleAttribute`
Create the `TitleAttribute` in a **runtime** folder. This attribute takes a string title, which will be used as a label in the Inspector.
```csharp
using System;
using UnityEngine;
[AttributeUsage(AttributeTargets.Field, Inherited = true, AllowMultiple = false)]
public class TitleAttribute : CustomAttribute
{
public string Title { get; }
public TitleAttribute(string title)
{
Title = title;
}
}
```
### Step 2: Create the CustomDrawer
Now, create a custom drawer for the TitleAttribute in an Editor folder. This drawer will display the title as a label in the Unity Inspector.
```c#
using UnityEditor;
using UnityEngine.UIElements;
using ArtificeToolkit.Editor.Artifice_CustomAttributeDrawers;
[CustomPropertyDrawer(typeof(TitleAttribute))]
public class Artifice_CustomAttributeDrawer_Title : Artifice_CustomAttributeDrawer
{
private TitleAttribute _titleAttribute;
// Initialize the TitleAttribute
public Artifice_CustomAttributeDrawer_Title()
{
_titleAttribute = (TitleAttribute)Attribute;
}
// Override to insert the custom label before the property field
public override VisualElement OnPrePropertyGUI(SerializedProperty property)
{
// Create a label using the title from the attribute
return new Label(_titleAttribute.Title)
{
style =
{
unityFontStyleAndWeight = FontStyle.Bold,
fontSize = 14,
color = Color.white
}
};
}
}
```
**NOTE**: When overriding the `OnPropertyGUI` method to completely override how the property will be rendered, you MUST also set `public override bool IsReplacingPropertyField { get; } = true;`.
How to Use:
You can now use the TitleAttribute in any of your MonoBehaviour or ScriptableObject classes to add custom headers to your serialized fields:
```c#
using UnityEngine;
public class ExampleComponent : MonoBehaviour
{
[Title("Player Settings")]
public float health;
[Title("Weapon Settings")]
public int ammoCount;
}
```
## Known Issues
- In Unity 2021.x.x the following warning may appear due to value tracking not working generic types of serialized properties.
```
Serialized property type Generic does not support value tracking; callback is not set for characters
UnityEditor.RetainedMode:UpdateSchedulers ()
```
- Copying an entire Artifice List requires both lists to be alive when the Paste happens. This will be fixed in the future.
- The ArtificeToolkit was created with Dark Theme is mind and is currently the only supported color palette.