네트워크를 통해 데이터 구조를 동기화하는 방법은 무엇입니까?


12

문맥

내가 작업하고있는 게임 (일종의 포인트 앤 클릭 그래픽 어드벤처)에서 게임 세계에서 발생하는 거의 모든 작업은 다음과 같은 구조의 액션 매니저에 의해 제어됩니다.

여기에 이미지 설명을 입력하십시오

예를 들어 객체를 검사 한 결과 캐릭터가 hello라고 말하고 조금 걸어 다니고 앉으면 다음 코드를 스폰합니다.

var actionGroup = actionManager.CreateGroup();
actionGroup.Add(new TalkAction("Guybrush", "Hello there!");
actionGroup.Add(new WalkAction("Guybrush", new Vector2(300, 300));
actionGroup.Add(new SetAnimationAction("Guybrush", "Sit"));

그러면 새 조치 그룹 (위 이미지의 전체 라인)이 작성되어 관리자에 추가됩니다. 모든 그룹은 병렬로 실행되지만 각 그룹 내의 작업 서로 연결되어 있으므로 두 번째 그룹은 첫 번째 그룹이 완료된 후에 만 ​​시작됩니다. 그룹의 마지막 작업이 완료되면 그룹이 삭제됩니다.

문제

이제 멀티 플레이어 세션에서 모든 플레이어가 동일한 정보를 볼 수 있도록 네트워크를 통해이 정보를 복제해야합니다. 개별 동작을 직렬화하는 것은 문제가되지 않습니다. 그러나 나는 네트워킹에 관해서는 절대 초보자이며 몇 가지 질문이 있습니다. 이 토론에서 간단하게하기 위해 액션 매니저 컴포넌트를 간단하게 추상화 할 수 있다고 생각합니다.

var actionManager = new List<List<string>>();

위의 데이터 구조의 내용을 모든 플레이어간에 동기화 된 상태로 유지하려면 어떻게해야합니까?

핵심 질문 외에도, 그와 관련된 몇 가지 다른 우려가 있습니다 (즉, 위의 동일한 문제에 대한 모든 가능한 의미).

  • 내가, 그리고 중 하나 (서버와 클라이언트 모두 역할을하는 선수 중 하나) 서버 / 클라이언트 아키텍처를 사용하는 경우 클라이언트 낳았다 작업 그룹을, 그는 매니저에게 직접 추가, 또는 유일한 요청을 보내야합니다 서버에 모든 클라이언트가 해당 그룹을 추가하도록 명령 합니까?
  • 패킷 손실 등은 어떻습니까? 게임은 결정 론적이지만 클라이언트에서 실행되는 일련의 동작에 불일치가 발생하면 세계의 일관성이없는 상태가 될 수 있다고 생각합니다. 그런 종류의 문제로부터 어떻게 보호 합니까?
  • 한 번에 너무 많은 작업을 추가하면 연결에 문제가 발생하지 않습니까? 그것을 완화시킬 방법이 있습니까?

5
필수 "이 첫 번째 읽기"링크 gafferongames.com/networking-for-game-programmers 는 일부 코드에도 불구하고 기술적이지는 않지만 말이 많고 옵션이 상당히 잘 설명되어 있습니다. 또한 링크를 읽는 다른 모든 사람들과 동등한 발판을 마련하고 행복한 곳입니다.
Patrick Hughes

@PatrickHughes 링크 감사합니다! 나는 확실히 모든 것을 읽을 것입니다.
David Gouveia

이런 종류의 것을 관리하는 패키지가 있습니다. 나는 그것이 얼마나 효율적이거나 빠른지 모르겠지만 NowJS ( nowjs.com )가 흥미로운 예입니다. 개발자의 관점에서 클라이언트와 서버간에 데이터 구조를 공유하기 만하면됩니다. 하나를 변경하고 다른 하나를 변경하십시오.
Tim Holt

답변:


9

서버 / 클라이언트 역할을하는 플레이어 중 하나와 함께 서버 / 클라이언트 아키텍처를 사용하고 클라이언트 중 하나가 작업 그룹을 생성 한 경우 관리자에게 직접 추가하거나 요청 만 보내야하는 경우 서버에 모든 클라이언트가 해당 그룹을 추가하도록 명령합니까?

이 경우 세 가지 옵션이 있으며 그 중 두 가지가 이미 언급했습니다. 어떤 옵션을 선택 하느냐는 본인 만 판단 할 수있는 다양한 요인에 따라 다릅니다.

1 : 클라이언트가 작업 그룹을 생성하여 작업을 직접 추가 한 다음 서버로 보냅니다. 서버는 확인하지 않고 서버를 수락합니다.

*이 접근법의 장점은 클라이언트에 관한 한, 자신의 행동으로 네트워크 지연과 무관하게 즉각적인 피드백을 제공한다는 것입니다. 단점은 클라이언트의 메시지 가 서버에 의해 사실로 받아 들여진다 는 것입니다.

2 : 클라이언트가 서버에 요청을 보낸 다음 요청을 보낸 클라이언트를 포함하여 모든 사람에게 요청을 브로드 캐스트합니다.

이 접근 방식의 장점은 불법 활동과 관련된 대부분의 문제를 완화시키는 게임에서 서버가 게임에서 발생하는 모든 것을 제어 할 수 있다는 것입니다 (여기서 불법은 클라이언트가 벽을 자르는 것부터 서버가 클라이언트가 특정 이동을 할 때 클라이언트에 없었던 추가 정보)

3 : 클라이언트가 작업 그룹을 생성하고 직접 추가 한 다음 서버로 보냅니다. 서버는 요청을 처리하고 작업을 자체 검사하여 불법이 아닌지 확인한 다음 클라이언트를 포함한 모든 플레이어에게 이동을 브로드 캐스트합니다.

약간 더 많은 대역폭 요구 사항으로 인해 1과 2를 모두 최대한 활용합니다. 이점은 자신의 이동에 대해 클라이언트에 즉각적인 피드백이며, 클라이언트가 수행 한 이동이 불법 인 경우 서버는 적절한 조치를 취합니다 (클라이언트를 강제로 수정).

패킷 손실 등은 어떻습니까? 게임은 결정 론적이지만 클라이언트에서 실행되는 일련의 동작에 불일치가 발생하면 세계의 일관성이없는 상태가 될 수 있다고 생각합니다. 이런 종류의 문제로부터 어떻게 보호합니까?

패킷 손실과 극단적 지연은 해결하기 어려운 문제 입니다. 게임의 종류 (예 : 교착 상태)에 따라 문제를 해결하기 위해 다른 솔루션 (아무도 완벽한 솔루션)이 사용됩니다. 게임에서 물리를 동기화 할 필요가 없다고 가정하겠습니다.

가장 먼저해야 할 일 중 하나는 모든 움직임을 타임 스탬프하는 것입니다. 시스템이 다음 계정으로이 걸릴해야 재생 따라 이동 (아마도 서버는이 책임을 한 후 불법 이동을 거부). 이 시스템을 구현할 때는 대기 시간을 0으로 가정합니다 (로컬 테스트).

물론 로컬 네트워크에서도 대기 시간은 좋은 가정이 아니라 좋은 가정이므로 이제 모든 움직임이 시간을 존중하므로 어느 시간을 신뢰하십니까? 그곳에서 시간 동기화 문제가 시작됩니다. 많은 기사 / 논문이이 문제를 해결하는 데 도움이 될 것입니다.

한 번에 너무 많은 작업을 추가하면 연결에 문제가 발생하지 않습니까? 그것을 완화시킬 방법이 있습니까?

먼저 명백한 것들. 문자열이나 직렬화 된 객체를 보내지 마십시오. 게임 자체가 업데이트되는 한 빨리 메시지를 보내지 마십시오. 청크로 보내십시오 (예 : 초당 10 회). 서버 / 클라이언트가 한 번에 한 번씩 오류를 수정해야하는 오류 (특히 반올림 오류)가 있습니다. 따라서 매 초마다 서버는 모든 것을 전송합니다. state] 클라이언트 상태를 수정하기 위해 스냅 하고 /하거나 고려합니다.편집 : 내 동료 중 하나가 UDP를 사용하고 있다면 (많은 데이터가있는 경우) 네트워크 순서가 없다고 언급했습니다. 초당 10 개 이상의 패킷을 보내면 패킷 도착 순서가 잘못 변경됩니다. 그 주장을 인용 할 수 있는지 살펴 보겠습니다. 고장난 패킷 자체에 대해서는, 패킷을 폐기하거나 시스템의 메시지 / 이동 대기열에 추가하여 과거의 변경 사항을 처리하여 현재 상태를 수정하도록 설계 할 수 있습니다.

공간을 거의 차지하지 않는 무언가에 의존하는 메시징 시스템이 있어야합니다. 두 개의 값만 가질 수있는 것을 보내야하는 경우에는 한 비트 만 보내십시오. 256 개의 이동 만 할 수있는 경우 서명되지 않은 문자를 보냅니다. 메시지를 가능한 한 밀접하게 포장하는 다양한 비트 트위들 링 트릭이 있습니다.

메시징 시스템은 들어오는 메시지에서 쉽게 이동을 추출 할 수 있도록 많은 열거 형을 사용합니다 (여기서 내가 의미하는 바를 이해하지 못하는 경우 RakNet 및 그 예를 살펴 보는 것이 좋습니다).

대기 시간이 길고 패킷 손실로 인해 발생하는 문제를 해결할 수는 없지만 그 효과를 덜 두드러지게 할 수 있다는 것을 이미 알고 있습니다 . 행운을 빕니다!

편집 : 링크 가있는 Patrick Hughes의 의견 은이 답변이 불완전하고 OP의 질문에 구체적으로 표시되도록합니다. 대신 연결된 주제를 읽는 것이 좋습니다.


자세한 답변에 대해 많은 감사를 표합니다. 당신이 말하는 부분에 관한 단 하나의 질문 so every second, the server sends everything ... which the client then snaps to. 이와 같은 대량의 정보를 한 번에 보낼 수 있습니까? 합리적인 최대 크기는 얼마입니까?
David Gouveia

합리적인 최대 값은 시차를 도입하지 않는 숫자가 될 것입니다.
Samaursa

또한 하나의 큰 덩어리를 보내야한다는 엄격한 규칙은 없습니다. 예를 들어 설명했습니다.
Samaursa

@Samaursa- "UDP를 사용하는 경우 [많은 데이터가있는 경우]] 의견에 동의하지 않습니다. 네트워크 프로그래밍에 익숙하지 않기 때문에 TCP는 훨씬 느린 비용으로 대부분의 어려운 작업을 처리합니다. 그들의 경우 병목 현상이 될 때까지 TCP를 사용합니다. 이 시점에서 그들은 앱이 네트워크를 사용하는 방법을 더 잘 이해하므로 UDP를 구현하는 것이 더 쉬울 것입니다.
Chris

@Chris : 동의하지 않을 것입니다 :) ... TCP와 UDP를 사용하는 결정은 개발을 위해 Python과 C ++를 선택하는 결정과 같습니다. 이론적으로는 괜찮을 것 같지만 실제로는 단순히 전환하기가 어렵습니다 (다시 말하면, imo입니다).
Samaursa
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.