Create loading text based on assets

local Loadables = {workspace:GetDescendants(), StarterGui:GetDescendants(), SoundService:GetDescendants()}
	
for i = 1, #Loadables do
	ContentProvider:PreloadAsync({Loadables[i]}) -- ERROR HERE
	Loading.Text = i .. "/" .. #Loadables
end

Unable to cast Array to Content

2 Likes

workspace:GetDescendants() and other values in Loadables are tables, encapsulating Loading[i] in {} makes a table with a value which is another table but with the descendants.

local Loadables = {object:GetDescendants}
-- Loadables is something like {{a, b, c}}
print(typeof(Loadables[1])) --> table
local whatYouPassed = {Loadables[1]}
print(typeof(whatYouPassed[1])) --> table (of descendants)
local whatShoudBePassed = Loadables[1]
print(whatShoudBePassed} --> a
1 Like
local Loadables = {workspace:GetDescendants(), StarterGui:GetDescendants(), SoundService:GetDescendants()}

for i = 1, #Loadables do
	ContentProvider:PreloadAsync(Loadables[i])
	Loading.Text = i .. "/" .. #Loadables
end

Still doesn’t work.

1 Like

Remember that i and #Loadables are numbers so you have to call tostring so it can concatonate with the / string: Loading.Text = tostring(i) .. "/" .. tostring(#Loadables)

Also, you don’t need to call GetDescendants because PreloadAsync iterates through all descendants for you I believe.

It only goes:
‘1/3’
‘2/3’
‘3/3’

It should have ALL the assets in game that it’s loading. There’s definately not just 3 assets

There are only three values in Loadables, each value is table which has several more values inside it. Remember, Loadables[i] contains the actual assets, Loadables contains tables of these assets.

That’s because you’re only printing the size of the table and not the nested table sizes. You should be indexing the ContentProvider.RequestQueueSize to get the amount of assets that are currently in the preload request queue.

1 Like
for i = 1, #Loadables do
	ContentProvider:PreloadAsync(Loadables[i])
	Loading.Text = 'Loading (' .. ContentProvider.RequestQueueSize .. ')'
end

Doesn’t work

This doesn’t work since you’re loading one chunk at a time and since PreloadAsync yields, ContentProvider.RequestQueueSize isn’t what you think it will be (probably around 0 till the point you set the text).
From the page on ContentProvider.RequestQueueSize:

Developers are advised not to use RequestQueueSize to create loading bars. This is because the queue size can both increase and decrease over time as new assets are added and downloaded.

The same page also contains an example that can help your problem:

for i = 1, #assets do
	local asset = assets[i]
	ContentProvider:PreloadAsync({asset}) -- 1 at a time, yields
	local progress = i / #assets
	bar.Size = UDim2.new(progress, 0, 1, 0)
end

I feel like you’ve already seen this and just went a bit wrong in it’s implementation. Here assets contains all the assets to be loaded, not as chunks but as separate values all at the same level, no nested tables. Here’s how you can implement this in your existing script:

local Loadables = {workspace:GetDescendants(), StarterGui:GetDescendants(), SoundService:GetDescendants()}

-- Make new table which doesn't have nested tables
local assets = {}
for _, container in pairs(Loadables) do
	-- container will always be a table with assets in it
	for _, asset in pairs(container) do
		table.insert(assets, asset)
	end
end

for i = 1, #assets do
	ContentProvider:PreloadAsync({assets[i]})
	Loading.Text = i .. "/" .. #assets
end

I think that ContentProvider is one of the most misunderstood services in terms of developer usage as it relates to creating loading sequences.

PreloadAsync automatically passes the object AND all of it’s descendants into the download queue, so never use GetDescendants with PreloadAsync. It’s a collosally bad idea and you add more unnecessary work to the script (e.g. that table delayering operation). Even worse off is to preload entire service containers. Don’t do this, it nullifies the point of PreloadAsync completely.

PreloadAsync is meant to push assets to the front of the download queue (and in the case of first-use assets, get the client to download them). If you push everything to the front, then there’s virtually no point in using PreloadAsync except as an alternate (and unintended) way of waiting until all specified assets have downloaded without the use of the arbitrary number RequestQueueSize.

Last thing: an engineer advised against using PreloadAsync one asset at a time. Take this information as you will.

cc @NinjoOnline @ankurbohra04

1 Like

Apparently not

local Loadables = {StarterGui, SoundService}
for _, container in pairs(Loadables) do
	for _, v in pairs(container) do
		table.insert(Assets, v)
	end
end

for i = 1, #Assets do
	ContentProvider:PreloadAsync({Assets[i]})
	Bar:TweenSize(UDim2.new(i / #Assets, 0, 1, 0), Enum.EasingDirection.Out, Enum.EasingStyle.Linear, 0.025, true)
end

Table expected, got object

That’s because you’re doing pointless iteration over the Loadables container, which the iteration itself isn’t even done properly and is malformed.

local StarterGui = game:GetService("StarterGui")
local SoundService = game:GetService("SoundService")

local Loadables = {StarterGui, SoundService}

for i = 1, #Loadables do
    ContentProvider:PreloadAsync({Loadables[i]})
    Bar:TweenSize(UDim2.new(i / #Assets, 0, 1, 0), Enum.EasingDirection.Out, Enum.EasingStyle.Linear, 0.025, true)
end

Again though; you really shouldn’t be preloading entire containers nor putting assets in a single-table loading iteration as specified by my above reply. Preload is only meant for downloading assets you need immediately visible on load and the rest can and should be download-streamed in the background.