[Photon] Finding PhotonNetwork.InstantiateSceneObject's object on clients

In my game, prefabs need to be spawned and some of its components must be modified; for instance, I need to instantiate an object and immediately child it to the player who issued the instantiate RPC to the MasterClient.

I’ve tried many solutions but I always get trouble with clients. In this case, GameObject.Find (chargeParticlesName + “(Clone)”); returns null (as the client). This works flawlessly when the MasterClient does it.

    void Start() {
        (...)
        chargeParticlesName = chargeParticlesPath.Split ('/').Last (); // chargeParticlesPath is the path to the prefab
    }
    [PunRPC] // When I call this RPC, PhotonTargets is AllBuffered.
    void Charge_Spawn(string path, Vector3 pos, Quaternion rot) {
        if (PhotonNetwork.isMasterClient)
            PhotonNetwork.InstantiateSceneObject (path, pos, rot, 0, null);
     
        chargeParticles = GameObject.Find (chargeParticlesName + "(Clone)");
        chargeParticles.transform.SetParent (transform);
        chargeParticles.transform.position = Vector3.zero;
        chargeParticles.transform.localPosition = Vector3.forward;
    }

Why does this happen? Has anyone done this before for their game?
Thanks in advance.

Why not try passing the viewID of the parent object in the instantiationdata of the child object, and then override OnPhotonInstantiate in the child object script and use PhotonView.Find(instantiationdata[index]) to retrieve the parent object which you can then use as the argument for the transform.SetParent() call.

You can also set the position and rotation at this point, and as it will run on all clients when the object is instantiated, they will all be synchronised.

2 Likes

Thank you so much. I never came across the data parameter in the docs, this solves everything.

Do you know how to change the name of the object from “somename(clone)” to some other name, I treida lot but it only changes the name on master client’s side and not on the other clients

You need to use an RPC to effect changes on the other clients. Send the new name as an argument in the RPC method.

I tried doing that but it says " RPC cant send objects", i have 9 objects per players to instantiate.

This is what i did but it didn’t work.

public void FirstInitializeBluePeices() {

for (int i = 0; i < GreenPos.Length; i++)
{
bluePieces = PhotonNetwork.Instantiate(playerPieceBlue.name, BluePos*, Quaternion.identity );*

bluePieces*.GetComponent().RPC(“changeBlueName”, RpcTarget.AllBuffered,i);*

}
}
[PunRPC]
public void changeBlueName(int i)
{
bluepieces*.name = “whatever name”; //bluepieces is a global array*
}

If you want to set the name when it’s instantiated, send the name in the instantiation data and you can retrieve it in OnPhotonInstantiate callback and set the game object name there.

Excerpt from the Photon PUN docs Pun 2 Instantiation | Photon Engine

Custom Instantiation Data
You can send some initial custom data when the instantiation call. Just make use of the last parameter in the PhotonNetwork.Instantiate* method.

This has two main advantages:

  • save traffic by avoiding extra messages: we don’t have to use a separate RPC or RaiseEvent call for synchronizing this kind of information
  • timing: the data exchanged is available on the time of the prefab instantiation which could be useful to do some initialization

The instantiation data is an object array (object[ ]) of anything Photon can serialize.

Example:

Instantiate with custom data:

object[] myCustomInitData = GetInitData();
PhotonNetwork.Instantiate("MyPrefabName", new Vector3(0, 0, 0), Quaternion.identity, 0, myCustomInitData);

Receive custom data:

public void OnPhotonInstantiate(PhotonMessageInfo info)
{
   object[] instantiationData = info.photonView.InstantiationData;
   // ...
}

What can Photon Serialise? Realtime Serialization in Photon | Photon Engine
You can also add custom types to be serialised by following the example given.

I had seen this too, but didn’t got any idea how can i use it to rename , because i am instantiating two times in two different loops.So which data will i get when i overload OnPhotonInstantiate() , Also i tried printing the contents of object[ ] instantiationData = info.photonView.InstantiationData; But for some reason the print statement also doesnt showup, can you please help me out

It doesn’t matter where you perform the instantiation, the callback will happen on the instantiated object when it gets created on each client, as long as you have registered the script as a callback target for IPunInstantiateMagicCallback.

You’ll need to post the script that you tried this in for anyone to be to help with why it isn’t working.

public class PlacePlayers : MonoBehaviourPun
{
// Start is called before the first frame update
public static string Winner;
public GameObject playerPieceBlue;
public GameObject playerPieceGreen;
public GameObject[ ] greenPieces = new GameObject[9];
public GameObject[ ] bluePieces = new GameObject[9];

void Start()
{
if (PhotonNetwork.IsMasterClient)
{
FirstInitializeBluePeices();
}

if (!PhotonNetwork.IsMasterClient)
{
FirstInitializeGreenPeices();
}
}

public void OnPhotonInstantiate(PhotonMessageInfo info)
{
object[ ] instantiationData = info.photonView.InstantiationData;
Debug.Log(instantiationData); //Trying to see whats coming in instantiation data

}
public void FirstInitializeBluePeices() {
for (int i = 0; i < GreenPos.Length; i++)
{
bluePieces = PhotonNetwork.Instantiate(playerPieceBlue.name, BluePos*, Quaternion.identity,0,bluePieces);*
}
}

public void FirstInitializeGreenPeices()
{
for (int i = 0; i < GreenPos.Length; i++)
{
greenPieces = PhotonNetwork.Instantiate(playerPieceGreen.name, GreenPos*, Quaternion.identity,0,greenPieces);*

}
}
}

For the OnPhotonInstantiate callback to work you need to implement the IPunInstantiateMagicCallback interface and register as a callback target.

I’ve amended your script accordingly, and you should now at least have the callback working.

Also you should learn how to use code tags properly if you continue to ask for advice concerning your scripts.

using Photon.Pun;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlacePlayers : MonoBehaviourPun, IPunInstantiateMagicCallback
{
    // Start is called before the first frame update
    public static string Winner;
    public GameObject playerPieceBlue;
    public GameObject playerPieceGreen;
    public GameObject[] greenPieces = new GameObject[9];
    public GameObject[] bluePieces = new GameObject[9];

    private void OnEnable()
    {
        PhotonNetwork.AddCallbackTarget(this);
    }

    private void OnDisable()
    {
        PhotonNetwork.RemoveCallbackTarget(this);
    }

    void Start()
    {
        if (PhotonNetwork.IsMasterClient)
        {
            FirstInitializeBluePeices();
        }

        if (!PhotonNetwork.IsMasterClient)
        {
            FirstInitializeGreenPeices();
        }
    }


    public void OnPhotonInstantiate(PhotonMessageInfo info)
    {
        object[] instantiationData = info.photonView.InstantiationData;
        Debug.Log(instantiationData); //Trying to see whats coming in instantiation data

    }
    public void FirstInitializeBluePeices()
    {
        for (int i = 0; i < GreenPos.Length; i++)
        {
            bluePieces = PhotonNetwork.Instantiate(playerPieceBlue.name, BluePos, Quaternion.identity, 0, bluePieces);
        }
    }


    public void FirstInitializeGreenPeices()
    {
        for (int i = 0; i < GreenPos.Length; i++)
        {
            greenPieces = PhotonNetwork.Instantiate(playerPieceGreen.name, GreenPos, Quaternion.identity, 0, greenPieces);

        }
    }
}