### Basic Lyra Setup for Player Data Source: https://paradoxum-games.github.io/lyra/docs/getting-started This Lua code demonstrates the basic setup of Lyra to manage player data. It defines a data template, creates a schema for validation, initializes a player store, and connects to player join/leave events to load and unload data. It also ensures data is saved when the game closes. ```lua 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) ``` -------------------------------- ### ProcessReceipt Example with Lyra Source: https://paradoxum-games.github.io/lyra/docs/getting-started This Lua example demonstrates integrating Lyra with Roblox's ProcessReceipt function for handling in-game purchases. It maps product IDs to callback functions that update player data using Lyra's `updateAsync` method and handles potential errors and duplicate purchases. ```lua 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(string.format("ProcessReceipt failed: %s", result)) return Enum.ProductPurchaseDecision.NotProcessedYet end return Enum.ProductPurchaseDecision.PurchaseGranted end ``` -------------------------------- ### Install Lyra using Wally Source: https://paradoxum-games.github.io/lyra/docs/getting-started This snippet shows how to add the Lyra library to your project's wally.toml file. Wally is a package manager for Roblox. Ensure you have Wally installed to use this. ```toml Lyra = "paradoxum-games/lyra@0.6.0" ``` -------------------------------- ### Basic Lyra Player Data Store with Multiple Field Additions Source: https://paradoxum-games.github.io/lyra/docs/advanced/migrations This example shows the creation of a basic player data store named 'PlayerData' and includes two migration steps using `Lyra.MigrationStep.addFields` to add 'settings' and 'level' fields. ```lua local store = Lyra.createPlayerStore({ name = "PlayerData", template = template, schema = schema, migrationSteps = { Lyra.MigrationStep.addFields("addSettings", { settings = { music = true, sfx = true, } }), Lyra.MigrationStep.addFields("addLevel", { level = 1, }), }, }) ``` -------------------------------- ### Chaining Transform Steps for Data Migration in Lyra Source: https://paradoxum-games.github.io/lyra/docs/advanced/migrations This example illustrates how to chain multiple `Lyra.MigrationStep.transform` calls to modify player data. The first step converts 'oldField' to 'temporaryField', and the second step transforms 'temporaryField' into 'newField', demonstrating intermediate data states. ```lua migrationSteps = { -- First migration returns data that doesn't match final schema Lyra.MigrationStep.transform("step1", function(data) return { temporaryField = data.oldField, } }), -- Second migration transforms it to match schema Lyra.MigrationStep.transform("step2", function(data) return { newField = data.temporaryField, } }), } ``` -------------------------------- ### Derive External State from Lyra Changes Source: https://paradoxum-games.github.io/lyra/docs/advanced/state-management This Lua example demonstrates how to update external game state by listening to changes in Lyra data using callbacks. This ensures external systems are synchronized with the primary data source. ```lua -- When Lyra data changes, update external state changedCallbacks = { function(key, newData, oldData) local playerId = tonumber(key) gameState.players[playerId][key] = newData[key] end } ``` -------------------------------- ### Lyra Frozen Data Safety Example Source: https://paradoxum-games.github.io/lyra/docs/advanced/networking This Lua code illustrates Lyra's data safety feature where data passed to callbacks is frozen (read-only). The commented-out line demonstrates that attempting to modify `newData` within a callback will result in an error. ```lua local function callback(key, newData, oldData) -- ❌ This will error - data is frozen newData.coins = 100 end ``` -------------------------------- ### Create Player Store and Manage Data with Lyra Source: https://paradoxum-games.github.io/lyra/docs/intro Demonstrates the basic usage of Lyra for creating a player data store, loading player data, performing safe updates with validation, and executing atomic transactions between players. It emphasizes modifying data only through update functions to avoid stale data. ```lua local store = Lyra.createPlayerStore({ name = "PlayerData", template = { coins = 0, inventory = {}, }, schema = t.strictInterface({ coins = t.number, inventory = t.table, }), }) -- Load data when players join Players.PlayerAdded:Connect(function(player) store:loadAsync(player) end) -- Safe updates with validation store:updateAsync(player, function(data) if data.coins < itemPrice then return false -- Abort if can't afford end data.coins -= itemPrice table.insert(data.inventory, itemId) return true end) -- Atomic trades between players store:txAsync({player1, player2}, function(state) -- Either both changes happen or neither does state[player1].coins -= 100 state[player2].coins += 100 return true end) ``` ```lua -- 🚫 Don't do this: local oldData = store:getAsync(player) store:updateAsync(player, function(newData) if not oldData.claimedDailyReward then -- This data might be stale! return false end newData.coins += 500 newData.claimedDailyReward = true return true end) -- ✅ Do this instead: store:updateAsync(player, function(data) if not data.claimedDailyReward then -- This data is always current return false end data.coins += 500 newData.claimedDailyReward = true return true end) ``` -------------------------------- ### Importing Existing Data with Lyra Source: https://paradoxum-games.github.io/lyra/docs/getting-started This Lua code shows how to configure Lyra to import data from an existing system during store creation. The `importLegacyData` function is provided to handle the logic of fetching and returning old data, ensuring a smooth transition for players. ```lua 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, }) ``` -------------------------------- ### Import Legacy Data with Lyra Source: https://paradoxum-games.github.io/lyra/docs/intro Shows how to configure Lyra to import existing player data from a legacy system when switching over. The `importLegacyData` function handles fetching data and returning it to Lyra for initialization. Errors during import will cause Lyra to prompt the player to rejoin. ```lua 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 -- If there's an error, Lyra will kick the player and prompt them -- to rejoin to try again. error("Failed to reach data system") end if data ~= nil then return data -- Return existing data to import end return nil -- Return nil for new players to use template end, }) ``` -------------------------------- ### Sequential Lyra Migrations: Add Fields and Restructure Inventory Source: https://paradoxum-games.github.io/lyra/docs/advanced/migrations This snippet shows how to define multiple migration steps in sequence. It first adds a 'gems' field using `addFields` and then restructures the 'inventory' data using a `transform` step named 'inventoryV2'. ```lua migrationSteps = { -- Add new currency Lyra.MigrationStep.addFields("addGems", { gems = 0, }), -- Restructure inventory Lyra.MigrationStep.transform("inventoryV2", function(data) data.inventory = { items = data.inventory, maxSlots = 20, } return data end), } ``` -------------------------------- ### Basic Lyra Log Handling Source: https://paradoxum-games.github.io/lyra/docs/advanced/debugging Sets up a basic log callback function to print all Lyra log messages, including their severity, message, and context, to the console. This is useful for general debugging. ```lua local function handleLogs(message) print(`[Lyra][{string.upper(message.level)}] {message.message}`) if message.context then -- Context contains relevant data like keys, session info, etc. print("Context:", message.context) end end local store = Lyra.createPlayerStore({ name = "PlayerData", template = template, schema = schema, logCallback = handleLogs, }) ``` -------------------------------- ### Promise-based API for Lyra Operations Source: https://paradoxum-games.github.io/lyra/docs/getting-started This Lua snippet showcases Lyra's Promise-based API for handling asynchronous data operations. It allows chaining `.andThen()` for success callbacks and `.catch()` for error handling, providing a more readable way to manage asynchronous workflows. ```lua 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(string.format("Purchase failed: %s", err)) end) ``` -------------------------------- ### Register Multiple Lyra Callbacks Source: https://paradoxum-games.github.io/lyra/docs/advanced/networking This Lua snippet shows how to register multiple callbacks for a Lyra player store. It includes a callback for syncing client data and another for logging changes to the console, demonstrating the flexibility of the `changedCallbacks` array. ```lua local store = Lyra.createPlayerStore({ changedCallbacks = { -- Keep clients in sync syncWithClient, -- Log changes for debugging function(key, newData, oldData) print(`Player {key} data changed`) end, }, }) ``` -------------------------------- ### Sync Player Data with Lyra Callbacks Source: https://paradoxum-games.github.io/lyra/docs/advanced/networking This Lua code demonstrates how to set up a Lyra player store with a `changedCallback` to synchronize player data with clients. It compares old and new data to send only necessary changes, optimizing network traffic. The callback receives frozen data, preventing direct mutation. ```lua local ReplicatedStorage = game:GetService("ReplicatedStorage") local Network = require(ReplicatedStorage.Network) local function syncWithClient(key: string, newData, oldData) local player = Players:GetPlayerByUserId(tonumber(key)) if not player then return end if oldData == nil then -- First time data is loaded Network.PlayerData:FireClient(player, newData) return end -- Send only changed data local changes = {} if newData.coins ~= oldData.coins then changes.coins = newData.coins end if not Tables.deepEquals(newData.inventory, oldData.inventory) then changes.inventory = newData.inventory end -- Send changes to client Network.PlayerData:FireClient(player, changes) end local store = Lyra.createPlayerStore({ name = "PlayerData", template = template, schema = schema, changedCallbacks = { syncWithClient }, }) ``` -------------------------------- ### Automatic Data Persistence and Shutdown Handling in Lyra Source: https://paradoxum-games.github.io/lyra/docs/core-concepts Automatically saves player data every 5 minutes. It requires calling `store:closeAsync()` within `BindToClose` to ensure all data is saved upon game shutdown. ```lua game:BindToClose(function() store:closeAsync() end) ``` -------------------------------- ### Implement Badge Award System with changedCallbacks in Lyra Source: https://paradoxum-games.github.io/lyra/docs/advanced/state-management This code snippet demonstrates how to set up a badge award system using Lyra's `changedCallbacks`. The callback function receives the data key, new data, and old data, allowing checks for specific conditions (e.g., coin milestones, quest completion) to award badges. It assumes the existence of `BadgeService` and `BADGES` definitions. ```lua -- Set up a badge award system that reacts to data changes changedCallbacks = { function(key, newData, oldData) if oldData == nil then return end local playerId = tonumber(key) -- Check if player reached a milestone if oldData.coins < 1000 and newData.coins >= 1000 { BadgeService.awardBadge(playerId, BADGES.COIN_COLLECTOR) } -- Check if player completed all quests if #oldData.completedQuests < 10 and #newData.completedQuests >= 10 { BadgeService.awardBadge(playerId, BADGES.QUEST_MASTER) } end } ``` -------------------------------- ### Player Session Management with Lyra Source: https://paradoxum-games.github.io/lyra/docs/core-concepts Manages player data sessions by loading data when a player joins and unloading it when they leave. This uses Lyra's session locking mechanism to ensure exclusive data access. ```lua Players.PlayerAdded:Connect(function(player) -- Establish exclusive access to the player's data store:loadAsync(player) end) Players.PlayerRemoving:Connect(function(player) -- Release the lock and save any pending changes store:unloadAsync(player) end) ``` -------------------------------- ### Lyra Log Level Handling Source: https://paradoxum-games.github.io/lyra/docs/advanced/debugging Demonstrates how to handle different Lyra log levels (fatal, error, warn, info, debug, trace) within a log callback function. Each level is processed differently, with errors and fatal issues triggering warnings, while others are printed. ```lua local function handleLogs(message) -- Handle based on severity if message.level == "fatal" then -- Unrecoverable errors (e.g., corrupted data) warn("FATAL:", message.message) elseif message.level == "error" then -- Operation failures (e.g., update failed) warn("Error:", message.message) elseif message.level == "warn" then -- Potential issues (e.g., slow operations) warn("Warning:", message.message) elseif message.level == "info" then -- Important operations (e.g., session started) print("Info:", message.message) elseif message.level == "debug" then -- Detailed operation info print("Debug:", message.message) elseif message.level == "trace" then -- Very detailed debugging info print("Trace:", message.message) end end ``` -------------------------------- ### Reading Player Data with Lyra Source: https://paradoxum-games.github.io/lyra/docs/getting-started This Lua snippet shows how to retrieve player data using Lyra's getAsync method. It's important to note that the data retrieved might be outdated if modified between reads. This method is intended for read-only operations. ```lua -- ⚠️ Only use this data for reading -- Don't save it for later use local data = store:getAsync(player) print(string.format("%s has %d coins", player.Name, data.coins)) ``` -------------------------------- ### Trading Between Players using Lyra Transactions Source: https://paradoxum-games.github.io/lyra/docs/getting-started This Lua snippet demonstrates how to perform atomic operations between multiple players using Lyra's txAsync method. This is crucial for actions like trading to ensure that both parties' data is updated correctly or not at all, maintaining data consistency. ```lua 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) ``` -------------------------------- ### Adding New Fields to Player Data with Lyra Source: https://paradoxum-games.github.io/lyra/docs/advanced/migrations This snippet demonstrates how to add a new field 'gems' to player data. It includes adding the field to the template, schema, and then using `Lyra.MigrationStep.addFields` to incorporate it into existing data. ```lua -- Step 1: Add to template local template = { coins = 0, -- Existing field gems = 0, -- New field } -- Step 2: Add to schema local schema = { coins = t.number, gems = t.number, -- New field } -- Step 3: Add migration local store = Lyra.createPlayerStore({ template = template, schema = schema, migrationSteps = { Lyra.MigrationStep.addFields("addGems", { gems = 0, }), }, }) ``` -------------------------------- ### Add Lyra Dependency to Wally TOML Source: https://paradoxum-games.github.io/lyra/docs/intro This snippet shows how to add the Lyra module as a dependency to your Roblox project using Wally, a package manager for Roblox. ```toml [dependencies] Lyra = "paradoxum-games/lyra@0.6.0" ``` -------------------------------- ### Transforming Inventory Data with Lyra Migration Source: https://paradoxum-games.github.io/lyra/docs/advanced/migrations This Lyra migration step uses `Lyra.MigrationStep.transform` to convert a simple 'inventory' list into a more structured 'items' table, removing the old 'inventory' field in the process. The transformation logic is defined within a Lua function. ```lua migrationSteps = { Lyra.MigrationStep.transform("inventoryToItems", function(data) -- Convert simple inventory list to detailed items data.items = {} for _, item in data.inventory do table.insert(data.items, { id = item, acquired = os.time(), }) end data.inventory = nil return data end), } ``` -------------------------------- ### Atomic Multi-Player Transactions in Lyra Source: https://paradoxum-games.github.io/lyra/docs/core-concepts Enables atomic modifications across multiple players' data using transactions. Either all changes succeed, or none do, crucial for maintaining data consistency in operations like trading. ```lua store:txAsync({player1, player2}, function(state) local item = table.remove(state[player1].inventory, 1) if not item then return false -- Abort the transaction end table.insert(state[player2].inventory, item) return true end) ``` -------------------------------- ### Lyra Development Mode Logging Source: https://paradoxum-games.github.io/lyra/docs/advanced/debugging Configures Lyra's logging behavior based on whether the game is running in a Studio environment. In Studio, all logs are shown; in production, only errors and fatal errors are logged. ```lua local RunService = game:GetService("RunService") local function createLogger() if RunService:IsStudio() then -- Show all logs in Studio return function(message) print(`[Lyra][{message.level}] {message.message}`) if message.context then print("Context:", message.context) end end else -- Only show errors in production return function(message) if message.level == "error" or message.level == "fatal" then warn(`[Lyra] {message.message}`) end end end end local store = Lyra.createPlayerStore({ logCallback = createLogger(), }) ``` -------------------------------- ### Update Player Coins (External State First) Source: https://paradoxum-games.github.io/lyra/docs/advanced/state-management This Lua function demonstrates an approach where external state is updated before flushing changes to Lyra. This pattern is not recommended as it can lead to data inconsistencies if Lyra updates fail. ```lua -- External state is the primary source of truth function giveCoins(player, amount) -- Update external state first gameState.players[player.UserId].coins += amount -- Then flush to Lyra as a secondary step store:updateAsync(player.UserId, function(data) data.coins = gameState.players[player.UserId].coins return true end) end ``` -------------------------------- ### Update Persistent Player Data with Lyra Source: https://paradoxum-games.github.io/lyra/docs/advanced/state-management This Lua snippet illustrates using Lyra to manage persistent player data, such as quest progress. Ephemeral game state can be handled separately by other state management libraries. ```lua -- Lyra handles persistent data store:updateAsync(player.UserId, function(data) data.questProgress.questId = 5 data.questProgress.stepsCompleted += 1 return true end) -- Game systems can track active state separately gameState.activeQuests[player.UserId] = { questId = 5, timeRemaining = 600, location = workspace.QuestLocations.Cave } ``` -------------------------------- ### Modifying Player Data with Lyra Update Functions Source: https://paradoxum-games.github.io/lyra/docs/getting-started This Lua code illustrates how to modify player data safely using Lyra's updateAsync method. It accepts a function that receives the current data and returns a boolean indicating success. This ensures data integrity by preventing direct manipulation. ```lua -- 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) ``` -------------------------------- ### Lyra Data Validation Schema Definition Source: https://paradoxum-games.github.io/lyra/docs/core-concepts Defines a data schema using 't' (Runtime Typechecker for Roblox) when creating a player store. Lyra enforces this schema on all operations to prevent invalid data from being saved. ```lua local store = Lyra.createPlayerStore({ name = "PlayerData", template = { coins = 0, inventory = {}, }, schema = t.strictInterface({ coins = t.number, inventory = t.table, }), }) ``` -------------------------------- ### Conditional Data Updates in Lyra Source: https://paradoxum-games.github.io/lyra/docs/core-concepts Performs atomic data updates using a provided function. The update only commits if the function returns true, ensuring data consistency. This pattern prevents partial changes. ```lua 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) ``` -------------------------------- ### Update Player Coins (Lyra as Source of Truth) Source: https://paradoxum-games.github.io/lyra/docs/advanced/state-management This recommended Lua pattern shows updating Lyra directly as the source of truth. Other systems can then react to these changes via callbacks, ensuring data integrity and atomicity. ```lua -- Lyra is the primary source of truth function giveCoins(player, amount) -- Update Lyra first store:updateAsync(player.UserId, function(data) data.coins += amount return true end) -- Other systems can derive from Lyra through changedCallbacks end ``` -------------------------------- ### Handle Non-Persistent State Separately Source: https://paradoxum-games.github.io/lyra/docs/advanced/state-management This Lua code shows how to manage ephemeral game state (like round information) in a separate variable, while using Lyra for persistent player data (rounds completed, total score). ```lua -- State that doesn't need persistence local gameState = { currentRound = 1, roundStartTime = os.time(), activePlayers = {}, } -- Player data that needs persistence uses Lyra function playerCompletedRound(player) local score = gameState.roundScores[player.UserId] or 0 store:updateAsync(player.UserId, function(data) data.roundsCompleted += 1 data.totalScore += score return true end) end ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.