Niv
Niv3mo ago

is the ReltimeView property 'preventOwnershipTakeover' synched between the clients?

Meaning, if clientA takes ownership and the sets the 'preventOwnershipTakeover' property to true - will client 'B' observe that property to be true on his end? If it is not synchronized and assuming we have a rigidbody with a RealtimeTransform component that clientA prevented ownership changes on - what would prevent client B from requesting ownership on that rigidbody (and immediately receiving it), only for it to be rolled back by the server. This process can happen again and again over multiple frames (as the rigidbody keeps colliding with clientB owned rigidbodies - creating an unnecessarily janky behavior of that rigidbody.
11 Replies
kapa.ai
kapa.ai3mo ago
Hi @Niv. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- The preventOwnershipTakeover property of a RealtimeView is indeed synchronized between clients. If client A takes ownership and sets the preventOwnershipTakeover property to true, client B will observe that property to be true on their end. This is mentioned in the documentation (https://normcore.io/documentation/room/ownership-and-lifetime-flags#prevent-ownership-takeover-of-a-realtimeview). As for your second question, if client A has set preventOwnershipTakeover to true on a RealtimeView, client B cannot request ownership of that RealtimeView. The server will block the request. This is because the preventOwnershipTakeover flag, when set to true, means the model owner must clear ownership before another client can request it. This is mentioned in the documentation (https://normcore.io/documentation/reference/classes/Normal.Realtime.RealtimeView). In the case of a Rigidbody with a RealtimeTransform component, if client A has set preventOwnershipTakeover to true, client B cannot request ownership of that Rigidbody. If client B attempts to request ownership, the server will block the request and roll back any changes that required ownership. This is mentioned in the documentation (https://normcore.io/documentation/room/ownership-and-lifetime-flags#requestownership--clearownership). Therefore, there should not be a situation where client B is repeatedly requesting and being denied ownership over multiple frames, creating janky behavior. If such a situation is occurring, it may be due to a bug or a misconfiguration. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3mo ago
<@269927864265211906> kapa.ai is still learning and improving, please let us know how it did by reacting below
Niv
Niv3mo ago
where specifically does the documentation mention that 'preventOwnershipTakeover' is synchronized?
maxweisel
maxweisel3mo ago
it is synchronized it’s not mentioned but the property doesn’t make any sense if it’s not it’s not a local value that needs to be synchronized it’s a setting on the server for this object all clients are referencing the same value on the server
Niv
Niv3mo ago
Hey Max, after some investigation I'm seeing something different. I have a rootView where I toggle 'preventOwnershipTakeover' to true and then to false. I print on that client (the owner) and another client that value of this boolean to the console. While on the owner side it seems the bool retains its FALSE value, the other client keeps seeing TRUE. Moreover - if I try to request ownership from the other client it seems to only toggle for one frame and then resets to the orignal owner - indicating that the server also 'thinks' ownership takeover is still prevented. Any clue what I'm doing wrong? I don't have a clean repro (our project is very big), I can probably make one but before I do that I thought to ask maybe you have a suggestion for things to look into ... Thanks
maxweisel
maxweisel3mo ago
well if it’s set to true and has an owner, you’re not going to be able to set it to false. that would defeat the purpose of the flag
Niv
Niv3mo ago
the owner himself is setting this back to false. The use case is say there is some physical game prop. When it is held by a player - that player takes ownership and prevents other from taking ownership (say by touching it). When he throws/lets go of the prop, I want him to stay the owner (someone needs to be, to drive its physics) but should enable others to take ownership should they interact with it. I have worked around it by doing this sequence of calls (all in 1 frame, I'm pretty surprised this worked): _rootView.preventOwnershipTakeover = false; _rootView.ClearOwnership(); _rootView.RequestOwnership(); Seems a bit weird to have to 'Clear Ownership' in order to reset the prevent flag, only to take ownership back. In any case, the side affect that two clients looking at the same root view observe other values of 'prevent...' seem flat out wrong
maxweisel
maxweisel3mo ago
I don't think your client is the owner then. That clear ownership call isn't going to do anything and request ownership will be written ahead of preventOwnershipTakeover in the packet those three lines are the equivalent of this:
_rootView.preventOwnershipTakeover = false;
_rootView.SetOwnership(-1);
_rootView.SetOwnership(realtime.clientID);
_rootView.preventOwnershipTakeover = false;
_rootView.SetOwnership(-1);
_rootView.SetOwnership(realtime.clientID);
Which is the equivalent of this:
_rootView.RequestOwnership();
_rootView.preventOwnershipTakeover = false;
_rootView.RequestOwnership();
_rootView.preventOwnershipTakeover = false;
because we don't serialize and send any of these calls until the next network tick
Niv
Niv3mo ago
From all my validations, the client setting 'prevent' to false IS the owner. and locally I can observe that flag is indeed cleared from that point on (the server doesn't dispute that). The other client, seems to get the flag being raised - but never resets that flag unless the owner calls 'ClearOwnership').. BTW: my reason for event attempting such workaround were these lines in your (decompiled) code:
/// <summary>
/// If true, the model owner must clear ownership before another client can request it.
/// </summary>
public bool preventOwnershipTakeover
{
get => this.GetLifetimeFlag(MetaModel.LifetimeFlags.PreventOwnershipTakeover);
set => this.SetLifetimeFlag(MetaModel.LifetimeFlags.PreventOwnershipTakeover, value);
}
/// <summary>
/// If true, the model owner must clear ownership before another client can request it.
/// </summary>
public bool preventOwnershipTakeover
{
get => this.GetLifetimeFlag(MetaModel.LifetimeFlags.PreventOwnershipTakeover);
set => this.SetLifetimeFlag(MetaModel.LifetimeFlags.PreventOwnershipTakeover, value);
}
Again, to show my argument I would need to demonstrate this in a lean repro - which would sidetrack me too much. The workaround miraculously works for me, so I'll stick to it (I'm only prototyping right now) and circle back to this when I have more time.
maxweisel
maxweisel3mo ago
this is correct, the thing is that your clear ownership call never goes out to the server because you’re immediately switching it right after that call is essentially a no-op
cryptomax
cryptomax3mo ago
we just disabe the grab script for everyone else than the player picking it up when you pickup the item and request ownership. Then turn on the grab scriptfor everyone else on release of the item. This works fine and the way normcore handles ownership passing it just works. Meaning it isn't taken over while the player holding it moves it if it is bumped, and you can easily throw the item to another person and ownership transfers as you would expect. Is it possible you don't need it more complicated than that?