Is this a viable solution to stopping projectile lag?

Greetings.

I am working on a game with tons of weapons, all being projectile based. I had a problem with projectile lag. The projectiles all act differently from each other (ex. some have dynamically changing sizes, speeds), but nothing that setting the network owner to the player that fired it didn’t solve (they’re specifically designed for this, for example there won’t be a boomerang projectile because the client would need to have custom code for it). This works fine, but I’m extremely cautious about this. There’s several implications with making projectiles owned by the client.

  1. Laggy players = laggy projectiles.
  2. Pausing the Roblox client (it’s public knowledge how to do this but I still won’t say it) = paused projectiles.
  3. And worst of all, exploiters could immediately teleport all their projectiles to enemy gamers.

These are enough for me to look for a better solution. Making the server own projectiles isn’t possible, as when that used to be the case, there would be obvious lag when firing a projectile (it would pause for about half a second before flying).

My theorized solution is as such:

  1. On the server, tag all projectiles before firing with something in CollectionService.
  2. On the client, use CollectionService.GetInstanceAddedSignal to detect when a projectile is spawned (fired).
  3. Still on the client, clone the projectile and parent it to Workspace, then hide away the old one (anchor it and shove it into a service is my idea, but how I do it isn’t important). Thus, we get a local projectile with all the same information as the last one. At the same time, the server still has its projectile which is the actual one that’s going to deal the damage.
  4. When the server projectile dies, because the client didn’t destroy the server projectile, CollectionService.GetInstanceRemovedSignal will be called. The client will then destroy the local projectile.

In short, all projectiles on the server are cloned on the client but removed at the same time.

What could potentially happen with this? Is this a good idea?

7 Likes

use Ping counter

Are you assuming FE is on?
You should be using RemoteEvents to tell the server about a projectile, rather than relying on the server detecting you creating a projectile. That will definitely not go over well when you decide to convert to FE.

Ideally, the flow should be, depending on who you give the projectile to:
Client fires a shot, tells the server. The server tells the other clients and the other clients begin to render the bullet. (On Roblox, you can also just render it on the server and it will be automatically replicated) The first client renders the bullet on his own and calculates the trajectory and hitmarkers. When the first client makes a hit, inform the server. Ping will affect this, but sometimes it is for the better.

I also highly recommend you use raycasting rather than the more archaic projectiles, for several reasons.

  • Rays are less prone to both latency and physics lag, due to having less to replicate and calculate.
  • Rays have much more reliable hit detection
  • Rays are a lot more predictable, and you have the freedom to do a lot more with them
6 Likes

This solves nothing.

1 Like

Rays are for guns and other hitscan weapons. That’s not my game.

The client isn’t the one making the projectiles, the server is. The client makes its own local projectiles so it doesn’t rely on the server’s physics.

One possible solution is to have the clients do all of the animation work and the server none at all, and the person who is shooting the projectile be in charge of sending the collision position and/or hit part to the server (exactly what you didn’t want but pls read on xd)

BTW I’m assuming you aren’t simulating drag or any of that fancy stuff, just gravity

The server then knows the following stuff:
The initial fire position, the initial velocity, and supposedly a point (the collision position) along the trajectory

You can then use some fancy formula to find the closest point (and then find the magnitude between this and the collision point)/distance between the trajectory quadratic and the collision point

If this distance > some threshold then you know the player tped the projectile / is lagging and so you should disregard it

I have to be afk for a bit now but I’ll let you know if I find an actual implementation of closest point, if you find it first though please share it XD

heres some trajectory formulas that might help (you might not even need closest point, finding different in y for a given x or x for a given y might suffice):

local function trajectory(v,theta,x)
	-- the trajectory a projectile will take assuming 0 air resistance, drag, etc (only accounts for gravity)
	
	return x*tan(theta) - g*x*x/(2*v*v*cos(theta)^2)
end

local function inverseTrajectory(v,theta,y,onRight)
	-- finds at what x the y will be reached
	-- you need to tell whether or not the x value lies on the right side (bool) of the function because there are two points where the y can occur; if its right on middle then you would know xd but also onRight doesn't matter for it because they intersect
	
	local cos2 = cos(theta)
	cos2 = cos2*cos2
	local tan = tan(theta)
	
	local a1 = (v*v*cos2)/g
	if onRight then
		return a1*(tan + (tan*tan - 2*y/a1)^0.5)
	else
		return a1*(tan - (tan*tan - 2*y/a1)^0.5)
	end
end
2 Likes

Yes this is exactly what I don’t want to read, haha. I read the rest of your post but if it all seems to hinge on this idea then I don’t want to go through with it. Not only is there the possibility of more crafty exploiters, but then you also have the possibility of latency being an issue.

I appreciate the idea, but this just wouldn’t work for my game.

If you’re not looking for a client authoritative model or to use math for safety checks (which you can make 99.9999% secure (if you clamp max x and min x using time since fire) but at the cost that if a client is lagging - as you mentioned - that person’s bullets will get discarded - but then again, that guy probably wouldn’t be playing your game if its that extreme because others would probably easily kill him/her) then probably the only solution is something like you mentioned: where the server keeps a copy of the bullet

TBH I think its better for the server to keep a copy like you mentioned, but there might be some hidden caveats because all the great games like phantom forces don’t do it

What i meant is that if you know the Ping of someone, you could easily know if he is lagging or not. For example lag switcher if still existed, their ping may be too high, so when they disabled it the ping goes back instantly.

This still does not help or solve my issue.

i agree that projectiles are pretty horribly replicated in general. there are quite a few reasons to use other methods.

your solution could work but its not going to look perfect. latency and just lag in general will desync your projectiles putting them in a different situation the server might not have seen it in. basically, the server and client will not see the projectile in the same position at the same point of time. to create a simple scenario:

the server tells client to make a small ball that rolls around the world, a client receives this message and then freezes for a second maybe due to latency or lag spike.
in the time a client was frozen anything could have happened; a player could have jumped on your ball, landscape around the ball changed, etc. this is going to desync the servers projectile from the client; they arent going to see the same thing.

the same thing is going to happen to essentially any kind of projectile you create. maybe for some, to a lesser degree.

i had the same issue in my case and what i did was just use custom replication. basically, i just fired messages through a remote event telling the client(s) where the projectile should be.

Your example is different from my proposed solution. My solution is the server creates the projectile, and by the time the client sees it, the client just stashes away the server projectile and creates a new local projectile with the same properties. Thus, the physics would be synced up.

Unless I have physics lag, and then they would not remain synced. The thing about syncing is it needs to be done more than once or it’s not in sync.

2 Likes

If you have physics lag then at worst you’ll lose a few projectiles, as it’ll probably be temporary. If you’re getting constant physics lag, you probably have issues worse than that that’ll prohibit you from playing.

Have you found an answer to your question?

I have seen multiple threads talking about the same issue, non of them have a solution.

It’s been a year since and maybe a solution was found?


I have one concern, so as you use the client for visuals and make shooting a smooth UX for the players, does this have a negative impact on the projectile’s (& raycast bullet’s) accuracy?

On the client’s PC might see that the bullet hit but on the server it didn’t for example.

I have not noticed a negative impact on projectile accuracy, and I don’t use raycast weapons in my game.

Awesome! Is your game public? I want to see the projectile in action.

I know, I’m asking because I want to know if it has any negative impacts for Raycast too, you might have experience so I ask.


so for me to replicated your method I would use CollectionService and the stuff you mentioned here?

It is (in a super unfinished state) but I haven’t finished the second part of the process which is making it look like the projectile fired from the base of the weapon and then swaying to its true position quickly.

It depends on player latency. For example, Overwatch tells the player they hit their shots (but doesn’t decrease any health bars) locally before the server even recognizes them unless their ping is over a certain threshold.

1 Like

Personally I would have every visual effect rendered by the clients, the effects wouldn’t even exist on the server. Then I would do hit boxes and such server-sided