Quick Flow
지연 보상(lag compensation)은 client가 발사했을 때 화면에서 본 과거 상태를 server가 제한적으로 되감아 hit을 판정하는 방식입니다. client가 적을 맞혔다고 확정하지 않으며, server가 보관한 history와 server가 추정한 command 시각으로 판정한 뒤 현재 world로 돌아옵니다.
server가 tick마다 player의 hitbox history를 기록
-> fire command 수신
-> server가 허용 가능한 과거 판정 시각을 추정·제한
-> 해당 시각의 대상 hitbox만 임시로 복원
-> server raycast·피해 규칙 적용
-> 현재 state로 복귀하고 결과 event 전송| 결정 | 서버가 정할 값 | 한쪽으로 치우쳤을 때 |
|---|---|---|
| history 기간 | 최대 되감기 시간과 memory 예산 | 길면 엄폐 뒤 피격이 늘고, 짧으면 고지연 입력이 불리 |
| 대상 | player hitbox, 일부 NPC 등 | 월드 전체를 되감으면 비용·부작용 증가 |
| 판정 시각 | server가 추정한 command 발생 시각 | client timestamp를 그대로 믿으면 조작 가능 |
| 적용 행동 | hitscan·근접 판정 등 | 투사체·지속 효과까지 같은 방식으로 적용하면 규칙 혼선 |
function resolveHitscan(session: Session, command: FireCommand, now: Tick) {
const rewindTick = clamp(
session.estimateCommandTick(now),
now - MAX_REWIND_TICKS,
now
);
return history.withRewoundHitboxes(rewindTick, () =>
world.validateHitscan(session.playerId, command.aim)
);
}무엇을 되감을까
가장 흔한 대상은 다른 플레이어의 위치와 hitbox입니다. 발사 command가 network를 건너오는 동안 target은 이미 이동했을 수 있지만, shooter의 화면은 보간 지연까지 포함한 과거 상태를 보고 있었을 수 있습니다. server는 이 차이를 보정할 수 있는 범위에서 target의 history를 샘플링해 raycast를 수행합니다.
현재 server state 전체를 과거로 바꾸고 다른 시스템 tick까지 다시 실행할 필요는 없습니다. hit 판정에 필요한 transform·hitbox·alive state처럼 최소한의 read-only representation을 만들고, 판정 callback이 끝나면 즉시 현재 state를 유지하는 방식이 안전합니다. 다른 player의 cooldown, inventory, AI decision까지 과거로 돌리면 concurrent tick과 부작용이 복잡해집니다.
투사체는 별도 선택이 필요합니다. client가 쏜 시점의 muzzle 위치를 되감아 생성할지, server가 command를 수신한 현재 tick에 생성할지, hitscan처럼 한 번에 판정할지는 게임 rule과 무기 성격에 따라 다릅니다. 모든 공격을 하나의 rewind rule로 묶지 않습니다.
판정 시각을 신뢰하지 않기
client가 보낸 timestamp는 참고 정보일 수는 있어도 그대로 신뢰할 권한 정보가 아닙니다. server는 수신 시각, session의 지연 추정, client interpolation 정책을 근거로 허용된 판정 시각을 계산하고 최대 과거 범위로 clamp합니다. input sequence는 중복 command를 막고 승인 지점을 알리는 데 쓰며, 그 자체를 과거 시각으로 해석하지 않습니다. 너무 오래된 command, 미래 시각, 이미 처리한 sequence는 거부합니다.
history에는 tick별 position만이 아니라 teleport·respawn·사망·map 이동 같은 불연속 event도 기록해야 합니다. teleport 직전과 직후를 선형 보간하면 존재하지 않았던 위치의 hitbox가 만들어집니다. history version 또는 discontinuity flag를 두고, 경계를 넘는 rewind는 현재 state 또는 명시적 실패로 처리합니다.
공정성과 비용의 경계
지연 보상은 공격자 입장에서는 조준했던 대상에 맞았다는 느낌을 주지만, target 입장에서는 이미 엄폐한 뒤 피격되는 상황을 만들 수 있습니다. 어느 정도의 과거까지 허용할지, 고지연 client를 어떻게 제한할지, 근접전·피격 판정·관전 화면에 같은 정책을 적용할지는 게임 장르의 공정성 선택입니다.
history를 길게 보관하고 모든 entity를 매 tick 복제하면 memory와 CPU 비용이 커집니다. 실제로 되감길 대상, 기록 field, history 간격, 동시에 실행할 판정 수를 profile합니다. 지연 보상은 네트워크 문제를 없애는 기능이 아니라, 어느 시점의 세계를 공정한 기준으로 볼지 정하는 server rule입니다.
client가 본 과거 화면을 존중하더라도, hit 결론은 항상 server가 내립니다. client가 targetId와 damage를 보내고 server가 history만 맞춰 주는 구조는 지연 보상이 아니라 신뢰 경계의 우회입니다.
참고 링크
2 sources