Advertisement

How to have flexible weapon firerate in multiplayer fps game when using prediction?

Started by September 04, 2024 09:02 AM
4 comments, last by hplus0603 1 week, 1 day ago

How to have flexible weapon firerate in multiplayer fps game when using client side prediction?


Right now I have a multiplayer fps game with tickrate of 40hz. My inputs are sampled @ 40hz on the client and at the same time physics are simulated (player movement). Client sends a sequence number to the server along with his inputs so any ‘weapon shoot’ commands are tick aligned. Server then processes these inputs so it has authority of player movement, toolbelt and hit detection.

40hz gives the following valid rpm values for weapons:

rpm: 2400
rpm: 1200
rpm: 800
rpm: 600
rpm: 480
rpm: 400
rpm: 343
rpm: 300
rpm: 267

If RPM value would be set to like 850 it would effectively make the rpm to 1200 due to tick alignment.

I have couple of options that come to mind:
1) Using subtick system where there is no fixed/discrete ticks. Client samples inputs at fps (frames per second) and bundles them and sends them via some tickrate. But this has an issue, what if the client is running at 300 FPS or even more? It would increase the number of inputs sent to the server and put more stress on the server so the sampling would need to be clamped to e.g. 120hz but it has the same issue (=weapon firerates are tick aligned)

2) Use variable tick where there is range of min/max sampling tickrates (e.g. [40hz, 120hz]) and discrete ticks. This allows for setting the firerate more accurately. These would be the valid firerate values:
rpm: 7200
rpm: 3600
rpm: 2400
rpm: 1800
rpm: 1440
rpm: 1200
rpm: 1029
rpm: 900
rpm: 800
rpm: 720
rpm: 655
rpm: 600
rpm: 554

(for example, you get values 1440 and 1800 between 1200 and 2400)

I have searched far and wide information about this with no success.

ForeverCoder1526 said:
Client sends a sequence number to the server along with his inputs so any ‘weapon shoot’ commands are tick aligned. Server then processes these inputs so it has authority of player movement, toolbelt and hit detection.

For understanding, does the server rewind the simulation so the input is considered within the same 40Hz time window? Or does the server process the input in the same time window it was received? Or do you do something else to resolve latency?

In general <50ms ping (round trip) is typically considered good for Internet-based games in a single region. Crossing the US, crossing Europe, or crossing an ocean can easily hit 100+ ms, potentially far more. For comparison, Unreal's network simulation uses 60-120 ms ping (30-60ms random each way) and 1% random packet loss as “average network condition” and 200-400 ms ping (100-200 each way) and 5% random packet loss as “bad network condition”, with the recommendation that games should try to remain playable even under those “bad” conditions.

How you deal with network latency makes all the difference to a network game.

Under “average” conditions and your 25 ms / 40Hz frames for processing the event would generally arrive about 4-5 frames late to the server. That's a frame to collect it on the client, 2-3 frames in transit, and the frame to process it on the server. How are you accounting for the latency in your simulation?

Advertisement

Yeah so right now each client runs before the server in their own timeline. Server executes their inputs when it receives them (at most one per tick). Simulation is only rewound whenever player uses any hitscan item (=lag compensation).

There aren't really any latency related issues. We have playtested the game and it runs fine when some people have even 200ms ping when connected.

In that case, I'd look at whatever it is that is triggering your RPM (rounds per minute? rotations per minute? rabbits per minute? something else?).

I'm going to assume you've gone the sane route of an event (start/stop) rather than creating and destroying hundreds of items per second across a network, so that would be the next place to look. When you get a start event, are you triggering that many RPM on both the client simulation and the server simulation, and then turning it off when you get the end event? I'd check whatever is handling that next. Somehow you've turned the thing on but it is generating inconsistent results while running.

How to have flexible weapon firerate in multiplayer fps game when using client side prediction

Assuming “rpm” is “rounds per minute,” then you need to take this into account in your simulation loop and asset creation.

For the sound of automatic fire, you should not re-trigger a shot effect for each round, but instead play a sound effec that has a recorded loop with the right timing. You might even drive the rest of the animation off of the sound playback location!

For the simulation, you have some choices:

  1. Fix your simulation rate, and only allow RPMs that are an even multiple. For 40 Hz sim rate (which is very low for a modern game,) this would let you do 2400 rpm, 1200 rpm, 800 rpm, and so on. This isn't great if you want very high rates of fire.
  2. Fix your simulatiopn rate, and allow multiple rounds per simulation step, but they all shoot at the same time, if the animation says you need to fire more than one. E g you keep a timer for how long the weapon has been firing, and how many rounds have been shot, and when “time * rpm - shot” is greater than or equal to 1, you simulate that many shots being spawned. For weapons with spread, this is still OK, for hitscan weapons, this obviously has problems.
  3. Cheat! You play the appropriate sound effects for the higher fire rate, but don't actually simulate that many bullets.
  4. Split simulation steps into multiple sub-steps, where the position of an object is interpolated to the position within the sub-step. Emit each round at the exact correct time within the substep by doing appropriate math. You don't need to collision detect players versus environment for each substep; instead, you simulate the player movement from T-1 to T, and then you simulate the bullets, and simply interpolate the player position at the fractional step based on that simulation outcome.
  5. Drastically increase your simulation rate, and use any of the above options. 120 Hz is a perfectly fine simulation rate for a modern game. Some monitors render at 240 Hz, so that's a good option, too. You could even be crazy and go to 1000 Hz simulation rate, which lets you adjust with less than a millisecond of jitter to any effective display rate.
enum Bool { True, False, FileNotFound };
Advertisement