Replicate your states with ReplicaService! (Networking system)

I didn’t know that. Nice to know.

Is there any built-in function which detects when a replica is added on the server?

Is there a way I can detect when key changes in a dictionary? Similar to how ListenToNewKey works but just whenever a key is changed or created.

How do I replicate and set values in a nested table? I want to replicate and set values for “Lock”.

local test_replica = ReplicaService.NewReplica({
	ClassToken = ReplicaService.NewClassToken("TestReplica"),
	Data = {
		Chair = {
			Basil = 0,
			Farm = 2,
			NestedTable = {
				Lock = 3
			}
		}
	},
	Replication = "All",
})

Hi @loleris! I’ve been trying to add a listener to my replica on the client for changes made on the server, but I figured out that ListenToChange() only works with SetValue() and not with SetValues(). The only way I can listen to those changes now is by using ListenToRaw(), so I suppose this is not how it should work/it may be a bug.

how do I even make a listener for server… on your example it looks like I have to create 2 different Data I don’t understand.

1 Like

This is a god sent module, sad I didn’t swap my games over to this quicker. Very simple module but also allows lots of customizations for very specific usecases

Im not sure, but what I did is require ReplicaServiceListeners instead ReplicaService

Why does it take 1 second to update the value? Is that normal? My game updates the data very frequently, I think it will cause some issues in some scenarios but I didn’t face it yet, I was using only profileservices no replica and there is no delay when updating the data

function DataService:SetData(player,path : string,newDataValue)
	
	local PlayerProfile = self:GetData(player)
	local DataReplica = Replicas[player]
	if PlayerProfile and DataReplica then
	
			--PlayerProfile.Data[dataToSet] = newDataValue
			DataReplica:SetValue(path, newDataValue)
		
	end
end

Yeah apparently requiring it just injects it Lol thank you.

1 Like

Hello i dont understand this part of documentation very well

All .NewReplicaSignal and .ReplicaOfClassCreated() listeners should be connected before calling .RequestData()! - refrain from connecting listeners afterwards!

If your game has local scripts that may run later during gameplay and they will need to interact with replicas, you should create a centralized module that connects Replica creation listeners before .RequestData() and provides those local scripts with the replica references they need.

How to creae this module to give replica reference to local script created at a later point ?
I dont really understand how to move the replicaofclasscreated around
also is it possible to listentochange of a replica without directly putting it in replicaofclasscreated?
thank you

You can send the reference to the replica returned from those listeners via BindableEvent

How do i extract data from the server to the client?

ReplicaOfClassCreated doesn’t signal when using it on a tool’s client script, any solutions so that i can send data to the client?

I have come to rely on ReplicaService for all of my recent projects because it simplifies the server-client communication for data needing to be synchronous.

One request I would like to make for this service is some getter functions. Typing out replica.Data["Some Data"] can get tiresome afterwhile. I suggest adding functionality that allows you to do replica:get("Some Data") instead. If you are trying to retrieve a tag instead of data, you could pass a parameter to this function, or you could make two separate functions: replica:getData(...) and replica:getTag(...).

I imagine this change would be relatively easy to implement, and it would have no impact on existing code as this would be an additional interface.

On a complete separate note, I would like to post my solution here for client replica handling. I hope this helps others who have struggled trying to keep up with replicas created on the client.

local ReplicatedStorage = game:GetService("ReplicatedStorage")

local ReplicaController = require(ReplicatedStorage.ReplicaController)

local ReplicaHandler = {
	_replicas = {},
	_events = {
		ReplicaCreated = Instance.new("BindableEvent")
	}
}

function ReplicaHandler:_init()
	ReplicaController.NewReplicaSignal:Connect(function(replica)
		if self._replicas[replica.Class] == nil then
			self._replicas[replica.Class] = {}
		end
		
		self._replicas[replica.Class][replica.Id] = replica
		self._events.ReplicaCreated:Fire(replica.Id)
		
		replica:AddCleanupTask(function()
			self._replicas[replica.Class][replica.Id] = nil
		end)
	end)

	ReplicaController.RequestData()
end

function ReplicaHandler:onReplicaCreated(class, callback)
	local replicas = self._replicas[class]
	if replicas ~= nil then
		for replicaId, replica in pairs(replicas) do
			callback(replica)
		end
	end
	
	return self._events.ReplicaCreated.Event:Connect(function(replicaId)
		local replicas = self._replicas[class]
		if replicas ~= nil then
			callback(replicas[replicaId])
		end
	end)
end

function ReplicaHandler:waitForReplica(class)
	local replica = nil
	
	repeat
		local replicas = self._replicas[class]
		if replicas == nil then
			task.wait()
			continue
		end
		
		for replicaId, discoveredReplica in pairs(replicas) do
			replica = discoveredReplica
			break
		end
	until replica ~= nil
	
	return replica
end

ReplicaHandler:_init()

return ReplicaHandler
1 Like

Is it possible to stop listening to changes or new keys? I’d rather fully disconnect it rather than use an if statement to prevent it, if possible.

EDIT: After reading Evercyan’s post, I discovered that they can be disconnected like any other event. The documentation does describe it as a ScriptConnection, but that type is not a Roblox standard type and it is not documented.

I’ve recently come across this module, and I can’t see any major advantages of parenting over using a single Replica or creating separate ones besides maybe organization?

Not being able to yield in the listener functions is a major mistake. There is no intuitive understanding that this isn’t something you should do. I thought of the listeners like listeners through :Connect() on roblox events, where you can yield. Only after noticing the subtle inconsistencies of skipping remote event listeners did I discover this downfall. Please just make it automatically run the listeners on seperate threads so this isn’t an issue. I don’t see any reason why this is a problem, and if there is a good reason, it would be great if you could state it in the warning on your documentation site so people don’t take matters into their own hands and just change the module outright, which is what I’m doing.

1 Like

replicated data doesnt seem to work in guis when the player resets

What I do is I have a “ReplicaManager” module, which essentially stores every Replica whichever side of the network you’re on in a table. This way your LocalScripts can still interact with Replicas.