Although the API is lengthy, most of it are just variations of mutators and listeners. For StreamingEnabled-like implementations you’ll need to use the Replica:ReplicateFor() and Replica:DestroyFor() server-side methods.
The functionality is straightforward - From a client’s perspective, the same replica can be created, destroyed, created again - the server decides whether the replica is loaded on any particular client.
The only difference from real StreamingEnabled is that you have to tell ReplicaService when to replicate and destroy Replicas when the player enters a region yourself. That being said… Don’t try to reinvent StreamingEnabled - ProfileService is going to be better for map chunks and finite “dimensions” (like MeepCity, AdoptMe) the player is teleported to.
Saw this thread and instantly started looking for a tutorial from you. I’ll most likely start using this after seeing a tutorial or two, this sounds like something I would need for a project I’m currently working on.
you will need a few modules server-side and client-side to run ReplicaService. ReplicaController is the main client-side module. If you miss any modules, the system will not run and will let you know about missing dependencies.
You may group these modules into folders as dependancies will be searched for recursively inside the entirety of ReplicatedStorage and ServerScriptService.
Hi I’m confused why ListenToChange is only available on client, I want to use it on server when SetValue is called as well as I want to generalise what I’m calling on the client to the server, here is my use-case: on the client
ReplicaController.ReplicaOfClassCreated("PlayerProfile", function(replica)
local data = replica.Data;
local function updateCash(newCash: number)
activeLobbyManager.store:dispatch(UpdateCash(newCash));
end;
local function updateOwned(newOwned)
activeLobbyManager.store:dispatch(UpdateOwned(newOwned));
end;
updateCash(data.cash);
updateOwned(data.owned);
replica:ListenToChange("cash", updateCash);
replica:ListenToChange("owned", updateOwned);
end);
I want the server to recognise the calls to ListenToChange to dispatch to the store on the server as well. (The server would just take the stuff in the body of the function since replica of class created cant be used on server.)
I decided to opt out server-side replica change listeners because a lot of the time server states are going to be passive / have no rendering hooks for GUI’s & parts. Additionally, it was designed to work with ProfileService which accepts direct writing to the table instead of using setter functions - you’re supposed to wrap Profile.Data with a Replica when using them together.
I also though that object.Replica:ListenToChange() would look pretty weird instead of something like object.CoinsChanged:Connect() on the server-side.
However, the overhead of checking for listeners might be negligible, so I’ll look into it. I would appreciate more examples of use cases where the server would need lots of change listening. I’ll try to evaluate that overhead and make a decision quickly.
I would assume that object.CoinsChanged:Connect() would require you to fire that event consecutively every time you change the data in ProfileService as from memory I believe there is no event that detects change in data on ProfileService that you can listen to. object.Replica:ListenToChange() does look kinda weird, however it can be a function call all based on preference:
function activeLobbyManager:hook(replica)
-- the body of the ReplicaController.ReplicaOfClassCreated listener mentioned above
end;
and then the server and client would just plug into that function when created. This would allow really easy management on server & client especially if you want to store player data in Rodux as you don’t have to pass the player data argument everytime as Rodux has more general uses, I can include player data & i can include other state stuff like managing UI.
This is my main use case, I can’t think of many other examples other than Rodux (unless you have another state management module). However, you could probably incorporate other calls to specific modules.
However, take the example in the other post I made, lets say in updateOwned I wanted to update it to Rodux store and imagine I wanted to call a module or function only available where the listeners are located, in my case, lobby manager. Imagine I wanted to fire a function or module only exclusive inside that specific module, this would be another use case other than Rodux.
Another problem with Replicas is that they usually are a clone of select members of a custom object (An object will have members that can’t or shouldn’t be replicated) and in many cases accessing data would be desired by indexing object.Value (Remember that custom objects also usually have methods as members!) instead of object.Replica.Data.Value. In other words, ReplicaService breaks the single source of truth paradigm in practical implementations and, in my opinion, can lead to nasty coding patterns when used as a signal provider server-side - I’m influenced by the fact that these features are something my future team would use.
If you’d still want this functionality, I could probably write a clean enough wrapper for the server-side to enable listeners for Replicas?
Just to be clear, my proposed alternative is to wrap replica mutator calls inside setter methods that also trigger signals created by the developer.
You’ll need to update the ReplicaService module to the latest version as the Replica class table has been publicly exposed to make this experimental module work.
I recommend keeping your Replica.Data tables as flat as possible (fewer tables inside tables) - if your tables become too nested, you can break them down into several replicas by passing references to the individual tables. This recommendation is purely for the sake of clean code.
It would be nice if we could place the files for this service wherever we like in our folder organization instead of the top level as your setup instructions say is required, is this possible?
You may add them to folders that are in the respective game containers - the requires use recursive search in ReplicatedStorage and ServerScriptService.
[12/16/2020] - IMPORTANT BUG FIX - Update ReplicaService and ReplicaController modules from GitHub or Roblox library!
Fixed a bug where both ReplicaService and ReplicaController would fail to populate the Replica.Children table with children replicas. Not updating your modules may result in failure to find expected children in replicas and memory leaks.
Check out the updated Replica Guarantees section in the official documentation!