本文整理汇总了C++中UObject::GetFName方法的典型用法代码示例。如果您正苦于以下问题:C++ UObject::GetFName方法的具体用法?C++ UObject::GetFName怎么用?C++ UObject::GetFName使用的例子?那么恭喜您, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类UObject
的用法示例。
在下文中一共展示了UObject::GetFName方法的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: ExportComponentDefinitions
void UExporter::ExportComponentDefinitions(const FExportObjectInnerContext* Context, const TArray<UObject*>& Components, FOutputDevice& Ar, uint32 PortFlags)
{
PortFlags |= PPF_ExportsNotFullyQualified;
if (!(PortFlags & PPF_SeparateDefine))
{
// export forward declarations
// technically we only need to do this if there are circular references but it doesn't seem worth it
// to complicate this code for a minor speed improvement in the text import path
for (int32 ComponentIndex = 0; ComponentIndex < Components.Num(); ComponentIndex++)
{
UObject* Component = Components[ComponentIndex];
FName ComponentName = Component->GetFName();
if (!Component->HasAnyMarks(OBJECTMARK_TagImp) && !Component->HasAnyFlags(RF_TextExportTransient))
{
if (Component->HasAnyFlags(RF_ClassDefaultObject) || Component->GetArchetype()->HasAllFlags(RF_ClassDefaultObject))
{
Ar.Logf(TEXT("%sBegin Object Class=%s Name=%s ObjName=%s%s"), FCString::Spc(TextIndent), *Component->GetClass()->GetName(), *ComponentName.ToString(), *Component->GetName(), LINE_TERMINATOR);
}
else
{
Ar.Logf(TEXT("%sBegin Object Class=%s Name=%s ObjName=%s Archetype=%s'%s'%s"),FCString::Spc(TextIndent),*Component->GetClass()->GetName(), *ComponentName.ToString(), *Component->GetName(), *Component->GetArchetype()->GetClass()->GetName(), *Component->GetArchetype()->GetPathName(), LINE_TERMINATOR);
}
if (PortFlags & PPF_SeparateDeclare)
{
ExportObjectInner(Context, Component, Ar, PortFlags, false);
}
Ar.Logf(TEXT("%sEnd Object%s"), FCString::Spc(TextIndent), LINE_TERMINATOR);
}
}
}
if (!(PortFlags & PPF_SeparateDeclare))
{
// export property definitions
for (int32 ComponentIndex = 0; ComponentIndex < Components.Num(); ComponentIndex++)
{
UObject* Component = Components[ComponentIndex];
FName ComponentName = Component->GetFName();
if (!Component->HasAnyMarks(OBJECTMARK_TagImp) && !Component->HasAnyFlags(RF_TextExportTransient))
{
Ar.Logf(TEXT("%sBegin Object Name=%s%s"), FCString::Spc(TextIndent), *ComponentName.ToString(), LINE_TERMINATOR);
uint32 OldPortFlags = PortFlags;
if (!(Component->HasAnyFlags(RF_ClassDefaultObject) || Component->GetArchetype()->HasAllFlags(RF_ClassDefaultObject)))
{
// we created this thing with an archetype (see archetype=, above), so we don't want to list the archetype because it is unqualified and will clash, resetting the archetype pointer to something silly
PortFlags |= PPF_NoInternalArcheType;
}
ExportObjectInner(Context, Component, Ar, PortFlags, false);
PortFlags = OldPortFlags;
Ar.Logf(TEXT("%sEnd Object%s"), FCString::Spc(TextIndent), LINE_TERMINATOR);
Component->Mark(OBJECTMARK_TagImp);
}
}
}
}
示例2: PostLoad
void UEdGraphPin::PostLoad()
{
Super::PostLoad();
static FName GameplayTagName = TEXT("GameplayTag");
static FName GameplayTagContainerName = TEXT("GameplayTagContainer");
static FName GameplayTagsPathName = TEXT("/Script/GameplayTags");
if (PinType.PinSubCategoryObject.IsValid())
{
UObject* PinSubCategoryObject = PinType.PinSubCategoryObject.Get();
if (PinSubCategoryObject->GetOuter()->GetFName() == GameplayTagsPathName)
{
if (PinSubCategoryObject->GetFName() == GameplayTagName)
{
// Pins of type FGameplayTag were storing "()" for empty arrays and then importing that into ArrayProperty and expecting an empty array.
// That it was working was a bug and has been fixed, so let's fixup pins. A pin that wants an array size of 1 will always fill the parenthesis
// so there is no worry about breaking those cases.
if (DefaultValue == TEXT("()"))
{
DefaultValue.Empty();
}
}
else if (PinSubCategoryObject->GetFName() == GameplayTagContainerName)
{
// Pins of type FGameplayTagContainer were storing "GameplayTags=()" for empty arrays, which equates to having a single item, default generated as detailed above for FGameplayTag.
// The solution is to replace occurances with an empty string, due to the item being a struct, we can't just empty the value and must replace only the section we need.
DefaultValue.ReplaceInline(TEXT("GameplayTags=()"), TEXT("GameplayTags="));
}
}
}
}
示例3: BindPossessableObject
void UWidgetAnimation::BindPossessableObject(const FGuid& ObjectId, UObject& PossessedObject, UObject* Context)
{
// If it's the Root Widget
if (&PossessedObject == PreviewWidget.Get())
{
PreviewObjectToIds.Add(&PossessedObject, ObjectId);
IdToPreviewObjects.Add(ObjectId, &PossessedObject);
FWidgetAnimationBinding NewBinding;
{
NewBinding.AnimationGuid = ObjectId;
NewBinding.WidgetName = PossessedObject.GetFName();
NewBinding.bIsRootWidget = true;
}
AnimationBindings.Add(NewBinding);
return;
}
UPanelSlot* PossessedSlot = Cast<UPanelSlot>(&PossessedObject);
if ((PossessedSlot != nullptr) && (PossessedSlot->Content != nullptr))
{
SlotContentPreviewObjectToIds.Add(PossessedSlot->Content, ObjectId);
IdToSlotContentPreviewObjects.Add(ObjectId, PossessedSlot->Content);
// Save the name of the widget containing the slots. This is the object
// to look up that contains the slot itself (the thing we are animating).
FWidgetAnimationBinding NewBinding;
{
NewBinding.AnimationGuid = ObjectId;
NewBinding.SlotWidgetName = PossessedSlot->GetFName();
NewBinding.WidgetName = PossessedSlot->Content->GetFName();
NewBinding.bIsRootWidget = false;
}
AnimationBindings.Add(NewBinding);
}
else if (PossessedSlot == nullptr)
{
PreviewObjectToIds.Add(&PossessedObject, ObjectId);
IdToPreviewObjects.Add(ObjectId, &PossessedObject);
FWidgetAnimationBinding NewBinding;
{
NewBinding.AnimationGuid = ObjectId;
NewBinding.WidgetName = PossessedObject.GetFName();
NewBinding.bIsRootWidget = false;
}
AnimationBindings.Add(NewBinding);
}
}
示例4: BindPossessableObject
void FUMGSequencerObjectBindingManager::BindPossessableObject( const FGuid& PossessableGuid, UObject& PossessedObject )
{
UPanelSlot* PossessedSlot = Cast<UPanelSlot>(&PossessedObject);
if ( PossessedSlot != nullptr && PossessedSlot->Content != nullptr )
{
SlotContentPreviewObjectToGuidMap.Add(PossessedSlot->Content, PossessableGuid);
GuidToSlotContentPreviewObjectsMap.Add(PossessableGuid, PossessedSlot->Content);
// Save the name of the widget containing the slots. This is the object to look up that contains the slot itself(the thing we are animating)
FWidgetAnimationBinding NewBinding;
NewBinding.AnimationGuid = PossessableGuid;
NewBinding.SlotWidgetName = PossessedSlot->GetFName();
NewBinding.WidgetName = PossessedSlot->Content->GetFName();
WidgetAnimation->AnimationBindings.Add(NewBinding);
}
else if( PossessedSlot == nullptr )
{
PreviewObjectToGuidMap.Add(&PossessedObject, PossessableGuid);
GuidToPreviewObjectsMap.Add(PossessableGuid, &PossessedObject);
FWidgetAnimationBinding NewBinding;
NewBinding.AnimationGuid = PossessableGuid;
NewBinding.WidgetName = PossessedObject.GetFName();
WidgetAnimation->AnimationBindings.Add(NewBinding);
}
}
示例5: ExportTextItem
void UObjectPropertyBase::ExportTextItem( FString& ValueStr, const void* PropertyValue, const void* DefaultValue, UObject* Parent, int32 PortFlags, UObject* ExportRootScope ) const
{
UObject* Temp = GetObjectPropertyValue(PropertyValue);
if( Temp != NULL )
{
if (PortFlags & PPF_DebugDump)
{
ValueStr += Temp->GetFullName();
}
else if (Parent && !Parent->HasAnyFlags(RF_ClassDefaultObject) && Temp->IsDefaultSubobject())
{
if ((PortFlags & PPF_Delimited) && (!Temp->GetFName().IsValidXName(INVALID_OBJECTNAME_CHARACTERS)))
{
ValueStr += FString::Printf(TEXT("\"%s\""), *Temp->GetName().ReplaceQuotesWithEscapedQuotes());
}
else
{
ValueStr += Temp->GetName();
}
}
else
{
ValueStr += GetExportPath(Temp, Parent, ExportRootScope, PortFlags);
}
}
else
{
ValueStr += TEXT("None");
}
}
示例6: Identical
bool UObjectPropertyBase::Identical( const void* A, const void* B, uint32 PortFlags ) const
{
UObject* ObjectA = A ? GetObjectPropertyValue(A) : NULL;
UObject* ObjectB = B ? GetObjectPropertyValue(B) : NULL;
if (!ObjectA && !ObjectB)
{
return true;
}
if (!ObjectA || !ObjectB)
{
return false;
}
// Compare actual pointers. We don't do this during PIE because we want to be sure to serialize everything. An example is the LevelScriptActor being serialized against its CDO,
// which contains actor references. We want to serialize those references so they are fixed up.
const bool bDuplicatingForPIE = (PortFlags&PPF_DuplicateForPIE) != 0;
bool bResult = !bDuplicatingForPIE ? (ObjectA == ObjectB) : false;
// always serialize the cross level references, because they could be NULL
// @todo: okay, this is pretty hacky overall - we should have a PortFlag or something
// that is set during SavePackage. Other times, we don't want to immediately return false
// (instead of just this ExportDefProps case)
// instance testing
if (!bResult && ObjectA->GetClass() == ObjectB->GetClass())
{
bool bPerformDeepComparison = (PortFlags&PPF_DeepComparison) != 0;
if ((PortFlags&PPF_DeepCompareInstances) && !bPerformDeepComparison)
{
bPerformDeepComparison = ObjectA->IsTemplate() != ObjectB->IsTemplate();
}
if (!bResult && bPerformDeepComparison)
{
// In order for deep comparison to be match they both need to have the same name and that name needs to be included in the instancing table for the class
if (ObjectA->GetFName() == ObjectB->GetFName() && ObjectA->GetClass()->GetDefaultSubobjectByName(ObjectA->GetFName()))
{
checkSlow(ObjectA->IsDefaultSubobject() && ObjectB->IsDefaultSubobject() && ObjectA->GetClass()->GetDefaultSubobjectByName(ObjectA->GetFName()) == ObjectB->GetClass()->GetDefaultSubobjectByName(ObjectB->GetFName())); // equivalent
bResult = AreInstancedObjectsIdentical(ObjectA,ObjectB,PortFlags);
}
}
}
return bResult;
}
示例7: CanEditNativeComponent
bool FComponentEditorUtils::CanEditNativeComponent(const UActorComponent* NativeComponent)
{
// A native component can be edited if it is bound to a member variable and that variable is marked as visible in the editor
// Note: We aren't concerned with whether the component is marked editable - the component itself is responsible for determining which of its properties are editable
bool bCanEdit = false;
UClass* OwnerClass = (NativeComponent && NativeComponent->GetOwner()) ? NativeComponent->GetOwner()->GetClass() : nullptr;
if (OwnerClass != nullptr)
{
// If the owner is a blueprint generated class, use the BP parent class
UBlueprint* Blueprint = UBlueprint::GetBlueprintFromClass(OwnerClass);
if (Blueprint != nullptr && Blueprint->ParentClass != nullptr)
{
OwnerClass = Blueprint->ParentClass;
}
for (TFieldIterator<UProperty> It(OwnerClass); It; ++It)
{
UProperty* Property = *It;
if (UObjectProperty* ObjectProp = Cast<UObjectProperty>(Property))
{
// Must be visible - note CPF_Edit is set for all properties that should be visible, not just those that are editable
if (( Property->PropertyFlags & ( CPF_Edit ) ) == 0)
{
continue;
}
UObject* ParentCDO = OwnerClass->GetDefaultObject();
if (!NativeComponent->GetClass()->IsChildOf(ObjectProp->PropertyClass))
{
continue;
}
UObject* Object = ObjectProp->GetObjectPropertyValue(ObjectProp->ContainerPtrToValuePtr<void>(ParentCDO));
bCanEdit = Object != nullptr && Object->GetFName() == NativeComponent->GetFName();
if (bCanEdit)
{
break;
}
}
}
}
return bCanEdit;
}
示例8:
int32 FReferenceChainSearch::FFindReferencerCollector::FindReferencedObjectIndex(const UObject& ReferencedBy, const UObject& ReferencedObject)
{
int32 Result = INDEX_NONE;
auto & TokenMap = ReferencedBy.GetClass()->DebugTokenMap;
for (int32 Index = 0, End = TokenMap.GetTokenMapSize(); Index < End; ++Index)
{
auto TokenName = TokenMap.GetTokenInfo(Index).Name;
if (ReferencedObject.GetFName() == TokenName)
{
Result = Index;
break;
}
}
return Result;
}
示例9: ExportTextItem
void UObjectPropertyBase::ExportTextItem( FString& ValueStr, const void* PropertyValue, const void* DefaultValue, UObject* Parent, int32 PortFlags, UObject* ExportRootScope ) const
{
UObject* Temp = GetObjectPropertyValue(PropertyValue);
if (0 != (PortFlags & PPF_ExportCpp))
{
FString::Printf(TEXT("%s%s*"), PropertyClass->GetPrefixCPP(), *PropertyClass->GetName());
ValueStr += Temp
? FString::Printf(TEXT("LoadObject<%s%s>(nullptr, TEXT(\"%s\"))")
, PropertyClass->GetPrefixCPP()
, *PropertyClass->GetName()
, *(Temp->GetPathName().ReplaceCharWithEscapedChar()))
: TEXT("nullptr");
return;
}
if( Temp != NULL )
{
if (PortFlags & PPF_DebugDump)
{
ValueStr += Temp->GetFullName();
}
else if (Parent && !Parent->HasAnyFlags(RF_ClassDefaultObject) && Temp->IsDefaultSubobject())
{
if ((PortFlags & PPF_Delimited) && (!Temp->GetFName().IsValidXName(INVALID_OBJECTNAME_CHARACTERS)))
{
ValueStr += FString::Printf(TEXT("\"%s\""), *Temp->GetName().ReplaceQuotesWithEscapedQuotes());
}
else
{
ValueStr += Temp->GetName();
}
}
else
{
ValueStr += GetExportPath(Temp, Parent, ExportRootScope, PortFlags);
}
}
else
{
ValueStr += TEXT("None");
}
}
示例10: CanVariableBeDropped
bool FKismetVariableDragDropAction::CanVariableBeDropped(const UProperty* InVariableProperty, const UEdGraph& InGraph) const
{
bool bCanVariableBeDropped = false;
if (InVariableProperty)
{
UObject* Outer = InVariableProperty->GetOuter();
// Only allow variables to be placed within the same blueprint (otherwise the self context on the dropped node will be invalid)
bCanVariableBeDropped = IsFromBlueprint(FBlueprintEditorUtils::FindBlueprintForGraph(&InGraph));
// Local variables have some special conditions for being allowed to be placed
if (bCanVariableBeDropped && Outer->IsA(UFunction::StaticClass()))
{
// Check if the top level graph has the same name as the function, if they do not then the variable cannot be placed in the graph
if (FBlueprintEditorUtils::GetTopLevelGraph(&InGraph)->GetFName() != Outer->GetFName())
{
bCanVariableBeDropped = false;
}
}
}
return bCanVariableBeDropped;
}
示例11: BuildSubobjectKey
inline UObject* BuildSubobjectKey(UObject* InObj, TArray<FName>& OutHierarchyNames)
{
auto UseOuter = [](const UObject* Obj)
{
if (Obj == nullptr)
{
return false;
}
const bool bIsCDO = Obj->HasAllFlags(RF_ClassDefaultObject);
const UObject* CDO = bIsCDO ? Obj : nullptr;
const bool bIsClassCDO = (CDO != nullptr) ? (CDO->GetClass()->ClassDefaultObject == CDO) : false;
if(!bIsClassCDO && CDO)
{
// Likely a trashed CDO, try to recover. Only known cause of this is
// ambiguous use of DSOs:
CDO = CDO->GetClass()->ClassDefaultObject;
}
const UActorComponent* AsComponent = Cast<UActorComponent>(Obj);
const bool bIsDSO = Obj->HasAnyFlags(RF_DefaultSubObject);
const bool bIsSCSComponent = AsComponent && AsComponent->IsCreatedByConstructionScript();
return (bIsCDO && bIsClassCDO) || bIsDSO || bIsSCSComponent;
};
UObject* Outermost = nullptr;
UObject* Iter = InObj;
while (UseOuter(Iter))
{
OutHierarchyNames.Add(Iter->GetFName());
Iter = Iter->GetOuter();
Outermost = Iter;
}
return Outermost;
}
示例12: if
//.........这里部分代码省略.........
ComponentTemplate = FindObject<UObject>(SubobjectOuter, *TemplateName.ToString());
if (ComponentTemplate != NULL)
{
// if we're overriding a subobject declared in a parent class, we should already have an object with that name that
// was instanced when ComponentOwnerClass's CDO was initialized; if so, it's archetype should be the BaseTemplate. If it
// isn't, then there are two unrelated subobject definitions using the same name.
if ( ComponentTemplate->GetArchetype() != BaseTemplate )
{
}
else if ( BaseTemplate == NULL )
{
// BaseTemplate should only be NULL if the Begin Object line specified a class
Warn->Logf(ELogVerbosity::Error, TEXT("BEGIN OBJECT: A subobject named %s is already declared in a parent class. If you intended to override that subobject, don't specify a class in the derived subobject definition: %s"), *TemplateName.ToString(), *StrLine);
return NULL;
}
}
}
// Propagate object flags to the sub object.
EObjectFlags NewFlags = SubobjectOuter->GetMaskedFlags( RF_PropagateToSubObjects );
if (!Archetype) // no override and we didn't find one from the class table, so go with the base
{
Archetype = BaseTemplate;
}
UObject* OldComponent = NULL;
if (ComponentTemplate)
{
bool bIsOkToReuse = ComponentTemplate->GetClass() == TemplateClass
&& ComponentTemplate->GetOuter() == SubobjectOuter
&& ComponentTemplate->GetFName() == TemplateName
&& (ComponentTemplate->GetArchetype() == Archetype || !Archetype);
if (!bIsOkToReuse)
{
UE_LOG(LogEditorObject, Log, TEXT("Could not reuse component instance %s, name clash?"), *ComponentTemplate->GetFullName());
ComponentTemplate->Rename(); // just abandon the existing component, we are going to create
OldComponent = ComponentTemplate;
ComponentTemplate = NULL;
}
}
if (!ComponentTemplate)
{
ComponentTemplate = NewObject<UObject>(
SubobjectOuter,
TemplateClass,
TemplateName,
NewFlags,
Archetype,
!!SubobjectOuter,
&InstanceGraph
);
}
else
{
// We do not want to set RF_Transactional for construction script created components, so we have to monkey with things here
if (NewFlags & RF_Transactional)
{
UActorComponent* Component = Cast<UActorComponent>(ComponentTemplate);
if (Component && Component->IsCreatedByConstructionScript())
{
示例13: RemapProperty
static void RemapProperty(UProperty* Property, int32 Index, const TMap<FName, AActor*>& ActorRemapper, uint8* DestData)
{
if (UObjectProperty* ObjectProperty = Cast<UObjectProperty>(Property))
{
// If there's a concrete index, use that, otherwise iterate all array members (for the case that this property is inside a struct, or there is exactly one element)
const int32 Num = (Index == INDEX_NONE) ? ObjectProperty->ArrayDim : 1;
const int32 StartIndex = (Index == INDEX_NONE) ? 0 : Index;
for (int32 Count = 0; Count < Num; Count++)
{
uint8* PropertyAddr = ObjectProperty->ContainerPtrToValuePtr<uint8>(DestData, StartIndex + Count);
UObject* Object = ObjectProperty->GetObjectPropertyValue(PropertyAddr);
if (Object)
{
AActor* const* RemappedObject = ActorRemapper.Find(Object->GetFName());
if (RemappedObject)
{
ObjectProperty->SetObjectPropertyValue(PropertyAddr, *RemappedObject);
}
}
}
}
else if (UArrayProperty* ArrayProperty = Cast<UArrayProperty>(Property))
{
FScriptArrayHelper ArrayHelper(ArrayProperty, ArrayProperty->ContainerPtrToValuePtr<void>(DestData));
if (Index != INDEX_NONE)
{
RemapProperty(ArrayProperty->Inner, INDEX_NONE, ActorRemapper, ArrayHelper.GetRawPtr(Index));
}
else
{
for (int32 ArrayIndex = 0; ArrayIndex < ArrayHelper.Num(); ArrayIndex++)
{
RemapProperty(ArrayProperty->Inner, INDEX_NONE, ActorRemapper, ArrayHelper.GetRawPtr(ArrayIndex));
}
}
}
else if (UStructProperty* StructProperty = Cast<UStructProperty>(Property))
{
if (Index != INDEX_NONE)
{
// If a concrete index was given, remap just that
for (TFieldIterator<UProperty> It(StructProperty->Struct); It; ++It)
{
RemapProperty(*It, INDEX_NONE, ActorRemapper, StructProperty->ContainerPtrToValuePtr<uint8>(DestData, Index));
}
}
else
{
// If no concrete index was given, either the ArrayDim is 1 (i.e. not a static array), or the struct is within
// a deeper structure (an array or another struct) and we cannot know which element was changed, so iterate through all elements.
for (int32 Count = 0; Count < StructProperty->ArrayDim; Count++)
{
for (TFieldIterator<UProperty> It(StructProperty->Struct); It; ++It)
{
RemapProperty(*It, INDEX_NONE, ActorRemapper, StructProperty->ContainerPtrToValuePtr<uint8>(DestData, Count));
}
}
}
}
}
示例14: PerformQuery
void PerformQuery(UObject* InObject, void* BasePointer, UStruct* InStruct, FString InPropertyName)
{
FString CompString;
FString PropString;
if (InPropertyName.Split(TEXT("."), &CompString, &PropString))
{
if (UStructProperty* StructProp = FindField<UStructProperty>(InStruct, *CompString))
{
// The first part of the path was a struct, look inside it
void* StructContainer = StructProp->ContainerPtrToValuePtr<void>(InObject);
PerformQuery(InObject, StructContainer, StructProp->Struct, PropString);
return;
}
else
{
// Now look for a component
const FName TrialCompName(*CompString);
const FName RemappedCompName = ULinkerLoad::FindSubobjectRedirectName(TrialCompName);
const FName CompName = (RemappedCompName != NAME_None) ? RemappedCompName : TrialCompName;
TArray<UObject*> Components;
InObject->CollectDefaultSubobjects(Components, false);
for (int32 ComponentIndex = 0; ComponentIndex < Components.Num(); ComponentIndex++)
{
UObject* Component = Components[ComponentIndex];
if (Component->GetFName() == CompName)
{
PerformQuery(Component, (void*)Component, Component->GetClass(), PropString);
return;
}
}
}
}
else
{
// Look for the property in the current scope
if (UProperty* Prop = FindField<UProperty>(InStruct, *InPropertyName))
{
OutPropContainer = BasePointer;
OutProperty = Prop;
OutObject = InObject;
}
else
{
// Handle legacy tracks that have unqualified paths to properties that are now in components by searching thru each component for the property name
TArray<UObject*> Components;
InObject->CollectDefaultSubobjects(Components, false);
for (int32 ComponentIndex = 0; ComponentIndex < Components.Num(); ComponentIndex++)
{
UObject* Component = Components[ComponentIndex];
PerformQuery(Component, (void*)Component, Component->GetClass(), InPropertyName);
if (IsValid())
{
return;
}
}
}
}
}
示例15: GetEntryToWrite
FVisualLogEntry* FVisualLogger::GetEntryToWrite(const class UObject* Object, float TimeStamp, ECreateIfNeeded ShouldCreate)
{
FVisualLogEntry* CurrentEntry = nullptr;
UObject * LogOwner = FVisualLogger::FindRedirection(Object);
if (LogOwner == nullptr || (LogOwner != Object && CurrentEntryPerObject.Contains(LogOwner) == false))
{
return nullptr;
}
bool InitializeNewEntry = false;
TWeakObjectPtr<UWorld> World = GetWorld(Object);
if (CurrentEntryPerObject.Contains(LogOwner))
{
CurrentEntry = &CurrentEntryPerObject[LogOwner];
InitializeNewEntry = TimeStamp > CurrentEntry->TimeStamp && ShouldCreate == ECreateIfNeeded::Create;
if (World.IsValid())
{
World->GetTimerManager().ClearTimer(VisualLoggerCleanupTimerHandle);
for (auto& CurrentPair : CurrentEntryPerObject)
{
FVisualLogEntry* Entry = &CurrentPair.Value;
if (Entry->TimeStamp >= 0 && Entry->TimeStamp < TimeStamp)
{
for (auto* Device : OutputDevices)
{
Device->Serialize(CurrentPair.Key, ObjectToNameMap[CurrentPair.Key], ObjectToClassNameMap[CurrentPair.Key], *Entry);
}
Entry->Reset();
}
}
}
}
if (!CurrentEntry)
{
// It's first and only one usage of LogOwner as regular object to get names. We assume once that LogOwner is correct here and only here.
CurrentEntry = &CurrentEntryPerObject.Add(LogOwner);
ObjectToNameMap.Add(LogOwner, LogOwner->GetFName());
ObjectToClassNameMap.Add(LogOwner, *(LogOwner->GetClass()->GetName()));
ObjectToPointerMap.Add(LogOwner, LogOwner);
InitializeNewEntry = true;
}
if (InitializeNewEntry)
{
CurrentEntry->Reset();
CurrentEntry->TimeStamp = TimeStamp;
if (RedirectionMap.Contains(LogOwner))
{
if (ObjectToPointerMap.Contains(LogOwner) && ObjectToPointerMap[LogOwner].IsValid())
{
const class AActor* LogOwnerAsActor = Cast<class AActor>(LogOwner);
if (LogOwnerAsActor)
{
LogOwnerAsActor->GrabDebugSnapshot(CurrentEntry);
}
}
for (auto Child : RedirectionMap[LogOwner])
{
if (Child.IsValid())
{
const class AActor* ChildAsActor = Cast<class AActor>(Child.Get());
if (ChildAsActor)
{
ChildAsActor->GrabDebugSnapshot(CurrentEntry);
}
}
}
}
else
{
const class AActor* ObjectAsActor = Cast<class AActor>(Object);
if (ObjectAsActor)
{
CurrentEntry->Location = ObjectAsActor->GetActorLocation();
ObjectAsActor->GrabDebugSnapshot(CurrentEntry);
}
}
}
if (World.IsValid())
{
//set next tick timer to flush obsolete/old entries
World->GetTimerManager().SetTimer(VisualLoggerCleanupTimerHandle, FTimerDelegate::CreateLambda(
[this, World](){
for (auto& CurrentPair : CurrentEntryPerObject)
{
FVisualLogEntry* Entry = &CurrentPair.Value;
if (Entry->TimeStamp >= 0 && (!World.IsValid() || Entry->TimeStamp < World->GetTimeSeconds())) // CurrentEntry->TimeStamp == -1 means it's not initialized entry information
{
for (auto* Device : OutputDevices)
{
Device->Serialize(CurrentPair.Key, ObjectToNameMap[CurrentPair.Key], ObjectToClassNameMap[CurrentPair.Key], *Entry);
}
Entry->Reset();
}
}
//.........这里部分代码省略.........