The event .ChildAdded isn’t… accurate enough? Idk what to call it.
Anyway, the problem is, it doesn’t fire every time. I use it for my leaderboard, and I’d expect it to fire every time a Child is added. But no, it only fires around 80% of the time, as I tested it about 50 times. There’s also other problems such as it firing twice or too early.
This can get really annoying, as in my case, I get many complaints about the leaderboard “glitching”, even though it’s just not being loaded.
To start, you should probably use PlayerAdded, or add a check to make sure ChildAdded is a player (I assume you are checking for players). Is there anything before the script that causes it to yeild, like a WaitForChild, or Http call?
No, that’s the full script - just made it as a test.
And does .PlayerAdded work client side now? Haven’t tried it in a while, but last time I did it didn’t work. Also I already used the workaround for this using a remote & .PlayerAdded on the server
Um… are you sure it works? https://gyazo.com/6e9a425d814dd2bff969b3c509da84cb
I have a function that loads the players. Which is supposedly meant to be called when a player is added. It is also called for the player that joins as soon as he/she joins, which is why Player2 has it all and Player1 doesn’t
Running the code you provided earlier seems to work as expected.
Make sure you are looping through the players that are already on the server for a new player that joins, so that these are added to the leaderboard as well.
Do something similar to:
for _,Player in pairs(game.Players:GetPlayers())do
AddPlayer(Player)
end
game.Players.PlayerAdded:Connect(function(Player)
AddPlayer(Player)
end)
function LoadPlayers()
PlayerHolder:ClearAllChildren()
local Players = game.Players:GetPlayers()
for i = 1, #Players do
-- Only the start of the Function that loops through the players.
-- LoadPlayers is the function that loads the leaderboard.
LoadPlayers() -- Fires it for the player that joins.
LeaderboardEvent.OnClientEvent:Connect(function()
LoadPlayers()
end)
-- LeaderboardEvent is fired from the server with a `.PlayerAdded` which works fine
Though if I instead use .PlayerAdded on the client, it won’t call the function.
local Gui = script.Parent.PlayerHolder.Frame
local PlayerHolder = Gui:WaitForChild("Full") -- Frame that holds all the players.
local UpdateLB = game.ReplicatedStorage.Remotes.UpdateLB
local GetData = game.ReplicatedStorage.Remotes.GetData
local LeaderboardEvent = game.ReplicatedStorage.Remotes.LeaderboardEvent
local data = "Mobux"
local WaitCounter = 0
function LoadPlayers()
PlayerHolder:ClearAllChildren()
local Players = game.Players:GetPlayers()
for i = 1, #Players do
local PlrName = Players[i].Name
GetData:FireServer(data, PlrName)
GetData.OnClientEvent:Connect(function(Mobux, ToMobux) -- To get the player's currency data, to display it on the leaderboard.
if ToMobux == "ToMobux" then
mobux = Mobux
end
end)
wait(0.2)
local YSize = 0.16
local Position = ((i * YSize + 0.02) - YSize)
local PlayerButton = script.PlayerTemplate:Clone()
if PlayerButton:FindFirstChild(Players[i].Name) then -- This is for players that have a "Special Tag" - It's just a thing for my game.
PlayerButton[Players[i].Name].Visible = true
PlayerButton.PlrName.Text = ""
else
PlayerButton.PlrName.Text = PlrName
end
PlayerButton.Name = Players[i].Name
PlayerButton.Parent = PlayerHolder
local thePlayer = game.Players:FindFirstChild(PlayerButton.Name)
PlayerButton.Position = UDim2.new(0, 0, Position, 0)
if game:GetService("GamePassService"):PlayerHasPass(thePlayer, 837859114) then
PlayerButton:WaitForChild("Mobux").Text = "Inf"
else
repeat
wait()
WaitCounter = WaitCounter + 1
until mobux or WaitCounter == 20 -- Sorry for the mess here. Was just making extra checks n that.
WaitCounter = 0
if mobux then
PlayerButton:WaitForChild("Mobux").Text = mobux
end
end
end
end
LoadPlayers()
LeaderboardEvent.OnClientEvent:Connect(function()
LoadPlayers()
end)
UpdateLB.OnClientEvent:connect(function(dataName, dataValue, playerName) -- Fired when a players' currency changes, to update it on the leaderboard.
local player = game.Players:FindFirstChild(playerName)
if dataName == "Mobux" and not game:GetService("GamePassService"):PlayerHasPass(player, 837859114) then
repeat
wait()
until PlayerHolder:FindFirstChild(playerName)
PlayerHolder:FindFirstChild(playerName).Mobux.Text = dataValue
elseif game:GetService("GamePassService"):PlayerHasPass(player, 837859114) == true then
PlayerHolder:FindFirstChild(playerName).Mobux.Text = "Inf"
end
end)
And yeah i’m aware that it’s not exactly efficient. Haven’t been a scripter for long But at least it works, right? Edit-Putting in comments to explain certain things
Your for each player loop yields at least 0.2s for each player. If you have 10 players, your script will yield for at least 2 seconds. If anyone joins during that time, they won’t be iterated over in the loop.
This code has me feeling some type of way so il help you out a bit
First section:
GetData:FireServer(data, PlrName)
GetData.OnClientEvent:Connect(function(Mobux, ToMobux) -- To get the player's currency data, to display it on the leaderboard.
if ToMobux == "ToMobux" then
mobux = Mobux
PlayerButton:WaitForChild("Mobux").Text = mobux
end
end)
You REALLY should be using remote functions here to return the table from the server while this can yield you can run these operations in spawn() or a co routine as they aren’t that intensive. Using the same remote event to listen to and fire data from is just wrong imo.
Second section:
wait(0.2)
There’s no reason to yield the script in this position
Third section:
local PlayerButton = script.PlayerTemplate:Clone()
if PlayerButton:FindFirstChild(Players[i].Name) then -- This is for players that have a "Special Tag" - It's just a thing for my game.
PlayerButton[Players[i].Name].Visible = true
PlayerButton.PlrName.Text = ""
else
PlayerButton.PlrName.Text = PlrName
end
You should probably clone the master PlayerButton outside of the LoadPlayers function and then remove it as to prevent a duplicate master from still being parented to the gui.
Fourth section:
if game:GetService("GamePassService"):PlayerHasPass(thePlayer, 837859114) then
PlayerButton:WaitForChild("Mobux").Text = "Inf"
else
repeat
wait()
WaitCounter = WaitCounter + 1
until mobux or WaitCounter == 20 -- Sorry for the mess here. Was just making extra checks n that.
WaitCounter = 0
if mobux then
PlayerButton:WaitForChild("Mobux").Text = mobux
end
end--]]
Once again with the yielding, what I would do is run this section inside spawn() and then remove the WaitCounter as there isnt a purpose to it besides using up resources, there’s no reason for additional checks.
As @einsteinK said, yielding inside these functions is whats causing your ChildAdded event not to fire. Its not firing because the event hasn’t connected, since the function is still yielding from the loading players.