• Removing Key From Table ( key is player object )
    16 replies, posted
I have a table called GAME.Participants where the key is the player object and the value is a table containing data such as score. When a player leaves, I need to remove the key from the table equal to their player object. Can this be done? table.remove only takes a integer key, is there another way to remove it?
When the missing player is gone their player object is NULL or nil. May it be that the data associated with an invalid key is automatically garbage collected? I've not used gmod lua in awhile to be sure of it. You could try storing the data where the keys are a ply:UniqueID() integer, and remove them like that. [editline]7th April 2016[/editline] or tonumber(ply:SteamID64())
[QUOTE=bitches;50090066]When the missing player is gone their player object is NULL or nil. May it be that the data associated with an invalid key is automatically garbage collected? I've not used gmod lua in awhile to be sure of it. You could try storing the data where the keys are a ply:UniqueID() integer, and remove them like that. [editline]7th April 2016[/editline] or tonumber(ply:SteamID64())[/QUOTE] I'm not sure, I know that when the player leaves it leaves 'Player [NULL]:' in the table as a key. I could just do IsValid checks each time I loop through the table, which is probably wise anyway. Just means it leaves junk in the database that I'd rather remove on logout. On logout I could run through the table and remove any NULL entries, which there would only be one each time - would just like a more direct way.
I'd rather use table.remove since it's made for the purpose. You can hook into a gameevent for getting the SteamID64 on disconnect and use the numeric conversion as an index. [editline]7th April 2016[/editline] [img]http://wiki.garrysmod.com/favicon.ico[/img] [url=http://wiki.garrysmod.com/page/util/SteamIDTo64]util.SteamIDTo64[/url] [img]http://wiki.garrysmod.com/favicon.ico[/img] [url=http://wiki.garrysmod.com/page/gameevent/Listen]gameevent.Listen[/url]
Saying that, I can't loop through and check if valid because even if it's not, I can't remove it :P So you're saying instead of storing the player object as a key, store the SteamID64, but that means each time I loop through the players I've got to convert it back to the player object.
Hook into PlayerDisconnected, as it passes a player object to hooks, and do [code] hook.Add("PlayerDisconnected", "Remove Player From Table", function(player) tableOfPlayers[player] = nil end) [/code] Similarly, if you just want to cleanse the table, I don't see why you couldn't do [code] for k, v in pairs(tableOfPlayers) do if ( !IsValid(k) ) then tableOfPlayers[k] = nil end end [/code]
Actually, I've got a better idea. I'll store [CODE]GAME.Participants = { [1] = player_object, [2] = player_object }[/CODE] then [CODE]GAME.Data = { player_object = { score = 0 } }[/CODE] Then I can use: [CODE]for _, ply in pairs(GAME.Participants) do print(GAME.Data[ply].score) end[/CODE] Then I can remove the player from the GAME.Participants when they disconnect - but the data of disconnected players is still available. [editline]8th April 2016[/editline] Ah, setting to nil would make it get removed anyway so I think you're right - but then my idea above means the data of players disconnected is still available, so I might do that anyway. Thanks a lot though for your advice.
When they disconnect that data will be destroyed, in the way you have represented. Data inside a player object is destroyed with the loss of the player object. If you want the data after they disconnect you need to store the player's identity, not the player. [editline]7th April 2016[/editline] [lua] GAME.playerdata = {} local datatemplate = { score = 0 connected = true } hook.Add("PlayerInitialSpawn","initspawndata",function(ply) local playerData = GAME.playerdata[util.SteamIDTo64(ply:SteamID())] if !playerData then playerData = table.Copy(datatemplate) else playerData.connected = true end end) function GAME.addToScore(ply,scoreIncrease) local playerData = GAME.playerdata[util.SteamIDTo64(ply:SteamID())] playerData.score = playerData.score + scoreIncrease end gameevent.Listen("player_disconnect") hook.Add("player_disconnect","disconnectgamedata",function(data) GAME.playerdata[util.SteamIDTo64(data.networkid)].connected = false end) [/lua] [editline]7th April 2016[/editline] and you could at the start of a new round, once you definitely don't care about old scores, remove them easily by doing a kv loop and table.remove(k) if !blahblah.connected [editline]7th April 2016[/editline] it's good to preserve scores mid-round because sometimes players get disconnected due to internet problems and it's really nice if they don't lose their score when they come back during the same round [editline]7th April 2016[/editline] i've just made one final edit to make that concept work and preserve the score
Ok, thanks a lot - I've decided to go for this. [CODE]hook.Add("PlayerAuthed", "SetupPlayer", function() table.insert(GAME.Participants, ply) GAME.Data[ply:SteamID64()] = {} GAME.Data[ply:SteamID64()].score = 0 end )[/CODE] This will equal: [CODE]GAME.Participants = { [1] = player_object, [2] = player_object } GAME.Data = { ["STEAMID64"] = { score = 0 }, ["STEAMID64"] = { score = 0 } }[/CODE] Then, I can loop through the players like: [CODE] for _, ply in pairs(GAME.Participants) do print(GAME.Data[ply:SteamID64()].score) end hook.Add("PlayerDisconnected", "RemoveFromParticipants", function(ply) table.remove(GAME.Participants, ply) end )[/CODE] Which means their data is preserved, but GAME.Participants will only hold valid players. I have to make it as generic as possible as it has to work over multiple game-modes in the same format.
I really don't see what the purpose of your Participants table is. Why not just use player.GetAll()?
[QUOTE=bitches;50090393]I really don't see what the purpose of your Participants table is. Why not just use player.GetAll()?[/QUOTE] Because some players may be on the server that are not participants, and therefore must not be affected by any game events. Putting the participants in GAME.Participants means there can be other people on the server who are unaffected by the flow of the game.
You could use the code I posted and additionally track whether or not they are participants. Keeping all the data in one concise spot per player is a lot nicer.
there's really no reason to do this player objects can't and won't be garbage collected under normal gmod conditions because of a leak of references, so even if you do remove it from your table you won't be able to have it collected if you need to find when it goes invalid, add a hook to playerdisconnected if you need to remove or use the keys for data usage you need to call IsValid
[QUOTE=bitches;50090419]You could use the code I posted and additionally track whether or not they are participants. Keeping all the data in one concise spot per player is a lot nicer.[/QUOTE] It's true, but it also feels a little odd for two reasons: 1. When looping through participants, every time I'd have to do: [CODE]for k, v in pairs(GAME.playerdata) do local p = player.GetBySteamID64( k ) print(p:Nick()) end[/CODE] 2. It's easier to remove them from the participants table, and not have to do an extra check when looping through participants to see if connected == false What's your opinion? [editline]8th April 2016[/editline] It also technically ( although practically probably doesn't make a difference ) avoids the having to skip past players no longer connected when looping through participants.
That's a good point.
Wouldn't it be easier to store the score directly onto the player object? Besides we got functions for gamemodes to handle joining players. Like :Team() and GM:PlayerSpawnAsSpectator. Even team.GetPlayers(n) :P But as long it works.
[QUOTE=Nak;50092789]Wouldn't it be easier to store the score directly onto the player object? Besides we got functions for gamemodes to handle joining players. Like :Team() and GM:PlayerSpawnAsSpectator. Even team.GetPlayers(n) :P But as long it works.[/QUOTE] The reason I think it's better for it to be in a separate table then on the player object, is because at the end of the game it needs to record a winner, and this won't be doable if the player has disconnected and their data is lost, hence the separate Participants and Data tables.
Sorry, you need to Log In to post a reply to this thread.