Merge pull request #333 from carla-simulator/Optimizations
Optimizations
This commit is contained in:
commit
ca14d4c8ab
5
Makefile
5
Makefile
|
@ -35,6 +35,11 @@ vsproject: MY_CMAKE_FLAGS+=-DCMAKE_BUILD_TYPE=Release
|
|||
vsproject: MY_CMAKE_FLAGS+=-G "Visual Studio 14 2015 Win64"
|
||||
vsproject: call_cmake
|
||||
|
||||
vsproject15: BUILD_FOLDER=$(BASE_BUILD_FOLDER)/visualstudio
|
||||
vsproject15: MY_CMAKE_FLAGS+=-DCMAKE_BUILD_TYPE=Release
|
||||
vsproject15: MY_CMAKE_FLAGS+=-G "Visual Studio 15 2017 Win64"
|
||||
vsproject15: call_cmake
|
||||
|
||||
build_linux: MY_CMAKE_FLAGS+=-G "Ninja"
|
||||
build_linux: call_cmake
|
||||
@cd $(BUILD_FOLDER) && ninja && ninja install
|
||||
|
|
|
@ -8,7 +8,11 @@ rem FOR %%G IN (Binaries,Intermediate,Plugins\Carla\Binaries,Plugins\Carla\Inter
|
|||
|
||||
rem echo Making CarlaServer...
|
||||
rem call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64
|
||||
rem Visual Studio 2017 Enterprise:
|
||||
rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvarsall.bat"
|
||||
rem START /wait cmd.exe /k "cd Plugins\Carla & make clean default & pause & exit"
|
||||
|
||||
|
||||
|
||||
rem echo Launch editor...
|
||||
rem start CarlaUE4.uproject
|
||||
|
|
|
@ -97,4 +97,4 @@
|
|||
"Enabled": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,3 +77,5 @@ InitialAverageFrameRate=0.016667
|
|||
PhysXTreeRebuildRate=10
|
||||
|
||||
|
||||
[/Script/AIModule.CrowdManager]
|
||||
MaxAgents=1000
|
|
@ -16,7 +16,7 @@
|
|||
"Modules": [
|
||||
{
|
||||
"Name": "Carla",
|
||||
"Type": "Developer",
|
||||
"Type": "Runtime",
|
||||
"LoadingPhase": "PreDefault",
|
||||
"AdditionalDependencies": [
|
||||
"Engine"
|
||||
|
|
|
@ -8,14 +8,16 @@
|
|||
|
||||
#include "Carla.h"
|
||||
#include "AgentComponent.h"
|
||||
|
||||
#include "Engine/World.h"
|
||||
#include "Game/CarlaGameModeBase.h"
|
||||
#include "Game/DataRouter.h"
|
||||
#include "Engine/Engine.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
|
||||
static FDataRouter &GetDataRouter(UWorld *World)
|
||||
{
|
||||
check(World != nullptr);
|
||||
auto *GameMode = Cast<ACarlaGameModeBase>(World->GetAuthGameMode());
|
||||
ACarlaGameModeBase *GameMode = Cast<ACarlaGameModeBase>(World->GetAuthGameMode());
|
||||
check(GameMode != nullptr);
|
||||
return GameMode->GetDataRouter();
|
||||
}
|
||||
|
@ -40,7 +42,20 @@ void UAgentComponent::BeginPlay()
|
|||
|
||||
if (bRegisterAgentComponent)
|
||||
{
|
||||
GetDataRouter(GetWorld()).RegisterAgent(this);
|
||||
/**
|
||||
* This only returns true if the current game mode is not null
|
||||
* because you can only access a game mode if you are the host
|
||||
* @param oftheworld UWorld is needed to access the game mode
|
||||
* @return true if there is a game mode and it is not null
|
||||
*/
|
||||
if(UGameplayStatics::GetGameMode(GetWorld())!=nullptr)
|
||||
{
|
||||
GetDataRouter(GetWorld()).RegisterAgent(this);
|
||||
} else
|
||||
{
|
||||
UCarlaGameInstance* GameInstance = Cast<UCarlaGameInstance>(UGameplayStatics::GetGameInstance(GetWorld()));
|
||||
if(GameInstance) GameInstance->GetDataRouter().RegisterAgent(this);
|
||||
}
|
||||
bAgentComponentIsRegistered = true;
|
||||
}
|
||||
}
|
||||
|
@ -49,9 +64,19 @@ void UAgentComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
|
|||
{
|
||||
if (bAgentComponentIsRegistered)
|
||||
{
|
||||
GetDataRouter(GetWorld()).DeregisterAgent(this);
|
||||
if(UGameplayStatics::GetGameMode(GetWorld())!=nullptr)
|
||||
{
|
||||
GetDataRouter(GetWorld()).DeregisterAgent(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
UCarlaGameInstance* GameInstance = Cast<UCarlaGameInstance>(UGameplayStatics::GetGameInstance(GetWorld()));
|
||||
if(GameInstance)
|
||||
GameInstance->GetDataRouter().DeregisterAgent(this);
|
||||
}
|
||||
bAgentComponentIsRegistered = false;
|
||||
}
|
||||
|
||||
Super::EndPlay(EndPlayReason);
|
||||
}
|
||||
|
||||
|
|
|
@ -202,7 +202,7 @@ void ACarlaGameModeBase::BeginPlay()
|
|||
void ACarlaGameModeBase::EndPlay(const EEndPlayReason::Type EndPlayReason)
|
||||
{
|
||||
Super::EndPlay(EndPlayReason);
|
||||
if (CarlaSettingsDelegate != nullptr)
|
||||
if (CarlaSettingsDelegate != nullptr && EndPlayReason!=EEndPlayReason::EndPlayInEditor)
|
||||
{
|
||||
CarlaSettingsDelegate->Reset();
|
||||
}
|
||||
|
|
|
@ -8,15 +8,17 @@
|
|||
#include "SceneCaptureCamera.h"
|
||||
|
||||
#include "Sensor/SensorDataView.h"
|
||||
|
||||
#include "Game/CarlaGameInstance.h"
|
||||
#include "Settings/CarlaSettings.h"
|
||||
#include "Components/DrawFrustumComponent.h"
|
||||
#include "Components/SceneCaptureComponent2D.h"
|
||||
#include "Components/StaticMeshComponent.h"
|
||||
#include "Engine/CollisionProfile.h"
|
||||
#include "Engine/TextureRenderTarget2D.h"
|
||||
#include "HighResScreenshot.h"
|
||||
#include "Materials/Material.h"
|
||||
#include "Paths.h"
|
||||
#include "Kismet/KismetSystemLibrary.h"
|
||||
#include <memory>
|
||||
#include "ConstructorHelpers.h"
|
||||
|
||||
|
||||
static constexpr auto DEPTH_MAT_PATH =
|
||||
|
@ -33,6 +35,8 @@ static constexpr auto SEMANTIC_SEGMENTATION_MAT_PATH =
|
|||
|
||||
static void RemoveShowFlags(FEngineShowFlags &ShowFlags);
|
||||
|
||||
uint32 ASceneCaptureCamera::NumSceneCapture = 0;
|
||||
|
||||
ASceneCaptureCamera::ASceneCaptureCamera(const FObjectInitializer& ObjectInitializer) :
|
||||
Super(ObjectInitializer),
|
||||
SizeX(720u),
|
||||
|
@ -42,7 +46,7 @@ ASceneCaptureCamera::ASceneCaptureCamera(const FObjectInitializer& ObjectInitial
|
|||
PrimaryActorTick.bCanEverTick = true;
|
||||
PrimaryActorTick.TickGroup = TG_PrePhysics;
|
||||
|
||||
MeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("CamMesh0"));
|
||||
MeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("CamMesh"));
|
||||
|
||||
MeshComp->SetCollisionProfileName(UCollisionProfile::NoCollision_ProfileName);
|
||||
|
||||
|
@ -51,28 +55,30 @@ ASceneCaptureCamera::ASceneCaptureCamera(const FObjectInitializer& ObjectInitial
|
|||
MeshComp->PostPhysicsComponentTick.bCanEverTick = false;
|
||||
RootComponent = MeshComp;
|
||||
|
||||
DrawFrustum = CreateDefaultSubobject<UDrawFrustumComponent>(TEXT("DrawFrust0"));
|
||||
DrawFrustum = CreateDefaultSubobject<UDrawFrustumComponent>(TEXT("DrawFrust"));
|
||||
DrawFrustum->bIsEditorOnly = true;
|
||||
DrawFrustum->SetupAttachment(MeshComp);
|
||||
|
||||
CaptureRenderTarget = CreateDefaultSubobject<UTextureRenderTarget2D>(TEXT("CaptureRenderTarget0"));
|
||||
CaptureRenderTarget = CreateDefaultSubobject<UTextureRenderTarget2D>(FName(*FString::Printf(TEXT("CaptureRenderTarget%d"),NumSceneCapture)));
|
||||
#if WITH_EDITORONLY_DATA
|
||||
CaptureRenderTarget->CompressionNoAlpha = true;
|
||||
CaptureRenderTarget->MipGenSettings = TextureMipGenSettings::TMGS_NoMipmaps;
|
||||
CaptureRenderTarget->bUseLegacyGamma = false;
|
||||
#endif
|
||||
CaptureRenderTarget->CompressionSettings = TextureCompressionSettings::TC_Default;
|
||||
CaptureRenderTarget->SRGB=0;
|
||||
CaptureRenderTarget->SRGB = false;
|
||||
CaptureRenderTarget->bAutoGenerateMips = false;
|
||||
CaptureRenderTarget->AddressX = TextureAddress::TA_Clamp;
|
||||
CaptureRenderTarget->AddressY = TextureAddress::TA_Clamp;
|
||||
CaptureComponent2D = CreateDefaultSubobject<USceneCaptureComponent2D>(TEXT("SceneCaptureComponent2D"));
|
||||
CaptureComponent2D->SetupAttachment(MeshComp);
|
||||
CaptureComponent2D->SetupAttachment(MeshComp);
|
||||
|
||||
// Load post-processing materials.
|
||||
static ConstructorHelpers::FObjectFinder<UMaterial> DEPTH(DEPTH_MAT_PATH);
|
||||
PostProcessDepth = DEPTH.Object;
|
||||
static ConstructorHelpers::FObjectFinder<UMaterial> SEMANTIC_SEGMENTATION(SEMANTIC_SEGMENTATION_MAT_PATH);
|
||||
PostProcessSemanticSegmentation = SEMANTIC_SEGMENTATION.Object;
|
||||
NumSceneCapture++;
|
||||
}
|
||||
|
||||
void ASceneCaptureCamera::PostActorCreated()
|
||||
|
@ -105,29 +111,69 @@ void ASceneCaptureCamera::BeginPlay()
|
|||
// Setup render target.
|
||||
const bool bInForceLinearGamma = bRemovePostProcessing;
|
||||
CaptureRenderTarget->InitCustomFormat(SizeX, SizeY, PF_B8G8R8A8, bInForceLinearGamma);
|
||||
|
||||
if(!IsValid(CaptureComponent2D)||CaptureComponent2D->IsPendingKill())
|
||||
{
|
||||
CaptureComponent2D = NewObject<USceneCaptureComponent2D>(this,TEXT("SceneCaptureComponent2D"));
|
||||
CaptureComponent2D->SetupAttachment(MeshComp);
|
||||
}
|
||||
CaptureComponent2D->Deactivate();
|
||||
CaptureComponent2D->TextureTarget = CaptureRenderTarget;
|
||||
|
||||
// Setup camera post-processing.
|
||||
if (PostProcessEffect != EPostProcessEffect::None) {
|
||||
CaptureComponent2D->CaptureSource = ESceneCaptureSource::SCS_FinalColorLDR; //HD is much slower!
|
||||
// Setup camera post-processing depending on the quality level:
|
||||
const UCarlaGameInstance* GameInstance = Cast<UCarlaGameInstance>(GetWorld()->GetGameInstance());
|
||||
check(GameInstance!=nullptr);
|
||||
const UCarlaSettings& CarlaSettings = GameInstance->GetCarlaSettings();
|
||||
switch(PostProcessEffect)
|
||||
{
|
||||
case EPostProcessEffect::None: break;
|
||||
case EPostProcessEffect::SceneFinal:
|
||||
{
|
||||
//we set LDR for high quality because it will include post-fx
|
||||
//and HDR for low quality to avoid high contrast
|
||||
switch(CarlaSettings.GetQualitySettingsLevel())
|
||||
{
|
||||
case EQualitySettingsLevel::Low:
|
||||
CaptureComponent2D->CaptureSource = ESceneCaptureSource::SCS_SceneColorHDRNoAlpha;
|
||||
break;
|
||||
default:
|
||||
//LDR is faster than HDR (smaller bitmap array)
|
||||
CaptureComponent2D->CaptureSource = ESceneCaptureSource::SCS_FinalColorLDR;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
CaptureComponent2D->CaptureSource = SCS_FinalColorLDR;
|
||||
break;
|
||||
}
|
||||
if (bRemovePostProcessing) {
|
||||
|
||||
if (bRemovePostProcessing)
|
||||
{
|
||||
RemoveShowFlags(CaptureComponent2D->ShowFlags);
|
||||
}
|
||||
if (PostProcessEffect == EPostProcessEffect::Depth) {
|
||||
|
||||
if (PostProcessEffect == EPostProcessEffect::Depth)
|
||||
{
|
||||
CaptureComponent2D->PostProcessSettings.AddBlendable(PostProcessDepth, 1.0f);
|
||||
} else if (PostProcessEffect == EPostProcessEffect::SemanticSegmentation) {
|
||||
} else if (PostProcessEffect == EPostProcessEffect::SemanticSegmentation)
|
||||
{
|
||||
CaptureComponent2D->PostProcessSettings.AddBlendable(PostProcessSemanticSegmentation, 1.0f);
|
||||
}
|
||||
|
||||
CaptureComponent2D->UpdateContent();
|
||||
CaptureComponent2D->Activate();
|
||||
|
||||
//Make sure that there is enough time in the render queue
|
||||
UKismetSystemLibrary::ExecuteConsoleCommand(GetWorld(), FString("g.TimeoutForBlockOnRenderFence 300000"));
|
||||
|
||||
Super::BeginPlay();
|
||||
}
|
||||
|
||||
void ASceneCaptureCamera::EndPlay(const EEndPlayReason::Type EndPlayReason)
|
||||
{
|
||||
if(NumSceneCapture!=0) NumSceneCapture = 0;
|
||||
}
|
||||
|
||||
void ASceneCaptureCamera::Tick(const float DeltaSeconds)
|
||||
{
|
||||
Super::Tick(DeltaSeconds);
|
||||
|
@ -284,27 +330,48 @@ void ASceneCaptureCamera::WritePixels(float DeltaTime) const
|
|||
UE_LOG(LogCarla, Error, TEXT("SceneCaptureCamera: Missing render texture"));
|
||||
return ;
|
||||
}
|
||||
const uint32 num_bytes_per_pixel = 4; // PF_R8G8B8A8
|
||||
const uint32 width = texture->GetSizeX();
|
||||
uint32 height = texture->GetSizeY();
|
||||
uint32 stride;
|
||||
uint8 *src = reinterpret_cast<uint8*>(RHILockTexture2D(texture, 0, RLM_ReadOnly, stride, false));
|
||||
const uint32 height = texture->GetSizeY();
|
||||
const uint32 dest_stride = width * height * num_bytes_per_pixel;
|
||||
uint32 src_stride;
|
||||
uint8 *src = reinterpret_cast<uint8*>(RHILockTexture2D(texture, 0, RLM_ReadOnly, src_stride, false));
|
||||
struct {
|
||||
uint32 Width;
|
||||
uint32 Height;
|
||||
uint32 Type;
|
||||
float FOV;
|
||||
} ImageHeader = {
|
||||
SizeX,
|
||||
SizeY,
|
||||
width,
|
||||
height,
|
||||
PostProcessEffect::ToUInt(PostProcessEffect),
|
||||
CaptureComponent2D->FOVAngle
|
||||
};
|
||||
FSensorDataView DataView(
|
||||
|
||||
std::unique_ptr<uint8[]> dest = nullptr;
|
||||
//Direct 3D uses additional rows in the buffer,so we need check the result stride from the lock:
|
||||
if(IsD3DPlatform(GMaxRHIShaderPlatform,false) && (dest_stride!=src_stride))
|
||||
{
|
||||
const uint32 copy_row_stride = width * num_bytes_per_pixel;
|
||||
dest = std::make_unique<uint8[]>(dest_stride);
|
||||
// Copy per row
|
||||
uint8* dest_row = dest.get();
|
||||
uint8* src_row = src;
|
||||
for (uint32 Row = 0; Row < height; ++Row)
|
||||
{
|
||||
FMemory::Memcpy(dest_row, src_row, copy_row_stride);
|
||||
dest_row += copy_row_stride;
|
||||
src_row += src_stride;
|
||||
}
|
||||
src = dest.get();
|
||||
}
|
||||
|
||||
const FSensorDataView DataView(
|
||||
GetId(),
|
||||
FReadOnlyBufferView{reinterpret_cast<const void *>(&ImageHeader), sizeof(ImageHeader)},
|
||||
FReadOnlyBufferView{src,stride*height}
|
||||
FReadOnlyBufferView{src,dest_stride}
|
||||
);
|
||||
|
||||
|
||||
WriteSensorData(DataView);
|
||||
RHIUnlockTexture2D(texture, 0, false);
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ protected:
|
|||
public:
|
||||
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
|
||||
virtual void Tick(float DeltaSeconds) override;
|
||||
|
||||
uint32 GetImageSizeX() const
|
||||
|
@ -68,7 +68,9 @@ public:
|
|||
void Set(const UCameraDescription &CameraDescription);
|
||||
|
||||
bool ReadPixels(TArray<FColor> &BitMap) const;
|
||||
|
||||
|
||||
protected:
|
||||
static uint32 NumSceneCapture;
|
||||
|
||||
private:
|
||||
///Read the camera buffer and write it to the client with no lock of the resources (for Vulkan API)
|
||||
|
@ -97,7 +99,7 @@ private:
|
|||
UDrawFrustumComponent* DrawFrustum;
|
||||
|
||||
/** Render target necessary for scene capture */
|
||||
UPROPERTY(Transient)
|
||||
UPROPERTY()
|
||||
UTextureRenderTarget2D* CaptureRenderTarget;
|
||||
|
||||
/** Scene capture component. */
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
ASceneCaptureToDiskCamera::ASceneCaptureToDiskCamera(const FObjectInitializer& ObjectInitializer) :
|
||||
Super(ObjectInitializer),
|
||||
SaveToFolder(FPaths::Combine(FPaths::ProjectSavedDir(), "SceneCaptures")),
|
||||
SaveToFolder(*FPaths::Combine(FPaths::ProjectSavedDir(), TEXT("SceneCaptures"))),
|
||||
FileName("capture_%05d.png") {}
|
||||
|
||||
void ASceneCaptureToDiskCamera::BeginPlay()
|
||||
|
|
|
@ -122,10 +122,7 @@ static void LoadSettingsFromConfig(
|
|||
// QualitySettings.
|
||||
FString sQualityLevel;
|
||||
ConfigFile.GetString(S_CARLA_QUALITYSETTINGS, TEXT("QualityLevel"), sQualityLevel);
|
||||
if(!Settings.SetQualitySettingsLevel(UQualitySettings::FromString(sQualityLevel)))
|
||||
{
|
||||
//error
|
||||
}
|
||||
Settings.SetQualitySettingsLevel(UQualitySettings::FromString(sQualityLevel));
|
||||
|
||||
// Sensors.
|
||||
FString Sensors;
|
||||
|
@ -176,17 +173,9 @@ FString UQualitySettings::ToString(EQualitySettingsLevel QualitySettingsLevel)
|
|||
return ptr->GetNameStringByIndex(static_cast<int32>(QualitySettingsLevel));
|
||||
}
|
||||
|
||||
bool UCarlaSettings::SetQualitySettingsLevel(EQualitySettingsLevel newQualityLevel)
|
||||
void UCarlaSettings::SetQualitySettingsLevel(EQualitySettingsLevel newQualityLevel)
|
||||
{
|
||||
if(newQualityLevel==EQualitySettingsLevel::None)
|
||||
{
|
||||
UE_LOG(LogCarla ,Warning, TEXT("Quality Settings Level not set!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
QualitySettingsLevel = newQualityLevel;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void UCarlaSettings::LoadSettings()
|
||||
|
|
|
@ -5,13 +5,11 @@
|
|||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/StaticMesh.h"
|
||||
#include "WeatherDescription.h"
|
||||
|
||||
#include "UObject/NoExportTypes.h"
|
||||
|
||||
#include "CarlaSettings.generated.h"
|
||||
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EQualitySettingsLevel : uint8
|
||||
{
|
||||
|
@ -42,7 +40,7 @@ public:
|
|||
};
|
||||
|
||||
class USensorDescription;
|
||||
struct FStaticMaterial;
|
||||
|
||||
/** Global settings for CARLA.
|
||||
* Setting object used to hold both config settings and editable ones in one place
|
||||
* To ensure the settings are saved to the specified config file make sure to add
|
||||
|
@ -57,12 +55,12 @@ public:
|
|||
|
||||
/**
|
||||
* Sets the new quality settings level and make changes in the game related to it.
|
||||
* Returns the result of the operation.
|
||||
* @note This will not apply the quality settings. Use ApplyQualitySettings functions instead
|
||||
* @param newQualityLevel Store the new quality
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category="CARLA Settings")
|
||||
bool SetQualitySettingsLevel(EQualitySettingsLevel newQualityLevel);
|
||||
void SetQualitySettingsLevel(EQualitySettingsLevel newQualityLevel);
|
||||
|
||||
/** @return current quality settings level (could not be applied yet) */
|
||||
UFUNCTION(BlueprintCallable, Category="CARLA Settings")
|
||||
EQualitySettingsLevel GetQualitySettingsLevel() const { return QualitySettingsLevel; }
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include "Carla.h"
|
||||
#include "Engine/World.h"
|
||||
|
||||
#include "Game/CarlaGameModeBase.h"
|
||||
#include "Settings/CarlaSettings.h"
|
||||
#include "CarlaSettingsDelegate.h"
|
||||
|
@ -10,6 +10,7 @@
|
|||
#include "Engine/StaticMesh.h"
|
||||
#include "Engine/PostProcessVolume.h"
|
||||
#include "UObjectIterator.h"
|
||||
#include "Async.h"
|
||||
|
||||
///quality settings configuration between runs
|
||||
EQualitySettingsLevel UCarlaSettingsDelegate::AppliedLowPostResetQualitySettingsLevel = EQualitySettingsLevel::Epic;
|
||||
|
@ -21,8 +22,7 @@ UCarlaSettingsDelegate::UCarlaSettingsDelegate() :
|
|||
|
||||
void UCarlaSettingsDelegate::Reset()
|
||||
{
|
||||
LaunchEpicQualityCommands(GetLocalWorld());
|
||||
AppliedLowPostResetQualitySettingsLevel = EQualitySettingsLevel::Epic;
|
||||
AppliedLowPostResetQualitySettingsLevel = EQualitySettingsLevel::None;
|
||||
}
|
||||
|
||||
void UCarlaSettingsDelegate::RegisterSpawnHandler(UWorld *InWorld)
|
||||
|
@ -62,7 +62,8 @@ void UCarlaSettingsDelegate::ApplyQualitySettingsLevelPostRestart()
|
|||
{
|
||||
CheckCarlaSettings(nullptr);
|
||||
UWorld *InWorld = CarlaSettings->GetWorld();
|
||||
EQualitySettingsLevel QualitySettingsLevel = CarlaSettings->GetQualitySettingsLevel();
|
||||
|
||||
EQualitySettingsLevel QualitySettingsLevel = CarlaSettings->GetQualitySettingsLevel();
|
||||
if(AppliedLowPostResetQualitySettingsLevel==QualitySettingsLevel) return;
|
||||
|
||||
switch(QualitySettingsLevel)
|
||||
|
@ -70,7 +71,7 @@ void UCarlaSettingsDelegate::ApplyQualitySettingsLevelPostRestart()
|
|||
case EQualitySettingsLevel::Low:
|
||||
{
|
||||
//execute tweaks for quality
|
||||
LaunchLowQualityCommands(InWorld);
|
||||
LaunchLowQualityCommands(InWorld);
|
||||
//iterate all directional lights, deactivate shadows
|
||||
SetAllLights(InWorld,CarlaSettings->LowLightFadeDistance,false,true);
|
||||
//Set all the roads the low quality materials
|
||||
|
@ -181,45 +182,49 @@ void UCarlaSettingsDelegate::LaunchLowQualityCommands(UWorld * world) const
|
|||
|
||||
void UCarlaSettingsDelegate::SetAllRoads(UWorld* world, const float max_draw_distance, const TArray<FStaticMaterial> &road_pieces_materials) const
|
||||
{
|
||||
TArray<AActor*> actors;
|
||||
UGameplayStatics::GetAllActorsWithTag(world, UCarlaSettings::CARLA_ROAD_TAG,actors);
|
||||
|
||||
for(int32 i=0; i<actors.Num(); i++)
|
||||
{
|
||||
if(!IsValid(actors[i]) || actors[i]->IsPendingKillPending()) continue;
|
||||
TArray<UActorComponent*> components = actors[i]->GetComponentsByClass(UStaticMeshComponent::StaticClass());
|
||||
for(int32 j=0; j<components.Num(); j++)
|
||||
{
|
||||
UStaticMeshComponent* staticmeshcomponent = Cast<UStaticMeshComponent>(components[j]);
|
||||
if(staticmeshcomponent)
|
||||
{
|
||||
staticmeshcomponent->bAllowCullDistanceVolume = (max_draw_distance>0);
|
||||
staticmeshcomponent->bUseAsOccluder = false;
|
||||
staticmeshcomponent->LDMaxDrawDistance = max_draw_distance;
|
||||
staticmeshcomponent->CastShadow = (max_draw_distance==0);
|
||||
if(road_pieces_materials.Num()>0)
|
||||
{
|
||||
TArray<FName> meshslotsnames = staticmeshcomponent->GetMaterialSlotNames();
|
||||
for(int32 k=0; k<meshslotsnames.Num(); k++)
|
||||
if(!world||!IsValid(world)||world->IsPendingKill()) return;
|
||||
AsyncTask(ENamedThreads::GameThread, [=](){
|
||||
if(!world||!IsValid(world)||world->IsPendingKill()) return;
|
||||
TArray<AActor*> actors;
|
||||
UGameplayStatics::GetAllActorsWithTag(world, UCarlaSettings::CARLA_ROAD_TAG,actors);
|
||||
|
||||
for(int32 i=0; i<actors.Num(); i++)
|
||||
{
|
||||
if(!IsValid(actors[i]) || actors[i]->IsPendingKillPending()) continue;
|
||||
TArray<UActorComponent*> components = actors[i]->GetComponentsByClass(UStaticMeshComponent::StaticClass());
|
||||
for(int32 j=0; j<components.Num(); j++)
|
||||
{
|
||||
UStaticMeshComponent* staticmeshcomponent = Cast<UStaticMeshComponent>(components[j]);
|
||||
if(staticmeshcomponent)
|
||||
{
|
||||
staticmeshcomponent->bAllowCullDistanceVolume = (max_draw_distance>0);
|
||||
staticmeshcomponent->bUseAsOccluder = false;
|
||||
staticmeshcomponent->LDMaxDrawDistance = max_draw_distance;
|
||||
staticmeshcomponent->CastShadow = (max_draw_distance==0);
|
||||
if(road_pieces_materials.Num()>0)
|
||||
{
|
||||
const FName &slotname = meshslotsnames[k];
|
||||
road_pieces_materials.ContainsByPredicate(
|
||||
[staticmeshcomponent,slotname](const FStaticMaterial& material)
|
||||
TArray<FName> meshslotsnames = staticmeshcomponent->GetMaterialSlotNames();
|
||||
for(int32 k=0; k<meshslotsnames.Num(); k++)
|
||||
{
|
||||
if(material.MaterialSlotName.IsEqual(slotname))
|
||||
const FName &slotname = meshslotsnames[k];
|
||||
road_pieces_materials.ContainsByPredicate(
|
||||
[staticmeshcomponent,slotname](const FStaticMaterial& material)
|
||||
{
|
||||
staticmeshcomponent->SetMaterial(
|
||||
staticmeshcomponent->GetMaterialIndex(slotname),
|
||||
material.MaterialInterface
|
||||
);
|
||||
return true;
|
||||
} else return false;
|
||||
});
|
||||
if(material.MaterialSlotName.IsEqual(slotname))
|
||||
{
|
||||
staticmeshcomponent->SetMaterial(
|
||||
staticmeshcomponent->GetMaterialIndex(slotname),
|
||||
material.MaterialInterface
|
||||
);
|
||||
return true;
|
||||
} else return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}); //,DELAY_TIME_TO_SET_ALL_ROADS, false);
|
||||
}
|
||||
|
||||
void UCarlaSettingsDelegate::SetActorComponentsDrawDistance(AActor* actor, const float max_draw_distance) const
|
||||
|
@ -243,20 +248,24 @@ void UCarlaSettingsDelegate::SetActorComponentsDrawDistance(AActor* actor, const
|
|||
void UCarlaSettingsDelegate::SetAllActorsDrawDistance(UWorld* world, const float max_draw_distance) const
|
||||
{
|
||||
///@TODO: use semantics to grab all actors by type (vehicles,ground,people,props) and set different distances configured in the global properties
|
||||
TArray<AActor*> actors;
|
||||
#define _MAX_SCALE_SIZE 50.0f
|
||||
//set the lower quality - max draw distance
|
||||
UGameplayStatics::GetAllActorsOfClass(world, AActor::StaticClass(),actors);
|
||||
for(int32 i=0; i<actors.Num(); i++)
|
||||
{
|
||||
if(!IsValid(actors[i]) || actors[i]->IsPendingKillPending() ||
|
||||
actors[i]->ActorHasTag(UCarlaSettings::CARLA_ROAD_TAG) ||
|
||||
actors[i]->ActorHasTag(UCarlaSettings::CARLA_SKY_TAG)
|
||||
){
|
||||
continue;
|
||||
}
|
||||
SetActorComponentsDrawDistance(actors[i], max_draw_distance);
|
||||
}
|
||||
if(!world||!IsValid(world)||world->IsPendingKill()) return;
|
||||
AsyncTask(ENamedThreads::GameThread, [=](){
|
||||
if(!world||!IsValid(world)||world->IsPendingKill()) return;
|
||||
TArray<AActor*> actors;
|
||||
#define _MAX_SCALE_SIZE 50.0f
|
||||
//set the lower quality - max draw distance
|
||||
UGameplayStatics::GetAllActorsOfClass(world, AActor::StaticClass(),actors);
|
||||
for(int32 i=0; i<actors.Num(); i++)
|
||||
{
|
||||
if(!IsValid(actors[i]) || actors[i]->IsPendingKillPending() ||
|
||||
actors[i]->ActorHasTag(UCarlaSettings::CARLA_ROAD_TAG) ||
|
||||
actors[i]->ActorHasTag(UCarlaSettings::CARLA_SKY_TAG)
|
||||
){
|
||||
continue;
|
||||
}
|
||||
SetActorComponentsDrawDistance(actors[i], max_draw_distance);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
@ -266,12 +275,12 @@ void UCarlaSettingsDelegate::SetPostProcessEffectsEnabled(UWorld* world, const b
|
|||
UGameplayStatics::GetAllActorsOfClass(world, APostProcessVolume::StaticClass(), actors);
|
||||
for(int32 i=0; i<actors.Num(); i++)
|
||||
{
|
||||
if(!IsValid(actors[i]) || actors[i]->IsPendingKillPending()) continue;
|
||||
APostProcessVolume* postprocessvolume = Cast<APostProcessVolume>(actors[i]);
|
||||
if(postprocessvolume)
|
||||
{
|
||||
postprocessvolume->bEnabled = enabled;
|
||||
}
|
||||
if(!IsValid(actors[i]) || actors[i]->IsPendingKillPending()) continue;
|
||||
APostProcessVolume* postprocessvolume = Cast<APostProcessVolume>(actors[i]);
|
||||
if(postprocessvolume)
|
||||
{
|
||||
postprocessvolume->bEnabled = enabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -318,21 +327,26 @@ void UCarlaSettingsDelegate::LaunchEpicQualityCommands(UWorld* world) const
|
|||
|
||||
void UCarlaSettingsDelegate::SetAllLights(UWorld* world, const float max_distance_fade, const bool cast_shadows, const bool hide_non_directional) const
|
||||
{
|
||||
TArray<AActor*> actors;
|
||||
UGameplayStatics::GetAllActorsOfClass(world, ALight::StaticClass(), actors);
|
||||
for(int32 i=0;i<actors.Num();i++)
|
||||
{
|
||||
if(!IsValid(actors[i]) || actors[i]->IsPendingKillPending()) continue;
|
||||
//tweak directional lights
|
||||
ADirectionalLight* directionallight = Cast<ADirectionalLight>(actors[i]);
|
||||
if(directionallight)
|
||||
if(!world||!IsValid(world)||world->IsPendingKill()) return;
|
||||
AsyncTask(ENamedThreads::GameThread, [=](){
|
||||
if(!world||!IsValid(world)||world->IsPendingKill()) return;
|
||||
TArray<AActor*> actors;
|
||||
UGameplayStatics::GetAllActorsOfClass(world, ALight::StaticClass(), actors);
|
||||
for(int32 i=0;i<actors.Num();i++)
|
||||
{
|
||||
directionallight->SetCastShadows(cast_shadows);
|
||||
directionallight->SetLightFunctionFadeDistance(max_distance_fade);
|
||||
continue;
|
||||
if(!IsValid(actors[i]) || actors[i]->IsPendingKillPending()) continue;
|
||||
//tweak directional lights
|
||||
ADirectionalLight* directionallight = Cast<ADirectionalLight>(actors[i]);
|
||||
if(directionallight)
|
||||
{
|
||||
directionallight->SetCastShadows(cast_shadows);
|
||||
directionallight->SetLightFunctionFadeDistance(max_distance_fade);
|
||||
continue;
|
||||
}
|
||||
//disable any other type of light
|
||||
actors[i]->SetActorHiddenInGame(hide_non_directional);
|
||||
}
|
||||
//disable any other type of light
|
||||
actors[i]->SetActorHiddenInGame(hide_non_directional);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -5,12 +5,10 @@
|
|||
// For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Engine/World.h"
|
||||
#include "CarlaSettingsDelegate.generated.h"
|
||||
|
||||
|
||||
class UCarlaSettings;
|
||||
|
||||
/// Used to set settings for every actor that is spawned into the world.
|
||||
UCLASS(BlueprintType)
|
||||
class CARLA_API UCarlaSettingsDelegate : public UObject
|
||||
|
|
|
@ -11,10 +11,12 @@
|
|||
#include "Vehicle/CarlaWheeledVehicle.h"
|
||||
#include "Vehicle/WheeledVehicleAIController.h"
|
||||
|
||||
#include "Engine/PlayerStartPIE.h"
|
||||
|
||||
#include "EngineUtils.h"
|
||||
#include "GameFramework/Character.h"
|
||||
#include "GameFramework/PlayerStart.h"
|
||||
#include "TimerManager.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
|
||||
// =============================================================================
|
||||
// -- Static local methods -----------------------------------------------------
|
||||
|
@ -35,8 +37,7 @@ static AWheeledVehicleAIController *GetController(ACarlaWheeledVehicle *Vehicle)
|
|||
// =============================================================================
|
||||
|
||||
// Sets default values
|
||||
AVehicleSpawnerBase::AVehicleSpawnerBase(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
AVehicleSpawnerBase::AVehicleSpawnerBase(const FObjectInitializer& ObjectInitializer): Super(ObjectInitializer)
|
||||
{
|
||||
PrimaryActorTick.bCanEverTick = false;
|
||||
}
|
||||
|
@ -55,31 +56,71 @@ void AVehicleSpawnerBase::BeginPlay()
|
|||
SpawnPoints.Add(*It);
|
||||
}
|
||||
|
||||
UE_LOG(LogCarla, Log, TEXT("Found %d positions for spawning vehicles"), SpawnPoints.Num());
|
||||
UE_LOG(LogCarla, Log, TEXT("Found %d PlayerStart positions for spawning vehicles"), SpawnPoints.Num());
|
||||
|
||||
if (SpawnPoints.Num() < NumberOfVehicles) {
|
||||
bSpawnVehicles = false;
|
||||
UE_LOG(LogCarla, Error, TEXT("We don't have enough spawn points for vehicles!"));
|
||||
if (SpawnPoints.Num() < NumberOfVehicles && SpawnPoints.Num()>0)
|
||||
{
|
||||
UE_LOG(LogCarla, Warning, TEXT("We don't have enough spawn points (PlayerStart) for vehicles!"));
|
||||
if(SpawnPoints.Num()==0)
|
||||
{
|
||||
UE_LOG(LogCarla, Error, TEXT("At least one spawn point (PlayerStart) is needed to spawn vehicles!"));
|
||||
} else
|
||||
{
|
||||
UE_LOG(LogCarla, Log,
|
||||
TEXT("To cover the %d vehicles to spawn after beginplay, it will spawn one new vehicle each %f seconds"),
|
||||
NumberOfVehicles - SpawnPoints.Num(),
|
||||
TimeBetweenSpawnAttemptsAfterBegin
|
||||
)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
if(NumberOfVehicles==0||SpawnPoints.Num()==0) bSpawnVehicles = false;
|
||||
|
||||
if (bSpawnVehicles) {
|
||||
const int32 MaximumNumberOfAttempts = 4 * NumberOfVehicles;
|
||||
if (bSpawnVehicles)
|
||||
{
|
||||
GetRandomEngine()->Shuffle(SpawnPoints);
|
||||
const int32 MaximumNumberOfAttempts = SpawnPoints.Num();
|
||||
int32 NumberOfAttempts = 0;
|
||||
while ((NumberOfVehicles > Vehicles.Num()) && (NumberOfAttempts < MaximumNumberOfAttempts)) {
|
||||
// Try to spawn one vehicle.
|
||||
TryToSpawnRandomVehicle();
|
||||
|
||||
while ((NumberOfVehicles > Vehicles.Num()) && (NumberOfAttempts < MaximumNumberOfAttempts))
|
||||
{
|
||||
SpawnVehicleAtSpawnPoint(*SpawnPoints[NumberOfAttempts]);
|
||||
++NumberOfAttempts;
|
||||
}
|
||||
|
||||
if (NumberOfVehicles > Vehicles.Num()) {
|
||||
|
||||
if (NumberOfAttempts > NumberOfVehicles)
|
||||
{
|
||||
UE_LOG(LogCarla, Error, TEXT("Requested %d vehicles, but we were only able to spawn %d"), NumberOfVehicles, Vehicles.Num());
|
||||
} else
|
||||
{
|
||||
if(NumberOfAttempts == NumberOfVehicles)
|
||||
{
|
||||
UE_LOG(LogCarla, Log, TEXT("Spawned all %d vehicles"), NumberOfAttempts);
|
||||
} else
|
||||
{
|
||||
UE_LOG(LogCarla, Log,
|
||||
TEXT("Starting the timer to spawn the other %d vehicles, one per %f seconds"),
|
||||
NumberOfVehicles - NumberOfAttempts,
|
||||
TimeBetweenSpawnAttemptsAfterBegin
|
||||
);
|
||||
GetWorld()->GetTimerManager().SetTimer(AttemptTimerHandle,this, &AVehicleSpawnerBase::SpawnVehicleAttempt, TimeBetweenSpawnAttemptsAfterBegin,false,-1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AVehicleSpawnerBase::EndPlay(const EEndPlayReason::Type EndPlayReason)
|
||||
{
|
||||
GetWorld()->GetTimerManager().ClearAllTimersForObject(this);
|
||||
}
|
||||
|
||||
void AVehicleSpawnerBase::SetNumberOfVehicles(const int32 Count)
|
||||
{
|
||||
if (Count > 0) {
|
||||
if (Count > 0)
|
||||
{
|
||||
bSpawnVehicles = true;
|
||||
NumberOfVehicles = Count;
|
||||
} else {
|
||||
|
@ -90,7 +131,8 @@ void AVehicleSpawnerBase::SetNumberOfVehicles(const int32 Count)
|
|||
void AVehicleSpawnerBase::TryToSpawnRandomVehicle()
|
||||
{
|
||||
auto SpawnPoint = GetRandomSpawnPoint();
|
||||
if (SpawnPoint != nullptr) {
|
||||
if (SpawnPoint != nullptr)
|
||||
{
|
||||
SpawnVehicleAtSpawnPoint(*SpawnPoint);
|
||||
} else {
|
||||
UE_LOG(LogCarla, Error, TEXT("Unable to find spawn point"));
|
||||
|
@ -102,11 +144,13 @@ void AVehicleSpawnerBase::SpawnVehicleAtSpawnPoint(
|
|||
{
|
||||
ACarlaWheeledVehicle *Vehicle;
|
||||
SpawnVehicle(SpawnPoint.GetActorTransform(), Vehicle);
|
||||
if ((Vehicle != nullptr) && !Vehicle->IsPendingKill()) {
|
||||
if ((Vehicle != nullptr) && !Vehicle->IsPendingKill())
|
||||
{
|
||||
Vehicle->AIControllerClass = AWheeledVehicleAIController::StaticClass();
|
||||
Vehicle->SpawnDefaultController();
|
||||
auto Controller = GetController(Vehicle);
|
||||
if (Controller != nullptr) { // Sometimes fails...
|
||||
if (Controller != nullptr)
|
||||
{ // Sometimes fails...
|
||||
Controller->GetRandomEngine()->Seed(GetRandomEngine()->GenerateSeed());
|
||||
Controller->SetRoadMap(GetRoadMap());
|
||||
Controller->SetAutopilot(true);
|
||||
|
@ -118,6 +162,38 @@ void AVehicleSpawnerBase::SpawnVehicleAtSpawnPoint(
|
|||
}
|
||||
}
|
||||
|
||||
void AVehicleSpawnerBase::SpawnVehicleAttempt()
|
||||
{
|
||||
if(Vehicles.Num()>=NumberOfVehicles)
|
||||
{
|
||||
UE_LOG(LogCarla, Log, TEXT("All vehicles spawned correctly"));
|
||||
return;
|
||||
}
|
||||
|
||||
APlayerStart* spawnpoint = GetRandomSpawnPoint();
|
||||
APawn* playerpawn = UGameplayStatics::GetPlayerPawn(GetWorld(),0);
|
||||
const float DistanceToPlayer = playerpawn&&spawnpoint? FVector::Distance(playerpawn->GetActorLocation(),spawnpoint->GetActorLocation()):0.0f;
|
||||
float NextTime = TimeBetweenSpawnAttemptsAfterBegin;
|
||||
if(DistanceToPlayer>DistanceToPlayerBetweenSpawnAttemptsAfterBegin)
|
||||
{
|
||||
SpawnVehicleAtSpawnPoint(*spawnpoint);
|
||||
} else
|
||||
{
|
||||
NextTime /= 2.0f;
|
||||
}
|
||||
|
||||
if(Vehicles.Num()<NumberOfVehicles)
|
||||
{
|
||||
auto &timemanager = GetWorld()->GetTimerManager();
|
||||
if(AttemptTimerHandle.IsValid()) timemanager.ClearTimer(AttemptTimerHandle);
|
||||
timemanager.SetTimer(AttemptTimerHandle,this, &AVehicleSpawnerBase::SpawnVehicleAttempt,NextTime,false,-1);
|
||||
} else
|
||||
{
|
||||
UE_LOG(LogCarla, Log, TEXT("Last vehicle spawned correctly"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
APlayerStart *AVehicleSpawnerBase::GetRandomSpawnPoint()
|
||||
{
|
||||
return (SpawnPoints.Num() > 0 ? GetRandomEngine()->PickOne(SpawnPoints) : nullptr);
|
||||
|
|
|
@ -28,6 +28,9 @@ protected:
|
|||
// Called when the game starts or when spawned
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
// Called when the actor is removed from the level
|
||||
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
|
||||
|
||||
UFUNCTION(BlueprintImplementableEvent)
|
||||
void SpawnVehicle(const FTransform &SpawnTransform, ACarlaWheeledVehicle *&SpawnedCharacter);
|
||||
|
||||
|
@ -57,6 +60,9 @@ public:
|
|||
{
|
||||
return RoadMap;
|
||||
}
|
||||
/** Function called to spawn another vehicle when there is not enough spawn points in the beginplay */
|
||||
UFUNCTION(Category = "Vehicle Spawner", BlueprintCallable)
|
||||
void SpawnVehicleAttempt();
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -65,7 +71,7 @@ protected:
|
|||
void SpawnVehicleAtSpawnPoint(const APlayerStart &SpawnPoint);
|
||||
|
||||
UPROPERTY()
|
||||
URoadMap *RoadMap;
|
||||
URoadMap *RoadMap = nullptr;
|
||||
|
||||
/** If false, no walker will be spawned. */
|
||||
UPROPERTY(Category = "Vehicle Spawner", EditAnywhere)
|
||||
|
@ -75,9 +81,22 @@ protected:
|
|||
UPROPERTY(Category = "Vehicle Spawner", EditAnywhere, meta = (EditCondition = bSpawnVehicles, ClampMin = "1"))
|
||||
int32 NumberOfVehicles = 10;
|
||||
|
||||
UPROPERTY(Category = "Vechicle Spawner", VisibleAnywhere, AdvancedDisplay)
|
||||
UPROPERTY(Category = "Vehicle Spawner", VisibleAnywhere, AdvancedDisplay)
|
||||
TArray<APlayerStart *> SpawnPoints;
|
||||
|
||||
UPROPERTY(Category = "Vehicle Spawner", BlueprintReadOnly, VisibleAnywhere, AdvancedDisplay)
|
||||
TArray<ACarlaWheeledVehicle *> Vehicles;
|
||||
|
||||
/** Time to spawn new vehicles after begin play if there was not enough spawn points at the moment */
|
||||
UPROPERTY(Category = "Vehicle Spawner", BlueprintReadWrite, EditAnywhere, meta = (ClampMin = "0.1", ClampMax = "1000.0", UIMin = "0.1", UIMax = "1000.0"))
|
||||
float TimeBetweenSpawnAttemptsAfterBegin = 3.0f;
|
||||
|
||||
/** Min Distance to the player vehicle to validate a spawn point location for the next vehicle spawn attempt */
|
||||
UPROPERTY(Category = "Vehicle Spawner", BlueprintReadWrite, EditAnywhere, meta = (ClampMin = "10", ClampMax = "10000", UIMin = "10", UIMax = "10000"))
|
||||
float DistanceToPlayerBetweenSpawnAttemptsAfterBegin = 5000;
|
||||
private:
|
||||
|
||||
/** Time handler to spawn more vehicles in the case we could not do it in the beginplay */
|
||||
FTimerHandle AttemptTimerHandle;
|
||||
|
||||
};
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include "Navigation/CrowdFollowingComponent.h"
|
||||
#include "Perception/AIPerceptionComponent.h"
|
||||
#include "Perception/AISenseConfig_Sight.h"
|
||||
#include "Perception/AISense_Sight.h"
|
||||
#include "WheeledVehicle.h"
|
||||
#include "WheeledVehicleMovementComponent.h"
|
||||
|
||||
|
@ -27,8 +26,8 @@ static constexpr float UPDATE_TIME_IN_SECONDS = 0.6f;
|
|||
static constexpr float PREVISION_TIME_IN_SECONDS = 5.0f;
|
||||
static constexpr float WALKER_SIGHT_RADIUS = 500.0f;
|
||||
static constexpr float WALKER_SPEED_DAMPING = 4.0f;
|
||||
static constexpr float WALKER_PERIPHERAL_VISION_ANGLE_IN_DEGREES = 155.0f;
|
||||
static constexpr float WALKER_MAX_TIME_PAUSED = 10.0f;
|
||||
static constexpr float WALKER_PERIPHERAL_VISION_ANGLE_IN_DEGREES = 130.0f;
|
||||
static constexpr float WALKER_MAX_TIME_PAUSED = 5.0f;
|
||||
static constexpr float VEHICLE_SAFETY_RADIUS = 600.0f;
|
||||
|
||||
|
||||
|
@ -176,11 +175,13 @@ void AWalkerAIController::Tick(float DeltaSeconds)
|
|||
{
|
||||
Super::Tick(DeltaSeconds);
|
||||
TimeInState+=DeltaSeconds;
|
||||
if (Status != EWalkerStatus::RunOver) {
|
||||
if (Status != EWalkerStatus::RunOver)
|
||||
{
|
||||
switch (GetMoveStatus())
|
||||
{
|
||||
case EPathFollowingStatus::Idle:
|
||||
case EPathFollowingStatus::Waiting:
|
||||
default: break;
|
||||
case EPathFollowingStatus::Idle:
|
||||
//case EPathFollowingStatus::Waiting: //<-- incomplete path
|
||||
LOG_AI_WALKER(Warning, "is stuck!");
|
||||
ChangeStatus(EWalkerStatus::Stuck);
|
||||
break;
|
||||
|
@ -190,7 +191,8 @@ void AWalkerAIController::Tick(float DeltaSeconds)
|
|||
TryResumeMovement();
|
||||
}
|
||||
break;
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -225,7 +227,7 @@ void AWalkerAIController::OnMoveCompleted(
|
|||
ChangeStatus(EWalkerStatus::MoveCompleted);
|
||||
}
|
||||
|
||||
void AWalkerAIController::SenseActors(const TArray<AActor *> Actors)
|
||||
void AWalkerAIController::SenseActors(TArray<AActor *> Actors)
|
||||
{
|
||||
const auto *aPawn = GetPawn();
|
||||
if ((Status == EWalkerStatus::Moving) &&
|
||||
|
|
|
@ -54,6 +54,9 @@ public:
|
|||
UFUNCTION(BlueprintCallable)
|
||||
void TrySetMovement(bool paused);
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
float GetTimeInState() const { return TimeInState; }
|
||||
|
||||
private:
|
||||
void ChangeStatus(EWalkerStatus status);
|
||||
void TryResumeMovement();
|
||||
|
@ -68,6 +71,6 @@ private:
|
|||
|
||||
UPROPERTY(VisibleAnywhere)
|
||||
EWalkerStatus Status = EWalkerStatus::Unknown;
|
||||
|
||||
/** Continous time in the same EWalkerStatus */
|
||||
float TimeInState=0.0f;
|
||||
};
|
||||
|
|
|
@ -10,10 +10,10 @@
|
|||
#include "Util/RandomEngine.h"
|
||||
#include "Walker/WalkerAIController.h"
|
||||
#include "Walker/WalkerSpawnPoint.h"
|
||||
|
||||
#include "Components/BoxComponent.h"
|
||||
#include "EngineUtils.h"
|
||||
#include "GameFramework/Character.h"
|
||||
#include "Kismet/KismetSystemLibrary.h"
|
||||
|
||||
// =============================================================================
|
||||
// -- Static local methods -----------------------------------------------------
|
||||
|
@ -78,14 +78,19 @@ void AWalkerSpawnerBase::BeginPlay()
|
|||
SpawnPoints.Add(SpawnPoint);
|
||||
}
|
||||
}
|
||||
#ifdef CARLA_AI_WALKERS_EXTRA_LOG
|
||||
UE_LOG(LogCarla, Log, TEXT("Found %d positions for spawning walkers at begin play."), BeginSpawnPoints.Num());
|
||||
UE_LOG(LogCarla, Log, TEXT("Found %d positions for spawning walkers during game play."), SpawnPoints.Num());
|
||||
|
||||
#endif
|
||||
if (SpawnPoints.Num() < 2) {
|
||||
bSpawnWalkers = false;
|
||||
#ifdef CARLA_AI_WALKERS_EXTRA_LOG
|
||||
UE_LOG(LogCarla, Error, TEXT("We don't have enough spawn points for walkers!"));
|
||||
#endif
|
||||
} else if (BeginSpawnPoints.Num() < NumberOfWalkers) {
|
||||
#ifdef CARLA_AI_WALKERS_EXTRA_LOG
|
||||
UE_LOG(LogCarla, Warning, TEXT("Requested %d walkers, but we only have %d spawn points. Some will fail to spawn."), NumberOfWalkers, BeginSpawnPoints.Num());
|
||||
#endif
|
||||
}
|
||||
|
||||
GetRandomEngine()->Shuffle(BeginSpawnPoints);
|
||||
|
@ -97,7 +102,9 @@ void AWalkerSpawnerBase::BeginPlay()
|
|||
++Count;
|
||||
}
|
||||
}
|
||||
#ifdef CARLA_AI_WALKERS_EXTRA_LOG
|
||||
UE_LOG(LogCarla, Log, TEXT("Spawned %d walkers at begin play."), Count);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,45 +117,139 @@ void AWalkerSpawnerBase::Tick(float DeltaTime)
|
|||
TryToSpawnWalkerAt(GetRandomSpawnPoint());
|
||||
}
|
||||
|
||||
if (WalkersBlackList.Num() > 0) {
|
||||
// If still stuck in the black list, just kill it.
|
||||
const int32 Index = (++CurrentIndexToCheck % WalkersBlackList.Num());
|
||||
auto Walker = WalkersBlackList[Index];
|
||||
const auto Status = GetWalkerStatus(Walker);
|
||||
if ((Status == EWalkerStatus::MoveCompleted) ||
|
||||
(Status == EWalkerStatus::Invalid) ||
|
||||
(Status == EWalkerStatus::RunOver)) {
|
||||
WalkersBlackList.RemoveAtSwap(Index);
|
||||
if ((Walker != nullptr) && (Status != EWalkerStatus::RunOver)) {
|
||||
Walker->Destroy();
|
||||
if (WalkersBlackList.Num() > 0)
|
||||
{
|
||||
CurrentBlackWalkerIndexToCheck = ++CurrentBlackWalkerIndexToCheck % WalkersBlackList.Num();
|
||||
ACharacter* BlackListedWalker = WalkersBlackList[CurrentBlackWalkerIndexToCheck];
|
||||
AWalkerAIController* controller = BlackListedWalker!=nullptr?Cast<AWalkerAIController>(BlackListedWalker->GetController()):nullptr;
|
||||
if(BlackListedWalker != nullptr && controller!=nullptr && IsValid(BlackListedWalker))
|
||||
{
|
||||
const auto Status = GetWalkerStatus(BlackListedWalker);
|
||||
#ifdef CARLA_AI_WALKERS_EXTRA_LOG
|
||||
UE_LOG(LogCarla, Log, TEXT("Watching walker %s with state %d"), *UKismetSystemLibrary::GetDisplayName(BlackListedWalker), (int)Status);
|
||||
#endif
|
||||
switch(Status)
|
||||
{
|
||||
case EWalkerStatus::RunOver:{
|
||||
//remove from list and wait for auto-destroy
|
||||
WalkersBlackList.RemoveAtSwap(CurrentBlackWalkerIndexToCheck);
|
||||
break;
|
||||
}
|
||||
case EWalkerStatus::MoveCompleted:
|
||||
{
|
||||
BlackListedWalker->Destroy();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
switch(controller->GetMoveStatus())
|
||||
{
|
||||
case EPathFollowingStatus::Idle:
|
||||
if(!TrySetDestination(*BlackListedWalker))
|
||||
{
|
||||
if(!SetRandomWalkerDestination(BlackListedWalker))
|
||||
{
|
||||
#ifdef CARLA_AI_WALKERS_EXTRA_LOG
|
||||
UE_LOG(LogCarla,Error,TEXT("Could not set a random destination to walker %s"),*UKismetSystemLibrary::GetDisplayName(BlackListedWalker));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EPathFollowingStatus::Waiting:
|
||||
//incomplete path
|
||||
break;
|
||||
case EPathFollowingStatus::Paused:
|
||||
//waiting for blueprint code
|
||||
break;
|
||||
case EPathFollowingStatus::Moving:
|
||||
if(BlackListedWalker->GetVelocity().Size()>1.0f)
|
||||
{
|
||||
WalkersBlackList.RemoveAtSwap(CurrentBlackWalkerIndexToCheck);
|
||||
Walkers.Add(BlackListedWalker);
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef CARLA_AI_WALKERS_EXTRA_LOG
|
||||
UE_LOG(LogCarla, Log, TEXT("New state for walker %s : %d"), *UKismetSystemLibrary::GetDisplayName(BlackListedWalker), (int)GetWalkerStatus(BlackListedWalker));
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (Walkers.Num() > 0) {
|
||||
if (Walkers.Num() > 0)
|
||||
{
|
||||
// Check one walker, if fails black-list it or kill it.
|
||||
const int32 Index = (++CurrentIndexToCheck % Walkers.Num());
|
||||
auto Walker = Walkers[Index];
|
||||
const auto Status = GetWalkerStatus(Walker);
|
||||
|
||||
if ((Status == EWalkerStatus::MoveCompleted) ||
|
||||
(Status == EWalkerStatus::Invalid) ||
|
||||
(Status == EWalkerStatus::RunOver)) {
|
||||
// Kill it.
|
||||
Walkers.RemoveAtSwap(Index);
|
||||
// If it was run over will self-destroy.
|
||||
if ((Walker != nullptr) && (Status != EWalkerStatus::RunOver)) {
|
||||
Walker->Destroy();
|
||||
}
|
||||
} else if (Status == EWalkerStatus::Stuck) {
|
||||
// Black-list it.
|
||||
TrySetDestination(*Walker);
|
||||
WalkersBlackList.Add(Walker);
|
||||
Walkers.RemoveAtSwap(Index);
|
||||
CurrentWalkerIndexToCheck = ++CurrentWalkerIndexToCheck % Walkers.Num();
|
||||
auto Walker = Walkers[CurrentWalkerIndexToCheck];
|
||||
if(Walker == nullptr || !IsValid(Walker))
|
||||
{
|
||||
Walkers.RemoveAtSwap(CurrentWalkerIndexToCheck);
|
||||
} else {
|
||||
const auto Status = GetWalkerStatus(Walker);
|
||||
switch (Status)
|
||||
{
|
||||
default:
|
||||
case EWalkerStatus::Paused:
|
||||
case EWalkerStatus::Unknown:
|
||||
break;
|
||||
case EWalkerStatus::RunOver: {
|
||||
Walkers.RemoveAtSwap(CurrentWalkerIndexToCheck);
|
||||
break;
|
||||
}
|
||||
case EWalkerStatus::MoveCompleted:
|
||||
Walker->Destroy();
|
||||
break;
|
||||
case EWalkerStatus::Invalid:
|
||||
case EWalkerStatus::Stuck:
|
||||
{
|
||||
SetRandomWalkerDestination(Walker);
|
||||
// Black-list it and wait for this walker to move
|
||||
WalkersBlackList.Add(Walker);
|
||||
Walkers.RemoveAtSwap(CurrentWalkerIndexToCheck);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool AWalkerSpawnerBase::SetRandomWalkerDestination(ACharacter *Walker)
|
||||
{
|
||||
const auto &DestinationPoint = GetRandomSpawnPoint();
|
||||
auto Controller = GetController(Walker);
|
||||
if(!Controller) {
|
||||
#ifdef CARLA_AI_WALKERS_EXTRA_LOG
|
||||
UE_LOG(LogCarla, Warning, TEXT("AWalkerSpawnerBase::SetRandomWalkerDestination: Walker %s has no controller"),
|
||||
*UKismetSystemLibrary::GetDisplayName(Walker)
|
||||
);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
const EPathFollowingRequestResult::Type request_result = Controller->MoveToLocation(DestinationPoint.GetActorLocation(),-1.0f,false,true,true,true,nullptr,true);
|
||||
switch(request_result)
|
||||
{
|
||||
case EPathFollowingRequestResult::Type::Failed:
|
||||
{
|
||||
#ifdef CARLA_AI_WALKERS_EXTRA_LOG
|
||||
UE_LOG(LogCarla, Warning, TEXT("AWalkerSpawnerBase::SetRandomWalkerDestination: Bad destination point %s"),
|
||||
*UKismetSystemLibrary::GetDisplayName(&DestinationPoint)
|
||||
);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
case EPathFollowingRequestResult::Type::AlreadyAtGoal:{
|
||||
#ifdef CARLA_AI_WALKERS_EXTRA_LOG
|
||||
UE_LOG(LogCarla, Log, TEXT("AWalkerSpawnerBase::SetRandomWalkerDestination already in destination, generating new location"));
|
||||
#endif
|
||||
return SetRandomWalkerDestination(Walker);
|
||||
}
|
||||
default: case EPathFollowingRequestResult::Type::RequestSuccessful: return true;
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// -- Other member functions ---------------------------------------------------
|
||||
// =============================================================================
|
||||
|
@ -205,7 +306,10 @@ bool AWalkerSpawnerBase::TryToSpawnWalkerAt(const AWalkerSpawnPointBase &SpawnPo
|
|||
|
||||
// Add walker and set destination.
|
||||
Walkers.Add(Walker);
|
||||
Controller->MoveToLocation(Destination);
|
||||
if (Controller->MoveToLocation(Destination,-1.0f,false,true,true,true,nullptr,true)!=EPathFollowingRequestResult::Type::RequestSuccessful)
|
||||
{
|
||||
SetRandomWalkerDestination(Walker);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -214,15 +318,22 @@ bool AWalkerSpawnerBase::TrySetDestination(ACharacter &Walker)
|
|||
// Try to retrieve controller.
|
||||
auto Controller = GetController(&Walker);
|
||||
if (Controller == nullptr) {
|
||||
UE_LOG(LogCarla, Warning, TEXT("Could not get valid controller for walker: %s"), *Walker.GetName());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try find destination.
|
||||
FVector Destination;
|
||||
if (!TryGetValidDestination(Walker.GetActorLocation(), Destination)) {
|
||||
#ifdef CARLA_AI_WALKERS_EXTRA_LOG
|
||||
UE_LOG(
|
||||
LogCarla, Warning,
|
||||
TEXT("Could not get a new destiny: %s for walker: %s"),
|
||||
*Destination.ToString(), *Walker.GetName()
|
||||
);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
Controller->MoveToLocation(Destination);
|
||||
return true;
|
||||
return Controller->MoveToLocation(Destination,-1.0f,false,true,true,true,nullptr,true)==EPathFollowingRequestResult::RequestSuccessful;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ public:
|
|||
|
||||
virtual void Tick(float DeltaTime) override;
|
||||
|
||||
|
||||
/// @}
|
||||
// ===========================================================================
|
||||
/// @name Blueprintable functions
|
||||
|
@ -87,6 +88,7 @@ private:
|
|||
|
||||
bool TrySetDestination(ACharacter &Walker);
|
||||
|
||||
bool SetRandomWalkerDestination(ACharacter * Walker);
|
||||
/// @}
|
||||
|
||||
private:
|
||||
|
@ -116,5 +118,7 @@ private:
|
|||
UPROPERTY(Category = "Walker Spawner", VisibleAnywhere, AdvancedDisplay)
|
||||
TArray<ACharacter *> WalkersBlackList;
|
||||
|
||||
uint32 CurrentIndexToCheck = 0u;
|
||||
uint32 CurrentWalkerIndexToCheck = 0u;
|
||||
|
||||
uint32 CurrentBlackWalkerIndexToCheck = 0u;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue