I'm making multiplayer game nad in code where I'm making pick up and drop item. I'm having error that player.transform.childCount is returning 3 right after i add children another children under player.
I try add some debug.log and output is in client side "3: 1" and "3" and on host side is output "4: 0" so on host side is everiting alright but on client side it's returning wrong value
thanks for any answers
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");
}
client's side:
host's side:
Like @Risord mentioned in the comment, RPC calls are not really method calls. The network libraries make it look like an ordinary method but it's not. When you call your AddItemToHandServerRpc
method on the client, you actually send out a network message to the server. This takes time. Once the server received that message, the actual method will be invoked on the server. The server will instantiate the object on his side and adds it as a child to the player object.
However here additional hidden magic is happening. A NetworkObject
when it's instantiated automatically sends out RPC calls to all clients to make them also create the analogue object on their side. Also the TrySetParent
call will also send out another RPC to all clients to tell them about the parent change. Only once those RPCs from the server have arrived and processed by the client(s) will the actual object be a child of the player.
Your code on the client side does not wait for potential answers from the server. Once the RPC is queued up, your AddItem
method will continue after the RPC call. At this point no object has been created on the client since the server most likely hasn't even received the RPC yet.
If you have important code that requires a certain sequence of events to happen, you could have the server send out a custom RPC to the clients to continue whatever you want to do after the object has been created.
It's probably possible to create some async construct that calls an RPC and waits for your return / acknowledge RPC in order to continue on the client. But as far as i know there's nothing build into Netcode at the moment.
Maybe you could go with some general "response" RPC and use some kind of "ticket number" to identify the event that finished. That way it would be possible to create a general purpose "callback" RPC that the server can call to finish / acknowledge the completion of the task and maybe have it return some generic return value as well. As explained here you can use ClientRpcParams
to send a ClientRPC
to only one client.