MMO에서 서버와 트래픽이 적은 클라이언트 동기화


22

나는 플레이어가 자신의 우주선에서 화살표 키로 제어하고 다른 플레이어와 협력하는 MMO를 구현하고 있습니다.

플레이어가 로켓이나 다른 것에서 배를 피할 수 있도록 구현하고 싶습니다. 따라서 서버 사용과 동일한 세계 시뮬레이션 알고리즘을 사용하여 클라이언트 측에서 전체 게임 상태를 예측하려고합니다. 이 게임 세계는 C #으로 작성되었으며 클라이언트 내에서 직접 (Unity3D로 작성 됨) C ++ 서버 (Linux의 경우)에서 CLR을 통해 호출됩니다. UDP를 통한 연결.

문제는 단일 맵 내에서 1000 명의 플레이어를 유지하는 방법입니다 (다른 모든 게임 개체, 몹 제외).

  • 초당 50 회 클라이언트와 서버 동기화
  • 그가 볼 수있는 게임 오브젝트 (및 플레이어)의 각 클라이언트 상태를 (반경 내에서)
  • 시야 반경 내에있는 각 플레이어에게 100 개의 물체를 보내야합니다
  • 게임 개체 당 평균 50 바이트를 보내야합니다 (ID, x, y 좌표, 회전, 상태 ...)

따라서 다음과 같은 네트워크 대역폭이 필요합니다 : 1000 (클라이언트) * 50 (초당 시간) * 100 (각 플레이어에게 보낼 객체) * 50 (객체 당 바이트) = 초당 250,000 바이트! 그것은 불가능!

어떻게 든이 값을 줄일 수 있습니까? 예를 들어 클라이언트가 게임 세계를 (장기간 동안) 완벽하게 시뮬레이션하고 다른 클라이언트의 입력 만 보내고 게임 세계를 동기화 할 수 있습니다. .

어쨌든, 그러한 게임은 어떻게 공통적 인 방식으로 프로그래밍됩니까? 고맙습니다.


1
객체에 대한 논리적 정보 (세계의 위치, 현재 상태 (1 바이트) 등)를 그래픽없이 보냅니다.
Slav

1
@ 슬라브 : 니스! 이 모든 비트 이동은 저의 ASM 프로그래밍 일을 생각 나게합니다.
Randolf Richardson

1
왜 "오늘"이 아닌가? :) AS3, Java, Lua, C #을 작성하고 성능이 좋지 않을 때 C ++을 놓치고 ASM에 대해 기억합니다.
Slav

1
@Slav : Heheh, 나는 최근에 많은 ASM을하지 않았습니다. 나를 위해 대부분의 것들이 요즘 Java와 Perl (주로 mod_perl2)이지만, 나는이 언어들도 정말로 즐깁니다.
Randolf Richardson

2
@Slav는 다음과 같이 썼습니다. "AS3, Java, Lua, C #으로 작성할 때 성능이 저하 될 때 C ++을 놓치고 ASM에 대해 기억합니다." Lua와 C #을 올바르게 사용하는 방법을 배워야합니다. 어쩌면 성능이 덜 열악 할 수 있습니다. 또한, 가장 빠른 스크립트 언어 에 대해 불평하는 것이 가장 특이합니다. 이것은 실시간 인간 게놈 분석에 관한 게임입니까?
Raine

답변:


20

초당 약 30 개의 업데이트 (또는 10 또는 20 개 미만) 만 필요합니다. 움직이는 클라이언트 객체의 위치를 ​​클라이언트 측으로 보간합니다. 일반적으로 데이터는 정말 필요할 때만 보내야합니다. 와우에서는 같은 위치에있는 플레이어보다 그룹에 속한 플레이어로부터 더 많은 업데이트를받을 수 있습니다. 또한 다른 플레이어가 당신과 멀리 떨어져 있다면, 그에 대한 초당 많은 업데이트를받지 못합니다.

그런 다음 연결할 때 각 플레이어에게 하나의 완전한 스냅 샷을 보냅니다. 그 후에는 게임 오브젝트의 변경 사항 만 보냅니다. 변경 사항이 없으면 보내지 마십시오.

그런 다음 BitVectors를 많이 사용하거나 불필요한 벡터의 양을 줄이기 위해 호출 할 수 있습니다! 예 : 1 바이트 (0 ~ 1 또는 -1 ~ 1 범위) 만 사용하여 float를 쓰려고 시도하면 256 또는 128 개의 다른 값 만 가질 수 있습니다. 그러나 보간 덕분에 플레이어는 흔들림을 느끼지 않습니다.

데이터 압축 방법에 대한 LidgrenLibrary의 예는 다음을 참조 하십시오 . http://code.google.com/p/lidgren-network-gen3/wiki/Optimization

다음 : 플레이어가 움직일 때 시야 반경을 줄이고 그 당시 중요한 정보 만 전송하십시오. 그런 다음 멈 추면 시야 반경을 다시 증가시킵니다. 공간 해싱 시스템 또는 bsp 트리를 사용하여 "범위 내에있는"객체를 찾는 오버 헤드를 줄일 수 있습니다. http://en.wikipedia.org/wiki/Collision_detection 주제를 잘 읽어보십시오 .

또한 데이터 구조와 데이터의 시간적 일관성 (악용 될 수 있고 악용 될 수 있음)에 대해서만 알고 있는 데이터를 직접 압축하십시오 . Bzip2, Deflate와 같은 일반적인 알고리즘을 사용해야하지만 압축의 최종 단계로만 사용해야합니다!

또한 게임에 중요하지 않은 정보의 경우 추가 P2P 기술을 사용할 수도 있습니다. 예 : 플레이어가 "hello"애니메이션을 재생합니다. (그래픽 효과 일뿐) 플레이어는이 정보를 서버로 보내지 만 서버는 정보를 다른 플레이어에게 릴레이하지 않습니다. 대신이 중요하지 않은 효과는 플레이어 자체에 의해 범위 내의 다른 클라이언트에게 전송됩니다.

편집 (의견 때문에) :

각 플레이어의 초당 평균 비트 수를 줄이는 추가 방법 :

  1. 당신은 "개체가 바뀌지 않았다"라고 썼다. 그렇게 할 이유가 없습니다. 패킷 손실에 대해 걱정하고 (이로 인해 시뮬레이션이 동기화되지 않는 경우) 다음을 고려하십시오. 각 고정 된 시간 간격 (예 : 100, 200, 300, 400 ...)에서 시뮬레이션 상태를 해시하여 서버로 전송 . 서버는 모든 데이터의 전체 스냅 샷을 확인하거나 다시 보냅니다.

  2. 로켓이나 플레이어와 같은 경우 시뮬레이션을보다 사실적으로 만들기 위해 보간뿐만 아니라 외삽을 사용할 수도 있습니다. 'Rocket'예 : '현재 위치 x에 있습니다'와 같은 메시지로 업데이트하는 대신 다음을 포함하는 메시지를 한 번만 보냅니다. "Rocket Spawned : position (vector), Time (로켓이 생성 된 시뮬레이션 단계), velocity ( 벡터)". 팁이 항상 "속도"방향에 있기 때문에 회전을 포함하지 않아도됩니다.

  3. udp 헤더가 메시지 자체보다 크기 때문에 하나의 메시지에 여러 명령을 결합하고 16-20 바이트보다 작은 메시지를 보내지 마십시오. 또한 조각화로 인해 전송 속도가 느려지므로 프로토콜의 MTU보다 큰 패키지를 보내지 마십시오.


오, 일부 객체를 다른 객체보다 더 자주 업데이트하고, P2P를 사용하고, 부동 소수점 정확도를 낮추고, 변경 사항을 보내는 것이 좋습니다. (오브젝트를 주기적으로 동기화하려고했지만 "오브젝트가 변경되지 않았습니다"는 정보이므로 사소한 것이 아닙니다. 너무). 이러한 모든 수정으로 전체 그림이 더욱 사실적으로 보입니다!
Slav

1
"개체가 변경되지 않았습니다"유형 통지를 보내는 것은 테스트는 네트워크뿐만 아니라 처리에 대한 요구를 가할 수 있기 때문에 바쁜 시간 동안 플레이어가 켜져있을 때 게임이 어떻게 수행되는지 확인하려는 테스트 목적에 유용한 기술 일 수 있습니다. 실제 게임 내 캐릭터를 제어하는 ​​독립형 데몬을 생성 한 다음 다른 머신에서 해당 데몬을 여러 번 실행하는 등 여전히 이보다 더 나은 솔루션이 있습니다.
랜돌프 리차드슨

5

두 가지 접근 방식이 있습니다.

첫째 :
결정 론적 물리학으로 전환하고, 플레이어 명령을 전송하고, 액션, 객체가 보이게하고 클라이언트 측에서 클라이언트 측으로 결정할 수없는 모든 것을 보냅니다. 여기에는 명령이 아닌 명령이 포함되어야하며, 특정 시점까지 보내고받은 명령 만 적용된다는 확인이 필요합니다.

클라이언트는 두세 개의 동시 시뮬레이션을 실행해야합니다.
1 : 다음 단계에서 데이터가 누락 될 때마다 중단됩니다.
2 : 추측 데이터를 계속 사용하고 렌더링에 사용 된 상태를 제공하십시오. 3 : 1이 멈추지 않을 때마다이 시뮬레이션은 1 번의 상태를 복사하고 현재 시간을 따라 잡은 다음 2 번을 인수 한 다음 삭제합니다.

캐치 업이 충분히 빠르면 no 2와 no 3의 차이를 제외하고 기존 데이터를 즉시 삭제하십시오.

둘째 :
결정 론적 물리학을 사용하지 말고 위와 동일하게 수행하되 몇 초마다 한 번씩 "전체 프레임"을 보내십시오. 글 머리 기호와 같은 임시 항목을 쉽게 전송하지 않아도됩니다.

두 경우 모두 죽어가는 사람을 예측하는 클라이언트에 대해 조심하고 싶을 수도 있습니다.

수학을하기 위해 +1하면 너무 많은 사람들이 간단한 자원 사용 추정을하지 못합니다.


2
"결정 론적 물리학"은 부동 소수점 값이나 다른 시뮬레이션 단계를 사용할 수 없다는 것을 의미합니까? 예를 들어 로켓이 클라이언트의 일부 적 포탑에 의해지나 갔지만 (부동 소수점 부정확성으로 인해) 서버에 부딪히면 플레이어가 다음 수신 서버의 동기화 패킷까지 계속 터렛과 싸우는 경우 중요한 비동기 화가 발생할 수 있습니다. (몇 초).
Slav

3
정수 및 고정 시간 단계를 의미합니다. 이론적으로 부동 소수점을 조롱하여 작동시킬 수 있지만 정수를 사용하는 것이 훨씬 간단합니다. 결정 론적 물리학을 사용하는 경우 미사일이 누락 된 사례가 있습니다. 서버가 사망을 완전히 처리하고 사망 / 파괴 사례를 신속하게 전달하는 것이 가장 좋습니다.
aaaaaaaaaaaa

5

먼저 몇 가지 질문이 있습니다.

'로켓이나 다른 것'이 지능적이거나 바보입니까? 그것들이 멍청하다면 불의 타임 스탬프, 원점 및 경로를 시뮬레이션하는 벡터입니다. 그들이 지능적이라면 얼마나 지능적입니까? 불이 났을 때 그들이 칠거나 놓칠 계산을 할 수 있습니까? 그렇다면 클라이언트에서 전체 경로를 시뮬레이션 할 수 있습니다. ( "T13에서 미사일이 플레이에서 닷지 롤을 잃어 버렸기 때문에 / 슈터가 치명타를 쳤다)"

일반적으로 다음과 같은 이유는 거의 없습니다. A) 클럭 속도가 50Hz입니다. (대부분의 슈팅 게임 은 15-20과 MMO가 그보다 적습니다.) B) 매 프레임마다 전체 상태를 보냅니다. (우주에서 미사일의 회전이 중요합니까? 아니면 '전면'이 이동하는 벡터를 따라 방향이 있다고 가정 할 수 있습니까?)

예측과 보간으로 시간을 보내면 대역폭이 급감하게됩니다. 내가 작업 한 프로젝트는 10Hz의 업데이트 속도와 14 바이트의 객체 상태 표현을 가졌습니다. (가능한 모든 것을 압축하십시오! 나는 우리가 x 평면 주위의 회전을 정의하기 위해 6 비트를 사용한 다음 그 평면 위 / 아래의 기울기를 위해 또 다른 6 비트를 사용했다고 생각합니다. 실제 회전 행렬 / 쿼터니언을 보내는 것과 구별 할 수 없었습니다.)

당신이 할 수있는 또 다른 일은 객체의 우선 순위를 정하는 것입니다. 관련 세트에 100 개의 객체가 있지만 서버에서 뷰 프러스 텀을 알고 있습니까? 그의 견해에없는 것이 있다면 업데이트 빈도를 몇 배나 떨어 뜨릴 수 있습니까?

일반적인 아이디어는 클라이언트에 대한 완벽한 시뮬레이션을 만드는 것이 아니며 불가능합니다. 아이디어는 플레이어가 완벽한 시뮬레이션이 아니라는 것을 알지 못하는 재미있는 게임을 만드는 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.