KLingo Project Documentation 1.0.0
Unreal Engine 5.6 C++ Project Documentation
로딩중...
검색중...
일치하는것 없음
ULingoGameInstance.cpp
이 파일의 문서화 페이지로 가기
1// Fill out your copyright notice in the Description page of Project Settings.
2
3
5
6#include <string>
7
8#include "OnlineSubsystem.h"
9#include "OnlineSubsystemUtils.h"
10#include "OnlineSessionSettings.h"
11#include "Online/OnlineSessionNames.h"
12#include "GameLogging.h"
14
19
21{
22 Super::Init();
23
24 // 현재 사용하는 서브시스템을 가져오자
25 IOnlineSubsystem* subsys = Online::GetSubsystem(GetWorld());
26 if (subsys)
27 {
28 // 서브시스템의 인터페이스를 가져오자.
29 sessionInterface = subsys->GetSessionInterface();
30 // 세션 생성 성공시 호출되는 함수 등록
31 sessionInterface->OnCreateSessionCompleteDelegates.AddUObject(
33 // 세션 조회 성공시 호출되는 함수 등록
34 sessionInterface->OnFindSessionsCompleteDelegates.AddUObject(
36 // 세션 참여 성공시 호출되는 함수 등록
37 sessionInterface->OnJoinSessionCompleteDelegates.AddUObject(
39 }
40}
41
43{
44 // 델리게이트 정리
45 if (sessionInterface.IsValid())
46 {
47 // 세션 델리게이트 바인딩 해제
48 sessionInterface->OnCreateSessionCompleteDelegates.RemoveAll(this);
49 sessionInterface->OnFindSessionsCompleteDelegates.RemoveAll(this);
50 sessionInterface->OnJoinSessionCompleteDelegates.RemoveAll(this);
51
52 PRINTLOG(TEXT("[LingoGameInstance] Session delegates cleared"));
53 }
54
55 // sessionSearch 정리
56 if (sessionSearch.IsValid())
57 {
58 sessionSearch.Reset();
59 }
60
61 // sessionInterface 정리
62 sessionInterface.Reset();
63
64 // selectCharacter 맵 정리
65 selectCharacter.Empty();
66
67 PRINTLOG(TEXT("[LingoGameInstance] Shutdown complete"));
68
69 Super::Shutdown();
70}
71//
72// void ULingoGameInstance::SetPlayerRole(APlayerController* PlayerController, EPlayerRole Role)
73// {
74// if (!PlayerController)
75// {
76// PRINTLOG(TEXT("[FireGameInstance] SetPlayerRole: Invalid PlayerController"));
77// return;
78// }
79//
80// // PlayerState의 PlayerName을 Key로 사용 (맵 전환 시에도 유지됨)
81// APlayerState* PS = PlayerController->GetPlayerState<APlayerState>();
82// if (!PS)
83// {
84// PRINTLOG( TEXT("[FireGameInstance] SetPlayerRole: PlayerState not found!"));
85// return;
86// }
87//
88// FString PlayerKey = PS->GetPlayerName();
89//
90// // PlayerName이 비어있으면 PlayerId 사용 (Fallback)
91// if (PlayerKey.IsEmpty())
92// {
93// PlayerKey = FString::Printf(TEXT("Player_%d"), PS->GetPlayerId());
94// PRINTLOG( TEXT("[FireGameInstance] PlayerName empty, using PlayerId: %s"), *PlayerKey);
95// }
96//
97// // PlayerRoleMap.Add(PlayerKey, Role);
98//
99// PRINTLOG( TEXT("[FireGameInstance] Player %s (Key: %s) selected role: %s"),
100// *PlayerController->GetName(),
101// *PlayerKey,
102// *UEnum::GetValueAsString(Role));
103// }
104//
105// EPlayerRole ULingoGameInstance::GetPlayerRole(APlayerController* PlayerController) const
106// {
107// if (!PlayerController)
108// {
109// PRINTLOG( TEXT("[FireGameInstance] GetPlayerRole: Invalid PlayerController"));
110// return EPlayerRole::None;
111// }
112//
113// // PlayerState의 PlayerName을 Key로 사용 (맵 전환 시에도 유지됨)
114// APlayerState* PS = PlayerController->GetPlayerState<APlayerState>();
115// if (!PS)
116// {
117// UE_LOG(LogTemp, Error, TEXT("[FireGameInstance] GetPlayerRole: PlayerState not found!"));
118// return EPlayerRole::None;
119// }
120//
121// FString PlayerKey = PS->GetPlayerName();
122//
123// // PlayerName이 비어있으면 PlayerId 사용 (Fallback)
124// if (PlayerKey.IsEmpty())
125// {
126// PlayerKey = FString::Printf(TEXT("Player_%d"), PS->GetPlayerId());
127// PRINTLOG( TEXT("[FireGameInstance] PlayerName empty, using PlayerId: %s"), *PlayerKey);
128// }
129//
130// // TMap에서 Role 조회
131// const EPlayerRole* FoundRole = PlayerRoleMap.Find(PlayerKey);
132//
133// if (FoundRole)
134// {
135// PRINTLOG( TEXT("[FireGameInstance] Found role for %s (Key: %s): %s"),
136// *PlayerController->GetName(),
137// *PlayerKey,
138// *UEnum::GetValueAsString(*FoundRole));
139// return *FoundRole;
140// }
141// else
142// {
143// PRINTLOG( TEXT("[FireGameInstance] No role found for %s (Key: %s), returning None"),
144// *PlayerController->GetName(),
145// *PlayerKey);
146// return EPlayerRole::None;
147// }
148// }
149//
150// void ULingoGameInstance::DebugPrintPlayerRoles() const
151// {
152// PRINTLOG( TEXT("=== [FireGameInstance] Current Player Roles ==="));
153//
154// if (PlayerRoleMap.Num() == 0)
155// {
156// PRINTLOG( TEXT(" (No players registered)"));
157// return;
158// }
159//
160// for (const auto& Entry : PlayerRoleMap)
161// {
162// PRINTLOG( TEXT(" Key: %s -> Role: %s"),
163// *Entry.Key,
164// *UEnum::GetValueAsString(Entry.Value));
165// }
166//
167// PRINTLOG( TEXT("==========================================="));
168// }
169
170void ULingoGameInstance::CreateMySession(FString displayName)
171{
172 // 로딩 서클 표시
173 if (UWorld* World = GetWorld())
174 {
175 if (ULoadingCircleManager* LoadingManager = ULoadingCircleManager::Get(World))
176 LoadingManager->LoadingCircle(true);
177 }
178
179 // 세션을 만들기 위한 옵션 담을 변수
180 FOnlineSessionSettings sessionSettings;
181 // 현재 사용중인 서브시스템 이름 가져오자.
182 FName subsysName = Online::GetSubsystem(GetWorld())->GetSubsystemName();
183 // 만약에 서브시스템이 이름이 NULL 이면 Lan 을 이용하게 설정
184 sessionSettings.bIsLANMatch = subsysName.IsEqual(FName(TEXT("NULL")));
185 UE_LOG(LogTemp, Warning, TEXT("서브시스템 : %s"), *subsysName.ToString());
186
187 // Steam 에선 필수 (bUseLobbiesIfAvailable, bUsesPresence)
188 // Lobby 사용 여부 설정
189 sessionSettings.bUseLobbiesIfAvailable = true;
190 // 친구 상태를 확인할 수 있는 여부
191 sessionSettings.bUsesPresence = true;
192
193 // 세션 검색 허용 여부
194 sessionSettings.bShouldAdvertise = true;
195 // 세션 최대 참여 인원 설정 (임시로 2명)
196 sessionSettings.NumPublicConnections = 2;
197 // 커스텀 정보
198 // displayName 을 Base64 로 변환
199 displayName = StringBase64Encode(displayName);
200 sessionSettings.Set(FName("DP_NAME"), displayName, EOnlineDataAdvertisementType::ViaOnlineServiceAndPing);
201 //sessionSettings.Set(FName("MAP_IDX"), 1, EOnlineDataAdvertisementType::ViaOnlineServiceAndPing);
202
203 // sessionSettings 이용해서 세션 생성
204 FUniqueNetIdPtr netId =
205 GetWorld()->GetFirstLocalPlayerFromController()->GetUniqueNetIdForPlatformUser().GetUniqueNetId();
206 sessionInterface->CreateSession(*netId, FName(displayName), sessionSettings);
207 //sessionInterface->CreateSession(0, FName(displayName), sessionSettings);
208
209}
210
211void ULingoGameInstance::OnCreateSessionComplete(FName sessionName, bool bWasSuccessful)
212{
213 if (bWasSuccessful)
214 {
215 UE_LOG(LogTemp, Warning, TEXT("[%s] 세션 생성 성공"), *sessionName.ToString());
216 // 맵 으로 이동 (로딩 서클은 맵 로딩 완료 후에 숨김)
217 GetWorld()->ServerTravel(TEXT("/Game/StarterBundle/CollectionMaps/Map1?listen"));
218 }
219 else
220 {
221 UE_LOG(LogTemp, Warning, TEXT("[%s] 세션 생성 실패"), *sessionName.ToString());
222
223 // 세션 생성 실패 시 로딩 서클 숨김
224 if (UWorld* World = GetWorld())
225 {
226 if (ULoadingCircleManager* LoadingManager = ULoadingCircleManager::Get(World))
227 LoadingManager->LoadingCircle(false);
228 }
229 }
230}
231
233{
234 UE_LOG(LogTemp, Warning, TEXT("세션 조회 시작"));
235 // sessionSearch 만들자.
236 sessionSearch = MakeShared<FOnlineSessionSearch>();
237 // 현재 사용중인 서브시스템 이름 가져오자.
238 FName subsysName = Online::GetSubsystem(GetWorld())->GetSubsystemName();
239 // 만약에 서브시스템이 이름이 NULL 이면 Lan 을 이용하게 설정
240 sessionSearch->bIsLanQuery = subsysName.IsEqual(FName(TEXT("NULL")));
241 // 어떤 옵션을 기준으로 검색
242 sessionSearch->QuerySettings.Set(SEARCH_LOBBIES, true, EOnlineComparisonOp::Equals);
243 //sessionSearch->QuerySettings.Set(FName("DP_NAME"), FName("Wanted"), EOnlineComparisonOp::Equals);
244 // 검색 갯수
245 sessionSearch->MaxSearchResults = 100;
246 // 위 설정을 가지고 세션 검색
247 sessionInterface->FindSessions(0, sessionSearch.ToSharedRef());
248}
249
251{
252 UE_LOG(LogTemp, Warning, TEXT("세션 조회 끝"));
253 if (bWasSuccessful)
254 {
255 // 검색된 세션 결과들
256 auto results = sessionSearch->SearchResults;
257 for (int32 i = 0; i < results.Num(); i++)
258 {
259 // 방 제목 이름 담을 변수
260 FString displayName;
261 results[i].Session.SessionSettings.Get(FName(TEXT("DP_NAME")), displayName);
262 // displayName 을 UTF8 string 으로 변환
263 displayName = StringBase64Decode(displayName);
264 UE_LOG(LogTemp, Warning, TEXT("세션 - %i, 이름 : %s"), i, *displayName);
265 // onFindComplete 에 들어있는 함수 실행
266 onFindComplete.ExecuteIfBound(i, displayName);
267 }
268 }
269 else
270 {
271 UE_LOG(LogTemp, Warning, TEXT("세션 조회 실패"));
272 }
273
274 onFindComplete.ExecuteIfBound(-1, FString());
275}
276
278{
279 // 로딩 서클 표시
280 if (UWorld* World = GetWorld())
281 {
282 if (ULoadingCircleManager* LoadingManager = ULoadingCircleManager::Get(World))
283 LoadingManager->LoadingCircle(true);
284 }
285
286 // 검색된 세션 결과들
287 auto results = sessionSearch->SearchResults;
288 // 5.5 이후 부터 바꼈다...
289 results[sessionIdx].Session.SessionSettings.bUseLobbiesIfAvailable = true;
290 results[sessionIdx].Session.SessionSettings.bUsesPresence = true;
291
292 // 세션 이름 가져오자.
293 FString displayName;
294 results[sessionIdx].Session.SessionSettings.Get(FName(TEXT("DP_NAME")), displayName);
295
296 // 세션 참여
297 sessionInterface->JoinSession(0, FName(displayName), results[sessionIdx]);
298}
299
300void ULingoGameInstance::OnJoinSessionComplete(FName sessionName, EOnJoinSessionCompleteResult::Type result)
301{
302 // 만약 참여 성공 했다면
303 if (result == EOnJoinSessionCompleteResult::Success)
304 {
305 // 서버가 만들어 놓은 세션 URL 을 얻어오자.k
306 FString url;
307 sessionInterface->GetResolvedConnectString(sessionName, url);
308 UE_LOG(LogTemp, Warning, TEXT("URL : %s"), *url);
309 // 서버가 있는 맵으로 이동 (로딩 서클은 맵 로딩 완료 후에 숨김)
310 APlayerController* pc = GetWorld()->GetFirstPlayerController();
311 pc->ClientTravel(url, TRAVEL_Absolute);
312 }
313 else
314 {
315 UE_LOG(LogTemp, Warning, TEXT("[%s] 세션 참여 실패"), *sessionName.ToString());
316
317 // 세션 참여 실패 시 로딩 서클 숨김
318 if (UWorld* World = GetWorld())
319 {
320 if (ULoadingCircleManager* LoadingManager = ULoadingCircleManager::Get(World))
321 LoadingManager->LoadingCircle(false);
322 }
323 }
324}
325
327{
328 // str 을 std::string 로 변환
329 std::string utf8String = TCHAR_TO_UTF8(*str);
330 // utf8String 을 uint8 의 Array 변환
331 TArray<uint8> arrayData = TArray<uint8>((uint8*)utf8String.c_str(), utf8String.length());
332
333 return FBase64::Encode(arrayData);
334}
335
337{
338 TArray<uint8> arrayData;
339 FBase64::Decode(str, arrayData);
340 std::string utf8String((char*)arrayData.GetData(), arrayData.Num());
341 return UTF8_TO_TCHAR(utf8String.c_str());
342}
343
344void ULingoGameInstance::SetSelectCharacter(FString userName, int32 characterIdx)
345{
346 selectCharacter.Add(userName, characterIdx);
347}
348
350{
351 int32* value = selectCharacter.Find(userName);
352 if (value == nullptr) return -1;
353
354 return *value;
355}
YiSan 전반에서 사용하는 공용 인터페이스를 선언합니다.
#define PRINTLOG(fmt,...)
Definition GameLogging.h:30
ULoadingCircleManager 클래스를 선언합니다.
void CreateMySession(FString displayName)
void JoinOtherSession(int32 sessionIdx)
IOnlineSessionPtr sessionInterface
virtual void Shutdown() override
void OnFindSessionComplete(bool bWasSuccessful)
TMap< FString, int32 > selectCharacter
virtual void Init() override
void OnJoinSessionComplete(FName sessionName, EOnJoinSessionCompleteResult::Type result)
void OnCreateSessionComplete(FName sessionName, bool bWasSuccessful)
FFindComplete onFindComplete
FString StringBase64Encode(FString str)
void SetSelectCharacter(FString userName, int32 characterIdx)
TSharedPtr< FOnlineSessionSearch > sessionSearch
int32 GetSelectCharacter(FString userName)
FString StringBase64Decode(FString str)
전역 로딩 서클의 표시 여부를 관리하는 LocalPlayerSubsystem입니다.