Example
Player Data
Load from DataStore on join, push to the client reliably, save on route request or on leave.
local DataStoreService = game:GetService("DataStoreService")
local playerStore = DataStoreService:GetDataStore("PlayerData")
local cache = {}
local function defaults()
return { coins = 0, level = 1, xp = 0, inventory = {} }
end
game.Players.PlayerAdded:Connect(function(player)
local ok, data = pcall(function() return playerStore:GetAsync(player.UserId) end)
cache[player.UserId] = (ok and data) or defaults()
app:Push(player, "player.data", cache[player.UserId])
end)
game.Players.PlayerRemoving:Connect(function(player)
if cache[player.UserId] then
pcall(function() playerStore:SetAsync(player.UserId, cache[player.UserId]) end)
cache[player.UserId] = nil
end
end)
app:Post("player/save", function(Player, Payload, req, res)
local d = cache[Player.UserId]
if not d then res:Status(404):Error("No data"); return end
local ok, err = pcall(function() playerStore:SetAsync(Player.UserId, d) end)
if ok then res:Send({ saved = true }) else res:Status(500):Error(err) end
end)
app:Get("player/data", function(Player, Payload, req, res)
res:Send(cache[Player.UserId] or res:Status(404):Error("Not loaded"))
end)
Client
listener:Once("player.data", function(data)
PlayerModel:Load(data)
UI:Refresh()
end)
What this demonstrates
| Pattern | Detail |
|---|---|
| Push on join | Server pushes data immediately after load | client doesn't have to poll |
listener:Once | Subscribe exactly once, disconnect automatically after receipt |
| Error status | res:Status(500):Error(err) | proper HTTP-style errors |
See also
Server Push ·
Listener | Once API ·
App ·
MVC Pattern | clean PlayerModel architecture