Wait for model to be fully replicated to client?

Hey guys. So, I have these vehicles on the server. Initially they were in ServerStorage, which would be ideal, but I moved them to ReplicatedStorage because the problem is amplified when they aren’t already loaded on the client. I use these pads to spawn vehicles, which just clones the vehicle from ReplicatedStorage into some folder in Workspace that holds all the vehicles. The problem is that when using ChildAdded, or CollectionService tags, not all of the parts have been replicated yet. This is expected behavior, as documented on the ChildAdded wiki page. But, I was curious if anyone had a suggestion to wait for all parts to replicate so that I wouldn’t have to do WaitForChild on every single thing that I want to index. Or, if there was some replication priority for certain classes so I could add a certain class to a vehicle if it is supposed to replicate after all the other parts and just wait for that one instance.

Thanks

Can’t you just use

game.Loaded:Wait()

Keep in mind that Loaded only checks if things are loaded for pre-existing objects, anything instances in a script wouldn’t count, as far as I know.


@sporting_goods replying to your reply below:
You only need to use WaitForChild for client objects, ServerObjects are already loaded. You can use:

Model.Loaded:Wait()

Unfortunately no, Loaded is only invoked once the game finishes loading for the first time. I’d like to wait for a specific model to finish replicating after it has been cloned from, say, ServerStorage. That’s why I was curious if there was any replication priority, so if something like ParticleEmitters (just an example) was guaranteed to replicate after BaseParts, then I could just put one ParticleEmitter in the model and use WaitForChild on that.

It seems like Loaded is only an event of datamodel, which is unfortunate because that would actually be pretty useful on specific models. I just had an idea of having some IntValue in the model which, on the server, I set the value to the amount of descendants in the model and I wait for it to be equal on the client. Could work but there must be some better solutions. As for using WaitForChild on the client, I know that. What I meant was adding some instance into the model on the server that is guaranteed to replicate to the client last, and then waiting for that on the client. Though, I don’t think there is any type of priority to replication.

Update for anyone else experiencing this problem in the future: I initially tried RequestQueueSize to make sure there were no parts being streamed to the client to verify that it was fully loaded. I thought it worked but turns out it didn’t, or at least not 100% of the time. So, I tried my other idea, which was to have some IntValue with the value set to the amount of descendants on the server, then check if the amount of descendants on the client matches it. Turns out, based on all of my testing, this IntValue always replicates last. This could either be that (from my initial idea) BaseParts have replication priority over IntValues, or that there is no priority and that replication is guaranteed to be in order (since I am creating the IntValue after cloning the model.) Whichever it is, it doesn’t really change anything because regardless I could just make sure the IntValue exists and not even check if the descendants are matching. Though, I’m sure there are edge cases in which some stuff will replicate before others, out of order. In which case it would break everything. So I think I’ll stick to checking if the amount of descendants match.

6 Likes

Hi @sporting_goods,

I think I have the same problem:
I am making a racing game and have various vehicles in ServerStorage. These are cloned to the starting grid in the beginning of the race.
When cloning 3 or more vehicles the 3rd quite often ends up sinking into the ground or wheels folded up, or even glitching away.

I guess the root of the problem is that the chassis of the vehicle does not have time to initialize everything (when multiple vehicles are cloned at the same time) in time for all vehicles and/or some parts are not fully ready so they can go into the ground.

I tried waiting a bit after clone-and-parent to workspace for each vehicle, which seamed to help at first but then it is not 100% reliable.
Should I be waiting after the clone and before parenting to workspace? Is that when all the things get created and initialized?
Of course you never know how long you have to wait so it would be nice to be able to detect when everything is ready.

Is your solution to check the amount of descendants after the clone and wait until it reaches the expected value? Before parenting it to the workspace?

I would really appreciate it if you could explain in detail how your solution works.
Thanks in advance!

My vehicles are cloned on the server, which causes the problem since not all parts of it will be replicated at once. However, all of the parts will be instantaneously available on the server after the clone. So, I create a NumberValue in the model named NumDescendants, and set the value of that to the amount of descendants in the model on the server. On the client, I wait for that NumberValue and then wait until the amount of descendants in the model is equal to or exceeds the value of NumDescendants.

I’ve been doing this for months now with absolutely no problems. Roblox really should have something built in that tells you when a model is done replicating, at least when it is first created. Anyways, I hope this helped.

2 Likes

Thank you for the reply and explanation!
Sounds great that your solution works perfectly. I also need to do this otherwise I am stuck with an unreliable racing part.

I’ll write down in detail how I believe it should work and then please correct me if I am wrong.

  1. In a server script clone the vehicle:
    local car = game.ServerStorage.Cars.NameOfCar:Clone()
  2. After this line the car is instantly available on the server
  3. Then continuing the script: create a NumberValue in the car model named NumDescendants, and set the value of that to the amount of descendants in the model on the server,
  4. Send a RemoteEvent to the specific client the car is for and in a local script:
  5. Wait for the NumberValue object and compare it’s value to the amount of descendants in the model is equal to or exceeds the value of NumDescendants,
  6. Send a Remote Event back to the server script to parent the car to the game.Workspace, so it appears on the server and for every client.
  7. The car starts simulating, the chassis makes all it’s joints and the car should not fall through the ground.

Is this correct?

By the way I destroy the cars once the race is over and clone new ones for the next race. Is this good?
I am beginning to doubt it as you wrote: “at least when it is first created”

Do you store your used cars in between races somewhere and then just move them back to the track when the same type of car is needed?

@sporting_goods, please help!
I am trying to code this but keep banging my head into various walls of my coding deficiency.

I would really appreciate it if you could explain the skeleton of your solution.
Thanks in advance!

This is what I am doing, but I have no idea how this will help me in preventing the vehicle from becoming occasionally (quite frequently) corrupted, like wheels breaking upwards and vehicle going into the ground.
@sporting_goods please check if you have some time and help me with some hints how to continue or what I am missing.

In a server script:
I clone a vehicle, position, name it, count the descendants and parent it to the workspace, then send a remote event to the client like:

local car = game.ServerStorage.Cars:FindFirstChild(v[1].ownership.SelectedCar.Value):Clone()
car:SetPrimaryPartCFrame((carSpawnPosition.CFrame + Vector3.new(0,2,0))* CFrame.Angles(0, math.rad(90), 0))
car.Name = v[1].Name.."_car"

local vehicleDescendantsTBL = car:GetDescendants()
local vehicleDescendantsCount = #vehicleDescendantsTBL

print("vehicleDescendantsCount : " .. tostring(vehicleDescendantsCount))
print("car.Name: " .. car.Name)
print("v[1].Name: " .. v[1].Name)

local carNumDescendants = car:FindFirstChild("NumDescendants")
carNumDescendants.Value = vehicleDescendantsCount
car.Parent = game.Workspace.RaceVehicles

checkVehicleDescendantsCountRE:FireClient(v[1],car.Name)

In a local script:
I count and print the descendants count.

local function onCheckVehicleDescendantsCountRequested(carName)
	
	print("carName: " .. carName)
	
	local vehicle = game.Workspace.RaceVehicles:WaitForChild(carName)
	
	local vehicleDescendantsTBL = vehicle:GetDescendants()
	local vehicleDescendantsCountClient = #vehicleDescendantsTBL
	print("vehicleDescendantsCountClient: " .. tostring(vehicleDescendantsCountClient))
	wait(1)
	
	local vehicleDescendantsTBL = vehicle:GetDescendants()
	local vehicleDescendantsCountClient = #vehicleDescendantsTBL
	print("vehicleDescendantsCountClient: " .. tostring(vehicleDescendantsCountClient))
	wait(1)
	
	local vehicleDescendantsTBL = vehicle:GetDescendants()
	local vehicleDescendantsCountClient = #vehicleDescendantsTBL
	print("vehicleDescendantsCountClient: " .. tostring(vehicleDescendantsCountClient))
	wait(1)
	
end

checkVehicleDescendantsCountRE.OnClientEvent:Connect(onCheckVehicleDescendantsCountRequested)

And this is the output I get:

from server:
vehicleDescendantsCount : 264
car.Name: purbanics_car
v[1].Name: purbanics

from client
carName: purbanics_car
vehicleDescendantsCountClient: 265

vehicleDescendantsCountClient: 328

vehicleDescendantsCountClient: 328

So how is this? You wrote that :

all of the parts will be instantaneously available on the server after the clone

but the server counts 264, then the client instantly after that counts 265 and after 1 sec delay counts 328 and again 328 after another sec delay.

???
Please help!

But anyway, this would not help me in any way to not get the vehicle become corrupted as I am just counting parts, not waiting for it to “materialize” properly.

What am I missing?
Should I wait before parenting the vehicle to the workspace for those parts to get created?


edit:
What seems to be happening is that the vehicle starts out with just 264 descendants, but then after it is parented to the workspace it goes up to 328 descendants quite quickly. In less then a sec.
I guess the vehicle chassis is creating springs and joints, etc.

I could weld the primary part of the vehicle to something (keeping it above the track) while waiting for the descendants count to stop increasing and then drop it on the track once it is all done.

Would this be a good solution?

I am using: INSPARE: AC6 Loaded - Build 6.52S2

How do other people solve this problem?

Try to set the ModelStreamingMode of the Model to “Persitent”