void InitializeInjectedNodes(UBehaviorTreeGraphNode* GraphNode, UBTCompositeNode* RootNode, uint16 ExecutionIndex, uint8 TreeDepth, int32 ChildIdx) { TMap<UBehaviorTreeGraphNode_CompositeDecorator*, FIntIntPair> CompositeMap; TArray<UBTDecorator*> DecoratorInstances; TArray<FBTDecoratorLogic> DecoratorOperations; for (int32 i = 0; i < GraphNode->Decorators.Num(); i++) { UBehaviorTreeGraphNode* MyNode = GraphNode->Decorators[i]; if (MyNode == NULL || !MyNode->bInjectedNode) { continue; } UBehaviorTreeGraphNode_Decorator* MyDecoratorNode = Cast<UBehaviorTreeGraphNode_Decorator>(MyNode); UBehaviorTreeGraphNode_CompositeDecorator* MyCompositeNode = Cast<UBehaviorTreeGraphNode_CompositeDecorator>(MyNode); if (MyDecoratorNode) { MyDecoratorNode->CollectDecoratorData(DecoratorInstances, DecoratorOperations); } else if (MyCompositeNode) { MyCompositeNode->SetDecoratorData(RootNode, ChildIdx); FIntIntPair RangeData; RangeData.FirstIdx = DecoratorInstances.Num(); MyCompositeNode->CollectDecoratorData(DecoratorInstances, DecoratorOperations); RangeData.LastIdx = DecoratorInstances.Num() - 1; CompositeMap.Add(MyCompositeNode, RangeData); } } for (int32 i = 0; i < DecoratorInstances.Num(); i++) { DecoratorInstances[i]->InitializeNode(RootNode, ExecutionIndex, 0, TreeDepth); DecoratorInstances[i]->InitializeDecorator(ChildIdx); ExecutionIndex++; } // initialize composite decorators for (TMap<UBehaviorTreeGraphNode_CompositeDecorator*, FIntIntPair>::TIterator It(CompositeMap); It; ++It) { UBehaviorTreeGraphNode_CompositeDecorator* Node = It.Key(); const FIntIntPair& PairInfo = It.Value(); if (DecoratorInstances.IsValidIndex(PairInfo.FirstIdx) && DecoratorInstances.IsValidIndex(PairInfo.LastIdx)) { Node->FirstExecutionIndex = DecoratorInstances[PairInfo.FirstIdx]->GetExecutionIndex(); Node->LastExecutionIndex = DecoratorInstances[PairInfo.LastIdx]->GetExecutionIndex(); } } }
void AZombieController::Possess(APawn* Pawn) { Super::Possess(Pawn); AZombieCharacter* Zombie = Cast<AZombieCharacter>(Pawn); if (Zombie) { //Initialize blackboard if (Zombie->BehaviorTree->BlackboardAsset) { BlackboardComp->InitializeBlackboard(*(Zombie->BehaviorTree->BlackboardAsset)); } //Get player and hold a reference of it TArray<AActor*> ActorsArray; UGameplayStatics::GetAllActorsOfClass(GetWorld(), ARoguelikeChar::StaticClass(), ActorsArray); if (ActorsArray.IsValidIndex(0)) { ARoguelikeChar* Player = Cast<ARoguelikeChar>(ActorsArray[0]); if (Player) { BlackboardComp->SetValueAsObject(PlayerBlackboardKey, Player); } } //Start the tree BehaviorComp->StartTree(*Zombie->BehaviorTree); } }
void AppendPathPointsHelper(TArray<FNavPathPoint>& PathPoints, const TArray<FPathPointInfo>& SourcePoints, int32 Index) { if (SourcePoints.IsValidIndex(Index) && SourcePoints[Index].Point.NodeRef != 0) { PathPoints.Add(SourcePoints[Index].Point); } }
void UGISInventoryBaseComponent::PreLootAction(TArray<class AGISPickupActor*> PickupsIn) { TArray<FGISPickupActorDistanceHelper> HelperStruct; FVector PawmLocation = PCOwner->GetPawn()->GetActorLocation(); for (AGISPickupActor* Pickup : PickupsIn) { if (Pickup) { if (Pickup->ItemToLoot.Num() > 0) { float Distance = FVector::Dist(PawmLocation, Pickup->GetActorLocation()); FGISPickupActorDistanceHelper helper(Distance, Pickup); HelperStruct.Add(helper); } } } HelperStruct.Sort(); if (HelperStruct.IsValidIndex(0)) { //don't need to check everything. If closest actor is to far, rest is as well. if (HelperStruct[0].Distance > MaxLootingDistance) StartLooting(HelperStruct[0].PickupActor.Get()); } }
FTrackInstancePropertyBindings::FPropertyAddress FTrackInstancePropertyBindings::FindPropertyRecursive( const UObject* Object, void* BasePointer, UStruct* InStruct, TArray<FString>& InPropertyNames, uint32 Index ) const { UProperty* Property = FindField<UProperty>(InStruct, *InPropertyNames[Index]); FTrackInstancePropertyBindings::FPropertyAddress NewAddress; UStructProperty* StructProp = Cast<UStructProperty>( Property ); if( StructProp ) { NewAddress.Property = StructProp; NewAddress.Address = BasePointer; if( InPropertyNames.IsValidIndex(Index+1) ) { void* StructContainer = StructProp->ContainerPtrToValuePtr<void>(BasePointer); return FindPropertyRecursive( Object, StructContainer, StructProp->Struct, InPropertyNames, Index+1 ); } else { check( StructProp->GetName() == InPropertyNames[Index] ); } } else if( Property ) { NewAddress.Property = Property; NewAddress.Address = BasePointer; } return NewAddress; }
FString FTextFormatData::Format_NoLock(const FPrivateTextFormatArguments& InFormatArgs) { ConditionalCompile_NoLock(); if (LexedExpression.Num() == 0) { return SourceExpression; } FString ResultString; ResultString.Reserve(BaseFormatStringLength + (InFormatArgs.EstimatedArgumentValuesLength * FormatArgumentEstimateMultiplier)); int32 ArgumentIndex = 0; for (int32 TokenIndex = 0; TokenIndex < LexedExpression.Num(); ++TokenIndex) { const FExpressionToken& Token = LexedExpression[TokenIndex]; if (const auto* Literal = Token.Node.Cast<TextFormatTokens::FStringLiteral>()) { ResultString.AppendChars(Literal->StringStartPos, Literal->StringLen); } else if (auto* Escaped = Token.Node.Cast<TextFormatTokens::FEscapedCharacter>()) { ResultString.AppendChar(Escaped->Character); } else if (const auto* ArgumentToken = Token.Node.Cast<TextFormatTokens::FArgumentTokenSpecifier>()) { const FFormatArgumentValue* const PossibleArgumentValue = InFormatArgs.GetArgumentValue(*ArgumentToken, ArgumentIndex++); if (PossibleArgumentValue) { if (LexedExpression.IsValidIndex(TokenIndex + 1)) { const FExpressionToken& NextToken = LexedExpression[TokenIndex + 1]; // Peek to see if the next token is an argument modifier if (const auto* ArgumentModifierToken = NextToken.Node.Cast<TextFormatTokens::FArgumentModifierTokenSpecifier>()) { ArgumentModifierToken->TextFormatArgumentModifier->Evaluate(*PossibleArgumentValue, InFormatArgs, ResultString); ++TokenIndex; // walk over the argument token so that the next iteration will skip over the argument modifier continue; } } PossibleArgumentValue->ToFormattedString(InFormatArgs.bRebuildText, InFormatArgs.bRebuildAsSource, ResultString); } else { ResultString.AppendChar(TextFormatTokens::ArgStartChar); ResultString.AppendChars(ArgumentToken->ArgumentNameStartPos, ArgumentToken->ArgumentNameLen); ResultString.AppendChar(TextFormatTokens::ArgEndChar); } } } return ResultString; }
TArray<FVector> ULeapImage::LocateBlobs(TArray<FVector> blobArray1, TArray<FVector> blobArray2) { TArray<FVector> BlobVectors; uint8 matchBlobs[200]; FVector blobLocation, blob1, blob2, cameraOffset;; cameraOffset = FVector(-0.02f, 0.0f, 0.0f); //MATCH THE LEFT RAYS TO THE RIGHT RAYS //MAKE SURE RAYS ARE AT LEAST WITHIN 0.05 OF EACHOTHER //PICK PAIR THAT RESULTS IN LONGER DISTANCE TO AVOID ENTANGLEMENT for (int i = 0; blobArray1.IsValidIndex(i); i++) { matchBlobs[i] = 255; } float farthest; for (int i = 0; blobArray1.IsValidIndex(i); i++){ farthest = 0.05f; //MUST BE FARTHER THAN THIS TO COUNT AT ALL for (int j = 0; blobArray2.IsValidIndex(j); j++){ //TEST ALL FOR FARTHEST WORKING BLOB float intersectiondistance = _private->ClosestDistOfApproach(-cameraOffset, blobArray1[i], cameraOffset, blobArray2[j]); float distancefromleap = _private->ClosestTimeOfApproach(-cameraOffset, blobArray1[i], cameraOffset, blobArray2[j]); if (distancefromleap > farthest) { if (intersectiondistance < 0.02f) { farthest = distancefromleap; matchBlobs[i] = j; } } } } //ADD BLOB POSITIONS (RELATIVE TO PARENT) ONLY AT THE INTERSECTION OF THE MATCHED RAYS for (int i = 0; blobArray1.IsValidIndex(i); i++){ if (matchBlobs[i] != 255){ blobLocation = _private->ClosestPointOfApproach(-cameraOffset, blobArray1[i], cameraOffset, blobArray2[matchBlobs[i]]); BlobVectors.Add(blobLocation); } } return BlobVectors; }
FVector ExtractLocation(TSubclassOf<UEnvQueryItemType> ItemType, const TArray<uint8>& RawData, const TArray<FEnvQueryItem>& Items, int32 Index) { if (Items.IsValidIndex(Index) && ItemType->IsChildOf(UEnvQueryItemType_VectorBase::StaticClass())) { UEnvQueryItemType_VectorBase* DefTypeOb = ItemType->GetDefaultObject<UEnvQueryItemType_VectorBase>(); return DefTypeOb->GetItemLocation(RawData.GetData() + Items[Index].DataOffset); } return FVector::ZeroVector; }
void ASignDialogueHandler::LoadFile(FString fileName) { FXmlFile file(fileName); FXmlNode* root = file.GetRootNode(); if (root != NULL) { TArray<FXmlNode*> rootChildren = root->GetChildrenNodes(); // Run through the root's children for (int i = 0; i < rootChildren.Num(); i++) { if (rootChildren.IsValidIndex(i)) { TArray<FXmlNode*> children = rootChildren[i]->GetChildrenNodes(); if (children.IsValidIndex(0) && children.IsValidIndex(1) && SignArray.IsValidIndex(i)) { SignArray[i]->signInfo.signID = FCString::Atoi(*children[0]->GetContent()); SignArray[i]->signInfo.line = children[1]->GetContent(); } } } } }
TValueOrError<FString, FExpressionError> FStringFormatter::FormatInternal(const TCHAR* InExpression, const TArray<FStringFormatArg>& Args, bool bStrict) const { TValueOrError<TArray<FExpressionToken>, FExpressionError> Result = ExpressionParser::Lex(InExpression, bStrict ? StrictOrderedDefinitions : OrderedDefinitions); if (!Result.IsValid()) { return MakeError(Result.StealError()); } TArray<FExpressionToken>& Tokens = Result.GetValue(); if (Tokens.Num() == 0) { return MakeValue(InExpression); } // This code deliberately tries to reallocate as little as possible FString Formatted; Formatted.Reserve(Tokens.Last().Context.GetTokenEndPos() - InExpression); for (auto& Token : Tokens) { if (const auto* Literal = Token.Node.Cast<FStringLiteral>()) { Formatted.AppendChars(Literal->String.GetTokenStartPos(), Literal->Len); } else if (auto* Escaped = Token.Node.Cast<FEscapedCharacter>()) { Formatted.AppendChar(Escaped->Character); } else if (const auto* IndexToken = Token.Node.Cast<FIndexSpecifier>()) { if (Args.IsValidIndex(IndexToken->Index)) { AppendToString(Args[IndexToken->Index], Formatted); } else if (bStrict) { return MakeError(FText::Format(LOCTEXT("InvalidArgumentIndex", "Invalid argument index: {0}"), FText::AsNumber(IndexToken->Index))); } else { // No replacement found, so just add the original token string const int32 Length = IndexToken->EntireToken.GetTokenEndPos() - IndexToken->EntireToken.GetTokenStartPos(); Formatted.AppendChars(IndexToken->EntireToken.GetTokenStartPos(), Length); } } } return MakeValue(Formatted); }
void FBehaviorTreeDebugger::SetCompositeDecoratorRuntimeDescription(const TArray<FString>& RuntimeDescriptions, class UBehaviorTreeGraphNode_CompositeDecorator* Node) { Node->DebuggerRuntimeDescription.Empty(); for (int32 i = Node->FirstExecutionIndex; i <= Node->LastExecutionIndex; i++) { if (RuntimeDescriptions.IsValidIndex(i) && RuntimeDescriptions[i].Len()) { if (Node->DebuggerRuntimeDescription.Len()) { Node->DebuggerRuntimeDescription.AppendChar(TEXT('\n')); } Node->DebuggerRuntimeDescription += FString::Printf(TEXT("[%d] %s"), i, *RuntimeDescriptions[i].Replace(TEXT("\n"), TEXT(", "))); } } }
/** * Called when a Controller is logout from the game or changes teams. If there is * atleast one teammate left on the team, then the team will continue to be in controll * of the leaving Controllers ControlPoints.If there is no other teammates left on the * team after the player changes teams/logout, then any ControlPoints controlled by the * Controller is set back to Neutral. * @param PS The Controller who is changing teams or is logout. */ void AUTDomGameMode::ClearControl(AUTPlayerState* PS) { TArray<AUTPlayerState*> Pick; uint8 Num, i; // find a teammate if (PS == NULL) { return; } for (FConstPlayerControllerIterator Iterator = GetWorld()->GetPlayerControllerIterator(); Iterator; ++Iterator) { AUTPlayerController* NextPlayer = Cast<AUTPlayerController>(*Iterator); AUTPlayerState* TestPS = NextPlayer ? Cast<AUTPlayerState>(NextPlayer->PlayerState) : NULL; if (TestPS != NULL && TestPS != PS && (PS->GetTeamNum() == TestPS->GetTeamNum())) { Pick.AddUnique(TestPS); } } if (Pick.Num() > 0) { Num = FMath::RandHelper(Pick.Num()); if (Pick.IsValidIndex(Num) && Pick[Num] != NULL) { // Give random team mate control over leaving players control points for (i = 0; i < CDomPoints.Num(); i++) { if (CDomPoints[i]->TeamNum != 255 && CDomPoints[i]->ControllingPawn == PS) { CDomPoints[i]->ControllingPawn = Pick[Num]; CDomPoints[i]->UpdateStatus(); } } return; } } // No teammate found, so reset the point to X for (i = 0; i < CDomPoints.Num(); i++) { if (CDomPoints[i]->ControllingPawn == PS) { CDomPoints[i]->ResetPoint(true); } } }
FString DataTableUtils::AssignStringToProperty(const FString& InString, const UProperty* InProp, uint8* InData) { FStringOutputDevice ImportError; if(InProp && IsSupportedTableProperty(InProp)) { if(InProp->ArrayDim == 1) { DataTableUtilsImpl::AssignStringToProperty(InString, InProp, InData, 0, PPF_None, ImportError); } else { if(InString.Len() >= 2 && InString[0] == '(' && InString[InString.Len() - 1] == ')') { // Trim the ( and ) FString StringToSplit = InString.Mid(1, InString.Len() - 2); TArray<FString> Values; StringToSplit.ParseIntoArray(Values, TEXT(","), 1); if (InProp->ArrayDim != Values.Num()) { UE_LOG(LogDataTable, Warning, TEXT("%s - Array is %d elements large, but we have %d values to import"), *InProp->GetName(), InProp->ArrayDim, Values.Num()); } for (int32 Index = 0; Index < InProp->ArrayDim; ++Index) { if (Values.IsValidIndex(Index)) { DataTableUtilsImpl::AssignStringToProperty(Values[Index], InProp, InData, Index, PPF_Delimited, ImportError); } } } else { UE_LOG(LogDataTable, Warning, TEXT("%s - Malformed array string. It must start with '(' and end with ')'"), *InProp->GetName()); } } } FString Error = ImportError; return Error; }
bool UColorPadActivator::DetermineIfPlayerOverlaps() { TArray<AActor*> OverlappingActors; GetOwner()->GetOverlappingActors( OUT OverlappingActors, ADefaultPawn::StaticClass() ); if (OverlappingActors.IsValidIndex(0)) { //player is overlapping return true; } else { //player is not overlapping return false; } }
int32 AHeliGameModeLobby::ChooseTeam(AHeliPlayerState* ForPlayerState) const { // choose one of the teams that are least populated TArray<int32> TeamBalance; TeamBalance.AddZeroed(NumTeams); // get current team balance for (int32 i = 0; i < GameState->PlayerArray.Num(); i++) { AHeliPlayerState const* const TestPlayerState = Cast<AHeliPlayerState>(GameState->PlayerArray[i]); if (TestPlayerState && TestPlayerState != ForPlayerState && TeamBalance.IsValidIndex(TestPlayerState->GetTeamNumber())) { TeamBalance[TestPlayerState->GetTeamNumber()]++; } } // find least populated one int32 BestTeamScore = TeamBalance[0]; for (int32 i = 1; i < TeamBalance.Num(); i++) { if (BestTeamScore > TeamBalance[i]) { BestTeamScore = TeamBalance[i]; } } // there could be more than one... TArray<int32> BestTeams; for (int32 i = 0; i < TeamBalance.Num(); i++) { if (TeamBalance[i] == BestTeamScore) { BestTeams.Add(i); } } // get random from best list const int32 RandomBestTeam = BestTeams[FMath::RandHelper(BestTeams.Num())]; return RandomBestTeam; }
bool FGameplayCueTranslationManager::BuildTagTranslationTable_r(const FName& TagName, const TArray<FName>& SplitNames) { #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) if (CVarGameplyCueTranslatorDebugTag->GetString().IsEmpty() == false && TagName.ToString().Contains(CVarGameplyCueTranslatorDebugTag->GetString())) { // UE_LOG(LogGameplayCueTranslator, Log, TEXT(".....")); } #endif bool HasValidRootTag = false; TArray<FName> SwappedNames; SwappedNames.Reserve(10); // Every NameSwap Rule/Class that gave us data for (FNameSwapData& NameSwapData : AllNameSwaps) { // Avoid rule recursion { if (FGameplayCueTranslatorNode* ChildNode = GetTranslationNodeForName(TagName, false)) { if (ChildNode->UsedTranslators.Contains(NameSwapData.ClassCDO)) { continue; } } } // Every Swap that this Rule/Class gave us for (int32 SwapRuleIdx=0; SwapRuleIdx < NameSwapData.NameSwaps.Num(); ++SwapRuleIdx) { const FGameplayCueTranslationNameSwap& SwapRule = NameSwapData.NameSwaps[SwapRuleIdx]; #if WITH_EDITOR if (SwapRule.EditorData.Enabled == false) { continue; } #endif // Walk through the original tag's elements for (int32 TagIdx=0; TagIdx < SplitNames.Num(); ++TagIdx) { // Walk through the potential new tag's elemnts for (int32 ToNameIdx=0; ToNameIdx < SwapRule.ToNames.Num() && TagIdx < SplitNames.Num(); ++ToNameIdx) { // If they match if (SwapRule.ToNames[ToNameIdx] == SplitNames[TagIdx]) { // If we are at the end if (ToNameIdx == SwapRule.ToNames.Num()-1) { // *Possible* tag translation found! This tag can be derived from out name swapping rules, // but we don't know if there actually is a tag that matches the tag which it would be translated *from* // Don't operator on SplitNames, since subsequent rules and name swaps use the same array SwappedNames = SplitNames; // Remove the "To Names" from the SwappedNames array, replace with the single "From Name" // E.g, GC.{Steel.Master} -> GC.{Hero} int32 NumRemoves = SwapRule.ToNames.Num(); // We are going to remove as many tags int32 RemoveAtIdx = TagIdx - (SwapRule.ToNames.Num() - 1); check(SwappedNames.IsValidIndex(RemoveAtIdx)); SwappedNames.RemoveAt(RemoveAtIdx, NumRemoves, false); SwappedNames.Insert(SwapRule.FromName, RemoveAtIdx); // Compose a string from the new name FString ComposedString = SwappedNames[0].ToString(); for (int32 ComposeIdx=1; ComposeIdx < SwappedNames.Num(); ++ ComposeIdx) { ComposedString += FString::Printf(TEXT(".%s"), *SwappedNames[ComposeIdx].ToString()); } UE_LOG(LogGameplayCueTranslator, Log, TEXT("Found possible expanded tag. Original Child Tag: %s. Possible Parent Tag: %s"), *TagName.ToString(), *ComposedString); FName ComposedName = FName(*ComposedString); // Look for this tag - is it an actual real tag? If not, continue on { FGameplayTag ComposedTag = TagManager->RequestGameplayTag(ComposedName, false); if (ComposedTag.IsValid() == false) { UE_LOG(LogGameplayCueTranslator, Log, TEXT(" No tag match found, recursing...")); FGameplayCueTranslatorNodeIndex ParentIdx = GetTranslationIndexForName( ComposedName, false ); if (ParentIdx.IsValid() == false) { ParentIdx = GetTranslationIndexForName( ComposedName, true ); check(ParentIdx.IsValid()); TranslationLUT[ParentIdx].UsedTranslators.Add( NameSwapData.ClassCDO ); HasValidRootTag |= BuildTagTranslationTable_r(ComposedName, SwappedNames); } } else { HasValidRootTag = true; } } if (HasValidRootTag) { // Add it to our data structures FGameplayCueTranslatorNodeIndex ParentIdx = GetTranslationIndexForName(ComposedName, true); check(ParentIdx.IsValid()); UE_LOG(LogGameplayCueTranslator, Log, TEXT(" Matches real tags! Adding to translation tree")); FGameplayCueTranslatorNodeIndex ChildIdx = GetTranslationIndexForName(TagName, true); ensure(ChildIdx != INDEX_NONE); // Note: important to do this after getting ChildIdx since allocating idx can move TranslationMap memory around FGameplayCueTranslatorNode& ParentNode = TranslationLUT[ParentIdx]; FGameplayCueTranslationLink& NewLink = ParentNode.FindOrCreateLink(NameSwapData.ClassCDO, NameSwapData.NameSwaps.Num()); // Verify this link hasn't already been established ensure(NewLink.NodeLookup[SwapRuleIdx] != ChildIdx); // Setup the link NewLink.NodeLookup[SwapRuleIdx] = ChildIdx; // Now make sure we don't reapply this rule to this child node or any of its child nodes FGameplayCueTranslatorNode& ChildNode = TranslationLUT[ChildIdx]; ChildNode.UsedTranslators.Append( ParentNode.UsedTranslators ); ChildNode.UsedTranslators.Add( NameSwapData.ClassCDO ); } else { UE_LOG(LogGameplayCueTranslator, Log, TEXT(" No tag match found after recursing. Dead end.")); } break; } else { // Keep going, advance TagIdx TagIdx++; continue; } } else { // Match failed break; } } } } } return HasValidRootTag; }
void UEnvQueryTest_Project::RunTest(FEnvQueryInstance& QueryInstance) const { BoolValue.BindData(QueryInstance.Owner.Get(), QueryInstance.QueryID); bool bWantsProjected = BoolValue.GetValue(); UEnvQueryItemType_Point* ItemTypeCDO = QueryInstance.ItemType->GetDefaultObject<UEnvQueryItemType_Point>(); if (ItemTypeCDO == nullptr) { return; } if (ProjectionData.TraceMode == EEnvQueryTrace::Navigation) { const ANavigationData* NavData = FEQSHelpers::FindNavigationDataForQuery(QueryInstance); if (NavData) { TSharedPtr<const FNavigationQueryFilter> NavigationFilter = UNavigationQueryFilter::GetQueryFilter(*NavData, ProjectionData.NavigationFilter); TArray<FNavigationProjectionWork> Workload; Workload.Reserve(QueryInstance.Items.Num()); const FVector VerticalOffset = (ProjectionData.ProjectDown == ProjectionData.ProjectUp) ? FVector::ZeroVector : FVector(0, 0, (ProjectionData.ProjectUp - ProjectionData.ProjectDown) / 2); for (int32 Idx = 0; Idx < QueryInstance.Items.Num(); Idx++) { if (QueryInstance.Items[Idx].IsValid()) { const FVector& ItemLocation = GetItemLocation(QueryInstance, Idx); Workload.Add(FNavigationProjectionWork(ItemLocation + VerticalOffset)); } } const FVector ProjectionExtent(ProjectionData.ExtentX, ProjectionData.ExtentX, (ProjectionData.ProjectDown + ProjectionData.ProjectUp) / 2); NavData->BatchProjectPoints(Workload, ProjectionExtent, NavigationFilter); int32 Idx = 0; for (FEnvQueryInstance::ItemIterator It(this, QueryInstance); It; ++It, Idx++) { const bool bProjected = Workload[Idx].bResult; if (bProjected) { ItemTypeCDO->SetItemNavLocation(It.GetItemData(), Workload[Idx].OutLocation); } It.SetScore(TestPurpose, FilterType, bProjected, bWantsProjected); } } } else if (ProjectionData.TraceMode == EEnvQueryTrace::Geometry) { TArray<FNavLocation> Workload; TArray<uint8> TraceHits; Workload.Reserve(QueryInstance.Items.Num()); for (int32 Idx = 0; Idx < QueryInstance.Items.Num(); Idx++) { if (QueryInstance.Items[Idx].IsValid()) { const FVector& ItemLocation = GetItemLocation(QueryInstance, Idx); Workload.Add(FNavLocation(ItemLocation)); } } FEQSHelpers::RunPhysProjection(QueryInstance.World, ProjectionData, Workload, TraceHits); int32 Idx = 0; for (FEnvQueryInstance::ItemIterator It(this, QueryInstance); It; ++It, Idx++) { const bool bProjected = TraceHits.IsValidIndex(Idx) && TraceHits[Idx]; if (bProjected) { ItemTypeCDO->SetItemNavLocation(It.GetItemData(), Workload[Idx]); } It.SetScore(TestPurpose, FilterType, bProjected, bWantsProjected); } } }
FName FSourceControlModule::GetSourceControlProviderName(int32 ProviderIndex) { TArray<ISourceControlProvider*> Providers = IModularFeatures::Get().GetModularFeatureImplementations<ISourceControlProvider>(SourceControlFeatureName); check(Providers.IsValidIndex(ProviderIndex)); return Providers[ProviderIndex]->GetName(); }
void FSourceControlModule::SetCurrentSourceControlProvider(int32 ProviderIndex) { TArray<ISourceControlProvider*> Providers = IModularFeatures::Get().GetModularFeatureImplementations<ISourceControlProvider>(SourceControlFeatureName); check(Providers.IsValidIndex(ProviderIndex)); SetCurrentSourceControlProvider(*Providers[ProviderIndex]); }
void FHttpNetworkReplayStreamer::HttpEnumerateSessionsFinished( FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded ) { check( HttpState == EHttptate::EnumeratingSessions ); HttpState = EHttptate::Idle; if ( bSucceeded && HttpResponse->GetResponseCode() == EHttpResponseCodes::Ok ) { UE_LOG( LogHttpReplay, Verbose, TEXT( "FHttpNetworkReplayStreamer::HttpEnumerateSessionsFinished." ) ); TArray<FNetworkReplayStreamInfo> Streams; FString StreamsString = HttpResponse->GetContentAsString(); int32 Index = INDEX_NONE; TArray< FString > Tokens; // Parse the string as { token 1, token ..., token n } // This isn't perfect, we should convert to JSON when the dust settles if ( StreamsString.FindChar( '{', Index ) ) { StreamsString = StreamsString.RightChop( Index + 1 ); while ( StreamsString.FindChar( ',', Index ) ) { Tokens.Add( StreamsString.Left( Index ) ); StreamsString = StreamsString.RightChop( Index + 1 ); } if ( StreamsString.FindChar( '}', Index ) ) { Tokens.Add( StreamsString.Left( Index ) ); } else { UE_LOG( LogHttpReplay, Warning, TEXT( "FHttpNetworkReplayStreamer::HttpEnumerateSessionsFinished. '}' not found." ) ); EnumerateStreamsDelegate.ExecuteIfBound( TArray<FNetworkReplayStreamInfo>() ); // FIXME: Notify failure here EnumerateStreamsDelegate = FOnEnumerateStreamsComplete(); return; } if ( Tokens.Num() > 0 ) { Tokens[ Tokens.Num() - 1 ].RemoveFromStart( TEXT( " " ) ); Tokens[ Tokens.Num() - 1 ].RemoveFromEnd( TEXT( " " ) ); } } else { UE_LOG( LogHttpReplay, Warning, TEXT( "FHttpNetworkReplayStreamer::HttpEnumerateSessionsFinished. '{' not found." ) ); EnumerateStreamsDelegate.ExecuteIfBound( TArray<FNetworkReplayStreamInfo>() ); // FIXME: Notify failure here EnumerateStreamsDelegate = FOnEnumerateStreamsComplete(); return; } const int NUM_TOKENS_PER_INFO = 6; if ( Tokens.Num() == 0 || ( Tokens.Num() % NUM_TOKENS_PER_INFO ) != 0 ) { UE_LOG( LogHttpReplay, Warning, TEXT( "FHttpNetworkReplayStreamer::HttpEnumerateSessionsFinished. Invalid number of tokens: %i" ), Tokens.Num() ); EnumerateStreamsDelegate.ExecuteIfBound( TArray<FNetworkReplayStreamInfo>() ); // FIXME: Notify failure here EnumerateStreamsDelegate = FOnEnumerateStreamsComplete(); return; } // Convert tokens to individual FNetworkReplayStreamInfo's for ( int i = 0; i < Tokens.Num(); i += NUM_TOKENS_PER_INFO ) { FNetworkReplayStreamInfo NewStream; NewStream.Name = Tokens[i]; NewStream.bIsLive = false; NewStream.SizeInBytes = 0; NewStream.Timestamp = 0; if ( Tokens.IsValidIndex( i + 1 ) ) { // Server returns milliseconds from January 1, 1970, 00:00:00 GMT // We need to compensate for the fact that FDateTime starts at January 1, 0001 A.D. and is in 100 nanosecond resolution NewStream.Timestamp = FDateTime( FCString::Atoi64( *Tokens[ i + 1 ] ) * 1000 * 10 + FDateTime( 1970, 1, 1 ).GetTicks() ); } if ( Tokens.IsValidIndex( i + 2 ) ) { NewStream.SizeInBytes = FCString::Atoi( *Tokens[ i + 2 ] ); } if ( Tokens.IsValidIndex( i + 3 ) ) { NewStream.LengthInMS = FCString::Atoi( *Tokens[ i + 3 ] ); } if ( Tokens.IsValidIndex( i + 4 ) ) { NewStream.NumViewers = FCString::Atoi( *Tokens[ i + 4 ] ); } if ( Tokens.IsValidIndex( i + 5 ) ) { NewStream.bIsLive = Tokens[ i + 5 ].Contains( TEXT( "true" ) ); } Streams.Add( NewStream ); } EnumerateStreamsDelegate.ExecuteIfBound( Streams ); } else { UE_LOG( LogHttpReplay, Warning, TEXT( "FHttpNetworkReplayStreamer::HttpEnumerateSessionsFinished. FAILED" ) ); EnumerateStreamsDelegate.ExecuteIfBound( TArray<FNetworkReplayStreamInfo>() ); // FIXME: Notify failure here } EnumerateStreamsDelegate = FOnEnumerateStreamsComplete(); }
void UBehaviorTreeGraphNode_CompositeDecorator::BuildDescription() { FString BaseDesc("Composite Decorator"); if (!bShowOperations) { CachedDescription = BaseDesc; return; } TArray<UBTDecorator*> NodeInstances; TArray<FBTDecoratorLogic> Operations; CollectDecoratorData(NodeInstances, Operations); TArray<FLogicDesc> OpStack; FString Description = BaseDesc + TEXT(":"); FString Indent("\n"); bool bPendingNotOp = false; for (int32 i = 0; i < Operations.Num(); i++) { const FBTDecoratorLogic& TestOp = Operations[i]; if (TestOp.Operation == EBTDecoratorLogic::And || TestOp.Operation == EBTDecoratorLogic::Or) { Indent += TEXT("- "); FLogicDesc NewOpDesc; NewOpDesc.NumLeft = TestOp.Number; NewOpDesc.OperationDesc = (TestOp.Operation == EBTDecoratorLogic::And) ? TEXT("AND") : TEXT("OR"); OpStack.Add(NewOpDesc); } else if (TestOp.Operation == EBTDecoratorLogic::Not) { // special case: NOT before TEST if (Operations.IsValidIndex(i + 1) && Operations[i + 1].Operation == EBTDecoratorLogic::Test) { bPendingNotOp = true; } else { Indent += TEXT("- "); Description += Indent; Description += TEXT("NOT:"); FLogicDesc NewOpDesc; NewOpDesc.NumLeft = 0; OpStack.Add(NewOpDesc); } } else if (TestOp.Operation == EBTDecoratorLogic::Test) { Description += Indent; if (bPendingNotOp) { Description += TEXT("NOT: "); bPendingNotOp = false; } Description += NodeInstances[TestOp.Number]->GetStaticDescription(); UpdateLogicOpStack(OpStack, Description, Indent); } } CachedDescription = Description; }
const FAIResourceID& GetResource(int32 ResourceIndex) { return ResourceIDs.IsValidIndex(ResourceIndex) ? ResourceIDs[ResourceIndex] : InvalidResource; }
void FBehaviorTreeDebugger::SetNodeRuntimeDescription(const TArray<FString>& RuntimeDescriptions, class UBehaviorTreeGraphNode* Node, class UBTNode* NodeInstance) { Node->DebuggerRuntimeDescription = RuntimeDescriptions.IsValidIndex(NodeInstance->GetExecutionIndex()) ? RuntimeDescriptions[NodeInstance->GetExecutionIndex()] : FString(); }
void UStaticMesh::FixupZeroTriangleSections() { if (RenderData->MaterialIndexToImportIndex.Num() > 0 && RenderData->LODResources.Num()) { TArray<int32> MaterialMap; FMeshSectionInfoMap NewSectionInfoMap; // Iterate over all sections of all LODs and identify all material indices that need to be remapped. for (int32 LODIndex = 0; LODIndex < RenderData->LODResources.Num(); ++ LODIndex) { FStaticMeshLODResources& LOD = RenderData->LODResources[LODIndex]; int32 NumSections = LOD.Sections.Num(); for (int32 SectionIndex = 0; SectionIndex < NumSections; ++SectionIndex) { FMeshSectionInfo DefaultSectionInfo(SectionIndex); if (RenderData->MaterialIndexToImportIndex.IsValidIndex(SectionIndex)) { int32 ImportIndex = RenderData->MaterialIndexToImportIndex[SectionIndex]; FMeshSectionInfo SectionInfo = SectionInfoMap.Get(LODIndex, ImportIndex); int32 OriginalMaterialIndex = SectionInfo.MaterialIndex; // If import index == material index, remap it. if (SectionInfo.MaterialIndex == ImportIndex) { SectionInfo.MaterialIndex = SectionIndex; } // Update the material mapping table. while (SectionInfo.MaterialIndex >= MaterialMap.Num()) { MaterialMap.Add(INDEX_NONE); } if (SectionInfo.MaterialIndex >= 0) { MaterialMap[SectionInfo.MaterialIndex] = OriginalMaterialIndex; } // Update the new section info map if needed. if (SectionInfo != DefaultSectionInfo) { NewSectionInfoMap.Set(LODIndex, SectionIndex, SectionInfo); } } } } // Compact the materials array. for (int32 i = RenderData->LODResources[0].Sections.Num(); i < MaterialMap.Num(); ++i) { if (MaterialMap[i] == INDEX_NONE) { int32 NextValidIndex = i+1; for (; NextValidIndex < MaterialMap.Num(); ++NextValidIndex) { if (MaterialMap[NextValidIndex] != INDEX_NONE) { break; } } if (MaterialMap.IsValidIndex(NextValidIndex)) { MaterialMap[i] = MaterialMap[NextValidIndex]; for (TMap<uint32,FMeshSectionInfo>::TIterator It(NewSectionInfoMap.Map); It; ++It) { FMeshSectionInfo& SectionInfo = It.Value(); if (SectionInfo.MaterialIndex == NextValidIndex) { SectionInfo.MaterialIndex = i; } } } MaterialMap.RemoveAt(i, NextValidIndex - i); } } SectionInfoMap.Clear(); SectionInfoMap.CopyFrom(NewSectionInfoMap); // Check if we need to remap materials. bool bRemapMaterials = false; for (int32 MaterialIndex = 0; MaterialIndex < MaterialMap.Num(); ++MaterialIndex) { if (MaterialMap[MaterialIndex] != MaterialIndex) { bRemapMaterials = true; break; } } // Remap the materials array if needed. if (bRemapMaterials) { TArray<UMaterialInterface*> OldMaterials; Exchange(Materials,OldMaterials); Materials.Empty(MaterialMap.Num()); for (int32 MaterialIndex = 0; MaterialIndex < MaterialMap.Num(); ++MaterialIndex) { UMaterialInterface* Material = NULL; int32 OldMaterialIndex = MaterialMap[MaterialIndex]; if (OldMaterials.IsValidIndex(OldMaterialIndex)) { Material = OldMaterials[OldMaterialIndex]; } Materials.Add(Material); } } } else { int32 FoundMaxMaterialIndex = -1; TSet<int32> DiscoveredMaterialIndices; // Find the maximum material index that is used by the mesh // Also keep track of which materials are actually used in the array for(int32 LODIndex = 0; LODIndex < RenderData->LODResources.Num(); ++LODIndex) { if (RenderData->LODResources.IsValidIndex(LODIndex)) { FStaticMeshLODResources& LOD = RenderData->LODResources[LODIndex]; int32 NumSections = LOD.Sections.Num(); for (int32 SectionIndex = 0; SectionIndex < NumSections; ++SectionIndex) { FMeshSectionInfo Info = SectionInfoMap.Get(LODIndex, SectionIndex); if(Info.MaterialIndex > FoundMaxMaterialIndex) { FoundMaxMaterialIndex = Info.MaterialIndex; } DiscoveredMaterialIndices.Add(Info.MaterialIndex); } } } // NULL references to materials in indices that are not used by any LOD. // This is to fix up an import bug which caused more materials to be added to this array than needed. for ( int32 MaterialIdx = 0; MaterialIdx < Materials.Num(); ++MaterialIdx ) { if ( !DiscoveredMaterialIndices.Contains(MaterialIdx) ) { // Materials that are not used by any LOD resource should not be in this array. Materials[MaterialIdx] = NULL; } } // Remove entries at the end of the materials array. if (Materials.Num() > (FoundMaxMaterialIndex + 1)) { Materials.RemoveAt(FoundMaxMaterialIndex+1, Materials.Num() - FoundMaxMaterialIndex - 1); } } }
void StoreSelection(HWND hWnd) { int32 Idx = SendDlgItemMessage(hWnd, IDC_BUILDLIST, CB_GETCURSEL, 0, 0); Identifier = SortedIdentifiers.IsValidIndex(Idx) ? SortedIdentifiers[Idx] : TEXT(""); }
bool DiffTreeView::HasPrevDifference(TSharedRef< STreeView<TSharedPtr< FBlueprintDifferenceTreeEntry > > > TreeView, const TArray< TSharedPtr<class FBlueprintDifferenceTreeEntry> >& Differences) { int32 CurrentIndex = CurrentDifference(TreeView, Differences); return Differences.IsValidIndex(CurrentIndex - 1); }
void FTextFormatData::Compile_NoLock() { LexedExpression.Reset(); if (SourceType == ESourceType::Text) { SourceExpression = SourceText.ToString(); CompiledTextSnapshot = FTextSnapshot(SourceText); } CompiledExpressionType = FTextFormat::EExpressionType::Simple; BaseFormatStringLength = 0; FormatArgumentEstimateMultiplier = 1; TValueOrError<TArray<FExpressionToken>, FExpressionError> Result = ExpressionParser::Lex(*SourceExpression, FTextFormatter::Get().GetTextFormatDefinitions()); bool bValidExpression = Result.IsValid(); if (bValidExpression) { LexedExpression = Result.StealValue(); // Quickly make sure the tokens are valid (argument modifiers may only follow an argument token) for (int32 TokenIndex = 0; TokenIndex < LexedExpression.Num(); ++TokenIndex) { const FExpressionToken& Token = LexedExpression[TokenIndex]; if (const auto* Literal = Token.Node.Cast<TextFormatTokens::FStringLiteral>()) { BaseFormatStringLength += Literal->StringLen; } else if (auto* Escaped = Token.Node.Cast<TextFormatTokens::FEscapedCharacter>()) { BaseFormatStringLength += 1; } else if (const auto* ArgumentToken = Token.Node.Cast<TextFormatTokens::FArgumentTokenSpecifier>()) { CompiledExpressionType = FTextFormat::EExpressionType::Complex; if (LexedExpression.IsValidIndex(TokenIndex + 1)) { const FExpressionToken& NextToken = LexedExpression[TokenIndex + 1]; // Peek to see if the next token is an argument modifier if (const auto* ArgumentModifierToken = NextToken.Node.Cast<TextFormatTokens::FArgumentModifierTokenSpecifier>()) { int32 ArgModLength = 0; bool ArgModUsesFormatArgs = false; ArgumentModifierToken->TextFormatArgumentModifier->EstimateLength(ArgModLength, ArgModUsesFormatArgs); BaseFormatStringLength += ArgModLength; FormatArgumentEstimateMultiplier += (ArgModUsesFormatArgs) ? 1 : 0; ++TokenIndex; // walk over the argument token so that the next iteration will skip over the argument modifier continue; } } } else if (Token.Node.Cast<TextFormatTokens::FArgumentModifierTokenSpecifier>()) { // Unexpected argument modifier token! const FText ErrorSourceText = FText::FromString(Token.Context.GetString()); Result = MakeError(FExpressionError(FText::Format(LOCTEXT("UnexpectedArgumentModifierToken", "Unexpected 'argument modifier' token: {0} (token started at index {1})"), ErrorSourceText, Token.Context.GetCharacterIndex()))); bValidExpression = false; break; } } } if (!bValidExpression) { LexedExpression.Reset(); CompiledExpressionType = FTextFormat::EExpressionType::Invalid; UE_LOG(LogTextFormatter, Warning, TEXT("Failed to compile text format string '%s': %s"), *SourceExpression, *Result.GetError().Text.ToString()); } }
bool FDesktopPlatformWindows::FileDialogShared(bool bSave, const void* ParentWindowHandle, const FString& DialogTitle, const FString& DefaultPath, const FString& DefaultFile, const FString& FileTypes, uint32 Flags, TArray<FString>& OutFilenames, int32& OutFilterIndex) { FScopedSystemModalMode SystemModalScope; WCHAR Filename[MAX_FILENAME_STR]; FCString::Strcpy(Filename, MAX_FILENAME_STR, *(DefaultFile.Replace(TEXT("/"), TEXT("\\")))); // Convert the forward slashes in the path name to backslashes, otherwise it'll be ignored as invalid and use whatever is cached in the registry WCHAR Pathname[MAX_FILENAME_STR]; FCString::Strcpy(Pathname, MAX_FILENAME_STR, *(FPaths::ConvertRelativePathToFull(DefaultPath).Replace(TEXT("/"), TEXT("\\")))); // Convert the "|" delimited list of filetypes to NULL delimited then add a second NULL character to indicate the end of the list WCHAR FileTypeStr[MAX_FILETYPES_STR]; WCHAR* FileTypesPtr = NULL; const int32 FileTypesLen = FileTypes.Len(); // Nicely formatted file types for lookup later and suitable to append to filenames without extensions TArray<FString> CleanExtensionList; // The strings must be in pairs for windows. // It is formatted as follows: Pair1String1|Pair1String2|Pair2String1|Pair2String2 // where the second string in the pair is the extension. To get the clean extensions we only care about the second string in the pair TArray<FString> UnformattedExtensions; FileTypes.ParseIntoArray( &UnformattedExtensions, TEXT("|"), true ); for( int32 ExtensionIndex = 1; ExtensionIndex < UnformattedExtensions.Num(); ExtensionIndex += 2) { const FString& Extension = UnformattedExtensions[ExtensionIndex]; // Assume the user typed in an extension or doesnt want one when using the *.* extension. We can't determine what extension they wan't in that case if( Extension != TEXT("*.*") ) { // Add to the clean extension list, first removing the * wildcard from the extension int32 WildCardIndex = Extension.Find( TEXT("*") ); CleanExtensionList.Add( WildCardIndex != INDEX_NONE ? Extension.RightChop( WildCardIndex+1 ) : Extension ); } } if (FileTypesLen > 0 && FileTypesLen - 1 < MAX_FILETYPES_STR) { FileTypesPtr = FileTypeStr; FCString::Strcpy(FileTypeStr, MAX_FILETYPES_STR, *FileTypes); TCHAR* Pos = FileTypeStr; while( Pos[0] != 0 ) { if ( Pos[0] == '|' ) { Pos[0] = 0; } Pos++; } // Add two trailing NULL characters to indicate the end of the list FileTypeStr[FileTypesLen] = 0; FileTypeStr[FileTypesLen + 1] = 0; } OPENFILENAME ofn; FMemory::Memzero(&ofn, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = (HWND)ParentWindowHandle; ofn.lpstrFilter = FileTypesPtr; ofn.nFilterIndex = 1; ofn.lpstrFile = Filename; ofn.nMaxFile = MAX_FILENAME_STR; ofn.lpstrInitialDir = Pathname; ofn.lpstrTitle = *DialogTitle; if(FileTypesLen > 0) { ofn.lpstrDefExt = &FileTypeStr[0]; } ofn.Flags = OFN_HIDEREADONLY | OFN_ENABLESIZING | OFN_EXPLORER; if ( bSave ) { ofn.Flags |= OFN_CREATEPROMPT | OFN_OVERWRITEPROMPT | OFN_NOVALIDATE; } else { ofn.Flags |= OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; } if ( Flags & EFileDialogFlags::Multiple ) { ofn.Flags |= OFN_ALLOWMULTISELECT; } bool bSuccess; if ( bSave ) { bSuccess = !!::GetSaveFileName(&ofn); } else { bSuccess = !!::GetOpenFileName(&ofn); } if ( bSuccess ) { // GetOpenFileName/GetSaveFileName changes the CWD on success. Change it back immediately. FPlatformProcess::SetCurrentWorkingDirectoryToBaseDir(); if ( Flags & EFileDialogFlags::Multiple ) { // When selecting multiple files, the returned string is a NULL delimited list // where the first element is the directory and all remaining elements are filenames. // There is an extra NULL character to indicate the end of the list. FString DirectoryOrSingleFileName = FString(Filename); TCHAR* Pos = Filename + DirectoryOrSingleFileName.Len() + 1; if ( Pos[0] == 0 ) { // One item selected. There was an extra trailing NULL character. OutFilenames.Add(DirectoryOrSingleFileName); } else { // Multiple items selected. Keep adding filenames until two NULL characters. FString SelectedFile; do { SelectedFile = FString(Pos); new(OutFilenames) FString(DirectoryOrSingleFileName / SelectedFile); Pos += SelectedFile.Len() + 1; } while (Pos[0] != 0); } } else { new(OutFilenames) FString(Filename); } // The index of the filter in OPENFILENAME starts at 1. OutFilterIndex = ofn.nFilterIndex - 1; // Get the extension to add to the filename (if one doesnt already exist) FString Extension = CleanExtensionList.IsValidIndex( OutFilterIndex ) ? CleanExtensionList[OutFilterIndex] : TEXT(""); // Make sure all filenames gathered have their paths normalized and proper extensions added for ( auto FilenameIt = OutFilenames.CreateIterator(); FilenameIt; ++FilenameIt ) { FString& Filename = *FilenameIt; Filename = IFileManager::Get().ConvertToRelativePath(*Filename); if( FPaths::GetExtension(Filename).IsEmpty() && !Extension.IsEmpty() ) { // filename does not have an extension. Add an extension based on the filter that the user chose in the dialog Filename += Extension; } FPaths::NormalizeFilename(Filename); } } else { uint32 Error = ::CommDlgExtendedError(); if ( Error != ERROR_SUCCESS ) { UE_LOG(LogDesktopPlatform, Warning, TEXT("Error reading results of file dialog. Error: 0x%04X"), Error); } } return bSuccess; }
void CollectDecorators(UBehaviorTree* BTAsset, UBehaviorTreeGraphNode* GraphNode, TArray<UBTDecorator*>& DecoratorInstances, TArray<FBTDecoratorLogic>& DecoratorOperations, bool bInitializeNodes, UBTCompositeNode* RootNode, uint16* ExecutionIndex, uint8 TreeDepth, int32 ChildIdx) { TMap<UBehaviorTreeGraphNode_CompositeDecorator*, FIntIntPair> CompositeMap; int32 NumNodes = 0; for (int32 i = 0; i < GraphNode->Decorators.Num(); i++) { UBehaviorTreeGraphNode* MyNode = GraphNode->Decorators[i]; if (MyNode == NULL || MyNode->bInjectedNode) { continue; } UBehaviorTreeGraphNode_Decorator* MyDecoratorNode = Cast<UBehaviorTreeGraphNode_Decorator>(MyNode); UBehaviorTreeGraphNode_CompositeDecorator* MyCompositeNode = Cast<UBehaviorTreeGraphNode_CompositeDecorator>(MyNode); if (MyDecoratorNode) { MyDecoratorNode->CollectDecoratorData(DecoratorInstances, DecoratorOperations); NumNodes++; } else if (MyCompositeNode) { MyCompositeNode->SetDecoratorData(RootNode, ChildIdx); FIntIntPair RangeData; RangeData.FirstIdx = DecoratorInstances.Num(); MyCompositeNode->CollectDecoratorData(DecoratorInstances, DecoratorOperations); NumNodes++; RangeData.LastIdx = DecoratorInstances.Num() - 1; CompositeMap.Add(MyCompositeNode, RangeData); } } for (int32 i = 0; i < DecoratorInstances.Num(); i++) { if (DecoratorInstances[i] && BTAsset && Cast<UBehaviorTree>(DecoratorInstances[i]->GetOuter()) == NULL) { DecoratorInstances[i]->Rename(NULL, BTAsset); } DecoratorInstances[i]->InitializeNode(RootNode, *ExecutionIndex, 0, TreeDepth); if (bInitializeNodes) { DecoratorInstances[i]->InitializeDecorator(ChildIdx); *ExecutionIndex += 1; // make sure that flow abort mode matches - skip for root level nodes DecoratorInstances[i]->UpdateFlowAbortMode(); } } if (bInitializeNodes) { // initialize composite decorators for (TMap<UBehaviorTreeGraphNode_CompositeDecorator*, FIntIntPair>::TIterator It(CompositeMap); It; ++It) { UBehaviorTreeGraphNode_CompositeDecorator* Node = It.Key(); const FIntIntPair& PairInfo = It.Value(); if (DecoratorInstances.IsValidIndex(PairInfo.FirstIdx) && DecoratorInstances.IsValidIndex(PairInfo.LastIdx)) { Node->FirstExecutionIndex = DecoratorInstances[PairInfo.FirstIdx]->GetExecutionIndex(); Node->LastExecutionIndex = DecoratorInstances[PairInfo.LastIdx]->GetExecutionIndex(); } } } // setup logic operations only when composite decorator is linked if (CompositeMap.Num()) { if (NumNodes > 1) { FBTDecoratorLogic LogicOp(EBTDecoratorLogic::And, NumNodes); DecoratorOperations.Insert(LogicOp, 0); } } else { DecoratorOperations.Reset(); } }
void SMergeTreeView::Construct(const FArguments InArgs, const FBlueprintMergeData& InData) { Data = InData; CurrentDifference = -1; TArray< FSCSDiffEntry > RemoteDifferingProperties; TArray< int > RemoteDiffsSortKeys; TArray< FSCSDiffEntry > LocalDifferingProperties; TArray< int > LocalDiffsSortKeys; DiffUtils::CompareUnrelatedSCS(InData.BlueprintBase, InData.BlueprintRemote, RemoteDifferingProperties, &RemoteDiffsSortKeys); DiffUtils::CompareUnrelatedSCS(InData.BlueprintBase, InData.BlueprintLocal, LocalDifferingProperties, &LocalDiffsSortKeys); check(RemoteDiffsSortKeys.Num() == RemoteDifferingProperties.Num() && LocalDifferingProperties.Num() == LocalDiffsSortKeys.Num()); // Order the differing properties, and eliminate dupes. Eventually dupes should be treated as collisions when // attempting to complete a merge automatically: int RemoteIter = 0; int LocalIter = 0; while (RemoteDifferingProperties.IsValidIndex(RemoteIter) || LocalDifferingProperties.IsValidIndex(LocalIter)) { const bool bStillHaveLocalDiffs = LocalDifferingProperties.IsValidIndex(LocalIter); const bool bStillHaveRemoteDiffs = RemoteDifferingProperties.IsValidIndex(RemoteIter); FSCSDiffEntry Entry; if (bStillHaveLocalDiffs && bStillHaveRemoteDiffs) { if (LocalDiffsSortKeys[LocalIter] <= RemoteDiffsSortKeys[RemoteIter]) { Entry = LocalDifferingProperties[LocalIter++]; } else { Entry = RemoteDifferingProperties[RemoteIter++]; } } else if (bStillHaveLocalDiffs) { Entry = LocalDifferingProperties[LocalIter++]; } else { check(bStillHaveRemoteDiffs); Entry = RemoteDifferingProperties[RemoteIter++]; } if (!DifferingProperties.Contains(Entry)) { DifferingProperties.Push(Entry); } } // generate controls: // EMergeParticipant::MERGE_PARTICIPANT_REMOTE { SCSViews.Push( FSCSDiff(InData.BlueprintRemote) ); } // EMergeParticipant::MERGE_PARTICIPANT_BASE { SCSViews.Push( FSCSDiff(InData.BlueprintBase) ); } // EMergeParticipant::MERGE_PARTICIPANT_LOCAL { SCSViews.Push( FSCSDiff(InData.BlueprintLocal) ); } ChildSlot[ SNew(SSplitter) + SSplitter::Slot() [ GetRemoteView().TreeWidget() ] + SSplitter::Slot() [ GetBaseView().TreeWidget() ] + SSplitter::Slot() [ GetLocalView().TreeWidget() ] ]; }