Replicate items to individual client

As a Roblox developer, it is currently hard to replicate objects from the server to an individual client.

Problem: Developers want to explicitly replicate a game object to a single client. Placing the object into ReplicatedStorage will replicate to all clients, not an individual. Developers are currently forced to use hacky solutions, such as placing game objects in the player’s PlayerGui.
(This works because the PlayerGui doesn’t replicate to other players, but it is clearly not a preferred method)

Solution: Provide a service or API to replicate an object to specific clients.


Here’s a possible solution I could think of using ReplicatedStorage:

  1. Add the method: void ReplicatedStorage:Replicate(Instance object, Player client)
  2. Add the event for client: ReplicatedStorage.OnReplicated(Instance object)
  3. The object will then be parented under ReplicatedStorage only for the given player.

Code example:

-- Server:
local part = Instance.new("Part")
game.ReplicatedStorage:Replicate(part, game.Players.SomePlayer)
-- Client:
game.ReplicatedStorage.OnReplicated:Connect(function(part)
   print(part:GetFullName()) -- > ReplicatedStorage.Part
end)

Obviously there are strange scenarios to consider: What does the server do with the object? Does it parent it somewhere? What if it gets destroyed server-side? What if the object gets parented into the game and thus replicated to everyone?

Ideally in my mind, the client should make a copy of the object and thus is no longer linked to the server-side object that it came from. Therefore, any server-side changes to the object won’t affect the client-side object.

147 Likes

With this being said, how would this be any different than physically creating the copy on the client, as a local object - apart from the server hosting the original copy.

In my opinion, this is a great request, however I believe server-side changes should still affect the client-side object, as it would be nice to have full control of the part from the server at all times.

For example with your suggestion:

  1. Server makes and replicates an object to a client, and begins monitoring activity to determine whether the client should continue having access to that object. Perhaps this object is something the player should only have in certain areas, such as a NPC follower, or something.
  2. Server decides that client no longer needs that object, destroys it or interacts with it in another way.
  3. Server now has to send a remote event to the client to “Unreplicate” the object, or, Destroy it.

Sure, the client could do these checks, but then we have possible security issues, etc.

A solution, or possibly addition could be:

a) Allow server access to the replicated object
b) Add another parameter to the proposed ReplicatedStorage:Replicate, as such: void ReplicatedStorage:Replicate(Instance object, Player client, Boolean enable), which would act as a on/off toggle for replication
or c) Another method: ReplicatedStorage:Unreplicate(Instance object, Player client), which would do just what it says, attempt to :Destroy() the object on both the server and the client.

I personally like option a best.

8 Likes

Hmm, what if the replicated objects were put under the Player object in a special folder?

This could mean the server and the target client has access, but no other clients do. It’d be somewhat inconsistent with the ReplicatedStorage model - but then it’d be consistent with the normal way of doing player-specific things, anyway.

In my opinion it would work better than Crazyman’s suggestion of having to manually code how the replication system works because it will just work like normal (as Roblox’s replication system doesn’t use any methods or signals at all right now).

3 Likes

I don’t like this much because what if you wanted two clients to have the same object?

Imo the easiest way to make this work would be to just have something like what crazyman said

game.ReplicatedStorage:Replicate(Player player, Instance object, Tuple data)

game.ReplicatedStorage.OnReplication(Instance object, Tuple data)

And just have the object patented to nil by default on the client. Imo it’s just the most convenient and easy to learn way.

4 Likes

Wouldn’t it be easier to just add these new methods. Replicate for instance to ServerStorage instead? Since its like an authoritative local storage. And that could place the part in the individual client’s workspace maybe in a folder or under a new service? Adding that functionality to ReplicatedStorage in which everything in it still replicates to all client would mean changing the functionality of ReplicatedStorage to not replicate by default. And personally speaking I don’t like that, it adds more work to an already functioning service. Just my two cents.

4 Likes

I see what you mean, but this is where I’m thinking the general replication system needs a bit of an update.

For the sake of consistency and ease of use, I think the behavior of the client-specific replication system should be limited to how the other replication systems work already – which in this case, is essentially just parenting and removing objects.

You say the methods and signals are the most convenient and easy to learn way, but IMO I think most convenient and easy to learn way is Object.Parent = Player.ReplicatedObjectsFolderNameWhateverHeck.

Every beginner scripter knows parenting already, and when they go on the documentation and look at services and methods (such as :Replicate()) and stuff, they have their brains fried until they learn to understand them. The one thing that needs to be learned in a situation like this is to do with this player replication object, but in your case to call the Replicate method you need the Player object anyway.

Better or not, this is really just another, alternate ‘limited’ solution. I think if we’re really looking for a clean, all-encompassing solution to the replication issue, an overhaul of the current system to generally afford more control to developers is what we want (as if we continue building on the existing, ‘implicit’ system, we become inconsistent and messy).

I’m a super big fan of design-related stuff like being consistent and clean and all of that fluffy stuff, as you can see lol, but the reason I am is because I think it really does affect the people who use it (and sometimes the system itself). If you want a stable, easy-to-maintain, easy-to-use, easy-to-learn system then these things gotta be in your priorities list.

6 Likes

I needed an API like this today. I ended up using the PlayerGui object and cloning, but that has a lot more overhead than just being able to replicate an instance directly.

I think there are arguments for use cases on both sides of whether or not the resultant object should be linked to the server object. Ideally, you could just choose with a flag parameter. I’m not sure if that’s trivial to implement or not, but I can see the usefulness. At the very least, the ability to replicate an unlinked version of an instance would be very useful for things like custom map chunking system since the stock StreamingEnabled is useless without the proposed room/zone/scene feature.

11 Likes

Intro

As a roblox developer, it is currently too hard to replicate objects to only one client. There are a few different reasons one may need to do this, in my case optimization. Developers are forced to use the PlayerGui in an unintended way by parenting objects to this from the server, and picking up on them from the client. This leads to many trade-offs, and is unacceptable in my case because the model I’m trying to replicate includes gui objects inside of it, meaning that they will project onto the player’s screen unintentionally.

My Case

My game is a racing game, and before now I had been replicating all the vehicles onto the client prior to rendering in Workspace. I realized this was horrible decision on my part and was a beginner mistake when building Midnight Racing. Client memory could spike to over 2 GB at times, loading would last minutes, and assets began to fail to load due to a high volume of requests. By moving my vehicles (over 100 with about 25 meshes minimum each) to the server, I can cut down substantially on load times, and updates will no longer cause exponential lag by nature.

Unfortunately, my game also now depends on placing the vehicles into Workspace as local parts for the garage and dealership guis. This means that somehow, I need to replicate the car to only this client (when they request it so memory usage doesn’t spike), and then move that car to Workspace using a LocalScript. Unfortunately, when the car is parented to the PlayerGui, scripts in the car run and parent the car’s gui the PlayerGui directly, meaning that when the car is moved out it leaves the guis behind and you’re stuck with vehicle gauges for every car you look at in your garage.

The Solution

Some sort of shared storage service between only one client and the server. Basically, a cross between ServerStorage and PlayerGui that doesn’t actually draw the gui or run code. This would help a lot of developers save memory and implement their own part streaming method.

EDIT: Link to game: https://www.roblox.com/games/3339374541/Midnight-Racing-Tokyo-DEMO

13 Likes

Yeah, I’ve had multiple use cases of replication to a single client only. From client-side admin scripts, to optimizations for map objects.

Having something to replicate to one client only would be really beneficial to my projects for sure. Perhaps a new object under each player that only replicates between the server and that player would work. Such as Player.PersonalStorage or just storage

6 Likes

In Restaurant Tycoon 2, currently all the furniture items (over 200) are stored in ReplicatedStorage.

We plan to add many more furniture items in the future, and continuously increasing the size of replicated storage seems like it is not scalable, and I think it’s adding on a lot of client memory. A single player playing Restaurant Tycoon 2 is unlikely to encounter every furniture item in the game during their play session, so loading every furniture item in replicated storage before they even load into the game does not seem like the best way to minimize client memory and joining times.

I believe the ability to replicate an individual furniture item when the player requires it would help solve this problem. Many, many other games on the Roblox platform have similar functionality, such as Adopt Me and Welcome to Bloxburg, and pretty much any other game with house furniture placement systems. I’m unsure how these other games deal with this problem, or if they simply put all furniture in ReplicatedStorage like I do.

15 Likes
1 Like

Even with streaming enabled, this is still an issue that developers face.

Earlier today I had a use case of replicating AI traffic to a specific players client when they were within a certain radius of the traffic (to optimize the experience for mobile devices which cannot handle keeping so many cars at once).

The issue with StreamingEnabled is that using it would ruin how the AI traffic moves throughout the map.

It would be extremely useful if we could choose what is replicated to clients without hacky workarounds.

2 Likes

You could do something similar to how GTA does things and simulate a chunk-based p2p system, and each chunk can have a network host, if there isn’t one then any player entering that chunk becomes the new network host and manages entities in that chunk. These entities will be entirely local and only exist on that client unless another client enters it, in which the network host will send some stuff to the server to tell the other client to spawn the stuff that is on the host’s screen on their end and update them roughly every 1/30 seconds or maybe just spawning parts who’s network owner is owned by the network host but their visual appearances are all local, so the position/orientation is managed by whoever is handling the chunk, while the visual stuff is handled by any client within the chunk.

2 Likes

Bumping this
I’m making a MMORPG with alot of npcs and my NPCS are all server sided with humanoid.
They are anchored when nobody is near but once a pleyr comes the npc will start moving but the problem is that it replicate to every players even if they are far away and that just make this player more laggy for no reason.Streaming Enabled helps me but not enough i want my npc to be less laggy than they are right now…Please roblox add this , we need this

You could just have the clients render the NPCs and keep position/orientation as data (not even having parts on the server), you could also go one step further and make it a chunk-based system with player as an “owner” that will manage and sync stuff like position/orientation and AI while other clients will just handle the rendering, if the owner leaves the chunk then the next player in the chunk will manage NPCs, if there isn’t one then they become “inactive” and be frozen at their last state (and on client-side, the rendered npcs will be removed)

EDIT: Looks like i already mentioned something similar, oh well. Regardless, the rendering part is still new so you should look into that on how to “render” NPCs locally but keep data-stuff on the server.

That true but tbh I don’t know how to sync them because I have complex box that use PathfindingService and they can jump.I alose have somes skill in my game that could bump my npcs.Right now what I’m doing for my npcs and makes my player’s experience better is SetNetworkOwnership to the last player hit the npc

That’s true, custom replication is kinda complex so it’s better to use default roblox replication unless it’s important for your game to use custom replication.
Nice idea for network ownership, but why force network owner instead of relying on engine to do it for you? I am assuming it’s something to do with timing and engine setting network owner is bit delayed than server instantly giving net owner to a player or itself? Since i read somewhere that automatic network ownership is bit delayed than forcing network owner to client.

Tho at the end of the day, network ownership just re-routes physics packets than give full client-authority to an object, unlike some other engines where “client authority” means client will replicate everything about the state of that object, altrough for Roblox this is prob set only for physics since full client ownership for the state of a character means outfit bypass which other games don’t have to worry since they use characters composed of a mesh.