This document is about: FUSION 2
SWITCH TO

수정중인 페이지 입니다.

호스트 마이그레이션 API

개요

Photon Fusion은 여러 아키텍처를 지원하며, 그중 하나는 클라이언트 호스팅 토폴로지로, Fusion에서는 HostMode라고도 부릅니다. HostMode는 게임 세션의 클라이언트 중 한 명이 게임의 호스트 역할도 겸한다는 것을 의미합니다. 클라이언트 호스트는 자신의 로컬 컴퓨터에서 새로운 게임 세션을 생성 및 제공하며, 다른 플레이어들이 해당 머신을 게임 세션 서버로 사용하여 함께 플레이할 수 있도록 합니다.

Fusion은 클라이언트와 호스트 간 연결을 설정하는 데 필요한 모든 작업을 처리하는 NAT Punchthrough 알고리즘을 구현합니다. 따라서 포트 포워딩이나 방화벽 규칙을 설정할 필요가 없으며, 이를 통해 플레이어 호스팅 게임 개발이 간단해집니다.

이 방식의 주요 장점은 동시에 가장 큰 단점이기도 한데, 즉 관련 인프라에 대한 제어가 부족하다는 점입니다. 게임 세션은 다음과 같은 이유로 품질이 불안정해지거나 중단될 수 있습니다:

  1. 가정용 네트워크의 트래픽 품질이 변동할 경우 – 이는 게임 호스트의 인터넷 연결 상태나 가입 요금제에 따라 달라집니다.
  2. 호스트 머신이 전원 차단, 시스템 업데이트 또는 플레이어에 의한 수동 종료 등으로 인해 꺼질 경우.

이 두 가지 상황 모두 플레이어 경험을 악화시킬 수 있으며, 특히 Fusion 게임이 HostMode에서 실행될 경우 게임 서버가 존재해야 하기 때문에 게임 세션이 갑자기 종료되면 문제가 됩니다.

이 문제를 해결하기 위해 Fusion은 개발자가 통합할 수 있는 Host Migration API/시스템을 구현했습니다. Fusion의 호스트 마이그레이션 기능을 활용하면 게임 세션 내의 다른 클라이언트 피어가 게임 호스트 역할을 인계받아 게임 세션 제공을 지속할 수 있습니다. 이는 전체적인 게임 경험을 향상시키며, 전용 서버의 ServerMode에서 헤드리스 인스턴스를 실행하는 데 필요한 인프라에 대한 확실한 대안이 됩니다.

참고: 예제 구현은 Fusion 호스트 마이그레이션 샘플에서 확인할 수 있습니다.

호스트 마이그레이션

호스트 마이그레이션을 수행하려면 프로젝트가 몇 가지 전제 조건을 충족해야 합니다:

  1. 클라이언트-호스트 게임: Fusion을 시작할 때 피어 중 한 명이 호스트(서버와 플레이어가 동일 머신에서 실행)로 시뮬레이션을 시작해야 합니다. 이는 NetworkRunner.StartGame()을 호출할 때 GameMode.Host 또는 GameMode.AutoHostOrClient 파라미터를 사용하여 수행할 수 있습니다.
  2. 호스트 마이그레이션 활성화: 이 기능은 선택적 기능으로, 구현을 위해 약간의 수작업이 필요하므로 기본적으로 활성화되어 있지 않습니다.
  3. 게임 마이그레이션 준비: 호스트를 다른 머신으로 마이그레이션하는 것은 간단한 작업은 아니지만, Fusion은 이를 최대한 쉽게 만들어줍니다. 시스템은 이전 호스트의 전체 게임 상태에 접근할 수 있도록 하며, 마이그레이션 프로세스에서 무엇이 포함되거나 제외될지를 강제하지 않습니다.

호스트 마이그레이션 활성화

호스트 마이그레이션을 활성화하려면, Fusion > Network Project Config 메뉴를 통해 NetworkProjectConfig 에셋을 열고, 에셋의 Config 섹션에서 다음 설정들을 확인하세요:

  • Enable Host Migration: Host Migration 시스템을 활성화하는 체크박스.
  • Host Migration Snapshot Interval: Photon Cloud로 전송되는 스냅샷의 간격(초 단위). 적절한 값은 게임의 진행 속도에 따라 다르며, 대부분의 경우 30초 간격을 권장합니다. 클라우드에는 최신 스냅샷만 저장되므로, 호스트 마이그레이션 시점과 마지막 스냅샷 사이에 발생한 게임 상태 변경은 손실됩니다.
Add Fusion Stats
NetworkProjectConfig 에셋의 Host Migration 설정

호스트 마이그레이션 수행

호스트 마이그레이션의 주요 진입점은 INetworkRunnerCallbacks.OnHostMigration 콜백입니다. 게임에서 호스트 마이그레이션 절차를 수행해야 할 때 OnHostMigration()이 호출됩니다.

Fusion은 이전 호스트의 게임 상태를 순회할 수 있는 NetworkObjects 목록으로 노출하며, 이를 통해 새로운 호스트가 이전 상태에 최대한 가깝게 게임 상태를 복원할 수 있도록 합니다.

호스트 마이그레이션 프로세스는 다음 단계로 구성됩니다:

  1. Photon Cloud에 호스팅 된 Fusion Server Plugin이 호스트 피어가 세션을 떠났음을 감지하면, 모든 다른 피어에서 호스트 마이그레이션 프로세스를 트리거 합니다. 이 시점에서:
    1. 새로운 호스트가 선택되고, 그리고
    2. 이전 호스트로부터 받은 마지막 저장된 게임 상태가 새로운 호스트로 전송됩니다. 참고: 이 스냅샷은 새로운 호스트에게만 전송되며, 다른 피어에게는 전달되지 않습니다.
  2. INetworkRunnerCallbacks.OnHostMigration 콜백이 호출되어 마이그레이션 프로세스가 시작됨을 알립니다.
    1. 현재의 Fusion NetworkRunner는 여전히 실행 중이며, 수동으로 종료되어야 합니다. 이를 통해 개발자는 마이그레이션 전에 필요한 초기화 및 정리를 수행할 수 있습니다.
    2. 새로운 호스트에 연결하고 게임을 다시 시작하기 위해 새로운 Fusion NetworkRunner를 생성해야 합니다. 이전의 Runner를 재사용하는 것은 지원되지 않습니다. 이전 게임에 대한 모든 필요한 정보는 OnHostMigration 콜백에서 제공되는 HostMigrationToken에 담겨 있습니다. 이 단계는 새로운 호스트와 연결되는 모든 클라이언트에서 동시에 수행됩니다. 각 피어가 사용할 SessionNameGameModeHostMigrationToken에 지정되어 있습니다.
  3. 마지막 단계는 게임 상태 재생성입니다. 이 단계는 새로운 호스트에서만 발생하며, Fusion NetworkRunnerStartGameArgs.HostMigrationResume 인자로 전달된 콜백을 호출하는 것으로 구성됩니다. 이 콜백은 NetworkRunner가 완전히 초기화되기 전에 호출되어, 개발자가 이전 게임 상태를 읽고, 이전의 NetworkObject를 재생성하며, 시뮬레이션 시작 전에 필요한 설정을 할 수 있도록 합니다.

다음 코드 스니펫은 위에서 설명한 단계를 예시합니다.

C#

public class FusionInit : MonoBehaviour, INetworkRunnerCallbacks {

  // other callbacks...

  // Step 1.
  // It happens on the Photon Cloud and there is no direct relation with the code on the peers.

  // Step 2.
  // OnHostMigration callback
  public async void OnHostMigration(NetworkRunner runner, HostMigrationToken hostMigrationToken) {

    // Step 2.1
    // Shutdown the current Runner, this will not be used anymore. Perform any prior setup and tear down of the old Runner

    // The new "ShutdownReason.HostMigration" can be used here to inform why it's being shut down in the "OnShutdown" callback
    await runner.Shutdown(shutdownReason: ShutdownReason.HostMigration);

    // Step 2.2
    // Create a new Runner.
    var newRunner = Instantiate(_runnerPrefab);

    // setup the new runner...

    // Start the new Runner using the "HostMigrationToken" and pass a callback ref in "HostMigrationResume".
    StartGameResult result = await newRunner.StartGame(new StartGameArgs() {
      // SessionName = SessionName,              // ignored, peer never disconnects from the Photon Cloud
      // GameMode = gameMode,                    // ignored, Game Mode comes with the HostMigrationToken
      HostMigrationToken = hostMigrationToken,   // contains all necessary info to restart the Runner 
      HostMigrationResume = HostMigrationResume, // this will be invoked to resume the simulation
      // other args
    });

    // Check StartGameResult as usual
    if (result.Ok == false) {
      Debug.LogWarning(result.ShutdownReason);
    } else {
      Debug.Log("Done");
    }
  }

  // Step 3. 
  // Resume Simulation on the new Runner
  void HostMigrationResume(NetworkRunner runner) {

    // Get a temporary reference for each NO from the old Host
    foreach (var resumeNO in runner.GetResumeSnapshotNetworkObjects())

      if (
          // Extract any NetworkBehavior used to represent the position/rotation of the NetworkObject
          // this can be either a NetworkTransform or a NetworkRigidBody, for example
          resumeNO.TryGetBehaviour<NetworkPositionRotation>(out var posRot)) {

          runner.Spawn(resumeNO, position: posRot.ReadPosition(), rotation: posRot.ReadRotation(), onBeforeSpawned: (runner, newNO) => 
          {
            // One key aspects of the Host Migration is to have a simple way of restoring the old NetworkObjects state
            // If all state of the old NetworkObject is all what is necessary, just call the NetworkObject.CopyStateFrom
            newNO.CopyStateFrom(resumeNO);

            // and/or

            // If only partial State is necessary, it is possible to copy it only from specific NetworkBehaviours
            if (resumeNO.TryGetBehaviour<NetworkBehaviour>(out var myCustomNetworkBehaviour))
            {
               newNO.GetComponent<NetworkBehaviour>().CopyStateFrom(myCustomNetworkBehaviour);
            }
          });
      }
    }
  }

  public void OnShutdown(NetworkRunner runner, ShutdownReason shutdownReason) {

    // Can check if the Runner is being shutdown because of the Host Migration
    if (shutdownReason == ShutdownReason.HostMigration) {
      // ...
    } else {
      // Or a normal Shutdown
    }
  }
}

API 개요

  • INetworkRunnerCallbacks.OnHostMigration: 호스트 마이그레이션을 수행해야 할 때 호출됩니다.
  • HostMigrationToken: 호스트 마이그레이션 수행 시 이전 NetworkRunner로부터 필요한 모든 정보를 담고 있으며, StartGame 호출 시 새로운 NetworkRunner에 전달되어야 합니다.
  • HostMigrationToken.GameMode: 로컬 피어가 시작할 새로운 GameMode로, Host 또는 Client일 수 있습니다. 플레이어에게 추가 정보를 표시하는 데 유용합니다.
  • StartGameArgs.HostMigrationToken: INetworkRunnerCallbacks.OnHostMigration 콜백에서 받은 HostMigrationToken을 받아들입니다.
  • StartGameArgs.HostMigrationResume: 게임 시뮬레이션 재시작 전에 새로운 호스트에서 게임 상태 재생성을 수행할 때 호출될 콜백을 받아들입니다.
  • NetworkRunner.GetResumeSnapshotNetworkObjects: 이전 호스트의 마지막 알려진 상태를 노출하는 NetworkObjects의 반복 가능한 목록을 반환합니다. 이를 통해 새로운 Fusion 시뮬레이션에서 다시 생성해야 할 항목을 확인할 수 있습니다.
  • NetworkObject.CopyStateFrom: 이전 NetworkObject의 모든 상태를 새로 생성된 오브젝트로 복사하는 데 사용됩니다.
  • NetworkBehaviour.CopyStateFrom: 특정 NetworkBehaviour의 모든 상태를 새 NetworkObject의 해당 행동으로 복사하는 데 사용됩니다.
  • ShutdownReason.HostMigration: NetworkRunner가 종료되는 이유를 나타내기 위해 사용되며, Host Migration에 적절히 대응할 수 있도록 합니다.
Back to top