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);
			}
		}
	}
}
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="));
			}
		}
	}
}
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);
	}
}
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);
	}
}
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");
	}
}
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;
}
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;
}
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;
}
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");
	}
}
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;
}
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
0
/**
 * Parse and import text as property values for the object specified.  This function should never be called directly - use ImportObjectProperties instead.
 * 
 * @param	ObjectStruct				the struct for the data we're importing
 * @param	DestData					the location to import the property values to
 * @param	SourceText					pointer to a buffer containing the values that should be parsed and imported
 * @param	SubobjectRoot					when dealing with nested subobjects, corresponds to the top-most outer that
 *										is not a subobject/template
 * @param	SubobjectOuter				the outer to use for creating subobjects/components. NULL when importing structdefaultproperties
 * @param	Warn						output device to use for log messages
 * @param	Depth						current nesting level
 * @param	InstanceGraph				contains the mappings of instanced objects and components to their templates
 *
 * @return	NULL if the default values couldn't be imported
 */
static const TCHAR* ImportProperties(
	uint8*						DestData,
	const TCHAR*				SourceText,
	UStruct*					ObjectStruct,
	UObject*					SubobjectRoot,
	UObject*					SubobjectOuter,
	FFeedbackContext*			Warn,
	int32						Depth,
	FObjectInstancingGraph&		InstanceGraph,
	const TMap<FName, AActor*>* ActorRemapper
	)
{
	check(!GIsUCCMakeStandaloneHeaderGenerator);
	check(ObjectStruct!=NULL);
	check(DestData!=NULL);

	if ( SourceText == NULL )
		return NULL;

	// Cannot create subobjects when importing struct defaults, or if SubobjectOuter (used as the Outer for any subobject declarations encountered) is NULL
	bool bSubObjectsAllowed = !ObjectStruct->IsA(UScriptStruct::StaticClass()) && SubobjectOuter != NULL;

	// true when DestData corresponds to a subobject in a class default object
	bool bSubObject = false;

	UClass* ComponentOwnerClass = NULL;

	if ( bSubObjectsAllowed )
	{
		bSubObject = SubobjectRoot != NULL && SubobjectRoot->HasAnyFlags(RF_ClassDefaultObject);
		if ( SubobjectRoot == NULL )
		{
			SubobjectRoot = SubobjectOuter;
		}

		ComponentOwnerClass = SubobjectOuter != NULL
			? SubobjectOuter->IsA(UClass::StaticClass())
				? CastChecked<UClass>(SubobjectOuter)
				: SubobjectOuter->GetClass()
			: NULL;
	}
	

	// The PortFlags to use for all ImportText calls
	uint32 PortFlags = PPF_Delimited | PPF_CheckReferences;
	if (GIsImportingT3D)
	{
		PortFlags |= PPF_AttemptNonQualifiedSearch;
	}

	FString StrLine;

	TArray<FDefinedProperty> DefinedProperties;

	// Parse all objects stored in the actor.
	// Build list of all text properties.
	bool ImportedBrush = 0;
	int32 LinesConsumed = 0;
	while (FParse::LineExtended(&SourceText, StrLine, LinesConsumed, true))
	{
		// remove extra whitespace and optional semicolon from the end of the line
		{
			int32 Length = StrLine.Len();
			while ( Length > 0 &&
					(StrLine[Length - 1] == TCHAR(';') || StrLine[Length - 1] == TCHAR(' ') || StrLine[Length - 1] == 9) )
			{
				Length--;
			}
			if (Length != StrLine.Len())
			{
				StrLine = StrLine.Left(Length);
			}
		}

		if ( ContextSupplier != NULL )
		{
			ContextSupplier->CurrentLine += LinesConsumed;
		}
		if (StrLine.Len() == 0)
		{
			continue;
		}

		const TCHAR* Str = *StrLine;

		int32 NewLineNumber;
		if( FParse::Value( Str, TEXT("linenumber="), NewLineNumber ) )
		{
			if ( ContextSupplier != NULL )
			{
				ContextSupplier->CurrentLine = NewLineNumber;
			}
		}
		else if( GetBEGIN(&Str,TEXT("Brush")) && ObjectStruct->IsChildOf(ABrush::StaticClass()) )
		{
			// If SubobjectOuter is NULL, we are importing defaults for a UScriptStruct's defaultproperties block
			if ( !bSubObjectsAllowed )
			{
				Warn->Logf(ELogVerbosity::Error, TEXT("BEGIN BRUSH: Subobjects are not allowed in this context"));
				return NULL;
			}

			// Parse brush on this line.
			TCHAR BrushName[NAME_SIZE];
			if( FParse::Value( Str, TEXT("Name="), BrushName, NAME_SIZE ) )
			{
				// If an initialized brush with this name already exists in the level, rename the existing one.
				// It is deemed to be initialized if it has a non-zero poly count.
				// If it is uninitialized, the existing object will have been created by a forward reference in the import text,
				// and it will now be redefined.  This relies on the behavior that NewObject<> will return an existing pointer
				// if an object with the same name and outer is passed.
				UModel* ExistingBrush = FindObject<UModel>( SubobjectRoot, BrushName );
				if (ExistingBrush && ExistingBrush->Polys && ExistingBrush->Polys->Element.Num() > 0)
				{
					ExistingBrush->Rename();
				}

				// Create model.
				UModelFactory* ModelFactory = NewObject<UModelFactory>();
				ModelFactory->FactoryCreateText( UModel::StaticClass(), SubobjectRoot, FName(BrushName, FNAME_Add, true), RF_NoFlags, NULL, TEXT("t3d"), SourceText, SourceText+FCString::Strlen(SourceText), Warn );
				ImportedBrush = 1;
			}
		}
		else if (GetBEGIN(&Str, TEXT("Foliage")))
		{
			UFoliageType* SourceFoliageType;
			FName ComponentName;
			if (SubobjectRoot &&
				ParseObject<UFoliageType>(Str, TEXT("FoliageType="), SourceFoliageType, ANY_PACKAGE) &&
				FParse::Value(Str, TEXT("Component="), ComponentName) )
			{
				UPrimitiveComponent* ActorComponent = FindObjectFast<UPrimitiveComponent>(SubobjectRoot, ComponentName);

				if (ActorComponent && ActorComponent->GetComponentLevel())
				{
					AInstancedFoliageActor* IFA = AInstancedFoliageActor::GetInstancedFoliageActorForLevel(ActorComponent->GetComponentLevel(), true);

					FFoliageMeshInfo* MeshInfo = nullptr;
					UFoliageType* FoliageType = IFA->AddFoliageType(SourceFoliageType, &MeshInfo);

					const TCHAR* StrPtr;
					FString TextLine;
					while (MeshInfo && FParse::Line(&SourceText, TextLine))
					{
						StrPtr = *TextLine;
						if (GetEND(&StrPtr, TEXT("Foliage")))
						{
							break;
						}

						// Parse the instance properties
						FFoliageInstance Instance;
						FString Temp;
						if (FParse::Value(StrPtr, TEXT("Location="), Temp, false))
						{
							GetFVECTOR(*Temp, Instance.Location);
						}
						if (FParse::Value(StrPtr, TEXT("Rotation="), Temp, false))
						{
							GetFROTATOR(*Temp, Instance.Rotation, 1);
						}
						if (FParse::Value(StrPtr, TEXT("PreAlignRotation="), Temp, false))
						{
							GetFROTATOR(*Temp, Instance.PreAlignRotation, 1);
						}
						if (FParse::Value(StrPtr, TEXT("DrawScale3D="), Temp, false))
						{
							GetFVECTOR(*Temp, Instance.DrawScale3D);
						}
						FParse::Value(StrPtr, TEXT("Flags="), Instance.Flags);

						// Add the instance
						MeshInfo->AddInstance(IFA, FoliageType, Instance, ActorComponent);
					}
				}
			}
		}
		else if( GetBEGIN(&Str,TEXT("Object")))
		{
			// If SubobjectOuter is NULL, we are importing defaults for a UScriptStruct's defaultproperties block
			if ( !bSubObjectsAllowed )
			{
				Warn->Logf(ELogVerbosity::Error, TEXT("BEGIN OBJECT: Subobjects are not allowed in this context"));
				return NULL;
			}

			// Parse subobject default properties.
			// Note: default properties subobjects have compiled class as their Outer (used for localization).
			UClass*	TemplateClass = NULL;
			bool bInvalidClass = false;
			ParseObject<UClass>(Str, TEXT("Class="), TemplateClass, ANY_PACKAGE, &bInvalidClass);
			
			if (bInvalidClass)
			{
				Warn->Logf(ELogVerbosity::Error,TEXT("BEGIN OBJECT: Invalid class specified: %s"), *StrLine);
				return NULL;
			}

			// parse the name of the template
			FName	TemplateName = NAME_None;
			FParse::Value(Str,TEXT("Name="),TemplateName);
			if(TemplateName == NAME_None)
			{
				Warn->Logf(ELogVerbosity::Error,TEXT("BEGIN OBJECT: Must specify valid name for subobject/component: %s"), *StrLine);
				return NULL;
			}

			// points to the parent class's template subobject/component, if we are overriding a subobject/component declared in our parent class
			UObject* BaseTemplate = NULL;
			bool bRedefiningSubobject = false;
			if( TemplateClass )
			{
			}
			else
			{
				// next, verify that a template actually exists in the parent class
				UClass* ParentClass = ComponentOwnerClass->GetSuperClass();
				check(ParentClass);

				UObject* ParentCDO = ParentClass->GetDefaultObject();
				check(ParentCDO);

				BaseTemplate = StaticFindObjectFast(UObject::StaticClass(), SubobjectOuter, TemplateName);
				bRedefiningSubobject = (BaseTemplate != NULL);

				if (BaseTemplate == NULL)
				{
					BaseTemplate = StaticFindObjectFast(UObject::StaticClass(), ParentCDO, TemplateName);
				}
				
				if ( BaseTemplate == NULL )
				{
					// wasn't found
					Warn->Logf(ELogVerbosity::Error, TEXT("BEGIN OBJECT: No base template named %s found in parent class %s: %s"), *TemplateName.ToString(), *ParentClass->GetName(), *StrLine);
					return NULL;
				}

				TemplateClass = BaseTemplate->GetClass();
			}

			// because the outer won't be a default object

			checkSlow(TemplateClass != NULL);
			if (bRedefiningSubobject)
			{
				// since we're redefining an object in the same text block, only need to import properties again
				SourceText = ImportObjectProperties( (uint8*)BaseTemplate, SourceText, TemplateClass, SubobjectRoot, BaseTemplate,
													Warn, Depth + 1, ContextSupplier ? ContextSupplier->CurrentLine : 0, &InstanceGraph, ActorRemapper );
			}
			else 
			{
				UObject* Archetype = NULL;
				UObject* ComponentTemplate = NULL;

				// Since we are changing the class we can't use the Archetype,
				// however that is fine since we will have been editing the CDO anyways
				if (!FBlueprintEditorUtils::IsAnonymousBlueprintClass(SubobjectOuter->GetClass()))
				{
					// if an archetype was specified in the Begin Object block, use that as the template for the ConstructObject call.
					FString ArchetypeName;
					if (FParse::Value(Str, TEXT("Archetype="), ArchetypeName))
					{
						// if given a name, break it up along the ' so separate the class from the name
						FString ObjectClass;
						FString ObjectPath;
						if ( FPackageName::ParseExportTextPath(ArchetypeName, &ObjectClass, &ObjectPath) )
						{
							// find the class
							UClass* ArchetypeClass = (UClass*)StaticFindObject(UClass::StaticClass(), ANY_PACKAGE, *ObjectClass);
							if (ArchetypeClass)
							{
								// if we had the class, find the archetype
								Archetype = StaticFindObject(ArchetypeClass, ANY_PACKAGE, *ObjectPath);
							}
						}
					}
				}

				if (SubobjectOuter->HasAnyFlags(RF_ClassDefaultObject))
				{
					if (!Archetype) // if an archetype was specified explicitly, we will stick with that
					{
						Archetype = ComponentOwnerClass->GetDefaultSubobjectByName(TemplateName);
						if(Archetype)
						{
							if ( BaseTemplate == NULL )
							{
								// BaseTemplate should only be NULL if the Begin Object line specified a class
								Warn->Logf(ELogVerbosity::Error, TEXT("BEGIN OBJECT: The component name %s is already used (if you want to override the component, don't specify a class): %s"), *TemplateName.ToString(), *StrLine);
								return NULL;
							}

							// the component currently in the component template map and the base template should be the same
							checkf(Archetype==BaseTemplate,TEXT("OverrideComponent: '%s'   BaseTemplate: '%s'"), *Archetype->GetFullName(), *BaseTemplate->GetFullName());
						}
					}
				}
				else // handle the non-template case (subobjects and non-template components)
				{
					// don't allow Actor-derived subobjects
					if ( TemplateClass->IsChildOf(AActor::StaticClass()) )
					{
						Warn->Logf(ELogVerbosity::Error,TEXT("Cannot create subobjects from Actor-derived classes: %s"), *StrLine);
						return NULL;
					}

					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())
						{
							NewFlags &= ~RF_Transactional;
						}
					}

					// Make sure desired flags are set - existing object could be pending kill
					ComponentTemplate->ClearFlags(RF_AllFlags);
					ComponentTemplate->SetFlags(NewFlags);
				}

				// replace all properties in this subobject outer' class that point to the original subobject with the new subobject
				TMap<UObject*, UObject*> ReplacementMap;
				if (Archetype)
				{
					checkSlow(ComponentTemplate->GetArchetype() == Archetype);
					ReplacementMap.Add(Archetype, ComponentTemplate);
					InstanceGraph.AddNewInstance(ComponentTemplate);
				}
				if (OldComponent)
				{
					ReplacementMap.Add(OldComponent, ComponentTemplate);
				}
				FArchiveReplaceObjectRef<UObject> ReplaceAr(SubobjectOuter, ReplacementMap, false, false, true);

				// import the properties for the subobject
				SourceText = ImportObjectProperties(
					(uint8*)ComponentTemplate, 
					SourceText, 
					TemplateClass, 
					SubobjectRoot, 
					ComponentTemplate, 
					Warn, 
					Depth+1,
					ContextSupplier ? ContextSupplier->CurrentLine : 0,
					&InstanceGraph,
					ActorRemapper
					);
			}
		}
		else if( FParse::Command(&Str,TEXT("CustomProperties")))
		{
			check(SubobjectOuter);

			SubobjectOuter->ImportCustomProperties(Str, Warn);
		}
		else if( GetEND(&Str,TEXT("Actor")) || GetEND(&Str,TEXT("DefaultProperties")) || GetEND(&Str,TEXT("structdefaultproperties")) || (GetEND(&Str,TEXT("Object")) && Depth) )
		{
			// End of properties.
			break;
		}
		else if( GetREMOVE(&Str,TEXT("Component")) )
		{
			checkf(false, TEXT("Remove component is illegal in pasted text"));
		}
		else
		{
			// Property.
			UProperty::ImportSingleProperty(Str, DestData, ObjectStruct, SubobjectOuter, PortFlags, Warn, DefinedProperties);
		}
	}

	if (ActorRemapper)
	{
		for (const auto& DefinedProperty : DefinedProperties)
		{
			RemapProperty(DefinedProperty.Property, DefinedProperty.Index, *ActorRemapper, DestData);
		}
	}

	// Prepare brush.
	if( ImportedBrush && ObjectStruct->IsChildOf<ABrush>() && !ObjectStruct->IsChildOf<AVolume>() )
	{
		check(GIsEditor);
		ABrush* Actor = (ABrush*)DestData;
		check(Actor->GetBrushComponent());
		if( Actor->GetBrushComponent()->Mobility == EComponentMobility::Static )
		{
			// Prepare static brush.
			Actor->SetNotForClientOrServer();
		}
		else
		{
			// Prepare moving brush.
			FBSPOps::csgPrepMovingBrush( Actor );
		}
	}

	return SourceText;
}
示例#13
0
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
0
		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
0
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();
				}
			}
		}
		), 0.1, false);
	}

	return CurrentEntry;
}
void FConfigPropertyHelperDetails::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder)
{
	TSharedPtr<IPropertyHandle> PropertyHandle = DetailBuilder.GetProperty("EditProperty");
	DetailBuilder.HideProperty(PropertyHandle);

	UObject* PropValue;
	PropertyHandle->GetValue(PropValue);
	OriginalProperty = CastChecked<UProperty>(PropValue);

	// Create a runtime UClass with the provided property as the only member. We will use this in the details view for the config hierarchy.
	ConfigEditorPropertyViewClass = NewObject<UClass>(GetTransientPackage(), TEXT("TempConfigEditorUClass"), RF_Public|RF_Standalone);

	// Keep a record of the UProperty we are looking to update
	ConfigEditorCopyOfEditProperty = DuplicateObject<UProperty>(OriginalProperty, ConfigEditorPropertyViewClass, PropValue->GetFName());
	ConfigEditorPropertyViewClass->ClassConfigName = OriginalProperty->GetOwnerClass()->ClassConfigName;
	ConfigEditorPropertyViewClass->SetSuperStruct(UObject::StaticClass());
	ConfigEditorPropertyViewClass->ClassFlags |= (CLASS_DefaultConfig | CLASS_Config);
	ConfigEditorPropertyViewClass->AddCppProperty(ConfigEditorCopyOfEditProperty);
	ConfigEditorPropertyViewClass->Bind();
	ConfigEditorPropertyViewClass->StaticLink(true);
	ConfigEditorPropertyViewClass->AssembleReferenceTokenStream();
	ConfigEditorPropertyViewClass->AddToRoot();
	
	// Cache the CDO for the object
	ConfigEditorPropertyViewCDO = ConfigEditorPropertyViewClass->GetDefaultObject(true);
	ConfigEditorPropertyViewCDO->AddToRoot();

	// Get access to all of the config files where this property is configurable.
	ConfigFilesHandle = DetailBuilder.GetProperty("ConfigFilePropertyObjects");
	DetailBuilder.HideProperty(ConfigFilesHandle);

	// Add the properties to a property table so we can edit these.
	IDetailCategoryBuilder& ConfigHierarchyCategory = DetailBuilder.EditCategory("ConfigHierarchy");
	ConfigHierarchyCategory.AddCustomRow(LOCTEXT("ConfigHierarchy", "ConfigHierarchy"))
	[
		// Create a property table with the values.
		ConstructPropertyTable(DetailBuilder)
	];

	// Listen for changes to the properties, we handle these by updating the ini file associated.
	FCoreUObjectDelegates::OnObjectPropertyChanged.AddSP(this, &FConfigPropertyHelperDetails::OnPropertyValueChanged);
}