Ownership Transfer Demo
This simple demo is a playground for a PUN feature that can be tricky to grasp.
Simply put, Ownership Transfer allows you to pass control of any networked object.
This page explains how to use this feature, some background and show which cases are more complex to handle.
The demo allows anyone to instantiate objects.
On click, a ownership transfer is requested.
The current owner can pass ownership or reject the request.
A pointer above each object marks the currently owned (and controlled) GameObjects per client.
The Basics
In PUN, every object can only be controlled by one client.
When a client instantiates something, it will be the owner of that new object, PhotonView.isMine
is true on that client only and if you use OnPhotonSerializeView
, only this client will write to the PhotonStream.
The others just receive and update accordingly.
If you want to pass control of a GameObject to another client, you will first have to configure the PhotonView.
In the Inspector, you can see the owner of the GameObject (prefabs only have one at runtime).
In the same line, you will find a dropdown which is Fixed
by default.
Other options are Takeover
and Request
.
- "Fixed" owner keeps the creator of a GameObject as owner.
- "Takeover" enables any client to take the GameObject from the current owner.
- "Request" asks the current owner to pass it over. This can be rejected.
Setup PhotonView
Select the "OwnershipSphere" to see it is set to TakeOver
.
It is used only once in the scene.
This makes it a "scene object" and anyone can take it anytime.
The "OwnershipCube" prefab is set to Request
, so the current owner can pass or reject ownership.
As toggle in this demo, we simply added a button in the top right corner (at runtime).
Request Ownership and Transfer
Both prefabs have a OnClickRequestOwnership
component.
When a GameObject with PhotonView gets clicked, this script calls this.photonView.RequestOwnership();
to request ownership - no matter which setting the PhotonView has.
The DemoOwnershipGui
script is the one that answers requests (for the Request
setting).
It implements OnOwnershipRequest()
:
C#
public void OnOwnershipRequest(object[] viewAndPlayer)
{
PhotonView view = viewAndPlayer[0] as PhotonView;
PhotonPlayer requestingPlayer = viewAndPlayer[1] as PhotonPlayer;
Debug.Log("OnOwnershipRequest(): Player " + requestingPlayer + " requests ownership of: " + view + ".");
if (this.TransferOwnershipOnRequest)
{
view.TransferOwnership(requestingPlayer.ID);
}
}
When someone requests ownership, this will be called by PUN on the client that is the current owner.
As you can see, the current owner calls view.TransferOwnership(requestingPlayer.ID)
to actually transfer the PhotonView to it's new owner.
When a GameObject's current owner leaves, the Master Client becomes the new owner.
The player who created a GameObject has to request ownership to get it back.
Tricky Situations
Ownership Transfer by itself should be relatively straighforward.
Control of GameObjects can be requested and transferred and if the current owner is gone, the Master Client takes over.
As noted above, the GameObject lifetime is not affected when control changes.
By default, all GameObjects created by one player will be destroyed when he/she leaves.
RPCs
RPCs are not bound to the lifetime of the GameObject.
If anyone uses RPCs on a GameObject he/she did not instantiate, (buffered) RPCs might still be sent to joining players.
In some cases, this can be ignored but you should be aware of this.
Also, you can clean up those RPCs corresponding to a PhotonView or the player who left.
Take a look at PhotonNetwork.RemoveRPCs()
.
Scene Objects
A player might lose the GameObject he/she is currently controlling.
This can be ok or annoying.
As possible workaround, the Master Client can instantiate GameObjects with InstantiateSceneObject()
.
This way, the GameObject will stay in the room until the last player leaves.
You can destroy these GameObjects, of course.
And the Master Client can also pass the ownership to the player who should control the GameObject.
Alternatively you can deactivate the automatic cleanup of the Event Buffer for a room by setting PhotonNetwork.autoCleanUpPlayerObjects
to false.
Then Photon will keep all events of players, even when they leave.
Unless you clean up past Instantiate calls and buffered RPCs, the buffer will grow.
Long running games (players joining and leaving for a while) will aggregate a lot of buffered events this way and might break (there is no limit for this by Photon).