Replicate your states with ReplicaService! (Networking system)

Has anyone used this in conjunction with Roact? Thinking about diving into Roact on my next project and this might be a good fit?

2 Likes

I’ll need to ask just a bit of questions:

  • Can I not put this inside ReplicatedStorage?
  • This is just intended to update if something has changed but can we get it like ReplicaState:Get("State_ Name_Here")?
  • Is this just for values or is it for everything?
1 Like
  • You can put it elsewhere, you’ll just need to change the references. CTRL + F to find where ReplicatedStorage is located and just adjust it to be wherever you want to put it.
  • Yes, you can get things. If you check out the examples here you’ll see that you can get the value like
    print("TestReplica received! Value:", replica.Data.Value)
  • Everything (although there might be some limitations - I haven’t ran into any yet
1 Like

Why does Replica:ArraySet() require the index to already exist?

It would be nice if this were adjusted so that tables with specific indexes (even if they are numerical) can also be affected by the handy event of Replica:ListenToArraySet() since, as it stands, you can only insert, remove, or set pre-existing indexes.

I’ve said it before - but amazing module :slight_smile:

1 Like

The term “array” is not interchangeable with the terms “table” or “dictionary” - Arrays in lua MUST be numeric and have no gaps between element at index 1 all the way to index n.

Creating a table with numeric indexes that has gaps between those indexes and index 1 (e.g. UserIds as indexes) will make that table not replicate properly - It’s listed as a limitation in the documentation and is also why Replica:ArraySet() prevents you from setting indexes beyond existing ones. Consider using a dictionary with numbers converted to strings as indexes if you run into this problem.

In any case, the built-in array modifiers exist purely for sanity purposes and can be entirely replaced by Replica:SetValue() or Replica:Write().

2 Likes

Would it be Ideal to create a replica for each player?

since I want their Profile to only replicate to them

2 Likes

You assumption is correct - You can create as many Replicas as you like! Replicas themselves are passive when you’re not changing data or sending signals, so a great amount of replicas should not have a performance impact.

2 Likes

If I for loop the data inside of a replica in PostSimulation or Stepped will it throttle? since I use Roact and it renders my ui like Stepped so if it’s a no i’ll just have to find another way

1 Like

ReplicaService doesn’t drop any state updates even when you change the state rapidly (within reason), but it’s designed for event-triggered updates, not constant streams of data every frame - you should consider not using these kind of streams in your games due to them using lots of bandwidth and usually being redundant data, but if you have to then just use a RemoteEvent without anything fancy wrapping them.

3 Likes

I tried implementing this to Roact and it worked but the problem is that I have to wait atleast a second for the RequestData() to load in, is their a way to yield until the Replica is not nil?

2 Likes

Replica capturing is “event-based” - your codebase shouldn’t be yielding until a replica is received since you can simply include the code you want to run when you get the replica inside the .ReplicaOfClassCreated() callback function. To implement exactly what you asked for, though:

local RunService = game:GetService("RunService")
local Replica

ReplicaController.ReplicaOfClassCreated("TestReplica", function(replica)
   Replica = replica
end))

while Replica == nil do
   RunService.Heartbeat:Wait()
end

print("Replica received:", Replica:Identify())

It would really make more sense to just add the print into the function that handles the replica in .ReplicaOfClassCreated().

1 Like

For some weird reason I think this would have flaws but whatever.

Great project btw I hope to use this further on.

1 Like

does it detect when a table value has been changed? sorry for the edit but it does not detect changes but If any value or table was changed inside the replica, will

Replica.Data

be changed?

1 Like

You have to use :SetValue() ‎‎‎‎‎‎‎‎

1 Like

It says on the API, “after wrapping a table with a Replica you may no longer write directly to that table”

It also says I can replicate Profile.Data (profile service), but I have many Scripts that are constantly writing to Profile.Data.

I want the client to know everytime Profile.Data.Inventory changes so I can update the UI, how would I do that with ReplicaService?

1 Like

You’re going to have to use (both or one of) these methods:
image

2 Likes

Great module! Question though

function PlayerProfile:GiveCash(cash_amount)
	if self:IsActive() == false then
		return
	end
	self.Replica:SetValue({"Cash"}, self.Replica.Data.Cash + cash_amount)
end

Thats the server- side,

local SETTINGS = {

}

----- Module Table -----

local ReplicaTestClient = {

}

----- Loaded Modules -----

local ReplicaController = require(game:GetService("ReplicatedStorage"):WaitForChild("ReplicaController"))

----- Private Variables -----

local Players = game:GetService("Players")
local LocalPlayer = Players.LocalPlayer

----- Private functions -----

----- Public functions -----

----- Initialize -----

ReplicaController.RequestData()

----- Connections -----

ReplicaController.ReplicaOfClassCreated("PlayerProfile", function(replica)
	local is_local = replica.Tags.Player == LocalPlayer
	local player_name = is_local and "your" or replica.Tags.Player.Name .. "'s"
	local replica_data = replica.Data

     	print("Received " .. player_name .. " player profile; Cash:", replica_data.Cash)
	replica:ListenToChange({"Cash"}, function(new_value)
LocalPlayer.PlayerGui.UI.HUD.Cash.Text = replica_data.Cash
	end)
end)

Thats the client side, the issue is that its making that cash value for 2 people. As in its showing my cash for another player, how can I fix this?

See ReplicaService.NewReplica in documentation

Thanks! Ill use that! :slight_smile:

image

Instead of “All” I replaced it with player, didn’t work. Any ideas?

Edit: I replaced it with “Profiles[player]” and it seemed to work.