What do you want to achieve?
I’d like to have the data be saved each time the user leaves or is about to leave.
What is the issue?
In the script, when the player leaves it should print “Data saved successfully” or something along those lines. The first time I wrote this code and tested it, it clearly saved indicated by the “Data Saved” print in the output. When I rejoin the data isn’t loaded though and my data is registered as “New Data”
What solutions have you tried so far?
I have tried 0 solutions. Do note that the code is taken from a tutorial I am following.
ShopServer script inside ServerScriptService. API access is turned on.
local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local towers = require(ReplicatedStorage:WaitForChild("TowerShop"))
local database = DataStoreService:GetDataStore("database")
local MAX_SELECTED_TOWERS = 5
local data = {
}
local defaultData = {
["Gems"] = 100,
["SelectedTowers"] = {"Cutler"},
["OwnedTowers"] = {"Cutler", "Gunslinger"}
}
local function LoadData(player)
local success = nil
local playerData = nil
local attempt = 1
repeat
success, playerData = pcall(function()
return database:GetAsync(player.UserId)
end)
attempt += 1
if not success then
warn(playerData)
task.wait()
end
until success == true or attempt == 3
if success then
print("Connection established")
if not playerData then
print("New player, giving default data")
playerData= {
["Gems"] = 100,
["SelectedTowers"] = {"Cutler"},
["OwnedTowers"] = {"Cutler", "Gunslinger"}
}
end
data[player.UserId] = playerData
else
warn("Unable to get data for player", player.UserId)
player:Kick("There was a problem loading your data! Message the developer on Roblox if this problem continues!")
end
end
Players.PlayerAdded:Connect(LoadData)
local function SaveData(player)
if data[player.UserId] then
local success = nil
local playerData = nil
local attempt = 1
repeat
success, playerData = pcall(function()
return database:UpdateAsync(player.UserId, function()
return data[player.UserId]
end)
end)
attempt += 1
if not success then
warn(playerData)
task.wait()
end
until success == true or attempt == 3
if success then
print("Data saved successfully")
else
warn("Unable to save data for", player.UserId)
end
else
warn("No session data for", player.UserId)
end
end
Players.PlayerRemoving:Connect(SaveData)
local function GetItemStatus(player, itemName)
local playerData = data[player.UserId]
if table.find(playerData.SelectedTowers, itemName) then
return "Equipped"
elseif table.find(playerData.OwnedTowers, itemName) then
return "Owned"
else
return "For Sale"
end
end
ReplicatedStorage.InteractItem.OnServerInvoke = function(player, itemName)
local shopItem = towers[itemName]
local playerData = data[player.UserId]
if shopItem and playerData then
local status = GetItemStatus(player, itemName)
if status == "For Sale" and shopItem.Price <= playerData.Gems then
-- Purchase
playerData.Gems -= shopItem.Price
table.insert(playerData, shopItem.Name)
elseif status == "Owned" then
--Equip Tower
table.insert(playerData.SelectedTowers, shopItem.Name)
if #playerData.SelectedTowers > MAX_SELECTED_TOWERS then
table.remove(playerData.SelectedTowers, 1)
end
elseif status == "Equipped" then
-- Unselect tower
if #playerData.SelectedTowers > 1 then
local towerToRemove = table.find(playerData.SelectedTowers, itemName)
table.remove(playerData.SelectedTowers, towerToRemove)
end
end
return playerData
else
warn("Tower/Player Data Does Not Exist!")
end
return false
end
ReplicatedStorage.GetData.OnServerInvoke = function(player)
return data[player.UserId]
end
If you need anymore information then please let me know!
local function LoadData(player)
local success
local playerData
local attempt = 1
repeat
success, errormessage = pcall(function()
playerData = database:GetAsync(player.UserId)
end)
attempt += 1
if not success then
warn(errormessage)
task.wait()
end
until success or attempt == 3
if success then
print("Connection established")
if playerData == nil then
print("New player, giving default data")
playerData= {
["Gems"] = 100,
["SelectedTowers"] = {"Cutler"},
["OwnedTowers"] = {"Cutler", "Gunslinger"}
}
end
data[player.UserId] = playerData
print(data[player.UserId]) --prints the loaded data for debugging. you can remove this later.
else
warn("Unable to get data for player", player.UserId)
player:Kick("There was a problem loading your data! Message the developer on Roblox if this problem continues!")
warn(errormessage)
end
end
Try the script again, I had to edit the post a few times
local function LoadData(player)
local playerData
local attempt = 1
local success, errormessage = pcall(function()
playerData = database:GetAsync(player.UserId)
end)
if not success then
warn("Error with loading data. Error: "..errormessage)
player:Kick("There was a problem loading your data! Message the developer on Roblox if this problem continues!")
return
end
if success then
print("Got data successfully.")
print(playerData)
if playerData == nil then
print("New player, giving default data")
playerData = {
["Gems"] = 100,
["SelectedTowers"] = {"Cutler"},
["OwnedTowers"] = {"Cutler", "Gunslinger"}
}
end
data[player.UserId] = playerData
print(data[player.UserId]) --prints the loaded data for debugging. you can remove this later.
end
end
Also, change this in your save script
success, errormessage = pcall(function()
database:SetAsync(player.UserId, data[player.UserId])
end)
if success then
print("Saved data for"..player.Name)
else
warn(errormessage)
end
I’ve made the changes and no “Data Saved” message appeared and it just reverts data. No errors appear at all.
Here is my updated code, maybe I made a change that were made wrong?
local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local towers = require(ReplicatedStorage:WaitForChild("TowerShop"))
local database = DataStoreService:GetDataStore("database")
local MAX_SELECTED_TOWERS = 5
local data = {
}
local defaultData = {
["Gems"] = 100,
["SelectedTowers"] = {"Cutler"},
["OwnedTowers"] = {"Cutler", "Gunslinger"}
}
local function LoadData(player)
local playerData
local attempt = 1
local success, errormessage = pcall(function()
playerData = database:GetAsync(player.UserId)
end)
if not success then
warn("Error with loading data. Error: "..errormessage)
player:Kick("There was a problem loading your data! Message the developer on Roblox if this problem continues!")
return
end
if success then
print("Got data successfully.")
print(playerData)
if playerData == nil then
print("New player, giving default data")
playerData = {
["Gems"] = 100,
["SelectedTowers"] = {"Cutler"},
["OwnedTowers"] = {"Cutler", "Gunslinger"}
}
end
data[player.UserId] = playerData
print(data[player.UserId]) --prints the loaded data for debugging. you can remove this later.
end
end
Players.PlayerAdded:Connect(LoadData)
local function SaveData(player)
if data[player.UserId] then
local success = nil
local playerData = nil
local attempt = 1
local errormessage = nil
repeat
success, errormessage = pcall(function()
return database:SetAsync(player.UserId, data[player.UserId])
end)
attempt += 1
if success then
print("Saved Data For " .. player.Name )
else
warn(errormessage)
end
until success == true or attempt == 3
--if success then
-- print("Data saved successfully")
--else
-- warn("Unable to save data for", player.UserId)
--end
else
warn("No session data for", player.UserId)
end
end
Players.PlayerRemoving:Connect(SaveData)
local function GetItemStatus(player, itemName)
local playerData = data[player.UserId]
if table.find(playerData.SelectedTowers, itemName) then
return "Equipped"
elseif table.find(playerData.OwnedTowers, itemName) then
return "Owned"
else
return "For Sale"
end
end
ReplicatedStorage.InteractItem.OnServerInvoke = function(player, itemName)
local shopItem = towers[itemName]
local playerData = data[player.UserId]
if shopItem and playerData then
local status = GetItemStatus(player, itemName)
if status == "For Sale" and shopItem.Price <= playerData.Gems then
-- Purchase
playerData.Gems -= shopItem.Price
table.insert(playerData, shopItem.Name)
elseif status == "Owned" then
--Equip Tower
table.insert(playerData.SelectedTowers, shopItem.Name)
if #playerData.SelectedTowers > MAX_SELECTED_TOWERS then
table.remove(playerData.SelectedTowers, 1)
end
elseif status == "Equipped" then
-- Unselect tower
if #playerData.SelectedTowers > 1 then
local towerToRemove = table.find(playerData.SelectedTowers, itemName)
table.remove(playerData.SelectedTowers, towerToRemove)
end
end
return playerData
else
warn("Tower/Player Data Does Not Exist!")
end
return false
end
ReplicatedStorage.GetData.OnServerInvoke = function(player)
return data[player.UserId]
end
If you’re testing in studio, data saving in studio is (from my experience) very unreliable, try testing in an actual game server
Other than that nothing appears to be wrong with the script (except for maybe UpdateAsync)
My Modified Version of the provided script
local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local towers = require(ReplicatedStorage:WaitForChild("TowerShop"))
local database = DataStoreService:GetDataStore("database")
local MAX_SELECTED_TOWERS = 5
local data = {
}
local defaultData = {
["Gems"] = 100,
["SelectedTowers"] = {"Cutler"},
["OwnedTowers"] = {"Cutler", "Gunslinger"}
}
local function LoadData(player)
local success = nil
local playerData = nil
local attempt = 1
while not success and attempt < 4 do
success, playerData = pcall(function()
return database:GetAsync(player.UserId)
end)
if not success then
attempt += 1
warn(playerData)
task.wait()
end
end
--[[ Repeat until is often unreliable
repeat
until
]]
if success then
print("Data Loaded Successfully") --Why connection established??
if not playerData then
print("New player, giving default data")
playerData= {
["Gems"] = 100,
["SelectedTowers"] = {"Cutler"},
["OwnedTowers"] = {"Cutler", "Gunslinger"}
}
end
data[player.UserId] = playerData
else
warn("Unable to get data for player", player.UserId)
player:Kick("There was a problem loading your data! Message the developer on Roblox if this problem continues!")
end
end
Players.PlayerAdded:Connect(LoadData)
local function SaveData(player)
if data[player.UserId] then
local success = nil
local playerData = nil
local attempt = 1
while not success and attempt < 4 do
success, playerData = pcall(function()
database:SetAsync(player.UserId, data[player.UserId])
--[[ UpdateAsync overcomplicates things in my opinion
return database:UpdateAsync(player.UserId, function()
return data[player.UserId]
end)
]]
end)
if not success then
attempt += 1
warn(playerData)
task.wait()
end
end
--[[ Again repeat until is often unreliable
repeat
until success == true or attempt == 3
]]
if success then
print("Data saved successfully")
else
warn("Unable to save data for", player.UserId)
end
else
warn("No Data for", player.UserId)
end
end
Players.PlayerRemoving:Connect(SaveData)
-- I won't bother changing anything else
local function GetItemStatus(player, itemName)
local playerData = data[player.UserId]
if table.find(playerData.SelectedTowers, itemName) then
return "Equipped"
elseif table.find(playerData.OwnedTowers, itemName) then
return "Owned"
else
return "For Sale"
end
end
ReplicatedStorage.InteractItem.OnServerInvoke = function(player, itemName)
local shopItem = towers[itemName]
local playerData = data[player.UserId]
if shopItem and playerData then
local status = GetItemStatus(player, itemName)
if status == "For Sale" and shopItem.Price <= playerData.Gems then
-- Purchase
playerData.Gems -= shopItem.Price
table.insert(playerData, shopItem.Name)
elseif status == "Owned" then
--Equip Tower
table.insert(playerData.SelectedTowers, shopItem.Name)
if #playerData.SelectedTowers > MAX_SELECTED_TOWERS then
table.remove(playerData.SelectedTowers, 1)
end
elseif status == "Equipped" then
-- Unselect tower
if #playerData.SelectedTowers > 1 then
local towerToRemove = table.find(playerData.SelectedTowers, itemName)
table.remove(playerData.SelectedTowers, towerToRemove)
end
end
return playerData
else
warn("Tower/Player Data Does Not Exist!")
end
return false
end
ReplicatedStorage.GetData.OnServerInvoke = function(player)
return data[player.UserId]
end