Stupid simple fast character position replication

Tired of having a big delay between players in your PVP experiences? Even with good ping?

Try this!

Less than 100 lines (no huge libraries of any kind !!!)

  • Most likely requires no changes to server code (server side hit reg is UNTOUCHED)
  • Tested with low fps clients (Down to 5 fps!), still responsive!
  • No changes have to made with the characters (unless you have some really custom stuff)
  • Turn off and on at any time! (This script does not make permanent modifications to datamodel)
  • Super easy to modify!
  • Can coexist with the current Roblox character replication (enable for some players if you want)

Potential Disadvantages:

  • Rotational data is set instantly and is not interpolated (lerped).
  • Any physics body connected to the replicated players might behave incorrectly, such as vehicles.
  • No network optimizations are implemented (e.g., delta encoding, avoiding sending the CFrame if it hasn’t changed, sending float16s instead of the entire CFrame) to keep it simple.
  • You will need to set all replicated humanoids to be in the Physics state type using Humanoid:ChangeState(Enum.HumanoidStateType.Physics) to avoid a humanoid quirk causing lag.
  • The example script currently uses :PivotTo to set the model cframe, this can be expensive for r15 games or games with high player counts.
  • This code contains 0 anticheat and antiexploit measures

Example video shows a earlier version before unreliable events were created!

If you find big issues with the code, let me know!

45 Likes

as cool as this is, this is horribly unperformant both in terms of networking (youre sending a remote every heartbeat if youre moving) and laggy in terms of constant replication updates (youre pivotting the characters every renderstep), not to mention the double replication from roblox still replicating your character alongside this code

cool idea though

5 Likes

I’ve put it in typical colors 2, no one noticed a difference in terms of jitter or lag even on 20 players.
Try it out in experimental servers, let me know what you think of it.
Sending a single cframe every heart beat is perfectly fine as long as you use an unreliable.

Just a fair warning, this game still uses standard instance replication for characters and weapons cosmetics as we parent everything on server still.
If you see high bandwidth while playing the game, that the reason why, not the custom replication doing that.

1 Like

what about the other two issues i mentioned?

Double replication happens but unlocks the potential to have both systems at the same time. I see this as an advantage. You never stated why this is an issue in the first place.

Render stepping 20 models isn’t a huge deal for the Roblox engine, but if they are instance-heavy (like R15 with lots of accessories), I can see why this could be an issue. Since you can switch back to the original Roblox replication at any time in real-time, you can create a system where it only render steps and uses the new replication for nearby players or those in front of your view. It would require a bit of work to optimize this for a real game.

Again, my example is the bare minimum to get started.
I made it simple and readable enough for people to understand the system without needing to open a GitHub doc every 20 seconds.

1 Like

Using buffers seems overkill. CFrames are already stored as f32 and you aren’t going to get better bandwidth if you just reconstruct them.

Here’s my version:

FastCharacterReplicate.rbxm (2.1 KB)

1 Like

I had this in mind, you wouldn’t have to send all the components if your game wont ever have the character rotate in some ways.

I noticed a drop in bandwidth usage sending a single cframe on blink, might have been some variance or unknown variable then, I have removed it now.

1 Like

I would recommend sending on Heartbeat, as that would send the latest simulated character position right after physics have completed simulating.
PreSimulation would be sending the previous physics simulation position
I would also keep the network send rate cap on 120hz, as sending more than that would be wasteful.

1 Like

Holy jesus, thank you so much for this!
Will definitively be trying to use it on the game I’m working on, thank you!

2 Likes

Just watch out for this, I found this out just now.
edit: nvm just do Humanoid:ChangeState(Enum.HumanoidStateType.Physics)

3 Likes

Sending remote events every frame is one of the most normal things ever, and its literally why unreliable remote events were made.

1 Like

double replication means double the network use, even with unreliable remotes
idk if im just a perfectionist or something but that feels bad

im not 100% sure how unreliable remotes work, but even if the packets get easily dropped thats a lot of requests, regardless of whether they arrive or not, which feels like clogging network usage to me

again, im unsure if this is just me nitpicking and this really doesnt matter at all in the grand scheme of things, but it still feels wrong

This is essentially how most games handles positional updates (advanced ones do a lot more: 2. Networked physics overview · jpetanjek/NextGenNetGames Wiki · GitHub)

Until recently, Roblox didn’t support UDP networking. All networking had to be ordered, and Roblox would resend dropped packets, which led to additional congestion and lag.

Unreliable events have resolved this issue to some extent. It’s not recommended to send large amounts of data on each heartbeat with it though. For smaller things like transmitting a single CFrame or a key input stream, it’s more than capable of handling it.

For example, here’s a project that sends updates almost every frame. It’s created by someone with lots more knowledge of Roblox replication: Chickynoid: Server Authoritative Character Replacement

A good read for people looking into the replication subject: Snapshot Compression | Gaffer On Games

1 Like

Roblox devs have this tendency to think if you do X thing every frame its a bad practice.

Doing a lot of things every frame is not a bad practice, in fact its literally how most systems within the roblox engine work already, humanoids have to constantly raycast to get the Humanoid.Floor property, roblox already sends positonal updates every frame, hell rendering is done every frame, physics are also done every frame.

Just make sure to optimize whatever you are running every frame and not waste unecesary resources, an example here would be to serialize/compress the data before sending it to clients to not waste bandwith.

6 Likes

i see, forgive my concern lol. im so used to normal remotes that sending a request every frame, unreliable or not just kinda manifested itself as “this is bad” in my head

Hey! I’ve seen you quite often on the Chikynoid forum post and I’m wondering if I should just ditch trying to learn Chikynoid for this. The implementation seems 100x more intuitive and doesn’t require extensive networking knowledge just to get started with it. Only advantages I can think of are that Chikynoid is server-authoritative (pseudo-eliminates movement exploits) and can do far more when it comes to state management. I’ve spent weeks trying to rewrite my movement-heavy fighting game into Chikynoid, while I can implement this module into virtually any of my games and get it working within a day or two.

No, you aren’t going to regret learning how Chickynoid works once you’ve learned it.

2 Likes

Not convinced… Mostly because of the lack of features and documentation. Sure I can write in these custom systems, but it will certainly take a few weeks (and a few headaches). One specific deal breaker for me is the lack of features regarding animations such as adjusting it’s weight and playing multiple at the same time. Keystrokes and input buffering is another headache where I don’t even know where to begin. Don’t get me wrong, Chikynoid is a phenomenal resource with far-reaching applications, but the lack of documentation and feature updates have stalled my interest. I sure do hope the Roblox physics team cooks up their own server-authoritative framework within the next 5 years :pray: