Part of the problem is that your code adopts severely bad practices that need to be rectified as soon as possible, because they’re kiting into other issues with your code that won’t be immediately realised.
As for the actual issue at hand, other than practice-related issues, your code is not at all wrong. So the question should be asked: how are you testing this, in a live game or in Studio? If in Studio, did you turn on API access and are you switching to the server view when you change Coins to test? HttpEnabled has no effect on DataStores working: if you have API access disabled and aren’t changing these from the server view, it will not do what you’re expecting.
Anyhow. It’s super important to address these practice problems moreso than the fact that your stats aren’t saving because these, again, kite into larger currently unseen issues. Better to tackle everything now than to wait for it to become a real problem.
I have included a refactoed system with comments to follow along. Make sure you actually gain some understanding from the code and read the annotations. They are there to help you learn, I’m not necessarily meaning to spoonfeed you code. If any issues arise, debug first and do some research so you can fix them on your own.
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
-- If you plan to add more DataStores, please use a single DataStore instead of
-- multiple. This'll save you request amounts and access headaches in the future.
local CoinsData = DataStoreService:GetDataStore("Coins")
-- We'll use this to track which players experienced an error in loading their
-- data, so that we can change how we're saving their data.
local DATA_ERRORED_FOR = table.create(100)
-- Let's assume your save operations are the same every time and so store
-- this in a function to prevent code redundancy.
local function saveData(player)
local userId = player.UserId
-- Assume this path exists, otherwise something's unexpectedly tampering with
-- the hierarchy of the player, especially its leaderstats.
local sessionCoins = player.leaderstats.Coins.Value
local encounteredError = DATA_ERRORED_FOR[userId]
if encounteredError then
-- Encountered a loading error, queue a data merge from this session.
-- We're assuming a load resulted in error and we're giving them 0 coins
-- to play with during this session, hence a merge.
CoinsData:UpdateAsync(userId, function(oldData)
-- Safe to default here, case is handled internally
local newCoins = oldData or 0
newCoins = newCoins + sessionCoins
return newCoins
end)
else
-- Never encountered an error, safe to overwrite
CoinsData:SetAsync(userId, sessionCoins)
end
end
local function playerAdded(player)
-- Create objects but don't parent until all properties are set
local folder = Instance.new("Folder")
folder.Name = "leaderstats"
local coins = Instance.new("IntValue")
coins.Name = "Coins"
local success, ret = pcall(CoinsData.GetAsync, CoinsData, player.UserId)
if success then
-- No load errors, okay to default here. We'll assume ret is an integer.
coins.Value = ret or 0
else
-- There was an error: log message in console, set to 0 and track player
warn("ERROR:", ret)
DATA_ERRORED_FOR[player.UserId] = true
coins.Value = 0
end
-- All values set and items handled, parent accordingly
coins.Parent = folder
folder.Parent = player
end
local function playerRemoving(player)
saveData(player)
-- Make sure key is nil, regardless of if player had a load error
DATA_ERRORED_FOR[player.UserId] = nil
end
Players.PlayerAdded:Connect(playerAdded)
Players.PlayerRemoving:Connect(playerRemoving)
for _, player in ipairs(Players:GetPlayers()) do
playerAdded(player)
end