Table Index is nil

  1. What do you want to achieve? Optimizing my datastores, from SetAsync() to UpdateAsync()

  2. What is the issue? kept getting this error: ServerScriptService.PlayerDataHandler.PlayerSettings.PlayerSettingsHandler:51: table index is nil

  3. What solutions have you tried so far? I found some similar issues of mine but, i don’t know why but i don’t get it

here is the lines of code that updates the player data when it leaves

local function createTable(player)
	local datafolder = player:WaitForChild("PlayerDataFolder")
	local playersettings = datafolder:WaitForChild("PlayerSettings")
	local playersettingsdatatable = {}
	
	for i, value in pairs(playersettings:GetChildren()) do
		playersettingsdatatable[value.Name] = value.Value
	end
	
	return playersettingsdatatable
end

game.Players.PlayerRemoving:Connect(function(player)
	local playersettingsdatatable = createTable(player)

	local success, err = pcall(function()
		local userId = player.UserId
		playersettingsdata:UpdateAsync(userId, function(oldData)
			local dataTable = oldData or {}

			for i, item in pairs(playersettingsdatatable) do
				if item then
					dataTable[item.Name] = item.Value
				end
			end

			return dataTable
		end)
	end)

	if success then
		print(player.Name .. "'s data successfully saved (settings)")
	else
		warn(player.Name .."'s data cant be found (settings)... cause: " .. err)
	end
end)

and here’s the entire code…

local datastoreservice = game:GetService("DataStoreService")
local playersettingsdata = datastoreservice:GetDataStore("PlayerSettingsDataStore")

game.Players.PlayerAdded:Connect(function(player)
	local datafolder = player:WaitForChild("PlayerDataFolder")
	
	local userId = player.UserId
	
	local playerSettings = Instance.new("Folder")
	playerSettings.Name = "PlayerSettings"
	playerSettings.Parent = datafolder
	
	local playerDisplayName = Instance.new("StringValue")
	playerDisplayName.Name = "PlayerDisplayName"
	playerDisplayName.Parent = playerSettings
	
	local data
	local success, err = pcall(function()
		data = playersettingsdata:GetAsync(userId)
	end)
	
	if data then
		playerDisplayName.Value = data["PlayerDisplayName"]
	else
		playerDisplayName.Value = player.Name
	end
end)

local function createTable(player)
	local datafolder = player:WaitForChild("PlayerDataFolder")
	local playersettings = datafolder:WaitForChild("PlayerSettings")
	local playersettingsdatatable = {}
	
	for i, value in pairs(playersettings:GetChildren()) do
		playersettingsdatatable[value.Name] = value.Value
	end
	
	return playersettingsdatatable
end

game.Players.PlayerRemoving:Connect(function(player)
	local playersettingsdatatable = createTable(player)

	local success, err = pcall(function()
		local userId = player.UserId
		playersettingsdata:UpdateAsync(userId, function(oldData)
			local dataTable = oldData or {}

			for i, item in pairs(playersettingsdatatable) do
				if item then
					dataTable[item.Name] = item.Value
				end
			end

			return dataTable
		end)
	end)

	if success then
		print(player.Name .. "'s data successfully saved (settings)")
	else
		warn(player.Name .."'s data cant be found (settings)... cause: " .. err)
	end
end)

game:BindToClose(function()

	for i, player in pairs(game.Players:GetPlayers()) do
		if player then
			player:Kick("Shutting down - Please rejoin, ariga2!")
		end
	end

	wait(5)

end)

im still optimizing the scripts as much as i can before working on the other features… suggestions will help a lot

1 Like

make sure that there are values inside the PlayerSettings folder. Try printing the value and if it says nil, thats the problem.

it prints it

server script

local function PRINTMEH(player)
	local datafolder = player:WaitForChild("PlayerDataFolder")
	local playerSettings = datafolder:WaitForChild("PlayerSettings")
		
	for i, item in pairs(playerSettings:GetChildren()) do
		print(item.Name .. " Value: ".. item.Value)
	end
end

game.ReplicatedStorage.DEBUGREMOTE.OnServerEvent:Connect(PRINTMEH) 

local script:

local UIS = game:GetService("UserInputService")


UIS.InputBegan:Connect(function(input)
	if input.KeyCode == Enum.KeyCode.L then
		game.ReplicatedStorage.DEBUGREMOTE:FireServer()
	end
end)

Output:

Changed the value through server side:

but when i leave, the player removing event fires and outputs this:

I don’t know where line 51 was so it was a bit of a nightmare to scroll through your code to find the exact part that’s throwing an error. Please make sure to add comments in your code for support threads indicating where the source of the problem is just so it’s easier to navigate.

In any case, from what I’ve gone over it looks like you slightly misunderstand your own code. Your create table function creates a dictionary where the index is your setting and the value is of course the value of that ValueObject. Your createTable function will return a structure like this:

{
    ["foobar"] = "Hello world"
}

This dictionary does not have a name or key property though you attempt to access them in the transform function given to UpdateAsync. Recall that a for loop will iterate through key-value pairs in a table, the respective variables representing the key and the value. You already have access to both the name and the value, so you shouldn’t treat the table as though it didn’t serialise the ValueObjects.

Just make a change with your UpdateAsync’s for loop to use the index of the pair.

for key, value in pairs(playersettingsdatatable) do
    dataTable[key] = value
end

Might I also suggest a different naming case, just on an unrelated note? Having your entire variable in flat case is kind of wonky to look at, but it’s fine if you can read it at least. I’d go with camelCase there as well as for a good number of your variables.

1 Like

tried this

for key, value in pairs(playersettingsdatatable) do
    dataTable[key] = value
end

the key prints the name of the value, but the value doesn’t print the values value… how is that?

edit:

i tried printing dataTable[key].Value and it prints properly

That’s not specific enough for me to know where you put it; I don’t know where you’re trying this. I’d like to reclarify that this is intended for the for loop in UpdateAsync, not createTable. The latter function in its original state takes care of serialising ValueObjects to a key-value paired dictionary. Please feel free to re-review my post for more information.

1 Like

yeah thanks for it, i actually fixed it a while ago and here’s the final script:

local dataStore = game:GetService("DataStoreService")
local playerSettingsData = dataStore:GetDataStore("SettingsData")

local function playerAdded(player)	
	local dataFolder = player:WaitForChild("PlayerDataFolder")
	local userId = player.UserId
	
	local playerSettings = Instance.new("Folder")
	playerSettings.Name = "PlayerSettings"
	playerSettings.Parent = dataFolder
	
	local playerDisplayName = Instance.new("StringValue")
	playerDisplayName.Name = "PlayerDisplayName"
	playerDisplayName.Parent = playerSettings
	
	local data
	local success, err = pcall(function()
		data = playerSettingsData:GetAsync(userId .. "-Settings")
	end)
	
	if data then
		print(player.Name .. "'s Settings has been loaded")
		for i, item in pairs(playerSettings:GetChildren()) do
			item.Value = data[item.Name]
		end
	else
		print(player.Name .. "'s a new player.. or forgotten.. created a new Settings")
		playerDisplayName.Value = player.Name
	end
end

local function dataTable(player)
	local dataFolder = player:WaitForChild("PlayerDataFolder")
	local settingsFolder = dataFolder:WaitForChild("PlayerSettings")
	
	local settingsTable = {}
	
	for i, item in pairs(settingsFolder:GetChildren()) do
		settingsTable[item.Name] = item.Value
	end
	
	return settingsTable
end


local function playerLeave(player)
	local settingsTable = dataTable(player)
	local userId = player.UserId
	
	local success, err = pcall(function()
		playerSettingsData:UpdateAsync(userId .. "-Settings", function(recentData)
			local dataTable = recentData or {}
			
			for item, value in pairs(settingsTable) do
				dataTable[item] = value
			end
			
			return dataTable
		end)
	end)
	
	if success then
		print(player.Name .. "'s Settings saved!")
	else
		print(player.Name .. "'s Settings failed to save!, because ".. err)
	end
end

game.Players.PlayerRemoving:Connect(playerLeave)
game.Players.PlayerAdded:Connect(playerAdded)

any suggestions will help, thanks again!