code
This commit is contained in:
750
Plugins/ObjectPool/Source/OBJPool/Private/OBJPool.cpp
Normal file
750
Plugins/ObjectPool/Source/OBJPool/Private/OBJPool.cpp
Normal file
@ -0,0 +1,750 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////
|
||||
/// Copyright 2019 (C) Bruno Xavier B. Leite
|
||||
//////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "OBJPool.h"
|
||||
#include "OBJPool_Shared.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Object Pool Component Functions
|
||||
|
||||
UObjectPool::UObjectPool(const FObjectInitializer &OBJ) : Super(OBJ) {
|
||||
TemplateClass = APooledActor::StaticClass();
|
||||
SetComponentTickEnabled(false);
|
||||
SetActive(true,false);
|
||||
//
|
||||
bWantsInitializeComponent = true;
|
||||
NeverFailDeferredSpawn = false;
|
||||
KeepOrphanActorsAlive = false;
|
||||
ReinitializeInstances = true;
|
||||
InstantiateOnDemand = false;
|
||||
AutoInitialize = true;
|
||||
}
|
||||
|
||||
void UObjectPool::BeginPlay() {
|
||||
Super::BeginPlay();
|
||||
//
|
||||
if (AutoInitialize) {InitializeObjectPool();}
|
||||
}
|
||||
|
||||
void UObjectPool::EndPlay(const EEndPlayReason::Type EndPlayReason) {
|
||||
if (!KeepOrphanActorsAlive) {EmptyObjectPool();}
|
||||
else {
|
||||
for (int32 ID = Pool.Num()-1; ID>=0; --ID) {
|
||||
if (Pool[ID]->Spawned) {continue;}
|
||||
Pool[ID]->Destroy(true,true);
|
||||
}
|
||||
}
|
||||
//
|
||||
Super::EndPlay(EndPlayReason);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void UObjectPool::InitializeObjectPool() {
|
||||
if (TemplateClass==nullptr) {
|
||||
LOG_OBJ(true,5.f,FColor::Red,GetNameSafe(this)+FString(" : ")+FString("Invalid Template Class!"));
|
||||
return;} EmptyObjectPool();
|
||||
//
|
||||
FTransform SpawnTransform(FRotator::ZeroRotator,FVector::ZeroVector,FVector(1.f,1.f,1.f));
|
||||
for (int32 I=0; I<PoolSize; I++) {
|
||||
const auto &ACT = GetWorld()->SpawnActorDeferred<APooledActor>(TemplateClass,SpawnTransform,this->GetOwner(),GetOwner()->GetInstigator(),ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn);
|
||||
if (ACT) {
|
||||
ACT->SharedPool = nullptr;
|
||||
ACT->OwningPool = const_cast<UObjectPool*>(this);
|
||||
ACT->FinishSpawning(SpawnTransform);
|
||||
ACT->Initialize();}}
|
||||
//
|
||||
FlushObjectPool();
|
||||
}
|
||||
|
||||
void UObjectPool::InitializeObjectPoolWithNewTemplateClass(const TSubclassOf<APooledActor> Template, const int32 SizeOfPool) {
|
||||
TemplateClass = Template;
|
||||
PoolSize = SizeOfPool;
|
||||
//
|
||||
InitializeObjectPool();
|
||||
}
|
||||
|
||||
void UObjectPool::FlushObjectPool() {
|
||||
if (!Pool.IsValidIndex(0)) {return;}
|
||||
//
|
||||
for (int32 ID = Pool.Num()-1; ID>=0; --ID) {
|
||||
if (!IsValid(Pool[ID])) {Pool.RemoveAt(ID,1,false);}
|
||||
}
|
||||
}
|
||||
|
||||
void UObjectPool::EmptyObjectPool() {
|
||||
if (!Pool.IsValidIndex(0)) {return;}
|
||||
//
|
||||
for (int32 ID = Pool.Num()-1; ID>=0; --ID) {
|
||||
if (Pool[ID]->IsValidLowLevelFast()) {Pool[ID]->Destroy(true,true);}
|
||||
} Pool.Empty();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
APooledActor* UObjectPool::BeginDeferredSpawnFromPool(const UObject* WorldContextObject, UObjectPool* ObjectPool, UClass* PooledClass, const FPoolSpawnOptions &SpawnOptions, const FTransform &SpawnTransform, ESpawnActorCollisionHandlingMethod CollisionHandlingOverride, AActor* Owner, const bool Reconstruct, bool &SpawnSuccessful) {
|
||||
if (!IsValid(ObjectPool)||ObjectPool->GetOwner()==nullptr||PooledClass==nullptr) {return nullptr;}
|
||||
//
|
||||
if (ObjectPool->TemplateClass.Get() != PooledClass) {
|
||||
LOG_OBJ(true,5.f,FColor::Red,ObjectPool->GetName()+FString(" : ")+FString::Printf(TEXT("Requested Class(%s) not implemented by this Pool. Check the value of 'Template Class' on the Pool Component."),*PooledClass->GetName()));
|
||||
return nullptr;}
|
||||
//
|
||||
if (ObjectPool->Pool.Num()==0) {ObjectPool->InitializeObjectPool();}
|
||||
APooledActor* DeferredSpawn = ObjectPool->GetInactiveObject();
|
||||
//
|
||||
if ((DeferredSpawn==nullptr) && ObjectPool->InstantiateOnDemand) {
|
||||
DeferredSpawn = ObjectPool->GetWorld()->SpawnActorDeferred<APooledActor>(ObjectPool->TemplateClass,SpawnTransform,Owner,ObjectPool->GetOwner()->GetInstigator(),CollisionHandlingOverride);
|
||||
if (DeferredSpawn) {DeferredSpawn->SharedPool = nullptr; DeferredSpawn->OwningPool = ObjectPool; DeferredSpawn->FinishSpawning(SpawnTransform);}
|
||||
} else if (DeferredSpawn==nullptr && ObjectPool->NeverFailDeferredSpawn) {
|
||||
DeferredSpawn = ObjectPool->GetSpawnedObject();
|
||||
if (DeferredSpawn!=nullptr) {DeferredSpawn->ReturnToPool();}
|
||||
} ObjectPool->FlushObjectPool();
|
||||
//
|
||||
if (DeferredSpawn!=nullptr) {
|
||||
const APawn* Instigator = Cast<APawn>(WorldContextObject);
|
||||
if (Instigator==nullptr) { if (const AActor* ContextActor = Cast<AActor>(WorldContextObject)) {Instigator=ContextActor->GetInstigator();} }
|
||||
if (Instigator!=nullptr) {DeferredSpawn->SetInstigator(const_cast<APawn*>(Instigator));}
|
||||
//
|
||||
DeferredSpawn->OwningPool = ObjectPool;
|
||||
DeferredSpawn->SharedPool = nullptr;
|
||||
DeferredSpawn->SetOwner(Owner);
|
||||
DeferredSpawn->Initialize();
|
||||
//
|
||||
DeferredSpawn->SpawnFromPool(Reconstruct,SpawnOptions,SpawnTransform);
|
||||
SpawnSuccessful = DeferredSpawn->Spawned;
|
||||
} else {
|
||||
SpawnSuccessful = false;
|
||||
DeferredSpawn = ObjectPool->GetSpawnedObject();
|
||||
} return DeferredSpawn;
|
||||
}
|
||||
|
||||
APooledActor* UObjectPool::FinishDeferredSpawnFromPool(APooledActor* Actor, const bool Reconstruct, const FTransform &SpawnTransform) {
|
||||
if (IsValid(Actor)&&(!Actor->IsActorInitialized())) {
|
||||
Actor->FinishSpawning(SpawnTransform);
|
||||
} if (IsValid(Actor)) {
|
||||
Actor->FinishSpawnFromPool(Reconstruct,SpawnTransform);
|
||||
} return Actor;
|
||||
}
|
||||
|
||||
void UObjectPool::ReturnActor(APooledActor* PooledActor) {
|
||||
if (!GetOwner()->IsValidLowLevelFast()||!IsValid(this)) {PooledActor->Destroy(true,true); return;}
|
||||
if (!IsValid(PooledActor)) {PooledActor->Destroy(true,true); return;}
|
||||
//
|
||||
if (TemplateClass.Get()==nullptr) {return;}
|
||||
if (PooledActor->GetClass()->IsChildOf(TemplateClass->GetDefaultObject()->GetClass())) {
|
||||
if (!Pool.Contains(PooledActor)) {
|
||||
PooledActor->SetActorLocation(GetOwner()->GetActorLocation());
|
||||
Pool.Add(PooledActor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void UObjectPool::GetObjectsFromPool(TArray<APooledActor*> &Spawned, TArray<APooledActor*> &Inactive) {
|
||||
for (const auto &OBJ : Pool) {
|
||||
if (!IsValid(OBJ)) {continue;}
|
||||
if (OBJ->Spawned) {Spawned.Add(OBJ);} else {Inactive.Add(OBJ);}}
|
||||
}
|
||||
|
||||
void UObjectPool::GetSpawnedObjects(TArray<APooledActor*> &Spawned) {
|
||||
for (const auto &OBJ : Pool) {
|
||||
if (!IsValid(OBJ)) {continue;}
|
||||
if (OBJ->Spawned) {Spawned.Add(OBJ);}}
|
||||
}
|
||||
|
||||
void UObjectPool::GetInactiveObjects(TArray<APooledActor*> &Inactive) {
|
||||
for (const auto &OBJ : Pool) {
|
||||
if (!IsValid(OBJ)) {continue;}
|
||||
if (!OBJ->Spawned) {Inactive.Add(OBJ);}}
|
||||
}
|
||||
|
||||
APooledActor* UObjectPool::GetSpawnedObject() const {
|
||||
for (int32 ID=0; ID < Pool.Num(); ++ID) {
|
||||
if (!IsValid(Pool[ID])) {continue;}
|
||||
if (Pool[ID]->Spawned) {return Pool[ID];}}
|
||||
//
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
APooledActor* UObjectPool::GetInactiveObject() const {
|
||||
for (int32 ID=0; ID < Pool.Num(); ++ID) {
|
||||
if (!IsValid(Pool[ID])) {continue;}
|
||||
if (!Pool[ID]->Spawned) {return Pool[ID];}}
|
||||
//
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Pawn Pool Component Functions
|
||||
|
||||
UPawnPool::UPawnPool(const FObjectInitializer &OBJ) : Super(OBJ) {
|
||||
TemplateClass = APooledPawn::StaticClass();
|
||||
SetComponentTickEnabled(false);
|
||||
SetActive(true,false);
|
||||
//
|
||||
bWantsInitializeComponent = true;
|
||||
NeverFailDeferredSpawn = false;
|
||||
KeepOrphanActorsAlive = false;
|
||||
ReinitializeInstances = true;
|
||||
InstantiateOnDemand = false;
|
||||
AutoInitialize = true;
|
||||
}
|
||||
|
||||
void UPawnPool::BeginPlay() {
|
||||
Super::BeginPlay();
|
||||
//
|
||||
if (AutoInitialize) {InitializeObjectPool();}
|
||||
}
|
||||
|
||||
void UPawnPool::EndPlay(const EEndPlayReason::Type EndPlayReason) {
|
||||
if (!KeepOrphanActorsAlive) {EmptyObjectPool();}
|
||||
else {
|
||||
for (int32 ID = Pool.Num()-1; ID>=0; --ID) {
|
||||
if (Pool[ID]->Spawned) {continue;}
|
||||
Pool[ID]->Destroy(true,true);
|
||||
}
|
||||
}
|
||||
//
|
||||
Super::EndPlay(EndPlayReason);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void UPawnPool::InitializeObjectPool() {
|
||||
if (TemplateClass==nullptr) {
|
||||
LOG_OBJ(true,5.f,FColor::Red,GetNameSafe(this)+FString(" : ")+FString("Invalid Template Class!"));
|
||||
return;} EmptyObjectPool();
|
||||
//
|
||||
FTransform SpawnTransform(FRotator::ZeroRotator,FVector::ZeroVector,FVector(1.f,1.f,1.f));
|
||||
for (int32 I=0; I<PoolSize; I++) {
|
||||
const auto &ACT = GetWorld()->SpawnActorDeferred<APooledPawn>(TemplateClass,SpawnTransform,this->GetOwner(),GetOwner()->GetInstigator(),ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn);
|
||||
if (ACT) {
|
||||
ACT->OwningPool = const_cast<UPawnPool*>(this);
|
||||
ACT->FinishSpawning(SpawnTransform);
|
||||
ACT->Initialize();}}
|
||||
}
|
||||
|
||||
void UPawnPool::InitializeObjectPoolWithNewTemplateClass(const TSubclassOf<APooledPawn> Template, const int32 SizeOfPool) {
|
||||
TemplateClass = Template;
|
||||
PoolSize = SizeOfPool;
|
||||
//
|
||||
InitializeObjectPool();
|
||||
}
|
||||
|
||||
void UPawnPool::FlushObjectPool() {
|
||||
if (!Pool.IsValidIndex(0)) {return;}
|
||||
//
|
||||
for (int32 ID = Pool.Num()-1; ID>=0; --ID) {
|
||||
if (!IsValid(Pool[ID])) {Pool.RemoveAt(ID,1,false);}
|
||||
}
|
||||
}
|
||||
|
||||
void UPawnPool::EmptyObjectPool() {
|
||||
if (!Pool.IsValidIndex(0)) {return;}
|
||||
//
|
||||
for (int32 ID = Pool.Num()-1; ID>=0; --ID) {
|
||||
if (IsValid(Pool[ID])) {Pool[ID]->Destroy(true,true);}
|
||||
} Pool.Empty();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
APooledPawn* UPawnPool::BeginDeferredSpawnFromPool(const UObject* WorldContextObject, UPawnPool* ObjectPool, UClass* PooledClass, const FPoolSpawnOptions &SpawnOptions, const FTransform &SpawnTransform, ESpawnActorCollisionHandlingMethod CollisionHandlingOverride, AActor* Owner, const bool Reconstruct, bool &SpawnSuccessful) {
|
||||
if (!IsValid(ObjectPool)||ObjectPool->GetOwner()==nullptr||PooledClass==nullptr) {return nullptr;}
|
||||
//
|
||||
if (ObjectPool->TemplateClass.Get() != PooledClass) {
|
||||
LOG_OBJ(true,5.f,FColor::Red,ObjectPool->GetName()+FString(" : ")+FString::Printf(TEXT("Requested Class(%s) not implemented by this Pool. Check the value of 'Template Class' on the Pool Component."),*PooledClass->GetName()));
|
||||
return nullptr;}
|
||||
//
|
||||
if (ObjectPool->Pool.Num()==0) {ObjectPool->InitializeObjectPool();}
|
||||
APooledPawn* DeferredSpawn = ObjectPool->GetInactiveObject();
|
||||
//
|
||||
if ((DeferredSpawn==nullptr) && ObjectPool->InstantiateOnDemand) {
|
||||
DeferredSpawn = ObjectPool->GetWorld()->SpawnActorDeferred<APooledPawn>(ObjectPool->TemplateClass,SpawnTransform,Owner,ObjectPool->GetOwner()->GetInstigator(),CollisionHandlingOverride);
|
||||
if (DeferredSpawn) {DeferredSpawn->OwningPool = ObjectPool; DeferredSpawn->FinishSpawning(SpawnTransform);}
|
||||
} else if (DeferredSpawn==nullptr && ObjectPool->NeverFailDeferredSpawn) {
|
||||
DeferredSpawn = ObjectPool->GetSpawnedObject();
|
||||
if (DeferredSpawn!=nullptr) {DeferredSpawn->ReturnToPool();}
|
||||
} ObjectPool->FlushObjectPool();
|
||||
//
|
||||
if (DeferredSpawn!=nullptr) {
|
||||
const APawn* Instigator = Cast<APawn>(WorldContextObject);
|
||||
if (Instigator==nullptr) { if (const AActor* ContextActor = Cast<AActor>(WorldContextObject)) {Instigator=ContextActor->GetInstigator();} }
|
||||
if (Instigator!=nullptr) {DeferredSpawn->SetInstigator(const_cast<APawn*>(Instigator));}
|
||||
//
|
||||
DeferredSpawn->OwningPool = ObjectPool;
|
||||
DeferredSpawn->SetOwner(Owner);
|
||||
DeferredSpawn->Initialize();
|
||||
//
|
||||
DeferredSpawn->SpawnFromPool(Reconstruct,SpawnOptions,SpawnTransform);
|
||||
SpawnSuccessful = DeferredSpawn->Spawned;
|
||||
} else {
|
||||
SpawnSuccessful = false;
|
||||
DeferredSpawn = ObjectPool->GetSpawnedObject();
|
||||
} return DeferredSpawn;
|
||||
}
|
||||
|
||||
APooledPawn* UPawnPool::FinishDeferredSpawnFromPool(APooledPawn* Pawn, const bool Reconstruct, const FTransform &SpawnTransform) {
|
||||
if (IsValid(Pawn)&&(!Pawn->IsActorInitialized())) {
|
||||
Pawn->FinishSpawning(SpawnTransform);
|
||||
} if (IsValid(Pawn)) {
|
||||
Pawn->FinishSpawnFromPool(Reconstruct,SpawnTransform);
|
||||
} return Pawn;
|
||||
}
|
||||
|
||||
void UPawnPool::ReturnActor(APooledPawn* PooledActor) {
|
||||
if (!IsValid(GetOwner())||!IsValid(this)) {PooledActor->Destroy(true,true); return;}
|
||||
if (!IsValid(PooledActor)) {PooledActor->Destroy(true,true); return;}
|
||||
//
|
||||
if (TemplateClass.Get()==nullptr) {return;}
|
||||
if (PooledActor->GetClass()->IsChildOf(TemplateClass->GetDefaultObject()->GetClass())) {
|
||||
if (!Pool.Contains(PooledActor)) {
|
||||
PooledActor->SetActorLocation(GetOwner()->GetActorLocation());
|
||||
Pool.Add(PooledActor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void UPawnPool::GetObjectsFromPool(TArray<APooledPawn*> &Spawned, TArray<APooledPawn*> &Inactive) {
|
||||
for (const auto &OBJ : Pool) {
|
||||
if (!IsValid(OBJ)) {continue;}
|
||||
if (OBJ->Spawned) {Spawned.Add(OBJ);} else {Inactive.Add(OBJ);}}
|
||||
}
|
||||
|
||||
void UPawnPool::GetSpawnedObjects(TArray<APooledPawn*> &Spawned) {
|
||||
for (const auto &OBJ : Pool) {
|
||||
if (!IsValid(OBJ)) {continue;}
|
||||
if (OBJ->Spawned) {Spawned.Add(OBJ);}}
|
||||
}
|
||||
|
||||
void UPawnPool::GetInactiveObjects(TArray<APooledPawn*> &Inactive) {
|
||||
for (const auto &OBJ : Pool) {
|
||||
if (!IsValid(OBJ)) {continue;}
|
||||
if (!OBJ->Spawned) {Inactive.Add(OBJ);}}
|
||||
}
|
||||
|
||||
APooledPawn* UPawnPool::GetSpawnedObject() const {
|
||||
for (int32 ID=0; ID < Pool.Num(); ++ID) {
|
||||
if (!IsValid(Pool[ID])) {continue;}
|
||||
if (Pool[ID]->Spawned) {return Pool[ID];}}
|
||||
//
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
APooledPawn* UPawnPool::GetInactiveObject() const {
|
||||
for (int32 ID=0; ID < Pool.Num(); ++ID) {
|
||||
if (!IsValid(Pool[ID])) {continue;}
|
||||
if (!Pool[ID]->Spawned) {return Pool[ID];}}
|
||||
//
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Character Pool Component Functions
|
||||
|
||||
UCharacterPool::UCharacterPool(const FObjectInitializer &OBJ) : Super(OBJ) {
|
||||
TemplateClass = APooledCharacter::StaticClass();
|
||||
SetComponentTickEnabled(false);
|
||||
SetActive(true,false);
|
||||
//
|
||||
bWantsInitializeComponent = true;
|
||||
NeverFailDeferredSpawn = false;
|
||||
KeepOrphanActorsAlive = false;
|
||||
ReinitializeInstances = true;
|
||||
InstantiateOnDemand = false;
|
||||
AutoInitialize = true;
|
||||
}
|
||||
|
||||
void UCharacterPool::BeginPlay() {
|
||||
Super::BeginPlay();
|
||||
//
|
||||
if (AutoInitialize) {InitializeObjectPool();}
|
||||
}
|
||||
|
||||
void UCharacterPool::EndPlay(const EEndPlayReason::Type EndPlayReason) {
|
||||
if (!KeepOrphanActorsAlive) {EmptyObjectPool();}
|
||||
else {
|
||||
for (int32 ID = Pool.Num()-1; ID>=0; --ID) {
|
||||
if (Pool[ID]->Spawned) {continue;}
|
||||
Pool[ID]->Destroy(true,true);
|
||||
}
|
||||
}
|
||||
//
|
||||
Super::EndPlay(EndPlayReason);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void UCharacterPool::InitializeObjectPool() {
|
||||
if (TemplateClass==nullptr) {
|
||||
LOG_OBJ(true,5.f,FColor::Red,GetNameSafe(this)+FString(" : ")+FString("Invalid Template Class!"));
|
||||
return;} EmptyObjectPool();
|
||||
//
|
||||
FTransform SpawnTransform(FRotator::ZeroRotator,FVector::ZeroVector,FVector(1.f,1.f,1.f));
|
||||
for (int32 I=0; I<PoolSize; I++) {
|
||||
const auto &ACT = GetWorld()->SpawnActorDeferred<APooledCharacter>(TemplateClass,SpawnTransform,this->GetOwner(),GetOwner()->GetInstigator(),ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn);
|
||||
if (ACT) {
|
||||
ACT->OwningPool = const_cast<UCharacterPool*>(this);
|
||||
ACT->FinishSpawning(SpawnTransform);
|
||||
ACT->Initialize();}}
|
||||
}
|
||||
|
||||
void UCharacterPool::InitializeObjectPoolWithNewTemplateClass(const TSubclassOf<APooledCharacter> Template, const int32 SizeOfPool) {
|
||||
TemplateClass = Template;
|
||||
PoolSize = SizeOfPool;
|
||||
//
|
||||
InitializeObjectPool();
|
||||
}
|
||||
|
||||
void UCharacterPool::FlushObjectPool() {
|
||||
if (!Pool.IsValidIndex(0)) {return;}
|
||||
//
|
||||
for (int32 ID = Pool.Num()-1; ID>=0; --ID) {
|
||||
if (!IsValid(Pool[ID])) {Pool.RemoveAt(ID,1,false);}
|
||||
}
|
||||
}
|
||||
|
||||
void UCharacterPool::EmptyObjectPool() {
|
||||
if (!Pool.IsValidIndex(0)) {return;}
|
||||
//
|
||||
for (int32 ID = Pool.Num()-1; ID>=0; --ID) {
|
||||
if (Pool[ID]->IsValidLowLevelFast()) {Pool[ID]->Destroy(true,true);}
|
||||
} Pool.Empty();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
APooledCharacter* UCharacterPool::BeginDeferredSpawnFromPool(const UObject* WorldContextObject, UCharacterPool* ObjectPool, UClass* PooledClass, const FPoolSpawnOptions &SpawnOptions, const FTransform &SpawnTransform, ESpawnActorCollisionHandlingMethod CollisionHandlingOverride, AActor* Owner, const bool Reconstruct, bool &SpawnSuccessful) {
|
||||
if (!IsValid(ObjectPool)||ObjectPool->GetOwner()==nullptr||PooledClass==nullptr) {return nullptr;}
|
||||
//
|
||||
if (ObjectPool->TemplateClass.Get() != PooledClass) {
|
||||
LOG_OBJ(true,5.f,FColor::Red,ObjectPool->GetName()+FString(" : ")+FString::Printf(TEXT("Requested Class(%s) not implemented by this Pool. Check the value of 'Template Class' on the Pool Component."),*PooledClass->GetName()));
|
||||
return nullptr;}
|
||||
//
|
||||
if (ObjectPool->Pool.Num()==0) {ObjectPool->InitializeObjectPool();}
|
||||
APooledCharacter* DeferredSpawn = ObjectPool->GetInactiveObject();
|
||||
//
|
||||
if ((DeferredSpawn==nullptr) && ObjectPool->InstantiateOnDemand) {
|
||||
DeferredSpawn = ObjectPool->GetWorld()->SpawnActorDeferred<APooledCharacter>(ObjectPool->TemplateClass,SpawnTransform,Owner,ObjectPool->GetOwner()->GetInstigator(),CollisionHandlingOverride);
|
||||
if (DeferredSpawn) {DeferredSpawn->OwningPool = ObjectPool; DeferredSpawn->FinishSpawning(SpawnTransform);}
|
||||
} else if (DeferredSpawn==nullptr && ObjectPool->NeverFailDeferredSpawn) {
|
||||
DeferredSpawn = ObjectPool->GetSpawnedObject();
|
||||
if (DeferredSpawn!=nullptr) {DeferredSpawn->ReturnToPool();}
|
||||
} ObjectPool->FlushObjectPool();
|
||||
//
|
||||
if (DeferredSpawn!=nullptr) {
|
||||
const APawn* Instigator = Cast<APawn>(WorldContextObject);
|
||||
if (Instigator==nullptr) { if (const AActor* ContextActor = Cast<AActor>(WorldContextObject)) {Instigator=ContextActor->GetInstigator();} }
|
||||
if (Instigator!=nullptr) {DeferredSpawn->SetInstigator(const_cast<APawn*>(Instigator));}
|
||||
//
|
||||
DeferredSpawn->OwningPool = ObjectPool;
|
||||
DeferredSpawn->SetOwner(Owner);
|
||||
DeferredSpawn->Initialize();
|
||||
//
|
||||
DeferredSpawn->SpawnFromPool(Reconstruct,SpawnOptions,SpawnTransform);
|
||||
SpawnSuccessful = DeferredSpawn->Spawned;
|
||||
} else {
|
||||
SpawnSuccessful = false;
|
||||
DeferredSpawn = ObjectPool->GetSpawnedObject();
|
||||
} return DeferredSpawn;
|
||||
}
|
||||
|
||||
APooledCharacter* UCharacterPool::FinishDeferredSpawnFromPool(APooledCharacter* Character, const bool Reconstruct, const FTransform &SpawnTransform) {
|
||||
if (IsValid(Character)&&(!Character->IsActorInitialized())) {
|
||||
Character->FinishSpawning(SpawnTransform);
|
||||
} if (IsValid(Character)) {
|
||||
Character->FinishSpawnFromPool(Reconstruct,SpawnTransform);
|
||||
} return Character;
|
||||
}
|
||||
|
||||
void UCharacterPool::ReturnActor(APooledCharacter* PooledActor) {
|
||||
if (!IsValid(GetOwner())||!IsValid(this)) {PooledActor->Destroy(true,true); return;}
|
||||
if (!IsValid(PooledActor)) {PooledActor->Destroy(true,true); return;}
|
||||
//
|
||||
if (TemplateClass.Get()==nullptr) {return;}
|
||||
if (PooledActor->GetClass()->IsChildOf(TemplateClass->GetDefaultObject()->GetClass())) {
|
||||
if (!Pool.Contains(PooledActor)) {
|
||||
PooledActor->SetActorLocation(GetOwner()->GetActorLocation());
|
||||
Pool.Add(PooledActor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void UCharacterPool::GetObjectsFromPool(TArray<APooledCharacter*> &Spawned, TArray<APooledCharacter*> &Inactive) {
|
||||
for (const auto &OBJ : Pool) {
|
||||
if (!IsValid(OBJ)) {continue;}
|
||||
if (OBJ->Spawned) {Spawned.Add(OBJ);} else {Inactive.Add(OBJ);}}
|
||||
}
|
||||
|
||||
void UCharacterPool::GetSpawnedObjects(TArray<APooledCharacter*> &Spawned) {
|
||||
for (const auto &OBJ : Pool) {
|
||||
if (!IsValid(OBJ)) {continue;}
|
||||
if (OBJ->Spawned) {Spawned.Add(OBJ);}}
|
||||
}
|
||||
|
||||
void UCharacterPool::GetInactiveObjects(TArray<APooledCharacter*> &Inactive) {
|
||||
for (const auto &OBJ : Pool) {
|
||||
if (!IsValid(OBJ)) {continue;}
|
||||
if (!OBJ->Spawned) {Inactive.Add(OBJ);}}
|
||||
}
|
||||
|
||||
APooledCharacter* UCharacterPool::GetSpawnedObject() const {
|
||||
for (int32 ID=0; ID < Pool.Num(); ++ID) {
|
||||
if (!IsValid(Pool[ID])) {continue;}
|
||||
if (Pool[ID]->Spawned) {return Pool[ID];}}
|
||||
//
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
APooledCharacter* UCharacterPool::GetInactiveObject() const {
|
||||
for (int32 ID=0; ID < Pool.Num(); ++ID) {
|
||||
if (!IsValid(Pool[ID])) {continue;}
|
||||
if (!Pool[ID]->Spawned) {return Pool[ID];}}
|
||||
//
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Shared Object Pool Component Functions
|
||||
|
||||
USharedObjectPool::USharedObjectPool(const FObjectInitializer &OBJ) : Super(OBJ) {
|
||||
SetComponentTickEnabled(false);
|
||||
SetActive(true,false);
|
||||
//
|
||||
bWantsInitializeComponent = true;
|
||||
NeverFailDeferredSpawn = false;
|
||||
KeepOrphanActorsAlive = false;
|
||||
ReinitializeInstances = true;
|
||||
InstantiateOnDemand = false;
|
||||
AutoInitialize = true;
|
||||
}
|
||||
|
||||
void USharedObjectPool::PostInitProperties() {
|
||||
Super::PostInitProperties();
|
||||
}
|
||||
|
||||
void USharedObjectPool::BeginPlay() {
|
||||
Super::BeginPlay();
|
||||
//
|
||||
if (AutoInitialize) {InitializeObjectPool();}
|
||||
}
|
||||
|
||||
void USharedObjectPool::EndPlay(const EEndPlayReason::Type EndPlayReason) {
|
||||
if (!KeepOrphanActorsAlive) {
|
||||
EmptyObjectPool(APooledActor::StaticClass());
|
||||
} else {
|
||||
for (int32 ID = Pool.Num()-1; ID>=0; --ID) {
|
||||
if (Pool[ID]->Spawned) {continue;}
|
||||
Pool[ID]->Destroy(true,true);
|
||||
}
|
||||
}
|
||||
//
|
||||
Super::EndPlay(EndPlayReason);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void USharedObjectPool::InitializeObjectPool() {
|
||||
if (TemplateClasses.Num()<=0) {
|
||||
LOG_OBJ(true,5.f,FColor::Red,GetNameSafe(this)+FString(" : ")+FString("Invalid Template Classes!"));
|
||||
return;} EmptyObjectPool(APooledActor::StaticClass());
|
||||
//
|
||||
FTransform SpawnTransform(FRotator::ZeroRotator,FVector::ZeroVector,FVector(1.f,1.f,1.f));
|
||||
TArray<TSubclassOf<APooledActor>>Classes;
|
||||
TemplateClasses.GenerateKeyArray(Classes);
|
||||
//
|
||||
for (const TSubclassOf<APooledActor>Class : Classes) {
|
||||
if (Class.Get()==nullptr) {continue;}
|
||||
int32 PoolSize = TemplateClasses.FindRef(Class);
|
||||
//
|
||||
for (int32 I=0; I<PoolSize; I++) {
|
||||
const auto &ACT = GetWorld()->SpawnActorDeferred<APooledActor>(Class,SpawnTransform,this->GetOwner(),GetOwner()->GetInstigator(),ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn);
|
||||
if (ACT) {
|
||||
ACT->OwningPool = nullptr;
|
||||
ACT->SharedPool = const_cast<USharedObjectPool*>(this);
|
||||
ACT->FinishSpawning(SpawnTransform);
|
||||
ACT->Initialize();}}
|
||||
}
|
||||
//
|
||||
FlushObjectPool();
|
||||
}
|
||||
|
||||
void USharedObjectPool::FlushObjectPool() {
|
||||
if (!Pool.IsValidIndex(0)) {return;}
|
||||
//
|
||||
for (int32 ID = Pool.Num()-1; ID>=0; --ID) {
|
||||
if (!IsValid(Pool[ID])) {Pool.RemoveAt(ID,1,false);}
|
||||
}
|
||||
}
|
||||
|
||||
void USharedObjectPool::EmptyObjectPool(const UClass* Class) {
|
||||
if (!Pool.IsValidIndex(0)) {return;}
|
||||
//
|
||||
for (int32 ID = Pool.Num()-1; ID>=0; --ID) {
|
||||
if (!Pool[ID]->IsA(Class)) {continue;}
|
||||
if (Pool[ID]->IsValidLowLevelFast()) {Pool[ID]->Destroy(true,true);}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void USharedObjectPool::GetObjectsFromPool(const UClass* Class, TArray<APooledActor*> &Spawned, TArray<APooledActor*> &Inactive) {
|
||||
for (const auto &OBJ : Pool) {
|
||||
if (!IsValid(OBJ)) {continue;}
|
||||
if (!OBJ->IsA(Class)) {continue;}
|
||||
//
|
||||
if (OBJ->Spawned) {Spawned.Add(OBJ);} else {Inactive.Add(OBJ);}
|
||||
}
|
||||
}
|
||||
|
||||
void USharedObjectPool::GetSpawnedObjects(const UClass* Class, TArray<APooledActor*> &Spawned) {
|
||||
for (const auto &OBJ : Pool) {
|
||||
if (!IsValid(OBJ)) {continue;}
|
||||
if (!OBJ->IsA(Class)) {continue;}
|
||||
//
|
||||
if (OBJ->Spawned) {Spawned.Add(OBJ);}
|
||||
}
|
||||
}
|
||||
|
||||
void USharedObjectPool::GetInactiveObjects(const UClass* Class, TArray<APooledActor*> &Inactive) {
|
||||
for (const auto &OBJ : Pool) {
|
||||
if (!IsValid(OBJ)) {continue;}
|
||||
if (!OBJ->IsA(Class)) {continue;}
|
||||
//
|
||||
if (!OBJ->Spawned) {Inactive.Add(OBJ);}
|
||||
}
|
||||
}
|
||||
|
||||
APooledActor* USharedObjectPool::GetSpawnedObject(const UClass* Class) const {
|
||||
for (int32 ID=0; ID < Pool.Num(); ++ID) {
|
||||
if (!IsValid(Pool[ID])) {continue;}
|
||||
if (!Pool[ID]->IsA(Class)) {continue;}
|
||||
//
|
||||
if (Pool[ID]->Spawned) {return Pool[ID];}
|
||||
}
|
||||
//
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
APooledActor* USharedObjectPool::GetInactiveObject(const UClass* Class) const {
|
||||
for (int32 ID = Pool.Num()-1; ID>=0; --ID) {
|
||||
if (!IsValid(Pool[ID])) {continue;}
|
||||
if (!Pool[ID]->IsA(Class)) {continue;}
|
||||
//
|
||||
if (!Pool[ID]->Spawned) {return Pool[ID];}
|
||||
}
|
||||
//
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
APooledActor* USharedObjectPool::BeginDeferredSpawnFromPool(const UObject* WorldContextObject, USharedObjectPool* SharedPool, UClass* Class, const FPoolSpawnOptions &SpawnOptions, const FTransform &SpawnTransform, ESpawnActorCollisionHandlingMethod CollisionHandlingOverride, AActor* Owner, const bool Reconstruct, bool &SpawnSuccessful) {
|
||||
if (!IsValid(SharedPool)||SharedPool->GetOwner()==nullptr) {
|
||||
UE_LOG(LogTemp,Warning,TEXT("{Pool}:: %s"),TEXT("Target Shared-Pool is about to be destroyed. Spawn aborted!"));
|
||||
return nullptr;}
|
||||
//
|
||||
//
|
||||
if (Class==nullptr) {
|
||||
UE_LOG(LogTemp,Warning,TEXT("{Begin Deferred Spawn from Pool}: Invalid Class."));
|
||||
return nullptr;}
|
||||
//
|
||||
bool IsTemplate = false;
|
||||
TArray<TSubclassOf<APooledActor>>Classes;
|
||||
SharedPool->TemplateClasses.GenerateKeyArray(Classes);
|
||||
//
|
||||
for (const TSubclassOf<APooledActor>TemplateClass : Classes) {
|
||||
if (Class==nullptr) {break;}
|
||||
if (TemplateClass.Get()==nullptr) {continue;}
|
||||
if (!Class->GetName().Equals(TemplateClass.Get()->GetName())) {continue;}
|
||||
//
|
||||
IsTemplate = true;
|
||||
if (SharedPool->TemplateClasses.FindChecked(TemplateClass)<=0) {
|
||||
UE_LOG(LogTemp,Warning,TEXT("{%s}:: %s (%s)"),*SharedPool->GetName(),TEXT("Target Class is zero-sized in Target Shared-Pool!"),*Class->GetName());
|
||||
break;}
|
||||
} if (!IsTemplate) {
|
||||
UE_LOG(LogTemp,Warning,TEXT("{%s}:: %s (%s)"),*SharedPool->GetName(),TEXT("This Shared-Pool does NOT implement Target Template Class. Spawn Aborted:"),*Class->GetName());
|
||||
return nullptr;}
|
||||
//
|
||||
//
|
||||
if (SharedPool->Pool.Num()==0) {SharedPool->InitializeObjectPool();}
|
||||
APooledActor* DeferredSpawn = SharedPool->GetInactiveObject(Class);
|
||||
//
|
||||
if ((DeferredSpawn==nullptr) && SharedPool->InstantiateOnDemand) {
|
||||
DeferredSpawn = SharedPool->GetWorld()->SpawnActorDeferred<APooledActor>(Class,SpawnTransform,Owner,SharedPool->GetOwner()->GetInstigator(),CollisionHandlingOverride);
|
||||
if (DeferredSpawn) {DeferredSpawn->SharedPool = SharedPool; DeferredSpawn->OwningPool = nullptr; DeferredSpawn->FinishSpawning(SpawnTransform);}
|
||||
} else if (DeferredSpawn==nullptr && SharedPool->NeverFailDeferredSpawn) {
|
||||
DeferredSpawn = SharedPool->GetSpawnedObject(Class);
|
||||
if (DeferredSpawn!=nullptr) {DeferredSpawn->ReturnToPool();}
|
||||
} SharedPool->FlushObjectPool();
|
||||
//
|
||||
if (DeferredSpawn!=nullptr) {
|
||||
const APawn* Instigator = Cast<APawn>(WorldContextObject);
|
||||
if (Instigator==nullptr) { if (const AActor* ContextActor = Cast<AActor>(WorldContextObject)) {Instigator = ContextActor->GetInstigator();} }
|
||||
if (Instigator!=nullptr) {DeferredSpawn->SetInstigator(const_cast<APawn*>(Instigator));}
|
||||
//
|
||||
DeferredSpawn->SharedPool = SharedPool;
|
||||
DeferredSpawn->OwningPool = nullptr;
|
||||
DeferredSpawn->SetOwner(Owner);
|
||||
DeferredSpawn->Initialize();
|
||||
//
|
||||
DeferredSpawn->SpawnFromPool(Reconstruct,SpawnOptions,SpawnTransform);
|
||||
SpawnSuccessful = DeferredSpawn->Spawned;
|
||||
} else {
|
||||
SpawnSuccessful = false;
|
||||
DeferredSpawn = SharedPool->GetSpawnedObject(Class);
|
||||
}
|
||||
//
|
||||
return DeferredSpawn;
|
||||
}
|
||||
|
||||
APooledActor* USharedObjectPool::FinishDeferredSpawnFromPool(APooledActor* Actor, const bool Reconstruct, const FTransform &SpawnTransform) {
|
||||
if (IsValid(Actor)&&(!Actor->IsActorInitialized())) {
|
||||
Actor->FinishSpawning(SpawnTransform);
|
||||
} if (IsValid(Actor)) {
|
||||
Actor->FinishSpawnFromPool(Reconstruct,SpawnTransform);
|
||||
} return Actor;
|
||||
}
|
||||
|
||||
void USharedObjectPool::ReturnActor(APooledActor* PooledActor) {
|
||||
if (!IsValid(GetOwner())||!IsValid(this)) {PooledActor->Destroy(true,true); return;}
|
||||
if (!IsValid(PooledActor)) {PooledActor->Destroy(true,true); return;}
|
||||
//
|
||||
TArray<TSubclassOf<APooledActor>>Classes;
|
||||
TemplateClasses.GenerateKeyArray(Classes);
|
||||
//
|
||||
for (const TSubclassOf<APooledActor>Class : Classes) {
|
||||
if (Class.Get()==nullptr) {continue;}
|
||||
//
|
||||
if (PooledActor->GetClass()->IsChildOf(Class->GetDefaultObject()->GetClass())) {
|
||||
if (!Pool.Contains(PooledActor)) {
|
||||
PooledActor->SetActorLocation(GetOwner()->GetActorLocation());
|
||||
Pool.Add(PooledActor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void LOG_OBJ(const bool Debug,const float Duration, const FColor Color, const FString Message) {
|
||||
if (!Debug) return; UE_LOG(LogTemp,Warning,TEXT("{Pool}:: %s"),*Message); if (!GEngine) {return;}
|
||||
GEngine->AddOnScreenDebugMessage(-1,Duration,Color,FString::Printf(TEXT("{Pool}:: %s"),*Message));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
Reference in New Issue
Block a user