ReplciatedRegistry2 is the successor to ReplicatedRegistry which has a better designed API, more flexibility and increased convenience and transparency.
It is a single module with 0 dependencies, making it very simple to insert and use in your games.
Some examples
Simple ProfileStore Example
--server
local server = ReplicatedRegistry.server
server.set_remote_instances(...)
local ProfileTemplate = {
Coins = 0,
Level = 1,
Inventory = {}
}
local ProfileStore = ProfileService.GetProfileStore(
"PlayerData",
ProfileTemplate
)
local Profiles = {}
Players.PlayerAdded:Connect(function(player)
local profile = ProfileStore:LoadProfileAsync("Player_" .. player.UserId)
if profile ~= nil then
profile:AddUserId(player.UserId)
profile:Reconcile()
profile:ListenToRelease(function()
Profiles[player] = nil
server.deregister(player.UserId)
player:Kick("Profile released")
end)
if player:IsDescendantOf(Players) then
Profiles[player] = profile
server.register(
player.UserId,
profile.Data,
ReplicatedRegistry.replication_filters.no_recieve(true)
)
else
profile:Release()
end
else
player:Kick("Failed to load data")
end
end)
Players.PlayerRemoving:Connect(function(player)
local profile = Profiles[player]
if profile ~= nil then
profile:Release()
Profiles[player] = nil
server.deregister(player.UserId)
end
end)
local function GetProfile(player)
return Profiles[player]
end
task.wait(5)
for _, player in Players:GetPlayers() do
local proxy = reg.server.view_as_proxy(player.UserId)
proxy.incr("Coins") (20) -- This also updates the data stored in ProfileStore since it keeps a reference
proxy.replicate {player}
end
--client
local client = ReplicatedRegistry.client
client.set_remote_instances(...)
local my_data = client.view(game.Players.LocalPlayer.UserId)
print(my_data.Coins) -- 20
Added a _auto_commit: boolean = true parameter to server.to_clients(), server.to_all_clients() and client.to_server(). This specifies if the aformentioned functions should call ReplicatedRegistry.commit_changes() automatically or not.
Changed RegistreeInterface_Server.replicate() to accept an array of Players as the 1st argument instead of only 1 player.
Nope, all it does is generate TableChanges which are deltas for tables to be sent over the network. You can make it buffered by calling ReplicatedRegistry.set_change_serde()
Added ReplicatedRegistry.meta.switch_signal_lib(s: typeof(Signal)), keep in mind the new signal library has to have the same structure as the one used by ReplicatedRegistry, which is 2 functions: connect: <T...>(tbl: {(T...) -> ()}, item: (T...) -> ()) -> ScriptConnection fire: <T...>(tbl: {(T...) -> ()}, ...: T...) -> ()
Unfortunately using a regular signal library will not work
Added the module as a Wally package, @athar-adv/replicated-registry
Changed customEvent arguments in replicator functions such as client.to_server() and server.to_clients() to _sender: Sender? which is a callback you pass that will get called to send the changes.
Removed the ReplicatedRegistry.set_change_serde() api as it is no longer necessary because you can just wrap a serde around the sender functions you pass
Added set_remote_callbacks() to client and server (kept set_remote_instances()
Removed server.to_all_clients() due to the new sender callbacks being implemented, instead you can just pass Players:GetPlayers() into server.to_clients()
Its alot simpler (not only to use but also the sourxe code itself) and has 0 dependencies
It doesnt do state management out of the box, pure table replication
It uses registries instead of oop so the syntax is alot simpler
Idk if Replica has this but ReplicatedRegistry2 allows clients to make modifications to the registry with server-authoritive rules, like being able to modify their own settings but not anything else for example (this is via Filters, callbacks.on_recieve_callback, etc)
Middleware isnt implemented out of the box and the way you implement it is via callbacks so its extremely customisable, for example you can pass a Sender callback that serdes TableChanges into buffers before sending and vice versa for ConnectReciever
You arent forced into using a proxy, the default option for table replication is just pure tables which will be diffed with an older copy to generate deltas
Couldnt name more but theres probably more :V U should check the docs to see examples of what kinda applications this module easily integrates into
Wdym by this btw, its pretty explicit
For example on the server you call server.set_remote_instances() to implement middleware as RemoteEvents and RemoteFunctions, then server.register() to register your keys, then either server.view_as_proxy() to view it as a RegistreeInterface to make replications queue per change instead of diff, or if you want replications to use deltas from diffs you can just call server.to_clients() with the _changes parameter passed as nil
I’ve ran out of time to see if implementing this would be better for our game. However, I love the fact its not proxied. I’ll definitely come back to this sometime in the future to have a proper look, thank you!
as for my question about the syntax looking weird, I think im just used to pascalcase and oop-style code, apologies.
Changed proxy methods set, get, and incr to accept an array of keys for the path instead of a vararg.
Added RegistreeInterface.key_changed() to detect when a key change is done by the opposite context, aka when you call .set on the same context as the proxy, this callback isnt fired.