Hello,
right now I am trying to create a syncronized event using a script from the documentation. It is the example 2 from this document
Herethe code:
using System.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Assertions;
public class SyncedEventExample : NetworkBehaviour
{
public GameObject ParticleEffect;
// Called by the client to create a synced particle event at its own position.
public void ClientCreateSyncedEffect()
{
Assert.IsTrue(IsOwner);
var time = NetworkManager.LocalTime.Time;
CreateSyncedEffectServerRpc(time);
StartCoroutine(WaitAndSpawnSyncedEffect(0)); // Create the effect immediately locally.
}
private IEnumerator WaitAndSpawnSyncedEffect(float timeToWait)
{
// Note sometimes the timeToWait will be negative on the server or the receiving clients if a message got delayed by the network for a long time. This usually happens only in rare cases. Custom logic could be implemented to deal with that scenario.
if (timeToWait > 0)
{
yield return new WaitForSeconds(timeToWait);
}
Instantiate(ParticleEffect, transform.position, Quaternion.identity);
}
[ServerRpc]
private void CreateSyncedEffectServerRpc(double time)
{
CreateSyncedEffectClientRpc(time); // Call a client RPC to also create the effect on each client.
var timeToWait = time - NetworkManager.ServerTime.Time;
StartCoroutine(WaitAndSpawnSyncedEffect((float)timeToWait)); // Create the effect on the server but wait for the right time.
}
[ClientRpc]
private void CreateSyncedEffectClientRpc(double time)
{
// The owner already created the effect so skip them.
if (IsOwner == false)
{
var timeToWait = time - NetworkManager.ServerTime.Time;
StartCoroutine(WaitAndSpawnSyncedEffect((float)timeToWait)); // Create the effect on the client but wait for the right time.
}
}
}
The problem is, if I run the code on the client, then nothing happens. If I run the code on the host, I use p2p, then the event happens 2x on the host and 1x on the client.
Maybe the comments in the code are also misleading. What am I doing wrong?
Hi @Nivagia , could it be that this script is on an object on which you don’t have ownership? By default, ServerRpcs require to be called from a NetworkObject that is owned by the client.
So you’ll get an error when trying to call this rpc as a client that is not the host.
Adding (RequireOwnership = false) parameter to your [ServerRPC] and [ClientRPC] attributes should do the trick
I figuered, that the example code on the unity documentation must be wrong.
This is my code now:
using System.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.Events;
public class SyncedGameStart : NetworkBehaviour
{
public UnityEvent GameStart;
// Called by the client to create a synced event at its own position.
public void ClientCreateSyncedEvent()
{
if (IsHost)
{
return;
}
var time = NetworkManager.LocalTime.Time;
CreateSyncedEventServerRpc(time);
StartCoroutine(WaitAndSpawnSyncedEvent(0));
// Create the event immediately locally.
Debug.Log("Client created synced event");
}
private IEnumerator WaitAndSpawnSyncedEvent(float timeToWait)
{
// Note sometimes the timeToWait will be negative on the server or the receiving clients if a message got delayed by the network for a long time. This usually happens only in rare cases. Custom logic could be implemented to deal with that scenario.
Debug.Log("Time to wait is: " + timeToWait);
if (timeToWait > 0)
{
yield return new WaitForSeconds(timeToWait);
}
Debug.Log("Invoke GameStartNow: " + System.DateTime.Now.ToString() +":"+ System.DateTime.Now.Millisecond.ToString());
GameStart?.Invoke();
}
[ServerRpc(RequireOwnership = false)]
private void CreateSyncedEventServerRpc(double time)
{
CreateSyncedEventClientRpc(time);
// Call a client RPC to also create the event on each client.
var timeToWait = time - NetworkManager.ServerTime.Time;
StartCoroutine(WaitAndSpawnSyncedEvent((float)timeToWait)); // Create the event on the server but wait for the right time.
}
[ClientRpc]
private void CreateSyncedEventClientRpc(double time)
{
// The owner already created the event so skip them.
if (IsHost)
{
return;
}
var timeToWait = time - NetworkManager.ServerTime.Time;
StartCoroutine(WaitAndSpawnSyncedEvent((float)timeToWait)); // Create the event on the client but wait for the right time.
}
}
I now have the problem, that when I add a little delay to the network, the timeToWait is always a negative number and the event is triggered right away.