Of course, using a table would be better because it allows you to store multiple values. Strings also allow you to store tables, but they need to be converted into strings using HttpService when saving, though you would still need to translate them to a table when getting the data. Table does the same thing, but you don’t need to encode and decode the data.
Seeing your code all messed up, not many people would read and understand the code; since the title is related to DataStores, others would just recommend using modules, which clearly you are not ready for since you don’t even know how to fix your own issue. Why they only recommend using modules is because they are reliable, which helps developers avoid player data loss.
Also, why are you creating an event listener for value inside the player’s GUI? The event would only get fired when the server was responsible for doing so. This probably the reason why the players data is not getting saved. You need a remote event.
And why are you saving the player’s data every time the event gets fired, which is unlikely to get fired unless the server changes the value? You need to only save the player’s data when leaving the game, or every five minutes, with the “UpdateAsync” method. Example:
Responsible for getting and saving player data
local KEY_IDENTIFIER = "Player_"
local MAX_ATTEMPT = 10
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local Datastore = DataStoreService:GetDataStore("PlayersData")
local PLAYERSDATA_PATH = ReplicatedStorage.PlayersData
-- This module does not contain anything
local PlayersData = require(PLAYERSDATA_PATH)
-- This is why open source services are reliable
-- We don't need to do this unnecessary function
local function GetPlayerData(player: Player, attempt: number?): (boolean, PlayersData.Data?)
attempt = attempt or 0
local success, data = pcall(function()
return Datastore:GetAsync(KEY_IDENTIFIER .. player.UserId)
end)
if not success and attempt < MAX_ATTEMPT then
task.wait(5)
return GetPlayerData(player, attempt + 1)
end
return success, data
end
Players.PlayerAdded:Connect(function(player)
local success, data = GetPlayerData(player)
if not success then
player:Kick("Something wen't wrong trying to retrieving data")
end
-- We are initilizing the players data for new players
if data == nil then
data = {
Items = {},
Money = 0,
}
end
PlayersData[player] = data
end)
Players.PlayerRemoving:Connect(function(player)
local data: PlayersData.Data = PlayersData[player]
if data then
Datastore:UpdateAsync(KEY_IDENTIFIER .. player.UserId, function(pastData)
-- this function just allows you to check if the data should be updated
-- you can do whatever you want from here
-- if your not going to do anything from here just use SetAsync instead.
return data
end)
else
-- This is unlikely to happen
warn(player.Name .. "_" .. player.UserId, "was not able to be added to PlayersData")
end
end)
PlayersData module
Like what I said from above this module does not contain anything other than a few stuffs, this just allows for other script to access the player data. Unless you want to do some advance scripting such as metatables which allows you to do a lot like adding event listeners for other script to listen when the data was changed.
export type Data = {
Items: { string },
Money: number,
}
return {}
When the player bought something from the shop
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local PLAYERSDATA_PATH = ReplicatedStorage.PlayersData
local RemoteFunctionBuy: RemoteFunction = ReplicatedStorage.RemoteFunctionBuy
local Items: Folder = ReplicatedStorage.Items
local PlayersData = require(PLAYERSDATA_PATH)
RemoteFunctionBuy.OnClientInvoke = function(player, itemName: string): (boolean, string?)
local data: PlayersData.Data = PlayersData[player]
local item = Items:FindFirstChild(itemName)
if not item then
return false, "Invalid item"
end
local price: number = item:GetAttribute("Price")
if data.Money < price then
return false, "You need " .. price - data.Money .. " more!"
end
item:Clone().Parent = player.Backpack
data.Money -= price
return true
end