Other clients can't see Master Client and where to call CRCCheckEnabled?

Hi everyone,

I started giving PUN a whirl a few days ago and I ran into a weird problem I am not sure how to resolve.

My setup:

I have a PhotonManager script that is connected to a GUI where player can create and join rooms. Once room is filled it loads up the main level.

I am using OnPhotonPlayerConnected to check for players count equaling the players max count in the room. Once that is reached I call PhotonNetwork.LoadlLevel() from the master client. I have AutoSyncLoadLevel set to true for everyone in OnConnectedToMaster()

The first problem is that once the level is loaded, the master client's player isn't visible by any other player. However it spawns normally on the master client. I tried using some fix mentioned in another thread involving setting isMessageQueueRunning to false but it didn't help.

My second issue is that I am trying to implement some simple anti-cheat measures. So I am trying to enable CRCCheckEnabled in OnPlayerConnected() but on master client I get a message stating that it can't be set while player is connecting. I tried setting it to true after loading the scene (which is something done in OnPhotonConnected as mentioned above) but it produces the same error. Tried to do it right after instantiating the player (which happens after loading the scene) but same message appears. Where exactly do I set this on all clients?

Thanks in advance.

Comments

  • JohnTube
    JohnTube ✭✭✭✭✭
    Hi @Vallar,

    Thank you for choosing Photon!

    For the CRC question:

    Try enabling the CRC check before connecting (before the initial connection attempt to any Photon server) as the error message states.
  • Vallar
    Vallar
    edited June 2018
    JohnTube said:

    Hi @Vallar,

    Thank you for choosing Photon!

    For the CRC question:

    Try enabling the CRC check before connecting (before the initial connection attempt to any Photon server) as the error message states.

    I see. I don't know why I kept thinking it should be set AFTER connecting not BEFORE. Thanks for the reply.

    First question remains, hopefully someone can assist with that.
  • Bump, any idea how to resolve the problem on the first question (other clients can't see master client)?
  • JohnTube
    JohnTube ✭✭✭✭✭
    How and When are you instantiating objects from master and non master clients ?
    When are you changing isMessageQueueRunning ?
    Share some code so we could take a look.
  • Vallar
    Vallar
    edited June 2018
    JohnTube said:

    How and When are you instantiating objects from master and non master clients ?
    When are you changing isMessageQueueRunning ?
    Share some code so we could take a look.

    Here is what I have in terms of code. I have AutoSyncScene turned on.
    private void OnPhotonPlayerConnected()
        {
            if (PhotonNetwork.isMasterClient == false)
                return;
    
            if (PhotonNetwork.room.PlayerCount == PhotonNetwork.room.MaxPlayers)
            {
                PhotonNetwork.room.IsOpen = false;
                PhotonNetwork.LoadLevel("GAME");
            }
        }
    Once the above is called I have the instantiation here:
    private void Awake()
        {
            SceneManager.sceneLoaded += OnSceneLoaded;
        }
    
        private void OnSceneLoaded(Scene _scene, LoadSceneMode _mode)
        {
            if (_scene.name.Equals("GAME"))
            {
                GameObject playerObject = PhotonNetwork.Instantiate(player.name, player.transform.localPosition, Quaternion.identity, 0);
                GameObject camera = Instantiate(playerCamera, playerCamera.transform.localEulerAngles, Quaternion.identity);
                camera.transform.rotation = Quaternion.Euler(new Vector3(90, 0, 0));
                camera.GetComponent<CameraMovement>().target = playerObject.transform;
            }
        }
    When I used the isMessageQueueRunning I changed it above the check for MasterClient in OnPhotonPlayerConnected();
  • Bump, still facing this problem.
  • Hi @Vallar,

    this seems to be a problem with the scene loading. Does this happen every time?

    To see if certain messages get lost, you can try to raise an event directly before and directly after the Instantiation call on the MasterClient and see if those events are received on the other clients.

    You can also check the NetworkingPeer class, especially the OnEvent callback. There is a case (lines 2622) where Instantiation calls are handled. You can check here if Instantiation calls by the MasterClients are received on the local client(s) as well as when those messages are received (maybe before or during loading).
  • Hi @Vallar,

    this seems to be a problem with the scene loading. Does this happen every time?

    To see if certain messages get lost, you can try to raise an event directly before and directly after the Instantiation call on the MasterClient and see if those events are received on the other clients.

    You can also check the NetworkingPeer class, especially the OnEvent callback. There is a case (lines 2622) where Instantiation calls are handled. You can check here if Instantiation calls by the MasterClients are received on the local client(s) as well as when those messages are received (maybe before or during loading).

    Thanks for your reply, @Christian_Simon . Yes it happens every time to all clients.

    I don't really know how to do what you mentioned -- I have just been using PUN for about 3 days so not familiar with it to that extent.

  • Before testing, if the clients are receiving custom events, let's test, if the clients receive the Instantiation call at all. Therefore please take a look at what I have mentioned before:

    You can also check the NetworkingPeer class, especially the OnEvent callback. There is a case (lines 2622) where Instantiation calls are handled. You can check here if Instantiation calls by the MasterClients are received on the local client(s) as well as when those messages are received (maybe before or during loading).


    You can check, if this gets called by placing a Debug.Log call inside this case for example. Please note, that you let the non-MasterClient either run in the Unity Editor or in a development build. If the client runs in the Unity Editor, the logs are directly printed to the console. If the clients runs as a development build, you can find the log file somewhere in the AppData folder.

    Example set up: Standalone version (MasterClient) and Unity Editor version (non-MasterClient).
  • Before testing, if the clients are receiving custom events, let's test, if the clients receive the Instantiation call at all. Therefore please take a look at what I have mentioned before:

    You can also check the NetworkingPeer class, especially the OnEvent callback. There is a case (lines 2622) where Instantiation calls are handled. You can check here if Instantiation calls by the MasterClients are received on the local client(s) as well as when those messages are received (maybe before or during loading).


    You can check, if this gets called by placing a Debug.Log call inside this case for example. Please note, that you let the non-MasterClient either run in the Unity Editor or in a development build. If the client runs in the Unity Editor, the logs are directly printed to the console. If the clients runs as a development build, you can find the log file somewhere in the AppData folder.

    Example set up: Standalone version (MasterClient) and Unity Editor version (non-MasterClient).
    So I tried what you've mentioned added a Debug.Log() and ran the MaserClient on a build while the client is in the Editor. The Debug.Log() appeared in the console window along with a warning:

    Received OnSerialization for view ID 1001. We have no such PhotonView! Ignored this if you're leaving a room. State: Joined
    UnityEngine.Debug:LogWarning(Object)
    NetworkingPeer:OnSerializeRead(Object[], PhotonPlayer, Int32, Int16) (at Assets/Photon Unity Networking/Plugins/PhotonNetwork/NetworkingPeer.cs:4316)
    NetworkingPeer:OnEvent(EventData) (at Assets/Photon Unity Networking/Plugins/PhotonNetwork/NetworkingPeer.cs:2618)
    ExitGames.Client.Photon.PeerBase:DeserializeMessageAndCallback(Byte[])
    ExitGames.Client.Photon.EnetPeer:DispatchIncomingCommands()
    ExitGames.Client.Photon.PhotonPeer:DispatchIncomingCommands()
    PhotonHandler:Update() (at Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonHandler.cs:158)


    So I put a Debug.Log() on the player to see which has this ID, of course since I don't have the MasterClient's player I didn't receive its Debug.Log() and I only received the local one. The local one wasn't 1001. This leads me to believe that 1001 is the MasterClient and some how it isn't "mirrored" on clients and this getting this error.
  • Yes, in this case ViewId 1001 is the first object (not scene object) created by the MasterClient. Furthermore you can say, that this certain object is either not instantiated (Instantiation messages has been never received) or missing (removed on scene loading).

    Since this is not the log message I would have expected (the one above is one of PUN's messages), I would say, that your clients don't receive the Instantiation message from the MasterClient.

    To make sure, that this is not a problem somewhere else in code, I'm asking you to apply the following workaround, which will delay the Instantiation call. Therefore add a Coroutine in which you do the network Instantiation (basically everything inside the condition in the OnSceneLoaded function, like this:
    private IEnumerator InstantiateObjectDelayed()
    {
        yield return new WaitForSeconds(2.0f);
    
        GameObject playerObject = PhotonNetwork.Instantiate(player.name, player.transform.localPosition, Quaternion.identity, 0);
        GameObject camera = Instantiate(playerCamera, playerCamera.transform.localEulerAngles, Quaternion.identity);
        camera.transform.rotation = Quaternion.Euler(new Vector3(90, 0, 0));
        camera.GetComponent<CameraMovement>().target = playerObject.transform;
    }
    For this example I have set a delay of two seconds, so that each client should have finished loading the scene properly. Now inside the condition in the OnSceneLoaded function, you have to start the Coroutine by using StartCoroutine(InstantiateObjectDelayed());.

    If this works afterwards, there is indeed a problem with the scene loading. In this case you would have two different ways to handle the situation. The first way is to mark the player objects as DontDestroyOnLoad. This way the objects won't get destroyed on scene loading. However this might result in some unwanted behaviour later. The second way is to wait until everyone has finished loading the scene before instantiating player objects. This way, you most likely won't have any trouble with not-instantiated objects, but possibly have to wait for a certain amount of time until all clients have finished loading the scene.
  • Yes, in this case ViewId 1001 is the first object (not scene object) created by the MasterClient. Furthermore you can say, that this certain object is either not instantiated (Instantiation messages has been never received) or missing (removed on scene loading)...

    So I have went ahead and made the necessary changes to use the coroutine. It worked well, both objects where there on both ends (MasterClient and remote client). So yeah, seems you were right.

    Now the question is how to tell if all clients (including master) loaded the scene correctly? I tried adding a variable playersCount in the SceneLoading script I posted earlier and in place of the StartCoroutine() code you gave me I used this:

    playeresCount += 1;

    if (playersCount == PhotonNetwork.room.MaxPlayers)
    {
    //Instantiation code;
    }

    But nothing happened. Any suggestions?

    Also out of curiosity what are the problems in case I used DontDestroyOnLoad()?
  • Bump, still looking to resolve this.
  • Now the question is how to tell if all clients (including master) loaded the scene correctly?


    We had something similar a few days ago, so I'm pasting the suggestion I have given to another user here, too. If you want to, you can read the entire post here. This is the suggestion I made:

    After loading the level synchronized, a client can set a Custom Player Property to notify each other client, that he has finished loading the level. The local client can do this by using PhotonNetwork.player.SetCustomProperties(...). This changes gets synchronized on all clients in the room and void OnPhotonPlayerPropertiesChanged(object[] playerAndUpdatedProps) will be called on each client. The MasterClient can use this callback, to iterate through all clients' properties and check, if all clients are ready. If a certain client is not ready, you can skip the rest until the callback gets called again. You would have to do this until all clients are ready. If so, you can for example raise an event for all clients telling them that they can begin moving now. Therefore you would have to block movement input somehow and unblock it after receiving a certain game event.


    Please note, that this one is not about Instantiation but about movement. Objects in this case were already instantiated. However you can basically apply the same system to get rid of the problem with the missing objects.

    Also out of curiosity what are the problems in case I used DontDestroyOnLoad()?


    Can't give you any explicit answer about that. I'm even not sure right now, if this would be a problem at all until you want to load a third scene or if you care about removing the objects properly when leaving the room. So you can basically try this approach as well and let me know, if you find any suspicious behaviour.
  • Now the question is how to tell if all clients (including master) loaded the scene correctly?


    We had something similar a few days ago, so I'm pasting the suggestion I have given to another user here, too. If you want to, you can read the entire post...
    Thanks for the post, I read through it. I tried the DontDestroyOnLoad() and it produced an opposite result; the MasterClient can't see others but they can see it.

    So I decided to go with a simpler approach. I just added a loading canvas when each client joins and their player spawns. Then the canvas disappears. Worked quite well. The only issue I may have is figuring out the correct time for loading when the project gets slightly bigger (i.e. start spawning stuff other than the player).