Malek
Malek3w ago

Dual User Grabbing

I have a relatively simple setup right now where i have a game object that has an on-selected event hook, when it is grabbed by someone, that person requests ownership. This works mostly fine except in cases where one person is already grabbing it, then when a second person grabs it both people seem to have ownership, and true ownership is only seen when one of them releases the object
15 Replies
kapa.ai
kapa.ai3w ago
Hi @Malek. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Your observation is correct and relates to how Normcore's ownership model works, especially with RealtimeTransform and multiplayer interactions. Key Points: - Single Owner at a Time: In Normcore, only one client can own a RealtimeTransform (or any RealtimeComponent) at a time. When a second user tries to grab and requests ownership, the server will only grant it if the object is currently unowned or if ownership takeover is allowed (i.e., preventOwnershipTakeover is not set). If the object is already owned and preventOwnershipTakeover is enabled, the request will be denied, and the original owner retains control. However, if takeover is allowed, the new request will transfer ownership to the second user, and the first user will lose it. There is never a state where both users truly have ownership simultaneously, but due to network latency and local prediction, both clients may temporarily believe they have control until the server resolves the conflict and updates all clients accordingly Ownership + Lifetime Flags. - Ownership Requests: When a user grabs the object and calls RequestOwnership(), Normcore assumes the request will succeed and allows local changes immediately. If the server later rejects the request (e.g., due to preventOwnershipTakeover), those changes are rolled back RealtimeTransform. - Race Conditions: If two users grab the object at nearly the same time, both may locally believe they have ownership until the server resolves the conflict. The server will enforce a single owner, and the final state will be synchronized to all clients. This can result in the "true" owner only being clear after one user releases the object or after the server's update propagates Networked Physics. Best Practices: - UI Feedback: Provide clear UI feedback to users about whether they actually have ownership, using the isOwnedLocallySelf or ownerIDSelf properties on the RealtimeTransform IRealtimeComponent. - Prevent Ownership Takeover: If you want to avoid users "stealing" objects from each other, set preventOwnershipTakeover to true on the RealtimeView or when instantiating the object. This way, only unowned objects can be grabbed Prevent ownership takeover of a RealtimeView. - Release Ownership: When a user releases the object, call ClearOwnership() so others can take control Requesting ownership of a RealtimeView. Summary:
What you’re seeing is a result of local prediction and network latency. Only one user can truly own the object at a time, but both may temporarily believe they do until the server resolves the conflict. Use ownership properties to provide accurate feedback and consider using preventOwnershipTakeover if you want to restrict ownership changes. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3w ago
<@305847762430328833> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Malek
MalekOP3w ago
hmm i am okay with users stealing ownership from eachother, but it just doesn't resolve until one of them releases the object, it is not a latency issue, if it resolved after a second that would be fine but it is indefinite
NormalMark
NormalMark3w ago
what's an on-selected event hook? does your code check if the object is already held by another client before applying the grab? one way you could do it is: 1. RequestOwnership when grabbing an object, but only grab if the object is unowned 2. When releasing an object, call ClearOwnership There could still be an edge case if two players try to grab the same object at the exact same time - both players will think the object is unowned and perform a grab. But that's very unlikely, I think the solution above can get the job done.
Mechabit
Mechabit3w ago
You can register for ownership changed event and drop the object if someone else grabs it
maxweisel
maxweisel3w ago
@Malek you need to leave ownership for the view alone. request ownership of the transform only. and all clients need to listen for ownership changing so if you have code that’s positioning the object while owned, it stops running when ownership is transferred to someone else
Malek
MalekOP3w ago
Ahh I expected it to not try if it was owned by someone else Okay Yeah I will just, prevent that I mean i'm fine with either but that seems easier to pull off
maxweisel
maxweisel3w ago
fwiw you don’t need to call ClearOwnership() if you’re using a rigidbody. If you request ownership of just the transform, and a player throws it, when it comes to rest ownership is cleared automatically. ownership can be stolen just fine. triple check you’re not also requesting ownership of the view. that will block ownership requests on the transform
Malek
MalekOP3w ago
Hmmm I see
maxweisel
maxweisel3w ago
and if you’re ok with ownership being stolen, you won’t have to check if it’s already owned before requesting ownership at all
Malek
MalekOP3w ago
I might have been requesting ownership of the view then Yeah its a rigidbody nope double checked i am requesting ownership of the transform not the view if two users try to do it each think they have ownership and once they let go it snaps to the correct position but also gravity stops working permanently i don't use 'clear ownership' anywhere i only use 'request ownership' on the realtime transform in one spot, on the grab event
maxweisel
maxweisel3w ago
You shouldn't need to use clear ownership. One will take over and the other will reflect that ownership has transferred. If a user lets go and it snaps to the correct position, that means your code is currently fighting RealtimeTransform by positioning the object even if you no longer have ownership anymore. If both client's RealtimeTransforms believed they owned the object, letting go wouldn't cause it to snap back because RealtimeTransform does not position an object that it thinks is owned by the local client. It only streams the local client's position to the server. I expect you need to update your grabbing code to stop grabbing/positioning the object once it sees that realtimeTransform.isOwnedLocally transitions to being false The fact that it snaps back when you let go means that your code stops trying to position an object you don't own anymore, and RealtimeTransform is able to successfully move the object to the position the remote client that owns it is setting it to.
Mechabit
Mechabit3w ago
your grab code is overriding the RealtimeTransform position, you need to release the object if it switches owners while you're holding it
Malek
MalekOP3w ago
this makes sense :ponko_nod:
maxweisel
maxweisel3w ago
lmk how it works out. I’m hoping that’ll do the trick

Did you find this page helpful?