Hi everyone!
We’re cooking up a special update for the VRChat Worlds SDK: Reworking how networking “ownership” is handled in VRChat and Udon. This should make multiplayer worlds more stable by fixing long-standing issues for world creators.
… But this means entering the Danger Zone since it may break existing VRChat worlds. That’s why we want to share our plans with creators to ensure we’re all on the same page.
We’ll release more detailed patch notes soon, but here’s a sneak peek at our current draft:
- The timing of the
OnPlayerLeft
event has been fixed. TheVRCPlayerApi
instance is now guaranteed to be valid in the event’s callback. LocalPlayer
is now guaranteed to be valid inStart
andOnEnable
.- Fixed several internal issues with ownership and owner transfer.
- Improved the stability of VRChat’s object sync.
The Quest to hunt a bug on live
Aside from the updates above, though, there is one particular issue that we are trying to tackle: Quest and Mobile players breaking instances by suspending the app or putting their devices into sleep mode.
This has been reported to us a lot over the past few weeks, and it often causes popular worlds such as No Time Two Talk or Super VR Ball to end up with “broken” instances.
The general problem is that when a device enters sleep mode or suspends the app, there is a timeout of approximately 4 minutes before the user gets kicked. During that time, the user will not run any Udon code in general, which includes networking.
More details
If you are wondering why we don’t time users out immediately, it would give mobile users a terrible user experience.
Imagine you take off your Quest to wipe off some sweat, grab a drink, put it back on, and… you’ve been disconnected, need to rejoin, and lost all your progress.
Or worse: You’re playing a VRChat game on your phone when someone sends you a DM. You click the notification, respond with “lmao,” tab back into VRChat… and you’ve been disconnected. Yikes.
Changing the 4-minute grace period is still up for debate. For now, we’ve opted to leave it at the default values given to us by our internal systems.
The actual bug is that this timeout will not always apply. Players may stick around for hours instead of minutes. We are working on fixing this in a separate, standalone patch.¹
Once that bug has been fixed, the 4-minute timeout would work as expected again. But that’s the core issue: Instances may break even if the timeout works as expected.
So, we dug a bit deeper.
Mastering the Quest (Master Transfer)
The affected worlds seem to have one thing in common: They only break if the instance master (docs, more docs) gets stuck this way. Wouldn’t it be nice to just swap the master away when someone’s device goes to sleep?
Well, we can. Our systems allow us to switch the master client at runtime, even without the current master leaving.
This is fine for our own systems, but we don’t know how it’ll affect your systems. As such, we want to gather your feedback on this. Here are some details on what we’re talking about (warning, technical!):
- Currently, the master behaves as follows: (Unfortunately, this is not fully explained in our documentation.)
- The first user joining an instance becomes the network master.
- The only time the master can switch is when the current master leaves the instance.
- When switching, the player that has been in the instance the longest among the remaining players will be chosen as master.
- This means, in your current scripts, it is viable to only ever check if you become master when someone else leaves.
- You don’t need to check every frame, because it can only happen in that event.
- Master status can only ever be given to a player, as removing it happens after Udon execution has already stopped.
- As a side note, we already recommend not relying on this way of networking. Explicit ownership checks should be used instead.
- Introducing what we call “Master Transfer” would change the above in a few ways:
- Master can now be taken away from a player even if they remain in the instance.
- This will transfer ownership of all implicitly owned objects. For example, if the master called
SetOwner
on something, that owner would keep it. Anything that never hadSetOwner
called will be transferred to the new master. - As before, when the current master leaves, a new master will still be chosen.
- What could this break?
- Any world that doesn’t expect master to be taken away from a player without them leaving (i.e. if Udon caches
Networking.IsMaster
at any point.) - Any Udon scripts that only check for master changes in
OnPlayerLeft
. - Prefabs that rely on any other aspect of the existing master behavior.
- Any world that doesn’t expect master to be taken away from a player without them leaving (i.e. if Udon caches
- Despite this, we’ve seen that it produces good results in the worlds mentioned above - that is, it might break things, but it definitely fixes others.
- Since PC players never go to sleep², this would only affect cross-platform worlds (for now?)
- The above also implies that when master switches, the new one will not be the oldest in the instance (since that, by definition, would be the one that just went to sleep)
- We’re considering changing this aspect separately. When the current master leaves, the new could instead chosen based on other factors (for example, preferring PC clients or choosing players with a stable internet connection).
- We believe the potential of breaking content with just this change is low enough that it could be worth releasing it unconditionally.
- In theory, all of this can be dynamically toggled per instance, so there’s the possibility of gating this behind world settings (e.g. an option in the SDK, or even similar to how the avatar scaling toggle on the web works)
- Whatever we decide on, we will document the specifications properly this time so you know what you can rely on (and which parts you shouldn’t!)
We would love to hear your feedback on these changes! We recognize the potential for breaking things here. But we see this as a more reliable fix for an issue plaguing several high-profile worlds.
Drop us any notes below, and we’ll monitor this thread for a while to see what you say. Aside from fixing the “indefinitely stuck” bug, nothing has been decided here yet.
And stay tuned for more updates on the (hopefully less polarizing for existing content ) networking open beta mentioned in the intro :)
Footnotes
¹ If you have any details on the “indefinitely stuck” issue, or know how to reliably trigger it, we’ll take any hints!
² Clubs don’t fill themselves, and timezones are hard, you know?