FirstGearGames / FishNet

FishNet: Unity Networking Evolved.
Other
1.35k stars 142 forks source link

Some nested NetworkObjects disable at start #796

Open f2069 opened 3 days ago

f2069 commented 3 days ago

General Unity version: 2021.3.18f Fish-Networking version: 4.5.1R Pro Discord link: https://discord.com/channels/424284635074134018/1293374787032191008 Related: #791

Description When the game scene starts, the server spawned a prefab tower. Inside the tower there are 4 holders that rotate. Each holder instantiates a cube into an internal container on the server. If the client connects to the server after the game scene has been loaded, there are no nested cubes on the client, only one holder is active and all nested containers are inactive. I've also tried turning on ‘Synchronize Parent’ on the cube, but it didn't work.

Objects:

Replication

  1. Open the "NestedSpawn.Menu" scene in both windows;
  2. Start the Server and Client in one window;
  3. Press the "Load Scene" button on Server and wait until the "NestedSpawn.Game" scene was loaded;
  4. In the second window (clone) start client;
  5. When the client loads the game scene, there will be no nested cubes in containers in the tower and some holders will be disabled.

Expected behavior When the client connects to the server scene - all nested network objects are enabled and spawned as it does on the server.

Screenshots Now:

Expected:

Video: https://youtu.be/XxR9sYFpESY Package: NestedSpawn.Report.151024.unitypackage.zip

Spawn tower:

public override void OnStartServer()
{
    base.OnStartServer();

    var tower = Instantiate(towerPrefab, Vector3.zero, Quaternion.identity);
    Spawn(tower);
}

Spawn nested cube:

public class TowerStoneHolder : NetworkBehaviour
{
    public override void OnStartClient()
    {
        base.OnStartClient();

        if (IsServerStarted)
        {
            var nested = Instantiate(nestedPrefab, stoneContainer.transform, false);

            nested.SetParent(stoneContainer);
            Spawn(nested);
        }
    }
}

If the client connects to the scene together with the server, everything works correctly. Also in version 4.4.7 and earlier - everything worked fine.

FREEZX commented 5 hours ago

Had a similar issue myself, doubly-nested NetObjects did not get enabled on clientHost, the issue was that the SortRootAndNestedByInitializeOrder function in ServerObjects.Observers.cs did not include double-nested objects. Try replacing it with this and see if it fixes your issue:

/// <summary>
/// Sorts a collection of NetworkObjects root and nested by initialize order.
/// Collection returned is a new cache and should be disposed of properly.
/// </summary>
internal List<NetworkObject> SortRootAndNestedByInitializeOrder(List<NetworkObject> nobs)
{
    List<NetworkObject> sortedRootCache = CollectionCaches<NetworkObject>.RetrieveList();

    //First order root objects.
    foreach (NetworkObject item in nobs)
    {
        if (item.IsNested)
            continue;

        sortedRootCache.AddOrdered(item);
    }

    /* After all root are ordered check
     * their nested. Order nested in segments
     * of each root then insert after the root.
     * This must be performed after all roots are ordered. */
    List<NetworkObject> sortedRootAndNestedCache = CollectionCaches<NetworkObject>.RetrieveList();
    List<NetworkObject> sortedNestedCache = CollectionCaches<NetworkObject>.RetrieveList();
    List<NetworkObject> nestedToIterate = CollectionCaches<NetworkObject>.RetrieveList();

    foreach (NetworkObject item in sortedRootCache)
    {
        nestedToIterate.AddRange(item.InitializedNestedNetworkObjects);

        while(nestedToIterate.Count > 0) {
            var iteratingNetObj = nestedToIterate[0];
            sortedNestedCache.AddOrdered(iteratingNetObj);
            sortedNestedCache.Add(iteratingNetObj);
            nestedToIterate.RemoveAt(0);
            nestedToIterate.InsertRange(0, iteratingNetObj.InitializedNestedNetworkObjects);
        }

        /* Once all nested are sorted then can be added to the
         * sorted root and nested cache. */
        sortedRootAndNestedCache.Add(item);
        sortedRootAndNestedCache.AddRange(sortedNestedCache);

        //Reset cache.
        nestedToIterate.Clear();
        sortedNestedCache.Clear();
    }

    //Store temp caches.
    CollectionCaches<NetworkObject>.Store(sortedRootCache);
    CollectionCaches<NetworkObject>.Store(sortedNestedCache);

    return sortedRootAndNestedCache;
}