How exactly should I go about making a client-sided projectile/hitbox system?

After my first attempt at making a projectile system, I learned that server sided projectiles are heavily affected by latency which could make the rocket or it’s hitbox look off on the client. Since then, I’ve been looking for how to make a client-sided projectile that’s safe and not resource heavy. But after a month or so, I haven’t been able to find any easy-to-understand posts that explain the specifics on how one can be made.

I avoid using something like FastCast because I prefer creating my own system for games I’m making, one that I could easily understand and edit to my liking (and also not need to update whenever changes are made). So, what should I do? because I’m very lost.

1 Like

Well, to sum it up you do all the calculations on the server-side, and then the server would send the calculations to the client-side to visualize it.

this just sounds like you telling me to use a server sided hitbox, it doesn’t explained anything related to how a client sided projectile would function.

image

2 Likes

erm actually uyour method is absolute TRASH. what you should do is return the raycast information on the client to the server, then damage human on server. pretty simple, and you acn implement seucirty checks.

I’d say raycast the position how much it’s moving by it’s lokvector and then if ray hit fire server destroy projectile.

you could try fastcast, tooo

The server doesn’t even need to do any of the hitbox calculations, as long as the path of the projectile is predictable. All you need, is the client to do the calculations and fire the server when it thinks there has been a hit, and then do sanity checks on the server. The server should calculate the expected position based on the time since the projectile was launched and do a magnitude check, while allocating some room for error due to latency. If it passes, register the damage.

I recommend checking this tutorial: Network Efficient And Safe Practices With Projectiles

2 Likes

what if it wasn’t?

would this be a different case if it was a physics-based projectile, such as a slingshot pellet?

would there need to be a separate “ghost projectile” on the server to ensure that the client doesn’t spoof the position of the projectile?

oh in that case there’s a method you insert part at firepos, make it point to mouse pos, then insert it into a folder.

eveyr renderstepped, for every gbullet in that folder, cast a raycaast 5 studs of the bullets lookvector, if hit, fire remote, destrroy projectile. after casting, move the projectile, if still exisitng, 5 studs of it’s lookvectro. I

for that the path of the projectile would need to be affected by external factors that could pop up in real time, like a homing projectile, in that case, gg.

the approach is the same, you know the initial variables like the position, time and in this case, the initial velocity, assuming the only force acting on the projectile is gravity, you can use this equation:
image
and the change in x and z will just be velocity for the respective dimension * time

Remember the reason the client is calculating the position in real time in the first place, is because it needs to visualize it too. In both cases, with the linear projectile and the one that curves due to gravity, a script can instantly calculate where that projectile will be at a certain point in time, if it knows the projectile’s properties.

So, there would be no need for the server to also be simulating the projectile’s motion in real time. The sanity check is just the server:

  1. calculating delta t (current instant in time - the instant the projectile was launched)
  2. plugging allat into magic physics equation to calculate where the projectile would be right now (expected position)
  3. do magnitude check on the position of each character the client claims to have hit and the expected position, if it’s under a few studs, great!

the client can’t really spoof the position, as the server predicts the position using information it gave to the client in the first place.

Alright then, what do you think about this step-by-step process for the system?

Steps:

  1. Create “ProjectileReplication” Local Script in StarterPlayerScripts. Create a remote called “clientCreateProjectile” which will be used for creating client-based projectiles.

  2. In the Rocket Launcher’s ServerScript, use [clientCreateProjectile:FireAllClients()].

  3. Send any info about the rocket, such as the model, the speed, and spawn point through the remote event. Make two variables called “startTime” and “endTime” which will be used to calculate the projectile’s position on the server.

  4. Clone the model on each client (through [client.CreateProjectile.OnClientEvent:Connect(function()]).

  5. Move the model on each client through RunService.Heatbeat on the Z axis by [-speed * deltaTime].

  6. Use a raycast on the client that fired the rocket until it detects something.

  7. Stop the rocket on all clients by firing (a, not sure which) remote to the server that tells all clients to stop the rocket once the raycast detects an object, and make it invisible and disable it’s collision.

  8. Calculate the hitbox on the client and send the server a table that includes players hit by the projectile.

  9. Do security checks by calculating the cframe of the projectile (on the server) based on [spawnPointCFrame * CFrame.new(0, 0, -speed * (endTime - startTime)))]. and getting the distance between an enemy hit and the projectile, and then comparing it to the projectile’s range.

  10. If the security check is accepted, deal damage to the enemy. If not, kick the enemy from the server and add a flag to their account using datastores. If they get three flags, ban them.

  11. Fire another remote (effectReplicationRemote) to visualize the hitbox for those that have the “Hitbox Visualizer” setting enabled.

  12. Fire it again right after to create the explosion particles.

FYI: I’m using a remote event that the server can use to broadcast to all clients a visual change (like a particle emitter or an object changing colors or becoming invisible) so that less load is put on the server.

you will probably also need an id for each projectile, so the server can differentiate between them. IDs between players can overlap. The server should check both the player and the id to see if it is the right projectile

you only need raycasts/fastcast if the projectile is small/fast enough to skip over a collision between 2 heartbeats. Otherwise, moving it and just doing basic hitbox detection with GetPartsBoundsInRadius should work (remember to keep the radius for the server higher than the client)

also make sure only one client does this hitbox detection (the person who launched it)

nvm, you should have unique id for each projectile, so that you can tell clients which rocket to destroy. Also, decide whether you want the client to automatically destroy their projectile after some time or wait for the server’s command

so if some dude is hacking and he claims to have damaged me, I get kicked?

Horrible idea. Never do this. Failing a magnitude check is NOT conclusive evidence to ban someone. A client ‘spoofing’ the position may just be latency or inaccuracy in your system.

if the hitbox is gonna stay there all the time, then you might as well have the client decide if they wanna have the hitbox visualized based on their setting

Why would the server need to differentiate between them?

If I simply made every rocket’s hitbox have a raycast, would that be more expensive optimization-wise?

meant to say the person who fired the rocket, not the enemy :joy:

true, I’ll take that into consideration and not do that then

How exactly would I go about doing that? Could I use the ID’s you mentioned to check that? and could an exploiter client spoof that?