As a Roblox developer, it is currently too troublesome to send dictionaries through RemoteEvents or RemoteFunctions when the dictionaries use Player instances as keys.
A common pattern in code is to have a dictionary on the server which uses Player instances as keys to map certain data to each player. In my game I use this pattern dozens of times to assign for example SpawnLocations to each player, or equipped items, or locations inside the game, and a lot more.
It is common that you may want to replicate this data to clients. The naive assumption is that you can send the dictionary through a RemoteEvent to the clients. There’s a caveat with this however, which is that the Player instance ‘key’ gets serialized which will change how a lot of checks may acts.
Consider the following server Script and client LocalScript:
-- server Script
local Dictionary = {}
game.Players.PlayerAdded:Connect(
function(Plr: Player)
Dictionary[Plr] = Plr
for k, v in pairs(Dictionary) do
print(k, v)
print(k == Plr, v == Plr)
print(k.UserId, v.UserId)
end
wait(2)
game.ReplicatedStorage.RemoteEvent:FireClient(Plr, Dictionary)
end
)
-- client LocalScript
game.ReplicatedStorage.RemoteEvent.OnClientEvent:Connect(
function(Dictionary)
for k, v in pairs(Dictionary) do
print(k, v)
print(k == game.Players.LocalPlayer, v == game.Players.LocalPlayer)
print(k.UserId, v.UserId)
end
end
)
The server will print the following information (in my case):
Zomebody Zomebody
true true
8291118 8291118
The client will print this information however:
<Instance> (Zomebody) Zomebody
false true
nil 8291118
The interesting part about what is printed on the client is that the value in the dictionary is still fully recognized as a player instance, but the key is serialized in some manner that makes it impossible to retrieve certain information. The key is no longer equal to my player character and the UserId is also set to nil so there seems to be no way to ‘recover’ the player in this case.
This means that when sending dictionaries of the form Dictionary[Player] = value
to clients, you will need to first transform the dictionary such that the player key is replaced with the player’s UserId so that the client can then use game.Players:GetPlayerByUserId()
to get back the player instance. This is very cumbersome because it usually involves creating a new table to copy information into and the client will then also need to take extra steps to get back the Player instance.
The existing behavior may also cause bugs in your code. The output will still print <Instance> (name)
which may be interpreted by the developer as a Player instance, even though it doesn’t quite work that way. Trying to compare this key to player instances will always equal false
, which has caught me off-guard many times by now.
I would like the current behavior to change such that the dictionary keys can be reconstructed into Player instances. This would simplify a lot of code that involves sending such dictionaries across the network.