OwlDataIntermediate
Player Profiles with OwlData
Loading a profile on join, syncing leaderstats reactively and awarding currency safely.
OwlDataObserveIncrement
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local Owl = require(ReplicatedStorage.OwlKnit.Owl)
local OwlData = Owl.Util.Data
local DEFAULT_SCHEMA = { Coins = 0, Level = 1 }
local StatsService = Owl.CreateService({ Name = "StatsService" })
function StatsService:OwlInit()
end
function StatsService:OwlStart()
end
function StatsService:OwlOnPlayerAdded(plr: Player)
OwlData.Load(plr, {
storeName = "PlayerStats_v1",
schema = DEFAULT_SCHEMA,
}):andThen(function(profile)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = plr
local coins = Instance.new("IntValue")
coins.Name = "Coins"
coins.Parent = leaderstats
-- > // Keeps leaderstats in sync with the profile automatically
profile:Observe("Coins", function(value)
coins.Value = value
end)
end):catch(warn)
end
function StatsService:AwardCoins(plr: Player, amount: number)
local profile = OwlData.Get(plr)
if not profile then return end
profile:Increment("Coins", amount)
end
return StatsServiceWhat's happening here
- profile:Observe("Coins", fn) fires immediately with the loaded value, so leaderstats.Coins is correct from the very first frame.
- OwlData.Get(plr) inside AwardCoins returns nil safely if the profile somehow isn't loaded yet no risk of indexing nil.
- profile:Increment is atomic safe to call from multiple places without a manual read-then-write race.
Related docs