# UdonSharp Nitpicks

<p class="callout warning">I hope you enjoy reading this - but keep in mind that this isn't quite finished ✌️</p>

Here's some things which I consider good practice when writing U# code, in no particular order. These suggestions are *somewhat* personal, so please let me know what you think in the comments below the article! ❤️

## `UdonSyncMode`
By default, the sync mode of an UdonBehaviour is chosen in the Unity inspector. Which is fine, until you accidently set it to the wrong sync mode. Yikes!

Instead, use [U#'s `UdonSyncMode` attribute](https://github.com/MerlinVR/UdonSharp/wiki/UdonSharp#udonsyncmode=) to make sure your `UdonBehaviour` always uses the sync mode you want.

```cs
using UdonSharp;
using UnityEngine;

[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)] 
public class Foo : UdonSharpBehaviour
{
  // ...
}
```
<p class="callout info">This will prevent you from changing the sync mode on different GameObjects reusing the same U# script.
  <br>But... does anyone actually do that? 🤔</p>
  
## `[SerializeField]`
If you make one of your variables `public`, it'll be accessible from the Unity inspector. It'll *also* make it accessible from any other `UdonBehaviour`. Most variables *aren't* accessed outside their own class, so making variables `public` makes your classes needlessly messy. 

The solution? Keep those variables `private` instead, and just add [`[SerializeField]`](https://docs.unity3d.com/ScriptReference/SerializeField.html) like so:
```cs
[SerializeField] private string foo;
```

<p class="callout info">You can also do the opposite: To hide a public variable from the inspector, use [HideInInspector].</p>

## `[Tooltip]` and `[Header]`
U# scripts can have long and messy inspectors. Why not make them look nicer with the [`[Header]`](https://docs.unity3d.com/ScriptReference/HeaderAttribute.html) and [`[Tooltip]`](https://docs.unity3d.com/ScriptReference/TooltipAttribute.html) attributes?

```cs
[Header("References")]
[Tooltip("Reference to the mirror GameObject.")]
[SerializeField] private GameObject mirror;
[Tooltip("Transform to move the mirror to.")]
[SerializeField] private Transform targetTransform;
```

## Cache your `LocalPlayer`
If you're doing something with `Networking.LocalPlayer` frequently, consider caching the reference in start:
```cs
private VRCPlayerApi localPlayer;

private void Start()
{
  localPlayer = Networking.LocalPlayer;
}
```
... and re-using that reference instead of calling `Networking.LocalPlayer` directly.
```cs
private void Update()
{
  Debug.Log(localPlayer.GetPosition();
}
```

## `OnDeserialization()` and `[FieldChangeCallback]`

### Call `OnDeserialization` as owner

When the owner of a script uses `RequestSerialization()`, all players *except* the owner will execute `OnDeserialization()`. But if you override `OnDeserialization()` in your script, you can have the owner call it manually. This is useful if you'd like the owner of the script to execute `OnDeserialization()`, to replicate the same behaviour as remote clients.

For example, here is a simple script which the master can use to increase a `score` variable. The `scoreText` is updated for everyone in `OnDeserialization`.

```cs
[UdonSynced] private int score;

[SerializeField] private TextMeshProUGUI scoreText;

// The script owner can call IncreaseScore anywhere to increase the score by 1.
public void IncreaseScore()
{
  score++;
  RequestSerialization();
  OnDeserialization()
}

public override void OnDeserialization()
{
  scoreText.text = score.ToString();
}
```

### `[FieldChangeCallback]` instead of `OnDeserialization()`

The approach above works fine for simple scripts. However, if you script has multiple synced variables, your `OnDeserialization()` method may become quite large. Consider using `[FieldChangeCallback]` with a Property instead. It is similar to the Udon Graph's `OnVariableChanged`node.  For example:
```cs
[UdonSynced, FieldChangeCallback(nameof(Score))] private int score;

private bool Score
{
  get => score;
  set
  {
    score = value;
    scoreText.text = score.ToString();
  }
}

[SerializeField] private TextMeshProUGUI scoreText;

public void IncreaseScore()
{
  Score++;
  RequestSerialization();
}
```

### `[FieldChangeCallback]` execution order issues

<p class="callout info">I've lost a lot of time identifying this issue. Please learn from my mistakes! 😁</p>

If you have multiple networked variables, watch out when using `[FieldChangeCallback]`. When a `[FieldChangeCallback]` happens, **other networked variables may not be updated yet.** In other words, if your networked variables depend on each other, you may want use `OnDeserialization()` instead.

Notably, the owner of the script will not suffer from this issue. If you're seeing no issues as an object's owner, but outdated variables on remote clients, you may be running into issues with `[FieldChangeCallback]`'s execution order!

## What else?
<details>
    <summary>There's more I'd like to write about... Let me know if any of these sound interesting! 😁</summary>
  
- Avoid Update(), use delayed events instead.
- Did you know that FixedUpdate() depends on your monitor's refresh rate?  Yeah.
- Use synced variables, avoid networked events, if you can.
- FieldChangeCallback is great.
- Name your classes and methods properly.
</details>