Supercharging our Debug Workflow in C#: Code Snippets, Enhanced Print(), and Hot Reload
One of the things that I'm really happy with in our project is our custom debug log tools. It's a combination of enhanced Print() functionality combined with code snippets that allow me to quickly type "xx", press tab and I'm able to debug values with their property name exposed next to their value, meaning we can expose MANY values all at once without the data turning into a tossed salad of chaos.
Combined with the Hot Reload asset on the Unity Store (A SAVING GRACE OF THIS ENGINE), I can tab to the IDE at any time, find the offending bit of logic causing me grief, quickly add some debugger logic, tab back to the project and IMMEDITLY get pertinent data to several bits of logic all at once!
It truly has transformed my project for the better.
It's been a rough week, I kinda figured we should do a bit of a more substantial blog actually about gamedev and I've been wanting to share this stuff for a while as I find it SO INCREDIBLY useful. I do have misgivings about being a whiney jackass all the time, even if I feel it is warrented. So anyway, here's some of the stuff I cooked up that has allowed me to debug so much better!
Here is the "BASE" logic that supercharges the usual print functionality and allows for more robust data reporting in the console:
=====BASE LOGIC=====
using System;
using System.Linq.Expressions;
using UnityEngine;
public class Base : MonoBehaviour
{
#region Print Debug Display
public string DisplayDebug(Expression<Func<float>> expression)
{
var returnString = "";
#if UNITY_EDITOR
if (expression.Body is MemberExpression memberExpression)
{
string fieldName = memberExpression.Member.Name;
float value = expression.Compile()();
returnString = ($"{fieldName}: {value}");
}
else
{
float value = expression.Compile()();
returnString = value.ToString("F2");
}
#endif
return returnString;
}
public string DisplayDebug(Expression<Func<int>> expression)
{
var returnString = "";
#if UNITY_EDITOR
if (expression.Body is MemberExpression memberExpression)
{
string fieldName = memberExpression.Member.Name;
int value = expression.Compile()();
returnString = ($"{fieldName}: {value}");
}
else
{
int value = expression.Compile()();
returnString = value.ToString();
}
#endif
return returnString;
}
public string DisplayDebug(Expression<Func<bool>> expression)
{
var returnString = "";
#if UNITY_EDITOR
if (expression.Body is MemberExpression memberExpression)
{
string fieldName = memberExpression.Member.Name;
bool value = expression.Compile()();
returnString = ($"{fieldName}: {value}");
}
else
{
bool value = expression.Compile()();
returnString = value.ToString();
}
#endif
return returnString;
}
public string DisplayDebug(Expression<Func<string>> expression)
{
var returnString = "";
#if UNITY_EDITOR
if (expression.Body is MemberExpression memberExpression)
{
string fieldName = memberExpression.Member.Name;
string value = expression.Compile()();
returnString = $"{fieldName}: {value}";
}
else
{
string value = expression.Compile()();
returnString = value ?? "null"; // Handle null strings
}
#endif
return returnString;
}
public string DisplayDebug(Expression<Func<Vector2>> expression)
{
var returnString = "";
#if UNITY_EDITOR
if (expression.Body is MemberExpression memberExpression)
{
string fieldName = memberExpression.Member.Name;
Vector2 value = expression.Compile()();
returnString = ($"{fieldName}: {value}");
}
else
{
Vector2 value = expression.Compile()();
returnString = value.ToString("F2");
}
#endif
return returnString;
}
public string DisplayDebug(Expression<Func<Vector3>> expression)
{
var returnString = "";
#if UNITY_EDITOR
if (expression.Body is MemberExpression memberExpression)
{
string fieldName = memberExpression.Member.Name;
Vector3 value = expression.Compile()();
returnString = ($"{fieldName}: {value}");
}
else
{
Vector3 value = expression.Compile()();
returnString = value.ToString("F2");
}
#endif
return returnString;
}
#endregion
}
===========================
Once our BASE logic is in our project, we just make sure our scripts are inheriting from our new class by shifting it from a base MonoBehavior, so where it says "SCRIPTNAME : MonoBehavior" at the top of your script change it to "BASE".
===========================
This code snippet will allow you to very quickly type "xx" and then "TAB" to auto generate the appropriate syntax to trigger our enhanced debugs from here you can do the standard string with quotes, or use an exterior variable which will have its value AND its name declared, making it VERY clear what multiple values are. You can also output the object name with the value if multiple objects are declaring values for clarity
=====CODE SNIPPET=====
<?xml version="1.0" encoding="utf-8"?>
<CodeSnippet Format="1.0.0">
<Header>
<Title>print</Title>
<Shortcut>xx</Shortcut>
<Description>Inserts Unity Debug.Log()</Description>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Imports>
<Import>
<Namespace>UnityEngine</Namespace>
</Import>
</Imports>
<Code Language="csharp"><![CDATA[print(DisplayDebug(() => $end$));]]></Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
==============================
And that's it! Once you have access to the enhanced print functionality, and you get the code snippet up and running simply type "xx", press tab, and your cursor will be right in the place where you paste whatever value you want to debug. When printed at runtime if you have this logical setup:
var test = 1;
print(DisplayDebug(() => test));
Instead of exporting only the "1" in the console, it will outpute the variable name with the value:
test: 1
It's so friggin' nice!
That's it, short and sweet blog today that I hope someone gets some value out of (SEE WHAT I DID THERE!?) instead of the usual bitching and moaning.
Ok, back to the bitching and moaning, if this isn't your thing, feel free to look away, it's what you guys do anyhow.
This song is so fucking relevant right now.
Believe it or not, I was kinda thinking of continuing to deescalate the rhetoric. I don't even know my own motivations. Am I fearing a fate akin to Charlies? Do I genuinly feel sympathy for you goofballs? Am I trying to be the bigger man? Do we need to dawn sheep's cloathing so we can be welcomed into the spheres of success in this tech echo chamber?
I honestly don't know.
What I do know is a price needs paying, and you dicklets can't recognize that because you're self absorbed fuck faces who cannot see what you have become as you continue to cash your easy paychecks, and have your backs scratched by the usual peanut galleries.
It truly is a vile and incestuous, pit of smarm fuck this industry remains. I hope that's changing, for all our sake.
Entitled, smarmy, ineffectual, and spiteful is no way to go through life.
Holy shit we are going way harder than was my intention. I really gotta stop listening to the song of the day while I blather these thoughts, but can you blame, me? What a banger!
I kinda wanted to go more in depth with this blog, I didn't go into how to get code snippets up and running, but I kinda can't be assed.
Why am I even posting this blog? Why am I posting resources on how to better create better games? No one gives a shit. No one tries. No one cares.
Everyone knows their troughs will be filled tomorrow morning, everyone knows their reach arounds will be waiting. Great effort, great principle not only isn't rewarded, it is a death sentence any more.
But I couldn't help myself. I love gamedev, I love gaming, and I want it to grow, I want it to be strong and healthy, so here is my small attempt at maybe this info reaching a few of you out there and it improving your work sessions.
It does bother me that instead of focusing the nuts and bolts, the work practices, the logics I'm here trying to save this industry from all the candy asses that have overtaken the whole of this industry, who sit with loaded weapon from afar, knives ready, disguised in the puffs of smoke that blow up their asses that they are the good ones, the smart, the talented, the moral, as all that we value festers.
Anyhow. Just another self incrimination for the void. That if read at all will be seen as nothing more than evil. That's all anything is that doesn't give you affirming back rubs.
It didn't have to be like this, we could be developing in the light of day in a meritocratic industry, where good games rose to the top, and we busied ourselves with the process of gamedev... NOT FUCKING SUBVERSIONS YOU FUCKS.
Oh well, it is what it is. So more pain tonight, more lonely nothing, in the dark muck of this cave.
I think SeaCrit inches forward, ever closer to being a truly radiant form, and if the light ever does touch this project, I fear so terribly what you fuck stains will do to it. You truly are a vile, destructive source for all who do not press their lips against your anuses.
And still, day after day, you cowards hide in your schools of meek.
It's so despicable. Self serving lies always spun as virtue.
Get SeaCrit
SeaCrit
Deceptively Deep!
Status | In development |
Author | illtemperedtuna |
Genre | Action, Role Playing, Shooter |
Tags | Beat 'em up, Casual, Indie, Roguelike, Roguelite, Side Scroller, Singleplayer |
More posts
- We are, in Fact, a Gamedev (I think)3 hours ago
- Turning Point1 day ago
- Grateful3 days ago
- Tired3 days ago
- 321 I'm the Bomb4 days ago
- Serenity5 days ago
- All We Can Do to Keep From Weeping8 days ago
Leave a comment
Log in with itch.io to leave a comment.