How Would I Create A Hourly Chest?

I’m unsure how I would create a chest that can be claimed every 6 hours? I know how to reward the player every six hours, I’m just don’t know how to display it locally?

I’ve tried making it display in a GUI, I’ve also tried making it appear above the chest but it doesn’t work for me?

The Claim GUI

local player = game.Players.LocalPlayer

script.Parent.MouseEnter:Connect(function()
	
	script.Parent.Parent.ImageColor3 = Color3.fromRGB(16, 186, 53)
	
	
end)

script.Parent.MouseLeave:Connect(function()
	
	script.Parent.Parent.ImageColor3 = Color3.fromRGB(23, 255, 77)
	
end)

local Rewards = require(game.ReplicatedStorage.Modules.GroupRewards)

local target = os.time() + 86400

local function toHMS(s)
	return ("%02i:%02i:%02i"):format(s/3600, s/60%60, s%60)
end

script.Parent.MouseButton1Click:Connect(function()
	
	local timeleft = tonumber(target)
     
	if (timeleft > 0 and timeleft - os.time() > 0) then
	
		script.Parent.Click:Play()
	
		game.ReplicatedStorage.Claim.ClaimGReward:FireServer()
		
	else
		
		script.Parent.Parent.X.Text = toHMS(target - os.time())
		
	end
	
end)

Server Script

local DS = game:GetService("DataStoreService")
local RS = game:GetService("ReplicatedStorage")
Rewards = require(game.ReplicatedStorage.Modules.GroupRewards)

function DailyReward(v)
	
	local Player = game.Players:GetPlayerByUserId(v)
	
    local MainCurrency = Player:WaitForChild("MainCurrency")
	
	local Gems = MainCurrency:FindFirstChild("Gems")
	
	if MainCurrency then
		
		Gems.Value = Gems.Value + 15 
	
	end
end



game.ReplicatedStorage.Chests.GChest.OnServerEvent:Connect(function(plr, mode, table)
		
     if (mode == "Group_R") then
		print("Mode Correct")
		if plr:IsInGroup(6154443) then 
	         local Data = DS:GetDataStore("DailyRewards_V.1", plr.UserId)
	         local timeleft = Data:GetAsync("TimeLeft")
	         local hours = os.time() + 86400 --Time in seconds, default is 24 hours
	         if timeleft == nil then
	             Data:SetAsync("TimeLeft", hours)
	             Data:IncrementAsync("Amount", 1) --Amount of times the player got the reward
	             DailyReward(plr.UserId)
	         else
	             local timeleft = tonumber(timeleft)
	             if (timeleft > 0 and timeleft - os.time() > 0) then
	                 DailyReward(plr.UserId)
             	end
	         end
     	end
	end
end)

Any better ways I could do this/ or ways I could make this work properly?

1 Like

The tick() function or os.time() may be your friend here as they return a number (in seconds) that has passed since (some UCT time I think).

It’s not precisely sycned across servers, some servers can (in bad cases) lag a minute or two behind but shouldn’t be an issue.

If you want to check if a hour has passed you could do this.

local lasttimeopened = os.time() --tick() is also perfectly acceptable but returns a number with decimals.

wait(60 * 60) --Les wait a hour.

if os.time() - lasttimeopened > (60 * 60) then
   print("Myes, 1 hour has passed, epic.")
end

You can save this value in a data store, which is epic.

Though, since os.time() and tick() both return like a large number (something like 20183027429), it will barely take up any space, but if you want to optimize it a little/make it smaller, subtract a large amount from it when saving it to a datastore, if you want to load it from data store, add the same amount you subtracted again so it becomes the original number again.

3 Likes

How would I display this in a text label for the local player to see how much time is left?

I haven’t tried this myself exactly but what I’d do is.

local function displaytime(time)
 local seconds = time % 60 --Using % divides and returns a remainder.
 local minutes = (time - seconds) / 60 --Remove remainder (seconds) from total time, get a rounded up number (minutes).

 return minutes, seconds
end

Could be wrong, but pretty sure this is how you do the math (anyone correct me if I made a mistake).

Basically you divide the seconds by 60, which should give you minutes, but before you divide that by 60, I first remove the remaining seconds, what can not be divided by 60 is a remainder which I remove from the total time, now I can divide it by 60 and get the total minutes left without the number being followed by decimals which is great.

Edit: This is just for minutes and seconds, if you want hours, days, weeks, etc displayed you have to divide more numbers and make more remainders to pull from the total time, etc, though, not entirely sure on how to extend that function a little more, but this should do the trick for you I hope, I think you only need minutes since it’s just 1 hour, right?

It’s going to be a 6 hour thing, but I found something that does the trick

local function toHMS(s)
	return ("%02i:%02i:%02i"):format(s/3600, s/60%60, s%60)
end

but it doesn’t seem to show up on the surface gui?

1 Like

Ah nevermind I got it working, but I’m unsure about how I would create the system?

Assuming that this needs to work across play sessions, use DataStores. Assume that the “lastClaimTime” or whatever for a player is 0 if they have no data saved, otherwise use the saved value as their last claim time value. Check the current os.time() and check if the elapsed time is over an hour either as a sum or a difference. I prefer a sum.

-- Sum
local currentTime = os.time()
if currentTime < lastClaimTime + 3600 then

-- Difference
local currentTime = os.time()
if currentTime - lastClaimTime >= 3600 then

If that condition succeeds, give them rewards and update their DataStore value with the seconds given in currentTime. That’s all the debounce you really need in terms of claiming.

As for counting down, use client-side prediction. Whatever the current amount of time they need to wait for is (calculate using a difference between the current time and last claim, then by an hour and the calculated difference), have the server send that to the client which it will then count the timer down itself with a variable internally and use a time formatter to represent it in a clean way on a Gui.