Infraestrutura cliente da promocao de classe (Jobs.1). WBP_JobChangePanel NAO esta neste commit — foi exploracao descartada (criar UI dinamica de botoes via MCP BP graph esbarrou em limites do CreateWidget node). A fundacao C++ fica pronta pra ser usada quando voltarmos pra UI. INFRA C++ NOVA (Source/ZMMOJobs/) * UZMMOJobChangeNetworkHandler (WorldSubsystem novo) — bind no OnJobChangeResult do plugin e re-broadcast via FZMMOOnJobChangeResultBP (dynamic multicast assignavel em BP). WBP futura escuta direto. * UZMMOJobsSubsystem helpers: GetJobsByTier(EZMMOJobTier) + GetEligibleNextJobs(currentClassId) — filtra por ParentClassId. Pure. * UZMMOJobsLibrary BPFL wrappers + SendJobChangeRequest convenience (delega pro UZeusNetworkSubsystem). Dep ZeusNetwork adicionada no Build.cs. ENUM + INPUT * EZMMOInGameUIState ganha JobChangePanel (entre StatusWindow e Inventory). DA_InGameScreenSet pendente de receber entry quando WBP for criada (tecla J vai falhar silenciosamente ate la). * ZMMOPlayerController: tecla J -> ToggleJobChangePanel -> Flow->ToggleScreen(JobChangePanel). Espelha pattern do Alt+A do StatusWindow (InputComponent legacy BindKey + FInputChord). UI TWEAKS * WBP_StatusWindow + DT_UI_Styles: ajustes visuais no Editor durante a sessao (sem mudanca funcional documentavel — provavelmente fontes/ spacing/cores). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
144 lines
4.3 KiB
C++
144 lines
4.3 KiB
C++
#include "ZMMOPlayerController.h"
|
|
|
|
#include "Blueprint/UserWidget.h"
|
|
#include "Components/InputComponent.h"
|
|
#include "EnhancedInputSubsystems.h"
|
|
#include "Engine/GameInstance.h"
|
|
#include "Engine/LocalPlayer.h"
|
|
#include "Framework/Commands/InputChord.h"
|
|
#include "InputMappingContext.h"
|
|
#include "UObject/ConstructorHelpers.h"
|
|
#include "Widgets/Input/SVirtualJoystick.h"
|
|
#include "ZMMO.h"
|
|
#include "UI/InGame/UIInGameFlowSubsystem.h"
|
|
#include "UI/InGameTypes.h"
|
|
|
|
AZMMOPlayerController::AZMMOPlayerController()
|
|
{
|
|
// Defaults dos Input Mapping Contexts (alinhados ao ZClientMMO). Permitem
|
|
// instanciar AZMMOPlayerController directamente como
|
|
// `PlayerControllerClass` do AZMMOGameMode sem exigir um BP filho. Se o
|
|
// projeto adicionar mais IMCs, podemos extender via BP filho ou via
|
|
// arquivos de Config (UPROPERTY EditAnywhere abaixo).
|
|
static ConstructorHelpers::FObjectFinder<UInputMappingContext> DefaultImc(
|
|
TEXT("/Game/Input/IMC_Default.IMC_Default"));
|
|
static ConstructorHelpers::FObjectFinder<UInputMappingContext> MouseLookImc(
|
|
TEXT("/Game/Input/IMC_MouseLook.IMC_MouseLook"));
|
|
|
|
if (DefaultImc.Succeeded())
|
|
{
|
|
DefaultMappingContexts.Add(DefaultImc.Object);
|
|
}
|
|
if (MouseLookImc.Succeeded())
|
|
{
|
|
MobileExcludedMappingContexts.Add(MouseLookImc.Object);
|
|
}
|
|
}
|
|
|
|
void AZMMOPlayerController::BeginPlay()
|
|
{
|
|
Super::BeginPlay();
|
|
|
|
if (IsLocalPlayerController())
|
|
{
|
|
// Limpa estado de input herdado da UI do FrontEnd (UIManagerSubsystem
|
|
// e LocalPlayerSubsystem — sobrevive ao travel, e o controller anterior
|
|
// (AZMMOFrontEndPlayerController) tinha setado FInputModeUIOnly +
|
|
// bShowMouseCursor=true). Sem este reset, WASD/Look podem nao chegar
|
|
// ao pawn porque o Slate ainda esta com foco no widget antigo.
|
|
FInputModeGameOnly InputMode;
|
|
InputMode.SetConsumeCaptureMouseDown(true);
|
|
SetInputMode(InputMode);
|
|
bShowMouseCursor = false;
|
|
FlushPressedKeys();
|
|
}
|
|
|
|
if (ShouldUseTouchControls() && IsLocalPlayerController())
|
|
{
|
|
MobileControlsWidget = CreateWidget<UUserWidget>(this, MobileControlsWidgetClass);
|
|
if (MobileControlsWidget)
|
|
{
|
|
MobileControlsWidget->AddToPlayerScreen(0);
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogZMMO, Error, TEXT("Could not spawn mobile controls widget."));
|
|
}
|
|
}
|
|
}
|
|
|
|
void AZMMOPlayerController::SetupInputComponent()
|
|
{
|
|
Super::SetupInputComponent();
|
|
|
|
if (!IsLocalPlayerController())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer()))
|
|
{
|
|
for (UInputMappingContext* CurrentContext : DefaultMappingContexts)
|
|
{
|
|
Subsystem->AddMappingContext(CurrentContext, 0);
|
|
}
|
|
|
|
if (!ShouldUseTouchControls())
|
|
{
|
|
for (UInputMappingContext* CurrentContext : MobileExcludedMappingContexts)
|
|
{
|
|
Subsystem->AddMappingContext(CurrentContext, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Hotkey global Alt+A -> toggle StatusWindow. Uso InputComponent legacy
|
|
// (BindKey com FInputChord) pra nao depender de assets InputAction.
|
|
// Migrar pra Enhanced Input (IA_OpenStatus, IA_OpenInventory, etc.) quando
|
|
// vier outro menu (Inventory I, SkillTree K).
|
|
if (InputComponent)
|
|
{
|
|
FInputKeyBinding& Binding = InputComponent->BindKey(
|
|
FInputChord(EKeys::A, /*bShift*/ false, /*bCtrl*/ false, /*bAlt*/ true, /*bCmd*/ false),
|
|
IE_Pressed,
|
|
this, &AZMMOPlayerController::ToggleStatusWindow);
|
|
Binding.bConsumeInput = true;
|
|
Binding.bExecuteWhenPaused = true; // dispara mesmo com StatusWindow aberto (CommonUI menu mode)
|
|
|
|
// Hotkey J -> toggle JobChangePanel (Jobs.1).
|
|
FInputKeyBinding& JobBinding = InputComponent->BindKey(
|
|
FInputChord(EKeys::J, /*bShift*/ false, /*bCtrl*/ false, /*bAlt*/ false, /*bCmd*/ false),
|
|
IE_Pressed,
|
|
this, &AZMMOPlayerController::ToggleJobChangePanel);
|
|
JobBinding.bConsumeInput = true;
|
|
JobBinding.bExecuteWhenPaused = true;
|
|
}
|
|
}
|
|
|
|
void AZMMOPlayerController::ToggleStatusWindow()
|
|
{
|
|
if (UGameInstance* GI = GetGameInstance())
|
|
{
|
|
if (UUIInGameFlowSubsystem* Flow = GI->GetSubsystem<UUIInGameFlowSubsystem>())
|
|
{
|
|
Flow->ToggleScreen(EZMMOInGameUIState::StatusWindow);
|
|
}
|
|
}
|
|
}
|
|
|
|
void AZMMOPlayerController::ToggleJobChangePanel()
|
|
{
|
|
if (UGameInstance* GI = GetGameInstance())
|
|
{
|
|
if (UUIInGameFlowSubsystem* Flow = GI->GetSubsystem<UUIInGameFlowSubsystem>())
|
|
{
|
|
Flow->ToggleScreen(EZMMOInGameUIState::JobChangePanel);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool AZMMOPlayerController::ShouldUseTouchControls() const
|
|
{
|
|
return SVirtualJoystick::ShouldDisplayTouchInterface() || bForceTouchControls;
|
|
}
|