Trying to prevent overwritten data: How can I use UpdateAsync properly?

I’m trying to fix my data and emotes system(which needs to be saved).

The problem is my previous data is overwriting current data. The emote progress data value(max: 2) would have a max of 10 because of it reverted back to a previous data session.

I did my research and found out SetAsync is not good practice when in using large scale tables(sessionData) for saving data. Now I’m using UpdateAsync which is specificially used for preventing this issue.

I used this and this source for my information.

The problem now is that I don’t know how to use UpdateAsync properly. Both tutorials have shown something similar to an ID and version which both were added(+=1) if the sessionData was saved to the datastore. I don’t know how to save the versions themselves across the datastore if overwriting is the issue. The posts I’ve seen didn’t show how to create a versionTable or add an IntValue acting as the Version to the player.

Any ideas?

PlayerDataScript
local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")

local Assets = ReplicatedStorage.Assets
local Bindables = ReplicatedStorage.Bindables
local Remotes = ReplicatedStorage.Remotes

local DataStore = DataStoreService:GetDataStore("Players")

local sessionData = {}
local versionTable = {}

local Leaderboards = require(script.Leaderboards)
local Leveling = require(script.Leveling)
local Battlepass = require(script.Battlepass)
local EmotesList = require(script.EmotesList)

local function data(player)
	--for i,v in pairs(sessionData[player]) do print(i,v) end
end

Bindables.OnServer.Event:Connect(function(signal,player)
	if signal == "InitServer" then
		ReplicatedStorage.Remotes.ToClient:FireClient(player,"CreateBattlepass",sessionData[player]["Level"],sessionData[player]["Experience"],Battlepass)
	elseif signal == "ResetPlayer" then
		sessionData[player] = nil
	end
end)

local function leaderstats(player)
	local folder = Instance.new("Folder")
	folder.Name = "leaderstats"
	local wins = Instance.new("IntValue")
	wins.Name = "Wins"
	wins.Value = sessionData[player]["Wins"]
	local kills = Instance.new("IntValue")
	kills.Name = "Kills"
	kills.Value = sessionData[player]["Kills"]
	local money = Instance.new("IntValue")
	money.Name = "Money"
	local ver = Instance.new("IntValue")
	ver.Name = "Version"
	ver.Value = sessionData[player]["Version"]
	versionTable[tostring(player.UserId)] = ver.Value
	
	money.Changed:Connect(function(value)
		sessionData[player]["Money"] = value
	end)
	
	ver.Parent = player
	money.Parent = player
	wins.Parent = folder
	kills.Parent = folder
	folder.Parent = player
end

ReplicatedStorage.Data.Event:Connect(function(signal,player,key,update)
	if signal == "Set" then
		sessionData[player][key] = update
	elseif signal == "Update" then
		local value = update(sessionData[player][key])
		ReplicatedStorage.Data:Fire("Set",player,key,value)
	end
	if key == "Wins" or key == "Kills" then
		player.leaderstats:FindFirstChild(key).Value = sessionData[player][key]
	end
end)

ReplicatedStorage.Get.OnInvoke = function(player,key)
	return sessionData[player][key]
end

local function Abilities(tab_)
	tab_ = {}
	for _,ability in Assets.Shop:GetChildren() do
		if ability:IsA("ModuleScript") then continue end
		tab_[ability.Name] = {false,0}
	end
	return tab_
end


local function deepCopy(tab_)
	local copy = {}
	for k, v in pairs(tab_) do
		if type(v) == "table" then
			v = deepCopy(v)
		end
		copy[k] = v
	end
	return copy
end

local function Emotes(tab_)
	tab_ = {}
	for emote,value in pairs(EmotesList) do
		tab_[emote] = value
	end
	deepCopy(tab_)
	return tab_
end

Players.PlayerAdded:Connect(function(player)
	local key = tostring(player.UserId)
	
	sessionData[player] = {}
	
	sessionData[player]["Version"] = 0
	sessionData[player]["Money"] = 0
	sessionData[player]["Equipped"] = ""
	sessionData[player]["Abilities"] = Abilities(sessionData[player]["Abilities"])
	sessionData[player]["Kills"] = 0
	sessionData[player]["Wins"] = 0
	
	sessionData[player]["Level"] = 1
	sessionData[player]["Experience"] = 0
	
	sessionData[player]["Emotes"] = Emotes(sessionData[player]["Emotes"]) -- this is empty despite being filled in with a list of values
	sessionData[player]["EmoteProgress"] = 2 -- This changes to 10 to players just joining because it was a previous initialization, but I want 2 now
	
	sessionData[player]["Gamepasses"] = {
		["DoubleEmotes"] = false
	}
	
	local success,result = pcall(function()
		return DataStore:GetAsync(key)
	end)
	print(sessionData[player]["EmoteProgress"])
	if success and result then
		for i,v in pairs(result) do
			sessionData[player][i] = v
		end
	end
	print(sessionData[player]["EmoteProgress"])
	leaderstats(player)
	data(player)
	task.spawn(function()
		while true do
			if DataStore:GetAsync(key) then
				Leaderboards:Set(player,"Kills",sessionData[player]["Kills"])
				Leaderboards:Set(player,"Wins",sessionData[player]["Wins"])
			end
			task.wait(100)
		end
	end)
	
	Leveling:Init(player)
end)

Players.PlayerRemoving:Connect(function(player)
	local key = tostring(player.UserId)
	if sessionData[player] then
		data(player)
		DataStore:UpdateAsync(key,function(pastData)
			if pastData.Version ~= versionTable[key] then
				print("Data version is not the same.")
				return nil
			else
				versionTable[key] += 1
				return sessionData[player]
			end
		end)
	end
	Leveling:Set(player)
end)

task.spawn(function()
	while true do
		Leaderboards:Refresh("Kills")
		Leaderboards:Refresh("Wins")
		task.wait(100)
	end
end)

I’ve done more research and what I’m trying to do is sessionlock(as in Sessionlocking which is used to prevent data regression).

I found that for sessionlocking, using profileservice is the best option.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.