How to update custom player properties

The whole answer can be found below.

Please note: The Photon forum is closed permanently. After many dedicated years of service we have made the decision to retire our forum and switch to read-only: we've saved the best to last! And we offer you support through these channels:

Try Our
Documentation

Please check if you can find an answer in our extensive documentation on PUN.

Join Us
on Discord

Meet and talk to our staff and the entire Photon-Community via Discord.

Read More on
Stack Overflow

Find more information on Stack Overflow (for Circle members only).

Write Us
an E-Mail

Feel free to send your question directly to our developers.

How to update custom player properties

MutantGopher
2014-06-11 05:10:14

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
2014-06-11 10:19:40

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
2014-06-11 15:31:07

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
2014-06-11 15:58:03

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
2014-06-11 16:00:33

I will update Photon first to make sure it's the most recent one...

MutantGopher
2014-06-11 16:06:13

Ok I'm using 1.25.3 of the free version on the Asset Store. I will try what you said...

MutantGopher
2014-06-11 16:15:51

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
2014-06-12 15:23:23

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
2014-06-12 16:26:08

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
2014-06-16 11:37:47

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
2014-06-16 16:04:00

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
2014-06-17 10:41:10

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
2014-06-17 17:11:40

Thanks. I will try this.

MutantGopher
2014-06-17 18:30:08

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
2014-06-18 09:00:03

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
2014-06-18 14:48:52

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
2014-06-18 15:37:19

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
2014-06-18 15:42:19

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.

aanimation
2015-02-23 05:37:06

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["LOCK"].ToString());
  }
}

thats any wrong?

aanimation
2015-02-23 08:40:50

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 && [??LOCK.count??] == PhotonNetwork.room.maxPlayers)
	{
		if(GUILayout.Button(" START THE BATTLE", GUILayout.MaxHeight(80)))
		{
			PhotonNetwork.LoadLevel("Map" + PhotonNetwork.room.customProperties["Map"].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[] map = new string[]{"BattleMap", "Battle"}; RoomOptions roomOptions = new RoomOptions() { isVisible = true, isOpen = true, maxPlayers = maxUser, customRoomProperties = new ExitGames.Client.Photon.Hashtable(), customRoomPropertiesForLobby = new string[2] };

      roomOptions.customRoomProperties.Add("NameRoom", map[mapSelect] + roomOptions.customRoomProperties.GetHashCode());
      roomOptions.customRoomProperties.Add("UserLock", 0);
      roomOptions.customRoomProperties.Add("Map", mapSelect);
      roomOptions.customRoomPropertiesForLobby[0] = map[mapSelect] + roomOptions.customRoomProperties.GetHashCode();
      roomOptions.customRoomPropertiesForLobby[1] = mapSelect.ToString();
    
          PhotonNetwork.CreateRoom(roomName, roomOptions, TypedLobby.Default);
    

    }

i use : roomOptions.customRoomProperties.Add("UserLock", 0); to save LOCK count????

vadim
2015-02-23 14:01:49

Use PhotonPlayer.SetCustomProperties for setting player properties

To count properties, iterate players list and check property of each player.

aanimation
2015-02-24 03:25:41

thanks for respons Vadim, the codes : :)

ExitGames.Client.Photon.Hashtable kode;
List<PhotonPlayer> pp = new List<PhotonPlayer> ();

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["LOCK"] == 1) pp.Add (p);
		}
		GUILayout.Label ("LOCKED " + pp.Count);
	}
}

the problem is while Hit the Lock Button, pp.add do looping ...

vadim
2015-02-24 14:50:54

I did not quite get what you mean but think OnGUI() is not best place for properties counting. Better user OnPhotonPlayerPropertiesChanged handler for that.

aanimation
2015-02-26 02:55:38

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
2015-02-26 06:17:41

@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"

roycefernandes3
2020-02-28 11:17:16

@MutantGopher;d-4947 wrote:

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);  
}
Back to top