I need help with two things for my leaderboards

So I have a leaderboard script that I have and now i want to do these two things:

  1. Every 30 minutes or so (on the dot! 11:30, 12:00, 12:30, etc.) my discord bot will post on my “Webhooks” server what are the top 10 people on the leaderboards.
  2. If the player has 0 of one currency they can’t be on the leaderboard.

I know from past experience that when you want it to be on the dot you do this:

local CurrentSec = date.min * 60 + date.sec
	
local AlignMin = 30 -- or whatever the minutes is
local AlignMinSecs = 60 * AlignMin

local TimeToWait = AlignMinSecs - CurrentSec
print(TimeToWait)
	
for i = 1, math.floor(60 / AlignMin) - 1 do
	if TimeToWait < 0 then
		TimeToWait = (i + 1) * AlignMinSecs - CurrentSec
		print(TimeToWait)
		else warn("TimeToWait is not under 0") break -- not really needed but it's good for debugging or whatever
	end
end

wait(TimeToWait)
	
while true do
	--whatever you want to do (make sure it is wrapped in a coroutine)
	wait(AlignMinSecs)
end

but I’m wondering if I should put it in the same script or in a different one.


Thanks for you help!

bacon
2 Likes

I would modulate it, as it would be easier to edit and change data whilst keeping the fast and effective as not to cause lag to server or client.

1 Like

Okay, but you didn’t really answer the question or the two problems:

I would use the same script.

It’d be difficult to fire an event from one script to another, especially considering both of these scripts would be on the server so RemoteEvents are out of the question. It’d also be easier to connect these two because another script would be clutter.

If you really wanted to use more than one script, then you could add a BoolValue or something and change it depending on the time, and use a .Changed event in another script.

Of course these are simply my thoughts; take it with a grain of salt.

Ok so I’m using your method of using the same script.

However, with this code:

local dss = game:GetService("DataStoreService")
local cashDataStore = dss:GetOrderedDataStore("TotalCash3")
local crystalsDataStore = dss:GetOrderedDataStore("TotalCrystals3")
local cocoaDataStore = dss:GetOrderedDataStore("TotalCocoa3")
local levelDataStore = dss:GetOrderedDataStore("LevelLeaderboard3")
local moltenDataStore = dss:GetOrderedDataStore("MoltenCocoa3")

local http = game:GetService("HttpService")
local webhook = "https://discordapp.com/api/webhooks/728418584778375180/OkG0XcvD0svq8UrnmZjZyFpsFwZTajddAh4BK5WDeSyB9Zwal_Wz9jSnnQI_klt7IgPY"

local formatter = require(game.ReplicatedStorage.Modules.AbbreviationModule)

local ranksNumber = 100
local padding = 0.01

local function setColor(rank, label)
	if rank == 1 then
		label.TextColor3 = Color3.fromRGB(0,255,255)
	elseif rank == 2 then
		label.TextColor3 = Color3.fromRGB(203, 156, 50)
	elseif rank == 3 then
		label.TextColor3 = Color3.fromRGB(126, 130, 148)
	elseif rank > 3 then
		label.TextColor3 = Color3.fromRGB(255,255,255)
	end
end

local function Update(dataStore, holder)
	local success, err = pcall(function()
		local Data = dataStore:GetSortedAsync(false, ranksNumber)
		local page = Data:GetCurrentPage()
		for Rank, data in ipairs(page) do
			local succ, result = pcall(game.Players.GetNameFromUserIdAsync, game.Players, tonumber(data.key))
			result = succ and result or "[Failed to load]"
			local Name = result
			local val = data.value
			local isOnLeaderboard = false
			for i, v in pairs(holder:GetChildren()) do
				if v.Player.Text == Name then
					isOnLeaderboard = true
					break
				end
			end
				
			if val and isOnLeaderboard == false then
				local newFrame = game.ReplicatedStorage:WaitForChild("Template"):Clone()
				newFrame.Player.Text = Name
				newFrame.Rebirths.Text = formatter:format(val)
				newFrame.Rank.Text = "#"..Rank
				setColor(Rank, newFrame.Rank)
				newFrame.Position = UDim2.new(0,0,newFrame.Position.Y.Scale + (0.01 * (#holder:GetChildren())),0)
				newFrame.Parent = holder
			end
		end
	end)
	
	if not success then
		warn(tostring(dataStore)..": "..err)
	end
end

local function SetAsync(dataStore, player, value)
	local success, err = pcall(function()
		dataStore:SetAsync(player.UserId, value)
	end)
	
	if not success then
		warn(err)
	end
end

local function MainUpdate()
	Update(cashDataStore, workspace.TotalCashLeaderboard.SurfaceGui.Holder)
	Update(crystalsDataStore, workspace.TotalCrystalsLeaderboard.SurfaceGui.Holder)
	Update(cocoaDataStore, workspace.TotalCocoaLeaderboard.SurfaceGui.Holder)
	Update(moltenDataStore, workspace.MoltenLeaderboard.SurfaceGui.Holder)
	Update(levelDataStore, workspace.LevelLeaderboard.SurfaceGui.Holder)
end

local function sendToDisc(dataStore)
	local success, err = pcall(function()
		local data = dataStore:GetSortedAsync(false, 10)
		local page = data:GetCurrentPage()
		for Rank, Data in ipairs(page) do
			local succ, result = pcall(game.Players.GetNameFromUserIdAsync, game.Players, tostring(Data.key))
			result = succ and result or "[Failed to load]"
			
			local payload = http:JSONEncode({
				content = "**#"..Rank.."** - "..result,
				username = tostring(dataStore)
			})
			
			http:PostAsync(webhook, payload)
			wait(1)
		end
	end)
	if success then
		print(tostring(dataStore)..": Success!")
	else
		warn(tostring(dataStore)..": "..err)
	end
end

local date = os.date("!*t",os.time())

local CurrentSec = date.min * 60 + date.sec
	
local AlignMin = 1
local AlignMinSecs = 60 * AlignMin

local TimeToWait = AlignMinSecs - CurrentSec
print(TimeToWait)
	
for i = 1, math.floor(60 / AlignMin) - 1 do
	if TimeToWait < 0 then
		TimeToWait = (i + 1) * AlignMinSecs - CurrentSec
		print(TimeToWait)
		else warn("TimeToWait is not under 0") break
	end
end

wait(TimeToWait)
	
while true do
	coroutine.wrap(sendToDisc)(cashDataStore)
	coroutine.wrap(sendToDisc)(crystalsDataStore)
	coroutine.wrap(sendToDisc)(cocoaDataStore)
	coroutine.wrap(sendToDisc)(levelDataStore)
	coroutine.wrap(sendToDisc)(moltenDataStore)
	
	for _, plr in pairs(game.Players:GetPlayers()) do
		SetAsync(cashDataStore, plr, plr.TotalStats:WaitForChild("TotalCash").Value)
		SetAsync(crystalsDataStore, plr, plr.TotalStats:WaitForChild("TotalCrystals").Value)
		SetAsync(cocoaDataStore, plr, plr.TotalStats:WaitForChild("TotalCocoa").Value)
		SetAsync(moltenDataStore, plr, plr.TotalStats:WaitForChild("TotalMolten").Value)
		SetAsync(levelDataStore, plr, plr:WaitForChild("EXP").Level.Value)
	end
	
	for _, frame in pairs(workspace.TotalCashLeaderboard.SurfaceGui.Holder:GetChildren()) do
		frame:Destroy()
	end
	
	for _, crystalFrame in pairs(workspace.TotalCrystalsLeaderboard.SurfaceGui.Holder:GetChildren()) do
		crystalFrame:Destroy()
	end
	
	for _, cocoaFrame in pairs(workspace.TotalCocoaLeaderboard.SurfaceGui.Holder:GetChildren()) do
		cocoaFrame:Destroy()
	end
	
	for _, levelFrame in pairs(workspace.LevelLeaderboard.SurfaceGui.Holder:GetChildren()) do
		levelFrame:Destroy()
	end

	coroutine.wrap(MainUpdate)()
	print("UPDATED")
	
	wait(AlignMinSecs)
end

This happened:

HTTP 429 (Too Many Requests)

Of course I’m using 1 minute to test (i’m going to make it do it every 30 minutes and the leaderboards update every 5 minutes), but I need to find a way to make the loop keep continuing like this:

I would use 2 scripts, a module and a regular server script.

Yes, I know, but I’m gonna need a reference to go by when making my module…