Player Folder Objects Dissappear Before DataStore Saving

Hello, I have been struggling to save an array/table to the DataStoreService. I am attempting to store various strings into the array, these strings come from a folder I created named “inventory.”

An example of this can be seen here:

image

Strangely the “inventory” folder appears to be emptied before saving for some reason. I verified this by printing the number of elements on “inventory” which oddly output zero (meaning “inventory” was empty). I also printed out the folder “leaderstats” where I am storing other information that is also meant to be saved and is successfully doing so. I left both print statements on and you can see the results in m output below:

image

I verified my game does not have any other scripts deleting the contents of the “inventory” folder. So at this point, I am fairly confused as to what may be causing this.

You may see the code below:

local DataStoreService = game:GetService("DataStoreService")
local inventoryDatastore = DataStoreService:GetDataStore("inventorySave")

local function equipAccessory(player, accessory)
	local character = player.Character

	if accessory ~= nil and character ~= nil then
		--local accessory = game.ReplicatedStorage.Hats.Crown
		accessory:Clone().Parent = player.Character
		print("Equipping cloned "..accessory.Name)
	end
end

game.Players.PlayerAdded:Connect(function(player)
	local inventory = Instance.new("Folder")
	inventory.Name = "inventory"
	inventory.Parent = player
	
	pcall(function()
		local accessoryData = inventoryDatastore:GetAsync("UserInventory-"..player.UserId) --Array type
		print(player.Name.."'s accessory data: "..typeof(accessoryData))--..accessoryData)
		if accessoryData then
			for i,v in pairs(accessoryData) do
				local accessoryFound = game.ReplicatedStorage.Accessories:FindFirstChild(v)
				if accessoryFound then
					print("Load item - i: "..i.."   v: "..v)
					local temp = Instance.new("StringValue")
					temp.Name = v
					temp.Parent = inventory
					game.ReplicatedStorage.RemoteEvents.AddAccessoryToInventory2:FireClient(temp) --Adding every item to the frame...
				end
			end
			game.ReplicatedStorage.RemoteEvents.SendData:FireClient(player, accessoryData)
			print("Fired sendData!")
		else
			print("No data found, must be a new player or something happened to the data")
		end
	end)
end)

--Saving Data for Leaving Players/Closing Server
local function saveData(player)
	print(player.Name.." leaving and saving their data...")
	if player:FindFirstChild("inventory") then
		local accessorySave = {} --To be used as an array
		local test1 = player.inventory:GetChildren()
		local test2 = player.leaderstats:GetChildren()
		print("Num of elements in inventory: "..#test1)
		print("Num of elements in leaderstats: "..#test2)
		for _,v in pairs(player.inventory:GetChildren()) do
			print("Insert item - i: ")--..i.."   acc: "..v.Name)
			table.insert(accessorySave,v.Name)
		end
		
		local success, errorMessage = pcall(function()
			inventoryDatastore:SetAsync("UserInventory-"..player.UserId, accessorySave) --Save
		end)
		
		if success then
			print(accessorySave)
			print(player.Name.."'s Accessory Inventory Saved!")
		else
			print("Error: "..errorMessage)
		end
	end
end

game:BindToClose(function()
	for i, player in pairs(game.Players:GetPlayers()) do
		saveData(player)
	end
end)

game.Players.PlayerRemoving:Connect(function(player)
	saveData(player)
end)

--Remote Events
game.ReplicatedStorage.RemoteEvents.EquipAccessory.OnServerEvent:Connect(function(player,accessoryName)
	local accessory = game.ReplicatedStorage.Accessories:FindFirstChild(accessoryName)
	-- Only let players Equip accessories they own
	if not player.inventory:FindFirstChild(accessoryName) then
		equipAccessory(player, accessory)
	end
end)

game.ReplicatedStorage.RemoteEvents.UnequipAccessory.OnServerEvent:Connect(function(player,accessoryName)
	if player.Character:FindFirstChild(accessoryName) then
		player.Character:FindFirstChild(accessoryName):Destroy()
	end
end)

Any ideas as to why this might happen or how to fix this?

Is the error your talking about, "DataStore request . . . "?

I also agree with what @ABHI1290 said. I would suggest learning how to use Datastore2 and learning about OOP (Object Oriented Programming)

I recomend using objects:

playerData = {
    inventory = {"apple", "sword", "sauce"},
    somethingElse = true,
    whatEver = 2783562873456
}

Learn more on Roblox developer page.

saveData is called when the player leaves the server. The problem could be, that when the player leaves the server, their folders are removed along with their player from “players”, before the function is called. So, the function won’t be able to find the folder because it got removed along with the player.

Try to print player.inventory in saveData

Edit: I read about the PlayerRemoving event a little, and it seems that it’s called right before the actual player is removed, so it may be that I am wrong, but it would still help if you print the player.inventory, so that we know whether player.inventory exists at the time when the function is called.

A possible solution that I would try would be moving saveData function into the game.Players.PlayerRemoving:Connect(function(player)
end)

So that would look something like this

game.Players.PlayerRemoving:Connect(function(player)
	print(player.Name.." leaving and saving their data...")
	if player:FindFirstChild("inventory") then
		local accessorySave = {} --To be used as an array
		local test1 = player.inventory:GetChildren()
		local test2 = player.leaderstats:GetChildren()
		print("Num of elements in inventory: "..#test1)
		print("Num of elements in leaderstats: "..#test2)
		for _,v in pairs(player.inventory:GetChildren()) do
			print("Insert item - i: ")--..i.."   acc: "..v.Name)
			table.insert(accessorySave,v.Name)
		end
		
		local success, errorMessage = pcall(function()
			inventoryDatastore:SetAsync("UserInventory-"..player.UserId, accessorySave) --Save
		end)
		
		if success then
			print(accessorySave)
			print(player.Name.."'s Accessory Inventory Saved!")
		else
			print("Error: "..errorMessage)
		end
	end
end)

It is possible that the function is called before the player is removed, but it probably runs after the player is removed.

I know OOP, that particular error does not concern me. I expect that since the data I am trying to store is disappearing/sending multiple empty requests to store nothing. I appreciate the help none the less.

That is an array/table and what I am using. Thanks for trying to help though.

Hey soflowsen,

Your suggestion is exactly what my code is doing already. The function call is the equivalent of moving all the data to “game.Players.PlayerRemoving” as your suggestion shows so it won’t do anything. Anyway, I did that for good measure and it did not make any changes. I appreciate the help though.

Did you try printing player.inventory?
What was the output?

The player inventory has nothing. It turns up the same result using your method as in the original post. You can see this from the lines containing:

local test1 = player.inventory:GetChildren()
print("Num of elements in leaderstats: "..#test2)

Note those lines are printing the number of elements in the player inventory folder.

I mean, what is the output if you try printing the player.inventory itself, not the number of values it contains.

It does not print anything (marks error) when I do the following:

print("Player inventory print: "..player.inventory)

Output:

I printed the type of the element and it stated it is an “Instance” too, which is what folders should print anyways.

print("Player inventory print: "..typeof(player.inventory))

Output:
image

Try printing

#player.inventory:GetChildren() 

before you call saveData in the playerRemoving event handler

game.Players.PlayerRemoving:Connect(function(player)
    print(#player.inventory:GetChildren())
	saveData(player)
end)

Following your suggestion printed out 0 as seen below:

image

Are you sure that the contents of the inventory get emptied right before the player is removed?
Could it be that they are not created there at all?

Yes, I am sure since I verified they are there every time I have tested it. It is mentioned in the original post as well.

image

That is why I am so confused.

In this case, I have no idea why is that happening.
However, it seems to happen before saveData is called, because you said that

game.Players.PlayerRemoving:Connect(function(player)
    print(#player.inventory:GetChildren())
	saveData(player)
end)

still prints 0

Yeah, I will keep prodding it and hopefully find an answer… Thanks anyways.