Проблемы с синхронизацией инвентаря и состоянием объекта в сети UnityC#

Место общения программистов C#
Ответить
Anonymous
 Проблемы с синхронизацией инвентаря и состоянием объекта в сети Unity

Сообщение Anonymous »

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

Код: Выделить всё

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

public class PlayerInventory : NetworkBehaviour
{
public List allItems;
public List collectedItems = new List();
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();
if (networkObject != null && !networkObject.IsSpawned)
{
networkObject.Spawn(true);
}

Rigidbody rb = droppedItem.GetComponent();
if (rb == null)
{
rb = droppedItem.AddComponent();
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.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

Код: Выделить всё

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();
if (interactText == null)
{
Debug.LogError("TMP_Text компонент не найден на interactUI объекте!");
}
}
else
{
Debug.LogError("interactUI объект не присвоен в инспекторе!");
}

playerInventory = GetComponent();
}

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();
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();
if (item != null)
{
playerInventory.AddItemToInventoryServerRpc(item.itemName, itemId);
Debug.Log("Предмет успешно добавлен в инвентарь и удален из мира.");
}
else
{
Debug.LogError("Item не найден на объекте NetworkObject!");
}
}
else
{
Debug.LogError("NetworkObject с данным itemId не найден!");
}
}
}
Скрипт элемента

Код: Выделить всё

using UnityEngine;
using Unity.Netcode;

public class Item : NetworkBehaviour
{
public string itemName;

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

}

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


Подробнее здесь: https://stackoverflow.com/questions/789 ... ty-network
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»