Datstore Module w/ Ordered Datastore Backups

So, I’ve just recently gotten back into scripting and am working on a sandbox-based tycoon for learning purposes, as it seems such will require me to know a lot. :slight_smile: I’ve practically gotten my datastore system up and ready, though I’m still adjusting a lot and implementing features I’ve forgotten/think I may need in the future. I’ve based it on the same saving methods that datastore 2 uses (As I’m sure you can tell.), and so far my implementation of it seems to be working well, but I haven’t tested it with large amounts of data yet.

I’m looking for any input on improvements I can make, or any issues that you think it could present in the future. Some specific parts I am slightly concerned about, is the updateData and retrieveData methods, I feel like there has to be a better way for those to work, though I am not sure.

local datastoreservice = game:GetService("DataStoreService")

local datasettings = require(game:GetService("ServerScriptService").settings.dataStoreSettings)

local loadedData = {}

local dataPreset = {inventory = {}, currencies = {coins = 100, gems = 25}, base = {}}

local dataModule = {}

function dataModule.getSaveList(plr)
	local saves = datastoreservice:GetOrderedDataStore(datasettings.version..plr.UserId)
	
	local pages = saves:GetSortedAsync(false, 5)
	local currentpage = pages:GetCurrentPage()
	
	local keys = {}
	for _, v in ipairs(currentpage) do
		table.insert(keys, {v.key, v.value})
	end
	
	return keys
end

function dataModule.getSelectedData(plr, key)
	local loaded = false
	for _, v in ipairs(loadedData) do
		if v.id == plr.UserId then
			loaded = true
			break
		end
	end
	
	if loaded == true then
		return true
	end
	
	local datastore = datastoreservice:GetDataStore(datasettings.version..plr.UserId)
	local selecteddata = datastore:GetAsync(key)
	
	if selecteddata then
		
		table.insert(loadedData, {id = plr.UserId, userdata = selecteddata})
		print("Successfully loaded data for..."..plr.Name)
		return true
	else
		return false
	end
end

function dataModule.saveLatestData(plr, unload)
	local savetime = os.time()
	local userdata
	for _, v in ipairs(loadedData) do
		if v.id == plr.UserId then
			userdata = v.userdata
			break
		end
	end
	
	if not userdata then
		print("No loaded data for..."..plr.Name)
		return "nodata"
	end
	
	local datastore = datastoreservice:GetDataStore(datasettings.version..plr.UserId)
	local saves = datastoreservice:GetOrderedDataStore(datasettings.version..plr.UserId)
	
	local success, err = pcall(function()
		datastore:SetAsync("save"..savetime, userdata)
		saves:SetAsync("save"..savetime, savetime)
	end)
	
	if not success then
		print("Failed to save data for..."..plr.Name.."...retrying.")
		wait(5)
		dataModule.saveLatestData(plr, true)
	else
		print("Successfully saved data for..."..plr.Name)
		dataModule.unloadData(plr)
	end
end

function dataModule.getPreset(plr)
	dataModule.unloadData(plr)
	table.insert(loadedData, {id = plr.UserId, userdata = dataPreset})
	print("Preset data loaded for..."..plr.Name)
end

function dataModule.unloadData(plr)
	for n, v in ipairs(loadedData) do
		if v.id == plr.UserId then
			table.remove(loadedData, n)
			print("Data unloaded for..."..plr.Name)
			break
		end
	end
end

function dataModule.retrieveData(plr, key, key2)
	for _,  v in ipairs(loadedData) do
		if v.id == plr.UserId then
			--Checking if it is retrieving a specific segment of data or just all of it.
			if key == "all" then
				return v
			end
			
			if not key2 then
				return v.userdata[key]
			else
				return v.userdata[key][key2]
			end
		end
	end
end

function dataModule.updateData(plr, key, key2, change)
	for _, v in ipairs(loadedData) do
		if v.id == plr.UserId then
			--Checking to see if we are updating data one layer deep or two.
			if not key2 then
				--Checking the type of data inputted as it does different things based on the results.
				if type(change) == "table" or "string" or "boolean" then
					v.userdata[key] = change
				elseif type(change) == "number" then
					v.userdata[key] = v.userdata[key] + change
				end
				return v.userdata[key]				
			else
				if type(change) == "table" or "string" or "boolean" then
					v.userdata[key][key2] = change
				elseif type(change) == "number" then
					v.userdata[key][key2] = v.userdata[key][key2] + change
				end
				return v.userdata[key][key2]
			end
		end
	end
end

return dataModule

Sorry for the late response just leaving it over here, OrderedDataStores on the BEREZAA method, only save the versions, and then save the actual data on an actual datastore, just having the OrderedDataStores values as ID’s.