레이블이 GAME SERVER인 게시물을 표시합니다. 모든 게시물 표시
레이블이 GAME SERVER인 게시물을 표시합니다. 모든 게시물 표시

Fast-Paced Multiplayer (파트 II) : 클라이언트 측 예측 및 서버 조정

소개

이 시리즈의 첫 번째 기사에서는 서버에 입력을 보내고 서버가 보낼 때 업데이트 된 게임 상태를 렌더링하는 신뢰할 수있는 서버와 바보 클라이언트가 있는 클라이언트 - 서버 모델을 살펴 보았습니다.

이 계획을 간단하게 구현하면 사용자 명령과 화면 변경 간의 지연이 발생합니다. 예를 들어 플레이어가 오른쪽 화살표 키를 누르면 캐릭터가 움직이기 전에 0.5 초가 걸립니다. 이는 클라이언트 입력이 먼저 서버로 이동해야하고 서버가 입력을 처리하고 새 게임 상태를 계산해야하며 업데이트 된 게임 상태가 클라이언트에 다시 도달해야하기 때문입니다.

Effect of network delays.

인터넷과 같이 지연이 10 분의 1 초가 될 수있는 네트워크 환경에서는 게임이 응답이 좋지 않거나 최악의 경우 재생할 수 없게 될 수 있습니다. 이 기사에서는 이러한 문제를 최소화하거나 제거하는 방법을 찾아 볼 것입니다.

클라이언트 측 예측

부정 행위자가 있지만 대부분의 경우 게임 서버는 비 부정한 클라이언트와 그 특정 시간에 부정 행위를하지 않는 속임수 클라이언트로부터 유효한 요청을 처리하고 있습니다. 이것은 수신 된 대부분의 입력이 유효 함을 의미하며 예상대로 게임 상태를 업데이트합니다. 즉, 캐릭터가 (10, 10)에 있고 오른쪽 화살표 키를 누르면 (11, 10)에 끝납니다.

우리는 이것을 우리의 장점으로 사용할 수 있습니다. 게임 세계가 충분히 결정적이라면 (즉, 게임 상태와 입력 집합이 주어지면 결과는 완전히 예측 가능합니다),

우리가 100ms 지연을 가지고 있고 한 사각형에서 다음 사각형으로 움직이는 캐릭터의 애니메이션이 100ms 걸린다 고 가정 해 봅시다. 순진한 구현을 사용하면 전체 동작에 200 밀리 초가 걸립니다.
Network delay + animation.

세계는 결정 론적이기 때문에 우리가 서버에 보내는 입력이 성공적으로 실행될 것이라고 가정 할 수 있습니다. 이 가정 하에서, 클라이언트는 입력이 처리 된 후에 게임 세계의 상태를 예측할 수 있으며, 대부분의 경우 이것이 정확할 것입니다.
Animation plays while the server confirms the action.
서버가 여전히 신뢰할 수 있는 반면 플레이어의 동작과 결과는 절대적으로 지연되지 않습니다 (해킹 된 클라이언트가 잘못된 입력을 보내면 화면에 원하는대로 렌더링 할 수는 있지만 상태에 영향을주지는 않습니다. 다른 플레이어가 보는 것입니다).

동기화 문제

위의 예에서 모든 것을 올바르게 작동하도록 숫자를 신중하게 선택했습니다. 그러나 약간 수정 된 시나리오를 고려하십시오. 서버에 250ms 지연이 있고 정사각형에서 다음 서버로 이동하는 데 100ms가 걸린다고 가정 해 봅시다. 플레이어가 오른쪽 키를 두 번 연속 눌러 2 개의 정사각형을 오른쪽으로 이동하려고합니다.

지금까지의 기술을 사용하면 다음과 같이됩니다.
Predicted state and authoritative state mismatch.
새로운 게임 상태가 도착하면 t = 250ms에서 재미있는 문제가 발생합니다. 클라이언트의 예상 상태는 x = 12이지만 서버는 새 게임 상태가 x = 11이라고 말합니다. 서버가 신뢰할 수 있기 때문에 클라이언트는 문자를 x = 11로 다시 이동해야합니다. 그런 다음 새 서버 상태가 도착합니다 t = 350에서 x = 12라고 말하면 문자가 다시 앞으로 점프합니다.

플레이어의 관점에서 그는 오른쪽 화살표 키를 두 번 눌렀습니다. 캐릭터는 오른쪽으로 두 칸을 옮기고 50ms 동안 그곳에 서서 왼쪽으로 한 칸 스퀘어를 뛰어 올라 100ms 동안 그 자리에 서서 오른쪽으로 한 칸 스퀘어를 뛰어 넘었습니다. 물론 이것은 받아 들일 수 없는 것입니다.

서버 조정

이 문제를 해결하는 열쇠는 클라이언트가 현재 게임 세계를보고 있다는 것을 인식하는 것입니다. 그러나 지연으로 인해 서버에서 가져 오는 업데이트는 실제로 과거의 게임 상태입니다. 서버가 업데이트 된 게임 상태를 보낼 때까지는 클라이언트가 보낸 모든 명령을 처리하지 않았습니다.

하지만 이 문제를 해결하는 것은 그리 어렵지 않습니다. 먼저, 클라이언트는 각 요청에 일련 번호를 추가합니다. 예에서 첫 번째 키 누름은 요청 # 1이고 두 번째 키 누름은 요청 # 2입니다. 그런 다음 서버가 응답하면 처리 된 마지막 입력의 순서 번호가 포함됩니다.
Client-side prediction + server reconciliation.
이제 t = 250에서 서버는 "귀하의 요청 # 1, 귀하의 위치는 x = 11"까지 본 것을 기반으로합니다. 서버가 신뢰할 수 있기 때문에 x = 11에 문자 위치를 설정합니다. 이제 클라이언트가 서버에 보내는 요청의 복사본을 보관한다고 가정 해 봅시다. 새로운 게임 상태에 따라 서버는 이미 요청 # 1을 처리 했으므로 해당 복사본을 삭제할 수 있습니다. 그러나 서버가 여전히 요청 # 2를 처리 한 결과를 되돌려 보내야 한다는 것도 알고 있습니다. 따라서 클라이언트 측 예측을 다시 적용하면 클라이언트는 서버가 보낸 마지막 신뢰할 수 있는 상태와 서버가 아직 처리하지 않은 입력을 기반으로 게임의 "현재"상태를 계산할 수 있습니다.

따라서 t = 250에서 클라이언트는 "x = 11, 마지막으로 처리 된 요청 = # 1"을 얻습니다. 전송 된 입력 사본을 최대 # 1 개까지 버리지 만 서버에 의해 확인되지 않은 # 2 사본을 보유합니다. 서버가 전송 한 내용 (x = 11)으로 내부 게임 상태를 업데이트 한 다음 서버에서 아직 볼 수없는 입력 (이 경우 입력 # 2, "오른쪽으로 이동")을 적용합니다. 최종 결과는 x = 12이며 올바른 값입니다.

예제를 계속 진행하면 t = 350에서 새로운 게임 상태가 서버에서 도착합니다. 이번에는 "x = 12, 마지막으로 처리 된 요청 = 2"라고 표시됩니다. 이 시점에서 클라이언트는 # 2까지의 모든 입력을 버리고 x = 12로 상태를 업데이트합니다. 재생할 입력이 처리되지 않으므로 처리가 올바른 결과와 함께 끝납니다.

잡동사니

위에 논의 된 예는 움직임을 의미하지만, 같은 원리가 거의 모든 것에 적용될 수 있습니다. 예를 들어 턴 기반 전투 게임에서 플레이어가 다른 캐릭터를 공격하면 피와 완료된 피해를 나타내는 숫자를 표시 할 수 있지만 실제로 서버가 말하기 전까지는 캐릭터의 상태를 업데이트해서는 안됩니다.

게임 상태의 복잡성으로 인해 쉽게 되돌릴 수있는 것은 아니기 때문에 클라이언트의 게임 상태에서 상태가 0 이하로 떨어지더라도 서버가 그렇게 말할 때까지 캐릭터를 죽이지 않도록 할 수 있습니다 (다른 캐릭터가 치명적인 공격을 받기 바로 전에 구급 상자가 있지만 서버가 아직 말하지 않았습니까?)

이것은 우리에게 흥미로운 점을 안겨줍니다. 세계가 완전히 결정적이고 클라이언트가 전혀 속임수를 쓰지 않는다고하더라도, 클라이언트가 예측 한 상태와 서버가 보낸 상태가 화해 후에 일치하지 않을 가능성은 여전히 ​​있습니다. 시나리오는 단일 플레이어에서 설명한 것처럼 불가능하지만 여러 플레이어가 한 번에 서버에 연결될 때 쉽게 실행될 수 있습니다. 이것은 다음 기사의 주제가 될 것입니다.

개요

신뢰할 수있는 서버를 사용할 때는 서버가 실제로 입력을 처리 할 때까지 기다리는 동안 플레이어에게 응답 성을 부여해야합니다. 이를 위해 클라이언트는 입력 결과를 시뮬레이션합니다. 업데이트 된 서버 상태가 도착하면 예측 된 클라이언트 상태가 업데이트 된 상태와 클라이언트가 보낸 입력에서 다시 계산되지만 서버가 승인하지 않았습니다.

Fast-Paced Multiplayer (파트 I) : 클라이언트 - 서버 게임 아키텍처

소개

빠르게 진행되는 멀티 플레이어 게임을 가능하게 하는 기술과 알고리즘을 탐구하는 기사 시리즈 중 첫 번째 기사입니다. 멀티 플레이어 게임의 개념에 익숙하다면 다음 기사로 건너 뛸 수 있습니다. 다음은 소개 토론입니다.

어떤 종류의 게임을 개발하는 것은 그 자체로 도전적입니다. 그러나 멀티 플레이어 게임에서는 완전히 새로운 일련의 문제가 추가됩니다. 흥미롭게도 핵심 문제는 인간 본성과 물리학입니다!

부정 행위의 문제

그것은 모두 속임수로 시작합니다.

게임 개발자는 일반적으로 플레이어가 싱글 플레이어 게임에서 속이는지 여부에 상관하지 않습니다. 그의 행동은 다른 사람에게 영향을 미치지 않습니다. 부정 행위자는 당신이 계획 한대로 정확하게 게임을 경험하지 못할 수도 있지만, 자신의 게임이기 때문에 어떤 방식 으로든 플레이 할 권리가 있습니다.

멀티 플레이어 게임은 다르다. 모든 경쟁 게임에서 부정 행위자는 자신의 경험을 향상시키는 것뿐만 아니라 다른 플레이어의 경험을 악화시킵니다. 개발자라면 플레이어를 게임에서 멀리 떨어 뜨리는 경향이 있으므로이를 피하고 싶을 것입니다.

부정 행위를 방지하기 위해 할 수있는 많은 일들이 있지만 가장 중요한 것 (그리고 아마도 유일한 의미있는 것)은 간단합니다. 플레이어를 신뢰하지 마십시오. 항상 최악의 경우를 가정합니다. 플레이어가 속이려고 시도합니다.

신뢰할 수있는 서버 및 DUMB 클라이언트

이것은 겉으로 보기에는 간단한 해결책으로 이 끕니다. 게임의 모든 것을 중앙 서버에서 제어 할 수있게 만들고 클라이언트가 게임의 특권을 얻은 관람자가되게합니다. 즉, 게임 클라이언트가 입력 (키 누름, 명령)을 서버에 보내고 서버가 게임을 실행하고 결과를 클라이언트에 다시 보냅니다. 이것은 일반적으로 권위있는 서버를 사용하여 호출됩니다. 왜냐하면 전 세계에서 일어나는 모든 일과 관련된 유일한 권한은 서버이기 때문입니다.

물론 서버가 취약점을 악용 될 수는 있지만 이는이 연재 기사에서 다루지 않습니다. 하지만 권위있는 서버를 사용하면 광범위한 해킹을 막을 수 있습니다. 예를 들어, 플레이어의 건강 상태로 클라이언트를 신뢰하지 않습니다. 해킹 된 클라이언트는 해당 값의 로컬 사본을 수정하여 10000 %의 상태를 플레이어에게 알릴 수 있지만 서버는 해킹 된 클라이언트가 생각할 수있는 것과 관계없이 플레이어가 공격 당하면 죽을 것입니다.

당신은 또한 세계에서의 지위를 가진 플레이어를 신뢰하지 않습니다. 그랬다면 해킹 된 클라이언트가 서버에 "내가 (10,10)에 있고"두 번째에 나중에 "(20,10)에"있다고 말하면서 벽을 통과하거나 다른 플레이어보다 빠르게 움직일 수 있습니다 . 그 대신에 서버는 플레이어가 (10,10)에 있다는 것을 알고, 클라이언트는 "나는 하나의 정사각형을 오른쪽으로 옮기고 싶다"라고 서버에 알리고, 서버는 (11,10)에 새로운 플레이어 위치로 내부 상태를 업데이트하고, 플레이어에게 "You 're at (11, 10)"이라고 응답합니다.
A simple client-server interaction.
요약하면 게임 상태는 서버 단독으로 관리됩니다. 클라이언트는 서버에 작업을 보냅니다. 서버는 주기적으로 게임 상태를 업데이트 한 다음 새로운 게임 상태를 다시 화면에 표시하는 클라이언트에게 보냅니다.

네트워크 다루기

벙어리 클라이언트 계획은 예를 들어 전략 게임이나 포커와 같은 느린 회전 기반 게임에서 잘 작동합니다. 또한 통신이 모든 실질적인 목적을 위해 즉각적으로 이루어지는 LAN 설정에서도 작동합니다. 그러나 이것은 인터넷과 같은 네트워크를 통해 빠르게 진행되는 게임에 사용될 때 고장납니다.

물리학에 대해 이야기 해 봅시다. 뉴욕에 있는 서버에 연결된 샌프란시스코에 있다고 가정합니다. 그것은 약 4,000km 또는 2,500 마일 (리스본과 모스크바 사이의 거리)입니다. 빛보다 빠르게 움직일 수있는 것은 없으며, 인터넷상의 바이트 (빛의 펄스, 케이블의 전자 또는 전자기파)가 아닙니다. 약 300,000 km / s의 속도로 여행하므로 4,000 km를 여행하는 데 13 ms가 걸립니다.

이것은 매우 빠르다고 들릴지 모르겠지만 실제로는 매우 낙관적 인 설정입니다. 데이터가 직선 경로의 빛의 속도로 이동한다고 가정 할 때, 대부분 그렇지 않을 가능성이 있습니다. 실생활에서 데이터는 라우터에서 라우터로 일련의 점프 (네트워킹 용어에서 홉 (hop)이라고 함)를 거치며, 대부분이 초고속으로 처리되지 않습니다. 라우터는 패킷을 복사, 검사 및 경로 변경해야 하므로 약간의 지연이 발생합니다.

논쟁을 위해서, 데이터가 클라이언트에서 서버로 50ms 걸린다고 가정 해 봅시다. 이것은 최상의 경우 시나리오에 가깝습니다. 도쿄에있는 서버에 연결된 NY에 있다면 어떻게됩니까? 어떤 이유로 네트워크 정체가 발생하면 어떻게해야합니까? 100, 200, 심지어 500ms의 지연은 전례가 없습니다.

예제로 돌아 가면 클라이언트는 서버에 입력을 보냅니다 ( "나는 오른쪽 화살표를 눌렀습니다"). 서버는 50ms 후에 가져옵니다. 서버가 요청을 처리하고 업데이트 된 상태를 즉시 반환한다고 가정 해 보겠습니다. 귀하의 고객은 50ms 후에 새로운 게임 상태 ( "지금 (1, 0)에 있습니다")를 얻습니다.

당신의 관점에서, 일어난 일은 당신이 오른쪽 화살표를 눌렀지만 1 초에 10 분 동안 아무 것도 일어나지 않았다는 것입니다. 당신의 캐릭터는 마침내 한 칸 오른쪽으로 움직였습니다. 입력과 그 결과 사이의 지각 된 지연은별로 들리지 않을 수 있지만 눈에 띄지 않습니다. 물론 0.5 초의 지연은 눈에 띄지 않을뿐 실제로 게임을 재생할 수 없게 만듭니다.

요약

네트워크 멀티 플레이어 게임은 놀랍지 만 재미 있지만 전혀 새로운 차원의 도전을 불러 일으 킵니다. 권위있는 서버 아키텍처는 대부분의 치트를 멈추게하는 데는 능숙하지만, 간단한 구현으로 인해 게임이 플레이어에게 상당히 반응하지 않을 수 있습니다.

다음 기사에서는 권위있는 서버를 기반으로 시스템을 구축하면서 플레이어가 겪는 지연을 최소화하면서 로컬 또는 단일 플레이어 게임과 거의 구별 할 수없는 방법을 탐색 할 것입니다.