Skip to content

Commit

Permalink
The SpawnNow method was simplified to only handle spawning, without c…
Browse files Browse the repository at this point in the history
…allbacks, reducing code complexity and potential errors in child factories.
  • Loading branch information
JanSeliv committed Apr 26, 2024
1 parent cbf7cf1 commit ddcb3c4
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 59 deletions.
34 changes: 8 additions & 26 deletions Source/PoolManager/Private/Factories/PoolFactory_Actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@ UObject* UPoolFactory_Actor::SpawnNow_Implementation(const FSpawnRequest& Reques
UWorld* World = GetWorld();
checkf(World, TEXT("ERROR: [%i] %s:\n'World' is null!"), __LINE__, *FString(__FUNCTION__));

const TSubclassOf<AActor> ClassToSpawn = const_cast<UClass*>(Request.Class.Get());
checkf(ClassToSpawn, TEXT("ERROR: [%i] %s:\n'ClassToSpawn' is null!"), __LINE__, *FString(__FUNCTION__));

FActorSpawnParameters SpawnParameters;
SpawnParameters.OverrideLevel = World->PersistentLevel; // Always keep new objects on Persistent level
SpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
Expand All @@ -40,31 +37,16 @@ UObject* UPoolFactory_Actor::SpawnNow_Implementation(const FSpawnRequest& Reques
SpawnParameters.bCreateActorPackage = false; // Do not bake this runtime actor into World Partition level
#endif

AActor* NewActor = World->SpawnActor(ClassToSpawn, &Request.Transform, SpawnParameters);
checkf(NewActor, TEXT("ERROR: [%i] %s:\n'NewActor' was not spawned!"), __LINE__, *FString(__FUNCTION__));

FPoolObjectData PoolObjectData;
PoolObjectData.bIsActive = true;
PoolObjectData.PoolObject = NewActor;
PoolObjectData.Handle = Request.Handle;

if (Request.Callbacks.OnPreRegistered != nullptr)
{
Request.Callbacks.OnPreRegistered(PoolObjectData);
}

if (AActor* SpawnedActor = Cast<AActor>(NewActor))
{
// Call construction script since it was delayed before to add it to the pool first
SpawnedActor->FinishSpawning(Request.Transform);
}
return World->SpawnActor(Request.GetClassChecked<AActor>(), &Request.Transform, SpawnParameters);
}

if (Request.Callbacks.OnPostSpawned != nullptr)
{
Request.Callbacks.OnPostSpawned(PoolObjectData);
}
// Is overridden to finish spawning the actor since it was deferred
void UPoolFactory_Actor::OnPreRegistered(const FSpawnRequest& Request, const FPoolObjectData& ObjectData)
{
Super::OnPreRegistered(Request, ObjectData);

return NewActor;
AActor& SpawnedActor = ObjectData.GetChecked<AActor>();
SpawnedActor.FinishSpawning(Request.Transform);
}

/*********************************************************************************************
Expand Down
66 changes: 42 additions & 24 deletions Source/PoolManager/Private/Factories/PoolFactory_UObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
//---
#include UE_INLINE_GENERATED_CPP_BY_NAME(PoolFactory_UObject)

/*********************************************************************************************
* Creation
********************************************************************************************* */

// Method to queue object spawn requests
void UPoolFactory_UObject::RequestSpawn_Implementation(const FSpawnRequest& Request)
{
Expand All @@ -32,29 +36,6 @@ void UPoolFactory_UObject::RequestSpawn_Implementation(const FSpawnRequest& Requ
}
}

// Method to immediately spawn requested object
UObject* UPoolFactory_UObject::SpawnNow_Implementation(const FSpawnRequest& Request)
{
UObject* CreatedObject = NewObject<UObject>(GetOuter(), Request.Class);

FPoolObjectData PoolObjectData;
PoolObjectData.bIsActive = true;
PoolObjectData.PoolObject = CreatedObject;
PoolObjectData.Handle = Request.Handle;

if (Request.Callbacks.OnPreRegistered != nullptr)
{
Request.Callbacks.OnPreRegistered(PoolObjectData);
}

if (Request.Callbacks.OnPostSpawned != nullptr)
{
Request.Callbacks.OnPostSpawned(PoolObjectData);
}

return CreatedObject;
}

// Removes the first spawn request from the queue and returns it
bool UPoolFactory_UObject::DequeueSpawnRequest(FSpawnRequest& OutRequest)
{
Expand Down Expand Up @@ -90,6 +71,30 @@ bool UPoolFactory_UObject::DequeueSpawnRequestByHandle(const FPoolObjectHandle&
return OutRequest.IsValid();
}

// Method to immediately spawn requested object
UObject* UPoolFactory_UObject::SpawnNow_Implementation(const FSpawnRequest& Request)
{
return NewObject<UObject>(GetOuter(), Request.GetClassChecked());
}

// Notifies all listeners that the object is about to be spawned
void UPoolFactory_UObject::OnPreRegistered(const FSpawnRequest& Request, const FPoolObjectData& ObjectData)
{
if (Request.Callbacks.OnPreRegistered != nullptr)
{
Request.Callbacks.OnPreRegistered(ObjectData);
}
}

// Notifies all listeners that the object is spawned
void UPoolFactory_UObject::OnPostSpawned(const FSpawnRequest& Request, const FPoolObjectData& ObjectData)
{
if (Request.Callbacks.OnPostSpawned != nullptr)
{
Request.Callbacks.OnPostSpawned(ObjectData);
}
}

// Is called on next frame to process a chunk of the spawn queue
void UPoolFactory_UObject::OnNextTickProcessSpawn_Implementation()
{
Expand All @@ -104,7 +109,16 @@ void UPoolFactory_UObject::OnNextTickProcessSpawn_Implementation()
FSpawnRequest OutRequest;
if (DequeueSpawnRequest(OutRequest))
{
SpawnNow(OutRequest);
UObject* CreatedObject = SpawnNow(OutRequest);
checkf(CreatedObject, TEXT("ERROR: [%i] %hs:\n'CreatedObject' is failed to spawn!"), __LINE__, __FUNCTION__);

FPoolObjectData ObjectData;
ObjectData.bIsActive = true;
ObjectData.PoolObject = CreatedObject;
ObjectData.Handle = OutRequest.Handle;

OnPreRegistered(OutRequest, ObjectData);
OnPostSpawned(OutRequest, ObjectData);
}
}

Expand All @@ -118,6 +132,10 @@ void UPoolFactory_UObject::OnNextTickProcessSpawn_Implementation()
}
}

/*********************************************************************************************
* Destruction
********************************************************************************************* */

// Method to destroy given object
void UPoolFactory_UObject::Destroy_Implementation(UObject* Object)
{
Expand Down
8 changes: 7 additions & 1 deletion Source/PoolManager/Public/Factories/PoolFactory_Actor.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ class POOLMANAGER_API UPoolFactory_Actor : public UPoolFactory_UObject
{
GENERATED_BODY()

/*********************************************************************************************
* Setup overrides
********************************************************************************************* */
public:
/** Is overridden to handle Actors-inherited classes. */
virtual const UClass* GetObjectClass_Implementation() const override;
Expand All @@ -28,6 +31,9 @@ class POOLMANAGER_API UPoolFactory_Actor : public UPoolFactory_UObject
/** Is overridden to spawn actors using its engine's Spawn Actor method. */
virtual UObject* SpawnNow_Implementation(const FSpawnRequest& Request) override;

/** Is overridden to finish spawning the actor since it was deferred. */
virtual void OnPreRegistered(const FSpawnRequest& Request, const FPoolObjectData& ObjectData) override;

/*********************************************************************************************
* Destruction
********************************************************************************************* */
Expand All @@ -44,7 +50,7 @@ class POOLMANAGER_API UPoolFactory_Actor : public UPoolFactory_UObject

/** Is overridden to reset transform to the actor before returning the object to its pool. */
virtual void OnReturnToPool_Implementation(UObject* Object) override;

/** Is overridden to change visibility, collision, ticking, etc. according new state. */
virtual void OnChangedStateInPool_Implementation(EPoolObjectState NewState, UObject* InObject) override;
};
32 changes: 24 additions & 8 deletions Source/PoolManager/Public/Factories/PoolFactory_UObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,32 +25,38 @@ class POOLMANAGER_API UPoolFactory_UObject : public UObject
{
GENERATED_BODY()

/*********************************************************************************************
* Setup overrides
********************************************************************************************* */
public:
/** Returns the class of object that this factory will create and manage.
* Has to be overridden by child classes if it wants to handle logic for specific class and its children.
/** OVERRIDE by child class to return the class of an object that this factory will create and manage.
* E.g: UObject for UPoolFactory_UObject, AActor for UPoolFactory_Actor, UWidget for UPoolFactory_Widget etc. */
UFUNCTION(BlueprintNativeEvent, BlueprintPure, Category = "Pool Factory")
const UClass* GetObjectClass() const;
virtual FORCEINLINE const UClass* GetObjectClass_Implementation() const { return UObject::StaticClass(); }

/*********************************************************************************************
* Creation
* RequestSpawn -> DequeueSpawnRequest -> SpawnNow -> OnPreRegistered -> OnPostSpawned
********************************************************************************************* */
public:
/** Method to queue object spawn requests. */
/** Method to queue object spawn requests.
* Is called from UPoolManagerSubsystem::CreateNewObjectInPool. */
UFUNCTION(BlueprintNativeEvent, Blueprintable, Category = "Pool Factory", meta = (AutoCreateRefTerm = "Request"))
void RequestSpawn(const FSpawnRequest& Request);
virtual void RequestSpawn_Implementation(const FSpawnRequest& Request);

/** Method to immediately spawn requested object. */
/** Removes the first spawn request from the queue and returns it.
* Is called after 'RequestSpawn'. */
UFUNCTION(BlueprintCallable, Category = "Pool Factory")
virtual bool DequeueSpawnRequest(FSpawnRequest& OutRequest);

/** Method to immediately spawn requested object.
* Is called after 'DequeueSpawnRequest'. */
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Pool Factory", meta = (AutoCreateRefTerm = "Request"))
UObject* SpawnNow(const FSpawnRequest& Request);
virtual UObject* SpawnNow_Implementation(const FSpawnRequest& Request);

/** Removes the first spawn request from the queue and returns it. */
UFUNCTION(BlueprintCallable, Category = "Pool Factory")
virtual bool DequeueSpawnRequest(FSpawnRequest& OutRequest);

/** Alternative method to remove specific spawn request from the queue and returns it. */
UFUNCTION(BlueprintCallable, Category = "Pool Factory")
virtual bool DequeueSpawnRequestByHandle(const FPoolObjectHandle& Handle, FSpawnRequest& OutRequest);
Expand All @@ -59,6 +65,16 @@ class POOLMANAGER_API UPoolFactory_UObject : public UObject
UFUNCTION(BlueprintPure, Category = "Pool Factory")
virtual FORCEINLINE bool IsSpawnQueueEmpty() const { return SpawnQueueInternal.IsEmpty(); }

/** Is called right after object is spawned and before it is registered in the Pool.
* Is called after 'SpawnNow'. */
UFUNCTION(BlueprintCallable, Category = "C++")
virtual void OnPreRegistered(const FSpawnRequest& Request, const FPoolObjectData& ObjectData);

/** Is called right after object is spawned and registered in the Pool.
* Is called after 'OnPreRegistered'. */
UFUNCTION(BlueprintCallable, Category = "C++")
virtual void OnPostSpawned(const FSpawnRequest& Request, const FPoolObjectData& ObjectData);

protected:
/** Is called on next frame to process a chunk of the spawn queue. */
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Pool Factory", meta = (BlueprintProtected))
Expand Down
5 changes: 5 additions & 0 deletions Source/PoolManager/Public/PoolManagerTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "UObject/Object.h"
//---
#include "Misc/Guid.h"
#include "Templates/NonNullSubclassOf.h"
//---
#include "PoolManagerTypes.generated.h"

Expand Down Expand Up @@ -210,4 +211,8 @@ struct POOLMANAGER_API FSpawnRequest

/** Returns true if this spawn request can be processed. */
FORCEINLINE bool IsValid() const { return Class && Handle.IsValid(); }

/** Returns requested class or crashes if it is not set or can't be casted to the specified type. */
template <typename T = UObject>
FORCEINLINE TNonNullSubclassOf<T> GetClassChecked() const { return TNonNullSubclassOf<T>(const_cast<UClass*>(Class.Get())); }
};

0 comments on commit ddcb3c4

Please sign in to comment.