Replicated values#
A replicated value is a value the server sets and clients read, with a signal when it changes, and no remote to set up. It is for game state that is not a property of anything: the round, the timer, the score of each team, a player's own coins.
One value for everyone#
A round timer is one value every player reads. The server counts it down, and each client's HUD shows it:
-- server
local replicated = require("@moud/replicated")
local round = replicated.value("round", { phase = "waiting", seconds = 0 })
local function countdown(phase, seconds)
for left = seconds, 1, -1 do
round:set({ phase = phase, seconds = left })
task.wait(1)
end
end
task.spawn(function()
while true do
countdown("intermission", 15)
countdown("playing", 120)
end
end)-- client
local replicated = require("@moud/replicated")
local hud = game.world:add("ScreenGui", { name = "RoundHud" })
local label = hud:add("TextLabel", {
position = udim2(0.5, -80, 0, 12),
size = udim2(0, 160, 0, 28),
textColor = color(1, 1, 1),
backgroundTransparency = 1,
})
local round = replicated.value("round")
local function show(state)
label.text = string.format("%s %d:%02d", state.phase, state.seconds // 60, state.seconds % 60)
end
round.changed:connect(show)
if round.loaded then
show(round:get())
end- The name is the value's identity. The server and every client that asks for
"round"get the same one. - The second argument is the starting value, read on the server.
setis server only. It sends the new value to every client and fireschangedon the server and on each client with the new and the old value.getis the value now. On a client it is nil until the first answer arrives;loadedturns true then, andchangedfires for it. A client that joins halfway through a round gets the value the server holds, which is why the HUD readsloadedonce as well as connecting tochanged.
One value per player#
Coins are each player's own. Here the server loads them from a store, adds to them, and each player's HUD shows only their own:
-- server
local replicated = require("@moud/replicated")
local coins = replicated.perPlayer("coins", 0)
local saves = store("coins")
game.players.joined:connect(function(player)
coins:set(player, saves:get(player.id) or 0)
end)
local function give(player: Player, amount: number)
coins:set(player, saves:increment(player.id, amount))
end-- client
local replicated = require("@moud/replicated")
local hud = game.world:add("ScreenGui", { name = "CoinHud" })
local label = hud:add("TextLabel", {
position = udim2(1, -136, 0, 12),
size = udim2(0, 120, 0, 28),
textColor = color(1, 0.85, 0.3),
backgroundTransparency = 1,
})
local coins = replicated.perPlayer("coins")
coins.changed:connect(function(amount)
label.text = amount .. " coins"
end)- On the server
set(player, value)andget(player)take the player. A player who was never set reads the starting value. - Each player is only sent their own value, so one player's coins never reach another player's
client. A client reads its own value with
get(). - A player's values are forgotten when they leave, and may already be gone by the time your own
leavinghandler runs. Save as the value changes, asgivedoes withincrement.
What may be in one#
A value crosses the boundary like a remote's argument: numbers, text, booleans, vectors, frames, colours, instances, and lists or text-keyed tables of those. See What may cross.
Setting a table sends the whole table again, and changed fires every time a table is set, since the
old and the new are different tables. A value that is the same number or text as before still goes
out but does not fire changed.
The remote it uses#
The first require on the server adds a Remote named ReplicatedValues under game.world, and
clients read every value through it. Leave it where it is.
Require the module from a server script that runs at start, so the remote exists before the first player's client asks for it.
For a value that belongs to an instance, use a value instance or an attribute instead; those replicate with the tree. See Shared state.
