ContentProvider:PreloadAsync() not working?

More or less. PreloadAsync doesn’t load in the map to the client. That’s done through the normal replication process. PreloadAsync just loads in the assets that are used in the map (images/textures, sounds, and meshes). If the asset load completes before 1) the server has finished building the map, or 2) the map hasn’t been replicated to the client yet, when the preload is finished and the loading gui goes away, visually the map hasn’t finished loading in, from the client’s perspective. The issue is more apparent when the server is first spun up since during server startup, as a lot of things are going on at the same time.

In other words, PreloadAsync is the what as in what’s being used. Replication is the how as how those assets are being used.

Ideally, both the asset preload and the replication happen at the same time, but in practice it doesn’t. When a player first logs in, there’s a massive data dump from the server to the client. This includes scripts, assets, instances, etc… There are a number of causes. Mainly limited network bandwidth or network congestion. Server lag can also be an issue, as is client performance since the client has to process all that data.

Assuming they are not the first person to join the server and the server has already loaded:
Is the problem that the PreloadAsync() is finishing before the server → client replication process?

I thought game.Loaded:Wait() waits for the client replication process to complete:
I have

if not game:IsLoaded() then game.Loaded:Wait() end
G.ContentProvider:PreloadAsync({Icon, GameTitle})
G.ContentProvider:PreloadAsync, G.GetDescendantsOfClass(workspace.Map.MainMap, "MeshPart"))
LoadingScreen:Destroy()

Yet the client sometimes looks like this after the loading screen completes (alot hasn’t loaded in yet)

In my case, the server does other things after the map loads, so it’s still working on things so I have to hold the client at the loading screen until the server finishes.

I’m confused how you’re measureing when the server has finished

Tweak this script to make it work for your situation.

local ContentProvider = game:GetService("ContentProvider")
local Players = game:GetService("Players")
local loadingScreen = script:WaitForChild("LoadingScreen"):Clone()

repeat task.wait() until game:IsLoaded()

local assets = workspace:GetDescendants()
local maxAssets = #assets
local client = Players.LocalPlayer
local plrGui = client:WaitForChild("PlayerGui")
loadingScreen.Parent = plrGui

for i, assetToLoad in assets do
	ContentProvider:PreloadAsync({assetToLoad})
	loadingScreen:WaitForChild("Assets").Text = "Assets loaded: "..i.."/"..maxAssets
end

loadingScreen["Loading Text"].Text = "Successfully loaded assets!"
loadingScreen.Assets.Visible = false

task.wait(5)

loadingScreen:Remove()

Hope this helped!

There is no measurement. When the last startup task is finished and the game is ready to play, then it spawns all the players in game and sends the event to release the loading screen. In other words, the startup sequence broadly follows this:

  1. Core package initialization
  2. Game initialization
  3. Load players
  4. Play game

Of course, every game is different.

How is that any different to my script which isn’t working
You’re just using a for loop instead which if anything would make it slower

ContentProvider also tends to yield in my case forever (Happened to a lot of my players), I would just add an automatic skip after 60 seconds has passed, which in this case would most likely be after all of the map parts have already replicated/loaded.

Seems like a non-ideal work around rather than a solution
There has to be better way as Pet Simulator X loading screen is short and always works perfectly and is never 60 seconds long.

Well, it was my only solution to ContentProvider hanging forever, you can also just load specific classes if needed.

local ToLoad = {}
local CC = game:GetService("ContentProvider")
for _,v in workspace:GetDescendants() do
	if v:IsA("Sound") then
		table.insert(ToLoad, v)
		continue
	end
	if v:IsA("MeshPart") then
		table.insert(ToLoad, v)
		continue
	end
end
for _,v in ToLoad do
	CC:PreloadAsync({v})
end
-- Make sure to clear ToLoad after usage.

Tried only loading meshparts (that’s the only thing I want to load) but it doesn’t seem to make the situation any better

Should you utilize the second parameter of PreloadAsync to print if an instance is actually loading forever, you could also do a before and after loading print debug an instance. Such as getting a part full name before loading then printing the same part full name after loading (Either after the load or using the built in function in PreloadAsync)

for _,v in ToLoad do
	print("Loading in ", v:GetFullName())
	CC:PreloadAsync({v}, function()
		-- also this 
	end)
	print("Finished loading ", v:GetFullName())
end

My preload async lasts anywhere between 2-60 + seconds and whether the map has loaded in is fairly random. It’s not that it’s yielding for ever it’s that preload async isn’t actually waiting for the map to load

ContentProvider:PreloadAsync() will not wait for the map to be loaded. It’s job is ONLY to preload the specified assets. Once that has completed, the local script will proceed. I know that a lot of people use it to delay the login process so maps get replicated to the client, but that’s not what it’s for. The root cause of the problem is that you are using it as a delay when you need another mechanism to delay the script. Refer to one of my previous posts in this thread here for an example of such a mechanism.

ContentProvider:PreloadAsync()

Specifically the first paragraph:


What this means is that ContentProvider:PreloadAsync() will yield the script only until all listed assets have loaded. This has absolutely no connection to the replication process for loading maps and shouldn’t be used for it.

As for using an array of textual asset identifiers as stated here:


In practice, I have found this to be false since I have used this method to not only load images, but also sounds and meshes, which is does without error (most of the time).

An alternate mechanism to wait for the map to be loaded would be to create a BoolValue in ReplicatedFirst with a value of false, then wait for it to turn true before proceeding.

1 Like

ok but what actually causes it to turn true, I’m not understanding your method of actually telling when the map has loaded

It’s when the map has finished loading into the workspace on the server so at the end of that routine, you set it to true. Although I didn’t mention it, you could still use game:IsLoaded() to check if it’s finished loading on the client. But my experience has been it seems to work intermittently. Intermittent is better than nothing.

So you’re using ContentProvider:PreloadAsync() on the server?
After that has happened you set a variable to true / fire client and complete the loading screen?

No. You use ContentProvider:PreloadAsync() on the client. Then you set a variable to true on the server which replicates to the client.