示例#1
0
void DecomposeUCXMesh( const TArray<FVector>& CollisionVertices, const TArray<int32>& CollisionFaceIdx, UBodySetup* BodySetup )
{
	// We keep no ref to this Model, so it will be GC'd at some point after the import.
	UModel* TempModel = new UModel(FPostConstructInitializeProperties(),NULL,1);

	FMeshConnectivityBuilder ConnectivityBuilder;

	// Send triangles to connectivity builder
	for(int32 x = 0;x < CollisionFaceIdx.Num();x += 3)
	{
		const FVector &VertexA = CollisionVertices[ CollisionFaceIdx[x + 2] ];
		const FVector &VertexB = CollisionVertices[ CollisionFaceIdx[x + 1] ];
		const FVector &VertexC = CollisionVertices[ CollisionFaceIdx[x + 0] ];
		ConnectivityBuilder.AddTriangle( VertexA, VertexB, VertexC );
	}

	ConnectivityBuilder.CreateConnectivityGroups();

	// For each valid group build BSP and extract convex hulls
	for ( int32 i=0; i<ConnectivityBuilder.Groups.Num(); i++ )
	{
		const FMeshConnectivityGroup &Group = ConnectivityBuilder.Groups[ i ];

		// TODO: add some BSP friendly checks here
		// e.g. if group triangles form a closed mesh

		// Generate polygons from group triangles
		TempModel->Polys->Element.Empty();

		for ( int32 j=0; j<Group.Triangles.Num(); j++ )
		{
			const FMeshConnectivityTriangle &Triangle = ConnectivityBuilder.Triangles[ Group.Triangles[j] ];

			FPoly*	Poly = new( TempModel->Polys->Element ) FPoly();
			Poly->Init();
			Poly->iLink = j / 3;

			// Add vertices
			new( Poly->Vertices ) FVector( ConnectivityBuilder.Vertices[ Triangle.Vertices[0] ].Position );
			new( Poly->Vertices ) FVector( ConnectivityBuilder.Vertices[ Triangle.Vertices[1] ].Position );
			new( Poly->Vertices ) FVector( ConnectivityBuilder.Vertices[ Triangle.Vertices[2] ].Position );

			// Update polygon normal
			Poly->CalcNormal(1);
		}

		// Build bounding box.
		TempModel->BuildBound();

		// Build BSP for the brush.
		FBSPOps::bspBuild( TempModel,FBSPOps::BSP_Good,15,70,1,0 );
		FBSPOps::bspRefresh( TempModel, 1 );
		FBSPOps::bspBuildBounds( TempModel );

		// Convert collision model into a collection of convex hulls.
		// Generated convex hulls will be added to existing ones
		BodySetup->CreateFromModel( TempModel, false );
	}
}
void DeselectAllSurfacesInLevel(ULevel* InLevel)
{
    if(InLevel)
    {
        UModel* Model = InLevel->Model;
        for( int32 SurfaceIndex = 0 ; SurfaceIndex < Model->Surfs.Num() ; ++SurfaceIndex )
        {
            FBspSurf& Surf = Model->Surfs[SurfaceIndex];
            if( Surf.PolyFlags & PF_Selected )
            {
                Model->ModifySurf( SurfaceIndex, false );
                Surf.PolyFlags &= ~PF_Selected;
            }
        }
    }
}
示例#3
0
/**
 * Deselects all BSP surfaces in the specified level.
 *
 * @param	Level		The level for which to deselect all levels.
 * @return				The number of surfaces that were deselected
 */
static uint32 DeselectAllSurfacesForLevel(ULevel* Level)
{
	uint32 NumSurfacesDeselected = 0;
	if ( Level )
	{
		UModel* Model = Level->Model;
		for( int32 SurfaceIndex = 0 ; SurfaceIndex < Model->Surfs.Num() ; ++SurfaceIndex )
		{
			FBspSurf& Surf = Model->Surfs[SurfaceIndex];
			if( Surf.PolyFlags & PF_Selected )
			{
				Model->ModifySurf( SurfaceIndex, false );
				Surf.PolyFlags &= ~PF_Selected;
				++NumSurfacesDeselected;
			}
		}
	}
	return NumSurfacesDeselected;
}
示例#4
0
void FLevelModel::DeselectAllSurfaces()
{
	ULevel* Level = GetLevelObject();

	if (Level == NULL)
	{
		return;
	}

	UModel* Model = Level->Model;
	for (int32 SurfaceIndex = 0; SurfaceIndex < Model->Surfs.Num(); ++SurfaceIndex)
	{
		FBspSurf& Surf = Model->Surfs[SurfaceIndex];
		if (Surf.PolyFlags & PF_Selected)
		{
			Model->ModifySurf(SurfaceIndex, false);
			Surf.PolyFlags&= ~PF_Selected;
		}
	}
}
bool FEdModeTexture::StartTracking(FEditorViewportClient* InViewportClient, FViewport* InViewport)
{
	// call base version because it calls the StartModify() virtual method needed to track drag events
	bool BaseRtn = FEdMode::StartTracking(InViewportClient, InViewport);

	// Complete the previous transaction if one exists
	if( ScopedTransaction )
	{
		EndTracking(InViewportClient, InViewport);
	}
	// Start a new transaction
	ScopedTransaction = new FScopedTransaction( NSLOCTEXT("UnrealEd", "TextureManipulation", "Texture Manipulation") );

	for( FConstLevelIterator Iterator = GetWorld()->GetLevelIterator(); Iterator; ++Iterator )
	{
		UModel* Model = (*Iterator)->Model;
		Model->ModifySelectedSurfs( true );
	}

	return BaseRtn;
}
示例#6
0
void UEditorEngine::polySelectMatchingResolution(UWorld* InWorld, bool bCurrentLevelOnly)
{
	// true if at least one surface was selected.
	bool bSurfaceWasSelected = false;

	TArray<float> SelectedResolutions;

	if (bCurrentLevelOnly == true)
	{
		for (TSelectedSurfaceIterator<FCurrentLevelSurfaceLevelFilter> It(InWorld); It; ++It)
		{
			SelectedResolutions.AddUnique(It->LightMapScale);
		}

		if (SelectedResolutions.Num() > 0)
		{
			if (SelectedResolutions.Num() > 1)
			{
				FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "BSPSelect_DifferentResolutionsSelected", "Different selected resolutions.\nCan only select matching for a single resolution."));
			}
			else
			{
				// Select all surfaces with matching materials.
				for (TSurfaceIterator<FCurrentLevelSurfaceLevelFilter> It(InWorld); It; ++It)
				{
					if (SelectedResolutions.Contains(It->LightMapScale))
					{
						UModel* Model = It.GetModel();
						const int32 SurfaceIndex = It.GetSurfaceIndex();
						Model->ModifySurf( SurfaceIndex, 0 );
						GEditor->SelectBSPSurf( Model, SurfaceIndex, true, false );
						bSurfaceWasSelected = true;
					}
				}
			}
		}
	}
	else
	{
		for (TSelectedSurfaceIterator<> It(InWorld); It; ++It)
		{
			SelectedResolutions.AddUnique(It->LightMapScale);
		}

		if (SelectedResolutions.Num() > 0)
		{
			if (SelectedResolutions.Num() > 1)
			{
				FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "BSPSelect_DifferentResolutionsSelected", "Different selected resolutions.\nCan only select matching for a single resolution."));
			}
			else
			{
				// Select all surfaces with matching materials.
				for (TSurfaceIterator<> It(InWorld); It; ++It)
				{
					if (SelectedResolutions.Contains(It->LightMapScale))
					{
						UModel* Model = It.GetModel();
						const int32 SurfaceIndex = It.GetSurfaceIndex();
						Model->ModifySurf( SurfaceIndex, 0 );
						GEditor->SelectBSPSurf( Model, SurfaceIndex, true, false );
						bSurfaceWasSelected = true;
					}
				}
			}
		}
	}

	if ( bSurfaceWasSelected )
	{
		NoteSelectionChange();
	}
}
示例#7
0
void UEditorEngine::polySelectMatchingMaterial(UWorld* InWorld, bool bCurrentLevelOnly)
{
	// true if at least one surface was selected.
	bool bSurfaceWasSelected = false;

	// true if default material representations have already been added to the materials list.
	bool bDefaultMaterialAdded = false;

	TArray<UMaterialInterface*> Materials;

	if ( bCurrentLevelOnly )
	{
		// Get list of unique materials that are on selected faces.
		for ( TSelectedSurfaceIterator<FCurrentLevelSurfaceLevelFilter> It(InWorld) ; It ; ++It )
		{
			if ( It->Material && It->Material != UMaterial::GetDefaultMaterial(MD_Surface) )
			{
				Materials.AddUnique( It->Material );
			}
			else if ( !bDefaultMaterialAdded )
			{
				bDefaultMaterialAdded = true;

				// Add both representations of the default material.
				Materials.AddUnique( NULL );
				Materials.AddUnique( UMaterial::GetDefaultMaterial(MD_Surface) );
			}
		}

		// Select all surfaces with matching materials.
		for ( TSurfaceIterator<FCurrentLevelSurfaceLevelFilter> It(InWorld) ; It ; ++It )
		{
			// Map the default material to NULL, so that NULL assignments match manual default material assignments.
			if( Materials.Contains( It->Material ) )
			{
				UModel* Model = It.GetModel();
				const int32 SurfaceIndex = It.GetSurfaceIndex();
				Model->ModifySurf( SurfaceIndex, 0 );
				GEditor->SelectBSPSurf( Model, SurfaceIndex, true, false );
				bSurfaceWasSelected = true;
			}
		}
	}
	else
	{
		// Get list of unique materials that are on selected faces.
		for ( TSelectedSurfaceIterator<> It(InWorld) ; It ; ++It )
		{
			if ( It->Material && It->Material != UMaterial::GetDefaultMaterial(MD_Surface) )
			{
				Materials.AddUnique( It->Material );
			}
			else if ( !bDefaultMaterialAdded )
			{
				bDefaultMaterialAdded = true;

				// Add both representations of the default material.
				Materials.AddUnique( NULL );
				Materials.AddUnique( UMaterial::GetDefaultMaterial(MD_Surface) );
			}
		}

		// Select all surfaces with matching materials.
		for ( TSurfaceIterator<> It(InWorld) ; It ; ++It )
		{
			// Map the default material to NULL, so that NULL assignments match manual default material assignments.
			if( Materials.Contains( It->Material ) )
			{
				UModel* Model = It.GetModel();
				const int32 SurfaceIndex = It.GetSurfaceIndex();
				Model->ModifySurf( SurfaceIndex, 0 );
				GEditor->SelectBSPSurf( Model, SurfaceIndex, true, false );
				bSurfaceWasSelected = true;
			}
		}
	}

	if ( bSurfaceWasSelected )
	{
		NoteSelectionChange();
	}
}
示例#8
0
/**
 * Selects all adjacent polygons (only coplanars if Coplanars==1)
 * @return		Number of polygons newly selected.
 */
static int32 TagAdjacentsType(UWorld* InWorld, EAdjacentsType AdjacentType)
{
	// Allocate GFlags1
	check( GFlags1.Num() == 0 );
	for( FConstLevelIterator Iterator = InWorld->GetLevelIterator(); Iterator; ++Iterator )
	{
		UModel* Model = (*Iterator)->Model;
		uint8* Ptr = new uint8[MAX_uint16+1];
		FMemory::Memzero( Ptr, MAX_uint16+1 );
		GFlags1.Add( Ptr );
	}

	FVert		*VertPool;
	FVector		*Base,*Normal;
	uint8		b;
	int32		    i;
	int			Selected,Found;

	Selected = 0;

	// Find all points corresponding to selected vertices:
	int32 ModelIndex1 = 0;
	for( FConstLevelIterator Iterator = InWorld->GetLevelIterator(); Iterator; ++Iterator )
	{
		UModel* Model = (*Iterator)->Model;
		uint8* Flags1 = GFlags1[ModelIndex1++];
		for (i=0; i<Model->Nodes.Num(); i++)
		{
			FBspNode &Node = Model->Nodes[i];
			FBspSurf &Poly = Model->Surfs[Node.iSurf];
			if (Poly.PolyFlags & PF_Selected)
			{
				VertPool = &Model->Verts[Node.iVertPool];
				for (b=0; b<Node.NumVertices; b++)
				{
					Flags1[(VertPool++)->pVertex] = 1;
				}
			}
		}
	}

	// Select all unselected nodes for which two or more vertices are selected:
	ModelIndex1 = 0;
	int32 ModelIndex2 = -1;
	for( FConstLevelIterator Iterator = InWorld->GetLevelIterator(); Iterator; ++Iterator )
	{
		UModel* Model = (*Iterator)->Model;
		uint8* Flags1 = GFlags1[ModelIndex1];
		ModelIndex1++;
		ModelIndex2++;
		for( i = 0 ; i < Model->Nodes.Num() ; i++ )
		{
			FBspNode &Node = Model->Nodes[i];
			FBspSurf &Poly = Model->Surfs[Node.iSurf];
			if (!(Poly.PolyFlags & PF_Selected))
			{
				Found    = 0;
				VertPool = &Model->Verts[Node.iVertPool];
				//
				Base   = &Model->Points [Poly.pBase];
				Normal = &Model->Vectors[Poly.vNormal];
				//
				for (b=0; b<Node.NumVertices; b++) Found += Flags1[(VertPool++)->pVertex];
				//
				if (AdjacentType == ADJACENT_COPLANARS)
				{
					if (!GFlags2[ModelIndex2][Node.iSurf]) Found=0;
				}
				else if (AdjacentType == ADJACENT_FLOORS)
				{
					if (FMath::Abs(Normal->Z) <= 0.85) Found = 0;
				}
				else if (AdjacentType == ADJACENT_WALLS)
				{
					if (FMath::Abs(Normal->Z) >= 0.10) Found = 0;
				}
				else if (AdjacentType == ADJACENT_SLANTS)
				{
					if (FMath::Abs(Normal->Z) > 0.85) Found = 0;
					if (FMath::Abs(Normal->Z) < 0.10) Found = 0;
				}

				if (Found > 0)
				{
					Model->ModifySurf( Node.iSurf, 0 );
					GEditor->SelectBSPSurf( Model, Node.iSurf, true, false );
					Selected++;
				}
			}
		}
	}

	// Free GFlags1.
	for ( i = 0 ; i < GFlags1.Num() ; ++i )
	{
		delete[] GFlags1[i];
	}
	GFlags1.Empty();

	GEditor->NoteSelectionChange();
	return Selected;
}
示例#9
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;
}
void SetLevelVisibility(ULevel* Level, bool bShouldBeVisible, bool bForceLayersVisible)
{
    // Nothing to do
    if ( Level == NULL )
    {
        return;
    }


    // Handle the case of the p-level
    // The p-level can't be unloaded, so its actors/BSP should just be temporarily hidden/unhidden
    // Also, intentionally do not force layers visible for the p-level
    if ( Level->IsPersistentLevel() )
    {
        //create a transaction so we can undo the visibilty toggle
        const FScopedTransaction Transaction( LOCTEXT( "ToggleLevelVisibility", "Toggle Level Visibility" ) );
        if ( Level->bIsVisible != bShouldBeVisible )
        {
            Level->Modify();
        }
        // Set the visibility of each actor in the p-level
        for ( TArray<AActor*>::TIterator PLevelActorIter( Level->Actors ); PLevelActorIter; ++PLevelActorIter )
        {
            AActor* CurActor = *PLevelActorIter;
            if ( CurActor && !FActorEditorUtils::IsABuilderBrush(CurActor) && CurActor->bHiddenEdLevel == bShouldBeVisible )
            {
                CurActor->Modify();
                CurActor->bHiddenEdLevel = !bShouldBeVisible;
                CurActor->RegisterAllComponents();
                CurActor->MarkComponentsRenderStateDirty();
            }
        }

        // Set the visibility of each BSP surface in the p-level
        UModel* CurLevelModel = Level->Model;
        if ( CurLevelModel )
        {
            CurLevelModel->Modify();
            for ( TArray<FBspSurf>::TIterator SurfaceIterator( CurLevelModel->Surfs ); SurfaceIterator; ++SurfaceIterator )
            {
                FBspSurf& CurSurf = *SurfaceIterator;
                CurSurf.bHiddenEdLevel = !bShouldBeVisible;
            }
        }

        // Add/remove model components from the scene
        for(int32 ComponentIndex = 0; ComponentIndex < Level->ModelComponents.Num(); ComponentIndex++)
        {
            UModelComponent* CurLevelModelCmp = Level->ModelComponents[ComponentIndex];
            if(CurLevelModelCmp)
            {
                if (bShouldBeVisible && CurLevelModelCmp)
                {
                    CurLevelModelCmp->RegisterComponentWithWorld(Level->OwningWorld);
                }
                else if (!bShouldBeVisible && CurLevelModelCmp->IsRegistered())
                {
                    CurLevelModelCmp->UnregisterComponent();
                }
            }
        }

        FEditorSupportDelegates::RedrawAllViewports.Broadcast();
    }
    else
    {
        ULevelStreaming* StreamingLevel = NULL;
        if (Level->OwningWorld == NULL || Level->OwningWorld->PersistentLevel != Level )
        {
            StreamingLevel = FLevelUtils::FindStreamingLevel( Level );
        }

        // If were hiding a level, lets make sure to close the level transform mode if its the same level currently selected for edit
        FEdModeLevel* LevelMode = static_cast<FEdModeLevel*>(GEditorModeTools().GetActiveMode( FBuiltinEditorModes::EM_Level ));
        if( LevelMode && LevelMode->IsEditing( StreamingLevel ) )
        {
            GEditorModeTools().DeactivateMode( FBuiltinEditorModes::EM_Level );
        }

        //create a transaction so we can undo the visibilty toggle
        const FScopedTransaction Transaction( LOCTEXT( "ToggleLevelVisibility", "Toggle Level Visibility" ) );

        // Handle the case of a streaming level
        if ( StreamingLevel )
        {
            // We need to set the RF_Transactional to make a streaming level serialize itself. so store the original ones, set the flag, and put the original flags back when done
            EObjectFlags cachedFlags = StreamingLevel->GetFlags();
            StreamingLevel->SetFlags( RF_Transactional );
            StreamingLevel->Modify();
            StreamingLevel->SetFlags( cachedFlags );

            // Set the visibility state for this streaming level.
            StreamingLevel->bShouldBeVisibleInEditor = bShouldBeVisible;
        }

        if( !bShouldBeVisible )
        {
            GEditor->Layers->RemoveLevelLayerInformation( Level );
        }

        // UpdateLevelStreaming sets Level->bIsVisible directly, so we need to make sure it gets saved to the transaction buffer.
        if ( Level->bIsVisible != bShouldBeVisible )
        {
            Level->Modify();
        }

        if ( StreamingLevel )
        {
            Level->OwningWorld->FlushLevelStreaming();

            // In the Editor we expect this operation will complete in a single call
            check(Level->bIsVisible == bShouldBeVisible);
        }
        else if (Level->OwningWorld != NULL)
        {
            // In case we level has no associated StreamingLevel, remove or add to world directly
            if (bShouldBeVisible)
            {
                if (!Level->bIsVisible)
                {
                    Level->OwningWorld->AddToWorld(Level);
                }
            }
            else
            {
                Level->OwningWorld->RemoveFromWorld(Level);
            }

            // In the Editor we expect this operation will complete in a single call
            check(Level->bIsVisible == bShouldBeVisible);
        }

        if( bShouldBeVisible )
        {
            GEditor->Layers->AddLevelLayerInformation( Level );
        }

        // Force the level's layers to be visible, if desired
        FEditorSupportDelegates::RedrawAllViewports.Broadcast();

        // Iterate over the level's actors, making a list of their layers and unhiding the layers.
        TTransArray<AActor*>& Actors = Level->Actors;
        for ( int32 ActorIndex = 0 ; ActorIndex < Actors.Num() ; ++ActorIndex )
        {
            AActor* Actor = Actors[ ActorIndex ];
            if ( Actor )
            {
                bool bModified = false;
                if ( bShouldBeVisible && bForceLayersVisible && GEditor->Layers->IsActorValidForLayer( Actor ) )
                {
                    // Make the actor layer visible, if it's not already.
                    if ( Actor->bHiddenEdLayer )
                    {
                        bModified = Actor->Modify();
                        Actor->bHiddenEdLayer = false;
                    }

                    const bool bIsVisible = true;
                    GEditor->Layers->SetLayersVisibility( Actor->Layers, bIsVisible );
                }

                // Set the visibility of each actor in the streaming level
                if ( !FActorEditorUtils::IsABuilderBrush(Actor) && Actor->bHiddenEdLevel == bShouldBeVisible )
                {
                    if ( !bModified )
                    {
                        bModified = Actor->Modify();
                    }
                    Actor->bHiddenEdLevel = !bShouldBeVisible;

                    if (bShouldBeVisible)
                    {
                        Actor->ReregisterAllComponents();
                    }
                    else
                    {
                        Actor->UnregisterAllComponents();
                    }
                }
            }
        }
    }

    FEditorDelegates::RefreshLayerBrowser.Broadcast();

    // Notify the Scene Outliner, as new Actors may be present in the world.
    GEngine->BroadcastLevelActorsChanged();

    // If the level is being hidden, deselect actors and surfaces that belong to this level.
    if ( !bShouldBeVisible )
    {
        USelection* SelectedActors = GEditor->GetSelectedActors();
        SelectedActors->Modify();
        TTransArray<AActor*>& Actors = Level->Actors;
        for ( int32 ActorIndex = 0 ; ActorIndex < Actors.Num() ; ++ActorIndex )
        {
            AActor* Actor = Actors[ ActorIndex ];
            if ( Actor )
            {
                SelectedActors->Deselect( Actor );
            }
        }

        DeselectAllSurfacesInLevel(Level);

        // Tell the editor selection status was changed.
        GEditor->NoteSelectionChange();
    }

    Level->bIsVisible = bShouldBeVisible;
}