Lighting datastore not saving lighting settings

I am trying to create a datastore for lighting settings in my game, which are adjustable. However, when I join the game, change some of the settings, leave, then rejoin, the settings aren’t saved. I am not getting any errors in the output. Also, the output for the line print(player.Name … " loaded settings:\n" … formattedSettings) appears, but doesn’t have any settings inside. Any help is appreciated.

Here is the server side script (located in Server Script Service:

-- Define the data store key for storing settings
local DATA_STORE_KEY = "LightingSettings"

-- Function to save settings to data store
local function saveSettings(player, brightness, saturation, contrast, shadows, sky)
	local dataStore = game:GetService("DataStoreService"):GetDataStore(DATA_STORE_KEY)

	local success, errorMessage = pcall(function()
		local data = {
			Brightness = brightness,
			Saturation = saturation,
			Contrast = contrast,
			Shadows = shadows,
			Sky = sky
		}
		local serializedData = game:GetService("HttpService"):JSONEncode(data)
		dataStore:SetAsync(player.UserId, serializedData)
	end)

	if not success then
		warn("Failed to save settings: " .. errorMessage)
	end
end

-- Function to load settings from data store
local function loadSettings(player)
	local dataStore = game:GetService("DataStoreService"):GetDataStore(DATA_STORE_KEY)

	local success, serializedData = pcall(function()
		return dataStore:GetAsync(player.UserId)
	end)

	if success and serializedData then
		local data = game:GetService("HttpService"):JSONDecode(serializedData)
		return data
	else
		warn("Failed to load settings")
		return nil
	end
end

-- Define the RemoteEvents
local saveSettingsEvent = game:GetService("ReplicatedStorage"):WaitForChild("SaveSettingsEvent")
local loadSettingsEvent = game:GetService("ReplicatedStorage"):WaitForChild("LoadSettingsEvent")

-- Handle saving settings
saveSettingsEvent.OnServerEvent:Connect(function(player, brightness, saturation, contrast, shadows, sky)
	saveSettings(player, brightness, saturation, contrast, shadows, sky)
end)

-- Handle loading settings
loadSettingsEvent.OnServerEvent:Connect(function(player)
	local loadedSettings = loadSettings(player)
	if loadedSettings then
		local formattedSettings = ""
		for key, value in pairs(loadedSettings) do
			formattedSettings = formattedSettings .. key .. ": " .. tostring(value) .. "\n"
		end
		print(player.Name .. " loaded settings:\n" .. formattedSettings)
	end
end)

Here is the client side script (located in Starter Player Scripts):

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local saveSettingsEvent = ReplicatedStorage:WaitForChild("SaveSettingsEvent")
local loadSettingsEvent = ReplicatedStorage:WaitForChild("LoadSettingsEvent")

-- Example function to save settings
local function saveSettings(brightness, saturation, contrast, shadows, sky)
	saveSettingsEvent:FireServer(brightness, saturation, contrast, shadows, sky)
end

-- Example function to load settings
local function loadSettings()
	loadSettingsEvent:FireServer()
end

-- Example usage
saveSettings()
loadSettings()

What does LoadSettings look like? my bad, forgot to scroll

Maybe try putting quotation marks around the keys for each of the settings

I will try that and see if it works.

Add a print statement at the end of the saving function - just to double check the whole thing ran.

I think you need a BindToClose function on the server script, to make sure all data is saved before the game closes.

I tried putting quotations around the different settings in the data list, but it is only printing the words brightness, saturation, etc.

Screenshot 2024-04-02 100750

Here is the updated server script:

-- Define the data store key for storing settings
local DATA_STORE_KEY = "LightingSettings"

-- Function to save settings to data store
local function saveSettings(player, brightness, saturation, contrast, shadows, sky)
	local dataStore = game:GetService("DataStoreService"):GetDataStore(DATA_STORE_KEY)

	local success, errorMessage = pcall(function()
		local data = {
			Brightness = "brightness",
			Saturation = "saturation",
			Contrast = "contrast",
			Shadows = "shadows",
			Sky = "sky"
		}
		local serializedData = game:GetService("HttpService"):JSONEncode(data)
		dataStore:SetAsync(player.UserId, serializedData)
	end)

	if not success then
		warn("Failed to save settings: " .. errorMessage)
	end
end

-- Function to load settings from data store
local function loadSettings(player)
	local dataStore = game:GetService("DataStoreService"):GetDataStore(DATA_STORE_KEY)

	local success, serializedData = pcall(function()
		return dataStore:GetAsync(player.UserId)
	end)

	if success and serializedData then
		local data = game:GetService("HttpService"):JSONDecode(serializedData)
		return data
	else
		warn("Failed to load settings")
		return nil
	end
end

-- Define the RemoteEvents
local saveSettingsEvent = game:GetService("ReplicatedStorage"):WaitForChild("SaveSettingsEvent")
local loadSettingsEvent = game:GetService("ReplicatedStorage"):WaitForChild("LoadSettingsEvent")

-- Handle saving settings
saveSettingsEvent.OnServerEvent:Connect(function(player, brightness, saturation, contrast, shadows, sky)
	saveSettings(player, brightness, saturation, contrast, shadows, sky)
end)

-- Handle loading settings
loadSettingsEvent.OnServerEvent:Connect(function(player)
	local loadedSettings = loadSettings(player)
	if loadedSettings then
		local formattedSettings = ""
		for key, value in pairs(loadedSettings) do
			formattedSettings = formattedSettings .. key .. ": " .. tostring(value) .. "\n"
		end
		print(player.Name .. " loaded settings:\n" .. formattedSettings)
	end
end)

I tried adding it at the end of the saveSettings() function, and it does print the settings saved message.

-- Handle saving settings
saveSettingsEvent.OnServerEvent:Connect(function(player, brightness, saturation, contrast, shadows, sky)
	saveSettings(player, brightness, saturation, contrast, shadows, sky)
	print("Settings Saved")
end)

Even if it does, the store request gets added to a queue. Still add a BindToClose function, it might fix the issue. If it doesn’t, it can prevent future issues.

I am currently working on implementing that, so I’ll let you know if it works.

1 Like

DataStores automatically JSON encode and decode the data they receive or fetch, so there’s no need to encode/decode it yourself and may cause problems since the data will be encoded/decoded twice if you do so

I tried this out, and it completely broke the datastore. There were no errors, but nothing was entered into the output.

I’ll work on some example code to show you what I meant


@jasper53682 Here’s the code (needs to be a server Script to work):

local DataStoreService = game:GetService("DataStoreService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local lightingSettings = DataStoreService:GetDataStore("LightingSettings") -- Better to store a DataStore in a global variable

local saveSettingsEvent = ReplicatedStorage.SaveSettingsEvent
local loadSettingsEvent = ReplicatedStorage.LoadSettingsEvent

saveSettingsEvent.OnServerEvent:Connect(function(player, brightness, saturation, contrast, shadows, sky)
	local success, result = pcall(lightingSettings.SetAsync, lightingSettings, player.UserId, {
		Brightness = brightness,
		Saturation = saturation,
		Contrast = contrast,
		Shadows = shadows,
		Sky = sky
	})

	if success then return end

	warn(`Failed to save settings: {result}`)
end)

loadSettingsEvent.OnServerEvent:Connect(function(player)
	local success, loadedSettings = pcall(lightingSettings.GetAsync, lightingSettings, player.UserId)

	if success then
		if loadedSettings then
			print(loadedSettings)
			-- Write the rest of the code in here
		else
			print(`Player {player.UserId} hasn't saved any data yet`)
		end
	else
		warn(`Failed to fetch settings: {loadedSettings}`)
	end
end)

@12345koip I added the close bind function, and edited the script a little, and now believe that the loading half of the script is the part that isn’t working. The saved lighting values are now being entered into the output, but when I reload into the game, the settings are still the default settings.

image

Here is the updated server side script:

-- Define the data store key for storing settings
local DATA_STORE_KEY = "LightingSettings"

-- Function to save settings to data store
local function saveSettings(player)
	local dataStore = game:GetService("DataStoreService"):GetDataStore(DATA_STORE_KEY)

	local success, errorMessage = pcall(function()
		local lighting = game:GetService("Lighting")
		local data = {
			Brightness = lighting.Brightness,
			Saturation = lighting.ColorCorrection.Saturation,
			Contrast = lighting.ColorCorrection.Contrast,
			Shadows = lighting.GlobalShadows,
		}
		local serializedData = game:GetService("HttpService"):JSONEncode(data)
		dataStore:SetAsync(player.UserId, serializedData)
	end)

	if not success then
		warn("Failed to save settings: " .. errorMessage)
	end
end

-- Function to load settings from data store
local function loadSettings(player)
	local dataStore = game:GetService("DataStoreService"):GetDataStore(DATA_STORE_KEY)

	local success, serializedData = pcall(function()
		return dataStore:GetAsync(player.UserId)
	end)

	if success and serializedData then
		local data = game:GetService("HttpService"):JSONDecode(serializedData)
		return data
	else
		warn("Failed to load settings")
		return nil
	end
end

-- Function to handle saving settings on game shutdown
local function saveSettingsOnShutdown()
	for _, player in ipairs(game.Players:GetPlayers()) do
		saveSettings(player)
	end
end

-- Bind to Close function to save settings when the game is shutting down
game:BindToClose(saveSettingsOnShutdown)

-- Define the RemoteEvents
local saveSettingsEvent = game:GetService("ReplicatedStorage"):WaitForChild("SaveSettingsEvent")
local loadSettingsEvent = game:GetService("ReplicatedStorage"):WaitForChild("LoadSettingsEvent")

-- Handle saving settings
saveSettingsEvent.OnServerEvent:Connect(function(player)
	saveSettings(player)
end)

-- Handle loading settings
loadSettingsEvent.OnServerEvent:Connect(function(player)
	local loadedSettings = loadSettings(player)
	if loadedSettings then
		local formattedSettings = ""
		for key, value in pairs(loadedSettings) do
			formattedSettings = formattedSettings .. key .. ": " .. tostring(value) .. "\n"
		end
		print(player.Name .. " loaded settings:\n" .. formattedSettings)
	end
end)

Here is the updated client side script:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local saveSettingsEvent = ReplicatedStorage:WaitForChild("SaveSettingsEvent")
local loadSettingsEvent = ReplicatedStorage:WaitForChild("LoadSettingsEvent")

-- Example function to save settings
local function saveSettings(Brightness, Saturation, Contrast, Shadows)
	saveSettingsEvent:FireServer(Brightness, Saturation, Contrast, Shadows)
end

-- Example function to load settings
local function loadSettings()
	loadSettingsEvent:FireServer()
end

-- Example usage
saveSettings()
loadSettings()

I don’t see you assigning the settings to any values, etc. If it prints the loaded data, it works - you just need to unpack it.

I tried implementing this script, and added the rest of the loaded settings where you said to write th rest of the code, but nothing is being printed into the output, and nothing is saving/loading. It is possible I did something wrong, since I am newer to scripting and am still learning.
Here is the datastore based on your script (placed in server script service):

local DataStoreService = game:GetService("DataStoreService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local lightingSettings = DataStoreService:GetDataStore("LightingSettings") -- Better to store a DataStore in a global variable

local saveSettingsEvent = ReplicatedStorage.SaveSettingsEvent
local loadSettingsEvent = ReplicatedStorage.LoadSettingsEvent

saveSettingsEvent.OnServerEvent:Connect(function(player, brightness, saturation, contrast, shadows, sky)
	local success, result = pcall(lightingSettings.SetAsync, lightingSettings, player.UserId, {
		Brightness = brightness,
		Saturation = saturation,
		Contrast = contrast,
		Shadows = shadows,
		Sky = sky
	})

	if success then return end

	warn(`Failed to save settings: {result}`)
end)

loadSettingsEvent.OnServerEvent:Connect(function(player)
	local success, loadedSettings = pcall(lightingSettings.GetAsync, lightingSettings, player.UserId)

	if success then
		if loadedSettings then
			print(loadedSettings)
			local formattedSettings = ""
			for key, value in pairs(loadedSettings) do
				formattedSettings = formattedSettings .. key .. ": " .. tostring(value) .. "\n"
			end
			print(player.Name .. " loaded settings:\n" .. formattedSettings)
		else
			print(`Player {player.UserId} hasn't saved any data yet`)
		end
	else
		warn(`Failed to fetch settings: {loadedSettings}`)
	end
end)

Both of those problems could be caused if the events aren’t being fired in the first place, I’ll check the client script to see what could cause it

Also, where is the client script located? LocalScripts are a bit fussy with where they work (LocalScripts work in StarterPlayerScripts so this isn’t the issue)


@jasper53682 Actually, an example as to how you’re firing the events in the client script would be ideal since the current example doesn’t really explain how they’re actually being fired


@jasper53682 I’m also noticing that there doesn’t seem to be a way for the data retrieved by the server to be sent to the client, so currently even if the code worked lighting would change for the whole server whenever the LoadSettingsEvent is fired


@jasper53682 I’ve made this place file for you that has a system to save settings for Lighting: LightSettingsSaveExample.rbxl (55.0 KB)

It includes:

  • A server Script in ServerScriptService
  • A LocalScript in StarterPlayerScripts
  • A RemoteEvent and RemoteFunction in ReplicatedStorage

The RemoteFunction is used so that the server has a way to tell the client if the data fails to save

Why are you using jsonencode? You can set a datastore to a table.

The test place you sent me is giving me this error after I leave the game after testing it:

@task_cancel How would I go about doing this? I am newer to scripting, and don’t know how to set this up (I am not asking for a full script, just an example).

I don’t know the exact documentation, but just do it like how you would save any other datastore, instead of saving a jsonencode value, save a table.