Search Unity

Sending complex data via RPC argument

Discussion in 'Multiplayer' started by KelsoMRK, Jun 23, 2015.

  1. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Is this possible in the new system? Legacy RPC was fairly restricted in what could be sent as arguments. I tried quickly and the argument seemed to come across null but the documentation doesn't make any mention of what types of arguments can be sent.

    If not, is there another way to achieve this? Perhaps a custom message or SyncVar implementation?
     
  2. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    what do you want to send?
     
  3. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    A custom data structure representing the skirmish map to load for a match.

    We load this at runtime from an XML file so when null came over the wire I briefly experimented with sending the raw XML to all clients in chunks (since NetworkWriter has a length limit) but it seems like some kind of message batching is going on because the same string was being RPC'd multiple times.

    It also seemed like multiple RPC calls in the same frame were being process in reverse order?
     
  4. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    the default channels have a low limit, if you use a Fragmented QoS channel you can send up to 64k packets.
     
  5. hrpbk

    hrpbk

    Joined:
    Jun 24, 2015
    Posts:
    1
    32k byte array is successfully sent, but 33k failed.
    I need to configure something else?
     
    hitmax87 likes this.
  6. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Which channel would that be? If you send larger than 64k does it silently fail or will additional packets be sent until the entire data structure is processed? How does this affect Rpc execution on the other side that needs to use the data?

    Or could this be achieved with a custom message/handler?
     
  7. Shinyclef

    Shinyclef

    Joined:
    Nov 20, 2013
    Posts:
    505
    To clarify a little, you can send up to 64k RPCs/Messages, which get split into multiple packets for you. MTU = Maximum Transmission Unit = max packet size = 1500 bytes.

    You can use any of the channels that say 'fragmented' for this. I used reliable fragmented for sending large messages.
    Set up your channel in the network manager inspector.

    You can achieve this via messages for sure, as I do it myself. I believe you can also do it with RPCs with a channel parameter in the the ClientRPC attribute.
    Something like [ClientRPC(channel = 2)]
    http://docs.unity3d.com/ScriptReference/Networking.ClientRpcAttribute.html
     
    seanr likes this.
  8. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Thanks for clarifying. So if you wanted to send more than 64k (or less than that? since I'm guessing that includes other data inherit in RPCs themselves?) then you'd have to break it up into smaller pieces and send them as individual RPC calls - correct?

    I've seen odd behavior doing something like this. If you chunk a string out and RPC it in a single frame it doesn't come across the wire correctly it seems

    Code (csharp):
    1.  
    2. int index = 0;
    3. while (index < someString.Length)
    4. {
    5.     RpcSendString(someString.Substring(index, 200));
    6.     index += 200;
    7. }
    8. RpcDoSomethingWithString();
    9.  
    If you log the substring here it's correct but if you log it in RpcSendString it is always the same string. Also - someString will be null in RpcDoSomething and log statements for it show up in the console before ones in RpcSendString.
     
  9. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    what channel QoS is that using? You would need a channel type that has "sequence" to guarantee delivery order.
     
  10. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    It's the default one. I was assuming RPCs behaved like the legacy ones where they were always executed in the order they were sent.
     
  11. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    the default channel zero is "Reliable". Try using ReliableSequenced
     
  12. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    How do you even configure this stuff? NetworkManager.connectionConfig is readonly.
     
  13. chrismarch

    chrismarch

    Joined:
    Jul 24, 2013
    Posts:
    472
    Click Advanced Configuration in your NetworkManager inspector
     
    bitbiome_llc and KelsoMRK like this.
  14. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    With Channel 0 set to Reliable Sequenced I did the following

    Code (csharp):
    1.  
    2. // gets raw XML as a string from some file
    3. string content = ReadFileText(filePath);
    4. int index = 0;
    5. while (index < content.Length)
    6. {
    7.     int size = 500;
    8.    if (index + size >= content.Length)
    9.    {
    10.       size = content.Length - index;
    11.    }
    12.    RpcSendData(content.Substring(index, size));
    13.    index += size;
    14. }
    15. RpcFinalizeData();
    16.  
    17.  
    18. [ClientRpc]
    19. void RpcSendData(string str)
    20. {
    21.     someString += str;
    22. }
    23.  
    24. [ClientRpc]
    25. void RpcFinalizeData()
    26. {
    27.    Debug.Log(someString);
    28. }
    29.  
    This results in the log statement reading that someString is null. If I log inside SendData then the logs appear in reverse order with finalize at the top and the XML file reversed in subsequent log statements underneath.

    Result was the same if I explicitly set channel=0 in the ClientRpcAttribute
     
    Last edited: Jun 25, 2015
  15. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    this seems to work fine..

    I dont see how someString could be null with your code.. what is it initialized to?

    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using UnityEngine.Networking;
    4.  
    5. class Data : NetworkBehaviour
    6. {
    7.     static string someString = null;
    8.  
    9.     void Update()
    10.     {
    11.         if (Input.GetKeyDown(KeyCode.Space))
    12.             CmdData();
    13.     }
    14.  
    15.     [Command]
    16.     void CmdData()
    17.     {
    18.         // gets raw XML as a string from some file
    19.         string content = "111111111111111111111111111122222222222222222222222222222222333333333333333333333333333333333334444444444444444444444444444444444444444455555555555555555555555555555555666666666666666666666666666666666666666777777777777777777777777777777788888888888888888888888888888899999999999999999999999999999999999999999999999";
    20.         content += content;
    21.         content += content;
    22.         content += content;
    23.         content += content;
    24.         content += content;
    25.         content += content;
    26.         content += content;
    27.  
    28.         int index = 0;
    29.         while (index < content.Length)
    30.         {
    31.             int size = 500;
    32.             if (index + size >= content.Length)
    33.             {
    34.                 size = content.Length - index;
    35.             }
    36.             RpcSendData(content.Substring(index, size));
    37.             index += size;
    38.         }
    39.  
    40.         RpcFinalizeData();
    41.     }
    42.  
    43.     [ClientRpc]
    44.     void RpcSendData(string str)
    45.     {
    46.         //Debug.Log(str);
    47.         someString += str;
    48.     }
    49.     [ClientRpc]
    50.     void RpcFinalizeData()
    51.     {
    52.         Debug.Log(someString);
    53.     }
    54.  
    55.    
    56. }
     
  16. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    All of your content is identical so how are you determining that the order is correct?

    The string isn't initialized to anything so Debug.Log(someString) outputs Null in the console.

    The only difference I see in your code is you route through a Command - which I didn't do only because this code would only ever execute on the server.

    My console prints:
    Null
    5th XML chunk
    4th chunk
    3rd
    2nd
    1st
     
    Last edited: Jun 25, 2015
  17. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    is that on a host from the local client?
     
  18. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Yup. I haven't tried it with any other clients connected - just in the Editor "by myself".
     
  19. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    there was a bug that cause ClientRpcs in the same frame to be called in reverse order on the local client. try upgrading to latest patch release.
     
    KelsoMRK likes this.