I spawn a Network Object Interactable from server,the host grab it correctly,but the client try grabbing is warning “Only the server can reparent NetworkObjects”. how can I grab On Client Side?
Thanks!
I spawn a Network Object Interactable from server,the host grab it correctly,but the client try grabbing is warning “Only the server can reparent NetworkObjects”. how can I grab On Client Side?
Thanks!
I didn‘t spawn XRrig or hand controller,these components are totally local. May this be the cause of the problem?
Two straightforward solutions:
OR
Either of these choices will prevent that error from appearing.
That being said, this will only allow the client to pickup the object and move it around locally. Replicating the Interactable component functionality across all clients will require additional steps.
Hope that helps!
-Joegre
Would be very nice with a simple example showing a cube able to be grabbed by a network client and getting synced in movement, even animation, in all the other clients view. Strange that it is so hard to find an example. Of this simple behaviour…
Hi! I have done via onwership change on Grab. The script is attached to a network interactable object. However, I personally have one problem. The grab attach position is kinda twisted with a network object. But works flawlessly with a local object. Trying to figure out the problem
using UnityEngine;
using Unity.Netcode;
using UnityEngine.XR.Interaction.Toolkit;
public class NetworkGrabbableObject : NetworkBehaviour
{
private XRGrabInteractable grabInteractable;
ulong clientID;
private NetworkObject networkObject;
public override void OnNetworkSpawn()
{
base.OnNetworkSpawn();
grabInteractable = GetComponent();
networkObject= GetComponent();
clientID= NetworkManager.Singleton.LocalClientId;
if (grabInteractable != null)
{
grabInteractable.selectEntered.AddListener(OnGrabbed);
}
}
private void OnGrabbed(SelectEnterEventArgs args)
{
RequestOwnershipServerRpc(clientID);
}
[ServerRpc(RequireOwnership = false)]
private void RequestOwnershipServerRpc(ulong clientID)
{
networkObject.ChangeOwnership(clientID);
}
}
[/code]
How about using Oculus SDK (hands) instead XR.Interaction.Toolkit?
Our VR Multiplayer Template will be releasing later and will have examples on how to sync this. This template will setup all of Unity’s multiplayer services for you, including lobbies and spatialized voice chat, It even supports hand tracking replication, all over OpenXR!
I also have issues reflecting an object’s position across Netcode-connected clients after it’s been grabbed via XRGrabInteractable. I can move them easily, otherwise, but once the XRRig gets involved, an object’s network position behaves weirdly - sort of floats around - forgive me, I’ve tried soooooo many things (including just about every option available in the NetworkObect and XRGrabInteractable, and various different things in code), so it’s hard to recreate here. However, here’s the current iteration of my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Netcode;
using UnityEngine.XR.Interaction.Toolkit;
public class NetworkItem : NetworkBehaviour
{
private XRGrabInteractable m_GrabInteractable;
private Rigidbody m_RigidBody;
private NetworkObject m_NetObject;
private Vector3 m_Position;
private Quaternion m_Rotation;
private Vector3 m_Scale;
private Vector3 m_Velocity;
private bool m_NeedsMoving = false;
private ulong m_ClientID;
//private const double m_IdleTime = 1000; //milliseconds
//private double m_TimeMove = 0;
public override void OnNetworkSpawn()
{
m_ClientID = NetworkManager.Singleton.LocalClientId;
m_NetObject = gameObject.GetComponent<NetworkObject>();
m_RigidBody = gameObject.GetComponent<Rigidbody>();
m_GrabInteractable = gameObject.GetComponent<XRGrabInteractable>();
if (m_GrabInteractable != null)
{
//Debug.Log("Grabbing");
m_GrabInteractable.selectEntered.AddListener(OnGrabbed);
m_GrabInteractable.selectExited.AddListener(OnLetGo);
} else {
Debug.Log("Cannot Grab");
}
}
private void OnGrabbed(SelectEnterEventArgs args)
{
SendMoveToServerRpc(transform.position, transform.rotation, transform.localScale, m_RigidBody.velocity, m_ClientID);
}
private void OnLetGo(SelectExitEventArgs args)
{
//Debug.Log("Sending info from OnLetGo");
SendMoveToServerRpc(transform.position, transform.rotation, transform.localScale, m_RigidBody.velocity, m_ClientID);
}
void OnCollisionEnter(Collision collision)
{
//Debug.Log("Sending info from OnCollisionEnter");
SendMoveToServerRpc(transform.position, transform.rotation, transform.localScale, m_RigidBody.velocity, m_ClientID);
}
private void GenerateMove()
{
if( IsOwner && transform.hasChanged )
{
//Debug.Log("Sending move info from server");
SendMoveToServerRpc(transform.position, transform.rotation, transform.localScale, m_RigidBody.velocity, m_ClientID);
transform.hasChanged = false;
}
}
private void ClientMove()
{
if ( !IsOwner && m_NeedsMoving)
{
//m_RigidBody.velocity = m_Velocity;
//Debug.Log("Client move on client" + m_Position.ToString() + m_Rotation.ToString());
m_RigidBody.Move(m_Position, m_Rotation);
m_NeedsMoving = false;
// transform.localScale = m_Scale;
}
}
private void FixedUpdate()
{
GenerateMove();
ClientMove();
}
[ServerRpc(RequireOwnership = false)]
private void SendMoveToServerRpc(Vector3 position, Quaternion rotation, Vector3 scale, Vector3 velocity, ulong clientID)
{
// var networkTime = NetworkManager.Singleton.ServerTime.TimeAsFloat;
Debug.Log("Client move from server" + position.ToString() + rotation.ToString() + scale.ToString());
m_NetObject.ChangeOwnership(clientID);
SendMoveToClientRpc(position, rotation, scale, velocity);
}
[ClientRpc]
private void SendMoveToClientRpc(Vector3 position, Quaternion rotation, Vector3 scale, Vector3 velocity)
{
m_Position = position;
m_Rotation = rotation;
m_Scale = scale;
m_Velocity = velocity;
m_NeedsMoving = true;
}
}
I’m sure there’s something I’m misunderstanding, but I’m kinda running out of ideas/the will to live, so any help would be appreciated (including a decent set of examples).
I’d recommend using a NetworkTransform (or more ideally a ClientNetworkTransform). Let the owner move the object and let all clients just view that movement.
I’ve tried both NetworkTransform and ClientNetworkTransform, and they didn’t seem to work. However, it was in the midst of an admittedly scattergun approach where I was trying everything and anything, and I may have missed something. So I will try again and attempt to be a little more systematic. Meanwhile, are there any working examples of ClientNetworkTransform and XRRigs I could reference?
What does your NetworkObject component look like on the interactables you are trying to sync across the network?
For Instance, make sure Auto Object Parent Sync is set to False.
Please forgive my slow reply - I’ve been busy with other projects and only now have I had a chance to try your suggestions…
…and they’ve worked! Thanks!
Here’s how:
NetworkItem
script just requests ownership of a grabbed object (so it’s been simplified tons)Auto Object Parent Sync
…boom!
Excellent. Glad you got it working. When it releases, the VR Multiplayer Template will have a bunch of examples on different types of XRI interactions over the network as well.
Just following up here, the VR Multiplayer Template has released!