Search Unity

setting the names in multiplayer?

Discussion in 'Multiplayer' started by Tom163, Mar 28, 2008.

  1. Tom163

    Tom163

    Joined:
    Nov 30, 2007
    Posts:
    1,290
    I have a trivial problem that for some reason eludes me, and I can't find anything in either the documentation or the forums.

    I want my players have names. What a surprise. So in my GUI you can pick a name, it's stored in a Preferences gameobject and then I call

    var player = Network.Instantiate(etc..)
    player.name = Preferences.PlayerName;

    But that only sets the name locally. Across the network, I still have the name of the prefab.

    If I put
    transform.name = Preferences.PlayerName;

    into the prefab script Start() function, then everyone gets my chosen name (no surprise there).



    So, what's the proper way?
     
  2. jashan

    jashan

    Joined:
    Mar 9, 2007
    Posts:
    3,307
    One solution might be to add the name to the serialize functions. That would synchronize the names across the network. What you're doing here is just setting the local name, which does not have an effect on the others on the network.

    The way I'm doing this is by having a player manager that has a network view, and the settings are sent via RPCs to everyone, so everyone always has the current status of everything (that I care about ;-) ).

    Sunny regards,
    Jashan
     
  3. nafonso

    nafonso

    Joined:
    Aug 10, 2006
    Posts:
    377
    I also suggest the same thing because this way you can control name conflicts, for example.
    Whenever a player connects, he creates a "player" instance. Then, you send to the Server "I want to have this name", and the Server checks, takes care of conflicts, and then says "everybody, this guy has this name", for example.

    Regards,
    Afonso
     
  4. Tom163

    Tom163

    Joined:
    Nov 30, 2007
    Posts:
    1,290
    Which leaves the question how I identify a game object in an RPC call. Did I miss something?
     
  5. jashan

    jashan

    Joined:
    Mar 9, 2007
    Posts:
    3,307
    Usually, you would use the NetworkViewID. However, for player objects, personally I prefer using my own "lightweight datastructures" which I look up in Dictionaries. That is: I'm not using MonoBehaviors for that, but simple C# objects.

    I guess it really depends on what you want to do... I guess I'd recommened using GameObjects with attached scripts instead. Then, the procedure is instantiating them and making sure there instantiated everywhere, having the same NetworkViewID (either use Network.Instantiate, or use the example of the RPC method in NetworkView, which I prefer because I don't want anything to be buffered, which Network.Instantiate obviously is).

    You can then use NetworkView.FindByID(NetworkViewID) (or something like that, I don't have time to look it up right now) to find an object by a given networkViewID.

    If you need to do that at all. When you call an RPC, it's automatically going to the right GameObject / MonoBehavior. There's really plenty of ways to do this. You could, for instance also have a "PlayerManager", which has a network view attached. That player manager could then simple keep lists of the used player names, and maybe references to the relevant objects / game objects.

    Sunny regards,
    Jashan
     
  6. Tom163

    Tom163

    Joined:
    Nov 30, 2007
    Posts:
    1,290
    Sounds all awfully complex for something as simple as having "Joe" be known as "Joe" to everyone in a networked game.

    Maybe this needs to be added to the Wishlist: Networked variables (name, guild/clan, hitpoints, whatever).
     
  7. jashan

    jashan

    Joined:
    Mar 9, 2007
    Posts:
    3,307
    Well, networked multiplayer is complex by nature. I've outlined a few of the possibilities because it's good to have an understanding of what's possible to be able to choose that which is most elegant for the specific task at hand.

    Depending on your individual needs, some of the possibilities may work for you better than the others; which in turn is the reason why I'm not sure "networked variables" on top of what's already available make that much sense.

    Networked variables are something that can be very easily added on top of what already exists - and that keeps things more flexible...

    The thing that probably makes this look a little complex is that you cannot know in advance (without knowing requirements of the game design), whether or not these variables should simply be "synchronized" or whether there should be some validation etc. etc.

    Getting the most simple form up and running is not more than having a script with the variable(s) in question, attached to a GameObject with a NetworkView, and its value sent to all via RPC whenever it has changed (buffered, if needed).

    Something like

    Code (csharp):
    1.  
    2. [RequireComponent(typeof(NetworkView))]
    3. public class MyNameScript : MonoBehavior {
    4.     // this must not be used be used outside of MyName!!!
    5.     // It's only public to make it accessible in the properties inspector.
    6.     public string myName = "NotSet";
    7.     // if you don't need the property inspector, do:
    8.     // private string myName = "NotSet";
    9.     public string MyName {
    10.         get { return this.myName; }
    11.         set {
    12.             if (value != null  !myName.Equals(value)) {
    13.                 this.myName = value;
    14.                 DistributeName();
    15.             }
    16.         }
    17.     }
    18.    
    19.     // use this to update others (e.g. on startup)
    20.     public void DistributeName() {
    21.        networkView.RPC("RPCUpdateName", RPCMode.All, myName);
    22.     }
    23.  
    24.     [RPC()]
    25.     public void RPCUpdateName(string newName) {
    26.         this.myName = newName;
    27.     }
    28. }
    29.  
    Now, if you do
    Code (csharp):
    1. MyNameScript myNameScript = (MyNameScript) gameObject.GetComponent(typeof(MyNameScript));
    2. myNameScript.MyName = "Dr. Cool";
    Somewhere in your code, all players that are currently online would get that update (assuming that the game object exists on all clients with the same NetworkViewID everywhere). If you want to make the change "a bit more persistent", you could replace RPCMode.All with RPCMode.AllBuffered...

    Maybe a more elegant and intuitive approach (once it is implemented) would be using OnSerializeNetworkView to synchronize the member variable.

    There's an example for that in the documentation:
    http://unity3d.com/support/documentation/ScriptReference/MonoBehaviour.OnSerializeNetworkView.html

    The way it looks to me, in C# you would probably have to pass health as ref ("ref health" instead of just "health").

    That's the "simple approach" - but of course, you might want to have an authoritative server that manages all the names and says "NO" if a user tries to enter a name that already exists. You could, for instance use the script I outlined above (haven't tried it in the compiler, so it might contain typos or other errors), add a static Dictionary with all the names, and then, instead of doing RPCs to All, you would do RPCMode.Server, plus you'd have another RPC "RPCUpdateNameToClients"... Then, in RPCUpdateName you'd do your "check" (on the server), and if it fails, you could for instance send the original back to the sender (which would overwrite the change of the "offending client"). Or, you could send an error RPC specifically to the client that tried changing the name... Or, if the server agrees that this is a cool new name - it would use RPCUpdateNameToClients with RPCMode.All(Buffered) to let everyone know the name has changed.

    Now, I'm not exactly sure how one would implement such mechanisms with the OnSerializeNetworkView approach. It might turn out that for such things, OnSerializeNetworkView is no longer elegant at all. That's why I feel it's good to know all the options and then make a decision depending on your current game.

    One thing I feel is something one should be aware of: Nothing is really "simple" in networked multiplayer. A networked multiplayer game is a "realtime distributed system"... That's one of the definitions of "complex" ;-)

    Sunny regards,
    Jashan
     
  8. darkwwc

    darkwwc

    Joined:
    Mar 8, 2011
    Posts:
    14
    Everything good jashan,
    I wonder if could post an example of a project for the network name of the player, I tested the above script, but it was not anyway.

    If you can help, I appreciate it, makes a time trying to fix it