I want to handle weapon cool-down timers in a fair and predictable way on both client on server.
- Multiple clients connected to server, which is doing hit detection / physics
- Clients have different latency for their connections to server ranging from 50ms to 500ms.
- They want to shoot weapons with fairly long reload/cool-down times (assume exactly 10 seconds) It is important that they get to shoot these weapons close to the cool-down time, as if some clients manage to shoot sooner than others (either because they are "early" or the others are "late") they gain a significant advantage.
- I need to show time remaining for reload on player's screen
- Clients can have clocks which are flat-out wrong (bad timezones, etc.)
What I'm currently doing to deal with latency:
- Client collects server side state in a history, tagged with server timestamps
Client assesses his time difference with server time:
behindServerTimeNs = (behindServerTimeNs + (System.nanoTime() - receivedState.getServerTimeNs())) / 2
Client renders all state received from server 200 ms behind from his current time, adjusted by what he believes his time difference with server time is (whether due to wrong clocks, or lag). If he has server states on both sides of that calculated time, he (mostly LERP) interpolates between them, if not then he (LERP) extrapolates.
No other client-side prediction of movement, e.g., to make his vehicle seem more responsive is done so far, but maybe will be added later
So how do I properly add weapon reload timers?
My first idea would be for the server to send each player the time when his reload will be done with each world state update, the client then adjusts it for the clock difference and thus can estimate when the reload will be finished in client-time (perhaps considering also for latency that the shoot message from client to server will take as well?), and if the user mashes the "shoot" button after (or perhaps even slightly before?) that time, send the shoot event.
The server would get the shoot event and consider the time shot was made as the server time when it was received. It would then discard it if it is nowhere near reload time, execute it immediately if it is past reload time, and hold it for a few physics cycles until reload is done in case if it was received a bit early.
It does all seem a bit convoluted, and I'm wondering whether it will work (e.g., whether it won't be the case that players with lower ping get better reload rates), and whether there are more elegant solutions to this problem.