// Copyright 2020 Phyronnaz #include "VoxelComponents/VoxelInvokerComponent.h" #include "VoxelWorldInterface.h" #include "VoxelMessages.h" #include "GameFramework/Pawn.h" #include "Engine/World.h" #include "Kismet/GameplayStatics.h" #include "Components/BrushComponent.h" FIntVector UVoxelInvokerComponentBase::GetInvokerVoxelPosition(const AVoxelWorldInterface* VoxelWorld) const { return GetInvokerVoxelPosition(const_cast(VoxelWorld)); } FVoxelInvokerSettings UVoxelInvokerComponentBase::GetInvokerSettings(const AVoxelWorldInterface* VoxelWorld) const { return GetInvokerSettings(const_cast(VoxelWorld)); } bool UVoxelInvokerComponentBase::IsLocalInvoker_Implementation() const { auto* Owner = Cast(GetOwner()); return !Owner || Owner->IsLocallyControlled(); } FIntVector UVoxelInvokerComponentBase::GetInvokerVoxelPosition_Implementation(AVoxelWorldInterface* VoxelWorld) const { return FIntVector(0); } FVoxelInvokerSettings UVoxelInvokerComponentBase::GetInvokerSettings_Implementation(AVoxelWorldInterface* VoxelWorld) const { return {}; } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// void UVoxelInvokerComponentBase::EnableInvoker() { if (bIsInvokerEnabled) { FVoxelMessages::Error(FUNCTION_ERROR("Invoker already enabled"), this); return; } bIsInvokerEnabled = true; auto& Array = Components.FindOrAdd(GetWorld()); Array.AddUnique(MakeWeakObjectPtr(this)); Array.RemoveAllSwap([](auto& X) { return !X.IsValid(); }); LOG_VOXEL(Log, TEXT("Voxel Invoker enabled; Name: %s; Owner: %s"), *GetName(), *GetOwner()->GetName()); } void UVoxelInvokerComponentBase::DisableInvoker() { if (!bIsInvokerEnabled) { FVoxelMessages::Error(FUNCTION_ERROR("Invoker already disabled"), this); return; } bIsInvokerEnabled = false; auto& Array = Components.FindOrAdd(GetWorld()); Array.RemoveAllSwap([this](auto& X) { return !X.IsValid() || X == this; }); LOG_VOXEL(Log, TEXT("Voxel Invoker disabled; Name: %s"), *GetName()); } bool UVoxelInvokerComponentBase::IsInvokerEnabled() const { return bIsInvokerEnabled; } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// void UVoxelInvokerComponentBase::OnRegister() { Super::OnRegister(); if (bStartsEnabled && ensure(!bIsInvokerEnabled)) { EnableInvoker(); } } void UVoxelInvokerComponentBase::OnUnregister() { Super::OnUnregister(); if (bIsInvokerEnabled) { DisableInvoker(); } } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// void UVoxelInvokerComponentBase::RefreshAllVoxelInvokers() { VOXEL_FUNCTION_COUNTER(); OnForceRefreshInvokers.Broadcast(); } const TArray>& UVoxelInvokerComponentBase::GetInvokers(UWorld* World) { auto& Result = Components.FindOrAdd(World); Result.RemoveAllSwap([](auto& X) { return !X.IsValid(); }); return Result; } FSimpleMulticastDelegate UVoxelInvokerComponentBase::OnForceRefreshInvokers; TMap, TArray>> UVoxelInvokerComponentBase::Components; /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// FIntVector UVoxelSimpleInvokerComponent::GetInvokerVoxelPosition_Implementation(AVoxelWorldInterface* VoxelWorld) const { return VoxelWorld->GlobalToLocal(GetInvokerGlobalPosition()); } FVoxelInvokerSettings UVoxelSimpleInvokerComponent::GetInvokerSettings_Implementation(AVoxelWorldInterface* VoxelWorld) const { const FVector InvokerGlobalPosition = GetInvokerGlobalPosition(); const auto GetVoxelBounds = [&](float Distance) { return FVoxelIntBox::SafeConstruct( VoxelWorld->GlobalToLocal(InvokerGlobalPosition - Distance, EVoxelWorldCoordinatesRounding::RoundDown), VoxelWorld->GlobalToLocal(InvokerGlobalPosition + Distance, EVoxelWorldCoordinatesRounding::RoundUp) ); }; FVoxelInvokerSettings Settings; Settings.bUseForLOD = bUseForLOD; Settings.LODToSet = LODToSet; Settings.LODBounds = GetVoxelBounds(LODRange); Settings.bUseForCollisions = bUseForCollisions; Settings.CollisionsBounds = GetVoxelBounds(CollisionsRange); Settings.bUseForNavmesh = bUseForNavmesh; Settings.NavmeshBounds = GetVoxelBounds(NavmeshRange); return Settings; } FVector UVoxelSimpleInvokerComponent::GetInvokerGlobalPosition_Implementation() const { return GetComponentLocation(); } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// FVector UVoxelInvokerWithPredictionComponent::GetInvokerGlobalPosition_Implementation() const { FVector Position = GetComponentLocation(); if (bEnablePrediction) { Position += GetOwner()->GetVelocity() * PredictionTime; } return Position; } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// FVector UVoxelInvokerAutoCameraComponent::GetInvokerGlobalPosition_Implementation() const { APlayerCameraManager* CameraManager = UGameplayStatics::GetPlayerCameraManager(GetWorld(), 0); if (ensure(CameraManager)) { return CameraManager->GetCameraLocation(); } else { return FVector::ZeroVector; } } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// UVoxelLODVolumeInvokerComponent::UVoxelLODVolumeInvokerComponent() { bUseForEvents = false; bUseForPriorities = false; } bool UVoxelLODVolumeInvokerComponent::IsLocalInvoker_Implementation() const { // Always true for a volume return true; } FIntVector UVoxelLODVolumeInvokerComponent::GetInvokerVoxelPosition_Implementation(AVoxelWorldInterface* VoxelWorld) const { return VoxelWorld->GlobalToLocal(GetComponentLocation()); } FVoxelInvokerSettings UVoxelLODVolumeInvokerComponent::GetInvokerSettings_Implementation(AVoxelWorldInterface* VoxelWorld) const { auto* Volume = CastChecked(GetOwner()); const FBox VolumeWorldBounds = Volume->GetBounds().GetBox(); const FVoxelIntBox VolumeBounds = FVoxelIntBox::SafeConstruct( VoxelWorld->GlobalToLocal(VolumeWorldBounds.Min, EVoxelWorldCoordinatesRounding::RoundDown), VoxelWorld->GlobalToLocal(VolumeWorldBounds.Max, EVoxelWorldCoordinatesRounding::RoundUp) ); FVoxelInvokerSettings Settings; Settings.bUseForLOD = bUseForLOD; Settings.LODToSet = LODToSet; Settings.LODBounds = VolumeBounds; Settings.bUseForCollisions = bUseForCollisions; Settings.CollisionsBounds = VolumeBounds; Settings.bUseForNavmesh = bUseForNavmesh; Settings.NavmeshBounds = VolumeBounds; return Settings; } /////////////////////////////////////////////////////////////////////////////// AVoxelLODVolume::AVoxelLODVolume() { GetBrushComponent()->SetCollisionProfileName(UCollisionProfile::NoCollision_ProfileName); GetBrushComponent()->bAlwaysCreatePhysicsState = true; GetBrushComponent()->SetMobility(EComponentMobility::Movable); InvokerComponent = CreateDefaultSubobject("Invoker Component"); InvokerComponent->SetupAttachment(RootComponent); } #if WITH_EDITOR void AVoxelLODVolume::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) { Super::PostEditChangeProperty(PropertyChangedEvent); UVoxelInvokerComponentBase::RefreshAllVoxelInvokers(); } #endif