Why is it saying it's nil when I'm indexing the table?

for i,v in ipairs(InstanceData:GetChildren()) do
	if v:IsA("Folder") then
		print("98".. v.Name)
		table.insert(dataTable,v.Name)
		for _,obj in ipairs(v:GetChildren()) do
			print(obj.Name)
			table.insert(dataTable[v.Name],obj.Name) -- dataTable[v.Name]
			dataTable[v.Name][obj.Name] = obj.Value
			--dataTable[v.Name][obj.Name] = obj.Value
		end
	end
end

Essentially the issue with this is this line.

table.insert(dataTable[v.Name],obj.Name)

image

image

The variable v is the Data Folder. obj is Avalue

Essentially I’ve inserted the folders name into the table and then i get the children of this folder as the isntance itself. So i’m trying to insert to a table in a table and then I want to set a value for the stored object name with its corresponding value.

Also if this is errorring does this also mean my data loading is done wrong as well? (SInce this will most likely also error)

local s,response = pcall(function()
	if player_data ~= nil then
		for i,v in pairs(player_data) do
			print(i)
			if #v > 1 then -- means its a table in a table
				Folder = TemplateData:FindFirstChild(player_data[i])
				print(Folder.Name.." 63 ")
				for ObjName,ObjValue in pairs(player_data[i]) do
					print(ObjName.." - "..ObjValue)
					for r,Instancee in ipairs(Folder:GetChildren()) do
						if Instancee.Name == ObjName then
							Instancee.Value = ObjValue
						end
					end
				end
			end
		end
		warn("Finished Loading data for "..Player.Name)
	else
		warn("Player has no data. Will keep with the defaults")
	end
end)

Looking for someone to explain my issues and help me understand why this error has happened as I’ve been looking for quite some time now to make this work.

dataTable[v.Name] if you try printing that, what do you get?

Or maybe, here’s your issue
table.insert(dataTable,v.Name)

Try doing this instead:
dataTable[v.Name] = {}

The error is basically saying that dataTable isn’t initialized or doesn’t exist.
if you have set it up as

local dataTable

then you need to set it as:

local dataTable={}

dataTable[v.Name] = {} …?
Ok I will try doing this. And for your question it prints nil however that’s normal behaviour as it has no value only a index

1 Like

Datatable already exists. That’s not the issue. The issue is with indexing a table in a table and applying a value

Here let me reproduce what your script is doing:

local dataTable = {}

table.insert(dataTable,v.Name) -- Inserting value in the table
--Result: dataTable = {v.Name}

dataTable[v.Name][obj.Name] = obj.Value -- Indexing [obj.Name] to nil index because v.Name is not indexes
-- So instead you need to do dataTable[v.Name] = {} which results in
-- dataTable = {[v.Name] = { --[[then you can insert in here]]  } }

dataTable[v.Name] = {}
^ This is not possible as it expects a expression to be passed

What do you mean by the last commented line?

dataTable = {[v.Name]} = {[Obj.Name] = Obj.Value}

This?

I don’t understand. You want to make it an array so then you can add index values to it.

Well not really, I meant something like
dataTable = {[v.Name] = {[obj.Name] = Obj.Value}}

So you have this master table containing dictionnaries. That’s what I understood from your code

1 Like

Ok thanks thats fixed the issue of data saving. Now my next issue in the post is a logic error. Could you please quickly check my code just to make sure its applying data correctly. I’ve checked it several times and see no faults however you probably will see an issue with it. Essentially when i view AValue in game it should say “Changed” in the value instead of “Hi” the code runs with no errors and i’ve done print checks however nothing appears.

Ok so now it saves and loads. However when it saves According to my print statements the table is as it should be Then it saves. Now it loads however its loading with the default??? So then I did a print check on the actual player data from getasync. The data itself is showing defaults which is VERY confusing. I honestly don’t even know where this logic error is and I’ve had over 9 people look at this code and every single one of them couldn’t notice any problems with my code.

Sorry for whoevers going to read this although it’s slightly lengthy. Firstly we have the “DataRetrieve”. Should be properly renamed to DataSettingUp tbh. Essentially this script will retrieve any data and if this players data is not nil then it will apply their data

function module.DataRetrieve(Player,data)
	local dataKey = nil
	local player_data = nil
	local Tries = 0
	local Failed_Loading = false
	
	repeat
		local s,response = pcall(function()
			dataKey = "data-"..tostring(Player.UserId)
			player_data = data:GetAsync(dataKey)
		end)
		
		if s then
			Tries = 3
		end
		
		if response then
			Tries = Tries + 1
			warn("Retrying data load for "..Player.UserId)
			warn(response)
			if Tries == 3 then
				Failed_Loading = true
			end
		end
		
	until Tries == 3 or s
	
	if Failed_Loading == true then
		Player:Kick("Error 1, Data failed to load for you. Please rejoin")
	end
	
	local TemplateData = serverStorage.TemplateData:Clone()
	TemplateData.Parent = replicatedStorage.PlayerData
	TemplateData.Name = Player.UserId
	local Folder = nil
	
	--[[
	 -- check to see what data exists
	for i,v in pairs(player_data) do
		print(i.." 59")
		for j,k in pairs(v) do
			print(j.."  61")	
			for _,value in pairs(k) do
				print(value.." 63")
			end
		end
	end
	]]
	local s,response = pcall(function()
		if player_data ~= nil then
			for i,v in ipairs(TemplateData:GetChildren()) do
				--for i,v in pairs(player_data) do
				if v:IsA("Folder") then-- means its a table in a table
					for index,data in pairs(player_data) do
						for folderName,Objects in pairs(data) do
							if v.Name == folderName then
								warn("Found Match")
								for ObjectName,ObjectValue in pairs(Objects) do
									print("81 "..ObjectName.." "..ObjectValue)
									for r,ActualInstance in ipairs(v:GetChildren()) do
										if ActualInstance.Name == ObjectName then
											warn("Found Match in instances. editing")
											ActualInstance.Value = ObjectValue
										end
									end
								end
							end
						end
					end
				end
			end
			warn("Finished Loading data for "..Player.Name)
		else
			warn("Player has no data. Will keep with the defaults")
		end
	end)
	
	if response then
		warn(response)
	end
end

Now moving onto what saves when you leave the game.

function module.DataSave(Player,Data)
	local dataKey = "data-"..tostring(Player.UserId)
	local player_data = nil	
	local Tries = 0
	local Failed_Save = false
	
	local InstanceData = replicatedStorage.PlayerData:FindFirstChild(Player.UserId)
	local dataToSave = {}
	local dataTable = {}
	for i,v in ipairs(InstanceData:GetChildren()) do
		if v:IsA("Folder") then
			for _,obj in ipairs(v:GetChildren()) do
				dataTable = {[v.Name] = {[obj.Name] = obj.Value}}
			end
		end
	end
	table.insert(dataToSave,dataTable)	
	repeat
		local s,response = pcall(function()
			Data:SetAsync(dataKey,dataToSave)
		end)
		
		if s then
			Tries = 3
			warn(Player.Name.."'s Data has saved")
		end
		
		if response then
			Tries = Tries + 1
			wait(1)
			if Tries == 3 then
				Failed_Save = true
				warn(Player.Name.."'s Data has failed to save.")
			end
		end
	until Tries == 3 or s
end

A few notes that may help. These are scripts in a module (Obviously). So here’s the scripts code incase this is connected.

local data = DataStoreService:GetDataStore(Key.Value.."Data")
DataModule.Initilize()

Player_Table = {}

Players.PlayerAdded:Connect(function(Player)
	DataModule.DataRetrieve(Player,data) -- Setting up / Loading data
	wait()
	if Players:FindFirstChild(Player.Name) then -- Checking to make sure they didn't get kicked for data not loading
		--table.insert(Player_Table,Player) -- Adding player to autosave queue
	end
	
	
end)

Players.PlayerRemoving:Connect(function(Player)
	local InstanceData = replicatedStorage.PlayerData:FindFirstChild(Player.UserId)
	print("wag1 g running the exact same print check from script lets see.. - "..replicatedStorage.PlayerData:FindFirstChild(Player.UserId).Data.AValue.Value)
	DataModule.DataSave(Player,data) -- Saving
	--table.remove(Player_Table,Player) -- Removing from auto-save queue
end)

Now for more context on what this is actually doing.
So basically in serverstorage I have this:image
The code will practically clone this and rename templatedata to their UserId. Then on player leaving it will copy all the data in the folder like this: For folders it will just save the name, For actual values it saves name and value. Then in the loading function it simply does a matching process to find out what var = instance name. Let me know if you need any more information as this is really starting to frustrate me. You can also see why I want this to work badly as a visual ds system is very very useful since I can easily add any new data values or remove them without any issues and its just ease-of-use.

i think your missing one of the values for table.insert
check

I’m not, as I stated above it already saves and loads. The issue is the saving part, since when u check the players data on loading it’s not giving the correct data meaning theirs an issue with the saving. Now the problem is no one has a clue what this problem is.

Are there any errors in the output?

No it’s a logic error. Could you try recreating what I’ve done and see if you get the same results?

I’ve resolved this painful issue that I spent 2 days trying to understand. making the game wait a few seconds when players leave fixes this issue completely. (Also not related but there was also a DS logic error where the actualy data name was different each time)

1 Like