I just need to save player data in my game, this is stuff they bought with in-game currency and leaderstat values. The issue I’m having is recently the data saves just stopped working for no apparent reason, I first noticed it yesterday but it could of started beforehand because I wasn’t paying attention to the win/bit values in my testing.
I looked for solutions around the web, I don’t know if I just didn’t search right but I think my problem would be hard to find considering I have no idea what is the problem causing the issue, I haven’t gotten any errors. It uses Server Scripts and Module Scripts. I don’t know if a roblox update might have something to do with it but I don’t see any other reason to why it would randomly stop working. The game has a in-game leaderboard tracking the player with the most wins, it updates every 120 seconds so I don’t know if this leaderboard could be causing issues
local DataHandler = require(script:WaitForChild("DataHandler"))
local Good = game.Workspace.Sounds.Letsgo
local Bad = game.Workspace.Sounds.ErrorSound
local Players = game:GetService("Players")
local Data = {}
game:GetService("Players").PlayerAdded:Connect(function(Player)
local data = DataHandler:Init(Player)
Data[Player] = {
TrailData = data.TrailData;
EmoteData = data.EmoteData;
AnimationData = data.AnimationData;
PetData = data.PetData;
UpdateId = data.UpdateId;
GPId = data.GPId
}
end)
---------------------------
local Conn = game.Players.PlayerRemoving:Connect(function(Player)
local leader = Player:FindFirstChild("leaderstats")
DataHandler:Save(Player, {
Bits = leader.Bits.Value,
Wins = leader.Wins.Value,
SinglePlayerWins = leader.SinglePlayerWins.Value,
CompWins = leader.CompWins.Value,
TrailData = Data[Player].TrailData,
AnimationData = Data[Player].AnimtationData,
EmoteData = Data[Player].EmoteData,
PetData = Data[Player].EmoteData,
UpdateId = Data[Player].UpdateId,
GPId = Data[Player].GPId
})
end)
-- BindToClose mass Save
game:BindToClose(function()
Conn:Disconnect()
for _, Player in pairs(Players:GetPlayers()) do
local leader = Player:FindFirstChild("leaderstats")
coroutine.wrap(DataHandler.Save)(nil, Player, {
Bits = leader.Bits.Value,
Wins = leader.Wins.Value,
SinglePlayerWins = leader.SinglePlayerWins.Value,
CompWins = leader.CompWins.Value,
TrailData = Data[Player].TrailData,
AnimationData = Data[Player].AnimtationData,
EmoteData = Data[Player].EmoteData,
PetData = Data[Player].EmoteData,
UpdateId = Data[Player].UpdateId,
GPId = Data[Player].GPId
})
end
if game:GetService("RunService"):IsStudio() then
wait(3)
else
wait(30)
end
end)
end)
This is the parts of the script that save the data as the rest of the script is a couple 100 lines and is irrelevant to the problem of saving data, if needed I can provide it if necessary.
local DSS, Run, Players = game:GetService("DataStoreService"), game:GetService("RunService"), game:GetService("Players")
local SERVER_STORE = "BitsNWins"
local TEST_STORE = "randomTestStore"
local MAX_RETRIES = 1
local CREATE_LEADERSTATS = true
local Store = DSS:GetDataStore(SERVER_STORE)
local DEFAULT_DATA = {
Bits = 0;
Wins = 0;
CompWins = 0;
SinglePlayerWins = 0;
TrailData = {};
EmoteData = {};
PetData = {};
AnimationData = {};
GPIdData = {};
UpdateId = 0;
}
if Run:IsStudio() then
Store = DSS:GetDataStore(TEST_STORE)
end
local DataHandler = {}
function DataHandler:AccuWait(n)
local t = tick()
while true do
if tick()-t >= n-0.005 then
return
end
Run.Stepped:Wait()
end
end
function DataHandler:CheckForInconsistencies(Data)
for Name, Val in pairs(DEFAULT_DATA) do
if not Data[Name] then
Data[Name] = Val
end
end
for Name, _ in pairs(Data) do
if not DEFAULT_DATA[Name] then
Data[Name] = nil
end
end
return Data
end
function DataHandler:Init(Player)
for i = 1, MAX_RETRIES do
local Success, Val = pcall(function()
return Store:GetAsync(Player.UserId) or DEFAULT_DATA
end)
if Success then
local Data = DataHandler:CheckForInconsistencies(Val)
if CREATE_LEADERSTATS then
local Leaderstats = Instance.new("Folder")
Leaderstats.Name = "leaderstats"
Leaderstats.Parent = Player
for Name, Val in pairs(Data) do
if Name == "UpdateId" then
continue
end
if type(Val) == "number" then
local newVal = Instance.new("IntValue")
newVal.Name = Name
newVal.Value = Val
newVal.Parent = Leaderstats
Data[Name] = nil
end
end
end
return Data
end
if DataHandler:GetReq("GetAsync") <= 5 then
DataHandler:AccuWait(7)
end
DataHandler:AccuWait(3)
end
end
-- Save player data
function DataHandler:Save(Player, Data)
for i = 1, MAX_RETRIES do
local Success, ErrorMessage = pcall(function()
Store:UpdateAsync(Player.UserId, function(OldData)
if not OldData or OldData.UpdateId == Data.UpdateId then
Data.UpdateId = Data.UpdateId + 1
return Data
end
return nil
end)
end)
if Success then
return
end
warn("Data was not saved! " .. ErrorMessage)
DataHandler:AccuWait(3)
end
end
function DataHandler:Erase(Player)
for i = 1, 3 do
local Success = pcall(Store.RemoveAsync, Player.UserId)
if Success then
DataHandler[Player.UserId] = DEFAULT_DATA
return
end
if DataHandler:GetReq("RemoveAsync") <= 5 then
DataHandler:AccuWait(7)
end
DataHandler:Accuwait(3)
end
end
return DataHandler
Module