How to detect when an AActor has become detached, from the derived AActor class?

To be notified of attachment changes, SceneComponents have the OnAttachmentChanged method that can be overridden. I can’t find anything similar for Actors. Is there a standard way?

When my actor becomes detached, I want to attach it elsewhere. The only way I have found to do it is check on every tick, or created a custom derived SceneComponent and then downcast the result of GetOwner to my actor call some method to notify it. Both are pretty ugly and invasive solutions. Many times you have an actor with a Root scene component that you can’t really control. Is there anything standard for this?

The closest I see in the code is this in USceneComponent:: DetachFromComponent:



#if WITH_EDITOR
        if(GEngine)
        {
            if(Owner && this == Owner->GetRootComponent())
            {
                GEngine->BroadcastLevelActorDetached(Owner, GetAttachParent()->GetOwner());
            }
        }
#endif


Only works in editor and is a global broadcast, so not what I need.

I’m thinking of just adding a AActor::OnAttachmentChanged and adding this to the engine code in USceneComponent:: DetachFromComponent and USceneComponent::AttachToComponent:



            if(Owner && this == Owner->GetRootComponent())
            {
                Owner->OnAttachmentChanged();
            }


Would that be useful enough to accept a pull request? Or is it the wrong way to go about it?

If you have something that works and think it is a good addition to the engine, I would suggest putting in a pull request. Worst case, it won’t be accepted, but you’ll still have something you need for your project.

Here’s what I ended up with for now just to avoid engine changes:



#pragma once

#include "Components/SceneComponent.h"

#include "AttachmentNotifier.generated.h"


DECLARE_DYNAMIC_MULTICAST_DELEGATE(FNotifyOnAttachmentChanged);

UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class SHOOTERGAME_API UAttachmentNotifier : public USceneComponent
{
	GENERATED_BODY()

public:	
	// Sets default values for this component's properties
	UAttachmentNotifier();

	// Called when the game starts
	virtual void BeginPlay() override;
	
	// Called every frame
	virtual void TickComponent( float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction ) override;

	virtual void OnAttachmentChanged() override;

	UPROPERTY(BlueprintAssignable, Category = "Components")
	FNotifyOnAttachmentChanged NotifyOnAttachmentChanged;
};


and the .cpp:



#include "YourGame.h"
#include "AttachmentNotifier.h"


// Sets default values for this component's properties
UAttachmentNotifier::UAttachmentNotifier()
{
	// 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;

	// ...
}


// Called when the game starts
void UAttachmentNotifier::BeginPlay()
{
	Super::BeginPlay();

	// ...
	
}


// Called every frame
void UAttachmentNotifier::TickComponent( float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction )
{
	Super::TickComponent( DeltaTime, TickType, ThisTickFunction );

	// ...
}

void UAttachmentNotifier::OnAttachmentChanged()
{
	if (this->NotifyOnAttachmentChanged.IsBound())
	{
		NotifyOnAttachmentChanged.Broadcast();
	}
}


But it won’t work if you want this for an Actor with a component hierarchy you don’t control, like ACharacter’s hardcoded capsule RootComponent.

I’d imagine a PR that added a multicast delegate to USceneComponent would be more likely to get accepted since it would provide the functionality more generically.

Having said that, can’t you simply trigger the logic yourself at the point you are causing the detachment? Component detachment isn’t something that the engine will do arbitrarily, you must be triggering it somewhere so you shouldn’t really need a delegate to achieve what you want.

Yeah, I wouldn’t put the above in a pull request, that’s just what I went for right now to avoid modifying the engine.

Adding a delegate to USceneComponent would make it take more memory and it is such a central class I probably wouldn’t want to do that (it isn’t going to take significant memory, but for cache etc.). I think adding an OnAttachmentChanged method to AActor and calling it from USceneComponent::OnAttachmentChanged when the component is the Actor’s root is a lighter weight approach (maybe not enough lighter to really matter vs a delegate).

There are a lot more scenarios where attachment can change than you might think: net relevancy culling, traveling to new level with actor in seamless travel actor list, …

Okay yeah I haven’t done a lot of network stuff. In that case yes I guess trying to control it at the call point isn’t feasible.

It’s true it would be a little heavier, I was just thinking if you have a use for this at the actor level, then chances are someone else will eventually want it at the component level - and of course the latter gives you the former also via the root component.