I'm trying to create a DataStore system that saves and loads number values when a player joins or leaves the game. To accomplish this, I clone a model with number values inside of it into ServerStorage when a player joins. Then, I rename the model to (player's name)Data. I'm running into a problem where the remote function is not returning the model, therefore not allowing me to manipulate the values.
First, I start by cloning the 'Data' model already inside of ServerStorage. NOTE: The 'default' table is indexed if the player has never player before. For example, if they haven't played before (no DataStore key is found), set the cash to 50. Otherwise, load the data.
local storage = game.ServerStorage
local service = game:GetService("DataStoreService"):GetDataStore("ForeverDevStats")
local default = {
cash = 50
}
game.Players.PlayerAdded:connect(function(player)
local data = storage.Data:clone()
data.Parent = storage
data.Name = player.Name .. "Data"
for _, store in ipairs(data:GetChildren()) do
--load the saved values, or set to the default value
store.Value = service:GetAsync(tostring(player.userId) .. store.Name:lower()) or default[store.Name:lower()]
end
end)
Next, I want to attach each value to a .Changed event (!!in a different script!!), so I can use them accordingly in my game. I do this by retrieving the data model through the use of a remote function.
The remote function is located in a model in Workspace, and is called 'GetPlayerData'. The code is as follows:
function script.Parent.GetPlayerData.OnServerInvoke(player)
return game.ServerStorage:FindFirstChild(player.Name .. "Data")
end
It is important that I note that the function does in fact find the data model, HOWEVER, it returns nil. Here is the script where I try to attach each value to a .Changed event:
--local script
local screen = script.Parent:WaitForChild("ScreenGui")
local displays = {
cash = screen:WaitForChild("Cash")
}
--inefficient, but I want to make sure the data exists
repeat wait() until Workspace.Functions.GetPlayerData:InvokeServer()
local data = Workspace.Functions.GetPlayerData:InvokeServer()
--the error is that 'data' is a nil value
for _, storage in ipairs(data:GetChildren()) do
storage.Changed:connect(function(value)
--manipulate a gui (not important)
displays[storage.Name:lower()].Output.Text = displays[storage.Name:lower()].StringOutput.Value:gsub("VALUE", tostring(value))
end)
end
For some reason, the remote function is returning a nil value instead of the player's data model. How can I fix this? Thanks in advance.

3 comments
Is the data being added to the ServerStorage like it's supposed to?
Yes. I made sure to check. Everything is being created properly. The only problem is that the remote function is returning nil for some reason.
I think I understand what is happening. Objects in ServerStorage cannot be changed from the client. I think that I have to have the .Changed function inside a remote function.