EBTNodeResult::Type UBTTask_WaitAnswer::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) { ClearAnswer(); EBTNodeResult::Type NodeResult = !bAnswerDone ? EBTNodeResult::InProgress : NodeResult = EBTNodeResult::Succeeded; TimerCount = Timer; AActor* OwnerActor = OwnerComp.GetOwner(); if (!DialogueWidget.IsNone()) { FName WidgetKeyName = DialogueWidget.SelectedKeyName; BlackboardComp = OwnerComp.GetBlackboardComponent(); Widget = Cast<UUserWidget>(BlackboardComp->GetValueAsObject(WidgetKeyName)); WidgetComp = Cast<UWidgetComponent>(BlackboardComp->GetValueAsObject(WidgetKeyName)); UDialogueButton* FirstButton = nullptr; if (!Widget && !WidgetComp) { #if WITH_EDITOR FMessageLog("PIE").Error() ->AddToken(FTextToken::Create(LOCTEXT("InvalidWidgetKey", "Invalid key for Dialogue Widget in "))) ->AddToken(FUObjectToken::Create((UObject*)OwnerComp.GetCurrentTree())); #endif return EBTNodeResult::Failed; } if (WidgetComp) { Widget = CreateWidget<UUserWidget>(GetWorld(), WidgetComp->GetWidgetClass()); PlayerController = WidgetComp->GetUserWidgetObject()->GetOwningPlayer(); bIsUserWidget = false; } else { bIsUserWidget = true; PlayerController = Widget->GetOwningPlayer(); } if (Widget && Widget->IsInViewport()) { Widget->RemoveFromParent(); } if (!Widget) { NodeResult = EBTNodeResult::Failed; } else { WidgetTree = Widget->WidgetTree; UWidget* DialogueQuestionsSlot = WidgetTree->FindWidget(DialogueQuestionsSlotName); UPanelWidget* Panel = Cast<UPanelWidget>(DialogueQuestionsSlot); if (Panel) { TArray<UWidget*> Buttons; UDialogueButton* SampleButton = nullptr; UTextBlock* SampleTextBlock = nullptr; WidgetTree->GetChildWidgets(DialogueQuestionsSlot, Buttons); for (auto& elem : Buttons) { UDialogueButton* Button = Cast<UDialogueButton>(elem); if (Button) { SampleButton = Button; WidgetTree->RemoveWidget(elem); } UTextBlock* TextBlock = Cast<UTextBlock>(elem); if (TextBlock) { SampleTextBlock = TextBlock; WidgetTree->RemoveWidget(elem); } } if (SampleButton != nullptr && SampleTextBlock != nullptr) { const UBTNode* BTNode = GetParentNode(); const UBTCompositeNode* CBTNode = Cast<UBTCompositeNode>(BTNode); Panel->SetVisibility(ESlateVisibility::Visible); if (CBTNode) { int32 ButtonNumber = 0; for (int32 Index = 0; Index != CBTNode->Children.Num(); ++Index) { auto& Child = CBTNode->Children[Index]; UBTComposite_Question* Question = Cast<UBTComposite_Question>(Child.ChildComposite); bool bDecoratorOk = CBTNode->DoDecoratorsAllowExecution(OwnerComp, OwnerComp.GetActiveInstanceIdx(), Index); if(Question) { Question->bCanExecute = false; Question->bSelected = false; } if ( Question && Question->Children.Num() > 0 && Question->GetVisibility(PlayerController) && Question->bVisible && bDecoratorOk ) { Question->bCanExecute = true; UDialogueButton *NewSampleButton = NewObject<UDialogueButton>(this, NAME_None, SampleButton->GetFlags(), SampleButton); UTextBlock *NewSampleTextBlock = NewObject<UTextBlock>(this, NAME_None, SampleTextBlock->GetFlags(), SampleTextBlock); ButtonNumber++; if (bUseGamepad) { NewSampleButton->IsFocusable = true; if (ButtonNumber == 1) { FirstButton = NewSampleButton; } } else { NewSampleButton->IsFocusable = false; } NewSampleTextBlock->SetText(FText::Format(NSLOCTEXT("DialogueSystem", "ButtonText", "{0}"), Question->QuestionThumbnail)); UWidget* Oldtext = NewSampleButton->GetChildAt(0); NewSampleButton->WaitTask = this; NewSampleButton->RemoveChild(Oldtext); NewSampleButton->AddChild(NewSampleTextBlock); Panel->AddChild(NewSampleButton); } } } } // Event Listener UWidget* DialogueEventListener = WidgetTree->FindWidget(FName("DialogueEventListener")); if (DialogueEventListener != nullptr) { UDialogueEventListener* EventListener = Cast<UDialogueEventListener>(DialogueEventListener); if (EventListener) { EventListener->WaitAnswerNode = this; } } } if (bIsUserWidget) { Widget->AddToViewport(); } else { WidgetComp->SetWidget(Widget); WidgetComp->SetVisibility(true); } PlayerController->bShowMouseCursor = !bUseGamepad; FInputModeUIOnly InputModeUIOnly; FInputModeGameAndUI InputModeGameAndUI; if (InputMode == EWidggetInputMode::UIOnly) { PlayerController->SetInputMode(InputModeUIOnly); } else { PlayerController->SetInputMode(InputModeGameAndUI); } if (bUseGamepad && Panel) { FirstButton->SetKeyboardFocus(); } else { if (InputMode == EWidggetInputMode::UIOnly) { InputModeUIOnly.SetWidgetToFocus(Widget->TakeWidget()); } else { InputModeGameAndUI.SetWidgetToFocus(Widget->TakeWidget()); } } } // cinematic if (DialogueCinematicOptions.bPlayMatinee && !DialogueCinematicOptions.Matinee.Equals("None")) { for (TActorIterator<AMatineeActor> It(OwnerActor->GetWorld()); It; ++It) { MatineeActor = *It; if (MatineeActor && MatineeActor->GetName().Equals(DialogueCinematicOptions.Matinee)) { MatineeActor->bLooping = DialogueCinematicOptions.bLoop; MatineeActor->Play(); break; } } } // camera if (DialogueCameraOptions.bUseCamera) { if (!DialogueCameraOptions.CameraToView.IsNone() && !DialogueCameraOptions.PlayerCamera.IsNone()) { FName CameraToViewKeyName = DialogueCameraOptions.CameraToView.SelectedKeyName; BlackboardComp = OwnerComp.GetBlackboardComponent(); UCameraComponent* CameraToView = Cast<UCameraComponent>(BlackboardComp->GetValueAsObject(CameraToViewKeyName)); FName PlayerCameraKeyName = DialogueCameraOptions.PlayerCamera.SelectedKeyName; PlayerCamera = Cast<UCameraComponent>(BlackboardComp->GetValueAsObject(PlayerCameraKeyName)); if (PlayerCamera && CameraToView) { SaveDefaultCameraData(PlayerCamera); if (PlayerCamera == CameraToView) { PlayerCamera->SetWorldLocationAndRotation(DefaultCameraLocation, DefaultCameraRotation); } else { PlayerCamera->SetWorldLocationAndRotation(CameraToView->GetComponentLocation(), CameraToView->GetComponentRotation()); } } } } } return NodeResult; }
void cht_Take (player_t *player, const char *name, int amount) { bool takeall; PClassActor *type; if (player->mo == NULL || player->health <= 0) { return; } takeall = (stricmp (name, "all") == 0); if (!takeall && stricmp (name, "health") == 0) { if (player->mo->health - amount <= 0 || player->health - amount <= 0 || amount == 0) { cht_Suicide (player); if (player == &players[consoleplayer]) C_HideConsole (); return; } if (amount > 0) { if (player->mo) { player->mo->health -= amount; player->health = player->mo->health; } else { player->health -= amount; } } if (!takeall) return; } if (takeall || stricmp (name, "backpack") == 0) { // Take away all types of backpacks the player might own. for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { PClass *type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf(PClass::FindClass(NAME_BackpackItem))) { AInventory *pack = player->mo->FindInventory(static_cast<PClassActor *>(type)); if (pack) pack->Destroy(); } } if (!takeall) return; } if (takeall || stricmp (name, "ammo") == 0) { for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { PClass *type = PClassActor::AllActorClasses[i]; if (type->ParentClass == RUNTIME_CLASS (AAmmo)) { AInventory *ammo = player->mo->FindInventory(static_cast<PClassActor *>(type)); if (ammo) ammo->DepleteOrDestroy(); } } if (!takeall) return; } if (takeall || stricmp (name, "armor") == 0) { for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS (AArmor))) { AInventory *armor = player->mo->FindInventory(static_cast<PClassActor *>(type)); if (armor) armor->DepleteOrDestroy(); } } if (!takeall) return; } if (takeall || stricmp (name, "keys") == 0) { for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS (AKey))) { AActor *key = player->mo->FindInventory(static_cast<PClassActor *>(type)); if (key) key->Destroy (); } } if (!takeall) return; } if (takeall || stricmp (name, "weapons") == 0) { for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { type = PClassActor::AllActorClasses[i]; if (type != RUNTIME_CLASS(AWeapon) && type->IsDescendantOf (RUNTIME_CLASS (AWeapon))) { AActor *weapon = player->mo->FindInventory(static_cast<PClassActor *>(type)); if (weapon) weapon->Destroy (); player->ReadyWeapon = nullptr; player->PendingWeapon = WP_NOCHANGE; } } if (!takeall) return; } if (takeall || stricmp (name, "artifacts") == 0) { for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS (AInventory))) { if (!type->IsDescendantOf (RUNTIME_CLASS (APuzzleItem)) && !type->IsDescendantOf (RUNTIME_CLASS (APowerup)) && !type->IsDescendantOf (RUNTIME_CLASS (AArmor)) && !type->IsDescendantOf (RUNTIME_CLASS (AWeapon)) && !type->IsDescendantOf (RUNTIME_CLASS (AKey))) { AActor *artifact = player->mo->FindInventory(static_cast<PClassActor *>(type)); if (artifact) artifact->Destroy (); } } } if (!takeall) return; } if (takeall || stricmp (name, "puzzlepieces") == 0) { for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS (APuzzleItem))) { AActor *puzzlepiece = player->mo->FindInventory(static_cast<PClassActor *>(type)); if (puzzlepiece) puzzlepiece->Destroy (); } } if (!takeall) return; } if (takeall) return; type = PClass::FindActor (name); if (type == NULL || !type->IsDescendantOf (RUNTIME_CLASS (AInventory))) { if (player == &players[consoleplayer]) Printf ("Unknown item \"%s\"\n", name); } else { player->mo->TakeInventory(type, amount ? amount : 1); } return; }
void UUnrealEdEngine::UpdatePivotLocationForSelection( bool bOnChange ) { // Pick a new common pivot, or not. AActor* SingleActor = nullptr; USceneComponent* SingleComponent = nullptr; if (GetSelectedComponentCount() > 0) { for (FSelectedEditableComponentIterator It(*GetSelectedComponents()); It; ++It) { UActorComponent* Component = CastChecked<UActorComponent>(*It); AActor* ComponentOwner = Component->GetOwner(); if (ComponentOwner != nullptr) { auto SelectedActors = GetSelectedActors(); const bool bIsOwnerSelected = SelectedActors->IsSelected(ComponentOwner); check(bIsOwnerSelected); if (ComponentOwner->GetWorld() == GWorld) { SingleActor = ComponentOwner; if (Component->IsA<USceneComponent>()) { SingleComponent = CastChecked<USceneComponent>(Component); } const bool IsTemplate = ComponentOwner->IsTemplate(); const bool LevelLocked = !FLevelUtils::IsLevelLocked(ComponentOwner->GetLevel()); check(IsTemplate || LevelLocked); } } } } else { for (FSelectionIterator It(GetSelectedActorIterator()); It; ++It) { AActor* Actor = static_cast<AActor*>(*It); checkSlow(Actor->IsA(AActor::StaticClass())); if (Actor->GetWorld() == GWorld) { const bool IsTemplate = Actor->IsTemplate(); const bool LevelLocked = !FLevelUtils::IsLevelLocked(Actor->GetLevel()); check(IsTemplate || LevelLocked); SingleActor = Actor; } } } if (SingleComponent != NULL) { SetPivot(SingleComponent->GetComponentLocation(), false, true); } else if( SingleActor != NULL ) { // For geometry mode use current pivot location as it's set to selected face, not actor FEditorModeTools& Tools = GLevelEditorModeTools(); if( Tools.IsModeActive(FBuiltinEditorModes::EM_Geometry) == false || bOnChange == true ) { // Set pivot point to the actor's location FVector PivotPoint = SingleActor->GetActorLocation(); // If grouping is active, see if this actor is part of a locked group and use that pivot instead if(GEditor->bGroupingActive) { AGroupActor* ActorGroupRoot = AGroupActor::GetRootForActor(SingleActor, true, true); if(ActorGroupRoot) { PivotPoint = ActorGroupRoot->GetActorLocation(); } } SetPivot( PivotPoint, false, true ); } } else { ResetPivot(); } }
void UAblTargetingBox::FindTargets(UAblAbilityContext& Context) const { AActor* SourceActor = m_Location.GetSourceActor(Context); check(SourceActor); UWorld* World = SourceActor->GetWorld(); FTransform QueryTransform; if (IsUsingAsync() && UAbleSettings::IsAsyncEnabled()) { // Check if we have a valid Async handle already. if (!Context.HasValidAsyncHandle()) { FCollisionShape BoxShape = FCollisionShape::MakeBox(m_HalfExtents); m_Location.GetTransform(Context, QueryTransform); // Push our query out by our half extents so we aren't centered in the box. FQuat Rotation = QueryTransform.GetRotation(); FVector HalfExtentsOffset = Rotation.GetForwardVector() * m_HalfExtents.X; QueryTransform *= FTransform(HalfExtentsOffset); FTraceHandle AsyncHandle = World->AsyncOverlapByChannel(QueryTransform.GetLocation(), QueryTransform.GetRotation(), GetCollisionChannel(), BoxShape); Context.SetAsyncHandle(AsyncHandle); } else // Poll and see if our query is done, if so - process it. { FOverlapDatum Datum; if (World->QueryOverlapData(Context.GetAsyncHandle(), Datum)) { ProcessResults(Context, Datum.OutOverlaps); FTraceHandle Empty; Context.SetAsyncHandle(Empty); // Reset our handle. } return; } } else // Normal Sync Query { FCollisionShape BoxShape = FCollisionShape::MakeBox(m_HalfExtents); m_Location.GetTransform(Context, QueryTransform); // Push our query out by our half extents so we aren't centered in the box. FQuat Rotation = QueryTransform.GetRotation(); FVector HalfExtentsOffset = Rotation.GetForwardVector() * m_HalfExtents.X; QueryTransform *= FTransform(HalfExtentsOffset); TArray<FOverlapResult> Results; if (World->OverlapMultiByChannel(Results, QueryTransform.GetLocation(), QueryTransform.GetRotation(), GetCollisionChannel(), BoxShape)) { ProcessResults(Context, Results); } } #if !UE_BUILD_SHIPPING if (FAblAbilityDebug::ShouldDrawQueries()) { // Nope, go ahead and fire off our Async query. FVector AlignedBox = GetAlignedBox(Context, QueryTransform); FAblAbilityDebug::DrawBoxQuery(World, QueryTransform, AlignedBox); } #endif // UE_BUILD_SHIPPING }
void USoundWave::Parse( FAudioDevice* AudioDevice, const UPTRINT NodeWaveInstanceHash, FActiveSound& ActiveSound, const FSoundParseParameters& ParseParams, TArray<FWaveInstance*>& WaveInstances ) { FWaveInstance* WaveInstance = ActiveSound.FindWaveInstance(NodeWaveInstanceHash); // Create a new WaveInstance if this SoundWave doesn't already have one associated with it. if( WaveInstance == NULL ) { if( !ActiveSound.bRadioFilterSelected ) { ActiveSound.ApplyRadioFilter(ParseParams); } WaveInstance = HandleStart( ActiveSound, NodeWaveInstanceHash); } // Looping sounds are never actually finished if (bLooping || ParseParams.bLooping) { WaveInstance->bIsFinished = false; #if !(NO_LOGGING || UE_BUILD_SHIPPING || UE_BUILD_TEST) if (!ActiveSound.bWarnedAboutOrphanedLooping && ActiveSound.GetAudioComponentID() == 0) { UE_LOG(LogAudio, Warning, TEXT("Detected orphaned looping sound '%s'."), *ActiveSound.GetSound()->GetName()); ActiveSound.bWarnedAboutOrphanedLooping = true; } #endif } // Check for finished paths. if( !WaveInstance->bIsFinished ) { // Propagate properties and add WaveInstance to outgoing array of FWaveInstances. WaveInstance->Volume = ParseParams.Volume * Volume; WaveInstance->VolumeMultiplier = ParseParams.VolumeMultiplier; WaveInstance->VolumeApp = ParseParams.VolumeApp; WaveInstance->Pitch = ParseParams.Pitch * Pitch; WaveInstance->bEnableLowPassFilter = ParseParams.bEnableLowPassFilter; WaveInstance->bIsOccluded = ParseParams.bIsOccluded; WaveInstance->LowPassFilterFrequency = ParseParams.LowPassFilterFrequency; WaveInstance->OcclusionFilterFrequency = ParseParams.OcclusionFilterFrequency; WaveInstance->AttenuationFilterFrequency = ParseParams.AttenuationFilterFrequency; WaveInstance->AmbientZoneFilterFrequency = ParseParams.AmbientZoneFilterFrequency; WaveInstance->bApplyRadioFilter = ActiveSound.bApplyRadioFilter; WaveInstance->StartTime = ParseParams.StartTime; WaveInstance->UserIndex = ActiveSound.UserIndex; WaveInstance->OmniRadius = ParseParams.OmniRadius; WaveInstance->StereoSpread = ParseParams.StereoSpread; WaveInstance->AttenuationDistance = ParseParams.AttenuationDistance; WaveInstance->AbsoluteAzimuth = ParseParams.AbsoluteAzimuth; bool bAlwaysPlay = false; // Properties from the sound class WaveInstance->SoundClass = ParseParams.SoundClass; if (ParseParams.SoundClass) { FSoundClassProperties* SoundClassProperties = AudioDevice->GetSoundClassCurrentProperties(ParseParams.SoundClass); // Use values from "parsed/ propagated" sound class properties WaveInstance->VolumeMultiplier *= SoundClassProperties->Volume; WaveInstance->Pitch *= SoundClassProperties->Pitch; //TODO: Add in HighFrequencyGainMultiplier property to sound classes WaveInstance->VoiceCenterChannelVolume = SoundClassProperties->VoiceCenterChannelVolume; WaveInstance->RadioFilterVolume = SoundClassProperties->RadioFilterVolume * ParseParams.VolumeMultiplier; WaveInstance->RadioFilterVolumeThreshold = SoundClassProperties->RadioFilterVolumeThreshold * ParseParams.VolumeMultiplier; WaveInstance->StereoBleed = SoundClassProperties->StereoBleed; WaveInstance->LFEBleed = SoundClassProperties->LFEBleed; WaveInstance->bIsUISound = ActiveSound.bIsUISound || SoundClassProperties->bIsUISound; WaveInstance->bIsMusic = ActiveSound.bIsMusic || SoundClassProperties->bIsMusic; WaveInstance->bCenterChannelOnly = ActiveSound.bCenterChannelOnly || SoundClassProperties->bCenterChannelOnly; WaveInstance->bEQFilterApplied = ActiveSound.bEQFilterApplied || SoundClassProperties->bApplyEffects; WaveInstance->bReverb = ActiveSound.bReverb || SoundClassProperties->bReverb; WaveInstance->OutputTarget = SoundClassProperties->OutputTarget; if (SoundClassProperties->bApplyAmbientVolumes) { WaveInstance->VolumeMultiplier *= ParseParams.InteriorVolumeMultiplier; WaveInstance->RadioFilterVolume *= ParseParams.InteriorVolumeMultiplier; WaveInstance->RadioFilterVolumeThreshold *= ParseParams.InteriorVolumeMultiplier; } bAlwaysPlay = ActiveSound.bAlwaysPlay || SoundClassProperties->bAlwaysPlay; } else { WaveInstance->VoiceCenterChannelVolume = 0.f; WaveInstance->RadioFilterVolume = 0.f; WaveInstance->RadioFilterVolumeThreshold = 0.f; WaveInstance->StereoBleed = 0.f; WaveInstance->LFEBleed = 0.f; WaveInstance->bEQFilterApplied = ActiveSound.bEQFilterApplied; WaveInstance->bIsUISound = ActiveSound.bIsUISound; WaveInstance->bIsMusic = ActiveSound.bIsMusic; WaveInstance->bReverb = ActiveSound.bReverb; WaveInstance->bCenterChannelOnly = ActiveSound.bCenterChannelOnly; bAlwaysPlay = ActiveSound.bAlwaysPlay; } // If set to bAlwaysPlay, increase the current sound's priority scale by 10x. This will still result in a possible 0-priority output if the sound has 0 actual volume if (bAlwaysPlay) { WaveInstance->Priority = MAX_FLT; } else { WaveInstance->Priority = ParseParams.Priority; } WaveInstance->Location = ParseParams.Transform.GetTranslation(); WaveInstance->bIsStarted = true; WaveInstance->bAlreadyNotifiedHook = false; WaveInstance->bUseSpatialization = ParseParams.bUseSpatialization; WaveInstance->SpatializationAlgorithm = ParseParams.SpatializationAlgorithm; WaveInstance->WaveData = this; WaveInstance->NotifyBufferFinishedHooks = ParseParams.NotifyBufferFinishedHooks; WaveInstance->LoopingMode = ((bLooping || ParseParams.bLooping) ? LOOP_Forever : LOOP_Never); WaveInstance->bIsPaused = ParseParams.bIsPaused; if (AudioDevice->IsHRTFEnabledForAll() && ParseParams.SpatializationAlgorithm == SPATIALIZATION_Default) { WaveInstance->SpatializationAlgorithm = SPATIALIZATION_HRTF; } else { WaveInstance->SpatializationAlgorithm = ParseParams.SpatializationAlgorithm; } // Only append to the wave instances list if we're virtual (always append) or we're audible (non-zero volume) if (WaveInstance->GetVolume() > KINDA_SMALL_NUMBER || (bVirtualizeWhenSilent && AudioDevice->VirtualSoundsEnabled())) { WaveInstances.Add(WaveInstance); } // We're still alive. ActiveSound.bFinished = false; // Sanity check if( NumChannels > 2 && WaveInstance->bUseSpatialization && !WaveInstance->bReportedSpatializationWarning) { static TSet<USoundWave*> ReportedSounds; if (!ReportedSounds.Contains(this)) { FString SoundWarningInfo = FString::Printf(TEXT("Spatialisation on stereo and multichannel sounds is not supported. SoundWave: %s"), *GetName()); if (ActiveSound.GetSound() != this) { SoundWarningInfo += FString::Printf(TEXT(" SoundCue: %s"), *ActiveSound.GetSound()->GetName()); } #if !NO_LOGGING const uint64 AudioComponentID = ActiveSound.GetAudioComponentID(); if (AudioComponentID > 0) { FAudioThread::RunCommandOnGameThread([AudioComponentID, SoundWarningInfo]() { if (UAudioComponent* AudioComponent = UAudioComponent::GetAudioComponentFromID(AudioComponentID)) { AActor* SoundOwner = AudioComponent->GetOwner(); UE_LOG(LogAudio, Warning, TEXT( "%s Actor: %s AudioComponent: %s" ), *SoundWarningInfo, (SoundOwner ? *SoundOwner->GetName() : TEXT("None")), *AudioComponent->GetName() ); } else { UE_LOG(LogAudio, Warning, TEXT("%s"), *SoundWarningInfo ); } }); } else { UE_LOG(LogAudio, Warning, TEXT("%s"), *SoundWarningInfo ); } #endif ReportedSounds.Add(this); } WaveInstance->bReportedSpatializationWarning = true; } } }
void NetDemo::readSnapshotData(byte *buf, size_t length) { byte cid = consoleplayer_id; byte did = displayplayer_id; P_ClearAllNetIds(); // Remove all players players.clear(); // Remove all actors TThinkerIterator<AActor> iterator; AActor *mo; while ( (mo = iterator.Next() ) ) mo->Destroy(); gameaction = ga_nothing; FLZOMemFile memfile; length = 0; memfile.Open(buf); // open for reading FArchive arc(memfile); // Read the server cvars byte vars[4096], *vars_p; vars_p = vars; size_t len = arc.ReadCount (); arc.Read(vars, len); cvar_t::C_ReadCVars(&vars_p); std::string mapname; bool intermission; arc >> mapname; arc >> intermission; G_SerializeSnapshots(arc); P_SerializeRNGState(arc); P_SerializeACSDefereds(arc); // Read the status of flags in CTF for (int i = 0; i < NUMFLAGS; i++) arc >> CTFdata[i]; // Read team points for (int i = 0; i < NUMTEAMS; i++) arc >> TEAMpoints[i]; arc >> level.time; for (int i = 0; i < NUM_WORLDVARS; i++) arc >> ACS_WorldVars[i]; for (int i = 0; i < NUM_GLOBALVARS; i++) arc >> ACS_GlobalVars[i]; netgame = multiplayer = true; // load a base level savegamerestore = true; // Use the player actors in the savegame serverside = false; G_InitNew(mapname.c_str()); displayplayer_id = consoleplayer_id = 1; savegamerestore = false; // read consistancy marker byte check; arc >> check; arc.Close(); if (check != 0x1d) error("Bad snapshot"); consoleplayer_id = cid; // try to restore display player player_t *disp = &idplayer(did); if (validplayer(*disp) && disp->ingame() && !disp->spectator) displayplayer_id = did; else displayplayer_id = cid; // restore player colors for (size_t i = 0; i < players.size(); i++) R_BuildPlayerTranslation(players[i].id, players[i].userinfo.color); // Link the CTF flag actors to CTFdata[i].actor TThinkerIterator<AActor> flagiterator; while ( (mo = flagiterator.Next() ) ) { if (mo->type == MT_BDWN || mo->type == MT_BCAR) CTFdata[it_blueflag].actor = mo->ptr(); if (mo->type == MT_RDWN || mo->type == MT_RCAR) CTFdata[it_redflag].actor = mo->ptr(); } // Make sure the status bar is displayed correctly ST_Start(); }
/** * Removes the actor from its level's actor list and generally cleans up the engine's internal state. * What this function does not do, but is handled via garbage collection instead, is remove references * to this actor from all other actors, and kill the actor's resources. This function is set up so that * no problems occur even if the actor is being destroyed inside its recursion stack. * * @param ThisActor Actor to remove. * @param bNetForce [opt] Ignored unless called during play. Default is false. * @param bShouldModifyLevel [opt] If true, Modify() the level before removing the actor. Default is true. * @return true if destroy, false if actor couldn't be destroyed. */ bool UWorld::DestroyActor( AActor* ThisActor, bool bNetForce, bool bShouldModifyLevel ) { check(ThisActor); check(ThisActor->IsValidLowLevel()); //UE_LOG(LogSpawn, Log, "Destroy %s", *ThisActor->GetClass()->GetName() ); if (ThisActor->GetWorld() == NULL) { UE_LOG(LogSpawn, Warning, TEXT("Destroying %s, which doesn't have a valid world pointer"), *ThisActor->GetPathName()); } // If already on list to be deleted, pretend the call was successful. // We don't want recursive calls to trigger destruction notifications multiple times. if (ThisActor->IsPendingKillPending()) { return true; } // In-game deletion rules. if( IsGameWorld() ) { // Never destroy the world settings actor. This used to be enforced by bNoDelete and is actually needed for // seamless travel and network games. if (GetWorldSettings() == ThisActor) { return false; } // Can't kill if wrong role. if( ThisActor->Role!=ROLE_Authority && !bNetForce && !ThisActor->bNetTemporary ) { return false; } // Don't destroy player actors. APlayerController* PC = Cast<APlayerController>(ThisActor); if ( PC ) { UNetConnection* C = Cast<UNetConnection>(PC->Player); if( C ) { if( C->Channels[0] && C->State!=USOCK_Closed ) { C->bPendingDestroy = true; C->Channels[0]->Close(); } return false; } } } else { ThisActor->Modify(); } // Prevent recursion //FMarkActorIsBeingDestroyed MarkActorIsBeingDestroyed(ThisActor); // Notify the texture streaming manager about the destruction of this actor. IStreamingManager::Get().NotifyActorDestroyed( ThisActor ); // Tell this actor it's about to be destroyed. ThisActor->Destroyed(); // Detach this actor's children TArray<AActor*> AttachedActors; ThisActor->GetAttachedActors(AttachedActors); if (AttachedActors.Num() > 0) { TInlineComponentArray<USceneComponent*> SceneComponents; ThisActor->GetComponents(SceneComponents); for (TArray< AActor* >::TConstIterator AttachedActorIt(AttachedActors); AttachedActorIt; ++AttachedActorIt) { AActor* ChildActor = *AttachedActorIt; if (ChildActor != NULL) { for (auto SceneCompIter = SceneComponents.CreateIterator(); SceneCompIter; ++SceneCompIter) { ChildActor->DetachSceneComponentsFromParent(*SceneCompIter, true); } #if WITH_EDITOR if( GIsEditor ) { GEngine->BroadcastLevelActorDetached(ChildActor, ThisActor); } #endif } } } // Detach from anything we were attached to USceneComponent* RootComp = ThisActor->GetRootComponent(); if( RootComp != NULL && RootComp->AttachParent != NULL) { AActor* OldParentActor = RootComp->AttachParent->GetOwner(); if (OldParentActor) { OldParentActor->Modify(); } ThisActor->DetachRootComponentFromParent(); #if WITH_EDITOR if( GIsEditor ) { GEngine->BroadcastLevelActorDetached(ThisActor, OldParentActor); } #endif } ThisActor->ClearComponentOverlaps(); // If this actor has an owner, notify it that it has lost a child. if( ThisActor->GetOwner() ) { ThisActor->SetOwner(NULL); } // Notify net players that this guy has been destroyed. UNetDriver* ActorNetDriver = GEngine->FindNamedNetDriver(this, ThisActor->NetDriverName); if (ActorNetDriver) { ActorNetDriver->NotifyActorDestroyed(ThisActor); } if ( DemoNetDriver ) { DemoNetDriver->NotifyActorDestroyed( ThisActor ); } // Remove the actor from the actor list. RemoveActor( ThisActor, bShouldModifyLevel ); // Invalidate the lighting cache in the Editor. We need to check for GIsEditor as play has not begun in network game and objects get destroyed on switching levels if ( GIsEditor ) { ThisActor->InvalidateLightingCache(); #if WITH_EDITOR GEngine->BroadcastLevelActorDeleted(ThisActor); #endif } // Clean up the actor's components. ThisActor->UnregisterAllComponents(); // Mark the actor and its direct components as pending kill. ThisActor->MarkPendingKill(); ThisActor->MarkPackageDirty(); ThisActor->MarkComponentsAsPendingKill(); // Unregister the actor's tick function const bool bRegisterTickFunctions = false; const bool bIncludeComponents = true; ThisActor->RegisterAllActorTickFunctions(bRegisterTickFunctions, bIncludeComponents); // Return success. return true; }
USceneComponent* USCS_Node::GetParentComponentTemplate(UBlueprint* InBlueprint) const { USceneComponent* ParentComponentTemplate = NULL; if(ParentComponentOrVariableName != NAME_None) { check(InBlueprint != NULL && InBlueprint->GeneratedClass != NULL); // If the parent component template is found in the 'Components' array of the CDO (i.e. native) if(bIsParentComponentNative) { // Access the Blueprint CDO AActor* CDO = InBlueprint->GeneratedClass->GetDefaultObject<AActor>(); if(CDO != NULL) { // Find the component template in the CDO that matches the specified name TInlineComponentArray<USceneComponent*> Components; CDO->GetComponents(Components); for(auto CompIt = Components.CreateIterator(); CompIt; ++CompIt) { USceneComponent* CompTemplate = *CompIt; if(CompTemplate->GetFName() == ParentComponentOrVariableName) { // Found a match; this is our parent, we're done ParentComponentTemplate = CompTemplate; break; } } } } // Otherwise the parent component template is found in a parent Blueprint's SCS tree (i.e. non-native) else { // Get the Blueprint hierarchy TArray<UBlueprint*> ParentBPStack; UBlueprint::GetBlueprintHierarchyFromClass(InBlueprint->GeneratedClass, ParentBPStack); // Find the parent Blueprint in the hierarchy for(int32 StackIndex = ParentBPStack.Num() - 1; StackIndex > 0; --StackIndex) { UBlueprint* ParentBlueprint = ParentBPStack[StackIndex]; if(ParentBlueprint != NULL && ParentBlueprint->SimpleConstructionScript != NULL && ParentBlueprint->GeneratedClass->GetFName() == ParentComponentOwnerClassName) { // Find the SCS node with a variable name that matches the specified name TArray<USCS_Node*> ParentSCSNodes = ParentBlueprint->SimpleConstructionScript->GetAllNodes(); for(int32 ParentNodeIndex = 0; ParentNodeIndex < ParentSCSNodes.Num(); ++ParentNodeIndex) { USceneComponent* CompTemplate = Cast<USceneComponent>(ParentSCSNodes[ParentNodeIndex]->ComponentTemplate); if(CompTemplate != NULL && ParentSCSNodes[ParentNodeIndex]->VariableName == ParentComponentOrVariableName) { // Found a match; this is our parent, we're done ParentComponentTemplate = CompTemplate; break; } } } } } } return ParentComponentTemplate; }
void UParticleModuleVelocityCone::Render3DPreview(FParticleEmitterInstance* Owner, const FSceneView* View,FPrimitiveDrawInterface* PDI) { #if WITH_EDITOR float ConeMaxAngle = 0.0f; float ConeMinAngle = 0.0f; Angle.GetOutRange(ConeMinAngle, ConeMaxAngle); float ConeMaxVelocity = 0.0f; float ConeMinVelocity = 0.0f; Velocity.GetOutRange(ConeMinVelocity, ConeMaxVelocity); float MaxLifetime = 0.0f; TArray<UParticleModule*>& Modules = Owner->SpriteTemplate->GetCurrentLODLevel(Owner)->Modules; for (int32 ModuleIndex = 0; ModuleIndex < Modules.Num(); ModuleIndex++) { UParticleModuleLifetimeBase* LifetimeMod = Cast<UParticleModuleLifetimeBase>(Modules[ModuleIndex]); if (LifetimeMod != NULL) { MaxLifetime = LifetimeMod->GetMaxLifetime(); break; } } const int32 ConeSides = 16; const float ConeRadius = ConeMaxVelocity * MaxLifetime; // Calculate direction transform const FVector DefaultDirection(0.0f, 0.0f, 1.0f); const FVector ForwardDirection = (Direction != FVector::ZeroVector)? Direction.GetSafeNormal(): DefaultDirection; FVector UpDirection(0.0f, 0.0f, 1.0f); FVector RightDirection(1.0f, 0.0f, 0.0f); if ((ForwardDirection != UpDirection) && (-ForwardDirection != UpDirection)) { RightDirection = UpDirection ^ ForwardDirection; UpDirection = ForwardDirection ^ RightDirection; } else { UpDirection = ForwardDirection ^ RightDirection; RightDirection = UpDirection ^ ForwardDirection; } FMatrix DirectionRotation; DirectionRotation.SetIdentity(); DirectionRotation.SetAxis(0, RightDirection.GetSafeNormal()); DirectionRotation.SetAxis(1, UpDirection.GetSafeNormal()); DirectionRotation.SetAxis(2, ForwardDirection); // Calculate the owning actor's scale and rotation UParticleLODLevel* LODLevel = Owner->SpriteTemplate->GetCurrentLODLevel(Owner); check(LODLevel); FVector OwnerScale(1.0f); FMatrix OwnerRotation(FMatrix::Identity); FVector LocalToWorldOrigin(0.0f); FMatrix LocalToWorld(FMatrix::Identity); if (Owner->Component) { AActor* Actor = Owner->Component->GetOwner(); if (Actor) { if (bApplyOwnerScale == true) { OwnerScale = Owner->Component->ComponentToWorld.GetScale3D(); } OwnerRotation = FQuatRotationMatrix(Actor->GetActorQuat()); } LocalToWorldOrigin = Owner->Component->ComponentToWorld.GetLocation(); LocalToWorld = Owner->Component->ComponentToWorld.ToMatrixWithScale().RemoveTranslation(); LocalToWorld.RemoveScaling(); } FMatrix Transform; Transform.SetIdentity(); // DrawWireCone() draws a cone down the X axis, but this cone's default direction is down Z const FRotationMatrix XToZRotation(FRotator((int32)(HALF_PI * 10430), 0, 0)); Transform *= XToZRotation; // Apply scale Transform.SetAxis(0, Transform.GetScaledAxis( EAxis::X ) * OwnerScale.X); Transform.SetAxis(1, Transform.GetScaledAxis( EAxis::Y ) * OwnerScale.Y); Transform.SetAxis(2, Transform.GetScaledAxis( EAxis::Z ) * OwnerScale.Z); // Apply direction transform Transform *= DirectionRotation; // Transform according to world and local space flags if (!LODLevel->RequiredModule->bUseLocalSpace && !bInWorldSpace) { Transform *= LocalToWorld; } else if (LODLevel->RequiredModule->bUseLocalSpace && bInWorldSpace) { Transform *= OwnerRotation; Transform *= LocalToWorld.InverseFast(); } else if (!bInWorldSpace) { Transform *= OwnerRotation; } // Apply translation Transform.SetOrigin(LocalToWorldOrigin); TArray<FVector> OuterVerts; TArray<FVector> InnerVerts; // Draw inner and outer cones DrawWireCone(PDI, InnerVerts, Transform, ConeRadius, ConeMinAngle, ConeSides, ModuleEditorColor, SDPG_World); DrawWireCone(PDI, OuterVerts, Transform, ConeRadius, ConeMaxAngle, ConeSides, ModuleEditorColor, SDPG_World); // Draw radial spokes for (int32 i = 0; i < ConeSides; ++i) { PDI->DrawLine( OuterVerts[i], InnerVerts[i], ModuleEditorColor, SDPG_World ); } #endif }
void UInterpToMovementComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) { QUICK_SCOPE_CYCLE_COUNTER(STAT_InterpToMovementComponent_TickComponent); Super::TickComponent(DeltaTime, TickType, ThisTickFunction); // skip if don't want component updated when not rendered or updated component can't move if (!UpdatedComponent || ShouldSkipUpdate(DeltaTime)) { return; } AActor* ActorOwner = UpdatedComponent->GetOwner(); if (!ActorOwner || !CheckStillInWorld()) { return; } if (UpdatedComponent->IsSimulatingPhysics()) { return; } if((bStopped == true ) || ( ActorOwner->IsPendingKill() ) ) { return; } if( ControlPoints.Num()== 0 ) { return; } // This will update any control points coordinates that are linked to actors. UpdateControlPoints(false); float RemainingTime = DeltaTime; int32 NumBounces = 0; int32 Iterations = 0; FHitResult Hit(1.f); FVector WaitPos = FVector::ZeroVector; if (bIsWaiting == true) { WaitPos = UpdatedComponent->GetComponentLocation(); } while (RemainingTime >= MIN_TICK_TIME && (Iterations < MaxSimulationIterations) && !ActorOwner->IsPendingKill() && UpdatedComponent) { Iterations++; const float TimeTick = ShouldUseSubStepping() ? GetSimulationTimeStep(RemainingTime, Iterations) : RemainingTime; RemainingTime -= TimeTick; // Calculate the current time with this tick iteration float Time = FMath::Clamp(CurrentTime + ((DeltaTime*TimeMultiplier)*CurrentDirection),0.0f,1.0f); FVector MoveDelta = ComputeMoveDelta(Time); // Update the rotation on the spline if required FRotator CurrentRotation = UpdatedComponent->GetComponentRotation(); // Move the component if ((bPauseOnImpact == false ) && (BehaviourType != EInterpToBehaviourType::OneShot)) { // If we can bounce, we are allowed to move out of penetrations, so use SafeMoveUpdatedComponent which does that automatically. SafeMoveUpdatedComponent(MoveDelta, CurrentRotation, true, Hit); } else { // If we can't bounce, then we shouldn't adjust if initially penetrating, because that should be a blocking hit that causes a hit event and stop simulation. TGuardValue<EMoveComponentFlags> ScopedFlagRestore(MoveComponentFlags, MoveComponentFlags | MOVECOMP_NeverIgnoreBlockingOverlaps); MoveUpdatedComponent(MoveDelta, CurrentRotation, true, &Hit); } //DrawDebugPoint(GetWorld(), UpdatedComponent->GetComponentLocation(), 16, FColor::White,true,5.0f); // If we hit a trigger that destroyed us, abort. if (ActorOwner->IsPendingKill() || !UpdatedComponent) { return; } // Handle hit result after movement if (!Hit.bBlockingHit) { // If we were 'waiting' were not any more - broadcast we are off again if( bIsWaiting == true ) { OnWaitEndDelegate.Broadcast(Hit, Time); bIsWaiting = false; } else { CalculateNewTime(CurrentTime, TimeTick, Hit, true, bStopped); if (bStopped == true) { return; } } } else { if (HandleHitWall(Hit, TimeTick, MoveDelta)) { break; } NumBounces++; float SubTickTimeRemaining = TimeTick * (1.f - Hit.Time); // A few initial bounces should add more time and iterations to complete most of the simulation. if (NumBounces <= 2 && SubTickTimeRemaining >= MIN_TICK_TIME) { RemainingTime += SubTickTimeRemaining; Iterations--; } } } if( bIsWaiting == false ) { FHitResult DummyHit; CurrentTime = CalculateNewTime(CurrentTime, DeltaTime, DummyHit, false, bStopped); } UpdateComponentVelocity(); }
void AMatineeActor::PostNetReceive() { Super::PostNetReceive(); if (MatineeData != NULL) { TArray<AActor*> ControlledActors; // Build a list of actors controlled by this matinee actor for( int32 InfoIndex = 0; InfoIndex < GroupActorInfos.Num(); ++InfoIndex ) { const FInterpGroupActorInfo& Info = GroupActorInfos[ InfoIndex ]; for (int32 ActorIndex = 0; ActorIndex < Info.Actors.Num(); ++ActorIndex ) { AActor* Actor = Info.Actors[ ActorIndex ]; if (Actor != NULL) { ControlledActors.Add( Actor ); } } } // if we just received the matinee action, set 'saved' values to default so we make sure to apply previously received values if (SavedInterpData == NULL) { AMatineeActor* Default = GetClass()->GetDefaultObject<AMatineeActor>(); SavedbIsPlaying = Default->bIsPlaying; SavedPosition = Default->InterpPosition; SavedbReversePlayback = Default->bReversePlayback; } // apply bReversePlayback if (SavedbReversePlayback!= bReversePlayback) { bReversePlayback = SavedbReversePlayback; if (SavedbIsPlaying && bIsPlaying) { // notify actors that something has changed for (int32 ActorIndex = 0; ActorIndex < ControlledActors.Num(); ++ActorIndex ) { IMatineeInterface * IMI = InterfaceCast<IMatineeInterface>(ControlledActors[ActorIndex]); if (IMI) { IMI->InterpolationChanged(this); } } } } // start up interpolation, if necessary if (!SavedbIsPlaying && (bIsPlaying || InterpPosition != SavedPosition)) { InitInterp(); // if we're playing forward, call Play() to process any special properties on InterpAction that may affect the meaning of 'Position' (bNoResetOnRewind, etc) if (!bReversePlayback) { Play(); } // find affected actors and set their ControllingMatineeActor // @warning: this code requires the linked actors to be static object references (i.e., some other Kismet action can't be assigning them) // this might not work for AI pawns for (int32 ActorIndex = 0; ActorIndex < ControlledActors.Num(); ++ActorIndex ) { AActor* Actor = ControlledActors[ActorIndex]; UInterpGroupInst * GrInst = FindGroupInst(Actor); if (Actor != NULL && !Actor->IsPendingKill() && GrInst != NULL) { Actor->AddControllingMatineeActor(*this); // fire an event if we're really playing (and not just starting it up to do a position update) if (bIsPlaying) { IMatineeInterface * IMI = InterfaceCast<IMatineeInterface>(Actor); if (IMI) { IMI->InterpolationStarted(this); } } } } } // if we received a different current position if (InterpPosition != SavedPosition) { //@hack: negate fade tracks if we're updating a stopped matinee // the right fix is probably to pass bJump=true to UpdateInterp() when (!bIsPlaying && !SavedbIsPlaying), // but that may have lots of other side effects I don't have time to test right now TArray<FSavedFadeState> SavedFadeStates; if (!bIsPlaying && !SavedbIsPlaying && MatineeData != NULL) { for (FLocalPlayerIterator It(GEngine, GetWorld()); It; ++It) { if (It->PlayerController != NULL && It->PlayerController->PlayerCameraManager != NULL) { new(SavedFadeStates)FSavedFadeState(It->PlayerController->PlayerCameraManager); } } } if (bIsPlaying && SavedPosition != -1 && FMath::Abs(InterpPosition - SavedPosition) < ClientSidePositionErrorTolerance) { // The error value between us and the server is too small to change gameplay, but will cause visual pops InterpPosition = SavedPosition; } else { // set to position replicated from server UpdateInterp(InterpPosition, false, false); } } // terminate interpolation, if necessary if ((SavedbIsPlaying || InterpPosition != SavedPosition) && !bIsPlaying) { TermInterp(); // find affected actors and remove InterpAction from their LatentActions list for (int32 ActorIndex = 0; ActorIndex < ControlledActors.Num(); ++ActorIndex ) { AActor* Actor = ControlledActors[ ActorIndex ]; if (Actor != NULL) { Actor->RemoveControllingMatineeActor(*this); // fire an event if we were really playing (and not just starting it up to do a position update) if (SavedbIsPlaying) { IMatineeInterface * IMI = InterfaceCast<IMatineeInterface>(Actor); if (IMI) { IMI->InterpolationFinished(this); } } } } } } }
void UAblRayCastQueryTask::OnTaskStart(const TWeakObjectPtr<const UAblAbilityContext>& Context) const { Super::OnTaskStart(Context); AActor* SourceActor = m_QueryLocation.GetSourceActor(*Context.Get()); check(SourceActor); UWorld* World = SourceActor->GetWorld(); FTransform QueryTransform; m_QueryLocation.GetTransform(*Context.Get(), QueryTransform); const FVector RayStart = QueryTransform.GetLocation(); const FVector RayEnd = RayStart + QueryTransform.GetRotation().GetForwardVector() * m_Length; if (m_UseAsyncQuery && UAbleSettings::IsAsyncEnabled()) { UAblRayCastQueryTaskScratchPad* ScratchPad = Cast<UAblRayCastQueryTaskScratchPad>(Context->GetScratchPadForTask(this)); check(ScratchPad); if (m_OnlyReturnBlockingHit) { ScratchPad->AsyncHandle = World->AsyncLineTraceByChannel(EAsyncTraceType::Single, RayStart, RayEnd, m_CollisionChannel); } else { ScratchPad->AsyncHandle = World->AsyncLineTraceByChannel(EAsyncTraceType::Multi, RayStart, RayEnd, m_CollisionChannel); } } else { TArray<FHitResult> HitResults; FHitResult TraceResult; if (m_OnlyReturnBlockingHit) { if (World->LineTraceSingleByChannel(TraceResult, RayStart, RayEnd, m_CollisionChannel)) { HitResults.Add(TraceResult); } } else { World->LineTraceMultiByChannel(HitResults, RayStart, RayEnd, m_CollisionChannel); } #if !(UE_BUILD_SHIPPING) if (IsVerbose()) { PrintVerbose(FString::Printf(TEXT("Raycast found %d results."), HitResults.Num())); } #endif if (HitResults.Num()) { #if !(UE_BUILD_SHIPPING) if (IsVerbose()) { // Quick distance print help to see if we hit ourselves. float DistanceToBlocker = HitResults[HitResults.Num() - 1].Distance; PrintVerbose(FString::Printf(TEXT("Raycast blocking hit distance: %4.2f."), DistanceToBlocker)); } #endif if (m_CopyResultsToContext) { #if !(UE_BUILD_SHIPPING) if (IsVerbose()) { PrintVerbose(FString::Printf(TEXT("Copying %d results into Context."), HitResults.Num())); } #endif CopyResultsToContext(HitResults, Context); } if (m_FireEvent) { #if !(UE_BUILD_SHIPPING) if (IsVerbose()) { PrintVerbose(FString::Printf(TEXT("Firing Raycast Event %s with %d results."), *m_Name.ToString(), HitResults.Num())); } #endif Context->GetAbility()->OnRaycastEvent(Context.Get(), m_Name, HitResults); } } } #if !UE_BUILD_SHIPPING if (FAblAbilityDebug::ShouldDrawQueries()) { FAblAbilityDebug::DrawRaycastQuery(World, QueryTransform, m_Length); } #endif }
FSelectedActorInfo BuildSelectedActorInfo( const TArray<AActor*>& SelectedActors) { FSelectedActorInfo ActorInfo; if( SelectedActors.Num() > 0 ) { // Get the class type of the first actor. AActor* FirstActor = SelectedActors[0]; if( FirstActor && !FirstActor->HasAnyFlags( RF_ClassDefaultObject ) ) { UClass* FirstClass = FirstActor->GetClass(); UObject* FirstArchetype = FirstActor->GetArchetype(); ActorInfo.bAllSelectedAreBrushes = Cast< ABrush >( FirstActor ) != NULL; ActorInfo.SelectionClass = FirstClass; // Compare all actor types with the baseline. for ( int32 ActorIndex = 0; ActorIndex < SelectedActors.Num(); ++ActorIndex ) { AActor* CurrentActor = SelectedActors[ ActorIndex ]; if( CurrentActor->HasAnyFlags( RF_ClassDefaultObject ) ) { continue; } ABrush* Brush = Cast< ABrush >( CurrentActor ); if( !Brush) { ActorInfo.bAllSelectedAreBrushes = false; } else { if( !ActorInfo.bHaveBuilderBrush ) { ActorInfo.bHaveBuilderBrush = FActorEditorUtils::IsABuilderBrush(Brush); } ActorInfo.bHaveBrush |= true; ActorInfo.bHaveBSPBrush |= (!Brush->IsVolumeBrush()); ActorInfo.bHaveVolume |= Brush->IsVolumeBrush(); } UClass* CurrentClass = CurrentActor->GetClass(); if( FirstClass != CurrentClass ) { ActorInfo.bAllSelectedActorsOfSameType = false; ActorInfo.SelectionClass = NULL; FirstClass = NULL; } else { ActorInfo.SelectionClass = CurrentActor->GetClass(); } ++ActorInfo.NumSelected; if( ActorInfo.bAllSelectedActorsBelongToCurrentLevel ) { if( !CurrentActor->GetOuter()->IsA(ULevel::StaticClass()) || !CurrentActor->GetLevel()->IsCurrentLevel() ) { ActorInfo.bAllSelectedActorsBelongToCurrentLevel = false; } } if( ActorInfo.bAllSelectedActorsBelongToSameWorld ) { if ( !ActorInfo.SharedWorld ) { ActorInfo.SharedWorld = CurrentActor->GetWorld(); check(ActorInfo.SharedWorld); } else { if( ActorInfo.SharedWorld != CurrentActor->GetWorld() ) { ActorInfo.bAllSelectedActorsBelongToCurrentLevel = false; ActorInfo.SharedWorld = NULL; } } } // To prevent move to other level for Landscape if its components are distributed in streaming levels if (CurrentActor->IsA(ALandscape::StaticClass())) { ALandscape* Landscape = CastChecked<ALandscape>(CurrentActor); if (!Landscape || !Landscape->HasAllComponent()) { if( !ActorInfo.bAllSelectedActorsBelongToCurrentLevel ) { ActorInfo.bAllSelectedActorsBelongToCurrentLevel = true; } } } if ( ActorInfo.bSelectedActorsBelongToSameLevel ) { ULevel* ActorLevel = CurrentActor->GetOuter()->IsA(ULevel::StaticClass()) ? CurrentActor->GetLevel() : NULL; if ( !ActorInfo.SharedLevel ) { // This is the first selected actor we've encountered. ActorInfo.SharedLevel = ActorLevel; } else { // Does this actor's level match the others? if ( ActorInfo.SharedLevel != ActorLevel ) { ActorInfo.bSelectedActorsBelongToSameLevel = false; ActorInfo.SharedLevel = NULL; } } } AGroupActor* FoundGroup = Cast<AGroupActor>(CurrentActor); if(!FoundGroup) { FoundGroup = AGroupActor::GetParentForActor(CurrentActor); } if( FoundGroup ) { if( !ActorInfo.bHaveSelectedSubGroup ) { ActorInfo.bHaveSelectedSubGroup = AGroupActor::GetParentForActor(FoundGroup) != NULL; } if( !ActorInfo.bHaveSelectedLockedGroup ) { ActorInfo.bHaveSelectedLockedGroup = FoundGroup->IsLocked(); } if( !ActorInfo.bHaveSelectedUnlockedGroup ) { AGroupActor* FoundRoot = AGroupActor::GetRootForActor(CurrentActor); ActorInfo.bHaveSelectedUnlockedGroup = !FoundGroup->IsLocked() || ( FoundRoot && !FoundRoot->IsLocked() ); } } else { ++ActorInfo.NumSelectedUngroupedActors; } USceneComponent* RootComp = CurrentActor->GetRootComponent(); if(RootComp != NULL && RootComp->AttachParent != NULL) { ActorInfo.bHaveAttachedActor = true; } TInlineComponentArray<UActorComponent*> ActorComponents; CurrentActor->GetComponents(ActorComponents); for( UActorComponent* Component : ActorComponents ) { if( UStaticMeshComponent* SMComp = Cast<UStaticMeshComponent>(Component) ) { if( SMComp->IsRegistered() ) { ActorInfo.bHaveStaticMeshComponent = true; } } // Check for experimental/early-access classes in the component hierarchy bool bIsExperimental, bIsEarlyAccess; FObjectEditorUtils::GetClassDevelopmentStatus(Component->GetClass(), bIsExperimental, bIsEarlyAccess); ActorInfo.bHaveExperimentalClass |= bIsExperimental; ActorInfo.bHaveEarlyAccessClass |= bIsEarlyAccess; } // Check for experimental/early-access classes in the actor hierarchy { bool bIsExperimental, bIsEarlyAccess; FObjectEditorUtils::GetClassDevelopmentStatus(CurrentClass, bIsExperimental, bIsEarlyAccess); ActorInfo.bHaveExperimentalClass |= bIsExperimental; ActorInfo.bHaveEarlyAccessClass |= bIsEarlyAccess; } if( CurrentActor->IsA( ALight::StaticClass() ) ) { ActorInfo.bHaveLight = true; } if( CurrentActor->IsA( AStaticMeshActor::StaticClass() ) ) { ActorInfo.bHaveStaticMesh = true; AStaticMeshActor* StaticMeshActor = CastChecked<AStaticMeshActor>( CurrentActor ); if ( StaticMeshActor->GetStaticMeshComponent() ) { UStaticMesh* StaticMesh = StaticMeshActor->GetStaticMeshComponent()->StaticMesh; ActorInfo.bAllSelectedStaticMeshesHaveCollisionModels &= ( (StaticMesh && StaticMesh->BodySetup) ? true : false ); } } if( CurrentActor->IsA( ASkeletalMeshActor::StaticClass() ) ) { ActorInfo.bHaveSkeletalMesh = true; } if( CurrentActor->IsA( APawn::StaticClass() ) ) { ActorInfo.bHavePawn = true; } if( CurrentActor->IsA( AEmitter::StaticClass() ) ) { ActorInfo.bHaveEmitter = true; } if ( CurrentActor->IsA( AMatineeActor::StaticClass() ) ) { ActorInfo.bHaveMatinee = true; } if ( CurrentActor->IsTemporarilyHiddenInEditor() ) { ActorInfo.bHaveHidden = true; } if ( CurrentActor->IsA( ALandscapeProxy::StaticClass() ) ) { ActorInfo.bHaveLandscape = true; } // Find our counterpart actor AActor* EditorWorldActor = EditorUtilities::GetEditorWorldCounterpartActor( CurrentActor ); if( EditorWorldActor != NULL ) { // Just count the total number of actors with counterparts ++ActorInfo.NumSimulationChanges; } } if( ActorInfo.SelectionClass != NULL ) { ActorInfo.SelectionStr = ActorInfo.SelectionClass->GetName(); } else { ActorInfo.SelectionStr = TEXT("Actor"); } } } // hack when only BSP is selected if( ActorInfo.SharedWorld == nullptr ) { ActorInfo.SharedWorld = GWorld; } return ActorInfo; }
/** * Creates an actor using the specified factory. * * Does nothing if ActorClass is NULL. */ static AActor* PrivateAddActor( UObject* Asset, UActorFactory* Factory, bool SelectActor = true, EObjectFlags ObjectFlags = RF_Transactional, const FName Name = NAME_None ) { if (!Factory) { return nullptr; } AActor* Actor = NULL; AActor* NewActorTemplate = Factory->GetDefaultActor( Asset ); if ( !NewActorTemplate ) { return nullptr; } // For Brushes/Volumes, use the default brush as the template rather than the factory default actor if (NewActorTemplate->IsA(ABrush::StaticClass()) && GWorld->GetDefaultBrush() != nullptr) { NewActorTemplate = GWorld->GetDefaultBrush(); } const FSnappedPositioningData PositioningData = FSnappedPositioningData(GCurrentLevelEditingViewportClient, GEditor->ClickLocation, GEditor->ClickPlane) .UseFactory(Factory) .UseStartTransform(NewActorTemplate->GetTransform()) .UsePlacementExtent(NewActorTemplate->GetPlacementExtent()); const FTransform ActorTransform = FActorPositioning::GetSnappedSurfaceAlignedTransform(PositioningData); // Do not fade snapping indicators over time if the viewport is not realtime bool bClearImmediately = !GCurrentLevelEditingViewportClient || !GCurrentLevelEditingViewportClient->IsRealtime(); FSnappingUtils::ClearSnappingHelpers( bClearImmediately ); ULevel* DesiredLevel = GWorld->GetCurrentLevel(); // Don't spawn the actor if the current level is locked. if ( FLevelUtils::IsLevelLocked(DesiredLevel) ) { FNotificationInfo Info( NSLOCTEXT("UnrealEd", "Error_OperationDisallowedOnLockedLevel", "The requested operation could not be completed because the level is locked.") ); Info.ExpireDuration = 3.0f; FSlateNotificationManager::Get().AddNotification(Info); return nullptr; } { FScopedTransaction Transaction( NSLOCTEXT("UnrealEd", "CreateActor", "Create Actor") ); if ( !(ObjectFlags & RF_Transactional) ) { Transaction.Cancel(); } // Create the actor. Actor = Factory->CreateActor( Asset, DesiredLevel, ActorTransform, ObjectFlags, Name ); if(Actor) { if ( SelectActor ) { GEditor->SelectNone( false, true ); GEditor->SelectActor( Actor, true, true ); } Actor->InvalidateLightingCache(); Actor->PostEditChange(); } } GEditor->RedrawLevelEditingViewports(); if ( Actor ) { Actor->MarkPackageDirty(); ULevel::LevelDirtiedEvent.Broadcast(); } return Actor; }
bool FMeshMergingTool::RunMerge(const FString& PackageName) { IMeshUtilities& MeshUtilities = FModuleManager::Get().LoadModuleChecked<IMeshUtilities>("MeshUtilities"); USelection* SelectedActors = GEditor->GetSelectedActors(); TArray<AActor*> Actors; TArray<ULevel*> UniqueLevels; for (FSelectionIterator Iter(*SelectedActors); Iter; ++Iter) { AActor* Actor = Cast<AActor>(*Iter); if (Actor) { Actors.Add(Actor); UniqueLevels.AddUnique(Actor->GetLevel()); } } // This restriction is only for replacement of selected actors with merged mesh actor if (UniqueLevels.Num() > 1 && bReplaceSourceActors) { FText Message = NSLOCTEXT("UnrealEd", "FailedToMergeActorsSublevels_Msg", "The selected actors should be in the same level"); OpenMsgDlgInt(EAppMsgType::Ok, Message, NSLOCTEXT("UnrealEd", "FailedToMergeActors_Title", "Unable to merge actors")); return false; } int32 TargetMeshLOD = bExportSpecificLOD ? ExportLODIndex : INDEX_NONE; FVector MergedActorLocation; TArray<UObject*> AssetsToSync; // Merge... { FScopedSlowTask SlowTask(0, LOCTEXT("MergingActorsSlowTask", "Merging actors...")); SlowTask.MakeDialog(); MeshUtilities.MergeActors(Actors, MergingSettings, NULL, PackageName, TargetMeshLOD, AssetsToSync, MergedActorLocation); } if (AssetsToSync.Num()) { FAssetRegistryModule& AssetRegistry = FModuleManager::Get().LoadModuleChecked<FAssetRegistryModule>("AssetRegistry"); int32 AssetCount = AssetsToSync.Num(); for (int32 AssetIndex = 0; AssetIndex < AssetCount; AssetIndex++) { AssetRegistry.AssetCreated(AssetsToSync[AssetIndex]); GEditor->BroadcastObjectReimported(AssetsToSync[AssetIndex]); } //Also notify the content browser that the new assets exists FContentBrowserModule& ContentBrowserModule = FModuleManager::Get().LoadModuleChecked<FContentBrowserModule>("ContentBrowser"); ContentBrowserModule.Get().SyncBrowserToAssets(AssetsToSync, true); // Place new mesh in the world if (bReplaceSourceActors) { UStaticMesh* MergedMesh = nullptr; if (AssetsToSync.FindItemByClass(&MergedMesh)) { const FScopedTransaction Transaction(LOCTEXT("PlaceMergedActor", "Place Merged Actor")); UniqueLevels[0]->Modify(); UWorld* World = UniqueLevels[0]->OwningWorld; FActorSpawnParameters Params; Params.OverrideLevel = UniqueLevels[0]; FRotator MergedActorRotation(ForceInit); AStaticMeshActor* MergedActor = World->SpawnActor<AStaticMeshActor>(MergedActorLocation, MergedActorRotation, Params); MergedActor->GetStaticMeshComponent()->StaticMesh = MergedMesh; MergedActor->SetActorLabel(AssetsToSync[0]->GetName()); // Remove source actors for (AActor* Actor : Actors) { Actor->Destroy(); } } } } return true; }
void UDemoNetDriver::TickDemoRecord( float DeltaSeconds ) { if ( ClientConnections.Num() == 0 ) { return; } if ( FileAr == NULL ) { return; } DemoDeltaTime += DeltaSeconds; DemoCurrentTime += DeltaSeconds; const double CurrentSeconds = FPlatformTime::Seconds(); const double RECORD_HZ = CVarDemoRecordHz.GetValueOnGameThread(); const double RECORD_DELAY = 1.0 / RECORD_HZ; if ( CurrentSeconds - LastRecordTime < RECORD_DELAY ) { return; // Not enough real-time has passed to record another frame } LastRecordTime = CurrentSeconds; // Save out a frame DemoFrameNum++; ReplicationFrame++; // Save elapsed game time for this frame *FileAr << DemoDeltaTime; #if DEMO_CHECKSUMS == 1 uint32 DeltaTimeChecksum = FCrc::MemCrc32( &DemoDeltaTime, sizeof( DemoDeltaTime ), 0 ); *FileAr << DeltaTimeChecksum; #endif DemoDeltaTime = 0; // Make sure we don't have anything in the buffer for this new frame check( ClientConnections[0]->SendBuffer.GetNumBits() == 0 ); bIsRecordingDemoFrame = true; // Dump any queued packets UDemoNetConnection * ClientDemoConnection = CastChecked< UDemoNetConnection >( ClientConnections[0] ); for ( int32 i = 0; i < ClientDemoConnection->QueuedDemoPackets.Num(); i++ ) { ClientDemoConnection->LowLevelSend( (char*)&ClientDemoConnection->QueuedDemoPackets[i].Data[0], ClientDemoConnection->QueuedDemoPackets[i].Data.Num() ); } ClientDemoConnection->QueuedDemoPackets.Empty(); const bool IsNetClient = ( GetWorld()->GetNetDriver() != NULL && GetWorld()->GetNetDriver()->GetNetMode() == NM_Client ); DemoReplicateActor( World->GetWorldSettings(), ClientConnections[0], IsNetClient ); for ( int32 i = 0; i < World->NetworkActors.Num(); i++ ) { AActor* Actor = World->NetworkActors[i]; Actor->PreReplication( *FindOrCreateRepChangedPropertyTracker( Actor ).Get() ); DemoReplicateActor( Actor, ClientConnections[0], IsNetClient ); } // Make sure nothing is left over ClientConnections[0]->FlushNet(); check( ClientConnections[0]->SendBuffer.GetNumBits() == 0 ); bIsRecordingDemoFrame = false; // Write a count of 0 to signal the end of the frame int32 EndCount = 0; *FileAr << EndCount; }
void USoundWave::Parse( FAudioDevice* AudioDevice, const UPTRINT NodeWaveInstanceHash, FActiveSound& ActiveSound, const FSoundParseParameters& ParseParams, TArray<FWaveInstance*>& WaveInstances ) { FWaveInstance* WaveInstance = ActiveSound.FindWaveInstance(NodeWaveInstanceHash); // Create a new WaveInstance if this SoundWave doesn't already have one associated with it. if( WaveInstance == NULL ) { if( !ActiveSound.bRadioFilterSelected ) { ActiveSound.ApplyRadioFilter( AudioDevice, ParseParams ); } WaveInstance = HandleStart( ActiveSound, NodeWaveInstanceHash); } // Looping sounds are never actually finished if (bLooping || ParseParams.bLooping) { WaveInstance->bIsFinished = false; #if !NO_LOGGING if (!ActiveSound.bWarnedAboutOrphanedLooping && !ActiveSound.AudioComponent.IsValid()) { UE_LOG(LogAudio, Warning, TEXT("Detected orphaned looping sound '%s'."), *ActiveSound.Sound->GetName()); ActiveSound.bWarnedAboutOrphanedLooping = true; } #endif } // Check for finished paths. if( !WaveInstance->bIsFinished ) { // Propagate properties and add WaveInstance to outgoing array of FWaveInstances. WaveInstance->Volume = ParseParams.Volume * Volume; WaveInstance->VolumeMultiplier = ParseParams.VolumeMultiplier; WaveInstance->Pitch = ParseParams.Pitch * Pitch; WaveInstance->HighFrequencyGain = ParseParams.HighFrequencyGain; WaveInstance->bApplyRadioFilter = ActiveSound.bApplyRadioFilter; WaveInstance->StartTime = ParseParams.StartTime; WaveInstance->UserIndex = ActiveSound.UserIndex; WaveInstance->OmniRadius = ParseParams.OmniRadius; bool bAlwaysPlay = false; // Properties from the sound class WaveInstance->SoundClass = ParseParams.SoundClass; if (ParseParams.SoundClass) { FSoundClassProperties* SoundClassProperties = AudioDevice->GetSoundClassCurrentProperties(ParseParams.SoundClass); // Use values from "parsed/ propagated" sound class properties WaveInstance->VolumeMultiplier *= SoundClassProperties->Volume; WaveInstance->Pitch *= SoundClassProperties->Pitch; //TODO: Add in HighFrequencyGainMultiplier property to sound classes WaveInstance->VoiceCenterChannelVolume = SoundClassProperties->VoiceCenterChannelVolume; WaveInstance->RadioFilterVolume = SoundClassProperties->RadioFilterVolume * ParseParams.VolumeMultiplier; WaveInstance->RadioFilterVolumeThreshold = SoundClassProperties->RadioFilterVolumeThreshold * ParseParams.VolumeMultiplier; WaveInstance->StereoBleed = SoundClassProperties->StereoBleed; WaveInstance->LFEBleed = SoundClassProperties->LFEBleed; WaveInstance->bIsUISound = ActiveSound.bIsUISound || SoundClassProperties->bIsUISound; WaveInstance->bIsMusic = ActiveSound.bIsMusic || SoundClassProperties->bIsMusic; WaveInstance->bCenterChannelOnly = ActiveSound.bCenterChannelOnly || SoundClassProperties->bCenterChannelOnly; WaveInstance->bEQFilterApplied = ActiveSound.bEQFilterApplied || SoundClassProperties->bApplyEffects; WaveInstance->bReverb = ActiveSound.bReverb || SoundClassProperties->bReverb; WaveInstance->OutputTarget = SoundClassProperties->OutputTarget; bAlwaysPlay = ActiveSound.bAlwaysPlay || SoundClassProperties->bAlwaysPlay; } else { WaveInstance->VoiceCenterChannelVolume = 0.f; WaveInstance->RadioFilterVolume = 0.f; WaveInstance->RadioFilterVolumeThreshold = 0.f; WaveInstance->StereoBleed = 0.f; WaveInstance->LFEBleed = 0.f; WaveInstance->bEQFilterApplied = ActiveSound.bEQFilterApplied; WaveInstance->bIsUISound = ActiveSound.bIsUISound; WaveInstance->bIsMusic = ActiveSound.bIsMusic; WaveInstance->bReverb = ActiveSound.bReverb; WaveInstance->bCenterChannelOnly = ActiveSound.bCenterChannelOnly; bAlwaysPlay = ActiveSound.bAlwaysPlay; } WaveInstance->PlayPriority = WaveInstance->Volume + ( bAlwaysPlay ? 1.0f : 0.0f ) + WaveInstance->RadioFilterVolume; WaveInstance->Location = ParseParams.Transform.GetTranslation(); WaveInstance->bIsStarted = true; WaveInstance->bAlreadyNotifiedHook = false; WaveInstance->bUseSpatialization = ParseParams.bUseSpatialization; WaveInstance->SpatializationAlgorithm = ParseParams.SpatializationAlgorithm; WaveInstance->WaveData = this; WaveInstance->NotifyBufferFinishedHooks = ParseParams.NotifyBufferFinishedHooks; WaveInstance->LoopingMode = ((bLooping || ParseParams.bLooping) ? LOOP_Forever : LOOP_Never); if (AudioDevice->IsHRTFEnabledForAll() && ParseParams.SpatializationAlgorithm == SPATIALIZATION_Default) { WaveInstance->SpatializationAlgorithm = SPATIALIZATION_HRTF; } else { WaveInstance->SpatializationAlgorithm = ParseParams.SpatializationAlgorithm; } // Don't add wave instances that are not going to be played at this point. if( WaveInstance->PlayPriority > KINDA_SMALL_NUMBER ) { WaveInstances.Add( WaveInstance ); } // We're still alive. ActiveSound.bFinished = false; // Sanity check if( NumChannels > 2 && WaveInstance->bUseSpatialization && !WaveInstance->bReportedSpatializationWarning) { static TSet<USoundWave*> ReportedSounds; if (!ReportedSounds.Contains(this)) { FString SoundWarningInfo = FString::Printf(TEXT("Spatialisation on stereo and multichannel sounds is not supported. SoundWave: %s"), *GetName()); if (ActiveSound.Sound != this) { SoundWarningInfo += FString::Printf(TEXT(" SoundCue: %s"), *ActiveSound.Sound->GetName()); } if (ActiveSound.AudioComponent.IsValid()) { // TODO - Audio Threading. This log would have to be a task back to game thread AActor* SoundOwner = ActiveSound.AudioComponent->GetOwner(); UE_LOG(LogAudio, Warning, TEXT( "%s Actor: %s AudioComponent: %s" ), *SoundWarningInfo, (SoundOwner ? *SoundOwner->GetName() : TEXT("None")), *ActiveSound.AudioComponent->GetName() ); } else { UE_LOG(LogAudio, Warning, TEXT("%s"), *SoundWarningInfo ); } ReportedSounds.Add(this); } WaveInstance->bReportedSpatializationWarning = true; } } }
void USimpleConstructionScript::PostLoad() { Super::PostLoad(); #if WITH_EDITOR // Get the Blueprint that owns the SCS UBlueprint* Blueprint = GetBlueprint(); if (!Blueprint) { // sometimes the PostLoad can be called, after the object was trashed, we dont want this UE_LOG(LogBlueprint, Warning, TEXT("USimpleConstructionScript::PostLoad() '%s' cannot find its owner blueprint"), *GetPathName()); return; } for (USCS_Node* Node : GetAllNodes()) { // Fix up any uninitialized category names if(Node->CategoryName.IsEmpty()) { Node->CategoryName = NSLOCTEXT("SCS", "Default", "Default"); } // Fix up components that may have switched from scene to non-scene type and vice-versa if(Node->ComponentTemplate != nullptr) { // Fix up any component template objects whose name doesn't match the current variable name; this ensures that there is always one unique template per node. FString VariableName = Node->GetVariableName().ToString(); FString ComponentTemplateName = Node->ComponentTemplate->GetName(); if(ComponentTemplateName.EndsWith(UActorComponent::ComponentTemplateNameSuffix) && !ComponentTemplateName.StartsWith(VariableName) && !GIsDuplicatingClassForReinstancing) { Node->ComponentTemplate->ConditionalPostLoad(); Node->ComponentTemplate = static_cast<UActorComponent*>(StaticDuplicateObject(Node->ComponentTemplate, Node->ComponentTemplate->GetOuter(), *(VariableName + UActorComponent::ComponentTemplateNameSuffix))); } // Check to see if switched from scene to a non-scene component type if (!Node->ComponentTemplate->IsA<USceneComponent>()) { // Otherwise, check to see if switched from scene to non-scene component type int32 RootNodeIndex = INDEX_NONE; if(!RootNodes.Find(Node, RootNodeIndex)) { // Move the node into the root set if it's currently in the scene hierarchy USCS_Node* ParentNode = FindParentNode(Node); if(ParentNode != nullptr) { ParentNode->RemoveChildNode(Node); } RootNodes.Add(Node); } else { // Otherwise, if it's a root node, promote one of its children (if any) to take its place int32 PromoteIndex = FindPromotableChildNodeIndex(Node); if(PromoteIndex != INDEX_NONE) { // Remove it as a child node USCS_Node* ChildToPromote = Node->GetChildNodes()[PromoteIndex]; Node->RemoveChildNodeAt(PromoteIndex, false); // Insert it as a root node just before its prior parent node; this way if it switches back to a scene type it won't supplant the new root we've just created RootNodes.Insert(ChildToPromote, RootNodeIndex); // Append previous root node's children to the new root ChildToPromote->MoveChildNodes(Node); // Copy any previous external attachment info from the previous root node ChildToPromote->bIsParentComponentNative = Node->bIsParentComponentNative; ChildToPromote->ParentComponentOrVariableName = Node->ParentComponentOrVariableName; ChildToPromote->ParentComponentOwnerClassName = Node->ParentComponentOwnerClassName; } // Clear info for any previous external attachment if set if(Node->ParentComponentOrVariableName != NAME_None) { Node->bIsParentComponentNative = false; Node->ParentComponentOrVariableName = NAME_None; Node->ParentComponentOwnerClassName = NAME_None; } } } } } #endif // WITH_EDITOR // Fix up native/inherited parent attachments, in case anything has changed FixupRootNodeParentReferences(); // Ensure that we have a valid scene root ValidateSceneRootNodes(); // Reset non-native "root" scene component scale values, prior to the change in which // we began applying custom scale values to root components at construction time. This // way older, existing Blueprint actor instances won't start unexpectedly getting scaled. if(GetLinkerUE4Version() < VER_UE4_BLUEPRINT_USE_SCS_ROOTCOMPONENT_SCALE) { // Get the BlueprintGeneratedClass that owns the SCS UClass* BPGeneratedClass = GetOwnerClass(); if(BPGeneratedClass != nullptr) { // Get the Blueprint class default object AActor* CDO = Cast<AActor>(BPGeneratedClass->GetDefaultObject(false)); if(CDO != NULL) { // Check for a native root component USceneComponent* NativeRootComponent = CDO->GetRootComponent(); if(NativeRootComponent == nullptr) { // If no native root component exists, find the first non-native, non-parented SCS node with a // scene component template. This will be designated as the root component at construction time. for (USCS_Node* Node : RootNodes) { if(Node->ParentComponentOrVariableName == NAME_None) { // Note that we have to check for nullptr here, because it may be an ActorComponent type USceneComponent* SceneComponentTemplate = Cast<USceneComponent>(Node->ComponentTemplate); if(SceneComponentTemplate != nullptr && SceneComponentTemplate->RelativeScale3D != FVector(1.0f, 1.0f, 1.0f)) { UE_LOG(LogBlueprint, Warning, TEXT("%s: Found non-native root component custom scale for %s (%s) saved prior to being usable; reverting to default scale."), *BPGeneratedClass->GetName(), *Node->GetVariableName().ToString(), *SceneComponentTemplate->RelativeScale3D.ToString()); SceneComponentTemplate->RelativeScale3D = FVector(1.0f, 1.0f, 1.0f); } // Done - no need to fix up any other nodes. break; } } } } } } if (GetLinkerUE4Version() < VER_UE4_SCS_STORES_ALLNODES_ARRAY) { // Fill out AllNodes if this is an older object if (RootNodes.Num() > 0) { AllNodes.Reset(); for (USCS_Node* RootNode : RootNodes) { if (RootNode != nullptr) { AllNodes.Append(RootNode->GetAllNodes()); } } } } }
AActor* UWorld::SpawnActor( UClass* Class, FTransform const* Transform, const FActorSpawnParameters& SpawnParameters ) { SCOPE_CYCLE_COUNTER(STAT_SpawnActorTime); check( CurrentLevel ); check(GIsEditor || (CurrentLevel == PersistentLevel)); // Make sure this class is spawnable. if( !Class ) { UE_LOG(LogSpawn, Warning, TEXT("SpawnActor failed because no class was specified") ); return NULL; } if( Class->HasAnyClassFlags(CLASS_Deprecated) ) { UE_LOG(LogSpawn, Warning, TEXT("SpawnActor failed because class %s is deprecated"), *Class->GetName() ); return NULL; } if( Class->HasAnyClassFlags(CLASS_Abstract) ) { UE_LOG(LogSpawn, Warning, TEXT("SpawnActor failed because class %s is abstract"), *Class->GetName() ); return NULL; } else if( !Class->IsChildOf(AActor::StaticClass()) ) { UE_LOG(LogSpawn, Warning, TEXT("SpawnActor failed because %s is not an actor class"), *Class->GetName() ); return NULL; } else if (SpawnParameters.Template != NULL && SpawnParameters.Template->GetClass() != Class) { UE_LOG(LogSpawn, Warning, TEXT("SpawnActor failed because template class (%s) does not match spawn class (%s)"), *SpawnParameters.Template->GetClass()->GetName(), *Class->GetName()); if (!SpawnParameters.bNoFail) { return NULL; } } else if (bIsRunningConstructionScript && !SpawnParameters.bAllowDuringConstructionScript) { UE_LOG(LogSpawn, Warning, TEXT("SpawnActor failed because we are running a ConstructionScript (%s)"), *Class->GetName() ); return NULL; } else if (bIsTearingDown) { UE_LOG(LogSpawn, Warning, TEXT("SpawnActor failed because we are in the process of tearing down the world")); return NULL; } else if (Transform && Transform->ContainsNaN()) { UE_LOG(LogSpawn, Warning, TEXT("SpawnActor failed because the given transform (%s) is invalid"), *Transform->ToString()); return NULL; } ULevel* LevelToSpawnIn = SpawnParameters.OverrideLevel; if (LevelToSpawnIn == NULL) { // Spawn in the same level as the owner if we have one. @warning: this relies on the outer of an actor being the level. LevelToSpawnIn = (SpawnParameters.Owner != NULL) ? CastChecked<ULevel>(SpawnParameters.Owner->GetOuter()) : CurrentLevel; } FName NewActorName = SpawnParameters.Name; AActor* Template = SpawnParameters.Template; // Use class's default actor as a template. if( !Template ) { Template = Class->GetDefaultObject<AActor>(); } else if (NewActorName.IsNone() && !Template->HasAnyFlags(RF_ClassDefaultObject)) { NewActorName = MakeUniqueObjectName(LevelToSpawnIn, Template->GetClass(), *Template->GetFName().GetPlainNameString()); } check(Template!=NULL); // See if we can spawn on ded.server/client only etc (check NeedsLoadForClient & NeedsLoadForServer) if(!CanCreateInCurrentContext(Template)) { UE_LOG(LogSpawn, Warning, TEXT("Unable to spawn class '%s' due to client/server context."), *Class->GetName() ); return NULL; } FVector NewLocation = Transform ? Transform->GetLocation() : (Template->GetRootComponent() ? Template->GetRootComponent()->RelativeLocation : FVector::ZeroVector); FRotator NewRotation = Transform ? Transform->GetRotation().Rotator() : (Template->GetRootComponent() ? Template->GetRootComponent()->RelativeRotation : FRotator::ZeroRotator); FVector NewScale = Transform ? Transform->GetScale3D() : (Template->GetRootComponent() ? Template->GetRootComponent()->RelativeScale3D : FVector(1.f) ); PRAGMA_DISABLE_DEPRECATION_WARNINGS; // handle existing (but deprecated) uses of bNoCollisionFail where user set it to true ESpawnActorCollisionHandlingMethod CollisionHandlingOverride = SpawnParameters.SpawnCollisionHandlingOverride; if ((CollisionHandlingOverride == ESpawnActorCollisionHandlingMethod::Undefined) && SpawnParameters.bNoCollisionFail) { CollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; } PRAGMA_ENABLE_DEPRECATION_WARNINGS; // "no fail" take preedence over collision handling settings that include fails if (SpawnParameters.bNoFail) { // maybe upgrade to disallow fail if (CollisionHandlingOverride == ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButDontSpawnIfColliding) { CollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn; } else if (CollisionHandlingOverride == ESpawnActorCollisionHandlingMethod::DontSpawnIfColliding) { CollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; } } // use override if set, else fall back to actor's preference ESpawnActorCollisionHandlingMethod const CollisionHandlingMethod = (CollisionHandlingOverride == ESpawnActorCollisionHandlingMethod::Undefined) ? Template->SpawnCollisionHandlingMethod : CollisionHandlingOverride; // see if we can avoid spawning altogether by checking native components // note: we can't handle all cases here, since we don't know the full component hierarchy until after the actor is spawned if (CollisionHandlingMethod == ESpawnActorCollisionHandlingMethod::DontSpawnIfColliding) { if (EncroachingBlockingGeometry(Template, NewLocation, NewRotation)) { // a native component is colliding, that's enough to reject spawning UE_LOG(LogSpawn, Warning, TEXT("SpawnActor failed because of collision at the spawn location [%s] for [%s]"), *NewLocation.ToString(), *Class->GetName()); return nullptr; } } // actually make the actor object AActor* const Actor = NewObject<AActor>(LevelToSpawnIn, Class, NewActorName, SpawnParameters.ObjectFlags, Template); check(Actor); #if WITH_EDITOR Actor->ClearActorLabel(); // Clear label on newly spawned actors #endif // WITH_EDITOR if ( GUndo ) { ModifyLevel( LevelToSpawnIn ); } LevelToSpawnIn->Actors.Add( Actor ); // Add this newly spawned actor to the network actor list AddNetworkActor( Actor ); #if PERF_SHOW_MULTI_PAWN_SPAWN_FRAMES if( Cast<APawn>(Actor) ) { FString PawnName = FString::Printf(TEXT("%d: %s"), ThisFramePawnSpawns.Num(), *Actor->GetPathName()); ThisFramePawnSpawns.Add(PawnName); } #endif // tell the actor what method to use, in case it was overridden Actor->SpawnCollisionHandlingMethod = CollisionHandlingMethod; Actor->PostSpawnInitialize(FTransform(NewRotation, NewLocation, NewScale), SpawnParameters.Owner, SpawnParameters.Instigator, SpawnParameters.bRemoteOwned, SpawnParameters.bNoFail, SpawnParameters.bDeferConstruction); if (Actor->IsPendingKill() && !SpawnParameters.bNoFail) { UE_LOG(LogSpawn, Warning, TEXT("SpawnActor failed because the spawned actor IsPendingKill")); return NULL; } // // // actor should have all of its components now, do any collision checking and handling that we need to do // switch (CollisionHandlingMethod) // { // case ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn: // // Try to find a spawn position // { // FVector AdjustedLocation = NewLocation; // FRotator AdjustedRotation = NewRotation; // if (FindTeleportSpot(Actor, AdjustedLocation, AdjustedRotation)) // { // Actor->SetActorLocationAndRotation(AdjustedLocation, AdjustedRotation); // } // } // break; // case ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButDontSpawnIfColliding: // // Try to find a spawn position // { // FVector AdjustedLocation = NewLocation; // FRotator AdjustedRotation = NewRotation; // if (FindTeleportSpot(Actor, AdjustedLocation, AdjustedRotation)) // { // Actor->SetActorLocationAndRotation(AdjustedLocation, AdjustedRotation); // } // else // { // UE_LOG(LogSpawn, Warning, TEXT("SpawnActor failed because of collision at the spawn location [%s] for [%s]"), *NewLocation.ToString(), *Class->GetName()); // DestroyActor(Actor); // return nullptr; // } // } // break; // case ESpawnActorCollisionHandlingMethod::DontSpawnIfColliding: // // #todo: don't recheck components checked above? // if (EncroachingBlockingGeometry(Actor, NewLocation, NewRotation)) // { // UE_LOG(LogSpawn, Warning, TEXT("SpawnActor failed because of collision at the spawn location [%s] for [%s]"), *NewLocation.ToString(), *Class->GetName()); // DestroyActor(Actor); // return nullptr; // } // break; // // note we use "always spawn" as default, so treat undefined as that // case ESpawnActorCollisionHandlingMethod::Undefined: // case ESpawnActorCollisionHandlingMethod::AlwaysSpawn: // default: // // nothing to do, just proceed as normal // break; // } Actor->CheckDefaultSubobjects(); // Broadcast notification of spawn OnActorSpawned.Broadcast(Actor); #if WITH_EDITOR if (GIsEditor) { GEngine->BroadcastLevelActorAdded(Actor); } #endif return Actor; }
void USimpleConstructionScript::FixupRootNodeParentReferences() { // Get the BlueprintGeneratedClass that owns the SCS UClass* BPGeneratedClass = GetOwnerClass(); if(BPGeneratedClass == NULL) { UE_LOG(LogBlueprint, Warning, TEXT("USimpleConstructionScript::FixupRootNodeParentReferences() - owner class is NULL; skipping.")); // cannot do the rest of fixup without a BPGC return; } for (int32 NodeIndex=0; NodeIndex < RootNodes.Num(); ++NodeIndex) { // If this root node is parented to a native/inherited component template USCS_Node* RootNode = RootNodes[NodeIndex]; if(RootNode->ParentComponentOrVariableName != NAME_None) { bool bWasFound = false; // If the node is parented to a native component if(RootNode->bIsParentComponentNative) { // Get the Blueprint class default object AActor* CDO = Cast<AActor>(BPGeneratedClass->GetDefaultObject(false)); if(CDO != NULL) { // Look for the parent component in the CDO's components array TInlineComponentArray<UActorComponent*> Components; CDO->GetComponents(Components); for (auto CompIter = Components.CreateConstIterator(); CompIter && !bWasFound; ++CompIter) { UActorComponent* ComponentTemplate = *CompIter; bWasFound = ComponentTemplate->GetFName() == RootNode->ParentComponentOrVariableName; } } else { // SCS and BGClass depends on each other (while their construction). // Class is not ready, so one have to break the dependency circle. continue; } } // Otherwise the node is parented to an inherited SCS node from a parent Blueprint else { // Get the Blueprint hierarchy TArray<const UBlueprintGeneratedClass*> ParentBPClassStack; const bool bErrorFree = UBlueprintGeneratedClass::GetGeneratedClassesHierarchy(BPGeneratedClass, ParentBPClassStack); // Find the parent Blueprint in the hierarchy for(int32 StackIndex = ParentBPClassStack.Num() - 1; StackIndex > 0; --StackIndex) { const UBlueprintGeneratedClass* ParentClass = ParentBPClassStack[StackIndex]; if( ParentClass != NULL && ParentClass->SimpleConstructionScript != NULL && ParentClass->GetFName() == RootNode->ParentComponentOwnerClassName) { // Attempt to locate a match by searching all the nodes that belong to the parent Blueprint's SCS for (USCS_Node* ParentNode : ParentClass->SimpleConstructionScript->GetAllNodes()) { if (ParentNode != nullptr && ParentNode->VariableName == RootNode->ParentComponentOrVariableName) { bWasFound = true; break; } } // We found a match; no need to continue searching the hierarchy break; } } } // Clear parent info if we couldn't find the parent component instance if(!bWasFound) { UE_LOG(LogBlueprint, Warning, TEXT("USimpleConstructionScript::FixupRootNodeParentReferences() - Couldn't find %s parent component '%s' for '%s' in BlueprintGeneratedClass '%s' (it may have been removed)"), RootNode->bIsParentComponentNative ? TEXT("native") : TEXT("inherited"), *RootNode->ParentComponentOrVariableName.ToString(), *RootNode->GetVariableName().ToString(), *BPGeneratedClass->GetName()); RootNode->bIsParentComponentNative = false; RootNode->ParentComponentOrVariableName = NAME_None; RootNode->ParentComponentOwnerClassName = NAME_None; } } } // call this after we do the above ParentComponentOrVariableName fixup, // because this operates differently for root nodes that have their // ParentComponentOrVariableName field cleared // // repairs invalid scene hierarchies (like when this Blueprint has been // reparented and there is no longer an inherited scene root... meaning one // of the scene component nodes here needs to be promoted) FixupSceneNodeHierarchy(); }
/** * Perform some collision sweep tests. Creates a given shape mesh and checks collision normal against a collision shape type. * Data for tests is in the [/Script/UnrealEd.CollisionAutomationTestConfigData] section of BaseEditor.ini * * @param Parameters - Unused for this test * @return TRUE if the test was successful, FALSE otherwise */ bool FComponentSweepMultiTest::RunTest(const FString& Parameters) { CollisionAutomationTests::TestBase = this; // Create map UWorld* World = AutomationEditorCommonUtils::CreateNewMap(); TestNotNull( TEXT("Failed to create world for Physics.Collision.Ray Test. Tests aborted."), World ); static FName TraceIdent = FName(TEXT("TestTrace")); FVector StartPos; FVector EndPos; ECollisionChannel Channel = ECC_WorldStatic; UCollisionAutomationTestConfigData* Data = UCollisionAutomationTestConfigData::StaticClass()->GetDefaultObject<UCollisionAutomationTestConfigData>(); // Get the tests for (int32 iTest = 0; iTest < Data->ComponentSweepMultiTests.Num(); iTest++) { FCollisionTestEntry OneElement = Data->ComponentSweepMultiTests[iTest]; // Create the Actor to check against AStaticMeshActor* TestRayMeshActor = CollisionAutomationTests::CreateShapeMeshActor( *OneElement.RootShapeAsset, OneElement.HitResult.TraceEnd); // Create the collision component AActor* TestRayCollisionActor = CollisionAutomationTests::CreateCollisionShape( World, OneElement.ShapeType, OneElement.HitResult.TraceStart); if ((TestRayMeshActor != nullptr) && (TestRayCollisionActor != nullptr)) { // Set the collision profile and enable collision and physics TestRayMeshActor->GetStaticMeshComponent()->BodyInstance.SetCollisionProfileName(TEXT("BlockAll")); TestRayMeshActor->SetActorEnableCollision(true); TestRayMeshActor->GetStaticMeshComponent()->BodyInstance.bSimulatePhysics = true; UShapeComponent* CollisionComponent = Cast<UShapeComponent>(TestRayCollisionActor->GetRootComponent()); TestRayCollisionActor->SetActorEnableCollision(true); if( CollisionComponent != nullptr ) { CollisionComponent->SetCollisionProfileName(TEXT("BlockAll")); CollisionComponent->SetSimulatePhysics(true); } // Setup positions StartPos = TestRayCollisionActor->GetActorLocation(); EndPos = TestRayMeshActor->GetActorLocation(); // Setup the query FComponentQueryParams ShapeQueryParameters(TraceIdent, nullptr); ShapeQueryParameters.bTraceComplex = true; ShapeQueryParameters.bTraceAsyncScene = true; // Perform test TArray<FHitResult> OutHits; bool WasBlocked = World->ComponentSweepMulti(OutHits, CollisionComponent, StartPos, EndPos, FRotator::ZeroRotator, ShapeQueryParameters); bool BlockedBySpecified = false; if (WasBlocked == true) { for (int32 iHits = 0; iHits < OutHits.Num(); iHits++) { AActor* EachActor = OutHits[iHits].GetActor(); if (EachActor == TestRayMeshActor) { BlockedBySpecified = true; // This generates a snippet you can copy/paste into the ini file for test validation //UE_LOG(CollisionAutomationTestLog, Log, TEXT("%d:HitResult=(%s)"), iTest+1, *(CollisionAutomationTests::HitToString(OutHits[iHits]))); CollisionAutomationTests::CheckVector( OutHits[iHits].ImpactNormal, OneElement.HitResult.ImpactNormal, TEXT("ComponentSweepMulti"), TEXT("ImpactNormal"), iTest ); CollisionAutomationTests::CheckVector( OutHits[iHits].Normal, OneElement.HitResult.Normal, TEXT("ComponentSweepMulti"), TEXT("Normal"), iTest ); CollisionAutomationTests::CheckVector( OutHits[iHits].ImpactPoint, OneElement.HitResult.ImpactPoint, TEXT("ComponentSweepMulti"), TEXT("ImpactPoint"), iTest ); CollisionAutomationTests::CheckFloat( OutHits[iHits].Time, OneElement.HitResult.Time, TEXT("ComponentSweepMulti"), TEXT("Time"), iTest ); } } } TestTrue(FString::Printf(TEXT("Test %d:ComponentSweepMulti from %s to %s failed. Should return blocking hit"), iTest+1, *TestRayMeshActor->GetName(), *TestRayCollisionActor->GetName()), BlockedBySpecified); } // Remove the actors TestRayMeshActor->Destroy(); TestRayCollisionActor->Destroy(); } return true; }
USceneComponent* USimpleConstructionScript::GetSceneRootComponentTemplate(USCS_Node** OutSCSNode) const { UBlueprint* Blueprint = GetBlueprint(); UClass* GeneratedClass = GetOwnerClass(); if(OutSCSNode) { *OutSCSNode = nullptr; } // Get the Blueprint class default object AActor* CDO = nullptr; if(GeneratedClass != nullptr) { CDO = Cast<AActor>(GeneratedClass->GetDefaultObject(false)); } // If the generated class does not yet have a CDO, defer to the parent class if(CDO == nullptr && Blueprint->ParentClass != nullptr) { CDO = Cast<AActor>(Blueprint->ParentClass->GetDefaultObject(false)); } // Check to see if we already have a native root component template USceneComponent* RootComponentTemplate = nullptr; if(CDO != nullptr) { // If the root component property is not set, the first available scene component will be used as the root. This matches what's done in the SCS editor. RootComponentTemplate = CDO->GetRootComponent(); if(!RootComponentTemplate) { TInlineComponentArray<USceneComponent*> SceneComponents; CDO->GetComponents(SceneComponents); if(SceneComponents.Num() > 0) { RootComponentTemplate = SceneComponents[0]; } } } // Don't add the default scene root if we already have a native scene root component if(!RootComponentTemplate) { // Get the Blueprint hierarchy TArray<UBlueprint*> BPStack; if(Blueprint->GeneratedClass != nullptr) { UBlueprint::GetBlueprintHierarchyFromClass(Blueprint->GeneratedClass, BPStack); } else if(Blueprint->ParentClass != nullptr) { UBlueprint::GetBlueprintHierarchyFromClass(Blueprint->ParentClass, BPStack); } // Note: Normally if the Blueprint has a parent, we can assume that the parent already has a scene root component set, // ...but we'll run through the hierarchy just in case there are legacy BPs out there that might not adhere to this assumption. TArray<const USimpleConstructionScript*> SCSStack; SCSStack.Add(this); for(int32 StackIndex = 0; StackIndex < BPStack.Num(); ++StackIndex) { if(BPStack[StackIndex] && BPStack[StackIndex]->SimpleConstructionScript && !SCSStack.Contains(BPStack[StackIndex]->SimpleConstructionScript)) { // UBlueprint::GetBlueprintHierarchyFromClass returns first children then parents. So we need to revert the order. SCSStack.Insert(BPStack[StackIndex]->SimpleConstructionScript, 0); } } for(int32 StackIndex = 0; StackIndex < SCSStack.Num() && !RootComponentTemplate; ++StackIndex) { // Check for any scene component nodes in the root set that are not the default scene root const TArray<USCS_Node*>& SCSRootNodes = SCSStack[StackIndex]->GetRootNodes(); for(int32 RootNodeIndex = 0; RootNodeIndex < SCSRootNodes.Num() && RootComponentTemplate == nullptr; ++RootNodeIndex) { USCS_Node* RootNode = SCSRootNodes[RootNodeIndex]; if(RootNode != nullptr && RootNode != DefaultSceneRootNode && RootNode->ComponentTemplate != nullptr && RootNode->ComponentTemplate->IsA<USceneComponent>()) { if(OutSCSNode) { *OutSCSNode = RootNode; } RootComponentTemplate = Cast<USceneComponent>(RootNode->ComponentTemplate); } } } } return RootComponentTemplate; }
float UAISense_Sight::Update() { static const FName NAME_AILineOfSight = FName(TEXT("AILineOfSight")); SCOPE_CYCLE_COUNTER(STAT_AI_Sense_Sight); const UWorld* World = GEngine->GetWorldFromContextObject(GetPerceptionSystem()->GetOuter()); if (World == NULL) { return SuspendNextUpdate; } int32 TracesCount = 0; static const int32 InitialInvalidItemsSize = 16; TArray<int32> InvalidQueries; TArray<FAISightTarget::FTargetId> InvalidTargets; InvalidQueries.Reserve(InitialInvalidItemsSize); InvalidTargets.Reserve(InitialInvalidItemsSize); AIPerception::FListenerMap& ListenersMap = *GetListeners(); FAISightQuery* SightQuery = SightQueryQueue.GetData(); for (int32 QueryIndex = 0; QueryIndex < SightQueryQueue.Num(); ++QueryIndex, ++SightQuery) { if (TracesCount < MaxTracesPerTick) { FPerceptionListener& Listener = ListenersMap[SightQuery->ObserverId]; ensure(Listener.Listener.IsValid()); FAISightTarget& Target = ObservedTargets[SightQuery->TargetId]; const bool bTargetValid = Target.Target.IsValid(); const bool bListenerValid = Listener.Listener.IsValid(); // @todo figure out what should we do if not valid if (bTargetValid && bListenerValid) { AActor* TargetActor = Target.Target.Get(); const FVector TargetLocation = TargetActor->GetActorLocation(); const FDigestedSightProperties& PropDigest = DigestedProperties[SightQuery->ObserverId]; const float SightRadiusSq = SightQuery->bLastResult ? PropDigest.LoseSightRadiusSq : PropDigest.SightRadiusSq; if (CheckIsTargetInSightPie(Listener, PropDigest, TargetLocation, SightRadiusSq)) { // UE_VLOG_SEGMENT(Listener.Listener.Get()->GetOwner(), Listener.CachedLocation, TargetLocation, FColor::Green, TEXT("%s"), *(Target.TargetId.ToString())); FVector OutSeenLocation(0.f); // do line checks if (Target.SightTargetInterface != NULL) { int32 NumberOfLoSChecksPerformed = 0; if (Target.SightTargetInterface->CanBeSeenFrom(Listener.CachedLocation, OutSeenLocation, NumberOfLoSChecksPerformed, Listener.Listener->GetBodyActor()) == true) { Listener.RegisterStimulus(TargetActor, FAIStimulus(*this, 1.f, OutSeenLocation, Listener.CachedLocation)); SightQuery->bLastResult = true; } else { // UE_VLOG_LOCATION(Listener.Listener.Get()->GetOwner(), TargetLocation, 25.f, FColor::Red, TEXT("")); Listener.RegisterStimulus(TargetActor, FAIStimulus(*this, 0.f, TargetLocation, Listener.CachedLocation, FAIStimulus::SensingFailed)); SightQuery->bLastResult = false; } TracesCount += NumberOfLoSChecksPerformed; } else { // we need to do tests ourselves /*const bool bHit = World->LineTraceTest(Listener.CachedLocation, TargetLocation , FCollisionQueryParams(NAME_AILineOfSight, true, Listener.Listener->GetBodyActor()) , FCollisionObjectQueryParams(ECC_WorldStatic));*/ FHitResult HitResult; const bool bHit = World->LineTraceSingle(HitResult, Listener.CachedLocation, TargetLocation , FCollisionQueryParams(NAME_AILineOfSight, true, Listener.Listener->GetBodyActor()) , FCollisionObjectQueryParams(ECC_WorldStatic)); ++TracesCount; if (bHit == false || (HitResult.Actor.IsValid() && HitResult.Actor->IsOwnedBy(TargetActor))) { Listener.RegisterStimulus(TargetActor, FAIStimulus(*this, 1.f, TargetLocation, Listener.CachedLocation)); SightQuery->bLastResult = true; } else { // UE_VLOG_LOCATION(Listener.Listener.Get()->GetOwner(), TargetLocation, 25.f, FColor::Red, TEXT("")); Listener.RegisterStimulus(TargetActor, FAIStimulus(*this, 0.f, TargetLocation, Listener.CachedLocation, FAIStimulus::SensingFailed)); SightQuery->bLastResult = false; } } } else { // UE_VLOG_SEGMENT(Listener.Listener.Get()->GetOwner(), Listener.CachedLocation, TargetLocation, FColor::Red, TEXT("%s"), *(Target.TargetId.ToString())); Listener.RegisterStimulus(TargetActor, FAIStimulus(*this, 0.f, TargetLocation, Listener.CachedLocation, FAIStimulus::SensingFailed)); SightQuery->bLastResult = false; } SightQuery->Importance = CalcQueryImportance(Listener, TargetLocation, SightRadiusSq); // restart query SightQuery->Age = 0.f; } else { // put this index to "to be removed" array InvalidQueries.Add(QueryIndex); if (bTargetValid == false) { InvalidTargets.AddUnique(SightQuery->TargetId); } } } else { // age unprocessed queries so that they can advance in the queue during next sort SightQuery->Age += 1.f; } SightQuery->RecalcScore(); } if (InvalidQueries.Num() > 0) { for (int32 Index = InvalidQueries.Num() - 1; Index >= 0; --Index) { // removing with swapping here, since queue is going to be sorted anyway SightQueryQueue.RemoveAtSwap(InvalidQueries[Index], 1, /*bAllowShrinking*/false); } if (InvalidTargets.Num() > 0) { for (const auto& TargetId : InvalidTargets) { // remove affected queries RemoveAllQueriesToTarget(TargetId, DontSort); // remove target itself ObservedTargets.Remove(TargetId); } // remove holes ObservedTargets.Compact(); } } // sort Sight Queries SortQueries(); //return SightQueryQueue.Num() > 0 ? 1.f/6 : FLT_MAX; return 0.f; }
DEFINE_ACTION_FUNCTION(AActor, A_LichAttack) { int i; AActor *fire; AActor *baseFire; AActor *mo; AActor *target; int randAttack; static const int atkResolve1[] = { 50, 150 }; static const int atkResolve2[] = { 150, 200 }; int dist; // Ice ball (close 20% : far 60%) // Fire column (close 40% : far 20%) // Whirlwind (close 40% : far 20%) // Distance threshold = 8 cells target = self->target; if (target == NULL) { return; } A_FaceTarget (self); if (self->CheckMeleeRange ()) { int damage = pr_atk.HitDice (6); P_DamageMobj (target, self, self, damage, NAME_Melee); P_TraceBleed (damage, target, self); return; } dist = P_AproxDistance (self->x-target->x, self->y-target->y) > 8*64*FRACUNIT; randAttack = pr_atk (); if (randAttack < atkResolve1[dist]) { // Ice ball P_SpawnMissile (self, target, PClass::FindClass("HeadFX1")); S_Sound (self, CHAN_BODY, "ironlich/attack2", 1, ATTN_NORM); } else if (randAttack < atkResolve2[dist]) { // Fire column baseFire = P_SpawnMissile (self, target, PClass::FindClass("HeadFX3")); if (baseFire != NULL) { baseFire->SetState (baseFire->FindState("NoGrow")); for (i = 0; i < 5; i++) { fire = Spawn("HeadFX3", baseFire->x, baseFire->y, baseFire->z, ALLOW_REPLACE); if (i == 0) { S_Sound (self, CHAN_BODY, "ironlich/attack1", 1, ATTN_NORM); } fire->target = baseFire->target; fire->angle = baseFire->angle; fire->velx = baseFire->velx; fire->vely = baseFire->vely; fire->velz = baseFire->velz; fire->Damage = 0; fire->health = (i+1) * 2; P_CheckMissileSpawn (fire); } } } else { // Whirlwind mo = P_SpawnMissile (self, target, RUNTIME_CLASS(AWhirlwind)); if (mo != NULL) { mo->z -= 32*FRACUNIT; mo->tracer = target; mo->special1 = 60; mo->special2 = 50; // Timer for active sound mo->health = 20*TICRATE; // Duration S_Sound (self, CHAN_BODY, "ironlich/attack3", 1, ATTN_NORM); } } }
// The second half of random spawning. Now that the spawner is initialized, the // real actor can be created. If the following code were in BeginPlay instead, // missiles would not have yet obtained certain information that is absolutely // necessary to them -- such as their source and destination. void PostBeginPlay() { AActor * newmobj = NULL; bool boss = false; Super::PostBeginPlay(); if (Species == NAME_None) { Destroy(); return; } const PClass * cls = PClass::FindClass(Species); if (this->flags & MF_MISSILE && target && target->target) // Attempting to spawn a missile. { if ((tracer == NULL) && (flags2 & MF2_SEEKERMISSILE)) tracer = target->target; newmobj = P_SpawnMissileXYZ(Pos(), target, target->target, cls, false); } else newmobj = Spawn(cls, Pos(), NO_REPLACE); if (newmobj != NULL) { // copy everything relevant newmobj->SpawnAngle = newmobj->angle = angle; newmobj->SpawnPoint[2] = SpawnPoint[2]; newmobj->special = special; newmobj->args[0] = args[0]; newmobj->args[1] = args[1]; newmobj->args[2] = args[2]; newmobj->args[3] = args[3]; newmobj->args[4] = args[4]; newmobj->special1 = special1; newmobj->special2 = special2; newmobj->SpawnFlags = SpawnFlags & ~MTF_SECRET; // MTF_SECRET needs special treatment to avoid incrementing the secret counter twice. It had already been processed for the spawner itself. newmobj->HandleSpawnFlags(); newmobj->SpawnFlags = SpawnFlags; newmobj->tid = tid; newmobj->AddToHash(); newmobj->velx = velx; newmobj->vely = vely; newmobj->velz = velz; newmobj->master = master; // For things such as DamageMaster/DamageChildren, transfer mastery. newmobj->target = target; newmobj->tracer = tracer; newmobj->CopyFriendliness(this, false); // This handles things such as projectiles with the MF4_SPECTRAL flag that have // a health set to -2 after spawning, for internal reasons. if (health != SpawnHealth()) newmobj->health = health; if (!(flags & MF_DROPPED)) newmobj->flags &= ~MF_DROPPED; // Handle special altitude flags if (newmobj->flags & MF_SPAWNCEILING) { newmobj->SetZ(newmobj->ceilingz - newmobj->height - SpawnPoint[2]); } else if (newmobj->flags2 & MF2_SPAWNFLOAT) { fixed_t space = newmobj->ceilingz - newmobj->height - newmobj->floorz; if (space > 48*FRACUNIT) { space -= 40*FRACUNIT; newmobj->SetZ(MulScale8 (space, pr_randomspawn()) + newmobj->floorz + 40*FRACUNIT); } newmobj->AddZ(SpawnPoint[2]); } if (newmobj->flags & MF_MISSILE) P_CheckMissileSpawn(newmobj, 0); // Bouncecount is used to count how many recursions we're in. if (newmobj->IsKindOf(PClass::FindClass("RandomSpawner"))) newmobj->bouncecount = ++bouncecount; // If the spawned actor has either of those flags, it's a boss. if ((newmobj->flags4 & MF4_BOSSDEATH) || (newmobj->flags2 & MF2_BOSS)) boss = true; // If a replaced actor has either of those same flags, it's also a boss. AActor * rep = GetDefaultByType(GetClass()->ActorInfo->GetReplacee()->Class); if (rep && ((rep->flags4 & MF4_BOSSDEATH) || (rep->flags2 & MF2_BOSS))) boss = true; } if (boss) this->tracer = newmobj; else // "else" because a boss-replacing spawner must wait until it can call A_BossDeath. Destroy(); }
void AActor::RerunConstructionScripts() { checkf(!HasAnyFlags(RF_ClassDefaultObject), TEXT("RerunConstructionScripts should never be called on a CDO as it can mutate the transient data on the CDO which then propagates to instances!")); 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) { USceneComponent* AttachParent = ActorTransactionAnnotation->RootComponentData.AttachedParentInfo.AttachParent.Get(); ParentComponent = (AttachParent ? AttachParent : FindObjectFast<USceneComponent>(Parent, ActorTransactionAnnotation->RootComponentData.AttachedParentInfo.AttachParentName)); SocketName = ActorTransactionAnnotation->RootComponentData.AttachedParentInfo.SocketName; DetachRootComponentFromParent(); } 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->IsCreatedByConstructionScript()) { // 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->IsCreatedByConstructionScript()) { 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 } #if WITH_EDITOR // Save the current construction script-created components by name TMap<const FName, UObject*> DestroyedComponentsByName; TInlineComponentArray<UActorComponent*> PreviouslyAttachedComponents; GetComponents(PreviouslyAttachedComponents); for (auto Component : PreviouslyAttachedComponents) { if (Component) { if (Component->IsCreatedByConstructionScript()) { DestroyedComponentsByName.Add(Component->GetFName(), Component); } else { UActorComponent* OuterComponent = Component->GetTypedOuter<UActorComponent>(); while (OuterComponent) { if (OuterComponent->IsCreatedByConstructionScript()) { DestroyedComponentsByName.Add(Component->GetFName(), Component); break; } OuterComponent = OuterComponent->GetTypedOuter<UActorComponent>(); } } } } #endif // 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 // Create the mapping of old->new components and notify the editor of the replacements TMap<UObject*, UObject*> OldToNewComponentMapping; TInlineComponentArray<UActorComponent*> NewComponents; GetComponents(NewComponents); for (auto NewComp : NewComponents) { const FName NewCompName = NewComp->GetFName(); if (DestroyedComponentsByName.Contains(NewCompName)) { OldToNewComponentMapping.Add(DestroyedComponentsByName[NewCompName], NewComp); } } if (GEditor && (OldToNewComponentMapping.Num() > 0)) { GEditor->NotifyToolsOfObjectReplacement(OldToNewComponentMapping); } if (ActorTransactionAnnotation) { CurrentTransactionAnnotation = NULL; } else #endif { delete InstanceDataCache; } } }
void UUnrealEdEngine::SetPivot( FVector NewPivot, bool bSnapPivotToGrid, bool bIgnoreAxis, bool bAssignPivot/*=false*/ ) { FEditorModeTools& EditorModeTools = GLevelEditorModeTools(); if( !bIgnoreAxis ) { // Don't stomp on orthonormal axis. if( NewPivot.X==0 ) NewPivot.X=EditorModeTools.PivotLocation.X; if( NewPivot.Y==0 ) NewPivot.Y=EditorModeTools.PivotLocation.Y; if( NewPivot.Z==0 ) NewPivot.Z=EditorModeTools.PivotLocation.Z; } // Set the pivot. //EditorModeTools.CachedLocation = NewPivot; // Don't set the cached location, this is our pre-move point EditorModeTools.PivotLocation = NewPivot; EditorModeTools.SnappedLocation = NewPivot; EditorModeTools.GridBase = FVector::ZeroVector; if( bSnapPivotToGrid ) { FRotator DummyRotator(0,0,0); FSnappingUtils::SnapToBSPVertex( EditorModeTools.SnappedLocation, EditorModeTools.GridBase, DummyRotator ); EditorModeTools.PivotLocation = EditorModeTools.SnappedLocation; } // Check all actors. int32 Count=0, SnapCount=0; //default to using the x axis for the translate rotate widget EditorModeTools.TranslateRotateXAxisAngle = 0.0f; EditorModeTools.TranslateRotate2DAngle = 0.0f; FVector TranslateRotateWidgetWorldXAxis; FVector Widget2DWorldXAxis; AActor* LastSelectedActor = NULL; for ( FSelectionIterator It( GetSelectedActorIterator() ) ; It ; ++It ) { AActor* Actor = static_cast<AActor*>( *It ); checkSlow( Actor->IsA(AActor::StaticClass()) ); if (Count==0) { TranslateRotateWidgetWorldXAxis = Actor->ActorToWorld().TransformVector(FVector(1.0f, 0.0f, 0.0f)); //get the xy plane project of this vector TranslateRotateWidgetWorldXAxis.Z = 0.0f; if (!TranslateRotateWidgetWorldXAxis.Normalize()) { TranslateRotateWidgetWorldXAxis = FVector(1.0f, 0.0f, 0.0f); } Widget2DWorldXAxis = Actor->ActorToWorld().TransformVector(FVector(1, 0, 0)); Widget2DWorldXAxis.Y = 0; if (!Widget2DWorldXAxis.Normalize()) { Widget2DWorldXAxis = FVector(1, 0, 0); } } LastSelectedActor = Actor; ++Count; ++SnapCount; } if( bAssignPivot && LastSelectedActor && GEditor->bGroupingActive ) { // set group pivot for the root-most group AGroupActor* ActorGroupRoot = AGroupActor::GetRootForActor(LastSelectedActor, true, true); if(ActorGroupRoot) { ActorGroupRoot->SetActorLocation( EditorModeTools.PivotLocation, false ); } } //if there are multiple actors selected, just use the x-axis for the "translate/rotate" or 2D widgets if (Count == 1) { EditorModeTools.TranslateRotateXAxisAngle = TranslateRotateWidgetWorldXAxis.Rotation().Yaw; EditorModeTools.TranslateRotate2DAngle = FMath::RadiansToDegrees(FMath::Atan2(Widget2DWorldXAxis.Z, Widget2DWorldXAxis.X)); } // Update showing. EditorModeTools.PivotShown = SnapCount>0 || Count>1; }
EBTNodeResult::Type UBTTask_MoveDirectlyToward::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) { const UBlackboardComponent* MyBlackboard = OwnerComp.GetBlackboardComponent(); FBTMoveDirectlyTowardMemory* MyMemory = reinterpret_cast<FBTMoveDirectlyTowardMemory*>(NodeMemory); AAIController* MyController = OwnerComp.GetAIOwner(); EBTNodeResult::Type NodeResult = EBTNodeResult::Failed; if (MyController && MyBlackboard) { if (GET_AI_CONFIG_VAR(bEnableBTAITasks)) { UAITask_MoveTo* AIMoveTask = NewBTAITask<UAITask_MoveTo>(OwnerComp); if (AIMoveTask != nullptr) { bool bSetUp = false; if (BlackboardKey.SelectedKeyType == UBlackboardKeyType_Object::StaticClass()) { UObject* KeyValue = MyBlackboard->GetValue<UBlackboardKeyType_Object>(BlackboardKey.GetSelectedKeyID()); AActor* TargetActor = Cast<AActor>(KeyValue); if (TargetActor) { AIMoveTask->SetUp(MyController, FVector::ZeroVector, TargetActor, AcceptableRadius, /*bUsePathfinding=*/false, FAISystem::BoolToAIOption(bStopOnOverlap)); NodeResult = EBTNodeResult::InProgress; } else { UE_VLOG(MyController, LogBehaviorTree, Warning, TEXT("UBTTask_MoveDirectlyToward::ExecuteTask tried to go to actor while BB %s entry was empty"), *BlackboardKey.SelectedKeyName.ToString()); } } else if (BlackboardKey.SelectedKeyType == UBlackboardKeyType_Vector::StaticClass()) { const FVector TargetLocation = MyBlackboard->GetValue<UBlackboardKeyType_Vector>(BlackboardKey.GetSelectedKeyID()); AIMoveTask->SetUp(MyController, TargetLocation, nullptr, AcceptableRadius, /*bUsePathfinding=*/false, FAISystem::BoolToAIOption(bStopOnOverlap)); NodeResult = EBTNodeResult::InProgress; } if (NodeResult == EBTNodeResult::InProgress) { AIMoveTask->ReadyForActivation(); } } } else { EPathFollowingRequestResult::Type RequestResult = EPathFollowingRequestResult::Failed; if (BlackboardKey.SelectedKeyType == UBlackboardKeyType_Object::StaticClass()) { UObject* KeyValue = MyBlackboard->GetValue<UBlackboardKeyType_Object>(BlackboardKey.GetSelectedKeyID()); AActor* TargetActor = Cast<AActor>(KeyValue); if (TargetActor) { RequestResult = bDisablePathUpdateOnGoalLocationChange ? MyController->MoveToLocation(TargetActor->GetActorLocation(), AcceptableRadius, bStopOnOverlap, /*bUsePathfinding=*/false, /*bProjectDestinationToNavigation=*/bProjectVectorGoalToNavigation, bAllowStrafe) : MyController->MoveToActor(TargetActor, AcceptableRadius, bStopOnOverlap, /*bUsePathfinding=*/false, bAllowStrafe); } } else if (BlackboardKey.SelectedKeyType == UBlackboardKeyType_Vector::StaticClass()) { const FVector TargetLocation = MyBlackboard->GetValue<UBlackboardKeyType_Vector>(BlackboardKey.GetSelectedKeyID()); RequestResult = MyController->MoveToLocation(TargetLocation, AcceptableRadius, bStopOnOverlap, /*bUsePathfinding=*/false, /*bProjectDestinationToNavigation=*/bProjectVectorGoalToNavigation, bAllowStrafe); } if (RequestResult == EPathFollowingRequestResult::RequestSuccessful) { const FAIRequestID RequestID = MyController->GetCurrentMoveRequestID(); MyMemory->MoveRequestID = RequestID; WaitForMessage(OwnerComp, UBrainComponent::AIMessage_MoveFinished, RequestID); NodeResult = EBTNodeResult::InProgress; } else if (RequestResult == EPathFollowingRequestResult::AlreadyAtGoal) { NodeResult = EBTNodeResult::Succeeded; } } } return NodeResult; }
void UUnrealEdEngine::NoteActorMovement() { if( !GUndo && !(GEditor->ClickFlags & CF_MOVE_ACTOR) ) { GEditor->ClickFlags |= CF_MOVE_ACTOR; const FScopedTransaction Transaction( NSLOCTEXT("UnrealEd", "ActorMovement", "Actor Movement") ); GLevelEditorModeTools().Snapping=0; AActor* SelectedActor = NULL; for ( FSelectionIterator It( GetSelectedActorIterator() ) ; It ; ++It ) { AActor* Actor = static_cast<AActor*>( *It ); checkSlow( Actor->IsA(AActor::StaticClass()) ); SelectedActor = Actor; break; } if( SelectedActor == NULL ) { USelection* SelectedActors = GetSelectedActors(); SelectedActors->Modify(); SelectActor( GWorld->GetDefaultBrush(), true, true ); } // Look for an actor that requires snapping. for ( FSelectionIterator It( GetSelectedActorIterator() ) ; It ; ++It ) { AActor* Actor = static_cast<AActor*>( *It ); checkSlow( Actor->IsA(AActor::StaticClass()) ); GLevelEditorModeTools().Snapping = 1; break; } TSet<AGroupActor*> GroupActors; // Modify selected actors. for ( FSelectionIterator It( GetSelectedActorIterator() ) ; It ; ++It ) { AActor* Actor = static_cast<AActor*>( *It ); checkSlow( Actor->IsA(AActor::StaticClass()) ); Actor->Modify(); if (GEditor->bGroupingActive) { // if this actor is in a group, add the GroupActor into a list to be modified shortly AGroupActor* ActorLockedRootGroup = AGroupActor::GetRootForActor(Actor, true); if (ActorLockedRootGroup != nullptr) { GroupActors.Add(ActorLockedRootGroup); } } ABrush* Brush = Cast< ABrush >( Actor ); if ( Brush ) { if( Brush->Brush ) { Brush->Brush->Polys->Element.ModifyAllItems(); } } } // Modify unique group actors for (auto* GroupActor : GroupActors) { GroupActor->Modify(); } } }
// // P_SpawnMapThing // The fields of the mapthing should // already be in host byte order. // // [RH] position is used to weed out unwanted start spots // void P_SpawnMapThing (mapthing2_t *mthing, int position) { int i; int bit; AActor *mobj; fixed_t x, y, z; if (mthing->type == 0 || mthing->type == -1) return; // count deathmatch start positions if (mthing->type == 11 || ((mthing->type == 5080 || mthing->type == 5081 || mthing->type == 5082)) && !sv_teamspawns) { if (deathmatch_p == &deathmatchstarts[MaxDeathmatchStarts]) { // [RH] Get more deathmatchstarts int offset = MaxDeathmatchStarts; MaxDeathmatchStarts *= 2; deathmatchstarts = (mapthing2_t *)Realloc (deathmatchstarts, MaxDeathmatchStarts * sizeof(mapthing2_t)); deathmatch_p = &deathmatchstarts[offset]; } memcpy (deathmatch_p, mthing, sizeof(*mthing)); deathmatch_p++; return; } // [Toke - CTF - starts] CTF starts - count Blue team start positions if (mthing->type == 5080 && sv_teamspawns) { if (blueteam_p == &blueteamstarts[MaxBlueTeamStarts]) { int offset = MaxBlueTeamStarts; MaxBlueTeamStarts *= 2; blueteamstarts = (mapthing2_t *)Realloc (blueteamstarts, MaxBlueTeamStarts * sizeof(mapthing2_t)); blueteam_p = &blueteamstarts[offset]; } memcpy (blueteam_p, mthing, sizeof(*mthing)); blueteam_p++; return; } // [Toke - CTF - starts] CTF starts - count Red team start positions if (mthing->type == 5081 && sv_teamspawns) { if (redteam_p == &redteamstarts[MaxRedTeamStarts]) { int offset = MaxRedTeamStarts; MaxRedTeamStarts *= 2; redteamstarts = (mapthing2_t *)Realloc (redteamstarts, MaxRedTeamStarts * sizeof(mapthing2_t)); redteam_p = &redteamstarts[offset]; } memcpy (redteam_p, mthing, sizeof(*mthing)); redteam_p++; return; } // [RH] Record polyobject-related things if (HexenHack) { switch (mthing->type) { case PO_HEX_ANCHOR_TYPE: mthing->type = PO_ANCHOR_TYPE; break; case PO_HEX_SPAWN_TYPE: mthing->type = PO_SPAWN_TYPE; break; case PO_HEX_SPAWNCRUSH_TYPE: mthing->type = PO_SPAWNCRUSH_TYPE; break; } } if (mthing->type == PO_ANCHOR_TYPE || mthing->type == PO_SPAWN_TYPE || mthing->type == PO_SPAWNCRUSH_TYPE) { polyspawns_t *polyspawn = new polyspawns_t; polyspawn->next = polyspawns; polyspawn->x = mthing->x << FRACBITS; polyspawn->y = mthing->y << FRACBITS; polyspawn->angle = mthing->angle; polyspawn->type = mthing->type; polyspawns = polyspawn; if (mthing->type != PO_ANCHOR_TYPE) po_NumPolyobjs++; return; } // check for players specially if ((mthing->type <= 4 && mthing->type > 0) || (mthing->type >= 4001 && mthing->type <= 4001 + MAXPLAYERSTARTS - 4)) { // [RH] Only spawn spots that match position. if (mthing->args[0] != position) return; playerstarts.push_back(*mthing); return; } // [RH] sound sequence overrides if (mthing->type >= 1400 && mthing->type < 1410) { return; } else if (mthing->type == 1411) { int type; if (mthing->args[0] == 255) type = -1; else type = mthing->args[0]; if (type > 63) { Printf (PRINT_HIGH, "Sound sequence %d out of range\n", type); } else { } return; } /*if (deathmatch) { if (!(mthing->flags & MTF_DEATHMATCH)) return; } else if (multiplayer) { if (!(mthing->flags & MTF_COOPERATIVE)) return; } if (!multiplayer) { if (!(mthing->flags & MTF_SINGLE)) return; }*/ // GhostlyDeath -- Correctly spawn things if (sv_gametype != GM_COOP && !(mthing->flags & MTF_DEATHMATCH)) return; if (sv_gametype == GM_COOP && sv_maxplayers == 1 && !(mthing->flags & MTF_SINGLE)) return; if (sv_gametype == GM_COOP && sv_maxplayers != 1 && !(mthing->flags & MTF_COOPERATIVE)) return; // check for apropriate skill level if (sv_skill == sk_baby) bit = 1; else if (sv_skill == sk_nightmare) bit = 4; else bit = 1 << ((int)sv_skill - 2); if (!(mthing->flags & bit)) return; // [RH] Determine if it is an old ambient thing, and if so, // map it to MT_AMBIENT with the proper parameter. if (mthing->type >= 14001 && mthing->type <= 14064) { mthing->args[0] = mthing->type - 14000; mthing->type = 14065; i = MT_AMBIENT; } // [RH] Check if it's a particle fountain else if (mthing->type >= 9027 && mthing->type <= 9033) { mthing->args[0] = mthing->type - 9026; i = MT_FOUNTAIN; } else { // find which type to spawn for (i = 0; i < NUMMOBJTYPES; i++) if (mthing->type == mobjinfo[i].doomednum) break; } if (i >= NUMMOBJTYPES) { // [RH] Don't die if the map tries to spawn an unknown thing Printf (PRINT_HIGH, "Unknown type %i at (%i, %i)\n", mthing->type, mthing->x, mthing->y); i = MT_UNKNOWNTHING; } // [RH] If the thing's corresponding sprite has no frames, also map // it to the unknown thing. else if (sprites[states[mobjinfo[i].spawnstate].sprite].numframes == 0) { Printf (PRINT_HIGH, "Type %i at (%i, %i) has no frames\n", mthing->type, mthing->x, mthing->y); i = MT_UNKNOWNTHING; } // don't spawn keycards and players in deathmatch if (sv_gametype != GM_COOP && mobjinfo[i].flags & MF_NOTDMATCH) return; // don't spawn deathmatch weapons in offline single player mode if (!multiplayer) { switch (i) { case MT_CHAINGUN: case MT_SHOTGUN: case MT_SUPERSHOTGUN: case MT_MISC25: // BFG case MT_MISC26: // chainsaw case MT_MISC27: // rocket launcher case MT_MISC28: // plasma gun if ((mthing->flags & (MTF_DEATHMATCH|MTF_SINGLE)) == MTF_DEATHMATCH) return; break; default: break; } } if (sv_nomonsters) if (i == MT_SKULL || (mobjinfo[i].flags & MF_COUNTKILL) ) return; // spawn it x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; if (i == MT_WATERZONE) { sector_t *sec = R_PointInSubsector (x, y)->sector; sec->waterzone = 1; return; } else if (i == MT_SECRETTRIGGER) { level.total_secrets++; } if (mobjinfo[i].flags & MF_SPAWNCEILING) z = ONCEILINGZ; else z = ONFLOORZ; mobj = new AActor (x, y, z, (mobjtype_t)i); if (z == ONFLOORZ) mobj->z += mthing->z << FRACBITS; else if (z == ONCEILINGZ) mobj->z -= mthing->z << FRACBITS; mobj->spawnpoint = *mthing; if (mobj->flags2 & MF2_FLOATBOB) { // Seed random starting index for bobbing motion mobj->health = M_Random(); mobj->special1 = mthing->z << FRACBITS; } // [RH] Set the thing's special mobj->special = mthing->special; memcpy (mobj->args, mthing->args, sizeof(mobj->args)); if (mobj->tics > 0) mobj->tics = 1 + (P_Random () % mobj->tics); if (mobj->flags & MF_COUNTKILL) level.total_monsters++; if (mobj->flags & MF_COUNTITEM) level.total_items++; if (i != MT_SPARK) mobj->angle = ANG45 * (mthing->angle/45); if (mthing->flags & MTF_AMBUSH) mobj->flags |= MF_AMBUSH; // [RH] Add ThingID to mobj and link it in with the others mobj->tid = mthing->thingid; mobj->AddToHash (); SV_SpawnMobj(mobj); if (sv_gametype == GM_CTF) { // [Toke - CTF] Setup flag sockets if (mthing->type == ID_BLUE_FLAG) { flagdata *data = &CTFdata[it_blueflag]; if (data->flaglocated) return; CTF_RememberFlagPos (mthing); CTF_SpawnFlag(it_blueflag); } if (mthing->type == ID_RED_FLAG) { flagdata *data = &CTFdata[it_redflag]; if (data->flaglocated) return; CTF_RememberFlagPos (mthing); CTF_SpawnFlag(it_redflag); } } // [RH] Go dormant as needed if (mthing->flags & MTF_DORMANT) P_DeactivateMobj (mobj); }