My current data store setup is I have a module script inside ServerStorage called ‘PlayerData’ which is literally just this
return {}
And how I set it up is when a player is added, it runs the below function.
function DataService:LoadData(player)
local LoadData = PlayerDataStore:GetAsync(player.UserId) or cloneTable(DefaultData)
PlayerData[player.UserId] = updateData(LoadData, cloneTable(DefaultData))
DataReady = true
end
DefaultData looks like this
return {
Level = 1
}
I’m just wondering, would this become a problem with a number of players in game? Since there’s only 1 module for PlayerData, or is how I have set it up correct? So PlayerData would look like this
return {
1234 = {Level = 1},
5678 = {Level = 1}
}
With the numbers being each individual players id.
This is how it should work, I’m just having trouble visualising how it would actually look. I try to store the PlayerData inside this separate module, so I can easily edit its contents (for anyone who might ask why it’s like this)
I am yet to test this in online play (tested in studio and worked fine with multiple clients, but not sure if it will act differently with real players)
This should work fine, I handle data like this too and I haven’t had any issues. If your concern is storing too many players in a table, you can always set the key to nil when a player leaves.
Simply assigning a key to nil removes that key. So removing a player’s data from the module is as simple as doing PlayerData[player.UserId] = nil.
Using table.remove would cause issues because table.remove removes the specified (numerical) key, let’s say k, and it moves down the keys above k by 1.
You’ll probably want to take a look at your code rather than where you’re placing it. The effectiveness of a ModuleScript does not change if you move it elsewhere. I prefer to keep all my modules in ServerScriptService however, given the name… ServerScriptService.
I only put data in ServerStorage if I’m working with caches and physical representations of player data, such as a hierarchy of folders and ValueObjects. This makes it easier for me to set up access points and after-leave saves. I also fancy working with ValueObjects for the sake of my own sanity.
I was going to comment on the way you were doing this being inefficient, but I see that you’ve come prepared with a copy function. That’s good. I personally set up default data sets by returning a newly constructed table.
return function()
return {
Level = 1,
}
end
This way, it doesn’t reference the same table each time it’s called and I don’t have to create any table copying functions. Fresh table each time.
local createNewSet = require(DefaultData)
local playerData = GetAsync or createNewSet()
Visually though, your data module would look exactly how you set it up to be. Each indice in the table would be a UserId, with the assigned value being their data table. Player number would not affect anything major. You’re only doing one table lookup at indice i.
{
[UserId] = {dataArray}
}
I would suggest not using table.remove in this case. It’s typically better to use it when you have a list and not a dictionary. If you need to blank out a player’s data or remove it from your session cache, set the indice of their UserId to nil. This is much like what above posted.
Please note that the advantage of it being hidden from the clients, is also a disadvantage. You won’t get the normal replication meaning that accessing the clients data from the clientside becomes more problematic.
You’d either set up a cache system to store the data on the client side as well, or have to request the data from the server.
Always had an easy fix to that. Whenever I change players data, I fire a RemoteEvent which contains the players data table. Then from the client I can just refer to it
DataUpdated:FireClient(player, Data) -- Data being their stored Data