Why is my self.Stats nil?

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? Keep it simple and clear!

I am trying to make my OOP data module.

  1. What is the issue? Include screenshots / videos if possible!

The variable self.Stats is nil in the SaveStats() function when it can be accessed by other functions just fine.

module

local StatsManager  = {}
StatsManager.__index = StatsManager

local Settings = {}

local TableUtil = require(game.ServerScriptService.TableUtil)

Settings.TriesAllowed = 3
Settings.DataKey = "TestKey"
Settings.StudioSave = true
Settings.DefaultTable = {Cash = 0}

local MainStore = game:GetService("DataStoreService"):GetDataStore(Settings.DataKey)

local PlayerObjects = {}

function StatsManager.new(player)
	local self = {}
	setmetatable(self, StatsManager)
	
	local leaderstats = Instance.new("Folder", player)
	leaderstats.Name = "leaderstats"
	
	self.Key = "PlayerData-"..player.UserId
	self.Id = player.UserId
	self.Stats = StatsManager[self.Id]
	self.Player = player
	self.leaderstats = leaderstats
	
	PlayerObjects[player.Name] = self
	
	return self
end

function StatsManager:GetPlayerManager(player)
	return PlayerObjects[player.Name]
end

function StatsManager:LoadStats()
	
	local tries = 0
	local success
	
	local data 
	
	repeat
		tries = tries + 1
		
		success = pcall(function()
			data = MainStore:GetAsync(self.Key)
		end)
	until tries == 3 or success
	
	if data then self.Stats = data else self.Stats = TableUtil.deepCopy(Settings.DefaultTable) end
	
	for key,value in pairs(self.Stats) do
		local newValue = Instance.new("StringValue", self.leaderstats)
		newValue.Name = key
		newValue.Value = value
	end
end

function StatsManager:SaveStats()
	local tries = 0
	local success
	
	local data 
	local err
	
	repeat
		tries = tries + 1
		
		success, err = pcall(function()
			MainStore:SetAsync(self.Key, self.Stats)
		end)
	until tries == 3 or success
	
	if not success then
		print("error saving")
		print(err)
	end
end

function StatsManager:IncrementStat(statName, incrementValue)
	if self.Stats[statName] then
		self.Stats[statName] = self.Stats[statName] + incrementValue
		self:UpdateStats()
	else
		warn(statName.." is not a valid member of stats")
	end
end

function StatsManager:SetStat(statName, newValue)
	if self.Stats[statName] then
		self.Stats[statName] = newValue
		self:UpdateStats()
	else
		warn(statName.." is not a valid member of stats")
	end
end

function StatsManager:GetStat(statName)
	if self.Stats[statName] then
		return self.Stats[statName]
	else
		warn(statName.." is not a valid member of stats")
	end
end

function StatsManager:UpdateStats()
	for key,value in pairs(self.Stats) do
		if self.leaderstats:FindFirstChild(tostring(key)) then
			self.leaderstats[tostring(key)].Value = value
		else
			warn(tostring(key).." is not a valid member of leaderstats")
		end
	end
end

function StatsManager:ClearStats()
	self.Stats = TableUtil.deepCopy(Settings.DefaultTable)
end

game.Players.PlayerRemoving:Connect(function(player)
	if PlayerObjects[player.Name] then
		if Settings.StudioSave then
			StatsManager:SaveStats()
			PlayerObjects[player.Name] = nil
		end
	end
end)

game:BindToClose(function()
	if game:GetService("RunService"):IsStudio() == false then
		for _,player in pairs(game.Players:GetPlayers()) do
			local PlayerStatManager = StatsManager:GetManager(player)
			PlayerStatManager:SaveStats()
		end
	else
		wait(2)
	end
end)

return StatsManager

script


local StatsManager = require(script.Parent.StatsManager)

game.Players.PlayerAdded:Connect(function(player)
	local PlayerStatManager = StatsManager.new(player)
	PlayerStatManager:LoadStats()
	
	while true do
		wait(1)
		PlayerStatManager:IncrementStat("Cash", 50)
	end
end)

1 Like

In your new method, you define self.Stats as StatsManager[self.Id]. StatsManager is your module. Do you ever define self.Id as an index of StatsManager, or more clearly, is the player’s UserId ever defined as an index in the module?

In your code shown, you never set StatsManager[UserId] to anything.

Edit: Ignore above. In PlayerRemoving, you call StatsManager instead of the class. You need to wrap the connections into the class itself so they use self instead of the module.

1 Like