When I was testing the game, I noticed that sometimes the data will not be saved because the write limit has been exhausted. That’s why I wrote this script.
Provide an overview of:
-
What does the code do and what are you not satisfied with?
-
The script adds all incoming data to the table, this allows you to:
- Read data quickly
- Bypass write and read restrictions
- Reading new data before writing it to the DataStore
- Data will not be lost if the DataStore does not write the data
- If the DataStore does not write the data, the script will try to write the data until it writes
Other data will be written even if the script fails to write any - Write only new data, rather than storing old data one by one.
- Less dependency on constant access to the DataStore (this works if the Datastore writes data from time to time)
- Providing a faster, more reliable, customizable alternative to UpdateAsync
- Data that is not in the table will be automatically read from the DataStore
-
Error messages and about data not suitable for writing, saving data about errors, in particular time, error, DataStore, key. Ability to get a table with errors
-
You can add settings and player’s UserId to the data
-
-
What potential improvements have you considered?
- Write player data only when player exits
- Adding new features
- Using DataStore 2
-
How (specifically) do you want to improve the code?
- Make it more optimized
- Remove bugs in code
- Improve the while loop if possible
local module = {}
local dss = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local ErrorData = {} -- [time] = {["Name"] = "", ["DDS"] = "", ["Key"] = key
local DataForSave = {}
local Data = {}
-- ! Check the data that is returned, because it may be an error
function WriteErrors (Error, DDSName, Key, Time)
if Time == nil then Time = os.time() end
table.insert(ErrorData, Time, {["Name"] = Error, ["DDS"] = DDSName, ["Key"] = Key})
warn(Error)
end
-- Read
function module.ReadEvent (dssName, key, ReadAgain) -- DataStoreName, Key, Request from the DataStore (true/false)
-- Checking the correctness of the data
if typeof(dssName) ~= typeof("") and key == nil then WriteErrors("The name of the DataStore is not a string and the key is nil", nil, nil) return "The name of the DataStore is not a string and the key is nill" end
if typeof(dssName) ~= typeof("") then WriteErrors('DataStore name is not a string', nil, key) return "DataStore name is not a string" end
if key == nil then WriteErrors('Key is nil', dssName, nil) return "Key is nil" end
print("Reading: " .. dssName, key)
if ReadAgain == true then
local success, Value = pcall(function()
local GDS = dss:GetDataStore(dssName)
return GDS:GetAsync(key)
end)
if not success then WriteErrors("Failed to read data from DataStore, error: " .. Value, dssName, key) return "Failed to read data from DataStore, error: " .. Value end
return Value
else
if Data[dssName] == nil then Data[dssName] = { ["Keys"] = {}, ["Warns"] = 0, ["Errors"] = 0 } end
if Data[dssName]["Keys"][key] == nil then
local success, Value = pcall(function()
local GDS = dss:GetDataStore(dssName)
return GDS:GetAsync(key)
end)
if not success then WriteErrors("Unable to read data from DataStore to write to table and return data, error: " .. Value, dssName, key) return "Unable to read data from DataStore to write to table and return data, error: " .. Value end
Data[dssName]["Keys"][key] = { ["Data"] = Value, ['Time'] = 0 }
end
end
return Data[dssName]["Keys"][key]["Data"]
end
-- Write DataStoreName, Data, Key, {"UpAs" - Save with function (data), "Fun" - the same as UpdateAsync(), but takes data from a table or accesses the DataStore, "InAs" - IncrementAsync()}
function module.WriteEvent(dssName, data, key, tegs, userIds, options)
--Checking the correctness of the data
local NonCorrectData = ""
if tegs == nil then tegs = {} end
if typeof(dssName) ~= typeof("") then NonCorrectData = NonCorrectData .. 'DataStore name is not a string, ' end
if key == nil then NonCorrectData = NonCorrectData .. 'Key is nil, ' end
if typeof(userIds) ~= typeof(8) then NonCorrectData = NonCorrectData .. "The fifth variable userId must be a number, i.e. the player's Id, " end
if table.find(tegs, "UpAs") or table.find(tegs, "Fun") then if typeof(data) ~= typeof(function ()end) then NonCorrectData = NonCorrectData .. "Second variable data should be a function or remove the UpAs/Fun tag" end end
print("Writing: " .. dssName, data, key, typeof(tegs), userIds, typeof(options))
if NonCorrectData ~= "" then WriteErrors(NonCorrectData, dssName, key) return NonCorrectData end
if Data[dssName] == nil then Data[dssName] = { ["Keys"] = {}, ["Warns"] = 0, ["Errors"] = 0 } end
if Data[dssName]["Keys"][key] == nil then
local success, Value = pcall(function()
local GDS = dss:GetDataStore(dssName)
return GDS:GetAsync(key)
end)
if not success then WriteErrors("Failed to read value:" .. Value) return "Failed to read value:" .. Value end
Data[dssName]["Keys"][key] = { ["Data"] = Value, ['Time'] = 0 }
end
if table.find(tegs, "Fun") then
local success, value = pcall(function()
return data(Data[dssName]["Keys"][key]["Data"])
end)
if success then
data = value
else
Data[dssName]["Errors"] += 1
WriteErrors("The function threw an error: " .. value, dssName, key)
return"The function threw an error: " .. value
end
end
Data[dssName]["Keys"][key]["Data"] = data
Data[dssName]["Keys"][key]['Time'] = 0
DataForSave[dssName] = { ["Key"] = key, ["Data"] = data, ["tegs"] = tegs, ["userIds"] = userIds, ["options"] = options }
end
function module.ReturnErrors () return ErrorData end
-- Save
delay(0,function()
while wait(1) do
for i in pairs(DataForSave) do
wait(Data[i]["Keys"][DataForSave[i]["Key"]]["Time"])
local dssName = i
local v = DataForSave[dssName]
local tegs = v["tegs"]
local data = v["Data"]
local key = v["Key"]
local userIds = v["userIds"]
local options = v["options"]
local pcallSuccess = nil
local pcallError = 0
if table.find(tegs, "UpAs") then
local success, Error = pcall(function()
local GDS = dss:GetDataStore(dssName)
GDS:UpdateAsync(key, data)
end)
pcallSuccess = success
pcallError = Error
elseif table.find(tegs, "InAs") then
local success, Error = pcall(function()
local dssPlus = dss:GetDataStore(dssName)
dssPlus:IncrementAsync(key, data, userIds, options)
end)
pcallSuccess = success
pcallError = Error
else
local success, Error = pcall(function()
local GDS = dss:GetDataStore(dssName)
GDS:SetAsync(key, data, userIds, options)
end)
pcallSuccess = success
pcallError = Error
end
if pcallSuccess ~= true then ErrorData("An error occurred while recording: " .. pcallError, dssName, key) return end
if v == DataForSave[dssName] then DataForSave[dssName] = nil end
delay(0, function()
for i = 6, 0, -1 do
Data[dssName]["Keys"][key]["Time"] = i
wait(1)
end
end)
end
end
end)
return module
Changes
- Detailed error information
- Error reading capability
- Incoming data is now better checked for errors
Reading time (arithmetic mean per 100 requests):
- Reading from DataStore (first reading) - 0.05117469999997411 (During the test, each time the reading time increased from 0.6 to 5.1)
- Reading from a table (second reading) - 0.0001611970004159957
I will be glad if you help me improve the code
If you use the script - write in the comments, I will be interested
Would you use my script?
- Yes
- I don’t use data store
- Scripts have already been written not for the script
- I am already using another script
- If there are more features, then yes
- No
0 voters