Closed TheCaveOfWonders closed 1 year ago
@TheCaveOfWonders Is there a way you could provide access to the project or could you create a culled down project that replicates the issue? It could be a timing issue or a bug with timing and Addressables... but I would need to be able to replicate the scenario on my end in order to determine what the core issue at hand is. If the addressable is being loaded from a remote location, then it could be as simple as not parenting the player row on the server side, have the player row on the client side send an RPC to the server notifying the addressable has loaded and spawned, and then having the server parent the player row using SetParent.
But really, I would need to debug it on my end to be able to determine if this is timing related or an actual bug (or both).
let me try to prepare a reproduceable sample, but just to clarify, am I doing something wrong with the way I'm parenting these run-time spawned network objects?
The addressables part might be a red herring here, on the server it waits for the prefab to be loaded and fully instantiated before it calls the network spawn on it, so for our purposes we can just as well assume we did not use addressables and simply instantiated the prefab.
As far as i know, NGO will not be using addressables when it spawns this network object on the client side.
Well, I think that anything marked as an addressable will be treated as an addressable on the client side. Consider this:
NetworkObject
's GlobalObjectIdHash
value.
Not saying this is happening, but it is one possible scenario that can happen with addressables under this particular scenario.
A way to isolate where the issue is happening would be to make a duplicate prefab that is not an addressable and use that prefab (as opposed to the addressable) as a test. When doing this I would recommend the following:
If the parenting works with a non-addressable prefab then it would be useful to see how long it takes to load and instantiate the addressable on the client side. If it happens to take longer than 1 second, then the above outlined scenario is most likely what is happening.
If the parenting does not work, then I would set your NetworkManager's Log Level to developer and repeat the test two more times and observe the console log output to see if you get any errors or warnings.
Let me know how it works out with a non-addressable prefab so I can determine the next best steps to take.
I tried using a prefab without Addressables, but still same issue on the client, except now I also see this error in the client's console.
[Netcode] NetworkPrefab hash was not found! In-Scene placed NetworkObject soft synchronization failure for Hash: 3433370220! 0x00007ff7911ac19d (Unity) StackWalker::GetCurrentCallstack 0x00007ff7911b1149 (Unity) StackWalker::ShowCallstack 0x00007ff79217b841 (Unity) GetStacktrace 0x00007ff7928371d2 (Unity) DebugStringToFile 0x00007ff790149886 (Unity) DebugLogHandler_CUSTOM_Internal_Log 0x00000206f101686a (Mono JIT Code) (wrapper managed-to-native) UnityEngine.DebugLogHandler:Internal_Log (UnityEngine.LogType,UnityEngine.LogOption,string,UnityEngine.Object) 0x00000206f10166db (Mono JIT Code) UnityEngine.DebugLogHandler:LogFormat (UnityEngine.LogType,UnityEngine.Object,string,object[]) 0x00000206f1015b5e (Mono JIT Code) UnityEngine.Logger:Log (UnityEngine.LogType,object) 0x00000206f10158ba (Mono JIT Code) UnityEngine.Debug:LogError (object) 0x00000206f10157c3 (Mono JIT Code) Unity.Netcode.NetworkLog:LogError (string) (at E:/New folder/MyProject/Library/PackageCache/com.unity.netcode.gameobjects@1.2.0/Runtime/Logging/NetworkLog.cs:34) 0x00000206f0ff841b (Mono JIT Code) Unity.Netcode.NetworkSpawnManager:CreateLocalNetworkObject (Unity.Netcode.NetworkObject/SceneObject) (at E:/New folder/MyProject/Library/PackageCache/com.unity.netcode.gameobjects@1.2.0/Runtime/Spawning/NetworkSpawnManager.cs:394) 0x00000206f0ff61fb (Mono JIT Code) Unity.Netcode.NetworkObject:AddSceneObject (Unity.Netcode.NetworkObject/SceneObject&,Unity.Netcode.FastBufferReader,Unity.Netcode.NetworkManager) (at E:/New folder/MyProject/Library/PackageCache/com.unity.netcode.gameobjects@1.2.0/Runtime/Core/NetworkObject.cs:1403) 0x00000206f0ff374b (Mono JIT Code) Unity.Netcode.SceneEventData:SynchronizeSceneNetworkObjects (Unity.Netcode.NetworkManager) (at E:/New folder/MyProject/Library/PackageCache/com.unity.netcode.gameobjects@1.2.0/Runtime/SceneManagement/SceneEventData.cs:877) 0x00000206f0f7defb (Mono JIT Code) Unity.Netcode.NetworkSceneManager:HandleClientSceneEvent (uint) (at E:/New folder/MyProject/Library/PackageCache/com.unity.netcode.gameobjects@1.2.0/Runtime/SceneManagement/NetworkSceneManager.cs:1781) 0x00000206f0fe5fd3 (Mono JIT Code) Unity.Netcode.NetworkSceneManager:ClientLoadedSynchronization (uint) (at E:/New folder/MyProject/Library/PackageCache/com.unity.netcode.gameobjects@1.2.0/Runtime/SceneManagement/NetworkSceneManager.cs:1747) 0x00000206f0fe4d7b (Mono JIT Code) Unity.Netcode.SceneEventProgress:<SetAsyncOperation>b__37_0 (UnityEngine.AsyncOperation) (at E:/New folder/MyProject/Library/PackageCache/com.unity.netcode.gameobjects@1.2.0/Runtime/SceneManagement/SceneEventProgress.cs:262) 0x00000206f0beae4c (Mono JIT Code) UnityEngine.AsyncOperation:InvokeCompletionEvent () 0x00000205acf2fac8 (Mono JIT Code) (wrapper runtime-invoke) object:runtime_invoke_void__this__ (object,intptr,intptr,intptr) 0x00007ffbe8960394 (mono-2.0-bdwgc) mono_jit_runtime_invoke (at C:/build/output/Unity-Technologies/mono/mono/mini/mini-runtime.c:3445) 0x00007ffbe889eb44 (mono-2.0-bdwgc) do_runtime_invoke (at C:/build/output/Unity-Technologies/mono/mono/metadata/object.c:3066) 0x00007ffbe889ecdc (mono-2.0-bdwgc) mono_runtime_invoke (at C:/build/output/Unity-Technologies/mono/mono/metadata/object.c:3113) 0x00007ff7910d4144 (Unity) scripting_method_invoke 0x00007ff7910b4aa4 (Unity) ScriptingInvocation::Invoke 0x00007ff790d4a936 (Unity) AsyncOperation::InvokeCoroutine 0x00007ff790da8ab1 (Unity) PreloadManager::UpdatePreloadingSingleStep 0x00007ff790da859d (Unity) PreloadManager::UpdatePreloading 0x00007ff790d78853 (Unity)
InitPlayerLoopCallbacks'::2'::EarlyUpdateUpdatePreloadingRegistrator::Forward 0x00007ff790d5feea (Unity) ExecutePlayerLoop 0x00007ff790d60073 (Unity) ExecutePlayerLoop 0x00007ff790d663d5 (Unity) PlayerLoop 0x00007ff791cee775 (Unity) PlayerLoopController::InternalUpdateScene 0x00007ff791cfb2cd (Unity) PlayerLoopController::UpdateSceneIfNeededFromMainLoop 0x00007ff791cf96c1 (Unity) Application::TickTimer 0x00007ff7921814fa (Unity) MainMessageLoop 0x00007ff792185830 (Unity) WinMain 0x00007ff79354c9ae (Unity) __scrt_common_main_seh 0x00007ffc539e7034 (KERNEL32) BaseThreadInitThunk 0x00007ffc55022651 (ntdll) RtlUserThreadStart
This error goes away if I wait a bit (5 seconds) before creating the joining player's row on the server, but the player row is still created in the root and not being parented correctly. To clarify, a player row is created when a player joins, most likely the scene is still being loaded on the client while the server already adds the player row and tries to spawn it.
All this was working just fine prior to the 1.1.0 version, I seems like something is now broken with the way parenting is working.
Did you add the non-addressable prefab to the NetworkManager prefab list?
yes.
I tried a workaround, where I simply create that prefab with no parent, wait for it to spawn everywhere, then on the server I set its parent (because only the server can change the parent since it's a network object), that didn't work either, which is weird. The server has the right parent, as expect it works on the server, but the client never updates its parent and the prefab remains on the root.
the prefab's network object has "Auto Object Parent Sync" turned off, i tried turning it on, but that didn't do anything.
Is there anyway you could share a repository link inviting me as a collaborator? This might require looking at the whole picture to determine where the culprit is.
unfortunately I cannot do that, I will try to create a similar scenario in a sample project when I get the time.
I have some additional questions. Regarding the scenes you are loading, are you doing any of the following things?
No I'm not doing any of that.
I just tried simplifying my scene hierarchy a bit, so I tried simply having my prefab be created directly under an empty canvas, but I'm still having the same issue. I will try to simplify the prefab itself, perhaps create a simple Text and see.
Tried creating a simple prefab in a simple canvas, still same issue.
This is the code that runs on the server side to create the prefab when a player connects.
private async Task AddLobbyPlayerRow(IPlayer player)
{
await new WaitForSeconds(2); // added this wait for testing
Instantiate(_playerRowPrefab, GameObject.Find("CanvasTest").transform).GetComponent<NetworkObject>().Spawn();
return;
}
This is my canvas, empty no children in it. Parent auto sync turned off. This is my prefab, very simple just a Text mesh pro. Parent auto sync turned off. This is the result on the client side. This is the result on the server side.
Also tried creating the prefab with no parent, and parenting it later, that didn't help.
private async Task AddLobbyPlayerRow(IPlayer player)
{
await new WaitForSeconds(2);
var test = Instantiate(_playerRowPrefab);
test.GetComponent<NetworkObject>().Spawn();
await new WaitForSeconds(5);
test.transform.SetParent(GameObject.Find("CanvasTest").transform);
return;
}
@TheCaveOfWonders thank you for providing me with those details. I believe that is enough for me to try replicating the issue on my side. Will whip together a project mirroring what you are doing above and see if I get the same result.
You're welcome, not sure if it makes a difference but I'm on Unity 2022.2.2
@TheCaveOfWonders Ahh, it looks like I didn't update some of the documentation =or= there is a bug with player instances (need to investigate this further). (The documentation calls out that you can do this with in-scene placed NetworkObjects, so either it is a mistake in the documentation on my behalf or it is a bug)
Since this is a blocker for you, I put together a simple project that provides you with an alternate approach that works with AutoObjectParentSync enabled and disabled (it defaults to disabled but you can change the SimpleUIPlayer's NetworkObject to see it being used under both conditions): The "work around" is that I have a "wrapper" in-scene placed NetworkObject that spawns the LobbyCanvas prefab (i.e. makes it dynamically spawned) and then parent players under that.
Alternate Approach Project Example: ParentingUnderCanvas.zip
I went ahead and marked this as a bug and it will be imported it into our internal bug tracking system.
Hopefully the project I included will provide you with an alternate way to handle this until I get a chance to see if it is only player NetworkObjects that are viewed as "nested in-scene placed NetworkObjects" when they are parented under an in-scene placed NetworkObject or if this happens for all dynamically spawned NetworkObjects that get parented under an in-scene placed NetworkObject.
Thanks for your support and for the suggested workaround, unfortunately my canvas has a few more nested network objects in it, and so I cannot spawn it dynamically, I get an error message along the lines of "cannot spawn nested network object, that's not supported, only in-scene nested network objects are supported."
Nevertheless I have a workaround, I'm simply setting the prefab's parent on the client side after it is spawned, in its OnNetworkSpawn() method.
I do know that my old way of having the server do all the work (create the prefab with a parent using addressables) was working, somewhere after NGO v1.0.0 something changed. Anyhow, thanks again for your help :).
Also remember that you don't always have to make the scene objects "NetworkObjects". If you have auto parent sync turned off then you can parent those under a GameObject (using the transform.SetParent and not NetworkObject.TrySetParent). So, you could have like a "LobbyCanvasManager" that is a NetworkObject that has all of the NetworkBehaviour components that handle the "netcode related" tasks and then the actual "LobbyCanvas" that has your complex hierarchy:
You would just need to make sure the client-side handles the parenting locally the same way the server does.
This issue will be resolved in v1.3.0.
I have a UI scene akin to a lobby, with an in-scene player list that's a network object, when a player connects, a player row prefab, also a network object, gets instantiated on the server side and added to that player list, NOT using SetParent, but using Addressables.InstantiateAsync and providing the player list as a parent, then the server spawns that prefab.
Scene: -Canvas (in scene network object) --Some Panels (in scene objects) ---Player List (in scene network object) ----Player1 Row (run-time network object) ----Player2 Row (run-time network object) ----Player3 Row (run-time network object)
This was working perfectly fine for a long while, I believe after the update to 1.1.0 it broke, and in 1.2.0 it still doesn't work.
The problem: on the client side, the player row is always at the root of the scene instead of being under the player list.
Am I doing something wrong here? what changed that's causing this to break? I tried messing around with the "Auto Object Parent Sync" for the player list and the player row, but that didn't help either. Also tried using SetParent on the player row, instead of having the Addressables.InstantiateAsync set the parent, but that didn't help.
What is the proper way of handling this type of network parenting?