I am currently implementing the multiplayer part of our game and had a few problems along the way that i could not immediately find solutions to.
So here is a little thread where i will post problems and their solutions that i come across while using unet so i don’t forget about them … and maybe it is also of some help to others
1. Different prefab for the client and server
(I am assuming you are using the NetworkManager)
You have to create a custom spawn handler on the client to do this.
On the server, spawn your prefab and use AddPlayerForConnection like you normally do:
//Add this to OnServerAddPlayer() in your NetworkManager
//Load prefab. It MUST have a NetworkIdentity
GameObject _prefab = Resources.Load("Server/Player") as GameObject;
//Create an instance
GameObject _object = Instantiate(_prefab);
//Send spawn message to client and make him the owner
NetworkServer.AddPlayerForConnection(conn, _object, playerControllerId);
Now on the client you do this:
//Add this to OnStartClient() in your NetworkManager
//Get SERVER Prefab
GameObject _serverPrefab = Resources.Load("Server/Player") as GameObject;
//Create a custom handler for the server prefab, so we can spawn a custom client prefab
ClientScene.RegisterSpawnHandler( _serverPrefab.GetComponent<NetworkIdentity>().assetId, SpawnPlayer, UnspawnPlayer );
And finally add the handlers on the client:
GameObject SpawnPlayer(Vector3 position, NetworkHash128 assetID)
{
//Finally: Load the client prefab. It must NOT have a NetworkIdentity! This is important
GameObject _clientPrefab = Resources.Load("Client/Player");
//Create an instance
GameObject _object = Instantiate(_clientPrefab);
//Add a NetworkIdentity
_object.AddComponent<NetworkIdentity>();
return _object;
}
void UnspawnPlayer(GameObject inObject)
{
Destroy(inObject);
}
2. (Fragmented) network channels are not working
You are most likely using the NetworkManager and trying to change connectionConfig by code and manually adding channels with connectionConfig.AddChannel(…).
To make this work, don’t forget to set
customConfig = true;
before making any changes to connectionConfig.
If you don’t set customConfig, the channels will be added and you can use them, but they won’t be of the QoS type you defined.
Alternatively, just create a new NetworkConfig and use that when calling StartServer(…);
3. I don’t want to use the default channel to send stuff around
For some reason, you can still use [RPC] with unet and the example i followed used them. But you should not. Instead, use [ClientRpc]. You can then use channel to set the … well … channel
[ClientRpc(channel=2)]
This also works for [Command]
If you wan’t to send large data around (database / long json string), QosType.ReliableFragmented is your friend.
4. I want to give control/ownership (NOT authority) of two gameobjects to a client, but with AddPlayerForConnection i can only use one.
This is actually very easy but is not that clear in the documentation (at least for me):
When calling AddPlayerForConnection(conn, player, playerControllerID) you just increase playerControllerID for every new object you want the player to control.
//Spawn 100 units and give control to the client.
//Honestly, you should not do that but create a single manager for this .. but as this is an example ... ;)
GameObject _prefab = Resources.Load("AwesomeUnit") as GameObject;
for(int i=0; i<100; ++i)
{
GameObject _object = Instantiate(_prefab);
NetworkServer.AddPlayerForConnection(conn, _object, i);
}
5. Send custom data over the network
Use NetworkServer.RegisterHandler and Send(…)/SendByChannel(…)/etc. for this.
//Define a custom message type
public class MsgTypeCustom{
//Add a new type and give it a unique id
public const short OnReceiveDatabase = 1001;
//You can add more Types here, just increase the id
}
//Register a handler for the custom message
NetworkServer.RegisterHandler(MsgTypeCustom.OnReceiveDatabase, OnReceiveDatabase);
//Custom Message class which will hold our data
public class MsgDatabase : MessageBase
{
public string someText;
public int stuff;
}
//Send custom message. We are sending from the server here, but you can also send from client, of course
[Command]
void Cmd_SendDatabase()
{
if (!isServer)
return;
//Create new message
MsgDatabase _msg = new MsgDatabase();
//fill message with data
...
//Send message
connectionToClient.Send(MsgTypeCustom.OnReceiveDatabase, _msg);
}
//Receive the message
void OnReceiveDatabase(NetworkMessage inMessage)
{
//"parse" message so we can access the data
var database = inMessage.ReadMessage<MsgDatabase>();
Debug.Log(database.someText);
}
to be continued