Hi there!
I have the following problem: I have Cover actors with an editor function to recreate some information they hold (their type of cover).
Now when I run this function (GenerateCoverTypeWrapper()), I receive a nullptr for my root component (CoverComponent), which holds all the actual cover information and functions.
Now when I create a new Cover actor, and hit the function, everything is fine!
This leads me to the assumption that both actors (old and fresh one) are different, and that the old actors are broken because they were differently constructed then the new ones.
I even tried to fire the RerunConstructionScripts() function in the editor, without success. Here the c++ files:
Cover.h
// Copyright by Felix Voigt
#pragma once
#include "CoreMinimal.h"
#include "AI/EQS/CoverComponent.h"
#include "Components/ArrowComponent.h"
#include "Components/BillboardComponent.h"
#include "Components/BoxComponent.h"
#include "Data/MoveTargetContainer.h"
#include "GameFramework/Actor.h"
#include "Cover.generated.h"
UCLASS()
class HARRISONPROJECT_API ACover : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ACover();
//Displays the disclosed Cover Type of the Cover Component
UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = Cover)
ECoverType CoverTypeDisplay;
//Displays the disclosed Cover Peek Direction of the Cover Component
UPROPERTY(BlueprintReadOnly, VisibleAnywhere, meta=(Bitmask, BitmaskEnum=CoverPeekDirectionMask), Category = Cover)
uint8 CoverPeekDirectionDisplay;
UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = Cover)
UCoverComponent* CoverComponent;
#if WITH_EDITOR
private:
//UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category=Cover)
UPROPERTY()
UBillboardComponent* BillboardComponent;
UPROPERTY()
class UTexture2D* HighCoverTexture;
UPROPERTY()
class UTexture2D* LowCoverTexture;
UPROPERTY()
class UTexture2D* NoCoverTexture;
UPROPERTY()
UArrowComponent* CoverDirectionComponent;
UPROPERTY()
UBoxComponent* CoverBoxComponent;
#endif
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
virtual void PostEditMove(bool bFinished) override;
virtual void PostEditUndo() override;
#if WITH_EDITOR
UFUNCTION(BlueprintCallable, CallInEditor, DisplayName = GenerateCoverType, Category = Cover)
void GenerateCoverTypeWrapper();
UFUNCTION(BlueprintCallable, CallInEditor, DisplayName = GenerateCoverTypesForAll, Category = Cover)
void GenerateCoverTypesForAllWrapper() const;
UFUNCTION(BlueprintCallable, CallInEditor, DisplayName = GenerateCoverTypesForAll, Category = Cover)
void ReConstruct();
#endif
};
Cover.cpp
// Copyright by Felix Voigt
#include "AI/EQS/Cover.h"
#include "Kismet/GameplayStatics.h"
// Sets default values
ACover::ACover()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = false;
CoverComponent = CreateDefaultSubobject<UCoverComponent>(TEXT("Cover Point Component"));
if(CoverComponent)
{
CoverComponent->Mobility = EComponentMobility::Static;
SetRootComponent(CoverComponent);
//UE_LOG(LogTemp, Warning, TEXT("ComponentSet"));
}
#if WITH_EDITOR
ConstructorHelpers::FObjectFinderOptional<UTexture2D> FullShieldTextureObject(TEXT("Texture2D'/Game/HarrisonProject/UI/Textures/Icons/T_IconShieldInverted_Full.T_IconShieldInverted_Full'"));
ConstructorHelpers::FObjectFinderOptional<UTexture2D> HalfShieldTextureObject(TEXT("Texture2D'/Game/HarrisonProject/UI/Textures/Icons/T_IconShieldInverted_Half.T_IconShieldInverted_Half'"));
ConstructorHelpers::FObjectFinderOptional<UTexture2D> NoShieldTextureObject(TEXT("Texture2D'/Game/HarrisonProject/UI/Textures/Icons/T_IconRedCross.T_IconRedCross'"));
HighCoverTexture = FullShieldTextureObject.Get();
LowCoverTexture = HalfShieldTextureObject.Get();
NoCoverTexture = NoShieldTextureObject.Get();
BillboardComponent = CreateEditorOnlyDefaultSubobject<UBillboardComponent>(TEXT("Cover Icon"));
if(BillboardComponent)
{
BillboardComponent->bIsScreenSizeScaled = true;
BillboardComponent->ScreenSize = 0.0005f;
BillboardComponent->Sprite = NoCoverTexture;
BillboardComponent->SetupAttachment(RootComponent);
BillboardComponent->AttachToComponent(RootComponent, FAttachmentTransformRules::SnapToTargetNotIncludingScale);
BillboardComponent->SetRelativeLocation(FVector(0.0f,0.0f, 25.0f));
}
CoverDirectionComponent = CreateEditorOnlyDefaultSubobject<UArrowComponent>(TEXT("Cover Direction Arrow"));
if(CoverDirectionComponent)
{
CoverDirectionComponent->SetupAttachment(RootComponent);
CoverDirectionComponent->AttachToComponent(RootComponent, FAttachmentTransformRules::SnapToTargetNotIncludingScale);
CoverDirectionComponent->SetRelativeLocation(FVector(0.0f,0.0f, 50.0f));
CoverDirectionComponent->SetRelativeRotation(GetActorForwardVector().ToOrientationRotator());
CoverDirectionComponent->ArrowSize = 0.5f;
}
CoverBoxComponent = CreateEditorOnlyDefaultSubobject<UBoxComponent>(TEXT("Cover Box Component"));
if(CoverBoxComponent)
{
CoverDirectionComponent->SetupAttachment(RootComponent);
CoverBoxComponent->AttachToComponent(RootComponent, FAttachmentTransformRules::SnapToTargetNotIncludingScale);
CoverBoxComponent->SetBoxExtent(FVector(30.0f, 30.0f, 100.0f));
CoverBoxComponent->SetRelativeLocation(FVector(0.0f,0.0f, 100.0f));
}
GenerateCoverTypeWrapper();
#endif
}
// Called when the game starts or when spawned
void ACover::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void ACover::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void ACover::PostEditMove(bool bFinished)
{
Super::PostEditMove(bFinished);
GenerateCoverTypeWrapper();
}
void ACover::PostEditUndo()
{
Super::PostEditUndo();
GenerateCoverTypeWrapper();
}
#if WITH_EDITOR
void ACover::GenerateCoverTypeWrapper()
{
CoverComponent->GenerateCoverType();
CoverTypeDisplay = CoverComponent->GetCoverType();
CoverPeekDirectionDisplay = CoverComponent->GetCoverPeekDirection();
switch (CoverTypeDisplay)
{
case ECoverType::CT_HighCover :
UE_LOG(LogTemp, Warning, TEXT("High"));
BillboardComponent->Sprite = HighCoverTexture;
CoverBoxComponent->SetBoxExtent(FVector(30.0f, 30.0f, 100.0f));
CoverBoxComponent->SetRelativeLocation(FVector(0.0f,0.0f, 100.0f));
break;
case ECoverType::CT_LowCover :
UE_LOG(LogTemp, Warning, TEXT("Low"));
BillboardComponent->Sprite = LowCoverTexture;
CoverBoxComponent->SetBoxExtent(FVector(30.0f, 30.0f, 50.0f));
CoverBoxComponent->SetRelativeLocation(FVector(0.0f,0.0f, 50.0f));
break;
case ECoverType::CT_NoCover :
UE_LOG(LogTemp, Warning, TEXT("No"));
BillboardComponent->Sprite = NoCoverTexture;
CoverBoxComponent->SetBoxExtent(FVector(30.0f, 30.0f, 0.0f));
CoverBoxComponent->SetRelativeLocation(FVector(0.0f,0.0f, 0.0f));
break;
}
}
void ACover::GenerateCoverTypesForAllWrapper() const
{
TArray<AActor*> AllCoverItems;
UGameplayStatics::GetAllActorsOfClass(this, ACover::StaticClass(), AllCoverItems);
for (AActor* CoverActorIterator : AllCoverItems)
{
Cast<ACover>(CoverActorIterator)->GenerateCoverTypeWrapper();
}
}
void ACover::ReConstruct()
{
RerunConstructionScripts();
}
#endif
Thank you in advance for your time!