16#include "EnhancedInputSubsystems.h"
17#include "EnhancedInputComponent.h"
19#include "InputMappingContext.h"
20#include "InputAction.h"
31#include "EngineUtils.h"
49#define IMC_DEFAULT_PATH TEXT("/Game/CustomContents/Input/IMC_Game_Player.IMC_Game_Player")
50#define IA_MOVE_PATH TEXT("/Game/CustomContents/Input/IA_Game_Movement.IA_Game_Movement")
51#define IA_LOOK_PATH TEXT("/Game/CustomContents/Input/IA_Game_LookAround.IA_Game_LookAround")
52#define IA_JUMP_PATH TEXT("/Game/CustomContents/Input/IA_Game_Jump.IA_Game_Jump")
53#define IA_RECORD_PATH TEXT("/Game/CustomContents/Input/IA_Game_Record.IA_Game_Record")
54#define IA_GRAB_PATH TEXT("/Game/CustomContents/Input/IA_Game_Grab.IA_Game_Grab")
55#define IA_INTERACT_PATH TEXT("/Game/CustomContents/Input/IA_Game_Interact.IA_Game_Interact")
56#define IA_RUN_PATH TEXT("/Game/CustomContents/Input/IA_Game_Run.IA_Game_Run")
57#define IA_INFO_PATH TEXT("/Game/CustomContents/Input/IA_Game_Info.IA_Game_Info")
58#define IA_HOOK_PATH TEXT("/Game/CustomContents/Input/IA_Game_Hook.IA_Game_Hook")
59#define IA_CHAT_PATH TEXT("/Game/CustomContents/Input/IA_EnterChat.IA_EnterChat")
60#define IA_HISTORY_PATH TEXT("/Game/CustomContents/Input/IA_Game_History.IA_Game_History")
61#define IA_HOWTOCTRL_PATH TEXT("/Game/CustomContents/Input/IA_Game_HowToCtrl.IA_Game_HowToCtrl")
62#define IA_HOWTOPLAY_PATH TEXT("/Game/CustomContents/Input/IA_Game_HowToPlay.IA_Game_HowToPlay")
83 TutorialComponent = CreateDefaultSubobject<UTutorialComponent>(TEXT(
"TutorialComponent"));
84 ChatHistorySystem = CreateDefaultSubobject<UChatHistorySystem>(TEXT(
"ChatHistorySystem"));
91 if (
auto LP = GetLocalPlayer())
93 if (
auto SubSystem = LP->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>())
97 SubSystem->ClearAllMappings();
102 if (IsLocalController())
104 UserInfo = ULingoGameInstanceSubsystem::Get(GetWorld())->GetUserInfo();
109 LoadingManager->LoadingCircle(
false);
121 Super::SetupInputComponent();
123 if (UEnhancedInputComponent* EIC = Cast<UEnhancedInputComponent>(InputComponent))
153 UBroadcastManager::Get(GetWorld())->SendUpdateQuestRole(QuestRole);
158 APawn* P = GetPawn();
175 PRINTLOG(TEXT(
"[Tutorial] User %d already completed tutorial"), UserId);
187 PRINTLOG(TEXT(
"[Tutorial] Starting tutorial manually"));
201 C->Cmd_Move(Value.Get<FVector2D>());
207 C->Cmd_Look(Value.Get<FVector2D>());
239 C->Cmd_RecordStart();
273 if (MyPlayer->
InteractionSystem->CurrentTarget->InteractionType == EInteractionType::Button)
276 if (UTutorialComponent* Tutorial = FindComponentByClass<UTutorialComponent>())
278 Tutorial->OnObjectInteracted(TargetActor);
286void APlayerControl::Server_OnGrab_Implementation()
295void APlayerControl::Server_OnGrabRelease_Implementation()
305void APlayerControl::Server_OnInteract_Implementation()
322 FInputModeUIOnly uiInputMode;
323 SetInputMode(uiInputMode);
331 if (
auto Popup = UPopupManager::ShowPopupAs<UPopup_History>(GetWorld(), EPopupType::History))
347 if (
auto PS = GetPlayerState<ALingoPlayerState>())
350 if (PS->bReadQuestIng && !PS->bReadQuestCompleted)
354 else if (PS->bListenQuestIng && !PS->bListenQuestCompleted)
358 else if (PS->bSpeakQuestIng && !PS->bSpeakQuestCompleted)
362 else if (PS->bWriteQuestIng && !PS->bWriteQuestCompleted)
371 if (
auto Popup = UPopupManager::ShowPopupAs<UPopup_HowToPlay>(GetWorld(), EPopupType::HowToPlay))
373 TArray<EHowToPlayPageType> PageTypes;
377 PageTypes.Add(EHowToPlayPageType::Control_P1);
378 PageTypes.Add(EHowToPlayPageType::Control_P2);
379 PageTypes.Add(EHowToPlayPageType::Control_P3);
380 PageTypes.Add(EHowToPlayPageType::Control_P4);
381 PageTypes.Add(EHowToPlayPageType::Control_P5);
382 PageTypes.Add(EHowToPlayPageType::Control_P6);
386 PageTypes.Add(EHowToPlayPageType::Read_P1);
387 PageTypes.Add(EHowToPlayPageType::Read_P2);
388 PageTypes.Add(EHowToPlayPageType::Read_P3);
389 PageTypes.Add(EHowToPlayPageType::Read_P4);
393 PageTypes.Add(EHowToPlayPageType::Listen_P1);
394 PageTypes.Add(EHowToPlayPageType::Listen_P2);
395 PageTypes.Add(EHowToPlayPageType::Listen_P3);
396 PageTypes.Add(EHowToPlayPageType::Listen_P4);
400 PageTypes.Add(EHowToPlayPageType::Speak_P1);
401 PageTypes.Add(EHowToPlayPageType::Speak_P2);
402 PageTypes.Add(EHowToPlayPageType::Speak_P3);
406 PageTypes.Add(EHowToPlayPageType::Write_P1);
407 PageTypes.Add(EHowToPlayPageType::Write_P2);
408 PageTypes.Add(EHowToPlayPageType::Write_P3);
411 Popup->InitPopup(PageTypes);
416void APlayerControl::Server_OnHook_Implementation()
425void APlayerControl::Server_SetUserInfo_Implementation(
const FResponseUserMe& InUserInfo)
432 if (
auto World = GetWorld())
434 for (TActorIterator<ADropper> It(World); It; ++It)
450 Dropper->
SetSpawnClass( LoadClass<AActor>(
nullptr, TEXT(
"/Game/CustomContents/Blueprints/Interactables/BP_Luggage.BP_Luggage_C")));
458void APlayerControl::Server_RequestDrop_Implementation()
463void APlayerControl::Client_ToastMessage_Implementation(
const FString& Message)
465 UDialogManager::Get(GetWorld())->ShowToast(Message);
468void APlayerControl::Client_UpdateSpeakQuest_Implementation(int32 StepIndex)
477 if (
auto Popup = UPopupManager::ShowPopupAs<UPopup_SpeakQuest>(GetWorld(), EPopupType::SpeakQuest))
480 FOnMsgBoxOkDelegate OnOkDelegate;
482 Popup->InitPopup( FOnMsgBoxOkDelegate().CreateLambda([
this, StepIndex]()
484 if (
APlayerActor* PlayerActor = Cast<APlayerActor>(GetPawn()))
486 PlayerActor->PlaySpeakInfo(StepIndex);
494 if (
APlayerActor* PlayerActor = Cast<APlayerActor>(GetPawn()))
495 PlayerActor->PlaySpeakInfo(StepIndex);
501void APlayerControl::Client_EndSpeakQuest_Implementation()
511void APlayerControl::Client_InteractKiosk_Implementation()
514 UInteractableComponent* component =
nullptr;
519 if (!component->bCanInteract)
523 component->OnInteractionTriggered.Broadcast(GetPawn());
527 PRINTLOG( TEXT(
"InteractableComponent::TriggerInteraction server server"));
531void APlayerControl::Client_RequestSpeakScenario_Implementation(
AWheatly*
Wheatly)
535 PRINTLOG(TEXT(
"[APlayerControl] Client_RequestSpeakScenario: Wheatly is null"));
540 APlayerActor* PlayerActor = Cast<APlayerActor>(GetPawn());
543 PRINTLOG(TEXT(
"[APlayerControl] Client_RequestSpeakScenario: PlayerActor is null"));
548 if (
auto KLingoNetwork = UKLingoNetworkSystem::Get(GetWorld()))
552 KLingoNetwork->RequestSpeakScenario( FResponseSpeakScenarioDelegate::CreateLambda(
559 PRINTLOG(TEXT(
"[APlayerControl] Client successfully received scenario data, syncing to server"));
564 PRINTLOG(TEXT(
"[APlayerControl] Client failed to receive scenario data"));
572 PRINTLOG(TEXT(
"[APlayerControl] Client_RequestSpeakScenario: Failed to get KLingoNetworkSystem"));
580 PRINTLOG(TEXT(
"[APlayerControl] Server_SyncSpeakScenarioData: Wheatly is null"));
585 APlayerActor* PlayerActor = Cast<APlayerActor>(GetPawn());
588 PRINTLOG(TEXT(
"[APlayerControl] Server_SyncSpeakScenarioData: PlayerActor is null"));
599 Wheatly->SyncSpeakScenarioData(PlayerActor, Data);
601 PRINTLOG(TEXT(
"[APlayerControl] Server successfully synced scenario data to Wheatly"));
604void APlayerControl::Server_SendDoorMessage_Implementation(int32 InDoorIndex,
bool bOpen)
610 if (APawn* MyPawn = GetPawn())
613 PRINTLOG(TEXT(
"[APlayerControl] Server sending DoorMessage: Index=%d, Open=%d"), InDoorIndex, bOpen);
619 if (
APlayerActor* PlayerActor = Cast<APlayerActor>(GetPawn()))
623 MainWidget->UpdateSpeakWidget(StepIndex);
630 if (
auto GS = Cast<ALingoGameState>(GetWorld()->GetGameState()) )
632 if (
auto KLingoNetwork = UKLingoNetworkSystem::Get(GetWorld()))
635 SpeakRequest.
room_id = GS->GetRoomId();
640 KLingoNetwork->RequestSpeakResult(SpeakRequest,
650 if (
auto PS = GetPlayerState<ALingoPlayerState>() )
655 if (
auto Popup = UPopupManager::ShowPopupAs<UPopup_SpeakResult>(GetWorld(), EPopupType::SpeakResult) )
656 Popup->InitPopup(ResponseData);
661 PRINTLOG(TEXT(
"[Result] Quest result Failed"));
677 if (
auto BM = UBroadcastManager::Get(GetWorld()))
679 TArray<FResultStatData> TestItems;
682 int32 ItemCount = FMath::RandRange(1, 3);
683 for (int32 i = 0; i < ItemCount; ++i)
688 int32 RandomType = FMath::RandRange(0, 3);
694 Item.
TitleText = FText::FromString(TEXT(
"등급"));
699 Item.
ScoreValue = FMath::RandRange(100, 9999);
700 Item.
TitleText = FText::FromString(TEXT(
"점수"));
706 Item.
TitleText = FText::FromString(TEXT(
"비율"));
711 Item.
SymbolValue = FString::SanitizeFloat( FMath::FRandRange(0.0f, 1.0f) );
712 Item.
TitleText = FText::FromString(TEXT(
"심볼"));
723 BM->SendAddItemToBoxList(TestItems);
727void APlayerControl::ServerRPC_SendChat_Implementation(
const FText& inMessage)
729 if (
auto* GS = GetWorld()->GetGameState<ALingoGameState>())
732 int32 PlayerIndex = -1;
735 PlayerIndex = GS->PlayerArray.IndexOfByKey(PS);
739 GS->MulticastRPC_SendChat(
UserInfo, inMessage, PlayerIndex);
743void APlayerControl::ServerRPC_SendAIQuestion_Implementation(
const FString& Question)
752 FResponseChatAnswersDelegate Delegate;
756 NetworkSystem->RequestChatQuestion(TEXT(
""), Question, Delegate);
758 PRINTLOG(TEXT(
"[AI Chat] Question sent to AI: %s"), *Question);
764 if (!bWasSuccessful || ResponseData.
answer.IsEmpty())
766 PRINTLOG(TEXT(
"[AI Chat] Failed to receive AI response"));
771 if (
auto* GS = GetWorld()->GetGameState<ALingoGameState>())
773 FText AIAnswer = FText::FromString(ResponseData.
answer);
783 if (
auto playerActor = Cast<APlayerActor>(GetPawn()))
785 playerActor->GetMiniOwlBot()->UpdateText(ResponseData.
answer);
818 if (EventInstigator !=
nullptr && EventInstigator != GetPawn())
826 if (EventInstigator !=
nullptr && EventInstigator != GetPawn())
843 if (EventInstigator == GetPawn())
851 if (EventInstigator == GetPawn())
859void APlayerControl::Multicast_OpenHowToPlay_Implementation(
EQuestType InType)
862 if (IsLocalController())
869void APlayerControl::Client_OpenHowToPlay_Implementation(
EQuestType InType)
878 APlayerActor* PlayerActor = Cast<APlayerActor>(GetPawn());
900 bool bShouldShow =
false;
905 Title = TEXT(
"Mission Goal");
906 Description = TEXT(
"Place the object on the switch to open the gate");
911 Title = TEXT(
"Move Food Court");
912 Description = TEXT(
"Move Food Court With Friend");
918 Title = TEXT(
"Move Next Goal");
919 Description = TEXT(
"Place the object on the switch to open the gate");
924 Title = TEXT(
"Move Jugdes");
925 Description = TEXT(
"Move Judes And Talk");
931 Title = TEXT(
"Press V Key And Talk");
932 Description = TEXT(
"Answer Judes Question");
944 Title = TEXT(
"Move Paper");
945 Description = TEXT(
"Find Wirte Kiosk And Interaction");
950 Title = TEXT(
"Move End Point");
951 Description = TEXT(
"Get Evalution");
959 QuestWidget->SetVisibility(ESlateVisibility::Visible);
963 QuestWidget->SetVisibility(ESlateVisibility::Collapsed);
970 APlayerActor* PlayerActor = Cast<APlayerActor>(GetPawn());
981 if (!QuestOrderWidget)
991 QuestOrderWidget->SetVisibility(ESlateVisibility::Visible);
네트워크 복제를 위한 전역 브로드캐스트 Actor
Declares the player-controlled character actor.
#define IA_HOWTOCTRL_PATH
#define IA_HOWTOPLAY_PATH
APlayerControl 선언에 대한 Doxygen 주석을 제공합니다.
EQuestRole
Read 퀘스트에서 플레이어의 역할을 정의합니다.
FComponentHelper 구조체를 선언합니다.
YiSan 전반에서 사용하는 공용 인터페이스를 선언합니다.
#define PRINTLOG(fmt,...)
UControllable 클래스를 선언합니다.
Chat 대화 기록을 GConfig를 이용하여 관리하는 컴포넌트입니다.
UDialogManager 클래스를 선언합니다.
KLingo API 요청을 담당하는 서브시스템을 선언합니다.
ULoadingCircleManager 클래스를 선언합니다.
void SetSpawnData(const FLuggageData &InData)
[Luggage용] 스폰 전에 Dropper가 생성될 액터에게 넘겨줄 데이터 등록
void SetSpawnClass(TSubclassOf< AActor > InClass)
스폰 전에 Dropper가 어떤 클래스를 스폰할지 등록
FORCEINLINE bool IsBusy() const
bool RequestSpawn()
스폰 요청 (서버에서만 동작)
bool bSpeakQuestIng
SpeakQuest 진행 여부 플래그
FResponseSpeakResult SpeakResult
void SetSpeakQuestCompleted()
SpeakQuest 완료 처리 (서버에서만 호출)
void SetListenQuestCompleted()
ListenQuest 완료 처리 (서버에서만 호출)
bool bWriteQuestCompleted
WriteQuest 완료 여부 플래그
bool bSpeakQuestCompleted
SpeakQuest 완료 여부 플래그
void SetSpeakQuestIng(bool bInProgress)
SpeakQuest 진행 상태 설정 (서버에서만 호출)
bool bWriteQuestIng
WriteQuest 진행 여부 플래그
void SetReadQuestCompleted()
ReadQuest 완료 처리 (서버에서만 호출)
bool bReadQuestIng
ReadQuest 진행 여부 플래그
void SetWriteQuestCompleted()
WriteQuest 완료 처리 (서버에서만 호출)
bool bListenQuestIng
ListenQuest 진행 여부 플래그
bool bListenQuestCompleted
ListenQuest 완료 여부 플래그
bool bReadQuestCompleted
ReadQuest 완료 여부 플래그
static ANetworkBroadcastActor * Get(const UObject *WorldContextObject)
싱글톤 인스턴스 가져오기
void SendDoorMessage(int InDoorIndex, bool bOpen, AActor *EventInstigator)
문 상태 변경 메시지를 네트워크로 전송
Main character driven directly by the player.
TObjectPtr< class UHookSystem > HookSystem
TObjectPtr< class UInteractionSystem > InteractionSystem
class UMainWidget * GetMainWidget() const
메인 위젯을 가져옵니다.
void UpdateSpeakWidget(int32 StepIndex)
class UTutorialComponent * TutorialComponent
void OnResponseSpeakResult(FResponseSpeakResult &ResponseData, bool bWasSuccessful)
void OnRecordReleased(const FInputActionValue &Value)
void OnJump(const FInputActionValue &Value)
void UpdateQuestOrderWidget(const FString &inQuestOrder)
void TEST_AddItemToBoxList()
void RequestSpeakResult()
TObjectPtr< class UChatHistorySystem > ChatHistorySystem
Chat History 관리 컴포넌트
void UpdateQuestRole(EQuestRole QuestRole)
void OnInteract(const FInputActionValue &Value)
virtual void BeginPlay() override
void StartTutorialManually()
void Client_ToastMessage(const FString &Message)
void OnGrabRelease(const FInputActionValue &Value)
FResponseUserMe UserInfo
사용자 정보 (레벨 전환에서도 유지됨)
void OnTutorialCompleted()
void OnMove(const FInputActionValue &Value)
void OnLook(const FInputActionValue &Value)
TObjectPtr< class UInputMappingContext > IMC_Default
void OnChat(const FInputActionValue &Value)
void OnChatAnswerReceived(FResponseChatAnswers &ResponseData, bool bWasSuccessful)
AI 응답을 받았을 때 Bot 정보로 채팅에 표시합니다.
void OnRun(const FInputActionValue &Value)
void RequestDrop(APlayerControl *Requester)
void OnInfo(const FInputActionValue &Value)
void Server_RequestDrop()
void OpenHowToPlay(EQuestType QuestType)
void UpdateQuestInfoWidget()
퀘스트 상태에 따라 QuestInfoWidget 업데이트
void OnGrab(const FInputActionValue &Value)
void OnHistory(const FInputActionValue &Value)
void TEST_DropperDropProcess()
virtual void SetupInputComponent() override
void OnHook(const FInputActionValue &Value)
void OnHowToCtrl(const FInputActionValue &Value)
void OnRecordPressed(const FInputActionValue &Value)
bool ShouldSkipTutorial() const
void Client_OpenHowToPlay(EQuestType InType)
void Server_SetUserInfo(const FResponseUserMe &InUserInfo)
void OnHowToPlay(const FInputActionValue &Value)
void Server_OnGrabRelease()
class IControllable * GetControllable() const
void Multicast_OpenHowToPlay(EQuestType InType)
void Server_SyncSpeakScenarioData(class AWheatly *Wheatly, const struct FResponseSpeakScenario &Data)
Client에서 받은 시나리오 데이터를 Wheatly에 전달 (Server RPC)
void OnStopMove(const FInputActionValue &Value)
void OnDoorMessage(int32 InDoorIndex, bool bInOpen, AActor *EventInstigator)
DoorMessage 이벤트 핸들러
static bool GetUserBool(int32 UserId, const FString &Key, bool bDefaultValue=false)
유저별 불린 설정 읽기
static void SetUserBool(int32 UserId, const FString &Key, bool bValue, bool bAutoSave=true)
유저별 불린 설정 저장
KLingo 서버와의 HTTP 요청을 중재하는 게임 인스턴스 서브시스템입니다.
static int32 GetUserId(const UObject *WorldContextObject)
static int32 GetStageTypeIndex(const EQuestType QuestType)
전역 로딩 서클의 표시 여부를 관리하는 LocalPlayerSubsystem입니다.
class UQuestOrderWidget * GetQuestOrderWidget() const
class UQuestInfoWidget * GetQuestInfoWidget() const
static const int32 Step3_End
static const int32 Step1_Tutorial
static const int32 Step2_Tutorial
static const int32 Step1_End
static const int32 Step4_End
static const int32 Step2_End
static const int32 Step3_Tutorial
static T * LoadAsset(const TCHAR *Path)
FWordInfo word1
시나리오 단어 정보
Result Stat 위젯 통합 데이터 구조 위젯 타입, 색상 스타일, 각 타입별 데이터를 통합 관리
float RatePercent
Rate 타입 전용: 퍼센트 값 (0.0 ~ 1.0)
EColorStyleType ColorType
색상 스타일
EResultItemWidgetType WidgetType
위젯 타입
EResourceTextureType GradeTextureType
Grade 타입 전용: 텍스처 타입
float ScoreValue
Score 타입 전용: 점수 값
static FWordInfo GetRandomAnimal()
랜덤 동물 선택 - CSV 기반 하드코딩
static FWordInfo GetRandomColor()
랜덤 색상 선택 - CSV 기반 하드코딩