This document is about: PUN 1
SWITCH TO

PUN Classic (v1), PUN 2 and Bolt are in maintenance mode. PUN 2 will support Unity 2019 to 2022, but no new features will be added. Of course all your PUN & Bolt projects will continue to work and run with the known performance in the future. For any upcoming or new projects: please switch to Photon Fusion or Quantum.

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.

screenshot of ownership demo scene
Ownership Demo

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.

screenshot of photonview ownership setting
PhotonView Ownership Setting

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).

The ownership setting does not affect the lifetime of a GameObject. By default, GameObjects get destroyed when the creator leaves the room no matter who controls the GameObject.

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 Requestsetting). 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);
        }
    }
OnOwnershipRequest() should be only once in your scene/game.

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).

Back to top