If both dateTable
and newDateTable
are updated constantly, they will always be equal.
im really confused right now, but my scripts to enforce the leaderboard dont work correctly, for example the script the saves the daily (minute) value saves but is supposed to be wiped out by a new key when the player joins when a new mminute begins, however it isnt working and keeps the old save
leaderboard script
local sg = script.Parent --Surface GUI
local sample = script:WaitForChild("Sample") --Our Sample frame
local sf = sg:WaitForChild("ScrollingFrame") --The scrolling frame
local ui = sf:WaitForChild("UI") --The UI list layout
local dateTable = os.date("*t", os.time())
local key = "Y:"..dateTable["year"].." M:"..dateTable["month"].." D:"..dateTable["day"].." H:"..dateTable["hour"].." I:"..dateTable["min"]
local dataStoreService = game:GetService("DataStoreService")
--The data store service
local dataStore = dataStoreService:GetOrderedDataStore(key)
--Get the data store with key "Leaderboard"
wait(10)
while true do
for i,plr in pairs(game.Players:GetChildren()) do--Loop through players
if plr.UserId>0 then--Prevent errors --PointsService
local w = plr.Value.Value --Get point balance
if w then
pcall(function()
--Wrap in a pcall so if Roblox is down, it won't error and break.
dataStore:UpdateAsync(plr.UserId,function(oldVal)
--Set new value
return tonumber(w)
end)
end)
end
end
end
local smallestFirst = false--false = 2 before 1, true = 1 before 2
local numberToShow = 100--Any number between 1-100, how many will be shown
local minValue = 1--Any numbers lower than this will be excluded
local maxValue = 10e30--(10^30), any numbers higher than this will be excluded
local pages = dataStore:GetSortedAsync(smallestFirst, numberToShow, minValue, maxValue)
--Get data
local top = pages:GetCurrentPage()--Get the first page
local data = {}--Store new data
for a,b in ipairs(top) do--Loop through data
local userid = b.key--User id
local points = b.value--Points
local username = "[Failed To Load]"--If it fails, we let them know
local s,e = pcall(function()
username = game.Players:GetNameFromUserIdAsync(userid)--Get username
end)
if not s then--Something went wrong
warn("Error getting name for "..userid..". Error: "..e)
end
local image = game.Players:GetUserThumbnailAsync(userid, Enum.ThumbnailType.HeadShot, Enum.ThumbnailSize.Size150x150)
--Make a image of them
table.insert(data,{username,points,image})--Put new data in new table
end
ui.Parent = script
sf:ClearAllChildren()--Remove old frames
ui.Parent = sf
for number,d in pairs(data) do--Loop through our new data
local name = d[1]
local val = d[2]
local image = d[3]
local color = Color3.new(1,1,1)--Default color
if number == 1 then
color = Color3.new(1,1,0)--1st place color
elseif number == 2 then
color = Color3.new(0.9,0.9,0.9)--2nd place color
elseif number == 3 then
color = Color3.fromRGB(166, 112, 0)--3rd place color
end
local new = sample:Clone()--Make a clone of the sample frame
new.Name = name--Set name for better recognition and debugging
new.LayoutOrder = number--UIListLayout uses this to sort in the correct order
new.Image.Image = image--Set the image
new.Image.Place.Text = number--Set the place
new.Image.Place.TextColor3 = color--Set the place color (Gold = 1st)
new.PName.Text = name--Set the username
new.Value.Text = val--Set the amount of points
new.Value.TextColor3 = color--Set the place color (Gold = 1st)
new.PName.TextColor3 = color--Set the place color (Gold = 1st)
new.Parent = sf--Parent to scrolling frame
end
wait()
sf.CanvasSize = UDim2.new(0,0,0,ui.AbsoluteContentSize.Y)
--Give enough room for the frames to sit in
wait(120)
end
while true do
local newdateTable = os.date("*t", os.time())
print(newdateTable["min"])
if newdateTable["min"] ~= dateTable["min"] then
key = "Y:"..newdateTable["year"].." M:"..newdateTable["month"].." D:"..newdateTable["day"].." H:"..newdateTable["hour"].." I:"..newdateTable["min"]
min = newdateTable["min"]
for i,v in game.Players:GetChildren() do
v.Value.Value = 0
end
print("lower than value")
print(dateTable["min"])
else
end
wait(1)
end
save script
local dateTable = os.date("*t", os.time())
local key = "Y:"..dateTable["year"].." M:"..dateTable["month"].." D:"..dateTable["day"].." H:"..dateTable["hour"].." I:"..dateTable["min"]
print(key)
print(dateTable["min"])
game.Players.PlayerAdded:Connect(function(player)
local value = Instance.new("IntValue")
value.Name = 'Value'
value.Parent = player
local stats = game.DataStoreService:GetDataStore(key)
local data = stats:GetAsync(player.UserId)
if data then
value.Value = data.Tests
end
value.Value = value.Value + 1
end)
game.Players.PlayerRemoving:Connect(function(player)
local stats = game.DataStoreService:GetDataStore(key)
local data = stats:SetAsync(player.UserId, {
["Tests"] = player.Value.Value
})
end)
while true do
local newdateTable = os.date("*t", os.time())
key = "Y:"..newdateTable["year"].." M:"..newdateTable["month"].." D:"..newdateTable["day"].." H:"..newdateTable["hour"].." I:"..newdateTable["min"]
wait(1)
end
The dateTable, which is basically the main data of the script, is pre defined and is always changed by a loop that compares it to the current time, and changes it if it is different in terms of the type of time that changed, which in my case was a minute, however it does not seem to work on the save script even though i think it set a new key which would be the new time
I have the rest of the script done myself but wanted to see how to make weekly leaderboards. I ended up here and used your method. However, I was wondering if making a new datastore every week will create needless amounts of data stores that never get deleted?
On Roblox, this isn’t as much of a problem. It would take more computational power to remove all of your entries then it would to just use a new datastore.
As a Roblox Developer, you don’t have to worry about database usage as long as it’s within your quotas.
Ok, thanks! this really helped me on my quest for a weekly leaderboard!
Something that might be more applicable than DataStores for that use case would be Memory Stores
because data in Memory Stores expire after a duration of time that you set (currently, the limit is up to 30 days max according to the announcement thread for the feature).
The problem with using MemoryStore expiration is it is relative to the time the data is saved, not since a certain point.
MemoryStores could be used for a leaderboard that needs to be updated constantly, but your quota is much better used in other features then leaderboards, in my opinion.
That’s true – in this use case then, from what I understand, the primary benefit of Memory Stores would moreover be the reduction in data you’d have to manually clear as a result of GDPR Data Erasure Requests because none of the data would be persistent so it’d be removed anyway.
Since there currently isn’t a built-in way to allow Roblox to automatically purge any info contained in DataStores upon receiving a data erasure request, it would probably save a lot of time that would have been spent clearing the UserId and associated data from each key (especially for games where multiple leaderboards are “reset” dozens or hundreds of times per year).
But there are / will probably be ways that would make that easier in the future so I guess it’d be dependent on how each game prefers to approach leaderboards & if they already use Memory Stores for other features in their game.
I’m not as knowledgeable about these yet so I appreciate the insight
It appears you haven’t set the SortOrder
of the UIListLayout
to LayoutOrder
.
How would i make it so, if the old value is smaller than the new one then update?
By doing that check and then returning it. You’d also want to reverse the sort order (set smallestFirst
to true).
Hello, this works but does it work globally or only in one server? I saved some values in a data store to my userid and when my friend tested it too it didn’t show?
This should work globally. There is a delay in between requests, so make sure you wait at least a minute before deciding it doesn’t work. Otherwise, it might be your specific set up that is broken, in which case make sure you followed the guide properly.
Quick question, say if a player is 9 hours ahead of another player in USA California (the time the os.time gives I believe).
It is 3PM, January 1st, 2020 for that player in California. Would the player 9 hours ahead of the California player see a different leaderboard? (since it’s 12AM, January 2nd, 2020 and a new day for that player)
Since we use UTC time, timezones are irrelevant. It’s not a good idea to try and adjust to timezones, as you’ll need to keep track of a lot more data.
If you want to make it easier for players to understand, you can always add a “resets in” text somewhere which counts down to the end of the day (using UTC time).
yeah that’s smart! Actually, like you said, I’ve seen “time in UTC” and “resets in hh mm ss” before (like in ZO and a donate game). That’ll be enough to let the players know.
Also, if you do resets, you should also have an update counter which tells you how long before new data will be retrieved.
There’s a lot of little things that can be added - every little feature makes your game feel more polished.
Hey, i need a little help. Send me the source code because it got deleted the orignal source code of the leaderboard
The source code is still there. Please make sure you read the notice about PlayerPoints at the top, though.