Overview

EasyStats is a compact server-side Roblox module for creating leaderstats-style value instances and persisting them to DataStore. It provides a simple API to create stats (IntValue, NumberValue, StringValue, BoolValue), set defaults, read/write values, export data for storage, and automatically saves players on leave with periodic autosave.

1 — Setup

Place the module on the server and require it from a Server script.

File layout

ServerScriptService/
  ├─ EasyStats.lua        -- (module file)
  └─ StatsLoader.server.lua  -- (small script to require and use it)

Basic loader example

local Leaderstats = require(game.ServerScriptService.EasyStats)

game.Players.PlayerAdded:Connect(function(player)
    -- Create or get stats and show them on the default leaderboard
    local stats = Leaderstats.GetStats(player, "leaderstats")

    -- Ensure default stats exist
    stats:setDefault("Coins", "IntValue", 0, {IsPrimary = true})
end)

2 — How it works (quick)

  • GetStats loads data for the player (DataStore), creates a Folder on the Player (default name leaderstats), and creates value Instances for each stat.
  • Each player's runtime object is tracked in an internal session registry.
  • On player leave, the module exports the stats to a plain table and saves with DataStore.
  • An autosave loop periodically saves every active session (default: every 120s).

3 — Basic usage examples

Require the module

local Leaderstats = require(game.ServerScriptService.EasyStats)

Create / get stats

game.Players.PlayerAdded:Connect(function(player)
    local stats = Leaderstats.GetStats(player, "leaderstats")
    stats:setDefault("Coins", "IntValue", 0, {IsPrimary = true})
end)

Create a stat manually

local kills = stats:create("Kills", "IntValue", 0, {Priority = 10})
-- 'kills' is the actual Instance returned; you can connect events to it.

Update and read stat values

stats:update("Coins", 100)
local coinCount = stats:call("Coins") -- returns 100

4 — Advanced usage & options

When creating or setting defaults, pass an options table with these keys:

  • IsPrimary = true — adds a BoolValue child IsPrimary on the stat instance.
  • Priority = <number> — adds a NumberValue child Priority, helpful for ordering.
stats:create("Level", "IntValue", 1, {IsPrimary = true})
stats:create("Score", "IntValue", 0, {Priority = 100})

5 — Data persistence & autosave behavior

The module uses a DataStore and stores each player's exported data under tostring(player.UserId).

Loading

GetStats attempts DataStore:GetAsync and recreates value instances from saved data when present.

Saving

On player leave, ExportData() is saved with DataStore:SetAsync. An autosave loop runs every 120s for active sessions.

Exported data format

{ 
  Coins = {
    Type = "IntValue",
    Value = 100,
    Options = { IsPrimary = true, Priority = 10 }
  },
}

6 — API reference

Assume: local Leaderstats = require(game.ServerScriptService.EasyStats)

Leaderstats.GetStats(key, leaderName)

Get/create a player's stats folder; leaderName controls the Folder name (use leaderstats for Roblox leaderboard visibility).

:setDefault(name, className, defaultValue, options)

:create(name, className, defaultValue, options)

:update(name, newValue)

:call(name)

:ExportData()

7 — Tweaks & customizations

Change autosave interval

task.spawn(function()
  while true do
    task.wait(120) -- change this number
    for _, obj in pairs(session) do
      savePlayer(obj._player)
    end
  end
end)

Use UpdateAsync for safer writes

local ok, err = pcall(function()
  DataStore:UpdateAsync(tostring(player.UserId), function(oldData)
    -- merge oldData with 'data' and return the merged table
    return data
  end)
end)

8 — Troubleshooting & best practices

  • Stat not found: Ensure setDefault or create ran before update.
  • DataStore failures: Consider retry/backoff; log warnings.
  • Concurrency: Prefer UpdateAsync for multi-server games.
  • Data size: Keep saved data small.

9 — Example complete server script

-- StatsLoader.server.lua
local Leaderstats = require(game.ServerScriptService.EasyStats)
local Players = game:GetService("Players")

Players.PlayerAdded:Connect(function(player)
  local stats = Leaderstats.GetStats(player, "leaderstats")

  stats:setDefault("Coins", "IntValue", 0, {IsPrimary = true})
  stats:setDefault("Kills", "IntValue", 0)
  stats:setDefault("Level", "IntValue", 1, {Priority = 50})

  local current = stats:call("Coins") or 0
  stats:update("Coins", current + 10)
end)

10 — FAQ / Notes

Q: Are stats persisted across servers?
A: Yes — saved to a DataStore keyed by UserId.

Q: Will stats appear on Roblox's leaderboard?
A: If the folder name is leaderstats, yes. Use another name to hide them.

Q: Can I use OrderedDataStore for ranked boards?
A: Extend the module to also write selected values into an OrderedDataStore.

Final notes & recommended improvements

  • Switch to UpdateAsync if you expect concurrent writes.
  • Add logging hooks for save/load failures.
  • Batch frequent small writes to reduce DataStore usage.