About
Replicate is a lightweight data replication library for Roblox that allows for easy synchronization of data between the server and clients, primarily from server to client. It provides a simple API for replicating tables, arrays, and primitive values.
Why?
I needed a way to automatically handle the replication of player data from the server to the client; specifically things like user settings, inventory items, and statistics (kills, deaths, currency, ex...). There are many public data replication modules that I could use, however, many have issues that I wanted to solve.
Bloat
Direct Data Modification
Most of the public modules simply clone the data you provide to their constructors, meaning if a player bought an item you would need to subtract the price from their saved data and replicated data, then add the item to their replicated data and saved data. Replicate solves this by allowing a Replicate to be created using reference data, for example, if you load a player's data profile when they join and then pass the data to Replicate, any changes you make to the Replicate will also apply to the data profile.
This works really well with data modules such as [ProfileStore]:
local DATA = {
fruit = { },
money = 0,
}
local fruitPath = ValuePath("fruit")
local moneyPath = ValuePath("money")
local playerData = { }
local function playerAdded(player: Player)
local loadedProfile = ProfileStore:StartSessionAsync(player.UserId)
local playerReplicate = Replicate.Server.new(player, loadedProfile.Data, {
SourceMode = "reference"
})
-- some money for joining
-- we only have to make the change to the replicate
playerReplicate:Increment(moneyPath, 100)
print(loadedProfile.Data.money) --> 100
print(playerReplicate.Data.money) --> 100
playerReplicate:StartReplicating()
playerData[player] = {
profile = loadedProfile,
replicate = playerReplicate,
}
end
local function playerRemoving(player: Player)
local playerData = playerData[player]
playerData.profile:EndSession()
playerData.replicate:Destroy()
end
This functionality actually exists between [ProfileStore] and [Replica]. I needed more than that though, I needed a way to set session only data.
Temporary Data
"Temporary" (or session-only data) is a feature available to Replicates using the reference source mode. Why is this needed? Sometimes you want to add items to a player's inventory without it saving to their permanent data. An example of this would be giving players with Roblox Premium a special item. You don't want to save it to their permanent data because if they unsubscribe, they would still have them item. I wanted the temporary data to be indistinguishable from regular data.
local function doesPlayerHaveItem(player: Player, item: string)
local playerReplicate = playerData[player].replicate
return playerReplicate:ArrayFind(fruitPath, item) ~= nil
end
local function givePlayerPremiumItem(player: Player, item: string)
local playerReplicate = playerData[player].replicate
if not doesPlayerHaveItem(player, item) then
playerReplicate:ArrayInsert(fruitPath, item, true)
end
end
local player = Players.SurNautica
givePlayerPremiumItem(player, "apple")
-- despite the item being added as temporary, it will still appear
-- in the replicate using replicate.Data, replicate:GetValue(), or replicate:ArrayFind()
print(doesPlayerHaveItem(player, "apple")) --> true
-- however, if we check the profile data, it wont be there
local hasItem = table.find(playerData[player].profile.Data.fruit, "apple") ~= nil
print(hasItem) --> false