๐Ÿ‘๏ธโ€๐Ÿ—จ๏ธ LiveWatch | Debug with full history of changes

LiveWatch is a powerful debugging tool for real-time monitoring of any variable type, with a full history of changes.

Tired of spamming Console with endless values to find bugs? Want to monitor not just the current game state but the entire history of changes? Introducing LiveWatch โ€” the unique debugging tool that lets you track any variable of any type with every change recorded. Experience the full history of your values, utilize advanced search queries, apply conditional formats, and much more!

:link: USEFUL LINKS :link:
Pro | Lite | Quick start | Manual | Reference API | Support | Discord

:rocket: KEY FEATURES :rocket:

  • Full Change History :scroll:
    Capture every change in your variables over time, making it easy to monitor the state of your game or identify sophisticated bugs. Minimal setup required.

  • Any type supported :hammer_and_wrench:
    Watch any possible type โ€” basic types (int, string, bool, float, double, etc.), collections (Dictionary, List, Array, HashSet, etc.), or any other classes from Unity or your own. No Reflection is used at runtime for complex types to achieve maximum performance.

  • Powerful search :magnifying_glass_tilted_left:
    Utilize complex queries to search through all recorded values based on their types and variable names. Queries are unlimited and connected via boolean operators, providing infinite possibilities.

  • Advanced customization :artist_palette:
    Change the color format for any variable name or value to highlight important data, including conditional formats based on the values themselves.

  • Adjustable view :straight_ruler:
    Modify height and width in Cell mode using simple shortcuts based on your needs, or switch to Graph mode to visualize the maximum amount of data changes over time.

  • Extra text :memo:
    Add metadata to every pushed value, giving more context about what caused the change. Inspect automatically added stack traces if an exception occurs during the update of your variable.

  • Flexible API :counterclockwise_arrows_button:
    Add new watches with a single call, and they will be tracked automatically. Or you can push values directly from anywhere in your project as often as needed. All features are accessible through a versatile, well-documented API.

  • Save/Load functonlaity :floppy_disk:
    Store your variable data as binary files and inspect the recorded values on different devices or projects, providing you with enhanced debugging capabilities.

:hourglass_not_done: CURRENT LIMITATIONS :hourglass_not_done:
LiveWatch is a powerful tool, though not without its limits. Many of these current limitations are temporary and will be resolved in version 2.0.0.

  • LiveWatch uses code generation, making it significantly faster than System.Reflection-based solutions. It can handle many variables efficiently, but tracking complex variables may still impact performance, so use it carefully.

  • Due to code generation, LiveWatch cannot monitor non-public members in custom-generated types. To track them, youโ€™ll need to watch these variables directly or expose them via public properties.

  • Currently, LiveWatch is available only in the Unity Editor. For build use, you can save variable data to a binary file and inspect it in the Editor. Remote debugging capabilities are coming soon.

If you have any inquiries or need assistance, feel free to ask questions! :light_bulb:

4 Likes

New version 1.0.2 is live!

Changelog:

  • Fixed error preventing non-dev builds
  • Improved performance of SetSortOrder (regenerate your watches to apply these changes)
  • Partially reduced generated code size (more changes in the next update)

Also we created a Discord server for supporting and discussion LiveWatch. Feel free to join to provide some feedback, report bugs or just ask questions regarding the tool if you consider buying it!

New version 1.0.3 is live!

Changelog:

  • Nested generic types generation support
  • Min/Max values shown in Graph mode
  • DontDestroyOnLoad included in WatchCreator by default
  • Added logs for unsupported generation types (e.g. System.Object)
  • Added pragma instructions to avoid warnings in Console

New version 1.0.4 is live!

Changelog:

  • Fixed manual push visual issues
  • Added Generate empty all menu option in window
  • Improved WatchManager script template (previously known as WatchCreator)
  • Current column index exposed to LiveWatchWindow.SelectedColumnIndex

New version 1.0.5 is live!

Changelog:

  • Added support for changing decimal places from both WatchReference and schema
  • Sorting order can now be set from a schema
  • SetAlwaysCollapsable can be used in a schema
  • Fixed visual bugs related to Clear in the window
  • Horizontal scrollbar now sticks to the right by default
  • Added Collapse All Rows option in the window menu
  • Improved value cell GUI for better readability and visuals

Does it support logging values during update/methods or is for end of frame only?

There are two dufferent ways of tracking values: auto and manual. And both allow you to track values in any place/moment.
In the first scenario you can call Watch.UpdateAll() (which triggers all auto variables) not just from LateUpdate(), but from any other place like usual Update(), and then using ScriptExecutionOrder ensure that it invokes earlier or in the middle of execution.
In the second scenario you can directly push a value from any place you want just like you can do it using Debug.Log

New version 1.0.6 is live!

Changelog:

  • Fully redesigned the info area in the window
  • Added stack trace support for variable creation and pushing
  • Introduced adjustable min/max modes for cell progress bar calculation
  • Added support for custom action buttons on variables


New version 1.0.7 is live!

Changelog:

  • Added object reference support for Scene and Project entities, allowing Unity objects to be located directly from the window
  • Enabled KeyCollectionMode to display arrays and lists like dictionaries
  • Introduced the UpdateOnce feature to force performance-heavy and non-changing members to update only once
  • Optimized generated code files for better readability and smaller size
  • Fixed watch sorting issues in various scenarios

New version 1.0.8 is live!

Changelog:

  • Schema hash code calculation reworked to produce consistent results across all OS
  • Destroy All Watches option added to the window
  • New API methods in WatchReference to directly add children of basic types
  • Minor visual improvements to the window

I am having bit troubles with ecs and this asset. I donโ€™t quite understand how do i get component data with .GetOrAdd method and does calling .GetOrAdd multiple times for same path name cause memory leaks. Example code like towerdefence code would be appreciated for ecs use cases. Also can the Watch.UpdateAll called multiple times in a frame?

Hey! I am going to add full ECS demo in the next updates. Meanwhile let me explain you how itโ€™s supposed to be used. First of all, you are right, Watch.GetOrAdd with getter is supposed to be called once, otherwise it will produce garbage every call. So for cases with ECS components retrieved in OnUpdate itโ€™s better to use Watch.Push which works similar to usual Debug.Log

Here is a small example

public partial class MobHealthSystem : SystemBase
{
    protected override void OnUpdate()
    {
        Entities
            .ForEach((Entity entity, ref MobHealth mobHealth) =>
            {
                 // Get or add mob health watch inside empty MobHealths parent watch
                 // Make sure to generate MobHealth type via code generation or just push a single field like `mobHealth.CurrentHealth`
                 var healthWatch = Watch.GetOrAdd<Any>("MobHealths")
                    .GetOrAdd<MobHealth>($"{mobHealth.MobId}"); // or .GetOrAdd<int>($"{mobHealth.MobId}")
                 Watch.Push(healthWatch, mobHealth); // or Watch.Push(healthWatch, mobHealth.CurrentHealth)
            }
    }
}

Regarding UpdateAll method itโ€™s completely up to you where to call it and how often, including several times per single frame. Just remember that every call will trigger all watches created via Watch.GetOrAdd to update there values based on getters you passed to them

Let me know if you need further assistance!

1 Like

New version 1.0.9 is live!

Changelog:

  • Fixed an issue where search didnโ€™t work in runtime when new values were being added
  • Added new pre-generated Unity type watches in the WatchUnity class
  • Improved Next/Previous triangle indicators and added a blue version for search results
  • Save API slightly changed
  • Development build requirement lifted
  • Changed behavior of ShowOnlyMember and IgnoreAllMembersDeclaredInClass. Now ignores all other members, including those from base classes

New version 1.1.0 is live!

Changelog:

  • Major performance improvements, achieving near-zero allocations at runtime through caching
  • Added Roslyn integration to support code generation even when compiler errors are present
  • Fixed minor bugs