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())
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.
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
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)
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
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
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