I wanted to make a daily reward system in an obby. But the problem is the timer. I don’t know how how to make the timer go on when the player is offline. How do I make it go when the player is offline?
This is a server script:
local DS = game:GetService("DataStoreService"):GetDataStore("Shut")
local function OnCharacterAdded(char)
game:GetService("RunService").Stepped:Wait()
local plr = game.Players:GetPlayerFromCharacter(char)
char:WaitForChild("HumanoidRootPart").CFrame = workspace.Checkpoints[tostring(plr.TeleportedStage.Value)].CFrame + Vector3.new(0,3.25,0)
end
function OnPlayerAdded(plr)
plr.CharacterAdded:Connect(OnCharacterAdded)
local stats = Instance.new("Folder")
stats.Name = "leaderstats"
stats.Parent = plr
local values = Instance.new("Folder")
values.Name = "Values"
values.Parent = plr
local stage = Instance.new("IntValue")
stage.Name = "Stage"
stage.Parent = stats
local TeleStage = Instance.new("IntValue")
TeleStage.Name = "TeleportedStage"
TeleStage.Parent = plr
local Skips = Instance.new("IntValue")
Skips.Name = "Skips"
Skips.Parent = values
local Time = Instance.new("IntValue")
Time.Name = "Time"
Time.Parent = values
Time.Value = 900
local daily = Instance.new("IntValue")
daily.Name = "Daily"
daily.Parent = values
daily.Value = 86400
local Coins = Instance.new("NumberValue")
Coins.Name = "Coins"
Coins.Parent = stats
local key = "id_" .. plr.userId
local data = DS:GetAsync(key)
if data then
stage.Value = data
TeleStage.Value = stage.Value
else
DS:GetAsync(key, stage)
end
while wait(1) do
if plr.leaderstats.Stage.Value >= 10 then
plr:WaitForChild("leaderstats"):WaitForChild("Coins").Value += plr.leaderstats.Stage.Value / 100
end
daily.Value -= 1
end
end
game.Players.PlayerAdded:Connect(OnPlayerAdded)
function OnPlayerRemoved(plr)
local key = "id_" .. plr.userId
local data = plr.leaderstats.Stage.Value
DS:SetAsync(key, data)
end
game.Players.PlayerRemoving:Connect(OnPlayerRemoved)
local RS = game:GetService("ReplicatedStorage")
repeat wait() until script.Main ~= nil
local main = require(script.Main)
function recived(plr, direction)
if direction == "up" then
main.up(plr, direction)
elseif direction == "down" then
main.down(plr, direction)
elseif direction == "doubleup" then
main.doubleup(plr, direction)
elseif direction == "doubledown" then
main.doubledown(plr, direction)
elseif plr.Stages > main.TOTAL_STAGES_IN_GAME then
print("Player is in an older version of the game!")
end
end
RS.StageTransfer.OnServerEvent:Connect(recived)
for _, v in pairs(workspace.Checkpoints:GetChildren()) do
v.Touched:Connect(function(hit)
if v ~= nil then
if v.Parent == workspace.Checkpoints then
local player = game:GetService("Players"):GetPlayerFromCharacter(hit.Parent)
if player then
if player.leaderstats.Stage.Value == tonumber(v.Name) - 1 then
if player.leaderstats.Stage.Value < tonumber(v.Name) then
player.leaderstats.Stage.Value = tonumber(v.Name)
end
end
if player.leaderstats.Stage.Value >= tonumber(v.Name) then
player.TeleportedStage.Value = tonumber(v.Name) --player.leaderstats.Stage.Value
end
end
end
end
end)
end
I created a GUI for the player to claim. The script is:
-- 12/20 chance for 1k coins, 5/20 chance for 2.5k coins, and free skip(3/10 chance)
game.Players.PlayerAdded:Connect(function(plr)
while wait(1) do
script.Parent.Visible = true
if plr:WaitForChild("Values"):WaitForChild("Daily").Value == 0 then
plr:WaitForChild("Values"):WaitForChild("Daily").Value = 86400
local chance = math.random(1, 20)
if chance == 1 or chance == 2 or chance == 3 or chance == 4 or chance == 5 or chance == 6 or chance == 7 or chance == 8 or chance == 9 or chance == 10 or chance == 11 or chance == 12 then
script.Parent.Description.Text = "You have earned 1,000 coins for logging in today! Come back tomorrow for a chance to get a free skip!"
game.ReplicatedStorage.DailyChances["1000Coins"]:FireServer()
elseif chance == 13 or chance == 14 or chance == 15 or chance == 16 or chance == 17 then
script.Parent.Description.Text = "You have earned 2,500 coins for logging in today! Come back tomorrow for a chance to get a free skip!"
game.ReplicatedStorage.DailyChances["2500Coins"]:FireServer()
else
script.Parent.Description.Text = "You have earned a free skip for logging in today! Come back tomorrow for a chance to get another one!"
game.ReplicatedStorage.FreeSkip:FireServer()
end
else
script.Parent.Visible = false
end
end
end)
Help is appreciated! Also this is how I might make an idle game, but I think this is the first step.
I would try to make a datastore for the timer, save it, and keep it counting down, even if the player is not online, but im not sure how to do that, that’s just an idea, I think there is another way.
When the player joins just create a number value and set its value to os.time. Then when they’re leaving save the value to the data store. When they click the button check if os.time() - player.leaderstats.Time.Value >= 86400. You can set their time value on the server back to os.time() once they collect the reward
I said create a value when they join, I’m not setting a new os.time when they’re leaving. As for collecting the reward, I omitted that as I was rather in a hurry
@MysteryX2076 solved it but i think you should wrap your get and set asyncs in a pcall. They could error at any given moment so a pcall gives you the ability to handle an error with care
was it because that i used the DataStoreService the wrong way? i have a script that saves everything in the values folder inside of the script creating the leaderstats and all of that(same as leaderstats)
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local Saver = DataStoreService:GetDataStore("SavePlrValues")
Players.PlayerAdded:Connect(function(player)
local Data = nil
local success, errormessage = pcall(function()
Data = Saver:GetAsync(tostring(player.UserId))
print("Successfully loaded "..tostring(player.Name)..tostring("'s data."))
end)
if success then
if Data then
for i, v in pairs(Data) do
player:WaitForChild("Values"):WaitForChild(i).Value = v
end
end
else
error(errormessage)
end
end)
local function Save(player)
local SavedData = {}
for _, v in pairs(player.Values:GetChildren()) do
SavedData[v.Name] = v.Value
end
local success, errormessage = pcall(function()
Saver:SetAsync(tostring(player.UserId), SavedData)
print("Successfully got "..tostring(player.Name)..tostring("'s data."))
end)
if not success then
error(errormessage)
end
end
Players.PlayerRemoving:Connect(Save)
game:BindToClose(function()
for _, v in pairs(Players:GetPlayers()) do
Save(v)
end
end)
Well you seem to be saving the right way (Unless the daily reward value isn’t in there). Please do look at my post above on how to implement the daily thing. Here’s how you would prob use it in the local script
--[[Client code]]--
local dailyrewardsbutton = script.Parent -- Script in button
local player = game.Players.LocalPlayer
local dailyevent = game.ReplicatedStorage.DailyEvent
dailyrewardsbutton.Activated:Connect(function()
local success = dailyevent:InvokeServer()
if success then dailyrewardsbutton.Text = 'Success!' end
end)
--[[Server code]]--
local dailyevent = game.ReplicatedStorage.DailyEvent
dailyevent.OnServerInvoke = function(plr)
if os.time() - plr.Values.Daily.Value >= 86400 then
local chance = math.random(1, 20)
if chance == 1 or chance == 2 or chance == 3 or chance == 4 or chance == 5 or chance == 6 or chance == 7 or chance == 8 or chance == 9 or chance == 10 or chance == 11 or chance == 12 then
script.Parent.Description.Text = "You have earned 1,000 coins for logging in today! Come back tomorrow for a chance to get a free skip!"
game.ReplicatedStorage.DailyChances["1000Coins"]:FireServer()
elseif chance == 13 or chance == 14 or chance == 15 or chance == 16 or chance == 17 then
script.Parent.Description.Text = "You have earned 2,500 coins for logging in today! Come back tomorrow for a chance to get a free skip!"
game.ReplicatedStorage.DailyChances["2500Coins"]:FireServer()
else
script.Parent.Description.Text = "You have earned a free skip for logging in today! Come back tomorrow for a chance to get another one!"
game.ReplicatedStorage.FreeSkip:FireServer()
end
return true
else
return false
end
end
Just remove the events in the server code, you can directly set the money and stuff
I only have the ones to award the player with the daily gift
Btw I might need to answer later because its getting late for me. Help = appreciated even when I’m away
I just noticed but what you’re doing by giving the client the power to decide how much coins they can have is extremely dangerous. This will allow exploiters to rapid-fire the daily chances event until they basically have inf money.
Make the remote function in replicated storage and follow my code
For the third time, make sure you create a daily number value when the player joins and assign the daily value the saved value when they left previously