Would having players data module in ServerStorage be problematic?

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)

1 Like

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.

1 Like

I did not even think about that! :open_mouth: Couldn’t I just remove their data from the module tho? Using table.remove or something

1 Like

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.

2 Likes

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.

DataTable[Player.UserId] = nil
4 Likes

Since ServerStorage and ServerScriptService aren’t visible to the client, you’d be perfectly fine storing data there!

1 Like

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

then in the client

DataUpdated.OnClientEvent:Connect(function(data)
    print(data.Level)
    print(data.Money)
    -- etc..
end)
1 Like