[v.20] ReplicatedRegistry | Simple server-client & client-server synchronized table registry

[{…} → {…}] ReplicatedRegistry

ReplicatedRegistry.rbxm (8.6 KB)

(Even though ReplicatedRegistry doesn't have simple in the name, it is in fact part of the simple suite!)

ReplicatedRegistry is a module I made that you can very easily use to sync table changes between server and client (or vice versa).

It is a single module with 0 dependencies, unlike charm-sync or Replica, and it is very easy to use.

Documentation
  1. ReplicatedRegistry.SetTable(registerKey: any, tbl: T?, filter: ((sender: Player?, key: any, value: any, path: {any}) -> boolean)?) -> (T?, Registree<T>)

    • Registers the table into the module so that it is subject to replication signals from the other side (or deregisters a table so that it is no longer subject to replication signals from the other side, if tbl is passed as nil).

      If a filter is specified, if a specific change does not pass the filter it is rejected (aka when the filter returns false). (This is on a per key-value pair basis.)
      If the change should be accepted, the filter should return true.
      Note that if the change was sent from the server, sender is always nil.

  2. ReplicatedRegistry.GetTable(registerKey: any): Table?

    • Retrieves a registered table using its key, or nil if not found.

  3. ReplicatedRegistry.WaitForTable(registerKey: any, timeOut: number?): Table?

    • Waits timeOut or math.huge seconds until the table with the specified key is found, then that table is returned.

  4. ReplicatedRegistry.SendChanges(replicationMode: "ToClient"|"ToAllClients"|"ToServer", registerKey: any, player: Player?, unreliable: boolean?)

    • Sends all changes (since SendChanges/SetTable was last called) to the side specified by replicationMode.
      If replicationMode is “ToClient”, then the player argument is required.
      If unreliable is passed as true, then the function will replicate changes via the unreliable changed remote event instead of the normal one.

  5. ReplicatedRegistry.RequestTable(registerKey: any): Table?

    • A client-only function that requests the table associated with registerKey from the server. Returns nil if rejected, the requested table if else.

  6. ReplicatedRegistry.OnRecieve(registerKey: any, fn: (sender: Player?, tbl: Table) -> ()): () -> ()

    • Sets a callback function to be called when a replication signal for the registerKey is sent to this side.
      Returns a function to disconnect the callback.

  7. ReplicatedRegistry.SetOnRequest(fn: (player: Player, registerKey: any) -> boolean)

    • A server-side function to set the filter for ReplicatedRegistry.RequestTable calls.
      By default, this filter only accepts RequestTable requests if the key matches/is the player’s UserId.
      However, the purpose of this function is so you can change that.

  8. ReplicatedRegistry.GetFilter(nameToArgs: FilterList): Filter

    • Returns a composite filter containing all filters specified within nameToArgs.
      The returned filter can be used in ReplicatedRegistry.SetTable()
Examples

The following example demonstrates simple player data replication between clients and the server.

Server:

local ReplicatedRegistry = require(path.to.module)
local setTbl = ReplicatedRegistry.SetTable
local replicate = ReplicatedRegistry.SendChanges
local filters = ReplicatedRegistry.Filters

-- A filter that rejects all replication requests from the client
local norecv = filters.NoReceive(true)

game.Players.PlayerAdded:Connect(function(plr)
	local tbl = {
		JoinTime = os.time(),
		Kills = 0
	}
	setTbl(plr.UserId, tbl, norecv)
	
	tbl.Kills = 10
	replicate("ToClient", plr.UserId, plr)
end)

Client:

local player = game.Players.LocalPlayer

local ReplicatedRegistry = require(path.to.module)
local setTbl = ReplicatedRegistry.SetTable
local request = ReplicatedRegistry.RequestTable
local filter = ReplicatedRegistry.GetFilter {
   DontAcceptIfNil = true,
   RateLimit = 10
}

local tbl = setTbl(player.UserId, request(player.UserId), filter)
while task.wait(1) do
	print(tbl.Kills) -- 10
	print(tbl.JoinTime) -- Some big number
end

Look at how easy it is to set server → client data replication!

image

I wouldn’t even know where to begin to do this with Replica

ReplicatedRegistry is also FAR more optimized than the likes of Replica, ReplicaService and charm-sync as it does not attempt to do any state management, only replication of table changes.

Hope you enjoyed this resource, and happy coding!

11 Likes

Package Version 10:

  • Added ReplicatedRegistry.OnKeyChanged()

Package Version 15:

  • The module now uses --!nonstrict
  • Added more clear names
  • Removed the seperate dict tables for callbacks and values, combining it into 1 dict mapping register key to Registrees which contain all data (such as filters, the actual table reference, callbacks, etc)
  • Added InvokeRequestCallback (a callback to be called on the server when a client calls .RequestTable) and Registrees (Where all registered tables are stored) as members of the ReplicatedRegistry return table, the exposing of Registrees allows you to replicate multiple tables at once

Note that theres a good chance i broke something in this update so please, PLEASE let me know

Package Version 18:

  • Fixed traversePathAndSet which was broken for nested tables for a while (Why didnt anyone tell me about this :sob: )
  • .RequestTable() now returns an empty table if one was not returned by the server
1 Like