Search Unity

Netcode offline to online

Discussion in 'Netcode for GameObjects' started by AdamBlaszczyk, Jan 17, 2023.

  1. AdamBlaszczyk

    AdamBlaszczyk

    Joined:
    Oct 8, 2018
    Posts:
    10
    Hello. I want to create game that can be played in coop using Relay service. But I also want this game to be viable in singleplayer even without internet connection. Moreover, I want to be able to switch from single mode to multi.

    What I'm aiming for is something like Minecraft. Player starts singleplayer session, then, if they want, they can open this session for other players via 'Open to LAN' (in my case, it will be connecting to Relay).

    All I was able to find is that I need two transport objects: one that is capable of creating local server without internet connection (I'm using Unity Transport) and second one, Relay Unity Transport. I start session with first one and then switch to second one when I want to open my game for others.

    But that's all I was able to come up with. I don't know how to switch from local server to Relay and how to do so while keeping all variable values.

    Does anyone of you have any idea how to do this?
     
  2. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    5,890
    In cases like these, there is no such thing as a singleplayer game. You will only implement a server-client game with the "singleplayer" simply being the host player playing on its own, hosting a game on his local machine that will reject any incoming client connections by default (optional) via connection approval.

    The functionality of "open game to LAN" is simply a switch with which the host can control whether connection approval will always reject new clients or not. With port forwarding set up, this would also allow players to join over the Internet if they have the public IP and port.

    In the same way you can implement "open game to internet" and that will make the host instance connect to the Relay service, allow other clients to join and enable them to join the game over the Internet via the Relay service.
     
  3. AdamBlaszczyk

    AdamBlaszczyk

    Joined:
    Oct 8, 2018
    Posts:
    10
    Yes, that's exactly what I want to achieve. The problem is that I don't know how to connect local 'singleplayer' server with Relay service without shutting down local server and starting new one with Relay settings.

    Right now, if I just change transport layer to Relay and setup Relay data in a NetworkManager, clients will get timeout when they try to connect.

    This is how I do it:

    Pseudo-Singleplayer
    Code (CSharp):
    1. // Set transport layer to one that allows local hosting (not Relay)
    2. NetworkManager.Singleton.NetworkConfig.NetworkTransport = localTransport;
    3. NetworkManager.Singleton.StartHost();
    Enabling Multiplayer
    Code (CSharp):
    1.  
    2. // Set transport layer to Relay
    3. NetworkManager.Singleton.NetworkConfig.NetworkTransport = relayTransport;
    4.  
    5. // Create Relay server
    6. Allocation alloc = await RelayService.Instance.CreateAllocationAsync(15);
    7.          
    8. // Subscribe to connection approval method
    9. NetworkManager.Singleton.ConnectionApprovalCallback = ApprovalCheck;
    10.          
    11. // Set password (host's connection also has to be approved)
    12. NetworkManager.Singleton.NetworkConfig.ConnectionData = System.Text.Encoding.ASCII.GetBytes(passwordInput.text);
    13.          
    14. // Open connection and start hosting
    15. relayTransport.SetHostRelayData(alloc.RelayServer.IpV4, (ushort)alloc.RelayServer.Port, alloc.AllocationIdBytes, alloc.Key, alloc.ConnectionData);
    16.  
    17. // Get join code, print it and copy to clipboard
    18. string joinCode = await RelayService.Instance.GetJoinCodeAsync(alloc.AllocationId);
     
  4. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    5,890
    Ah, I see. I haven‘t used Relay yet but it makes sense that it expects the server/host session to be created via/through the Relay service. Currently there is no host migration feature in NGO and I would suspect that this also affects your use case. Though I have no first hand experience in this scenario.

    Personally I would try to make the „open game“ feature to do what is necessary, ie persist the current state, end the (LAN/local) host session and start a new host via Relay. In theory this should be relatively seamless despite reloading the world on the host‘s side.

    You could perhaps probe whether the Relay service is accessible, and make the singleplayer session host the game via Relay to make the transition smoother while disallowing connections until the game is opened for others. However you should test how it behaves when the singleplayer host loses internet connection. To me it seems like (for now) choosing the lesser evil, ie possible singleplayer game ending due to loss of Internet or a delay in moving the currently running game to an online state.

    All the while check if NGO starts supporting host migration. Check the roadmap, if host migration isn‘t on the roadmap you may want to request it, otherwise vote for it.
    https://unity.com/roadmap/unity-platform/multiplayer-networking