Add component to instantiated gameboject

The whole answer can be found below.

Please note: The Photon forum is closed permanently. After many dedicated years of service we have made the decision to retire our forum and switch to read-only: we've saved the best to last! And we offer you support through these channels:

Try Our
Documentation

Please check if you can find an answer in our extensive documentation on PUN.

Join Us
on Discord

Meet and talk to our staff and the entire Photon-Community via Discord.

Read More on
Stack Overflow

Find more information on Stack Overflow (for Circle members only).

Write Us
an E-Mail

Feel free to send your question directly to our developers.

Add component to instantiated gameboject

Clevereen
2020-05-11 21:54:42

hello,

i'm using the PhotonNetwork.Instantiate in order to instantiate a game object accross the network. This work fine so far. But, when i'm trying to add a component to this, it adds only localy.
How can i make the other player see this added component?

ennemySpawn = PhotonNetwork.Instantiate(ennemyData.ennemyGO.name, new Vector3(spawnVectorX, spawnVectorY, spawnVectorZ), Quaternion.identity);

creepStats = ennemySpawn.AddComponent();//attach data to the creep

Comments

Tobias
2020-05-12 14:50:38

Yes, when you locally add components, those won't be synchronized.
Most networking solutions try to sync as few info as possible. Recreating whatever gets added or removed will end in disaster, so it's not done.

Add the components you need to the prefab that resembles your networked object. Then, on instantiate, you may enable or disable some.
In general: Don't mess around with this too much, as it will be hard to analyze when it's buggy.

Clevereen
2020-05-12 17:45:03

Thank you so much for your answer, i've spent soooo much time trying to solve this issue....
well i'm a bit disapointed that it's not possible however, let's suppose that i add the component before, i still have to synchronize the datas:

i saw that when we instantiate a game object, it is possible to set data

    object[] myCustomInitData=new object[]  
    {  
        player.transform.position, player.transform.rotation, photonView.ViewID  
    };

PhotonNetwork.Instantiate("MyPrefabName", new Vector3(0, 0, 0), Quaternion.identity, 0, myCustomInitData);

the question is :
can i set scriptable object & other variables to the instantiated object data?
i want to do something like so :

    object[] myCustomInitData=new object[]  
    {  
        itemData,  
       name  
    };

How can i use the data and ensure that other players see the updated values?

Tobias
2020-05-13 07:43:34

I understood your post wrong and got "I want to change my components frequently". Yes, you can customize the instantiated networked object but you have to do it on all client in a way that sender and receiver fit together. E.g. while the object reacts to input on the controlling client, it will ignore input when it's a remote variant.

Yes, you can use the CustomInitData. It's meant specifically to customize the instantiated object, too. It's a one time setup, which is fine.

You don't have to send the viewID and Transform, as that's part of the parameters for PhotonNetwork.Instantiate and gets synced!

Clevereen
2020-05-13 11:18:46

I confirm that I only want to add the component once and for all (one time setup). How can i do to ensure that all client receives the info?

I've spent nearly 5 days searching everywhere and trying every solution to reach my first solution, which is, instantiate a game object and add a component on it. Before trying the 2nd way, could you help me achieve the first way?

here are the solution i've tryied :

  • Instantiation through the photonnetwork.instantiate //instantiate and add a component
  • Manual instantiation //local instatiation + add component and synchronize
  • [PunRPC] //=> bug
  • public void OnPhotonInstantiate(PhotonMessageInfo info) //=> not possible as the component script is added after the instantiation

No solution seems to work as the other client doesn't see the added component. i'm a bit hopeless.

Tobias
2020-05-14 15:47:30

How can i do to ensure that all client receives the info?

The best way is to do this via the CustomInitData. This is permanently recorded and relates to the View anyways.
You need some script that is enabled and will be called OnPhotonInstantiate, to add/remove other scripts, which are not part of the instantiation.

If you need to modify the networked object post-creation, you could use a buffered RPC.
Meaning: RPC( ... RpcTarget.OthersBuffered, ...)
This will store the RPC on the server for anyone joining. If nobody else is expected, you can use a normal RPC.

Clevereen
2020-05-15 06:33:59

Thank you very much, after some time, i've finally done what i wanted!

let me resume the final purpose was:
1-Instantiate a gameobject accross the network
2-Add a component with a scriptable object on it and ensure the other players see it

for those who are interrested, here is the code :

//EnnemyData.cs => This is my scriptable object that contains my datas  
using UnityEngine;  
public class EnnemyData : ScriptableObject  
{  
    public GameObject ennemyGO;  
    public Transform target;

    //ACCROSS THE NETWORK  
    public byte Id { get; set; }  
}

//MyGroundPlayer.cs => the script that has the photonview component  
using System.Collections;  
using System.Collections.Generic;  
using UnityEngine;  
using Photon.Pun;  
public class MyGroundPlayer : MonoBehaviourPun, IPunObservable  
{  
    /*---------------------------------------------------------------------------------------------*/  
    /*           ADD A COMPONENT ACCROSS THE NETWORK  
    /*--------------------------------------------------------------------------------------------*/

    //called by Spawn.cs  
    [PunRPC]   
    public void RPC_SpawnOnNetwork(int ennemyPhotonView_i, EnnemyData ennemyData_i)  
    {  
        Debug.Log("The RPC_SpawnNetwork is receiving :" + ennemyPhotonView_i, ennemyData_i);  
        CreepStats creepStats= PhotonView.Find(ennemyPhotonView_i).gameObject.AddComponent<CreepStats>();  
        creepStats.ennemyData = ennemyData_i; //pass the value  
        creepStats.parent = this.gameObject;//pass the value  
        creepStats.useNetwork = true;  
    }  
}


//Spawn.cs : => The script that allows to instantiated a game object with custom parameters  
using Photon.Pun;  
using ExitGames.Client.Photon;  
public class Spawn : MonoBehaviourPun  
{  
[SerializeField] PhotonView thePhotonView;

    private void Awake()  
    {  
        if (useNetwork)  
        {  
            //Photon doesn't recognize by default custom class, so we need to register it  
            PhotonPeer.RegisterType(typeof(EnnemyData), (byte)'A', SerializeEnnemyData, DeserializeEnnemyData);  
        }

    }

private void InstantGO()  
{  
                //Instantiate accross the network (never use PUN RPC to spawn)  
                ennemySpawn = PhotonNetwork.Instantiate(ennemyData.ennemyGO.name, new Vector3(spawnVectorX, spawnVectorY, spawnVectorZ), Quaternion.identity);  
                //Get the photonView of the instantiated GameObject in order to pass it as a parameter  
                ennemyPhotonView = ennemySpawn.GetPhotonView().ViewID;

                //Call the RPC of MyGroundPlayer.cs to add the component post-instantiation  
                thePhotonView.RPC("RPC_SpawnOnNetwork", RpcTarget.AllBuffered,ennemyPhotonView, ennemyData);  
}  
    /*---------------------------------------------------------------------------------------------*/  
    /*                                    ACCROSS THE NETWORK  
    /*--------------------------------------------------------------------------------------------*/

    #region Serialize/Deserialize a class  
    /// <summary>  
    /// IN ORDER TO PASS A SCRIPTABLE OBJECT WITH PUN RPC, WE NEED TO SERIALIZE IT AS PHOTON  
    /// DOESN'T RECOGNIZE IT BY DEFAULT CUSTOM CLASS  
    /// </summary>  
    /// <param name="data"></param>  
    /// <returns></returns>

    public static object DeserializeEnnemyData(byte[] data)  
    {  
        //var result = new EnnemyData();//for monobehaviour  
        var result = ScriptableObject.CreateInstance<EnnemyData>();//Scriptable Object  
        result.Id = data[0];  
        return result;  
    }

    public static byte[] SerializeEnnemyData(object ennemyData)  
    {  
        var c = (EnnemyData)ennemyData;  
        return new byte[]   
        {  
            c.Id  
        };  
    }  
    #endregion  
}  

Again Tobias, i'm really greatfull!

Back to top