#include "PlayerControllerBase.h" #include "Common.h" #include "Tangible.h" #include "TangibleManager.h" #include "Kismet/GameplayStatics.h" #include "Engine/GameInstance.h" #include "Engine/GameViewportClient.h" #include "Framework/Application/SlateApplication.h" #include "Widgets/SViewport.h" #include "Slate/SObjectWidget.h" FString AlxPlayerControllerBase::GetUserWidgetName(SWidget *W) { while (W) { if (W->GetType() == FName("SObjectWidget")) { UUserWidget *UW = static_cast(W)->GetWidgetObject(); if (UW) return UW->GetClass()->GetName(); } W = W->GetParentWidget().Get(); } return TEXT("Unknown Widget"); } AlxPlayerControllerBase *AlxPlayerControllerBase::FromContext(const UObject *Context) { APlayerController *PC = Context->GetWorld()->GetFirstPlayerController(); AlxPlayerControllerBase *Result = Cast(PC); if (Result == nullptr) { UE_LOG(LogLuprexIntegration, Fatal, TEXT("Not currently using a Luprex Player Controller.")); } return Result; } const FHitResult &AlxPlayerControllerBase::GetLookAt(const UObject *Context) { return FromContext(Context)->CurrentLookAt; } const AActor *AlxPlayerControllerBase::GetLookAtActor(const UObject *Context) { return FromContext(Context)->CurrentLookAt.GetActor(); } void AlxPlayerControllerBase::SetLookAt(const UObject *Context, const FHitResult &HitResult) { AlxPlayerControllerBase *PC = FromContext(Context); if (PC->CurrentLookAt.HitObjectHandle != HitResult.HitObjectHandle) { PC->MustCallLookAtChanged = true; } PC->CurrentLookAt = HitResult; } void AlxPlayerControllerBase::SetLookAtChanged(const UObject *Context) { AlxPlayerControllerBase *PC = FromContext(Context); PC->MustCallLookAtChanged = true; } FVector2D AlxPlayerControllerBase::GetLookAtPixel(const UObject *Context) { AlxPlayerControllerBase *PC = FromContext(Context); FVector2D ScreenPosition; if (!UGameplayStatics::ProjectWorldToScreen(PC, PC->CurrentLookAt.Location, ScreenPosition, false)) { return FVector2D(); } return ScreenPosition; } void AlxPlayerControllerBase::BeginPlay() { Super::BeginPlay(); CharacterModeInput = NewObject(this); CharacterModeInput->bBlockInput = false; PushInputComponent(CharacterModeInput); } void AlxPlayerControllerBase::UpdateEventDispatch() { EventRequests.GarbageCollect(); // If we're in GameOnly mode, check that focus is still on the viewport. if (CurrentInputMode == InputMode::GameOnly) { UGameViewportClient *GVC = GetWorld() ? GetWorld()->GetGameViewport() : nullptr; if (GVC) { TSharedPtr ViewportWidget = GVC->GetGameViewportWidget(); if (ViewportWidget.IsValid()) { TSharedPtr Focused = FSlateApplication::Get().GetKeyboardFocusedWidget(); if (Focused.Get() != ViewportWidget.Get()) { UE_LOG(LogLuprexIntegration, Error, TEXT("In GameOnly mode, keyboard focus must stay on viewport, but was stolen by: %s. Restoring."), *GetUserWidgetName(Focused.Get())); EventRequests.SetDirty(); } if (!ViewportWidget->HasMouseCapture()) { UE_LOG(LogLuprexIntegration, Error, TEXT("In GameOnly mode, viewport must have mouse capture, but lost it. Restoring.")); EventRequests.SetDirty(); } } } } if (!EventRequests.IsDirty()) return; EventRequests.ClearDirty(); CurrentInputMode = EventRequests.GetRequestedMode(); const TArray &Requests = EventRequests.GetRequests(); if (CurrentInputMode == InputMode::UIOnly) { SetInputMode(FInputModeUIOnly().SetWidgetToFocus(Requests[0].Widget->GetCachedWidget())); } else { SetInputMode(FInputModeGameOnly()); CharacterModeInput->KeyBindings.Empty(); TSet BoundKeys; for (const FlxEventRequest &Req : Requests) { for (const FKey &Key : Req.Hotkeys) { if (!BoundKeys.Contains(Key)) { BoundKeys.Add(Key); CharacterModeInput->BindKey(Key, IE_Pressed, this, &AlxPlayerControllerBase::ForwardKeyEvent); } } } } } void AlxPlayerControllerBase::ForwardKeyEvent(FKey Key) { // TODO: implement } void AlxPlayerControllerBase::RequestEvents(const FlxEventRequest &Request) { if (!FlxEventRequests::SanityCheck(Request)) return; AlxPlayerControllerBase *PC = FromContext(Request.Widget); PC->EventRequests.Request(Request); } void AlxPlayerControllerBase::UnRequestEvents(UUserWidget *Widget) { if (Widget == nullptr) { UE_LOG(LogLuprexIntegration, Error, TEXT("UnRequestEvents called with null widget.")); return; } AlxPlayerControllerBase *PC = FromContext(Widget); PC->EventRequests.Remove(Widget); } void AlxPlayerControllerBase::UpdateLookAt() { UlxTangibleManager *TM = GetGameInstance()->GetSubsystem(); if (TM == nullptr) return; UlxTangible *Possessed = TM->GetPossessedTangible(); if (Possessed == nullptr) return; APawn *Pawn = GetPawn(); if (Pawn == nullptr) return; if (Possessed->GetActor() != Cast(Pawn)) return; if (PlayerCameraManager == nullptr) return; CalculateLookAt(); if (MustCallLookAtChanged) { MustCallLookAtChanged = false; LookAtChanged(); } }