UDN
Search public documentation:

PackagesAndNetworkingKR
English Translation
日本語訳
中国翻译

Interested in the Unreal Engine?
Visit the Unreal Technology site.

Looking for jobs and company info?
Check out the Epic games site.

Questions about support via UDN?
Contact the UDN Staff

패키지 및 네트워킹의 상위 수준 분석

문서 요약: 네트워킹 관점에서의 관련 패키지에 대한 중요한 정보.

문서 변경 내역: Michiel Hendriks 마지막 업데이트. Two.PackagesAndNetworking 에서 옮김. 원저자: Mike Lambert(UdnStaff?).

개요

Unreal Engine 의 편집 작업을 조금이라도 해 보았다면 패키지가 무엇인지 알 수 있습니다. 텍스처 매핑, 코드 등의 모든 게임 콘텐츠는 패키지에 저장됩니다. 패키지는 다양한 "요소" 집합에 불과합니다. 패키지는 맵, 텍스처, 코드, 사운드, 음악, 또는 이들의 조합을 임의로 저장할 수 있습니다. Unreal 의 디렉터리 구조는 누구나 쉽게 정리할 수 있도록 텍스처, 음악, 맵의 위치가 나뉘어 있습니다. 따라서 맵 제작자가 텍스처 및 코드를 맵에 포함시킬 수 있어 맵이 .u 파일을 포함해야 하는 필요성을 제거시킵니다. 그러나 일반적으로 혼동되지 않도록 하기 위해 Unreal Engine 에서 제공하는 샘플 세트를 따르는 것이 현명한 방법이라할 수 있습니다. 맵에 .umap (또는 자체 맵 확장명)을 지정하고, .u 로 코드 작성하여, 나머지를 정리된 디렉터리에 있는 .upk 로 배치시킵니다. UnrealScript? 컴파일 성능 향상을 위해 할 수 있는 한 가지 일은 패키지를 분할시키는 것입니다. 코드 패키지에 게임 텍스처와 모델을 포함시키지 마십시오. 그 대신, 이러한 것들을 더미 클래스를 포함한 패키지로 컴파일 시키십시오. 이렇게 하면 아트 데이터가 사전에 한번 컴파일되어 코드 컴파일은 이 패키지를 단순히 참조하면 됩니다 ( #obj load exec 행을 사용함). 또 다른 장점은 작은 코드 파일로 패치를 배포할 수 있어 모델과 텍스처를 포함한 전체 패키지를 다시 다운로드 받을 필요가 없게 됩니다.

본 문서는 NetworkingTomeKR 의 일부입니다.

ServerPackages

서버가 시작하면 게임에 필요한 모든 패키지를 로드합니다. 맵, 관련 텍스처, 사운드, 음악 패키지를 로드합니다. 또한 servertravel 명령에서의 ?game=XX 에 정의된 게임을 로드합니다. gamename .ini (ExampleGame.ini)에서 언급된 serverpackages 도 로드합니다. 이러한 패키지와 클래스의 로딩이 완료되면 서버에 저장된 패키지 목록에 패키지가 더 이상 추가되지 않습니다. serverpackages 목록이라 호칭하는 이 목록은 서버에 접속하는 모든 클라이언트에 전송됩니다. 그런 다음 클라이언트는 이러한 패키지를 자체 방식으로 로드하여 클라이언트에 전송된 액터를 차질없이 불러올 수 있게됩니다. 이러한 패키지가 모두 로드될 때까지 코드가 실행되지 않습니다. 이것이 서버인 경우, 패키지 로드가 완료될 때까지 클라이언트 연결을 허용하지 않습니다. Unreal 에서 레벨 또는 서버를 로드할 때 무 응답 지연 시간이 긴 것은 이런 이유 때문입니다. DynamicLoadObject() 를 사용하여 추가 패키지를 불러올 수 있지만, 이러한 패키지는 로컬 시스템에만 로드되어집니다. Unreal 은 다른 연결된 컴퓨터에게 이러한 패키지를 로드하도록 지시하지 않습니다. 레벨을 로드하는 데 필요한 모든 패키지는 자동으로 패키지 맵에 추가됩니다.

패키지 로드로 인해 몇 가지 이상한 현상이 발생하는 것을 경험할 수 있습니다. 이러한 예제에는 mutator 가 있습니다. Mutator 에 관심이 없더라도 다른 곳에서 이와 비슷한 문제가 발생할 수 있으므로 이것에 대해 읽어보는 것은 유용합니다. Mutator 는 구체적으로 GameInfo's InitGame() 에서의 DynamicLoadObject() 를 사용하여 UnrealScript 에 의해 로드됩니다. 이것은 패키지 목록을 로드한 후에 이루어지기 때문에 이 시점에서 mutator 패키지는 serverpackages 에 로드되지 않습니다. Unreal 에 포함된 mutator 는 게임 코드 자체에 포함되어있기 때문에 이런 문제가 생기지 않습니다. 서버쪽에서만 작동하는 mutator 의 경우 해당 패키지의 액터로 클라이언트를 보낼 필요가 없기 때문에 문제될 것이 없습니다. 그러나 액터를 클라이언트로 보내도록 mutator 에 정의되어 있는 경우 이러한 액터는 클라이언트에게 표시되게 됩니다. 이 패키지는 serverpackages 목록에 추가되지 않았기 때문에 클라이언트에 로드되지 않았고, 그렇기에 클라이언트는 액터의 기본 속성에 대해 알지 못합니다. 따라서 이 패키지는 표시되지 않습니다. 이 문제를 해결하려면 [Engine.GameEngine] 아래의 gamename .ini 파일에 있는 serverpackages 배열에 문제 mutator 를 명시적으로 추가하는 것입니다. 이렇게 되면 게임이 시작되기 전에 mutator 패키지가 로드되어집니다. 나중에 GameInfo 가 해당 패키지를 로드할 때 이미 serverpackages에 포함되어 있기 때문에 결과적으로 클라이언트에서 작동하게 됩니다.

동일한 문제는 스킨 패키지에도 적용됩니다. 사용자의 스킨은 연결된 명령줄 옵션에서 지정되고 GameInfo 의 Login 이 실행되기 전까지는 로드되지 않습니다. 이것은 모든 serverpackages 가 로드된 다음입니다. 따라서 각 클라이언트에 이 텍스처가 복제되지만 클라이언트가 표시하려고 하면 해당 텍스처 패키지는 클라이언트의 로컬 메모리에 존재하지 않기에 (serverpackages 에 포함되어 있지 않기 때문에) 악명 높은 녹색 스킨 문제가 발생하게 됩니다.

GUIDs

모든 패키지에는 GUID (Globally Unique Identifier: 전역적으로 독특한 인식자)가 연결되어 있습니다. 패키지를 저장하면 GUID 가 생성됩니다. 이 GUID 는 동일한 패키지의 각기 다른 버전을 인식하거나 패키지를 구분하는 데 사용됩니다. GUID 는 128 비트 ID 를 생성하는데에 시간 및 다른 정보를 고려하므로 2 개의 GUID 가 우연히 같을 가능성은 전무하다고 할 수 있습니다. 2128 = 2.4 x 1038개의 가능 GUID 가 있습니다. 이 만큼의 수가 있으므로 당분간 걱정할 필요는 없습니다. :)

Epic 에서 GUID 가 실수로 반복되지 않도록 조취를 취한 후 의도적으로 이것을 수행할 방법을 만들었습니다. 패키지 생성 과정에서 원래 패키지와 동일한 GUID 가 새 패키지에 주어지고, 그 의도와 목적이 동일한 것으로 간주되도록 합니다. 그 이유는 후반 섹션에서 설명합니다.

서버에 연결하기

서버로의 접속 과정은 대략 다음과 같습니다.

  1. 서버는 각 패키지로 GUID 와 함께 serverpackage 목록을 보냅니다 (Engine/UnConn -> UNetConnection::SendPackageMap).
  2. 서버는 [IpDrv.TcpNetDriver] 의 DownloadManagers 배열을 검사하여 클라이언트가 패키지를 다운로드하는 방법을 검색합니다. 이 목록을 클라이언트로 보냅니다 (Engine/UnConn -> UNetConnection::SendPackageMap).
  3. 클라이언트는 [Core.System] -> Path 배열에 의해 정의된 디렉터리 목록을 확인하여 서버에 의해 전송된 패키지와 동일한 이름의 패키지를 찾습니다. 동일한 이름 패키지의 GUID 가 서버에 의해 보내진 것과 일치하는지 확인하거나 그렇지 않으면 "Version Mismatch" (버전 불일치) 오류를 발생시킵니다.
  4. 위 단계에서 클라이언트에 의해 검색되지 않은 모든 패키지에 대해 클라이언트는 [Core.System] 's CachePath and CacheExt 에 의해 정의된 Cache 디렉터리를 검사하여 주어진 GUID 를 가진 패키지를 찾습니다.
  5. 찾을 수 없는 패키지는 다운로드 받아야 합니다. 패키지가 다운로드 가능한지(해당 패키지의 packageflags 에 정의되어 있음), 클라이언트가 [IpDrv.TcpNetDriver] 's AllowDownloads 를 사용하여 다운로드 받을 수 있는지 확인합니다 ("WELCOME" 의 경우, Engine/UnPenLev -> UNetPendingLevel::NotifyReceivedText).
  6. 클라이언트는 목록을 순차적으로 확인하여 실제로 클라이언트에 존재하는 것을 찾을 때까지 각 다운로드 관리자를 차례로 실행합니다 (Engine/UnConn -> UNetConnection::ReceiveFile). 아무것도 찾을 수 없으면 기본 Engine.ChannelDownload 를 사용하도록 기본 설정됩니다. 그런 다음, 다운로드하는 방법을 서버에 요청합니다 (Engine/UnConn -> UNetConnection::ReceiveFile).
  7. 서버는 이 방법을 사용할 수 있는지 여부를 확인하고, 사용할 수 있다면 어떻게 사용할 수 있는지 확인합니다. 사용자가 Engine.ChannelDownload: (Engine/UnDownload) 를 요청하는 경우,
    1. 서버가 [IpDrv.TcpNetDriver] 's AllowDownloads Boolean 의 값이 true 인 여부를 확인하여, 만약 true 이면 파일을 전송하지 않습니다.
    2. 서버는 클라이언트로 파일을 전송합니다. 특정 클라이언트로의 파일 전송에 대역폭이 소모되므로 다른 클라이언트에게는 지연이 발생할 수 있습니다. 파일의 최대 전송 속도는 [IpDrv.TcpNetDriver] -> MaxClientRate 에 의해 결정됩니다.
  8. 서버가 클라이언트의 다운로드르 허용하지 않기 때문에 다운로드 받을 수 없으면, 클라언트는 포기하고 서버로의 연결에 실패하게 됩니다.

동조화 패키지

동조화 패키지의 목적은 패키지의 각기 다른 두 가지 버전간에 네트워크 호환성을 제공하는 것입니다. 이것은 다음과 같이 작동합니다. 예를 들어 제품의 버전 1 을 이미 출시했고 지금은 버전 2 를 출시하려 하는 경우, 이 새 버전으로 인해 패치를 적용하지 않은 사용자가 적용된 서버에서 게임을 할 수 없게 되지 않게, 또 반대로 업그레이드한 사용자가 아직 패치하지 않은 서버에서 플레이할 수 없는 상황이 발생하길 원치 않는 경우, 버전 동조화를 사용해야 합니다. 버전 동조화는 Unreal 로 하여금 2 가지 버전이 동일한 것으로 여기도록 하고 이전 패키지의 사용자가 업그레이드된 버전 사용자와 더불어 플레이할 수 있게 하여줍니다. 패키지 동조화를 실행하려면 새 버전에게 이전 버전이라고 ‘믿게’ 시키기 위해 필요한 이전 버전이 요구됩니다. 패키지를 동조화 시키는 데에는 2 가지 방법이 있습니다.

  • 게임 디렉터리의 guires 디렉터리에 이전 버전의 복사본을 저장합니다. 이것은 Binaries 디렉터리 옆에 있을 것입니다. 'ucc make' 를 사용하여 컴파일된 버전은 자동적으로 guires 에 저장된 버전을 상대로 동조화 작업을 진행합니다.
  • 패키지 새 버전의 복사본을 컴파일합니다. 그런 다음, conform commandlet 를 사용하여 패키지의 동조화 작업을 실행합니다.

패키지를 컴파일하는 경우 이것은 패키지의 동조성 기록을 저장하는 Generations 라 하는 패키지에서의 배열을 포함합니다 (Core/UnObj -> UObject::SavePackage). 따라서, 버전 2 를 사용한 서버가 버전 1의 클라이언트를 볼 때 Generations 배열에서 버전 1을 검색하므로 클라이언트와 적절히 통신하는 방법을 이해하게 됩니다.

이 방법은 동조화하기에 대한 구현 또한 갖고 있습니다. 패키지의 버전 3 를 동조화 시키지 원하는 경우, 버전 1 과 버전 2 모두로 동조화 시키기 위해서 반드시 버전 3 을 버전 1 이 아닌 버전 2 에 대해 동조화 시켜야 합니다. 버전 2 는 버전 1 과 2 모두와 통신하는 방법에 대한 정보를 포함하고 있습니다. 버전 3 가 버전 1 과 버전 2 모두와 호환되기 위해서는 이 정보가 필요하므로 반드시 버전 2 를 상대로 동조화 시켜야 합니다. 따라서, 자신의 제어 밖에 있는 가능한 공개적으로 출시되는 코드의 공개 버전을 출시할 때마다 guires 디렉터리에 해당 버전을 저장해 두어 내부적으로 컴파일 할(결국 공개적으로 출시할) 다음 버전이 이전 다른 모든 버전과 호환될 수 있도록 해야 합니다. 패키지의 각 버전은 최초 버전이 아닌 이전 버전을 상대로 반드시 동조화되야 합니다. 그러므로 버전 4 의 클라이언트가 버전 2 의 서버와 대면했을 때, 역호환성 및 패치가 적용되지 않는 서버와 통신하는 방법을 알 수 있게됩니다 (Core/UnCoreNet -> UPackageMap::Compute).

실제 동조화 과정은 nametable의 동기화를 유지하는 작업으로 구성됩니다. 버전 2 가 버전 1 을 대상으로 동조화되는 경우 버전 1 에서 동일한 위치에 나온 모든 이름을 그래로 유지하면서 nametable 을 저장합니다. 버전 2 에서 나오는 추가 이름 모두는 이 목록 뒤에 표시되게 됩니다. 서버와 클라이언트가 함수 또는 변수에 대한 정보를 보낼 때 실제 색인을 nametable 로 보냅니다. 따라서 클라이언트가 버전 2 고 서버가 버전 1 이라도 통신하는 데 사용되는 nametable 이 동일하므로 매끄한 통신이 허용되는 것입니다. Generations 배열을 디스크에 저장할 때 해당 이름의 수와 내보내기 개수를 저장합니다. 그러므로 이것은 Unreal 로 하여금 nametable 의 첫 번째 X 개 항목(버전 1 에서도 동일한 수의 항목)을 사용하여 버전 2 패키지가 버전 1의 패키지와 통신할 수 있다라는 것을 알려줍니다.

Localized 패키지 동조화의 경우 각 언어가 다른 모든 언어와 함께 작동될 수 있도록 체인 방식으로 동조화를 실행해야 합니다. 예를 들면, 'int', 'fra', 'esn', 'deu' 로컬리제이션 패키지 버전이 있는 경우, 'int' 를 'fra' 에 대해 동조화시킨 다음, 'fra' 를 'esn' 에 대해, 그리고 'esn' 를 'deu' 에 대해, 등등의 순서로 동조화를 실행합니다. 언어의 순서는 특별히 상관 없습니다. https://udn.epicgames.com/lists/showpost.php?list=unprog3&id=30760 을 참조해 주십시오.

패키지 플래그 경고

패키지 플래그 중에 흥미로울 뿐만 아니라 필요한 몇 가지가 있습니다. 넷플레이에서 패키지를 사용하고 클라이언트가 패키지를 다운로드할 수 있도록 하려면 패키지에 대해 AllowDownload 플래그를 활성 설정해야 합니다. PackageFlags? 참조를 확인해 주십시오.

패키지 불일치 오류

동일한 이름 그러나 다른 GUID 를 가진 패키지를 다운로드 하면 패키지 불일치 오류가 발생합니다. 동일한 패키지의 이전 버전과의 동조화를 실행하여 이 오류를 해결할 수 있습니다(새로운 generation 을 만들게 됨). 그러나 서버가 두 패키지의 체크섬의 존재를 모르는 경우 불법 처리 사항이 작동하므로 주의해 주십시오.