Hello! I am making a table that stores player instances. But if a player left, will that player instance in the table become nil? And if yes, can I remove that with table.remove()?
You need to first find the player that was removed with table.find, here is a code example:
local myCoolPlayerTable = {}
game.Players.PlayerAdded:Connect(function(player)
table.insert(myCoolPlayerTable, player)
print(myCoolPlayerTable) -- prints all players who joined
end)
game.Players.PlayerRemoving:Connect(function(player)
local PlayerPos = table.find(myCoolPlayerTable, player)
table.remove(myCoolPlayerTable, PlayerPos)
print(myCoolPlayerTable) -- prints all players except the one who left (might be an empty table when there was only 1 player in the game)
end)
Adding on to this, if you don’t wish to use table.remove for whatever reason, you can also set the index to nil and it should do the same thing table.remove does.
If it’s a local script the script will become by default nil meaning the table wouldn’t exist for that certain client once he’s left the game but doing it on the server side or by script it would only set to nil once the game has shutdown.
So if you have the table on the server side you’ll have to set it to nil manually.
Why even make a seperate table? Why not just use game.Players:GetPlayers()
?
You’d have to constantly update it
Why bother with all these elaborate procedures with the table library? Just do this:
local playerService = game:GetService("Players")
local playerDataTable = {}
playerService.PlayerAdded:Connect(function(player)
local key = player.UserId
playerDataTable[key] = player
end)
playerService.PlayerRemoving:Connect(function(player)
local key = player.UserId
playerDataTable[key] = nil
end)
That’s all there is to it. You use the player’s UserId as the key into the table. If something weird happens, you can audit the table by checking each entry and see if they are in the list provided by Players:GetChildren()
. Alternatively, you can use the player instance itself as the key as well. Not sure what you are using it for though so I can’t recommend which way you want to go with this.
No? When ever you want to use the table just call that function.
Or
local plrtable = {}
local function UpdatePlrTable()
table.clear(plrtable)
for _,plr in pairs(game.Players:GetPlayers())
table.insert(plrtable,plr)
end
end
game.Players.PlayerAdded:Connect(UpdatePlrTable)
game.Players.PlayerRemoving:Connect(UpdatePlrTable)
But I am local scripting a spectate system so game.Players.PlayerAdded and Removing is kinda confusing for me
Here’s the script:
local button = script.Parent
local ScreenGui = button.Parent
local plr = game.Players.LocalPlayer
local ShopE = ScreenGui.SpecE
local number = 1
local speclabel = ScreenGui.Spectate
local cam = game.Workspace.CurrentCamera
local function getplayers()
local e = {}
for i,plr in pairs(game.Teams.Player:GetPlayers()) do
if plr.Character and plr.Character:FindFirstChild("Humanoid") and plr.Character:FindFirstChild("Humanoid").Health ~= 0 then
table.insert(e,plr)
end
end
return e
end
local currentplayers
local ts = game:GetService("TweenService")
local tsinfo = TweenInfo.new(
0.4,
Enum.EasingStyle.Linear,
Enum.EasingDirection.Out,
0,
false,
0
)
button.MouseButton1Click:Connect(function()
button.Click:Play()
if speclabel.Visible then
speclabel.Visible = false
cam.CameraSubject = plr.Character.Humanoid
else
if plr.Team == game.Teams.Lobby and game.Workspace.CanSpectateAndBuy.Value then
local plrss = getplayers()
if #plrss > 0 then
currentplayers = plrss
speclabel.Visible = true
number = 1
cam.CameraSubject = plrss[number].Character.Humanoid
speclabel.Text = plrss[number].Name
end
end
end
end)
game.Workspace.CanSpectateAndBuy.Changed:Connect(function()
if game.Workspace.CanSpectateAndBuy.Value == false then
speclabel.Visible = false
cam.CameraSubject = plr.Character.Humanoid
end
end)
speclabel.Right.MouseButton1Click:Connect(function()
local testnumber = number+1
local spectateplr
repeat
if testnumber > #currentplayers then
testnumber = 1
end
if currentplayers[testnumber] and currentplayers[testnumber].Character:FindFirstChild("Humanoid") and currentplayers[testnumber].Character.Humanoid.Health ~= 0 then
else
table.remove(currentplayers,currentplayers[testnumber])
testnumber+=1
end
until (currentplayers[testnumber] and currentplayers[testnumber].Character:FindFirstChild("Humanoid") and currentplayers[testnumber].Character.Humanoid.Health ~= 0) or #currentplayers == 0
if #currentplayers ~= 0 then
number = testnumber
cam.CameraSubject = currentplayers[number].Character.Humanoid
speclabel.Text = currentplayers[number].Name
end
end)
speclabel.Left.MouseButton1Click:Connect(function()
local testnumber = number-1
local spectateplr
repeat
if testnumber <1 then
testnumber = #currentplayers
end
if currentplayers[testnumber] and currentplayers[testnumber].Character:FindFirstChild("Humanoid") and currentplayers[testnumber].Character.Humanoid.Health ~= 0 then
else
table.remove(currentplayers,currentplayers[testnumber])
testnumber-=1
end
until (currentplayers[testnumber] and currentplayers[testnumber].Character:FindFirstChild("Humanoid") and currentplayers[testnumber].Character.Humanoid.Health ~= 0) or #currentplayers == 0
if #currentplayers ~= 0 then
number = testnumber
cam.CameraSubject = currentplayers[number].Character.Humanoid
speclabel.Text = currentplayers[number].Name
end
end)
button.MouseEnter:Connect(function()
ts:Create(ShopE,tsinfo,{BackgroundTransparency = 0.5}):Play()
end)
button.MouseLeave:Connect(function()
ts:Create(ShopE,tsinfo,{BackgroundTransparency = 1}):Play()
end)
Well, if you’re going to go through all that, then just do this:
local plrtable = {}
local function UpdatePlrTable()
plrtable = game.Players:GetPlayers()
end
game.Players.PlayerAdded:Connect(UpdatePlrTable)
game.Players.PlayerRemoving:Connect(UpdatePlrTable)
game.Players:GetPlayers()
returns a table, so just use that. No need to copy it in a for loop into a new table.
Yep I did mention that but why go through the hassle of doing that when you can simply whenever you call plrtable you replace it with game.Players:GetPlayers()
Pardon me but… what? Care to explain a bit more?
In any case, you’re still going to have to burn CPU time on the server for it. The solution that I posted works well. I see nothing wrong with it because it’s event driven, as yours is. I believe that mine is simpler to use and understand. Plus, it uses the player’s UserId as the key which Rolbox guarantees is unique to each player unlike the name.
He’s doing a spectate. That’s on the client.
As players are added and removed from the server, the table of players get’s updated. That’s all that Players.PlayerAdded and Players.PlayerRemoving does. There’s a community tutorial on this that’s pretty good. I’ve used it myself when making a spectate.
local playerService = game:GetService("Players")
local localPlayer = playerService.LocalPlayer
local playerDataTable = {}
-- Add players to the list when the join the server.
playerService.PlayerAdded:Connect(function(player)
playerDataTable[player.UserId] = player
end)
-- Remove players from the list when they leave the server.
playerService.PlayerRemoving:Connect(function(player)
playerDataTable[player.UserId] = nil
end)
-- Initial filling of the table.
for _, player in ipairs(playerService:GetPlayers()) do
if player ~= localPlayer then
playerDataTable[player.UserId] = player
end
end)
That’s the basics as I remember them. You fill the table initially, then just add or remove players when the arrive or leave the server. It still needs the events to handle the spectate toggle, next player, and previous player GUI buttons, but that’s the gist of it.
So, i made a nil value called currentplayers and a number var = 1. And inside the spectate button click event, I set currentplayers to a table that contains players with choosen team and set number to 1 and make the players cam’scamera subject to currentplayers[number].Character.Humanoid.
In the “right” button click event. I checked if currentplayers[number+1] isn’t nil(I guess if that player left that value will become nil). Same with left button but number-1
I can’t test cuz my potato pc will explode if I open 2 boblox apps. So can you tell me is my thought about when a player left, all that player instances in every table will become nil right?
I am not sure if a player goes nil or not when left. You can test that out with a friend perhaps? But if not then you can see if game.Players:FindFirstChild(currentplayers[number+1]) ~= nil
My guess is no. The reasoning is that the Player instance has an active reference to it in the table. When the player leaves, Player.Parent
is set to nil, but it’s not removed from memory or garbage collected because of the active table reference. When the table entry gets set to nil, then the Player instance goes away.
@ImNotInfected13 If you code it that way and explicitly set the table entry representing the player to nil, you will not go wrong. It’s considered good practice to clean things up when you’re done using them.
Nvm I found a way to check. Just check if the parent is nil or not
This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.