Search Unity

[Solved] Different prefab client / server , (fragmented) network channel not working and other stuff

Discussion in 'Multiplayer' started by dotmos, Oct 21, 2015.

  1. dotmos


    Jan 2, 2011
    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:

    Code (CSharp):
    2. //Add this to OnServerAddPlayer() in your NetworkManager
    3. //Load prefab. It MUST have a NetworkIdentity
    4. GameObject _prefab = Resources.Load("Server/Player") as GameObject;
    5. //Create an instance
    6. GameObject _object = Instantiate(_prefab);
    7. //Send spawn message to client and make him the owner
    8. NetworkServer.AddPlayerForConnection(conn, _object, playerControllerId);
    Now on the client you do this:

    Code (CSharp):
    2. //Add this to OnStartClient() in your NetworkManager
    3. //Get SERVER Prefab
    4. GameObject _serverPrefab = Resources.Load("Server/Player") as GameObject;
    5. //Create a custom handler for the server prefab, so we can spawn a custom client prefab
    6. ClientScene.RegisterSpawnHandler( _serverPrefab.GetComponent<NetworkIdentity>().assetId, SpawnPlayer, UnspawnPlayer );
    And finally add the handlers on the client:

    Code (CSharp):
    1. GameObject SpawnPlayer(Vector3 position, NetworkHash128 assetID)
    2. {
    3.     //Finally: Load the client prefab. It must NOT have a NetworkIdentity! This is important
    4.     GameObject _clientPrefab = Resources.Load("Client/Player");
    5.     //Create an instance
    6.     GameObject _object = Instantiate(_clientPrefab);
    7.     //Add a NetworkIdentity
    8.     _object.AddComponent<NetworkIdentity>();
    10.     return _object;
    11. }
    13. void UnspawnPlayer(GameObject inObject)
    14. {
    15.     Destroy(inObject);
    16. }

    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
    Code (CSharp):
    1. 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
    Code (CSharp):
    1. [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.

    Code (CSharp):
    1. //Spawn 100 units and give control to the client.
    2. //Honestly, you should not do that but create a single manager for this .. but as this is an example ... ;)
    3. GameObject _prefab = Resources.Load("AwesomeUnit") as GameObject;
    4. for(int i=0; i<100; ++i)
    5. {
    6.     GameObject _object = Instantiate(_prefab);
    7.     NetworkServer.AddPlayerForConnection(conn, _object, i);
    8. }

    5. Send custom data over the network

    Use NetworkServer.RegisterHandler and Send(..)/SendByChannel(..)/etc. for this.

    Code (CSharp):
    2. //Define a custom message type
    3. public class MsgTypeCustom{
    4.     //Add a new type and give it a unique id
    5.     public const short OnReceiveDatabase = 1001;
    6.     //You can add more Types here, just increase the id
    7. }
    9. //Register a handler for the custom message
    10. NetworkServer.RegisterHandler(MsgTypeCustom.OnReceiveDatabase, OnReceiveDatabase);
    12. //Custom Message class which will hold our data
    13. public class MsgDatabase : MessageBase
    14. {
    15.     public string someText;
    16.     public int stuff;
    17. }
    20. //Send custom message. We are sending from the server here, but you can also send from client, of course
    21. [Command]
    22. void Cmd_SendDatabase()
    23. {
    24.     if (!isServer)
    25.         return;
    27.     //Create new message
    28.     MsgDatabase _msg = new MsgDatabase();
    29.     //fill message with data
    30.     ...
    31.     //Send message
    32.     connectionToClient.Send(MsgTypeCustom.OnReceiveDatabase, _msg);
    33. }
    35. //Receive the message
    36. void OnReceiveDatabase(NetworkMessage inMessage)
    37. {
    38.     //"parse" message so we can access the data
    39.     var database = inMessage.ReadMessage<MsgDatabase>();
    40.     Debug.Log(database.someText);
    41. }

    to be continued ;)
    markf-hutch, metroidsnes and sYnoptik like this.
  2. sYnoptik


    May 31, 2013
    Awesome I'm stucked on this too. I'm coding a driving simulator that have 3 x 40" monitors for tge front and 3 x 27" monitors for the rear view, also 2 touch screen monitors used for beacon and emergency lights and a last monitor for the dashboard. The current projet (for an airport) is the first one that I use uNet and yeah.... kinda bored. Each station connect to the instructor station that is the server and allow the instructor to manage the IA traffic, follow the simulator vehicule and so on. So each station has and identifier stored locally to determine if the server needs to spawn a drivable car, activate a specific cam, or activate the instructor interface. Now, I'm not sure if I should make the server spawn each appropriate gameobject at client connect or if I should just place the objects where they belong in the scene and assign network ids to the appropriate stations based on their identifiers. Because its an educationnal simulator, I know that exactly whats needed every sessions... Any thoughts on that anyone ?