Why do we have two separate myUnits lists and not one SyncVar list?

In RTSPlayer, we are keeping a server and a client list for each player. Why can’t we just make one list using a SyncVar variable?

Other questions:

  • How do we know a script/GameObject will exist on both the server and the client? Does it have to do with Registered Spawnable Prefabs?
  • Why is unit.connectionToClient.connectionId != connectionToClient.connectionId used for the server and !hasAuthority for the client?

Hi there, good questions!

We don’t have a syncVar for the myUnits list as there is no need to pass that information to the server or other clients. The myUnits list is used exclusively by the local authority to keep track of which unit’s it has spawned.

For knowing where a gameObject will exist, this has to do without how it was added to the scene. If it was spawned by the server, this will send action will cause the gameObject to be instantiated on all the clients as well as the server. If the gameObject was just instantiated locally or it appears already in a scene, then we can only guarantee it exists locally. Typically Mirror requires that all clients have the same starting scene setup to prevent users from have different objects appear when a scene is loaded. Later in the course we will create a preview of a building we are placing. This is instantiated locally just for the user to see where their building will go. This obejct appears only on the client it is created by and is not spawned by the server.

By default, the server has authority over all clients. So the check of !hasAuthority will always be false for a server owned object. In this case we need to check the connectionId instead to see if the server object belongs to local client or not. For other clients, only the local client has authority by default, so we can check if it hasAuthority to see if it’s the local client or a another client.

1 Like

Thank you for the detailed response!

In RTSPlayer, I do see that the server keeps an updated myUnits list (see below). Since there is a similar myUnits.Add(unit) call on the client for the player owning the unit, why are two lists being maintained for each unit?

public override void OnStartServer()
{
    Unit.ServerOnUnitSpawned += ServerHandleUnitSpawned;
    Unit.ServerOnUnitDespawned += ServerHandleUnitDespawened;
}

private void ServerHandleUnitSpawned(Unit unit)
{
    if (unit.connectionToClient.connectionId != connectionToClient.connectionId) { return; }

    myUnits.Add(unit);
}

The server version is just the local version on the server. So there isn’t 2 versions per say. There is one version for each instance of the game. If you have the host (server+client) and two other players (clients) let’s say, then you have one version on the server, and one version on each of the clients. So 3 players, 3 unit lists. That way each player can see get a reference to their units. The server is one of the 3 players in this case since since the host is a client and a server.

I just wrote some print statements and found that on the host only ServerHandleUnitSpawned was called when spawning units and not AuthorityHandleUnitSpawned. Why is the server method called but not the client one (since the host is both a server and client)? In addition, myUnits.Add(unit) runs in ServerHandleUnitSpawned regardless of which player has spawned the unit.

OnStartAuthority is a Client callback, you can see this is the documentation where it is listed under Client only:

That’s just how Mirror has it set up.

For ServerHandleUnitSpawned we have this check:
if (unit.connectionToClient.connectionId != connectionToClient.connectionId) { return; }
That should limit it to just the server adding the unit, si that not working?

I have found that in either case, Unit.OnStartServer is called, ServerHandleUnitSpawned is called by both players, and then the player who owns the unit (because of the check) has it added to their list with myUnits.Add(unit) within ServerHandleUnitSpawned. Does this mean both players have a server version of myUnits being updated? If so, why is AuthorityHandleUnitSpawned needed and only called on the client that is not the host?

I think the structure is like this:
Clients: have their units added to their unit list locally, this lets them select units and do other local unit tasks etc.
Server: Each player object on the server stores it’s own units. This allows the server to maintain a list of each player’s units in order to do networked processes with the units, like attacking and moving.

Privacy & Terms