Help Getting Values From Data Store

Did you try my new method? (also remove the GetData in your regular script, just don’t set the value there, it’ll be set in the module script) Then check your explorer window to see if the data is set there.

Also, just as a recommendation, for the change stat function, also modify it to this:

function PlayerStatManager:ChangeStat(player, statName, value)
	local playerUserId = "Player_" .. player.UserId
	assert(typeof(sessionData[playerUserId][statName]) == typeof(value), "ChangeStat error: types do not match")
	if typeof(sessionData[playerUserId][statName]) == "number" then
		sessionData[playerUserId][statName] = sessionData[playerUserId][statName] + value
	else
		sessionData[playerUserId][statName] = value
	end
	UpdateBoard2Player(player)
end

I think you meant AddBoard2Player instead of UpdateBoard2Player.

Lol, I wasn’t seeing the code, sorry about that.

I’m not sure if it works; there are no errors.

1 Like

Yeah so if you’re testing it in Roblox Studio, just check the Explorer tab, and go under your Player object, search for the value, and check its Value property to see if it’s correct. Hope this helps!

1 Like

Everything in the explorer looks good, but the NameCol and BioCol values are “0, 0, 0” and appear black.

Edit: I think it’s because I made the color of the Gui to be the value, which is “255, 255, 255” instead of adding a Color3.fromRGB in front of it.

I have the Cash value in a leaderstats folder. How would I index the Cash value?

The Color values are blank for some reason.

Oh yeah, I just want to add a friendly tip. As I made two games before, here’s my experience. Sometimes you want to add more types of data in your game, and if you already have data before playing the game, it would cause you to not have that extra data, so here’s my solution for that:
Add a table of the default values you want for your data:

local DefaultData = {
	Cash = 50000,
	Name = player.Name,
	Bio = "",
	NameCol = "255, 255, 255",
	BioCol = "0, 255, 255"
}

Then a function that can return a copy of your default values (setting a variable as a table will reference it, not make a copy of it):

local function CloneTableFunction(Table)
	local CloneTable = {}
	for Key,Value in pairs(Table) do
		if type(Value) == "table" then
			Value = CloneTableFunction(Value)
		end
		CloneTable[Key] = Value
	end
	return DefaultData
end

So then you could change your setupPlayerData function to this:

local function setupPlayerData(player)
	local playerUserId = "Player_" .. player.UserId
	local success, data = pcall(function()
		return playerData:GetAsync(playerUserId)
	end)
	if success then
		if data then
			local DefaultClone = CloneTableFunction(DefaultData)
			local function CheckFunction(BaseTable, CheckTable)
				for Key,Value in pairs(CheckTable) do
					if BaseTable[Key] and type(Value) == "table" then
						CheckFunction(BaseTable[Key], Value)
					end
					if not BaseTable[Key] then
						BaseTable[Key] = Value
					end
				end
				return BaseTable
			end
			data = CheckFunction(data, DefaultClone)
			sessionData[playerUserId] = data
		else
			sessionData[playerUserId] = CloneTableFunction(DefaultData)
		end
		AddBoard2Player(player)
	else
		warn("Cannot access data store for player!")
	end
end

Also, I see your new replies as I’m typing this, so can you show me your Value object hierarchy in the Explorer?

1 Like

Let’s try this:

function AddBoard2Player(player)
	local playerUserId = "Player_" .. player.UserId
	if sessionData[playerUserId] then
		for DataName, DataValue in pairs(sessionData[playerUserId]) do
			local DataObject = player:FindFirstChild(DataName)
			if DataObject then
				DataObject.Value = DataValue
			end
			local Leaderstats = player:FindFirstChild("leaderstats")
			if Leaderstats then
				local LeaderstatDataObject = Leaderstats:FindFirstChild(DataName)
				if LeaderstatDataObject then
					LeaderstatDataObject.Value = DataValue
				end
			end
		end
	end
end

image
How do I get the player value?

Replace that with a “”, but what I don’t really get is that you can already get the player name easily from player.Name, so why bother use up space in the DataStore to store the player’s name? But yeah, after that, also go to your setupPlayerData function and write:

local function setupPlayerData(player)
	local playerUserId = "Player_" .. player.UserId
	local success, data = pcall(function()
		return playerData:GetAsync(playerUserId)
	end)
	if success then
		if data then
			local DefaultClone = CloneTableFunction(DefaultData)
			local function CheckFunction(BaseTable, CheckTable)
				for Key,Value in pairs(CheckTable) do
					if BaseTable[Key] and type(Value) == "table" then
						CheckFunction(BaseTable[Key], Value)
					end
					if not BaseTable[Key] then
						BaseTable[Key] = Value
					end
				end
				return BaseTable
			end
			data = CheckFunction(data, DefaultClone)
			sessionData[playerUserId] = data
			sessionData[playerUserId]["Name"] = player.Name
		else
			sessionData[playerUserId] = CloneTableFunction(DefaultData)
			sessionData[playerUserId]["Name"] = player.Name
		end
		AddBoard2Player(player)
	else
		warn("Cannot access data store for player!")
	end
end

This is my ModuleScript now:

-- Set up table to return to any script that requires this module script
local PlayerStatManager = {}

local DataStoreService = game:GetService("DataStoreService")
local playerData = DataStoreService:GetDataStore("PlayerData")
-- Table to hold player information for the current session

local DefaultData = {
	Cash = 50000,
	Name = "",
	Bio = "",
	NameCol = "255, 255, 255",
	BioCol = "0, 255, 255"
}

local function CloneTableFunction(Table)
	local CloneTable = {}
	for Key,Value in pairs(Table) do
		if type(Value) == "table" then
			Value = CloneTableFunction(Value)
		end
		CloneTable[Key] = Value
	end
	return DefaultData
end

local sessionData = {}

function AddBoard2Player(player)
	local playerUserId = "Player_" .. player.UserId
	if sessionData[playerUserId] then
		for DataName, DataValue in pairs(sessionData[playerUserId]) do
			local DataObject = player:FindFirstChild(DataName)
			if DataObject then
				DataObject.Value = DataValue
			end
			local Leaderstats = player:FindFirstChild("leaderstats")
			if Leaderstats then
				local LeaderstatDataObject = player:FindFirstChild(DataName)
				if LeaderstatDataObject then
					LeaderstatDataObject.Value = DataValue
				end
			end
		end
	end
end

-- Function that other scripts can call to change a player's stats
function PlayerStatManager:ChangeStat(player, statName, value)
	local playerUserId = "Player_" .. player.UserId
	assert(typeof(sessionData[playerUserId][statName]) == typeof(value), "ChangeStat error: types do not match")
	if typeof(sessionData[playerUserId][statName]) == "number" then
		sessionData[playerUserId][statName] = sessionData[playerUserId][statName] + value
		print(sessionData)
	else
		sessionData[playerUserId][statName] = value
		print(sessionData)
	end
	AddBoard2Player(player)
end

-- Function to add player to the "sessionData" table
local function setupPlayerData(player)
	local playerUserId = "Player_" .. player.UserId
	local success, data = pcall(function()
		return playerData:GetAsync(playerUserId)
	end)
	if success then
		if data then
			local DefaultClone = CloneTableFunction(DefaultData)
			local function CheckFunction(BaseTable, CheckTable)
				for Key,Value in pairs(CheckTable) do
					if BaseTable[Key] and type(Value) == "table" then
						CheckFunction(BaseTable[Key], Value)
					end
					if not BaseTable[Key] then
						BaseTable[Key] = Value
					end
				end
				return BaseTable
			end
			data = CheckFunction(data, DefaultClone)
			sessionData[playerUserId] = data
			sessionData[playerUserId]["Name"] = player.Name
		else
			sessionData[playerUserId] = CloneTableFunction(DefaultData)
			sessionData[playerUserId]["Name"] = player.Name
		end
		AddBoard2Player(player)
	else
		warn("Cannot access data store for player!")
	end
end

local function savePlayerData(playerUserId)
	if sessionData[playerUserId] then
		local tries = 0	
		local success
		repeat
			tries = tries + 1
			success = pcall(function()
				playerData:SetAsync(playerUserId, sessionData[playerUserId])
			end)
			if not success then wait(1) end
		until tries == 3 or success
		local success, err = pcall(function()
			playerData:SetAsync(playerUserId, sessionData[playerUserId])
		end)
		if not success then
			warn("Cannot save data for player!")
		end
	end
end

function PlayerStatManager:GetData(player, statName)
	local playerUserId = "Player_" .. player.UserId
	if sessionData[playerUserId][statName] then
		return sessionData[playerUserId][statName]
	end
end

-- Function to save player data on exit
local function saveOnExit(player)
	local playerUserId = "Player_" .. player.UserId
	savePlayerData(playerUserId)
end

-- Connect "setupPlayerData()" function to "PlayerAdded" event
game.Players.PlayerAdded:Connect(setupPlayerData)

-- Connect "saveOnExit()" function to "PlayerRemoving" event
game.Players.PlayerRemoving:Connect(saveOnExit)

return PlayerStatManager

I don’t know if its right or not.

This is what my explorer looks like
image

Just check their properties and see if they’re right. Hopefully they are! :slight_smile:

The colors are still black though.

I don’t know if this script is the problem or not:

local DataStoreService = game:GetService("DataStoreService")
local playerData = DataStoreService:GetDataStore("PlayerData")
local Players = game:GetService("Players")
local PlayerStatManager = require(game.ServerScriptService.DataSetup)

Players.PlayerAdded:Connect(function(player)
	
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

	local Cash = Instance.new("IntValue")
	Cash.Name = "Cash"
	Cash.Parent = leaderstats
	
	local RPName = Instance.new("StringValue")
	RPName.Name = "RPName"
	RPName.Parent = player
	
	local RPBio = Instance.new("StringValue")
	RPBio.Name = "RPBio"
	RPBio.Parent = player
	
	local NameCol = Instance.new("StringValue")
	NameCol.Name = "NameCol"
	NameCol.Parent = player
	
	local BioCol = Instance.new("StringValue")
	BioCol.Name = "BioCol"
	BioCol.Parent = player
	
	local OwnsHouse = Instance.new("BoolValue")
	OwnsHouse.Name = "OwnsHouse"
	OwnsHouse.Value = false
	OwnsHouse.Parent = player
	
	local Char = player.Character or player.CharacterAdded:Wait()

	local HeadCol = Instance.new("Color3Value")
	HeadCol.Parent = player
	HeadCol.Value =  Char:WaitForChild("Humanoid").HumanoidDescription.HeadColor
	HeadCol.Name = "HeadCol"
	
	local TorsoCol = Instance.new("Color3Value")
	TorsoCol.Parent = player
	TorsoCol.Value =  Char:WaitForChild("Humanoid").HumanoidDescription.TorsoColor
	TorsoCol.Name = "TorsoCol"
	
	local LeftArmCol = Instance.new("Color3Value")
	LeftArmCol.Parent = player
	LeftArmCol.Value =  Char:WaitForChild("Humanoid").HumanoidDescription.LeftArmColor
	LeftArmCol.Name = "LeftArmCol"
	
	local RightArmCol = Instance.new("Color3Value")
	RightArmCol.Parent = player
	RightArmCol.Value =  Char:WaitForChild("Humanoid").HumanoidDescription.RightArmColor
	RightArmCol.Name = "RightArmCol"
	
	local LeftLegCol = Instance.new("Color3Value")
	LeftLegCol.Parent = player
	LeftLegCol.Value =  Char:WaitForChild("Humanoid").HumanoidDescription.LeftLegColor
	LeftLegCol.Name = "LeftLegCol"
	
	local RightLegCol = Instance.new("Color3Value")
	RightLegCol.Parent = player
	RightLegCol.Value =  Char:WaitForChild("Humanoid").HumanoidDescription.RightLegColor
	RightLegCol.Name = "RightLegCol"
	
	local ShirtId = Instance.new("StringValue")
	ShirtId.Parent = player
	ShirtId.Name = "ShirtId"
	
	if Char:WaitForChild("Shirt") ~= nil then
		ShirtId.Value = Char.Shirt.ShirtTemplate
	else
		ShirtId.Value = ""
	end
	
	local PantsId = Instance.new("StringValue")
	PantsId.Parent = player
	PantsId.Name = "PantsId"
	
	if Char:WaitForChild("Pants") ~= nil then
		PantsId.Value = Char.Pants.PantsTemplate
	else
		PantsId.Value = ""
	end
end)

Can you tell me which values isn’t working? And can you provide me a screenshot of your new sessionData?

The Color values are correct, but it makes the TextLabel black.

Also, I’m testing it out right now.

sessionData:
image

Nice, the data is correct. I think the problem would be that your Label’s Color3 value needs to be set to something like this: Label.TextColor3 = Color3.fromRGB(NameCol.Value). Basically it needs to be wrapped by the Color3.fromRGB(). I’m not sure if you already scripted it that way though.