#include "EBBullet.h" #include "EBBarrel.h" void AEBBullet::Deactivate() { //server only if (!HasAuthority()) { return; } OnDeactivated(); this->DeactivateToPool(); DeactivationBroadcast(); } AEBBullet* AEBBullet::GetFromPool(UWorld* World, UClass* BulletClass) { AEBBullet* Pool = Cast(BulletClass->GetDefaultObject()); if (Pool) { //find first of correct class; bool CleanupRequired=false; int32 FoundIndex = Pool->Pooled.IndexOfByPredicate( [&](auto InItem) { if (InItem.IsValid() && InItem->GetWorld() == World) { return true; } else { CleanupRequired = true; return false; } }); TWeakObjectPtr Found = nullptr; if (FoundIndex != INDEX_NONE) { Found = Pool->Pooled[FoundIndex]; Pool->Pooled.RemoveAtSwap(FoundIndex,EAllowShrinking::Yes); } if (CleanupRequired) { #ifdef WITH_EDITOR if (Pool->DebugPooling) { GEngine->AddOnScreenDebugMessage(2, 2, FColor::White, TEXT("Invalid reference in pool, cleaning up")); } #endif Pool->Pooled.RemoveAll([&](auto InItem) { if (InItem.IsValid() && InItem->GetWorld() == World) { return false; } else { return true; } }); } return(Found.Get()); } else { return nullptr; } } AEBBullet* AEBBullet::SpawnOrReactivate(UWorld* World, TSubclassOf BulletClass, const FTransform& Transform, FVector BulletVelocity, AActor* BulletOwner, APawn* BulletInstigator) { AEBBullet* bullet; AEBBullet* Recycled = GetFromPool(World, BulletClass); if (Recycled) { AEBBullet* Default = Cast(BulletClass->GetDefaultObject()); Recycled->Reset(); Recycled->SetOwner(BulletOwner); Recycled->SetInstigator(BulletInstigator); Recycled->SetActorTransform(Transform,false,nullptr,ETeleportType::TeleportPhysics); Recycled->Velocity = BulletVelocity; Recycled->SetActorHiddenInGame(Default->IsHidden()); Recycled->SetActorTickEnabled(true); Recycled->CanRetrace = false; Recycled->IgnoredActors = Default->IgnoredActors; Recycled->SafeDelay = Default->SafeDelay; Recycled->SetLifeSpan(Default->InitialLifeSpan); AEBBullet* FinishedBullet = Recycled->FinishSpawning(Transform); if (!FinishedBullet) { // If spawning failed, return nullptr return nullptr; } //if (!Recycled->HasActorBegunPlay()){ Recycled->BeginPlay(); } //Recycled->ReactivationBroadcast(UGameplayStatics::RebaseLocalOriginOntoZero(Recycled->GetWorld(), Transform.GetLocation()), BulletVelocity, BulletOwner, BulletInstigator); #ifdef WITH_EDITOR if (Recycled->DebugPooling) { GEngine->AddOnScreenDebugMessage(0, 2, FColor::Green, TEXT("Recycling pooled bullet")); } #endif return FinishedBullet; } else { bullet = Cast(World->SpawnActorDeferred(BulletClass, Transform, BulletOwner, BulletInstigator)); bullet->RandomStream.GenerateNewSeed(); bullet->Velocity = BulletVelocity; AEBBullet* FinishedBullet = bullet->FinishSpawning(Transform); if (!FinishedBullet) { // If spawning failed, return nullptr return nullptr; } //UGameplayStatics::FinishSpawningActor(bullet, Transform); #ifdef WITH_EDITOR if (bullet->DebugPooling) { GEngine->AddOnScreenDebugMessage(0, 2, FColor::Orange, TEXT("Spawning new bullet")); } #endif return FinishedBullet; } } AEBBullet* AEBBullet::SpawnOrReactivateFromBarrel(UWorld* World, TSubclassOf BulletClass, const FTransform& Transform, FVector BulletVelocity, AActor* BulletOwner, APawn* BulletInstigator, class UEBBarrel* SourceBarrel) { AEBBullet* bullet; AEBBullet* Recycled = GetFromPool(World, BulletClass); if (Recycled) { AEBBullet* Default = Cast(BulletClass->GetDefaultObject()); Recycled->Reset(); Recycled->SetOwner(BulletOwner); Recycled->SetInstigator(BulletInstigator); Recycled->SetActorTransform(Transform,false,nullptr,ETeleportType::TeleportPhysics); Recycled->Velocity = BulletVelocity; Recycled->SetFiringBarrel(SourceBarrel); Recycled->SetActorHiddenInGame(Default->IsHidden()); Recycled->SetActorTickEnabled(true); Recycled->CanRetrace = false; Recycled->IgnoredActors = Default->IgnoredActors; Recycled->SafeDelay = Default->SafeDelay; Recycled->SetLifeSpan(Default->InitialLifeSpan); AEBBullet* FinishedBullet = Recycled->FinishSpawning(Transform); if (!FinishedBullet) { // If spawning failed, return nullptr return nullptr; } //if (!Recycled->HasActorBegunPlay()){ Recycled->BeginPlay(); } //Recycled->ReactivationBroadcast(UGameplayStatics::RebaseLocalOriginOntoZero(Recycled->GetWorld(), Transform.GetLocation()), BulletVelocity, BulletOwner, BulletInstigator); #ifdef WITH_EDITOR if (Recycled->DebugPooling) { GEngine->AddOnScreenDebugMessage(0, 2, FColor::Green, TEXT("Recycling pooled bullet")); } #endif return FinishedBullet; } else { bullet = Cast(World->SpawnActorDeferred(BulletClass, Transform, BulletOwner, BulletInstigator)); bullet->RandomStream.GenerateNewSeed(); bullet->Velocity = BulletVelocity; bullet->SetFiringBarrel(SourceBarrel); AEBBullet* FinishedBullet = bullet->FinishSpawning(Transform); if (!FinishedBullet) { // If spawning failed, return nullptr return nullptr; } //UGameplayStatics::FinishSpawningActor(bullet, Transform); #ifdef WITH_EDITOR if (bullet->DebugPooling) { GEngine->AddOnScreenDebugMessage(0, 2, FColor::Orange, TEXT("Spawning new bullet")); } #endif return FinishedBullet; } } AEBBullet* AEBBullet::FinishSpawning(FTransform Transform) { if(IsRecycled){ if (!HasActorBegunPlay()){ BeginPlay(); } ReactivationBroadcast(UGameplayStatics::RebaseLocalOriginOntoZero(this->GetWorld(), Transform.GetLocation()), this->Velocity, this->GetOwner(), this->GetInstigator()); return this; }else{ AActor* FinishedActor = UGameplayStatics::FinishSpawningActor(this, Transform); return Cast(FinishedActor); } } void AEBBullet::ReactivationBroadcast_Implementation(FVector_NetQuantize NewLocation, FVector NewVelocity, AActor* BulletOwner, APawn* BulletInstigator) { if (!HasAuthority()) { AEBBullet* Default = Cast(this->StaticClass()->GetDefaultObject()); SetOwner(BulletOwner); SetInstigator(BulletInstigator); SetActorLocation(UGameplayStatics::RebaseZeroOriginOntoLocal(GetWorld(), NewLocation)); Velocity = NewVelocity; CanRetrace = false; SetActorHiddenInGame(Default->IsHidden()); SetActorTickEnabled(true); SafeDelay = Default->SafeDelay; OwnerSafe = Default->SafeLaunch; BeginPlay(); } } void AEBBullet::DeactivationBroadcast_Implementation() { if (!HasAuthority()) { OnDeactivated(); this->DeactivateToPool(); } } void AEBBullet::LifeSpanExpired() { Deactivate(); } void AEBBullet::DeactivateToPool() { AEBBullet* Pool = Cast(GetClass()->GetDefaultObject()); if (Pool && EnablePooling) { SetActorHiddenInGame(true); SetActorTickEnabled(false); Pool->Pooled.Add(this); EndPlay(EEndPlayReason::RemovedFromWorld); if (Pool->Pooled.Num() > MaxPoolSize) { AEBBullet* Oldest = (Pool->Pooled[0].Get()); Pool->Pooled.RemoveAtSwap(0,EAllowShrinking::Yes); if (Oldest) { Oldest->Destroy(); } } #ifdef WITH_EDITOR if (DebugPooling) { GEngine->AddOnScreenDebugMessage(2, 2, FColor::White, FString("Bullet pooled: ") + FString::FromInt(Pool->Pooled.Num())); } #endif } else { Destroy(); } }