I’m making a player list system, and waiting for the humanoid to die. The humanoid.Died event only fires once. I used a character.removing at first - and for some reason that event fires right before the character respawns, so it is equally buggy.
I have tried to re-define the character and humanoid variables, however the humanoid.Died event still only triggers the first time the humanoid dies.
--Update the list when an event happends
local function updateListBasedOnEvents()
local players = game.Players:GetPlayers()
for index,plr in pairs(players) do
--Cache detection
local humanoid = character:WaitForChild("Humanoid")
plr.CharacterAdded:Connect(function()
print("character respawned")
character = plr.Character or plr.CharacterAdded:Wait()
humanoid = character:WaitForChild("Humanoid")
formatPlayerList(shouldUpdateCharacter)
end)
humanoid.Died:Connect(function()
print("character died")
end)
end
end
It’s not just the humanoid.Died event, it is all other events in that scope. This means that the character.Added event destroys the scope of the loop?
If that is the case I don’t know how to approach this. My system relies on looping through the players in a loop that is in a function that is connected to a corountine.
Because when the player dies, their character is deleted and all descendants are as well.
Move your humanoid.Died under the characteradded.
When a descendant or any type becomes nil, any connections ALSO become nil. This is to prevent leakage and unnecessary code to disconnect old connections.
--Update the list when an event happends
local function updateListBasedOnEvents()
local players = game.Players:GetPlayers()
for index,plr in pairs(players) do
--Cache detection
local humanoid = character:WaitForChild("Humanoid")
plr.CharacterAdded:Connect(function()
print("character respawned")
character = plr.Character or plr.CharacterAdded:Wait()
humanoid = character:WaitForChild("Humanoid")
humanoid.Died:Connect(function() -- move here so its redefined after death
print("character died")
end)
formatPlayerList(shouldUpdateCharacter)
end)
end
end
Ok wow that is interesting.
I tested the new version and it seems to be working.
Is this system looking bug-free? I will mark you post as solution either way.
local function events(plr)
--Reels detection
local leaderstats = plr:WaitForChild("leaderstats")
local reels = leaderstats:WaitForChild("Reels")
reels:GetPropertyChangedSignal("Value"):Connect(function()
shouldUpdateCharacter = true
formatPlayerList(shouldUpdateCharacter)
end)
--Equipment detection
local character = plr.Character or plr.CharacterAdded:Wait()
local equipmentFolder = character:WaitForChild("Equipment")
equipmentFolder.DescendantAdded:Connect(function(descendant)
if descendant:FindFirstChild("KeyModel") then
shouldUpdateCharacter = true
formatPlayerList(shouldUpdateCharacter)
end
end)
equipmentFolder.DescendantRemoving:Connect(function(descendant)
if descendant:FindFirstChild("KeyModel") then
shouldUpdateCharacter = true
formatPlayerList(shouldUpdateCharacter)
end
end)
--Cache detection
local humanoid = character:WaitForChild("Humanoid")
humanoid.Died:Connect(function()
print("character died")
end)
end
--Update the list when an event happends
local function updateListBasedOnEvents()
local players = game.Players:GetPlayers()
for index,plr in pairs(players) do
events(plr)
plr.CharacterAdded:Connect(function()
print("character respawned")
events(plr)
formatPlayerList(shouldUpdateCharacter)
end)
end
end
equipmentFolder.DescendantAdded:Connect(function(descendant)
if descendant:FindFirstChild("KeyModel") then
shouldUpdateCharacter = true
formatPlayerList(shouldUpdateCharacter)
end
end)
equipmentFolder.DescendantRemoving:Connect(function(descendant)
if descendant:FindFirstChild("KeyModel") then
shouldUpdateCharacter = true
formatPlayerList(shouldUpdateCharacter)
end
end)
I’m not sure what these are for, but ensure that you want these to stick around forever once you connect them.
If you destroy the folder, then ignore this completely. However, if this stays in the game for a while and doesn’t need these connections, ensure to disconnect at some point.
local leaderstats = plr:WaitForChild("leaderstats")
local reels = leaderstats:WaitForChild("Reels")
please do not use waitforchild. WaitForChild is useless in most cases because FindFirstChild does its job better. WaitForChild should be used for things that wont exist until the game/player is loaded. For example, waiting for elements of a player’s GUI to load.
Do this for all elements in your script that use waitforchild that ARE NOT one of the cases I described
leaderstats will exist the moment the server adds a player to the game, assuming your leaderstats is instantaneous. use FindFirstChild; if it returns nil then you can reloop and try again or cancel. FindFirstChild will simply check if the object exists; waitforchild will wait FOREVER until the object exists, or until a set time passes. In most cases, if the object didn’t exist in the first place, It will not randomly appear 30 seconds in the future.
I used to overuse waitforchild and it has no purpose when objects either will or wont exist.
One more thing I noticed:
This will continuously add the same players as a connection.
Change to this:
--Update the list when an event happends
local addedPlrs = {}
local function updateListBasedOnEvents()
local players = game.Players:GetPlayers()
for index,plr in pairs(players) do
events(plr)
if not addedPlrs[plr] then
addedPlrs[plr] = true
plr.CharacterAdded:Connect(function()
print("character respawned")
events(plr)
formatPlayerList(shouldUpdateCharacter)
end)
players.PlayerRemoving:Connect(function() addedPlrs[plr] = nil end)
end
end
end
This is a function that is created and destroyed by players joining and leaving. I tested it with PlayerRemoving, and it seemed to function like it should - updating both the list of players and no duplication of events, because closing a coroutine should remove all the events.
local corountineVariable = coroutine.create(updateListBasedOnEvents)
coroutine.resume(corountineVariable)
--Runs when a player joins
game.Players.PlayerAdded:Connect(function(plr)
coroutine.close(corountineVariable)
shouldUpdateCharacter = true
corountineVariable = coroutine.create(updateListBasedOnEvents)
formatPlayerList(shouldUpdateCharacter)
end)
--Runs when a player leaves
game.Players.PlayerRemoving:Connect(function(plr)
coroutine.close(corountineVariable)
shouldUpdateCharacter = true
corountineVariable = coroutine.create(updateListBasedOnEvents)
formatPlayerList(shouldUpdateCharacter)
end)
Those are for equipment changes so that the character updates according to what they’re currently wearing. They should function just like the reel update (reels sort the list).
The first time the function is ran, wouldn’t it be somewhat close to the function that sets up the values on the server? Especially because these values are relying on datastores? I get what you mean if the values are inside a fishing loop or something - cause those values probably have a 99.99999% chance to be loaded, but here in the playerList script I am not sure.
No, it will not be somewhat close. The task scheduler is a very advanced concept that even I myself do not fully comprehend, although imagine every script as a point on a graph. The script will not run until x = (x position of script) and x is representing time.
Essentially, scripts are scheduled to run at a certain point automatically by Studio. Creation of services, objects, scripts, and assets are all the first thing that occurs. Scripts will not run until somewhere after the server has loaded, probably a few milliseconds which is more than enough time for all your objects to be created.