Search Unity

RPC gotcha and documentation error

Discussion in 'Multiplayer' started by Factoid, Jun 30, 2009.

  1. Factoid

    Factoid

    Joined:
    Mar 30, 2008
    Posts:
    69
    My apologies if this is posted elsewhere in the forums, a quick search didn't turn up any hits, but I didn't dig too deeply.

    I've discovered that the RPC Buffered calls only really work if the buffer call is made from the server. On reflection this makes perfect sense, but the behaviour isn't clear in the documentation, so it took a little experimentation to uncover. Maybe adding a network warning if a client issues a 'Buffered' call would help developers track down weird behaviour.

    Also, the documentation for RPCMode.Others and RPCMode.OthersBuffered says the message goes to "everyone except the server", but in reality it goes to "everyone except the sender". This is probably common knowledge (and since I'd never looked to closely at the doc, I just assumed "Others" meant everyone but me), but the documentation should reflect this.
     
  2. larus

    larus

    Unity Technologies

    Joined:
    Oct 12, 2007
    Posts:
    280
    Buffered RPCs work from clients as well. You could post your code snippet here if that isn't working for you, maybe there is something wrong there. The second client which connects to the server sees the RPC message as if it was from the server though as thats where he sees all messages coming from.

    Yes, that's an error in the documentation there for sure. Thanks for pointing it out.
     
  3. Factoid

    Factoid

    Joined:
    Mar 30, 2008
    Posts:
    69
    Hi, after reworking the particular buffered issue into a "On client connect, request updates" solution, we encountered a bug that would crash the server instance when the 2nd client connected.

    Ultimately I think it boiled down to two problems.

    1) Client-to-client communication does not seem to be permitted via NetworkView::RPC( string, NetworkPlayer, ... ); NetworkView assumes it's always a client-server message.

    2) Using NetworkMessageInfo.Sender to return a response to an RPC seems to be what ultimate crashed the server when dealing with client-to-client communications. Explicitly sending Network.player as a 'replyTo' parameter stopped the crashing, but resulted in some sort of ViewID: x LevelPrefix : y does not exist error on the recipient of the RPC call.

    At any rate, we've resolved our issues with with the following workarounds.

    1) When Buffered communications fail, fall back on explicitly requesting the information you want.

    2) When requesting state information from another game client, you need to route the message through the Server (or ideally, the server has an up to date copy of the state information and can reply immediately on behalf of the other client).

    If this is possibly a new bug that you guys would be prepared to work on, I might be able to distill our issues down to a test case project, but at the moment I can't spare the time for something that might get shelved.

    If my assumptions are correct, hopefully you guys can put together a test case anyway.

    Thanks for your reply though, we did find that the rest of our client issued buffered commands do work as expected. It was just this one instance.

    EDIT: Re-reading your post, I realized that the reason the buffered call failed was because we were expecting the NetworkMessageInfo.sender field from the buffered call to be from the client that issued the RPC buffered call. If we'd instead had the sending client include its Network.player id in the parameter list everything would probably would have worked.

    Thanks for the clarification on buffered call behaviour. Is this gotcha clearly identified in the documentation?
     
  4. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    client client would require that all are nat enabled and are able to receive UDP streams.
    Thats neither reallistic, nor is it commonly enjoyable with more than a handfull of player due to upstream restrictions and the upstream latency especially on cable and non-dsl.
    To me the main problem is security. if the server isn't the one handling the packets, what ensures that users with cracked versions aren't going to drive other player nuts?


    As for workaround 2)
    I would potentially implement the information requesting on the server, for the following two reasons:
    - If it does not receive updates, it has to do it anyway to keep its simulation in sync, so why doing it from a second place
    - It is also in the position to verify the correctness of the data in this case


    A detail question on your implementation:
    Do you allocate the network views yourself or do you use the automatic handling?
     
  5. Factoid

    Factoid

    Joined:
    Mar 30, 2008
    Posts:
    69
    client-client communication would be easy if it were auto-magically handled by the server. So that when A wants to talk to B, the message actually goes A to S, S to B, but the NetworkMessageInfo reports the sender as A.

    This can ultimately be done by the developer anyway, so why not standardize the implementation?

    As for your question, we sort of do both. Our game requires the use of dynamic content fetched from Asset bundles. The objects in the asset bundles frequently require their own network views in order to communicate.

    Since Asset bundles objects cannot be used in NetworkView.Instantiate (understandable, since you can't guarantee that the asset bundle has been downloaded by all clients), we use a 'bootstrapping' prefab which is included in the Resources folder. The bootstrapper gets an automatically assigned networkViewID courtesy of Network.Instantiate. It is then able to request a 2nd network view for the asset bundle component, and then distribute the 2nd id, and the name of the Asset bundle asset that is to be loaded. The remote copies of the bootstrapper take responsiblity for constructing the prefab and assigning the network view.

    We developed an AssetBundle management system that lets us treat asset bundles like Resources, but provides a co-routine version of Load which will download the assetbundle(s) if required (i.e. it's a blocking Load call which guarantees to get the asset if it's available). The non-blocking version simply returns null if the asset hasn't been downloaded yet.
     
  6. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    Hmm, content from asset bundles can't be used to instanciate?
    Are you sure there that using them after having actually loaded them through the corresponding functionality fails?
    Was under the impression that after the prefabs are loaded from the asset bundle, they are the same as "in application" data (and especially content from Resources folder which is not loaded automagically too but requires Resources.Load(prefabname, ...) ) which if it is present in the level, is just autoloaded.


    The message info actually contains the network player information from the other player, not the server one (unless you sent the message from the server naturally)

    Main reason I asked if you instantiate the views yourself is, that there potentially might be requirements for globally (player -> server -> player)linked views (not sure, I never allocated them myself) on top of the server allocating them.
    The manual network part is the one where, at least out of my view, the most documentation is missing. But this mode also is an advanced topic and thus often no problem as Network.Instantiate is much simpler and complete in its usage.
     
  7. Factoid

    Factoid

    Joined:
    Mar 30, 2008
    Posts:
    69
    They are the same as in application data, except for network instantiate. Consider that asset bundles are a voluntary download, so there is no way to guarantee that the asset is available on all clients, so how are you supposed to instantiate a prefab that may or may not exist on the remote machines?

    From my experience, a network view ID is simply an identifier that is assigned to a network view. When you send a message, the receiving machine attempts to locate the network view with the corresponding ID and routes the message to it.

    NOTE: We experimented with 'giving' the network instantiated prefab's ID to the dynamic content. The resulting behaviour is undefined, sometimes the message goes to the dynamic asset, sometimes to network instantiated prefab. Presumably we could pass the network view id to the dynamic asset and then instruct the network instantiated asset to die (so that there is only one asset using the view id), but we elected to just create extra ids where needed.

    I think Unity deserves a lot of credit for implementing a networking layer that continues to make rational sense even when I hit these kinds of gotchas. When something doesn't work, I can usually guess as to why, but it'd be nice not to have to figure these things out for myself. :)
     
  8. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    What is not present can not be instantiated visually.
    This can for the network either mean that the object is not instantiated at all so no network view and no problem or that it is generated as a game object component container, which would mean all works but it will just not show you anything.
    Neither is actually a problem, but I would expect that the first thing happens + an error in the log that the prefab could not be instantiated


    definitely the way to go I would say, otherwise the ids might not be registered right with the server.

    fully agree
    Has saved me a fair amount of time compared to other similarly priced indie game technologies where the answer can be found but only if you have a week for source search.
    Also unity has an active and helpfull community.

    In this specific case its likely more because asset bundles have been introduced with 2.1, are a pro only feature and are likely not used that much as webplayer streaming (the place where the bundles are often of real interest) can compensate for it with much less work ^^
    But a combined Network + Asset Bundle (+ Terrain neighboring) demo project / article / tutorial would definitely be a great thing.