3

Trying to create a ready check using PUN2 so that all players will load into the game scene at the same time, but I do not understand how to check another players custom property and keep a count of how many players are currently ready and if all are ready then start the game. I think I have a custom property set up for every player that should be but I am unsure if it working at all.

 public class HeroSelectController : MonoBehaviour
 {
     [HideInInspector]
     public string selectedHero;

     private PhotonView PV;
     private bool PlayerReady = false;
     private ExitGames.Client.Photon.Hashtable _playerCustomProperties = new ExitGames.Client.Photon.Hashtable();

     private void Update()
     {
         Debug.Log("Player Ready = " + _playerCustomProperties["PlayerReady"]);
     }

     private void HeroSelect()
     {
         PlayerReady = true;    
         selectedHero = "PlayerTest";
         PhotonNetwork.SetPlayerCustomProperties(_playerCustomProperties);
         _playerCustomProperties["PlayerReady"] = PlayerReady;
     }

     public void OnClickHeroButton()
     {
         HeroSelect();

         if (PhotonNetwork.IsMasterClient)
         {
             foreach (var photonPlayer in PhotonNetwork.PlayerList)
             {
                 photonPlayer.CustomProperties["PlayerReady"] = true;
                 PhotonNetwork.LoadLevel(3);
             }
         }

     }
 }

What is currently happening is that the master client can start the game regardless of everyone else's state. Feel like I might be overthinking all of this and there is a much similar solution as I would expect a function like this to be common place as I would expect something similar to be used in many online games so if I am going about completely the wrong way please point me a more suitable direction

1 Answers1

5

Don't know exactly how Photon works but I assume these properties are already synchronized and as far as I understand you simply want some kind of a check like e.g.

private bool AllPlayersReady
{
    get
    {
        foreach (var photonPlayer in PhotonNetwork.PlayerList)
        {
            if(photonPlayer.CustomProperties["PlayerReady"] == false) return false;
        }

        return true;
    }
}

Which you could probably also shorten using Linq like

using System.Linq;

...

private bool AllPlayersReady => PhotonNetwork.PlayerList.All(player => player.CustomProperties["PlayerReady"] == true);

And then use it like

public void OnClickHeroButton()
 {
     HeroSelect();

     if (!PhotonNetwork.IsMasterClient) return;

     if(!AllPlayersReady)
     {
         return;
     }


     PhotonNetwork.LoadLevel(3);
 }

This can still be enhanced since now the master has to press repeatedly until maybe everyone is ready. I would additionally use a Coroutine like

public void OnClickHeroButton()
{
     HeroSelect();

     if (!PhotonNetwork.IsMasterClient) return;

     StartCoroutine (WaitAllReady ());   
 }

 private IEnumerator WaitAllReady()
 {
     yield return new WaitUntil (() => AllPlayersReady);

     PhotonNetwork.LoadLevel(3);
 }

Thanks to Iggy:

Instead of a routine which checks every frame you can use OnPlayerPropertiesUpdate in order to check for the ready state

void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps)
{
    if (!PhotonNetwork.IsMasterClient) return;

    // you can even limit the check to make it 
    // only if "PlayerReady" is among the changed properties
    if(!changedProps.Contains("PlayerReady")) return;

    if(!AllPlayersReady) return;

    PhotonNetwork.LoadLevel(3);
}

Note: Typed on smartphone but I hope the idea gets clear

derHugo
  • 83,094
  • 9
  • 75
  • 115
  • @JoshuaDavidson please note that I made `AllPlayersReady` a property not a method ;) you might also be interested in the update adding a Coroutine for waiting until all are ready instead of having to click repeatedly – derHugo Dec 27 '19 at 14:28
  • Instead of checking custom properties every frame you can listen for one of the callbacks that PUN provides `OnRoomPropertiesUpdate` & `OnPlayerPropertiesUpdate`. Scroll down to [Custom Properties](https://doc.photonengine.com/en-us/pun/current/gameplay/synchronization-and-state). – Iggy Dec 27 '19 at 14:36
  • @derHugo is there something I am missing, I am tying to do exactly this but I am getting a error on the "private bool AllPlayersReady()" error it "Cannot implicitly convert type 'object' to 'bool'. An explicit conversion exists (are you missing a cast?)" – Joshylad Dec 27 '19 at 14:37
  • Apparently `CustomProperties` is a `Hashtable` .. you probably have to explicitly use either `player.CustomProperties["PlayerReady"] == true` again or cast it like `(bool)player.CustomProperties["PlayerReady"]` – derHugo Dec 27 '19 at 15:01
  • changedProps.Contains must be changed to changedProps.ContainsKey – Sajitha Rathnayake Jun 09 '20 at 19:50