fix: unregister NetworkPlayerLoop systems from PlayerLoop#588
fix: unregister NetworkPlayerLoop systems from PlayerLoop#588JesseOlmer merged 9 commits intorelease/0.1.0from
Conversation
|
Can you add a description of how a tester would test this? I realize it would have to be manual, but can we say something like "hit play on a project, wait for it to get into a certain state, then stop and observe the console to have / not have _____"? |
JesseOlmer
left a comment
There was a problem hiding this comment.
Help me understand what's going on here. Why do you say NetworkUpdateLoop will still tick systems after we stop? NUL doesn't do the ticking - it just adds systems to the PlayerLoop before Awake... why are our systems still running but systems like behaviourupdate, audio, input etc. aren't having issues?
| { | ||
| if (stateChange == PlayModeStateChange.ExitingPlayMode) | ||
| { | ||
| PlayerLoop.SetPlayerLoop(PlayerLoop.GetDefaultPlayerLoop()); |
There was a problem hiding this comment.
This doesn't feel right. We start with CurrentPlayerLoop, not DefaultPlayerLoop, so feels odd overwriting any other customizations with the default loop.
There was a problem hiding this comment.
Why do you say NetworkUpdateLoop will still tick systems after we stop?
DomainReload happens when we enter PlayMode and that'd cause NUL to be injected into PlayerLoop.
However, when we exit PlayMode (stop playing), nothing reloads so that PlayerLoop still executes its systems and NetworkUpdateLoop systems are still being ticked therefore NUL still ticks INetworkUpdateSystem instances underneath.
As I mentioned in the PR description, the proper handling of this scenario is to unregister from NUL on OnApplicationQuit, OnDestroy, OnDisable but sometimes that's not the case, people might forget and/or somehow unregister codepath might not be executed.
If this is supposed to be a fix for Noel's #558 / MTT-529 can you please note that in the PR description or title somewhere.
No, we're just playing safe here and revert PlayerLoop changes back when we exit PlayMode in the Editor.
This is not a fix for #558 — this is just hardening.
why are our systems still running but systems like behaviourupdate, audio, input etc. aren't having issues?
I can't paste codes here for obvious reasons :) but I can say that they're being protected if not playing. That's not a PlayerLoop logic, that's systems' own logic to execute or skip. PlayerLoop is always around and being ticked, it never stops. Systems under PlayerLoop might pause/stop/start or do whatever they want. They're being registered into low-level engine ticking loop, in this case NetworkUpdateLoop is still being ticked by the PlayerLoop — that's completely normal.
This doesn't feel right. We start with CurrentPlayerLoop, not DefaultPlayerLoop, so feels odd overwriting any other customizations with the default loop.
We only do that when we stop playing in the Editor (exit PlayMode), not when we enter PlayMode.
(We start with the default playerloop after domainreload anyway, systems relying on playerloop injection should already re-register after domainreload).
… exiting PlayMode in the Editor
| [RuntimeInitializeOnLoadMethod] | ||
| private static void Initialize() | ||
| { | ||
| #if UNITY_EDITOR | ||
| EditorApplication.playModeStateChanged += stateChange => | ||
| { | ||
| switch (stateChange) | ||
| { | ||
| case PlayModeStateChange.EnteredPlayMode: | ||
| InjectSystems(); | ||
| break; | ||
| case PlayModeStateChange.ExitingPlayMode: | ||
| UninjectSystems(); | ||
| break; | ||
| } | ||
| }; | ||
| #else | ||
| InjectSystems(); | ||
| #endif | ||
| } |
There was a problem hiding this comment.
hmm, I think we should have a good comment block explaining what's going on here :P
will put that in too!
| } | ||
|
|
||
| #if UNITY_EDITOR | ||
| private static void UninjectSystems() |
There was a problem hiding this comment.
We might want to comment on what this is doing and why this is important?
(or at least replicate the comments in Initialize)? (maybe)
There was a problem hiding this comment.
I did comment in the Initialize() method above, do you think that's not enough?
JesseOlmer
left a comment
There was a problem hiding this comment.
Today seems like a PERFECT day for a couple of unit tests :)
| { | ||
| var playerLoopSystem = customPlayerLoop.subSystemList[i]; | ||
|
|
||
| if (playerLoopSystem.type == typeof(Initialization)) |
There was a problem hiding this comment.
nit: there is a ton of copy/paste and weird { scoping here. Could just extract method that takes a type for the system and a type for the network subsystem :)
There was a problem hiding this comment.
sure, I'll try to make it look fancier :)
| // + childSystem | ||
| newSubsystemList[systemPosition] = childLoopSystem; | ||
| // + systemsAfter | ||
| Array.Copy(parentLoopSystem.subSystemList, systemPosition, newSubsystemList, systemPosition + 1, parentLoopSystem.subSystemList.Length - systemPosition); |
There was a problem hiding this comment.
Just so I am clear is there a reason we are doing a copy twice? I feel like there is a missing check here.
There was a problem hiding this comment.
we copy from 0 to systemPosition (systemsBefore)
then we set childLoopSystem at systemPosition (childSystem)
and finally copy from systemPosition + 1 to the end (systemsAfter)
we don't double-copy, it is basically: half + 1 + half = all + 1
if code doesn't read like that, I might comment more and/or introduce more local variables to indicate what's going on more clearly.
UnregisterLoopSystems()to unregister systems injected into thePlayerLoopby theNetworkUpdateLoopNetworkUpdateLoopdoes NOT cause any side-effects onPlayerLoopTryAddLoopSystem&TryRemoveLoopSystem)