나만의 작은 도서관

[TIL][C++] 250606 MMO 서버 개발 34일차: NDC 영상을 보고 정리한 글 2(어떻게 보정을 해야할까: 정확하게 때리기) 본문

Today I Learn

[TIL][C++] 250606 MMO 서버 개발 34일차: NDC 영상을 보고 정리한 글 2(어떻게 보정을 해야할까: 정확하게 때리기)

pledge24 2025. 6. 6. 22:23
주의사항: 해당 글은 일기와 같은 기록용으로, 다듬지 않은 날것 그대로인 글입니다. 

이번 TIL은 아래 영상을 시청하고 정리한 글입니다.

https://youtu.be/HSRo7TAV4T4?si=BrW2TNlgXAYGMmVK

 

어떻게 보정을 해야 할까: 정확하게 때리기

 

Q. 상대가 움직이면 잘 맞는데, 가만히 서 있으면 잘 안 맞아요.

  • 원인을 파악해 보니, 각 클라이언트에서 보이는 캐릭터 위치가 살짝씩 달라서 발생한 문제였다.
  • 디버깅을 해보니 스킬을 사용한 시전자, 피격자의 위치가 각 클라와 서버가 전부 다르게 가지고 있었다!

 

이러한 결과가 나타난 배경

  • 프라시아 전기라는 게임은 바닥에 폴리를 깔고, 각 캐릭터가 폴리 위를 자유롭게 돌아다닐 수 있도록 하는 방식의 게임이다.
  • 처음에는 스킬처럼 서버의 허가를 받고 이동하는 서버 주도적 이동 방식을 사용했지만, 아무래도 서버를 찍고 돌아와야지 이동할 수 있다는 것 때문에 조작감이 크게 떨어졌다.
    • 결국, 서버에게 이동한 위치를 통지하는 “클라 주도적 이동 방식”을 채택

 

클라 주도적 이동 방식의 채택

  • 서버 주도적 이동 방식은 장점은 서버가 클라로부터 위치를 받고 한 번에 뿌려주기 때문에(Broadcast), 지연 시간에 따라 약간의 오차가 있을 수 있지만 대체로 맞아떨어진다.
  • 하지만, 클라 주도적 이동 방식은 서버의 허락 없이 클라가 계속 이동하므로, 지연 시간의 영향을 서버 주도 방식보다 영향을 크게 받는다. 즉, 내 클라, 다른 클라, 서버가 알고 있는 위치가 전부 다르며, 오차 또한 커지게 된다.

  • 프라시아 전기는 대규모 전투를 할 수 있는 환경을 조성해야 한다. 따라서 각 캐릭터의 위치를 짧은 빈도로 동기화하는 방식은 감당할 수 없는 트래픽을 발생시키기 때문에 적용할 수는 없었고, 그렇기에 “적당한 길이의 이동 구간을 만들어서 동기화”하는 방식을 채택하였다.
    • 즉, 다른 클라이언트가 드문드문 동기화를 위한 이동 패킷을 서버에게 전송한다면, 내 클라이언트는 해당 패킷을 서버를 통해 받고, 받은 패킷의 이동 정보를 이용해 “적당한 길이의 이동 구간”을 만들어 다른 캐릭터를 이동시킨다.

 

왜 멈춰있을 때 더 차이 나는가? (아마도 지면 클릭 이동인 듯)

  • 캐릭터가 목표 위치(터치로 찍은 지면)까지 이동한다면, 위치의 오차는 크지 않다.
    • 추가 설명: 지연에 따른 예측(데드 레커닝)을 하든, 지연을 고려하지 않든 동시간대 오차는 발생하지만 그 차이는 크지 않다는 의미인 듯하다.
  • 하지만, 캐릭터가 목표 위치를 재설정하거나, 멈춰버리면 위치의 오차가 크게 발생하기 시작한다.
    • 목표 위치를 재설정(특히 방향을 크게 트는 경우)하는 경우는 그나마 낫다. 다음 목표 위치가 있기 때문에 방향을 재설정하여 보정하면 되기 때문이다. 도중의 오차가 발생하긴 하지만…
    • 반면, 캐릭터가 갑자기 제자리에 멈춰버리는 경우, 클라이언트는 해당 캐릭터의 방향에 대한 데이터가 없어지게 되는데, 문제는 ‘어느 위치에 멈춘다!’라는 정보가 왔을 때 이동으로 보정하기 난감해진다.
      • 캐릭터가 멈추는 시점을 넘지 않았다면 이동을 하여 보정을 할 수 있지만, 멈추는 시점을 이미 넘어서 처리하는 중이라면 캐릭터가 예측으로 더 가있는 상황에서 멈춰야 하기 때문에 위치의 오차가 크게 발생한 상태에서 멈춰있게 된다.

 

Q. 그냥 오차가 났을 때 옳은 위치로 캐릭터를 옮기면 되는 거 아닌가요?

  • 이렇게 보간 없이 그 위치로 옮겨서 위치를 동기화하는 방식은 Hard 한 방식이며, 이러한 방식을 롤백(rollback)이라고 한다. 문제는 롤백은 유저의 경험을 떨어뜨린다는 것이다.
  • 프라시아 전기에서는 이 방식을 “즉시 동기화”라고 설명하는데, 적용한 결과에서 엄청나게 많이 캐릭터가 튀기 시작했다고 한다. 즉, 롤백이 너무 많이 발생했다는 것이다.
    • 이렇게 너무 많은 롤백이 발생하면 유저 경험을 크게 떨어뜨리므로, 적합한 방법은 될 수 없다.
    •  

갑자기 멈췄을 때도 보정할 수 있는 구간을 만들자!

 

핑의 표준 분포표와 튀는 핑에서의 캐릭터 이동 멈춤 처리

  • 이 그래프는 게임 도중 발생하는 핑의 표준 분포표이다. 그림으로 예를 들자면, 120ms 핑이 가장 많이 발생했으며, 핑이 좋아지는 경우 40ms, 나빠지는 경우 200ms까지 올라간다.
  • 다른 캐릭터의 이동 동기화를 할 때 핑이 없으면 좋겠지만, 그럴 순 없으므로 안정적인 핑을 찾아 그에 맞게 예측을 하는 것이 좋다.

현재 보정 방식의 문제점: 핑의 상태에 따른 보정 확률이 반반

  • 문제는 안정적인 네트워크 환경이 아닐 경우, 핑의 상태가 왔다 갔다 하면서 멈췄다는 데이터가 통지되는 시점이 그전에 움직이는 시점의 핑과 다를 수 있다는 것인데, 핑의 상태 변화가 어떻게 되느냐에 따라 아래와 같이 처리한다.
  • 핑의 상태 변화에 따른 처리방식(지연 시간에 대한 추가 보정 없음 기준: 데드 레커닝 안 씀)
    • 핑이 안정적임(120ms): 원래부터 120ms 지연을 기준으로 이동을 시키고 있었다. 따라서, 보정을 하지 않는다.
    • 핑이 갑자기 좋아짐(40ms에 가까워짐): 내 기준에선 다른 캐릭터의 미래의 이동 상태가 전송된 것과 다름없다. 이동 중이었으니 목표 위치를 재설정하면 이동을 통해 보정을 할 수 있다.
    • 핑이 갑자기 안 좋아짐(200ms에 가까워짐): 내 기준에선 다른 캐릭터의 과거의 이동 상태가 전송된 것과 다름없다. 예측을 통해 이미 이동을 더한 상태. 과거의 자리로 돌아가는 것은 이상하니 그저 오차가 발생한 위치에 서있을 수밖에 없다.

 

새로운 보정 방식: 대부분이 보정될 수 있게!

  • 핑이 나쁜 상태에서 멈췄을 때 위치가 동기화되지 않는다면, 보정이 될 수 있는 상한선을 오른쪽으로 밀면 된다. 그러면 아무리 핑이 나빠도 대부분의 이동 데이터가 보정이 될 것이다.
  • 예를 들어 다른 캐릭터의 이동 동기화 데이터를 120ms에 통지받았을 때, 마치 200ms에 받은 것처럼 80ms 뒤에 처리를 해주면 된다.
  • 이렇게 하면, 모든 이동 동기화 데이터가 “미래의 이동 상태”를 전송한 것과 같아지므로, 보정을 할 수 없는 케이스는 거의 사라지게 된다.

결론적으로 이동 동기화에 딜레이를 추가해서 이동을 예측하도록 모델을 바꿈, 멈춘 캐릭터를 못 때리는 것보다 나으니까 ‘조금 오차가 이동 중에 생겨도 괜찮을 것 같다’라고 판단을 한 거죠

 

Tradoff: 이동하는 중의 오차는 오히려 좀 커지게 된다

  • 어찌 보면 당연한 거지만 다른 캐릭터의 이동에 딜레이를 추가했다는 것은 해당 캐릭터의 위치 오차는 더 심해진다. 기존에 120ms 전의 움직임을 바라보았지만, 딜레이를 추가함으로써 200ms 전의 움직임을 바라보기 때문.
    • 즉, 멈췄을 때 안 맞는 최악의 상황을 피하기 위해서 트레이드오프를 감행한 것이다.

유저는 심해진 위치 오차를 용인할 수 있을까?

  • 위 동영상에선, 인간의 인지 특성상 이동하는 물체에 대한 위치 오차는 더 관대하다고 한다. 즉, 사람은 이동하는 물체의 위치는 조금 삐끗 나도 이해하지만, 가만히 있는 거 못 맞추면 이해해주지 않는다는 것이다.

 

결론 및 정리

  • 네트워크를 통하면 예측하지 못한 외부 요인에 의해 주요 상태가 변경되었을 때 예측이 한쪽이 틀리게 된다. 이걸 내가 늦게 알게 되면 틀리게 된다. 이때 바로 보정을 한다.
  • 내가 계산해서 예측을 해서 가지고 있는 현재 상태랑, 믿을 수 있는 소스(서버의 상태)가 서로 다를 경우에 내가 가지고 있는 상태 → 실제 상태를 보정이라고 한다.