Add component to instantiated gameboject
The whole answer can be found below.
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).
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
Comments
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.
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?
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!
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.
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.
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