Thumbnail Pitfalls in Unity networking

Door: Thijs Zumbrink
17-08-2016 12:34

Here are some problems I encountered when adding networking to a previously single-player game. Some implementations worked fine for single-player, but are incompatible with a straight-forward multiplayer implementation in Unity. The results in-game can be quite puzzling!

Most early issues you encounter during the conversion can be solved by checking if the code runs as the local player, with authority, etc. Some method calls must be converted to Commands or ClientRpcs. Object instantiation and destruction must be performed via special calls. But this is all well explained in the documentation.

That leaves us to the more puzzling problems!

Problem: Dynamically added components are not synchronized/sent between client and server.
Solution: Make sure the prefab already the necessary component, but disable it until it is needed. Change the code that originally adds the component into one that enables it.

This way the client and server already know what components a prefab has, as long as it's registered in the NetworkManager.

Having disabled components leads to:

Problem: Server-side objects are missing obvious initialization even though your Start() method looks great and passes its assertions.
Solution: Move the initialization (setting references and asserting them) to Awake(). This makes sure they are executed even though the component is disabled. OnEnable() can also be used.

I didn't totally understand why this problem popped up, but in some cases the solution was as simple as renaming Start() to Awake().

Problem: Cannot send a command with a Prefab reference as a parameter.
Solution: Normally the recommendation for sending GameObjects is using their Net ID. But a prefab doesn't have one. To solve it, use the Asset ID, like so:

public void SomeClientFunction (GameObject prefab) {
NetworkHash128 assetId = prefab.GetComponent<NetworkIdentity>().assetId;
CmdCommunicate(assetId);
}

[Command]
public void CmdCommunicate (NetworkHash128 assetId) {
GameObject prefab = ClientScene.prefabs[assetId];
Instantiate(prefab); // etc.
}


Problem: Command parameters lose polymorphism.
Solution: Do not send the object but a simple identifier. Use a factory to construct the object again.

I had the problem with an Item class and a UsableItem subclass. I used a UsableItem as an argument to another method with an Item parameter. When the game was still single-player, this worked well, but I had to change it into a Command. This demoted the object to an Item object, losing the polymorphism. Fortunately I already had an ItemFactory that knows how to build the correct class for an ItemIdentifier, so the fix was simple.

More information about this issue can be found here.

Reacties
Log in of registreer om reacties te plaatsen.