Search Unity

Third Party [Photon] TransferOwnership behaving strangely

Discussion in 'Multiplayer' started by scrant, Nov 25, 2019.

  1. scrant

    scrant

    Joined:
    Jun 1, 2017
    Posts:
    73
    Hi, I'm just not understanding the docs or example code for Transfer ownership. This is what the interfaces provide:

    Code (CSharp):
    1. public interface IPunOwnershipCallbacks
    2.     {
    3.         ///
    4.  
    5.         /// Called when another player requests ownership of a PhotonView from you (the current owner).
    6.         ///
    7.  
    8.         ///
    9.         /// The parameter viewAndPlayer contains:
    10.         ///
    11.         /// PhotonView view = viewAndPlayer[0] as PhotonView;
    12.         ///
    13.         /// Player requestingPlayer = viewAndPlayer[1] as Player;
    14.         ///
    15.         /// PhotonView for which ownership gets requested.
    16.         /// Player who requests ownership.
    17.         void OnOwnershipRequest(PhotonView targetView, Player requestingPlayer);
    18.  
    19.         ///
    20.  
    21.         /// Called when ownership of a PhotonView is transfered to another player.
    22.         ///
    23.  
    24.         ///
    25.         /// The parameter viewAndPlayers contains:
    26.         ///
    27.         /// PhotonView view = viewAndPlayers[0] as PhotonView;
    28.         ///
    29.         /// Player newOwner = viewAndPlayers[1] as Player;
    30.         ///
    31.         /// Player oldOwner = viewAndPlayers[2] as Player;
    32.         ///
    33.         /// void OnOwnershipTransfered(object[] viewAndPlayers) {} //
    34.         /// PhotonView for which ownership changed.
    35.         /// Player who was the previous owner (or null, if none).
    36.         void OnOwnershipTransfered(PhotonView targetView, Player previousOwner);
    So for OnOwnershipTransfered which is it? Does it take an object array as the docs state or the targetView and previousOwner parameters? Furthermore, it won't let me implement anything but the latter as in above code sample but previousOwner seems to return the owner doing the requesting. It also appears that both callbacks (OnOwnershipRequest and OnOwnershipTransfered) are called on both the requesting client's machine and the owner's machine. Both are called on both! Why is this? Is this intended behavior? Seems OnOwnershipRequest should only get called on the owner's node while OnOwnershipTransfered gets called on the requestor's node. Help!
     
  2. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    Hi,

    First of all, you need to request Ownership, please check the script OnClickRequestOwnership to check how it's done.

    then, you need to implement on your network prefab susceptible to owner ship changes that interface.

    - OnOwnershipRequest will called to the PhotonView requested for a change, it's then up to the instance to acknowledge it or not, by doing view.TransferOwnership(requestingPlayer.ID);

    - OnOwnershipTransfered, will be cakked once TransferOwnership() was called.

    So don't over think this, it's actually a simple process.

    Check out PUN classic on a fresh project, and check the demo ownership, it will have all the code for this.

    Also, make sure to read on the doc for that interface: https://doc-api.photonengine.com/en...on_1_1_pun_1_1_i_pun_ownership_callbacks.html

    Let me know if you still have troubles.

    Bye,

    Jean
     
    JohnTube likes this.
  3. scrant

    scrant

    Joined:
    Jun 1, 2017
    Posts:
    73
    Hi Jean, thanks for your reply. I did in fact do all of that above. My questions are more nuanced. OnOwnershipRequest doesn't appear to just call ownership on the object requested. It calls it on ALL objects that are subscribing to those events. So you need to have extra logic to see if you own it and if you should transfer it as EVERY client gets those calls. Very weird. Also, they seem to fire more than once. I get TWO calls for each OwnershipRequest and OwnershipTransfered. Even though Request was only asked once and Transfer was only called once. I've read all the docs and this doesn't line up or make sense. Cheers, Grant
     
  4. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    Hi,

    then, you need to implement it once in your scene, and not on the prefabs. you have the interface on your network prefab right now right?

    indeed if you have it on each prefab, all will receive it, and you will need to check if this if of concern for your prefab, your instance and also for your game context. The interface gives you callback with all the information about the request or the transfer.

    Bye,

    Jean
     
  5. scrant

    scrant

    Joined:
    Jun 1, 2017
    Posts:
    73
    Hey again, yeah I've implemented it not on the prefabs but on my Game Controller as there is a lot of logic as to who gets what when. Each player has their own controller and subscribe to the OnOwnership events there. But again, the OnOwnershipRequest should go to the controller of the owner of that object right? So if I call object.RequestOwnership() that should call OnOwnershipRequest on the OWNER'S Controller that implements and subscribes to those events right? But it calls it on EVERYONE'S OnOwnershipRequest. Seems counterintuitive. It also seems to make 2 calls for every object.RequestOwnership and then 2 for every return TransferOwnership even though that happens only once. I have Debug statements at every step so I see all this happening. All very weird. I've implemented extra logic in everyone's controller to see who is asking and for what object and dealing with it that way but a lot of extra work and differing from what the documentation seems to say.
     
  6. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    Hi,

    I just doubled check with our test scene (Pun classic has a demo on that, we haven't included it to pun 2 set of samples, but maybe we should, I'll see internally what can be done on that front), and all is well, I don't get duplicated callbacks.

    Every single instances ( owner or not, scene object or not), that implement this interface will get the callbacks, so it could be that you have some instances of that component running and you are not aware of it. I would log properly each occurrence and understand where each callbacks come from.

    If you can create a small repro case showing this duplicate issue, I'll have a look.


    Bye,

    Jean
     
  7. tanoshimi

    tanoshimi

    Joined:
    May 21, 2013
    Posts:
    297
    I came to this thread having experienced almost exactly the same sequence of events as @scrant - first discovering that the behaviour of transfer callbacks does not match the PUN2 documentation, then some confusion as to exactly the conditions under which the callbacks are triggered, and then finding that they are being called twice!

    I already wrote my comments about the documentation in this thread - https://forum.photonengine.com/disc...cumentation-mistakes-lack-of-clarity/p1?new=1 - however, if it's helpful for you to fix the duplicate callback triggers @Jean-Fabre I include steps to reproduce the problem below:

    Here are steps to reproduce:
    1. Create a brand new project (I'm using Unity 2019.1.2.f1 on Windows 10 64-bit)
    2. Import latest PUN2 package from Asset Store (v2.18.1 30 April 2020)
    3. Load the "PunBasics-Room for 2" scene in the editor
    4. Create a new 3D Cube in the scene hierarchy and position it at (0,1,0)
    5. Add a PhotonView component to the cube
    6. Add the OwnserhipBug.cs script attached below to the cube
    7. Add the PunBasics-Launcher, Punbasics-Room for 1, and Punbasics-Room for 2 to the build settings
    8. Build and Run one instance, and then play another instance in the editor
    Here's the behaviour I observe:
    • When the scene first loads, the photonView on the cube is owned by "Scene" (as expected)
    • When the master client (i.e. whichever of build or editor joined the room first) first clicks on the cube, nothing happens - i.e. the photonview is still shown as owned by "Scene" in the editor inspector, and no logs are shown from the callback (expected behaviour would be for it to be shown as now owned by that player rather the scene, and for a log message from the OnOwnershipRequest and OnOwnershipTransferred shown in the console))
    • When the other client clicks on the cube, the inspector changes to show the correct new owner of the photonView, the console log shows the debug message produced by OnOwnershipRequest and two messages produced by OnOwnershipTransferred (expected behaviour would be for a single message from
    • For each subsequent click by the player who doesn't currently own the cube, an additional OnOwnershipRequest message and two OnOwnershipTransferred messages are produced. (expected behaviour - one of each)
    Any assistance would be gratefully received - thanks!


    PUNCallbackBug.jpg
     

    Attached Files:

  8. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    Hi,

    I can replicate the issue, This is odd indeed, we are on it. Thanks for reporting!

    Bye,

    Jean
     
    tanoshimi likes this.
  9. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    Hi,

    so, I think you got confused with the process, your callback response was calling a transfer on both network objects, here is how you should do it:

    Code (CSharp):
    1.     public void OnOwnershipRequest(PhotonView targetView, Player requestingPlayer) {
    2.         // OnOwnershipRequest gets called on every script that implements it every time a request for ownership transfer of any object occurs
    3.         // So, firstly, only continue if this callback is getting called because *this* object is being transferred
    4.         if (targetView.gameObject != this.gameObject) {
    5.             return;
    6.         }
    7.         if (targetView.Owner != requestingPlayer)
    8.         {
    9.             Debug.Log("Requesting granted");
    10.             targetView.TransferOwnership(requestingPlayer);
    11.         }  
    12.     }
    OnOwnershipRequest will be called to everyone, and since you have two players ( two instances of the cube on each local running app, your code was making a call on one client app and a call on the other client app.

    So all is good.

    Bye,

    Jean
     
  10. tanoshimi

    tanoshimi

    Joined:
    May 21, 2013
    Posts:
    297
    Thanks for the response, @Jean-Fabre - so that leads me back to my first problem, which is that the documentation is incorrect.... According to https://doc-api.photonengine.com/en...on_1_1_pun_1_1_i_pun_ownership_callbacks.html

    void OnOwnershipRequest (PhotonView targetView, Player requestingPlayer)
    Called when another player requests ownership of a PhotonView from you (the current owner)

    So you're saying the correct description for the OnOwnershipRequest behaviour should be "Called when a player requests ownership of a PhotonView from another player"?
     
  11. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    Yes,

    In your case, you call it twice so you essentially make two requests, my version of your script only call it once. So this is not a documentation issue here but the script calling twice for a request.

    Bye,

    Jean
     
  12. tanoshimi

    tanoshimi

    Joined:
    May 21, 2013
    Posts:
    297
    We seem to be having a slight communication issue - the point I'm trying to make is that, if the behaviour of OnOwnershipRequest matched the description in the documentation, it shouldn't have been called twice using my code!

    The description states that OnOwnershipRequest is "called when another player requests ownership from you (the current owner)" - I'm not sure how else that can be interpreted other than to assume that the callback will only fire on the client that is the current owner. But the actual behaviour is that it is called on all clients, whether they are the owner or nor.
    The reason why your script only fires once is because you explicitly add an additional check condition
    if (targetView.Owner != requestingPlayer)
    . But, based on the description in the documentation, that condition should be assumed to be implicitly present in the callback already.

    The workaround is straightforward - I'm just informing you for the benefit of future customers who get misled in the same way I did.
     
  13. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    Hi,

    yeah, it seems we are not understanding each other, I am sorry about that... :) We'll see if we can word the documentation better.

    Bye,

    Jean
     
  14. WisockiJr

    WisockiJr

    Joined:
    Jul 5, 2014
    Posts:
    30
    Jean, I can confirm that OnOwnershipTransfered is being called twice, and the previousOwner parameter is incorrectly pointing to the new owner. Also the documentation is incorrect.
     
  15. tobiass

    tobiass

    Joined:
    Apr 7, 2009
    Posts:
    3,070
    @WisockiJr, please send us a minimal repro case, which we can run relatively easy to check. Mail to: developer@photonengine.com and if the project zip is bigger than a few MB, please just link to it. Thanks.
     
  16. shreee

    shreee

    Joined:
    Aug 31, 2016
    Posts:
    19
    Hy,

    my project like puck sliing..in this i want to all players have ownership of all players. but i can't fixed it..try ownership demo but only one player have ownership but i want all have access for moevement.
     
  17. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    Hi,

    you can't have all players to have access to control one networked object, at least not by design.

    however, you can certainly send movement actions to the master client which in turn will control that network object, and so any one who send an order to move this object will get executed by the master client.

    Bye,

    Jean
     
  18. shreee

    shreee

    Joined:
    Aug 31, 2016
    Posts:
    19
    Please, give me an example code..if possible
     
  19. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    Hi,

    I won't have time in the next few days, but ping me early next week, meanwhile, I suggest you experiment with the following, don't overthink this, it's not complex:

    - work with a network scene object, which means that the masterclient is owning it,
    - try to control that object from the master client using simple controls like arrow keys, when key is down it moves, until it's up
    - now on non master client, using the same script that controlled the scene object, modify it to only output the input value themselves ( a vector2, like {1,1} meaning moving forward and right at full speed), everytime this vector2 input value changes, send an RPC to the masterClient passing this vector2 as data to the rpc
    - the masteClient received this rpc and moves the scene network object using this vector 2 input coming from the rpc.

    That's it. try to work out each step one by one.


    Bye

    Jean
     
  20. shreee

    shreee

    Joined:
    Aug 31, 2016
    Posts:
    19
    okk i will try,
    actully my project is like puck sling so when player-1 sling to opponent's area and touch to opponent puck then puck generally sling due to player-1's puck force..but just movenent opponent puck slding to orignal position..
     
  21. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    shreee likes this.
  22. shreee

    shreee

    Joined:
    Aug 31, 2016
    Posts:
    19
    thank you , for replay still i m confuse...
    Ex.
    Player-1 had 5 Puck all puck have diffrent controlling for sling...
    Player-2 has also diffrent 5 puck(opponent of Player-1)

    actully happing is that..when player-1 sling puck and case of touch to player-2' puck that point both have rigidbody but player-2 puck not sling or change the position due to force of player-1's puck because of..we have not ownership of player-2..so can't move puck(have rigidbody and apply force from player-1's puck)....and i m totally new in multiplayer so this thing is possible with PUN or not ..i don't know
     
  23. DRRosen3

    DRRosen3

    Joined:
    Jan 30, 2014
    Posts:
    683
    Almost a year later and no further updates? I can also confirm that OnOwnershipRequest and OnOwnershipTransferred are called twice on the same client from a single object. I was going to seek help with this issue, but I've found the cause of it. If you have a class that inherits MonoBehaviourPunCallbacks (instead of MonoBehaviour) and that class also contains your IPunOwnershipCallbacks...you need to make sure you're not accidentally adding that class to the PhotonNetwork.AddCallbackTarget twice.

    MonoBehaviourPunCallbacks already has an OnEnable method built in that adds it to PhotonNetwork.AddCallbackTarget. So unless you override OnEnable, AND do NOT call base.OnEnable, you don't need to actually add a MonoBehaviourPunCallbacks class as a PhotonNetwork callback target.
     
  24. tobiass

    tobiass

    Joined:
    Apr 7, 2009
    Posts:
    3,070
    You are right and we had this case several times. It's a bit more tricky with the registrations (compared to PUN Classic) but once correctly setup, it's also more performant.

    Thanks for posting your finding.