Search Unity

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

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

  1. WaaghMan

    WaaghMan

    Joined:
    Jan 27, 2014
    Posts:
    245
    On the NetworkMigration: I'm unable to continue, I'm stuck on the clients trying to connect to the new host: The new host sets the lobby data (New IPs, GUID, etc.), and the clients know who they have to connect (by changing some Steam lobby data values), but as @yuchun1108 said , the method ReconnectToNewHost() only takes a single address, so no external IP/internal IP/punchthrough is probably made at this point.

    Not really sure, though,and I've tried to do it manually but attempting to connect to the external IP and try again for the internal if it didn't work, but it reports success on the first attempt (the external IP) even when it's not true.

    My code (really messy):

    Code (csharp):
    1.  
    2. protected override void OnClientDisconnectedFromHost(UnityEngine.Networking.NetworkConnection conn, out UnityEngine.Networking.NetworkMigrationManager.SceneChangeOption sceneChange)
    3.     {
    4.         Debug.Log("OnClientDisconnectedFromHost");
    5.         sceneChange = SceneChangeOption.StayInOnlineScene;
    6.  
    7.         //base.OnClientDisconnectedFromHost(conn, out sceneChange);
    8.  
    9.         StartCoroutine(WaitForNewHost(conn));
    10.     }
    11.  
    12. IEnumerator WaitForNewHost(UnityEngine.Networking.NetworkConnection conn)
    13.     {
    14.  
    15.         float time = Time.realtimeSinceStartup;
    16.         while (Time.realtimeSinceStartup - time < 10.0f)
    17.         {
    18.            // Check the new owner of the Steam lobby.
    19.             if (MilkNetworkManager.singleton.Session.IsHost)
    20.             {
    21.                 // We're the new host
    22.                 for (int i = 0; i < peers.Length; i++)
    23.                 {
    24.                     if (peers[i].isYou)
    25.                     {
    26.                         NetworkServer.Configure(networkManager.topo);
    27.  
    28.                         bool success = base.BecomeNewHost(networkManager.networkPort);
    29.                      
    30.                         Debug.Log("BecomeNewHost: " + success);
    31.  
    32.                         if (success)
    33.                         {
    34.                             ((MilkNetworkManager)networkManager).BecameHost(peers[i].connectionId);
    35.                         }
    36.  
    37.                         yield break;
    38.  
    39.                     }
    40.                 }
    41.             }
    42.             else
    43.             {
    44.                // Get Steam Data
    45.                 Milkstone.Game.Steam.Network.SteamSessionProperties ssp = MilkNetworkManager.singleton.Session.SessionProperties as Milkstone.Game.Steam.Network.SteamSessionProperties;
    46.                 if (ssp!=null)
    47.                 {
    48.                     ssp.RefreshData();
    49.  
    50.                     // Wait until the new host sets the connection Id for us to know who it is.
    51.                     int connectionId = Milkstone.Utils.GameMath.ParseInt(ssp.GetLobbyData("hostConnectionId"));
    52.                     Debug.Log("New host connection id: "+connectionId);
    53.  
    54.                     for(int i=0;i<peers.Length;i++)
    55.                     {
    56.                         // This host (connectionId 0) is the one that just left
    57.                         if (peers[i].isHost) continue;
    58.                         if (peers[i].connectionId == connectionId)
    59.                         {
    60.                             string address = ssp.GetLobbyData("publicIP");
    61.  
    62.                             // This is the new host. Try External IP first.
    63.                             Debug.Log("ReconnectToNewHost: " + address + " " + networkManager.networkPort);
    64.                             base.newHostAddress = address;
    65.  
    66.                          
    67.                             ReconnectToNewHost(address, networkManager.networkPort);
    68.  
    69.                             float t = Time.realtimeSinceStartup;
    70.                             // Attempt connection for 5 seconds
    71.                             while((client.connection == null || !client.connection.isConnected) && ((Time.realtimeSinceStartup - t) < 5.0f))
    72.                                 yield return null;
    73.  
    74.                             if (!client.connection.isConnected)
    75.                             {
    76.                                 address = ssp.GetLobbyData("internalIP");
    77.                                 base.newHostAddress = address;
    78.  
    79.                                 Debug.Log("ReconnectToNewHost (2nd attempt): " + address + " " + networkManager.networkPort);
    80.                                 // Try the private address
    81.                                 ReconnectToNewHost(address, networkManager.networkPort);
    82.  
    83.                                 t = Time.realtimeSinceStartup;
    84.                                 // Attempt connection for 5 seconds
    85.                                 while ((client.connection == null || !client.connection.isConnected) && ((Time.realtimeSinceStartup - t) < 5.0f))
    86.                                     yield return null;
    87.                             }
    88.  
    89.                             if (client.connection.isConnected)
    90.                             {
    91.                                 Debug.Log("Managed to reconnect!");
    92.                             }
    93.                             else
    94.                             {
    95.                                 Debug.Log("Failed to reconnect");
    96.                                 networkManager.StopClient();
    97.                             }
    98.  
    99.                             yield break;
    100.                         }
    101.                     }
    102.                 }
    103.             }
    104.  
    105.             yield return null;
    106.         }
    107.  
    108.         // Time out, the host didn't set the lobby data in time.
    109.         networkManager.OnClientDisconnect(conn);
    110.     }
     
  2. bekilo

    bekilo

    Joined:
    Apr 22, 2013
    Posts:
    3
    @WaaghMan
    I have now set it to icanhaz and its ipv6 equivalent. same exact error.
     
  3. Imtnt

    Imtnt

    Joined:
    Nov 13, 2013
    Posts:
    8
    Ipv6 lookup causes fatal errors when run on networks that don't support ipv6 (e.g. College Networks). Is there a way I can disable the ipv6 lookup?

    EDIT: confirmed, rolled back to pre ipv6 version and everything works fine
     
    Last edited: Nov 17, 2016
  4. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    I just tried with that version of the editor and only relay connections enabled and it seemed to work fine.
     
  5. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    Yeah, definitely seeing this. Rolling back is the way to go for now. It will be fixed in the next update which I'm putting together now.
     
  6. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    @bekilo If you override the start method you definitely do want to call base.Start() at the top. If you have an Awake method things get kind of weird. See this post and especially the comment on it. You need to call the base Awake method via reflection because it's not public so you can't call it like you would normally call a base method.
     
    Last edited: Nov 18, 2016
  7. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    I just fixed it so that it will it will be set in the next update but for future reference this is how I get the internal IP's:

    hostInternalIP = Network.player.ipAddress;
    hostInternalIPv6 = networkManager.getIPAddress("", IPTYPE.LOCAL_IP, ADDRESSFAM.IPv6);
     
  8. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    Yeah, I'm working on expanding this now so that it will properly handle all the normal connection info. Looks like punch-through isn't ever actually happening during host migration right now which is kind of...limiting.

    This should be the last fix and then I'll package it all up.
     
  9. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    @WaaghMan Using the externalIP in ReconnectToNewHost() should be the correct thing to do and should work except where direct connections aren't possible. Can you elaborate on what happens when it reports success but fails?
     
  10. WaaghMan

    WaaghMan

    Joined:
    Jan 27, 2014
    Posts:
    245
    Sure, what I meant is that on these lines of code:

    Code (csharp):
    1.  
    2. ReconnectToNewHost(address, networkManager.networkPort);
    3. float t = Time.realtimeSinceStartup;
    4. // Attempt connection for 5 seconds
    5. while((client.connection == null || !client.connection.isConnected) && ((Time.realtimeSinceStartup - t) < 5.0f))
    6. yield return null;
    The loop ends properly (client.connection is not null, and isConnected is true), however no connection was actually established, I think. At least the new host didn't get the new connection, and the client trying to reconnect to the new host will fail when sending messages as if it was not connected.

    The connection in this specific case is NOT expected to work, because it's trying to connect to our public IP from within the LAN, so it should fail and then we would try with the internal IP.

    Maybe I'm just not checking the correct properties/variables, I'm not really sure...
     
  11. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    Try client.isConnected instead of client.connection.isConnected. They sort of mean different things. The connection is "connected" as soon as the socket is open. The client isn't connected until it is actually connected.

    That should get that failing properly at least. I'm in the process of fixing the underlying problem of punch-through not being used for migrations.
     
  12. iddqd

    iddqd

    Joined:
    Apr 14, 2012
    Posts:
    501
    Thanks, i now got it working too without the Matchmaker and just the MatchID!
     
  13. bekilo

    bekilo

    Joined:
    Apr 22, 2013
    Posts:
    3
    @thegreatzebadiah I did indeed have an Awake function, but i have since removed it and nothing has changed, still error at line 689 of networkManager.cs called by base.Start(); are there any other functions i shouldn't override or should call before base.Start?

    This is my full class (minus two coroutines which are not called when hosting(getOrSetNetworkID, and joinCoroutine)):
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using UnityEngine.Networking;
    4. using UnityEngine.SceneManagement;
    5. using UnityEngine.Networking.Match;
    6.  
    7. public class SpecialNetworkManager : NATTraversal.NetworkManager {
    8.     public NetworkConnection conn;
    9.     public override void OnServerConnect(NetworkConnection conn)
    10.     {
    11.         base.OnServerConnect(conn);
    12.         this.conn = conn;
    13.         GameManager.SNM = this;
    14.     }
    15.     public override void OnClientConnect(NetworkConnection conn)
    16.     {
    17.         base.OnClientConnect(conn);
    18.         this.conn = conn;
    19.         GameManager.SNM = this;
    20.     }
    21.     public override void OnServerAddPlayer(NetworkConnection conn, short playerControllerId)
    22.     {
    23.         base.OnServerAddPlayer(conn, playerControllerId);
    24.        
    25.     }
    26.     public override void OnStopClient()
    27.     {
    28.         base.OnStopClient();
    29.  
    30.         SceneManager.LoadScene("MainMenu");//TODO only useful for debugging remove later
    31.  
    32.     }
    33.     public const float connectionTimeout = 60.0f;
    34.     public override void Start()
    35.     {
    36.         base.Start();
    37.         MatchParams mp = MetaManager.matchParamsCurrent;
    38.         if (mp.host)
    39.         {
    40.            
    41.             Debug.Log(MetaManager.matchParamsCurrent);
    42.             StartHostAll("1234", 2);
    43.             return;
    44.             StartHostAll(MetaManager.matchParamsCurrent.mid,
    45.                 2, true, MetaManager.matchParamsCurrent.pass, 0, 1,
    46.                 delegate (bool sc, string exi, MatchInfo mi) {
    47.                     if (!sc) GameManager.showFailedConnection();
    48.                     StartCoroutine(getOrSetNetworkID(mi.networkId.ToString(),delegate{ }));
    49.             });
    50.            
    51.             GameManager.showWaitingForOtherPlayer();
    52.  
    53.         }
    54.         else
    55.         {
    56.             GameManager.showWaitingForOtherPlayer();
    57.             StartCoroutine(getOrSetNetworkID("", delegate
    58.             {
    59.                 StartCoroutine(joinCoroutine(0));
    60.  
    61.             }));
    62.         }
    63.  
    64.     }
    65.     public int getRTT()
    66.     {
    67.         byte b;
    68.         if (conn.hostId > -1)
    69.             return NetworkTransport.GetCurrentRtt(conn.hostId, conn.connectionId, out b);
    70.         else
    71.             return -1;
    72.  
    73.     }
    74. }
     
  14. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    Looks like you're just missing the NATHelper component. It should be added to the same object as your SpecialNetworkManager script. I'll add a more helpful error message in there.
     
  15. akuno

    akuno

    Joined:
    Dec 14, 2015
    Posts:
    88
    I am connecting to a friend's computer.

    It does NOT connect using only direct and punch connect (without relay).
    When I do StartClientAll with only ConnectRelay, I can connect and play fine.
    When I do StartClientAll with all 3 options(relay, direct, punch) I can connect, but after 10s I get disconnected and the following error:

    "host id out of bound id {0} max id should be greater 0 and less than {0}"

    Maybe it could be the plugin trying to jump to a direct connection? Any ideas to fix it?
     
    Last edited: Nov 19, 2016
  16. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    @akuno that's definitely odd behaviour. Is this happening in the Example scene without any code modifications?
     
  17. Trekopep

    Trekopep

    Joined:
    Dec 18, 2013
    Posts:
    15
    I have the Facilitator up and running on an Ubuntu server, but it seems to attach to the first interface it finds, which is an internal docker only network. Is there a way to choose which IP the Facilitator is listening on?
     
  18. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    @Trekopep Have you tried connecting to it even though it appears to bind to the wrong ip? I've had reports before of it reporting the wrong ip but working anyway. Let me know though if that's not the case and I can rework it a bit so you can pass in the ip to bind to.
     
  19. Trekopep

    Trekopep

    Joined:
    Dec 18, 2013
    Posts:
    15
    It is working (it's listening to port 61111 on one, and port 61112 on the other), but since the docker network is only for docker containers and their associated services, and the facilitator isn't a container, I'm worried it could interfere with the docker network. Being able to pass the ip to bind to would be fantastic.
     
  20. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
  21. iddqd

    iddqd

    Joined:
    Apr 14, 2012
    Posts:
    501
    I'm setting up host migration and am encountering the following issue:
    1) A is the Host
    2) B connects as client
    3) A leaves, B becomes the new host > Working fine
    4) C would like to join the game on B: B throws the following error: "Unknown message ID 32763 connId:1"

    I am using the NAT Traversal Host migration script, but I'm guessing it's a generic UNET issue.

    Any idea what the cause could be for this.

    Thanks.
     
  22. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    @iddqd This post just convinced me to fix yet another host migration issue just to be able to test the scenario you describe. With unet matchmaking the match was being destroyed as soon as A disconnected so C couldn't even find the match to connect. I just tried not doing that (duh) and (with a couple other modifications to the plugin) it seems to work perfectly. I was thinking that the match should be destroyed since the host is disconnected but it seems like the new host is able to take over the match no problem. Long story short, I'll send you the latest build in a few minutes and it may work better. It seems like you're _not_ using unet matchmaking but I think some of the changes I just made might fix the issue you're having anyway.
     
  23. Trekopep

    Trekopep

    Joined:
    Dec 18, 2013
    Posts:
    15
    Worked like a charm. Thanks!
     
    thegreatzebadiah likes this.
  24. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    For one glorious moment I thought I was going to be able to get host migration working with the relays but it just doesn't seem to be possible. The new host tries to take over as the UNet match host but it's no good. When another client tries to connect to the match it acts like there is no match host :(

    I don't think migration with relays is going to be possible until the Unity team does some infrastructure updates but I'd love it if someone can prove me wrong. Has anyone been able to get migration working with the relays? Am I just doing it wrong?!
     
  25. iddqd

    iddqd

    Joined:
    Apr 14, 2012
    Posts:
    501
    I guess one way would be for the new Host to just create a completely new Match and have the remaining players connect to him, it wouldn't be seamless - but better than a disconnect. But I guess it depends on the type of game too.
     
  26. Jos-Yule

    Jos-Yule

    Joined:
    Sep 17, 2012
    Posts:
    292
    I'm getting this error, and i can't figure out if it is something i'm doing or what... Any suggestions?

    Code (CSharp):
    1. Failed to send big message of 1404 bytes. The maximum is 1400 bytes on this channel.
    2. UnityEngine.Networking.NetworkServer:SetClientReady(NetworkConnection)
    3. NATTraversal.NetworkManager:OnServerReadyMsg(NetworkMessage) (at E:/_Noble Whale/NAT Traversal Stuff/NAT Traversal DLL/NATTraversalForUNET/NetworkManager.cs:912)
    4. UnityEngine.Networking.NetworkServerSimple:Update()
    5. NATTraversal.<>c:<Update>b__62_0(ExternalServer) (at E:/_Noble Whale/NAT Traversal Stuff/NAT Traversal DLL/NATTraversalForUNET/NetworkManager.cs:703)
    6. System.Collections.Generic.List`1:ForEach(Action`1)
    7. NATTraversal.NetworkManager:Update() (at E:/_Noble Whale/NAT Traversal Stuff/NAT Traversal DLL/NATTraversalForUNET/NetworkManager.cs:703)
     
  27. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    My first guess would be that you're sending a large spawn message over a non-fragmented channel. I don't think it's anything specific to the plugin. If you are using a fragmented channel then maybe it is something I'm doing wrong. Let me know.
     
  28. Jos-Yule

    Jos-Yule

    Joined:
    Sep 17, 2012
    Posts:
    292
    Yeah there are several scripts all on the same game object, all with a SyncVar which is a string. I also did set the channel to fragmented via the [NetworkSettings] attribute. Does the attribute work for syncvar items too? I didn't think the string was very large but I can see that it would be larger in total for all the components then 1400 bytes. Is this limit a per-networkIdentity limit?
     
  29. Jos-Yule

    Jos-Yule

    Joined:
    Sep 17, 2012
    Posts:
    292
    Ok i've fixed the previous error by moving the SyncVar value to another component on a different GameObject.

    However, i do get this error when exiting from a game, trying to clean up all or any leftover network bits.

    Code (CSharp):
    1. host id out of bound id {-1} no host exists
    2. UnityEngine.Networking.NetworkServer:Shutdown()
    3. NATTraversal.NetworkManager:StopServer() (at E:/_Noble Whale/NAT Traversal Stuff/NAT Traversal DLL/NATTraversalForUNET/NetworkManager.cs:614)
    4. ScarcityNetworkManager:ShutdownNetwork() (at Assets/Scarcity/Scripts/Networking/ScarcityNetworkManager.cs:251)
    5. GameInitializationAndCleanup:Cleanup() (at Assets/Scarcity/Scripts/Game Setup/GameInitializationAndCleanup.cs:173)
    6. <LobbyBackButtonPressedHelper>c__IteratorA6:MoveNext() (at Assets/Scarcity/Scripts/Game Setup/GameInitializationAndCleanup.cs:436)
    7.  
    and then i get this repeating

    Code (CSharp):
    1. host id out of bound id {0} max id should be greater 0 and less than {0}
    2. UnityEngine.Networking.NetworkIdentity:UNetStaticUpdate()
    3.  
    This is my current block of "just try everything to shut it all down" clean up code. This exists in a subclass of NATTraversal.NetworkManager .

    Code (CSharp):
    1. StopMatchMaker();
    2. StopClient();
    3. StopServer();
    4.  
    5. natHelper.StopListeningForPunchthrough();
    6. natHelper.stopPortForwarding();
    7. natHelper.StopPunchingThrough();
    8.  
    9. NetworkServer.Shutdown();
     
    deliinteractive likes this.
  30. akuno

    akuno

    Joined:
    Dec 14, 2015
    Posts:
    88
    I got the same problem when cleaning up, It happened because I was calling NetworkServer.SetClientNotReady(conn); twice.

    I resolved by just calling it once at OnMultiClientDisconnect()
     
  31. akuno

    akuno

    Joined:
    Dec 14, 2015
    Posts:
    88
    I fixed the hostID error message, but I am still getting those annoying disconnects as described. I ve tested with different friends, it happens when I cannot connect directly to them.

    I noticed a pattern between the disconnects.

    -Using only ConnectRelay, I can connect and play fine.
    -Using only direct and punch connect (without relay): Not able to connect, triggers OnMultiClientDisconnect() around 45s after using StartClientAll()
    -Using all 3 options (direct, punch, relay): Connects to the game, and I am able to play a little. But OnMultiClientDisconnect() is triggers around 45s after using StartClientAll().

    It seems that the manager is disconnecting when trying to change from relay to direct connection. How can I stop the plugin trying to direct connect once relay connected?


     
    Last edited: Nov 24, 2016
    deliinteractive likes this.
  32. Jos-Yule

    Jos-Yule

    Joined:
    Sep 17, 2012
    Posts:
    292
    @akuno Thanks - i was missing a call to NetworkServer.SetAllClientsNotReady(); - that fixed most of those errors up.

    I am still having an interesting error. If i have joined a server, but then leave the server, calling the above "clean it all up" code, i still sometimes get re-joined to the server! I'm assuming because under the hood it is trying to connect me directly after an initial relay connection. How can I really stop all networking activity?
     
    akuno likes this.
  33. WaaghMan

    WaaghMan

    Joined:
    Jan 27, 2014
    Posts:
    245
    Hello, new issue (ok, actually not new, but found the cause). StartClientAll may cause JoinMatch to throw an ArgumentNull exception that isn't handled. I think it happens if StartClientAll is called before our External IP is obtained, passing a null string to the method.

    We'll just wait until we have the external IP before calling the StartClientAll method, but it would probably be a good idea to warn / wait for the external IP in the plugin.
     
  34. KaldrisRelm

    KaldrisRelm

    Joined:
    Mar 8, 2014
    Posts:
    10
    @thegreatzebadiah - I noticed in your 1.45 patch notes you mentioned support for NetworkLobbyManager, did you have an idea of when that would be up and running? I jumped the gun and picked up the asset before I noticed it didn't initially work with the Lobby system. I'm looking at the prospect of trying to implement the Lobby system, but figured I should ask in case it was something already / close to up and running.
     
  35. TCROC

    TCROC

    Joined:
    Aug 15, 2015
    Posts:
    230
    Hey I have been having issues with the Host Migration. I connect my players directly. The host leaves, and the next player in line to become host gets prompted to become the host. Before the player selects to become the new host, there is an error message constantly being called saying:

    "Send command attempted with no client running [client=hostId: 0 connectionId: 1 isReady: True channel count: 2].
    UnityEngine.Networking.NetworkBehaviour:SendCommandInternal(NetworkWriter, Int32, String)
    Player_Controller_1:CallCmdToShoot(Boolean)
    Player_Controller_1:Update() (at Assets/JellyBall/Scripts/_JellyScripts/Player_Controller_1.cs:255)"

    Upon becoming the new host, the player loses all control of himself and he is moved to the center of the scene by his Network Transform Child components. When I try to reconnect the host to him, Unity crashes on the new host. I am using the ExampleMigrationManager script provided by the NAT Traversal asset for host migration.
     
    Last edited: Nov 26, 2016
  36. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    @akuno The call to OnMultiClientDisconnect is a good thing. The direct connection is started at the same time as the relay connection, when the direct connection fails OnMultiClientDisconnect() will be called. At that point the plugin should see that there is a relay connection and ignore the disconnect by not switching to the offlineScene or calling OnClientDisconnect(). I think maybe the problem is you're overriding OnMultiClientDisconnect() and not calling the base method, or you're treating OnMultiClientDisconnect() like a real disconnection in some other way. Unless you really need to know when one of the multiple clients (direct, punchthrough, relay) disconnects you should override OnClientDisconnect() instead which will only be called when the client is actually fully disconnected.
     
    akuno likes this.
  37. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    I believe this is fixed in the new build. I just emailed you.
     
  38. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    Added to my list. Thanks for reporting.
     
  39. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    @KaldrisRelm I haven't even started working on it so you're probably better off implementing your own lobby system. Sorry but I'm a busy man! It will probably get done around the same time I get around to implementing steam lobby support for matchmaking.
     
  40. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    Have you tried to replicate the problem in the Example scene? It sounds like you're trying to send CmdToShoot while the client is not connected. Maybe check ClientScene.ready or client.isConnected on the NetworkManager before sending the message.

    Not sure about the teleporting and crashing though, definitely test in Example scene and see if there's anything you are doing different.
     
  41. KaldrisRelm

    KaldrisRelm

    Joined:
    Mar 8, 2014
    Posts:
    10
    No worries at all - had done some testing over the weekend to see if I could slot the network lobby system into StartHostAll(), but I think StartHostAll() automatically sets a player to ready and skips directly to the online scene. Wasn't able to find a way to prevent that though. I think to properly utilize the lobby system the StartHostAll() would need to be changed directly (or maybe a StartLobbyHostAll() call instead).

    I'm going to do some more testing next week on a base lobby networking system, if I find out a way to get it to work I'll post it up here for everyone.
     
  42. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    @KaldrisRelm Just off the top of my head I think if you override OnClientConnect() and don't call base.OnClientConnect() it will not set the client ready and (hopefully) not change to the online scene.
     
  43. TCROC

    TCROC

    Joined:
    Aug 15, 2015
    Posts:
    230
    Thanks for the reply. I followed your advice and narrowed down my issue to being somewhere within my CustomNetworkManager as I got it working correctly with your ExampleNetworkManager with my project. That one shouldn't be too hard to figure out. However, in the process I came across one other issue:

    Upon disconnecting as the host, the match is removed from the Unity match list and I am no longer able to join it via the join button even though the host has migrated to someone else. (I'm pretty sure I saw you address this issue somewhere else in the forum but I thought I would bring it to your attention just in case).
     
  44. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    @TCROC I've got some bad news for you. The relays do not support host migration. There is no way for a client to become the host on the relay, so even if the match was not destroyed all that would happen would be that someone would try to join it, see that there there is no host, and disconnect. As far as I can tell this is entirely on unet's end. There is some code that looks like it's intended to let a client take over the match on the relays but it just doesn't seem to work: https://docs.unity3d.com/ScriptReference/Networking.NetworkServer.BecomeHost.html

    Disclaimer: I could be totally wrong but I tried to get it to work for a few days with no luck. I've also asked around a bit on the discord channel and here. I haven't found anyone yet who claims to have gotten migration working with the relays. Plus there is the disconcerting line at the very bottom of this page: https://docs.unity3d.com/Manual/UNetHostMigration.html

    All that being said...I believe in the latest update (that just hit the store) I did change it so that the match is not destroyed. This is so that you can still list the match and join it directly or via punch-through, just don't expect the relay connection to work.
     
    Last edited: Nov 29, 2016
  45. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    NAT Traversal v1.46 Released
    • Improved host migration support.
    • Improved IPv6 Support
    • Moved some stuff from Start() to Awake() to avoid issues with connecting too early.
    • Fixed some issues with fetching local ipv6 address.
    • Fixed issue with disconnecting on the host after a direct connection is established but before punch-through has finished.
    • Fixed a problem with punch-through in editor version 5.3.0 specifically.
    • Fixed an issue with timeout disconnects not being cleaned up correctly causing subsequent connections to fail.
    • Fixed a problem with null arguments when deleting port mappings.
    • Added extra info to failed to join match error message.
    • Fixed issue with OnClientConnect being called before the onlineScene is loaded instead of after
    Notice: Some of these changes may effect existing functionality. In particular if you have an Awake method in your NetworkManager you should now make sure to call base.Awake(). Also if you were using the reflection hack described here to call the base Awake() method it is no longer necessary, just call base.Awake().
     
  46. WaaghMan

    WaaghMan

    Joined:
    Jan 27, 2014
    Posts:
    245
    Thank you for the update. We finally got the host migration to work (not enough testing yet though).

    Some issues we found (not really related with the plugin, but worth mentioning for others having the same issues):

    * We manually rejected connections when a game is in progress, this caused a problem because people joining to the new host would get kicked because of this. We had to allow a grace period (easy) and determine if players connecting were also in the old host (hard). For that, we needed to save a copy of the peers list in the old server before it got cleaned, and parse IP addresses to compare (since the client is just connecting, there's not much more info available). There was a problem with comparing IPv6 format addresses with IPv4 ones, so I had to manually remove the "::ffff:" part from the string. Dirty but it worked.
    * We also have to manually use the following code on OnClientConnect to ensure ClientScene.AddPlayer() gets called when doing host migration:
    Code (csharp):
    1.  
    2. // Happens during host migration (I think...)
    3.         if (MigratingHost && clientLoadedScene)
    4.         {
    5.             ClientScene.Ready(conn);
    6.             if (autoCreatePlayer)
    7.                 ClientScene.AddPlayer(0);
    8.         }
    9.  
    MigratingHost is a variable we set while performing the migration.

    * Since @thegreatzbadiah said relay didn't support host migration, we just create a new match on the new host when it happens, and set the new matchId on the Steam lobby, so new players will be able to use relay to connect to the new host. It won't work for current players (it probably could with some more work), but at least the game will be still joinable by new ones.
     
    thegreatzebadiah likes this.
  47. qingmeng

    qingmeng

    Joined:
    Oct 29, 2016
    Posts:
    5
    @thegreatzebadiah
    Thank you. So is it that if I want to create a game with more than 2 players, I just need to tell the 2nd, and 3rd, etc clients about this port? And then they can connect directly with the public IP on this port?
     
  48. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    No, each additional client will need to punch-through and the server will listen on an additional port for each new client.
     
  49. TwistedSage

    TwistedSage

    Joined:
    Dec 12, 2012
    Posts:
    21
    Is it possible to skip the facilitator, if I have my own master server? I'm only interested in then punchthrough NAT through the router.
     
  50. thegreatzebadiah

    thegreatzebadiah

    Joined:
    Nov 22, 2012
    Posts:
    836
    The facilitator is what makes punch-through work so I'm afraid it's necessary.