When I create a folder with a bunch of values inside of it on the server, I parent the values to the folder first, then once they are all parented, parent the folder to a folder in workspace. However, when I do that and have ChildAdded function, it doesnt pick up on the values inside said folder
-- Server
-- Create the pet folder
local NewPet = Instance.new('Folder')
NewPet.Name = HttpService:GenerateGUID(false) -- Generate unique ID
-- Create pet name value
local PetName = Instance.new('StringValue')
PetName.Name = 'PetName'
PetName.Value = GetRandomPetName(PetsData.Type .. 's')
PetName.Parent = NewPet
-- Create pet value (the type of pet)
local Pet = Instance.new('StringValue')
Pet.Name = 'Pet'
Pet.Value = pet
Pet.Parent = NewPet
-- Create age value
local Age = Instance.new('IntValue')
Age.Name = 'Age'
Age.Value = 0
Age.Parent = NewPet
-- Create shiny bool
local Shiny = Instance.new('BoolValue')
Shiny.Name = 'Shiny'
Shiny.Value = false
Shiny.Parent = NewPet
NewPet.Parent = Player.Pets
-- Client
Player.Pets.ChildAdded:Connect(function(child)
print(child.Age.Value) -- returns nil
-- or trying this
local Age = child:FindFirstChild('Age')
print(Age.Value) -- returns nil
end)
As you can see, the ‘Age’ value is parented to the folder before that folder is inserted into the Player.Pets folder. Thus, those values should exist immediately as the folder is added to the Player.Pets folder. So why are these prints returning nil?
I don’t wanna resort to WaitForChild() either. I know there’s a timeout feature, but it might timeout before the values load (for whatever reason)
Was a feature request made years ago, however I don’t wanna bump, because I know it won’t ever get resolved.
Many games do this, you would load from top to bottom. Roblox could try parenting the instances to nil and waiting for the instances to fully load before parenting them to the specified location.
Ultimately, parenting any object results in this, no way to go around it.
Well this mainly comes down to how object orientation works, a computer is extremely fast to begin with, as such when something changes it notices on the cycle and then flags to deal with it. A client is essentially replicating what the server asks, as such the instance of folder on the server isn’t technically the same as the one on the client - the client has to create its version itself so it reflects what the server knows. This can be a bit difficult to get your head around and requires you to understand the finer details of how the client-server model is really working without getting confused or lost.
Essentially, the server asks the client to replicate this folder across so the client acknowledges it and as such the client gets to work and does it. As you are referencing, the parent object gets created followed by the children of the object - this is because this action isn’t contextual. As its done by a program, it doesn’t see the context that you’ve put in (that it has to be done in a specific way) and so it just does it in the way it thinks is best (which is create parent, then create its children, then its children’s children etc…).
So what can you do then?
I mean to me, the simplest method to keep your current methodology might just be to create another ChildAdded event connection to the child like so:
Player.Pets.ChildAdded:Connect(function(child)
local Age = child:FindFirstChild('Age')
if not Age then
child.ChildAdded:Connect(new_handler_func)
-- as its asynchronous you might want to another presence check here just in case
end
end)
Be aware though that the :WaitForChild() would likely be very quick if you know its always going to exist, and the thread will be terminated if the parent is removed in this time.
So what’s a secondary method?
Well the second method would be to send a contextual package using an event to give information about the pet, and as such remove the need for the StringValue and IntValue (which saves memory). Therefore the player will be given these packages whenever data changes about their pet.