/** 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;
	}
}
Example #10
0
// 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);
			}
		}
	}
Example #15
0
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);
	}
}