Предметы работают только для хоста, но не для клиента

В моей многопользовательской игре система предметов работает идеально для хоста. Однако у клиента возникают проблемы. В частности: Предметы, которые подбирает клиент, добавляются в инвентарь, но не отображаются у него в руке. Клиент не может выбрасывать предметы. Клиент не видит предметы, которые выбросил хост. Я реализовал систему инвентаря с использованием Unity Netcode, но кажется, что синхронизация для клиента работает некорректно. Что может быть причиной этих проблем, и как я могу обеспечить корректную синхронизацию предметов при их подборе и выбрасывании между хостом и клиентами? Буду признателен за любые советы или предложения!

PlayerInventory script

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

public class PlayerInventory : NetworkBehaviour
{
    public List<GameObject> allItems;
    public List<GameObject> collectedItems = new List<GameObject>();
    private int currentItemIndex = -1;
    private const int maxInventorySlots = 3;
    public Transform dropPosition;

    public override void OnNetworkSpawn()
    {
        foreach (GameObject item in allItems)
        {
            item.SetActive(false);
        }
    }

    [ServerRpc(RequireOwnership = false)]
    public void AddItemToInventoryServerRpc(string itemName, ulong networkObjectId, ServerRpcParams rpcParams = default)
    {
        Debug.Log($"Попытка добавить предмет {itemName} в инвентарь на сервере.");
        if (collectedItems.Count < maxInventorySlots)
        {
            GameObject itemToActivate = allItems.Find(item => item.name == itemName);
            if (itemToActivate != null)
            {
                collectedItems.Add(itemToActivate);
                HideItemForAllClientsClientRpc(itemName);
                ActivateItemClientRpc(collectedItems.Count - 1);
                SyncItemInHandClientRpc(itemName, true);
                RemoveItemFromWorldClientRpc(networkObjectId);
                Debug.Log($"Предмет {itemName} успешно добавлен в инвентарь.");
            }
            else
            {
                Debug.LogError($"Предмет {itemName} не найден среди скрытых предметов.");
            }
        }
        else
        {
            Debug.Log("Инвентарь полон!");
        }
    }

    [ClientRpc]
    void RemoveItemFromWorldClientRpc(ulong networkObjectId)
    {
        if (NetworkManager.Singleton.SpawnManager.SpawnedObjects.TryGetValue(networkObjectId, out NetworkObject networkObject))
        {
            GameObject itemObject = networkObject.gameObject;
            itemObject.SetActive(false);
            Destroy(itemObject);
        }
    }

    [ClientRpc]
    void HideItemForAllClientsClientRpc(string itemName)
    {
        GameObject itemToDeactivate = allItems.Find(item => item.name == itemName);
        if (itemToDeactivate != null)
        {
            itemToDeactivate.SetActive(false);
        }
    }

    [ClientRpc]
    void ActivateItemClientRpc(int index)
    {
        if (index >= 0 && index < collectedItems.Count)
        {
            if (currentItemIndex != -1)
            {
                collectedItems[currentItemIndex].SetActive(false);
            }
            currentItemIndex = index;
            collectedItems[currentItemIndex].SetActive(true);
            Debug.Log($"Активирован предмет: {collectedItems[currentItemIndex].name}");
        }
    }

    [ServerRpc(RequireOwnership = false)]
    public void DropCurrentItemServerRpc(ServerRpcParams rpcParams = default)
    {
        if (currentItemIndex >= 0 && currentItemIndex < collectedItems.Count)
        {
            GameObject currentItem = collectedItems[currentItemIndex];
            Debug.Log($"Выбрасывание предмета: {currentItem.name}");
            GameObject droppedItem = Instantiate(currentItem, dropPosition.position, Quaternion.identity);
            droppedItem.SetActive(true);

            var networkObject = droppedItem.GetComponent<NetworkObject>();
            if (networkObject != null && !networkObject.IsSpawned)
            {
                networkObject.Spawn(true);
            }

            Rigidbody rb = droppedItem.GetComponent<Rigidbody>();
            if (rb == null)
            {
                rb = droppedItem.AddComponent<Rigidbody>();
                rb.collisionDetectionMode = CollisionDetectionMode.Continuous;
                rb.mass = 1f;
            }

            rb.AddForce(dropPosition.forward * 1.5f, ForceMode.Impulse);
            currentItem.SetActive(false);
            collectedItems.RemoveAt(currentItemIndex);
            if (collectedItems.Count > 0)
            {
                currentItemIndex = Mathf.Clamp(currentItemIndex - 1, 0, collectedItems.Count - 1);
                ActivateItemClientRpc(currentItemIndex);
            }
            else
            {
                currentItemIndex = -1;
                Debug.Log("Инвентарь пуст.");
            }

            SpawnDroppedItemClientRpc(droppedItem.name, droppedItem.transform.position, droppedItem.transform.rotation);
        }
        else
        {
            Debug.LogWarning("Не удалось выбросить предмет: текущий индекс не валиден.");
        }
    }

    [ClientRpc]
    void SpawnDroppedItemClientRpc(string itemName, Vector3 position, Quaternion rotation)
    {
        GameObject itemPrefab = allItems.Find(item => item.name == itemName);
        if (itemPrefab != null)
        {
            GameObject droppedItem = Instantiate(itemPrefab, position, rotation);
            droppedItem.SetActive(true);
            var networkObject = droppedItem.AddComponent<NetworkObject>();
            networkObject.Spawn(true);
        }
    }

    void Update()
    {
        if (!IsOwner || collectedItems.Count == 0) return;

        if (Input.GetAxis("Mouse ScrollWheel") != 0f)
        {
            int direction = Input.GetAxis("Mouse ScrollWheel") > 0f ? 1 : -1;
            SwitchItem(direction);
        }

        if (Input.GetKeyDown(KeyCode.G))
        {
            DropCurrentItemServerRpc();
        }
    }

    private void SwitchItem(int direction)
    {
        if (collectedItems.Count == 0) return;

        if (currentItemIndex != -1)
        {
            collectedItems[currentItemIndex].SetActive(false);
        }

        currentItemIndex += direction;
        if (currentItemIndex >= collectedItems.Count) currentItemIndex = 0;
        if (currentItemIndex < 0) currentItemIndex = collectedItems.Count - 1;

        ActivateItemClientRpc(currentItemIndex);
    }

    public bool HasItemInHand(string itemName)
    {
        return currentItemIndex != -1 && collectedItems[currentItemIndex].name == itemName;
    }

    [ServerRpc(RequireOwnership = false)]
    public void RemoveItemFromHandServerRpc(string itemName, ServerRpcParams rpcParams = default)
    {
        if (HasItemInHand(itemName))
        {
            Debug.Log($"Удаление предмета {itemName} из рук.");
            collectedItems[currentItemIndex].SetActive(false);
            collectedItems.RemoveAt(currentItemIndex);
            currentItemIndex = -1;
        }
    }

    [ClientRpc]
    void SyncItemInHandClientRpc(string itemName, bool isActive)
    {
        GameObject itemInHand = collectedItems.Find(item => item.name == itemName);
        if (itemInHand != null)
        {
            itemInHand.SetActive(isActive);
        }
    }
}

PlayerInteract script

using UnityEngine;
using Unity.Netcode;
using TMPro;

public class PlayerInteract : NetworkBehaviour
{
    public float interactionRange = 3f;
    public Camera playerCamera;
    public GameObject interactUI;
    private TMP_Text interactText;
    private Item itemInFocus;
    private PlayerInventory playerInventory;

    private void Start()
    {
        if (interactUI != null)
        {
            interactText = interactUI.GetComponent<TMP_Text>();
            if (interactText == null)
            {
                Debug.LogError("TMP_Text компонент не найден на interactUI объекте!");
            }
        }
        else
        {
            Debug.LogError("interactUI объект не присвоен в инспекторе!");
        }

        playerInventory = GetComponent<PlayerInventory>();
    }

    private void Update()
    {
        if (!IsOwner) return;

        Ray ray = playerCamera.ScreenPointToRay(new Vector3(Screen.width / 2, Screen.height / 2));
        RaycastHit hit;

        if (Physics.Raycast(ray, out hit, interactionRange))
        {
            Item item = hit.collider.GetComponent<Item>();
            if (item != null)
            {
                itemInFocus = item;
                ShowItemInfo(item);
                if (Input.GetKeyDown(KeyCode.E))
                {
                    Debug.Log("Нажата клавиша E для подбора предмета: " + item.itemName);
                    PickupItemServerRpc(item.NetworkObjectId);
                }
            }
            else
            {
                HideItemInfo();
            }
        }
        else
        {
            HideItemInfo();
        }
    }

    void ShowItemInfo(Item item)
    {
        if (interactText != null)
        {
            interactUI.SetActive(true);
            interactText.text = $"Нажмите E, чтобы подобрать {item.itemName}";
        }
    }

    void HideItemInfo()
    {
        if (interactUI != null)
        {
            interactUI.SetActive(false);
        }
    }

    [ServerRpc]
    void PickupItemServerRpc(ulong itemId)
    {
        Debug.Log("ServerRpc вызван для предмета с ID: " + itemId);
        if (NetworkManager.Singleton.SpawnManager.SpawnedObjects.TryGetValue(itemId, out NetworkObject networkObject))
        {
            Item item = networkObject.GetComponent<Item>();
            if (item != null)
            {
                playerInventory.AddItemToInventoryServerRpc(item.itemName, itemId);
                Debug.Log("Предмет успешно добавлен в инвентарь и удален из мира.");
            }
            else
            {
                Debug.LogError("Item не найден на объекте NetworkObject!");
            }
        }
        else
        {
            Debug.LogError("NetworkObject с данным itemId не найден!");
        }
    }
}

Item script

using UnityEngine;
using Unity.Netcode;

public class Item : NetworkBehaviour
{
    public string itemName;

    public override void OnNetworkSpawn()
    {
        if (IsServer)
        {
            //
        }

        
    }

    
}

Я потратил значительное количество времени, пытаясь устранить эту проблему, но так и не смог найти решение. Я неоднократно пересматривал свой код и сетевую настройку, но проблема по-прежнему сохраняется.


Ответы (0 шт):