Skip to content

17 – Dev Console: SusConsoleService, SusConsoleDriver

Service:SusConsoleService (sus-core/Runtime/Services/) Driver:SusConsoleDriver (sus-core/Runtime/Services/) Parent plan: LAYER-CONSOLE.md (in package repo)


1. Purpose

In-game dev console: intercepts Unity logs and displays them on top of the entire UI (categoryConsole = 50- the very top), allows you to filter/search and execute teams. The main case is debugging on a device/build without Editor Console.


2. Connection

Wrap in#ifto exclude from release builds:

csharp
#if DEVELOPMENT_BUILD || UNITY_EDITOR
var overlay = SusBootstrap.GetOrCreateOverlay(uiDocument.rootVisualElement);
var console = new SusConsoleService
{
    OverlayHost = overlay,
    ToggleKey = KeyCode.BackQuote, // ~
    MaxEntries = 500,
};
console.Attach(); // subscription to log + hotkey driver
SusConsoleService.Instance = console; // for access from any code
#endif

Attach()does three things:

  1. Subscribes toApplication.logMessageReceivedThreaded.
  2. Creates (or finds)SusConsoleDriverfor surveyToggleKeyVUpdate.
  3. Registers built-in commands (clear, help, filter).

Detach()unsubscribes from the log and hides the UI.


3. Use

User Interface

Click~— the console opens from the bottom (40% of the screen height), dark panel:

ElementDestination
Buttons All / Log / Warn / ErrFilter by type
Search fieldFilter by substring (case-insensitive)
Command input fieldEnter command → Enter → execute
Tab in command fieldCommand name completion
Close console

Colored logs: gray (Log), yellow (Warning), red (Error/Exception/Assert). Autoscroll down for new messages; When manually scrolling up, it stops.

Registering commands

csharp
#if DEVELOPMENT_BUILD || UNITY_EDITOR
SusConsoleService.Instance.RegisterCommand("spawn", args =>
{
    if (args.Length > 0)
        SpawnUnit(args[0]);
    else
        Debug.Log("Usage: spawn <unitId>");
}, help: "Spawn a unit by id");

SusConsoleService.Instance.RegisterCommand("gold", args =>
{
    int amount = args.Length > 0 ? int.Parse(args[0]) : 1000;
    player.Gold += amount;
    Debug.Log($"Added {amount} gold. Total: {player.Gold}");
}, help: "Add gold (default 1000)");
#endif

Built-in commands (registered automatically inAttach):

TeamDestination
clearClear log buffer
helpList of all commands
filter <all|log|warn|error>Toggle filter

4. Architecture

Thread safety

Application.logMessageReceivedThreadedcan be called from a background thread. The records are added up toQueue<SusLogEntry>underlock, ASusConsoleDriver.Update() causesDrainPendingEntries()in the main thread - transfers records to the loop buffer and updates the UI.

###Ring buffer

When overflowing (MaxEntries, default 500) old entries are evicted:

csharp
if (_buffer.Count >= MaxEntries)
    _buffer.RemoveAt(0);
_buffer.Add(entry);

Lazy UI design

UI (_root, _scrollView, toolbar, command field) is built at the firstShow(). When closed, the console does not createVisualElement-ov - zero overhead to render.

Z-order

OverlayCategory.Console = 50 — the top floor of screen-space OverlayHost. The console is always above modals, tooltips, dropdowns, and toasts.

World-space UI (healthbars) is not in this stack: it uses a separate panel under the screens. See 07-overlayhost.md.

World-space panel                         ← UNDER screens (not OverlayHost)
└── healthbar / nameplate / …

Screen UIDocument
├── SusRouteView                          ← screens
└── OverlayHost
     ├── [Transition = 10]
     ├── [Modal      = 20]
     ├── [Tooltip    = 30]  ← above modals
     ├── [Dropdown   = 40]
     ├── [Toast      = 45]
     └── [Console    = 50]  ← console here (topmost)

5. API

SusConsoleService

Method/PropertyTypeDestination
Attach()voidLog subscription + hotkey driver
Detach()voidUnsubscribe + close
Show()voidShow console
Hide()voidHide
Toggle()voidToggle
Clear()voidClear buffer
DrainPendingEntries()voidTransfer records from queue to buffer (main thread)
SetFilter(filter)voidConsoleFilter.All/Log/Warning/Error
SetSearch(text)voidFilter by substring
RegisterCommand(name, handler, help)voidRegister a team
ExecuteCommand(input)boolExecute command line
IsOpenboolIs the console open?
OverlayHostOverlayHostPortal container
ToggleKeyKeyCodeHotkey (default~)
MaxEntriesintRing Buffer Size (500)
Instancestatic SusConsoleServiceSingleton

SusConsoleDriver

csharp
public class SusConsoleDriver : MonoBehaviour
{
    public SusConsoleService Service;

    private void Update()
    {
        if (Input.GetKeyDown(Service.ToggleKey))
            Service.Toggle();
        Service.DrainPendingEntries();
    }
}

SusLogEntry

csharp
public struct SusLogEntry
{
    public LogType Type;        // Log, Warning, Error, Exception, Assert
    public string Message;      // Text
    public string StackTrace;   // Stack (for errors)
    public float Time;          // Time.unscaledTime
}

ConsoleFilter

csharp
public enum ConsoleFilter { All, Log, Warning, Error }

6. Tests

FileTestsWhat covers
sus-core/Runtime/Tests/SusConsoleServiceTests.cs10 playmodeShow/Hide/Toggle, log interception, buffer overflow, filter, search, RegisterCommand/ExecuteCommand, Clear

Open-core: Core & Router MIT · Kit & Game commercial