상태 동기화 세부사항들(State Synchronization Details)

State Synchronization드롭 다운으로부터 신뢰할 수 있는 델타 압축(Reliable Delta Compressed) 또는 신뢰 할 수 없는(Unreliable)을 선택하여 매 네트워크 보기 마다 상태 동기화를 가능하게 할 수 있습니다. Observed속성에서 어떤 데이터가 동기화될지를 반드시 선택해야 합니다.

유니티는 몇몇 특정 클래스들을 묶을 수, 풀 수 있습니다: Transform, Animation, Rigidbody 그리고 MonoBehaviour.

Transforms는 위치, 회전, 스케일(scale)의 저장에 의해 직렬화 됩니다. Parenting 정보는 네트워크를 통해 전송되지는 않습니다.

Animation는 각각의 실행되는 애니메이션 상태(시간, 가중치, 속력, 가능/불가능)를 직렬화 합니다.

Rigidbody는 위치, 회전, 속도, 각속도를 직렬화 합니다.

스크립트들 (MonoBehaviours)은OnSerializeNetworkView()함수를 부릅니다.

신뢰성과 대역폭(Reliability and bandwidth)

네트워크 보기들은 신뢰성에 관한 두 종류의 타입을 지원합니다. Reliable Delta Compressed와 Unreliable입니다.

둘 다 그들 자신의 장점과 단점이 있고, 올바른 모드가 경우에 맞게 선택되어야 합니다.

대역폭을 최소화 하는 것에 의한 추가적인 정보는 Minimizing Bandwidth page를 참조하시기 바랍니다.

신뢰할 수 있는 델타 압축(Reliable Delta Compressed)

Reliable Delta Compressed 모드는 자동으로 클라이언트에 의해 마지막으로 수신 받은 데이터를 비교합니다. 만약 데이터가 변경되거나 비교되었다면, 아무 데이터도 보내어지지 않습니다. 그러나, 데이터는 속성 별로 비교 될 것입니다. 예를 들어, 위치가 변경되었지만 회전은 변화되지 않았으면, 오직 위치만 네트워크를 통해서 보내져야 합니다.

이 모드에서 유니티는 내부적으로 각각의 속성 앞에 비트 하나를 싸서 실제 데이터가 변경되었는지 결정합니다. 변경되지 않았으면, 속성은 직렬화된 데이터 내에 포함되지 않아 대역폭을 많이 아낄 수 있게 됩니다.

유니티는 보내지는 모든 패킷이 도착하도록 보장합니다. 이는, 패킷을 받을 시 UDP 패킷이 누락된다면, 패킷을 다시 보내게 함을 통해서 입니다. 만약 패킷이 누락된다면, 누락된 패킷 이후에 보낸 패킷은 누락된 패킷이 다시 보내지고 수신되어야 적용이 되게 합니다. 그때까지는 모든 이후의 패킷들은 버퍼에서 기다릴 것입니다.

신뢰할 수 없는(Unreliable)

Unreliable 모드에서는, 유니티는 변경되었거나 되지 않는 것에 관계없이 현재의 상태를 보낼 것입니다. 보내진 데이터가 실제로 제대로 수신될지 알 수 없으므로, 상태는 델타 압축 처리되지 않을 것입니다.

어떤 방법을 사용할지 결정

네트워크 계층은 UDP를 사용하는데, UDP는 신뢰할 수 없고, 순서가 정확하지 않는 프로토콜입니다. 그러나 UDP도 신뢰할 수 있고, 순차적인 패킷을 TCP와 마찬가지로 보낼 수 있습니다. 내부적으로 패킷의 전송을 위해 ACKs와 NACKs 를 사용하여 패킷이 누락되지 않도록 합니다. 신뢰할 수 있는 순차적인 패킷을 사용했을 때의 안 좋은 점은 패킷이 누락되거나 지연되면, 그 패킷이 안전하게 도착 할 때까지 모든 것이 멈춘다는 점입니다. 이는 지연이 민감한 네트워크에서는 전송의 지연을 알아차릴 수 있게 됩니다.

Unreliable전송은 매 프레임마다 변하는 것을 알 수 있는 데이터를 전송하는데 유용합니다. 예를 들면, 레이싱 게임에서, 플레이어의 차는 항상 움직인다는 점에 사실상 의존합니다. 그러므로, 델타 압축과 신뢰성 있는 전송은 실질적인 이득 없이 네트워크 부하만 증가 시킵니다.

일반적으로, 데이터가 항상 변하는 것을 알 때와 지연을 최소화하는 것이 아주 중요할 때 Unreliable전송을 사용하여야 합니다. 네트워크 보기에 의해 트랙(track)된 데이터가 매 프레임마다 바뀌지 않고 대역폭이 중요하다면, 델타 압축이 선호됩니다.

지연(lag) 과 대역폭(bandwidth)는 같지않다는 것을 이해하는 것은 중요합니다. 다른 사용의 경우에, 그들은 당신이 최적화를 원하는 두 분리된 속성입니다.

예측(Prediction)

서버가 world 상태에 full authority이 있으면, 클라이언트들은 서버로부터 수신 받는 상태들에 의해 게임을 업데이트 합니다. 하나의 문제점은 이러한 제어가 자연스럽지 못한 경우가 있습니다. 예를 들어, 플레이어가 “forward” 버튼을 눌렀을 때, 서버로부터 업데이트된 상태를 받을 때까지 플레이어가 움직일 수 없는 그런 경우입니다. 이러한 지연은 접속의 반응 시간(latency)에 의존하며, 접속이 더 나쁠 수록, 플레이어의 액션들은 더 부자연스러워 집니다.

이를 돕는 하나의 방식은 Player Prediction입니다. 클라이언트는 플레이어 예측으로 서버가 자신의 움직임을 어떻게 계산 하는지를 알고, 그 움직임을 자신이 예측합니다. 그래서, 플레이어는 컨트롤과 함께 즉시 움직이지만, 서버는 플레이어의 위치를 마지막 업데이트로부터 봅니다. 서버로부터 상태 업데이트가 도착할 때, 클라이언트는 실제 일어난 것들과 예측한 것들의 차이를 비교할 것입니다. 서버가 플레이어 주위의 환경에 대해 더 많이 알 수 있고 클라이언트는 자신에게 필요한 것들만 알기 때문에 차이가 있을 수 있습니다. 예측시의 에러는 실제로 일어날 때 교정이 되며, 교정이 서서히 이루어 진다면, 더 부드럽고 덜 눈에 띌 것입니다.

데드 레커닝(Dead reckoning) 또는 보간/보외 (interpolation/extrapolation)

플레이어 예측과 같은 원리를 플레이어의 상대편에 적용하는 것이 가능합니다. Extrapolation는 몇몇 마지막 (버퍼된) 알려진 위치로부터, 상대편이 다음 프레임들 동안 어디에 있을지를 예측하기 위해서 상대편의 속도와 방향을 사용합니다. 다음 상태가 정확한 위치와 함께 마지막으로 도착할 때, 클라이언트의 상태는 정확한 정보로 업데이트 될 것이며, 예측이 나쁘면, 업데이트는 건너 띌 것입니다. FPS 게임들에는, 플레이어들의 행동은 매우 오류가 많으므로, 이런 종류의 예측은 제한된 효과를 가집니다. 만약, 지연이 충분히 높으면, 예측의 에러들이 점점 더 커지므로, 상대편은 심하게 건너 띌(skip) 것입니다.

Interpolation은 패킷 들이 클라이언트에 오는 중간에 누락되고 상대편의 위치는 멈출 때 사용되어, 새로운 패킷이 도착할 때에야 새로운 위치로 점프 합니다. World 상태를 어떤 시간의 단위(예: 100ms)로 지연시키고, 마지막 알려진 상태를 새로운 상태로 보간 시켜서, 패킷들이 누락된 두 점 사이의 움직임을 부드럽게 합니다.

역링크