UDN
Search public documentation:

FunctionReplicationKR
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 마지막 업데이트. FunctionReplication 에서 옮김. Mike Lambert (UdnStaff?) 원저자.

개요

싱글플레이어 게임 중에 함수는 항상 실행되고 네트워킹은 또 다른 문제를 발생시킵니다. 함수는 로컬 컴퓨터에서 실행될 수 있거나, 원격 컴퓨터에서 실행되게 네트워크를 거쳐 복제될 수 있거나, 그냥 무시될 수 있습니다. 함수를 네트워크상을 거쳐 실행되게 하는 과정은 때때로 원격 절차 호출 (Remote Procedure Calls: RPC) 이라 호칭되지만 Ureal에서는 함수 복제라고 합니다.

내부적으로 Unreal 엔진은 함수에 대해 매우 간단한 시스템을 사용합니다. 이 시스템은 해당 컴퓨터에서 UnrealScript? 함수를 호출할 수 있는지 결정하기 위해 함수를 호출합니다. UnrealScript? 함수를 호출할 수 있으며 호출하고, 그렇지 못하면 호출하지 않습니다. 이것이 모두 시뮬레이션과 복제의 필연적 사항으로 본 시스템로의 유일한 추가 사항은 UnrealScript? 시뮬레이션 원점, 이벤트(나중에 논의될 것임), 함수 복제 자체입니다(이것에 대해서는 이미 많은 것을 알고 계심).

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

함수 복제에 대한 시간

복제된 함수는 호출된 후 바로 복제됩니다. 그러므로 2개의 함수를 호출하면 바로 전송 네트워크 (outgoing network) queue 에 삽입됩니다. 따라서 변수를 변경하면 함수를 호출하게 되고, 호출된 함수는 복제가 변수가 클라이언트에 도달하기 전에 클라이언트에 도달할 가능성이 높습니다. 변수는 현재의 tick 이 종료하기 전까지 복제되지 않으므로 현재의 네트워크 패킷의 나중 또는 다음 번 패킷에 있게 됩니다. 순서의 뒤바뀜이 발생하지 않는 한 클라이언트는 전송된 순서대로 수신 받고 처리합니다. 해당 함수는 변수가 수신되기 전에 호출될 것입니다. 따라서 함수의 실행을 위해 클라이언트상에서 변수가 필요한 경우 그 해당 변수를 함수로 확실히 전달하도록 하십시오. 모든 액터는 해당 액터에 대한 packagemap 으로의 색인을 사용하여 복제되고, 따라서 함수의 인수로 액터 자체가 아닌 해당 액터로의 참조만을 복제하기 때문에 이것은 간단한 데이터 유형인 경우에만 작동한다는 것에 유의하십시오.

함수의 신뢰성

함수는 일반적으로 신뢰할 수 있거나 신뢰할 수 없습니다. 신뢰할 수 있는 함수는 수신된 순서로 처리되는 것이 보장됩니다. 신뢰할 수 없는 함수는 상대편으로 도달하는 것 또는 심지어 올바른 순서로 처리된다는 것에 대한 보장이 없습니다. 비순차적 순서로 처리되면 안되는 흔히 호출된 함수에 대해 유용한 그 중간이 있지만 주어진 함수가 드롭되는 경우 상관하지 않습니다. 이러한 유형들은 아래에서 보다 자세하게 논의됩니다.

신뢰할 수 있는 함수 호출

신뢰할 수 있는 함수 호출은 원격 컴퓨터에서 함수가 실행되는 것에 대한 보장이 필요할 때마다 사용되야 합니다. 비록 다수의 정의된 신뢰할 수 있는 함수를 갖는 것은 괜찮지만 아껴서 호출되야 합니다. 액터내에서는 다수의 신뢰할 수 있는 함수는 로컬 컴퓨터에서 호출되는 동일한 순서대로 원격 컴퓨터에서 호출되는 것이 보장됩니다. 이것을 실행하기 위해서는 실뢰할 수 있는 함수를 포함한 모든 드롭된 패킷은 함수 호출을 다시 전송해야 하고, 이렇게 하면 이어서 호출되는 함수의 실행이 지연되게 됩니다. 따라서 신뢰할 수 있는 함수 호출을 너무 과하게 사용하게 되면 정말로 실행되야 하는 함수의 실행이 지연되게 되는 위험을 감수하게 되고 이러한 신뢰 가능한 함수 호출을 재전송함으로 인해 발생한 패킷 손실 상태로 대역폭이 속도가 감소되는 위험을 감수해야 합니다. 연결의 대역폭이 포화상태에 이르면 실뢰할 수 있는 함수는 여전히 전송되어 포화상태 문제를 심화시키게 됩니다. 예를 들어, 신뢰할 수 있는 함수는 서버가 그것에 대해 알고 있는 것을 확인하고 싶기 때문에 플레이어가 'feigndeath' (죽은 척) 키를 누를 경우 사용되야 합니다. 마우스의 각 클릭/클릭 해제에 대해 신뢰할 수 있는 함수를 전송하는 것은 플레이어들이 키를 빠르게 누를 가능성이 높기 때문에 좋지 않은 생각입니다(실제로 이것에 대해 신뢰할 수 없는 함수를 사용하는 것도 또한 좋지 않지만 그것이 여기서의 문제 핵심은 아닙니다).

신뢰할 수 없는 함수 호출

신뢰할 수 있는 함수와 균형을 이루기 위해서 순서 또는 연결의 상대쪽에 이르게 되는 것에 관한 보장을 하지 않는 신뢰할 수 없는 함수도 있습니다. 신뢰할 수 없는 함수는 연결에 여유가 있으면 전송되고 사용 가능한 대역폭이 없으면 무시됩니다. 함수는 호출되는 즉시 바로 복제된다는 것에 대해 유념하는 것이 중요합니다. 이것은 즉 여러 신뢰할 수 없는 함수가 네트워크 연결을 포화시킬 수 있고, 그로 인해 레벨 tick 끝에서 변수 데이터가 복제될 여유가 없다는 것을 의미합니다. 비순차식 패킷 및 패킷 손실로 인해 신뢰할 수 없는 함수는 연결 상대쪽에서 아무 순서로 처리될 수 있고, 심지어 원격 연결에서 실행될 수 있습니다. 신뢰할 수 없는 함수는 주어진 클라이언트에서 사운드를 재생하는데 사용됩니다. ClientPlaySound 의 PlayerController 에 대한 주어진 사운드를 재생하는 함수가 처리되지 못하면 네트워크에게 해당 정보를 강제로 재전송하도록 하는 것 보다 사운드를 그냥 재생하지 않는 것이 더 낫습니다. 늦게 재생되는 사운드는 잘못된 사운드이므로 사운드 자체를 재생하지 않는 것이 더 낫습니다. 따라서 ClientPlaySound 가 확실히 복제되는지 확인하는 것에 대해 걱정하지 않는 것이 더 현명한 방법입니다.

부분적으로 신뢰 가능한 함수 호출

때때로 함수가 옳은 순서로 실행되는지 확인할 필요가 있지만 드롭된다고 신경쓰지 마십시오. 다음은 예제입니다. 클라이언트가 이동한다고 생각하는 장소와 서버가 생각하는 클라이언트 이동 장소가 틀리기 때문에 서버는 신뢰할 수 없는 ClientAdjustPosition 호출을 클라이언트에게 보내 플레이어의 위치에 대한 로컬 클라이언트의 정보를 업데이트합니다. 이러한 호출이 처리되지 않으면 뒤이은 ClientAdjustPositions 가 그 오류를 보완합니다. 그러나 그렇게 되면 플레이어의 폰이 필요 이상으로 나타나서 뛰어다니기 때문에 Unreal 은 이러한 호출들을 비순차적으로 처리하지 않습니다. 클라이언트가 자신의 현재 bFire, bJump, ViewRotation, 등에 관한 업데이트를 ServerMove 를 통해 전송할 때 동일한 논리가 적용됩니다. 이전의 ServerMoves 는 가장 최근 데이터가 처리된 후에는 처리되지 말아야 합니다. 이러한 경우 손실은 있지만 순차적으로 함수 호출을 에뮬레이션하기 위해 이전 데이터를 간단히 폐기하는 것이 더 낫습니다. 이것을 구현하기 위해 UnrealScript? 코드는 수동으로 WorldInfo.TimeSeconds 에서부터 계산되는 TimeStamp 값을 각 함수로 전달합니다. 아무 종류의 TimeStamp (이전 함수 호출을 폐기하기 위해 액터에 현재 값을 저장) 를 사용해도 제대로 작동하지만 일반적으로 정수 또는 정수가 아닌 값이 용량 이상으로 범람하는 것에 대한 걱정을 할 필요 없이 두 시간간의 정교하게 세분화된 차이점을 가질 수 있기 때문에 WorldInfo.TimeSeconds float 를 복제하는 것이 더 간단합니다 (비록 어느 순간에는 공간적으로 근접한 두 개의 tick 을 구별하기 위해 아래 소숫점을 누락할 수 있을 정도록 float 값을 충분히 증가시키는 것에 대해 걱정해야 하지만).

함수 복제와 시뮬레이션

복제/시뮬레이션 함수 규칙

먼저, 클라이언트 또는 함수가 함수를 로컬에서 실행할 수 있는가를 결정하는 것에 대한 기본적으로 간단한 규칙에 대해 설명하겠습니다. 다음 조건은 위의 상황이 발생하는 여부를 결정합니다. 조건이 일치하면 검사가 일치된 부분에서 정지하게 되고 해당 조건의 결과 절에 따라 로컬에서 실행되게 됩니다.

  1. 정적 함수인 경우 해당 컴퓨터에서 호출될 수 있습니다.
  2. 독립 실행형 서버에 있는 경우 해당 컴퓨터에서 호출될 수 있습니다.
  3. 복제된 함수가 아닌 경우 9번 절차로 이동합니다.
    (3번 조건에 따라 나머지는 복제된 함수에만 적요됩니다.)
  4. 서버이고 이 액터에 부모 PlayerController 이 없는 경우(부모 계층 구조의 어느 지점에서나), 또는 플레이어가 연결을 갖고 있는 않은 경우 (해당 서버의 플레이어에 대한 청취 서버), 로컬에서 실행됩니다.
  5. 실뢰할 수 있는 함수이고 연결 (서버-클라이언트 또는 클라이언트-서버) 은 포화된 경우 원격적으로 실행되는 ‘척’을 합니다 (예: 로컬에서 실행하지 마십시오.).
  6. 함수를 복제한 다음 로컬에서 실행하지 마십시오.
    이것은 위의 단계에 의해 호출된 경우에만 사용될 마지막 절차입니다.
  7. 서버에 있는 경우 호출될 수 있습니다.
  8. Autonomous Proxy 로 클라이언트에 있는 경우 로컬에서 호출될 수 있습니다.
  9. Dumb Proxy 또는 Simulated Proxy (Autonomous Proxy 가 아님) 로 클라이언트에 있고 시뮬레이션 함수인 경우, 로컬에서 호출될 수 있습니다.

복잡해 보일 수 있으나 Unreal 의 함수 처리 방법 및 원격 절차 호출 (Remote Procedure Call: RPC) 의 특징에 대한 자세한 세부 사항을 정확하게 설명합니다. 다음 또는 그다음 절에서 몇 가지 간단한 규칙으로 단순화시킬 수 있었으면 합니다.

복제/시뮬레이션 함수 규칙 재설명

함수가 연결의 상대쪽에서 복제되기 위해서는 반드시 다음 사항을 모두 충족해야 합니다.

  1. 부모 계층 구조에 있는 어느 시점에서 네트워크 PlayerController 에 의해 소유됨.
  2. 반드시 신뢰할 수 있는 함수이거나 사용 가능 대역폭을 가진 신뢰할 수 없는 함수이어야 함.

복제된 해당 함수가 상대쪽 컴퓨터에서 실제로 실행되기 위해서는 10번 규칙을 반드시 통과해야 합니다. 또한, 클라이언트에 있는 경우 다음 규칙을 모두 만족해야 합니다.

  1. 정적 함수.
  2. 시뮬레이션 함수.
  3. AutonomousProxy? Role (클라이언트상에서의 로컬 PlayerController 또는 로컬 GuidedWarhead?) 을 가진 액터에 있음.

위의 규칙은 시뮬레이션 또는 복제를 통해서든 클라이언트에서 실행될 모든 함수에 대해 통과되어야 합니다.

복제/시뮬레이션 함수 요약

이러한 규칙을 생각하면서 전체 경우를 아래에 요약해 보았습니다.

서버에서는 (클라이언트-서버) 복제된 함수이고 위의 검사를 만족시키지 않는 한 모든 함수는 실행됩니다. 따라서 실행하지 말라고 구체적으로 지시하지 않는 한 모든 함수가 서버에서 실행된다고 확신할 수 있습니다.

클라이언트에서는 모든 함수는 ‘소스’ 에서부터 출발해야 합니다. 소스는 서버-클라이언트 복제 함수, 실행 함수, 또는 이벤트일 수 있습니다. 이전에는 다루어지지 않았지만 이벤트는 아주 간단합니다. 이벤트는 native 코드에서부터 호출되는 모든 함수입니다. 이벤트는 서버 및 클라이언트상에서 모두 발생합니다. 서버는 직접 클라이언트에게 이벤트를 실행하도록 지시하지 않지만 클라이언트는 게임 상태(충돌 액터, 벽에 충돌, 타이머 이벤트, 게임 상태의 똑딱거림,등등)에 따라 이벤트를 실행하는 것을 이해합니다. 해당 이벤트가 시뮬레이션되면 클라이언트쪽 함수 호출의 ‘소스’ 의 역할을 할 수 있습니다. 소스는 함수가 클라이언트측 실행 조건을 만족한다는 가정하에 호출하고 싶은 함수를 호출할 수 있고, 호출된 함수는 다른 함수를 호출하게 되게 등, 계속해서 진행되게 됩니다.

함수가 호출되지만 상대측에서 복제되기 때문에 또는 클라이언트측의 실행 조건을 만족하지 못한 이유로 인해 실행 조건을 만족하지 못하게 되는 경우 함수는 결코 실행되지 않는 것과 같이 됩니다. 그러한 함수의 반환 값은 콘텍스에 따라 0, "", 또는 None 입니다. 해당 함수에 의해 정의된 모든 출력 매개 변수는 정확히 입력된 값으로 전달됩니다. 결코 실행되지 못할 함수의 결과에 의존하는 것은 클라이언트측에서만 나타나는 무수한 액세스된 none 의 소스입니다. 실행 함수(키 입력에 연결될 수 있는 함수)는 자연적으로 클라이언트상에서 평가합니다. 일부의 경우, Server-Administrator 명령 (PlayerController 에서 정의된 이러한 명령은 많음) 의 경우에서처럼 해당 서버로 함수가 복제되는 것을 원할 수 있습니다. 이 경우, 복제를 실행할 또 다른 함수를 만들어야 합니다. 실행 함수는 복제되어질 수 없습니다.

exec function doStuffOnServer(string args)
{
  // 클라이언트상에서 실행될 것임.
  serverDoStuffOnServer(args);
}

reliable server function serverDoStuffOnServer(string args)
{
  // 서버상에서 실행될 것임.
}

시뮬레이션 함수내에서 스폰하기

즉시 표시되지 않는 다른 흥미로운 감쳐진 행동이 있습니다. 예를 들면, 부모 계층 구조의 어느 시점에서 PlayerController 에 의해 액터가 소유되야 하는 조건 때문에 함수는 게임의 단일 플레이로 오직 복제될 수 있습니다 (다른 플레이어에 의해 플레이어가 소유되게 만드는 것은 문제를 해결하지 않음). ;) 멀티캐스트 함수 복제는 존재하지 않습니다. 시뮬레이션 함수를 사용하여 이 행동을 가질 수 있지만 서버와 클라이언트간에 정보는 전달되지 않습니다(시뮬레이션 함수도 로컬 컴퓨터에서 시작하고 로컬 컴퓨터에서만 존재하므로). 또는 플레이어들이 서로 상대적이라는 가정하에 게임에서의 모든 플레이어로 복제될 수 있는 복제된 변수를 사용할 수 있습니다.

스폰이 시뮬레이션 함수(시뮬레이션 함수는 나중에 설명될 것임)에서 실행되면 해당 액터의 여러 복사 (서버 및 시뮬레이션 함수가 실행되었던 각 클라이언트) 가 스폰될 수 있습니다. 서버의 버전은 일반적으로 클라이언트로 복제되므로 클라이언트는 2가지 버전을 보게됩니다. 2가지 버전이 비동기되면서 이상한 행동이 만들어지게 되고 클라이언트-스폰된 버전은 어떤 이유로 인해 ‘공식적인 버전’ 으로 쉽게 잘못 인식될 수 있지만 복제된 변수를 갖지 못합니다.

시뮬레이션 코드 (스폰 효과 클라이언트측 등과 같은 유효한 수많은 이유가 있음) 에서 스폰을 할 필요가 있으면 반드시 이 점을 고려해야 합니다. 클라이언측 효과를 만들려고 한다면 즉시 RemoteRoleROLE_None 으로 설정하도록 하십시오. 연관성은 틱간에만 검사되기 때문에 검사가 이루어지고 연관성이 확인되지 않으면 복제되지 않습니다. 이런 방식으로 서버와 클라이언트는 각자의 코스를 실행하는 효과의 로컬 복사를 갖게 되고 자체적으로 파괴하게 됩니다. 시뮬레이션 함수는 모든 클라이언트상에서 실행되지 않고 연관된 시뮬레이션 함수를 포함한 액터가 있는 클라이언트에서만 실행되기 때문에 영구 효과에는 유용하지 않습니다. 이는 즉 시뮬레이션 함수가 실행되지 않았으면 (그 시점에서 연관된 액터가 아니였기에) 그 효과의 뷰에 들어왔을때 해당 효과는 표시되지 않습니다. 그런 이유로 인해 코스에서 실행되고 자체적으로 파괴되는 임시 효과에만 사용되야 합니다.

그러나 영구적인 의도로 무언가를 스폰하거나 서버에서 데이터 복제(십자선 점과 같이)가 필요한 경우에는 클라이언트에서 스폰하지 말아야 합니다. 일반적으로 해당 스폰을 실행하기 전에 'If (WorldInfo?.NetMode = NM_Client)' 검사를 사용하여 이것을 이룰 수 있습니다. 그런 경우 스폰된 액터는 연관적 (조건이 일치한다라는 가정하에) 이게 되고 액터의 변수는 해당 클라이언트로 복제됩니다. 클라이언트측 액터가 스폰된 경우에는 2개의 액터가 있고, 그 중 하나는 서버로부터의 정보 없이 그냥 거기에 앉아있게 됩니다.

시뮬레이션 상태

또 다른 많이 관과되는 기능은 시뮬레이션 상태입니다. 상태 코드를 이미 보았을 것인데 함수 밖에 존재하는 코드이지만 상태에서는 일반적으로 라벨로 접두어 표시됩니다. 일반 상태에서 이 코드는 서버에서만 실행됩니다. 하지만 state statename 앞에 simulated 를 붙여 상태 코드 자체가 시뮬레이션되게 만들 수 있습니다. 따라서 개정된 상태 선언은 simulated state statename 입니다. 상태 변경은 기본적으로 클라이언트로 복제되어지거나 보내지지 않는다는 점에 유의하십시오. 하지만 클라이언트에서 실행되는 함수에서 gotostate 가 실행되면(복제 또는 시뮬레이션을 통해) 클라이언트는 새로운 상태를 알게 됩니다. PlayerController 의 상속 시뮬레이션은 그것의 모든 함수가 해당 상태를 제어할 수 있게 하여 주지만 다른 클래스들은 시뮬레이션 소스로부터 실행되는 시뮬레이션 함수 및 상태 변경을 알기 위한 함수 호출의 체인을 가질 필요가 있습니다.