[Released] Transform Changes Debugger

Get It on Asset Store | Website | Documentation

Have you ever tried to debug transform that’s not behaving as it should?

  • maybe in some random frames, position is not where it should be - making it ‘jitter’ a bit?
  • perhaps its rotation is completely messed up?
  • or scale goes all odd destroying the shape?

I bet you did and you’ve likely found that it’s DIFFICULT to pinpoint the exact code/game-object that’s causing the issue, as:

  • transforms can be changed MULTIPLE times per frame and EVERY frame
  • they can be changed by absolutely ANY object
  • standard debugging methods are just not enough - attaching a debugger to find specific issue takes AGES, finding where to put a breakpoint is HARD and recompilation every time is simply FRUSTRATING

I know, I’ve had to battle with those more times than I’d like to admit. This tool is a solution that’ll change the way you troubleshoot from painful to simple.

VIEW ALL TRANSFORM CHANGES IN AN INTUITIVE NODE-GRAPH
FRAME-BY-FRAME

Any change, any transform, any frame - displayed in an easy to navigate node-graph with powerful GUI that’ll enable you to quickly identify hard to find transform issues.

No more guessing in your debugging process - every change will be recorded and displayed, you’ll quickly get information about:

  • Game Object that initiated change (eg. Mover-01)

  • with a single click you can see that object in Hierarchy View - this goes beyond just seeing script that causes the issue, you may be after a specific object instance as the issue could be due to individual setup

  • Script and Method name

  • exact place in code where change originated (eg. HardToFindScript.cs - method: IntroduceTransformJitterJustToFrustrateDeveloper())

  • navigate directly to the code with a mouse click to find out why it’s causing issues

  • New Value

  • actual value that’s been set, this makes it much simpler to pinpoint changes that are out of line

  • Actual method Call and method arguments that caused the change

  • all methods/setters affecting transform will be captured

  • could be Transform.set_postion setter

  • or more complex Transform.Translate(float x, float y, float z)

  • whatever it is - you’ll get those details

REPLAY CHANGES IN GAME/SCENE VIEW
Not only you can view and inspect changes in a friendly manner - you can go one step further and REPLAY them directly in Scene/Game view with a single click.

This means you don’t have to focus on raw numbers you can simply and visually inspect suspicious changes and directly see if they cause the issue you’re trying to find.

QUICKLY IDENTIFY AND TEMPORALIRY DISABLE SPECIFIC TRANSFORM MODIFIERS TO FIND THE ONE THAT’S CAUSING ISSUES
Tool groups changes by originating Game-Object-instance / Script and Method-name into Transform Modifiers

  • this makes it easy for you to see at a glance which code is affecting the object in current frame-range
    It also allows you to quickly turn them on/off via checkbox directly from gui with NO compilation needed!
  • you can now instantly turn them off one by one and see in Game/Scene view how your tracked object is affected
  • with that approach, it’ll only take you few moments (instead of sometimes a few hours) to pinpoint that hard to find code that’s causing the issue

VERY SIMPLE SETUP
Setup is pretty much non-existent:

  • import the asset
  • add ‘TrackTransformChanges’ script to objects you want to be tracked
  • hit play

That’s it. No-fuss.

The tool is designed to integrate into your workflow seamlessly, you should see its load time under 0.5f second (and that is ONLY when you’re using it).

WELL DOCUMENTED API ALLOWS YOU TO EXTEND BEYOND WHAT I THOUGHT OF
GUI is built on top of API that’s well documented and allows you to programmatically:

  • track specific transform changes
  • skip changes based on passed predicate/s
  • access changes data structures that can be grouped by object / frame / TransformModifier

With that, you can tackle more complex debugging scenarios when you have a better idea of what you’re after.

Have a look in docs pages to see what’s avaialable:

WHAT IS NOT SUPPORTED (YET)

  • physics originating changes - gravity / rigidbody movements (say via AddForce()). For now, it’s best to temporarily turn rigidbody off when debugging
  • changes made outside of the main thread
  • methods changing more than a single transform property, eg ‘SetPositionAndRotation’ - will be captured as a position change (you’ll still get correct information about method and method arguments)
  • production builds - while this tool will work in production build it’ll likely affect performance - it’s been designed as an editor / debugging tool.
  • NET Standard 2.0 API Compatibility level - currently you have to use .NET 4.x

Nice Tool.
However, they are too many warning messages for a clean install.

  • Remove the double directives (using statements at the top). They cause unnecessary warning messages.
  • Add a null check on nodes before calling nodes.Clear() in the Clear method of XNode.NodeGraph class.
  • Maybe create a private method of GetThreePointAngle in the AngleBetweenPoints class, and have the GetThreePointAngleSigned180 and GetThreePointAngleUnsigned360 call it. When those methods call the GetThreePointAngle method, it gives the Obsolete method warning.

Other than those minor things, this is a very useful tool. Nice work.

@NelsonHurst glad you like it and appreciate your feedback, I’ll get those sorted for the next release.

Hi,

I attempted to use your asset but ran into some issues.

#1. If you have Odin installed, the asset does not compile successfully after import. There are a number of namespace additions/changes that must be done.

#2. After making those changes, it will successfully compile but not track transform changes, even after patching all User Code assemblies and adding a Track Transform Changes component to the GameObject in question.

It does say “No methods found to patch” next to the enabled Assemblies.

Do you have any suggestions on what I can change to maybe fix it?

Thanks

Hi @CW3MH6 ,

I’ll double check with Odin installed as I didn’t test that before.

I think it depends on the changes you had to make, perhaps some change actually affected functionality.

Can you please try to use it in the project without Odin (just to test that it’s that and not something else).

Alternatively if you have a small reproduction project I can have a look.

Thanks,
Chris

Hi @ChrisHandzlik

I’ve ran into some of the same issues as CW3MH6, plus a few more. I’m using Unity 2021.3.0f1 for this.

First the Odin Inspector issues. In order to get the asset to compile I had to add the following code to InputAttributeDrawer.cs, OutputAttributeDrawer.cs, and InNodeEditorAttributeProcessor.cs:
using TransformChangesDebugger.Editor.XNode;
I also had change line 18 in GraphAndNodeEditor.cs to read:
NodeEditorWindow.Open(serializedObject.targetObject as global::XNode.NodeGraph);
And line 49 of the same file to read
NodeEditorWindow w = NodeEditorWindow.Open(graphProp.objectReferenceValue as global::XNode.NodeGraph);
Once those changes were made, the asset would compile successfully.

At least until I changed from .NET Standard to .NET Framework. Once I made that change, there was an error in TransformPatches.cs, relating to the variable jumpLabelAfterSetter, due to it being used while unassigned. The assignment for that variable happens in an if statement, and the compiler seems to think there’s a codepath where instructionsInjectedBeforeCurrentInstructions can evaluate as true, without jumpLabelAfterSetter being set. Worked around this by changing line 229 to read Label jumpLabelAfterSetter; = new Label();

Next issue is patching time. I make substantial use of assembly definitions, both for my own code, Unity packages, and for third party assets. Adding even a core subset of assemblies for the character controller (I use Opsive’s UCC), packages like Cinemachine, and my own code, entering play mode takes in excess of 60 seconds on my computer (Ryzen 5900X CPU).

Then, in play mode, the object tracker isn’t detecting any changes to an object that has the Track Transform Changes component attached, regardless of what assemblies are patched for tracking. Unfortunately I don’t have further time to debug this at the moment. Strangely the object tracker does work in your sample scenes, so I’m not quite sure what is happening here. I know for sure that at least one of the assemblies I’ve selected is manipulating the transform of the game object, so I’m not sure why I’m not seeing any moves. This issue occurs regardless of whether Unity is in release or debug mode.

Finally, there’s an odd bug when leaving play mode that causes the Assembly list to act as if it is still in play mode. The only workarounds I’ve found are either restarting Unity, or toggling between release and debug mode.

1 Like

Thanks @SideSwipe9th , I’ll make adjustments to fix those compile time errors.

The timing to process larger assemblies might not be something that can be easily addressed. Those should be significantly faster after first processing (when assembly is scanned to find all instructions that call transforming methods).

The changes however should show unless the transform is adjusted by not utilizing methods exposed in the Transform.cs (eg. moving them via physics).

If you have a small project where the issue can be replicated I can have a look and see what I can do there.

@ChrisHandzlik
Hi,

I recently asked you some questions about MissingUnityEvents.

I’m using custom playable graph to interact with MxmMotionMatching(Animation plugin with burst and job system),
But often encounter difficult to debug Transform glitch (even does not 100% happen).

Wish I have this honor to test the compatibility of this plugin with the Job system in Unity 2022 LTS version,
thank you!

Hi @makaolachsiungca , I’ve sent you code. Please let me know how you got on.

First thing - I had been chasing a camera position issue for hours…bought this tool and within 30 minutes found the problem (and that included the install and looking at how to use it). That is awesome. Thank you for making this available on the Asset store, it potentially saved me another several hours/days? of trying to track this down. And now that I know what was doing it, I realize I wasn’t even close yet…

Second thing - I did hit a couple of issues when using it. The first was the error related to jumpLabelAfterSetter being used before initialization. I corrected that with Label jumpLabelAfterSetter = new Label(); as @SideSwipe9th indicated above.

I was also receiving this:
System.NullReferenceException: Object reference not set to an instance of an object
at TransformChangesDebugger.Editor.TransformChangesDebuggerInitializer+<>c.<.cctor>b__0_9 (System.Object sender, TransformChangesDebugger.API.Patches.RedirectSetterMethodsFromCallingCodeResult result) [0x00001] in E:\Development\Unity\ARPG_Farming_Engine\Assets\TransformChangesDebugger\Editor\TransformChangesDebuggerInitializer.cs:90
at (wrapper delegate-invoke) System.EventHandler1[TransformChangesDebugger.API.Patches.RedirectSetterMethodsFromCallingCodeResult].invoke_void_object_TEventArgs(object,TransformChangesDebugger.API.Patches.RedirectSetterMethodsFromCallingCodeResult) at TransformChangesDebugger.API.Patches.TransformPatches.InterceptMethodsToEnableChangeTracking (HarmonyLib.Harmony harmony, System.Collections.Generic.List1[T] assemblyPaths) [0x00369] in E:\Development\Unity\ARPG_Farming_Engine\Assets\TransformChangesDebugger\API\Runtime\Patches\TransformPatches.cs:135
at TransformChangesDebugger.API.TransformChangesDebuggerManager.Initialize (System.Collections.Generic.List1[T] allAvailableAssyPaths, System.Collections.Generic.List1[T] assemblyPathsChosenToPatchByUser) [0x00080] in E:\Development\Unity\ARPG_Farming_Engine\Assets\TransformChangesDebugger\API\Runtime\TransformChangesDebuggerManager.cs:99
at TransformChangesDebugger.Editor.TransformChangesDebuggerInitializer…cctor () [0x001a2] in E:\Development\Unity\ARPG_Farming_Engine\Assets\TransformChangesDebugger\Editor\TransformChangesDebuggerInitializer.cs:95
UnityEditor.EditorAssemblies:ProcessInitializeOnLoadAttributes (System.Type[ ])

Unity version 2021.3.11f1

@clarson2974 thanks - that’s great to hear. I’m about to publish an update that addresses some of those smaller issues with compilation and few others later today.

PS: if you wouldn’t mind copying and pasting what you wrote above as a review that’d be real help.

Hi,
I seem to be running into the same issues as a couple of the previous posters have when Odin is in the project. Unity version is 2021.3.16f1 LTS). For the NodeEditor error I added
using TransformChangesDebugger.Editor.XNode;
For the XNode.NodeGraph I removed XNode.
It now compiles, however I don’t see anything showing up in the Tracker window.
Here is a video to show the issue

It looks that on latest change that introduced XNode as a separate asm-def (so it doesn’t collide if your already have XNode imported) I’ve missed references that target ODIN pre-processor directive. Sorry about that.

Specifying adjusted namespace in those files will help (also there’s a link at the end for updated version)

using TransformChangesDebugger.Editor.XNode;

for:
InNodeEditorAttributeProcessor.cs
OutputAttributeDrawer.cs
InputAttributeDrawer.cs

and changing line 17 in
GraphAndNodeEditor.cs

from

public override void OnInspectorGUI() {
    if (GUILayout.Button("Edit graph", GUILayout.Height(40))) {
        NodeEditorWindow.Open(serializedObject.targetObject as XNode.NodeGraph);
    }
    base.OnInspectorGUI();
}

to

public override void OnInspectorGUI() {
    if (GUILayout.Button("Edit graph", GUILayout.Height(40))) {
        NodeEditorWindow.Open(serializedObject.targetObject as [B]global[/B]::XNode.NodeGraph); //added global:: before XNode
    }
    base.OnInspectorGUI();
}

will get it to compile

and same for GraphAndNodeEditor.cs line 48

public override void OnInspectorGUI() {
    if (GUILayout.Button("Edit graph", GUILayout.Height(40))) {
        SerializedProperty graphProp = serializedObject.FindProperty("graph");
        NodeEditorWindow w = NodeEditorWindow.Open(graphProp.objectReferenceValue as global::XNode.NodeGraph); //added global:: before XNODE
        w.Home(); // Focus selected node
    }
    base.OnInspectorGUI();
}

I think you’ve also got in touch via email, I’ve sent you link to updated package.

Thank you for your respones, much appreciated. It now compiles, however I still don’t see any of the objects I added the tracker to in the debug window.

Alright,

If you try demo scene - does that work as expected?

If so can you please:

  1. select to patch all assemblies (just in case change is originating from some odd place)
  2. make sure game object has tracker component added (as in demo scene)

If there are still no hits, it’s possible that change will be made via physics or ourside of managed code (eg directly by Unity on c++ side).

If you could share part of your project where issue can be reproduced I’d be happy to have a look.

@ChrisHandzlik

Hey Chris, I sent you a couple emails with coexistence issues with Odin and Ultimate Editor Enhancer. If you could please take a look and let me know if these can be fixed?

I did manage to get rid of the Odin and Ultimate Editor Enhancer coexistence issues by creating a copy of my project and deleting those assets.

However, Transform Changes Debugger is not capturing any data? I did a short video to show my setup.

The demo scene works. So I know it is installed properly. Can you confirm the debugger will track changes on prefabs instantiated at runtime? I assume it would, because this is a must have. Can you see a problem with how I am using the tool in the video?

I tried tracking a simple cube in my startup scene. Nothing was tracked on this either. .

@Zaddo , thanks for the video. Everything looks fine.

I’ve sent you an email with updated files (but I suspect you applied same fix to get Odin error gone) - just to double check you can re-import the changed files to make sure nothing is broken.

I know that you had to make some adjustments with harmony.dll as it’s also used in other asset.

You already checked demo scene (was that done in same project?) - if so then it all looks fine on that front.

For change to be captured transform has to be moved via one of Transform methods / properties (on c# side).

Say changes originating from physics will not be captured or any changes that are not coming from c# side.

With yours am I right thinking that zombies move via NavMeshAgent.Move? If so they won’t be visible, sorry!

@ChrisHandzlik Thanks for the quick reply. I did, delete your asset and re-install a clean copy. The demo scene testing and the video were done in this project with the clean install of Transform Changes Debugger.

A* pathfinding is used for the zombie paths, the character movement is controlled by Opsive’s Ultimate Character Controller, which sets the position/rotation in C# code. I have copied the method below that sets the position, m_Transform is the zombie’s transform.

I rebooted my computer, just to make sure nothing in the Unity state was causing an issue. The zombie movements are still not being tracked by the debugger.

I just tried another test. I created a cube in the main scene (without a collider), and attached the “Track Transform Changes” component. I modified the ApplyPosition Method below to move the cube so it sat on the zombie. The cube movement also was not tracked by the debugger?

When I hit play, the patching assemblies show up for about a minute. And so the code is definitely running to patch and I have included the DLL that is handling this movement.

Any other thoughts?

        protected virtual void ApplyPosition()
        {
            // Apply the position.
            var position = m_Transform.position + m_MoveDirection;
            m_Velocity = (position - m_PrevPosition) / (m_TimeScale * Time.deltaTime);

            m_Transform.position = m_PrevPosition = position;
            m_MoveDirection = Vector3.zero;
            // Update the platform variables.
            if (m_Platform != null) {
                m_PlatformRelativePosition = m_Platform.InverseTransformPoint(m_PrevPosition);
            }
        }

Alright tha ks, leave it with me. Today / tomorrow I’ll get Opsive asset and will have a look.

If it’s also using harmony maybe it’s that somehow causing issues.

Ps: the asset asks to use .net 4.x backend, just to double check you’re not ignorong the prompt when launchng project? As in you’re not using .net standard backend?