Download

GetOwner() crashing the engine

Hello Forum, I am having this problem for the last 3 days or so.
I created a weapon and attached it to my character and then set the character as the owner but when I use GetOwner() back in the Gun.cpp, the engine crashes showing me that line where I call GetOwner().

This is part of the Character.h file where I set the owner.

And this is the snippet of where I call the GetOwner().

Thanks in advance

Is ABallCharacter a subclass of ACharacter or APawn?

@Kris It probably is, since it has a GetController function, which is defined on APawn.

@micksayno So are you saying that the game currently crashes at line 38 or that the log message you defined right after that is displayed? If the game actually crashes, could it be that you’re calling PullTrigger on a null gun actor?

Hey Kris, it is a subclass of ACharacter.

Yes @and-rad, it crashes at line 38 and I thought of maybe am calling a null gun actor but I set the character as owner after spawning the gun in the game. I don’t think its null maybe you elaborate more on your null pointer issue.

Well, you have two guns. Whenever you call AGunBaseActor::PullTrigger on any one of them, do you absolutely, positively know that both actors are set up and are not null?

Yeah they are well setup in the game

So you check whether any of the gun actors are null before you call PullTrigger on them? Can you post a stack trace of the crash happening? I’m mostly interested in which functions are called that lead up to the final PullTrigger call before it crashes.

This is the ABallCharacter.cpp

#include "BallCharacter.h"
#include "Camera/CameraComponent.h"
#include "GameFramework/SpringArmComponent.h"
#include "GameFramework/Controller.h"
#include "GunBaseActor.h"
#include "Components/SkeletalMeshComponent.h"


// Sets default values
ABallCharacter::ABallCharacter()
{
 	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void ABallCharacter::BeginPlay()
{
	Super::BeginPlay();

	PlayerController = GetController();
	BallMesh = GetMesh();

	GunSetupLeft(LeftGun);
	GunSetupRight(RightGun);
}

void ABallCharacter::Shoot() 
{
	LeftGun->PullTrigger();
}

void ABallCharacter::UpdatePlayerPOV() 
{
	// Get Player Point Of View(POV) to be used for rotating pawn to face direction of player.
	FVector POV_Location;
	FRotator POV_Rotation;
	PlayerController->GetPlayerViewPoint(POV_Location, POV_Rotation);
	
	FRotator NewRotation = FRotator(GetActorRotation().Pitch, POV_Rotation.Yaw, GetActorRotation().Roll);

	// Set the pawn to face the direction of player's POV'
	SetActorRotation(FQuat(NewRotation));
}

void ABallCharacter::GunSetupLeft(AGunBaseActor* GunLeft) 
{
	if (GunLeftClass == nullptr)
	{
		UE_LOG(LogTemp, Error, TEXT("There is no GunLeftClass!!"));
		return;
	}

	GunLeft = GetWorld()->SpawnActor<AGunBaseActor>(GunLeftClass);

	FAttachmentTransformRules GunLeftAttachmentRules = FAttachmentTransformRules(EAttachmentRule::KeepRelative, EAttachmentRule::KeepWorld, EAttachmentRule::KeepRelative, true);
	GunLeft->AttachToActor(this, GunLeftAttachmentRules);

	GunLeft->SetActorRelativeRotation(FRotator(0.0f, 90.0f, 0.0f) ,true);
	GunLeft->SetActorRelativeLocation(FVector(12.0f, -35.0f, 0.0f), true);
	MoveIgnoreActorAdd(GunLeft);

	GunLeft->SetOwner(this);
}

void ABallCharacter::GunSetupRight(AGunBaseActor* GunRight) 
{
	if (GunRightClass == nullptr)
	{
		UE_LOG(LogTemp, Error, TEXT("There is no GunRightClass!!"));
		return;
	}

	GunRight = GetWorld()->SpawnActor<AGunBaseActor>(GunRightClass);

	FAttachmentTransformRules GunRightAttachmentRules = FAttachmentTransformRules(EAttachmentRule::KeepRelative, EAttachmentRule::KeepWorld, EAttachmentRule::KeepRelative, true);
	GunRight->AttachToActor(this, GunRightAttachmentRules);
			
	GunRight->SetActorRelativeRotation(FRotator(0.0f, 90.0f, 0.0f) ,true);
	GunRight->SetActorRelativeLocation(FVector(12.0f, 22.f, 0.0f), true);
	MoveIgnoreActorAdd(GunRight);
	
	GunRight->SetOwner(this);
}

Then I use a custom PlayerController to call the PullTrigger as shown below.

// Called to bind functionality to input
void ABallPlayerController::PushInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::PushInputComponent(PlayerInputComponent);

	PlayerCharacter = Cast<ABallCharacter>(this->GetCharacter());
	if (PlayerCharacter)
	{
		// Axis Bindings
		PlayerInputComponent->BindAxis("MoveForward", PlayerCharacter, &ABallCharacter::BallMoveForward);
		PlayerInputComponent->BindAxis("Strafe", PlayerCharacter, &ABallCharacter::BallStrafe);

		// Action Bindings
		PlayerInputComponent->BindAction("Jump", IE_Pressed, PlayerCharacter, &ABallCharacter::BallJump);
		PlayerInputComponent->BindAction("Shoot", IE_Pressed, PlayerCharacter, &ABallCharacter::Shoot);
	}
	else
	{
		UE_LOG(LogTemp, Error, TEXT("Player Pawn is null!!"));
	}

}

Then Finally the PullTrigger called from the AGunBaseActor.cpp

#include "GunBaseActor.h"
#include "Components/StaticMeshComponent.h"
#include "GameFramework/Controller.h"

// Sets default values
AGunBaseActor::AGunBaseActor()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	SceneGunRoot = CreateDefaultSubobject<USceneComponent>(TEXT("Scene Gun Root"));
	SetRootComponent(SceneGunRoot);

	GunMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Gun Mesh"));
	GunMesh->SetupAttachment(SceneGunRoot);
}

// Called when the game starts or when spawned
void AGunBaseActor::BeginPlay()
{
	Super::BeginPlay();
	
}

// Called every frame
void AGunBaseActor::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

void AGunBaseActor::PullTrigger() 
{
	if (IsValid(GetOwner()))
	{
		GunOwner = Cast<APawn>(GetOwner());
		OwningController = GunOwner->GetController();

		FHitResult TraceResult;
		FVector PlayerViewPointLocation;
		FRotator PlayerViewPointRotation;
		OwningController->GetPlayerViewPoint(PlayerViewPointLocation, PlayerViewPointRotation);
		FVector TraceEnd = PlayerViewPointLocation + PlayerViewPointRotation.Vector() * ShootRange;	

		bool TraceSuccess = GetWorld()->LineTraceSingleByChannel(TraceResult, PlayerViewPointLocation, TraceEnd, ECollisionChannel::ECC_Visibility);

		if (TraceSuccess)
		{
			UE_LOG(LogTemp, Warning, TEXT("Line was traced!!"));
		}
	}
	else
	{
		UE_LOG(LogTemp, Error, TEXT("There is no valid gun owner!!!"));
	}
}

The moment I hit the Left Mouse Button, it crashes with this message.

LoginId:f776299044de3ce83aa2cda5da18cf99
EpicAccountId:3ee1a0225580486195fe5d56ce1d7e5a

Unhandled Exception: EXCEPTION_ACCESS_VIOLATION reading address 0x000000e8

UE4Editor_Test_4600!AGunBaseActor::PullTrigger() >[D:\UnrealProjects\Test\Source\Test\GunBaseActor.cpp:37]
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Core
UE4Editor_Core
UE4Editor_Core
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_Engine
UE4Editor_UnrealEd
UE4Editor_UnrealEd
UE4Editor
UE4Editor
UE4Editor
UE4Editor
UE4Editor
kernel32
ntdll

Couple things.

  1. You don’t check whether the gun actor is null before calling PullTrigger in ABallCharacter::Shoot. Do that. My guess is you will find out that it isn’t. Tell me if I’m right. I have a pretty strong suspicion on what’s happening.
  2. If you want that log output to show anything meaningful you need to download debugging symbols for the engine version. It’s fairly big download so it might take a while. It should then offer actually useful information. You don’t have to do that right away, though, number 1 is more important.

Hey you are right I logged out and the gun actor is null but I can’t tell how it is being null

Okay, I’m at work right now and the sun is going down soon, but I need to finish a thing before it does. I’ll be brief now and can explain in more detail later. For now, take this piece of code

if (GunLeftClass == nullptr)
	{
		UE_LOG(LogTemp, Error, TEXT("There is no GunLeftClass!!"));
		return;
	}

	GunLeft = GetWorld()->SpawnActor<AGunBaseActor>(GunLeftClass);

out of ABallCharacter::GunSetupLeft and put it in ABallCharacter::BeginPlay() right before you call

GunSetupLeft(LeftGun);
GunSetupRight(RightGun);

and change the GunLeft variable to LeftGun. It’s important that this code is not called in ABallCharacter::GunSetupLeft anymore. That should do it. It might not, depending on what else is going on that you haven’t shown yet (where do LeftGun and RightGun come from?), but there’s a good change this fixes it for the left gun for now.

Sorry for this long issue but that did not fix it the guns were still setup in the game and the LeftGun and RightGun are from my BallCharacter.h below.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "BallCharacter.generated.h"

class USpringArmComponent;
class UCameraComponent;
class AController;
class USkeletalMeshComponent;
class AGunBaseActor;

UCLASS()
class TEST_API ABallCharacter : public ACharacter
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	ABallCharacter();

	// Called every frame
	virtual void Tick(float DeltaTime) override;

	void BallMoveForward(float InputValue);

	void BallStrafe(float InputValue);

	void BallJump();

	void Shoot();
	
	void GunSetupLeft(AGunBaseActor* GunLeft);

	void GunSetupRight(AGunBaseActor* GunRight);

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

	UPROPERTY(EditAnywhere)
	USpringArmComponent* SpringArm;

	UPROPERTY(EditAnywhere)
	UCameraComponent* BallCamera;

	UPROPERTY(EditAnywhere)
	float MoveSpeed = 100.0f;

	UPROPERTY(EditAnywhere)
	TSubclassOf<AGunBaseActor> GunLeftClass;

	UPROPERTY()
	AGunBaseActor* LeftGun;

	UPROPERTY(EditAnywhere)
	TSubclassOf<AGunBaseActor> GunRightClass;

	UPROPERTY()
	AGunBaseActor* RightGun;

	AController* PlayerController;

	USkeletalMeshComponent* BallMesh;

private:
	void UpdatePlayerPOV();

Can you post the CPP file of ABallCharacter again the way it looks now?

Alright here is the updated one it doesn’t crash now but does not call PullTrigger() on the LeftGun.

#include "BallCharacter.h"
#include "Camera/CameraComponent.h"
#include "GameFramework/SpringArmComponent.h"
#include "GameFramework/Controller.h"
#include "GunBaseActor.h"
#include "Components/SkeletalMeshComponent.h"


// Sets default values
ABallCharacter::ABallCharacter()
{
 	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void ABallCharacter::BeginPlay()
{
	Super::BeginPlay();

	PlayerController = GetController();
	BallMesh = GetMesh();

	if (GunLeftClass == nullptr)
	{
		UE_LOG(LogTemp, Error, TEXT("There is no GunLeftClass!!"));
		return;
	}
	
	GunSetupLeft(LeftGun);
	GunSetupRight(RightGun);
}

// Called every frame
void ABallCharacter::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	UpdatePlayerPOV();
}

void ABallCharacter::BallJump() 
{
	Jump();	
}

void ABallCharacter::Shoot() 
{
	if (IsValid(LeftGun))
	{
		LeftGun->PullTrigger();
	}
	else
	{
		UE_LOG(LogTemp, Error, TEXT("The Gun Actor is null!!"));
	}
}

void ABallCharacter::UpdatePlayerPOV() 
{
	// Get Player Point Of View(POV) to be used for rotating pawn to face direction of player.
	FVector POV_Location;
	FRotator POV_Rotation;
	PlayerController->GetPlayerViewPoint(POV_Location, POV_Rotation);
	
	FRotator NewRotation = FRotator(GetActorRotation().Pitch, POV_Rotation.Yaw, GetActorRotation().Roll);

	// Set the pawn to face the direction of player's POV'
	SetActorRotation(FQuat(NewRotation));
}

void ABallCharacter::GunSetupLeft(AGunBaseActor* GunLeft) 
{
	GunLeft = GetWorld()->SpawnActor<AGunBaseActor>(GunLeftClass);

	FAttachmentTransformRules GunLeftAttachmentRules = FAttachmentTransformRules(EAttachmentRule::KeepRelative, EAttachmentRule::KeepWorld, EAttachmentRule::KeepRelative, true);
	GunLeft->AttachToActor(this, GunLeftAttachmentRules);

	GunLeft->SetActorRelativeRotation(FRotator(0.0f, 90.0f, 0.0f) ,true);
	GunLeft->SetActorRelativeLocation(FVector(12.0f, -35.0f, 0.0f), true);
	MoveIgnoreActorAdd(GunLeft);

	GunLeft->SetOwner(this);
}

void ABallCharacter::GunSetupRight(AGunBaseActor* GunRight) 
{
	if (GunRightClass == nullptr)
	{
		UE_LOG(LogTemp, Error, TEXT("There is no GunRightClass!!"));
		return;
	}

	GunRight = GetWorld()->SpawnActor<AGunBaseActor>(GunRightClass);

	FAttachmentTransformRules GunRightAttachmentRules = FAttachmentTransformRules(EAttachmentRule::KeepRelative, EAttachmentRule::KeepWorld, EAttachmentRule::KeepRelative, true);
	GunRight->AttachToActor(this, GunRightAttachmentRules);
			
	GunRight->SetActorRelativeRotation(FRotator(0.0f, 90.0f, 0.0f) ,true);
	GunRight->SetActorRelativeLocation(FVector(12.0f, 22.f, 0.0f), true);
	MoveIgnoreActorAdd(GunRight);
	
	GunRight->SetOwner(this);
}

You didn’t copy the entire piece of code like I wrote above. You missed the line

GunLeft = GetWorld()->SpawnActor<AGunBaseActor>(GunLeftClass);

Move that to BeginPlay too.

I’ve replaced it in BeginPlay() and it is finally working :smiley: :smiley: :smiley: :smiling_face_with_three_hearts:

But how can I spawn the actor in a function so I can just call that function in BeginPlay()

First I’ll tell you what you’re doing wrong. Look at the comments in the code snippet:

void ABallCharacter::GunSetupLeft(AGunBaseActor* GunLeft) 
{
    // GunLeft is passed to the function as a pointer, pointing at some object
    // in memory. Whatever we do to GunLeft, we do to that object too.
    if (GunLeftClass == nullptr)
    {
        UE_LOG(LogTemp, Error, TEXT("There is no GunLeftClass!!"));
        return;
    }

    // This is the problematic part. GunLeft is reassigned to a NEW actor,
    // the one which is spawned here. It now points at this actor instead
    // of the one it pointed at at the beginning of the function call. 
    // Anything we do to GunLeft after this point, we do to that new 
    // object and not to the original one.
    GunLeft = GetWorld()->SpawnActor<AGunBaseActor>(GunLeftClass);

    // All of the stuff we do in the follwing lines of code we do to the newly 
    // created gun actor. So a gun actor will be created, it will be attached 
    // to this actor and its owner will be this character. The only problem is
   // the character's LeftGun variable is not that actor. It's still just an
   // uninitialized pointer sitting around.
    FAttachmentTransformRules GunLeftAttachmentRules = FAttachmentTransformRules(EAttachmentRule::KeepRelative, EAttachmentRule::KeepWorld, EAttachmentRule::KeepRelative, true);
    GunLeft->AttachToActor(this, GunLeftAttachmentRules);

    GunLeft->SetActorRelativeRotation(FRotator(0.0f, 90.0f, 0.0f) ,true);
    GunLeft->SetActorRelativeLocation(FVector(12.0f, -35.0f, 0.0f), true);
    MoveIgnoreActorAdd(GunLeft);

    GunLeft->SetOwner(this);

    // By the end of this function LeftGun is still null. If you call it 
   // anywhere without checking for it first, the game crashes, 
   // which you had to find out the hard way.
}

As for how to avoid it, the quickest way in your case would be to just not pass the pointer to the function in the first place. Since LeftGun and RightGun are properties of your character, it’s an unnecessary indirection anyway. the new function would look like this:

void ABallCharacter::GunSetupLeft() 
{
	if (GunLeftClass == nullptr)
	{
		UE_LOG(LogTemp, Error, TEXT("There is no GunLeftClass!!"));
		return;
	}

	LeftGun = GetWorld()->SpawnActor<AGunBaseActor>(GunLeftClass);

	FAttachmentTransformRules GunLeftAttachmentRules = FAttachmentTransformRules(EAttachmentRule::KeepRelative, EAttachmentRule::KeepWorld, EAttachmentRule::KeepRelative, true);
	LeftGun->AttachToActor(this, GunLeftAttachmentRules);

	LeftGun->SetActorRelativeRotation(FRotator(0.0f, 90.0f, 0.0f) ,true);
	LeftGun->SetActorRelativeLocation(FVector(12.0f, -35.0f, 0.0f), true);
	MoveIgnoreActorAdd(LeftGun);

	LeftGun->SetOwner(this);
}

And you can keep calling it like this:

void ABallCharacter::BeginPlay()
{
	Super::BeginPlay();

	PlayerController = GetController();
	BallMesh = GetMesh();

	GunSetupLeft();
	GunSetupRight();
}

Wow! I think I was blinded by what I wanted to happen rather than what was happening. Thanks @and-rad