Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Hiding variable information from certain clients

Discussion in 'Multiplayer' started by Wihtman, Aug 3, 2015.

  1. Wihtman

    Wihtman

    Joined:
    Aug 3, 2015
    Posts:
    10
    I am planning/developing a card game using UNet. I am stuck on figuring out how to ensure that only the appropriate player will be able to see info about their cards when others should not, such as cards in his/her hand.

    My initial thoughts were to have a cardID that would assign the appropriate card image, card text, etc. client-side once a card is spawned; the cardID would be initialized to 0 (which would have a blank card image and text to prevent cheating), but if the local player is the 'owner' of the card (player who drew the card, etc), then the server would send that client the cardID for that card. This would involve a lot of variable tracking in code, however, and I haven't been able to work out how to implement it in a simple prototype game.

    Any advice on the best way to instantiate/spawn cards such that the card info is kept hidden from all clients except the one intended to see it?
     
  2. l3fty

    l3fty

    Joined:
    Mar 23, 2013
    Posts:
    86
    With messages ( http://docs.unity3d.com/Manual/UNetMessages.html ) the server can talk directly to a specific client, or to all clients. The client can also send messages to the server. You just need to register message handlers on the objects you want to handle those messages.

    For example if you had a card deck controller component, you might keep a list of PlayerDeck objects which contained each players deck and their connectionID on the server. Then when required the client could send a message to the server requesting their deck, and the server can respond with the deck which belongs to that connectionID.

    You just need a reference to NetworkManager.client to register message handlers and send messages from the client. You can do the same on the server with NetworkServer when a server is active.
     
  3. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    Right, unfortunately there is no built-in way to do this. This has come up a few times as a feature request, so it is something we will look at adding. Ideally it would be something like:

    Code (CSharp):
    1. [SyncVar(scope=OwnerOnly)]
    2. int cardId;
     
  4. Wihtman

    Wihtman

    Joined:
    Aug 3, 2015
    Posts:
    10
    Thank you both for the information. According to your scheme l3fty, where would I register message handlers, as in under what function? I haven't been able to figure that out.

    EDIT: Nevermind, I think I figured it out. I am overriding OnStartServer and OnStartClient and placing the "RegisterHandler" calls in each of those. Thanks again!
     
    Last edited: Aug 8, 2015
    l3fty likes this.
  5. nsmith1024

    nsmith1024

    Joined:
    Mar 18, 2014
    Posts:
    869
    I need this feature too
     
  6. LastDude

    LastDude

    Joined:
    Aug 5, 2015
    Posts:
    15
    The UNet HLAPI is pretty useless and it's not production ready. The lack of scope for VarSync and ClientRpc is a pretty bad design choice.

    I wonder why they thought it was a good idea to release it like that.
     
  7. l3fty

    l3fty

    Joined:
    Mar 23, 2013
    Posts:
    86
    I'm managing to use UNet quite well having converted one project to it. It's early days for sure, but probably difficult for them to know how everyone wants to use it without releasing it to the masses.

    The developers have been active here mentioning that they want to add loads of the things people are suggesting. I think it's going to turn out well.
     
    SuperNeon likes this.
  8. DWORD

    DWORD

    Joined:
    Jun 22, 2010
    Posts:
    38
    LastDude is right, UNet is not production ready. "Scoping" is basic feature of any high level networking framework. The fact that they "forgot" to implement something like this just reminds me of other Unity features that are badly designed or just old (terrain, input, decals, pathfinding, ....).

    I had to switch to Unreal because I need a decent networking system and I already spent too much money with other plugins (that fills most holes with the engine) and Pro versions of Unity (I bought every Pro version of Unity since 3). I decided to switch to Unreal out of disappointment since it's very counter productive (as a solo developer) to keep buying plugins and/or implement every "basic" feature yourself instead of focusing on the game.

    I still keep an eye on unity forums to see if things change.

    Sorry about my rant.
     
  9. Wihtman

    Wihtman

    Joined:
    Aug 3, 2015
    Posts:
    10
    Here's how to send variable info to a single client
    • Create an empty game object
    • Add a MasterNetworkManager script that inherits from NetworkManager (public class MasterNetworkManager : NetworkManager); don't forget the 'using UnityEngine.Networking'
    • Add overrides for OnStartServer and OnStartClient
    • Add NetworkServer.RegisterHandler under OnStartServer and client.RegisterHandler under OnClientStart
      • For those unfamiliar, like I was when creating this post, RegisterHandler takes a message type (you can use 'const short msgTypeName = 151' like variables) and a handler, which is just what method to invoke upon receiving a network message of that message type: RegisterHandler( msgDrawCard, OnDrawCard )
    • Set all handlers to take the parameter 'NetworkMessage netMsg' (e.g. public void OnDrawCard( NetworkMessage netMsg )
    Then, to send a message to the server, basically "asking" the server for the info you want
    • Create a public class for a message that inherits MessageBase
      • e.g. public class ExampleClass: MessageBase
    • Create public variables inside that class
    • Make 'var msg = new ExampleClass'
    • Set whatever variables you want within that class
      • e.g. if ExampleClass has the public variables 'public int a' and 'public string t'; then after making msg, you set 'msg.a = (some int)' and 'msg.t = (some string)
      • These variables don't need to be there if you aren't sending the server any info from the client necessarily, but I wrote it here so I don't have to rewrite it for an explanation of how to create the server's response message
    • Reference the MasterNetworkManager script you created (I call the reference netManager)
    • Call netManager.client.Send( message type for Example class, msg )
    • Create a method for the server's handler of 'message type for Example class', such as OnExampleClass( NetworkMessage netMsg )
    • Make 'var msg = netMsg.Read<ExampleClass>();
    • Do what you want with msg.a and msg.t
    • Create a response message (I call it 'response') in the same way that we created 'msg' for the client's sent message
    • Send the response message netMsg.conn.Send( message type, response )
    • Repeat what was done for the server's handler method but for the client
    It's not as short and sweet as "scoping", but it is still pretty simple and functional; plus, the flexibility you have at each stage of messaging is pretty nice.
     
    Zelek likes this.
  10. Zelek

    Zelek

    Joined:
    Jun 12, 2010
    Posts:
    87
    Thanks Wihtman for putting together this great summary of the steps for sending and receiving messages, it was really helpful.