FGameplayCueTranslationLink& FGameplayCueTranslatorNode::FindOrCreateLink(const UGameplayCueTranslator* RuleClassCDO, int32 LookupSize) { int32 InsertIdx = 0; int32 NewPriority = RuleClassCDO->GetPriority(); #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) if (CVarGameplyCueTranslatorDebugTag->GetString().IsEmpty() == false && this->CachedGameplayTagName.ToString().Contains(CVarGameplyCueTranslatorDebugTag->GetString())) { UE_LOG(LogGameplayCueTranslator, Log, TEXT(".....")); } #endif for (int32 LinkIdx=0; LinkIdx < Links.Num(); ++LinkIdx) { if (Links[LinkIdx].RulesCDO == RuleClassCDO) { // Already here, return return Links[LinkIdx]; } if (Links[LinkIdx].RulesCDO->GetPriority() > NewPriority) { // Insert after the existing one with higher priority InsertIdx = LinkIdx+1; } } check(InsertIdx <= Links.Num()); FGameplayCueTranslationLink& NewLink = Links[Links.Insert(FGameplayCueTranslationLink(), InsertIdx)]; NewLink.RulesCDO = RuleClassCDO; NewLink.NodeLookup.SetNum( LookupSize ); return NewLink; }
FGameplayCueTranslatorNodeIndex FGameplayCueTranslationManager::GetTranslationIndexForName(FName Name, bool CreateIfInvalid) { FGameplayCueTranslatorNodeIndex Idx; if (CreateIfInvalid) { FGameplayCueTranslatorNodeIndex& MapIndex = TranslationNameToIndexMap.FindOrAdd(Name); if (MapIndex.IsValid() == false) { MapIndex = TranslationLUT.AddDefaulted(); } Idx = MapIndex; if (TranslationLUT[Idx].CachedIndex.IsValid() == false) { TranslationLUT[Idx].CachedIndex = Idx; TranslationLUT[Idx].CachedGameplayTag = TagManager->RequestGameplayTag(Name, false); TranslationLUT[Idx].CachedGameplayTagName = Name; } } else { if (FGameplayCueTranslatorNodeIndex* IdxPtr = TranslationNameToIndexMap.Find(Name)) { Idx = *IdxPtr; } } #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) if (Idx.IsValid() && TranslationLUT[Idx].CachedGameplayTagName.ToString().Contains(CVarGameplyCueTranslatorDebugTag->GetString())) { UE_LOG(LogGameplayCueTranslator, Log, TEXT(".....")); } #endif ensureAlways(!Idx.IsValid() || TranslationLUT[Idx].CachedGameplayTagName != NAME_None); #if WITH_EDITOR // In the editor tags can be created after the initial creation of the translation data structures. // This will update the tag in subsequent requests if (Idx.IsValid() && TranslationLUT[Idx].CachedGameplayTag.IsValid() == false) { TranslationLUT[Idx].CachedGameplayTag = TagManager->RequestGameplayTag(Name, false); } #endif return Idx; }
void USignificanceManager::OnShowDebugInfo(AHUD* HUD, UCanvas* Canvas, const FDebugDisplayInfo& DisplayInfo, float& YL, float& YPos) { static const FName NAME_SignificanceManager("SignificanceManager"); if (Canvas && HUD->ShouldDisplayDebug(NAME_SignificanceManager)) { if (HasAnyFlags(RF_ClassDefaultObject)) { if (USignificanceManager* SignificanceManager = Get(HUD->GetWorld())) { SignificanceManager->OnShowDebugInfo(HUD, Canvas, DisplayInfo, YL, YPos); } } else { FDisplayDebugManager& DisplayDebugManager = Canvas->DisplayDebugManager; DisplayDebugManager.SetFont(GEngine->GetSmallFont()); DisplayDebugManager.SetDrawColor(FColor::Red); DisplayDebugManager.DrawString(FString::Printf(TEXT("SIGNIFICANCE MANAGER - %d Managed Objects"), ManagedObjects.Num())); const FName SignificanceManagerTag(*CVarSignificanceManagerFilterTag->GetString()); TArray<const FManagedObjectInfo*> AllObjects; const TArray<const FManagedObjectInfo*>& ObjectsToShow = (SignificanceManagerTag.IsNone() ? AllObjects : GetManagedObjects(SignificanceManagerTag)); if (SignificanceManagerTag.IsNone()) { GetManagedObjects(AllObjects, true); } DisplayDebugManager.SetDrawColor(FColor::White); const int32 NumObjectsToShow = FMath::Min(GSignificanceManagerObjectsToShow, ObjectsToShow.Num()); for (int32 Index = 0; Index < NumObjectsToShow; ++Index) { const FManagedObjectInfo* ObjectInfo = ObjectsToShow[Index]; const FString Str = FString::Printf(TEXT("%6.3f - %s (%s)"), ObjectInfo->GetSignificance(), *ObjectInfo->GetObject()->GetName(), *ObjectInfo->GetTag().ToString()); DisplayDebugManager.DrawString(Str); } } } }
void FGameplayCueTranslationManager::BuildTagTranslationTable_Forward_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 TArray<FName> SwappedNames; SwappedNames.Reserve(10); // Each nameswap rule group for (FNameSwapData& NameSwapData : AllNameSwaps) { // Avoid rule recursion { if (FGameplayCueTranslatorNode* ChildNode = GetTranslationNodeForName(TagName, false)) { if (ChildNode->UsedTranslators.Contains(NameSwapData.ClassCDO)) { continue; } } } // Each swaprule 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 // Each subtag within this GameplayTag for (int32 TagIdx=0; TagIdx < SplitNames.Num(); ++TagIdx) { if (SplitNames[TagIdx] == SwapRule.FromName) { SwappedNames = SplitNames; // Possible match! // Done - full match found SwappedNames.RemoveAt(TagIdx, 1, false); for (int32 ToIdx=0; ToIdx < SwapRule.ToNames.Num(); ++ToIdx) { SwappedNames.Insert(SwapRule.ToNames[ToIdx], TagIdx + ToIdx); } 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 new expanded tag. Original: %s. Parent: %s"), *TagName.ToString(), *ComposedString); FName ComposedName = FName(*ComposedString); FGameplayCueTranslatorNodeIndex ChildIdx = GetTranslationIndexForName( ComposedName, true ); if ( ChildIdx.IsValid() ) { FGameplayCueTranslatorNodeIndex ParentIdx = GetTranslationIndexForName( TagName, true ); if (ParentIdx.IsValid()) { FGameplayCueTranslatorNode& ParentNode = TranslationLUT[ParentIdx]; FGameplayCueTranslatorNode& ChildNode = TranslationLUT[ChildIdx]; // Find or create the link structure out of the parent node FGameplayCueTranslationLink& NewLink = ParentNode.FindOrCreateLink(NameSwapData.ClassCDO, NameSwapData.NameSwaps.Num()); NewLink.NodeLookup[SwapRuleIdx] = ChildNode.CachedIndex; ChildNode.UsedTranslators.Append(ParentNode.UsedTranslators); ChildNode.UsedTranslators.Add(NameSwapData.ClassCDO); } } BuildTagTranslationTable_Forward_r(ComposedName, SwappedNames); } } } } }
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; }