Steam Session Subsystem 기획서
프로젝트: SagoMagic
작성 기준: UE5 + Steam + AWS EC2 데디케이티드 서버
세션 방식: Steam 친구 초대 전용 (불특정 다수 매칭 없음)
1. 개요
1.1 목표
- 최대 4인(최소 1인)이 Steam 친구 초대를 통해 같은 서버에 모여 디벤스 게임을 진행
- 모든 게임 로직의 권위는 AWS 데디케이티드 서버가 가진다.
- 방장(호스트)은 게임 서버 역할을 하지 않으며, Steam 세션 등록과 UI 진행만 담당한다.
1.2 핵심 용어 정리
| 용어 | 설명 |
|---|---|
| 데디케이티드 서버 | AWS EC2에서 24시간 실행되는 게임 서버 프로세스. 게임 로직의 단일 권위자 |
| Steam 세션 | Steam 서버 목록에 등록되는 메타데이터. 접속 주소(AWS IP) 포함 |
| 방장 (Host) | 로비를 생성하고 Steam 세션을 등록하는 클라이언트 플레이어 |
| SeamlessTravel | 클라이언트 연결을 유지한 채 레벨을 전환하는 UE5 기능 |
| CopyProperties | SeamlessTravel 시 PlayerState 데이터를 새 레벨로 복사하는 UE5 함수 |
2. 전체 흐름
[L_Main] 방장이 Host 클릭
│
│ ClientTravel (AWS 고정 IP)
▼
[L_Lobby / AWS 데디서버] 방장 접속
│
│ 방장 클라이언트가 Steam 세션 등록
│ Steam 친구 초대
│ 친구들1 ClientTravel (AWS IP) 로 합류
│ PlayerState에 캐릭터/장비 저장
│ 전원 Ready + 방장 Start
│
│ ServerTravel + SeamlessTravel
▼
[L_Play / AWS 데디서버] 게임 시작
│
│ CopyProperties → PlayerState 데이터 유지
│ GameMode가 PlayerState 읽어 Pawn 스폰
▼
게임 진행
3. 레벨 구조
3.1 레벨 목록
| 레벨 | 실행 위치 | GameMode |
|---|---|---|
| L_Main | 플레이어 로컬 PC | 없음 (기본값) |
| L_Lobby | AWS 데디케이티드 서버 | ASMLobbyGameMode |
| L_Play | AWS 데디케이티드 서버 | ASMGameMode |
3.2 레벨별 역할
L_Main
- 플레이어의 로컬 PC에서만 동작하는 오프라인 화면
- 게임 실행 시 Steam에 자동으로 온라인 연결됨 (코드 불필요)
- 세션 없음. Host 버튼 클릭 시 AWS 서버로 ClientTravel
L_Lobby
- AWS 데디서버에서 실행
- 플레이어 슬롯 (1~4) 표시 및 준비 상태 관리
- Steam 친구 초대 진행
- 캐릭터/장비 선택 및 PlayerState 저장
- 전원 Ready 확인 후 방장이 Start → L_Play로 ServerTravel
L_Play
- AWS 데디서버에서 실행
- SeamlessTravel로 L_Lobby에서 전환됨
- GameMode가 PlayerState를 읽어 Pawn 스폰
- 디펜스 게임플레이 진행
4. Steam 세션 동작 방식
4.1 세션 등록 주체
데디케이티드 서버가 직접 Steam에 세션을 등록하려면 Steam Game Server API 연동이 필요하여 구현 복잡도가 높다. 따라서 방장 클라이언트가 세션을 등록하는 방식을 채택한다.
방장은 Listen Server 역할을 하지 않는다.
Steam 세션 등록은 단순히 "이 AWS 서버에 이런 게임이 열려있다"는 메타데이터를 Steam에 알리는 행위이며, 게임 트래픽은 방장 PC를 경유하지 않고 AWS 서버로 직접 전달된다.
4.2 세션 등록 시점
- 방장이 Host 클릭 → AWS 서버로 ClientTravel
- L_Lobby 진입 완료
- 방장 클라이언트의
USMSessionSubsystem.CreateSession()호출 - Steam 세션 등록 완료 → InviteButton 활성화
4.3 세션 설정값
| 설정 | 값 | 이유 |
|---|---|---|
| NumPublicConnections | 4 | 최대 4인 |
| bIsDedicated | false | 방장 클라이언트가 등록 주체 |
| bUsesPresence | true | Steam 친구 초대에 필요 |
| bUseLobbiesIfAvailable | true | Steam Lobby 활용 |
| bShouldAdvertise | true | 초대 가능 상태로 노출 |
| bAllowJoinInProgress | false | 게임 시작 후 합류 불가 |
4.4 친구 초대 흐름
- 방장 → Steam 오버레이 → 친구 초대 전송
- 친구 → 초대 수락
- Steam → AWS 서버 IP 반환
- 친구 클라이언트 →
ClientTravel(AWS IP)→ L_Lobby 진입
4.5 게임 외부에서 초대 수락 시
- 친구가 Steam에서 초대 수락 → 게임 자동 실행
- 게임 실행 →
USMSessionSubsystem.Initialize()에서 InviteAccepted 콜백 발동 - 자동으로 AWS 서버 접속
5. 레벨 전환 및 데이터 전달
5.1 L_Main → L_Lobby
- 방장:
ClientTravel(AWS_ELASTIC_IP:7777) - 게스트:
OnSessionUserInviteAccepted()→GetResolvedConnectString()→ClientTravel
5.2 L_Lobby → L_Play
// ASMLobbyGameMode.TryStartGame()
GetWorld()->ServerTravel("/Game/Maps/L_Play?listen?MaxPlayers=N");
bUseSeamlessTravel = true상태에서 ServerTravel 호출- 연결된 모든 클라이언트가 자동으로 L_Play로 전환
ASMPlayerState::CopyProperties()자동 호출 → 데이터 유지
5.3 PlayerState 데이터 유지 조건
PlayerState는 레벨 전환 시 파괴 후 재생성된다. 데이터 유지를 위해 아래 두 조건이 반드시 충족되어야 한다.
| 조건 | 설정 위치 | 내용 |
|---|---|---|
| SeamlessTravel 활성화 | ASMLobbyGameMode 생성자 | bUseSeamlessTravel = true |
| CopyProperties 오버라이드 | ASMPlayerState.cpp | 커스텀 변수 직접 복사 |
UPROPERTY(Replicated) 는 서버→클라이언트 동기화 용도이며, 레벨 전환 후 데이터 유지와 무관하다.
5.4 L_Play에서 데이터 수신
ASMGameMode.BeginPlay()에서GetGameInstance<USMGameInstance>()->GetLobbyInfo()호출ASMGameMode.PostLogin()에서 PlayerState 직접 읽기 (캐릭터·장비 정보)- Pawn 스폰 및 빙의(Possess)
6. GameMode별 PlayerState 클래스 지정
두 GameMode 모두 동일한 PlayerState 클래스를 지정해야 CopyProperties가 정상 동작한다.
// ASMLobbyGameMode 생성자
PlayerStateClass = ASMPlayerState::StaticClass();
bUseSeamlessTravel = true;
// ASMGameMode 생성자 (게임플레이 팀)
PlayerStateClass = ASMPlayerState::StaticClass();
bUseSeamlessTravel = true;
7. 테스트 전략
| 단계 | 방법 | 목적 | Steam 필요 |
|---|---|---|---|
| 1단계 | PIE + NULL Subsystem | 로직·Replication 검증 | 불필요 |
| 2단계 | PIE + Steam | Steam 초기화·세션 생성 확인 | 필요 (단일 클라이언트) |
| 3단계 | Standalone + Steam | 팀원과 실제 Steam 초대 테스트 | 필요 (각 PC별 계정) |
| 4단계 | 패키징 빌드 + AWS | 최종 통합 테스트 | 필요 |
PIE에서 클라이언트 2개 이상 + Steam 동시 연결은 불가능하다. (Steam 계정 1개당 1인스턴스 제한)
Steam 초대 기능은 반드시 Standalone 단계에서 팀원 PC와 함께 검증한다.
8. Build.cs 의존 모듈
PublicDependencyModuleNames.AddRange(new string[]
{
"Core",
"OnlineSubsystem",
"OnlineSubsystemSteam",
"UMG",
"Slate",
"SlateCore"
});
PrivateDependencyModuleNames.AddRange(new string[]
{
"CoreUObject",
"Engine",
"Slate",
"SlateCore"
});
9. DefaultEngine.ini 설정
; 개발 중 (PIE 테스트)
[OnlineSubsystem]
DefaultPlatformService=NULL
; Steam 연동 시 (Standalone 이후)
[OnlineSubsystem]
DefaultPlatformService=Steam
[OnlineSubsystemSteam]
bEnabled=true
SteamDevAppId=480
bInitServerOnClient=true
; SeamlessTravel 활성화
[/Script/Engine.GameMapsSettings]
bUseSmoothTravel=true
10. 문제점

동시에 여러개의 session 생성 불가능.
반응형
'언리얼 게임개발' 카테고리의 다른 글
| [팀 프로젝트 회고] 2026-04-24 | 팀 프로젝트 회고 (0) | 2026.04.27 |
|---|---|
| [TIL] 2026-04-16 | GameplayCueNotify에서 무기 소켓 위치 올바르게 가져오기 (0) | 2026.04.16 |
| [TIL] 2026-04-13 | UE5 멀티플레이 로비 - 캐릭터 외형 커스터마이징 시스템 설계 (0) | 2026.04.13 |
| [TIL] 2026-04-06 | UnrealEngine에서의 Null체크: IsValid(Thing), Thing.IsValid, !Thing의 차이점 (0) | 2026.04.06 |
| [TIL] 2026-04-02 | UnrealEngine에서의 TObjectPtr과 Raw포인터의 사용 (0) | 2026.04.02 |