IncrementAsync Under Non-Numerical Key

IncrementAsync() increases a numerical key in a datastore by a delta value. How can I assign my player as a key whilst using this function?

The syntax of IncrementAsync()'s parameters are key and delta. On the other hand, throughout my entire datastore, the only key I’d prefer is playerKey. Can I apply this function to a value in a playerData table under the scope of playerKey? This is the most convenient solution I can think of, yet its syntax seems quite limiting.

જ⁀➴

local playerData = {}
local playerKey = ("Player_"..plr.UserId)
success, err = pcall(function()
				
	playerDataStore:IncrementAsync(playerData[playerKey].playTimeValue, time())
	playerDataStore:SetAsync(playerKey, playerData[playerKey])
				
end)
Full Script
local players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local playerDataStore = DataStoreService:GetDataStore("PlayerDataStore")

local playerData = {}
game.Players.PlayerAdded:Connect(function(plr)
	
	local playerKey = ("Player_"..plr.UserId)
	local success, sessionData;
	local count = 0

	repeat
		
		success, sessionData = pcall(function()
			return playerDataStore:GetAsync(playerKey)
		end)
		
		if not success then
			count += 1
			warn("Fetching data, attempt #"..count, "\nError:", sessionData)
			task.wait(5)
		end
		
	until success or count >= 12
	
	if success then
		
		print("success", sessionData)
		
		if not sessionData then
			sessionData = {
				playTimeValue = 0;
			}
		end
		
		playerData[playerKey] = sessionData
		print(playerData[playerKey])
		
	else
		
		warn("Unable to fetch data for:", playerKey)
		plr:Kick("Unable to fetch your data, rejoin or try again later. >:(")
		
	end
	
	addLeaderstats(plr, playerKey)
	
end)

game.Players.PlayerRemoving:Connect(function(plr)
	
	local playerKey = ("Player_"..plr.UserId)
	
	if playerData[playerKey] then
		local success, err;
		local count = 0
		
		repeat
			
			success, err = pcall(function()
				
				playerDataStore:IncrementAsync(playerKey, time())
				playerDataStore:SetAsync(playerKey, playerData[playerKey])
				
			end)

			if not success then
				count += 1
				warn("Saving data, attempt #".. count, "\nError:", err)
				task.wait(5)
			end

		until success or count >= 12
		
		if success then
			print("Data saved for", playerKey)
		else
			warn("Data unsaved for", playerKey)
		end
		
	end
	
end)

જ⁀➴
As a whole, I want to add the value of time() to the player’s last saved playTimeValue without:

  • Using SetAsync() or UpdateAsync()

  • Making a new table, key, or datastore

౨ৎ
With thanks,
vamp

Only numerical values work for IncrementAsync, so you can’t use any tables or arrays in the datastore if you wish to use IncrementAsync.


Is there any particular reason for this? IncrementAsync is basically identical to the following code:

function IncrementAsync(key, delta)
    DS:UpdateAsync(key, function(old)
        return old + delta
    end)
end
1 Like

I’d figured that IncrementAsync() would be the most straightforward, as it was dealing with numerical values. Anyhow, I ran into a teeny problem trying your suggestion; the scope for my table is causing an error at its bracket.

The error reads:

ServerScriptService.dataScript:82: Expected ')' (to close '(' at column 52), got '[' 

old is the variable that is the current value of the datastore, so don’t try to replace it like that.

If you are already using GetAsync, and are keeping track of the actual time elesewhere, just stick with SetAsync.

If you don’t store the previous amount of time, then use UpdateAsync

1 Like

Originally, I wished to avoid using Set/UpdateAsync() because I would have to assign the value of playTimeData as so:

success, err = pcall(function()

	playerData[playerKey].playTimeValue = rawTime 
    --rawTime = playerData[playerKey].playTimeValue + time()

	playerDataStore:SetAsync(playerKey, playerData[playerKey])
	print(playerData[playerKey])
				
end)

rawTime is the return of a function placed in a RunService.Heartbeat:Connect() function. In the case of an error and multiple retry attempts to save, I was afraid that once playTimeValue is set to rawTime, the repetition of the RunService function would cause the value to accumulate inaccurately if it were to continue whilst the player’s data was saving.

rawTime Function
local function calcPlayTime(playerKey)

	local rawTime = playerData[playerKey].playTimeValue + time()
	local roundTime = rawTime-- / (60*60)

	return rawTime, roundTime

end
RunService Function
game:GetService("RunService").Heartbeat:Connect(function()
	
	for _, plr in pairs(players:GetPlayers()) do
		local playerKey = ("Player_"..plr.UserId)
		
		if playerData[playerKey] then
			
			local rawTime, roundTime = calcPlayTime(playerKey)
			print(rawTime, roundTime)

			local leaderstats = plr:FindFirstChild("leaderstats")

			if leaderstats and leaderstats:FindFirstChild("Playtime") then
				leaderstats["Playtime"].Value = roundTime
				-- set their time played to what was saved + how long it's been since they've joined (in min)
			end	
		end

	end
	
end)

If this is the only method using time(), I will resort to using timestamps with os.time(). I wanted to see how far I could get with time(), however, as both methods have the same value, just different costs in coding. Any ideas?

I’ve never seen any reference to using RobloxAPI. Could you explain and link some tutorials?

I might actually switch over to using timestamps. Thank you for all your help, @Miserable_Haven and @SeargentAUS.

Appreciated,
vamp

1 Like

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