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.

93 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.

7 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).

2 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.

3 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.

3 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.

5 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.

10 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

11 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

5 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.

6 Likes