나만의 작은 도서관
[TIL][C++] 250605 MMO 서버 개발 33일차: NDC 영상을 보고 정리한 글 1(어떻게 예측을 해야할까: 차지게 때리기) 본문
Today I Learn
[TIL][C++] 250605 MMO 서버 개발 33일차: NDC 영상을 보고 정리한 글 1(어떻게 예측을 해야할까: 차지게 때리기)
pledge24 2025. 6. 6. 00:51주의사항: 해당 글은 일기와 같은 기록용으로, 다듬지 않은 날것 그대로인 글입니다.
이번 TIL은 아래 영상을 시청하고 정리한 글입니다.
https://youtu.be/HSRo7 TAV4 T4? si=BrW2 TNlgXAYGMmVK
정보의 전달에는 “지연 시간”이 존재한다.
- 네트워크 지연 시간은 흔히 “핑(Ping)”이라고 부르는 것, 개발자들은 “레이턴시(Latency)” 또는 “트립 타입(Trip Time)”이라고 부르는 것을 의미한다. (이하 지연 시간이라 칭함)
- 지연 시간은 호스트가 서버를 거쳐 다른 호스트로 데이터가 전송되면서 걸리는 시간이다. 지연 시간은 네트워크 종류에 따라 다른데, 알려진 바에 따르면 각 네트워크 종류에 따른 지연 시간은 다음과 같다.
- 유선 네트워크(PC): 평균 10ms, 많아야 20~30ms정도
- 무선 네트워크(wifi, LTE): 짧게는 100ms, 이동통신(핸드폰)은 200~300ms까지도 나옴
어느 정도 지연되어야 유저가 인지하는가?
- 게임을 할 때 FPS는 보통 30 FPS이거나 60 FPS이다. 30 FPS와 60 FPS일 때 한 프레임이 유지되는 시간을 구하면, 30 FPS는 33ms, 60 FPS는 16ms 정도로 계산된다.
- 유저는 프레임이 밀리면 ‘게임이 부자연스럽다’라고 인지하게 된다. 즉, 30 FPS는 33ms, 60 FPS는 16ms 이상의 지연시간을 가질 때 부자연스러움을 느낀다.
지연에 의해 발생하는 문제
- 반응성 저하: 지연이 발생한다는 것은 내가 요청한 행동이 지연 시간만큼 뒤에 내 클라이언트에 적용된다는 것이다. 지연 시간이 1초인 환경에서 스킬을 시전 요청을 서버에 보내면, 대략 1초 뒤에 내 스킬이 발사된다는 것이다.
- 나만 그런 것이 아니다. 내 입장에선 모르겠지만, 다른 캐릭터의 액션 적용 또한 지연된 시간만큼 늦게 발동된 것들일 것이다. (참고로, 다른 캐릭터의 지연 정도는 해당 유저의 네트워크 환경에 따라 1초가 아닐 수 있다.)
- 불안정한 통신 상태: 흔히들 말하는 ‘핑이 튀는’ 상황이 발생할 수 있다. 핑이 튀는 현상은 특히 이동 통신을 하는 핸드폰에서 많이 발생하는데, 핑이 급작스럽게 올라가는, 즉, 네트워크가 급격히 나빠지면 서버는 제때 데이터를 못 보내주는 상황이 발생하게 된다.
- 가장 대표적인 예시로, 다른 유저의 캐릭터가 멍청하게 벽을 향해 계속 이동하다가, 갑자기 내 앞으로 텔포 하는 경우가 있다. 이 현상은 해당 유저의 이동 데이터를 통신을 통해 받지 못해 서버가 이전 결과를 이용해 예측한 이동을 하다가, 통신이 안정화되자마자 받은 이동 데이터를 통해 이동 동기화를 hard 하게 하여 텔포 하는 현상(롤백)이 발생한 것이다.
- 즉, 텔포 현상은 생각한 것과 달리, 통신이 악화되었을 때 서버 프로그래머들이 처리를 해둔 의도된 현상인 것이다. 정리하자면 다음과 같다.
1. 유저의 통신 상태가 악화됨. 2. 서버는 해당 유저로부터 이동 패킷을 받지 못함. 3. 그럼에도 서버는 다른 유저들에게 해당 유저의 위치를 알려줘야하므로 예측된 이동 패킷을 전송함. (벽으로 돌진하는 상황 발생) ------------------- 4. 유저의 통신 상태가 안정화됨. 5. 서버는 해당 유저로부터 이동 패킷을 저때 받음. 6. 서버는 받은 이동 패킷을 통해 다른 유저들에게 새로운 위치를 담은 이동 패킷을 전송(강제 텔레포드 발생)
네트워크 지연의 대처법: 예측과 보정
- 클라이언트는 다른 클라이언트의 데이터가 항상 제때 도착할 것이라고 신뢰할 수 없다. 내 클라든, 다른 클라든, 별의별 이유로 네트워크 통신 상태가 악화되어 와야 할 데이터가 오지 않을 수 있다는 것이다. 그래서 클라는,
- 언제 올지 모르는 원격의 알림(패킷)이 올 때까지 기다리는 것이 아니라,
- 가지고 있는 정보들을 통해서 미리 예측을 하고,
- 정확한 정보가 담긴 원격의 알림(패킷)이 왔을 때 예측한 결과와 비교하여,
- 예측이 틀렸을 경우 정확한 정보에 맞추어서 보정을 한다.
- 위에서 잠깐 이야기했던 롤백 현상도 hard 하긴 하지만 마지막 과정인 ‘예측이 틀렸을 경우, 정확한 정보에 맞추어서 보정을 한다’에 해당한다.
어떻게 예측을 해야 할까: 차지게 때리기
예측을 개선하게 된 배경 1: 논타겟팅 스킬을 위한 “시전 시점”과 “스킬 피격 대상 선정”의 시점 분리
타겟팅 공격의 처리 흐름
- 타기팅 스킬(또는 평타)의 경우 아래와 같은 흐름으로 처리된다.
- A가 B를 타깃 스킬 시전.
- 클라이언트는 서버에게 공격에 대한 처리를 “요청”
- “요청”을 받은 서버는 검증(validation)을 한 다음, 결과를 클라이언트에게 “통지”
- 통지를 받은 클라는 B의 체력을 깎고, 피격에 대한 연출을 적용.
- 타기팅 스킬은 위와 같이 클라이언트가 통지를 받는 순간 피격에 대한 연출이 자연스레 실행되었다. 즉, 성공적으로 맞았다는 판정으로 서버에게 통지받으면 0.5초 뒤에 피격 연출을 했어도 문제가 없다는 것이다.
그렇다면 논타깃은?
- 논타깃 스킬의 경우, 타기팅 스킬과 다르게 시전의 성공이 타깃에게 반드시 맞을 거란 보장이 없다. 투사체가 날아가든, 몇 초 뒤에 해당 영역에 발동하든, 시전이 아닌 발동 시점에 스킬 영역 내에 있어야만 피격 판정을 해야 한다.
- 하지만 이런 논타깃 스킬의 특성을 무시하고 타기팅 스킬과 동일하게 처리하게 되면, 아래와 같은 문제가 발생한다.
- A가 B위에 논타깃 스킬을 시전
- 클라이언트는 서버에게 공격에 대한 처리를 “요청”
- “요청”을 받은 서버는 검증(validation)을 한 다음, 결과를 클라이언트에게 “통지”
- 통지를 받은 클라는 B의 체력을 깎고(?), 피격에 대한 연출을 적용.
- 타기팅 스킬에선 이상한 점이 아니었던 마지막 과정이 논타깃 스킬에선 굉장히 이상한 상황이 되었다. 발동은 한참 뒤에 실행될 수도 있는데, 시전 한 시점에 스킬 영역 안에 있었다는 이유로 피격되기 때문이다.
- 즉, 논타깃을 타기팅과 같은 로직으로 처리하는 경우, 영역 안에 있는 대상을 타깃으로 바로 선정했을 때 그 대상들이 스킬 영역 밖으로 도망을 가도 피격되는 문제가 발생하게 된다.
분리되어야 할 시점은 한 두 개가 아니었다.
- 결국 논타깃 스킬은 시전 할 때, 발동할 때 시점을 구분하여 처리하면 되었다. 문제는 요구 사항이 쌓이며 이러한 이유로 분리되어야 하는 시점이 점점 늘어났다는 것이다. 예를 들어,
- 쿨다운은 선데 후 타격 전에 돌리고 싶다. (타격 시점과 분리)
- 스킬 시전 중에 넉백 당하면 취소되어야 함(시전 시점과 분리)
- 영역은 그대로, 3번에 걸쳐 영역에 타격(피격 시점을 여러 개로 분리)
- 기를 모으는 시간에 따라 효과가 다르게(시전 시점 내에서 여러 개로 분리)
- 이동하면서 5번 정도 주변에 있는 대상들을 순서대로 밀어낼 수 있어야…(어… 아무튼 분리)
- 요구 사항은 언제 얼마나 올 지 모르는데, 올 때마다 새로운 시점을 분리한다는 것은 굉장히 부담되는 작업이 된다. 어떻게 해서든 해결해야 한 부분이었고, 이는 새로운 시스템을 도입해 해결하기로 하였다. 그것은 바로 “스킬 스테이지” 시스템!
예측을 개선하게 된 배경 2: 합리적인 시점 분리를 위한 “스킬 스테이지” 시스템 도입
- 스킬 스테이지는 스킬을 시전 할 때부터 스킬의 발동 및 후처리까지의 과정에서 발생하는 각 이벤트들을 그룹화하여 처리하는 방식이다.
- 각 이벤트를 추가할 때, 해당 이벤트가 처리되어야 할 스테이지에 분류되고, 스킬이 시전 된 다음 스테이지가 진행되면서 속한 스테이지가 진행될 때 해당 이벤트가 처리된다.
- 이러한 스킬 스테이지를 이용하면 처리되어야 할 각 이벤트마다 시점은 분리하지 않아도 된다!
LTE, 이동통신망 환경에서 생긴 문제: 때리기도 전에 피격 모션이 연출된다.
- LTE를 사용하는 이동 통신망 환경은 핑이 튈 가능성이 높다. 언제 200~300ms 지연을 찍어도 이상하지 않은 환경이라는 것이다.
- 문제는 이동 통신망 환경에서 캐릭터가 때리기도 전에 피격 모션이 마중 나오듯 먼저 연출되는 상황이 발생한다는 것이다. 해당 현상은 유저의 경험을 떨어뜨리는 결과로 이어지는 문제이다.
원인은 무엇일까?
- 문제는 위에서 도입한 스킬 스테이지와 관련이 있다. 각 스테이지는 하나의 결정 시점이 되고, 각 결정 시점마다 패킷을 전송하게 되는데, 전송할 때 각기 다른 지연 시간으로 전달이 되는 경우 원하는 타이밍에 전달이 되지 않기 시작한다.
- 즉, 스킬 사용에 대한 통지를 받고 스킬을 사용하였는데(시작 스테이지), 피격된 대상의 피격 결과 통지를 받을 때 갑자기 핑이 튀면서 뒤늦게 피격 연출이 발생하거나, (위 사진을 기준. 공격 후 한참뒤 피격 연출), 반대로 갑자기 핑이 좋아지면서 예상보다 통지가 빨리 도착해 피격 연출이 먼저 발생(피격 연출 후 공격)하는 것이다.
현재 상황에서의 결론: 네트워크가 불안정하면 필연적으로 타격 모션과 피격 연출이 어긋난다.
어떻게 해결해야 할까?
- Sol?. 처음부터 클라이언트에서 모든 스테이지의 결과를 계산해서 연출한다.
- Res. 계산하는 시점에서 정보가 너무 부족해서 계산을 정확히 하지 못할 가능성이 높음.
- Sol?. 그렇다면 연출을 보여줄 때 클라이언트가 정보가 부족한 상황이었으니, 정보를 채워줘서 예측 가능하도록 하면 되지 않을까?
- ⇒ 아직 시작되지 않은 스킬 스테이지를 미리 계산 및 공유한다.
- → 이에 맞춰 각자 스테이지를 진행
- 하지만, 전체를 미리 계산할 수는 없다(이게 안되었기 때문에 생긴 게 스킬 스테이지)
- ⇒ 계산 가능한 스테이지들을 묶어서 미리 계산하자!
- ⇒ 아직 시작되지 않은 스킬 스테이지를 미리 계산 및 공유한다.
“스킬 스테이지 플로우”: 스테이지를 묶어서 미리 계산하자!
- 반드시 시점을 나눠야 하는 부분만 나누고 나머지는 미리 계산한다.
스킬 스테이지 플로우 도입 전과 후
- 미리 계산된 스테이지를 서버에게 전달 → 서버로부터 통지를 받으면 클라이언트는 해당 스테이지를 실행한다. 대신, 곧바로 실행하지 않고, 속한 스테이지 플로우의 스테이지가 전부 도착할 때 실행한다.
- 타격 애니메이션을 실행하는 스테이지와 피격 효과가 발생하는 스테이지를 하나의 플로우로 묶어 처리함으로써, 타격 모션과 피격 연출이 어긋나는 현상을 해결!
- ⇒ 예측을 잘해서 더 정확한 연출도 보여주고 손맛도 살리는 기능 개선 사례