Search Unity

Resolved ClientId to TransportId in NetworkManager

Discussion in 'Netcode for GameObjects' started by teamclouday, Dec 21, 2022.

  1. teamclouday

    teamclouday

    Joined:
    Jan 11, 2022
    Posts:
    5
    Hey, I'm using netcode v1.2.0 and have created my customized transport (for Nakama).

    The transport assigns an ID for each connection. I need to use the transport IDs in code to identify the users in Nakama.
    I thought I could use the client IDs assigned by NetworkManager.
    However, NetworkManager internally uses a different set of client IDs and creates a mapping between ClientId and TransportId.

    Is there anyway to access these mappings? Currently, the mappings are private and the related functions are all internal.
     
  2. NoelStephens_Unity

    NoelStephens_Unity

    Unity Technologies

    Joined:
    Feb 12, 2022
    Posts:
    259
    Hi teamclouday!

    There is a way to do this with NGO today, but it is a bit more code than you would expect.
    Here are some areas of interest you might want to reference (although if you are writing your own transport I am assuming you already have combed over these areas):
    Path To Creating Your Own Transport ID to NGO Client ID Mapping Table
    Since you are writing your own transport, you can add your own callbacks that are registered on the server side. For this example, let's assume you have a server specific script called "TransportConnectionMapping" that registers for these callbacks.

    Starting in your custom transport where you are invoking InvokeOnTransportEvent and the event is of type NetworkEvent.Connect:
    • Add a special case here that invokes custom events that you add to your Transport:
      • Invoke "OnTransportPendingConnection" (your transport's custom callback) that includes the Nakama' s transport ID and is invoked prior to invoking InvokeOnTransportEvent.
        • When this is invoked you will want to create a copy of NetworkManager.PendingClients in your server-side "TransportConnectionMapping" script (or whatever you name the class that handles this)
      • Invoke your InvokeOnTransportEvent next as that will add a new entry to the NetworkManager.PendingClients dictionary.
      • Invoke "OnTransportMapPendingClient" (your transport's custom callback), this will look at your current pending clients copy in your TransportConnectionMapping script and determine which entry was added to the NetworkManager.PendingClients dictionary.
        • The new keypair entry's key (ulong) is the NGO client id waiting for approval
        • You now should have both the Nakama transport ID and the NGO assigned client ID that you can create your two dictionaries to be able to map between NGO client ID and Nakama transport ID.
    • At this point you just need to wait for the connecting client to finish the approval process.
      • If the pending client fails to be approved or is approved and disconnects later, you obviously will want to remove it from your own mapping tables (i.e. need to handle cleaning it up yourself)
    The Logical Flow Will Look Like :
    • When your transport is handling NetworkEvent.Connect:
      • CustomTransport.OnTransportPendingConnection (with NakamaId)
        • Replicate/Track NetworkManager.PendingClients
      • CustomTransport.InvokeOnTransportEvent
        • NetworkManager creates new pending client entry
      • CustomTransport.OnTransportMapPendingClient
        • Compare your replicated pending clients with the NetworkManager.PendingClients
          • The key of the KeyValuePair is the assigned NGO ClientID
        • Create the two new entries in your own NGO ClientID to Nakama Transport Connection ID mapping (to and from) tables
    While it is a bit of "hoop" jumping to get your own mapping, using an approach like this will get you moving forward.
    Let me know if the above solution, for now, works out for you or if you run into any further issues or have further questions.

    Cheers,
    Noel

    If you find this tedious/too complicated, then I would definitely recommend filing a feature request to have us (NGO Team) add the following methods to NetworkManager:
    • ulong NetworkManager.GetTransportIdentifier(ulong clientId)
    • ulong NetworkManafer.GetClientId(ulong transportId)
     
    teamclouday likes this.
  3. teamclouday

    teamclouday

    Joined:
    Jan 11, 2022
    Posts:
    5
    Hi NoelStephens_Unity

    Thank you very much for the detailed response! I'm able to successfully create the mapping by following your advice! This is really helpful!

    By filing feature request, do you mean posting an issue on the GitHub repo? I would love to do so!

    Btw, I wasn't aware that the transport can use event-based messaging (I followed the example of the community websockets transport). I switched to use InvokeOnTransportEvent and it worked great!
     
    RikuTheFuffs-U likes this.
  4. RikuTheFuffs-U

    RikuTheFuffs-U

    Unity Technologies

    Joined:
    Feb 20, 2020
    Posts:
    440
    @teamclouday Yes! You can do it from here :D
     
    teamclouday likes this.
  5. teamclouday

    teamclouday

    Joined:
    Jan 11, 2022
    Posts:
    5
    RikuTheFuffs-U likes this.
  6. NoelStephens_Unity

    NoelStephens_Unity

    Unity Technologies

    Joined:
    Feb 12, 2022
    Posts:
    259
    Glad I could help and that it unblocked you so you can continue to make something awesome! :D
    Thank you for using NGO! :)
     
    teamclouday likes this.
  7. dmellobosco17

    dmellobosco17

    Joined:
    Feb 27, 2016
    Posts:
    1
    Hi everyone.

    After digging into NGO code I found that NGO already maintains the dictionaries for the same. The problem is that they are kept "internal" to the library. However, we can just get reference to those dictionaries using reflection and you are good to go. Worked like a charm for me.
    Here is my code to get those references.

    Code (CSharp):
    1. var bindings = BindingFlags.NonPublic | BindingFlags.Instance;
    2. var netConnManagerInstance = typeof(NetworkManager)
    3.                 .GetField("ConnectionManager", bindings)
    4.                 .GetValue(_networkManager);
    5.  
    6. var conManType = typeof(NetworkConnectionManager);
    7.  
    8. clientToTransportId = conManType.GetField("ClientIdToTransportIdMap", bindings)
    9.                 .GetValue(netConnManagerInstance) as Dictionary<ulong, ulong>;
    10.  
    11. transportToClientId = conManType.GetField("TransportIdToClientIdMap", bindings)
    12.                 .GetValue(netConnManagerInstance) as Dictionary<ulong, ulong>;
     
    Davidaval8r likes this.
  8. Davidaval8r

    Davidaval8r

    Joined:
    Apr 8, 2016
    Posts:
    3
    DUDE OMG THANK YOU SO MUCH I WAS STRUGGELING WITH THIS FOR A WEEK