Settings store script not remembering changes made when rejoining

Hello,

I have made a script which should be saving settings and getting the correct value, but it does not seem to be working properly.

When I call Load(), it seems to always be pulling an old table, because when I call Save() and save a setting and rejoin after commenting it out, the changes are lost.

I’m sure the solution is simple and I’m just missing something, but here is the code.

local DefaultSettings = require(game.ReplicatedStorage:WaitForChild("PreloadService"):WaitForChild("Config"))["Settings"]
local Settings = {}
local SettingsRemoteFolder = Instance.new("Folder", game.ReplicatedStorage.PSRemotes)
SettingsRemoteFolder.Name = "SettingsRemotes"
local DSS = game:GetService("DataStoreService")
local DS = DSS:GetDataStore("SettingsStore")
local Active = true

local function Save(Property, Value)
	
	if not Active then
		warn(`Failed to change {Property}, because editing is not active at the moment. Try again later.`)
		return
	end
	
	task.wait(2)
	
	Settings[Property] = Value
	
	local ToWrite = game:GetService("HttpService"):JSONEncode(Settings)
	DS:SetAsync("MainStore", ToWrite)
end

local function merge(...) -- Merge tables incase of new update to module
	local result = {}
	for _, t in ipairs{...} do
		for k, v in pairs(t) do
			result[k] = v
		end
	end
	return result
end

local function Load()
	local Data = DS:GetAsync("MainStore")
	if Data then
		local Success, Mod = pcall(function()
			return game:GetService("HttpService"):JSONDecode(Data)
		end)

		if not Success then
			warn("Failed to fetch settings state - is DataStoreService operational?")
		else
			Settings = merge(Mod, DefaultSettings)
		end
	else
		local Success, Error = pcall(function()
			DS:SetAsync("MainStore", game:GetService("HttpService"):JSONEncode(DefaultSettings))
		end)

		if not Success then
			warn("Failed to run first-time setup on Settings - is DataStoreService enabled?")
		else
			print("Data was not found, went to backup")
			Settings = DefaultSettings
		end
	end
end


Load()

--Save("RequireShift", false)

local function GetSettings()
	return Settings
end

print(GetSettings())
2 Likes

It seems like the issue is that the Save() function is not fully waiting for the DataStore to save the changes before the function ends. You can fix this by using the :SetAsync() method’s success callback to ensure it has been saved before continuing. This is basically it:

local function Save(Property, Value)
	
	if not Active then
		warn(`Failed to change {Property}, because editing is not active at the moment. Try again later.`)
		return
	end
	
	task.wait(2)
	
	Settings[Property] = Value
	
	local ToWrite = game:GetService("HttpService"):JSONEncode(Settings)
	
	DS:SetAsync("MainStore", ToWrite, function(success)
		if not success then
			warn("Failed to save changes to DataStore")
		end
	end)
end

This should ensure that the changes are saved before the function ends and returns.

1 Like

There isn’t a callback method on the SetAsync method, but I tried this and the same issue is there.

	
	local Success, Error = pcall(function()
		DS:SetAsync("MainStore", ToWrite)
	end)
	
	if not Success then
		return {false, Error}
	else
		return {true, "Success!"}
	end

I moved “Load()” function call to the end :slight_smile:

local DefaultSettings = require(game.ReplicatedStorage:WaitForChild("PreloadService"):WaitForChild("Config"))["Settings"]
local Settings = {}
local SettingsRemoteFolder = Instance.new("Folder", game.ReplicatedStorage.PSRemotes)
SettingsRemoteFolder.Name = "SettingsRemotes"
local DSS = game:GetService("DataStoreService")
local DS = DSS:GetDataStore("SettingsStore")
local Active = true

local function Save(Property, Value)
	
	if not Active then
		warn(`Failed to change {Property}, because editing is not active at the moment. Try again later.`)
		return
	end
	
	task.wait(2)
	
	Settings[Property] = Value
	
	local ToWrite = game:GetService("HttpService"):JSONEncode(Settings)
	DS:SetAsync("MainStore", ToWrite)
end

local function merge(...) -- Merge tables incase of new update to module
	local result = {}
	for _, t in ipairs{...} do
		for k, v in pairs(t) do
			result[k] = v
		end
	end
	return result
end

local function Load()
	local Data = DS:GetAsync("MainStore")
	if Data then
		local Success, Mod = pcall(function()
			return game:GetService("HttpService"):JSONDecode(Data)
		end)

		if not Success then
			warn("Failed to fetch settings state - is DataStoreService operational?")
		else
			Settings = merge(Mod, DefaultSettings)
		end
	else
		local Success, Error = pcall(function()
			DS:SetAsync("MainStore", game:GetService("HttpService"):JSONEncode(DefaultSettings))
		end)

		if not Success then
			warn("Failed to run first-time setup on Settings - is DataStoreService enabled?")
		else
			print("Data was not found, went to backup")
			Settings = DefaultSettings
		end
	end
end

-- Save a setting
Save("RequireShift", false)

-- Print the settings
print(Settings)

-- Load the settings after changes
Load()
print(Settings)

Seems like in this case it will just overwrite:

   ▼  {
    ["RequireShift"] = false
  }  -  Server - SettingsStore:64
   ▼  {
    ["AutoCloseUI"] = true,
    ["BanForExploits"] = false,
    ["DisplayHours"] = false,
    ["InBetweenAssetsDelay"] = 0,
    ["LightDefaultUI"] = false,
    ["MaxHistoryItems"] = 250,
    ["NotificationCloseTimer"] = 15,
    ["PanelKeybind"] = Z,
    ["PanelLoadingTime"] = 0.2,
    ["PrefixString"] = "Shift + Z",
    ["PrintData"] = true,
    ["RequireShift"] = true,
    ["SendErrorLogs"] = true,
    ["SendOptionalAnalytics"] = true,
    ["ShortNumberDecimals"] = 2,
    ["ShutdownIfOutofDate"] = false,
    ["StartDelay"] = 0,
    ["UseAcrylic"] = true,
    ["UseTweens"] = true
  }  -  Server - SettingsStore:68

With this change, the Save function will update the specified Property in the Settings table instead of overwriting the entire table.

local function Save(Property, Value)
	if not Active then
		warn("Failed to change "..Property..", because editing is not active at the moment. Try again later.")
		return
	end
	
	Settings[Property] = Value
	
	local ToWrite = game:GetService("HttpService"):JSONEncode(Settings)
	DS:SetAsync("MainStore", ToWrite)
end

Same thing is happening, still calling Save() before Load()

This way, you avoid overwriting the entire table and only update the specified property. Make sure to replace the existing Save function with this updated version in your code.

local function Save(Property, Value)
	if not Active then
		warn("Failed to change "..Property..", because editing is not active at the moment. Try again later.")
		return
	end
	
	-- Call Load function to ensure the Settings table is up to date
	Load()
	
	Settings[Property] = Value
	
	local ToWrite = game:GetService("HttpService"):JSONEncode(Settings)
	DS:SetAsync("MainStore", ToWrite)
end

Are you using chatgpt? also, when calling Load() again, it didn’t work again

1 Like

I’m thinking the same thing. There is no way he’s responding to lines of code that fast.

1 Like

The same with the random comments, and the way the general post is written lol

If you look in scripting support, you’ll see that he’s responding to codes with over 20 lines in 2 minutes.

No, I just copy and paste from my past projects :slight_smile:

I think I know what’s wrong now.

Can you modify the merge function to only add keys that don’t already exist in the result table? Make
It like this:

local function merge (...)

local result = {}

for _, t in ipairst...} do for k, v in pairs (t) do if result[k] == nil then result[k]=v end end end return result

end
1 Like

That just makes the table blank

   ▼  {
    ["RequireShift"] = false
  }  -  Server - SettingsStore:58
  {}  -  Server - SettingsStore:62