Changes to Non-ReplicatedFirst Loading Order

Does this mean that I’ve been using WaitForChild incorrectly all these years? I use it for top-level instances (such as ScreenGuis) in the PlayerGui and Folders etc. in ReplicatedStorage. Then I index the descendants normally. According to the wiki…

WaitForChild is extremely important when working on code ran by the client (in a LocalScript ). Roblox does not guarantee the time or order in which objects are replicated from the server to the client. This can cause scripts to break when indexing objects that do not exist yet.

Additionally, does this change how I should approach waiting for Folders etc. created by the server with their descendants contained within and then parented to ReplicatedStorage? I always used to assume that the descendants would be replicated along with the folder.

Note that I am talking about LocalScripts/ModuleScripts located in StarterCharacterScripts and StarterPlayerScripts (but primarily the latter).

Perhaps not wrong, but unnecessary might be the word there. Using WaitForChild when the instance is already there just returns the instance immediately with no yield.

Not sure why the DevHub says that. That seems inaccurate. By the time your non-ReplicatedFirst code starts running, the entire game is available to use, even items created by scripts before the player joined the game.

If the server creates an instance when the player is already there (or moves one into a replicated container), ChildAdded can fire before all of its children have replicated. You can make sure that an instance has all of its children replicated by having the server use a RemoteEvent and FireClient with that instance as an argument. The OnClientEvent won’t fire on the client until all of that instance’s children are ready and available.

2 Likes

Though there’s no way to reliably use this information because you can’t tell the difference between an object that was there before the player joined the game and one that was just created. If something gets created at runtime by a script, you need to be using WaitForChild to get a reference to anything you’re accessing inside of it.

This doesn’t change anything regarding that, but you’ve just been getting lucky. The bottom line is that if you dynamically create an object using a script, you have to be using WaitForChild to access stuff within it on the other side of the network.

1 Like

Yes, to clarify: I would advocate for using WaitForChild on all script-generated objects. If you don’t, it’s pretty common for the first player to join to have timing issues. If you don’t want to name every child something unique though, you can always use the RemoteEvent trick.

With that in mind, the excerpt from the DevHub is still wrong in the more common case of accessing instances that are available in Studio.

1 Like

Unfortunately yes, you do need to explicitly invoke WaitForChild for each individual descendant that you want to access, not just the root. We do not guarantee atomicity of sending currently. In practice, the instances frequently end up in the same bundle of messages, but it is not a guarantee. You can try this out locally by cloning some huge model (e.g. with 10k+ parts) into replicated storage, using WaitForChild on the root, and then as soon as that returns examining the contents of the clone.

3 Likes

I wrote a post related to instance lifetimes that may be helpful:

The gist is to treat the game tree as a dynamic structure, identify when instances are added, removed, and the conditions involved, and make use of APIs with guarantees as much as possible.

1 Like

Final question on the topic of script created instances:
It seems simpler to me to merely have a remote function that returns an instance from ReplicatedStorage with the given name as opposed to firing a remote from the server when the player joins or manually waiting for the object on the client. Is this a valid solution or is there some reason remote events would work and remote functions wouldn’t?

Thanks for the answers I have received, by the way. I clearly had a misunderstanding about how Roblox handles replication. I would appreciate it if the documentation was clearer on use-cases for methods like WaitForChild. It might also be nice if there was some visual or worded representation of how things are streamed/replicated to the client on Roblox. Maybe I’m missing some documentation pages somewhere, but I’ve never been able to find a clear source on it and, as a result, have been left second-guessing my codebase at certain points.

This isn’t just me. I have seen too many other developers using WaitForChild everywhere or nowhere. (and just a really bad wait(n) at the start of their client-side code). There does not appear to be general knowledge of how to approach this part of scripting in the community of developers that I have seen, and I think many would benefit from a solid resource. Maybe I’m missing it. I have seen devforum posts, yes. However, they are not comprehensive, and the devhub really needs an update in this department.

Please correct me if I’m wrong.

2 Likes

Status Update: As of late in the day on 8/24 this is now live for desktop clients, with more platforms to follow soon.

1 Like

This change has broken every RedManta project (Robloxian High School, World // Zero)

We are having a hard time reproducing it ourselves and are working with bug reports from users.

We never saw any issues arise after August 17 when this was supposedly enabled in studio. We only saw users begin having errors when it was flipped live.

Please turn this off to give developers more time to update their projects. This is a huge change unfortunately.

Edit: Reports of other devs saying their games are all of a sudden “exploding” as well

5 Likes

Earlier today we further altered the load order, this seems to have triggered the issues AbstractAlex has mentioned, we just reverted this follow-up change. We will make another post on this thread with an announcement for when we will do a test run of the follow-up change in studio.

Why did this happen without any warning to devs or beta tests? This feels like the definition of testing on live :confused:

8 Likes

When deciding to enable the flag, my (incorrect) expectation was that the flag would not have visible further impact beyond what we had already enabled on 8/24. We will be more careful going forward with this change.

1 Like

Will this flag being flipped off replicate to existing servers or do we need to shutdown running instances to patch this?

The flag only affected desktop clients. No updates to servers should be needed to resolve the issue, the clients will be resolved after they are closed and they rejoin.

1 Like

This change seriously had me nervous, popped open studio and BAM! All UI is completely off. I would appreciate the heads up next time instead of just spontaneously enabling a flag that ruined my game’s interface (including billboard UI). I was able to resolve this with code, but please don’t do this again. Ever.

5 Likes

Was this re-enabled? Yesterday I began seeing reports of people not being able to join Robloxian High School, the errors are related to this replication change. Game has not been updated since last Friday.

1 Like

The secondary change (where siblings are not guaranteed to be in order) has not been re-enabled.

The original change on this thread (where join is not loaded in strict tree-traversal order, but final sibling order is maintained as of when game.Loaded fires) was never disabled / is still enabled.

3 Likes

Ever since this shipped I’ve had really bad ping issues in my game. I believe my issues are related to this update but I really don’t have anything other than timing to link them together.

Is there a way to check if all children of an object have loaded? Or is this not possible and I have to know the names of all children beforehand so I can :WaitForChild()?

LMH_Hutch I’ll reply in your thread