How do I avoid "Recursive instantiation of" error when creating many of the same prefab?

I am creating prefabs whenever the user clicks on an object. I attach the prefab wherever they clicked, send a message with a GUID over the network, and everyone else in the room creates the same prefab. When a new user joins, they get all of the networked messages and recreate all of the correct prefabs even though they were not in the room when originally created.

However, when they first join, the network code blasts out a whole bunch of messages to create prefabs. If I try to create them all at once I get a whole bunch of errors from engine_addressables about “Recursive instantiation”

I put the network messages into a queue and now I handle them one at a time, so I don’t get a ‘bunch’ of the recursive instantiation errors, but I still do get an error when I try to create the second object.

Presumably, the first object takes a while to instantiate and is still in the process of being created when I try to create the second one.

           if (AssetReference.currentlyInstantiating.indexOf(this.uri) >= 0) {
                console.error("Recursive instantiation of", this.uri);
                return null;

The code in engine_addressables is throwing the error because of the above code. If I could access the ‘currentlyInstantiating’ list I could solve my issue but I don’t see a way for my code to peek in to the process and determine when it is safe to create subsequent copies of the same prefab.

How can I know when it is safe to call instantiate on the same prefab again?

Original Post on Discord

by user 563549194137239552

I hacked my way around the issue by instantiating one of the prefabs in awake and putting a three second delay after startup before starting to process the queue but it would be great to have a more certain way to ensure that the prefab is ready to go without getting the recursion error

by user 563549194137239552

Interesting, thanks for reporting. I’ll let Marcel respond to the network technicalities :slightly_smiling_face: I don’t think we have that issue in Castle Builder (where many instances of the same thing are created this way)

my prefab is an AssetReference and not in the cene to begin with so it’s being loaded or created the first time it’s used. Once the first one is created the code seems to use to one that’s already loaded to clone it and it works fine. there is a preload method on AssetReference objects i tried calling. Maybe I need to use a different instantiate method - there is an instantiateSync method that doesn’t seem to make a difference

by user 563549194137239552

    async addAnnotation(parent : Object3D, position : Vector3)
        if (this.annoPrefab) {
            if ("uri" in this.annoPrefab) {
                await this.annoPrefab.instantiate(parent)
                .then((result) => {
                    if (result)
                        console.log("Instantiate succeeded")
                        this.curResult = result as GameObject;

                        let p = parent.worldToLocal(position)
                        result.position.set(p.x, p.y, p.z)
                console.log("No URI")

This is how I anstantiate the prefab. If there is another way I should be using let me know!

by user 563549194137239552

I see. So I guess what that call should do instead of erroring and returning null is returning a promise to the result (so they all resolve at the same time), but not sure how to catch actual recursive instantiation in that case

I’m not sure wha6t the solution is but I didn’t think I was doing anything weird or anything responding to the network messages you get on startup… I think they are great… but I know from trying to re-enable the code in engine_networking_files_default_components the needle engine system doesn’t seem to be fully initialized when the code from engine_networking_files recreates the scene graph objects it has to load from the storage server when someone new joins

by user 563549194137239552

as for the specific case of instantiating prefabs… something that would solve my case would be a new method called preloadAssetReference(name/uuid) and isAssetReferenceReady(name/uuid) - that would not change anything already in the existing code

by user 563549194137239552

wouldn’t even need the preload thing… just the isAssetReferenceLoaded or something would do

by user 563549194137239552