≡ SpacerZ ≡
Knowing when a script fails and receiving feedback on what is actively occurring within is one of the most crucial aspects of developing any project. This essay aims to provide you a solid foundation to establish your own debugging system.
Console Logging And You
Debug.Log is the focal point of how we get our feedback. Its cousins; LogError will neatly sort your console window into its three main categories of response.
Console messages should be brief, providing just enough information to tell you what happened at a glance. Contents should describe where in the script it happened, pointing you in the right direction to correct any mistakes.
For example: Let's say we have a function that gets passed a GameObject. We'd likely want to make sure that object isn't null, so we could use a precondition check:
However, this fails to provide adequate information to go off: Where did this fail? What function caused this to fail? ect.. We can resolve the first question by referencing the game object the script is attached to in the second parameter field for the logger:
Debug.LogError("Reference is not set !", this.gameObject);
Now when we click on the message inside our console, the hierarchy in our GUI will expand to reveal the offending game object this script is attached to.
We can further expand on this by directly informing ourselves of the functions name via the "$" Interpolator, this allows us to convey variables easily without the usage of string conversions. By using the "nameof" Expression, we can get the name of any variable or function without statically declaring it.
Debug.LogError($"{nameof(Start)} : Reference is not set !",
this.gameObject);
This is essentially what I use as my error logging, but you can change the formatting to suit your own needs; add more information, the variable itself, ect..
I like to keep a text document to make log templates easily copy-pastable, you can use mine below!
// Error Debug.LogError($"[<color ="red">Error</color>] :
{nameof(Function_Name)}\n _message_", this.gameObject);
// Information Debug.Log($"[<color ="cyan">Info</color>] :
{nameof(Function_Name)}\n _message_", this.gameObject);
// Event Debug.Log($"[<color ="blue">Event</color>] :
{nameof(Function_Name)}\n _message_", this.gameObject);
Beautification & Customizing
Eventually, you'll have many, many log messages strewn about. Errors to notifications, warnings and coordinate displays. Logs may become overwhelming, but there are steps we can take to mitigate repetitiveness.
This section is primarily your own preference. Overtime you will come to establish your own formatting.
We can colorize our messages by using the color style tag. Doing so will make important messages more visible in the console.
It should be noted that Udon itself has colored messages. To prevent confusion, it's best to avoid the color purple and yellow.
Debug.LogError($"[<color="red">Error</color>] : {nameof(Start)} :
Reference is not set !", this.gameObject);
Note, the "$" operator is not needed to colorize your messages.
By default, Unity offers two preview lines for your messages. You can utilize the secondary line quickly by adding '\n' to specify the new line.
Failing Fast
Remember that precondition check* from the start? I want to quickly emphasize the importance of them and the fail-fast principle: Checking your passed parameters, serialized and public fields on startup is VERY important to ensuring no problems occur later.
By testing and forcing these checks early, you can catch problems before they occur. Whether you forget to assign a reference in the inspector, or a variable is too large, checking your variables for issues before they occur will save you a ton of headache later.
It doesn't take much time to write them, and you'll be ensuring the overall health of your code by doing it!
Udon 3.8.1 Beta
There is a new update for Udon revolving around custom network events. These events have parameters and can grab information about the requesting player.
This is an experimental feature, allowing network calls to send unchecked data could be an issue. Having established boundary checks will help prevent unwanted users from influencing data over the network. Here's an example:
You can also grab the calling players' API. This allows you to check if a specific player is sending constant network requests and clogging your traffic.
VRCPlayerApi callingPlayer = NetworkCalling.CallingPlayer;
It could be useful to know who is causing the issue. You could use the API to get the display name or user ID to directly identify them in your logs.
...
This post was brought to you by my Patrons.
This post is an archive and does not contain proper formatting.