SecureCast, server-authoritative projectiles with lag compensation, multi-threading and more!

Introduction

There aren’t a lot of sources out there on creating proper server authoritative combat, I aim to address this and help roblox developers with creating more secure games.

Prerequisites / Features

  • Good performance
  • Synced Server-Client simulation
  • Multi-threading / Parallel LuaU support
  • Lag compensated hitboxes on the server
  • Bullet drop, grenades bouncing, ricochets, wall penetration

Technical Deep Dive

Click me for a technical deep dive into how the system works.

Parallel LuaU has one big limitation we must solve if we want to have lag compensated hitboxes: the inability to modify the DataModel in parallel execution. This prevents us from being able to create hitbox parts for the lag compensation which means we must do the hit detection for players completely in Lua, thankfully we can achieve pretty good results due to the massive amount of work done by the LuaU team in making the VM very fast.

I took advantage of various algorithms to achieve this with ~410 microseconds when checking against 100 players, let’s explore those various algorithms below.

Fast Voxel Traversal

First we need to separate the world into a 3D voxel grid, we use the voxel grid to quickly filter out which players the ray might intersect.
~1 Microsecond per traversal

VoxelGrid
Red dots are players
Blue line is our ray
Green squares are the voxels which contain our ray

Axis-Aligned Bounding Box

Next we will employ a bounding box intersection test, we use this to quickly discard any players which the voxel traversal returned but are not actually possible to intersect. This is done so we don’t spend time running exact hitbox collision checks (15 per player) on players which we have no possible intersection with.

image

Blue boxes are the voxels traversed
Green box is our Axis Aligned Bounding Box

Oriented Bounding Box

Finally we use an oriented bounding box intersection to determine the precise point at which an intersection occurs, these checks are relatively expensive so we only want to use them as a last resort.

image

This is also worsened by relatively slow CFrame interpolation needed to compute the precise hitbox position, I assume this is due to CFrame being a non native type.

Images / Showcase


Benchmark / Performance

I conducted a benchmark on 2023-08-31T20:50:00Z using Native Luau code generation which consisted of ~630 projectiles intersecting 50 characters spread over 9 cores every frame, I was able to maintain 60 FPS on the server with less than half of the frame time being used up. I advise anyone looking to use this project to run their own set of benchmarks and teststo evaluate the performance of the module for their specific use case, for those of you who are not able to or are willing to trust my numbers I can say with 100% confidence that this module should work for 99% of use cases out there.

Download

NOTICE: This system hasn’t been used in a production environment, use at your own risk.

Downloading from Wally

secure-cast = "1axen/secure-cast"

Downloading from GitHub releases

Downloading the source from GitHub

Documentation

The documentation can be found at SecureCast API

Feedback / Suggestions

This is my second community resource, if you have any suggestions/feedback for me please don’t hesitate to share it with me. I would also love to hear any ideas on making the system even more performant.

License

MIT License

Copyright (c) 2023 Axen

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the “Software”), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

160 Likes

YOU CODED WHAT? Yooo finally, people are not forced to use chickynoid to get server sided hitboxes less go

15 Likes

Just wondering, what makes this better than RayCasting?

4 Likes

This module isn’t aimed at replacing Raycasting, it’s meant to provide a way to do server authoritative hit detection/registration. It still very much uses Raycasting under the hood.

5 Likes

There might be some issues with the lag compensation as I don’t account for interpolation done on the client, Im planning to address this in a subsequent update.

3 Likes

I see, this module peaked my interest because I am working on server authoritative combat right now, specifically projectiles. I use ReplicaService to replicate the direction and speed of a projectile to the clients after a request to shoot one has been validated. The server and client use the same module to model the projectile’s motion (but the server only calculates its path without creating any objects). I cast a ray for each frame of motion to detect collisions. With this in mind, do you think it would be more efficient to use your module?

2 Likes

as far as I know you cannot really account for the roblox buffer that they add for interpolation unfortunately, as no one knows exactly how it works.

However someone could just replicate positions via remote events to the servers and it would still work, even better if anyone has any custom character controllers that rely on the custom replication behavior they could easily fork your resource to get server sided hitboxes

So this resource is still a W

2 Likes

Calling workspace:GetServerTimeNow() actually accounts for this buffer and works as a precise synced clock between the server and client

2 Likes

Using GetServerTimeNow() only accounts for a players one way trip latency, the interpolation buffer is separate from the players latency and is applied between position packets, the best estimate which I’ve come across for this buffer is a range from 80-100 ms.

3 Likes

Lag compensation is something I am really interested about. Cool to see someone actually try to implement it

2 Likes

I think it’s best for you to decide, I don’t know your game structure and would be biased towards my own resource.

4 Likes

Version 0.0.1

  • Added a name to the project
  • Create a public github repository for the project with support for rojo where everyone can contribute.
  • Published the package to wally
  • Added support for modifiers which allow you to define per cast settings like velocity, gravity and to override event handling

Note: I’m not trying to compete with FastCast, I am just bad at coming up with names

8 Likes

Another great resource by you, good work.

3 Likes

Version 0.0.2

  • Added support for native Luau
  • Removed unused variables and cleaned up the code
  • Removed the discard phase, it had cases where a ray would intersect but be discarded, it has also become obsolete following the recent release of native Luau code generation which has given the system a substantial performance improvement overall (Please release native vector SIMD support soon :pray: )
  • Fixed an edge case in the OBB intersection test which would skip an axis if one or more of the size axes were the same (Thanks zeuxcg for pointing it out)
  • Switched to dynamic frame time allocation. It tracks how much time was spent between PreSimulation and PostSimulation to dynamically determine how much frame time is left in the current frame, currently the simulation is allowed to run for half of the remaining frame time.

Note: I have also included a section on performance in the post.

8 Likes

Version 0.1.0

  • Added documentation
  • Removed OOP from the voxels utility
  • Added a Collaterals property to projectiles
  • Added a settings module to allow for easier modification of the system
  • Decoupled the snapshots from the simulation module, snapshots can now be used from outside the simulation
  • Server now correctly detects RaycastFilters using RaycastFilterType.Exclude which intersect characters
5 Likes

Is your system tailored to hit detection on players or will the OnImpact callback fire with any part? I have NPCs and destructible objects that I can be hit by projectiles.

Edit: looked thru API, answered my own question. :face_with_hand_over_mouth:

1 Like

Sorry to bother you, but it seems like the download link is not there. I don’t know if I’m missing something or like blind or dumb

1 Like

Hello! I’ve just added the latest version of the module as a release in the GitHub repository.

3 Likes

Thank you for letting me know! Also nice job :+1:

2 Likes

Version 1.0.0

  • Improved types
  • Re-structured the documentation
  • Added setup guide to the documentation page
  • Modifiers now take a BindableEvent for each event you want to override instead of overriding every event
  • Added definitions folder to the settings module which allows you to specify an alternative directory to load projectile definitions from
  • Added interpolation handling to the documentation (Make sure to read this as it is key to proper lag compensation) (Getting Started->Simulation->Setting up your server)

With this version I finally have this module in a pretty good place feature wise, I don’t expect to add much more other than a GetPosition() method for projectiles, I will continue to maintain it and fix any bugs as they arise but updates will come at a much more reduced rate.

10 Likes