synchronization of objects
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).
synchronization of objects
deadlysnix
2018-06-06 12:02:26
Hello,
I am creating a multiplayer with photon PUN. I already managed to sync the headset and controller. Now I want to sync a cube. The players should be able to pick the cube up and the other players should see the movement of the cube. I tried to create a cube with a script to interact with it (this works fine) and than I just added Photon View and Transform View (in the observe field) to sync position and rotation.
The result is, that only the master host (the first one joining the room) can interact with the cube and the other one sees it, but when the second one interacts with the cube, the first one does not see any movement. I tried to put the interactable Item script in the observe field of photon view, but than I get the error "The observed monobehaviour cube of this PhotonView does not implement OnPhotonSerializeView()!". What components does an interactable object need in the scripts to be observed by PhotonView?
I also tried the OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) method, this did not work either.
Any solutions ideas or completely different options to sync an interactable object over the photon PUN Network?
Please explain in easy steps, because I am totally new in programming and VR =)
Thx
Comments
deadlysnix
2018-06-06 13:41:04
this is my interactable Item code:
Problem is, that only the movement of the master client (first one entering the room) with the object is synchronized, the movement of the second player with the cube is not synchronized.
I added Photon View, Photon Transform view, Rigidbody and this script to the cube and the photon view is observing the transform and the Interactable Item script below.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class InteractableItem : Photon.PunBehaviour, IPunObservable
{
public Rigidbody rigidbody;
private bool currentlyInteracting;
private float velocityFactor = 20000f;
private Vector3 posDelta;
private float rotationFactor = 400f;
private Quaternion rotationDelta;
private Vector3 axis;
private float angle;
private WandController attachedWand;
private Transform interactionPoint;
// Use this for initialization
void Start () {
rigidbody = GetComponent<Rigidbody>();
interactionPoint = new GameObject().transform;
velocityFactor /= rigidbody.mass;
}
// Update is called once per frame
void Update() {
if (attachedWand && currentlyInteracting)
{
posDelta = attachedWand.transform.position - interactionPoint.position;
this.rigidbody.velocity = posDelta * velocityFactor * Time.fixedDeltaTime;
rotationDelta = attachedWand.transform.rotation * Quaternion.Inverse(interactionPoint.rotation);
rotationDelta.ToAngleAxis(out angle, out axis);
if (angle < 180) {
angle -= 360;
}
this.rigidbody.angularVelocity = (Time.fixedDeltaTime * angle * axis) * rotationFactor;
}
}
public void BeginInteraction(WandController wand)
{
attachedWand = wand;
interactionPoint.position = wand.transform.position;
interactionPoint.rotation = wand.transform.rotation;
interactionPoint.SetParent(transform, true);
currentlyInteracting = true;
}
public void EndInteraction(WandController wand)
{
if (wand == attachedWand)
{
attachedWand = null;
currentlyInteracting = false;
}
}
public bool IsInteracting()
{
return currentlyInteracting;
}
public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
{
if (stream.isWriting)
{
// We own this player: send the others our data
stream.SendNext(this.currentlyInteracting);
}
else
{
// Network player, receive data
this.currentlyInteracting = (bool)stream.ReceiveNext();
}
}
}
[Deleted User]
2018-06-07 08:53:23
Hi @deadlysnix,
before interacting with the object, the client have to request the Ownership of it.
A few words on the OnPhotonSerializeView function: this one is for sending or receiving modifications of an object. It is used within the PhotonTransformView for example and gets called regularly. When it gets called on a client, it is either called for the Owner of the object (in this case you can write data to the stream which gets synchronized with other clients) or for a non-Owner of the object (in this case you can only read data from the stream and apply it to the object).
Your current situation: a non-Owner interacts with the object and moves it around. On his view it is updated (just locally) and gets reset as soon as OnPhotonSerializeView is called (because he receives different data from the Owner). To fix this, the client who wants to interact with the object, has to request the Ownership of the object in order to become the Owner of the object and to write updates to the stream inside the OnPhotonSerializeView function (which then gets synchronized across all clients).
To see how Ownership Transfer works I would recommend you taking a look at the certain documentation page and maybe at the Ownership Transfer demo which is included in the PUN package as well.
If you have further questions about that topic, please feel free to ask.
deadlysnix
2018-06-11 07:16:29
Hi @Christian_Simon , thank you very much. It works now with the Ownership-Transfer. =)
I now have a different problem. My objects has a rigidbody and I would like to enable the use of gravity. But when I mark "use gravity" the synchronization doesn't work anymore. The owner of the object can interact completely with the object (lift it up etc.), but the other clients only see the object moving on the ground. It seems like the gravity is locally added and is not synchronized through the network.
Any suggestions?
Thx
deadlysnix
2018-06-12 12:28:28
I dropped the gravity thing and I am using iskinematic now when the player is not interacting with the object.
I tried to implement the ownership that it is not possible to interact with an object while an other client is currently interacting. The problem is, that the ownership in the photonView component is not being synchronized. The MasterClient sees the object owned by scene, the clients see the object owned by player 1 even it he is not ineracting with the object.
How can I sync the ownership, so that everyone can interact with the object as long as no other player is interacting with it?
Thanks for helping =)
this is my code:
public void BeginInteraction(WandController wand)
{
print("current owner on start interaction: " + this.photonView.ownerId);
if (this.photonView.ownerId == 0)
{
this.photonView.TransferOwnership(PhotonNetwork.player.ID);
print("Ownership transfered from scene to player");
gameObject.GetComponent<Rigidbody>().isKinematic = false;
attachedWand = wand;
interactionPoint.position = wand.transform.position;
interactionPoint.rotation = wand.transform.rotation;
interactionPoint.SetParent(transform, true);
currentlyInteracting = true;
}
else
{
Debug.Log("Object is already used by player" + this.photonView.ownerId);
gameObject.GetComponent<Rigidbody>().isKinematic = true;
return;
}
}
public void EndInteraction(WandController wand)
{
if (wand == attachedWand)
{
attachedWand = null;
currentlyInteracting = false;
gameObject.GetComponent<Rigidbody>().isKinematic = true;
//this.photonView.RPC("aktualisieren von current Owner", PhotonTargets.All, );
this.photonView.TransferOwnership(0);
print("end interaction and ownership transfered back to scene, current Owner:" + this.photonView.ownerId);
}
[Deleted User]
2018-06-14 09:01:40
You can try to set the Ownership Option of the prefab to Request in the inspector. This way, a client can request the Ownership of the object at runtime. Therefore the current owner will be asked to pass the Ownership to another client. If the current owner is currently interacting with the object, he can reject transferring the Ownership. If he is not interacting with the object, he can pass the Ownership to the requesting client. This procedure is described in the section Request Ownership and Transfer of the Ownership Transfer documentation page (mentioned above). Note: a SceneObject is owned and controlled by the MasterClient by default.
So basically when you call void BeginInteraction(WandController wand)
the client wants to request the Ownership of the object and sends a certain message. This request can either get accepted or rejected by the current owner of the object.
When you call void EndInteraction(WandController wand)
you can pass the Ownership to the MasterClient. This can be done by the TransferOwnership(...)
function. But you don't have to do this. You will be fine if another client sends a request to the current as well.