Skip to content

fix: unregister NetworkPlayerLoop systems from PlayerLoop#588

Merged
JesseOlmer merged 9 commits intorelease/0.1.0from
fix/editor-unreg-netupdateloop
Mar 15, 2021
Merged

fix: unregister NetworkPlayerLoop systems from PlayerLoop#588
JesseOlmer merged 9 commits intorelease/0.1.0from
fix/editor-unreg-netupdateloop

Conversation

@0xFA11
Copy link
Copy Markdown
Contributor

@0xFA11 0xFA11 commented Mar 11, 2021

  • implement UnregisterLoopSystems() to unregister systems injected into the PlayerLoop by the NetworkUpdateLoop
  • implement a register-then-unregister test to verify NetworkUpdateLoop does NOT cause any side-effects on PlayerLoop
  • refactor for performance (use array ops instead of lists), for better namings (inject → register) and styling (extract duplicate code into helper methods: TryAddLoopSystem & TryRemoveLoopSystem)

Copy link
Copy Markdown
Member

@NoelStephensUnity NoelStephensUnity left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!
I like how you simplified!

@mattwalsh-unity
Copy link
Copy Markdown
Contributor

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 _____"?

Copy link
Copy Markdown
Contributor

@JesseOlmer JesseOlmer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't feel right. We start with CurrentPlayerLoop, not DefaultPlayerLoop, so feels odd overwriting any other customizations with the default loop.

Copy link
Copy Markdown
Contributor Author

@0xFA11 0xFA11 Mar 11, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

@JesseOlmer
Copy link
Copy Markdown
Contributor

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.

Comment on lines 241 to +260
[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
}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, I think we should have a good comment block explaining what's going on here :P
will put that in too!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done ✅

@0xFA11 0xFA11 changed the title fix: reset PlayerLoop back to DefaultPlayerLoop on ExitingPlayMode in the Editor fix: uninject NetworkPlayerLoop systems from PlayerLoop when exiting PlayMode in the Editor Mar 11, 2021
}

#if UNITY_EDITOR
private static void UninjectSystems()
Copy link
Copy Markdown
Member

@NoelStephensUnity NoelStephensUnity Mar 11, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might want to comment on what this is doing and why this is important?
(or at least replicate the comments in Initialize)? (maybe)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did comment in the Initialize() method above, do you think that's not enough?

Copy link
Copy Markdown
Contributor

@JesseOlmer JesseOlmer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Today seems like a PERFECT day for a couple of unit tests :)

{
var playerLoopSystem = customPlayerLoop.subSystemList[i];

if (playerLoopSystem.type == typeof(Initialization))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 :)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, I'll try to make it look fancier :)

@0xFA11 0xFA11 changed the title fix: uninject NetworkPlayerLoop systems from PlayerLoop when exiting PlayMode in the Editor fix: unregister NetworkPlayerLoop systems from PlayerLoop Mar 13, 2021
@0xFA11 0xFA11 requested a review from wackoisgod March 13, 2021 18:25
// + childSystem
newSubsystemList[systemPosition] = childLoopSystem;
// + systemsAfter
Array.Copy(parentLoopSystem.subSystemList, systemPosition, newSubsystemList, systemPosition + 1, parentLoopSystem.subSystemList.Length - systemPosition);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just so I am clear is there a reason we are doing a copy twice? I feel like there is a missing check here.

Copy link
Copy Markdown
Contributor Author

@0xFA11 0xFA11 Mar 14, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor

@wackoisgod wackoisgod left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGMT

@JesseOlmer JesseOlmer merged commit 8b2e771 into release/0.1.0 Mar 15, 2021
@JesseOlmer JesseOlmer deleted the fix/editor-unreg-netupdateloop branch March 15, 2021 20:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants