KLingo Project Documentation 1.0.0
Unreal Engine 5.6 C++ Project Documentation
로딩중...
검색중...
일치하는것 없음
UPopupManager.cpp
이 파일의 문서화 페이지로 가기
1// Copyright (c) 2025 Doppleddiggong. All rights reserved. Unauthorized copying, modification, or distribution of this file, via any medium is strictly prohibited. Proprietary and confidential.
2
3#include "UPopupManager.h"
4#include "UBasePopup.h"
5#include "UPopup_MsgBox.h"
6#include "UPopup_InputMsg.h"
7#include "UPopup_ReadQuest.h"
8
9#include "FComponentHelper.h"
10#include "GameLogging.h"
11#include "Popup_AskTutorial.h"
12#include "Popup_Questionnaire.h"
14#include "Popup_Result.h"
15#include "Popup_WriteBoard.h"
16#include "ULingoGameHelper.h"
17#include "UPopup_Interview.h"
19#include "UPopup_SpeakQuest.h"
21#include "UPopup_SpeakResult.h"
22#include "UPopup_Word.h"
23#include "UPopup_Evaluation.h"
24#include "UPopup_LevelSelect.h"
25#include "UPopup_History.h"
26#include "UPopup_HowToPlay.h"
27#include "UPopup_DailyStudy.h"
28#include "UPopup_DailyResult.h"
29#include "UPopup_SpeakJudes.h"
30
31#include "Onepiece/Onepiece.h"
32
33#define POPUP_PATH TEXT("/Game/CustomContents/UI/Widgets/WBP_PopupMsg.WBP_PopupMsg_C")
34#define INPUT_POPUP_PATH TEXT("/Game/CustomContents/UI/Widgets/WBP_InputPopupMsg.WBP_InputPopupMsg_C")
35#define READQUEST_POPUP_PATH TEXT("/Game/CustomContents/UI/Widgets/WBP_PopupReadQuest.WBP_PopupReadQuest_C")
36#define RESULT_POPUP_PATH TEXT("/Game/CustomContents/UI/Widgets/WBP_Result.WBP_Result_C")
37#define INTERVIEW_POPUP_PATH TEXT("/Game/CustomContents/UI/Widgets/WBP_PopupInterview.WBP_PopupInterview_C")
38#define Questionnaire_POPUP_PATH TEXT("/Game/CustomContents/UI/Widgets/Write/WBP_PopupWriteKiosk.WBP_PopupWriteKiosk_C")
39#define WriteBoard_POPUP_PATH TEXT("/Game/CustomContents/UI/Widgets/Write/WBP_WriteBoard.WBP_WriteBoard_C")
40#define QuestionnaireResult_POPUP_PATH TEXT("/Game/CustomContents/UI/Widgets/Write/WBP_PopupWriteResult.WBP_PopupWriteResult_C")
41#define WORD_POPUP_PATH TEXT("/Game/CustomContents/UI/Widgets/WBP_PopupWord.WBP_PopupWord_C")
42#define INTERVIEWHELLO_POPUP_PATH TEXT("/Game/CustomContents/UI/Widgets/WBP_PopupInterviewHello.WBP_PopupInterviewHello_C")
43#define SPEAKQUEST_POPUP_PATH TEXT("/Game/CustomContents/UI/Widgets/WBP_PopupSpeakQuest.WBP_PopupSpeakQuest_C")
44#define SPEAKQUESTJUDES_POPUP_PATH TEXT("/Game/CustomContents/UI/Widgets/WBP_PopupSpeakQuestJudes.WBP_PopupSpeakQuestJudes_C")
45#define SPEAKRESULT_POPUP_PATH TEXT("/Game/CustomContents/UI/Widgets/WBP_SpeakResult.WBP_SpeakResult_C")
46#define EVALUATION_POPUP_PATH TEXT("/Game/CustomContents/UI/Widgets/WBP_PopupEvaluation.WBP_PopupEvaluation_C")
47#define ASKTUTORIAL_POPUP_PATH TEXT("/Game/CustomContents/UI/Widgets/WBP_PopupAskTutorial.WBP_PopupAskTutorial_C")
48#define LEVELSELECT_POPUP_PATH TEXT("/Game/CustomContents/UI/Widgets/WBP_PopupLevelSelect.WBP_PopupLevelSelect_C")
49#define HISTORY_POPUP_PATH TEXT("/Game/CustomContents/UI/Widgets/WBP_PopupHistory.WBP_PopupHistory_C")
50#define SPEAKJUDES_POPUP_PATH TEXT("/Game/CustomContents/UI/Widgets/WBP_PopupSpeakJudes.WBP_PopupSpeakJudes_C")
51#define HOWTOPLAY_POPUP_PATH TEXT("/Game/CustomContents/UI/Widgets/WBP_PopupHowToPlay.WBP_PopupHowToPlay_C")
52#define DAILYSTUDY_POPUP_PATH TEXT("/Game/CustomContents/UI/Widgets/WBP_PopupDailyStudy.WBP_PopupDailyStudy_C")
53#define DAILYRESULT_POPUP_PATH TEXT("/Game/CustomContents/UI/Widgets/WBP_PopupDailyResult.WBP_PopupDailyResult_C")
54
56{
57 // 기본 팝업 클래스 등록
80
81
82}
83
84// ========================================
85// 범용 팝업 관리 함수
86// ========================================
87
89{
90 UUserWidget* PopupWidget = EnsurePopupWidget(Type);
91 if (!PopupWidget)
92 {
93 PRINTLOG(TEXT("[UPopupManager] Failed to create popup: %s"), *ENUM_TO_NAME(EPopupType, Type));
94 return nullptr;
95 }
96
97 // 첫 팝업이 열릴 때 마우스 커서 표시
98 bool bIsFirstPopup = (PopupStack.Num() == 0);
99
100 // 이미 뷰포트에 있으면 스택 맨 위로 이동
101 if (PopupWidget->IsInViewport())
102 {
104 }
105 else
106 {
107 // UBasePopup으로 캐스팅하여 애니메이션 재생
108 if (UBasePopup* BasePopup = Cast<UBasePopup>(PopupWidget))
109 {
110 BasePopup->OpenAnimation();
111 }
112 else
113 {
114 // UBasePopup이 아닌 경우 기본 방식으로 추가
115 PopupWidget->AddToViewport(GameLayer::Popup);
116 }
117 }
118
119 // 스택에 추가
120 PushPopupToStack(Type);
121
122 // 첫 팝업이 열렸다면 마우스 커서 표시
123 if (bIsFirstPopup)
124 {
126 }
127
128 return PopupWidget;
129}
130
131void UPopupManager::HidePopup(EPopupType Type, bool bDestroyWidget)
132{
133 UUserWidget** PopupWidgetPtr = PopupWidgetMap.Find(Type);
134 if (!PopupWidgetPtr || !(*PopupWidgetPtr))
135 return;
136
137 UUserWidget* PopupWidget = *PopupWidgetPtr;
138
139 // 뷰포트에서 제거
140 if (PopupWidget->IsInViewport())
141 {
142 PopupWidget->RemoveFromParent();
143 }
144
145 // 스택에서 제거
147
148 // 모든 팝업이 닫혔다면 마우스 커서 숨기기
149 if (PopupStack.Num() == 0)
150 {
151 FString MapName = GetWorld()->GetMapName();
152 MapName.RemoveFromStart(GetWorld()->StreamingLevelsPrefix);
153 if (MapName.Contains(TEXT("Map1")) ||
154 MapName.Contains(TEXT("Person")) )
155 {
157 }
158 }
159
160 // 위젯 파괴
161 if (bDestroyWidget)
162 {
163 PopupWidgetMap.Remove(Type);
164 }
165}
166
167void UPopupManager::HideCurrentPopup(bool bDestroyWidget)
168{
169 if (PopupStack.Num() == 0)
170 return;
171
172 EPopupType CurrentType = PopupStack.Last();
173 HidePopup(CurrentType, bDestroyWidget);
174}
175
176void UPopupManager::HideAllPopups(bool bDestroyWidgets)
177{
178 // 스택을 역순으로 순회하며 모두 닫기
179 while (PopupStack.Num() > 0)
180 {
181 HideCurrentPopup(bDestroyWidgets);
182 }
183}
184
185// ========================================
186// 팝업 쿼리 함수
187// ========================================
188
190{
191 if (PopupStack.Num() == 0)
192 return false;
193
194 OutType = PopupStack.Last();
195 return true;
196}
197
199{
200 if (PopupStack.Num() == 0)
201 return nullptr;
202
203 EPopupType CurrentType = PopupStack.Last();
204 return GetPopupWidget(CurrentType);
205}
206
208{
209 // 1. 해당 타입의 팝업이 맵에 있는지 확인
210 if (!PopupWidgetMap.Contains(Type))
211 return nullptr;
212
213 // 2. 맵에서 위젯 가져오기
214 UUserWidget* Widget = PopupWidgetMap[Type];
215
216 // 3. 위젯이 유효한지 확인 후 반환
217 return Widget;
218}
219
221{
222 return PopupStack.Contains(Type);
223}
224
226{
227 return PopupStack.Num();
228}
229
231{
232 // 팝업이 없으면 조작 허용
233 if (PopupStack.Num() == 0)
234 return false;
235
236 // 현재 팝업 위젯 가져오기
237 UUserWidget* CurrentWidget = GetCurrentPopupWidget();
238 if (!CurrentWidget)
239 return false;
240
241 // UBasePopup으로 캐스팅하여 bAllowPlayerControl 확인
242 if (UBasePopup* BasePopup = Cast<UBasePopup>(CurrentWidget))
243 {
244 // bAllowPlayerControl이 true면 조작 허용 (차단하지 않음)
245 return !BasePopup->bAllowPlayerControl;
246 }
247
248 // UBasePopup이 아닌 팝업은 기본적으로 조작 차단
249 return true;
250}
251
252// ========================================
253// 메시지 박스 전용 함수
254// ========================================
255
257 const FString& InTitle,
258 const FString& InDescription,
259 EMsgBoxType InType,
260 const FOnMsgBoxOkDelegate& InOkDelegate)
261{
262 UUserWidget* Widget = ShowPopup(EPopupType::MsgBox);
263 if (!Widget)
264 return;
265
266 if (auto MsgBox = Cast<UPopup_MsgBox>(Widget))
267 {
268 MsgBox->InitPopup(InTitle, InDescription, InType, InOkDelegate);
269 }
270}
271
273 const FString& InTitle,
274 const FString& InDescription,
275 EMsgBoxType InType,
276 const FOnMsgBoxOkDelegate& InOkDelegate,
277 const FOnMsgBoxCancelDelegate& InCancelDelegate)
278{
279 UUserWidget* Widget = ShowPopup(EPopupType::MsgBox);
280 if (!Widget)
281 return;
282
283 if (auto Popup = Cast<UPopup_MsgBox>(Widget))
284 {
285 Popup->InitPopup(InTitle, InDescription, InType, InOkDelegate, InCancelDelegate);
286 }
287}
288
290 const FString& InTitle,
291 const FString& InDescription,
292 EMsgBoxType InType)
293{
294 // 델리게이트 없이 팝업만 표시 (블루프린트용)
295 UUserWidget* Widget = ShowPopup(EPopupType::MsgBox);
296 if (!Widget)
297 return;
298
299 if (auto MsgBox = Cast<UPopup_MsgBox>(Widget))
300 {
301 // 빈 델리게이트로 초기화
302 FOnMsgBoxOkDelegate EmptyOkDelegate;
303 FOnMsgBoxCancelDelegate EmptyCancelDelegate;
304 MsgBox->InitPopup(InTitle, InDescription, InType, EmptyOkDelegate, EmptyCancelDelegate);
305 }
306}
307
308// ========================================
309// 내부 헬퍼 함수
310// ========================================
311
313{
314 UWorld* World = GetWorld();
315 if (!World || !World->IsGameWorld())
316 return nullptr;
317
318 // 이미 생성된 위젯이 있는지 확인
319 UUserWidget** ExistingWidgetPtr = PopupWidgetMap.Find(Type);
320 if (ExistingWidgetPtr && IsValid(*ExistingWidgetPtr))
321 {
322 UUserWidget* ExistingWidget = *ExistingWidgetPtr;
323 // 같은 월드인지 확인
324 if (ExistingWidget->GetWorld() == World)
325 {
326 return ExistingWidget;
327 }
328 else
329 {
330 // 다른 월드면 제거
331 if (ExistingWidget->IsInViewport())
332 ExistingWidget->RemoveFromParent();
333 PopupWidgetMap.Remove(Type);
334 }
335 }
336
337 // 팝업 클래스 가져오기
338 TSubclassOf<UUserWidget>* PopupClassPtr = PopupClassMap.Find(Type);
339 if (!PopupClassPtr || !(*PopupClassPtr))
340 {
341 PRINTLOG(TEXT("[UPopupManager] No popup class registered for type: %s"),
342 *ENUM_TO_NAME(EPopupType, Type));
343 return nullptr;
344 }
345
346 // 플레이어 컨트롤러 가져오기
347 ULocalPlayer* LocalPlayer = GetLocalPlayer();
348 if (!LocalPlayer)
349 return nullptr;
350
351 APlayerController* PC = LocalPlayer->GetPlayerController(World);
352 if (!PC)
353 return nullptr;
354
355 // 위젯 생성
356 // UUserWidget* NewWidget = CreateWidget<UUserWidget>(PC, *PopupClassPtr);
357
358 // 위젯 생성 - GetTransientPackage()를 outer로 사용하여 GameInstance outer 문제 방지
359 // CreateWidget은 내부적으로 GameInstance를 outer로 사용하므로 직접 NewObject 사용
360 UUserWidget* NewWidget = NewObject<UUserWidget>(GetTransientPackage(), *PopupClassPtr, NAME_None, RF_Transient);
361 if (NewWidget)
362 {
363 // 위젯 초기화
364 NewWidget->Initialize();
365
366 // PlayerController를 Owning Player로 설정
367 NewWidget->SetOwningPlayer(PC);
368 }
369 else
370 {
371 PRINTLOG(TEXT("[UPopupManager] Failed to create widget for type: %s"), *ENUM_TO_NAME(EPopupType, Type));
372 return nullptr;
373 }
374
375 // 맵에 추가
376 PopupWidgetMap.Add(Type, NewWidget);
377
378 return NewWidget;
379}
380
382{
383 // 이미 스택에 있으면 제거 후 재추가 (최상단으로)
385 PopupStack.Add(Type);
386}
387
389{
390 PopupStack.Remove(Type);
391}
EMsgBoxType
Definition EPopupType.h:49
EPopupType
팝업 타입 정의
Definition EPopupType.h:14
FComponentHelper 구조체를 선언합니다.
YiSan 전반에서 사용하는 공용 인터페이스를 선언합니다.
#define PRINTLOG(fmt,...)
Definition GameLogging.h:30
#define ENUM_TO_NAME(EnumType, Value)
Definition Macro.h:83
#define HOWTOPLAY_POPUP_PATH
#define HISTORY_POPUP_PATH
#define ASKTUTORIAL_POPUP_PATH
#define INPUT_POPUP_PATH
#define QuestionnaireResult_POPUP_PATH
#define LEVELSELECT_POPUP_PATH
#define SPEAKJUDES_POPUP_PATH
#define Questionnaire_POPUP_PATH
#define RESULT_POPUP_PATH
#define DAILYRESULT_POPUP_PATH
#define DAILYSTUDY_POPUP_PATH
#define EVALUATION_POPUP_PATH
#define INTERVIEWHELLO_POPUP_PATH
#define SPEAKQUESTJUDES_POPUP_PATH
#define WORD_POPUP_PATH
#define POPUP_PATH
#define WriteBoard_POPUP_PATH
#define READQUEST_POPUP_PATH
#define SPEAKQUEST_POPUP_PATH
#define INTERVIEW_POPUP_PATH
#define SPEAKRESULT_POPUP_PATH
Chat History를 표시하는 팝업 위젯입니다.
모든 팝업의 기본 클래스
Definition UBasePopup.h:19
static void HideMouseCursor(const UObject *WorldContextObject)
마우스 커서를 숨기고 게임 전용 입력 모드로 설정합니다.
static void ShowMouseCursor(const UObject *WorldContextObject)
마우스 커서를 표시하고 게임+UI 입력 모드로 설정합니다.
void ShowMsgBoxSimple(const FString &InTitle, const FString &InDescription, EMsgBoxType InType)
메시지 박스 표시 (블루프린트용 - 델리게이트 없음)
UUserWidget * GetCurrentPopupWidget() const
현재 활성화된 팝업 위젯 가져오기 (스택 최상단)
void PushPopupToStack(EPopupType Type)
팝업을 스택에 추가
UUserWidget * GetPopupWidget(EPopupType Type) const
특정 타입의 팝업 위젯 가져오기
bool IsPopupInStack(EPopupType Type) const
특정 타입의 팝업이 현재 스택에 있는지 확인
UUserWidget * EnsurePopupWidget(EPopupType Type)
팝업 위젯 생성 또는 가져오기
void HideAllPopups(bool bDestroyWidgets=false)
모든 팝업 숨기기
void RemovePopupFromStack(EPopupType Type)
팝업을 스택에서 제거
UUserWidget * ShowPopup(EPopupType Type)
팝업 표시
int32 GetPopupStackCount() const
활성화된 팝업 개수 가져오기
TArray< EPopupType > PopupStack
팝업 스택 (표시 순서, 마지막이 최상단)
void ShowMsgBox(const FString &InTitle, const FString &InDescription, EMsgBoxType InType, const FOnMsgBoxOkDelegate &InOkDelegate)
메시지 박스 표시 (OK 버튼만)
TMap< EPopupType, UUserWidget * > PopupWidgetMap
팝업 타입별 위젯 인스턴스 맵
bool ShouldBlockPlayerControl() const
현재 팝업이 플레이어 조작을 차단해야 하는지 확인
void HidePopup(EPopupType Type, bool bDestroyWidget=false)
특정 팝업 숨기기
TMap< EPopupType, TSubclassOf< UUserWidget > > PopupClassMap
팝업 타입별 위젯 클래스 맵 (에디터에서 설정)
void HideCurrentPopup(bool bDestroyWidget=false)
현재 활성화된 팝업 숨기기 (스택 최상단)
bool GetCurrentPopupType(EPopupType &OutType) const
현재 활성화된 팝업 타입 가져오기 (스택 최상단)
static const int32 Popup
Definition Onepiece.h:9
static T * LoadAsset(const TCHAR *Path)