void AZombieCharacter::Attack() { //This function is used only when it's permitted by the zombie's animation instance //It creates a raycast in a sphere shape and checks for possible hits //If the hits contain our player it makes sure it applies damage to him //Setting up the start and end location of the raycast FVector StartLocation = GetMesh()->GetSocketLocation(FName("MeleeStartSocket")); FVector EndLocation = GetMesh()->GetSocketLocation(FName("MeleeEndSocket")); //Raycasting in a sphere to detect collisions TArray<FHitResult> HitResults; //Setting up the shape of the raycast FCollisionShape CollisionShape; CollisionShape.ShapeType = ECollisionShape::Sphere; CollisionShape.SetSphere(AttackRaycastRadius); //Object query parameters FCollisionObjectQueryParams ObjectQueryParams; ObjectQueryParams.AllDynamicObjects; //Handling ignored actors FCollisionQueryParams QueryParams; QueryParams.AddIgnoredActor(this); UWorld* World = GetWorld(); if (World && ZAnimInstance->bEligibleForAttack) { //Raycasting... bool bHit = World->SweepMultiByObjectType(HitResults, StartLocation, EndLocation, FQuat::Identity, ObjectQueryParams, CollisionShape, QueryParams); //Raycast visualization /*FVector Center = ((EndLocation - StartLocation) / 2) + StartLocation; DrawDebugSphere(World, Center, AttackRaycastRadius, 20, FColor::Green, false, 2.f);*/ //Checking for possible hits if (bHit) { for (auto It = HitResults.CreateIterator(); It; It++) { ARoguelikeChar* Char = Cast<ARoguelikeChar>(It->GetActor()); if (Char && ZAnimInstance && GetCharacterMovement()) { //Calling the attack function from character Char->TakeDamageFromZombie(Damage); //Closing the flag which checks for the attack function ZAnimInstance->bEligibleForAttack = false; //Updating with new movement speed GetCharacterMovement()->MaxWalkSpeed = InitialMaxWalkSpeed; ZAnimInstance->Speed = InitialMaxWalkSpeed; break; } } } } }
void UChildActorComponent::CreateChildActor() { // Kill spawned actor if we have one DestroyChildActor(); // This is no longer needed if (CachedInstanceData) { delete CachedInstanceData; CachedInstanceData = nullptr; } // If we have a class to spawn. if(ChildActorClass != nullptr) { UWorld* World = GetWorld(); if(World != nullptr) { // Before we spawn let's try and prevent cyclic disaster bool bSpawn = true; AActor* Actor = GetOwner(); while (Actor && bSpawn) { if (Actor->GetClass() == ChildActorClass) { bSpawn = false; UE_LOG(LogChildActorComponent, Error, TEXT("Found cycle in child actor component '%s'. Not spawning Actor of class '%s' to break."), *GetPathName(), *ChildActorClass->GetName()); } Actor = Actor->ParentComponentActor.Get(); } if (bSpawn) { FActorSpawnParameters Params; Params.bNoCollisionFail = true; Params.bDeferConstruction = true; // We defer construction so that we set ParentComponentActor prior to component registration so they appear selected Params.bAllowDuringConstructionScript = true; Params.OverrideLevel = GetOwner()->GetLevel(); Params.Name = ChildActorName; if (!HasAllFlags(RF_Transactional)) { Params.ObjectFlags &= ~RF_Transactional; } // Spawn actor of desired class FVector Location = GetComponentLocation(); FRotator Rotation = GetComponentRotation(); ChildActor = World->SpawnActor(ChildActorClass, &Location, &Rotation, Params); // If spawn was successful, if(ChildActor != nullptr) { ChildActorName = ChildActor->GetFName(); // Remember which actor spawned it (for selection in editor etc) ChildActor->ParentComponentActor = GetOwner(); ChildActor->AttachRootComponentTo(this); // Parts that we deferred from SpawnActor ChildActor->FinishSpawning(ComponentToWorld); } } } } }
FORCEINLINE_DEBUGGABLE FVector RunBoxTrace(const FVector& StartPos, const FVector& EndPos) { FHitResult OutHit; const bool bHit = World->SweepSingle(OutHit, StartPos, EndPos, FQuat((EndPos - StartPos).Rotation()), Channel, FCollisionShape::MakeBox(Extent), Params); return bHit ? OutHit.ImpactPoint : EndPos; }
void UGameplayDebuggingComponent::CollectEQSData() { #if USE_EQS_DEBUGGER if (!ShouldReplicateData(EAIDebugDrawDataView::EQS)) { return; } UWorld* World = GetWorld(); UEnvQueryManager* QueryManager = World ? UEnvQueryManager::GetCurrent(World) : NULL; const AActor* Owner = GetSelectedActor(); AGameplayDebuggingReplicator* Replicator = Cast<AGameplayDebuggingReplicator>(GetOwner()); if (QueryManager == NULL || Owner == NULL) { return; } auto AllQueries = QueryManager->GetDebugger().GetAllQueriesForOwner(Owner); const class APawn* OwnerAsPawn = Cast<class APawn>(Owner); if (OwnerAsPawn != NULL && OwnerAsPawn->GetController()) { const auto& AllControllerQueries = QueryManager->GetDebugger().GetAllQueriesForOwner(OwnerAsPawn->GetController()); AllQueries.Append(AllControllerQueries); } struct FEnvQueryInfoSort { FORCEINLINE bool operator()(const FEQSDebugger::FEnvQueryInfo& A, const FEQSDebugger::FEnvQueryInfo& B) const { return (A.Timestamp < B.Timestamp); } }; TArray<FEQSDebugger::FEnvQueryInfo> QueriesToSort = AllQueries; QueriesToSort.Sort(FEnvQueryInfoSort()); //sort queries by timestamp QueriesToSort.SetNum(FMath::Min<int32>(Replicator->MaxEQSQueries, AllQueries.Num())); for (int32 Index = AllQueries.Num() - 1; Index >= 0; --Index) { auto &CurrentQuery = AllQueries[Index]; if (QueriesToSort.Find(CurrentQuery) == INDEX_NONE) { AllQueries.RemoveAt(Index); } } EQSLocalData.Reset(); for (int32 Index = 0; Index < FMath::Min<int32>(Replicator->MaxEQSQueries, AllQueries.Num()); ++Index) { EQSDebug::FQueryData* CurrentLocalData = NULL; CachedQueryInstance = AllQueries[Index].Instance; const float CachedTimestamp = AllQueries[Index].Timestamp; if (!CurrentLocalData) { EQSLocalData.AddZeroed(); CurrentLocalData = &EQSLocalData[EQSLocalData.Num()-1]; } UEnvQueryDebugHelpers::QueryToDebugData(CachedQueryInstance.Get(), *CurrentLocalData); CurrentLocalData->Timestamp = AllQueries[Index].Timestamp; } TArray<uint8> UncompressedBuffer; FMemoryWriter ArWriter(UncompressedBuffer); ArWriter << EQSLocalData; const int32 UncompressedSize = UncompressedBuffer.Num(); const int32 HeaderSize = sizeof(int32); EQSRepData.Init(0, HeaderSize + FMath::TruncToInt(1.1f * UncompressedSize)); int32 CompressedSize = EQSRepData.Num() - HeaderSize; uint8* DestBuffer = EQSRepData.GetData(); FMemory::Memcpy(DestBuffer, &UncompressedSize, HeaderSize); DestBuffer += HeaderSize; FCompression::CompressMemory((ECompressionFlags)(COMPRESS_ZLIB | COMPRESS_BiasMemory), (void*)DestBuffer, CompressedSize, (void*)UncompressedBuffer.GetData(), UncompressedSize); EQSRepData.SetNum(CompressedSize + HeaderSize, false); if (World && World->GetNetMode() != NM_DedicatedServer) { OnRep_UpdateEQS(); } #endif }
UWorld* NUTNet::CreateUnitTestWorld(bool bHookTick/*=true*/) { UWorld* ReturnVal = NULL; // Unfortunately, this hack is needed, to avoid a crash when running as commandlet // NOTE: Sometimes, depending upon build settings, PRIVATE_GIsRunningCommandlet is a define instead of a global #ifndef PRIVATE_GIsRunningCommandlet bool bIsCommandlet = PRIVATE_GIsRunningCommandlet; PRIVATE_GIsRunningCommandlet = false; #endif ReturnVal = UWorld::CreateWorld(EWorldType::None, false); #ifndef PRIVATE_GIsRunningCommandlet PRIVATE_GIsRunningCommandlet = bIsCommandlet; #endif if (ReturnVal != NULL) { UnitTestWorlds.Add(ReturnVal); // Hook the new worlds 'tick' event, so that we can capture logging if (bHookTick) { FWorldTickHook* TickHook = new FWorldTickHook(ReturnVal); ActiveTickHooks.Add(TickHook); TickHook->Init(); } // Hack-mark the world as having begun play (when it has not) ReturnVal->bBegunPlay = true; // Hack-mark the world as having initialized actors (to allow RPC hooks) ReturnVal->bActorsInitialized = true; // Enable pause, using the PlayerController of the primary world (unless we're in the editor) if (!GIsEditor) { AWorldSettings* CurSettings = ReturnVal->GetWorldSettings(); if (CurSettings != NULL) { ULocalPlayer* PrimLocPlayer = GEngine->GetFirstGamePlayer(NUTUtil::GetPrimaryWorld()); APlayerController* PrimPC = (PrimLocPlayer != NULL ? PrimLocPlayer->PlayerController : NULL); APlayerState* PrimState = (PrimPC != NULL ? PrimPC->PlayerState : NULL); if (PrimState != NULL) { CurSettings->Pauser = PrimState; } } } // Create a blank world context, to prevent crashes FWorldContext& CurContext = GEngine->CreateNewWorldContext(EWorldType::None); CurContext.SetCurrentWorld(ReturnVal); } return ReturnVal; }
void UChildActorComponent::CreateChildActor() { // Kill spawned actor if we have one DestroyChildActor(); // If we have a class to spawn. if(ChildActorClass != nullptr) { UWorld* World = GetWorld(); if(World != nullptr) { // Before we spawn let's try and prevent cyclic disaster bool bSpawn = true; AActor* MyOwner = GetOwner(); AActor* Actor = MyOwner; while (Actor && bSpawn) { if (Actor->GetClass() == ChildActorClass) { bSpawn = false; UE_LOG(LogChildActorComponent, Error, TEXT("Found cycle in child actor component '%s'. Not spawning Actor of class '%s' to break."), *GetPathName(), *ChildActorClass->GetName()); } if (UChildActorComponent* ParentComponent = Actor->GetParentComponent()) { Actor = ParentComponent->GetOwner(); } else { Actor = nullptr; } } if (bSpawn) { FActorSpawnParameters Params; Params.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; Params.bDeferConstruction = true; // We defer construction so that we set ParentComponent prior to component registration so they appear selected Params.bAllowDuringConstructionScript = true; Params.OverrideLevel = (MyOwner ? MyOwner->GetLevel() : nullptr); Params.Name = ChildActorName; if (!HasAllFlags(RF_Transactional)) { Params.ObjectFlags &= ~RF_Transactional; } // Spawn actor of desired class FVector Location = GetComponentLocation(); FRotator Rotation = GetComponentRotation(); ChildActor = World->SpawnActor(ChildActorClass, &Location, &Rotation, Params); // If spawn was successful, if(ChildActor != nullptr) { ChildActorName = ChildActor->GetFName(); // Remember which component spawned it (for selection in editor etc) FActorParentComponentSetter::Set(ChildActor, this); // Parts that we deferred from SpawnActor const FComponentInstanceDataCache* ComponentInstanceData = (CachedInstanceData ? CachedInstanceData->ComponentInstanceData : nullptr); ChildActor->FinishSpawning(ComponentToWorld, false, ComponentInstanceData); ChildActor->AttachRootComponentTo(this, NAME_None, EAttachLocation::SnapToTarget); } } } } // This is no longer needed if (CachedInstanceData) { delete CachedInstanceData; CachedInstanceData = nullptr; } }
void UAudioComponent::PlayInternal(const float StartTime, const float FadeInDuration, const float FadeVolumeLevel) { UWorld* World = GetWorld(); UE_LOG(LogAudio, Verbose, TEXT("%g: Playing AudioComponent : '%s' with Sound: '%s'"), World ? World->GetAudioTimeSeconds() : 0.0f, *GetFullName(), Sound ? *Sound->GetName() : TEXT("nullptr")); if (bIsActive) { // If this is an auto destroy component we need to prevent it from being auto-destroyed since we're really just restarting it bool bCurrentAutoDestroy = bAutoDestroy; bAutoDestroy = false; Stop(); bAutoDestroy = bCurrentAutoDestroy; } if (Sound && (World == nullptr || World->bAllowAudioPlayback)) { if (FAudioDevice* AudioDevice = GetAudioDevice()) { FActiveSound NewActiveSound; NewActiveSound.AudioComponent = this; NewActiveSound.World = GetWorld(); NewActiveSound.Sound = Sound; NewActiveSound.SoundClassOverride = SoundClassOverride; NewActiveSound.VolumeMultiplier = (VolumeModulationMax + ((VolumeModulationMin - VolumeModulationMax) * FMath::SRand())) * VolumeMultiplier; NewActiveSound.PitchMultiplier = (PitchModulationMax + ((PitchModulationMin - PitchModulationMax) * FMath::SRand())) * PitchMultiplier; NewActiveSound.HighFrequencyGainMultiplier = HighFrequencyGainMultiplier; NewActiveSound.RequestedStartTime = FMath::Max(0.f, StartTime); NewActiveSound.OcclusionCheckInterval = OcclusionCheckInterval; NewActiveSound.SubtitlePriority = SubtitlePriority; NewActiveSound.bShouldRemainActiveIfDropped = bShouldRemainActiveIfDropped; NewActiveSound.bHandleSubtitles = (!bSuppressSubtitles || OnQueueSubtitles.IsBound()); NewActiveSound.bIgnoreForFlushing = bIgnoreForFlushing; NewActiveSound.bIsUISound = bIsUISound; NewActiveSound.bIsMusic = bIsMusic; NewActiveSound.bAlwaysPlay = bAlwaysPlay; NewActiveSound.bReverb = bReverb; NewActiveSound.bCenterChannelOnly = bCenterChannelOnly; NewActiveSound.bLocationDefined = !bPreviewComponent; if (NewActiveSound.bLocationDefined) { NewActiveSound.Transform = ComponentToWorld; } const FAttenuationSettings* AttenuationSettingsToApply = (bAllowSpatialization ? GetAttenuationSettingsToApply() : nullptr); NewActiveSound.bAllowSpatialization = bAllowSpatialization; NewActiveSound.bHasAttenuationSettings = (AttenuationSettingsToApply != nullptr); if (NewActiveSound.bHasAttenuationSettings) { NewActiveSound.AttenuationSettings = *AttenuationSettingsToApply; } NewActiveSound.InstanceParameters = InstanceParameters; NewActiveSound.TargetAdjustVolumeMultiplier = FadeVolumeLevel; if (FadeInDuration > 0.0f) { NewActiveSound.CurrentAdjustVolumeMultiplier = 0.f; NewActiveSound.TargetAdjustVolumeStopTime = FadeInDuration; } else { NewActiveSound.CurrentAdjustVolumeMultiplier = FadeVolumeLevel; } // TODO - Audio Threading. This call would be a task call to dispatch to the audio thread AudioDevice->AddNewActiveSound(NewActiveSound); bIsActive = true; } } }
void UParticleModuleCollision::Update(FParticleEmitterInstance* Owner, int32 Offset, float DeltaTime) { SCOPE_CYCLE_COUNTER(STAT_ParticleCollisionTime); check(Owner); check(Owner->Component); UWorld* World = Owner->Component->GetWorld(); if (Owner->ActiveParticles == 0 || (bDropDetail && World && World->bDropDetail)) { return; } //Gets the owning actor of the component. Can be NULL if the component is spawned with the World as an Outer, e.g. in UGameplayStatics::SpawnEmitterAtLocation(). AActor* Actor = Owner->Component->GetOwner(); UParticleLODLevel* LODLevel = Owner->SpriteTemplate->GetCurrentLODLevel(Owner); check(LODLevel); const int32 MeshRotationOffset = Owner->GetMeshRotationOffset(); const bool bMeshRotationActive = Owner->IsMeshRotationActive(); const FTransform& OwnerTM = Owner->Component->GetAsyncComponentToWorld(); const FVector ParentScale = OwnerTM.GetScale3D(); FParticleEventInstancePayload* EventPayload = NULL; if (LODLevel->EventGenerator) { EventPayload = (FParticleEventInstancePayload*)(Owner->GetModuleInstanceData(LODLevel->EventGenerator)); if (EventPayload && (EventPayload->bCollisionEventsPresent == false) && (EventPayload->bDeathEventsPresent == false)) { EventPayload = NULL; } } FParticleCollisionInstancePayload* CollisionInstPayload = (FParticleCollisionInstancePayload*)(Owner->GetModuleInstanceData(this)); const TArray<FVector>& PlayerLocations = Owner->Component->GetPlayerLocations(); TArray<float> PlayerLODDistanceFactor = Owner->Component->GetPlayerLODDistanceFactor(); //Make a copy because we need to square it later const int32 PlayerCount = PlayerLocations.Num(); if (World->IsGameWorld()) { bool bIgnoreAllCollision = false; // LOD collision based on visibility // This is at the 'emitter instance' level as it will be true or false for the whole instance... if (bCollideOnlyIfVisible && ((World->TimeSeconds - Owner->Component->LastRenderTime) > 0.1f)) { // no collision if not recently rendered bIgnoreAllCollision = true; } else { // If the MaxCollisionDistance is greater than WORLD_MAX, they obviously want the check disabled... if (MaxCollisionDistance < WORLD_MAX) { // If we have at least a few particles, do a simple check vs. the bounds if (Owner->ActiveParticles > 7) { if (CollisionInstPayload->CurrentLODBoundsCheckCount == 0) { FBox BoundingBox; BoundingBox.Init(); if (Owner->Component->Template && Owner->Component->Template->bUseFixedRelativeBoundingBox) { BoundingBox = Owner->Component->Template->FixedRelativeBoundingBox.TransformBy(OwnerTM); } else { // A frame behind, but shouldn't be an issue... BoundingBox = Owner->Component->GetAsyncBounds().GetBox(); } // see if any player is within the extended bounds... bIgnoreAllCollision = true; // Check for the system itself beyond beyond the bounds // LOD collision by distance bool bCloseEnough = false; for (int32 PlyrIdx = 0; PlyrIdx < PlayerCount; PlyrIdx++) { // Invert the LOD distance factor here because we are using it to *expand* the // bounds rather than shorten the distance checked as it is usually used for. float InvDistanceFactor = 1.0f / PlayerLODDistanceFactor[PlyrIdx]; FBox CheckBounds = BoundingBox; float BoxExpansionValue = MaxCollisionDistance * InvDistanceFactor; BoxExpansionValue += BoxExpansionValue * 0.075f; // Expand it by the max collision distance (and a little bit extra) CheckBounds = CheckBounds.ExpandBy(BoxExpansionValue); if (CheckBounds.IsInside(PlayerLocations[PlyrIdx])) { // If one is close enough, that's all it takes! bCloseEnough = true; break; } } if (bCloseEnough == true) { bIgnoreAllCollision = false; } } CollisionInstPayload->CurrentLODBoundsCheckCount++; // Every 30 frames recheck the overall bounds... if (CollisionInstPayload->CurrentLODBoundsCheckCount > 30) { CollisionInstPayload->CurrentLODBoundsCheckCount = 0; } } } } if (bIgnoreAllCollision == true) { // Turn off collision on *all* existing particles... // We don't want it to turn back on and have particles // already embedded start performing collision checks. BEGIN_UPDATE_LOOP; { Particle.Flags |= STATE_Particle_IgnoreCollisions; } END_UPDATE_LOOP; return; } // Square the LODDistanceFactor values now, so we don't have to do it // per particle in the update loop below... for (int32 SquareIdx = 0; SquareIdx < PlayerLocations.Num(); SquareIdx++) { PlayerLODDistanceFactor[SquareIdx] *= PlayerLODDistanceFactor[SquareIdx]; } } float SquaredMaxCollisionDistance = FMath::Square(MaxCollisionDistance); BEGIN_UPDATE_LOOP; { if ((Particle.Flags & STATE_Particle_CollisionIgnoreCheck) != 0) { CONTINUE_UPDATE_LOOP; } PARTICLE_ELEMENT(FParticleCollisionPayload, CollisionPayload); if ((Particle.Flags & STATE_Particle_DelayCollisions) != 0) { if (CollisionPayload.Delay > Particle.RelativeTime) { CONTINUE_UPDATE_LOOP; } Particle.Flags &= ~STATE_Particle_DelayCollisions; } FVector Location; FVector OldLocation; // Location won't be calculated till after tick so we need to calculate an intermediate one here. Location = Particle.Location + Particle.Velocity * DeltaTime; if (LODLevel->RequiredModule->bUseLocalSpace) { // Transform the location and old location into world space Location = OwnerTM.TransformPosition(Location); OldLocation = OwnerTM.TransformPosition(Particle.OldLocation); } else { OldLocation = Particle.OldLocation; } FVector Direction = (Location - OldLocation).GetSafeNormal(); // Determine the size FVector Size = Particle.Size * ParentScale; FVector Extent(0.0f); // Setup extent for mesh particles. UParticleModuleTypeDataMesh* MeshType = Cast<UParticleModuleTypeDataMesh>(LODLevel->TypeDataModule); if (MeshType && MeshType->Mesh) { Extent = MeshType->Mesh->GetBounds().BoxExtent; Extent = MeshType->bCollisionsConsiderPartilceSize ? Extent * Size : Extent; } FHitResult Hit; Hit.Normal.X = 0.0f; Hit.Normal.Y = 0.0f; Hit.Normal.Z = 0.0f; check( Owner->Component ); FVector End = Location + Direction * Size / DirScalar; if ((World->IsGameWorld() == true) && (MaxCollisionDistance < WORLD_MAX)) { // LOD collision by distance bool bCloseEnough = false; for (int32 CheckIdx = 0; CheckIdx < PlayerCount; CheckIdx++) { float CheckValue = (PlayerLocations[CheckIdx] - End).SizeSquared() * PlayerLODDistanceFactor[CheckIdx]; if (CheckValue < SquaredMaxCollisionDistance) { bCloseEnough = true; break; } } if (bCloseEnough == false) { Particle.Flags |= STATE_Particle_IgnoreCollisions; CONTINUE_UPDATE_LOOP; } } AActor* IgnoreActor = bIgnoreSourceActor ? Actor : NULL; if (PerformCollisionCheck(Owner, &Particle, Hit, IgnoreActor, End, OldLocation, Extent)) { bool bDecrementMaxCount = true; bool bIgnoreCollision = false; if (Hit.GetActor()) { bDecrementMaxCount = !bPawnsDoNotDecrementCount || !Cast<APawn>(Hit.GetActor()); bIgnoreCollision = bIgnoreTriggerVolumes && Hit.GetActor()->IsA(ATriggerBase::StaticClass()); //@todo.SAS. Allow for PSys to say what it wants to collide w/? } if (bIgnoreCollision == false) { if (bDecrementMaxCount && (bOnlyVerticalNormalsDecrementCount == true)) { if ((Hit.Normal.IsNearlyZero() == false) && (FMath::Abs(Hit.Normal.Z) + VerticalFudgeFactor) < 1.0f) { //UE_LOG(LogParticles, Log, TEXT("Particle from %s had a non-vertical hit!"), *(Owner->Component->Template->GetPathName())); bDecrementMaxCount = false; } } if (bDecrementMaxCount) { CollisionPayload.UsedCollisions--; } if (CollisionPayload.UsedCollisions > 0) { if (LODLevel->RequiredModule->bUseLocalSpace) { // Transform the particle velocity to world space FVector OldVelocity = OwnerTM.TransformVector(Particle.Velocity); FVector BaseVelocity = OwnerTM.TransformVector(Particle.BaseVelocity); BaseVelocity = BaseVelocity.MirrorByVector(Hit.Normal) * CollisionPayload.UsedDampingFactor; Particle.BaseVelocity = OwnerTM.InverseTransformVector(BaseVelocity); Particle.BaseRotationRate = Particle.BaseRotationRate * CollisionPayload.UsedDampingFactorRotation.X; if (bMeshRotationActive && MeshRotationOffset > 0) { FMeshRotationPayloadData* PayloadData = (FMeshRotationPayloadData*)((uint8*)&Particle + MeshRotationOffset); PayloadData->RotationRateBase *= CollisionPayload.UsedDampingFactorRotation; } // Reset the current velocity and manually adjust location to bounce off based on normal and time of collision. FVector NewVelocity = Direction.MirrorByVector(Hit.Normal) * (Location - OldLocation).Size() * CollisionPayload.UsedDampingFactor; Particle.Velocity = FVector::ZeroVector; // New location FVector NewLocation = Location + NewVelocity * (1.f - Hit.Time); Particle.Location = OwnerTM.InverseTransformPosition(NewLocation); if (bApplyPhysics) { check(IsInGameThread()); UPrimitiveComponent* PrimitiveComponent = Hit.Component.Get(); if(PrimitiveComponent && PrimitiveComponent->IsAnySimulatingPhysics()) { FVector vImpulse; vImpulse = -(NewVelocity - OldVelocity) * ParticleMass.GetValue(Particle.RelativeTime, Owner->Component); PrimitiveComponent->AddImpulseAtLocation(vImpulse, Hit.Location, Hit.BoneName); } } } else { FVector vOldVelocity = Particle.Velocity; // Reflect base velocity and apply damping factor. Particle.BaseVelocity = Particle.BaseVelocity.MirrorByVector(Hit.Normal) * CollisionPayload.UsedDampingFactor; Particle.BaseRotationRate = Particle.BaseRotationRate * CollisionPayload.UsedDampingFactorRotation.X; if (bMeshRotationActive && MeshRotationOffset > 0) { FMeshRotationPayloadData* PayloadData = (FMeshRotationPayloadData*)((uint8*)&Particle + MeshRotationOffset); PayloadData->RotationRateBase *= CollisionPayload.UsedDampingFactorRotation; } // Reset the current velocity and manually adjust location to bounce off based on normal and time of collision. FVector vNewVelocity = Direction.MirrorByVector(Hit.Normal) * (Location - OldLocation).Size() * CollisionPayload.UsedDampingFactor; Particle.Velocity = FVector::ZeroVector; Particle.Location += vNewVelocity * (1.f - Hit.Time); if (bApplyPhysics) { check(IsInGameThread()); UPrimitiveComponent* PrimitiveComponent = Hit.Component.Get(); if(PrimitiveComponent && PrimitiveComponent->IsAnySimulatingPhysics()) { FVector vImpulse; vImpulse = -(vNewVelocity - vOldVelocity) * ParticleMass.GetValue(Particle.RelativeTime, Owner->Component); PrimitiveComponent->AddImpulseAtLocation(vImpulse, Hit.Location, Hit.BoneName); } } } if (EventPayload && (EventPayload->bCollisionEventsPresent == true)) { LODLevel->EventGenerator->HandleParticleCollision(Owner, EventPayload, &CollisionPayload, &Hit, &Particle, Direction); } } else { if (LODLevel->RequiredModule->bUseLocalSpace == true) { Size = OwnerTM.TransformVector(Size); } Particle.Location = Hit.Location + (Size / 2.0f); if (LODLevel->RequiredModule->bUseLocalSpace == true) { // We need to transform the location back relative to the PSys. // NOTE: LocalSpace makes sense only for stationary emitters that use collision. Particle.Location = OwnerTM.InverseTransformPosition(Particle.Location); } switch (CollisionCompletionOption) { case EPCC_Kill: { if (EventPayload && (EventPayload->bDeathEventsPresent == true)) { LODLevel->EventGenerator->HandleParticleKilled(Owner, EventPayload, &Particle); } KILL_CURRENT_PARTICLE; } break; case EPCC_Freeze: { Particle.Flags |= STATE_Particle_Freeze; } break; case EPCC_HaltCollisions: { Particle.Flags |= STATE_Particle_IgnoreCollisions; } break; case EPCC_FreezeTranslation: { Particle.Flags |= STATE_Particle_FreezeTranslation; } break; case EPCC_FreezeRotation: { Particle.Flags |= STATE_Particle_FreezeRotation; } break; case EPCC_FreezeMovement: { Particle.Flags |= STATE_Particle_FreezeRotation; Particle.Flags |= STATE_Particle_FreezeTranslation; } break; } if (EventPayload && (EventPayload->bCollisionEventsPresent == true)) { LODLevel->EventGenerator->HandleParticleCollision(Owner, EventPayload, &CollisionPayload, &Hit, &Particle, Direction); } } Particle.Flags |= STATE_Particle_CollisionHasOccurred; } } } END_UPDATE_LOOP; }
void AGameplayDebuggingReplicator::OnDebugAIDelegate(class UCanvas* Canvas, class APlayerController* PC) { #if WITH_EDITOR && !(UE_BUILD_SHIPPING || UE_BUILD_TEST) if (!GIsEditor) { return; } if (!LocalPlayerOwner || IsGlobalInWorld()) { return; } UEditorEngine* EEngine = Cast<UEditorEngine>(GEngine); if (GFrameNumber == LastDrawAtFrame || !EEngine || !EEngine->bIsSimulatingInEditor) { return; } if (!Canvas || !Canvas->SceneView || Canvas->SceneView->bIsGameView == false) { return; } LastDrawAtFrame = GFrameNumber; FEngineShowFlags EngineShowFlags = Canvas && Canvas->SceneView && Canvas->SceneView->Family ? Canvas->SceneView->Family->EngineShowFlags : FEngineShowFlags(GIsEditor ? EShowFlagInitMode::ESFIM_Editor : EShowFlagInitMode::ESFIM_Game); if (!EngineShowFlags.DebugAI) { return; } EnableDraw(true); UWorld* World = GetWorld(); UGameplayDebuggingComponent* DebuggingComponent = GetDebugComponent(); if (World && DebuggingComponent && DebuggingComponent->GetOwnerRole() == ROLE_Authority) { UGameplayDebuggingControllerComponent* GDC = FindComponentByClass<UGameplayDebuggingControllerComponent>(); TArray<int32> OryginalReplicateViewDataCounters; OryginalReplicateViewDataCounters = DebuggingComponent->ReplicateViewDataCounters; for (uint32 Index = 0; Index < EAIDebugDrawDataView::MAX; ++Index) { DebuggingComponent->ReplicateViewDataCounters[Index] = GameplayDebuggerSettings(this).CheckFlag((EAIDebugDrawDataView::Type)Index) ? 1 : 0; } // looks like Simulate in UE4 Editor - let's find selected Pawn to debug AActor* FullSelectedTarget = NULL; for (FConstPawnIterator Iterator = World->GetPawnIterator(); Iterator; ++Iterator) { AActor* NewTarget = Cast<AActor>(*Iterator); if (NewTarget->IsSelected() && !FullSelectedTarget) { FullSelectedTarget = NewTarget; continue; } //We needs to collect data manually in Simulate DebuggingComponent->SetActorToDebug(NewTarget); DebuggingComponent->CollectDataToReplicate(NewTarget->IsSelected()); DrawDebugData(Canvas, PC); } const AActor* OldActor = LastSelectedActorToDebug; ServerSetActorToDebug(FullSelectedTarget); if (FullSelectedTarget) { DebuggingComponent->CollectDataToReplicate(true); DebuggingComponent->SetEQSIndex(ActiveEQSIndex); DrawDebugData(Canvas, PC); } if (GetSelectedActorToDebug() != OldActor) { DebuggingComponent->MarkRenderStateDirty(); } DebuggingComponent->ReplicateViewDataCounters = OryginalReplicateViewDataCounters; } #endif }
void AGameplayDebuggerReplicator::TickActor(float DeltaTime, enum ELevelTick TickType, FActorTickFunction& ThisTickFunction) { Super::TickActor(DeltaTime, TickType, ThisTickFunction); #if ENABLED_GAMEPLAY_DEBUGGER UWorld* World = GetWorld(); const ENetMode NetMode = GetNetMode(); if (!World) { // return without world return; } UGameInstance* GameInstance = World->GetGameInstance(); if (!GameInstance || !World->IsGameWorld()) { return; } if (NetMode != NM_DedicatedServer) { if (bActivationKeyPressed) { ActivationKeyTime += DeltaTime; if (ActivationKeyTime >= GameplayDebuggerHelpers::ActivationKeyTimePch) { GEngine->bEnableOnScreenDebugMessages = false; if (AHUD* const GameHUD = LocalPlayerOwner ? LocalPlayerOwner->GetHUD() : nullptr) { GameHUD->bShowHUD = false; } BindKeyboardInput(InputComponent); ServerActivateGameplayDebugger(true); ClientActivateGameplayDebugger(true); bActivationKeyPressed = false; } } if (bEnabledTargetSelection) { if (GetLocalPlayerOwner()) { SelectTargetToDebug(); } } bool bMarkComponentsAsRenderStateDirty = false; for (UGameplayDebuggerBaseObject* Obj : ReplicatedObjects) { if (Obj && Obj->IsRenderStateDirty()) { if (!bMarkComponentsAsRenderStateDirty) { MarkComponentsRenderStateDirty(); } bMarkComponentsAsRenderStateDirty = true; Obj->CleanRenderStateDirtyFlag(); } } } if (NetMode < NM_Client && LocalPlayerOwner) { TMap<FString, TArray<UGameplayDebuggerBaseObject*> > CategoryToClasses; for (UGameplayDebuggerBaseObject* Obj : ReplicatedObjects) { if (Obj) { FString Category = Obj->GetCategoryName(); if (IsCategoryEnabled(Category)) { CategoryToClasses.FindOrAdd(Category).Add(Obj); } } } for (auto It(CategoryToClasses.CreateIterator()); It; ++It) { TArray<UGameplayDebuggerBaseObject*>& CurrentObjects = It.Value(); for (UGameplayDebuggerBaseObject* Obj : CurrentObjects) { Obj->CollectDataToReplicateOnServer(LocalPlayerOwner, LastSelectedActorToDebug); } } } #endif }
bool SVisualLogger::HandleCameraCommandCanExecute() const { UWorld* World = FLogVisualizer::Get().GetWorld(); return FVisualLogger::Get().IsRecording() && World && (World->bPlayersOnly || World->bPlayersOnlyPending) && World->IsPlayInEditor() && (GEditor && !GEditor->bIsSimulatingInEditor); }
TSharedRef< SWidget > FLevelEditorToolBar::GenerateOpenBlueprintMenuContent( TSharedRef<FUICommandList> InCommandList, TWeakPtr< SLevelEditor > InLevelEditor ) { #define LOCTEXT_NAMESPACE "LevelToolBarViewMenu" struct FBlueprintMenus { /** Generates a sub-level Blueprints sub-menu */ static void MakeSubLevelsMenu(FMenuBuilder& InMenuBuilder, TWeakPtr< SLevelEditor > InLvlEditor) { FSlateIcon EditBP(FEditorStyle::Get().GetStyleSetName(), TEXT("LevelEditor.OpenLevelBlueprint")); InMenuBuilder.BeginSection(NAME_None, LOCTEXT("SubLevelsHeading", "Sub-Level Blueprints")); { UWorld* World = InLvlEditor.Pin()->GetWorld(); for (int32 iLevel = 0; iLevel < World->GetNumLevels(); iLevel++) { ULevel* Level = World->GetLevel(iLevel); if (Level != NULL && Level->GetOutermost() != NULL) { if (!Level->IsPersistentLevel()) { FUIAction UIAction ( FExecuteAction::CreateStatic(&FLevelEditorToolBar::OnOpenSubLevelBlueprint, Level) ); FText DisplayName = FText::Format(LOCTEXT("SubLevelBlueprintItem", "Edit {LevelName}"), FText::FromString(FPaths::GetCleanFilename(Level->GetOutermost()->GetName()))); InMenuBuilder.AddMenuEntry(DisplayName, FText::GetEmpty(), EditBP, UIAction); } } } } InMenuBuilder.EndSection(); } /** Handle BP being selected from popup picker */ static void OnBPSelected(const class FAssetData& AssetData) { UBlueprint* SelectedBP = Cast<UBlueprint>(AssetData.GetAsset()); if(SelectedBP) { FAssetEditorManager::Get().OpenEditorForAsset(SelectedBP); } } /** Generates 'eopn blueprint' sub-menu */ static void MakeOpenClassBPMenu(FMenuBuilder& InMenuBuilder) { FContentBrowserModule& ContentBrowserModule = FModuleManager::Get().LoadModuleChecked<FContentBrowserModule>(TEXT("ContentBrowser")); // Configure filter for asset picker FAssetPickerConfig Config; Config.Filter.ClassNames.Add(UBlueprint::StaticClass()->GetFName()); Config.InitialAssetViewType = EAssetViewType::List; Config.ThumbnailScale = 0; // make thumbnails as small as possible Config.OnAssetSelected = FOnAssetSelected::CreateStatic(&FBlueprintMenus::OnBPSelected); Config.bAllowDragging = false; // Don't show stuff in Engine Config.Filter.PackagePaths.Add("/Game"); Config.Filter.bRecursivePaths = true; TSharedRef<SWidget> Widget = SNew(SBox) .WidthOverride(300.f) .HeightOverride(300.f) [ ContentBrowserModule.Get().CreateAssetPicker(Config) ]; InMenuBuilder.BeginSection(NAME_None, LOCTEXT("BrowseHeader", "Browse")); { InMenuBuilder.AddWidget(Widget, FText::GetEmpty()); } InMenuBuilder.EndSection(); } }; const bool bShouldCloseWindowAfterMenuSelection = true; FMenuBuilder MenuBuilder( bShouldCloseWindowAfterMenuSelection, InCommandList ); MenuBuilder.BeginSection(NAME_None, LOCTEXT("LevelScriptBlueprints", "Level Blueprints")); { MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().OpenLevelBlueprint ); // If there are any sub-levels, display the sub-menu. A single level means there is only the persistent level UWorld* World = InLevelEditor.Pin()->GetWorld(); if(World->GetNumLevels() > 1) { MenuBuilder.AddSubMenu( LOCTEXT( "SubLevelsSubMenu", "Sub-Levels" ), LOCTEXT( "SubLevelsSubMenu_ToolTip", "Shows available sub-level Blueprints that can be edited." ), FNewMenuDelegate::CreateStatic( &FBlueprintMenus::MakeSubLevelsMenu, InLevelEditor ), FUIAction(), NAME_None, EUserInterfaceActionType::Button, false, FSlateIcon(FEditorStyle::Get().GetStyleSetName(), TEXT("LevelEditor.OpenLevelBlueprint")) ); } } MenuBuilder.EndSection(); MenuBuilder.BeginSection(NAME_None, LOCTEXT("GameBlueprints", "Game Blueprints")); { FSlateIcon EditBPIcon(FEditorStyle::Get().GetStyleSetName(), TEXT("PropertyWindow.Button_Edit")); FSlateIcon NewBPIcon(FEditorStyle::Get().GetStyleSetName(), TEXT("PropertyWindow.Button_AddToArray")); // Game Mode TAttribute<FText>::FGetter DynamicGameModeGetter; DynamicGameModeGetter.BindStatic(&FLevelEditorToolBar::GetOpenGameModeBlueprintLabel, InLevelEditor); TAttribute<FText> DynamicGameModeLabel = TAttribute<FText>::Create(DynamicGameModeGetter); TAttribute<FText>::FGetter DynamicGameModeGetter_Tooltip; DynamicGameModeGetter_Tooltip.BindStatic(&FLevelEditorToolBar::GetOpenGameModeBlueprintTooltip, InLevelEditor); TAttribute<FText> DynamicGameModeTooltip = TAttribute<FText>::Create(DynamicGameModeGetter_Tooltip); MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().OpenGameModeBlueprint, NAME_None, DynamicGameModeLabel, DynamicGameModeTooltip, IsValidGameModeBlueprint(InLevelEditor)? EditBPIcon : NewBPIcon ); // Game State TAttribute<FText>::FGetter DynamicGameStateGetter; DynamicGameStateGetter.BindStatic(&FLevelEditorToolBar::GetOpenGameStateBlueprintLabel, InLevelEditor); TAttribute<FText> DynamicGameStateLabel = TAttribute<FText>::Create(DynamicGameStateGetter); TAttribute<FText>::FGetter DynamicGameStateGetter_Tooltip; DynamicGameStateGetter_Tooltip.BindStatic(&FLevelEditorToolBar::GetOpenGameStateBlueprintTooltip, InLevelEditor); TAttribute<FText> DynamicGameStateTooltip = TAttribute<FText>::Create(DynamicGameStateGetter_Tooltip); MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().OpenGameStateBlueprint, NAME_None, DynamicGameStateLabel, DynamicGameStateTooltip, IsValidGameStateBlueprint(InLevelEditor)? EditBPIcon : NewBPIcon ); // Pawn TAttribute<FText>::FGetter DynamicDefaultPawnGetter; DynamicDefaultPawnGetter.BindStatic(&FLevelEditorToolBar::GetOpenPawnBlueprintLabel, InLevelEditor); TAttribute<FText> DynamicDefaultPawnLabel = TAttribute<FText>::Create(DynamicDefaultPawnGetter); TAttribute<FText>::FGetter DynamicDefaultPawnGetter_Tooltip; DynamicDefaultPawnGetter_Tooltip.BindStatic(&FLevelEditorToolBar::GetOpenPawnBlueprintTooltip, InLevelEditor); TAttribute<FText> DynamicDefaultPawnTooltip = TAttribute<FText>::Create(DynamicDefaultPawnGetter_Tooltip); MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().OpenDefaultPawnBlueprint, NAME_None, DynamicDefaultPawnLabel, DynamicDefaultPawnTooltip, IsValidPawnBlueprint(InLevelEditor)? EditBPIcon : NewBPIcon ); // HUD TAttribute<FText>::FGetter DynamicHUDGetter; DynamicHUDGetter.BindStatic(&FLevelEditorToolBar::GetOpenHUDBlueprintLabel, InLevelEditor); TAttribute<FText> DynamicHUDLabel = TAttribute<FText>::Create(DynamicHUDGetter); TAttribute<FText>::FGetter DynamicHUDGetter_Tooltip; DynamicHUDGetter_Tooltip.BindStatic(&FLevelEditorToolBar::GetOpenHUDBlueprintTooltip, InLevelEditor); TAttribute<FText> DynamicHUDTooltip = TAttribute<FText>::Create(DynamicHUDGetter_Tooltip); MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().OpenHUDBlueprint, NAME_None, DynamicHUDLabel, DynamicHUDTooltip, IsValidHUDBlueprint(InLevelEditor)? EditBPIcon : NewBPIcon ); // Player Controller TAttribute<FText>::FGetter DynamicPlayerControllerGetter; DynamicPlayerControllerGetter.BindStatic(&FLevelEditorToolBar::GetOpenPlayerControllerBlueprintLabel, InLevelEditor); TAttribute<FText> DynamicPlayerControllerLabel = TAttribute<FText>::Create(DynamicPlayerControllerGetter); TAttribute<FText>::FGetter DynamicPlayerControllerGetter_Tooltip; DynamicPlayerControllerGetter_Tooltip.BindStatic(&FLevelEditorToolBar::GetOpenPlayerControllerBlueprintTooltip, InLevelEditor); TAttribute<FText> DynamicPlayerControllerTooltip = TAttribute<FText>::Create(DynamicPlayerControllerGetter_Tooltip); MenuBuilder.AddMenuEntry( FLevelEditorCommands::Get().OpenPlayerControllerBlueprint, NAME_None, DynamicPlayerControllerLabel, DynamicPlayerControllerTooltip, IsValidPlayerControllerBlueprint(InLevelEditor)? EditBPIcon : NewBPIcon ); } MenuBuilder.EndSection(); MenuBuilder.BeginSection(NAME_None, LOCTEXT("ClassBlueprints", "Class Blueprints")); { // New Class Blueprint... MenuBuilder.AddMenuEntry(FLevelEditorCommands::Get().CreateClassBlueprint, NAME_None, LOCTEXT("NewClassBlueprint", "New Class Blueprint...")); // Open Class Blueprint... FSlateIcon OpenBPIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.OpenClassBlueprint"); MenuBuilder.AddSubMenu( LOCTEXT("OpenClassBlueprintSubMenu", "Open Class Blueprint..."), LOCTEXT("OpenClassBlueprintSubMenu_ToolTip", "Open an existing Class Blueprint in this project"), FNewMenuDelegate::CreateStatic(&FBlueprintMenus::MakeOpenClassBPMenu), false, OpenBPIcon ); } MenuBuilder.EndSection(); #undef LOCTEXT_NAMESPACE return MenuBuilder.MakeWidget(); }
void AActor::RerunConstructionScripts() { FEditorScriptExecutionGuard ScriptGuard; // don't allow (re)running construction scripts on dying actors bool bAllowReconstruction = !IsPendingKill() && !HasAnyFlags(RF_BeginDestroyed|RF_FinishDestroyed); #if WITH_EDITOR if(bAllowReconstruction && GIsEditor) { // Generate the blueprint hierarchy for this actor TArray<UBlueprint*> ParentBPStack; bAllowReconstruction = UBlueprint::GetBlueprintHierarchyFromClass(GetClass(), ParentBPStack); if(bAllowReconstruction) { for(int i = ParentBPStack.Num() - 1; i > 0 && bAllowReconstruction; --i) { const UBlueprint* ParentBP = ParentBPStack[i]; if(ParentBP && ParentBP->bBeingCompiled) { // don't allow (re)running construction scripts if a parent BP is being compiled bAllowReconstruction = false; } } } } #endif if(bAllowReconstruction) { // Set global flag to let system know we are reconstructing blueprint instances TGuardValue<bool> GuardTemplateNameFlag(GIsReconstructingBlueprintInstances, true); // Temporarily suspend the undo buffer; we don't need to record reconstructed component objects into the current transaction ITransaction* CurrentTransaction = GUndo; GUndo = NULL; // Create cache to store component data across rerunning construction scripts #if WITH_EDITOR FActorTransactionAnnotation* ActorTransactionAnnotation = CurrentTransactionAnnotation.Get(); #endif FComponentInstanceDataCache* InstanceDataCache; FTransform OldTransform = FTransform::Identity; FName SocketName; AActor* Parent = NULL; USceneComponent* ParentComponent = NULL; bool bUseRootComponentProperties = true; // Struct to store info about attached actors struct FAttachedActorInfo { AActor* AttachedActor; FName AttachedToSocket; bool bSetRelativeTransform; FTransform RelativeTransform; }; // Save info about attached actors TArray<FAttachedActorInfo> AttachedActorInfos; #if WITH_EDITOR if (ActorTransactionAnnotation) { InstanceDataCache = &ActorTransactionAnnotation->ComponentInstanceData; if (ActorTransactionAnnotation->bRootComponentDataCached) { OldTransform = ActorTransactionAnnotation->RootComponentData.Transform; Parent = ActorTransactionAnnotation->RootComponentData.AttachedParentInfo.Actor.Get(); if (Parent) { DetachRootComponentFromParent(); SocketName = ActorTransactionAnnotation->RootComponentData.AttachedParentInfo.SocketName; } for (const auto& CachedAttachInfo : ActorTransactionAnnotation->RootComponentData.AttachedToInfo) { AActor* AttachedActor = CachedAttachInfo.Actor.Get(); if (AttachedActor) { FAttachedActorInfo Info; Info.AttachedActor = AttachedActor; Info.AttachedToSocket = CachedAttachInfo.SocketName; Info.bSetRelativeTransform = true; Info.RelativeTransform = CachedAttachInfo.RelativeTransform; AttachedActorInfos.Add(Info); AttachedActor->DetachRootComponentFromParent(); } } bUseRootComponentProperties = false; } } else #endif { InstanceDataCache = new FComponentInstanceDataCache(this); // If there are attached objects detach them and store the socket names TArray<AActor*> AttachedActors; GetAttachedActors(AttachedActors); for (AActor* AttachedActor : AttachedActors) { USceneComponent* EachRoot = AttachedActor->GetRootComponent(); // If the component we are attached to is about to go away... if (EachRoot && EachRoot->AttachParent && EachRoot->AttachParent->bCreatedByConstructionScript) { // Save info about actor to reattach FAttachedActorInfo Info; Info.AttachedActor = AttachedActor; Info.AttachedToSocket = EachRoot->AttachSocketName; Info.bSetRelativeTransform = false; AttachedActorInfos.Add(Info); // Now detach it AttachedActor->Modify(); EachRoot->DetachFromParent(true); } } } if (bUseRootComponentProperties && RootComponent != nullptr) { // Do not need to detach if root component is not going away if (RootComponent->AttachParent != NULL && RootComponent->bCreatedByConstructionScript) { Parent = RootComponent->AttachParent->GetOwner(); // Root component should never be attached to another component in the same actor! if (Parent == this) { UE_LOG(LogActor, Warning, TEXT("RerunConstructionScripts: RootComponent (%s) attached to another component in this Actor (%s)."), *RootComponent->GetPathName(), *Parent->GetPathName()); Parent = NULL; } ParentComponent = RootComponent->AttachParent; SocketName = RootComponent->AttachSocketName; //detach it to remove any scaling RootComponent->DetachFromParent(true); } OldTransform = RootComponent->ComponentToWorld; OldTransform.SetTranslation(RootComponent->GetComponentLocation()); // take into account any custom location } // Destroy existing components DestroyConstructedComponents(); // Reset random streams ResetPropertiesForConstruction(); // Exchange net roles before running construction scripts UWorld *OwningWorld = GetWorld(); if (OwningWorld && !OwningWorld->IsServer()) { ExchangeNetRoles(true); } // Run the construction scripts ExecuteConstruction(OldTransform, InstanceDataCache); if(Parent) { USceneComponent* ChildRoot = GetRootComponent(); if (ParentComponent == NULL) { ParentComponent = Parent->GetRootComponent(); } if (ChildRoot != NULL && ParentComponent != NULL) { ChildRoot->AttachTo(ParentComponent, SocketName, EAttachLocation::KeepWorldPosition); } } // If we had attached children reattach them now - unless they are already attached for(FAttachedActorInfo& Info : AttachedActorInfos) { // If this actor is no longer attached to anything, reattach if (!Info.AttachedActor->IsPendingKill() && Info.AttachedActor->GetAttachParentActor() == NULL) { USceneComponent* ChildRoot = Info.AttachedActor->GetRootComponent(); if (ChildRoot && ChildRoot->AttachParent != RootComponent) { ChildRoot->AttachTo(RootComponent, Info.AttachedToSocket, EAttachLocation::KeepWorldPosition); if (Info.bSetRelativeTransform) { ChildRoot->SetRelativeTransform(Info.RelativeTransform); } ChildRoot->UpdateComponentToWorld(); } } } // Restore the undo buffer GUndo = CurrentTransaction; #if WITH_EDITOR if (ActorTransactionAnnotation) { CurrentTransactionAnnotation = NULL; } else #endif { delete InstanceDataCache; } } }
void UGameplayDebuggingComponent::ServerCollectNavmeshData_Implementation(FVector_NetQuantize10 TargetLocation) { #if WITH_RECAST UNavigationSystem* NavSys = UNavigationSystem::GetCurrent(GetWorld()); ARecastNavMesh* NavData = GetNavData(); if (NavData == NULL) { NavmeshRepData.Empty(); return; } const double Timer1 = FPlatformTime::Seconds(); TArray<int32> Indices; int32 TileX = 0; int32 TileY = 0; const int32 DeltaX[] = { 0, 1, 1, 0, -1, -1, -1, 0, 1 }; const int32 DeltaY[] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 }; NavData->BeginBatchQuery(); // add 3x3 neighborhood of target int32 TargetTileX = 0; int32 TargetTileY = 0; NavData->GetNavMeshTileXY(TargetLocation, TargetTileX, TargetTileY); for (int32 i = 0; i < ARRAY_COUNT(DeltaX); i++) { const int32 NeiX = TargetTileX + DeltaX[i]; const int32 NeiY = TargetTileY + DeltaY[i]; if (FMath::Abs(NeiX - TileX) > 1 || FMath::Abs(NeiY - TileY) > 1) { NavData->GetNavMeshTilesAt(NeiX, NeiY, Indices); } } const FNavDataConfig& NavConfig = NavData->GetConfig(); FColor NavMeshColors[RECAST_MAX_AREAS]; NavMeshColors[RECAST_DEFAULT_AREA] = NavConfig.Color.DWColor() > 0 ? NavConfig.Color : NavMeshRenderColor_RecastMesh; for (uint8 i = 0; i < RECAST_DEFAULT_AREA; ++i) { NavMeshColors[i] = NavData->GetAreaIDColor(i); } TArray<uint8> UncompressedBuffer; FMemoryWriter ArWriter(UncompressedBuffer); int32 NumIndices = Indices.Num(); ArWriter << NumIndices; for (int32 i = 0; i < NumIndices; i++) { FRecastDebugGeometry NavMeshGeometry; NavMeshGeometry.bGatherPolyEdges = false; NavMeshGeometry.bGatherNavMeshEdges = false; NavData->GetDebugGeometry(NavMeshGeometry, Indices[i]); NavMeshDebug::FTileData TileData; const FBox TileBoundingBox = NavData->GetNavMeshTileBounds(Indices[i]); TileData.Location = TileBoundingBox.GetCenter(); for (int32 VertIndex = 0; VertIndex < NavMeshGeometry.MeshVerts.Num(); ++VertIndex) { const NavMeshDebug::FShortVector SV = NavMeshGeometry.MeshVerts[VertIndex] - TileData.Location; TileData.Verts.Add(SV); } for (int32 iArea = 0; iArea < RECAST_MAX_AREAS; iArea++) { const int32 NumTris = NavMeshGeometry.AreaIndices[iArea].Num(); if (NumTris) { NavMeshDebug::FAreaPolys AreaPolys; for (int32 AreaIndicesIndex = 0; AreaIndicesIndex < NavMeshGeometry.AreaIndices[iArea].Num(); ++AreaIndicesIndex) { AreaPolys.Indices.Add(NavMeshGeometry.AreaIndices[iArea][AreaIndicesIndex]); } AreaPolys.Color = NavMeshColors[iArea]; TileData.Areas.Add(AreaPolys); } } TileData.Links.Reserve(NavMeshGeometry.OffMeshLinks.Num()); for (int32 iLink = 0; iLink < NavMeshGeometry.OffMeshLinks.Num(); iLink++) { const FRecastDebugGeometry::FOffMeshLink& SrcLink = NavMeshGeometry.OffMeshLinks[iLink]; NavMeshDebug::FOffMeshLink Link; Link.Left = SrcLink.Left - TileData.Location; Link.Right = SrcLink.Right - TileData.Location; Link.Color = ((SrcLink.Direction && SrcLink.ValidEnds) || (SrcLink.ValidEnds & FRecastDebugGeometry::OMLE_Left)) ? DarkenColor(NavMeshColors[SrcLink.AreaID]) : NavMeshRenderColor_OffMeshConnectionInvalid; Link.PackedFlags.Radius = (int8)SrcLink.Radius; Link.PackedFlags.Direction = SrcLink.Direction; Link.PackedFlags.ValidEnds = SrcLink.ValidEnds; TileData.Links.Add(Link); } ArWriter << TileData; } NavData->FinishBatchQuery(); const double Timer2 = FPlatformTime::Seconds(); const int32 HeaderSize = sizeof(int32); NavmeshRepData.Init(0, HeaderSize + FMath::TruncToInt(1.1f * UncompressedBuffer.Num())); const int32 UncompressedSize = UncompressedBuffer.Num(); int32 CompressedSize = NavmeshRepData.Num() - HeaderSize; uint8* DestBuffer = NavmeshRepData.GetData(); FMemory::Memcpy(DestBuffer, &UncompressedSize, HeaderSize); DestBuffer += HeaderSize; FCompression::CompressMemory((ECompressionFlags)(COMPRESS_ZLIB | COMPRESS_BiasMemory), (void*)DestBuffer, CompressedSize, (void*)UncompressedBuffer.GetData(), UncompressedSize); NavmeshRepData.SetNum(CompressedSize + HeaderSize, false); const double Timer3 = FPlatformTime::Seconds(); UE_LOG(LogGDT, Log, TEXT("Preparing navmesh data: %.1fkB took %.3fms (collect: %.3fms + compress %d%%: %.3fms)"), NavmeshRepData.Num() / 1024.0f, 1000.0f * (Timer3 - Timer1), 1000.0f * (Timer2 - Timer1), FMath::TruncToInt(100.0f * NavmeshRepData.Num() / UncompressedBuffer.Num()), 1000.0f * (Timer3 - Timer2)); #endif if (World && World->GetNetMode() != NM_DedicatedServer) { OnRep_UpdateNavmesh(); } }
void UMaterialParameterCollection::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) { // If the array counts have changed, an element has been added or removed, and we need to update the uniform buffer layout, // Which also requires recompiling any referencing materials if (ScalarParameters.Num() != PreviousScalarParameters.Num() || VectorParameters.Num() != PreviousVectorParameters.Num()) { // Limit the count of parameters to fit within uniform buffer limits const uint32 MaxScalarParameters = 1024; if (ScalarParameters.Num() > MaxScalarParameters) { ScalarParameters.RemoveAt(MaxScalarParameters, ScalarParameters.Num() - MaxScalarParameters); } const uint32 MaxVectorParameters = 1024; if (VectorParameters.Num() > MaxVectorParameters) { VectorParameters.RemoveAt(MaxVectorParameters, VectorParameters.Num() - MaxVectorParameters); } // Generate a new Id so that unloaded materials that reference this collection will update correctly on load StateId = FGuid::NewGuid(); // Update the uniform buffer layout CreateBufferStruct(); // Recreate each instance of this collection for (TObjectIterator<UWorld> It; It; ++It) { UWorld* CurrentWorld = *It; CurrentWorld->AddParameterCollectionInstance(this, false); } // Build set of changed parameter names TSet<FName> ParameterNames; for (const FCollectionVectorParameter& Param : PreviousVectorParameters) { ParameterNames.Add(Param.ParameterName); } for (const FCollectionScalarParameter& Param : PreviousScalarParameters) { ParameterNames.Add(Param.ParameterName); } for (const FCollectionVectorParameter& Param : VectorParameters) { ParameterNames.Remove(Param.ParameterName); } for (const FCollectionScalarParameter& Param : ScalarParameters) { ParameterNames.Remove(Param.ParameterName); } // Create a material update context so we can safely update materials using this parameter collection. { FMaterialUpdateContext UpdateContext; // Go through all materials in memory and recompile them if they use this material parameter collection for (TObjectIterator<UMaterial> It; It; ++It) { UMaterial* CurrentMaterial = *It; bool bRecompile = false; // Preview materials often use expressions for rendering that are not in their Expressions array, // And therefore their MaterialParameterCollectionInfos are not up to date. if (CurrentMaterial->bIsPreviewMaterial) { bRecompile = true; } else { for (int32 FunctionIndex = 0; FunctionIndex < CurrentMaterial->MaterialParameterCollectionInfos.Num() && !bRecompile; FunctionIndex++) { if (CurrentMaterial->MaterialParameterCollectionInfos[FunctionIndex].ParameterCollection == this) { TArray<UMaterialExpressionCollectionParameter*> CollectionParameters; CurrentMaterial->GetAllExpressionsInMaterialAndFunctionsOfType(CollectionParameters); for (UMaterialExpressionCollectionParameter* CollectionParameter : CollectionParameters) { if (ParameterNames.Contains(CollectionParameter->ParameterName)) { bRecompile = true; break; } } } } } if (bRecompile) { UpdateContext.AddMaterial(CurrentMaterial); // Propagate the change to this material CurrentMaterial->PreEditChange(NULL); CurrentMaterial->PostEditChange(); CurrentMaterial->MarkPackageDirty(); } } } } // Update each world's scene with the new instance, and update each instance's uniform buffer to reflect the changes made by the user for (TObjectIterator<UWorld> It; It; ++It) { UWorld* CurrentWorld = *It; CurrentWorld->UpdateParameterCollectionInstances(true); } PreviousScalarParameters.Empty(); PreviousVectorParameters.Empty(); Super::PostEditChangeProperty(PropertyChangedEvent); }
void AOnlineBeaconHost::NotifyControlMessage(UNetConnection* Connection, uint8 MessageType, class FInBunch& Bunch) { if(NetDriver->ServerConnection == nullptr) { bool bCloseConnection = false; // We are the server. #if !(UE_BUILD_SHIPPING && WITH_EDITOR) UE_LOG(LogBeacon, Verbose, TEXT("%s[%s] Host received: %s"), *GetName(), Connection ? *Connection->GetName() : TEXT("Invalid"), FNetControlMessageInfo::GetName(MessageType)); #endif switch (MessageType) { case NMT_Hello: { UE_LOG(LogBeacon, Log, TEXT("Beacon Hello")); uint8 IsLittleEndian; uint32 RemoteNetworkVersion = 0; uint32 LocalNetworkVersion = FNetworkVersion::GetLocalNetworkVersion(); FNetControlMessage<NMT_Hello>::Receive(Bunch, IsLittleEndian, RemoteNetworkVersion); if (!FNetworkVersion::IsNetworkCompatible(LocalNetworkVersion, RemoteNetworkVersion)) { UE_LOG(LogBeacon, Log, TEXT("Client not network compatible %s"), *Connection->GetName()); FNetControlMessage<NMT_Upgrade>::Send(Connection, LocalNetworkVersion); bCloseConnection = true; } else { Connection->Challenge = FString::Printf(TEXT("%08X"), FPlatformTime::Cycles()); FNetControlMessage<NMT_BeaconWelcome>::Send(Connection); Connection->FlushNet(); } break; } case NMT_Netspeed: { int32 Rate; FNetControlMessage<NMT_Netspeed>::Receive(Bunch, Rate); Connection->CurrentNetSpeed = FMath::Clamp(Rate, 1800, NetDriver->MaxClientRate); UE_LOG(LogBeacon, Log, TEXT("Client netspeed is %i"), Connection->CurrentNetSpeed); break; } case NMT_BeaconJoin: { FString ErrorMsg; FString BeaconType; FUniqueNetIdRepl UniqueId; FNetControlMessage<NMT_BeaconJoin>::Receive(Bunch, BeaconType, UniqueId); UE_LOG(LogBeacon, Log, TEXT("Beacon Join %s %s"), *BeaconType, *UniqueId.ToDebugString()); if (Connection->ClientWorldPackageName == NAME_None) { AOnlineBeaconClient* ClientActor = GetClientActor(Connection); if (ClientActor == nullptr) { UWorld* World = GetWorld(); Connection->ClientWorldPackageName = World->GetOutermost()->GetFName(); AOnlineBeaconClient* NewClientActor = nullptr; FOnBeaconSpawned* OnBeaconSpawnedDelegate = OnBeaconSpawnedMapping.Find(BeaconType); if (OnBeaconSpawnedDelegate && OnBeaconSpawnedDelegate->IsBound()) { NewClientActor = OnBeaconSpawnedDelegate->Execute(Connection); } if (NewClientActor && BeaconType == NewClientActor->GetBeaconType()) { NewClientActor->SetConnectionState(EBeaconConnectionState::Pending); FNetworkGUID NetGUID = Connection->Driver->GuidCache->AssignNewNetGUID_Server(NewClientActor); NewClientActor->SetNetConnection(Connection); Connection->PlayerId = UniqueId; Connection->OwningActor = NewClientActor; NewClientActor->Role = ROLE_Authority; NewClientActor->SetReplicates(false); check(NetDriverName == NetDriver->NetDriverName); NewClientActor->SetNetDriverName(NetDriverName); ClientActors.Add(NewClientActor); FNetControlMessage<NMT_BeaconAssignGUID>::Send(Connection, NetGUID); } else { ErrorMsg = NSLOCTEXT("NetworkErrors", "BeaconSpawnFailureError", "Join failure, Couldn't spawn beacon.").ToString(); } } else { ErrorMsg = NSLOCTEXT("NetworkErrors", "BeaconSpawnExistingActorError", "Join failure, existing beacon actor.").ToString(); } } else { ErrorMsg = NSLOCTEXT("NetworkErrors", "BeaconSpawnClientWorldPackageNameError", "Join failure, existing ClientWorldPackageName.").ToString(); } if (!ErrorMsg.IsEmpty()) { UE_LOG(LogBeacon, Log, TEXT("%s: %s"), *Connection->GetName(), *ErrorMsg); FNetControlMessage<NMT_Failure>::Send(Connection, ErrorMsg); bCloseConnection = true; } break; } case NMT_BeaconNetGUIDAck: { FString ErrorMsg; FString BeaconType; FNetControlMessage<NMT_BeaconNetGUIDAck>::Receive(Bunch, BeaconType); AOnlineBeaconClient* ClientActor = GetClientActor(Connection); if (ClientActor && BeaconType == ClientActor->GetBeaconType()) { FOnBeaconConnected* OnBeaconConnectedDelegate = OnBeaconConnectedMapping.Find(BeaconType); if (OnBeaconConnectedDelegate) { ClientActor->SetReplicates(true); ClientActor->SetAutonomousProxy(true); ClientActor->SetConnectionState(EBeaconConnectionState::Open); // Send an RPC to the client to open the actor channel and guarantee RPCs will work ClientActor->ClientOnConnected(); UE_LOG(LogBeacon, Log, TEXT("Handshake complete for %s!"), *ClientActor->GetName()); OnBeaconConnectedDelegate->ExecuteIfBound(ClientActor, Connection); } else { // Failed to connect. ErrorMsg = NSLOCTEXT("NetworkErrors", "BeaconSpawnNetGUIDAckError1", "Join failure, no host object at NetGUIDAck.").ToString(); } } else { // Failed to connect. ErrorMsg = NSLOCTEXT("NetworkErrors", "BeaconSpawnNetGUIDAckError2", "Join failure, no actor at NetGUIDAck.").ToString(); } if (!ErrorMsg.IsEmpty()) { UE_LOG(LogBeacon, Log, TEXT("%s: %s"), *Connection->GetName(), *ErrorMsg); FNetControlMessage<NMT_Failure>::Send(Connection, ErrorMsg); bCloseConnection = true; } break; } case NMT_BeaconWelcome: case NMT_BeaconAssignGUID: default: { FString ErrorMsg = NSLOCTEXT("NetworkErrors", "BeaconSpawnUnexpectedError", "Join failure, unexpected control message.").ToString(); UE_LOG(LogBeacon, Log, TEXT("%s: %s"), *Connection->GetName(), *ErrorMsg); FNetControlMessage<NMT_Failure>::Send(Connection, ErrorMsg); bCloseConnection = true; } break; } if (bCloseConnection) { UE_LOG(LogBeacon, Verbose, TEXT("Closing connection %s: %s"), *Connection->GetName(), *Connection->PlayerId.ToDebugString()); AOnlineBeaconClient* ClientActor = GetClientActor(Connection); if (ClientActor) { UE_LOG(LogBeacon, Verbose, TEXT("- BeaconActor: %s %s"), *ClientActor->GetName(), *ClientActor->GetBeaconType()); AOnlineBeaconHostObject* BeaconHostObject = GetHost(ClientActor->GetBeaconType()); if (BeaconHostObject) { UE_LOG(LogBeacon, Verbose, TEXT("- HostObject: %s"), *BeaconHostObject->GetName()); BeaconHostObject->NotifyClientDisconnected(ClientActor); } RemoveClientActor(ClientActor); } Connection->FlushNet(true); Connection->Close(); UE_LOG(LogBeacon, Verbose, TEXT("--------------------------------")); } } }
bool FGameplayDebuggerCompat::Exec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) { #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) bool bHandled = false; if (FParse::Command(&Cmd, TEXT("RunEQS")) && InWorld) { APlayerController* MyPC = InWorld->GetGameInstance() ? InWorld->GetGameInstance()->GetFirstLocalPlayerController() : nullptr; UAISystem* AISys = UAISystem::GetCurrent(*InWorld); UEnvQueryManager* EQS = AISys ? AISys->GetEnvironmentQueryManager() : NULL; if (MyPC && EQS) { AGameplayDebuggingReplicator* DebuggingReplicator = NULL; for (TActorIterator<AGameplayDebuggingReplicator> It(InWorld); It; ++It) { AGameplayDebuggingReplicator* A = *It; if (!A->IsPendingKill()) { DebuggingReplicator = A; if (!DebuggingReplicator->IsGlobalInWorld() && DebuggingReplicator->GetLocalPlayerOwner() == MyPC) { break; } } } UObject* Target = DebuggingReplicator != NULL ? DebuggingReplicator->GetSelectedActorToDebug() : NULL; FString QueryName = FParse::Token(Cmd, 0); if (Target) { AISys->RunEQS(QueryName, Target); } else { MyPC->ClientMessage(TEXT("No debugging target to run EQS")); } } bHandled = true; } else if (FParse::Command(&Cmd, TEXT("EnableGDT"))) { FString UniquePlayerId = FParse::Token(Cmd, 0); APlayerController* LocalPC = NULL; UWorld* MyWorld = InWorld; if (MyWorld == nullptr) { if (UniquePlayerId.Len() > 0) { // let's find correct world based on Player Id const TIndirectArray<FWorldContext> WorldContexts = GEngine->GetWorldContexts(); for (const FWorldContext& Context : WorldContexts) { if (Context.WorldType != EWorldType::Game && Context.WorldType != EWorldType::PIE) { continue; } UWorld *CurrentWorld = Context.World(); for (FConstPlayerControllerIterator Iterator = CurrentWorld->GetPlayerControllerIterator(); Iterator; ++Iterator) { APlayerController* PC = *Iterator; if (PC && PC->PlayerState->UniqueId.ToString() == UniquePlayerId) { LocalPC = PC; MyWorld = PC->GetWorld(); break; } } if (LocalPC && MyWorld) { break; } } } } if (LocalPC == nullptr && MyWorld != nullptr) { if (UniquePlayerId.Len() > 0) { for (FConstPlayerControllerIterator Iterator = MyWorld->GetPlayerControllerIterator(); Iterator; ++Iterator) { APlayerController* PlayerController = *Iterator; UE_LOG(LogGameplayDebugger, Log, TEXT("- Client: %s"), *PlayerController->PlayerState->UniqueId.ToString()); if (PlayerController && PlayerController->PlayerState->UniqueId.ToString() == UniquePlayerId) { LocalPC = PlayerController; break; } } } if (!LocalPC && MyWorld->GetNetMode() != NM_DedicatedServer) { LocalPC = MyWorld->GetGameInstance() ? MyWorld->GetGameInstance()->GetFirstLocalPlayerController() : nullptr; } } if (LocalPC != nullptr && MyWorld != nullptr) { if (MyWorld->GetNetMode() == NM_Client) { AGameplayDebuggingReplicator* Replicator = NULL; for (TActorIterator<AGameplayDebuggingReplicator> It(MyWorld); It; ++It) { Replicator = *It; if (Replicator && !Replicator->IsPendingKill()) { APlayerController* PCOwner = Replicator->GetLocalPlayerOwner(); if (LocalPC == PCOwner) { break; } } Replicator = NULL; } if (!Replicator) { LocalPC->ClientMessage(TEXT("Enabling GameplayDebugger on server, please wait for replicated data...")); if (LocalPC->PlayerState) { const FString ServerCheatString = FString::Printf(TEXT("cheat EnableGDT %s"), *LocalPC->PlayerState->UniqueId.ToString()); UE_LOG(LogGameplayDebugger, Warning, TEXT("Sending to Server: %s"), *ServerCheatString); LocalPC->ConsoleCommand(*ServerCheatString); } } else { if (Replicator->IsToolCreated() == false) { Replicator->CreateTool(); Replicator->EnableTool(); } else { Replicator->EnableDraw(!Replicator->IsDrawEnabled()); } } } else { UE_LOG(LogGameplayDebugger, Warning, TEXT("Got from client: EnableGDT %s"), *UniquePlayerId); { AGameplayDebuggingReplicator* Replicator = NULL; for (TActorIterator<AGameplayDebuggingReplicator> It(MyWorld); It; ++It) { Replicator = *It; if (Replicator && !Replicator->IsPendingKill()) { APlayerController* PCOwner = Replicator->GetLocalPlayerOwner(); if (LocalPC == PCOwner) { break; } } Replicator = NULL; } if (!Replicator) { CreateGameplayDebuggerForPlayerController(LocalPC); for (TActorIterator<AGameplayDebuggingReplicator> It(MyWorld); It; ++It) { Replicator = *It; if (Replicator && !Replicator->IsPendingKill()) { APlayerController* PCOwner = Replicator->GetLocalPlayerOwner(); if (LocalPC == PCOwner) { break; } } Replicator = NULL; } } if (MyWorld->GetNetMode() != NM_DedicatedServer) { if (Replicator && !Replicator->IsToolCreated()) { Replicator->CreateTool(); Replicator->EnableTool(); } } else { if (Replicator) { Replicator->ClientAutoActivate(); } } } } } bHandled = true; } return bHandled; #else return false; #endif //!(UE_BUILD_SHIPPING || UE_BUILD_TEST) }
void FFoliageInstanceBaseCache::CompactInstanceBaseCache(AInstancedFoliageActor* IFA) { UWorld* World = IFA->GetWorld(); if (!World || World->IsGameWorld()) { return; } FFoliageInstanceBaseCache& Cache = IFA->InstanceBaseCache; TSet<FFoliageInstanceBaseId> BasesInUse; for (auto& Pair : IFA->FoliageMeshes) { for (const auto& Pair : Pair.Value->ComponentHash) { if (Pair.Key != FFoliageInstanceBaseCache::InvalidBaseId) { BasesInUse.Add(Pair.Key); } } } // Look for any removed maps TSet<FFoliageInstanceBasePtr> InvalidBasePtrs; for (auto& Pair : Cache.InstanceBaseLevelMap) { const auto& WorldAsset = Pair.Key; bool bExists = (WorldAsset == World); // Check sub-levels if (!bExists) { const FName PackageName = FName(*FPackageName::ObjectPathToPackageName(WorldAsset.ToStringReference().ToString())); if (World->WorldComposition) { bExists = World->WorldComposition->DoesTileExists(PackageName); } else { bExists = (World->GetLevelStreamingForPackageName(PackageName) != nullptr); } } if (!bExists) { InvalidBasePtrs.Append(Pair.Value); Cache.InstanceBaseLevelMap.Remove(Pair.Key); } else { // Remove dead links for (int32 i = Pair.Value.Num()-1; i >= 0; --i) { // Base needs to be removed if it's not in use by existing instances or component was removed if (Pair.Value[i].IsNull() || !BasesInUse.Contains(Cache.GetInstanceBaseId(Pair.Value[i]))) { InvalidBasePtrs.Add(Pair.Value[i]); Pair.Value.RemoveAt(i); } } if (Pair.Value.Num() == 0) { Cache.InstanceBaseLevelMap.Remove(Pair.Key); } } } TSet<FFoliageInstanceBaseId> InvalidBaseIds; Cache.InstanceBaseInvMap.Empty(); // Look for any removed base components for (const auto& Pair : Cache.InstanceBaseMap) { const FFoliageInstanceBaseInfo& BaseInfo = Pair.Value; if (InvalidBasePtrs.Contains(BaseInfo.BasePtr)) { InvalidBaseIds.Add(Pair.Key); Cache.InstanceBaseMap.Remove(Pair.Key); } else { // Regenerate inverse map check(!Cache.InstanceBaseInvMap.Contains(BaseInfo.BasePtr)); Cache.InstanceBaseInvMap.Add(BaseInfo.BasePtr, Pair.Key); } } if (InvalidBaseIds.Num()) { for (auto& Pair : IFA->FoliageMeshes) { auto& MeshInfo = Pair.Value; MeshInfo->ComponentHash.Empty(); int32 InstanceIdx = 0; for (FFoliageInstance& Instance : MeshInfo->Instances) { if (InvalidBaseIds.Contains(Instance.BaseId)) { Instance.BaseId = FFoliageInstanceBaseCache::InvalidBaseId; } MeshInfo->ComponentHash.FindOrAdd(Instance.BaseId).Add(InstanceIdx); InstanceIdx++; } } Cache.InstanceBaseMap.Compact(); Cache.InstanceBaseLevelMap.Compact(); } }
PyObject *py_ue_actor_spawn(ue_PyUObject * self, PyObject * args, PyObject *kwargs) { ue_py_check(self); PyObject *py_class; PyObject *py_obj_location = nullptr; PyObject *py_obj_rotation = nullptr; if (!PyArg_ParseTuple(args, "O|OO:actor_spawn", &py_class, &py_obj_location, &py_obj_rotation)) { return nullptr; } UWorld *world = ue_get_uworld(self); if (!world) return PyErr_Format(PyExc_Exception, "unable to retrieve UWorld from uobject"); UClass *u_class = ue_py_check_type<UClass>(py_class); if (!u_class) return PyErr_Format(PyExc_Exception, "argument is not a UClass"); if (!u_class->IsChildOf<AActor>()) { return PyErr_Format(PyExc_Exception, "argument is not a UClass derived from AActor"); } FVector location = FVector(0, 0, 0); FRotator rotation = FRotator(0, 0, 0); if (py_obj_location) { ue_PyFVector *py_location = py_ue_is_fvector(py_obj_location); if (!py_location) return PyErr_Format(PyExc_Exception, "location must be an FVector"); location = py_location->vec; } if (py_obj_rotation) { ue_PyFRotator *py_rotation = py_ue_is_frotator(py_obj_rotation); if (!py_rotation) return PyErr_Format(PyExc_Exception, "location must be an FRotator"); rotation = py_rotation->rot; } if (kwargs && PyDict_Size(kwargs) > 0) { FTransform transform; transform.SetTranslation(location); transform.SetRotation(rotation.Quaternion()); AActor *actor = world->SpawnActorDeferred<AActor>(u_class, transform); if (!actor) return PyErr_Format(PyExc_Exception, "unable to spawn a new Actor"); ue_PyUObject *py_actor = ue_get_python_uobject_inc(actor); if (!py_actor) return PyErr_Format(PyExc_Exception, "uobject is in invalid state"); PyObject *py_iter = PyObject_GetIter(kwargs); while (PyObject *py_key = PyIter_Next(py_iter)) { PyObject *void_ret = py_ue_set_property(py_actor, Py_BuildValue("OO", py_key, PyDict_GetItem(kwargs, py_key))); if (!void_ret) { Py_DECREF(py_iter); return PyErr_Format(PyExc_Exception, "unable to set property for new Actor"); } } Py_DECREF(py_iter); UGameplayStatics::FinishSpawningActor(actor, transform); return (PyObject *)py_actor; } AActor *actor = world->SpawnActor(u_class, &location, &rotation); if (!actor) return PyErr_Format(PyExc_Exception, "unable to spawn a new Actor"); Py_RETURN_UOBJECT(actor); }
void FUMGViewportClient::Draw(FViewport* InViewport, FCanvas* Canvas) { FViewport* ViewportBackup = Viewport; Viewport = InViewport ? InViewport : Viewport; // Determine whether we should use world time or real time based on the scene. float TimeSeconds; float RealTimeSeconds; float DeltaTimeSeconds; const bool bIsRealTime = true; UWorld* World = GWorld; if ( ( GetScene() != World->Scene ) || ( bIsRealTime == true ) ) { // Use time relative to start time to avoid issues with float vs double TimeSeconds = FApp::GetCurrentTime() - GStartTime; RealTimeSeconds = FApp::GetCurrentTime() - GStartTime; DeltaTimeSeconds = FApp::GetDeltaTime(); } else { TimeSeconds = World->GetTimeSeconds(); RealTimeSeconds = World->GetRealTimeSeconds(); DeltaTimeSeconds = World->GetDeltaSeconds(); } // Setup a FSceneViewFamily/FSceneView for the viewport. FSceneViewFamilyContext ViewFamily(FSceneViewFamily::ConstructionValues( Canvas->GetRenderTarget(), GetScene(), EngineShowFlags) .SetWorldTimes(TimeSeconds, DeltaTimeSeconds, RealTimeSeconds) .SetRealtimeUpdate(bIsRealTime)); ViewFamily.EngineShowFlags = EngineShowFlags; //UpdateLightingShowFlags(ViewFamily.EngineShowFlags); //ViewFamily.ExposureSettings = ExposureSettings; //ViewFamily.LandscapeLODOverride = LandscapeLODOverride; FSceneView* View = CalcSceneView(&ViewFamily); //SetupViewForRendering(ViewFamily, *View); FSlateRect SafeFrame; View->CameraConstrainedViewRect = View->UnscaledViewRect; //if ( CalculateEditorConstrainedViewRect(SafeFrame, Viewport) ) //{ // View->CameraConstrainedViewRect = FIntRect(SafeFrame.Left, SafeFrame.Top, SafeFrame.Right, SafeFrame.Bottom); //} if ( IsAspectRatioConstrained() ) { // Clear the background to black if the aspect ratio is constrained, as the scene view won't write to all pixels. Canvas->Clear(FLinearColor::Black); } Canvas->Clear(BackgroundColor); // workaround for hacky renderer code that uses GFrameNumber to decide whether to resize render targets --GFrameNumber; GetRendererModule().BeginRenderingViewFamily(Canvas, &ViewFamily); // Remove temporary debug lines. // Possibly a hack. Lines may get added without the scene being rendered etc. if ( World->LineBatcher != NULL && ( World->LineBatcher->BatchedLines.Num() || World->LineBatcher->BatchedPoints.Num() ) ) { World->LineBatcher->Flush(); } if ( World->ForegroundLineBatcher != NULL && ( World->ForegroundLineBatcher->BatchedLines.Num() || World->ForegroundLineBatcher->BatchedPoints.Num() ) ) { World->ForegroundLineBatcher->Flush(); } Viewport = ViewportBackup; }
void AGameModeBase::ReplicateStreamingStatus(APlayerController* PC) { UWorld* MyWorld = GetWorld(); if (MyWorld->GetWorldSettings()->bUseClientSideLevelStreamingVolumes) { // Client will itself decide what to stream return; } // Don't do this for local players or players after the first on a splitscreen client if (Cast<ULocalPlayer>(PC->Player) == nullptr && Cast<UChildConnection>(PC->Player) == nullptr) { // If we've loaded levels via CommitMapChange() that aren't normally in the StreamingLevels array, tell the client about that if (MyWorld->CommittedPersistentLevelName != NAME_None) { PC->ClientPrepareMapChange(MyWorld->CommittedPersistentLevelName, true, true); // Tell the client to commit the level immediately PC->ClientCommitMapChange(); } if (MyWorld->StreamingLevels.Num() > 0) { // Tell the player controller the current streaming level status for (int32 LevelIndex = 0; LevelIndex < MyWorld->StreamingLevels.Num(); LevelIndex++) { ULevelStreaming* TheLevel = MyWorld->StreamingLevels[LevelIndex]; if (TheLevel != nullptr) { const ULevel* LoadedLevel = TheLevel->GetLoadedLevel(); UE_LOG(LogGameMode, Log, TEXT("levelStatus: %s %i %i %i %s %i"), *TheLevel->GetWorldAssetPackageName(), TheLevel->bShouldBeVisible, LoadedLevel && LoadedLevel->bIsVisible, TheLevel->bShouldBeLoaded, *GetNameSafe(LoadedLevel), TheLevel->bHasLoadRequestPending); PC->ClientUpdateLevelStreamingStatus( TheLevel->GetWorldAssetPackageFName(), TheLevel->bShouldBeLoaded, TheLevel->bShouldBeVisible, TheLevel->bShouldBlockOnLoad, TheLevel->LevelLODIndex); } } PC->ClientFlushLevelStreaming(); } // If we're preparing to load different levels using PrepareMapChange() inform the client about that now if (MyWorld->PreparingLevelNames.Num() > 0) { for (int32 LevelIndex = 0; LevelIndex < MyWorld->PreparingLevelNames.Num(); LevelIndex++) { PC->ClientPrepareMapChange(MyWorld->PreparingLevelNames[LevelIndex], LevelIndex == 0, LevelIndex == MyWorld->PreparingLevelNames.Num() - 1); } // DO NOT commit these changes yet - we'll send that when we're done preparing them } } }
void SBlueprintEditorSelectedDebugObjectWidget::GenerateDebugWorldNames(bool bRestoreSelection) { TSharedPtr<FString> OldSelection; // Store off the old selection if (bRestoreSelection && DebugWorldsComboBox.IsValid()) { OldSelection = DebugWorldsComboBox->GetSelectedItem(); } DebugWorldNames.Empty(); DebugWorlds.Empty(); DebugWorlds.Add(NULL); DebugWorldNames.Add(MakeShareable(new FString(GetDebugAllWorldsString()))); UWorld* PreviewWorld = NULL; TSharedPtr<SSCSEditorViewport> PreviewViewportPtr = BlueprintEditor.Pin()->GetSCSViewport(); if (PreviewViewportPtr.IsValid()) { PreviewWorld = PreviewViewportPtr->GetPreviewScene().GetWorld(); } for (TObjectIterator<UWorld> It; It; ++It) { UWorld *TestWorld = *It; if (!TestWorld || TestWorld->WorldType != EWorldType::PIE) { continue; } DebugWorlds.Add(TestWorld); ENetMode NetMode = TestWorld->GetNetMode(); FString WorldName; switch (NetMode) { case NM_Standalone: WorldName = NSLOCTEXT("BlueprintEditor", "DebugWorldStandalone", "Standalone").ToString(); break; case NM_ListenServer: WorldName = NSLOCTEXT("BlueprintEditor", "DebugWorldListenServer", "Listen Server").ToString(); break; case NM_DedicatedServer: WorldName = NSLOCTEXT("BlueprintEditor", "DebugWorldDedicatedServer", "Dedicated Server").ToString(); break; case NM_Client: FWorldContext &PieContext = GEngine->WorldContextFromWorld(TestWorld); WorldName = FString::Printf(TEXT("%s %d"), *NSLOCTEXT("BlueprintEditor", "DebugWorldClient", "Client").ToString(), PieContext.PIEInstance - 1); break; }; DebugWorldNames.Add(MakeShareable(new FString(WorldName))); } // Attempt to restore the old selection if (bRestoreSelection && DebugWorldsComboBox.IsValid()) { bool bMatchFound = false; for (int32 WorldIdx = 0; WorldIdx < DebugWorldNames.Num(); ++WorldIdx) { if (*DebugWorldNames[WorldIdx] == *OldSelection) { DebugWorldsComboBox->SetSelectedItem(DebugWorldNames[WorldIdx]); bMatchFound = true; break; } } // No match found, use the default option if (!bMatchFound) { DebugWorldsComboBox->SetSelectedItem(DebugWorldNames[0]); } } // Finally ensure we have a valid selection if (DebugWorldsComboBox.IsValid()) { TSharedPtr<FString> CurrentSelection = DebugWorldsComboBox->GetSelectedItem(); if (DebugWorldNames.Find(CurrentSelection) == INDEX_NONE) { if (DebugWorldNames.Num() > 0) { DebugWorldsComboBox->SetSelectedItem(DebugWorldNames[0]); } else { DebugWorldsComboBox->ClearSelection(); } } } }
void UHUDBlueprintLibrary::FindScreenLocationForWorldLocation(UObject* WorldContextObject, const FVector& InLocation, const float EdgePercent, FVector2D& OutScreenPosition, float& OutRotationAngleDegrees, bool &bIsOnScreen) { bIsOnScreen = false; OutRotationAngleDegrees = 0.f; FVector2D *ScreenPosition = new FVector2D(); UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject); if (!World->IsValidLowLevel()) return; if (GEngine->GameViewport == NULL) return; if (GEngine->GameViewport->Viewport == NULL) return; const FVector2D ViewportSize = FVector2D(GEngine->GameViewport->Viewport->GetSizeXY()); const FVector2D ViewportCenter = FVector2D(ViewportSize.X/2, ViewportSize.Y/2); APlayerController* PlayerController = (WorldContextObject ? UGameplayStatics::GetPlayerController(WorldContextObject, 0) : NULL); ACharacter *PlayerCharacter = static_cast<ACharacter *> (PlayerController->GetPawn()); if (!PlayerCharacter) return; FVector Forward = PlayerCharacter->GetActorForwardVector(); FVector Offset = (InLocation - PlayerCharacter->GetActorLocation()).GetSafeNormal(); float DotProduct = FVector::DotProduct(Forward, Offset); bool bLocationIsBehindCamera = (DotProduct < 0); if (bLocationIsBehindCamera) { // For behind the camera situation, we cheat a little to put the // marker at the bottom of the screen so that it moves smoothly // as you turn around. Could stand some refinement, but results // are decent enough for most purposes. FVector DiffVector = InLocation - PlayerCharacter->GetActorLocation(); FVector Inverted = DiffVector * -1.f; FVector NewInLocation = PlayerCharacter->GetActorLocation() * Inverted; NewInLocation.Z -= 5000; PlayerController->ProjectWorldLocationToScreen(NewInLocation, *ScreenPosition); ScreenPosition->Y = (EdgePercent * ViewportCenter.X) * 2.f; ScreenPosition->X = -ViewportCenter.X - ScreenPosition->X; } PlayerController->ProjectWorldLocationToScreen(InLocation, *ScreenPosition); // Check to see if it's on screen. If it is, ProjectWorldLocationToScreen is all we need, return it. if (ScreenPosition->X >= 0.f && ScreenPosition->X <= ViewportSize.X && ScreenPosition->Y >= 0.f && ScreenPosition->Y <= ViewportSize.Y) { OutScreenPosition = *ScreenPosition; bIsOnScreen = true; return; } *ScreenPosition -= ViewportCenter; float AngleRadians = FMath::Atan2(ScreenPosition->Y, ScreenPosition->X); AngleRadians -= FMath::DegreesToRadians(90.f); OutRotationAngleDegrees = FMath::RadiansToDegrees(AngleRadians) + 180.f; float Cos = cosf(AngleRadians); float Sin = -sinf(AngleRadians); ScreenPosition = new FVector2D(ViewportCenter.X + (Sin * 150.f), ViewportCenter.Y + Cos * 150.f); float m = Cos / Sin; FVector2D ScreenBounds = ViewportCenter * EdgePercent; if (Cos > 0) { ScreenPosition = new FVector2D(ScreenBounds.Y/m, ScreenBounds.Y); } else { ScreenPosition = new FVector2D(-ScreenBounds.Y/m, -ScreenBounds.Y); } if (ScreenPosition->X > ScreenBounds.X) { ScreenPosition = new FVector2D(ScreenBounds.X, ScreenBounds.X*m); } else if (ScreenPosition->X < -ScreenBounds.X) { ScreenPosition = new FVector2D(-ScreenBounds.X, -ScreenBounds.X*m); } *ScreenPosition += ViewportCenter; OutScreenPosition = *ScreenPosition; }
FORCEINLINE_DEBUGGABLE FVector RunLineTrace(const FVector& StartPos, const FVector& EndPos) { FHitResult OutHit; const bool bHit = World->LineTraceSingle(OutHit, StartPos, EndPos, Channel, Params); return bHit ? OutHit.ImpactPoint : EndPos; }
bool UGameInstance::InitializePIE(bool bAnyBlueprintErrors, int32 PIEInstance) { UEditorEngine* const EditorEngine = CastChecked<UEditorEngine>(GetEngine()); // Look for an existing pie world context, may have been created before WorldContext = EditorEngine->GetWorldContextFromPIEInstance(PIEInstance); if (!WorldContext) { // If not, create a new one WorldContext = &EditorEngine->CreateNewWorldContext(EWorldType::PIE); WorldContext->PIEInstance = PIEInstance; } WorldContext->OwningGameInstance = this; const FString WorldPackageName = EditorEngine->EditorWorld->GetOutermost()->GetName(); // Establish World Context for PIE World WorldContext->LastURL.Map = WorldPackageName; WorldContext->PIEPrefix = WorldContext->PIEInstance != INDEX_NONE ? UWorld::BuildPIEPackagePrefix(WorldContext->PIEInstance) : FString(); const ULevelEditorPlaySettings* PlayInSettings = GetDefault<ULevelEditorPlaySettings>(); // We always need to create a new PIE world unless we're using the editor world for SIE UWorld* NewWorld = nullptr; bool bNeedsGarbageCollection = false; const EPlayNetMode PlayNetMode = [&PlayInSettings]{ EPlayNetMode NetMode(PIE_Standalone); return (PlayInSettings->GetPlayNetMode(NetMode) ? NetMode : PIE_Standalone); }(); const bool CanRunUnderOneProcess = [&PlayInSettings]{ bool RunUnderOneProcess(false); return (PlayInSettings->GetRunUnderOneProcess(RunUnderOneProcess) && RunUnderOneProcess); }(); if (PlayNetMode == PIE_Client) { // We are going to connect, so just load an empty world NewWorld = EditorEngine->CreatePIEWorldFromEntry(*WorldContext, EditorEngine->EditorWorld, PIEMapName); } else if (PlayNetMode == PIE_ListenServer && !CanRunUnderOneProcess) { // We *have* to save the world to disk in order to be a listen server that allows other processes to connect. // Otherwise, clients would not be able to load the world we are using NewWorld = EditorEngine->CreatePIEWorldBySavingToTemp(*WorldContext, EditorEngine->EditorWorld, PIEMapName); } else { // Standard PIE path: just duplicate the EditorWorld NewWorld = EditorEngine->CreatePIEWorldByDuplication(*WorldContext, EditorEngine->EditorWorld, PIEMapName); // Duplication can result in unreferenced objects, so indicate that we should do a GC pass after initializing the world context bNeedsGarbageCollection = true; } // failed to create the world! if (NewWorld == nullptr) { FMessageDialog::Open(EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "Error_FailedCreateEditorPreviewWorld", "Failed to create editor preview world.")); return false; } NewWorld->SetGameInstance(this); WorldContext->SetCurrentWorld(NewWorld); WorldContext->AddRef(EditorEngine->PlayWorld); // Tie this context to this UEngine::PlayWorld* // @fixme, needed still? // make sure we can clean up this world! NewWorld->ClearFlags(RF_Standalone); NewWorld->bKismetScriptError = bAnyBlueprintErrors; // Do a GC pass if necessary to remove any potentially unreferenced objects if(bNeedsGarbageCollection) { CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS); } Init(); return true; }
FORCEINLINE_DEBUGGABLE FVector RunCapsuleTrace(const FVector& StartPos, const FVector& EndPos) { FHitResult OutHit; const bool bHit = World->SweepSingle(OutHit, StartPos, EndPos, FQuat::Identity, Channel, FCollisionShape::MakeCapsule(Extent.X, Extent.Z), Params); return bHit ? OutHit.ImpactPoint : EndPos; }
void UPrimitiveComponent::UnWeldFromParent() { FBodyInstance* NewRootBI = GetBodyInstance(NAME_None, false); UWorld* CurrentWorld = GetWorld(); if (NewRootBI == NULL || NewRootBI->bWelded == false || CurrentWorld == nullptr || IsPendingKill()) { return; } FName SocketName; UPrimitiveComponent * RootComponent = GetRootWelded(this, AttachSocketName, &SocketName); if (RootComponent) { if (FBodyInstance* RootBI = RootComponent->GetBodyInstance(SocketName, false)) { bool bRootIsBeingDeleted = RootComponent->HasAnyFlags(RF_PendingKill) || RootComponent->HasAnyFlags(RF_Unreachable); if (!bRootIsBeingDeleted) { //create new root RootBI->UnWeld(NewRootBI); //don't bother fixing up shapes if RootComponent is about to be deleted } NewRootBI->bWelded = false; const FBodyInstance* PrevWeldParent = NewRootBI->WeldParent; NewRootBI->WeldParent = nullptr; bool bHasBodySetup = GetBodySetup() != nullptr; //if BodyInstance hasn't already been created we need to initialize it if (bHasBodySetup && NewRootBI->IsValidBodyInstance() == false) { bool bPrevAutoWeld = NewRootBI->bAutoWeld; NewRootBI->bAutoWeld = false; NewRootBI->InitBody(GetBodySetup(), GetComponentToWorld(), this, CurrentWorld->GetPhysicsScene()); NewRootBI->bAutoWeld = bPrevAutoWeld; } if(PrevWeldParent == nullptr) //our parent is kinematic so no need to do any unwelding/rewelding of children { return; } //now weld its children to it TArray<FBodyInstance*> ChildrenBodies; TArray<FName> ChildrenLabels; GetWeldedBodies(ChildrenBodies, ChildrenLabels); for (int32 ChildIdx = 0; ChildIdx < ChildrenBodies.Num(); ++ChildIdx) { FBodyInstance* ChildBI = ChildrenBodies[ChildIdx]; if (ChildBI != NewRootBI) { if (!bRootIsBeingDeleted) { RootBI->UnWeld(ChildBI); } //At this point, NewRootBI must be kinematic because it's being unwelded. It's up to the code that simulates to call Weld on the children as needed ChildBI->WeldParent = nullptr; //null because we are currently kinematic } } } } }
void UGameplayDebuggingComponent::SelectTargetToDebug() { #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) AGameplayDebuggingReplicator* Replicator = Cast<AGameplayDebuggingReplicator>(GetOwner()); APlayerController* MyPC = Replicator->GetLocalPlayerOwner(); if (MyPC ) { APawn* BestTarget = NULL; if (MyPC->GetViewTarget() != NULL && MyPC->GetViewTarget() != MyPC->GetPawn()) { BestTarget = Cast<APawn>(MyPC->GetViewTarget()); if (BestTarget && ((BestTarget->PlayerState != NULL && BestTarget->PlayerState->bIsABot == false) || BestTarget->GetActorEnableCollision() == false)) { BestTarget = NULL; } } float bestAim = 0.f; FVector CamLocation; FRotator CamRotation; check(MyPC->PlayerCameraManager != NULL); MyPC->PlayerCameraManager->GetCameraViewPoint(CamLocation, CamRotation); FVector FireDir = CamRotation.Vector(); UWorld* World = MyPC->GetWorld(); check( World ); APawn* PossibleTarget = NULL; for (FConstPawnIterator Iterator = World->GetPawnIterator(); Iterator; ++Iterator ) { APawn* NewTarget = *Iterator; if (NewTarget == NULL || NewTarget == MyPC->GetPawn() || (NewTarget->PlayerState != NULL && NewTarget->PlayerState->bIsABot == false) || NewTarget->GetActorEnableCollision() == false) { continue; } if (BestTarget == NULL && (NewTarget != MyPC->GetPawn())) { // look for best controlled pawn target const FVector AimDir = NewTarget->GetActorLocation() - CamLocation; float FireDist = AimDir.SizeSquared(); // only find targets which are < 25000 units away if (FireDist < 625000000.f) { FireDist = FMath::Sqrt(FireDist); float newAim = FireDir | AimDir; newAim = newAim/FireDist; if (newAim > bestAim) { PossibleTarget = NewTarget; bestAim = newAim; } } } } BestTarget = BestTarget == NULL ? PossibleTarget : BestTarget; if (BestTarget != NULL && BestTarget != GetSelectedActor()) { if (AGameplayDebuggingReplicator* Replicator = Cast<AGameplayDebuggingReplicator>(GetOwner())) { Replicator->SetActorToDebug(Cast<AActor>(BestTarget)); } //always update component for best target SetActorToDebug(Cast<AActor>(BestTarget)); ServerReplicateData(EDebugComponentMessage::ActivateReplication, EAIDebugDrawDataView::Empty); } } #endif //!(UE_BUILD_SHIPPING || UE_BUILD_TEST) }