I’m trying to create a daily reward system that only rewards a player exactly once per day. This system would allow a player to collect their daily reward late a night and be able to do so once again early in the morning with a reset at midnight local time. I attempted to write this using a combination of DateTime and sending the clients local time to the server but I just couldn’t wrap my head around the logic.
Couldn’t you save the date when the reward was collected then when next attempt to collect daily reward check if its greater then the day/month/year last collected.
edit: using something like
os.date(“%c”)
Yes, you can send the client’s os.date() to the server, more specifically the day and year, and check if the player has already claimed the reward for the day with a datastore and a RemoteFunction (or RemoteEvent)
LocalScript:
-- Reward is a RemoteFunction in ReplicatedStorage
local canReward = game.ReplicatedStorage:WaitForChild("Reward"):InvokeServer(os.date("%j%Y")) -- Send the day and year to the server
if canReward then
print("I can collect the daily reward")
else
print("I already claimed today's reward")
end
Server script:
local datastore = game:GetService("DataStoreService"):GetDataStore("Reward")
game.ReplicatedStorage:WaitForChild("Reward").OnServerInvoke = function(player, date)
if datastore:GetAsync(player.UserId) ~= date then -- Has this player already claimed the reward today
datastore:UpdateAsync(player.UserId, function(old)
local new = old or 0
new = date
return new
end)
--reward stuff
return true
elseif datastore:GetAsync(player.UserId) == nil then -- If there is no date saved for reward collection
datastore:SetAsync(player.UserId, date)
--reward stuff
return true
else
return false
end
end
It shouldn’t be based on the client’s local time, it should be based on the server getting UTC time (w/ os.time()) when the client tells it to.
The client is not to be trusted.
Then, when the client is added, or when the server runs a core logic loop, get the last reward’s os.time() – current os.time().
@mymommakesbathbombs4’s example works with this idea, except that the client doesn’t send its time, the server just checks its own time (as it is always in UTC).
I’m mostly hung up on the logic that prevents exploiters from time jumping to collect rewards. I think the maximum time jump threshold should be one day in the future.
You can use the clients time as long as the server verifies that the time is not too far into the future or past and other measures to prevent time jumping for extra daily rewards.
I figured it out. Using the clients year and day was the best route to go. Thanks
You could, but I think the server time is easier, as you do not have to calculate difference from real time or send a message back to the client when they may be ‘cheating’.
The time needs to go to your server anyway, so doing the other method is more of an inconvenience.
You need the client’s time in order to reset their daily rewards at midnight. Midnight is at a different for every player depending on their time zone.
Okay, I didn’t know that was what you were looking for.
A lot of games simply wait 24 hours since the last claim.
I am on the same page now.