본문 바로가기
Unreal 게임 개발/Unreal 강의 개인 정리

Network Mode, 로그인 과정, GameMode, GameState - Unreal Network MultiPlayer Framework

by daisy0461 2025. 3. 6.

Network Mode

  • 독립형(Standalone)
    게임이 원격 클라이언트의 접속을 허용하지 않는 서버로 실행된다.
    게임에 참여하는 모든 플레이어는 로컬 플레이어뿐이다.
    이 모드는 싱글 플레이어 게임 및 로컬 멀티플레이 게임에 사용된다.
    서버와 클라이언트를 구분하지 않고, 모든 로직을 로컬 컴퓨터에서 실행한다.
    (즉, 네트워크를 사용하지 않는 게임 환경)

  • 클라이언트(Client)
    이미 존재하는 서버(Server)에 접속하여 플레이하는 방식이다.
    클라이언트는 게임 상태를 직접 계산하지 않고, 서버에서 받은 데이터를 기반으로 동작하며 화면을 구성한다.
    서버가 종료되면 연결된 모든 클라이언트도 자동으로 접속이 종료된다.

  • 리슨 서버(Listen Server)
    원격 클라이언트의 접속을 허용한다.
    가벼운 협동(Co-op) 및 경쟁(PvP) 멀티플레이에 사용된다.
    서버를 호스팅하는 플레이어가 직접 게임을 플레이하는 구조이다.
    (예: 로컬 컴퓨터에서 서버를 실행하고, 친구들을 초대하여 함께 게임을 함)
    서버를 호스팅하는 플레이어는 네트워크를 통해 접속하는 다른 플레이어보다 지연(Latency) 없이 즉각적인 반응이 가능
    (공정성 문제가 발생할 가능성이 있음)
    또한, 호스트는 서버 역할 + 그래픽/사운드 처리까지 해야 하므로 추가적인 부하가 발생한다.
    따라서 공정성이 중요한 게임이나 네트워크 부하가 높은 게임에는 적합하지 않다.

  • 데디케이티드 서버(Dedicated Server)
    원격 클라이언트의 접속을 허용하지만, 서버 자체에서는 플레이어가 존재하지 않는다.
    리슨 서버와 다르게, 로컬 플레이어가 없기 때문에 플레이 관련 기능(그래픽, 사운드 등)은 모두 비활성화된다.
    데디케이티드 서버는 설정이 어렵고 유지 비용이 발생할 수 있으며, 모든 플레이어가 서버에 네트워크를 통해 접속해야 한다.
    하지만 공정성이 보장되며, 서버가 게임 플레이를 하지 않으므로 네트워킹을 더 효율적으로 처리 가능하다.
    공정성과 안정성, 고성능이 중요한 게임(예: 대규모 멀티플레이, MMO, FPS 등)에 적합한 방식이다.

네트워크 멀티플레이어 게임에 클라이언트가 접속하는 과정 (로그인 과정)

더보기

(서버에만 존재하는 Actor인 게임모드를 중심으로 설명한다. 또한 아래의 설명의 로그인 플로우는 PIE(Play In Editor)를 중심으로 설명한다.)

  1. 서버의 초기화 단계
    서버를 담당하는 애플리케이션은 실행되었지만, 게임은 아직 시작되지 않은 상태. (서버는 실행되었지만, 게임 진행은 X)
    애플리케이션의 네트워크 기능이 활성화되지 않았음. 따라서 네트워크 모드는 스탠드얼론(싱글플레이용 서버) 상태.
    서버에는 게임의 규칙을 결정하는 GameMode Actor가 존재함.

    서버 실행 ≠ 네트워크 기능 활성화
    • 서버가 실행되었다는 것은 단순히 프로그램이 실행되었다는 의미.
    • 네트워크 기능이 활성화된다는 것은 클라이언트가 접속할 수 있도록 서버가 네트워크를 열었다는 의미.
    • 즉, 현재 서버는 클라이언트 접속을 허용하지 않는 상태로 실행됨.
  2. 플레이어(호스트) 로그인
    리슨 서버가 네트워크 기능을 활성화하기 위해서 GameMode가 서버를 실행하는 플레이어(호스트)의 PlayerController(Player를 대표하는 Actor)를 생성해야한다. 
    리슨 서버의 방식은 서버 + 플레이어(호스트)이므로에 서버가 자기 자신의 PlayerController를 먼저 생성해야 다른 클라이언트를 받을 수 있다.
    이때 자기 자신이 게임에 참여해도 Game Mode가 제공하는 로그인 과정을 통해 진행된다.
    아직 네트워크를 열지 않아 네트워크 모드는 스탠드얼론이다.

  3. 리슨 서버 시작
    이제 GameMode와 Player Controller가 생성되었으니 다른 클라이언트를 받을 수 있다. 
    네트워크를 열어서 게임 서비스를 시작한다. 그러므로 네트워크 모드가 리슨 서버로 변경된다.

  4. 클라이언트의 접속 시도
    클라이언트에서 게임에 참가하기 위해 신호를 보낸다. (서버는 거절도 가능하다.)
  5. 클라이언트 접속 허용
    클라이언트의 접속을 허용했다면 Game Mode가 해당 클라이언트를 대표하는 PlayerController1를 리슨서버에 생성한다.

  6. 클라이언트 초기화
    클라이언트를 대표하는 PlayerController1은 클라이언트에 복제된다.
    이제부터 클라이언트는 리슨 서버에 있는 컨텐츠, 데이터를 복제해서 사용자에게 보여준다.
    이전에 설명했듯이 모든 정보를 넘기지 않고 문제가 없을 정도의 데이터의 양만 클라이언트에게 전달한다.
    해당 클라이언트는 서버에서 게임이 시작되었기에 접속하자마자 게임을 시작한다.

  7. 게임의 시작
    GameMode는 클라이언트에 존재하지 않는다.
    StartPlay 함수가 실행된 후, BeginPlay는 서버에서 실행되는데, 클라이언트는 어떻게 신호를 받아서 BeginPlay를 실행할까?
    GameState라는 Actor를 사용한다.

    GameState의 역할
    GameState는 서버와 클라이언트 모두에 존재하며, 서버-클라이언트 간 동기화 역할을 한다.
    이유는 GameMode는 서버 전용이라 클라이언트에는 존재하지 않기 때문이다.
    따라서 클라이언트에게 직접 게임이 시작되었음을 알릴 수 없다.
    대신, 동기화되는 GameState를 통해 클라이언트에게 게임이 시작되었음을 전달한다.

    BeginPlay 호출 흐름
    게임이 시작되면 GameMode는 리슨 서버의 Actor들에게 BeginPlay를 호출하라고 지시한다.
    이때, GameMode의 GameState와 클라이언트의 GameState가 동기화된다.
    동기화된 타이밍에, 복제된 GameState가 있는 클라이언트의 모든 Actor에게 BeginPlay를 호출하라는 지시를 내린다.
    그럼 왜 클라이언트에서도 BeginPlay를 호출해야할까? 서버만 하면 되는 것 아닌가?
    서버의 BeginPlay에는 체력 = 100, AI Controll, 게임 로직 등 데이터를 활용한 작업을 수행하는 것이고
    클라이언트의 BeginPlay는 서버에서 하지 못하는 UI, Effect & Sound, Model 등 로컬에 필요한 작업을 수행한다.

멀티플레이 프레임워크 Game Mode의 중요 함수
(AGameModeBase에 구현이 되어 있다. override 사용)

  • PreLogin : 클라이언트의 접속을 요청을 허용할 것인지 거절할 것인지 처리하는 함. 호스트는 따로 이 함수가 실행되지 않는다.
    매개변수 중 ErrorMessage에 값을 입력하면 Error로 간주하여 접속을 거절한다.
  • Login : 접속을 허용한 클라이언트에 대응하는 PlayerController를 만드는 함수
    return값이 PlayerController이다. 이것 서버에서 PlayerController를 만들어서 접속한 클라이언트에게 보내주는 것이다.
  • PostLogin : 플레이어 입장을 위해 플레이어에 필요한 기본 설정을 모두 마무리하는 함수.
    이 함수가 끝나면 게임을 시작할 준비가 완료된다.
  • StartPlay : 게임의 시작을 지시하는 함수 (이 이후 BeginPlay 실행)

Log를 추가해서 호스트의 실행 순서를 확인함.
타 클라이언트 접속 순서 (PreLogin이 있음)
StartPlay를 주석처리하면 BeginPlay가 실행되지 않음.

 

멀티플레이 프레임워크 GameState의 중요 함수
(AGameStateBase에 구현이 되어 있다. override 사용)

GameState를 설정하려면 GameMode에서 다음과 같은 코드를 생성자에 추가해야한다.

  • HandleBeginPlay : GameMode가 StartPlay()를 호출하여 GameState에 명령을 받았을 때 GameState가 월드에 있는 모든 Actor에게 BeginPlay를 호출하고 게임을 시작하도록 하는 함. 로컬의 로직이어서 서버에서만 실행된다.
  • OnRep_ReplicatedHasBegunPlay : 클라이언트가 서버로부터 게임 시작을 동기화 받으면 처리되며 HandleBeginPlay와 비슷한 작업을 수행한다.
    하지만 클라이언트에는 GameMdoe가 없어 StartPlay를 호출할 수 없다.
    따라서 서버의 GameState의 bReplicatedHasBegunPlay 프로퍼티가 서버에서 변경되면, 클라이언트에서 이를 감지하고 OnRep_ReplicatedHasBegunPlay가 실행된다. .


호스트의 StartPlay - HandleBeginPlay - BeginPlay 순서를 확인 가능
클라이언트가 OnRep_ReplicatedHasBegunPlay 이후 BeginPlay가 호출됨을 확인할 수 있다.