Callback for ContentProvider:PreloadAsync


#1

As a Roblox developer, it is currently too hard to make an accurate loading screen when using :PreloadAsync

I’d like to make an accurate loading screen, showing how many assets are loaded from an array that I give to :PreloadAsync(). The callback would fire every time an asset is finished loading, and would pass an array of all assets that are loaded

This would be especially useful when you want to load meshes/textures/sounds only when the client needs them, eg when loading a new world

local assetsToLoad = {123, 456, 789, ...}

game:GetService("ContentProvider"):PreloadAsync(assetsToLoad, function(assetsLoaded)
    --assetsLoaded = {123, 456}

    print((#assetsLoaded / #assetsToLoad) .. "% of assets are loaded")
end)

#2

The ContentProvider preloading used to work with a list of asset ids but Roblox changed this to use a list of Instances to preload. As for the callback this can be done simple in code but you would need to preload each instance in a new thread.

I do agree that the whole process can be made better from a developers point of view. Like including a priority to the order of which things are downloaded. e.g. download gui assets first then download lobby music which have a lower priority.


#3

The current ways to create loading bars:

https://developer.roblox.com/api-reference/property/ContentProvider/RequestQueueSize

Since the preload request queue can dynamically increase or decrease after you’ve requested an asset list (eg.: new players joined and the client started loading their avatar assets), I recommend the following code to display loading progress:

local ContentProvider = game:GetService("ContentProvider")

local load_start = ContentProvider.RequestQueueSize
local load_progress = 0

while true do
if load_start == 0 then load_progress = 1 break end
load_progress = math.max(load_progress, (load_start - ContentProvider.RequestQueueSize) / load_start)
if load_progress == 1 then break end
wait()
end

Another untested method would be:

local ContentProvider = game:GetService("ContentProvider")

local assets = {
"rbxassetid://301964312",
"rbxassetid://301964312"
}

local assets_pending = 0

for _, id in pairs(assets) do
assets_pending = assets_pending + 1
spawn(function()
pcall(function()
ContentProvider:PreloadAsync({id})
end)
assets_pending = assets_pending - 1
end)
end

while assets_pending > 0 do
local progress = (#assets - assets_pending) / #assets
wait()
end

#4

pcall is not requiored when using PreloadAsync as a load error will not cause the PreloadAsync function call to error.