How can I ensure only 1 player at a time can hold an item with xr interaction toolkit?
I'm using RequestOwnership and ClearOwnership so any player can grab an item with Realtime Transform and move it around networked.
But with the XR Grab Interactable component it allows another player to grab the item when it's already being held, and then it desyncs and each client sees themself holding the item.
I'm using the XR Grab Interactable's Interactable Events (Select and Select Exited) to call methods with RequestOwnership.
7 Replies
Hi @dontworry. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
----------------------
To ensure that only one player at a time can hold an item in a networked environment using the XR Grab Interactable component, you need to manage the ownership of the RealtimeTransform component associated with the item.
When a player grabs an item, you should call
RequestOwnership()
on the RealtimeTransform component. This will make the player the owner of the object, and their updates to the object will be visible to other clients. Other clients can then use the ownerID
property on RealtimeTransform to see who is holding the item.
However, you should be aware that Normcore doesn't send changes to the server immediately when you change ownership or the value on a model. Instead, it synchronizes at 20hz and sends the latest state. If you change something and then change it back immediately, nothing will be sent to the server. In this case, you should skip calling ClearOwnership()
. As long as the RealtimeView’s owner is None, then any other client in the future can just call RequestOwnership()
to take over the transform and move it.
Instead, you should only call ClearOwnership()
when the player releases the item. This will allow other players to grab the item.
Remember that a RequestOwnership()
call is only rejected if the RealtimeView or a parent RealtimeView is owned by a different client. So, if a player tries to grab an item that is already owned by another player, the RequestOwnership()
call will be rejected, and the item will remain in the possession of the current owner.
Sources:
- How can I check who is holding an object? (https://normcore.io/documentation/room/common-questions#how-can-i-check-who-is-holding-an-object)
- I’m calling RequestOwnership(), setting the position of a transform, and then immediately calling ClearOwnership()—but nothing happens. How can I fix this? (https://normcore.io/documentation/realtime/common-questions#im-calling-requestownership-setting-the-position-of-a-transform-and-then-immediately-calling-clearownershipbut-nothing-happens-how-can-i-fix-this)
- How it works (https://normcore.io/documentation/realtime/realtimetransform#how-it-works)
- Ownership (https://normcore.io/documentation/realtime/realtimeview#ownership)
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@666359106176679966> kapa.ai is still learning and improving, please let us know how it did by reacting below
When a player grabs an item I'm calling RequestOwnership, and when another player grabs the same item that is already being held, it may be rejecting this new RequestOwnership call since it hasn't been released yet by the first player and ClearOwnership hasn't happened. But the problem is XR Grab Interactable still allows the 2nd player to grab the item and see themself locally moving it around, even if it's owned by the 1st player still. When the 2nd player releases the item it snaps back to the 1st player's hand since they are the owner and still holding it on their client.
a simple solution is to set the rigidbody to kinematic and do a check for isKinematic before grabbing the item
another option is to check if the owner ID is -1 (unowned) before grabbing
another option is to create a custom model with a bool called canGrab which you flip to false when someone picks it up
thanks for the help. i've started attempts for options 2 & 3, but how do you suggest I interrupt "before grabbing"?
i was changing the Interaction Layer Masks on the XR Grab Interactable to "OneHolder" and the XR Origin Rig to "OneHolder" so the other player's Rig that is still set on "Default" wouldn't be able to grab, in theory...
but I can't figure out how to detect which player did the "Select" grab on the XR Grab Interactable, since the corresponding XR Direct Interactor components are on the XR Origin Rig (only 1 in the scene), not on the avatar prefabs that get called in as separate ids in the scene.
just disable the interactable for other players while it's being held
that is much easier 🙂
i couldn't understand how to determine "other players" in the update sync then i realized
isOwnedRemotelySelf
does the trick!
thanks @Mechabit 🙏