void FICUCamelCaseBreakIterator::TokenizeString(TArray<FToken>& OutTokens)
{
	OutTokens.Empty(String.Len());

	FICUTextCharacterIterator CharIter(String);
	for(CharIter.setToStart(); CharIter.current32() != FICUTextCharacterIterator::DONE; CharIter.next32PostInc())
	{
		const UChar32 CurrentChar = CharIter.current32();

		ETokenType TokenType = ETokenType::Other;
		if(u_isULowercase(CurrentChar))
		{
			TokenType = ETokenType::Lowercase;
		}
		else if(u_isUUppercase(CurrentChar))
		{
			TokenType = ETokenType::Uppercase;
		}
		else if(u_isdigit(CurrentChar))
		{
			TokenType = ETokenType::Digit;
		}

		const int32 CharIndex = CharIter.InternalIndexToSourceIndex(CharIter.getIndex());
		OutTokens.Emplace(FToken(TokenType, CharIndex));
	}

	OutTokens.Emplace(FToken(ETokenType::Null, String.Len()));

	// There should always be at least one token for the end of the string
	check(OutTokens.Num());
}
	virtual void FireEvent_FlushChatStats() override
	{
		if (AnalyticsProvider.IsValid())
		{
			IOnlineIdentityPtr OnlineIdentity = Online::GetIdentityInterface(TEXT("MCP"));
			if (OnlineIdentity.IsValid())
			{
				TSharedPtr<const FUniqueNetId> UserId = OnlineIdentity->GetUniquePlayerId(0);
				if (UserId.IsValid())
				{
					auto RecordSocialChatCountsEvents = [=](const TMap<FString, int32>& ChatCounts, const FString& ChatType)
					{
						if (ChatCounts.Num())
						{
							TArray<FAnalyticsEventAttribute> Attributes;
							for (const auto& Pair : ChatCounts)
							{
								Attributes.Empty(3);
								Attributes.Emplace(TEXT("Name"), Pair.Key);
								Attributes.Emplace(TEXT("Type"), ChatType);
								Attributes.Emplace(TEXT("Count"), Pair.Value);
								AnalyticsProvider->RecordEvent("Social.Chat.Counts.2", Attributes);
							}
						}
					};

					RecordSocialChatCountsEvents(ChannelChatCounts, TEXT("Channel"));
					RecordSocialChatCountsEvents(PrivateChatCounts, TEXT("Private"));
				}
			}
		}
		ChannelChatCounts.Empty();
		PrivateChatCounts.Empty();
	}
Example #3
0
void FAssetEditorManager::OnExit()
{
	SaveOpenAssetEditors(true);

	TGuardValue<bool> GuardOnShutdown(bSavingOnShutdown, true);

	CloseAllAssetEditors();

	// Don't attempt to report usage stats if analytics isn't available
	if (FEngineAnalytics::IsAvailable())
	{
		TArray<FAnalyticsEventAttribute> EditorUsageAttribs;
		EditorUsageAttribs.Empty(2);
		for (auto Iter = EditorUsageAnalytics.CreateConstIterator(); Iter; ++Iter)
		{
			const FAssetEditorAnalyticInfo& Data = Iter.Value();
			EditorUsageAttribs.Reset();
			EditorUsageAttribs.Emplace(TEXT("TotalDuration.Seconds"), FString::Printf(TEXT("%.1f"), Data.SumDuration.GetTotalSeconds()));
			EditorUsageAttribs.Emplace(TEXT("OpenedInstances.Count"), FString::Printf(TEXT("%d"), Data.NumTimesOpened));

			const FString EventName = FString::Printf(TEXT("Editor.Usage.%s"), *Iter.Key().ToString());
			FEngineAnalytics::GetProvider().RecordEvent(EventName, EditorUsageAttribs);
		}
	}
}
void FLegacyCamelCaseBreakIterator::TokenizeString(TArray<FToken>& OutTokens)
{
	OutTokens.Empty(String.Len());

	for(int32 CurrentCharIndex = 0; CurrentCharIndex < String.Len(); ++CurrentCharIndex)
	{
		const TCHAR CurrentChar = String[CurrentCharIndex];

		ETokenType TokenType = ETokenType::Other;
		if(FChar::IsLower(CurrentChar))
		{
			TokenType = ETokenType::Lowercase;
		}
		else if(FChar::IsUpper(CurrentChar))
		{
			TokenType = ETokenType::Uppercase;
		}
		else if(FChar::IsDigit(CurrentChar))
		{
			TokenType = ETokenType::Digit;
		}

		OutTokens.Emplace(FToken(TokenType, CurrentCharIndex));
	}

	OutTokens.Emplace(FToken(ETokenType::Null, String.Len()));

	// There should always be at least one token for the end of the string
	check(OutTokens.Num());
}
TSharedRef< FRichTextSyntaxHighlighterTextLayoutMarshaller > FRichTextSyntaxHighlighterTextLayoutMarshaller::Create(const FSyntaxTextStyle& InSyntaxTextStyle)
{
	TArray<FSyntaxTokenizer::FRule> TokenizerRules;
	TokenizerRules.Emplace(FSyntaxTokenizer::FRule(TEXT("</>")));
	TokenizerRules.Emplace(FSyntaxTokenizer::FRule(TEXT("<")));
	TokenizerRules.Emplace(FSyntaxTokenizer::FRule(TEXT(">")));
	TokenizerRules.Emplace(FSyntaxTokenizer::FRule(TEXT("=")));
	TokenizerRules.Emplace(FSyntaxTokenizer::FRule(TEXT("\"")));

	return MakeShareable(new FRichTextSyntaxHighlighterTextLayoutMarshaller(FSyntaxTokenizer::Create(TokenizerRules), InSyntaxTextStyle));
}
bool FHttpServiceTracker::Tick(float DeltaTime)
{
	// flush events at the specified interval.
	if (FPlatformTime::Seconds() > NextFlushTime)
	{
		if (AnalyticsProvider.IsValid())
		{
			TArray<FAnalyticsEventAttribute> Attrs;
			Attrs.Reserve(10);
			// one event per endpoint.
			for (const auto& MetricsMapPair : EndpointMetricsMap)
			{
				Attrs.Reset();
				Attrs.Emplace(TEXT("DomainName"), MetricsMapPair.Value.LastAnalyticsName);
				Attrs.Emplace(TEXT("FailCount"), MetricsMapPair.Value.FailCount);
				Attrs.Emplace(TEXT("SuccessCount"), MetricsMapPair.Value.SuccessCount);
				// We may have had no successful requests, so these values would be undefined.
				if (MetricsMapPair.Value.SuccessCount > 0)
				{
					Attrs.Emplace(TEXT("DownloadBytesSuccessTotal"), MetricsMapPair.Value.DownloadBytesSuccessTotal);
					Attrs.Emplace(TEXT("ElapsedTimeSuccessTotal"), MetricsMapPair.Value.ElapsedTimeSuccessTotal);
					Attrs.Emplace(TEXT("ElapsedTimeSuccessMin"), MetricsMapPair.Value.ElapsedTimeSuccessMin);
					Attrs.Emplace(TEXT("ElapsedTimeSuccessMax"), MetricsMapPair.Value.ElapsedTimeSuccessMax);
				}
				if (MetricsMapPair.Value.FailCount > 0)
				{
					Attrs.Emplace(TEXT("DownloadBytesFailTotal"), MetricsMapPair.Value.DownloadBytesFailTotal);
					Attrs.Emplace(TEXT("ElapsedTimeFailTotal"), MetricsMapPair.Value.ElapsedTimeFailTotal);
					Attrs.Emplace(TEXT("ElapsedTimeFailMin"), MetricsMapPair.Value.ElapsedTimeFailMin);
					Attrs.Emplace(TEXT("ElapsedTimeFailMax"), MetricsMapPair.Value.ElapsedTimeFailMax);
				}
				// one attribute per response code.
				for (const auto& ResponseCodeMapPair : MetricsMapPair.Value.ResponseCodes)
				{
					Attrs.Emplace(FString(TEXT("Code-")) + LexicalConversion::ToString(ResponseCodeMapPair.Key), ResponseCodeMapPair.Value);
				}
				AnalyticsProvider->RecordEvent(MetricsMapPair.Key.ToString(), Attrs);
			}
			// force an immediate flush always. We already summarized.
			AnalyticsProvider->FlushEvents();
		}
		EndpointMetricsMap.Reset();
		NextFlushTime += FlushIntervalSec;
	}
	return true;
}
Example #7
0
TArray<FPathAndMountPoint> FAutoReimportManager::GetMonitoredDirectories() const
{
	TArray<FPathAndMountPoint> Dirs;
	for (const auto& Monitor : DirectoryMonitors)
	{
		Dirs.Emplace(Monitor.GetDirectory(), Monitor.GetMountPoint());
	}
	return Dirs;
}
void FAssetFixUpRedirectors::ExecuteFixUp(TArray<TWeakObjectPtr<UObjectRedirector>> Objects) const
{
	TArray<FRedirectorRefs> RedirectorRefsList;
	for (auto Object : Objects)
	{
		auto ObjectRedirector = Object.Get();

		if (ObjectRedirector)
		{
			RedirectorRefsList.Emplace(ObjectRedirector);
		}
	}

	if ( RedirectorRefsList.Num() > 0 )
	{
		// Gather all referencing packages for all redirectors that are being fixed.
		PopulateRedirectorReferencers(RedirectorRefsList);

		// Update Package Status for all selected redirectors if SCC is enabled
		if ( UpdatePackageStatus(RedirectorRefsList) )
		{
			// Load all referencing packages.
			TArray<UPackage*> ReferencingPackagesToSave;
			LoadReferencingPackages(RedirectorRefsList, ReferencingPackagesToSave);

			// Prompt to check out all referencing packages, leave redirectors for assets referenced by packages that are not checked out and remove those packages from the save list.
			const bool bUserAcceptedCheckout = CheckOutReferencingPackages(RedirectorRefsList, ReferencingPackagesToSave);
			if ( bUserAcceptedCheckout )
			{
				// If any referencing packages are left read-only, the checkout failed or SCC was not enabled. Trim them from the save list and leave redirectors.
				DetectReadOnlyPackages(RedirectorRefsList, ReferencingPackagesToSave);

				// Fix up referencing FStringAssetReferences
				FixUpStringAssetReferences(RedirectorRefsList, ReferencingPackagesToSave);

				// Save all packages that were referencing any of the assets that were moved without redirectors
				TArray<UPackage*> FailedToSave;
				SaveReferencingPackages(ReferencingPackagesToSave, FailedToSave);

				// Save any collections that were referencing any of the redirectors
				SaveReferencingCollections(RedirectorRefsList);

				// Wait for package referencers to be updated
				UpdateAssetReferencers(RedirectorRefsList);

				// Delete any redirectors that are no longer referenced
				DeleteRedirectors(RedirectorRefsList, FailedToSave);

				// Finally, report any failures that happened during the rename
				ReportFailures(RedirectorRefsList);
			}
		}
	}
}
Example #9
0
void FAutoReimportManager::SetUpDirectoryMonitors()
{
	struct FParsedSettings
	{
		FString SourceDirectory;
		FString MountPoint;
		FMatchRules Rules;
	};

	TArray<FParsedSettings> FinalArray;
	auto SupportedExtensions = GetAllFactoryExtensions();
	for (const auto& Setting : GetDefault<UEditorLoadingSavingSettings>()->AutoReimportDirectorySettings)
	{
		FParsedSettings NewMapping;
		NewMapping.SourceDirectory = Setting.SourceDirectory;
		NewMapping.MountPoint = Setting.MountPoint;

		if (!FAutoReimportDirectoryConfig::ParseSourceDirectoryAndMountPoint(NewMapping.SourceDirectory, NewMapping.MountPoint))
		{
			continue;
		}

		// Only include extensions that match a factory
		NewMapping.Rules.SetApplicableExtensions(SupportedExtensions);
		for (const auto& WildcardConfig : Setting.Wildcards)
		{
			NewMapping.Rules.AddWildcardRule(WildcardConfig.Wildcard, WildcardConfig.bInclude);
		}
		
		FinalArray.Add(NewMapping);
	}

	for (int32 Index = 0; Index < FinalArray.Num(); ++Index)
	{
		const auto& Mapping = FinalArray[Index];

		// We only create a directory monitor if there are no other's watching parent directories of this one
		for (int32 OtherIndex = Index + 1; OtherIndex < FinalArray.Num(); ++OtherIndex)
		{
			if (FinalArray[Index].SourceDirectory.StartsWith(FinalArray[OtherIndex].SourceDirectory))
			{
				UE_LOG(LogAutoReimportManager, Warning, TEXT("Unable to watch directory %s as it will conflict with another watching %s."), *FinalArray[Index].SourceDirectory, *FinalArray[OtherIndex].SourceDirectory);
				goto next;
			}
		}

		DirectoryMonitors.Emplace(Mapping.SourceDirectory, Mapping.Rules, Mapping.MountPoint);

	next:
		continue;
	}
}
void FRichTextMarkupProcessing::CalculateLineRanges(const FString& Input, TArray<FTextRange>& LineRanges) const
{
	// Iterate over each line break candidate, adding ranges from after the end of the last line added to before the newline or end of string.
	FLineBreakIterator LBI(Input);
	int32 RangeBegin = LBI.GetCurrentPosition();
	for(;;)
	{
		const int32 BreakIndex = LBI.MoveToNext();

		// If beginning or potential end is invalid, cease.
		if(RangeBegin == INDEX_NONE || BreakIndex == INDEX_NONE)
		{
			break;
		}

		const int32 BreakingCharacterIndex = BreakIndex - 1;
		if(BreakingCharacterIndex >= RangeBegin) // Valid index check.
		{
			const TCHAR BreakingCharacter = Input[BreakingCharacterIndex];
			// If line break candidate is after a newline, add the range as a new line.
			if(FChar::IsLinebreak(BreakingCharacter))
			{
				LineRanges.Emplace( FTextRange(RangeBegin, BreakingCharacterIndex) );
			}
			// If the line break candidate is the end of the string, add the range as a new line.
			else if(BreakIndex == Input.Len())
			{
				LineRanges.Emplace( FTextRange(RangeBegin, BreakIndex) );
			}
			else
			{
				continue;
			}
			RangeBegin = BreakIndex; // The next line begins after the end of the current line.
		}
	}
}
TSharedRef< FCPPRichTextSyntaxHighlighterTextLayoutMarshaller > FCPPRichTextSyntaxHighlighterTextLayoutMarshaller::Create(const FSyntaxTextStyle& InSyntaxTextStyle)
{
	TArray<FSyntaxTokenizer::FRule> TokenizerRules;

	// operators
	for(const auto& Operator : Operators)
	{
		TokenizerRules.Emplace(FSyntaxTokenizer::FRule(Operator));
	}	

	// keywords
	for(const auto& Keyword : Keywords)
	{
		TokenizerRules.Emplace(FSyntaxTokenizer::FRule(Keyword));
	}

	// Pre-processor Keywords
	for(const auto& PreProcessorKeyword : PreProcessorKeywords)
	{
		TokenizerRules.Emplace(FSyntaxTokenizer::FRule(PreProcessorKeyword));
	}

	return MakeShareable(new FCPPRichTextSyntaxHighlighterTextLayoutMarshaller(FSyntaxTokenizer::Create(TokenizerRules), InSyntaxTextStyle));
}
Example #12
0
// Called when the game starts or when spawned
void ABot::BeginPlay()
{
	progression = new FParagonProgression();

	TArray<Goal*> goals;
	Goal *g1 = new Goal_Exp(((FParagonProgression*)progression)->getExpForNextLevel());
	Goal *g2 = new Goal_Gold(((FParagonProgression*)progression)->gold);
	goals.Emplace(g1);
	goals.Emplace(g2);

	worldModel = WorldModel(goals);

	planner = new ActionPlanner();

	Super::BeginPlay();
}
void FPlainTextLayoutMarshaller::SetText(const FString& SourceString, FTextLayout& TargetTextLayout)
{
	const FTextBlockStyle& DefaultTextStyle = static_cast<FSlateTextLayout&>(TargetTextLayout).GetDefaultTextStyle();

	TArray<FTextRange> LineRanges;
	FTextRange::CalculateLineRangesFromString(SourceString, LineRanges);

	TArray<FTextLayout::FNewLineData> LinesToAdd;
	LinesToAdd.Reserve(LineRanges.Num());

	TArray<FTextLineHighlight> LineHighlightsToAdd;
	TSharedPtr<FSlateTextUnderlineLineHighlighter> UnderlineLineHighlighter;
	if (!DefaultTextStyle.UnderlineBrush.GetResourceName().IsNone())
	{
		UnderlineLineHighlighter = FSlateTextUnderlineLineHighlighter::Create(DefaultTextStyle.UnderlineBrush, DefaultTextStyle.Font, DefaultTextStyle.ColorAndOpacity, DefaultTextStyle.ShadowOffset, DefaultTextStyle.ShadowColorAndOpacity);
	}

	const bool bUsePasswordRun = bIsPassword.Get(false);
	for (int32 LineIndex = 0; LineIndex < LineRanges.Num(); ++LineIndex)
	{
		const FTextRange& LineRange = LineRanges[LineIndex];
		TSharedRef<FString> LineText = MakeShareable(new FString(SourceString.Mid(LineRange.BeginIndex, LineRange.Len())));

		TArray<TSharedRef<IRun>> Runs;
		if (bUsePasswordRun)
		{
			Runs.Add(FSlatePasswordRun::Create(FRunInfo(), LineText, DefaultTextStyle));
		}
		else
		{
			Runs.Add(FSlateTextRun::Create(FRunInfo(), LineText, DefaultTextStyle));
		}

		if (UnderlineLineHighlighter.IsValid())
		{
			LineHighlightsToAdd.Add(FTextLineHighlight(LineIndex, FTextRange(0, LineRange.Len()), FSlateTextUnderlineLineHighlighter::DefaultZIndex, UnderlineLineHighlighter.ToSharedRef()));
		}

		LinesToAdd.Emplace(MoveTemp(LineText), MoveTemp(Runs));
	}

	TargetTextLayout.AddLines(LinesToAdd);
	TargetTextLayout.SetLineHighlights(LineHighlightsToAdd);
}
Example #14
0
TArray<FLayoutGeometry> SSplitter2x2::ArrangeChildrenForLayout( const FGeometry& AllottedGeometry ) const
{
	check( Children.Num() == 4 );

	TArray<FLayoutGeometry> Result;
	Result.Empty(Children.Num());

	int32 NumNonCollapsedChildren = 0;
	FVector2D CoefficientTotal(0,0);

	// The allotted space for our children is our geometry minus a little space to show splitter handles
	const FVector2D SpaceAllottedForChildren = AllottedGeometry.Size - FVector2D(SplitterHandleSize,SplitterHandleSize);

	// The current offset that the next child should be positioned at.
	FVector2D Offset(0,0);

	for (int32 ChildIndex=0; ChildIndex < Children.Num(); ++ChildIndex)
	{
		const FSlot& CurSlot = Children[ChildIndex];

		// Calculate the amount of space that this child should take up.  
		// It is based on the current percentage of space it should take up which is defined by a user moving the splitters
		const FVector2D ChildSpace = SpaceAllottedForChildren * CurSlot.PercentageAttribute.Get();

		// put them in their spot
		Result.Emplace(FSlateLayoutTransform(Offset), ChildSpace);

		// Advance to the next slot. If the child is collapsed, it takes up no room and does not need a splitter
		if( ChildIndex == 1 )
		{
			// ChildIndex of 1 means we are starting the next column so reset the Y offset.
			Offset.Y = 0.0f;
			Offset += FVector2D( ChildSpace.X + SplitterHandleSize, 0);
		}
		else
		{
			Offset += FVector2D( 0, ChildSpace.Y + SplitterHandleSize );
		}
	}
	return Result;
}
TArray<FAssetData> FAssetSourceFilenameCache::GetAssetsPertainingToFile(const IAssetRegistry& Registry, const FString& AbsoluteFilename) const
{
	TArray<FAssetData> Assets;
	
	if (const auto* ObjectPaths = SourceFileToObjectPathCache.Find(FPaths::GetCleanFilename(AbsoluteFilename)))
	{
		for (const FName& Path : *ObjectPaths)
		{
			FAssetData Asset = Registry.GetAssetByObjectPath(Path);
			TOptional<FAssetImportInfo> ImportInfo = ExtractAssetImportInfo(Asset.TagsAndValues);
			if (ImportInfo.IsSet())
			{
				auto AssetPackagePath = FPackageName::LongPackageNameToFilename(Asset.PackagePath.ToString() / TEXT(""));

				// Attempt to find the matching source filename in the list of imported sorce files (generally there are only one of these)
				const bool bWasImportedFromFile = ImportInfo->SourceFiles.ContainsByPredicate([&](const FAssetImportInfo::FSourceFile& File){

					if (AbsoluteFilename == FPaths::ConvertRelativePathToFull(AssetPackagePath / File.RelativeFilename) ||
						AbsoluteFilename == FPaths::ConvertRelativePathToFull(File.RelativeFilename))
					{
						return true;
					}

					return false;
				});

				if (bWasImportedFromFile)
				{
					Assets.Emplace();
					Swap(Asset, Assets[Assets.Num() - 1]);
				}
			}
		}
	}

	return Assets;
}
EConvertQueryResult ConvertRaycastResults(bool& OutHasValidBlockingHit, const UWorld* World, int32 NumHits, PxRaycastHit* Hits, float CheckLength, const PxFilterData& QueryFilter, TArray<FHitResult>& OutHits, const FVector& StartLoc, const FVector& EndLoc, bool bReturnFaceIndex, bool bReturnPhysMat)
{
#if PLATFORM_LINUX	// to narrow down OR-24947
	_Pragma("clang optimize off");
#endif // PLATFORM_LINUX

	OutHits.Reserve(OutHits.Num() + NumHits);
	EConvertQueryResult ConvertResult = EConvertQueryResult::Valid;
	bool bHadBlockingHit = false;

	PxTransform PStartTM(U2PVector(StartLoc));
	for(int32 i=0; i<NumHits; i++)
	{
		FHitResult& NewResult = OutHits[OutHits.Emplace()];
		const PxRaycastHit& PHit = Hits[i];

		if (ConvertQueryImpactHit(World, PHit, NewResult, CheckLength, QueryFilter, StartLoc, EndLoc, NULL, PStartTM, bReturnFaceIndex, bReturnPhysMat) == EConvertQueryResult::Valid)
		{
			bHadBlockingHit |= NewResult.bBlockingHit;
		}
		else
		{
			// Reject invalid result (this should be rare). Remove from the results.
			OutHits.Pop(/*bAllowShrinking=*/ false);
			ConvertResult = EConvertQueryResult::Invalid;
		}
	}

	// Sort results from first to last hit
	OutHits.Sort( FCompareFHitResultTime() );
	OutHasValidBlockingHit = bHadBlockingHit;
	return ConvertResult;

#if PLATFORM_LINUX	// to narrow down OR-24947
	_Pragma("clang optimize on");
#endif // PLATFORM_LINUX
}
	void ExtractSourceFilePaths(UObject* Object, TArray<FString>& OutSourceFiles)
	{
		TArray<UObject::FAssetRegistryTag> TagList;
		Object->GetAssetRegistryTags(TagList);

		const FName TagName = UObject::SourceFileTagName();
		for (const auto& Tag : TagList)
		{
			if (Tag.Name == TagName)
			{
				int32 PreviousNum = OutSourceFiles.Num();

				TOptional<FAssetImportInfo> ImportInfo = FAssetImportInfo::FromJson(Tag.Value);
				if (ImportInfo.IsSet())
				{
					for (const auto& File : ImportInfo->SourceFiles)
					{
						OutSourceFiles.Emplace(UAssetImportData::ResolveImportFilename(File.RelativeFilename, Object->GetOutermost()));
					}
				}
				break;
			}
		}
	}
Example #18
0
		FStaticBounds()
		{
			MetricDistance.Emplace(EUnit::Micrometers,	1000);
			MetricDistance.Emplace(EUnit::Millimeters,	10);
			MetricDistance.Emplace(EUnit::Centimeters,	100);
			MetricDistance.Emplace(EUnit::Meters,			1000);
			MetricDistance.Emplace(EUnit::Kilometers,		0);

			ImperialDistance.Emplace(EUnit::Inches,	12);
			ImperialDistance.Emplace(EUnit::Feet,		3);
			ImperialDistance.Emplace(EUnit::Yards,	1760);
			ImperialDistance.Emplace(EUnit::Miles,	0);

			MetricMass.Emplace(EUnit::Micrograms,	1000);
			MetricMass.Emplace(EUnit::Milligrams,	1000);
			MetricMass.Emplace(EUnit::Grams,		1000);
			MetricMass.Emplace(EUnit::Kilograms,	1000);
			MetricMass.Emplace(EUnit::MetricTons,	0);

			ImperialMass.Emplace(EUnit::Ounces,	16);
			ImperialMass.Emplace(EUnit::Pounds,	14);
			ImperialMass.Emplace(EUnit::Stones,	0);

			Frequency.Emplace(EUnit::Hertz,		1000);
			Frequency.Emplace(EUnit::Kilohertz,	1000);
			Frequency.Emplace(EUnit::Megahertz,	1000);
			Frequency.Emplace(EUnit::Gigahertz,	0);

			DataSize.Emplace(EUnit::Bytes,		1000);
			DataSize.Emplace(EUnit::Kilobytes,	1000);
			DataSize.Emplace(EUnit::Megabytes,	1000);
			DataSize.Emplace(EUnit::Gigabytes,	1000);
			DataSize.Emplace(EUnit::Terabytes,	0);

			Time.Emplace(EUnit::Milliseconds,		1000);
			Time.Emplace(EUnit::Seconds,			60);
			Time.Emplace(EUnit::Minutes,			60);
			Time.Emplace(EUnit::Hours,			24);
			Time.Emplace(EUnit::Days,				365.242f / 12);
			Time.Emplace(EUnit::Months,			12);
			Time.Emplace(EUnit::Years,			0);
		}
Example #19
0
TArray<FLayoutGeometry> SSplitter::ArrangeChildrenForLayout(const FGeometry& AllottedGeometry) const
{
	TArray<FLayoutGeometry> Result; 
	Result.Empty(Children.Num());

	const int32 AxisIndex = (Orientation == Orient_Horizontal) ? 0 : 1;

	// Splitters divide the space between their children proportionately based on size coefficients.
	// The size coefficients are usually determined by a user, who grabs the handled between the child elements
	// and moves them to resize the space available to the children.
	// Some children are sized automatically based on their content; those children cannot be resized.
	//
	// e.g.   _____________________________________ Children
	//       /              /                  /
	//      v              v                  v
	//   + - - - - - + + - - - + + - - - - - - - - - - - - - - +
	//   |           | |       | |                             |
	//   | Child 0   | |Child1 | |  Child2                     |
	//   + - - - - - + + - - - + + - - - - - - - - - - - - - - +
	//                ^         ^
	//                 \_________\___________ Resize handles.

	int32 NumNonCollapsedChildren = 0;
	int32 NumResizeableChildren = 0;
	float CoefficientTotal = 0;
	// Some space is claimed by non-resizeable elements (auto-sized elements)
	float NonResizeableSpace = 0;
	{
		for (int32 ChildIndex=0; ChildIndex < Children.Num(); ++ChildIndex)	
		{
			if (Children[ChildIndex].GetWidget()->GetVisibility() != EVisibility::Collapsed)
			{
				++NumNonCollapsedChildren;

				if ( Children[ChildIndex].SizingRule == SSplitter::SizeToContent )
				{
					NonResizeableSpace += Children[ChildIndex].GetWidget()->GetDesiredSize()[AxisIndex];
				}
				else // SizingRule == SSplitter::FractionOfParent
				{
					CoefficientTotal += Children[ChildIndex].SizeValue.Get();
				}
			}			
		}
	}



	// The user-sizeable children must make room for the resize handles and for auto-sized children.
	const float SpaceNeededForHandles = FMath::Max(0, NumNonCollapsedChildren-1) * PhysicalSplitterHandleSize;
	const float ResizeableSpace = AllottedGeometry.Size.Component(AxisIndex) - SpaceNeededForHandles - NonResizeableSpace;

	// Arrange the children horizontally or vertically.
	float XOffset = 0;
	for (int32 ChildIndex=0; ChildIndex < Children.Num(); ++ChildIndex)
	{
		const FSlot& CurSlot = Children[ChildIndex];

		const float ChildSpace = ( CurSlot.SizingRule == SSplitter::SizeToContent )
			? CurSlot.GetWidget()->GetDesiredSize()[AxisIndex]
		: ResizeableSpace * CurSlot.SizeValue.Get() / CoefficientTotal;

		const EVisibility ChildVisibility = CurSlot.GetWidget()->GetVisibility();

		FVector2D ChildOffset = Orientation == Orient_Horizontal ? FVector2D(XOffset, 0) : FVector2D(0, XOffset);
		FVector2D ChildSize = Orientation == Orient_Horizontal ? FVector2D(ChildSpace, AllottedGeometry.Size.Y) : FVector2D(AllottedGeometry.Size.X, ChildSpace);
		Result.Emplace(FSlateLayoutTransform(ChildOffset), ChildSize);

		// Advance to the next slot. If the child is collapsed, it takes up no room and does not need a splitter
		if ( ChildVisibility != EVisibility::Collapsed)
		{
			XOffset += ChildSpace + PhysicalSplitterHandleSize;
		}
	}
	return Result;
}
void FContentDirectoryMonitor::ProcessModifications(const DirectoryWatcher::FTimeLimit& TimeLimit, TArray<UPackage*>& OutPackagesToSave, FReimportFeedbackContext& Context)
{
	auto* ReimportManager = FReimportManager::Instance();

	for (int32 Index = 0; Index < ModifiedFiles.Num(); ++Index)
	{
		Context.MainTask->EnterProgressFrame();

		auto& Change = ModifiedFiles[Index];
		const FString FullFilename = Cache.GetDirectory() + Change.Filename.Get();

		// Move the asset before reimporting it. We always reimport moved assets to ensure that their import path is up to date
		if (Change.Action == DirectoryWatcher::EFileAction::Moved)
		{
			const FString OldFilename = Cache.GetDirectory() + Change.MovedFromFilename.Get();
			const auto Assets = Utils::FindAssetsPertainingToFile(*Registry, OldFilename);

			if (Assets.Num() == 1)
			{
				UObject* Asset = Assets[0].GetAsset();
				if (Asset && Utils::ExtractSourceFilePaths(Asset).Num() == 1)
				{
					UPackage* ExistingPackage = Asset->GetOutermost();

					const bool bAssetWasDirty = IsAssetDirty(Asset);

					const FString NewAssetName = ObjectTools::SanitizeObjectName(FPaths::GetBaseFilename(Change.Filename.Get()));
					const FString PackagePath = PackageTools::SanitizePackageName(MountedContentPath / FPaths::GetPath(Change.Filename.Get()));
					const FString FullDestPath = PackagePath / NewAssetName;

					if (ExistingPackage && ExistingPackage->FileName.ToString() == FullDestPath)
					{
						// No need to process this asset - it's already been moved to the right location
						Cache.CompleteTransaction(MoveTemp(Change));
						continue;
					}

					const FText SrcPathText = FText::FromString(Assets[0].PackageName.ToString()),
						DstPathText = FText::FromString(FullDestPath);

					if (FPackageName::DoesPackageExist(*FullDestPath))
					{
						Context.AddMessage(EMessageSeverity::Warning, FText::Format(LOCTEXT("MoveWarning_ExistingAsset", "Can't move {0} to {1} - one already exists."), SrcPathText, DstPathText));
					}
					else
					{
						TArray<FAssetRenameData> RenameData;
						RenameData.Emplace(Asset, PackagePath, NewAssetName);

						Context.AddMessage(EMessageSeverity::Info, FText::Format(LOCTEXT("Success_MovedAsset", "Moving asset {0} to {1}."),	SrcPathText, DstPathText));

						FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools").Get().RenameAssets(RenameData);

						TArray<FString> Filenames;
						Filenames.Add(FullFilename);

						// Update the reimport file names
						FReimportManager::Instance()->UpdateReimportPaths(Asset, Filenames);
						Asset->MarkPackageDirty();

						if (!bAssetWasDirty)
						{
							OutPackagesToSave.Add(Asset->GetOutermost());
						}
					}
				}
			}
		}
		else
		{
			// Modifications or additions are treated the same by this point
			for (const auto& AssetData : Utils::FindAssetsPertainingToFile(*Registry, FullFilename))
			{
				if (UObject* Asset = AssetData.GetAsset())
				{
					ReimportAsset(Asset, FullFilename, OutPackagesToSave, Context);
				}
			}
		}

		// Let the cache know that we've dealt with this change
		Cache.CompleteTransaction(MoveTemp(Change));

		if (TimeLimit.Exceeded())
		{
			ModifiedFiles.RemoveAt(0, Index + 1);
			return;
		}
	}

	ModifiedFiles.Empty();
}
Example #21
0
	FLongPackagePathsSingleton()
	{
		EngineRootPath = TEXT("/Engine/");
		GameRootPath   = TEXT("/Game/");
		ScriptRootPath = TEXT("/Script/");
		TempRootPath   = TEXT("/Temp/");

		EngineContentPath      = FPaths::EngineContentDir();
		ContentPathShort       = TEXT("../../Content/");
		EngineShadersPath      = FPaths::EngineDir() / TEXT("Shaders/");
		EngineShadersPathShort = TEXT("../../Shaders/");
		GameContentPath        = FPaths::GameContentDir();
		GameScriptPath         = FPaths::GameDir() / TEXT("Script/");
		GameSavedPath          = FPaths::GameSavedDir();

		FString RebasedGameDir = FString::Printf(TEXT("../../../%s/"), GGameName);

        GameContentPathRebased = RebasedGameDir / TEXT("Content/");
        GameScriptPathRebased  = RebasedGameDir / TEXT("Script/");
        GameSavedPathRebased   = RebasedGameDir / TEXT("Saved/");
		
		ContentPathToRoot.Empty(10);
		ContentPathToRoot.Emplace(EngineRootPath, EngineContentPath);
#if IS_MONOLITHIC
		ContentPathToRoot.Emplace(GameRootPath,   ContentPathShort);
#else
		ContentPathToRoot.Emplace(EngineRootPath, ContentPathShort);
#endif
		ContentPathToRoot.Emplace(EngineRootPath, EngineShadersPath);
		ContentPathToRoot.Emplace(EngineRootPath, EngineShadersPathShort);
		ContentPathToRoot.Emplace(GameRootPath,   GameContentPath);
		ContentPathToRoot.Emplace(ScriptRootPath, GameScriptPath);
		ContentPathToRoot.Emplace(TempRootPath,   GameSavedPath);
		ContentPathToRoot.Emplace(GameRootPath,   GameContentPathRebased);
		ContentPathToRoot.Emplace(ScriptRootPath, GameScriptPathRebased);
		ContentPathToRoot.Emplace(TempRootPath,   GameSavedPathRebased);


		ContentRootToPath.Empty(8);
		ContentRootToPath.Emplace(EngineRootPath, EngineContentPath);
		ContentRootToPath.Emplace(EngineRootPath, EngineShadersPath);
		ContentRootToPath.Emplace(GameRootPath,   GameContentPath);
		ContentRootToPath.Emplace(ScriptRootPath, GameScriptPath);
		ContentRootToPath.Emplace(TempRootPath,   GameSavedPath);
		ContentRootToPath.Emplace(GameRootPath,   GameContentPathRebased);
		ContentRootToPath.Emplace(ScriptRootPath, GameScriptPathRebased);
		ContentRootToPath.Emplace(TempRootPath,   GameSavedPathRebased);


		// Allow the plugin manager to mount new content paths by exposing access through a delegate.  PluginManager is 
		// a Core class, but content path functionality is added at the CoreUObject level.
		IPluginManager::Get().SetRegisterMountPointDelegate( IPluginManager::FRegisterMountPointDelegate::CreateStatic( &FPackageName::RegisterMountPoint ) );
	}
void FEngineAnalytics::Initialize()
{
	checkf(!bIsInitialized, TEXT("FEngineAnalytics::Initialize called more than once."));

	check(GEngine);

	// this will only be true for builds that have editor support (currently PC, Mac, Linux)
	// The idea here is to only send editor events for actual editor runs, not for things like -game runs of the editor.
	const bool bIsEditorRun = WITH_EDITOR && GIsEditor && !IsRunningCommandlet();

	// We also want to identify a real run of a game, which is NOT necessarily the opposite of an editor run.
	// Ideally we'd be able to tell explicitly, but with content-only games, it becomes difficult.
	// So we ensure we are not an editor run, we don't have EDITOR stuff compiled in, we are not running a commandlet,
	// we are not a generic, utility program, and we require cooked data.
	const bool bIsGameRun = !WITH_EDITOR && !IsRunningCommandlet() && !FPlatformProperties::IsProgram() && FPlatformProperties::RequiresCookedData();

	const bool bShouldInitAnalytics = bIsEditorRun || bIsGameRun;

	// Outside of the editor, the only engine analytics usage is the hardware survey
	bShouldSendUsageEvents = bIsEditorRun 
		? GEngine->AreEditorAnalyticsEnabled() 
		: bIsGameRun 
			? GEngine->bHardwareSurveyEnabled 
			: false;

	if (bShouldInitAnalytics)
	{
		{
			// Setup some default engine analytics if there is nothing custom bound
			FAnalytics::FProviderConfigurationDelegate DefaultEngineAnalyticsConfig;
			DefaultEngineAnalyticsConfig.BindLambda( 
				[=]( const FString& KeyName, bool bIsValueRequired ) -> FString
				{
					static TMap<FString, FString> ConfigMap;
					if (ConfigMap.Num() == 0)
					{
						ConfigMap.Add(TEXT("ProviderModuleName"), TEXT("AnalyticsET"));
						ConfigMap.Add(TEXT("APIServerET"), TEXT("http://etsource.epicgames.com/ET2/"));

						// We always use the "Release" analytics account unless we're running in analytics test mode (usually with
						// a command-line parameter), or we're an internal Epic build
						const FAnalytics::BuildType AnalyticsBuildType = FAnalytics::Get().GetBuildType();
						const bool bUseReleaseAccount =
							(AnalyticsBuildType == FAnalytics::Development || AnalyticsBuildType == FAnalytics::Release) &&
							!FEngineBuildSettings::IsInternalBuild();	// Internal Epic build
						const TCHAR* BuildTypeStr = bUseReleaseAccount ? TEXT("Release") : TEXT("Dev");
						const TCHAR* UE4TypeStr = FRocketSupport::IsRocket() ? TEXT("Rocket") : FEngineBuildSettings::IsPerforceBuild() ? TEXT("Perforce") : TEXT("UnrealEngine");
						if (bIsEditorRun)
						{
							ConfigMap.Add(TEXT("APIKeyET"), FString::Printf(TEXT("UEEditor.%s.%s"), UE4TypeStr, BuildTypeStr));
						}
						else
						{
							const UGeneralProjectSettings& ProjectSettings = *GetDefault<UGeneralProjectSettings>();
							ConfigMap.Add(TEXT("APIKeyET"), FString::Printf(TEXT("UEGame.%s.%s|%s|%s"), UE4TypeStr, BuildTypeStr, *ProjectSettings.ProjectID.ToString(), *ProjectSettings.ProjectName));
						}
					}

					// Check for overrides
					if( GetEngineAnalyticsOverrideConfigDelegate().IsBound() )
					{
						const FString OverrideValue = GetEngineAnalyticsOverrideConfigDelegate().Execute( KeyName, bIsValueRequired );
						if( !OverrideValue.IsEmpty() )
						{
							return OverrideValue;
						}
					}

					FString* ConfigValue = ConfigMap.Find(KeyName);
					return ConfigValue != NULL ? *ConfigValue : TEXT("");
				} );

			// Connect the engine analytics provider (if there is a configuration delegate installed)
			Analytics = FAnalytics::Get().CreateAnalyticsProvider(
				FName(*DefaultEngineAnalyticsConfig.Execute(TEXT("ProviderModuleName"), true)), 
				DefaultEngineAnalyticsConfig);
			if (Analytics.IsValid())
			{
				Analytics->SetUserID(FString::Printf(TEXT("%s|%s|%s"), *FPlatformMisc::GetMachineId().ToString(EGuidFormats::Digits).ToLower(), *FPlatformMisc::GetEpicAccountId(), *FPlatformMisc::GetOperatingSystemId()));

				TArray<FAnalyticsEventAttribute> StartSessionAttributes;
				GEngine->CreateStartupAnalyticsAttributes( StartSessionAttributes );
				// Add project info whether we are in editor or game.
				const UGeneralProjectSettings& ProjectSettings = *GetDefault<UGeneralProjectSettings>();
				StartSessionAttributes.Emplace(TEXT("ProjectName"), ProjectSettings.ProjectName);
				StartSessionAttributes.Emplace(TEXT("ProjectID"), ProjectSettings.ProjectID);
				StartSessionAttributes.Emplace(TEXT("ProjectDescription"), ProjectSettings.Description);
				StartSessionAttributes.Emplace(TEXT("ProjectVersion"), ProjectSettings.ProjectVersion);

				Analytics->StartSession( StartSessionAttributes );
			}
		}
	}
	bIsInitialized = true;
}
	FExpressionResult Evaluate(const TArray<FCompiledToken>& CompiledTokens, const IOperatorEvaluationEnvironment& InEnvironment)
	{
		// Evaluation strategy: the supplied compiled tokens are const. To avoid copying the whole array, we store a separate array of
		// any tokens that are generated at runtime by the evaluator. The operand stack will consist of indices into either the CompiledTokens
		// array, or the RuntimeGeneratedTokens (where Index >= CompiledTokens.Num())
		TArray<FExpressionToken> RuntimeGeneratedTokens;
		TArray<int32> OperandStack;

		/** Get the token pertaining to the specified operand index */
		auto GetToken = [&](int32 Index) -> const FExpressionToken& {
			if (Index < CompiledTokens.Num())
			{
				return CompiledTokens[Index];
			}

			return RuntimeGeneratedTokens[Index - CompiledTokens.Num()];
		};

		/** Add a new token to the runtime generated array */
		auto AddToken = [&](FExpressionToken&& In) -> int32 {
			auto Index = CompiledTokens.Num() + RuntimeGeneratedTokens.Num();
			RuntimeGeneratedTokens.Emplace(MoveTemp(In));
			return Index;
		};


		for (int32 Index = 0; Index < CompiledTokens.Num(); ++Index)
		{
			const auto& Token = CompiledTokens[Index];

			switch(Token.Type)
			{
			case FCompiledToken::Benign:
				continue;

			case FCompiledToken::Operand:
				OperandStack.Push(Index);
				continue;

			case FCompiledToken::BinaryOperator:
				if (OperandStack.Num() >= 2)
				{
					// Binary
					const auto& R = GetToken(OperandStack.Pop());
					const auto& L = GetToken(OperandStack.Pop());

					auto OpResult = InEnvironment.ExecBinary(Token, L, R);
					if (OpResult.IsValid())
					{
						// Inherit the LHS context
						OperandStack.Push(AddToken(FExpressionToken(L.Context, MoveTemp(OpResult.GetValue()))));
					}
					else
					{
						return MakeError(OpResult.GetError());
					}
				}
				else
				{
					FFormatOrderedArguments Args;
					Args.Add(FText::FromString(Token.Context.GetString()));
					return MakeError(FText::Format(LOCTEXT("SyntaxError_NotEnoughOperandsBinary", "Not enough operands for binary operator {0}"), Args));
				}
				break;
			
			case FCompiledToken::PostUnaryOperator:
			case FCompiledToken::PreUnaryOperator:

				if (OperandStack.Num() >= 1)
				{
					const auto& Operand = GetToken(OperandStack.Pop());

					FExpressionResult OpResult = (Token.Type == FCompiledToken::PreUnaryOperator) ?
						InEnvironment.ExecPreUnary(Token, Operand) :
						InEnvironment.ExecPostUnary(Token, Operand);

					if (OpResult.IsValid())
					{
						// Inherit the LHS context
						OperandStack.Push(AddToken(FExpressionToken(Operand.Context, MoveTemp(OpResult.GetValue()))));
					}
					else
					{
						return MakeError(OpResult.GetError());
					}			
				}
				else
				{
					FFormatOrderedArguments Args;
					Args.Add(FText::FromString(Token.Context.GetString()));
					return MakeError(FText::Format(LOCTEXT("SyntaxError_NoUnaryOperand", "No operand for unary operator {0}"), Args));
				}
				break;
			}
		}

		if (OperandStack.Num() == 1)
		{
			return MakeValue(GetToken(OperandStack[0]).Node.Copy());
		}

		return MakeError(LOCTEXT("SyntaxError_InvalidExpression", "Could not evaluate expression"));
	}
	TOptional<FExpressionError> CompileGroup(const FExpressionToken* GroupStart, const FGuid* StopAt)
	{
		enum class EState { PreUnary, PostUnary, Binary };

		TArray<FWrappedOperator> OperatorStack;
		OperatorStack.Reserve(Tokens.Num() - CurrentTokenIndex);

		bool bFoundEndOfGroup = StopAt == nullptr;

		// Start off looking for a unary operator
		EState State = EState::PreUnary;
		for (; CurrentTokenIndex < Tokens.Num(); ++CurrentTokenIndex)
		{
			auto& Token = Tokens[CurrentTokenIndex];
			const auto& TypeId = Token.Node.GetTypeId();

			if (const FGuid* GroupingEnd = Grammar.GetGrouping(TypeId))
			{
				// Ignore this token
				CurrentTokenIndex++;

				// Start of group - recurse
				auto Error = CompileGroup(&Token, GroupingEnd);

				if (Error.IsSet())
				{
					return Error;
				}

				State = EState::PostUnary;
			}
			else if (StopAt && TypeId == *StopAt)
			{
				// End of group
				bFoundEndOfGroup = true;
				break;
			}
			else if (State == EState::PreUnary)
			{
				if (Grammar.HasPreUnaryOperator(TypeId))
				{
					// Make this a unary op
					OperatorStack.Emplace(FCompiledToken(FCompiledToken::PreUnaryOperator, MoveTemp(Token)));
				}
				else if (Grammar.GetBinaryOperatorPrecedence(TypeId))
				{
					return FExpressionError(FText::Format(LOCTEXT("SyntaxError_NoBinaryOperand", "Syntax error: No operand specified for operator '{0}'"), FText::FromString(Token.Context.GetString())));
				}
				else if (Grammar.HasPostUnaryOperator(TypeId))
				{
					// Found a post-unary operator for the preceeding token
					State = EState::PostUnary;

					// Pop off any pending unary operators
					while (OperatorStack.Num() > 0 && OperatorStack.Last().Precedence <= 0)
					{
						Commands.Add(OperatorStack.Pop(false).Steal());
					}

					// Make this a post-unary op
					OperatorStack.Emplace(FCompiledToken(FCompiledToken::PostUnaryOperator, MoveTemp(Token)));
				}
				else
				{
					// Not an operator, so treat it as an ordinary token
					Commands.Add(FCompiledToken(FCompiledToken::Operand, MoveTemp(Token)));
					State = EState::PostUnary;
				}
			}
			else if (State == EState::PostUnary)
			{
				if (Grammar.HasPostUnaryOperator(TypeId))
				{
					// Pop off any pending unary operators
					while (OperatorStack.Num() > 0 && OperatorStack.Last().Precedence <= 0)
					{
						Commands.Add(OperatorStack.Pop(false).Steal());
					}

					// Make this a post-unary op
					OperatorStack.Emplace(FCompiledToken(FCompiledToken::PostUnaryOperator, MoveTemp(Token)));
				}
				else
				{
					// Checking for binary operators
					if (const int32* Prec = Grammar.GetBinaryOperatorPrecedence(TypeId))
					{
						// Pop off anything of higher precedence than this one onto the command stack
						while (OperatorStack.Num() > 0 && OperatorStack.Last().Precedence < *Prec)
						{
							Commands.Add(OperatorStack.Pop(false).Steal());
						}

						// Add the operator itself to the op stack
						OperatorStack.Emplace(FCompiledToken(FCompiledToken::BinaryOperator, MoveTemp(Token)), *Prec);

						// Check for a unary op again
						State = EState::PreUnary;
					}
					else
					{
						// Just add the token. It's possible that this is a syntax error (there's no binary operator specified between two tokens),
						// But we don't have enough information at this point to say whether or not it is an error
						Commands.Add(FCompiledToken(FCompiledToken::Operand, MoveTemp(Token)));
						State = EState::PreUnary;
					}
				}
			}
		}

		if (!bFoundEndOfGroup)
		{
			return FExpressionError(FText::Format(LOCTEXT("SyntaxError_UnmatchedGroup", "Syntax error: Reached end of expression before matching end of group '{0}' at line {1}:{2}"),
				FText::FromString(GroupStart->Context.GetString()),
				FText::AsNumber(GroupStart->Context.GetLineNumber()),
				FText::AsNumber(GroupStart->Context.GetCharacterIndex())
			));
		}

		// Pop everything off the operator stack, onto the command stack
		while (OperatorStack.Num() > 0)
		{
			Commands.Add(OperatorStack.Pop(false).Token);
		}

		return TOptional<FExpressionError>();
	}
// Reads a set of specifiers (with optional values) inside the () of a new-style metadata macro like UPROPERTY or UFUNCTION
void FBaseParser::ReadSpecifierSetInsideMacro(TArray<FPropertySpecifier>& SpecifiersFound, const FString& TypeOfSpecifier, TMap<FName, FString>& MetaData)
{
	int32 FoundSpecifierCount = 0;
	FString ErrorMessage = FString::Printf(TEXT("%s declaration specifier"), *TypeOfSpecifier);

	RequireSymbol(TEXT("("), *ErrorMessage);

	while (!MatchSymbol(TEXT(")")))
	{
		if (FoundSpecifierCount > 0)
		{
			RequireSymbol(TEXT(","), *ErrorMessage);
		}
		++FoundSpecifierCount;

		// Read the specifier key
		FToken Specifier;
		if (!GetToken(Specifier))
		{
			FError::Throwf(TEXT("Expected %s"), *ErrorMessage);
		}

		if (Specifier.Matches(TEXT("meta")))
		{
			RequireSymbol(TEXT("="), *ErrorMessage);
			RequireSymbol(TEXT("("), *ErrorMessage);

			// Keep reading comma-separated metadata pairs
			do 
			{
				// Read a key
				FToken MetaKeyToken;
				if (!GetIdentifier(MetaKeyToken))
				{
					FError::Throwf(TEXT("Expected a metadata key"));
				}

				FString Key = MetaKeyToken.Identifier;

				// Potentially read a value
				FString Value;
				if (MatchSymbol(TEXT("=")))
				{
					Value = ReadNewStyleValue(TypeOfSpecifier);
				}

				// Validate the value is a valid type for the key and insert it into the map
				InsertMetaDataPair(MetaData, Key, Value);
			} while ( MatchSymbol(TEXT(",")) );

			RequireSymbol(TEXT(")"), *ErrorMessage);
		}
		// Look up specifier in metadata dictionary
		else if (FMetadataKeyword* MetadataKeyword = GetMetadataKeyword(Specifier.Identifier))
		{
			if (MatchSymbol(TEXT("=")))
			{
				if (MetadataKeyword->ValueArgument == EMetadataValueArgument::None)
				{
					FError::Throwf(TEXT("Incorrect = after metadata specifier '%s'"), Specifier.Identifier);
				}

				FString Value = ReadNewStyleValue(TypeOfSpecifier);
				MetadataKeyword->ApplyToMetadata(MetaData, &Value);
			}
			else
			{
				if (MetadataKeyword->ValueArgument == EMetadataValueArgument::Required)
				{
					FError::Throwf(TEXT("Missing = after metadata specifier '%s'"), Specifier.Identifier);
				}

				MetadataKeyword->ApplyToMetadata(MetaData);
			}
		}
		else
		{
			// Creating a new specifier
			SpecifiersFound.Emplace(Specifier.Identifier);

			// Look for a value for this specifier
			if (MatchSymbol(TEXT("=")) || PeekSymbol(TEXT("(")))
			{
				TArray<FString>& NewPairValues = SpecifiersFound.Last().Values;
				if (!ReadOptionalCommaSeparatedListInParens(NewPairValues, TypeOfSpecifier))
				{
					FString Value = ReadNewStyleValue(TypeOfSpecifier);
					NewPairValues.Add(Value);
				}
			}
		}
	}
}
Example #26
0
void UtilitySystem::finishPrint(FString str)
{
  str.Trim();
  str.Shrink();
  FStrPrintArray.Emplace(str);
}
	void Pointify(const FInterpCurveVector& SplineInfo, TArray<FLandscapeSplineInterpPoint>& Points, int32 NumSubdivisions,
		float StartFalloffFraction, float EndFalloffFraction,
		const float StartWidth, const float EndWidth,
		const float StartSideFalloff, const float EndSideFalloff,
		const float StartRollDegrees, const float EndRollDegrees)
	{
		// Stop the start and end fall-off overlapping
		const float TotalFalloff = StartFalloffFraction + EndFalloffFraction;
		if (TotalFalloff > 1.0f)
		{
			StartFalloffFraction /= TotalFalloff;
			EndFalloffFraction /= TotalFalloff;
		}

		const float StartRoll = FMath::DegreesToRadians(StartRollDegrees);
		const float EndRoll = FMath::DegreesToRadians(EndRollDegrees);

		float OldKeyTime = 0;
		for (int32 i = 0; i < SplineInfo.Points.Num(); i++)
		{
			const float NewKeyTime = SplineInfo.Points[i].InVal;
			const float NewKeyCosInterp = 0.5f - 0.5f * FMath::Cos(NewKeyTime * PI);
			const float NewKeyWidth = FMath::Lerp(StartWidth, EndWidth, NewKeyCosInterp);
			const float NewKeyFalloff = FMath::Lerp(StartSideFalloff, EndSideFalloff, NewKeyCosInterp);
			const float NewKeyRoll = FMath::Lerp(StartRoll, EndRoll, NewKeyCosInterp);
			const FVector NewKeyPos = SplineInfo.Eval(NewKeyTime, FVector::ZeroVector);
			const FVector NewKeyTangent = SplineInfo.EvalDerivative(NewKeyTime, FVector::ZeroVector).GetSafeNormal();
			const FVector NewKeyBiNormal = FQuat(NewKeyTangent, -NewKeyRoll).RotateVector((NewKeyTangent ^ FVector(0, 0, -1)).GetSafeNormal());
			const FVector NewKeyLeftPos = NewKeyPos - NewKeyBiNormal * NewKeyWidth;
			const FVector NewKeyRightPos = NewKeyPos + NewKeyBiNormal * NewKeyWidth;
			const FVector NewKeyFalloffLeftPos = NewKeyPos - NewKeyBiNormal * (NewKeyWidth + NewKeyFalloff);
			const FVector NewKeyFalloffRightPos = NewKeyPos + NewKeyBiNormal * (NewKeyWidth + NewKeyFalloff);
			const float NewKeyStartEndFalloff = FMath::Min((StartFalloffFraction > 0 ? NewKeyTime / StartFalloffFraction : 1.0f), (EndFalloffFraction > 0 ? (1 - NewKeyTime) / EndFalloffFraction : 1.0f));

			// If not the first keypoint, interp from the last keypoint.
			if (i > 0)
			{
				const int32 NumSteps = FMath::CeilToInt((NewKeyTime - OldKeyTime) * NumSubdivisions);
				const float DrawSubstep = (NewKeyTime - OldKeyTime) / NumSteps;

				// Add a point for each substep, except the ends because that's the point added outside the interp'ing.
				for (int32 j = 1; j < NumSteps; j++)
				{
					const float NewTime = OldKeyTime + j*DrawSubstep;
					const float NewCosInterp = 0.5f - 0.5f * FMath::Cos(NewTime * PI);
					const float NewWidth = FMath::Lerp(StartWidth, EndWidth, NewCosInterp);
					const float NewFalloff = FMath::Lerp(StartSideFalloff, EndSideFalloff, NewCosInterp);
					const float NewRoll = FMath::Lerp(StartRoll, EndRoll, NewCosInterp);
					const FVector NewPos = SplineInfo.Eval(NewTime, FVector::ZeroVector);
					const FVector NewTangent = SplineInfo.EvalDerivative(NewTime, FVector::ZeroVector).GetSafeNormal();
					const FVector NewBiNormal = FQuat(NewTangent, -NewRoll).RotateVector((NewTangent ^ FVector(0, 0, -1)).GetSafeNormal());
					const FVector NewLeftPos = NewPos - NewBiNormal * NewWidth;
					const FVector NewRightPos = NewPos + NewBiNormal * NewWidth;
					const FVector NewFalloffLeftPos = NewPos - NewBiNormal * (NewWidth + NewFalloff);
					const FVector NewFalloffRightPos = NewPos + NewBiNormal * (NewWidth + NewFalloff);
					const float NewStartEndFalloff = FMath::Min((StartFalloffFraction > 0 ? NewTime / StartFalloffFraction : 1.0f), (EndFalloffFraction > 0 ? (1 - NewTime) / EndFalloffFraction : 1.0f));

					Points.Emplace(NewPos, NewLeftPos, NewRightPos, NewFalloffLeftPos, NewFalloffRightPos, NewStartEndFalloff);
				}
			}

			Points.Emplace(NewKeyPos, NewKeyLeftPos, NewKeyRightPos, NewKeyFalloffLeftPos, NewKeyFalloffRightPos, NewKeyStartEndFalloff);

			OldKeyTime = NewKeyTime;
		}

		// Handle self-intersection errors due to tight turns
		FixSelfIntersection(Points, &FLandscapeSplineInterpPoint::Left);
		FixSelfIntersection(Points, &FLandscapeSplineInterpPoint::Right);
		FixSelfIntersection(Points, &FLandscapeSplineInterpPoint::FalloffLeft);
		FixSelfIntersection(Points, &FLandscapeSplineInterpPoint::FalloffRight);
	}