DataStorage saving nil values in ModuleScript?

Hello!

I’m working on a simple EXP system to experiment on, yet I’m encountering several issues.
Would anyone here care to help me out? I’m just stuck at this point.

The main issue I’m facing is that player experience and levels don’t save to the datastorage, resulting in me being unable to use the variables entirely. What I’ve found so far is in the function Player:Leave(), where it prints nil.

ModuleScript

local Player = {}
Player.__index = Player
local Services = require(script.Services)

function Player.new(exp,level)
	local newPlayer = {}
	setmetatable(newPlayer,Player)
	
	newPlayer.Experience = exp or 0
	newPlayer.Level = level or 0
	
	return newPlayer
end

function Player:Leave(user)
	print(self.Experience) --Prints "nil"
	print(self.Level) --Also prints "nil"
	local DataStore = Services.DataStoreService:GetDataStore("userData")
	DataStore:SetAsync(user.UserId,{
		self.Experience, --Saving nil
		self.Level --Also saving nil
	})
end

return Player

Script

local Player = require(script.Parent)
local Services = require(script.Parent.Services)
local DataStore = Services.DataStoreService:GetDataStore("userData")

Services.Players.PlayerAdded:Connect(function(user)
	local data = DataStore:GetAsync(user.UserId)
	
	if data then		
		local newPlayer = Player.new(
			data[1], --Saved data is nil so this is also set to nil
			data[2] --Same here
		)
		print("Experience: "..data[1]) --Clearly also erroring here.
	else
		local newPlayer = Player.new()
	end
end)

Services.Players.PlayerRemoving:Connect(function(user)
	Player:Leave(user)
end)

It’s clear to me there’s something wrong once the player leaves the game, because for some reason it can’t find self.Experience and self.Level. The Experience and Levels are set to 0 if the player has no data yet, so that’s working fine. The issue arises once the script tries to save data by leaving.

Thanks in advance!

This is because you’re not using the returned variable from the module:
In the module you stated:

And then in the script you stated:

You should be using the return, in this case newPlayer, because self uses the passed table:


image
So you should be using newPlayer:Leave() and not Player:Leave() because you’re not using the returned table.

A solution to this can be making a new table and defining a new index for the player:

local PlayerTable = {}

-- Player Added
PlayerTable[user.Name] = Player.new()

-- Player Removed
PlayerTable[user.Name]:Leave()
PlayterTable[user.Name] = nil -- This is to remove the table from memory