Simple answer: Don’t use this module.
??? lmao what do you mean?? Why not?
There you go, why you don’t have to use RemoteEvents
and ReplicaService instead.
Hi, I’ve been using ReplicaService for a while and I think it’s an amazing module.
I’ve been wondering if there’s a recommended way to go about representing the same object on both the client and the server? I’ve historically just made a separate class for each, e.g. PartyServer and PartyClient.
Each PartyServer has its own replica and that replica being received by the client leads to the creation of a PartyClient. It’s manageable, but it feels like a lot of code repetition. In my mind, it’s somewhat justifiable - after all, the function of the PartyClient is really only to forward changes in a readable way (Party.PartyMemberAdded is easier to read than Party.Replica:ListenToArrayInsert …).
Still, it’s preferable that the interface of PartyServer is at least partially reflected in the PartyClient. PartyServer has setter methods, but all getters, signals, etc should be the same (I think…). Is there a way to go around solving this problem that you’d recommend?
Many thanks,
Zairky
You could create a shared class for all the shared methods and then create whatever client/server specific code you need by checking RunService:IsClient()
or RunService:IsServer()
respectively.
Thanks for the quick reply!
I’ve trialed this in my code before and I feel there’s a messy pattern of continually having:
if IS_SERVER then
-- Server sided stuff
else
-- Client sided stuff
end
littered all around the code. I think this makes code harder to read, but that’s entirely down to personal preference and not a fault of the approach. However, I also imagine it isn’t good practice to expose the server-sided methods to the client (as it allows insight into server-sided code vulnerabilities which are otherwise hidden).
Still, I’m unsure what’s recommended as standard practice - if anything is at all. I have a suspicion that there’s a way to take advantage of the nature of the relationships between the server and client sided objects, but I’m waiting for someone smarter than me to tell me what that is!
Yeah, it’s definitely a situation that’s up to you on how to approach it. One approach that I like is how Knit initializes its framework by deleting the server-side code from the client on startup so its removed from the bytecode entirely on their end. You do end up writing separate classes still but at least you only require a single file with reflected API.
Im experiencing an issue where a server replica does not get received by the client.
Both the client and server uses modules, also using ProfileService.
Server code:
local function playerAdded(player)
local profile = profileStore:LoadProfileAsync("Player_"..player.UserId) -- get profile
if profile ~= nil then
profile:AddUserId(player.UserId) -- GDPR
profile:Reconcile() -- add missing stuff
profile:ListenToRelease(function() -- loaded on another server
profiles[player].Replica:Destroy()
profiles[player] = nil
player:Kick("Your data might have been loaded on another server, please rejoin")
end)
if player:IsDescendantOf(players) == true then -- loaded and player didnt leave
HandleData(player, profile) -- this just changes profile.Data before its sent to the client
-- create profile object with replica
local profileObject = {
Profile = profile,
Replica = replicaService.NewReplica({
ClassToken = profileToken,
Tags = {Player = player},
Data = profile.Data,
Replication = player,
}),
Player = player,
}
profiles[player] = profileObject
else -- left before loaded
profile:Release()
end
else -- could not load
player:Kick("Could not load data, please rejoin")
end
end
Client code:
local dataUtil = {}
local plr = game.Players.LocalPlayer
print(0)
local controller = require(game.ReplicatedStorage.UtilityModules.ReplicaService.ReplicaController)
print(.5)
controller.ReplicaOfClassCreated("PlayerProfile", function(replica)
print(3)
if replica.Tags.Player == plr then
print("Data has been received!")
end
end)
print(1)
controller.RequestData()
print(2)
return dataUtil
You can see I already added debug prints to the client side, and 0, 0.5, 1 and 2 get printed, but 3 does not. ([ReplicaController]: Initial data received
does not get printed either)
What am I doing wrong here?
I tried making a repro for the issue but was unsuccessful.
EDIT: Looks like this was caused by mistakenly adding a ReplicaRemoteEvents folder into replicatedStorage beforehand, causing the module to make a duplicate. Whoops
Hey, I’m unsure as to how I would create a centralized module that connects Replica
creation listeners. I want to get data and listen to data changes at any time and from any LocalScript
. If anyone has any guidance on this topic, please let me know
Is it possible to replicate instances?
Is there anyway to set the value for only a player or a group of players? Or to stop listening for changes?
You serialize it? You must have basic data storing knowledge before getting into this type of stuff.
I have basic data storing knowledge. I’m not just walking around with my head cut off, buddy.
I’m asking a simple question. Is there a way or function in this module, because I have already tried to find it in the API, and have failed.
Well, it would be sort of useless to include if serializers already exist.
how do i change the replica data client side?
local CharacterReplicaClassToken = ReplicaService.NewClassToken("Character")
local player -- A Player instance
local character -- A Model instance
local replica = ReplicaService.NewReplica({
ClassToken = CharacterReplicaClassToken,
Tags = {Player = player, Character = character, Appearance = "Ninja"},
Replication = "All",
})
https://madstudioroblox.github.io/ReplicaService/api/#replicatags
Replication - (Default: {}
not replicated to anyone) Pass "All"
to replicate to everyone in the game and everyone who will join the game later. Pass {Player = true, Player = true, ...}
dictionary or Player
instance for selective replication.
https://madstudioroblox.github.io/ReplicaService/api/#replicaservicenewreplica
Methods [ScriptConnection]:
ScriptConnection:Disconnect() -- Disconnect listener from signal
Treat it like any other lua connection.
local NewKeySignal = Replica:ListenToNewKey(path, listener)
NewKeySignal:Disconnect()
bruh moment
yes bruh moment
3000 thousand characters
all in good fun
i’ve been trying to implement this along with profileservice for a good week now and i feel like i’m only now getting the hang of it
it doesn’t help that there’s not a lot of case examples from the community using this in specific scenarios like there is with profileservice
@loleris hasn’t replied to this thread for about a year now, either because he’s busy or the replies aren’t worth addressing, so maybe we can try to find answers together
Yes, I actually already figured it out. It was a kind of hacky way, though. This is better.
No it isn’t. Bytecode doesn’t get deallocated in this context and thus is retrievable by exploiters and technically anybody on Windows via task manager memory dump.