Today I Learn
[TIL][C++] 250623 MMO 서버 개발 41일차: 클라이언트를 믿지 못하는 서버의 충돌 판정 처리
pledge24
2025. 6. 24. 00:19
주의사항: 해당 글은 일기와 같은 기록용으로, 다듬지 않은 날것 그대로인 글입니다.
클라이언트를 믿지 못하는 서버의 충돌 판정 처리
- 온라인 게임을 제작할 때 항상 명심해둬야 하는 사실은, “클라이언트를 절대 믿어선 안된다”는 것이다. 개발자 입장에서 가져야 할 태도는 [클라는 모든 소스코드와 데이터가 공개되어 있고, 모든 보안은 서버에서 처리한다]가 되어야 한다.
온라인 게임에서의 충돌 판정 처리의 차이점
- 문제는 이러한 태도와 사실을 기반으로 온라인 게임을 제작하기 시작하면 게임 엔진에서 제공하는 충돌 판정을 사용하지 못하는 경우가 발생하게 된다. 만약, 온라인 게임이 아닌 오프라인 게임(콘솔 게임류)이라면 아래와 같이 진행되겠지만,
- 캐릭터가 나무 쪽으로 이동한다.
- 캐릭터가 나무에 닿으면 나무의 콜라이더와 충돌 판정이 발생한다.(게임 엔진에 의해)
- 충돌 판정에 의해 나무로 뚫고 이동하는 것을 막는다.
- 온라인 게임인 경우 클라이언트 프로그램의 충돌 판정을 사용할 수 없기 때문에 아래와 같이 진해되어야 한다.
- 서버에서 캐릭터 1의 이동을 처리한다.
- 캐릭터가 나무에 충돌했는지 계산하고, 나무와의 충돌 판정이 발생한다.(서버 내부 코드에 의해)
- 충돌 판정에 의해 나무를 뚫고 이동하는 것을 막는다.
서버에서 충돌 처리를 할 경우 발생하는 문제
- 대부분의 게임의 경우, 서버는 10Hz(100ms) 보다 높은 업데이트 주기를 가져갈 수 없기 때문에 모든 충돌 판별을 전부 다 하기엔 무리가 있다. 왜냐하면 업데이트 주기 사이에 발생한 이벤트들의 타이밍 구분이 되지 않기 때문이다.
대표적인 예시: FPS 장르의 Super Bullet
- FPS 장르에서 사용하는 총기의 연사 속도는 750 RPM이거나 그 이상이 된다. 즉, 분당 발사할 수 있는 총알이 750개 이상이며, 총알 하나가 80ms 마다 발사되거나 80ms 보다 짧은 시간에 발사된다는 것이다.
- 만약, 서버가 100ms를 업데이트 주기를 가지고, 모든 총알은 히트스캔 방식이 아닌 투사체 방식(projectile)이라면, 각 총알 투사체들은 100ms 보다 빠르게 연사 되기 때문에, 한 번의 업데이트 주기에 여러 개의 총알이 발사 처리 및 이동 + 피격 처리가 되어야 한다.
- 이렇게 발사된 두 총알을 하나의 캐릭터가 맞았다면, 사람 1을 컨트롤하는 유저의 입장에선, 한 번에 2배의 피해를 받는, 일명, “Super Bullet”에 의해 피해를 받는 경험을 하게 된다.
// 이전 업데이트 주기의 상황
- - [사람1]
// 현재 업데이트 주기의 상황
[사람1] - -
// 현재 업데이트 주기의 시뮬레이션 결과
// 기대한 결과: 첫번째, 두번째 나눠서 피해를 입음
// 실제 결과: 첫번째, 두번째 한 번에 피해를 입음
또 다른 문제: 이게 왜 맞는 거지?
- 서버에서 업데이트 주기가 느릴수록 클라이언트에서 진작에 뜬 자리에 계속 캐릭터가 남아있기 때문에 해당 위치로 날아오는 모든 투사체를 다 맞게 된다.
- 문제는 기본적으로 총알이 날아가는 속도는 굉장히 빠르기 때문에, 느린 업데이트 주기에 의한 안 맞을 총알에 피격되는 횟수가 꽤 많다는 것이다.
FPS에서 발생하는 Super Bullet 문제의 해결책: 보다 빠른 업데이트 주기
- 무식하지만 가장 효과적인 방법이라고 본다. 서버의 업데이트 주기를 10hz가 아닌 30hz까지 올려서 Super Bullet 문제를 유의미한 정도까지 해결할 수 있다.
- 그래서 실제로 FPS 게임들은 30Hz~60hz 정도의 높은 업데이트 주기를 유지한다.
MMORPG 장르의 충돌 판정 처리
- 사실 위와 같이 30hz로 높은 업데이트 주기를 가져야 한 하는 경우는 많지 않다. (속도가 빠른 오브젝트가 있는 레이싱 게임이나 FPS 게임에서만 고려하는 듯하다) MMORPG의 경우도 10hz만 들고 가도 전반적인 충돌 판정에 큰 문제는 없다.
- 그럼에도 불구하고, 워낙 MMORPG 게임 서버가 처리해야 할 작업이 많기 때문에 모든 충돌 처리를 도맡아서 하기에는 문제가 있다. 예를 들어, 공중 도약 후, 지면과 충돌이 발생하면 충격파를 발생시키는 스킬을 기획했다면, 서버는 언제쯤 지면에 충돌이 났음을 알 수 있을까? 캐릭터의 위치를 추적해서 지면과 닿는 시점을 추적해야 할까?
- 정석적인 방법은 그렇겠지만, 당연히 이 부분은 서버가 먹는 부하도 생각해야 한다. 데디케이티드 서버로 돌리는 “한 판” 단위의 게임 같은 경우, 아예 게임 엔진을 올려서 시뮬레이션 돌릴 수 있겠지만, MMORPG 같은 경우 그럴 수 없다.
- 결국, “클라이언트의 힘을 빌려 어느 정도 충돌 판정을 받고, 서버에서 러프하게 검사하는 식으로 만들게 된다.”