#pragma region CPL License /* Nuclex Unreal Module Copyright (C) 2014-2021 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #pragma endregion // CPL License #include "Actors/PawnController.h" #include "NuclexErrors.h" // --------------------------------------------------------------------------------------------- // UPawnController::UPawnController() : DebugAnnounceMoveSwitches(false), activeMove(nullptr), owningPawn(nullptr), wasBeginPlayCalled(false), moveSelectedBeforeBeginPlay(false) { // Set this component to be initialized when the game starts, // and to be ticked every frame. You can turn these features // off to improve performance if you don't need them. PrimaryComponentTick.bCanEverTick = true; } // --------------------------------------------------------------------------------------------- // void UPawnController::BeginPlay() { Super::BeginPlay(); // Look up the pawn that owns this component. Selected moves interact directly // with the pawn rather than going through the actor controller. If the actor // controller is used on a non-pawn, leave all flags unset and refuse work. AActor *owningActor = GetOwner(); this->owningPawn = Cast(owningActor); if(this->owningPawn == nullptr) { UE_LOG( LogNuclex, Error, TEXT("%s - ERROR: %s"), TEXT("UPawnController::BeginPlay()"), TEXT("Actor controller was used on vanilla Actor (not a pawn or character)") ); return; } // If we have a valid pawn, set the flag so the active move (even if it is // switched during OnInitialize()) will be initialized on switch. This is // necessary as there is no second call to BeginPlay(). this->wasBeginPlayCalled = true; // Finally, if the currently active move was selected before BeginPlay() // happened, deliver the outstanding OnInitialized() notification. if(this->moveSelectedBeforeBeginPlay) { this->moveSelectedBeforeBeginPlay = false; if(this->activeMove != nullptr) { initializeMove(this->activeMove); UPawnMove::Execute_OnStarted(this->activeMove); } } } // --------------------------------------------------------------------------------------------- // void UPawnController::TickComponent( float deltaTime, ELevelTick tickType, FActorComponentTickFunction *thisTickFunction ) { Super::TickComponent(deltaTime, tickType, thisTickFunction); if(this->wasBeginPlayCalled) { if(this->activeMove != nullptr) { UPawnMove::Execute_PhysicsTick(this->activeMove, deltaTime); } } } // --------------------------------------------------------------------------------------------- // void UPawnController::SetActiveMove(UPawnMove *move) { // Start by getting rid of the currently active move dropActiveMove(); // If the move is switched after BeginPlay(), perform its initialization // right away. Also check that the move isn't owned by another pawn if(move != nullptr) { this->activeMove = move; if(this->wasBeginPlayCalled) { initializeMove(move); UPawnMove::Execute_OnStarted(move); } else { this->moveSelectedBeforeBeginPlay = true; } } if(UNLIKELY(this->DebugAnnounceMoveSwitches)) { logMoveSwitch(); } } // --------------------------------------------------------------------------------------------- // void UPawnController::initializeMove(UPawnMove *move) { check(this->owningPawn != nullptr); APawn *movePawn = move->GetPawn(); if(UNLIKELY(movePawn == nullptr)) { move->Initialize(this->owningPawn); } else if(UNLIKELY(movePawn != this->owningPawn)) { UE_LOG( LogNuclex, Error, TEXT("%s - ERROR: %s"), TEXT("UPawnController::initializeMove()"), TEXT("Actor move has already been initialized for another pawn!") ); } } // --------------------------------------------------------------------------------------------- // void UPawnController::dropActiveMove() { // If a move is still running, inform it that it's no longer active if(this->activeMove != nullptr) { // ...unless we postponed the BeginPlay() and thus also OnStarted() call, // in which case we just silently drop it. if(this->moveSelectedBeforeBeginPlay) { this->moveSelectedBeforeBeginPlay = false; } else { UPawnMove::Execute_OnEnded(this->activeMove); } this->activeMove = nullptr; } } // --------------------------------------------------------------------------------------------- // void UPawnController::logMoveSwitch() { // Figure out the name of the pawn executing the move FString pawnActorName; { if(this->wasBeginPlayCalled) { check(this->owningPawn != nullptr); pawnActorName = this->owningPawn->GetName(); } else { AActor *owningActor = GetOwner(); check(owningActor != nullptr); pawnActorName = owningActor->GetName(); } } // Figure out what the actor move class is called FString moveClassName; { if(this->activeMove == nullptr) { moveClassName = TEXT(""); } else { UClass *moveClass = this->activeMove->GetClass(); if(moveClass != nullptr) { moveClassName = moveClass->GetName(); } else { moveClassName = TEXT(""); } } } // Finally, log the move switch UE_LOG( LogNuclex, Display, TEXT("%s - INFO: Pawn/Character %s switched to move %s"), TEXT("UPawnController::logMoveSwitch()"), *pawnActorName, *moveClassName ); } // --------------------------------------------------------------------------------------------- //