Replica - Server to client state replication (Module)

“Replica” by loleris

(Successor module to ReplicaService)

[GitHub repo]

(WARNING: Full documentation is not done yet - Replica functionality is similar to ReplicaService, but there were changes to some member and method names. You can also find short API docs inside the Replica scripts!)

Read documentation here: (NOT FINISHED)
Replica wiki (Click me)

Get the module here:
Roblox library (Click me)

(If you make a tutorial for this module, please contact me and I might share the link here!)

:moneybag::moneybag::moneybag:
Consider donating R$ to the creator of ProfileStore (Click here) if you find this resource helpful!


Replica is a Roblox server to client state replication solution which lets the developer subscribe certain players to certain states.

Individual states in the Replica module are called “replicas”. Replicas can only be created and changed server-side, both server and client can connect clean-up tasks for the moment of replica destruction, state changes can trigger listeners on the client-side.

Changes from ReplicaService

Replica is a successor to ReplicaService - you will find that these modules are very similar, but Replica has much shorter member and method names, yield safety in signal listeners, luau types for autocompletion, Roblox streaming support with Replica:BindToInstance() and several minor performance improvements.

  • There is no longer a Replication argument in the Replica constructor - all new replicas are not replicated by default until Replica:Replicate() or Replica:Subscribe(player) are called or the new replica is parented to an already replicated replica.

  • The Parent argument in the Replica constructor has been removed - You will have to use Replica:SetParent() after creating a replica instead.

  • For listening to Replica destruction, instead of Replica:AddCleanupTask() you will now have to use Replica.Maid:Add() - these are functionally the same.

Basic example

Server-side

local Replica = require(game.ServerScriptService.ReplicaServer)

local replica = Replica.New({
    Token = Replica.Token("GlobalData"),
    Data = { -- Passed table reference will be used
        Score = 0,
        Nested = {
            Value = false,
        },
    },
})

replica:Replicate()

task.spawn(function()
    while true do
        replica:Set({"Score"}, replica.Data.Score + 100)
        task.wait(1)
    end
end)

replica:Set({"Nested", "Value"}, true)

Client-side

local Replica = require(game.ReplicatedStorage.ReplicaClient)

Replica.OnNew("GlobalData", function(replica)

    print(`Replica received client-side! Data:`, replica.Data)

    replica:OnSet({"Score"}, function(new_value, old_value)
        print(`Score has changed from {old_value} to {new_value}`)
    end)

end)

Replica.RequestData() -- Must be called once anywhere in game code client-side

Other resources:

Check out ProfileStore - DataStore wrapper for handling player data

98 Likes

Consider donating R$ to the creator of Replica if you find this resource helpful!

Your support helps me make more epic open source code :sunglasses: :+1:
Of course, Replica is completely free to use! :eyes:

10 Likes

Loleris classic, helping roblox be less garbage as usual!

But good question, when is roblox going to remake their engine? And maybe switch to a language that isnt older then most of its developers… twofold…

Or add basic features like actual decent godrays, functionality in their server to client communication so something like this wouldnt have to be created.

I mean there is literally modules for networking bro, NETWORKING… because firing 2 remote events at once is a little to hard for poor old buddy in the back.

Sorry for my rant. But im so glad you made this, replica service is already crazy useful but this?

I mean come on, its like you asked god for instructions on how to make this, its like serenity met with sigma and created Replica.

6 Likes

Looks good! :fire: It will be great to use Replica with ProfileStore.

3 Likes

Is there any particular reason why some signals were combined into the OnChange signal? It just seems a lot less convenient compared to ReplicaService.

Can’t wait for full documentation to come out. The instance binding seems pretty interesting

3 Likes

How could we use this with ProfileService? I already use ReplicaService + ProfileService and I was wondering how I could switch out ReplicaService for the new version!

It’s probably because having 5-20 events merged into one is better for memory and readability of the source code. If I misunderstood, please correct me!

4 Likes

Yeah there were changes to the built-in mutators, but you can still do everything you previously could. These changes were made based on my personal use of the module and also in favor of trying to decrease the memory footprint of Replica.

For example Replica:ArraySet() was just a simple set with one argument moved outside of “path”.

4 Likes

Hey, @loleris! Thank you so much for releasing this module. We really appreciate your work and effort. Looking at the source code for the module, it’s a huge improvement to the old ReplicaService, and I’m really happy for that.

So far it seems to be working just fine. However, I may ask if there’s a way to listen to the data changing on the server. I know it sounds redundant and probably not necessary, but I can assure you if it will have no impact on the performance, then it would be a huge “optional” addition as part of the Replica module.

image

4 Likes

my solutions are:

  1. Make a class / service that contains the replica itself in the server, but only opened itself with methods that also fires BindableEvent or signals to outside.
  2. Make your own dictionary implementation with signals (over engineered but it works for me)

kinda self explanatory from the title of post, there’s no methods for server to server.

3 Likes

Hey, thanks for the follow-up. I’ll fork my own signal then. Thanks so much.

4 Likes

Another Hot And Fire :fire: Release By loleris . This is awesome .

4 Likes

if Roblox 1 is so good, then why didn’t they make Roblox 2?

1 Like

Is the Replica.OnNew method has be set up early before calling RequestData like the original replica service? or can we connect to it later on?

1 Like

Replica.OnNew can be called anytime - if it’s called after replicas are received client-side it will be triggered with existing replicas of the specified token immediately after calling.

2 Likes

Could I send client to server for Character Replication?

2 Likes

Hi Loleris/somebody, I am currently doing a save slot system, And i was wondering, if i need tochange the replica token to another string like… Slot1… Slot2, because i am doing this with ProfileService

1 Like

You can create as many replicas with the same token.
and you can just pass in a unique identifier on the Tags table for each replica when you create one.
so you can differentiate them easily.

on the replice.OnNew() if there are multiple replica with the same token it will be called multiple times passing each replica on the arguments given from the method.

2 Likes

Are you still including or adding the NewReplicaSignal? I heavily rely on this. I was about to port all of my codebase to the new Replica module. I don’t wanna write OnNew callbacks everytime I create a new replica token.

I have already made a system where I cache all of the replicas into 1 module for the client.

1 Like

If you’re not listening to specific tokens, then why make different tokens?

1 Like

my current scenario is:

I have tokens that are assigned to only 1 replica.
and tokens that assigned to multiple replica.

I have replicas that have unique token for each of them.
Such as:

  1. GameTimer
  2. GameState
  3. Teams

And I have multiple replica sharing a single token.
such as:

  1. PlayerDataStore
  2. Enemys
  3. Units (eg. soldier)

Since some of the replica have identical token
I assign a unique identifier inside the Tags to differentiate them.
so I can just use a single event such as NewReplicaSignal and have them sort into a dictionary based on their tags.

therefore, I can fetch them easily from a single module.
without even calling OnNew everytime i need to get a specific replica, of-course i have to make utility function just to check if they even exist on the dictionary, or an Observer function that calls a callback once that specific replica with the same token exist. But that besides the point.

I’m just having trouble to get a specific replica if the replica have same token as other replica’s. I don’t wanna waste memory connecting to OnNew everytime and checking if that replica has this specific tag. even then having to always set up a clean up once I don’t need the OnNew.

Anyway, If you have any better solution i’d really appreciate it!
Love the module! It is basically the backbone of my current project and I cannot do it without it.

1 Like