How to update custom player properties

Options
First of all, this seems like it should be very simple but I have searched and searched and found nothing about it.

I have a multiplayer game and I'm implementing a scoreboard. I'm tracking each player's score (kills) in a player custom property. So each player has a property ["Score"] that holds that player's score.

If 2 players join a room and then start scoring, it works fine. If a player joins after other players in the room have already scored, it doesn't show the scores that those players have already got. I would think custom properties should be synced automatically when a player joins, but I guess not. If not, is there a way I can update the player properties when a player joins?

Thanks.

Comments

  • Tobias
    Options
    It does not work, if you set player.customProperties["score"] = value.
    It should work if you use player.SetCustomProperties(Hashtable propertiesToSet).

    If you just change the content of the customProperties Hashtable, we don't detect this currently but as it's a Hashtable, we also can't keep you from setting values.
    Maybe we can change this in the future but so far, it's only described in the doc.
  • MutantGopher
    Options
    I am doing it that way. Sorry I didn't put it quite right in the first post. Here is the code:

    [code2=csharp]// Set this player's custom properties
    ExitGames.Client.Photon.Hashtable props = new ExitGames.Client.Photon.Hashtable();
    props.Add("Team", team);
    props.Add("Score", 0);
    PhotonNetwork.player.SetCustomProperties(props);[/code2]

    And this is working, but not for players that join later, after people have already scored. So when someone else joins, they see that everyone has a score of zero, which is not accurate.
  • Tobias
    Options
    Usually, the server should send custom properties of players who are in the room already. I wonder what might be wrong.
    Can you let me know which PUN version you are using? If it's not the latest, can you please update?

    And also implement void OnPhotonPlayerPropertiesChanged(object[] playerAndUpdatedProps) and see if that gets called with the missing values.
    Maybe it's just an internal timing issue (means: PUN is calling your code before it read and applied the props).
  • MutantGopher
    Options
    I will update Photon first to make sure it's the most recent one...
  • MutantGopher
    Options
    Ok I'm using 1.25.3 of the free version on the Asset Store. I will try what you said...
  • MutantGopher
    Options
    Ok the OnPhotonPlayerPropertiesChanged(object[] playerAndUpdatedProps) method is being called when a player joins. But the custom props are still not right. How can I check for the correct player properties when a new player joins?
  • Tobias
    Options
    The props are still not right means they show old values or are the not there at all?
    We will test this tomorrow.
    Can you let me know if this is in Editor and in which version of Unity? We will test with 4.5, as 4.3 has some known issues with exports to iOS, etc.
  • MutantGopher
    Options
    This is Unity 4.4. It doesn't matter if I build it and open two instances, or open one instance and play in the editor.

    The custom player properties do work. But if a player joins after other players have already been playing (and scoring), then the new player's scoreboard just shows that everyone has zero. If people then score after that, it keeps track of that, but the newer player's scoreboard will say something totally different from everyone else's.

    Here is the code that gives players a score custom property and sets it to 0. This code is in the Start() function.
    [code2=csharp]// Set this player's custom properties
    ExitGames.Client.Photon.Hashtable props = new ExitGames.Client.Photon.Hashtable();
    props.Add("Team", team);
    props.Add("Score", 0);
    PhotonNetwork.player.SetCustomProperties(props);[/code2]

    Here is my GUI window which displays the players' names and their scores:
    void PlayerList(int windowID)
    [code2=csharp]void PlayerList(int windowID)
    {
    GUILayout.BeginVertical();
    GUILayout.FlexibleSpace();

    foreach (PhotonPlayer player in PhotonNetwork.playerList)
    {
    GUILayout.BeginHorizontal();
    GUILayout.Label(player.name);
    GUILayout.Label(player.customProperties["Score"].ToString());
    GUILayout.EndHorizontal();

    }

    GUILayout.EndVertical();

    GUI.DragWindow();
    }[/code2]
  • Tobias
    Options
    I only see PhotonNetwork.player.SetCustomProperties(props) for the initial 0 score.
    You do call PhotonNetwork.player.SetCustomProperties(props) when the score changes, right? It will not automatically do that.
  • MutantGopher
    Options
    Yes, I do, of course.
    Here is the code for that:
    [code2=csharp]// If someone else kills this player, give that someone a +1
    foreach (PhotonPlayer player in PhotonNetwork.playerList)
    {
    if (player.name == killer)
    {
    player.customProperties["Score"] = (int)player.customProperties["Score"] + 1;
    }
    }

    // If this player gets killed, give this player a -1
    gameObject.GetComponent<PhotonView>().owner.customProperties["Score"] = (int)gameObject.GetComponent<PhotonView>().owner.customProperties["Score"] - 1;[/code2]

    Now this code is in a function that is called from an RPC which is called on each player character. This might have something to do with it now that I think of it.
  • Tobias
    Options
    This will be part of your problem.
    One client only should set the properties. The RPC is called on all clients, so any of them might be last and if that last client sets the Score to 0, then it IS 0 for everyone.
    Maybe you use the Master Client to update the properties only.
  • MutantGopher
    Options
    Thanks. I will try this.
  • MutantGopher
    Options
    Actually no, when I only set the player props on the master client, it doesn't update on other clients at all. Like I said before, it's just not syncing the player props accross the network at all. I don't get it.
  • Tobias
    Options
    Again, I don't see where you are using PhotonNetwork.player.SetCustomProperties(props). I hope you do, because that's the only way you can set/update properties in a synchronized way.
    I do know that this works in our demos, so something else must be wrong in your case. So far, I didn't notice what it could be :(
  • MutantGopher
    Options
    I have
    [code2=csharp]PhotonNetwork.player.SetCustomProperties(props)[/code2]
    in the original code I gave, that's in my Start() function. The above code,
    [code2=csharp]player.customProperties["Score"] = (int)player.customProperties["Score"] + 1;[/code2]
    is where I add 1 to the score.

    So what you're telling me is that I need to store all the properties in a variable, edit the property that I want, and then set the player.customProperties to that whole variable? I can't just edit one of the custom properties directly?
  • Tobias
    Options
    You can set the properties one by one but you have to use our Hashtable class and SetCustomProperties(props).
    If Start() is the right place to increase the Score, is another question. Start's execution depends on when that particular GameObject and it's scripts are loaded and enabled. It could be happening before the properties got updated.
  • MutantGopher
    Options
    No, I'm not trying to increase the score in Start().
    Basically I want to know if this is incorrect syntax to add one to the score for this player:
    [code2=csharp]player.customProperties["Score"] = (int)player.customProperties["Score"] + 1;[/code2]
    This is working. I'm doing this in a function called when a player dies. It just doesn't load the correct scores when a new player joins. I don't know how to put it any other way.
  • yeah..actually..i need too do that how to change value of my key in photonnetwork.player.customproperties
    ExitGames.Client.Photon.Hashtable kode;
    void OnJoinedRoom()
    {
      kode.Add ("LOCK", 0);
      PhotonNetwork.player.SetCustomProperties (kode);
    }
    
    void OnGUI()
    {
      if(GUILayout.Button("LOCK CHARACTER"))
      {
        if(kode.ContainsKey("LOCK"))
        {
    	   kode.Clear();
    	   kode.Add("LOCK", 1);
    	   PhotonNetwork.player.SetCustomProperties (kode);
        }
      }
    
      foreach (PhotonPlayer player in PhotonNetwork.playerList)
      {
         GUILayout.Label("LOCKED " + player.customProperties&#91;"LOCK"&#93;.ToString());
      }
    }
    

    thats any wrong?
  • and my big problem is....
    how to count the values of "LOCK" 's key of all players in room?
    cos i need it to make it as required of masterclient to "start the battle"

    the logic code
    if(PhotonNetwork.isMasterClient)
    {
    	if(PhotonNetwork.room.maxPlayers == PhotonNetwork.room.playerCount && &#91;??LOCK.count??&#93; == PhotonNetwork.room.maxPlayers)
    	{
    		if(GUILayout.Button(" START THE BATTLE", GUILayout.MaxHeight(80)))
    		{
    			PhotonNetwork.LoadLevel("Map" + PhotonNetwork.room.customProperties&#91;"Map"&#93;.ToString());
    		}
    	}
    }
    
    once again
    how to count the values of "LOCK" 's key of all players in room?
    Helpppp......


    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    + before it..im create room like this :)
    if (GUILayout.Button("CREATE/START"))
    {
    	string&#91;&#93; map = new string&#91;&#93;{"BattleMap", "Battle"};
    	RoomOptions roomOptions = new RoomOptions() 
    	{
    		isVisible = true, 
    		isOpen = true,	
    		maxPlayers = maxUser,
    		customRoomProperties = new ExitGames.Client.Photon.Hashtable(),
    		customRoomPropertiesForLobby = new string&#91;2&#93;
    	};
    
    	roomOptions.customRoomProperties.Add("NameRoom", map&#91;mapSelect&#93; + roomOptions.customRoomProperties.GetHashCode());
    	roomOptions.customRoomProperties.Add("UserLock", 0);
    	roomOptions.customRoomProperties.Add("Map", mapSelect);
    	roomOptions.customRoomPropertiesForLobby&#91;0&#93; = map&#91;mapSelect&#93; + roomOptions.customRoomProperties.GetHashCode();
    	roomOptions.customRoomPropertiesForLobby&#91;1&#93; = mapSelect.ToString();
    	
            PhotonNetwork.CreateRoom(roomName, roomOptions, TypedLobby.Default);
    }
    

    i use : roomOptions.customRoomProperties.Add("UserLock", 0); to save LOCK count????
  • vadim
    Options
    Use PhotonPlayer.SetCustomProperties for setting player properties

    To count properties, iterate players list and check property of each player.
  • thanks for respons Vadim,
    the codes : :)
    ExitGames.Client.Photon.Hashtable kode;
    List&lt;PhotonPlayer&gt; pp = new List&lt;PhotonPlayer&gt; ();
    
    void Start ()
    {
    	kode = new ExitGames.Client.Photon.Hashtable();
    }
    
    void OnJoinedRoom()
    {
    	kode.Add ("LOCK", 0); //0 as not lock
    	PhotonNetwork.player.SetCustomProperties (kode);
    }
    
    void OnGUI()
    {
      //Lock Button
      if(GUILayout.Button("Lock Now"))
      {
        ExitGames.Client.Photon.Hashtable changer = new ExitGames.Client.Photon.Hashtable();
    	changer.Add("LOCK", 1);
    	kode.MergeStringKeys(changer);
    	PhotonNetwork.player.SetCustomProperties (kode);
      }
      
     //Unlock Button
      if(GUILayout.Button("unLock"))
      {
        ExitGames.Client.Photon.Hashtable changer = new ExitGames.Client.Photon.Hashtable();
    	changer.Add("LOCK", 0);
    	kode.MergeStringKeys(changer);
    	PhotonNetwork.player.SetCustomProperties (kode);
      }
    
      //count player of LOCKED
     if(PhotonNetwork.player.isMasterClient)
    	{
    		foreach(PhotonPlayer p in PhotonNetwork.playerList)
    		{
    			if((int)p.customProperties&#91;"LOCK"&#93; == 1) pp.Add (p);
    		}
    		GUILayout.Label ("LOCKED " + pp.Count);
    	}
    }
    
    the problem is
    while Hit the Lock Button, pp.add do looping ...
  • vadim
    Options
    I did not quite get what you mean but think OnGUI() is not best place for properties counting.
    Better user OnPhotonPlayerPropertiesChanged handler for that.
  • oh ... Vadim
    for last question about "update custom player properties",
    how to get value "custom player properties" by photonView of each player?

    im not found this in any search

    :):):)
  • aanimation wrote:
    oh ... Vadim
    for last question about "update custom player properties",
    how to get value "custom player properties" by photonView of each player?

    im not found this in any search

    :):):)

    :D:D:D:D [SOLVED]

    use photonview.owner.name; OR photonview..owner.customProperties["NAME"];
    just found on "ShowInfoOfPlayer.cs"
  • First of all, this seems like it should be very simple but I have searched and searched and found nothing about it.

    I have a multiplayer game and I'm implementing a scoreboard. I'm tracking each player's score (kills) in a player custom property. So each player has a property ["Score"] that holds that player's score.

    If 2 players join a room and then start scoring, it works fine. If a player joins after other players in the room have already scored, it doesn't show the scores that those players have already got. I would think custom properties should be synced automatically when a player joins, but I guess not. If not, is there a way I can update the player properties when a player joins?

    Thanks.


    Hey @MutantGopher , I was facing the same problem and have found out why you may have been facing those errors.

    I'll post 3 scripts that may be helpful to you.
    1)Bullet Script - Bullet Script - it sends the score to the player that sent the bullet
    2)RankManager - this code snippet (displayed here) is part of the rank manager script and it basically updates the score everytime someone hits the cube
    3)PlayerScore - probably the most important script in this case. It sets the score to customproperties
    I've given my reason on why you may not be getting the desired result in the end

    So my example game involves 2 players shooting at a cube .
    If the bullets hit the cube, their score is updated. Along with the score of the other player.
    All the player's scores can be seen on the screen and it updates everytime somebody hits the cube.

    ///////////////////////////////////////////////////////////////////////////////////////////////////////
    Bullet Script - it sends the score to the player that sent the bullet
    public class ScoreSender : MonoBehaviourPun
    {
    //this gameObject is set on the parent
    public GameObject spawnParent;

    private void OnCollisionEnter(Collision collision)
    {
    if (collision.gameObject.tag == "Dexter" && spawnParent != null)
    {
    spawnParent.SendMessage("SendScore", 1);
    }
    Destroy(gameObject);
    }
    }
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////

    **************************************************************************************
    RankManager - this code snippet is part of the rank manager script and it basically updates the score everytime someone hits the cube
    public override void OnPlayerPropertiesUpdate(Player targetPlayer, ExitGames.Client.Photon.Hashtable changedProps)
    {
    if (playerRankList == null)
    {
    return;
    }

    Debug.Log("OnPlayerPropertiesUpdate");
    Debug.Log(targetPlayer + " has a score of :" + targetPlayer.CustomProperties["Score"].ToString());

    GameObject playerObject = playerRankList[targetPlayer.ActorNumber];

    playerObject.GetComponent<Text>().text = targetPlayer.NickName + " : " + targetPlayer.CustomProperties["Score"].ToString();
    }
    ***************************************************************************************

    ====================================================================================

    PlayerScore - probably the most important script in this case. It sets the score to customproperties

    public class PlayerScore : MonoBehaviourPunCallbacks
    {
    public Text scoreText;
    private int score;

    private ExitGames.Client.Photon.Hashtable MyCustomProperties = new ExitGames.Client.Photon.Hashtable();

    private void Start()
    {
    if (!photonView.IsMine)
    {
    return;
    }

    SetCustomPropertiesForPlayer(0);
    }

    public void SendScore(int scoreReceived)
    {
    score += scoreReceived;
    scoreText.text = "Score: " +score.ToString();

    SetCustomPropertiesForPlayer(score);
    }

    private void SetCustomPropertiesForPlayer(int scoreUpdate)
    {
    MyCustomProperties["Score"] = scoreUpdate;
    PhotonNetwork.LocalPlayer.SetCustomProperties(MyCustomProperties);
    }
    }
    ==================================================================================

    Reason for not getting the desired result
    Reason - not using photonView.isMine when using SetCustomProperties(Property_To_Be_Sync)

    following the method below should work for you.
    If this still doesn't work I can send you my project.

    private void Start()
    {
    if (!photonView.IsMine)
    {
    return;
    }

    SetCustomPropertiesForPlayer(0);
    }