UInterface and IInterface
///////// header file /////////
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "UObject/Interface.h"
#include "WhenCalled.generated.h"
class IWhenCalledInterface;
class UWhenCalledInterface;
UINTERFACE(BlueprintType, MinimalAPI)
class UWhenCalledManagerInterface: public UInterface
{
GENERATED_UINTERFACE_BODY()
};
class SURAXR_API IWhenCalledManagerInterface
{
GENERATED_IINTERFACE_BODY()
public:
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category="SURAXR")
int AddHandler(const TScriptInterface<IWhenCalledInterface>& Handler);
virtual void BindDelegates() = 0;
};
UINTERFACE(BlueprintType, MinimalAPI)
class UWhenCalledInterface: public UInterface
{
GENERATED_UINTERFACE_BODY()
};
class SURAXR_API IWhenCalledInterface
{
GENERATED_IINTERFACE_BODY()
public:
UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category="SURAXR")
int GetPriority() const;
UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category="SURAXR")
void DoAtBeginFrame();
UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category="SURAXR")
void DoAtEndFrame();
UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category="SURAXR")
void DoAtBeginFrameRT();
UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category="SURAXR")
void DoAtEndFrameRT();
};
UCLASS(Blueprintable, BlueprintType)
class SURAXR_API AWhenCalled : public AActor, public IWhenCalledManagerInterface
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AWhenCalled();
// Begin IWhenCalledManagerInterface
// Return: 0 on success; -1 on null Handler; 1 on Handler exists; 2 on Priority conflicts.
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category="SURAXR")
int AddHandler(const TScriptInterface<IWhenCalledInterface>& Handler);
virtual int AddHandler_Implementation(const TScriptInterface<IWhenCalledInterface>& Handler) override;
virtual void BindDelegates() override;
// End IWhenCalledManagerInterface
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
private:
// Begin IWhenCalledManagerInterface
UPROPERTY()
TMap<int, TScriptInterface<IWhenCalledInterface>> Manager;
// End IWhenCalledManagerInterface
};
//////// implementation file //////
// Fill out your copyright notice in the Description page of Project Settings.
#include "WhenCalled.h"
UWhenCalledInterface::UWhenCalledInterface(class FObjectInitializer const &ObjectInitializer)
:Super(ObjectInitializer)
{}
UWhenCalledManagerInterface::UWhenCalledManagerInterface(class FObjectInitializer const &ObjectInitializer)
:Super(ObjectInitializer)
{}
// Sets default values
AWhenCalled::AWhenCalled()
{
// 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;
}
int AWhenCalled::AddHandler_Implementation( const TScriptInterface<IWhenCalledInterface>& Handler )
{
UObject* Object = Handler.GetObject();
IWhenCalledInterface* IHandler = Cast<IWhenCalledInterface>(Object);
if (Object || IHandler)
{
if (Manager.FindKey(Handler) != nullptr)
{
return 1; // Handler exists
}
TArray<int> Keys;
Manager.GetKeys(Keys);
for (int k: Keys)
{
int Prior = IHandler == nullptr? IWhenCalledInterface::Execute_GetPriority(Object) : IHandler->GetPriority();
if (k == Prior)
{
return 2; // Priority conflicts.
}
}
int Prior = IHandler == nullptr ? IWhenCalledInterface::Execute_GetPriority(Object) : IHandler->GetPriority();
Manager.Add(Prior, Handler);
Manager.KeyStableSort([](int A, int B)
{
return A < B;
});
return 0;
}
return -1;
}
void AWhenCalled::BindDelegates( )
{
FCoreDelegates::OnBeginFrame.AddWeakLambda(this, [this]()
{
for (auto& iter : Manager)
{
UObject* Object = iter.Value.GetObject();
if (Object)
{
IWhenCalledInterface::Execute_DoAtBeginFrame(Object);
continue;
}
IWhenCalledInterface* IHandler = Cast<IWhenCalledInterface>(Object);
if (IHandler)
{
IHandler->DoAtBeginFrame();
continue;
}
}
});
FCoreDelegates::OnEndFrame.AddWeakLambda(this, [this]()
{
for (auto& iter : Manager)
{
UObject* Object = iter.Value.GetObject();
if (Object)
{
IWhenCalledInterface::Execute_DoAtEndFrame(Object);
continue;
}
IWhenCalledInterface* IHandler = Cast<IWhenCalledInterface>(Object);
if (IHandler)
{
IHandler->DoAtEndFrame();
continue;
}
}
});
/*FCoreDelegates::OnBeginFrameRT.AddWeakLambda(this, [this]()
{
for (auto& iter : Manager)
{
IWhenCalledInterface* IHandler = Cast<IWhenCalledInterface>(iter.Value);
if (IHandler)
{
IHandler->DoAtBeginFrameRT();
}
}
});
FCoreDelegates::OnEndFrameRT.AddWeakLambda(this, [this]()
{
for (auto& iter : Manager)
{
IWhenCalledInterface* IHandler = Cast<IWhenCalledInterface>(iter.Value);
if (IHandler)
{
IHandler->DoAtEndFrameRT();
}
}
});*/
}
// Called when the game starts or when spawned
void AWhenCalled::BeginPlay()
{
Super::BeginPlay();
BindDelegates();
}
void AWhenCalled::EndPlay( const EEndPlayReason::Type EndPlayReason )
{
Super::EndPlay(EndPlayReason);
}
// Called every frame
void AWhenCalled::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}