I’ve made a pretty straightforward module for loading and saving leaderstats here. One major drawback of this module is that it uses the DataStoreService’s SetAsync()
function which may lead to data loss if you’re not careful.
Functions
You’ll work directly with three functions
.Init(STAT, STAT TYPE, DEFAULT_VALUE)
Returns two functions; get()
and update()
Example usage:
local STAT = "Minutes"
local STAT_TYPE = "IntValue"
local DEFAULT_VALUE = 0
local get, update = LeaderstatsHandler.Init(STAT, STAT_TYPE, DEFAULT_VALUE)
get(PLAYER)
Returns value of stat. Type depends on the type you’ve chosen (i.e., IntValue, StringValue)
Example usage:
local oldValue = get(player)
update(PLAYER, NEW_VALUE)
Returns nil.
Example usage:
update(player, oldValue + 1)
Loading and Saving
This module will load and save automatically using the PlayerAdded
and PlayerRemoving
events. You may modify this to use datastore modules such DataStore2 and ProfileService.
Avoiding Data Loss
Only use get()
and update()
when the player’s datastores have loaded in properly. To do this, I used a BindableEvent that is fired by the module only after the game has tried to load in the player’s data.
Example Code
Below is a script that keeps track of how long the player has been in the game. It subscribes to a BindableEvent named Ready
which is fired by the LeaderstatsHandler. This is so that get()
and update()
are only called once the player’s data has loaded.
If get() is called before the player’s data has been loaded, it will likely return the default value. If you update the player’s data with this, it may lead to data loss.
local Players = game:GetService("Players")
local LeaderstatsHandler = require(script.Parent)
local isReady = script.Parent.Ready
local STAT = "Minutes"
local STAT_TYPE = "IntValue"
local DEFAULT_VALUE = 0
local get, update = LeaderstatsHandler.Init(STAT, STAT_TYPE, DEFAULT_VALUE)
local TIME_TO_INCREMENT = 1 -- Every 'x' seconds, add 1
isReady.Event:Connect(function(player)
local oldValue = get(player) or DEFAULT_VALUE
while true do
task.wait(TIME_TO_INCREMENT)
oldValue = get(player)
update(player, oldValue + 1)
end
end)
Roblox Model
GitHub Repo
In hindsight, I think I should let get()
query the datastore directly to prevent data loss but it’s set up this way to avoid hitting the request limits.