Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

attempt to index function with 'SName' | Data module creation (?)

I'm working on a dataModule right now, and I'm a bit confused with this error

 10:56:08.088  ServerScriptService.DataModule:80: attempt to index function with 'SName'  -  Server - DataModule:80
  10:56:08.089  Stack Begin  -  Studio
  10:56:08.089  Script 'ServerScriptService.DataModule', Line 80  -  Studio - DataModule:80
  10:56:08.089  Script 'ServerScriptService.PlayerData', Line 38  -  Studio - PlayerData:38
  10:56:08.090  Stack End  -  Studio

I'm trying to load player data thru a table to minimize datastore throttling, however, the only character on line 80 is a }. If anybody has a fix, please tell me, it'd be great This is what it is connected to

local saveData = {
	
}

The dataModule

local dataModule = {}

local DSS = game:GetService("DataStoreService")
local http = game:GetService("HttpService")
local dataStore = DSS:GetDataStore("plr-Data")

--[[
	Create leaderstats
	
	Args:
	userStats (table) - Table of all stats
	plr (Player) - Player to create the leaderstats for
]]
dataModule.init = function(userStats, plr)
	if userStats and plr then
		local leaderstats = Instance.new("Folder")
		leaderstats.Name = "leaderstats"
		leaderstats.Parent = plr
		
		for i, v in pairs(userStats) do
			if v.SName and v.Type and v.StartValue >= 0 then
				local stat = Instance.new(v.Type.."Value")
				stat.Name = v.SName
				stat.Parent = leaderstats
			end
		end
	end
end

--[[
	Load leaderstats
	
	Args:
	userStats (table) - Table of all stats
	plr (Player) - Player to load the leaderstats for
	
	Returns:
	stats (table) - Entire table of the user's stats
]]
dataModule.load = function(userStats, plr)
	if plr and userStats then
		
		local saveData
		
		local success, err = pcall(function()
			local data = dataStore:GetAsync("plr-"..plr.UserId)
			
			if data then
				saveData = http:JSONDecode(data)
			end
		end)
		
		if success then
			if saveData then
				for i, v in pairs(userStats) do
					local stat = plr.leaderstats[v.NSame]
					stat.Value = saveData[v.SName]
				end
			else
				for i, v in pairs(userStats) do
					local stat = plr.leaderstats[v.SName]
					stat.Value = v.StartValue
				end
			end
		end
	end
end

--[[
	Save leaderstats
	
	Args:
	userStats (table) - Table of all stats
	plr (Player) - Player to save the leaderstats for
]]
dataModule.save = function(userStats, plr)
	if plr and userStats then
		local saveData = {
			
		}
		
		for i, v in pairs(userStats) do
			local stat = plr.leaderstats[v.SName]
			saveData[v.SName] = stat.Value
		end
		
		print(http:JSONEncode(saveData))
	end
end

return dataModule

The server script

local dataModule = require(script.Parent:WaitForChild("DataModule",60))

-- recommended you close this
local userStats = {
	["Stat1"] = {
		["SName"] = "Bank",
		["Type"] = "Int",
		["StartValue"] = 2000
	},
	["Stat2"] = {
		["SName"] = "Wallet",
		["Type"] = "Int",
		["StartValue"] = 0
	},
	["Stat3"] = {
		["SName"] = "Jail",
		["Type"] = "Int",
		["StartValue"] = 0
	},
	["Stat4"] = {
		["SName"] = "Hunger",
		["Type"] = "Int",
		["StartValue"] = 100
	},
	["Stat5"] = {
		["SName"] = "Thirst",
		["Type"] = "Int",
		["StartValue"] = 100
	}
}

game.Players.PlayerAdded:Connect(function(plr)
	dataModule.init(userStats, plr)
	dataModule.load(userStats, plr)
end)

game.Players.PlayerRemoving:Connect(function(plr)
	dataModule:save(userStats, plr)
end)

1 answer

✓ Accepted answer

The error comes from line 84 where you are indexing [v] which is a function, your issue is that you are declaring [save] like this

dataModule.save = function(userStats, plr)

The same syntax would be

function dataModule.save(userStats, plr)

And here you can probably see the issue, you are declaring [save] with a dot (.) and on line 38 you call it with a colon (:)

dataModule:save(userStats, plr)

To fix it, call it with a dot on that line 38

dataModule.save(userStats, plr)

The reason for that problem is that when you use a colon when calling a function, you are automatically passing self argument to the function, self is keyword that refers to table that called the function, it is used with metatables and in your case [self] refers to the [dataModule] because you called [save] like that.

If you were to define [save] like this

dataModule:save(userStats, plr)

You would not have any issues, however when the function is defined with a dot, when calling it with a colon you are going to pass [self] as a first parameter and all other parameters are going to be one slot off like this:

-- self will be dataModule in your case
dataModule.save(self, userStats, plr)

You might think, why you need that? Well i talked about them metatables however the simpler use is this for example:

local kirda = {
	Health = 10,

	Kill = function()
		-- i want to kill kirda, but how do i change [Health] variable?
		kirda.Health = 0 -- not working
		Health = 0 -- not working
	end,
}

You can fix that by using [self]!

local kirda = {
	Health = 10,

	Kill = function(self)
		self.Health = 0
	end,
}

kirda:Kill() -- colon passes self, self is who called the function, kirda did!

In your case since the [dataModule] was self, you was looping through the module and of course [v] was one of the module functions.

This discussion is preserved as it was. New answers, comments, and votes are closed.