Making a working daily reward timer/countdown

So in short I want to make a daily chest reward system that is a bit like Bubble gum simulator :
sf

for our game
(this is the game link).

and I’ve finished working on daily reward chests,respawn products, and more, now all I need is to create a timer/countdown that shows how long you have left till your next reward.

This is my script so far :

local DataStore = game:GetService("DataStoreService"):GetDataStore("DailyReward")
local TimePeriod = 24*60^2 -- ==>> 86400 (1 DAY)

game.Players.PlayerAdded:Connect(function(plr)
	local currenttime = os.time()
	local RecordedPreviousTime = DataStore:GetAsync(plr.userId)

	if RecordedPreviousTime then
		if type(RecordedPreviousTime) == "number" then
			timeelapsed = currenttime - RecordedPreviousTime
			if timeelapsed >= TimePeriod then
				if not workspace.Reward:FindFirstChild("Chest") then
					DataStore:SetAsync(plr.userId, os.time())
					RewardEvent(plr)
				end
			end
		end
	end

	game:BindToClose(function()
		DataStore:SetAsync(plr.userId, os.time())
	end)
end)

game.Players.PlayerRemoving:Connect(function(plr)
	DataStore:SetAsync(plr.userId, os.time())
end)

local Timer = workspace.Timer.Timer.Ui.Frame.Timer
while wait(1) do
	--[[
	
	I AM STUCK HERE :(
	
	]]--
end

Btw I DONT REALLY KNOW HOW TO USE OS.TIME() AND STORING IT,SO PLEASE DON’T BULLY ME. :cry:

Thank You.

2 Likes

I don’t get why are you storing the os.time() on PlayerRemoving and after the server’s closure. Doesn’t that obbligate the player to stay online for an entire day?

Also, in case where there isn’t a RecordedPreviousTime, shouldn’t the player be able to get the chest, since it’s their first login?

2 Likes

Ahhh, i dont really know how to use os.Time(), btw can you help me with this script?.

You can use this article to learn more about os.time().

I think what you want to do is to only store the RecordedPreviousTime when the player gets their reward.

As for the timer, you can use math.max(TimePeriod - (os.time() - RecordedPreviousTime), 0) to calculate the amount of seconds left until the next reward is available, and then you can format that to any pattern you’d like (such as HH:MM:SS).

1 Like

For the section you were struggling with, all you need to do is:

while wait(1) do
	Timer.Text = os.difftime(RecordedPreviousTime, os.time())
end

However, you may want to change the previous part of the script to make it a bit more reliable. DataStores have a notorious reputation for errors and a throttle on requests so I would recommend having a retry system. Obviously, it won’t help if it fails all of the retries.
Keep in mind that:

  • GetAsync has a limit of 60 + (Number of players * 10)
  • Write requests (SetAsync, IncrementAsync, UpdateAsync and RemoveAsync) have a collective limit of 60 + (Number of players * 10)
  • Write requests (for the same key in a datastore) must have a 6 second gap between them.
  • GetSortedAsync has a limit of 5 + (Number of players × 2)

I personally do this for general usage:

local RetryInterval = 0.05 -- This can be anything above 0.03
local MaximumRetries = 3 -- This can be anything

local function SetAsync(DataStore, Key)
	local Tries = 0	
	local Success
	repeat
		Tries = Tries + 1
		Success = pcall(function()
			DataStore:SetAsync(Key)
		end)
		if not Success then wait(RetryInterval) end
	until Tries == MaximumRetries or Success

	if not Success then
		warn("Error processing SetAsync.")
	end
end
3 Likes

i’ve edited my script like what you told :

local RetryInterval = 0.05
local MaximumRetries = 3

game.Players.PlayerAdded:Connect(function(plr)

	currenttime = os.time()
	RecordedPreviousTime = DataStore:GetAsync(plr.userId)

	local function SetAsync(DataStore, Key)
		local Tries = 0	
		local Success
		repeat
			Tries = Tries + 1
			Success = pcall(function()
				DataStore:SetAsync(Key)
			end)
			if not Success then 
				wait(RetryInterval) 
			end
			
		until Tries == MaximumRetries or Success

		if not Success then
			warn("Error processing SetAsync.")
		end
	end

	if RecordedPreviousTime then
		if type(RecordedPreviousTime) == "number" then
			local timeelapsed = currenttime - RecordedPreviousTime
			if timeelapsed >= TimePeriod then
				if not workspace.Reward:FindFirstChild("Chest") then
					SetAsync(plr.userId, timeelapsed)
					RewardEvent(plr)
				end
			end
		end
	end
end)

local Timer = workspace.Timer.Timer.Ui.Frame.Timer

while wait(1) do
	Timer.Text = "Next Chest In : " .. os.difftime(RecordedPreviousTime, currenttime)
end

but output send me this :
'[invalid argument #1 to 'difftime' (number expected, got nil)])'

Not sure what the problem is, I ran this and it worked fine:

local Timer = game.StarterGui.ScreenGui.Timer
local RecordedPreviousTime = 1606585374

Timer.Text = "Next chest in " .. os.difftime(os.time(), RecordedPreviousTime).." seconds."

RecordedPreviousTime is about 2020-11-28T17:43:00Z.

1 Like

Its seems like its working now,but now the problem is, its not countdown/stop. But No Problem,i think i can fixed it, Thank you so much for the help!.

1 Like