Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

NAT Traversal - Automatic port forwarding, punch-through, and more!

Discussion in 'Assets and Asset Store' started by thegreatzebadiah, Apr 5, 2016.

  1. OtspIII

    OtspIII

    Joined:
    Jul 17, 2015
    Posts:
    2
    Is the Facilitator currently running? When I try to run the example scene I get these messages:

    NATTraversal: External ip source responded with something other than an IP:
    NATHelper: NAT Device not found
    NATHelper: Failed to connect to Facilitator at grabblesgame.com:61111. Are you sure that it is running and that the address and port are correct?

    I'll be switching to hosting our own facilitator soon, but it'd be nice to confirm that I have things working using the test facilitator before I go through the process of setting up my own.

    Also, painfully, when I try to run the Facilitator on my AWS Linux server I get the message "
    ./Facilitator: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by ./Facilitator)". As far as I can tell the style of linux I'm using does not support any version of libstdc++ recent enough to support the Facilitator, which is a bit annoying.
     
  2. sammyben

    sammyben

    Joined:
    Nov 12, 2013
    Posts:
    7
    No don't seem to get the errors in there as they seem to arise in example scene. It the network script I have written it uses the unity match system which I have basically copied straight from your example network manager script.
     
  3. gabmedalv

    gabmedalv

    Joined:
    Sep 21, 2015
    Posts:
    6
    Thanks for your response.

    We've been reimplementing some methods fixing some issues, but at the end windows clients can't connect to host (mac clients can connect correctly) ... we are trying to figure it out.
    After that we tried to update the NAT Traversal plugin to the most recent version (1.52), but, when we tried to start the host we get this error :

    NullReferenceException: Object reference not set to an instance of an object
    NATTraversal.NetworkManager.StartHostAll (System.String matchName, UInt32 maxPlayers, Boolean advertise, System.String password, Int32 eloScore, Int32 requestDomain, UnityEngine.Networking.Match.ResponseDelegate`1 callback)
    ExampleNetworkManager.OnGUI () (at Assets/NAT Traversal Example/ExampleNetworkManager.cs:87)

    Note that this error happens even on the Example scene of the plugin, do you know why this error happens??

    Thanks in advance
     
    filthsu_rustogames and Glordim like this.
  4. Glordim

    Glordim

    Joined:
    Feb 8, 2015
    Posts:
    2
    Same for me.
     
  5. Swearsoft

    Swearsoft

    Joined:
    Mar 19, 2009
    Posts:
    1,632
    Hey guys,

    change the platform dependent compilation code from 'UNITY_6' to 'UNITY_2017' in your example scripts and such.

    Thanks
     
  6. DrZeuss

    DrZeuss

    Joined:
    Apr 9, 2013
    Posts:
    4
    Hi - I need some assistance.I'm using Unity 5.6 on MacOS and have just purchased your NAT Traversal Plugin and am having some problems with StartHostAll not firing the custom callback OnMatchCreate.

    I'm using the following line to call StartHostAll from my custom LobbyManager.

    LobbyManager.Singleton.StartHostAll(Properties.LobbyName, (uint)LobbyManager.Singleton.maxPlayers, true, Properties.Password, 0, 0, LobbyManager.Singleton.OnMatchCreate);

    Where the LobbyManager is extended from NATTraversal.NATLobbyManager and OnMatchCreate is:

    public override void OnMatchCreate(bool success, string extendedInfo, MatchInfo matchInfo)
    {
    base.OnMatchCreate(success, extendedInfo, matchInfo);
    m_ulCurrentMatchID = (System.UInt64)matchInfo.networkId;
    Debug.Log("Match Created:" + m_ulCurrentMatchID);
    }

    The OnStartHost callback is being called successfully however the callback for OnMatchCreate never gets called. If I replace the StartHostAll line call with a simple call to matchMaker.CreateMatch(), the OnMatchCreate callback is called?

    The relay and matchmaking checkboxes on the LobbyManager are checked and I have tried this with direct and punch-through checked/unchecked - it seems to make no difference with OnMatchCreate never being called.

    What am I doing wrong? What other reasons would prevent StartHostAll from successfully creating a match and calling OnMatchCreate?

    Given the regular call through matchMaker.CreateMatch works is this a bug?

    I'm running on MacOS 10.11.4 El Capitan by the way.
     
  7. DrZeuss

    DrZeuss

    Joined:
    Apr 9, 2013
    Posts:
    4
    Any update please on why StartHostAll() is failing to register a match via Unity matchmaking?
     
  8. DrZeuss

    DrZeuss

    Joined:
    Apr 9, 2013
    Posts:
    4
    I fixed the match creation issue - it was down to an initialisation ordering issue in my LobbyManager. All fixed and working now.

    Q: Does anyone have a CentOS 6.9 compiled version of the Facilitator, unfortunately our standard builds don't include CentOS.
     
  9. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    No
     
  10. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    @OtspIII The facilitator goes down for a bit every now and then when I'm doing funky things on our server.

    @OtspIII @DrZeus I'll see if I can compile some new versions of the Facilitator using an older version of GLIBC
     
  11. RoyArtorius

    RoyArtorius

    Joined:
    Jul 11, 2013
    Posts:
    73
    Recently, I took a look at the documentation again. Under StartClientAll it says this:
    "The first connection to succeed will be used, but if it is a relay connection it may later be replaced by a non-relay connection if one is established. This ensures that clients are always connected using the best connection possible."
    What exactly does this mean then?
     
  12. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    I guess I misspoke a bit. What I meant to say is that if punchthrough fails and relay connection is made there is no second punchthrough attempt. It is possible that a relay connection could succeed first and then be replaced with a successful punchthrough connection but that's still only one punchthrough attempt.
     
  13. HappyBadgerStudio

    HappyBadgerStudio

    Joined:
    May 6, 2014
    Posts:
    19
    Hello!

    We are nearing our launch in a dew days and have been trying to solve an issue that seems to be related to specific network settings on the user's end..

    It seems that even if a user has allowed our game in their firewall (private and public), they still can't make a connection until they go into their Network Properties (on windows 10, click wifi, and choose properties on your current wifi connection) and they have to enable "Make this PC discoverable" if that is off (which it usually is) then the connection will not work..

    Another one is a little more straight-forward and it related to a user being on a gateway instead of a modem. (AT&T for example does this) Unless the user connects an eternal router to it and sets it in DMZ mode, (or sets their own computer in DMZ mode via the gateway) then they also can not connect.

    Have you run into these problems at all? If so, could you please give me some suggestions on how to handle them? Steam is not able to make connections so they are failing our build, yet we are able to connect just fine..
     
  14. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    I haven't encountered this personally. We use a computer on wifi for testing all the time, but it's not on Windows 10 so I haven't run into it. Oddly I don't think anyone else has reported it either, which I would definitely expect if it's disabled by default.

    That's funny that you describe this one as more straight-forward because it sounds super confusing to me! I believe punchthrough just doesn't work over these type of connections though and you will have to rely on the relays.
     
  15. HappyBadgerStudio

    HappyBadgerStudio

    Joined:
    May 6, 2014
    Posts:
    19
    Haha! I thought it was more straight forward because it was directly related to a certain network setup, while the other issue just seems really weird and I'm not sure why it is a problem at all.. :(

    I have the relay checked but it never seems to try to use it, not sure why. I'll try to report back after I dig around some more.
     
  16. richeso

    richeso

    Joined:
    Jan 4, 2016
    Posts:
    1
    Will this plug in work with photon bolt networking ?. If so, is there some sample code you can point me to get started?
     
  17. thanhle

    thanhle

    Joined:
    May 2, 2013
    Posts:
    162
  18. Eideren

    Eideren

    Joined:
    Aug 20, 2013
    Posts:
    309
    Hey, I am finalizing my p2p network using unity's network traversal and everything is working fine so I have been trying to implement your plugin on top of my system but I am not certain as to what I am supposed to do once the connection request has been accepted.

    To test that out I am connecting a built player to the unity editor in play mode on the same PC by using my external IP. I can connect just fine when doing so locally ( 127.0.0.1 using a default port ).


    Both players start the network like so:
    nat.findNatDevice()
    wait for nat.isDoneFindingNATDevice

    nat.connectToNATFacilitator()
    wait for that enumerator to finish

    setup unity's network transport:
    NetworkTransport.Init();
    add channels
    create new topology
    AddHost() using distinct ports on both instance, ex: 55111 for editor, 55112 for player

    nat.startListeningForPunchthrough(onHolePunched) (yes, on both instances)
    wait for that enumerator to finish

    get my external IP

    start pulling network messages using NetworkTransport.Receive

    --Done

    Here 's how the "client" continues
    nat.StopListeningForPunchthrough()
    nat.StartCoroutine(nat.punchThroughToServer(guid, onHolePunched))
    onHolePunched success =>
    int socketId = AddHost(clientPort/first int argument)
    NetworkTransport.Connect(socketId, externalIP of who we want to connect to, serverPort/second int argument, 0, out error);

    --Done

    The function passed as argument on ListeningForPunchthrough looks like so:
    AddHost(port/first int argument)

    --Done



    Here's the shortened log for the "host" :
    NATHelper: Searching for nat devices
    NATHelper: NAT Device not found
    NATHelper: Received RakNet message: -Redacted:External IPv4-|61111: ID_CONNECTION_REQUEST_ACCEPTED
    NATHelper: Connected to Facilitator: 756604738565463948
    NATHelper: Listening for punchthrough
    NATHelper: Received RakNet message: 192.168.56.1|55258: ID_NAT_PUNCHTHROUGH_SUCCEEDED
    NATHelper: Received punch-through: 192.168.56.1|55258
    NATHelper: Received RakNet message: 192.168.56.1|55258: ID_NEW_INCOMING_CONNECTION
    NATHelper: Received incoming RakNet connection.
    NATHelper: Received RakNet message: 192.168.56.1|55258: ID_DISCONNECTION_NOTIFICATION
    NATHelper: Received RakNet message: -Redacted:External IPv4-|61111: ID_DISCONNECTION_NOTIFICATION
    NATHelper: Hole is punched on port: 57483
    NATHelper: Received RakNet message: -Redacted:External IPv4-|61111: ID_CONNECTION_REQUEST_ACCEPTED
    NATHelper: Connected to Facilitator: 756604738565463948
    NATHelper: Listening for punchthrough

    Here's the shortened log for the "client" :
    NATHelper: Searching for nat devices
    // Might not be related but posting it anyway :
    Fallback handler could not load library [...]_Data/Mono/libc
    Fallback handler could not load library [...]_Data/Mono/.\libc
    Fallback handler could not load library [...]_Data/Mono/libc
    NATHelper: NAT device found
    NATHelper: Received RakNet message: -Redacted:External IPv4-|61111: ID_CONNECTION_REQUEST_ACCEPTED
    NATHelper: Connected to Facilitator: 40532397827471947
    NATHelper: Attempting to map port 55258->55258 (Both)
    NATHelper: Listening for punchthrough
    Starting punchthrough on guid 756604738565463948
    NATHelper: Attempting to punch through to host: 756604738565463948
    NATHelper: Received RakNet message: 192.168.56.1|57483: ID_NAT_PUNCHTHROUGH_SUCCEEDED
    NATHelper: Listening for incoming RakNet connection.
    NATHelper: Received RakNet message: 192.168.56.1|57483: ID_CONNECTION_REQUEST_ACCEPTED
    NATHelper: RakNet connection received.
    NATHelper: Received RakNet message: 192.168.56.1|57483: ID_DISCONNECTION_NOTIFICATION
    NATHelper: Hole punched: 55258->57483
    NATHelper: Received RakNet message: -Redacted:External IPv4-|61111: ID_DISCONNECTION_NOTIFICATION
    // Logged onHolePunched success
    Start a socket on 55258 and connect to the server on 57483
    NATHelper: Received RakNet message: -Redacted:External IPv4-|61111: ID_CONNECTION_REQUEST_ACCEPTED
    NATHelper: Connected to Facilitator: 40532397827471947
    NATHelper: Attempting to map port 55652->55652 (Both)
    NATHelper: Port mapping finished 55258->55258 (Udp)
    NATHelper: Something went wrong mapping port 55258->55258 (Tcp)
    NATHelper: Something went wrong mapping port 55652->55652 (Udp)
    NATHelper: Something went wrong mapping port 55652->55652 (Tcp)
    Log: cannot connect after {10} attempt address {::ffff:-Redacted:External 'host' IPv4-:57483}
    NATHelper: Received RakNet message: -Redacted:External IPv4-|61111: ID_CONNECTION_LOST
    NATHelper: Ignoring message: ID_CONNECTION_LOST

    I can send you my project if you want to take a look, thanks !
     
  19. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    I sent you a message regarding this.
     
  20. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    By default Unity's NetworkTransform that is used to sync the players does not do any interpolation, so it's going to be jerky. You can try adding a rigidbody and syncing that instead of just the transform, or you can write your own custom script for syncing player position.
     
  21. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    This is not correct. You want to startListeningForPunchthrough on the host but you should only call punchThroughToServer on the client. Not sure if that's the cause of the issue, but it's something to try.

    It looks like it can't connect through the punched hole for some reason. In my experience usually once the hole is punched the connection is more or less guaranteed to work so it seems like something is definitely funky here. Try switching the client / server port that the client uses when connecting to the host, maybe I got something switched somewhere.

    Overall your code looks correct though. You seem to be doing all the right things.
     
  22. Eideren

    Eideren

    Joined:
    Aug 20, 2013
    Posts:
    309
    I'm calling nat.StopListeningForPunchthrough() right before connecting to the server from the client so I thought it didn't matter that much.

    The ports are accurate, I verified them inside the logs and if I swap them it triggers a 'WrongHost' error when using AddHost(), i.e.: it is already used by the server so can't use it for the client.

    Here are the logs when removing the startListeningForPunchthrough() on the client
    Client:
    NATHelper: Searching for nat devices
    NATHelper: NAT Device not found
    NATHelper: Received RakNet message: -Redacted:External IPv4-|61111: ID_CONNECTION_REQUEST_ACCEPTED
    NATHelper: Connected to Facilitator: 918734341094459528
    Starting punchthrough on guid 400820383924889306
    NATHelper: Attempting to punch through to host: 400820383924889306
    NATHelper: Received RakNet message: 192.168.56.1|54238: ID_NAT_PUNCHTHROUGH_SUCCEEDED
    NATHelper: Listening for incoming RakNet connection.
    NATHelper: Received RakNet message: 192.168.56.1|54238: ID_CONNECTION_REQUEST_ACCEPTED
    NATHelper: RakNet connection received.
    NATHelper: Received RakNet message: 192.168.56.1|54238: ID_DISCONNECTION_NOTIFICATION
    NATHelper: Hole punched: 51161->54238
    NATHelper: Received RakNet message: -Redacted:External IPv4-|61111: ID_DISCONNECTION_NOTIFICATION
    NATHelper: Received RakNet message: -Redacted:External IPv4-|61111: ID_CONNECTION_REQUEST_ACCEPTED
    NATHelper: Connected to Facilitator: 918734341094459528
    Log: cannot connect after {10} attempt address {::ffff:-Redacted:External 'host' IPv4-:54238}
    << I received a disconnectevent here through NetworkTransport.Receive without receiving any previous connectionevent, might be because of the failed connection, not sure >>

    Host:
    NATHelper: Searching for nat devices
    NATHelper: NAT Device not found
    NATHelper: Received RakNet message: -Redacted:External IPv4-|61111: ID_CONNECTION_REQUEST_ACCEPTED
    NATHelper: Connected to Facilitator: 400820383924889306
    NATHelper: Listening for punchthrough
    NATHelper: Received RakNet message: 192.168.56.1|51161: ID_NAT_PUNCHTHROUGH_SUCCEEDED
    NATHelper: Received punch-through: 192.168.56.1|51161
    NATHelper: Received RakNet message: 192.168.56.1|51161: ID_NEW_INCOMING_CONNECTION
    NATHelper: Received incoming RakNet connection.
    NATHelper: Received RakNet message: 192.168.56.1|51161: ID_DISCONNECTION_NOTIFICATION
    NATHelper: Received RakNet message: -Redacted:External IPv4-|61111: ID_DISCONNECTION_NOTIFICATION
    NATHelper: Hole is punched on port: 54238
    NATHelper: Received RakNet message: -Redacted:External IPv4-|61111: ID_CONNECTION_REQUEST_ACCEPTED
    NATHelper: Connected to Facilitator: 400820383924889306
    NATHelper: Listening for punchthrough

    Its kind of weird though, Am I really not supposed to do anything with the GUID of the client when received from onHolePunchedServer ?

    Could this have anything to do with the fact that I'm connecting using an ipv4 casted as an ipv6 like so : '11.22.33.44' => '::ffff:11.22.33.44' ?
    It works flawlessly when I do a straightforward connection with my local ip, but I am not certain that that's the right way to do so for external ips.
     
  23. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    Could be, I would definitely try with a regular old ipv4 address. IPv6 doesn't need punchthrough anyway since it isn't effected by NAT issues.

    The only thing the GUID is used for is so the clients can specify which host they are punching through to. Think of it like another IP for the host.
     
  24. Morderkaine

    Morderkaine

    Joined:
    Oct 22, 2016
    Posts:
    11
    Hi thegreatzebadiah,
    I have just purchased your asset and I am struggling a bit in getting it working.

    First off, would it be possible to use NAT punch-through without using the Unity Matchmaking stuff at all? For the game we are working on, for our first networking attempts we created a system where we have a program running on a server that will get notified regularly by all existing matches for our game. People can request a list of matches from the server (name, external IP address, number of players, etc) and then select one to join. What we have been doing is always using port 7776 and for our game server and port forwarding that port to our server to allow people to join. While that works fine for running matches on the server I manage, we also want to allow people to host their own matches and not solely rely on our server. So the end result we want is to run a game on the server, as well as have the match listing service running on the server to support people making their own games. Though we will likely move to using Steam to track players.

    So I guess the question is, if I have a system in place where I can get a list of matches running with the IP of the host and a set port the game is running on, is there a simple command or two I can use to use NAT Punch Through to a host in this instance NOT using Unity multiplayer matchmaking?
     
  25. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    @Morderkaine, yeah, should be no problem. You'll just need to include the host's guid along with the other matchmaking info. Then when a client pulls down the match info, pass the host's ip and guid into StartClientAll and you should be good to go.
     
  26. Morderkaine

    Morderkaine

    Joined:
    Oct 22, 2016
    Posts:
    11
    Was hoping to not need to use the facilitator (as we currently have our own solution(s) that do essentially the same thing (store IP address, Match name, port ) ). Without the facilitator there is no GUID, right?

    I must admit I am fairly new to Unity and C# coding, and especially new to Networking so some help with the code would help. Sorry to be a newbie bug, but while I know what to do, I don't know HOW (the code).
    The only example I have been able to find so far is

    MatchDesc match = matchList.matches [0];
    StartClientAll (match);

    And MatchDesc is depreciated and no longer will compile. Maybe I just don't know where your latest guides are but the links I followed seem to be mostly missing or for old versions.

    What I am sorta expecting to be able to do (please correct me if wrong) is to take the host info and make it into the format of the structure that StartClientAll expects and pass it to that function. Not really sure what the GUID is needed for if we have the IP. But I don't know what the structure is ATM.

    Thanks
     
  27. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    This is not what the Facilitator does. You're describing what UNet's matchmaking servers do, which is a totally separate thing. All the Facilitator does is help clients and hosts agree on which ports to connect over using complicated punchthrough magic. You can't have punchthrough without a Facilitator to do the punching.

    Take a look at that link to StartClientAll() in my previous post. There are two versions of the method, one takes the MatchInfo/Desc but the other takes separate internal IP, external IP, guid, etc. Just call that second method and pass in whatever connection info you've got (if you don't have ipv6 for example that's fine).

    There really isn't much code to show in this case. You've got your custom matchmaking system, so I don't really know what that code would look like, but once the client has the host's connection info it should just be something like:
    Code (CSharp):
    1. StartClientAll (hostExternalIP, hostInternalIP, hostGUID)
    I believe the reason the Facilitator uses a GUD is because the only alternative way to uniquely identify a client is by a combination of internalIP, externalIP, and port, but since the punchthrough process causes the port to change all the time during the initial connection something else was needed. If it was just the IP's then two builds on the same computer would look identical to the Facilitator.
     
  28. Morderkaine

    Morderkaine

    Joined:
    Oct 22, 2016
    Posts:
    11
    Hi,
    I think I get how to use this without UNET matchmaking.

    First thing when the game starts up, it will connect to the facilitator.
    I get the GUID from the facilitator.

    Host creates a game using our existing method and lists the game with external IP address, internal IP address and GUID.
    Using info from our server list process, Client runs StartClientAll (hostExternalIP, hostInternalIP, hostGUID, null, "","",null, "", 0, 0, false);

    My hopefully last questions/checks are:
    To get the GUID from the facilitator, I need to be 'using NATTraversal;' , create a public NATHelper that points to the NATHelper on the NetworkManager object and get the GUID from that.

    How do I determine the hosts Internal IP ? I have not needed this for networking in the past (likely due to using port forwarding?).

    If I am not using UNET matchmaking, is the StartClientAll call above correct, in that I can null out all the Matchmaking and UNET fields as long as it is getting the IPs and GUID?
     
  29. Morderkaine

    Morderkaine

    Joined:
    Oct 22, 2016
    Posts:
    11
    I think I have the internal IP from Network.player.ipAddress;

    So just a confirmation I am getting the GUID from facilitator properly and what to do for the StartClientAll call if not using matchmaking
     
  30. CloudyVR

    CloudyVR

    Joined:
    Mar 26, 2017
    Posts:
    714
    Is it possible to use this plugin with Unity's Network Lobby? If so could somebody PLEASE help me? :)
     
  31. Morderkaine

    Morderkaine

    Joined:
    Oct 22, 2016
    Posts:
    11
    So I didn't realize (because its not in the documentation) that one can call StartClientAll with just the 3 arguments as was suggested.
    Got the GUID successfully, ran StartClientAll giving it the external and internal IPs and GUID of the server, did not work.

    Going to try using Unity MM now.
     
  32. CloudyVR

    CloudyVR

    Joined:
    Mar 26, 2017
    Posts:
    714
    I am trying to use the NATLobbyManager with the NATNetworkManagerHUD which seems to work except for when the "Stop(x)" button is pressed then I get a swarm of errors saying:
    host id out of bound id {0} max id should be greater 0 and less than {0}

    This always occurs on the client right after calling manager.StopHost();

    [EDIT]
    I think my issue was that I wasn't waiting for the connection to the facilitator to complete prior to starting and joining games. I added some checks to make sure OnDoneConnectingToFacilitator() was called before allowing the host/join buttons to be shown.

    However I still get the same error upon pressing "Stop (x)" but I only see it printed once and no longer repeatedly. And when I press stop on the server there was still LobbyPlayers visible in the list (even though nothing was connected). I think I fixed that issue by adding a call to NetworkClient.ShutdownAll() like so:

    Code (csharp):
    1.          void OnGUI() {
    2.                 ...
    3.  
    4.                 //From:
    5.                 if (GUI.Button(new Rect(xpos, ypos, 200, 20), "Stop (X)")) {
    6.                     manager.StopHost();
    7.                 }
    8.  
    9.                 //To:
    10.                 if (GUI.Button(new Rect(xpos, ypos, 200, 20), "Stop (X)")) {
    11.                     manager.StopHost ();
    12.                     NetworkClient.ShutdownAll ();
    13.                 }
    14.              
    15.  
    16.                ...
    Now all of the lobbyplayers clear properly.
     
    Last edited: Jun 10, 2017
    thegreatzebadiah likes this.
  33. Eideren

    Eideren

    Joined:
    Aug 20, 2013
    Posts:
    309
    So I tried all of that and in the end the reason why I couldn't connect externally was because it doesn't always find the NAT device ('NATHelper: NAT Device not found') around 2/3 of the times I try.

    I thought, since it was a warning and you didn't mention anything about it, that it wasn't that important but now I can conclude that I must retry the search until it finds the device to be able to connect properly, is this expected ?

    If it is of any help to you, I have multiple ethernet and tunnel adapter, it might be related ?

    For IPv6 you should still have to port forward right ? 'cause I can't connect using my IPv6 from an external machine, I tried both non-linklocal v6 on my regular ethernet adapter that windows' ipconfig returns and none of them worked, even external sites report that my IPv6 is one of those so it couldn't be the wrong one.
     
  34. CloudyVR

    CloudyVR

    Joined:
    Mar 26, 2017
    Posts:
    714
    I'm interested to know what method you use to invoke the retries?
     
  35. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    Can you expand on how it didn't work? Did punchthrough fail? Did the connection time out? I can probably help you out with some more details. Also the version of StartClientAll that you want to use is documented. Though you're certainly not the first person who couldn't find it. One day I'll get around to writing a better tutorial and updating the docs...
     
  36. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    What version of Unity are you using? I don't seem to be able to replicate this issue, but I'm probably just not testing right. It looks like you were able to work around it at least so I guess it's not a big deal, but if you get me some details I might be a able to find the root cause so the next person won't run into the same issue.
     
  37. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    You could try setting the portForwardingTimeout to something longer. It uses that timeout both for finding the nat device and the actual port forwarding (lame and confusing I know). Maybe I've just got the default timeout too low.

    Here's some code from another user that is supposed to pick the real adapter and filter out vpn adapters and whatnot. I don't know if it's what you're looking for, but it might help:
    Code (CSharp):
    1.  
    2.     void BindBestNetworkAdapter() //Only binds server to an IP if an optimal network adapter exists. Otherwise uses Unity default.
    3.     {
    4.         List<NetworkManagerBehavior.IPNamePair> possibleBindIPs = new List<NetworkManagerBehavior.IPNamePair>();
    5.         if (NetworkManagerBehavior.allPrivateIPs.Count > 0)
    6.         {
    7.             foreach (NetworkManagerBehavior.IPNamePair pair in NetworkManagerBehavior.allPrivateIPs)
    8.             {
    9.                 if(pair.interfaceType == NetworkInterfaceType.Tunnel)
    10.                 {
    11.                     Debug.LogWarning("Possible host network interface skipped due to being a tunnel: " + pair.name);
    12.                     continue;
    13.                 }
    14.                 string uppercaseName = pair.name.ToUpper();
    15.                 if (uppercaseName.Contains("EVOLV") || uppercaseName.Contains("HAMACH") || uppercaseName.Contains("VIRTUALBOX")
    16.                     || uppercaseName.Contains("VMWARE") || uppercaseName.Contains("VPN"))
    17.                 {
    18.                     Debug.LogWarning("PlayMenuManagerBehavior excluded the following network device when attempting to bind host to IP: " + uppercaseName + " whose type is: " + pair.interfaceType.ToString());
    19.                     continue;
    20.                 }
    21.                 else
    22.                 {
    23.                     if (pair.ip != null)
    24.                     {
    25.                         Debug.Log("PlayMenuManagerBehavior added the following network device to the host bind IP list: " + uppercaseName + " whose type is: " + pair.interfaceType.ToString());
    26.                         possibleBindIPs.Add(pair);
    27.                     }
    28.                     //We don't include a case for IPv6 as an IP here because it's likely not an optimal network interface to bind to.
    29.                     //If the only interface's address is strictly IPv6, that should still be used in the Unity backend by default.
    30.                 }
    31.             }
    32.             if (possibleBindIPs.Count > 0)
    33.             {
    34.                 if (possibleBindIPs.Count == 1)
    35.                 {
    36.                     Debug.Log("Found ONE optimal IP to bind to for host! IP used is: " + possibleBindIPs[0].ip + " whose interface name is: " + possibleBindIPs[0].name);
    37.                 }
    38.                 else
    39.                 {
    40.                     Debug.LogWarning("Found MULTIPLE optimal IPs to bind to for host! IP used is: " + possibleBindIPs[0].ip + " whose interface name is: " + possibleBindIPs[0].name);
    41.                 }
    42.                 NetworkManagerBehavior.singleton.serverBindToIP = true;
    43.                 NetworkManagerBehavior.singleton.serverBindAddress = possibleBindIPs[0].ip;
    44.                 NetworkManagerBehavior.privateIPv6 = ""; //UN-write your IPv6! This could prevent multi-binding!
    45.                 return;
    46.             }
    47.         }
    48.         else
    49.         {
    50.             Debug.LogError("NetworkManager list of network adapters was empty! Server was not bound to an IP!");
    51.             return;
    52.         }
    53.         Debug.LogError("Failed to find an optimal network adapter for host! Other players may not be able to join.");
    54.         return;
    55.     }
     
  38. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    Are you sure the machine you are connecting from supports ipv6? Also, are you sure all ISPs involved support ipv6?
     
  39. Eideren

    Eideren

    Joined:
    Aug 20, 2013
    Posts:
    309
    I increased the timeout to two entire minutes and it still couldn't find it, right after that I tried to do a 20 second timeout which would restart the search after each failed attempt until it found it and it didn't work either.

    About the network adapter, I mentioned it because I thought that your plugin might have issues with it, on my side I don't have to care about adapters at all besides showing IPs which is already working and in all cases where doubly verified through websites and windows 's ipconfig.

    So for the IPv6 test, I thought that the support for it was more widespread than it is, I can't actually find another person that has supports for it besides me so, you're right, the issue might simply come from my other peer's lack of support.
     
    thegreatzebadiah likes this.
  40. FlyingHighUp

    FlyingHighUp

    Joined:
    Apr 23, 2012
    Posts:
    16
    Hey @thegreatzebadiah ! I'm currently going through the process of integrating the plugin in my game.

    While using NatTraversal.NetworkManager, I get a NullReferenceException from inside your OnClientSceneChanged(NetworkConnection conn) override. It was strange because I didn't get that exception from the default NetworkManager.

    In specific, it comes from this line in OnClientSceneChanged():
    Code (CSharp):
    1. networkClient.RegisterHandler((short) 32, new NetworkMessageDelegate((object) this, __methodptr(OnMultiClientConnectMsg)));
    (That line was decompiled, so it's going to look different on your end)

    From my observation, "networkClient" was null because "directClient" was null.
    And I think "directClient" is null because I used StartClient() instead of StartClientAll().

    My setup is a little special in that I have some server hosted games that don't require Nat Punchthrough. In cases like these, I have it use StartClient() instead. Is this okay? The only issue so far is it seems to cause this bug. I'm currently getting around it by overriding it with Unity's default implementation.

    If you think I'm on the right track and it's a bug, would you mind adding a check to that block or something for the next release?

    Let me know what you think :confused:

    Edit:
    I also got a NullReferenceException from StartClientAll(). This was because NatHelper was null, and I was calling it before Start() ran. I got around this by waiting a frame so Start() had a chance to run. A warning might help let people know they should wait a frame, as I thought that GetComponent<NatHelper>() would be in Awake.

    Edit2:
    As a suggestion for next release, in UnetGameRoom.cs, could you mark
    OnRoomRegistered(RoomController roomController) virtual? It looks like you guys might have forgot to expose that.
     
    Last edited: Jun 15, 2017
  41. Murgilod

    Murgilod

    Joined:
    Nov 12, 2013
    Posts:
    10,083
    I'm only just getting into networking like... at all, so I apologise if this question has an obvious answer. I'm making a game with Unet and want people to be able to play across the internet without having to resort to using Hamachi or similar programs. I just want people to be able to play my game together without messing around with port forwarding or anything on their end. Just set up the server, enter an IP and go to town punching each other over the internet.

    Would this asset help me accomplish this? It's pretty much a guaranteed sale if it will.
     
  42. CloudyVR

    CloudyVR

    Joined:
    Mar 26, 2017
    Posts:
    714
    Yes, this plugin allows clients to establish connections directly across the web (and offers options to fallback to Unity's relay servers if you wish).

    Keep in mind you must own a server that is connected to the internet to act as your facilitator. However you can find a Virtual Private Server relatively easily and they are priced very competitively. You will need it in order to act as the facilitator which your game will connect to and is only required so as to handle the handshaking of players with other players on the web. After which your players will be connected as peer-to-peer and you can play for hours without any bandwidth caps. Your server is mostly idle so a minimum spec/cheapest available VPS will suffice (or host a server from home/work..).

    Best of luck on you MP game!
     
    Last edited: Jun 15, 2017
    thegreatzebadiah likes this.
  43. Murgilod

    Murgilod

    Joined:
    Nov 12, 2013
    Posts:
    10,083
    Hm. I'll look into VPSs first. I'm a bit strapped for cash until I next get paid. Thanks for the help and for wishing me luck!
     
  44. CloudyVR

    CloudyVR

    Joined:
    Mar 26, 2017
    Posts:
    714
    Keep in mind that the developer of this plugin has configured his server at http://www.grabblesgame.com/ to act as a facilitator and allows all developers to use it freely. This makes it convenient to test as it's something you can use as soon as you have imported the plugin into your project. Just don't use his server for a production game is all!
     
    thegreatzebadiah likes this.
  45. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    I've tried digging in to the Open.NAT code a bit to see if I can find any reason why it would sometimes fail to find the device but I don't see anything obvious. It seems like if it works once it should work every time. Obviously that's not what you're seeing though, and I'm at a loss to explain why.

    I did find a possible issue in the plugin code where it looks like attempting to find the device more than once will output that error, but only in cases where a device is already found anyway, so it's more of a false error report than an actual issue. If you're seeing that error the first time you try and find a device then something is definitely going wrong.

    You may want to try using Open.NAT directly just to be 100% sure it's not something my code is doing. It should look something like:

    Code (CSharp):
    1. NatDiscoverer discoverer = new NatDiscoverer();
    2. Task portForwardingTask = discoverer.DiscoverDeviceAsync(PortMapper.Upnp | PortMapper.Pmp, portForwardingCancellationToken).ContinueWith(
    3.     task =>
    4.     {
    5.         // Check if a device was found
    6.         if (!task.IsFaulted && !task.IsCanceled && task.Result != null)
    7.         {
    8.             // Got a result, we are done task.Result is the device
    9.         }
    10.         else
    11.         {
    12.             // No device found
    13.         }
    14.     }  
    15. );
    If you get the same results with that code then your next step would be to report the issue to the Open.NAT developer I'm afraid.
     
    Last edited: Jun 15, 2017
  46. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    @FlyingHighUp I don't think mixing StartClient() and StartClientAll() is going to work well. You would probably be better of turning off punchthrough and relay connections and leaving only direct connect on. Then you can call StartClientAll() and it will behave more-or-less like a normal client.

    Noted and fixed. In the next release the NATHelper reference will be set in Awake().

    Mmmm, I think you may be confused, UnetGameRoom.cs isn't anything from the plugin.
     
  47. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
  48. Murgilod

    Murgilod

    Joined:
    Nov 12, 2013
    Posts:
    10,083
    Alright, on the advice of @trappist-1 and having read into some VPS options for when I finally reach a release phase, I've bought it. I've managed to get Unet working smoothly for LAN stuff, so hopefully this will go as smoothly in integration.
     
    CloudyVR likes this.
  49. Eideren

    Eideren

    Joined:
    Aug 20, 2013
    Posts:
    309
    Alright, I did a couple of other tests using your code and the open nat dll that you are providing with your asset, here's the time it took to complete each discovery inside a normal run in seconds :
    n1 : 274.65
    n2 : 223.73
    n3 : 1324.75
    n4 : 348.04
    n5 : 793.71
    n6 : 1438.54
    Yes, between 4.5 minutes to 24 minutes just to find the device.

    Here's the time it takes if I call it inside a constructor which occurs on Play before Start()
    n1 : 62.51
    n2 : 13.81
    n3 : 32.51
    n4 : 9.29
    n5 : 10.70
    n6 : 10.28
    n7 : 7.21

    Now here's another test that uses the same code but under a visual studio WPF application instead of unity editor's play mode and using Open.NAT 2.1.0's nugget package.
    n1 : 15.66
    n2 : 15.49
    n3 : 8.50
    n4 : 20.50
    n5 : 37.49
    n6 : 11.50
    n7 : 38.49
    n8 : 5.50
    n9 : 17.49
    n10 : 6.49
    n11 : 7.49
    n12 : 46.50
    n13 : 64.49
    n14 : 28.50
    n15 : 5.50
    n16 : 2.49
    n17 : 17.49
    n18 : 41.49
    n19 : 4.50
    n20 : 12.49
    Looks very similar to the run inside a constructor but those occurred one after another, it doesn't look like it comes from Open.NAT.
    The first test under Unity looks like a job priority issue ? I guess I could call it as early as possible but it would be far more healthy if we actually knew why it happens instead of working around it.


    Edit : Your System.Threading.dll creates conflicts with the new experimental scripting runtime of version 2017.1.0b9 when working with threading classes.
     
    Last edited: Jun 18, 2017
    FlyingHighUp likes this.
  50. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    Hey @HappyBadgerStudio, have you made any progress on these issues? Does it seem like a problem with the plugin or something you were able to work around? We're finally about ready for our own steam release so I'm curious how your experience is going.