I am currently making a save and load system for player inventories. I have an issue with loading the data, to sum it up, the game saves the data but when loading it the saved data is deleted.
Here is a video of the problem.
Given the fact that I have tried to solve it myself, I have not been able to find the solution to the problem.
Here is the script I am currently using.
local ds = game:GetService("DataStoreService")
local plrData = ds:GetDataStore("InventorySaves")
-- load data
local function onPlayerJoin(plr)
local key = "ID-"..plr.UserId
print("ID-"..plr.UserId)
print("[+] Player " .. plr.Name .. " has joined the game")
local ItemFolder = Instance.new("Folder", plr)
ItemFolder.Name = "PlayerItems"
local ItemSwords = Instance.new("Folder", ItemFolder)
ItemSwords.Name = "Swords"
local ItemBoosts = Instance.new("Folder", ItemFolder)
ItemBoosts.Name = "Boosts"
local success, data = pcall(function()
return plrData:GetAsync(key)
end)
if success then
print(data)
if data ~= nil then
print("Data was found for "..plr.Name.." ("..plr.UserId..")")
for _, v in pairs(data) do
local tool = FindToolInFolders(game.ReplicatedStorage.ItemsFolder, v)
if tool then
local ItemClone = tool.Handle:Clone()
ItemClone.Name = tool.Name
local destinationFolder = GetDestinationFolder(tool, plr)
ItemClone.Parent = destinationFolder
end
end
else
print("New player")
end
else
print("Error loading data for "..plr.Name..": " .. data)
end
end
-- saves data
local function onPlayerLeft(plr)
local key = "ID-"..plr.UserId
local inveSaves = {}
print("[-] Player " .. plr.Name .. " has left the game")
pcall(function()
local swordsFolder = plr.PlayerItems:FindFirstChild("Swords")
if swordsFolder then
for _, sword in pairs(swordsFolder:GetChildren()) do
if sword:IsA("Part") then
table.insert(inveSaves, sword.Name)
print("new sword save: "..sword.Name)
end
end
end
local boostsFolder = plr.PlayerItems:FindFirstChild("Boosts")
if boostsFolder then
for _, boost in pairs(boostsFolder:GetChildren()) do
if boost:IsA("Part") then
table.insert(inveSaves, boost.Name)
print("new boost save: "..boost.Name)
end
end
end
print(inveSaves)
plrData:SetAsync(key, inveSaves)
end)
end
-- Function to find a tool in folders
function FindToolInFolders(parentFolder, toolName)
for _, folder in pairs(parentFolder:GetChildren()) do
local tool = folder:FindFirstChild(toolName)
if tool then
return tool
end
end
return nil
end
-- Function to get the destination folder for the tool
function GetDestinationFolder(tool, player)
local folderName = tool.Parent.Name
local destinationFolder = player.PlayerItems:FindFirstChild(folderName)
if not destinationFolder then
destinationFolder = Instance.new("Folder", player.PlayerItems)
destinationFolder.Name = folderName
end
return destinationFolder
end
game.Players.PlayerAdded:Connect(onPlayerJoin)
game.Players.PlayerRemoving:Connect(onPlayerLeft)
If anyone has any ideas on how to solve this problem, it would be a great help!
From my understanding of looking over the script, you never once call upon “ServerStorage” which is where you keep said tool, you have to script the function of it going back into the players swords folder, it wont automatically be there because of a datastore.
Hi, to give you more information, the objects are stored in ReplicatedStorage, that is in this image.
It is there where all the tools that occupy the inventory load are stored, the item that is in ServerStorage, this one.
It is a test one, so that the inventory interface can detect it, but that is another topic.
The main problem is the cause of the deletion of the data when I load them, if you see in the Output you can see how the data is saved and loaded, but it does not work as it should.
If you check the script that I have provided, you can never notice that I have given an instruction to delete data on loading (at least what I have seen), it is as if it does not exist in the loading process.
That would be the main problem, anyway, thanks for visiting my topic.
The issue might be the scope of your inveSaves table. In the function for saving player data, you’re creating a new inveSaves table each time a player leaves. This table is local to the onPlayerLeft function which means it’s not accessible from the onPlayerJoin function.
When a player joins the game, the load function tries to load in data from the inveSaves table, but since this table is not defined in the function or globally, the inveSaves table is likely empty or nil when you try to load the data.
To fix this, you should try defining the inveSaves at the top of the script. This makes it a global variable that accessible from all functions in the script. Something like:
local ds = game:GetService("DataStoreService")
local plrData = ds:GetDataStore("InventorySaves")
local inveSaves = {} -- define inveSaves here
-- load data
local function onPlayerJoin(plr)
-- ... (rest of your script)
end
-- saves data
local function onPlayerLeft(plr)
local key = "ID-"..plr.UserId
inveSaves = {} -- reset inveSaves here, but don't redefine it
-- ... (rest of your script)
end
-- ... (rest of your script)
(srry for long explanation that might not even work or be the issue)
No, the function should work just fine even in-studio. After all, I’m having a somewhat similar issue to his with my data but the saving still works correctly with .PlayerRemoved.
Hey, about your solution, I have tried it, but I still have the same problem, and yes, I agree with you that creating a table for each player is a very bad idea because of future conflicts that may arise.
Something that might be helpful and that I did not mention is that the script is executed exactly in ServerScriptService. (something obvious)
Anyway, thanks for trying to help this problem I have.
Ok, after looking at many possible solutions, the save worked!
The solution was to use game:BindToClose:(), as I was testing it in Studio, but the game fails to save the :SetAsync() properly when in Studio.
Here is part of the script with the solution
local function SaveData(player)
local key = "ID-"..player.UserId
local inveSaves = {}
print("[-] Player " .. player.Name .. " has left the game")
local swordsFolder = player.PlayerItems:FindFirstChild("Swords")
if swordsFolder then
for _, sword in pairs(swordsFolder:GetChildren()) do
if sword:IsA("Part") then
table.insert(inveSaves, sword.Name)
end
end
end
local boostsFolder = player.PlayerItems:FindFirstChild("Boosts")
if boostsFolder then
for _, boost in pairs(boostsFolder:GetChildren()) do
if boost:IsA("Part") then
table.insert(inveSaves, boost.Name)
end
end
end
local success, result = pcall(function()
plrData:SetAsync(key, inveSaves)
end)
if not success then
warn("Failed to save "..player.Name.." data : "..result)
end
end
-- saves data
local function onPlayerLeft(plr)
if not game:GetService("RunService"):IsStudio() then
local success = pcall(function()
SaveData(plr)
end)
end
end
game:BindToClose(function()
for _, plr in pairs(game:GetService("Players"):GetPlayers()) do
local success = pcall(function()
SaveData(plr)
end)
end
end)
Thanks to everyone who tried to help with this problem. See you next time!