An alternative that actually serializes and deserializes with same functionality as replica: RemoteTable-Light
I had an interesting idea to improve WriteLibs
Add this under line 131 in ReplicaServer:
local WriteFunctionInjectionCache: {[ModuleScript]: boolean} = {}
And add this on line 297 in ReplicaServer:
if not WriteFunctionInjectionCache[params.WriteLib] then
WriteFunctionInjectionCache[params.WriteLib] = true
local loadedWriteLib = require(params.WriteLib)
for name, func in loadedWriteLib do
Replica[name] = function(self, ...)
return Replica.Write(self, name, ...)
end
end
end
Created replica type:
type NewReplica = Replica.Replica & typeof(require(WriteLib))
You can now use WriteLib functions directly:
(
replica is type casted to NewReplica)
Is there any reason I shouldn’t do this? It seems to work completely fine.
Old method
Add this on line 319 in ReplicaServer:
local loadedWriteLib = require(params.WriteLib)
for name, func in loadedWriteLib do
self[name] = function(_, ...)
return self:Write(name, ...)
end
end
The new method injects the function directly into the module, instead of the created metatable, so it should use less memory.
Hey that’s pretty nice! The changes are pretty simple as well ![]()
I actually have a personal Replica branch I’m currently experimenting with serialised WriteLibs using my Sera serdes library - it extends WriteLibs to support tables with Fn & Schema pairs like so:
This implementation sends one buffer and no other arguments over a remote event whenever a WriteLib function is invoked. The Fn is the same WriteLib function format, only the user has to put all of their arguments as members in the second table argument and it has to match the data schema.
It makes it a little hard to add WriteLib replica type support when it’s defined like that…
Hey @vialucid, glad you found the Replica module helpful! Regarding your question about TableInsert and string indexes, I think what’s happening is that TableInsert requires numerical indices because it’s designed to insert at a specific position in the table.
For your use case, you could try using Replica:Set with a nested table as @unknown suggested. This way, you can still maintain your Data system structure while avoiding numerical indices.
As for saving changes, make sure that your Replica module is properly synced with the ProfileStore. You might need to revisit your Data system setup and ensure that both modules are communicating correctly.
Lastly, I totally get where you’re coming from about nested tables - they can be a real pain! But sometimes it’s just the most straightforward way to organize complex data structures
Hey, do I understand it right, that ReplicaClient.OnNew triggers for every client and it can be exploited because if some hacker catch another player’s replica, he can exchange data with it freely?
I mean that is not a thing with default RemoteEvents which fire only for specific players. It bothers me as I am concerned about security. If I am mistaken sorry.
Is it intentional for any OnSet hooks to not fire when modifying values with SetValues? If it is, then why? It just makes things more verbose having to listen to OnChange and manually check paths just so I could receive batch updates.
yo can you tell me is it possible to update leaderstats when I change data using :Set for example:
replica:Set({
“Coins”
}, playerData.Coins + 100)
you have to update it separately. Like if you have it under the leaderstats folder
you would do player.leaderstats.Coins.Value = playerData.Coins
Whats the correct way to replicate a reference to a instance, without the client thinking its nil from either not being loaded yet or being streamed out?
Best way is not using a replicated table to replicate instances.
Todo:
- Add package to Wally
- Finish docs
What I’ve done is first setting some attributes for the instance on the server:
-- Have a global counter that increases every new instance you need to replicate to use as a unique id
local replicatedInstCounter = 0
...
inst:SetAttribute("NumDescendants", #inst:GetDescendants())
inst:SetAttribute("HasPrimaryPart", inst:IsA("Model") and inst.PrimaryPart ~= nil)
replicatedInstCounter += 1
inst:SetAttribute("ReplicatedId", replicatedInstCounter)
This is important part so that the client can wait for it to load in:
inst:AddTag("ReplicatedInstance")
Then on the client:
CollectionService:GetInstanceAddedSignal("ReplicatedInstance"):Connect(function(inst)
-- Wait for "NumDescendants" descendants to load in (or 0 if it is not set)
-- Wait for inst.PrimaryPart if it has "HasPrimaryPart" attribute set
-- Cache it in a dictionary like:
resolvedReplicatedInstances[inst:GetAttribute("ReplicatedId")] = inst
end)
Now when you send just the ReplicatedId from the server, you can resolve it from your resolvedReplicatedInstances dictionary:
remote.OnClientEvent:Connect(function(replicatedId)
-- First wait for it to be resolved in the resolvedNetInstances dictionary
-- Now you can convert the id to a fully streamed-in instance:
local inst = resolvedReplicatedInstances[replicatedId]
end)
My version of this (warning: it has not been cleaned up for public use):
NetInstance.rbxm (7.1 KB)
I’ve created a Replica inspired library called Plums: GitHub - wrello/Plums: Replicate table changes from server to client in Roblox · GitHub that has full documentation. Note: It has not been thorougly tested in a production environment, so it is currently in beta. But it’s definitely usable and adds some things Replica is missing.
Hello, currently I am doing this to give units to a player:
function module.AddUnit(player: Player, unit: PlayerDataTemplate.Unit)
local replica = playerSessions[player].Replica
replica:Set({"Inventory", "Units", HttpService:GenerateGUID(false)}, table.clone(unit))
end
On the client side:
function module.OnDataChanged(path: {string}, listener: (newValue: any, oldValue: any) -> ())
playerDataReplica:OnSet(path, listener)
end
PlayerDataController.OnDataChanged({"Inventory", "Units"}, function(newValue, oldValue)
print(newValue)
print(oldValue)
end)
I am unable to listen for any changes to the Units dictionary as only the key and value is being set instead of the dictionary itself. Is there a proper way to listen for changes inside a dictionary? Or am I supposed to set the whole dictionary into a new one?
Thanks in advance!
quite a late reply from me as i have gotten quite curious as well, but i think u are listening to the whole “Units” table and not individual unit (set as guid i guess) it would not listen for anything under the “Units” as it would only proc the listener if you updated the whole “Units” table (doing this is quite inefficient)
No worries! Currently I am connecting listeners that handle when the Replica changes (I found out that you can use the Replica:OnChange() function over OnSet()).
local function onDataChanged(action: string, path: {string}, newValue: any, oldValue: any?)
if action ~= "Set" then return end
if path[1] ~= "Inventory" then return end
if path[2] == "Currencies" then onCurrencyChanged(path[3], newValue, oldValue)
elseif path[2] == "Items" then onItemChanged(path[3], newValue, oldValue)
elseif path[2] == "Units" then onUnitChanged(path, newValue, oldValue) end
end
This is how my listener for player inventory looks like at the moment. Not sure if there are better ways.
This looks pretty cool, I’ll check it out in a simple side project I am making
Hello, the link to the Roblox library module does not seem to work.


