Skip to content

feat: tool to enable monobehaviours only on server or client #477

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

Closed

Conversation

LPLafontaineB
Copy link
Contributor

@LPLafontaineB LPLafontaineB commented Feb 10, 2022

Description (*)

This PR adds a NetworkBehaviour that can be placed on a NetworkObject to make sure certain MonoBehaviours can only be enabled on active servers or active clients by using specific interfaces that those MonoBehaviours would inherit. This would remove that responsibility from those MonoBehaviours. It would also allow us to make some of them not be NetworkBehaviours anymore since it was mostly used for the OnNetworkSpawn to enable/disable themselves.

As an example, I have included in this draft PR an implementation of this feature with the interactive door.

Some pros of this solution:

  • Provides a unified solution for something we currently need to do in a lot of different places
  • Allows us to change some NetworkBehaviours back to just MonoBehaviours
  • Provides a single point on which to configure which MonoBehaviours are executed on clients and which are executred on servers

Cons:

  • Adds weight to the actual prefabs and in-scene GameObjects
  • Needs us to make sure that all MonoBehaviours that should only be enabled on a client/server implement the correct interface and that this NetworkBehaviour is added to every prefab and in-scene GameObject that uses it

Related Pull Requests

Issue Number(s) (*)

Fixes issue(s): When implemented, should fix MTT-1683 & MTT-2433

Manual testing scenarios

  1. ...
  2. ...

Questions or comments

Contribution checklist

  • Pull request has a meaningful description of its purpose
  • All commits are accompanied by meaningful commit messages
  • All new or changed code is covered with unit/integration tests (if applicable)
  • All automated tests passed successfully (all builds are green)

Inheriting from this abstract class insteead of a NetworkBehaviour allows a script to be disabled on Awake and only enabled in a client or a server specifically
using Unity.Netcode;
using UnityEngine;

namespace Unity.Multiplayer.Samples.Utilities
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This file will be moved to the Utilities package when the PR will leave the draft status. I kept it here to make testing and iterating easier since ParrelSync doesn't sync the packages folder automatically

@SamuelBellomo SamuelBellomo added the 5-Design Review Draft to review design ideas before committing to future work label Feb 17, 2022
@LPLafontaineB
Copy link
Contributor Author

The issue this PR fixes could also be the cause of MTT-2475, but hard to verify since we don't have consistent reproduction steps for that bug yet


namespace Unity.Multiplayer.Samples.Utilities
{
public interface IClientOnlyMonoBehaviour
Copy link
Contributor

Choose a reason for hiding this comment

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

So if those interfaces are tightly coupled to monobehaviour and netcode, any reason we wouldn't just have an abstract class that inherits from NetworkBehaviour and has SetEnabled as abstract method?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

An earlier version of this used inheritance, with a single class inheriting NetworkBehavior with a protected field telling if it was meant for a server or a client. The disabling/enabling was handled by that abstract class in its Awake, OnSpawn and OnDespwn events.
The advantage was that we did not need a second script to enable/disable it, but it came with more restrictions that I wasn't really happy with. First, we would need to make sure to call the base methods inside those three methods if we wanted to override it in daughter classes. Also, it would mean that if a specific class needs that behaviour, all its parents would have to have it too, which might not make sense. i.e. class A is a client-only netbehaviour inheriting from class B that doesn't need to know if it is on a client or on a server. In this case, if we want to restrict A to only clients, we would have to have B inherit this abstract class, even though B doesn't require it.

Copy link
Contributor

Choose a reason for hiding this comment

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

I see. Yeah makes sense. I wonder if there could be a way to dynamically add the enabler without requiring us to remember to add it. It's too bad "RequireComponent" doesn't work on interfaces.
Or we could have some editor script magic with some reflection...?

Copy link
Contributor

Choose a reason for hiding this comment

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

@LukeStampfli @pdeschain @fernando-cortez what do you guys think?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We could add "RequireComponent" to the classes implementing these interfaces themselves I suppose, but it's still not as plug-and-play as I hoped it could be

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thinking back on it, would adding this recommendation as remarks in the interface descriptions be sufficient?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think using an interface here is better than using inheritance. With the updated xml docs on the interfaces I think it is easy enough to understand how to use this.

{
if (IsClient)
{
foreach (var behaviour in gameObject.GetComponents<IClientOnlyMonoBehaviour>())
Copy link
Contributor

Choose a reason for hiding this comment

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

OnNetworkSpawn would be called with network pooling correct? This has the potential to be a very costly spawn, GetComponent isn't performant

Copy link
Contributor

Choose a reason for hiding this comment

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

especially if there's multiple multiple spawns with pooling

Copy link
Contributor Author

@LPLafontaineB LPLafontaineB Feb 28, 2022

Choose a reason for hiding this comment

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

Oh you're right, that would be super costly. Maybe I should cache all of this in its Awake method? Another solution could be to expose a list to the editor, but that would require us to manually enter all netbehaviours, and that would be even more work than what this tool is trying to simplify

Copy link
Contributor

Choose a reason for hiding this comment

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

yeah caching would be good

@SamuelBellomo SamuelBellomo added 4-On Hold PR can't proceed because it's blocked or is otherwise waiting on something. and removed GDC-cherrypick labels Mar 8, 2022
@SamuelBellomo
Copy link
Contributor

on hold until we have true solution

@SamuelBellomo
Copy link
Contributor

Adding this for all PRs that have been opened since this new flow has been added. Please add your changelog here project changelog file and/or package changelog file

@LPLafontaineB LPLafontaineB deleted the feature/tool-to-enable-only-on-server-or-client branch October 3, 2022 15:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
4-On Hold PR can't proceed because it's blocked or is otherwise waiting on something. 5-Design Review Draft to review design ideas before committing to future work
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants