-
Notifications
You must be signed in to change notification settings - Fork 450
fix: nested gameobject networkmanager scenename exception #1432
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: nested gameobject networkmanager scenename exception #1432
Conversation
added fix into the unreleased section of the changelog.
Changed NetworkManager.GetParent to be renamed to NetworkManager.GetRootParent to better reflect what the method does. Updated NetworkManager.GetRootParent to automatically return the root parent without having to pass in the GameObject that the NetworkManager component is attached to. Added the ability to override the server and client creation process for MultiInstanceHelpers. We could expand upon what portions of MultiInstanceHelpers can be overridden, but this at least puts a framework in place and should be useful to handle construction of customized NetworkManager instances in place of the default MultiInstanceHelpers way.
// We must always move the root GameObject into the DDOL | ||
DontDestroyOnLoad(GetRootParent()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have mixed feelings about this.
We might just throw an exception here (similar to DontDestroyOnLoad
API throwing "only root objects can be marked DDOL") and expect user to do the right thing so that they could be much more intentional.
One thing I don't want to encourage here is to fix issues "automagically" for the user — they should face invalid use cases and align things accordingly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so to be clear, maybe the fix is just throwing a descriptive exception here.
having said that, it looks like issue #1417 never got an exception but instead got a "not found" error.
perhaps we should properly throw an exception to better inform user what's going on so that they could understand and react?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe the fix is just throwing a descriptive exception here.
Object.DontDestroyOnLoad is basically a "one off" method from SceneManager.MoveGameObjectToScene which has the following requirement:
You can only move root GameObjects from one Scene to another. This means the GameObject to move must not be a child of any other GameObject in its Scene.
This makes it a requirement to provide the root GameObject to Object.DontDestroyOnLoad.
never got an exception but instead got a "not found" error.
Don't forget the second part of what the user reports in the issue:
and everything related to the network will not working.
It can get many different types of errors when this happens for different reasons.
So, keeping in alignment with the default UnityEngine requirements solves the issue. For NetworkManager (only), it should be perfectly valid to place the NetworkManager component's GameObject as a child under another GameObject (or several depending upon what the user need might be).
Throwing an exception I am going to try to stay away from for this one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I disagree. DDOL on a child object is not OK in Unity therefore I believe we should not magically fix user errors here but instead just shout them out loud.
We could chat about this but I'm also happy to defer this one to @andrews-unity or @mattwalsh-unity
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I do agree about the requirement to send the root parent into the DDOL. I also think that we could throw an exception or warn the user in the editor. The only thing I wonder about is whether it is the right thing to throw an exception under this condition since everything NGO is really "a child" (component) of GameObject. If you have GameObject-A as a root parent with no NGO components and GameObject-B with a NetworkObject component as the child of GameObject-A but you want to make sure the NetworkObject (GameObject-B) itself is moved into the DDOL then the big question is do we assert/except on this condition or do we just hunt for the root parent and move that into DDOL?
I am open to both lines of thinking and will see if I can stir up a discussion on this topic to discuss further.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, per our slack exchange, I'd like to go ahead and do the following:
- (having conferred with @TwoTenPvP) Make NetworkManager always "DDOL" - remove the setting. That is we never ever want to have the act of changing a scene implicitly tear down a NM
- require NetworkManager to be sitting on a GameObject which itself is a root-level component, else complain as loudly and proudly and early as possible (ideally in the editor, ideally to block running at all)
- (not in this PR) investigate how we can make "NM is a component of a GO" not a thing
public interface IMultiInstanceHelperOverrides | ||
{ | ||
bool OnCreateNewClients(int clientCount, out NetworkManager[] clients); | ||
|
||
bool OnCreateHostServer(out NetworkManager server); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
huh? what's going on here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This provides developers with the ability to override the client and host-server creation process for the MultiInstanceHelpers class by implementing IMultiInstanceHelperOverrides and assigning the implementation to MultiInstanceHelpers.MultiInstanceHelperOverrides. There have been many instances where this capability would be useful in the past, but in order to be able to test it does require nesting the NetworkManager which needs to be done prior to initialization.
Maybe I should put some better comments above it? :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why it's in this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is for testing. It provides the ability to override how we construct the server and client NetworkManagers.
This was the solution I came up with to test a nested NetworkManager GameObject. It also provides developers with this added functionality.
This might change as we might just throw an exception under this condition and as such would be an editor specific test as opposed to runtime (i.e. no need for using any kind of MultiInstance test).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^ see my comments
currentGameObject = currentGameObject == null ? gameObject : currentGameObject; | ||
if (currentGameObject.transform.parent != null) | ||
{ | ||
return GetRootParent(currentGameObject.transform.parent.gameObject); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can transform.root
work here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes! Awesome catch! I am about to check in that adjustment.
@@ -117,7 +159,8 @@ public static void Destroy() | |||
// Destroy the network manager instances | |||
foreach (var networkManager in NetworkManagerInstances) | |||
{ | |||
Object.DestroyImmediate(networkManager.gameObject); | |||
// Always destroy the root parent |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if we don't want to destroy the parent? This is making parents of NM's special.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For MultiInstance specific testing scenarios, yes that would make this uniquely handled.
I am not aware of a condition where we want to persist the parent GameObject of a nest NetworkManager GameObject, but if we keep this approach then I could add some additional functionality. If we go the path of just throwing an exception then the majority of the unit/integration test specific code would be removed and this would no longer be here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, see my one comment
// We must always move the root GameObject into the DDOL | ||
DontDestroyOnLoad(GetRootParent()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, per our slack exchange, I'd like to go ahead and do the following:
- (having conferred with @TwoTenPvP) Make NetworkManager always "DDOL" - remove the setting. That is we never ever want to have the act of changing a scene implicitly tear down a NM
- require NetworkManager to be sitting on a GameObject which itself is a root-level component, else complain as loudly and proudly and early as possible (ideally in the editor, ideally to block running at all)
- (not in this PR) investigate how we can make "NM is a component of a GO" not a thing
The fix for this has been migrated to PR-1484 |
This fixes Github-Issue #1417 (described above)
MTT-1732
PR Checklist
type:backport-release-*
label. After you backport the PR, the label changes tostat:backported-release-*
.CHANGELOG.md
file.Changelog
com.unity.netcode.gameobjects
Testing and Documentation