Skip to content

A wrapper over the Unity Debug class, offering fluent syntax and extra features.

License

Notifications You must be signed in to change notification settings

meredoth/Unity-Fluent-Debug

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Unity Fluent Debug

License Made For Unity Maintenance

  • A wrapper over Unity Debug with some additional functionality. Using fluent syntax supports infinite chaining of debug conditions and statements to display different messages in the console log depending on the state of your game.

  • Supports creating different debuggers and enabling/disabling them depending on your situation (for example you may want to keep you debug logs for your AI enabled but have you debug logs for your stat system disabled).

  • Uses conditions to log debug information and increase performance by not calling debug logs when conditions are false, not calculating expensive boolean logic returned by methods or logging any debug messages when your debug is disabled.

  • Supports a global preprocessor directive to exclude all debug calls from your builds instead of having to comment them out or erase them each time you make a production build to gain performance.

  • Comes with extra extension methods besides the usual Unity's debug methods, like support for speech for windows x64 systems, null checking statements and Execute a method extension after a condition is true.

  • Supports complex condition chaining like If -> statement -> Andif -> statement and statement (see examples)


Getting Started

Copy UnityFluentDebug folder to you Unity Assets folder.

If you want speech support, build the dll from the WindowsTTS folder and add the WindowsTTS.dll to your Unity Assets folder.

Simple Usage

Add the namespace with the following using statement:

using UnityFluentDebug;

The FluentDebugFactory is your entry point.

Create a new fluent debugger with:

private readonly FluentDebug myDebug = FluentDebugFactory.Create();

then use myDebug as you would use the Debug class in unity:

myDebug.Log("Hello World!");

Syntax

Unity Fluent Debug supports fluent syntax, you can chain statements and conditions:

myDebug.If(x > 69).Log("x is grater than 69.");

myDebug.If(x > 4).Log("x is grater than 4.").
        If(y < 2).LogWarning("y is less than 2.");

myDebug.Log("Waiting at the inn").
        If(barbarian.IsNear).Log("A barbarian is near.").
        AndIf(barbarian.AttackMode == AttackMode.Berserk).LogWarning("Watch out.").
        AndIf(barbarian.XPToNextLevel < 5f).LogError("We are going to die!").And().Say("Run for your lives.");

Advanced usage

Unity fluent debug supports some extra functionality like speech or avoiding the evaluation of conditions when you have disabled the fluentDebugger.

The FluentDebugFactory static class

The FluentDebugFactory static class is your entry point. You can create different debuggers by calling the FluentDebugFactory.Create() method:

FluentDebug myDebug = FluentDebugFactory.Create();

if you have compiled the WindowsTTS.dll the FluentDebugFactory is responsible for controlling the speech engine through the following methods:

(WARNING)

The WindowsTTs.dll provides speech only for the Windows x64 systems, it requires:

uses modified code from the The UnityWindowsTTS project.

FluentDebugFactory.InitializeSpeechEngine();

Initializes the speech engine. If you want speech this has to be called before using the Say() method.

FluentDebugFactory.UnloadSpeechEngine();

Unloads the speech engine. You don't need to call this as it gets automatically called every time you exit the play mode.

FluentDebugFactory.SelectVoice(int idx);

changes the voice of the speech engine, depending on the voices you have installed on your machine.

bool FluentDebugFactory.IsSpeaking;

This property returns true while the speech engine is speaking.

bool FluentDebugFactory.IsSpeechEngineInitialized;

This property returns true if the speech engine has been successfully initialized.


The Debuggers

After you have created a debugger with the FluentDebugFactory.Create() method you can call all the usual methods from the Unity Debug class including the isDebugBuild , unityLogger and developerConsoleVisible commands that call the same Unity Debug methods.

There is also the Enabled boolean property which can be used to enable/disable only a specific debugger. For example you may have created two debuggers the myAIdebug for your AI system debugging and the myStatSystemDebug for your StatSystem Debugging. The command myAIdebug.Enabled = false will only disable the myAIdebug debugger, leaving only the myStatSystemDebug statements to be printed to the console (or heard, if you use the Say() statement and the speech engine is initialized).

The Debuggers offer some extra functionality that works well with the fluent syntax.

There are two groups of methods that you can use: statements and conditions. The statements include all the usual methods of the Unity Debug class plus a few extra methods.

You can start with either a statement or a condition, but after that you create a chain that alternates between statements and conditions.

Extra statements

AssertNotNull(object obj, object message)
AssertNotNull(object obj, object message, Object context)

if the obj is null calls a LogAssertion method.

Say(string msg, bool clearPreviousMessages = false)

If the speak engine is initialized, instead of writing in the debug console you will hear the msg through your speakers. the clearPreviousMessages boolean clears the queue of any previous messages so that you can hear the message the time this method is invoked, useful if you have a lot of messages that play, but you need to hear a specific message the time the say method is called.

Execute(Action method)

Executes the method provided as argument, for example:

int x = 0;

private int foo(int i)
{
      Debug.Log("Hello from foo!");
      return ++i;
}

myDebug.If(x == 0).Execute(() =>
         {
            x++;
            x--;
         }).
         And().Execute(() => foo(x)).
         AndIf(x == 0).Execute(() => x = foo(x)).
         And().Log($"x is now {x.ToString()}");

will output in the console:

Hello from foo!
Hello from foo!
x is now 1

The methods:

Enable()
Disable()

will enable or disable the debugger like calling the Enabled property but obey the rules for the statements that get executed only if the proceeding if condition is true, for example:

myDebug.If(true).Log("message 1").
        If(false).Disable().
        If(true).Log("message2").
        If(true).Log("message 3").And().Disable().
        If(true).Log("message 4").
        If(true).Enable().And().Log("message 5");

will output to the console:

message 1
message 2
message 3
message 5

The method:

PlayAudioClip(AudioClip clip, Vector3 position)

is a wrapper over Unity's

PlayClipAtPoint(AudioClip clip, Vector3 position, float volume = 1.0F);

method.


Conditions

If(bool condition)
If(Func<bool> condition)

The next statement will be called if the condition is true. The overload If(Func<bool> condition) is useful to avoid the performance and boxing costs of expensive boolean expressions when you have disabled the debugger.

In Unity the if(somethingExpensive) Debug... and in the Fluent Debugger the myDebug.If(somethingExpensive).Debug... cost performance for no reason when the debug is disabled because you pay the cost of calculating the somethingExpensive in the if statements anyway. With the If(Func<bool> condition) overload: If(() => {return somethingExpensive;}) the boolean expression somethingExpensive is not calculated if you have disabled the debugger.

And()

Use the And() method to add statements together so both of them are only executed if the If() expression before them was true. For example:

myDebug.If( people > 420 ).LogWarning("Hello World").And().Say("Hello Everyone");

will write a warning in the console with the message Hello World and you will hear Hello everyone only if the people variable is greater than 420.

AndIf(bool condition)
AndIf(Func<bool> condition)

The AndIf() method adds a condition that executes the following statement only if the previous condition was true. For example:

myDebug.If(true).Log("citious").
        AndIf(true).Log("altius").
        AndIf(true).Log("fortius");

will print to the console:

citius 
altius 
fortius

and

myDebug.If(true).Log("citious").
        AndIf(false).Log("altius").
        AndIf(true).Log("fortius");

will print to the console:

citius 

but

myDebug.If(true).Log("citious").
        If(false).Log("altius").
        uIf(true).Log("fortius");

will print to the console:

citius 
fortius

the overload AndIf(Func<bool> condition) serves the same purpose as the If(Func<bool> condition) overload.

If the AndIf() method is called without an If() method before them they behave as the If() methods.


Preprocessor Directives

The DISABLE_FLUENT_DEBUG preprocessor directive added to project settings -> scripting define symbols in Unity will disable all Debuggers.


Unity console click

The Unity Fluent Debug uses the [HideInCallstack] attribute so that a double click in the unity console will take you to your own script that calls the debug command. This attribute is supported only in versions of Unity 2022.2 or newer.

In previous versions, if you want when you double click the unity console to be taken to your script instead in one of the Unity Fluent Debug scripts, compile the project in a DLL and put it in your assets folder.


License

This project is licensed under the Apache-2.0 License - see the LICENSE.md file for details. () This project uses modified code from The UnityWindowsTTS project by Virtuality for Safety

The The UnityWindowsTTS project is licensed under the MIT License. See the LICENSE.md file for details.


Acknowledgments

The Speech Engine in this project is a modified version of the https://github.com/VirtualityForSafety/UnityWindowsTTS by Virtuality for Safety which is based on code from Chad Weisshaar

This source code was originally from here