Photon PUN2 Integration - newPlayer.CustomProperties not working as expected

Colin MacLeod

New member
I'm trying to change the character that is spawned based on a custom player property. The thing is, I can only get it to work on the Master client - the value for Player in my other clients always seems to be the same - the master value.

Not sure of the best way to describe this - there are quite a few steps, but here goes… (I have a copy of the whole test project which I could share with you via a Google Drive link.)

Steps to Reproduce:

I created a minimal test project to show the issue. Here's what I did:

- On Unity 2019.2.8f1, start a new project
- Import Photon "PUN 2 - FREE", Opsive "Third Person Controller" and Opsive "PUN Multiplayer Add-On for Opsive Character Controllers"
- Add these scenes to the build properties:
* Assets/Opsive/UltimateCharacterController/Add-Ons/Multiplayer/PhotonPUN/Demo/Menu.unity
* Assets/Opsive/UltimateCharacterController/Add-Ons/Multiplayer/PhotonPUN/Demo/DemoRoom.unity
- Open DemoRoom.unity. Bake lighting. Save.
- Get hold of the Kyle character and use the character manager to make a prefab.
- Set a fixed spawn location - I was having issues getting the spawn points to work
- Change the SingleCharacterSpawnManager class. Add a new custom character game object to look like this:

C#:
        [Tooltip("A reference to the character that PUN should spawn _if we want something custom_. This character must be setup using the PUN Multiplayer Manager.")]
        [SerializeField] protected GameObject m_CustomCharacter;

- Change the SingleCharacterSpawnManager class implementation for GetCharacterPrefab to this:

C#:
protected override GameObject GetCharacterPrefab(Player newPlayer)
{
    if (newPlayer.CustomProperties != null)
    {
        var character = newPlayer.CustomProperties["Character"];
        if ("Custom".Equals(character))
        {
            Debug.Log("CUSTOM CHARACTER SELECTED");
            return m_CustomCharacter;
        }
    }
    return m_Character;
}

- Add m_CustomCharacter to SingleCharacterSpawnManagerInspector, so the OnInspectorGUI is now:

C#:
public override void OnInspectorGUI()
{
    EditorGUI.BeginChangeCheck();
    EditorGUILayout.PropertyField(PropertyFromName("m_Character"));
    EditorGUILayout.PropertyField(PropertyFromName("m_CustomCharacter"));
    if (EditorGUI.EndChangeCheck()) {
        InspectorUtility.RecordUndoDirtyObject(target, "Change Value");
        serializedObject.ApplyModifiedProperties();
    }

    base.OnInspectorGUI();
}

- Back in DemoRoom.unity, set the Kyle prefab to the value of m_CustomCharacter
- Open scene Menu.unity
- Add a toggle. Add the following component to the toggle

C#:
using Photon.Pun;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.UI;
using Hashtable = ExitGames.Client.Photon.Hashtable;

[RequireComponent(typeof(Toggle))]
public class CharacterSetterToggle : MonoBehaviour
{
    [SerializeField] private string _defaultCharacter = "Default";
    [SerializeField] private string _customCharacter = "Custom";

    private Toggle _toggle;

    private void Awake()
    {
        PhotonNetwork.LocalPlayer.SetCustomProperties(new Hashtable
        {
            {"Character", _defaultCharacter}
        });

        _toggle = GetComponent<Toggle>();
        Assert.IsNotNull(_toggle, "I need a component of type " + nameof(Toggle));
        _toggle.isOn = false;
    
        _toggle.onValueChanged.AddListener(OnToggleChanged);
    }

    private void OnDestroy()
    {
        _toggle.onValueChanged.RemoveListener(OnToggleChanged);
    }

    private void OnToggleChanged(bool isOn)
    {
        var character = isOn ? _customCharacter : _defaultCharacter;
        PhotonNetwork.LocalPlayer.SetCustomProperties(new Hashtable
        {
            {"Character", character}
        });
    }
}

- Start up 2 clients and run the app
- Toggle the custom character on the master client but not the other

Expected Behavior:

On the master client, you control the custom character, and see the other player as the normal character.
On the other client, you control the normal character and see the other player as the custom character.

Actual Behavior:

On the master client, you control the custom character, and see the other player as the normal character.
1572121885743.png
But on the other client, both characters look the same - like the custom character
1572121869483.png


Could you please help me work this out?

Thanks!
Colin
 
Last edited:
These lines (197, 198) from SpawnManagerBase.OnEvent(EventData photonEvent) don't look right to me:

C#:
var player = PhotonNetwork.CurrentRoom.GetPlayer(photonEvent.Sender);
var character = Instantiate(GetCharacterPrefab(player), (Vector3)data[i * 3], (Quaternion)data[i * 3 + 1]);

Won't that always set player to the value of the master?
 
These lines (197, 198) from SpawnManagerBase.OnEvent(EventData photonEvent) don't look right to me:

C#:
var player = PhotonNetwork.CurrentRoom.GetPlayer(photonEvent.Sender);
var character = Instantiate(GetCharacterPrefab(player), (Vector3)data[i * 3], (Quaternion)data[i * 3 + 1]);

Won't that always set player to the value of the master?
Good catch. If you change the GetPlayer line to:

Code:
var player = PhotonNetwork.CurrentRoom.GetPlayer((int)data[i * 3 + 3]);

And then send the ActorNumber on line 101 it should point to the correct player:

Code:
player.transform.position, player.transform.rotation, photonView.ViewID, newPlayer.ActorNumber
 
I have set up a new project exactly like yours only using Unity 2019.2.12f1 and I am currently experiencing this issue!

Same Character for Different Player Thread

Good catch. If you change the GetPlayer line to:

Code:
var player = PhotonNetwork.CurrentRoom.GetPlayer((int)data[i * 3 + 3]);

And then send the ActorNumber on line 101 it should point to the correct player:

Code:
player.transform.position, player.transform.rotation, photonView.ViewID, newPlayer.ActorNumber

Once I update lines 101 and 197, build the project and run 2 instances I run into this problem: sc02.jpg
the master sees everything just fine; but the other sees nothing:
sc01.jpg
Plus produces an error: Index was outside the bounds of the array.
 
Top