Adding new rules
The set of rules is open: you can write your own and they'll show up in the workspace's rule list automatically, right next to the built-in ones. A rule is just a small C# class.
How to create a new rule
A rule needs four things:
It must live in an Editor assembly (an
Editorfolder, or an asmdef that referencesHats.Editor).It must inherit from
RuleBaseand be marked[System.Serializable].It must carry a
[RuleInteractionType(...)]attribute that says when it acts.It must implement
RuleName,RuleDescription,OnBecameActiveandOnBecameInactive.
That's it. Public serializable fields appear in the Inspector on their own, and the rule is added to the + menu of Workspaces automatically.
An example of a simple custom Rule:
using Hats.Editor;
using Hats.Editor.Attributes;
using Hats.Editor.Rules;
namespace MyGame.HatsRules
{
[System.Serializable]
[RuleInteractionType(RuleInteractionType.OnWorkspaceActivated)]
public class MyRule : RuleBase
{
public override string RuleName => "My Rule";
public override string RuleDescription =>
"A short explanation of what this rule does. " +
"It's shown in the (?) tooltip next to the rule in the Inspector.";
public override bool OnBecameActive(Hats.ChangeReason reason)
{
// Do the thing here.
// Return true if it worked, false if it couldn't run.
return true;
}
public override bool OnBecameInactive() => true;
}
}Interaction type
The [RuleInteractionType(...)] attribute is required, and decides which submenu the rule lands in:
OnWorkspaceActivated— the rule does something only when the workspace is turned on (On Activation).OnWorkspaceDeactivated— the rule does something only when the workspace is turned off (On Deactivation).OnOff— the rule does something on activation and undoes it on deactivation (On & Off).
Don't forget the attribute. A rule without [RuleInteractionType(...)] won't be picked up correctly by the + menu.
Return values
OnBecameActive and OnBecameInactive return a bool: return true when the rule applied successfully, and false when it couldn't (for example because a required field is empty or the Prefab it was trying to load has been destroyed, etc.). When returning false, it's good practice to log a warning prefixed with (Hats) so the user knows why nothing happened.
Also, the return is used to decide whether to execute following rules in the Workspace. This is to avoid that if a rule doesn't execute correctly, following rules fail too.
Handling recompiles
OnBecameActive is also called after a domain reload (a script recompile) for whichever workspace is active, with reason == Hats.ChangeReason.Recompile.
Many rules early-return in that case, because whatever they did is already in place, but rules can be set to act again after a recompile if that makes sense.
If you don't need a rule to act again on recompile, you can early exit using this line:
Remembering previous state
Since rules are not serialised by default, an OnOff rule that needs to restore something to a previous state might lose the original state if a recompile happens while it's active.
As such, a good idea is to store the state value in a ScriptableSingleton, so that the value will survive a recompile:
Renaming a rule later
If you rename a rule's class after it's already been used in some workspaces, add the [MovedFrom] attribute so existing references keep working:
Custom Inspector (optional)
By default the rule's fields are drawn with Unity's standard property field, and the (?) tooltip is filled from RuleDescription. If you want a custom layout (extra buttons, a different control), add a drawer that inherits from RulePropertyDrawer and override CreateMainElement (to replace the body) or AddExtraElements (to append to the foldout).
Last updated