How to create a matchmaking clock?

In RTSNetworkManager, I added this:

float lobbyTimer;
public float LobbyTimer => lobbyTimer;

public override void OnServerAddPlayer(NetworkConnectionToClient conn)
{
    // ...

    if (Players.Count == 1)
    {
        lobbyCreatedTime = Time.time;
    }

    // ...
}

public override void Update()
{
    base.Update();

    lobbyTimer = Time.time - lobbyCreatedTime;
}

However, when I access LobbyTimer from a lobby script I find it is not synced for different players in the lobby if either:

  • The second player starts their game (from the main menu) after the first player starts their server
  • The first player hosts and leaves the lobby, and then the second player hosts a lobby and the first player joins

How should I go about creating/fixing this matchmaking clock? Is RTSNetworkManager the right place for this?

1 Like

I’m, kinda tired but thought maybe I could squeeze in another post, here’s my best shot at helping you, based on your description, it seems that the issue is that the lobbyTimer variable is not being synchronized across all clients, leading to inconsistencies when multiple clients are involved in the matchmaking process.

One possible solution is to use a server authoritative clock that is synchronized across all clients using the Network Time Protocol (NTP). This would ensure that all clients have the same reference point for measuring the lobbyTimer.

To implement this, you could create a new script that inherits from NetworkBehaviour and uses the NTP to synchronize a server authoritative clock. Each client would periodically query the server for the current time and adjust their own clock accordingly. You could then use this synchronized clock to calculate the lobbyTimer.

As for where to place this logic, it would be best to keep it separate from the RTSNetworkManager, which is responsible for managing the overall network state of the game. Instead, create a new script that handles the matchmaking clock specifically and attach it to an appropriate game object in your scene.

Overall, the key is to ensure that all clients have a consistent reference point for measuring time. By using a server authoritative clock synchronized with NTP, you can achieve this and avoid the inconsistencies you are currently experiencing.

Hope this helps you out a bit

1 Like

Thanks for the detailed response!

I tried creating a new NetworkIdentity GameObject in my lobby scene (existing in editor mode) and put on the following NetworkBehaviour script:

using Mirror;
using UnityEngine;
using TMPro;

public class LobbyClock : NetworkBehaviour
{
    [SyncVar(hook = nameof(OnTimeChanged))]
    private double time;

    [SyncVar]
    private double startTime;

    [SerializeField]
    private TMP_Text timeText;

    void Start()
    {
        if (isServer)
        {
            startTime = NetworkTime.time;
            time = startTime;
        }
    }

    public override void OnStartClient()
    {
        gameObject.SetActive(true);
    }

    public override void OnStartServer()
    {
        gameObject.SetActive(true);
    }

    void Update()
    {
        if (!isServer)
        {
            double elapsedTime = NetworkTime.time - startTime;
            timeText.text = elapsedTime.ToString("F2");
        }
    }

    void OnTimeChanged(double oldTime, double newTime)
    {
        if (isServer)
        {
            time = NetworkTime.time - startTime;
        }
        else
        {
            timeText.text = newTime.ToString("F2");
        }
    }
}

However, I find that the GameObject sets itself to inactive when entering my lobby scene, even with my additional SetActive(true) parts (does it have to be spawned by NetworkServer?). Is this the correct approach, and what seems to be the issue?

1 Like

It looks like you’re on the right track with using a separate NetworkBehaviour to handle the synchronized clock.

Regarding the issue with the object becoming inactive, this might be because you are manually setting the object to active in the OnStartClient and OnStartServer methods. In Mirror, objects with NetworkIdentity components are automatically spawned and activated by the network system when they are needed.

To ensure that the object is properly spawned and activated, you can remove the gameObject.SetActive(true) calls from the OnStartClient and OnStartServer methods. Instead, you can make sure that the object is properly set up in the scene by enabling the NetworkIdentity component on it in the editor, and then starting the server and clients.

In addition, it looks like there may be an issue with the way you’re calculating the elapsed time on the client. Instead of using NetworkTime.time, which is the current time on the local machine, you should be using the synchronized time value that is being sent from the server. You can do this by updating the Update method to use the time sync var:

void Update()
{
if (!isServer)
{
double elapsedTime = time - startTime;
timeText.text = elapsedTime.ToString(“F2”);
}
}

With these changes, the clock object should be properly spawned and activated by the network system, and the elapsed time should be calculated correctly on the client.

Hope this helps!

That makes sense, I originally tried NetworkTime.time as Mirror says it should be synced between server and clients. I’ll try out and see how the time SyncVar works!

I added the gameObject.SetActive(true) calls because without them, the GameObject was being disabled when going into Play Mode.

Thanks again for the help!

1 Like

Glad I could help!

Do you think you might know why the NetworkIdentity GameObject is disabling and how to prevent that from happening?

1 Like

Hopefully I understand your question properly, the NetworkIdentity component in Unity is responsible for identifying networked objects and synchronizing their state across multiple clients. It’s possible that the NetworkIdentity GameObject is being disabled due to a variety of reasons, such as network connectivity issues or a code logic error.

To prevent the NetworkIdentity from being disabled, you can try the following steps:

1.Ensure that your game objects with NetworkIdentity components are active in the scene hierarchy.

2.Make sure that the NetworkIdentity component is enabled on the GameObject in question.

3.Check that you are not manually disabling the NetworkIdentity component or GameObject in your code.

4.Verify that your network connectivity is stable and there are no connectivity issues with your network topology.

5.If you’re using a custom script to control the NetworkIdentity component, ensure that it’s properly implemented and working as intended.

Hope this helps a bit!

Unfortunately, I haven’t had any luck with these steps. I made a prefab (on the scene with the NetworkManager and added it to the Registered Spawnable Prefabs) that is active in Editor Mode like so:
image

When going into Play Mode, the GameObject immediately disables:
image

(Checking the Server Only box doesn’t help either.)

The GameObject has no other scripts attached to it.

1 Like

Hm, this might be getting out of my skill range soon, but here’s some possibilities for your issue

Check if the GameObject has any dependencies that are not being properly initialized when it is spawned on the network. If a dependency is missing or not initialized correctly, it could cause the GameObject to disable.

Check if the NetworkManager is properly configured. Make sure that the transport layer is set up correctly, and that the server and client are properly connected.

Check if the NetworkIdentity component is set up correctly. Make sure that the “Local Player Authority” checkbox is unchecked if you don’t want the player to have control over this object.

Check if there are any errors or warnings in the Unity console related to the NetworkIdentity GameObject. If there are, it may provide a clue as to why the object is being disabled.

Try creating a new prefab from scratch and see if the same issue persists.

I hope this can at least narrow down your issue to further target the problem.

I checked the Mirror docs and this is what they say:

When building your game, Unity disables all Scene-based game objects with Network Identity components.

There is also this page about networked scene GameObjects:

When the Scene is loaded, all networked game objects in the Scene are disabled on both the client and the server. Then, when the Scene is fully loaded, the Network Manager automatically processes the Scene’s networked game objects, registering them all (and therefore causing them to be synchronized across clients), and enabling them, as if they were spawned at runtime. Networked game objects will not be enabled until a client has requested a Player object.

Do you know a good way of adding in the matchmaking clock then? The players are created during the lobby process, so I’m not sure why my GameObject is still being disabled.

1 Like

That’s a good point and thank you for bringing up the information from the Mirror documentation. It’s true that when building a game, Unity disables all Scene-based game objects with Network Identity components. However, during runtime, these objects should be automatically registered and enabled by the Network Manager when the Scene is fully loaded.

Regarding the matchmaking clock, if you are trying to add a countdown timer during the lobby process, you could add a script to the Network Manager or another GameObject in the Scene that manages the timer. When a player joins the lobby, you could have the script start the timer and update all connected clients with the current time remaining. Once the timer reaches zero, the script could then trigger the Network Manager to start the game by calling the appropriate function or setting a flag.

I’m pretty sure that if you are still experiencing issues with your GameObject being disabled, you could try the following:

1.Ensure that the NetworkIdentity component is properly configured and has a unique NetworkInstanceId assigned to it.

2.Check if any other components attached to the GameObject may be causing it to disable.

3.Check if the GameObject is being properly spawned on the network. You could try to manually spawn the object on both the client and server to see if it behaves differently.

4.If the GameObject is part of a scene, ensure that the scene is properly configured to work with networking. You may need to set up a custom NetworkManager or add additional components to the scene to ensure proper functionality.

Sorry that I’m am not immediately able to solve this, my 14 year old brain sometimes has difficulties comprehending things, hopefully what I just provided could help out a bit.

Hi there,
NetworkBehaviours need to be spawned by then Network Manager similar to how players and units are spawned etc. This is what sets up their connection and authority etc.
So make your clock a prefab, add it to the list of spawnable prefabs, then get the server to spawn it when it first loads or when it is needed.

1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms