Getting Started
Let's get Lyra set up in your game and cover the basics of saving player data.
Installation
Add Lyra to your wally.toml
:
Lyra = "paradoxum-games/lyra@0.4.1"
tip
If you're new to Wally, check out the Wally installation guide.
Basic Setup
Here's how to set up Lyra with a simple data structure:
local Players = game:GetService("Players")
local Lyra = require(path.to.Lyra)
-- Define your data template
local template = {
coins = 0,
inventory = {},
}
-- Create schema to validate data
local schema = t.strictInterface({
coins = t.number,
inventory = t.table,
})
-- Create the store
local store = Lyra.createPlayerStore({
name = "PlayerData",
template = template,
schema = schema,
})
-- Load data when players join
Players.PlayerAdded:Connect(function(player)
store:loadAsync(player)
end)
-- Save and clean up when they leave
Players.PlayerRemoving:Connect(function(player)
store:unloadAsync(player)
end)
-- Ensure data is saved when the game closes
game:BindToClose(function()
store:closeAsync()
end)
Working with Data
Reading Data
You can read player data, but remember that it might change between reads:
-- ⚠️ Only use this data for reading
-- Don't save it for later use
local data = store:getAsync(player)
print(`{player.Name} has {data.coins} coins`)
Modifying Data
Always modify data through update functions:
-- Simple update
store:updateAsync(player, function(data)
data.coins += 100
return true
end)
-- Conditional update
store:updateAsync(player, function(data)
if data.coins < itemPrice then
return false -- Abort the update
end
data.coins -= itemPrice
table.insert(data.inventory, itemId)
return true
end)
Trading Between Players
Use transactions for operations involving multiple players:
store:txAsync({player1, player2}, function(state)
-- Transfer coins
if state[player1].coins < amount then
return false -- Abort if not enough coins
end
state[player1].coins -= amount
state[player2].coins += amount
return true
end)
Importing Existing Data
If you're migrating from another DataStore library, you can import your existing data:
local store = Lyra.createPlayerStore({
name = "PlayerData",
template = template,
schema = schema,
importLegacyData = function(key)
local success, data = pcall(function()
return YourCurrentSystem.getData(key)
end)
if not success then
error("Failed to reach data system") -- Player will be kicked and can retry
end
if data ~= nil then
return data -- Return existing data to import
end
return nil -- Return nil for new players to use template
end,
})
ProcessReceipt Example
Here's an example of how you would use Lyra in ProcessReceipt:
local ProductCallbacks = {
[12345] = function(player, receiptInfo, data)
data.coins += 100
return true
end,
}
local function processReceipt(receiptInfo)
local player = Players:GetPlayerByUserId(receiptInfo.PlayerId)
if not player then
return Enum.ProductPurchaseDecision.NotProcessedYet
end
local productCallback = ProductCallbacks[receiptInfo.ProductId]
if not productCallback then
return Enum.ProductPurchaseDecision.NotProcessedYet
end
local ok, result = pcall(function()
store:updateAsync(player, function(data)
-- Assuming you have 'purchaseHistory' in your template and schema:
if table.find(data.purchaseHistory, receiptInfo.PurchaseId) then
return false -- Prevent duplicate purchases
end
table.insert(data.purchaseHistory, 1, receiptInfo.PurchaseId)
for i = 1000, #data.purchaseHistory do
data.purchaseHistory[i] = nil -- Remove old purchases
end
return productCallback(player, receiptInfo, data)
end)
store:saveAsync(player)
end)
if not ok then
warn(`ProcessReceipt failed: {result}`)
return Enum.ProductPurchaseDecision.NotProcessedYet
end
return Enum.ProductPurchaseDecision.PurchaseGranted
end
Promise-based API
Lyra also offers a Promise-based API:
store:update(player, function(data)
data.coins -= itemPrice
data.inventory.weapon = "starter_sword"
return true
end):andThen(function()
print("Purchase successful!")
end):catch(function(err)
print(`Purchase failed: {err}`)
end)
Next Steps
Now that you've got the basics down, check out:
- Core Concepts for a deeper understanding
- Data Migrations for updating data structure
- Network Updates for client synchronization
- Debugging for troubleshooting