This document provides an overview of the data handling system implemented in the Altair project, based on the approach used in the Helios project.
The data handling system consists of two main components:
- ServerData - Manages server-side data, including player profiles and game-wide data
- ClientData - Manages client-side data and mirrors server data on the client
The system uses the following libraries:
- Reflex for state management
- ProfileService for data persistence
- Signal for event handling
- Promise for asynchronous operations
- Bridgenet2 for networking (indirectly through remote events)
The ServerData module (src/server/modules/ServerData.luau) manages server-side data. It has the following responsibilities:
- Loading player data from the datastore when a player joins
- Saving player data to the datastore when a player leaves
- Providing access to player data through a producer pattern
- Replicating player data changes to the client
- Managing game-wide data (e.g., server start time, active players)
- Providing access to game data through a producer pattern
- Replicating game data changes to all clients
The module sets up the following remote events and functions for communication with clients:
ReplicateStore- For replicating player data changesReplicateGameStore- For replicating game data changesGetPlayerData- For clients to get their player dataGetGameData- For clients to get game data
The ClientData module (src/client/modules/ClientData.luau) manages client-side data. It has the following responsibilities:
- Loading player data from the server
- Mirroring server-side player data
- Providing access to player data through a producer pattern
- Replicating player data changes to the server
- Loading game data from the server
- Mirroring server-side game data
- Providing access to game data through a producer pattern
- Replicating game data changes to the server
- Managing client-specific data (e.g., local settings)
- Providing access to client-specific data through a producer pattern
-- Get a player's profile
local profile = ServerData:GetPlayerProfile(player)
-- Wait for a player's profile to be loaded
local profileYielded = ServerData:WaitForPlayerProfile(player):expect()
-- Wait for a player's profile.producer to be loaded
ServerData:GetPlayerProducerAsync(player):andThen(function(producer)
-- Use producer
local coins = producer:getState().coins
print("Player has", coins, "coins")
-- Modify profile data
producer.addCoins(100)
end)
-- Access game data
local activePlayers = ServerData.gameProducer:getState().activePlayers
print("Active players:", activePlayers)
-- Modify game data
ServerData.gameProducer:setActivePlayers(10)-- Get player data
ClientData:GetPlayerProducerAsync():andThen(function(producer)
-- Use player data
local coins = producer:getState().coins
print("I have", coins, "coins")
-- Modify player data
producer.addCoins(100)
end)
-- Get game data
ClientData:GetGameProducerAsync():andThen(function(producer)
-- Use game data
local activePlayers = producer:getState().activePlayers
print("Active players:", activePlayers)
-- Cannot modify game data by client
end)
-- Access client-specific data [WIP]
local musicVolume = ClientData.clientProducer:getState().localSettings.musicVolume
print("Music volume:", musicVolume)
-- Modify client-specific data
ClientData.clientProducer.setLocalSetting("musicVolume", 0.8)- When a player joins, the server loads their data from the datastore
- The server creates a producer for the player's data
- The client requests the player's data from the server
- The client creates a producer for the player's data
- When the server or client modifies the data, the changes are replicated to the other side
- When a player leaves, the server saves their data to the datastore
- Secure actions (prefixed with "secure") cannot be replicated from the client to the server
- The server validates all data received from clients
- The server handles data persistence, ensuring data is saved properly
The ServerData module is implemented as a controller in the Altair project's module system. It has the following key components:
profiles- A table mapping players to their profilesgameProducer- A producer for game-wide dataplayerDataLoadedEvent- A signal fired when a player's data is loadedGetPlayerProfile- A function to get a player's profileWaitForPlayerProfile- A function to wait for a player's profile to be loadedGetPlayerProducerAsync- A function to get the player producer asynchronouslyGetGameProducerAsync- A function to get the game producer asynchronouslyPlayerAdded- A function called when a player joinsPlayerRemoving- A function called when a player leavesInit- A function called when the module is initialized
The ClientData module is implemented as a controller in the Altair project's module system. It has the following key components:
playerProducer- A producer for player datagameProducer- A producer for game dataclientProducer- A producer for client-specific dataisPlayerDataLoaded- A boolean indicating if player data is loadedisGameDataLoaded- A boolean indicating if game data is loadedplayerDataLoadedSignal- A signal fired when player data is loadedgameDataLoadedSignal- A signal fired when game data is loadedGetPlayerProducerAsync- A function to get the player producer asynchronouslyGetGameProducerAsync- A function to get the game producer asynchronouslyPlayerAdded- A function called when a player joinsInit- A function called when the module is initialized