Performance Concerns - Replication

Extreme Example:

  • The server creates a car.
  • To keep performance low, it only handles the necessary physics;
  • Imagine a simple Part for the base and four Balls acting as wheels.

Now, this car is supposed to be extremely detailed, though.

Imagine the craziest contraption you can think of: extremely high fidelity, multiple animations firing off, particle emitters going wild, dancing NPCs hanging off it, doors and meshes being tweened, and so on -
basically, a performance‑destroying beast.

Handling all of this on the server wouldn’t be smart.
50 of these cars, and you have your servers running like 100 ms slower.

If I want to handle all of these things on the client, what would be the smartest way to do it?

Ideally, I’d like to encapsulate the car as an OOP object on the client to make actions and interactions easier to manage.
Normally, you could send the client the necessary information - like which models you want loaded only on the client, or details such as how fast a propeller is spinning, what animations are playing and so on…

However, StreamingEnabled makes this tricky. How can you locally apply this information / ‘skin’ to the server‑version of the car if it doesn’t even exist on the client yet? What would be the ideal way to solve this?

Ideas I had:

  1. Using individual attributes per model, which means having all of the necessary data be loaded in immediately once the model is loaded in, so an OOP object can be created locally. Each individual attribute would be listened to for changes.
    For functions that the cars might trigger, which might send large amounts of data, I can save the cars in a table on the client / server and listen to a RemoteEvent.
    Attributes that hold complicated data, such as e.g. large tables, could be passed down as JSON.

  2. Same as above, but having one single attribute per model which saves everything as JSON

  3. :

  • Client loads in server object
  • Client sees Tag / Attribute of it being a special object
  • Client sets it invisible / it was invisible on the server already
  • Client Requests information from → Server, needs data
  • Server sends it back → Client creates an OOP object and renders the object

Option 3 probably isn’t good because of the extra back-and-fourth communication between server and client..

Should I go for the first / second approach? Or is there something better? Is this unnecessary overthinking in general?

2 Likes

CollectionService/Tags and Attributes would be my approach. I try to minimize my use of RemoteEvents. Attribute strings have a size limit now.

1 Like

#1 sounds kind of like the best option, but I dont suggest trying to condense all the states about the car into one huge json. Not just because it means 1 change will have to re-replicate all states, but its also over complicated. If you want to use OOP, i suggest heavily relying on composition for all the different gadgets of the car like propeller, doors, etc, or moreso like componenents, which the client will detect when it loads on the complex model via tags, and search for the states of the objects which the server would set on the simplistic base instance, with attributes like “IsLDoorOpen”, “IsHeadlightsOn”. With this, there shouldnt be any use for remote events, which I suggest avoiding (I dont exactly understand your usecase), because any data the client keeps locally about the car will be lost when the car is out of range, and when the base model and all the gadgers unload. But this is why attributes are helpful, because you’ll be able to see all the up-to-date states again via the attributes when the car is next loaded

3 Likes

This is something I had thought about quite a while ago,. to fix this i had to make my own custom “replication” system.

The main problem with it is networking.

So if you wanna know what I did for my custom replication system. I have the vehicles stored under the camera object in workspace. So they don’t replicate to the client. Whenever a player joins, i fire to the client and slowly (via task.wait) “replicate” the vehicle instances to them.

In a local script, whenever the client tries to drive the car. First I move the car on their client so they have the most responsive movement. Then I fire to the server and move the vehicles that are parented to the camera so that you can track the movement if you ever need to. and then notify other clients with fireallclients. Then in the onclientevent you just move the car aswell.

You can even decide not to move the cars if they arent visible in the client camera view, which is great for optimisation. This is why you “replicate” the client car cframe movement to the server.

You need to give the other clients info about a car and its features like max speed so that they can move the car at the proper speed on their own client. Use a remote event to send.

When a new player joins, you need to give it info on where the current vehicles cframes are. So that’s why you need a remote event again.

I think you get the idea sorry if the explanation is kinda weird, but overall this can improve FPS and ping. Since the task scheduler has to spend less time working on outgoing/incoming data tasks in a frame.

The reason most developers simply don’t care about this is just because it’s alot more complex to deal with + most games are capped at 20-30 players per server. I had done a test where I moved all 50 baseparts at the same time (pretend they’re cars).

About 20kb/s was incoming and outgoing. Obviously it’s not ideal but you’re still under the 50kb/s limit so there’s a low chance of data packets being queued or dropped or worse ping.

But it’s definitely something you should deal with but most people don’t take it into account, in the same logic. Why care if a server-side tween sends alot more incoming data for clients compared to a client-sided tween? Just because it’s eaiser to handle?

Or why add datastore retry methods? The chances of a datastore request failing is still very low. But it can happen.

The truth is, movement should be a client-sided visual. But 99% of developers think it’s fine to just give the client network ownership of the car and let all that data go in and out. It can lead to problems with ping, FPS, possibly even load times for other clients who are joining. Alot of games are just lucky they don’t have too many vehicles since their servers are capped at probably 20-30 players. And players might just not be moving their car for some time.

2 Likes