Improbable Icon

Request for Feedback: Experimental MonoBehaviour Components

feedback-request

#1

Hey folks!

Now that v10 has been out for a while, I’m really keen to hear any feedback you might have about the new Unity MonoBehaviour Components. Interested in the good, the bad, and the ugly :slight_smile:

If you’re not using them, I’d also be interested in hearing why :wink:

Thanks!
:support:


#2

Hey @Morrison,

I have been experimenting with the Monobehaviour components and so far I have not used them extensively because of the following:

  1. They don’t always seem to show the correct info in the inspector - when I boot up a Unity Worker (not client) that is the only one in my simulation it still says it is not authorative or won’t show the data at all
  2. Coordinates cannot be displayed - the Coordinates class is not serializable and has no property drawer; this is one of my most important things I would like to see
  3. The editor is unwieldy - it is too large and I only seldom want to see the message transfers, I am more interested in the state contained in the component
  4. I get confused whether state is available - I am not sure when to check that it is enabled or authorative, meaning that I add a callback for when it is enabled when I just want the state and the delaying of state is sometimes also an issue (see 5)
  5. State is only available after the callback triggered - in MonoBehaviours I sometimes depend on the state of a component in the OnEnable method; with Readers / Writers the MonoBehaviour will wait to become enabled until the state is available but with the Components it doesn’t. This means that I would need to delegate the initialization of my MonoBehaviour until an unknown time, which means I need to add extra checks in my FixedUpdate, Update and LateUpdate to verify that the MonoBehaviour is ready before handling the data.

Some of my feedback may be based on misunderstanding, but that is feedback too, but I currently stick with Readers / Writers because they are more predictable to me.


#3

@draconigra - great (and ridiculously fast) feedback, thanks!

Will look into all of this for the next UnitySDK version :spy:


#4

It makes more sense to use these generated classes as base classes rather than another component added to the prefab and hooked into through an observer pattern. I think it’s much cleaner that way.
E.g

public class PlayerControlsSender : SpatialOsPlayerControlsComponent

Doing this you should also seal OnEnable and OnDisable in SpatialOsComponentBase and instead expose a virtual OnEnabled and OnDisabled.

Adding another script and “hooking” into it seems messy to me and I’m too used to using base classes and the use of interfaces.


#5

I’d prefer not; there is a reason that inheritance is basically an anti-pattern. In most modern languages you cannot extend from multiple base classes and that means that if these components are base classes that I am no longer able to introduce my own structure but am forced to stick to that of Spatial.

This means that my code becomes inherently tied to Spatial and makes it harder to migrate to a newer, bc-breaking, version of the platform or a different platform altogether.

One other solution to your feedback would be to generate MonoBehaviour extensions that will provide helper methods to the MonoBehaviour class with which you can easily retrieve such a components.


#6

I agree with you. I haven’t used the generated monobehavious much so I haven’t seen the problems caused by this. I could probably work around this and create my own abstract implementation to fit my needs.

That could actually work. Also I’m currently trying to come up with a way I can use interfaces in a workflow like this. Such as implementing an IHealthComponent’s HealthUpdated(…)


#7

Echoing the sentiments of draconigra, I would also like to add that variable names would look more in line with the base-Unity style if they had this function called on them:
https://docs.unity3d.com/ScriptReference/ObjectNames.NicifyVariableName.html


#8

Came in at v10 without prior experience with spatial. I’m using the experimental MonoBehaviours pretty much exclusively because it matches how we were doing networked entities in our previous implementation (Bolt, a more traditional client/server stack). That being said I haven’t formed a super strong opinion either way yet.

The way I’m currently using these is to have something like a PlayerBehaviour that requires both a SpatialOsWorldTransformComponent and a SpatialOsPlayerComponent, and then I will read and write to various parts of the entity during the update loops. We’re trying to keep our data separated into separate (SpatialOS) components where appropriate and so we can split authority between client and server, but retain most of the code in a single (Unity) component. We’re finding this seems to serve fairly well for being able to reason about all the logic in one place, rather than worrying about how different components are interacting with each other. It’s maybe a bit against the grain of how Unity is set up by default, but so far it’s helping our team.

Agree with @draconigra in terms of not deriving from the generated classes - as well as trying to avoid inheritance, I find it helpful to keep it clear what is network-synced state and what is local-only state.

Likes:

  • Events and commands seem slightly easier to send
  • I know that I’m managing whether or not the component is enabled.

Dislikes:

  • Also not crazy about seeing the updates directly in the editor as an always-on thing. Personally I would prefer being able to enable logging of all message coming in and going out of the network (maybe this is available and I haven’t found it yet?)

Requests:

  • I believe OnComponentReady fires before authority has been granted? It looks like even on a component that has authority, I get HasAuthority as false in the Ready callback. There have been a couple cases where I’d like to use this to set up different behaviour based on whether I’m authoritative or not.
  • Access to the client id of the client sending a command. Using the regular command callbacks with a write I believe I could read that out of the request, it would be good to have that exposed on the new CommandResponseHandle handlers.