In pairs loop returning nil

Greetings! I’m creating an RPG game with a sword-saving system. Whenever the player leaves, I add all of the swords into a table, however, this table is nil once the player rejoins.

I couldn’t really add the full script hence the length
sword

FYI, once the sword enters a player’s inventory, I created a string value holding the names of the swords (I later use the names to grab it out of server storage) this explains the ‘player.SwordSaver:GetChildren()’

The data is nil or is it just an empty table ({})?

The data is an empty table
Here’s the other part of the script

First off:

data = savedData:GetAsync(player.UserId, savedInstances)

The second parameter (savedInstances) is not necessary, therefore you can remove the for loop above that.

I recommend adding print statements to your loops in the first script you provided to see if the loops are running.

I can better help you with a full script. If you are uncomfortable sending your script in the public forum, you can DM it to me if you’d like.

Alright, here is the full script:

Does anything print out on line 47?

No, nothing prints out on line 47.

Can you add print(tool) under line 39, and let me know if anything prints there.

ALSO, copy that new for loop (with the print statement included) and paste it under line 67.

Nothing from both of those. However, the string values still pop-up under the folder.

Okay. I think I have an idea. Could you send the script as text? (To do this, copy and paste it, and embed it in these: ```)

local dataStore = game:GetService("DataStoreService")
local savedData = dataStore:GetDataStore("savedData")

local timesRan = 0
local timesRan1 = 0

local serverStorage = game:GetService("ServerStorage")

game.Players.PlayerAdded:Connect(function(player)
   if not player:FindFirstChild("SwordSaver") then

   	-- Include folder for swords
   	local swordSaver = Instance.new("Folder", player)
   	swordSaver.Name = "SwordSaver"	
   end

   local char = player.Character or player.CharacterAdded:Wait()

   local backpackTools = player.Backpack:GetChildren()
   local charTools = char:GetChildren()
   	
   local data
   
   -- Loop through, and create the destined amount of string values
   for _, tool in pairs(backpackTools and charTools) do
   		
   	if tool.ClassName == "Tool" then
   		if not player.SwordSaver:FindFirstChild(tool.Name) then

   			local swordString = Instance.new("StringValue", player.SwordSaver)
   			swordString.Name = tool.Name
   		end 
   	end
   end
   	
   local savedInstances = {}

   for _, tool in pairs(player.SwordSaver:GetChildren()) do
   	print(tool)
   	table.insert(savedInstances, tool.Name)
   end
   	
   local success, err = pcall(function()
   	data = savedData:GetAsync(player.UserId, savedInstances)
   		
   	print("test")
   	for i, v in pairs(data) do
   		print(v)
   	end
   end)
   	
   if success then
   	for _, tool in pairs(data) do
   		
   		print(tool)
   		local newSwords = serverStorage.Swords[data]:Clone()
   		newSwords.Parent = player.Backpack
   			
   		local newString = Instance.new("StringValue", player)
   		newString.Name = tool
   	end
   end
end)


-- Finalizes the sword once the player leaves
game.Players.PlayerRemoving:connect(function(player)
   
   local savedInstances = {}

   for _, tool in pairs(player.SwordSaver:GetChildren()) do
   	print(tool)
   	table.insert(savedInstances, tool.Name)
   end
   
   savedData:SetAsync(player.UserId, savedInstances)
end)''''

Try this updated code, sorry for all the delays:

local dataStore = game:GetService("DataStoreService")
local savedData = dataStore:GetDataStore("savedData")
local serverStorage = game:GetService("ServerStorage")

game.Players.PlayerAdded:Connect(function(player)
	local data
	local success, err = pcall(function()
		data = savedData:GetAsync(player.UserId)
		for i, v in pairs(data) do -- this is for you to debug
			print(v)
		end
	end)
	if success then
		for _, tool in pairs(data) do
			print(tool)
			local newSwords = serverStorage.Swords[data]:Clone()
			newSwords.Parent = player.Backpack
		end
	end
end)

game.Players.PlayerRemoving:connect(function(player)
	local char = player.Character or player.CharacterAdded:Wait()
	local backpackTools = player.Backpack:GetChildren()
	local charTools = char:GetChildren()
	local savedInstances = {}
	for _, tool in pairs(backpackTools) do
		if tool.ClassName == "Tool" then
			savedInstances[#savedInstances+1]=tool.Name
		end
	end
    for _, tool in pairs(charTools) do
		if tool.ClassName == "Tool" then
			savedInstances[#savedInstances+1]=tool.Name
		end
	end
	savedData:SetAsync(player.UserId, savedInstances)
end)

Let me know if you would like me to explain what I changed.

Sir that is not how the and operator works…

I won’t modify it for you since I’m gonna use this as a teaching experience, so try again.

This script didn’t work either, no errors in the output or prints.

I used the script he provided, did not look at that.

That’s fair, so cheers, but yeah it’s those tiny details that you really gotta look out for when something’s not working right. Probably is the original issue.

@IDoLua Pointed out the misuse of the and operator. Made one final edit to my response.

local playerTools = {unpack(backpackTools), unpack(charTools)}
for _, tool in ipairs(playerTools) do

Can simplify this down into a single iteration structure.

I will add, by default the character can only contain a single tool child instance, so iterating over it isn’t necessary.

local playerTools = {backpack:GetChildren(), character:FindFirstChildOfClass("Tool")}

Thank you for those recommendations, as always.