lyuma / Av3Emulator

Emulator for VRChat's Avatars 3.0 system, built on the Unity PlayableGraph API
Other
538 stars 32 forks source link

Inconsistency with "Reload Domain" off #92

Closed DorCoMaNdO closed 1 year ago

DorCoMaNdO commented 1 year ago

Thanks to Dreadrith I recently learned that entering play mode/building can be made a whole lot faster and reduce crash occurrences significantly by enabling Edit -> Project Settings -> Editor -> Enter Play Mode Settings (Experimental) and leaving Reload Domain off (which reloads scripts when entering play mode), it worked great, crashes stopped, everything looked to be working just fine, except that in a second (randomly fixed itself for now) and third project I encounter an issue where Av3Emulator doesn't animate the avatar properly, so they enter the "motorcycle" pose, every other feature of the emulator seems to work fine, and using Gesture Manager without the emulator seems to pose the character correctly, as does enabling Reload Domain, but then I'm back to square one with a 10-20% chance of crashing when entering play mode.

This is reproduced both in "legacy" projects as well as VCC, and with Av3Emulator versions 2.8.11, 2.8.12 and 3.0.1.

lyuma commented 1 year ago

Sorry, experimental unity features were not taken into consideration in the design of Av3Emulator. I am not familiar with how Reload Domain off handles static variable references in C#, so I do not know enough to resolve this issue. I would need help from someone using experimental unity features to debug it.

Since you say it also hits motorcycle pose, it may offer a clue about the cause of the crash. This hints at failing to destroy the animator's PlayableGraph object: Under normal usage, PlayableGraph (an extremely well tested and implemented Unity api /s) is not very battle tested. Hence, any mistake at all, even calling functions in the wrong order during initialization or uninitialization, may cause Unity to crash if the graph was not cleaned up correctly.

Seeing the connection with internal animator state and the way domain reload works, this may indicate an internal bug to unity that is difficult or impossible to workaround in Av3Emulator.

I'd welcome more info on the exact issue if you or someone has time to debug it. Otherwise, I am unlikely to personally provide a resolution, and I would recommend enabling Domain Reload when using Av3Emulator.

DorCoMaNdO commented 1 year ago

I am not familiar with how Reload Domain off handles static variable references in C#

Reload Domain means that the scripts' AppDomain is being re-created when you enter play mode, this means all scripts are effectively reloaded (it is also why entering play mode can take a while with projects that have a bunch of scripts, or even just Av3Emulator, with Reload Domain off entering play mode is practically instant), this is the cause of frequent crashes I've been having, not necessarily due to Av3Emulator, the main culprit was/is suspected to be ControllerEditor having to re-auth (because it was reloaded, it no longer "remembers" it previously authenticated) and failing, it may also be other scripts (I've had a couple of crashes lately without ControllerEditor and/or without Av3Emulator, although to a far lesser degree).

As for static variables - they do not persist when Reload Domain is on (the default behavior), which means that they do persist with Reload Domain off, so if you've got a static constructor or a field/property initialized in declaration (basically the same thing as a static constructor, in either case the behavior would be that as soon as the class is referenced for the first time, those values are assigned) those values aren't "renewed" as you might expect with the default Reload Domain behavior. Unity offers you an attribute that would let you create a method to explicitly reset/re-initialize static objects (although you can probably do that when entering play mode), it is explained in the docs here: https://docs.unity3d.com/Manual/DomainReloading.html

Since you say it also hits motorcycle pose, it may offer a clue about the cause of the crash

The motorcycle pose happens when Reload Domain is off, it is not a precursor to a crash, Av3Emulator simply fails to pose the avatar, everything else with Av3Emulator that doesn't involve posing the avatar seems to function correctly, including animator debugging, the expressions menu (clothing/hues/gimmicks/etc) and non-local clones, hand gestures won't animate when stuck in the motorcycle pose, but the parameter values will change, which causes face expressions to work. On a project where the avatar is posed correctly even with Reload Domain off, everything works just fine, including the hand gestures.

This is really the only thing I'm reporting here, sometimes the avatar gets posed correctly and sometimes not, and it appears to differ with something regarding the project/avatar configuration that I can't seem to determine, however this same behavior is not exhibited by Gesture Manager, which has posed the avatar correctly in every project where Av3Emulator failed.

I've re-tested with version 3.1.0 and the issue persists, the new Default Pose option does not seem to affect the behavior. There's also an odd "DynamicBone not found in the project." prompt that appears when entering play mode or when using Restart Emulator, although that message appears regardless of whether Reload Domain is on or off, in both a project where Av3Emulator poses the avatar regardless of Reload Domain on/off and in a project where it only poses the avatar with Reload Domain on. For now I'm reverting to 3.0.1 as the prompt is bothersome.

lyuma commented 1 year ago

however this same behavior is not exhibited by Gesture Manager

Thank you thank you thank you. This was the tip I needed to isolate the issue

Using PlayableGraph Visualizer and toggling individual layers on and off, I was able to identify that the AvatarMask were being set to null after one play (they are stored in a static dictionary).

After about an hour of messing around with C# property getters, I managed to write the code in a way to workaround this. I have no idea why it works now, or why it didn't work before. None of this stuff makes sense. Thanks, Unity.

It still crashes some, but maybe it no longer crashes as often now that I fixed it?

Well, if users see a checkbox labeled Experimental, users will do what users do and click all the checkboxes. Maybe it works a little more often than it used to.

I can't really offer support for random experimental editor features. But since a few people ran into this I did something. Try 3.1.1 and see if it fixes the issue you ran into.