I’m trying to get some dirt simple stuff going in UNET and I’m really starting to feel that UNET is the problem and not me.
Here’s the problem:
I want to have a button object in the world. Players can walk up to the button and interact with the button to push it. The object should be host authority but any player can interact with it.
In a sane networking engine, I should be able to send a message through the button object from the client to the server (or better yet, to the authority of the object, but now we’re getting into a more P2P architecture). In UNET, only the client with authority on that object can send messages, meaning that for all server owned objects, there is no direct line of communication from the clients to the server.
As far as I can tell, the way that UNET wants me to do this is to have a giant dumping ground of network calls that exists in the player script. So for this example, it would mean adding a [Command] function to the player script that’s something along the lines of CmdButtonPressed( Button button ). The client would call CmdButtonPressed, send a net message to the server, and the server would execute that function. I would have to write that function so that it would get the Button object in question and then call the ButtonPressed() function in the Button script.
Is that right?
It seems crazy, bloated, and neither object oriented or component driven. I’m forced to have a single object that knows about all possible network calls across my entire game. I’m really hoping I’m wrong here.
“Starting with Unity release 5.2 it is possible to send commands from non-player objects that have client authority. These objects must have been spawned with NetworkServer.SpawnWithClientAuthority or have authority set with NetworkIdentity.AssignClientAuthority. Commands sent from these object are run on the server instance of the object, not on the associated player object for the client.”
Yeah, the problem is that it’s still limited to a single direction of communication i.e. either the client can send to the server (Client Authority) or the server can send to the clients (Server Authority). There’s no way (as far as I can tell) to have the server and client both able to send messages on the same object.
You can look into the SendMessage functions in NetworkClient. It allows you to send messages to the server (or other NetworkConnections) regardless of object state. The only downside is that it’s slightly lower-level than Rpcs and Commands, but that’s pretty much all they are; Wrappers around the NetworkMessage system.
Hmm, this might be what I need. It’s not a channel directly tied to the specific game object instance, but it should at least allow me to keep my network logic contained in the classes that actually use it.
I’m going to make the assumption that Unity must have some sort of guid system for identifying game objects over the network (I’m guessing the net identity component must handle that), so I’ll start working on a solution using this.
Looks like UNET handles this all automagically. If I send a GameObject as a member of the net message, it automatically connects it to the corresponding GameObject on the receiving side.
The messaging system appears to just choose an arbitrary version of the class to call the handler function, though, so you definitely need to send the relevant GameObject with the message, even when sending from that object (not too surprising, since the send function doesn’t know where you’re sending from).
Overall, I should be able to do everything I need with this. Thanks again.
Yeah, messages aren’t connected to objects as you figured out. The only thing is the way you register the message so the right function is called.
Also, for interacting with the world you might be better off handling on your player. This makes it easier to interact with more objects without having to write more netcode, which you usually want to do. I can explain more once I get on my PC if you want.
I’d be interested to hear more about how you would do this. As I mentioned in the original post, I want to avoid a dumping ground file that needs to know about all of the possible network messages. I could probably find a way of generalizing world interactions specifically (a single net message, a game object with a shared interface for different interaction types, and some virtual functions), but I’m not sure it would be worth the hassle.
That’s actually pretty close to what I was going to describe. Your world objects would have some interface, or maybe just a tag, that you would identify it as interactable. When a player tries to interact with it, he just sends a [Command] with some ID of the object, and then the Command will call the appropriate methods on the object on the server. You can of course also just do it with the NetworkMessage system, doesn’t really matter.
Of course having the code on the object is also feasable. But from my experiences with netcode, it’s best to have as little as possible of it, as it can get quite messy if you have a lot of netcode. It also prevents you from having to manage all the message IDs that UNET requires, which is also a plus. Here you just send the ID of the item as data. You could even have a NetworkMessage class that all Interactable objects should take in a method and pass that along from your message, which will hold whatever data you want to go along with the interaction.
That’s interesting, because I’ve found just the opposite in my experience, but most of my experience has been on large scale games with large teams. When you’ve got 20+ programmers all working on multiplayer features, having all of the code in one file is a nightmare.
It’s good to know that I have a few options available, though.
Hm, that may be true. I have only worked with small teams (usually by myself, and up to 3 people programming), so it may very well be different for larger scale.
Either way, both methods would work fine. It’s just a matter of architecture, scalability and maintainability. And it’s hard to learn this from other than experience.