twistedsignal/replication

Typed reactive server-to-client replication for Roblox

replication

Typed, reactive server-to-client player state for Roblox. State lives only for the current server session. This package does not use DataStoreService, ProfileStore, or any other persistence layer.

This repository is based on twistedsignal/data. It keeps nested typed values, reactive UI integration, change callbacks, and selective replication. All profile loading, saving, session locking, offline profiles, and global profile messages have been removed.

Install

pesde add twistedsignal/replication

Create shared replication state

Call the package once from a shared module:

local replication = require(path.to.Replication)({
	template = {
		coins = 0,
		inventory = {} :: { string },
		settings = { musicEnabled = true },
	},
})

return replication

Each player gets a deep copy of the template when they join. The copy is discarded when they leave.

-- Server
local state = replication.server:waitForData(player)
state.coins(function(previous)
	return previous + 10
end)
state.inventory.insertArray("Sword")
-- Client
print(replication.client.coins())
replication.client.settings.musicEnabled(false)

Server writes replicate to that player's client by default. Pass false as the second argument to a write, or the third argument to insertArray, to keep a change on the server.

Value API

All values support reads, writes, updater functions, .observable, and changed(callback).

Array values add:

  • insertArray(item, position?, shouldReplicate?)
  • removeArray(position?, shouldReplicate?)
  • onArrayInserted(callback)
  • onArrayRemoved(callback)

Dictionary values add onKeyAdded(callback) and onKeyRemoved(callback). Callback registration returns a cleanup function.

The server service provides waitForData, reset, onPlayerInit, and addPlayerRemovingCallback. reset(player) replaces the player's current session state with a new copy of the template. It does not touch persistent data.

Reactive UI

Every node is callable like ui.value() and participates in twistedsignal/ui dependency tracking:

local ui = require(path.to.UI)

local labelText = ui.derive(function()
	return `Coins: {replication.client.coins()}`
end)

Credits

Based on twistedsignal/data and leifstout/dataServiceTyped. Licensed under MIT.