/** Prunes any nodes that weren't visited from the graph, printing out a warning */ void FGraphCompilerContext::PruneIsolatedNodes(const TArray<UEdGraphNode*>& RootSet, TArray<UEdGraphNode*>& GraphNodes) { FEdGraphUtilities::FNodeVisitor Visitor; for (TArray<UEdGraphNode*>::TConstIterator It(RootSet); It; ++It) { UEdGraphNode* RootNode = *It; Visitor.TraverseNodes(RootNode); } for (int32 NodeIndex = 0; NodeIndex < GraphNodes.Num(); ++NodeIndex) { UEdGraphNode* Node = GraphNodes[NodeIndex]; if (!Visitor.VisitedNodes.Contains(Node)) { if (!CanIgnoreNode(Node)) { // Disabled this warning, because having orphaned chains is standard workflow for LDs //MessageLog.Warning(TEXT("Node @@ will never be executed and is being pruned"), Node); } if (!ShouldForceKeepNode(Node)) { Node->BreakAllNodeLinks(); GraphNodes.RemoveAtSwap(NodeIndex); --NodeIndex; } } } }
void FMessageRouter::FilterSubscriptions( TArray<IMessageSubscriptionPtr>& Subscriptions, const IMessageContextRef& Context, TArray<IReceiveMessagesPtr>& OutRecipients ) { EMessageScope MessageScope = Context->GetScope(); for (int32 SubscriptionIndex = 0; SubscriptionIndex < Subscriptions.Num(); ++SubscriptionIndex) { const IMessageSubscriptionPtr& Subscription = Subscriptions[SubscriptionIndex]; if (Subscription->IsEnabled() && Subscription->GetScopeRange().Contains(MessageScope)) { IReceiveMessagesPtr Subscriber = Subscription->GetSubscriber().Pin(); if (Subscriber.IsValid()) { if (MessageScope == EMessageScope::Thread) { ENamedThreads::Type RecipientThread = Subscriber->GetRecipientThread(); ENamedThreads::Type SenderThread = Context->GetSenderThread(); if (RecipientThread != SenderThread) { continue; } } OutRecipients.AddUnique(Subscriber); } else { Subscriptions.RemoveAtSwap(SubscriptionIndex); --SubscriptionIndex; } } } }
static void BuildDependencyMapAndCompile(const TArray<UUserDefinedStruct*>& ChangedStructs, FCompilerResultsLog& MessageLog) { struct FDependencyMapEntry { UUserDefinedStruct* Struct; TSet<UUserDefinedStruct*> StructuresToWaitFor; FDependencyMapEntry() : Struct(NULL) {} void Initialize(UUserDefinedStruct* ChangedStruct, const TArray<UUserDefinedStruct*>& AllChangedStructs) { Struct = ChangedStruct; check(Struct); auto Schema = GetDefault<UEdGraphSchema_K2>(); for (auto& VarDesc : FStructureEditorUtils::GetVarDesc(Struct)) { auto StructType = Cast<UUserDefinedStruct>(VarDesc.SubCategoryObject.Get()); if (StructType && (VarDesc.Category == Schema->PC_Struct) && AllChangedStructs.Contains(StructType)) { StructuresToWaitFor.Add(StructType); } } } }; TArray<FDependencyMapEntry> DependencyMap; for (auto Iter = ChangedStructs.CreateConstIterator(); Iter; ++Iter) { DependencyMap.Add(FDependencyMapEntry()); DependencyMap.Last().Initialize(*Iter, ChangedStructs); } while (DependencyMap.Num()) { int32 StructureToCompileIndex = INDEX_NONE; for (int32 EntryIndex = 0; EntryIndex < DependencyMap.Num(); ++EntryIndex) { if(0 == DependencyMap[EntryIndex].StructuresToWaitFor.Num()) { StructureToCompileIndex = EntryIndex; break; } } check(INDEX_NONE != StructureToCompileIndex); UUserDefinedStruct* Struct = DependencyMap[StructureToCompileIndex].Struct; check(Struct); FUserDefinedStructureCompilerInner::CleanAndSanitizeStruct(Struct); FUserDefinedStructureCompilerInner::InnerCompileStruct(Struct, GetDefault<UEdGraphSchema_K2>(), MessageLog); DependencyMap.RemoveAtSwap(StructureToCompileIndex); for (auto EntryIter = DependencyMap.CreateIterator(); EntryIter; ++EntryIter) { (*EntryIter).StructuresToWaitFor.Remove(Struct); } } }
static inline void RemoveIdFromMuteList(TArray< TSharedRef<const FUniqueNetId> >& MuteList, const TSharedPtr<const FUniqueNetId>& UniqueIdToRemove) { FUniqueNetIdMatcher UniqueIdToRemoveMatch(*UniqueIdToRemove); int32 RemoveIndex = MuteList.IndexOfByPredicate(UniqueIdToRemoveMatch); if (RemoveIndex != INDEX_NONE) { MuteList.RemoveAtSwap(RemoveIndex); } }
void FGAActiveEffectContainer::RemoveTargetAggregation(TSharedPtr<FGAActiveDuration> EffectIn) { TArray<FGAEffectHandle>* handles; handles = MyEffects.Find(EffectIn->EffectName); for (auto It = handles->CreateIterator(); It; ++It) { if (*It == EffectIn->MyHandle) { handles->RemoveAtSwap(It.GetIndex()); } } }
void FSessionManager::GetSelectedInstances( TArray<ISessionInstanceInfoPtr>& OutInstances) const { if (SelectedSession.IsValid()) { SelectedSession->GetInstances(OutInstances); for (int32 Index = OutInstances.Num() - 1; Index >= 0 ; --Index) { if (DeselectedInstances.Contains(OutInstances[Index])) { OutInstances.RemoveAtSwap(Index); } } } }
void FAggregator::RemoveModsWithActiveHandle(TArray<FAggregatorMod>& InMods, FActiveGameplayEffectHandle ActiveHandle) { check(ActiveHandle.IsValid()); for(int32 idx=InMods.Num()-1; idx >= 0; --idx) { if (InMods[idx].ActiveHandle == ActiveHandle) { if (InMods[idx].IsPredicted) { NumPredictiveMods--; } InMods.RemoveAtSwap(idx, 1, false); } } }
void DeleteOcclusionQueriesForCurrentContext(EGLContext Context) { if (!ReleasedQueriesGuard) { ReleasedQueriesGuard = new FCriticalSection; } { FScopeLock Lock(ReleasedQueriesGuard); for (int32 Index = 0; Index < ReleasedQueries.Num(); ++Index) { if (ReleasedQueries[Index].Context == Context) { FOpenGL::DeleteQueries(1, &ReleasedQueries[Index].Query); ReleasedQueries.RemoveAtSwap(Index); --Index; } } } }
void PlatformGetNewRenderQuery( GLuint* OutQuery, uint64* OutQueryContext ) { if( !ReleasedQueriesGuard ) { ReleasedQueriesGuard = new FCriticalSection; } { FScopeLock Lock(ReleasedQueriesGuard); #ifdef UE_BUILD_DEBUG check( OutQuery && OutQueryContext ); #endif HGLRC Context = GetCurrentContext(); check( Context ); GLuint NewQuery = 0; // Check for possible query reuse const int32 ArraySize = ReleasedQueries.Num(); for( int32 Index = 0; Index < ArraySize; ++Index ) { if( ReleasedQueries[Index].Context == Context ) { NewQuery = ReleasedQueries[Index].Query; ReleasedQueries.RemoveAtSwap(Index); break; } } if( !NewQuery ) { FOpenGL::GenQueries( 1, &NewQuery ); } *OutQuery = NewQuery; *OutQueryContext = (uint64)Context; } }
// TODO: Refactor this (and some other stuff) into a preprocessing step for use by any compiler? bool FNiagaraCompiler::MergeInFunctionNodes() { struct FReconnectionInfo { public: UEdGraphPin* From; TArray<UEdGraphPin*> To; //Fallback default value if an input connection is not connected. FString FallbackDefault; FReconnectionInfo() : From(NULL) {} }; TMap<FName, FReconnectionInfo> InputConnections; TMap<FName, FReconnectionInfo> OutputConnections; TArray<class UEdGraphPin*> FuncCallInputPins; TArray<class UEdGraphPin*> FuncCallOutputPins; //Copies the function graph into the main graph. //Removes the Function call in the main graph and the input and output nodes in the function graph, reconnecting their pins appropriately. auto MergeFunctionIntoMainGraph = [&](UNiagaraNodeFunctionCall* InFunc, UNiagaraGraph* FuncGraph) { InputConnections.Empty(); OutputConnections.Empty(); FuncCallInputPins.Empty(); FuncCallOutputPins.Empty(); check(InFunc && FuncGraph); if (InFunc->FunctionScript) { //Get all the pins that are connected to the inputs of the function call node in the main graph. InFunc->GetInputPins(FuncCallInputPins); for (UEdGraphPin* FuncCallInputPin : FuncCallInputPins) { FName InputName(*FuncCallInputPin->PinName); FReconnectionInfo& InputConnection = InputConnections.FindOrAdd(InputName); if (FuncCallInputPin->LinkedTo.Num() > 0) { check(FuncCallInputPin->LinkedTo.Num() == 1); UEdGraphPin* LinkFrom = FuncCallInputPin->LinkedTo[0]; check(LinkFrom->Direction == EGPD_Output); InputConnection.From = LinkFrom; } else { //This input has no link so we need the default value from the pin. InputConnection.FallbackDefault = FuncCallInputPin->GetDefaultAsString(); } } //Get all the pins that are connected to the outputs of the function call node in the main graph. InFunc->GetOutputPins(FuncCallOutputPins); for (UEdGraphPin* FuncCallOutputPin : FuncCallOutputPins) { FName OutputName(*FuncCallOutputPin->PinName); for (UEdGraphPin* LinkTo : FuncCallOutputPin->LinkedTo) { check(LinkTo->Direction == EGPD_Input); FReconnectionInfo& OutputConnection = OutputConnections.FindOrAdd(OutputName); OutputConnection.To.Add(LinkTo); } } //Remove the function call node from the graph now that we have everything we need from it. SourceGraph->RemoveNode(InFunc); //Keep a list of the Input and Output nodes we see in the function graph so that we can remove (most of) them later. TArray<UEdGraphNode*, TInlineAllocator<64>> ToRemove; //Search the nodes in the function graph, finding any connections to input or output nodes. for (UEdGraphNode* FuncGraphNode : FuncGraph->Nodes) { if (UNiagaraNodeInput* InputNode = Cast<UNiagaraNodeInput>(FuncGraphNode)) { check(InputNode->Pins.Num() == 1); //Get an array of "To" pins from one or more input nodes referencing each named input. FReconnectionInfo& InputConnection = InputConnections.FindOrAdd(InputNode->Input.Name); if (InputConnection.From) { //We have a connection from the function call so remove the input node and connect to that. ToRemove.Add(InputNode); } else { //This input has no connection from the function call so what do we do here? //For now we just leave the input node and connect back to it. //This will mean unconnected pins from the function call will look for constants or attributes. //In some cases we may want to just take the default value from the function call pin instead? //Maybe have some properties on the function call defining that. InputConnection.From = InputNode->Pins[0]; } TArray<UEdGraphPin*>& LinkToPins = InputNode->Pins[0]->LinkedTo; for (UEdGraphPin* ToPin : LinkToPins) { check(ToPin->Direction == EGPD_Input); InputConnection.To.Add(ToPin); } } else if (UNiagaraNodeOutput* OutputNode = Cast<UNiagaraNodeOutput>(FuncGraphNode)) { //Unlike the input nodes, we don't have the option of keeping these if there is no "From" pin. The default values from the node pins should be used. ToRemove.Add(OutputNode); //For each output, get the "From" pin to be reconnected later. for (int32 OutputIdx = 0; OutputIdx < OutputNode->Outputs.Num(); ++OutputIdx) { FName OutputName = OutputNode->Outputs[OutputIdx].Name; UEdGraphPin* OutputNodePin = OutputNode->Pins[OutputIdx]; check(OutputNodePin->LinkedTo.Num() <= 1); FReconnectionInfo& OutputConnection = OutputConnections.FindOrAdd(OutputName); UEdGraphPin* LinkFromPin = OutputNodePin->LinkedTo.Num() == 1 ? OutputNodePin->LinkedTo[0] : NULL; if (LinkFromPin) { check(LinkFromPin->Direction == EGPD_Output); OutputConnection.From = LinkFromPin; } else { //This output is not connected so links to it in the main graph must use it's default value. OutputConnection.FallbackDefault = OutputNodePin->GetDefaultAsString(); } } } } //Remove all the In and Out nodes from the function graph. for (UEdGraphNode* Remove : ToRemove) { FuncGraph->RemoveNode(Remove); } //Copy the nodes from the function graph over into the main graph. FuncGraph->MoveNodesToAnotherGraph(SourceGraph, false); //Finally, do all the reconnection. auto MakeConnection = [&](FReconnectionInfo& Info) { for (UEdGraphPin* LinkTo : Info.To) { if (Info.From) { Info.From->MakeLinkTo(LinkTo); } else { LinkTo->DefaultValue = Info.FallbackDefault; } } }; for (TPair<FName, FReconnectionInfo>& ReconnectInfo : InputConnections){ MakeConnection(ReconnectInfo.Value); } for (TPair<FName, FReconnectionInfo>& ReconnectInfo : OutputConnections){ MakeConnection(ReconnectInfo.Value); } } }; //Helper struct for traversing nested function calls. struct FFunctionContext { //True if this context's function has been merged into the main graph. bool bProcessed; //The index of this context into the ContextPool. int32 PoolIdx; //Pointer back to the parent context for traversal. FFunctionContext* Parent; //The function call node for this function in the source/parent graph. UNiagaraNodeFunctionCall* Function; //The graph for this function that we are going to merge into the main graph. UNiagaraGraph* FunctionGraph; //The script from which the graph is copied. Used for re entrance check. UNiagaraScript* Script; //Contexts for function calls in this function graph. TArray<FFunctionContext*, TInlineAllocator<64>> SubFunctionCalls; FFunctionContext() : bProcessed(false) , PoolIdx(INDEX_NONE) , Parent(NULL) , Function(NULL) , FunctionGraph(NULL) , Script(NULL) { } /** We don't allow re-entrant functions as this would cause an infinite loop of merging in graphs. Maybe in the future if we allow branching in the VM we can allow this. */ bool CheckForReentrance()const { UNiagaraNodeFunctionCall* Func = Function; FFunctionContext* Curr = Parent; while (Curr) { if (Curr->Script == Script) return true; Curr = Curr->Parent; } return false; } FString GetCallstack()const { FString Ret; const FFunctionContext* Curr = this; while (Curr) { if (Curr->Script) { Ret.Append(*(Curr->Script->GetPathName())); } else { Ret.Append(TEXT("Unknown")); } Ret.Append(TEXT("\n")); Curr = Curr->Parent; } return Ret; } }; //A pool of contexts on the stack to avoid loads of needless, small heap allocations. TArray<FFunctionContext, TInlineAllocator<512>> ContextPool; ContextPool.Reserve(512); FFunctionContext RootContext; FFunctionContext* CurrentContext = &RootContext; CurrentContext->FunctionGraph = SourceGraph; CurrentContext->Script = Script; //Depth first traversal of all function calls. while (CurrentContext) { //Find any sub functions and process this function call. if (!CurrentContext->bProcessed) { CurrentContext->bProcessed = true; //Find any sub functions and check for re-entrance. if (CurrentContext->FunctionGraph) { for (UEdGraphNode* Node : CurrentContext->FunctionGraph->Nodes) { UNiagaraNodeFunctionCall* FuncNode = Cast<UNiagaraNodeFunctionCall>(Node); if (FuncNode) { int32 NewIdx = ContextPool.AddZeroed(); FFunctionContext* SubFuncContext = &ContextPool[NewIdx]; CurrentContext->SubFunctionCalls.Push(SubFuncContext); SubFuncContext->Parent = CurrentContext; SubFuncContext->Function = FuncNode; SubFuncContext->PoolIdx = NewIdx; SubFuncContext->Script = FuncNode->FunctionScript; if (SubFuncContext->CheckForReentrance()) { FString Callstack = SubFuncContext->GetCallstack(); MessageLog.Error(TEXT("Reentrant function call!\n%s"), *Callstack); return false; } //Copy the function graph as we'll be modifying it as we merge in with the main graph. UNiagaraScriptSource* FuncSource = CastChecked<UNiagaraScriptSource>(FuncNode->FunctionScript->Source); check(FuncSource); SubFuncContext->FunctionGraph = CastChecked<UNiagaraGraph>(FEdGraphUtilities::CloneGraph(FuncSource->NodeGraph, NULL, &MessageLog)); } } } //Merge this function into the main graph now. if (CurrentContext->Function && CurrentContext->FunctionGraph) { MergeFunctionIntoMainGraph(CurrentContext->Function, CurrentContext->FunctionGraph); } } if (CurrentContext->SubFunctionCalls.Num() > 0) { //Move to the next sub function. CurrentContext = CurrentContext->SubFunctionCalls.Pop(); } else { //Done processing this function so remove it and move back to the parent. if (CurrentContext->PoolIdx != INDEX_NONE) { CurrentContext->FunctionGraph->MarkPendingKill(); ContextPool.RemoveAtSwap(CurrentContext->PoolIdx); } CurrentContext = CurrentContext->Parent; } } return true; }
bool UBlendSpaceBase::GetSamplesFromBlendInput(const FVector &BlendInput, TArray<FBlendSampleData> & OutSampleDataList) const { TArray<FGridBlendSample, TInlineAllocator<4> >& RawGridSamples = FBlendSpaceScratchData::Get().RawGridSamples; check(!RawGridSamples.Num()); // this must be called non-recursively GetRawSamplesFromBlendInput(BlendInput, RawGridSamples); OutSampleDataList.Reset(); OutSampleDataList.Reserve(RawGridSamples.Num() * FEditorElement::MAX_VERTICES); // consolidate all samples for (int32 SampleNum=0; SampleNum<RawGridSamples.Num(); ++SampleNum) { FGridBlendSample& GridSample = RawGridSamples[SampleNum]; float GridWeight = GridSample.BlendWeight; FEditorElement& GridElement = GridSample.GridElement; for(int32 Ind = 0; Ind < GridElement.MAX_VERTICES; ++Ind) { const int32 SampleDataIndex = GridElement.Indices[Ind]; if(SampleDataIndex != INDEX_NONE) { int32 Index = OutSampleDataList.AddUnique(SampleDataIndex); OutSampleDataList[Index].AddWeight(GridElement.Weights[Ind]*GridWeight); OutSampleDataList[Index].Animation = SampleData[SampleDataIndex].Animation; } } } // go through merge down to first sample for (int32 Index1 = 0; Index1 < OutSampleDataList.Num(); ++Index1) { for (int32 Index2 = Index1 + 1; Index2 < OutSampleDataList.Num(); ++Index2) { // if they have sample sample, remove the Index2, and get out if (OutSampleDataList[Index1].Animation == OutSampleDataList[Index2].Animation) { // add weight OutSampleDataList[Index1].AddWeight(OutSampleDataList[Index2].GetWeight()); // as for time or previous time will be the master one(Index1) OutSampleDataList.RemoveAtSwap(Index2, 1, false); --Index2; } } } /** Used to sort by Weight. */ struct FCompareFBlendSampleData { FORCEINLINE bool operator()(const FBlendSampleData& A, const FBlendSampleData& B) const { return B.TotalWeight < A.TotalWeight; } }; OutSampleDataList.Sort(FCompareFBlendSampleData()); // remove noisy ones int32 TotalSample = OutSampleDataList.Num(); float TotalWeight = 0.f; for (int32 I=0; I<TotalSample; ++I) { if (OutSampleDataList[I].TotalWeight < ZERO_ANIMWEIGHT_THRESH) { // cut anything in front of this OutSampleDataList.RemoveAt(I, TotalSample-I, false); // we won't shrink here, that might screw up alloc optimization at a higher level, if not this is temp anyway break; } TotalWeight += OutSampleDataList[I].TotalWeight; } for (int32 I=0; I<OutSampleDataList.Num(); ++I) { // normalize to all weights OutSampleDataList[I].TotalWeight /= TotalWeight; } RawGridSamples.Reset(); return (OutSampleDataList.Num()!=0); }
/** * Performs a topological sort on the graph of nodes passed in (which is expected to form a DAG), scheduling them. * If there are cycles or unconnected nodes present in the graph, an error will be output for each node that failed to be scheduled. */ void FGraphCompilerContext::CreateExecutionSchedule(const TArray<UEdGraphNode*>& GraphNodes, /*out*/ TArray<UEdGraphNode*>& LinearExecutionSchedule) const { TArray<UEdGraphNode*> NodesWithNoEdges; TMap<UEdGraphNode*, int32> NumIncomingEdges; int32 TotalGraphEdgesLeft = 0; // Build a list of nodes with no antecedents and update the initial incoming edge counts for every node for (int32 NodeIndex = 0; NodeIndex < GraphNodes.Num(); ++NodeIndex) { UEdGraphNode* Node = GraphNodes[NodeIndex]; const int32 NumEdges = CountIncomingEdges(Node); NumIncomingEdges.Add(Node, NumEdges); TotalGraphEdgesLeft += NumEdges; if (NumEdges == 0) { NodesWithNoEdges.Add(Node); } } // While there are nodes with no unscheduled inputs, schedule them and queue up any that are newly scheduleable while (NodesWithNoEdges.Num() > 0) { // Schedule a node UEdGraphNode* Node = NodesWithNoEdges[0]; NodesWithNoEdges.RemoveAtSwap(0); LinearExecutionSchedule.Add(Node); // Decrement edge counts for things that depend on this node, and queue up any that hit 0 incoming edges for (int32 PinIndex = 0; PinIndex < Node->Pins.Num(); ++PinIndex) { UEdGraphPin* OutPin = Node->Pins[PinIndex]; if ((OutPin->Direction == EGPD_Output) && PinIsImportantForDependancies(OutPin)) { for (int32 LinkIndex = 0; LinkIndex < OutPin->LinkedTo.Num(); ++LinkIndex) { UEdGraphPin* LinkedToPin = OutPin->LinkedTo[LinkIndex]; if( !LinkedToPin ) { // If something went wrong in serialization and we have a bad connection, skip this. continue; } UEdGraphNode* WasDependentNode = OutPin->LinkedTo[LinkIndex]->GetOwningNodeUnchecked(); int32* pNumEdgesLeft = WasDependentNode ? NumIncomingEdges.Find(WasDependentNode) : NULL; // Remove the edge between these two nodes, since node is scheduled if (pNumEdgesLeft) { int32& NumEdgesLeft = *pNumEdgesLeft; if (NumEdgesLeft <= 0) { MessageLog.Error(TEXT("Internal compiler error inside CreateExecutionSchedule (site 1); there is an issue with node/pin manipulation that was performed in this graph, please contact the Blueprints team!")); LinearExecutionSchedule.Empty(); return; } NumEdgesLeft--; TotalGraphEdgesLeft--; // Was I the last link on that node? if (NumEdgesLeft == 0) { NodesWithNoEdges.Add(WasDependentNode); } } else { MessageLog.Error(TEXT("Internal compiler error inside CreateExecutionSchedule (site 2); there is an issue with node/pin manipulation that was performed in this graph, please contact the Blueprints team!")); LinearExecutionSchedule.Empty(); return; } } } } } // At this point, any remaining edges are either within an unrelated subgraph (unconnected island) or indicate loops that break the DAG constraint // Before this is called, any unconnected graphs should have been cut free so we can just error if (TotalGraphEdgesLeft > 0) { // Run thru and print out any nodes that couldn't be scheduled due to loops for (TMap<UEdGraphNode*, int32>::TIterator It(NumIncomingEdges); It; ++It) { //@TODO: Probably want to determine the actual pin that caused the cycle, instead of just printing out the node if (It.Value() > 0) { MessageLog.Error(TEXT("Dependency cycle detected, preventing node @@ from being scheduled"), It.Key()); } } } }
void FSoundCueGraphConnectionDrawingPolicy::BuildAudioFlowRoadmap() { UAudioComponent* PreviewAudioComponent = GEditor->GetPreviewAudioComponent(); FAudioDevice* AudioDevice = PreviewAudioComponent ? PreviewAudioComponent->GetAudioDevice() : nullptr; if (AudioDevice) { USoundCueGraph* SoundCueGraph = CastChecked<USoundCueGraph>(GraphObj); USoundCue* SoundCue = SoundCueGraph->GetSoundCue(); if (PreviewAudioComponent && PreviewAudioComponent->IsPlaying() && PreviewAudioComponent->Sound == SoundCue) { TArray<FWaveInstance*> WaveInstances; const int32 FirstActiveIndex = AudioDevice->GetSortedActiveWaveInstances(WaveInstances, ESortedActiveWaveGetType::QueryOnly); // Run through the active instances and cull out anything that isn't related to this graph if (FirstActiveIndex > 0) { WaveInstances.RemoveAt(0, FirstActiveIndex + 1); } for (int32 WaveIndex = WaveInstances.Num() - 1; WaveIndex >= 0 ; --WaveIndex) { UAudioComponent* WaveInstanceAudioComponent = WaveInstances[WaveIndex]->ActiveSound->AudioComponent.Get(); if (WaveInstanceAudioComponent != PreviewAudioComponent) { WaveInstances.RemoveAtSwap(WaveIndex); } } for (int32 WaveIndex = 0; WaveIndex < WaveInstances.Num(); ++WaveIndex) { TArray<USoundNode*> PathToWaveInstance; if (SoundCue->FindPathToNode(WaveInstances[WaveIndex]->WaveInstanceHash, PathToWaveInstance)) { TArray<USoundCueGraphNode_Root*> RootNode; TArray<UEdGraphNode*> GraphNodes; SoundCueGraph->GetNodesOfClass<USoundCueGraphNode_Root>(RootNode); check(RootNode.Num() == 1); GraphNodes.Add(RootNode[0]); TArray<double> NodeTimes; NodeTimes.Add(FApp::GetCurrentTime()); // Time for the root node for (int32 i = 0; i < PathToWaveInstance.Num(); ++i) { const double ObservationTime = FApp::GetCurrentTime() + 1.f; NodeTimes.Add(ObservationTime); GraphNodes.Add(PathToWaveInstance[i]->GraphNode); } // Record the unique node->node pairings, keeping only the most recent times for each pairing for (int32 i = GraphNodes.Num() - 1; i >= 1; --i) { UEdGraphNode* CurNode = GraphNodes[i]; double CurNodeTime = NodeTimes[i]; UEdGraphNode* NextNode = GraphNodes[i-1]; double NextNodeTime = NodeTimes[i-1]; FExecPairingMap& Predecessors = PredecessorNodes.FindOrAdd(NextNode); // Update the timings if this is a more recent pairing FTimePair& Timings = Predecessors.FindOrAdd(CurNode); if (Timings.ThisExecTime < NextNodeTime) { Timings.PredExecTime = CurNodeTime; Timings.ThisExecTime = NextNodeTime; } } } } } } }
static void BuildDependencyMapAndCompile(TArray<UBlueprintGeneratedStruct*>& ChangedStructs, FCompilerResultsLog& MessageLog) { struct FFindStructureDescriptionPred { const UBlueprintGeneratedStruct* const Struct; FFindStructureDescriptionPred(const UBlueprintGeneratedStruct* InStruct) : Struct(InStruct) { check(Struct); } bool operator()(const FBPStructureDescription& Desc) { return (Desc.CompiledStruct == Struct); } }; struct FDependencyMapEntry { UBlueprintGeneratedStruct* Struct; TSet<UBlueprintGeneratedStruct*> StructuresToWaitFor; FDependencyMapEntry() : Struct(NULL) {} void Initialize(UBlueprintGeneratedStruct* ChangedStruct, TArray<UBlueprintGeneratedStruct*>& AllChangedStructs) { Struct = ChangedStruct; check(Struct && Struct->StructGeneratedBy); FBPStructureDescription* StructureDescription = Struct->StructGeneratedBy->UserDefinedStructures.FindByPredicate(FFindStructureDescriptionPred(Struct)); check(StructureDescription); auto Schema = GetDefault<UEdGraphSchema_K2>(); for (auto FieldIter = StructureDescription->Fields.CreateIterator(); FieldIter; ++FieldIter) { FEdGraphPinType FieldType = (*FieldIter).VarType; auto StructType = Cast<UBlueprintGeneratedStruct>(FieldType.PinSubCategoryObject.Get()); if (StructType && (FieldType.PinCategory == Schema->PC_Struct) && AllChangedStructs.Contains(StructType)) { StructuresToWaitFor.Add(StructType); } } } }; TArray<FDependencyMapEntry> DependencyMap; for (auto Iter = ChangedStructs.CreateIterator(); Iter; ++Iter) { DependencyMap.Add(FDependencyMapEntry()); DependencyMap.Last().Initialize(*Iter, ChangedStructs); } while (DependencyMap.Num()) { int32 StructureToCompileIndex = INDEX_NONE; for (int32 EntryIndex = 0; EntryIndex < DependencyMap.Num(); ++EntryIndex) { if(0 == DependencyMap[EntryIndex].StructuresToWaitFor.Num()) { StructureToCompileIndex = EntryIndex; break; } } check(INDEX_NONE != StructureToCompileIndex); UBlueprintGeneratedStruct* Struct = DependencyMap[StructureToCompileIndex].Struct; check(Struct->StructGeneratedBy); FBPStructureDescription* StructureDescription = Struct->StructGeneratedBy->UserDefinedStructures.FindByPredicate(FFindStructureDescriptionPred(Struct)); check(StructureDescription); FUserDefinedStructureCompilerInner::CleanAndSanitizeStruct(Struct); FUserDefinedStructureCompilerInner::InnerCompileStruct(*StructureDescription, GetDefault<UEdGraphSchema_K2>(), MessageLog); DependencyMap.RemoveAtSwap(StructureToCompileIndex); for (auto EntryIter = DependencyMap.CreateIterator(); EntryIter; ++EntryIter) { (*EntryIter).StructuresToWaitFor.Remove(Struct); } } }
void AHUD::UpdateHitBoxCandidates( TArray<FVector2D> InContactPoints ) { HitBoxHits.Reset(); for (FHUDHitBox& HitBox : HitBoxMap) { bool bAdded = false; for (int32 ContactPointIndex = InContactPoints.Num() - 1; ContactPointIndex >= 0; --ContactPointIndex) { if (HitBox.Contains(InContactPoints[ContactPointIndex])) { if (!bAdded) { HitBoxHits.Add(&HitBox); bAdded = true; } if (HitBox.ConsumesInput()) { InContactPoints.RemoveAtSwap(ContactPointIndex); } else { break; } } } if (InContactPoints.Num() == 0) { break; } } TSet<FName> NotOverHitBoxes = HitBoxesOver; TArray<FName> NewlyOverHitBoxes; // Now figure out which boxes we are over and deal with begin/end cursor over messages for (FHUDHitBox* HitBox : HitBoxHits) { const FName HitBoxName = HitBox->GetName(); if (HitBoxesOver.Contains(HitBoxName)) { NotOverHitBoxes.Remove(HitBoxName); } else { NewlyOverHitBoxes.AddUnique(HitBoxName); } } // Dispatch the end cursor over messages for (const FName HitBoxName : NotOverHitBoxes) { NotifyHitBoxEndCursorOver(HitBoxName); HitBoxesOver.Remove(HitBoxName); } // Dispatch the newly over hitbox messages for (const FName HitBoxName : NewlyOverHitBoxes) { NotifyHitBoxBeginCursorOver(HitBoxName); HitBoxesOver.Add(HitBoxName); } }