How to make a daily reward system with streaks

Overview:

This tutorial will show you how to make a basic daily reward system that includes streaks.
The rewards are fully customizable as you have to create a function for reach streak reward, and that function you can make it give a player anything you want it to.

Step 1: Main Server Script

  • Create a script Inside of ServerScriptService, then name it “DailyRewards”, or whatever you want.
  • Put this provided code into the script
--> Get The Services Needed.
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local DataStoreService = game:GetService("DataStoreService")

--> Setup The Data Stores
local DataStore = DataStoreService:GetDataStore("DailyRewardData")

--> Get The Remote Event
local Event = ReplicatedStorage:WaitForChild("Daily")

--> Setup Rewards For Streaks
local Rewards = {
	[1] = function(player: Player)
		--> Do Whatever
		
		--> Fire Remote With Reward String To Put In GUI
		Event:FireClient(player, "You Recieved 50 Coins!")
	end,
	[2] = function(player: Player)
		--> Do Whatever

		--> Fire Remote With Reward String To Put In GUI
		Event:FireClient(player, "You Recieved 50 Coins!")
	end,
	[3] = function(player: Player)
		--> Do Whatever

		--> Fire Remote With Reward String To Put In GUI
		Event:FireClient(player, "You Recieved 50 Coins!")
	end,
	[4] = function(player: Player)
		--> Do Whatever

		--> Fire Remote With Reward String To Put In GUI
		Event:FireClient(player, "You Recieved 50 Coins!")
	end,
	[5] = function(player: Player)
		--> Do Whatever

		--> Fire Remote With Reward String To Put In GUI
		Event:FireClient(player, "You Recieved 50 Coins!")
	end,
	[6] = function(player: Player)
		--> Do Whatever

		--> Fire Remote With Reward String To Put In GUI
		Event:FireClient(player, "You Recieved 50 Coins!")
	end,
	[7] = function(player: Player)
		--> Do Whatever

		--> Fire Remote With Reward String To Put In GUI
		Event:FireClient(player, "You Recieved 50 Coins!")
	end,
}

--> Data Functions
local function GetPlayerData(player: Player)
	local Succ, Data = pcall(function()
		return DataStore:GetAsync(player.UserId)
	end)
	
	return Data
end

local function SavePlayerData(player: Player)
	local Table = {
		Claimed = player:GetAttribute("DailyClaimed") or false,
		LastLogin = player:GetAttribute("LastLogin") or os.date("%j"),
		Streak = player:GetAttribute("Streak") or 1
	}
	
	DataStore:SetAsync(player.UserId, Table)
end

--> Player Functions
local function PlayerAdded(player: Player)
	local SavedData = GetPlayerData(player)
	
	if SavedData == nil or type(SavedData) ~= "table" then
		SavedData = {
			Claimed = false,
			LastLogin = 0,
			Streak = 1,
		}
	end
	
    --> Set the players data as attributes
	player:SetAttribute("DailyClaimed", SavedData.Claimed)
	player:SetAttribute("LastLogin", SavedData.LastLogin)
	player:SetAttribute("Streak", SavedData.Streak)
	
	--> Check If Player Gets Daily Reward
	if (tonumber(os.date("%j")) - 1) >= tonumber(player:GetAttribute("LastLogin")) and player:GetAttribute("DailyClaimed") == false then
		local Streak = player:GetAttribute("Streak")
		
		player:SetAttribute("DailyClaimed", true)
		player:SetAttribute("LastLogin", os.date("%j"))
		
		Rewards[Streak](player)
		
		player:SetAttribute("Streak", Streak + 1)
		
		--> Reset Streak If It Goes Passed The Number Of Streaks
		if player:GetAttribute("Streak") > #Rewards then
			player:SetAttribute("Streak", 1)
		end
	end
	
end

local function PlayerRemoving(player: Player)
	SavePlayerData(player)
end

--> Race Conditions (If a player loads before this script does.)
for _, player in pairs(Players:GetPlayers()) do
	PlayerAdded(player)
end

--> Player Connections
Players.PlayerAdded:Connect(PlayerAdded)
Players.PlayerRemoving:Connect(PlayerRemoving)

--> Incase of server shutting down
game:BindToClose(function()
	for _, player in pairs(Players:GetPlayers()) do
		PlayerRemoving(player)
	end
end)

If you don’t know what os.date("%j") is, it is basically getting the day of the year as a day out of 365. For example, 10/19/2023 would be 292.

Step 2: Create a Remote Event

  • Create a RemoteEvent inside of ReplicatedStorage
  • Name it “Daily”, if you name it something else, don’t forget to change it inside of the scripts.

Step 3: Create a GUI that shows the player their reward

  • Create a GUI that has a TextLabel named “Label”, and a TextButton named “TextButton”
  • Create a LocalScript that will detect when the remote has fired the client, and set the text to the sent text.
  • Provided Code:
--> Get The Needed Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")

--> Get The Remote Event
local Event = ReplicatedStorage:WaitForChild("Daily")

--> Get Needed UI Objects
local UI = script.Parent
local Daily = UI:WaitForChild("Daily")
local Label = Daily:WaitForChild("Label")
local Close = Daily:WaitForChild("TextButton")

--> Open & Close Function
local function CloseUI()
	Daily.Visible = false
end

local function OpenUI()
	Daily.Visible = true
end

--> Event Functions
local function onClientEvent(RewardString: string)
	Label.Text = RewardString
	
	OpenUI()
end

--> Connections
Close.MouseButton1Click:Connect(CloseUI)
Event.OnClientEvent:Connect(onClientEvent)

This will set the TextLabel to the text that the reward sends to the client when they claim their reward, which you can change in the DailyRewards script in each Reward function in the “Rewards” table.

Free Model:

I have made a free model of this, including a basic GUI.

Conclusion:

If this helped you it would be appreciated to leave a like!
Any questions or feedback would be appreciated as well.
Thank you

30 Likes

Thanks I will defiantly use this some time!
But just to be clear this isn’t much of a tutorial considering you are just telling us to copy and paste code so we aren’t really learning it

2 Likes

This was the only tutorial that actually worked with the systems I already had in place. Very straightforward and useful. Thank you for this!

1 Like

I used this, and it doesnt really seem to work (works for the first time but you can never claim it after that) I did modify the script a bit, but I dont think it’s enough to effect anything in this way.

Edit I think I figured it out, the script never actually turns daily claimed back off. so I simply added another if statement at the beginning checking if the player’s time is ready, and if it is it turns dailyclaimed to false

3 Likes