How to select a specific network player - photon unity networking

Options
Hi guys. This is my first post at photonengine. Please excuse if i have posted this in the wrong section.
I have been working on unity for a few months now and have a basic understanding of the environment. Currently i am working on a multiplayer game and for that i am using Photon Unity Networking utility ( PUN intended :P ). This would be my first multiplayer game.
I have a room and a corresponding scene where all the players join and can roam around freely. What i want to do is to be able to touch/click on a player and start a battle with just that player ( I have the code for selecting objects using raycast and colliders but what that does is give me the object that i created locally using photon.instantiate to mimic the network players. )
The way i have decided on implementing this is to take myself and the target player to a different room ( battle room ) and load a new scene ( battle scene ) while the other players are still in the free roaming room / scene.

QUESTIONS:
(1) How can i select a specific network player and communicate with just that player to tell them that a match is about to start between that player and myself and make them join a different room with me?
(2) Does it make a difference if i load the battle scene before or after i join the battle room?
(3) How can i make the target player load the new scene and check over the network if their device has finished loading the new scene?


I AM a Photon illiterate ( maybe even a Unity illiterate ) so please excuse if i annoy you.

I shall appreciate all answers.

EDIT: Here is the code i am using:
(Selecting opponent through touch )
            if (Input.touchCount >= 1)
            {
                Touch touch = Input.GetTouch(0);
                if (touch.phase == TouchPhase.Began)
                {
                    touchStartPos = touch.position;
                }
                if (touch.phase == TouchPhase.Ended)
                {
                    if (touch.position == touchStartPos)
                    {
                        Ray cursorRay = Camera.main.ScreenPointToRay(touch.position);
                        RaycastHit hit;
                        if (Physics.Raycast(cursorRay, out hit, 1000.0f))
                        {
                            if (hit.transform.gameObject.tag == "opponent")
                            {
                                selectedOpponent = hit.transform.gameObject;
                                myObj = GameObject.FindGameObjectWithTag("MyObj");
                                string roomName = "" + myObj.gameObject.transform.name + selectedOpponent.gameObject.transform.name + (int) Random.Range(1,100) ;
                                myObj.GetComponent<PhotonView>().RPC("StartFight", PhotonTargets.All, myObj.GetComponent<PhotonView>().viewID.ToString(), selectedOpponent.GetComponent<PhotonView>().viewID.ToString(), roomName);
                            }              
                        }
                    }
                }
            }
(StartFight RPC)

    [PunRPC]
    void StartFight( string pID , string oID , string roomName )  //pID = local player's viewID, oID = target player's viewID
    {
        foreach ( PhotonPlayer player in PhotonNetwork.playerList )
        {            
            if (player.customProperties.ContainsValue(pID) )
            {
               PhotonNetwork.LeaveRoom();
                PlayerPrefs.SetString("roomName", roomName);
                StartCoroutine(newRoom(roomName));
            }
            else if ( player.customProperties.ContainsValue(oID) )
            {
                PhotonNetwork.LeaveRoom();
                PlayerPrefs.SetString("roomName", roomName);
                StartCoroutine(newRoom(roomName));
            }
        }
    }
The issue here is that even though i am checking player's ID and only executing PhotonNetwork.LeaveRoom() for the player's whose ID is matched, it is making all the players leave the room.
(newRoom CoRoutine)

IEnumerator newRoom ( string roomName )
    {
        PhotonNetwork.LoadLevel("Teset_Scene4");
        yield return null;
    }
This function is called when the new scene is loaded, here is where i attempt to join a new room

    void JoinFightRoom ( )
    {        
        if (!(PhotonNetwork.connected))
        {
            PhotonNetwork.ConnectUsingSettings(Constants.VERSION);    // Constants.VERSION = "v0.0.1"
        }
        else
        {
            string roomName = PlayerPrefs.GetString("roomName");
            RoomOptions roomOptions = new RoomOptions() { isVisible = false, maxPlayers = 2 };
            PhotonNetwork.JoinOrCreateRoom(roomName, roomOptions, TypedLobby.Default);
        }        
    }
 

The issue here is that it gives me the following error:
JoinOrCreateRoom failed. Client is not on Master Server or not yet ready to call operations. Wait for callback: OnJoinedLobby or OnConnectedToMaster.

Best Answer

  • jeanfabre
    jeanfabre mod
    Answer ✓
    Options
    Hi,

    Only the MasterClient should be loading level using PhotonNetwork.LoadLevel, this is the first issue that must be resolve.

    Also, as the error mention you need to listen to OnJoinedLobby or OnConnectedToMaster callbacks in order to take further actions to join rooms for example. So only make a call to joinOrCreateRoom when you are at least connected to master if you don't join lobby automatically or when you joined lobby.

    Bye,

    Jean

Answers

  • jeanfabre
    Options
    Hi,

    Indeed your first task is to join or create a room. Do you have auto join lobby set to true?

    Bye,

    Jean
  • garrodtheif
    Options
    Hi @jeanfabre,

    Thank you for your response.

    I have set auto join lobby to false , but i use the following code to join a lobby:
    if (SceneManager.GetActiveScene().name.Equals(Constants.menuSceneName))
            {
                PhotonNetwork.autoJoinLobby = false;
                PhotonNetwork.automaticallySyncScene = true;
                if (!(PhotonNetwork.connected))
                {
                    PhotonNetwork.ConnectUsingSettings(Constants.VERSION);
                }
            }
    Now, in the last few days, i have made some progress and have been able to select specific players and load a new scene for just myself and the target player and make the two leave the lobby room and join the battle room. But now i am facing another problem ( i encountered the same error previously as well ). It takes both the players to the new scene, attempts to join a new room, gives an error and jumps back to the lobby scene and lobby room. The error is:
    JoinOrCreateRoom failed. Client is not on Master Server or not yet ready to call operations. Wait for callback: OnJoinedLobby or OnConnectedToMaster.
    First as players are instantiated i set the GameObject names as follows:
    PhotonView pView = GetComponent<PhotonView>();
    photonView.transform.name = "" + pView.ownerId;
    Here is my code where i touch to select opponent and call RPC for the specific players:
    if (Input.touchCount >= 1)
                {
                    Touch touch = Input.GetTouch(0);
                    if (touch.phase == TouchPhase.Began)
                    {
                        touchStartPos = touch.position;
                    }
                    if (touch.phase == TouchPhase.Ended)
                    {
                        if (touch.position == touchStartPos)
                        {
                            Ray cursorRay = Camera.main.ScreenPointToRay(touch.position);
                            RaycastHit hit;
                            if (Physics.Raycast(cursorRay, out hit, 1000.0f))
                            {
                                if (hit.transform.gameObject.tag == "opponent")
                                {
                                    selectedOpponent = hit.transform.gameObject;
                                    myObject = GameObject.FindGameObjectWithTag("MyObject");
                                    string roomName = "" + myObject.gameObject.transform.name + selectedOpponent.gameObject.transform.name + (int) Random.Range(1,100) ;
                                    myObject.GetComponent<PhotonView>().RPC("StartFight", PhotonPlayer.Find(int.Parse(selectedOpponent.transform.name)), myObject.GetComponent<PhotonView>().ownerId.ToString(), selectedOpponent.GetComponent<PhotonView>().ownerId.ToString(), roomName);
                                    myObject.GetComponent<PhotonView>().RPC("StartFight", PhotonPlayer.Find(int.Parse(myObject.transform.name)), myObject.GetComponent<PhotonView>().ownerId.ToString(), selectedOpponent.GetComponent<PhotonView>().ownerId.ToString(), roomName);
    
                                }
                            }
                        }
                    }
                }
    Here is my RPC:
    [PunRPC]
        void StartFight(string pID, string oID, string roomName)//pID = local player's viewID, oID = target player's viewID
        {        
            PhotonNetwork.LeaveRoom();
            PlayerPrefs.SetString("roomName", roomName);
            PhotonNetwork.LoadLevel(Constants.fightSceneName);
        }
    Finally, the following script executes network commands according to the scene that has been loaded:
    using UnityEngine;
    using UnityEngine.UI;
    using UnityEngine.SceneManagement;
    using System.Collections;
    
    public class NetworkManager : MonoBehaviour
    {
        public Transform spawnPoint;
        public bool testingOnly;
        private bool fightRoomCheck = false ;
    
        void Start()
        {
            if (SceneManager.GetActiveScene().name.Equals(Constants.menuSceneName))
            {
                PhotonNetwork.autoJoinLobby = false;
                PhotonNetwork.automaticallySyncScene = true;                    //TESTING
                if (!(PhotonNetwork.connected))
                {
                    PhotonNetwork.ConnectUsingSettings(Constants.VERSION);
                }
            }
    
            else if (SceneManager.GetActiveScene().name.Equals(Constants.lobbySceneName))
            {
                RoomOptions roomOptions = new RoomOptions() { isVisible = false, maxPlayers = 16 };
                PhotonNetwork.JoinOrCreateRoom(Constants.lobbyName, roomOptions, TypedLobby.Default);
            }
    
            else if (SceneManager.GetActiveScene().name.Equals(Constants.fightSceneName))
            {
                fightRoomCheck = true;
            }
        }
    
        void Update()
        {
            if (SceneManager.GetActiveScene().name.Equals(Constants.fightSceneName))
            {
                if (fightRoomCheck)
                {
                    if (PhotonNetwork.connectionStateDetailed.ToString().Equals("ConnectedToMaster"))
                    {
                        string roomName = PlayerPrefs.GetString("roomName");
                        RoomOptions roomOptions = new RoomOptions() { isVisible = false, maxPlayers = 2 };
                        PhotonNetwork.JoinOrCreateRoom(Constants.lobbyName, roomOptions, TypedLobby.Default);
                        fightRoomCheck = false;
                    }
                }
            }
        }
    
        void OnJoinedRoom()
        {        
    		if (myAttributesPlayer.player_my_Texture.name == "red")
    		{
    			GameObject temp = PhotonNetwork.Instantiate(Constants.myPrefabs + "/my04", spawnPoint.position, spawnPoint.rotation, 0);
    		}
    		else if (myAttributesPlayer.player_my_Texture.name == "blue")
    		{
    			GameObject temp = PhotonNetwork.Instantiate(Constants.myPrefabs + "/my01", spawnPoint.position, spawnPoint.rotation, 0);
    		}
    		else if (myAttributesPlayer.player_my_Texture.name == "green")
    		{
    			GameObject temp = PhotonNetwork.Instantiate(Constants.myPrefabs + "/my02", spawnPoint.position, spawnPoint.rotation, 0);
    		}
    		else if (myAttributesPlayer.player_my_Texture.name == "yellow")
    		{
    			GameObject temp = PhotonNetwork.Instantiate(Constants.myPrefabs + "/my03", spawnPoint.position, spawnPoint.rotation, 0);
    		}
        }
    }
    
    I don't understand why it would take me to the next scene, give that error and take me back to the lobby scene.
  • jeanfabre
    jeanfabre mod
    Answer ✓
    Options
    Hi,

    Only the MasterClient should be loading level using PhotonNetwork.LoadLevel, this is the first issue that must be resolve.

    Also, as the error mention you need to listen to OnJoinedLobby or OnConnectedToMaster callbacks in order to take further actions to join rooms for example. So only make a call to joinOrCreateRoom when you are at least connected to master if you don't join lobby automatically or when you joined lobby.

    Bye,

    Jean
  • garrodtheif
    Options
    Hi @jeanfabre

    Great advice, i fixed the issues that you pointed out and it worked. I set PhotonNetwork.autoJoinLobby = true; and used OnJoinedLobby and OnJoinedRoom

    Thanks a lot for your help.

    Asim