Alix Ollivier
Alix Ollivier3d ago

Grabbing object with realtimetransform doesn't sync position across clients.

I have fruit in my game with an XR Grab Interactable and a RealtimeTransform. When one player picks up a piece of fruit, the others can't see it moving. I'm assuming it has something to do with ownership?
11 Replies
kapa.ai
kapa.ai3d ago
Hi @Alix Ollivier. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Yes, your issue is almost certainly related to ownership of the RealtimeTransform component. In Normcore, only the client that owns a RealtimeTransform is considered the "source of truth" for its position, rotation, and other properties. If you want to move an object and have that movement synchronized across all clients, your client must first request ownership of the RealtimeTransform. If you don't do this, any changes you make locally will be overwritten by the values from the current owner (or the initial state if there is no owner), and other clients won't see your updates. Solution:
When a player grabs a fruit (e.g., via XR Grab Interactable), you should call RequestOwnership() on the fruit's RealtimeTransform. This will make the grabbing client the owner, and their movements will be synchronized to all other clients. Example:
// When the fruit is grabbed
fruit.GetComponent<RealtimeTransform>().RequestOwnership();
// When the fruit is grabbed
fruit.GetComponent<RealtimeTransform>().RequestOwnership();
This is a common pattern in Normcore for interactive objects. If you want to check who currently owns the object, you can use the ownerID property on the RealtimeTransform. Also, make sure you are not requesting ownership of the RealtimeView unless you want to lock down the entire object and its children, as this can prevent proper ownership handoff for interactive objects like grabbable fruit. For more details, see the documentation on RealtimeTransform and ownership and the networked physics guide.
"In order to move an object with a RealtimeTransform component, your client needs to be the owner of the RealtimeTransform component"
RealtimeTransform "When you grab an object, you’ll need to call RequestOwnership() on the RealtimeTransform in order for others to see your updates to that object."
Room Common Questions
If you implement this and still have issues, double-check that you are not reparenting the object at runtime, as this is not supported and can cause synchronization problems. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3d ago
<@185325614775926784> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Alix Ollivier
Alix OllivierOP3d ago
@Normcore Assistant so do I need to make a new script for grabbable objects?
kapa.ai
kapa.ai3d ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- You do not strictly need to make a new script, but you do need to ensure that ownership of the RealtimeTransform is requested when the object is grabbed. This is not handled automatically by Normcore or XR Grab Interactable. The recommended approach is to add a small script to your grabbable objects that calls RequestOwnership() on the RealtimeTransform when the object is picked up. This ensures the grabbing client becomes the owner, and movement is synchronized across all clients. Here’s an example pattern from the documentation:
// When the fruit is grabbed
GetComponent<RealtimeTransform>().RequestOwnership();
// When the fruit is grabbed
GetComponent<RealtimeTransform>().RequestOwnership();
You can attach this logic to the appropriate grab event in your XR interaction system. This pattern is described in the Normcore docs for interactive objects and is necessary for proper synchronization of movement during grabs RealtimeTransform, Room Common Questions. So, while you don’t have to make a complex new script, you do need to add this ownership request logic somewhere in your project for grabbable objects. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3d ago
<@185325614775926784> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Alix Ollivier
Alix OllivierOP3d ago
@Normcore Assistant could you show me where in the docs it shows interactive objects
kapa.ai
kapa.ai3d ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- The Normcore documentation does not have a dedicated section specifically titled "interactive objects," but it does cover the pattern for synchronizing interactive (grabbable) objects using RealtimeTransform and ownership. The most relevant information is found in the following places: - The RealtimeTransform documentation explains that to move an object and have it sync across clients, your client must own the RealtimeTransform. It states:
"In order to move an object with a RealtimeTransform component, your client needs to be the owner of the RealtimeTransform component. You can request ownership of a RealtimeTransform component by calling RequestOwnership() or by using the Request Ownership button in the editor inspector."
This is the core mechanic for making objects interactive and synchronized. - The Room Common Questions section specifically addresses how to check who is holding an object and emphasizes:
"When you grab an object, you’ll need to call RequestOwnership() on the RealtimeTransform in order for others to see your updates to that object."
- The Networked Physics guide also explains the concept of ownership and how it relates to synchronizing movement for objects that are interacted with by multiple clients. While there isn’t a step-by-step “interactive object” tutorial, these sections together describe the required pattern for making grabbable or interactive objects work correctly in a multiplayer context with Normcore. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3d ago
<@185325614775926784> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Alix Ollivier
Alix OllivierOP3d ago
@Normcore Assistant does this code look like it would do the trick? using Normal.Realtime; using UnityEngine; using UnityEngine.XR.Interaction.Toolkit; public class NetworkedGrabbable : MonoBehaviour { #region Private Fields private RealtimeTransform m_RealtimeTransform; private XRGrabInteractable m_GrabInteractable; #endregion #region Unity Lifecycle private void Awake() { // Cache component references if (!TryGetComponent(out m_RealtimeTransform)) { Debug.LogError($"[{nameof(NetworkedGrabbable)}] Missing RealtimeTransform component!"); return; } if (!TryGetComponent(out m_GrabInteractable)) { Debug.LogError($"[{nameof(NetworkedGrabbable)}] Missing XRGrabInteractable component!"); return; } // Subscribe to grab events m_GrabInteractable.selectEntered.AddListener(OnGrabbed); m_GrabInteractable.selectExited.AddListener(OnReleased); } private void OnDestroy() { // Unsubscribe from events if (m_GrabInteractable != null) { m_GrabInteractable.selectEntered.RemoveListener(OnGrabbed); m_GrabInteractable.selectExited.RemoveListener(OnReleased); } } #endregion #region Private Methods private void OnGrabbed(SelectEnterEventArgs _args) { // Request ownership when grabbed m_RealtimeTransform.RequestOwnership(); } private void OnReleased(SelectExitEventArgs _args) { // Optionally: Clear ownership when released // m_RealtimeTransform.ClearOwnership(); } #endregion }
kapa.ai
kapa.ai3d ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- Your code follows the correct pattern described in the Normcore documentation for synchronizing interactive (grabbable) objects using RealtimeTransform and ownership. Specifically, it requests ownership of the RealtimeTransform when the object is grabbed, which is required for the grabbing client to become the source of truth and have its movements synchronized across all clients:
private void OnGrabbed(SelectEnterEventArgs _args)
{
// Request ownership when grabbed
m_RealtimeTransform.RequestOwnership();
}
private void OnGrabbed(SelectEnterEventArgs _args)
{
// Request ownership when grabbed
m_RealtimeTransform.RequestOwnership();
}
This matches the recommended approach in the docs:
"When you grab an object, you’ll need to call RequestOwnership() on the RealtimeTransform in order for others to see your updates to that object."
Room Common Questions
Additionally, your code subscribes and unsubscribes to the grab events in a safe way, and checks for the required components, which is good practice. A few notes based on the docs: - You generally do not need to call ClearOwnership() on release unless you want to allow other clients to immediately take over. Normcore will often handle this automatically for rigidbodies when they go to sleep, but you can control this behavior as needed (RealtimeTransform + Physics). - Make sure you are not reparenting the object at runtime, as this is not supported and can cause issues (RealtimeTransform Extra Notes). Summary:
Your script is aligned with the documented approach for making grabbable objects networked and interactive in Normcore. As long as your objects have both a RealtimeTransform and XRGrabInteractable, this should work as expected. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3d ago
<@185325614775926784> Kapa.ai is still learning and improving, please let me know how I did by reacting below.

Did you find this page helpful?