Can I use game.Loaded to avoid using WaitForChild?

The only things you should be using Instance:WaitForChild() for is Player.PlayerGui and top-level ScreenGuis.

No, you can’t use game.Loaded to avoid that. GUIs are not cloned until the character spawns from game.StarterGui.

I recommend ditching game.StarterGui entirely so as not to wait on the player’s character, and instead just clone them all from a folder in game.ReplicatedStorage.

10 Likes

You can do something like this on the server and just wait for the Loaded bool value since it was created last it will load in last.

local StarterGuiObjects = {}
for _,x in ipairs(game.StarterGui:GetChildren())do
	x.Parent = nil
	table.insert(StarterGuiObjects, x)
end


local function PlayerAdded(player)
	local playerGui = player:WaitForChild("PlayerGui")
	for _,x in ipairs(StarterGuiObjects)do
		x:Clone().Parent = playerGui
	end
	local loaded = Instance.new("BoolValue")
	loaded.Name = "Loaded"
	loaded.Parent = playerGui
end

for _,x in ipairs(game.Players:GetPlayers())do
	coroutine.wrap(PlayerAdded)(x)
end
game.Players.PlayerAdded:Connect(PlayerAdded)
2 Likes

Someone just posted a community resource which could be the solution to your problem :joy:

Probably mainly useful for Guis

[Haven’t tested it myself right now, but from the way he has set it up, seems to work quite well]

2 Likes

That’s the thread that spawned my idea for this topic. I figured this would be way easier, but I guess it doesn’t work.

I put this at the beginning of all my client scripts. Never seen an error since.
image

Cringing at this post a year and a half later.

3 Likes

I think just putting wait() at the beginning of the LocalScript is enough.

Otherwise, The only thing that occurs to me so far is a LocalScript in PlayerGui that waits for all children to load and then creates an object called “Loaded” or else you change the name or disable etc, then in the rest of the scripts a line at the beginning like this.

game.Players.LocalPlayer:WaitForChild("Loaded")

You can make a Plugin that generates a script with a WaitForChild for each object in the StarterGui.

1 Like

Wiki:
Instance:WaitForChild, a function which can be used to wait for an individual Instance to replicate without having to wait for the whole game to.

Unless they are parented to ReplicatedFirst, LocalScripts will not run while the game has not loaded.

This would imply that waiting for game to load is enough.

I’ve rarely had any issues with referencing Instances in LocalScripts instantly.

Some tests in studio:

Game loaded: 1547240178.5973
LocalScript started 1547240180.0001
Difference: 1.4027998447418

Parenting 100 GuiObjects to Gui and checking how many are loaded:

print(#script.Parent:GetChildren()-1) --> 100

You mean there is no need to use WaitForChild in LocalScripts located in PlayerGui?, because I’m confused with your answer, of course it’s necessary.

2 Likes

In that case there would be no such thing as WaitForChild() to begin with. I belive this is misinformation. Roblox does not guarantee the time or order in which objects are replicated from the server to the client.

They give hints about it, but never explicitly say so:
Unless they are parented to ReplicatedFirst, LocalScripts will not run while the game has not loaded.

Although, it’s probably not safe to reference any object which wasn’t there when game started, as theres a possibility they won’t be loaded when you reference them.

They do accually, sorry for not linking to it, I’ve edited my post to properly redirect now.

That shouldn’t matter, as game.Loaded fires when all of them are replicated.
It doesn’t matter if A gets replicated before B, because you LocalScripts start after they’re both replicated.

1 Like

NOTICE: I have since renounced the content of this post. This explanation details why, and provides advice for dealing with the game tree in a more robust manner.



Refer to the diagram in this post:

Using the information in this post, I can come up with a system to determine how objects should be accessed:

Use of WaitForChild depends on the location of the invoking script, and whether the target object is

  • “static”: exists before game starts; i.e. stored in the place file.
  • “dynamic”: added after the game starts; opposite of static.

Consider the following rules (subsequent rules override previous rules, when applicable):

  1. Generally, scripts may access static objects directly.
  2. Generally, scripts must use WaitForChild to access dynamic objects.
  3. Scripts under ReplicatedFirst must use WaitForChild to access static objects.
  4. Scripts under ReplicatedFirst may access static objects under ReplicatedFirst directly.
  5. Code protected by game.Loaded may access static objects directly.

Services, as targets, are exempt from these rules as long as they are accessed via GetService.

Also worth noting is that an object being static assumes that the object is never removed during the runtime of the game. A supposedly static object that is removed at any point must be treated as dynamic. Technically, because any object can be removed at any time, even before scripts run, static objects do not exist. But it’s probably safe to assume that the runtime has some integrity, and leaves removing objects only to the developer.

Finally, here’s a handy table:

LocalScript\Target Static Dynamic Static (RF) Dynamic (RF)
General Direct WFC Direct WFC
ReplicatedFirst (RF) WFC WFC Direct WFC
Loaded-Protected Direct WFC Direct WFC
39 Likes

It should be mentioned that this is only for LocalScripts.
Regular scripts still require you to use :WaitForChild on both Static and Dynamic objects.

Loading order times, tested in studio:

  Regular Script: 0
  Local Script inside ReplicatedFirst: 0.1
  Game Loaded: 0.1
  Local Script: 3.1
1 Like

I think that in Studio everything goes well, but in ROBLOX Player is a little different, I have happened bugs when I do not put WaitForChild in a LocalScript, I have all those errors in my Game Analytics, do not always occur, I think it depends on the performance of the client, never occur in ROBLOX Studio.

The rules can be applied to server scripts (Static → Direct, Dynamic → WaitForChild). But there are no nuances like ReplicatedFirst and game.Loaded. Basically, rules 3-onward apply only to the client.
Server scripts can access static server objects directly because they are on the same peer, and are therefore visible from the start.

On the client, the game tree starts out empty, and all static objects replicated from the server are actually dynamic. However, there are procedures and APIs (as described in the referred post) that allow us to treat a subset of these objects (“DataModel” in the diagram) as static, as long as certain conditions are met. The rules were created from these conditions.

4 Likes

false information

Animus is correct

It’s extremely annoying to write “:WaitForChild()” instead if a period for one.

Also it messes up the intellisense.

1 Like

This is unnecessary, you gain nothing from doing this. Cloning is a synchronous operation, meaning that the entire descendant tree from the root will be available once the root is. This means that you only need to wait for the ScreenGui itself if is loaded in from game.StarterGui, and Player.PlayerGui.

Waiting for the GUI’s descendants is pointless. Why add a function call which does nothing meaningful?

2 Likes

Whoa. That looks even more painful to type out

2 Likes