Trying to parent network object with net. transform under another net. object

I’m trying to create inv system i already have like inventory ect. but I’m having problem with setting item to player hand I tried setting item to correct possition by another script by using:

transform.position = hand.position;
transform.rotation = hand.rotation;

in update function that works well on host side but on client side it doesn’t work at all. The “item” walks behind the client player like some type of pet from roblox and it doesn’t even go to correct possition it’s on ground. I also tried to add insted of normal net. transform, anticipated net. transform. That works well in hand with settitg it to right possition, but when player on client side tries to throw away the item it’s got stuck in the player, but on the host side it was trown by client normaly, idk why. So i decided to parent the item under the hand gameObject, but that sets the item to possion 0, 0, 0 and don’t parent it under hand without any error.

Can sombody help me please???

Hiearchy:

player
image
image
image

item


(Network Transform is set to default settings)

scripts:

using System.Collections;
using System.Collections.Generic;
using Unity.Netcode;
using UnityEngine;

public class SetPossionToHand : NetworkBehaviour
{
    // Start is called before the first frame update

    Transform hand = null;
    public override void OnNetworkSpawn()
    {
        base.OnNetworkSpawn();

        if (Camera.main == null)
        {
            Debug.LogError("Main camera not found!");
            return;
        }

        if (hand == null)
        {
            hand = Camera.main.transform.GetChild(0);
        }
            

    }

    // Update is called once per frame
    void Update()
    {
        transform.position = hand.position;
        transform.rotation = hand.rotation;
    }
}
using Unity.Netcode;
using Unity.Netcode.Components;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class HandSlot : NetworkBehaviour, IDropHandler
{
    #region Sigleton

    public static HandSlot instance;

    private void Awake()
    {
        instance = this;
    }
    #endregion

    public Image icon;
    GameObject player;
    [SerializeField] private ListOfPrefabsToSpawn list; 

    [HideInInspector] public ItemData itemData = null;
    private int addItemAction = 0;

    public void AddItem(ItemData itemData)
    {
        if(itemData == null)
            return;

        this.itemData = itemData;

        icon.sprite = itemData.icon;
        icon.enabled = true;

        if (player == null)
            player = NetworkManager.Singleton.SpawnManager.GetLocalPlayerObject().gameObject;

        if (player != null)
        {
            NetworkObject networkObject = player.GetComponent<NetworkObject>();

            if (networkObject != null)
            {
                AddItemToHandServerRpc(itemData.index, networkObject.NetworkObjectId, NetworkManager.Singleton.LocalClientId);
            }
            else
                Debug.Log("none");
        }
        else
        {
            Debug.LogError("Hand object is not properly initialized or is disabled.");
        }
    }

    public void ClearSlot(bool delete)
    {
        itemData = null;

        icon.sprite = null;
        icon.enabled = false;

        if (player.transform.childCount == 4 && delete) // NullReferenceException: Object reference not set to an instance of an object
        {
            if (player == null)
                player = NetworkManager.Singleton.SpawnManager.GetLocalPlayerObject().gameObject;
            GameObject item = player.transform.GetChild(player.transform.childCount - 1).gameObject;
            DespawnObjectServerRpc(item.GetComponent<NetworkObject>().NetworkObjectId);
        }
    }

    [ServerRpc]
    void AddItemToHandServerRpc(int index, ulong handId, ulong clientID)
    {
        GameObject item = list.prefabs[index];
        var instance = Instantiate(item);
        var instanceNetworkObject = instance.GetComponent<NetworkObject>();

        Transform player = NetworkManager.Singleton.SpawnManager.SpawnedObjects[handId].gameObject.transform;
        Transform hand = player.Find("CameraHolder/Main Camera/Hand");

        instanceNetworkObject.SpawnWithOwnership(handId);

        Rigidbody rigi = instanceNetworkObject.GetComponent<Rigidbody>();
        rigi.isKinematic = true;

        instanceNetworkObject.TrySetParent(hand, false);
        instanceNetworkObject.transform.localScale = new Vector3(.01f, .01f, .01f);


        ClientRpcParams clientRpcParams = new ClientRpcParams
        {
            Send = new ClientRpcSendParams
            {
                TargetClientIds = new ulong[] { clientID }
            }
        };

        //ClientRpc(addItemAction, clientRpcParams);
    }

    [ClientRpc]
    void ClientRpc(int action, ClientRpcParams clientRpcParams = default)
    {
        if (action == addItemAction) 
        {
            if (player.transform.childCount == 4)
            {
                GameObject item = player.transform.GetChild(player.transform.childCount - 1).gameObject;
                item.GetComponent<SetPossionToHand>().enabled = true;
            }
            else
            {
                Debug.LogWarning("ClientRpc addItem error: incorect num of childrens");
            }
        }
    }

    public void OnDrop(PointerEventData eventData)
    {
        if (itemData != null) { return; }

        GameObject icon = eventData.pointerDrag;

        ItemDrag itemDrag = icon.GetComponent<ItemDrag>();

        if (itemDrag != null)
        {
            AddItem(itemDrag.slot.itemData);
            itemDrag.slot.ClearSlot();
        }
    }

    [ServerRpc]
    private void DespawnObjectServerRpc(ulong itemNetworkObjectId)
    {
        NetworkObject networkObject = NetworkManager.SpawnManager.SpawnedObjects[itemNetworkObjectId];
        networkObject.Despawn();
    }
}

If you need some thing else just comment.

Thanks for any solutions and your time.

This may be due to:

  • the player’s Update running after the item’s - use LateUpdate to sync positions
  • the player may have Interpolate checked - but you are setting the position to the actual network position, not the object’s current interpolated position
  • you are setting the local position to the item, but you need to use the hand.position + item.localPosition

One or several of these need fixing, and then it’s solved.

Parenting network objects is just one big headache I wouldn’t dare to get into.

1 Like

OK, so you telling that is better to set the items possition by the script SetPossionToHand and just fix one of these possible errors?? If so i look if i havent one of these errors and let you now if it helps

1 Like

Thanks it’s now working, when I put the items possition to lateUpdate (player movement is in fixedUpdate) and in player’s “client network transform” I check “interpolate” it’s working fine. When I uncheck interpolate item is gliding to the correct possition :smiley:

1 Like

This is a common issue, I went over the problem and solution in a previous thread: Player hierarchical networkobjects

Essentially, there is no valid ownership/authority for an item that’s being held by a player. No matter who is responsible for the position, everyone else will see the item in a slightly different position. This causes the issue where the item “walks behind the client player”, whoever is responsible for the item’s position is going to see it in the correct place but for everyone else it won’t match the animation. It’s impossible to sync up the animations between players precisely enough for this not to be a problem.

The solution is that you disable the network syncing of the position of an object while it’s being held by someone. Every client must know what bone on what player the item is supposed to go into and moves it there themselves, either by setting the position and rotation every frame as you did above or using a position constraint.

Basically when an object is picked up you have everyone disable its NetworkTransform and switch on that script that sets it position and rotation every frame, and don’t even reparent the object. When the item is dropped, everyone’s client re-enables the NetworkTransform and disables the position script.

1 Like