The ghost collection contains a ghost which does not have a valid prefab on the client

in my case server load all scene contain ghost prefab, client conenct to server ( add NetworkStreamInGame) but not load any scene contain ghost prefab. i only load ghost prefab scene on client when needed.

This is going to be tricky to the it working, due the way it currently work.

Little explanation:

The server send to the client as part of the initial snapshot(s) the list of all loaded prefab he have. The list is not sorted or order in a specific way, but it is pretty much populated based on ghost prefab entity order in the chunks. And the depend on when scenes are loaded etc etc.

The client receives that list, and reply to the server (inside the command stream) the number of loaded ghosts from the beginning of the list.

The server will then only stream to the client the ghost for which he know he have acked he loaded them.

If the client wants to load the prefabs at specific point in time, it must inform the GhostCollectionSystem that the missing prefab is going to be loaded at a later moment.

For that you can use the GhostCollectionPrefab.LoadActive flag. That would remove that exception, because now the system know it should not validate that the prefab is present.

For example

// The ghost collection prefab is populated with data received from server and contains the hash for all
// the prefab loaded by server. The client will associated the loaded prefab and verify the hash.
// Prefab entries are never removed.
var ghostCollectionPrefabs = SystemAPI.GetSingletonBuffer<GhostCollectionPrefab>();
for (int i = 0; i < ghostCollectionPrefabs.Length; ++i)
{
    ref var prefab = ref ghostCollectionPrefabs.ElementAt(i);   
    //If the ghost prefab entity is not set and not ghost for this type is present in the world (yet)
    //we need to mark the prefab as loading.
    //We should also do that only if the serializer for this prefab hasn't been initialized yet.
    if (prefab.GhostPrefab == Entity.Null)
    {        
        //The ghost prefab need to be loaded by the client (or will be loaded at later point). This need to be marked with
        // the GhostCollection will forcibly disconnect the client and report an error.
        if (prefab.Loading == GhostCollectionPrefab.LoadingState.NotLoading)
        {
            //Set the prefab state to LoadingActive inform the GhostCollectionSystem that the application is actively loading or will load this resource.
            prefab.Loading = GhostCollectionPrefab.LoadingState.LoadingActive;
            //maybe you want to track these or add a timeout
        }
        else
        {
            //Until the prefab is loaded, the server will mark this ghost with GhostCollectionPrefab.LoadingState.LoadingNotActive.
            Assert.IsTrue(prefab.Loading == GhostCollectionPrefab.LoadingState.LoadingNotActive);
            prefab.Loading = GhostCollectionPrefab.LoadingState.LoadingActive;
            // maybe check for timeout or other logics
        }
    }
}

But there is a caveat: because the client only reply the Number of loaded prefabs (not an individual ack per prefab), loading scenes in “random” order on the client , generally speaking, does not work.

Example:
if the server say loaded A,B,C,D and client only load C,D, the client will report 0 prefab loaded (in that list order).

There are two way to make this work:

  • Load the scene in a way that respect the that list order. This way, progressively the server can send the necessary ghost. That impose many restriction. If you have a use case that load scenes “linearly” (i.e level section 1,2,3 .) it is possible to do it.
  • a little more flexible, is to move all the prefabs (and only them) on a specific shared subscene. Then this is loaded on both client and server (so they can act the what they load). But then, the level data (that will use the referenced prefabs, so no duplication in that sense) can be loaded at any time and order.
3 Likes

thanks, i ll go with option two create a share scene with all ghost prefab.