Help with saving player's 'settings'

Hello!

I am trying to make a settings page for my game but am having trouble saving it. This setting page would just store bool, number and string values for each of the settings through a table/dictionary.

My issue is that it isn’t saving. I have a ‘test button’ that when you click on it it changes the value of one of the settings, but when I rejoin, it doesn’t save.

Solutions I have tried are RemoteEvents, rewriting code, Developer Hub and the DevForum, all to no avail.

I will really appreciate it if any of you guys can help.

ServerScript (in SSS)
local settingsTable = require(game.ReplicatedStorage.SettingsTable)
local notificationModule = require(game.ReplicatedStorage.NotificationModule)
local plr = game.Players.LocalPlayer

local settingsTableSuccess = {
	BackgroundColor = Color3.fromRGB(0,0,0);
	TextColor = Color3.fromRGB(255,255,255);
	Text = "Data was saved Succesfully!";
	Duration = 10;
	Player = plr; 
}

local settingsTableHasntSaved = {
	BackgroundColor = Color3.fromRGB(0,0,0);
	TextColor = Color3.fromRGB(255,255,255);
	Text = "Data hasn't been saved!";
	Duration = 10;
	Player = plr; 
}

local settingsTableNoData = {
	BackgroundColor = Color3.fromRGB(0,0,0);
	TextColor = Color3.fromRGB(255,255,255);
	Text = "This player has no data!";
	Duration = 10;
	Player = plr; 
}
-- // Assigning variables //
local DataStoreService = game:GetService("DataStoreService")
local dataStore = DataStoreService:GetDataStore("SettingsDataStore") -- This can be changed to whatever you want

local function saveData(player) -- The functions that saves data

	local tableToSave = {
		settingsTable;
	}

	local success, err = pcall(function()
		dataStore:SetAsync(player.UserId, tableToSave) -- Save the data with the player UserId, and the table we wanna save
	end)

	if success then -- If the data has been saved
		notificationModule:CreatePlayerNotification(settingsTableSuccess)
	else -- Else if the save failed
		notificationModule:CreatePlayerNotification(settingsTableHasntSaved)
		warn(err)		
	end
end


game.Players.PlayerAdded:Connect(function(player) -- When a player joins the game

	local data -- We will define the data here so we can use it later, this data is the table we saved
	local success, err = pcall(function()

		data = dataStore:GetAsync(player.UserId) -- Get the data from the datastore

	end)

	if success then -- If there were no errors and player loaded the data

		settingsTable = data -- Set the money to the first value of the table (data)

	else -- The player didn't load in the data, and probably is a new player
		notificationModule:CreatePlayerNotification(settingsTableNoData) -- The default will be set to 0
	end

end)

game.Players.PlayerRemoving:Connect(function(player) -- When a player leaves
	local success, err  = pcall(function()
		saveData(player) -- Save the data
	end)

	if success then
		notificationModule:CreatePlayerNotification(settingsTableSuccess)
	else
		notificationModule:CreatePlayerNotification(settingsTableHasntSaved)
	end
end)

game:BindToClose(function() -- When the server shuts down
	for _, player in pairs(game.Players:GetPlayers()) do -- Loop through all the players
		local success, err  = pcall(function()
			saveData(player) -- Save the data
		end)

		if success then
			notificationModule:CreatePlayerNotification(settingsTableSuccess)
		else
			notificationModule:CreatePlayerNotification(settingsTableHasntSaved)
		end
	end
end)

ModuleScript (in RS)
local settingsTable = {
DarkMode = false,
Brightness = 1,
MuteAllAudio = false,
DebugMode = false,
CreatorCode = "",
}

return settingsTable
TestScript (in SG)
local tButton = script.Parent.Container.DarkMode.testButton
local settingsTable = require(game.ReplicatedStorage.SettingsTable)

print(settingsTable["DarkMode"])

tButton.MouseButton1Click:Connect(function()
	settingsTable["DarkMode"] = true
	wait(2)
	print(settingsTable["DarkMode"])
end)

Thanks in advance,
cursecode

3 Likes

Anybody have some solutions or questions?

You need to use data stores. Data Stores | Documentation - Roblox Creator Hub

This way a player’s data can be saved across all servers.

forgive if im wrong but at the save data function You placed the settings table into a table

but later you when you got the data from the save you put the settings table as the data this would make it so that

data[1] was the saved settings
while if you did data[“DarkMode”]
it would return as nil

i think a solution would be to
`
local function saveData(player) – The functions that saves data

local tableToSave = settingsTable

local success, err = pcall(function()
	dataStore:SetAsync(player.UserId, tableToSave) -- Save the data with the player UserId, and the table we wanna save
end)

if success then -- If the data has been saved
	notificationModule:CreatePlayerNotification(settingsTableSuccess)
else -- Else if the save failed
	notificationModule:CreatePlayerNotification(settingsTableHasntSaved)
	warn(err)		
end

end
`

1 Like

It might be because you’re using a module for storing the table. Some of these problems include:

  • The client and the server have their own copies of modules.
  • Once a player joins, the module will have it’s data changed to the one of the new player.

I will give you an alternative to you that I personally use (and a way of sending that data to the client!):
Server script:

local dss = game:GetService("DataStoreService")
local settingsStore = dss:GetDataStore("settingsStore")

local playersData = {}
local sendDataEvent = game:GetService("ReplicatedStorage"):WaitForChild("sendData")

game.Players.PlayerAdded:Connect(function(player)
	
	local retrievedData
	
	local suc = pcall(function()
		
		retrievedData = settingsStore:GetAsync(player.UserId)
		
	end)
	
	if suc then
		
		if retrievedData then -- if they have data
			
			playersData[player.UserId] = retrievedData -- we create an index which is the player id and put the table in there
			
		else -- if they dont have data
			
			-- we do the same thing as above however we will create a new table for them
			
			playersData[player.UserId] = {
				
				DarkMode = false,
				Brightness = 1,
				MuteAllAudio = false,
				DebugMode = false,
				CreatorCode = "",
				
			}
			
		end
		
	end
	
	sendDataEvent:FireClient(player,settingsStore[player.UserId])
	
end)

game.Players.PlayerRemoving:Connect(function(player)
	
	-- from what i remember there is no need for pcalls when writing to data stores (correct me if im wrong)
	
	settingsStore:SetAsync(player.UserId,playersData[player.UserId])
	
end)

Local script:

local sendDataEvent = game:GetService("ReplicatedStorage"):WaitForChild("sendData")
local playerData

local tButton = script.Parent:WaitForChild("Container"):WaitForChild("DarkMode"):WaitForChild("testButton") -- recommend putting all of these in a :WaitForChild

tButton.MouseButton1Click:Connect(function()
	
	-- pro tip: you don't need to use [""] when the index doesn't contain spaces (such as "Dark Mode")
	-- that means you wanna use playerData.DarkMode
	-- and if the index was "Dark Mode", then you use playerData["Dark Mode"]
	playerData.DarkMode = true
	wait(2)
	print(playerData.DarkMode)
end)

sendDataEvent.OnClientEvent:Connect(function(newPlayerData)
	
	playerData = newPlayerData
	
end)

Hope this was helpful!
Edit: create a remote event inside ReplicatedStorage caled sendData

5 Likes

I am well aware of this

@zamd157 The output has some errors, and nil. I think the issue is that on line 4, you didn’t define the default player data.

EDIT: As well, I believe that instead of calling dictionaries/tables like print(playerData.DarkMode), I believe it’s print(playerData["DarkMode"])

It also seems like you forgot to define anywhere where the DataStore is or calling it in the client script.

1 Like