Estou fazendo um jogo multijogador e no código onde estou fazendo itens de pegar e largar. Estou tendo um erro que player.transform.childCount está retornando 3 logo depois que adiciono filhos e outros filhos abaixo do jogador.
Eu tento adicionar algum debug.log e a saída está no lado do cliente "3: 1" e "3" e no lado do host está a saída "4: 0", então no lado do host está tudo bem, mas no lado do cliente está retornando o valor errado
Obrigado por qualquer resposta
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)
{
Debug.Log(player.transform.childCount + ": 1");
AddItemToHandServerRpc(itemData.index, networkObject.NetworkObjectId);
Debug.Log(player.transform.childCount);
if (player.transform.childCount == 4)
{
GameObject item = player.transform.GetChild(player.transform.childCount - 1).gameObject;
item.GetComponent<SetPossionToHand>().enabled = true;
item.transform.localScale = new Vector3(.01f, .01f, .01f);
}
else
{
Debug.Log("fsjfhshuyferh");
}
}
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)
{
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)
{
GameObject item = list.prefabs[index];
var instance = Instantiate(item);
var instanceNetworkObject = instance.GetComponent<NetworkObject>();
Transform player = NetworkManager.Singleton.SpawnManager.SpawnedObjects[handId].gameObject.transform;
instanceNetworkObject.SpawnWithOwnership(handId);
instanceNetworkObject.TrySetParent(player, false);
Debug.Log(player.transform.childCount + ": 0");
}
lado do cliente:
lado do anfitrião:
Como @Risord mencionou no comentário, chamadas RPC não são realmente chamadas de método. As bibliotecas de rede fazem com que pareça um método comum, mas não é. Quando você chama seu
AddItemToHandServerRpc
método no cliente, você na verdade envia uma mensagem de rede para o servidor. Isso leva tempo. Uma vez que o servidor recebeu essa mensagem, o método real será invocado no servidor. O servidor instanciará o objeto do seu lado e o adicionará como um filho ao objeto player.No entanto, aqui uma mágica oculta adicional está acontecendo.
NetworkObject
Quando é instanciado, ele envia automaticamente chamadas RPC para todos os clientes para fazê-los também criar o objeto analógico do seu lado. Além disso, aTrySetParent
chamada também enviará outro RPC para todos os clientes para informá-los sobre a mudança do pai. Somente quando esses RPCs do servidor tiverem chegado e sido processados pelo(s) cliente(s) o objeto real será um filho do jogador.Seu código no lado do cliente não espera por respostas potenciais do servidor. Uma vez que o RPC esteja na fila, seu
AddItem
método continuará após a chamada RPC. Neste ponto, nenhum objeto foi criado no cliente, já que o servidor provavelmente nem recebeu o RPC ainda.Se você tiver um código importante que exija uma determinada sequência de eventos, você pode fazer com que o servidor envie um RPC personalizado aos clientes para continuar o que você quiser fazer depois que o objeto for criado.
Provavelmente é possível criar alguma construção assíncrona que chame um RPC e aguarde seu retorno/reconhecimento de RPC para continuar no cliente. Mas, até onde eu sei, não há nada construído no Netcode no momento.
Talvez você possa usar algum RPC de "resposta" geral e usar algum tipo de "número de tíquete" para identificar o evento que terminou. Dessa forma, seria possível criar um RPC de "retorno de chamada" de propósito geral que o servidor pode chamar para terminar/reconhecer a conclusão da tarefa e talvez fazer com que ele retorne algum valor de retorno genérico também. Conforme explicado aqui, você pode usar
ClientRpcParams
para enviar umClientRPC
para apenas um cliente.