Merge UE5/Release-Engine-Staging @ CL# 15299266 to UE5/Main

This represents UE4/Main @ CL# 15277572

[CL 15299962 by Marc Audy in ue5-main branch]
This commit is contained in:
Marc Audy
2021-02-03 14:57:28 -04:00
parent 3a91f64f60
commit cac1fe0019
9583 changed files with 96500 additions and 1575537 deletions
@@ -99,6 +99,9 @@
#include "BlueprintTypePromotion.h"
#include "K2Node_PromotableOperator.h"
#include "Editor/EditorPerProjectUserSettings.h"
#include "BlueprintPaletteFavorites.h"
//////////////////////////////////////////////////////////////////////////
// FBlueprintMetadata
@@ -7381,6 +7384,319 @@ bool UEdGraphSchema_K2::SafeDeleteNodeFromGraph(UEdGraph* Graph, UEdGraphNode* N
return true;
}
#if WITH_EDITORONLY_DATA
//////////////////////////////////////////////////////////////////////////
/** CVars for tweaking how the blueprint context menu search picks the best match */
namespace ContextMenuConsoleVariables
{
/** Increasing this weight will make shorter words preferred */
static float ShorterWeight = 15.0f;
static FAutoConsoleVariableRef CVarShorterWeight(
TEXT("ContextMenu.ShorterWeight"), ShorterWeight,
TEXT("Increasing this weight will make shorter words preferred"),
ECVF_Default);
/** Increasing this will prefer whole percentage matches when comparing the keyword to what the user has typed in */
static float PercentageMatchWeightMultiplier = 1.0f;
static FAutoConsoleVariableRef CVarPercentageMatchWeightMultiplier(
TEXT("ContextMenu.PercentageMatchWeightMultiplier"), PercentageMatchWeightMultiplier,
TEXT("A multiplier for how much weight to give something based on the percentage match it is"),
ECVF_Default);
/** How much weight the description of actions have */
static float DescriptionWeight = 10.0f;
static FAutoConsoleVariableRef CVarDescriptionWeight(
TEXT("ContextMenu.DescriptionWeight"), DescriptionWeight,
TEXT("The amount of weight placed on search items description"),
ECVF_Default);
/** Weight used to prefer categories that are the same as the node that was dragged off of */
static float MatchingFromPinCategory = 500.0f;
static FAutoConsoleVariableRef CVarMatchingFromPinCategory(
TEXT("ContextMenu.MatchingFromPinCategory"), MatchingFromPinCategory,
TEXT("The amount of weight placed on actions with the same category as the node being dragged off of"),
ECVF_Default);
/** Weight that a match to a category search has */
static float CategoryWeight = 5.0f;
static FAutoConsoleVariableRef CVarCategoryWeight(
TEXT("ContextMenu.CategoryWeight"), CategoryWeight,
TEXT("The amount of weight placed on categories that match what the user has typed in"),
ECVF_Default);
/** How much weight the node's title has */
static float NodeTitleWeight = 5.0f;
static FAutoConsoleVariableRef CVarNodeTitleWeight(
TEXT("ContextMenu.NodeTitleWeight"), NodeTitleWeight,
TEXT("The amount of weight placed on the search items title"),
ECVF_Default);
/** Weight used to prefer keywords of actions */
static float KeywordWeight = 30.0f;
static FAutoConsoleVariableRef CVarKeywordWeight(
TEXT("ContextMenu.KeywordWeight"), KeywordWeight,
TEXT("The amount of weight placed on search items keyword"),
ECVF_Default);
/** The multiplier given if the keyword starts with a letter the user typed in */
static float StartsWithBonusWeightMultiplier = 5.0f;
static FAutoConsoleVariableRef CVarStartsWithBonusWeightMultiplier(
TEXT("ContextMenu.StartsWithBonusWeightMultiplier"), StartsWithBonusWeightMultiplier,
TEXT("The multiplier given if the keyword starts with a letter the user typed in"),
ECVF_Default);
/** The multiplier given if the keyword starts with a letter the user typed in */
static float WordContainsLetterWeightMultiplier = 0.5f;
static FAutoConsoleVariableRef CVarWordContainsLetterWeightMultiplier(
TEXT("ContextMenu.WordContainsLetterWeightMultiplier"), WordContainsLetterWeightMultiplier,
TEXT("The multiplier given if the keyword only contains a letter the user typed in"),
ECVF_Default);
/** The bonus given if node is a favorite */
static float FavoriteBonus = 1000.0f;
static FAutoConsoleVariableRef CVarWordContainsLetterFavoriteBonus(
TEXT("ContextMenu.FavoriteBonus"), FavoriteBonus,
TEXT("The bonus given if node is a favorite"),
ECVF_Default);
/** Enabling the debug printing of context menu selections */
static bool bPrintDebugContextSelection = false;
static FAutoConsoleVariableRef CVarPrintDebugContextSelection(
TEXT("ContextMenu.bPrintDebugContextSelection"), bPrintDebugContextSelection,
TEXT("Flag for printing the debug info about the context menu selection"),
ECVF_Default);
}; // namespace ContextMenuConsoleVariables
/**
* Debug Info about how the preferred context menu action is chosen
* @see SGraphActionMenu::GetActionFilteredWeight
*/
struct FContextMenuWeightDebugInfo
{
float TotalWeight = 0.0f;
// Info about which sets of words match up with what weight
float KeywordArrayWeight = 0.0f;
float DescriptionWeight = 0.0f;
float NodeTitleWeight = 0.0f;
float CategoryWeight = 0.0f;
float FavoriteBonusWeight = 0.0f;
float PercentageMatchWeight = 0.0f;
/** The calculated match percentage */
float PercMatch = 0.0f;
float ShorterWeight = 0.0f;
float CategoryBonusWieight = 0.0f;
/**
* Print out the debug info about this weight info to the console
*/
void Print()
{
UE_LOG(LogTemp, Warning, TEXT("[Weight Debug info] \
TotalWeight: %-8.2f | PercentageMatchWeight: %-8.2f | PercMatch: %-8.2f | ShorterWeight: %-8.2f | CategoryBonusWeight: %-8.2f | KeywordArrayWeight: %-8.2f | DescriptionWeight: %-8.2f | NodeTitleWeight: %-8.2f | CategoryWeight: %-8.2f | Fav. Bonus:%-8.2f\n"),
TotalWeight, PercentageMatchWeight, PercMatch, ShorterWeight, CategoryBonusWieight, KeywordArrayWeight, DescriptionWeight, NodeTitleWeight, CategoryWeight, FavoriteBonusWeight);
}
};
float UEdGraphSchema_K2::GetActionFilteredWeight(const FGraphActionListBuilderBase::ActionGroup& InCurrentAction, const TArray<FString>& InFilterTerms, const TArray<FString>& InSanitizedFilterTerms, const TArray<UEdGraphPin*>& DraggedFromPins) const
{
// The overall 'weight' of this action
float TotalWeight = 0.0f;
// Helper array for tracking actions and the weight that they have added
struct FArrayWithWeight
{
FArrayWithWeight(const TArray< FString >* InArray, float InWeightModifier, float* OutDebugWeight)
: Array(InArray)
, OutWeight(OutDebugWeight)
, WeightModifier(InWeightModifier)
{
}
const TArray< FString >* Array = nullptr;
float* OutWeight = nullptr;
float WeightModifier = 0.0f;
};
// Setup an array of arrays so we can do a weighted search
TArray< FArrayWithWeight > WeightedArrayList;
FContextMenuWeightDebugInfo OutDebugInfo;
const bool bIsFromDrag = (DraggedFromPins.Num() > 0);
int32 Action = 0;
if (InCurrentAction.Actions[Action].IsValid() == true)
{
TSharedPtr<FEdGraphSchemaAction> CurrentAction = InCurrentAction.Actions[Action];
// Combine the actions string, separate with \n so terms don't run into each other, and remove the spaces (incase the user is searching for a variable)
// In the case of groups containing multiple actions, they will have been created and added at the same place in the code, using the same description
// and keywords, so we only need to use the first one for filtering.
const FString& SearchText = InCurrentAction.GetSearchTextForFirstAction();
// First the localized keywords
WeightedArrayList.Add(FArrayWithWeight(&InCurrentAction.GetLocalizedSearchKeywordsArrayForFirstAction(), ContextMenuConsoleVariables::KeywordWeight, &OutDebugInfo.KeywordArrayWeight));
// The localized description
WeightedArrayList.Add(FArrayWithWeight(&InCurrentAction.GetLocalizedMenuDescriptionArrayForFirstAction(), ContextMenuConsoleVariables::DescriptionWeight, &OutDebugInfo.DescriptionWeight));
// The node search localized title weight
WeightedArrayList.Add(FArrayWithWeight(&InCurrentAction.GetLocalizedSearchTitleArrayForFirstAction(), ContextMenuConsoleVariables::NodeTitleWeight, &OutDebugInfo.NodeTitleWeight));
// The localized category
WeightedArrayList.Add(FArrayWithWeight(&InCurrentAction.GetLocalizedSearchCategoryArrayForFirstAction(), ContextMenuConsoleVariables::CategoryWeight, &OutDebugInfo.CategoryWeight));
// First the keywords
WeightedArrayList.Add(FArrayWithWeight(&InCurrentAction.GetSearchKeywordsArrayForFirstAction(), ContextMenuConsoleVariables::KeywordWeight, &OutDebugInfo.KeywordArrayWeight));
// The description
WeightedArrayList.Add(FArrayWithWeight(&InCurrentAction.GetMenuDescriptionArrayForFirstAction(), ContextMenuConsoleVariables::DescriptionWeight, &OutDebugInfo.DescriptionWeight));
// The node search title weight
WeightedArrayList.Add(FArrayWithWeight(&InCurrentAction.GetSearchTitleArrayForFirstAction(), ContextMenuConsoleVariables::NodeTitleWeight, &OutDebugInfo.NodeTitleWeight));
// The category
WeightedArrayList.Add(FArrayWithWeight(&InCurrentAction.GetSearchCategoryArrayForFirstAction(), ContextMenuConsoleVariables::CategoryWeight, &OutDebugInfo.CategoryWeight));
// Give a weight bonus to actions whose category matches what was dragged off of
if (bIsFromDrag)
{
const TArray<FString>& InActionCategories = InCurrentAction.GetCategoryChain();
bool bAddMatchBonus = false;
for (const FString& InActionCategory : InActionCategories)
{
for (UEdGraphPin* const FromPin : DraggedFromPins)
{
check(FromPin != nullptr);
// If we can't find anything there, check the subcategory of the object
// This covers most of the more complex struct types (LinearColor, date time, etc)
if (UObject* const SubCatObj = FromPin->PinType.PinSubCategoryObject.Get())
{
const FString& SubCatObjName = SubCatObj->GetFullName();
// The pin SubObjectCategory names don't have any spaces, so split up the category
TArray<FString> DelimitedArray;
InActionCategory.ParseIntoArray(DelimitedArray, TEXT(" "), true);
for (const FString& DelimetedCat : DelimitedArray)
{
if (SubCatObjName.Contains(DelimetedCat))
{
bAddMatchBonus = true;
break;
}
}
}
// Check the category of the pin, this works for basic math types (int, float, byte, etc)
else if (InActionCategory.Contains(FromPin->PinType.PinCategory.ToString()))
{
bAddMatchBonus = true;
}
// If we found match in any cases above then add the weight bonus and stop looking
if (bAddMatchBonus)
{
TotalWeight += ContextMenuConsoleVariables::MatchingFromPinCategory;
OutDebugInfo.CategoryBonusWieight += ContextMenuConsoleVariables::MatchingFromPinCategory;
// Break out of the loop so that we don't give any extra bonuses
break;
}
}
}
}
// If the user has favorite this action, then give it a hefty bonus
const UEditorPerProjectUserSettings& EditorSettings = *GetDefault<UEditorPerProjectUserSettings>();
if (UBlueprintPaletteFavorites* BlueprintFavorites = EditorSettings.BlueprintFavorites)
{
if (BlueprintFavorites->IsFavorited(CurrentAction))
{
TotalWeight += ContextMenuConsoleVariables::FavoriteBonus;
OutDebugInfo.FavoriteBonusWeight += ContextMenuConsoleVariables::FavoriteBonus;
}
}
// Now iterate through all the filter terms and calculate a 'weight' using the values and multipliers
const FString* EachTerm = nullptr;
const FString* EachTermSanitized = nullptr;
// For every filter item the user has typed in (the text in the search bar, seperated by spaces)
for (int32 FilterIndex = 0; FilterIndex < InFilterTerms.Num(); ++FilterIndex)
{
EachTerm = &InFilterTerms[FilterIndex];
EachTermSanitized = &InSanitizedFilterTerms[FilterIndex];
int32 TermLen = EachTerm->Len();
// Now check the weighted lists (We could further improve the hit weight by checking consecutive word matches)
for (int32 iFindCount = 0; iFindCount < WeightedArrayList.Num(); ++iFindCount)
{
const TArray<FString>& KeywordArray = *WeightedArrayList[iFindCount].Array;
float WeightPerList = 0.0f;
float KeywordArrayWeight = WeightedArrayList[iFindCount].WeightModifier;
// Count of how many words in this keyword array contain a filter(letter) that the user has typed in
int32 WordMatchCount = 0;
// The number of characters in this keyword array
int32 KeywordArrayCharLength = 0;
// Loop through every word that the user could be looking for
for (int32 iEachWord = 0; iEachWord < KeywordArray.Num(); ++iEachWord)
{
// Keep track of how long all the words in the array are
KeywordArrayCharLength += KeywordArray[iEachWord].Len();
// If a word contains the letter that the user has typed in, than increment the whole match count
if (KeywordArray[iEachWord].Contains(*EachTermSanitized, ESearchCase::CaseSensitive) || KeywordArray[iEachWord].Contains(*EachTerm, ESearchCase::CaseSensitive))
{
++WordMatchCount;
WeightPerList += KeywordArrayWeight * ContextMenuConsoleVariables::WordContainsLetterWeightMultiplier;
// If the word starts with the letter, give it a little extra boost of weight
if (KeywordArray[iEachWord].StartsWith(*EachTermSanitized, ESearchCase::CaseSensitive) || KeywordArray[iEachWord].StartsWith(*EachTerm, ESearchCase::CaseSensitive))
{
WeightPerList += KeywordArrayWeight * ContextMenuConsoleVariables::StartsWithBonusWeightMultiplier;
}
}
}
// If the user has dragged off of a pin then do not prefer shorter things, because that will result
// in the matching of "Add" for a container instead of "+" for numeric types
if (KeywordArrayCharLength > 0)
{
// How many words that we are checking had partial matches compared to what the user typed in?
float PercMatch = (float)WordMatchCount / (float)KeywordArray.Num();
float PercentageBonus = (WeightPerList * PercMatch * ContextMenuConsoleVariables::PercentageMatchWeightMultiplier);
WeightPerList += PercentageBonus;
// The longer the match is, the more points it loses
float ShortWeight = KeywordArrayCharLength * ContextMenuConsoleVariables::ShorterWeight * (bIsFromDrag ? 0.25f : 1.0f);
WeightPerList -= ShortWeight;
OutDebugInfo.PercMatch += PercMatch;
OutDebugInfo.ShorterWeight -= ShortWeight;
OutDebugInfo.PercentageMatchWeight += PercentageBonus;
}
TotalWeight += WeightPerList;
if (WeightedArrayList[iFindCount].OutWeight)
{
*WeightedArrayList[iFindCount].OutWeight = WeightPerList;
}
}
}
}
OutDebugInfo.TotalWeight = TotalWeight;
return TotalWeight;
}
#endif // WITH_EDITORONLY_DATA
/////////////////////////////////////////////////////
#undef LOCTEXT_NAMESPACE