Unity Mirror How to find player object and update SyncVar

Hello, Unity Community. :slight_smile:
I want to make an online event with a help of Mirror, where players register for an event, and plays there own game till event finishes, when event finishes I need to update SyncVar of all players who register for an event. SyncVar mode Owner only.

At the moment when I register for event I save netID. Is there a way to find specific player object and update SynVar if I know netID?

Or should I save something else if I want to access specific player Object at any time from server?

One option is to have the server keep a list of all players in an event, and when the event ends send a TargetRpc to each player with the values you want to update.

If this is really a single player game, then staying connected to a mirror based server the whole time doesn’t even sound necessary. You could have clients connect, and register for the event. When registering the client provides some information like player’s name, and server generates a kind of token for the client. Like just a random long, and provides that to the client. Then the client disconnects and plays the single player game.

At the end of each client’s game, it reconnects to the server, provides both the username and token, along with the game’s results.

You could also use deviceUniqueIdentifier for this, where the client provides theirs when registering and when providing results to identify the client.
Unity - Scripting API: SystemInfo.deviceUniqueIdentifier (unity3d.com)

Thanks for answers :slight_smile:
@Joe-Censored in the future it will be more then just registration.

@cerestorm So there is no proper way to identify players GameObject by having only netId?

I am thinking on a server I will add a list of each register players, but instead of netid I will save

[Command]
void CmdSaveRegisteredPlayerEventData()
{
     NetworkIdentity networkIdentity = NetworkClient.connection.identity;
     PlayerManager = networkIdentity.GetComponent<player>();
     eventData(PlayerManager);
}

If I am right by doing so I will be able to access any player game object at any time.
In my eyes Mirror should have some think like this already build in. But I can’t find it in documentation.
Didn’t have time to test it yet, don’t know if it will work :slight_smile:

I’m not sure on getting gameobjects by their netId as I’ve not looked into it. If you do want to use a pre-existing identifier the player’s connectionId is another option. You can get this on the server with player.connectionToClient.connectionId.

Ignoring an id look up, in its simplest form you could make a call like this from the player:

[Command]
public void CmdRegisterForEvent(EventType eventType)
{
    EventManager.Instance().RegisterPlayerForEvent(eventType, this);
}

What do You mean “I don’t want to use pre-existing identifier”?

What identifier are You talking about?

I will try Your suggestion thanks :slight_smile:

You might want to track a player outside of the network values, if they get disconnected and reconnect for example. Perhaps something to think about further down the line. :slight_smile:

AA now I get it. In my idea You quit the game no event for You. As I planning, it there wont be even a scene change. That’s why I need to notify player in real time.

I am not getting SyncVar Hook triggered and SyncVar Updated, don’t know if I am doing Right.

Each player when he join games:

public override void OnStartClient()
    {
        if (!isLocalPlayer) { return; }
        uint id = NetworkClient.localPlayer.netId;
        NetworkIdentity networkIdentity = NetworkClient.connection.identity;
        CmdplayerLogin(id, this);
    }

    [Command]
    void CmdplayerLogin(uint id, playerOBJ pp)
    {
        if (isServer)
        {
            player p = new player
            {
                playerOBJ    = pp,
                playerID     = id,
                nickName     = "QQ" + id.ToString(),
                coinsTotal   = 200000,
                tableID      = 0,
                coinsAtTable = 0
            };
            player = p;
            serverStart.ServerPlayers.Add(p);
        }
    }
-public class player {
    public playerOBJ playerOBJ;
    public bool eventRegistration;
    public bool eventStart;
    public uint playerID;
    public string nickName;
    public int tableID;
    public int tableChair;
    public int joinedListIndex;
    public float coinsTotal;
    public float coinsAtTable;
}

playerOBJ it’s a script that is added to Player prefab and it contains all the syncvars…

now lets just say I need 5 players to register for an event. Registration starts like so:

[Command]
void CmdRegisterPlayerToEvent() {
     if (serverStart.ServerPlayers.Count() < 5) 
     {
           addPlayerForEvent();
     } 

     if (serverStart.ServerPlayers.Count() == 5) 
     {
           for (int i = 0; i < serverStart.ServerPlayers.Count(); i++) 
           {
                  if (serverStart.ServerPlayers[i].playerOBJ.player.eventRegistration) 
                  {
                          serverStart.ServerPlayers[i].playerOBJ.player.eventStart = true;
                  }
           }
     }
}

After that there is a hook that should be triggered when I update serverStart.ServerPlayers*.playerOBJ.player SyncVar, but it’s not triggered.*
csharp* *[SyncVar(hook = nameof(playerDataChanged))] public player player = new player();* *
csharp* *private void playerDataChanged(player oldP, player newP) { Debug.Log("Triggered"); }* *
Any idea what I am doing wrong?

You don’t need to pass the player to CmdplayerLogin (actually it might not work as intended), instead use ‘this’ within the method, as that code is running on the server’s copy of the player. I don’t know if that’s the issue but it’s a place to start.

even if I do

 player p = new player
{
      playerOBJ    = this,
      playerID     = id,
      nickName     = "QQ" + id.ToString(),
      coinsTotal   = 200000,
      tableID      = 0,
      coinsAtTable = 0
};

playerOBJ gets updated only on host but not on clients.

Maybe I am not getting the right result because I create a Copy of playerOBJ not a reference to original? It should be so simple task and I stuck here for two days :smile:

Does the hook get called? You’ll likely want to have SyncVar on all the fields in the player class that you want to update on the client. To be honest I haven’t used syncvars so much as for what I’m doing it was more convenient to create my own message services.

I was wondering though why you have a separate player class and not just have those fields on playerOBJ?

No the hook did get triggered.
I can see it only on update function:

private void Update()
    {
        if (!isLocalPlayer) { return; }
        if (player.eventStart) {
             Debug.Log("True");
        }
      
    }

I have SyncVar player on playerOBJ, where I store data about player.
And I have a List joinedPlayers on server only, where I store everything about all players on a server. That helps me track everything.

In case this is in reference to this:

I don’t think you can use object references to tie objects together between client and server, so you may well be ending up with a new playerOBJ on the client.

So how to notify register player that event started from server? Any other way not a SyncVar.
To get all players I need for event can take a wile.

You can use syncvars, but I think you’re adding an extra layer of complexity using the player class rather than have those fields on playerOBJ.

Another option is to use ClientRpc or TargetRpc to let the client know the event has started.

I don’t understand what do You mean: “adding an extra layer of complexity using the player class rather than have those fields on playerOBJ”. I am not that good with programing just learning :slight_smile:

ClientRPC will send message to all players on a server, that’s the worst case scenarios for me.

Target RPC wont be same as SyncVar? Can I identify players connection somehow?

I mean you can just use playerOBJ and do away with the ‘player’ class, it looks to contain values integral to the player and should be on the playerOBJ.

A little advice on class names, it’s best to follow convention and start class names with capitals. If you’re using a decent IDE like Visual Studio or Visual Code they should be giving hints as guidance. I’d just go with Player for the player’s prefab/script, playerOBJ is misleading as it’s a class not an object.

If you’re learning programming + Unity + multiplayer that’s a real steep learning curve, I would suggest not worrying about multiplayer for now as you might find it overwhelming trying to learn it all at once.

Well most of my programing was with PHP… php class that stores variables, arrays etc… we call Objects.
https://www.tutorialspoint.com/php-objects
playerOBj class stores all the information about player and the game that surrounds him. For me is natural to call it obj :slight_smile:
player class is just a helper class that helps to construct SyncVar player for playerOBj and serverOBj there is a list of players :slight_smile: there is no mono/network behavior

Go with what you’re comfortable with, but it’s best to follow conventions. If nothing else it makes the code more readable. It will also be beneficial to use descriptive naming to make the code self-commenting. At a glance I can’t see the difference in responsibility between the player and playerOBJ classes.

I think the player class is more a hindrance than a help but if you’re going to stick with it one thing I wanted to mention was that the playerOBJ field is only relevant on the server so I would avoid using it on the client.