# Creating Custom Attributes

### Example

Here is a sample of an attribute that achieves several goals

* Changes the background of the element to a yellow color
* Adds a header on top
* Adds a reset button on the bottom

The final look we want to achieve

![](/files/-MW72PbAEAhR5OYJrwp0)

Based on that - we need to do a couple of things

1. Create a new file for your attributes, let's say `MyCustomAttributes.cs` anywhere in your project
2. Add an `#if UNITY_EDITOR` at the beginning, followed by an empty line and an `#endif`
3. Between those you will create your new class Inheriting from the `UTPropertyAttribute`

```csharp
using UnityEditor;
using UnityEngine;
using System; // This in particular is very important
// As it will be used down th eline

#if UNITY_EDITOR
public class MyAttribute : UTPropertyAttribute {
}
#endif
```

Another  very important thing is that we need a separate version of the attribute for the VRChat's build system (otherwise we'll get build errors, and those aren't fun!)

1. Change an `#endif` to `#else`
2. Add a separate version of `MyAttribute` that inherits from `Attribute` (that is why we needed `using System;` earlier)

```csharp
using UnityEditor;
using UnityEngine;
using System; // This in particular is very important
// As it will be used down th eline

#if UNITY_EDITOR
public class MyAttribute : UTPropertyAttribute {
}
#else
// this just tells unity to use this attribute on fields
[AttributeUsage(AttributeTargets.Field)]
public class MyAttribute : Attribute {
  public MyAttribute() { // since we do not have any parameters
  // we create an empty constructor
  }
}
#endif
```

{% hint style="info" %}
The above process is required, because VRChat will need some version of the attribute to build the code. In this case we are using a dummy empty attribute as nothing we're doing here is important for the final build.

You can check the last third of the `UTAttributes` file to see how to handle attributes with parameters in a similar fashion
{% endhint %}

With that - let's add it to our behaviour code

1. Create a new UdonBehaviour and make a script
2. Inside of the script - make a new public variable, for example `public float someVariable`
3. Add the `MyAttribute` attribute to it

```csharp
public class CustomAttributeTest : UdonSharpBehaviour {
  [MyAttribute] public float someVariable;
  private void Start() {
  }
}
```

If you check the Behaviour now - nothing would change! It will just be a normal field.

Now we can override some methods to make it look different! Let's start with the things **above** or **before** the field. For this we'll use the `BeforeGUI` method.

1. Add a `public override void BeforeGUI(SerializedProperty property)` method
2. Inside of it - add our header label
3. Follow that with a new `GUI.color` assignment. Which will color everything that is rendered below it - with that color

```csharp
#if UNITY_EDITOR
public class MyAttribute : UTPropertyAttribute {
  public override void BeforeGUI(SerializedProperty property) {
    EditorGUILayout.LabelField("HEADER TEXT", EditorStyles.largeLabel);
    GUI.color = new Color(0.98f, 0.92f, 0.35f);
  }
}
#endif
```

You should now see the field with a header and colored with a shade of yellow!

![](/files/-MW7KaJZ11l_-JQtDJBM)

The only problem is - if you have any other fields bellow the `someVariable` they will also be colored in this yellow color, as it will override everything it encounters. Try it out: let's add another variable below the `someVaribale`.

```csharp
public class CustomAttributeTest : UdonSharpBehaviour {
  [MyAttribute] public float someVariable;
  
  public bool anotherVariable;
  
  private void Start() {
  }
}
```

![](/files/-MW7LQLUa8zEMvv9q8KT)

Now that's not really what we want. Let's fix that by adding another method override that would be called **below** or **after** the field. This one is called `AfterGUI`!

1. Add a `public override void AfterGUI(SerializedProperty property)` method
2. Reset the color back to white by assigning to the `GUI.color` again

```csharp
#if UNITY_EDITOR
public class MyAttribute : UTPropertyAttribute {
  public override void BeforeGUI(SerializedProperty property) {
    EditorGUILayout.LabelField("HEADER TEXT", EditorStyles.largeLabel);
    GUI.color = new Color(0.98f, 0.92f, 0.35f);
  }

  public override void AfterGUI(SerializedProperty property) {
    GUI.color = Color.white;
  }
}
#endif
```

Now its fixed and the 2nd property doesn't get colored.

![](/files/-MW7Luke8dLXOmHo4gPy)

The only thing left to do now is to add a button!

1. Add a `GUILayout.Button("Reset Value")` wrapped in an if
2. Reset the value of our property to `0` inside of that if

```csharp
#if UNITY_EDITOR
public class MyAttribute : UTPropertyAttribute {
  public override void BeforeGUI(SerializedProperty property) {
    EditorGUILayout.LabelField("HEADER TEXT", EditorStyles.largeLabel);
    GUI.color = new Color(0.98f, 0.92f, 0.35f);
  }

  public override void AfterGUI(SerializedProperty property) {
    GUI.color = Color.white;
    if (GUILayout.Button("Reset Value")) {
      property.floatValue = 0;
    }
  }
}
#endif
```

![](/files/-MW72l-nBamup7-i0hN0)

And we're done! Read below to see what else you can do by overriding methods like `OnGUI` and `GetVisible`

{% hint style="warning" %}
One important thing to note here! You might've noticed that we used a `property.floatValue` to reset our value. That will only work for... well... variables that are of `float` type. If you'll want to work with a `bool` or an `int` or some other property type - you'll need to check the documentation for `serializedProperty` [to learn how to access and change those!](https://docs.unity3d.com/2018.4/Documentation/ScriptReference/SerializedProperty.html)

For those who know about serialized properties - do not worry, you do not need to call `ApplyModifiedProperties` yourself - UdonToolkit's editor will do it for you!
{% endhint %}

{% hint style="info" %}
The final code is provided in the `Demo/CustomAttributeSample` folder, so feel free to use it as a starting point!
{% endhint %}

### UTPropertyAttribute

The base class for an attribute that would modify the display logic for a particular property.

It has a couple methods that you can override

#### GetVisible

`public virtual bool GetVisible(SerializedProperty property)`

This method determines if the property will be visible in the inspector. The attributes will be called from top to bottom, from left to right. As soon as at least one of the attributes returns `false` in the `GetVisible` method - the property won't be drawn and the code will proceed to the next one.

```csharp
// HideIf attribute implementation
public override bool GetVisible(SerializedProperty property) {
  isVisible = UTUtils.GetVisibleThroughAttribute(property, methodName, true);
  return isVisible;
}
```

#### BeforeGUI

`public virtual void BeforeGUI(SerializedProperty property)`

This method will be called right before drawing the field. It is useful for adding headers and other special info right above the actual field.

```csharp
// SectionHeader attribute implementation
public override void BeforeGUI(SerializedProperty property) {
  UTStyles.RenderSectionHeader(text);
}
```

#### OnGUI

`public virtual void OnGUI(SerializedProperty property)`

This method **replaces** the drawing of the serialized property with the logic provided within it.

{% hint style="info" %}
UT will always use the first provided OnGUI method. So if the property has multiple attributes that override OnGUI - only the first one will be called
{% endhint %}

```csharp
// Toggle attribute implementation
public override void OnGUI(SerializedProperty property) {
  var text = String.IsNullOrWhiteSpace(label) ? property.displayName : label;      
  property.boolValue = GUILayout.Toggle(property.boolValue, text, "Button");
}
```

#### AfterGUI

public virtual void AfterGUI(SerializedProperty property)

This method will be called right after drawing the field. You can add extra information, buttons or anything else that is related to the field above in here.

```csharp
// HelpBox attribute implementation
public override void AfterGUI(SerializedProperty property) {
  UTStyles.RenderNote(text);
}
```

### UTVisualAttribute

The base class for purely data-storing attributes that are generally used to alter general looks of the editor UI and not just the single field it is attached too. Things like `ListView` or `TabGroup` are inherited from `UTVisualAttribute`

While inheriting from this attribute does not do anything on its own - it is useful if you are planning to extend the `UTEditor` class itself.

Internally its just an empty C# attribute

```csharp
  /// <summary>
  /// These attributes are used to pass dat to custom logic in the UTEditor
  /// </summary>
  [AttributeUsage(AttributeTargets.Field, AllowMultiple = true)]
  public class UTVisualAttribute : Attribute {
  }
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ut.orels.sh/attributes/creating-custom-attributes.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
