Stop a client authoring the clock its own shots are judged against - #150
Merged
Conversation
usercmd.gameTime arrives from the client and reaches the game unchanged, where anything that measures a command's age against the server clock becomes a dial the client can turn. Overwriting it with the frame index the server already filed the command under is a no-op for an honest client - that is exactly what idAsyncClient sends - and it removes the dial permanently. Staleness detection is unaffected: a slot that was never received still holds a stamp from a whole backup window ago, so DuplicateUsercmd still fires. Add tools/tests/mp_lag_compensation_contract.py, and register it in the two workflows and the local validation profile. Lag compensation was pinned by nothing in either repository, which is how it came to ship with a rewind that could not measure what it was for. The contract pins three agreements: the estimate must not be derived from the command's age, the hit target must be restored before anything acts on the hit, and a discontinuity must invalidate the history. It also pins net_mpLagCompensation at 0, so the default cannot be flipped by accident - only deliberately, by editing the assertion with it. Pairs with openQ4-game "Make the lag-compensation rewind measure something, and put the target back". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
mp_lag_compensation_contract.py asserts code that exists only in openQ4-game 6804902, so the pin has to move with it or the engine's cross-repo tests would assert contracts against a tree that predates them. 6804902 is the tree these engine commits were measured against, and it carries all three merged multiplayer changes: the projectile prestep (#11), remote-player re-simulation (#12) and the lag-compensation rewind (#14). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Engine half of the multiplayer lag-compensation work. Pairs with openQ4-game #14, which is merged.
The sanitisation
usercmd.gameTimearrives from the client and reaches the game unchanged, so anything that measures a command's age against the server clock becomes a dial the client can turn. Overwriting it with the frame index the server already filed the command under is a no-op for an honest client — that is exactly whatidAsyncClientsends — and it removes the dial permanently.Staleness detection is unaffected: a slot that was never received still holds a stamp from a whole backup window ago, so
DuplicateUsercmdstill fires. Worth noting the obvious exploit is the mirror of the intuitive one — stamping the value low is self-defeating becauseDuplicateUsercmdoverwrites it, so the live vector was stamping it high.The contract
Lag compensation was pinned by nothing in either repository, which is how it came to ship with a rewind that could not measure what it was for.
tools/tests/mp_lag_compensation_contract.pypins three agreements:RunFramehas advancedtimepast it);It also pins
net_mpLagCompensationat 0, so the default cannot be flipped by accident — only deliberately, by editing the assertion alongside it. Registered in both workflows and the local validation profile.Pin bump
OPENQ4_GAMELIBS_SHAmoves to6804902, which is the tree these commits were measured against and carries all three merged multiplayer changes (openQ4-game #11, #12, #14). The contract test asserts code that exists only there.🤖 Generated with Claude Code