So I’ve recently some feedbacks from my community, and some players are complaining about their data not saving when afking for too long. I don’t know what is causing this, and I don’t know what I’ve done wrong too
(perhaps the :BindToClose event not coded right?)
This is my script :
-------------------- CONFIG --------------------
local DataStore_Name = "Data V2"
local Default_Luck = 2
local Default_Speed = 1
local Default_Coins = 1
local Default_SlotsAmount = 5
-------------------- VARIABLES --------------------
local DSS = game:GetService("DataStoreService")
local DS = DSS:GetDataStore(DataStore_Name)
local SessionData = {}
local Modules = script.Parent.Parent:WaitForChild("Modules")
local PlayerFunctions = require(Modules.PlayerFunctions)
local GameShutdown = false
-------------------- FUNCTIONS --------------------
local function GiveQuest(Player, QuestInfos)
local Quests = Player:WaitForChild("Quests")
task.wait(1.1)
if not Quests:FindFirstChild(QuestInfos.Title) then
local Done = false
local NewQuest = PlayerFunctions.CreateFolder(Quests, QuestInfos.Title)
local QuestTitle = PlayerFunctions.CreateValue(NewQuest, "StringValue", "Title", QuestInfos.Title)
local QuestTask = PlayerFunctions.CreateValue(NewQuest, "StringValue", "Task", QuestInfos.Task)
local QuestGoal = PlayerFunctions.CreateValue(NewQuest, "IntValue", "Goal", QuestInfos.Goal)
local QuestGoalCurrency = PlayerFunctions.CreateValue(NewQuest, "StringValue", "GoalCurrency", QuestInfos.GoalCurrency)
local Reward_Gold = PlayerFunctions.CreateValue(NewQuest, "IntValue", "Reward_Gold", QuestInfos.Reward_Gold)
local QuestProgress = PlayerFunctions.CreateValue(NewQuest, "IntValue", "Progress", 0)
for i, Table in pairs(SessionData[Player.UserId]) do -- "Quests"
if tostring(type(Table)) == "table" then
for i, SubTable in pairs(Table) do -- "QuestFolder"
if tostring(type(SubTable)) == "table" then
if SubTable[1] == QuestTitle.Value then
for i, ValueTable in pairs(SubTable) do -- "Title", etc
if tostring(type(ValueTable)) == "table" then
if ValueTable[1] == "Progress" then
QuestProgress.Value = ValueTable[2]
end
end
end
end
end
end
end
end
if QuestInfos.Reward_Aura then
if QuestInfos.Reward_Aura ~= "" then
local Reward_Aura = PlayerFunctions.CreateValue(NewQuest, "StringValue", "Reward_Aura", QuestInfos.Reward_Aura)
end
end
if Quests:FindFirstChild(NewQuest.Name) then
Player:WaitForChild("leaderstats"):WaitForChild(QuestInfos.GoalCurrency):GetPropertyChangedSignal("Value"):Connect(function()
if not Done then
QuestProgress.Value += 1
if QuestProgress.Value >= QuestGoal.Value then
Done = true
Player:WaitForChild("leaderstats"):WaitForChild("Gold").Value += Reward_Gold.Value
if QuestInfos.Reward_Aura then
PlayerFunctions.GiveAura(Player, QuestInfos.Reward_Aura, 1)
end
NewQuest:Destroy()
end
end
end)
end
end
end
local function SaveValues(Player, Value, Folder)
task.spawn(function()
Value:GetPropertyChangedSignal("Value"):Connect(function() -- Update the value when it changes
for i, Table in pairs(SessionData[Player.UserId]) do -- Loop trough the Data
if type(Table == "table") then -- If v is a table
if tostring(Table[1]) == Folder.Name then
if type(Table[2] == "table") then
for i, v in pairs(Table[2]) do
if tostring(v[1]) == Value.Name then
if v[2] then
v[2] = Value.Value
print(v[1].." is now "..v[2])
end
break
end
end
end
break
end
end
end
end)
end)
end
local function SaveFolder(Player, Folder)
task.spawn(function()
for i, Table in pairs(SessionData[Player.UserId]) do -- Loop trough the Data
local Success, Error = pcall(function()
if type(Table == "table") then
if type(Table[1] == "string") then -- If the name of the table corresponds with the Folder
if tostring(Table[1]) == Folder.Name then
for i, v in pairs(Folder:GetDescendants()) do -- Get everything inside the folder
if v:IsA("ValueBase") then -- If it's a value
task.spawn(function()
local AlreadyExists = false
for i, ExistingValue in pairs(Table[2]) do
if ExistingValue[1] == v.Name then
AlreadyExists = true
end
end
if not AlreadyExists then
table.insert(Table[2], {v.Name, v.Value}) -- Insert the value into the data
end
end)
task.spawn(function()
v:GetPropertyChangedSignal("Value"):Connect(function()
for i, ValueTable in pairs(Table[2]) do
if tostring(ValueTable[1]) == v.Name then
ValueTable[2] = v.Value
break
end
end
end)
end)
end
end
end
end
end
end)
end
end)
end
local function SetData(Player, Table)
local Potions = Player:WaitForChild("Potions")
local Gears = Player:WaitForChild("Gears")
local Collection = Player:WaitForChild("Collection")
local QuestInfos = {
["Title"] = "",
["Task"] = "",
["Goal"] = 0,
["GoalCurrency"] = "",
["Reward_Gold"] = 0,
["Reward_Aura"] = "",
}
for i, v in pairs(Table[2]) do
if v[1] ~= nil then
print("Loaded "..v[1].." ("..v[2]..")")
if Table[1] == "Auras" then
if not Player:WaitForChild("Auras"):FindFirstChild(v[1]) then
local Aura = Instance.new("IntValue", Player:WaitForChild("Auras"))
Aura.Name = v[1]
Aura.Value = 1
PlayerFunctions.GiveAura(Player, v[1], v[2] - 1)
end
elseif Table[1] == "Potions" then
if not Player:WaitForChild("Potions"):FindFirstChild(v[1]) then
PlayerFunctions.CreateValue(Potions, "IntValue", v[1], v[2])
end
elseif Table[1] == "Gears" then
if not Player:WaitForChild("Gears"):FindFirstChild(v[1]) then
PlayerFunctions.CreateValue(Gears, "StringValue", v[1], v[2])
end
elseif Table[1] == "Collection" then
if not Collection:FindFirstChild(v[1]) then
PlayerFunctions.CreateValue(Collection, "StringValue", v[1], v[2])
end
elseif Table[1] == "Quests" then
local Info = v[1]
QuestInfos[Info] = v[2]
end
end
end
warn("QuestInfos: ", QuestInfos.Title, QuestInfos.Task, QuestInfos.Goal, QuestInfos.Progress, QuestInfos.GoalCurrency, QuestInfos.GoldReward, QuestInfos.AuraReward)
if QuestInfos.Title ~= "" then
task.spawn(function()
task.wait(1)
GiveQuest(Player, QuestInfos)
end)
end
end
local function RemoveFromData(Player : Player, ItemName : string)
for i, Table in pairs(SessionData[Player.UserId]) do
local Succ, Err = pcall(function()
if type(Table == "table") then
if type(Table[2] == "table") then
for i, v in pairs(Table[2]) do
if type(v == "table") and v[1] == ItemName then
print(v[1].." removed from Data")
v[1] = nil
print(v[1])
end
end
elseif type(Table[2] ~= "table") then
print(Table[1].." removed from Data")
Table = nil
end
end
end)
end
end
-------------------- EVENTS --------------------
game.Players.PlayerAdded:Connect(function(Player)
local Success = nil
local PlayerData = nil
local Attempt = 1
local DefaultData = {
{"Gold", 0},
{"Rolls", 0},
{"Aura", ""},
{"Gear", ""},
{"Speed", Default_Speed},
{"Luck", Default_Luck},
{"Coins", Default_Coins},
{"Auras", {}},
{"Gears", {}},
{"Potions", {}},
{"Quests", {}},
{"Titles", {}},
{"Storage", 0},
{"MaxStorage", Default_SlotsAmount},
{"LuckBoostDuration", 0},
{"SpeedBoostDuration", 0},
{"CoinsBoostDuration", 0},
{"Banned", false},
{"Title", "PLAYER"},
{"AutoSkip", 0},
{"AutoEquip", 0},
{"Collection", {}},
}
-------------------- GETTING DATA --------------------
repeat
Success, PlayerData = pcall(function()
return DS:GetAsync(Player.UserId)
end)
Attempt += 1
if not Success then
warn(PlayerData)
task.wait(2)
end
until Success or Attempt == 5
if Success then
print("Connected to DataBase")
if not PlayerData then
print("Assigning default Data")
PlayerData = DefaultData
end
SessionData[Player.UserId] = PlayerData
else
Player:Kick("Unable to load your data. Please try again later.")
end
local function UpdateData(Val)
if Val:IsA("Folder") then
-------------------- SAVE VALUES --------------------
task.spawn(function()
Val.ChildRemoved:Connect(function(Child)
RemoveFromData(Player, Child.Name)
end)
Val.ChildAdded:Connect(function(Child) -- When a value is added into a folder
if Child:IsA("ValueBase") then
SaveValues(Player, Child, Val)
for i, Table in pairs(SessionData[Player.UserId]) do -- Loop trough the Data
if type(Table == "table") then -- If v is a table
local Error, Success = pcall(function()
if tostring(Table[1]) == Val.Name then -- Auras
if type(Table[2] == "table") then
task.spawn(function()
local AlreadyExists = false
for i, ExistingValue in pairs(Table[2]) do
if ExistingValue[1] == Child.Name then
AlreadyExists = true
end
end
if not AlreadyExists then
table.insert(Table[2], {Child.Name, Child.Value}) -- Insert the value into the data
print(Child.Name, Child.Value)
end
end)
end
end
end)
end
end
-------------------- SAVE FOLDERS --------------------
elseif Child:IsA("Folder") then
SaveFolder(Player, Val)
end
end)
end)
-------------------- LOAD FOLDERS --------------------
task.spawn(function()
for i, Table in pairs(SessionData[Player.UserId]) do
if tostring(type(Table)) == "table" then
if tostring(Table[1]) == Val.Name then -- Auras
if type(Table[2] == "table") then
SetData(Player, Table)
end
break
end
end
end
end)
else
-------------------- LOADING VALUES --------------------
local Success, ErrorMessage = pcall(function()
for i, Table in pairs(SessionData[Player.UserId]) do
if tostring(type(Table)) == "table" then
if Table[1] == Val.Name then -- Auras
if type(Table[2] == "number") then
Val.Value = Table[2]
end
break
end
end
end
end)
if ErrorMessage then
print(Val, ":", ErrorMessage)
end
Val:GetPropertyChangedSignal("Value"):Connect(function()
for i, v in pairs(SessionData[Player.UserId]) do
if tostring(type(v)) == "table" then
if v[1] == Val.Name then
if type(v[2] == "number") then
v[2] = Val.Value
elseif type(v[2] == "table") then
for _, e in pairs(v[2]) do
e[2] = Val.Value
end
end
break
end
end
end
end)
end
end
-------------------- STATS --------------------
local Leaderstats = Player:WaitForChild("leaderstats")
local Gold = Leaderstats:WaitForChild("Gold")
local Rolls = Leaderstats:WaitForChild("Rolls")
local Aura = Leaderstats:WaitForChild("Aura")
local Gear = Leaderstats:WaitForChild("Gear")
local Upgrades = Player:WaitForChild("Upgrades")
local Autoroll = Upgrades:WaitForChild("Autoroll")
local Quickroll = Upgrades:WaitForChild("Quickroll")
local Speed = Upgrades:WaitForChild("Speed")
local Luck = Upgrades:WaitForChild("Luck")
local Coins = Upgrades:WaitForChild("Coins")
local Auras = Player:WaitForChild("Auras")
local Gears = Player:WaitForChild("Gears")
local Potions = Player:WaitForChild("Potions")
local Quests = Player:WaitForChild("Quests")
local Titles = Player:WaitForChild("ChatTitles")
local Values = Player:WaitForChild("Values")
local Storage = Values:WaitForChild("Storage")
local MaxStorage = Values:WaitForChild("MaxStorage")
local IsDialoguing = Values:WaitForChild("IsDialoguing")
local CanRoll = Values:WaitForChild("CanRoll")
local LuckBoostDuration = Values:WaitForChild("LuckBoostDuration")
local SpeedBoostDuration = Values:WaitForChild("SpeedBoostDuration")
local CoinsBoostDuration = Values:WaitForChild("CoinsBoostDuration")
local IsInArena = Values:WaitForChild("IsInArena")
local AutoEquip = Values:WaitForChild("AutoEquip")
local Banned = Values:WaitForChild("Banned")
local AutoSkip = Values:WaitForChild("AutoSkip")
local AutoEquip = Values:WaitForChild("AutoEquip")
local Title = Values:WaitForChild("Title")
local Collection = Player:WaitForChild("Collection")
-------------------- UPDATE DATA --------------------
task.spawn(function()
UpdateData(Gold)
UpdateData(Rolls)
UpdateData(Aura)
UpdateData(Gear)
UpdateData(Luck)
UpdateData(Speed)
UpdateData(Coins)
UpdateData(Auras)
UpdateData(Gears)
UpdateData(Potions)
UpdateData(Titles)
UpdateData(Quests)
UpdateData(Storage)
UpdateData(MaxStorage)
UpdateData(LuckBoostDuration)
UpdateData(SpeedBoostDuration)
UpdateData(CoinsBoostDuration)
UpdateData(Banned)
UpdateData(AutoSkip)
UpdateData(AutoEquip)
UpdateData(Title)
UpdateData(Collection)
end)
-------------------- STORAGE --------------------
Storage.Value = #Auras:GetChildren()
SessionData[Player.UserId]["Storage"] = Storage.Value
Auras.ChildAdded:Connect(function(Child)
Storage.Value = #Auras:GetChildren()
SessionData[Player.UserId]["Storage"] = Storage.Value
end)
Auras.ChildRemoved:Connect(function(Child)
Storage.Value = #Auras:GetChildren()
SessionData[Player.UserId]["Storage"] = Storage.Value
end)
end)
-------------------- SAVE DATA --------------------
game.Players.PlayerRemoving:Connect(function(Player)
if not GameShutdown then
if SessionData[Player.UserId] then
local Success = nil
local ErrorMessage = nil
local Attempt = 1
for i, Table in pairs(SessionData[Player.UserId]) do -- "Quests"
if tostring(type(Table)) == "table" then
for i, SubTable in pairs(Table) do -- "QuestFolder"
if tostring(type(SubTable)) == "table" then
for i, ValueTable in pairs(SubTable) do -- "Title", etc
if tostring(type(ValueTable)) == "table" then
print("Saved", tostring(ValueTable[1]), "("..tostring(ValueTable[2])..")")
end
break
end
end
break
end
end
end
repeat
Success, ErrorMessage = pcall(function()
DS:SetAsync(Player.UserId, SessionData[Player.UserId])
end)
Attempt += 1
if not Success then
warn(ErrorMessage)
task.wait(2)
end
until Success or Attempt == 5
end
end
end)
-------------------- GIVE QUEST --------------------
game:GetService("ReplicatedStorage"):WaitForChild("RemoteEvents"):WaitForChild("GiveQuest").OnServerEvent:Connect(function(Player, QuestInfos)
local QuestTable = {
["Title"] = "",
["Task"] = "",
["Goal"] = 0,
["GoalCurrency"] = "",
["Reward_Gold"] = 0,
["Reward_Aura"] = "",
}
QuestTable.Title = QuestInfos[1]
QuestTable.Task = QuestInfos[2]
QuestTable.Goal = QuestInfos[3]
QuestTable.GoalCurrency = QuestInfos[4]
QuestTable.Reward_Gold = QuestInfos[5]
if QuestInfos[6] then
QuestTable.Reward_Aura = QuestInfos[6]
end
GiveQuest(Player, QuestTable)
end)
-------------------- SAVE ON SHUTDOWN --------------------
game:BindToClose(function()
GameShutdown = true
task.wait(5)
end)
Thank you for any help!