FText FSimpleAssetEditor::GetToolkitName() const
{
	const TArray<UObject*>& EditingObjs = GetEditingObjects();

	check( EditingObjs.Num() > 0 );

	FFormatNamedArguments Args;
	Args.Add( TEXT("ToolkitName"), GetBaseToolkitName() );

	if( EditingObjs.Num() == 1 )
	{
		const UObject* EditingObject = EditingObjs[ 0 ];

		const bool bDirtyState = EditingObject->GetOutermost()->IsDirty();

		Args.Add( TEXT("ObjectName"), FText::FromString( EditingObject->GetName() ) );
		Args.Add( TEXT("DirtyState"), bDirtyState ? FText::FromString( TEXT( "*" ) ) : FText::GetEmpty() );
		return FText::Format( LOCTEXT("ToolkitTitle", "{ObjectName}{DirtyState} - {ToolkitName}"), Args );
	}
	else
	{
		bool bDirtyState = false;
		UClass* SharedBaseClass = nullptr;
		for( int32 x = 0; x < EditingObjs.Num(); ++x )
		{
			UObject* Obj = EditingObjs[ x ];
			check( Obj );

			UClass* ObjClass = Cast<UClass>(Obj);
			if (ObjClass == nullptr)
			{
				ObjClass = Obj->GetClass();
			}
			check( ObjClass );

			// Initialize with the class of the first object we encounter.
			if( SharedBaseClass == nullptr )
			{
				SharedBaseClass = ObjClass;
			}

			// If we've encountered an object that's not a subclass of the current best baseclass,
			// climb up a step in the class hierarchy.
			while( !ObjClass->IsChildOf( SharedBaseClass ) )
			{
				SharedBaseClass = SharedBaseClass->GetSuperClass();
			}

			// If any of the objects are dirty, flag the label
			bDirtyState |= Obj->GetOutermost()->IsDirty();
		}

		check(SharedBaseClass);

		Args.Add( TEXT("NumberOfObjects"), EditingObjs.Num() );
		Args.Add( TEXT("ClassName"), FText::FromString( SharedBaseClass->GetName() ) );
		Args.Add( TEXT("DirtyState"), bDirtyState ? FText::FromString( TEXT( "*" ) ) : FText::GetEmpty() );
		return FText::Format( LOCTEXT("ToolkitTitle_EditingMultiple", "{NumberOfObjects} {ClassName}{DirtyState} - {ToolkitName}"), Args );
	}
}
void FAssetEditorManager::SaveOpenAssetEditors(bool bOnShutdown)
{
	if(!bSavingOnShutdown)
	{
		TArray<FString> OpenAssets;

		// Don't save a list of assets to restore if we are running under a debugger
		if(!FPlatformMisc::IsDebuggerPresent())
		{
			for (auto EditorPair : OpenedEditors)
			{
				IAssetEditorInstance* Editor = EditorPair.Key;
				if (Editor != NULL)
				{
					UObject* EditedObject = EditorPair.Value;
					if(EditedObject != NULL)
					{
						// only record assets that have a valid saved package
						UPackage* Package = EditedObject->GetOutermost();
						if(Package != NULL && Package->GetFileSize() != 0)
						{
							OpenAssets.Add(EditedObject->GetPathName());
						}
					}
				}
			}
		}

		GConfig->SetArray(TEXT("AssetEditorManager"), TEXT("OpenAssetsAtExit"), OpenAssets, GEditorPerProjectIni);
		GConfig->SetBool(TEXT("AssetEditorManager"), TEXT("CleanShutdown"), bOnShutdown, GEditorPerProjectIni);
		GConfig->Flush(false, GEditorPerProjectIni);
	}
}
bool USelection::Modify(bool bAlwaysMarkDirty/* =true */)
{
	// If the selection currently contains any PIE objects we should not be including it in the transaction buffer
	for (TWeakObjectPtr<UObject>& ObjectPtr : SelectedObjects)
	{
		UObject* Object = ObjectPtr.Get();
		if (Object && Object->GetOutermost()->HasAnyPackageFlags(PKG_PlayInEditor | PKG_ContainsScript | PKG_CompiledIn))
		{
			return false;
		}
	}

	return Super::Modify(bAlwaysMarkDirty);
}
bool FTransaction::FObjectRecord::ContainsPieObject() const
{
	{
		UObject* Obj = Object.Object;

		if(Obj && Obj->GetOutermost()->HasAnyPackageFlags(PKG_PlayInEditor))
		{
			return true;
		}
	}

	for (const FPersistentObjectRef& ReferencedObject : ReferencedObjects)
	{
		const UObject* Obj = ReferencedObject.Object;
		if( Obj && Obj->GetOutermost()->HasAnyPackageFlags(PKG_PlayInEditor))
		{
			return true;
		}
	}

	return false;
}
FGuid FSequencerActorBindingManager::FindGuidForObject( const UMovieScene& MovieScene, UObject& Object ) const
{
	FGuid ObjectGuid = FindSpawnableGuidForPuppetObject( &Object );
	if( !ObjectGuid.IsValid() )
	{
		// Spawnable
		// Is this a game preview object?
		const bool bIsGamePreviewObject = !!( Object.GetOutermost()->PackageFlags & PKG_PlayInEditor );
		if( bIsGamePreviewObject )
		{
			// OK, so someone is asking for a handle to an object from a game preview session, probably because
			// they want to capture keys during live simulation.

			// Check to see if we already have a puppet that was generated from a recording of this game preview object
			// @todo sequencer livecapture: We could support recalling counterpart by full name instead of weak pointer, to allow "overdubbing" of previously recorded actors, when the new actors in the current play session have the same path name
			// @todo sequencer livecapture: Ideally we could capture from editor-world actors that are "puppeteered" as well (real time)
			const FMovieSceneSpawnable* FoundSpawnable = MovieScene.FindSpawnableForCounterpart( &Object );
			if( FoundSpawnable != NULL )
			{
				ObjectGuid = FoundSpawnable->GetGuid();
			}
		}
		else
		{
			BindToPlayMovieSceneNode( false );

			// Possessable
			// When editing within the level editor, make sure we're bound to the level script node which contains data about possessables.
			if( PlayMovieSceneNode.IsValid() )
			{
				ObjectGuid = PlayMovieSceneNode->FindGuidForObject( &Object );
			}
		}

	}
	
	return ObjectGuid;
}
void UExporter::EmitBeginObject( FOutputDevice& Ar, UObject* Obj, uint32 PortFlags )
{
	check(Obj);

	// figure out how to export
	bool bIsExportingDefaultObject = Obj->HasAnyFlags(RF_ClassDefaultObject) || Obj->GetArchetype()->HasAnyFlags(RF_ClassDefaultObject);

	// start outputting the string for the Begin Object line
	Ar.Logf(TEXT("%sBegin Object"), FCString::Spc(TextIndent));

	if (!(PortFlags & PPF_SeparateDefine))
	{
		Ar.Logf(TEXT(" Class=%s"), *Obj->GetClass()->GetName());
	}

	// always need a name, adding "" for space handling
	Ar.Logf(TEXT(" Name=\"%s\""), *Obj->GetName());

	if (!(PortFlags & PPF_SeparateDefine))
	{
		// do we want the archetype string?
		if (!bIsExportingDefaultObject)
		{
			UObject* Archetype = Obj->GetArchetype();
			Ar.Logf(TEXT(" Archetype=%s"), *UObjectPropertyBase::GetExportPath(Archetype, Archetype->GetOutermost(), Archetype->GetOuter(), PortFlags));
		}
	}

	// end in a return
	Ar.Logf(TEXT("\r\n"));

	if ( bEnableDebugBrackets )
	{
		Ar.Logf(TEXT("%s{%s"), FCString::Spc(TextIndent), LINE_TERMINATOR);
	}
}
	/**
	* Nulls out references to a given object
	*
	* @param InObject - Object to null references to
	*/
	void NullReferencesToObject(UObject* InObject)
	{
		TArray<UObject*> ReplaceableObjects;
		TMap<UObject*, UObject*> ReplacementMap;
		ReplacementMap.Add(InObject, NULL);
		ReplacementMap.GenerateKeyArray(ReplaceableObjects);

		// Find all the properties (and their corresponding objects) that refer to any of the objects to be replaced
		TMap< UObject*, TArray<UProperty*> > ReferencingPropertiesMap;
		for (FObjectIterator ObjIter; ObjIter; ++ObjIter)
		{
			UObject* CurObject = *ObjIter;

			// Find the referencers of the objects to be replaced
			FFindReferencersArchive FindRefsArchive(CurObject, ReplaceableObjects);

			// Inform the object referencing any of the objects to be replaced about the properties that are being forcefully
			// changed, and store both the object doing the referencing as well as the properties that were changed in a map (so that
			// we can correctly call PostEditChange later)
			TMap<UObject*, int32> CurNumReferencesMap;
			TMultiMap<UObject*, UProperty*> CurReferencingPropertiesMMap;
			if (FindRefsArchive.GetReferenceCounts(CurNumReferencesMap, CurReferencingPropertiesMMap) > 0)
			{
				TArray<UProperty*> CurReferencedProperties;
				CurReferencingPropertiesMMap.GenerateValueArray(CurReferencedProperties);
				ReferencingPropertiesMap.Add(CurObject, CurReferencedProperties);
				for (TArray<UProperty*>::TConstIterator RefPropIter(CurReferencedProperties); RefPropIter; ++RefPropIter)
				{
					CurObject->PreEditChange(*RefPropIter);
				}
			}

		}

		// Iterate over the map of referencing objects/changed properties, forcefully replacing the references and then
		// alerting the referencing objects the change has completed via PostEditChange
		int32 NumObjsReplaced = 0;
		for (TMap< UObject*, TArray<UProperty*> >::TConstIterator MapIter(ReferencingPropertiesMap); MapIter; ++MapIter)
		{
			++NumObjsReplaced;

			UObject* CurReplaceObj = MapIter.Key();
			const TArray<UProperty*>& RefPropArray = MapIter.Value();

			FArchiveReplaceObjectRef<UObject> ReplaceAr(CurReplaceObj, ReplacementMap, false, true, false);

			for (TArray<UProperty*>::TConstIterator RefPropIter(RefPropArray); RefPropIter; ++RefPropIter)
			{
				FPropertyChangedEvent PropertyEvent(*RefPropIter);
				CurReplaceObj->PostEditChangeProperty(PropertyEvent);
			}

			if (!CurReplaceObj->HasAnyFlags(RF_Transient) && CurReplaceObj->GetOutermost() != GetTransientPackage())
			{
				if (!CurReplaceObj->RootPackageHasAnyFlags(PKG_CompiledIn))
				{
					CurReplaceObj->MarkPackageDirty();
				}
			}
		}
	}
UObject* UObjectPropertyBase::FindImportedObject( const UProperty* Property, UObject* OwnerObject, UClass* ObjectClass, UClass* RequiredMetaClass, const TCHAR* Text, uint32 PortFlags/*=0*/ )
{
	UObject*	Result = NULL;
	check( ObjectClass->IsChildOf(RequiredMetaClass) );

	bool AttemptNonQualifiedSearch = (PortFlags & PPF_AttemptNonQualifiedSearch) != 0; 

	// if we are importing default properties, first look for a matching subobject by
	// looking through the archetype chain at each outer and stop once the outer chain reaches the owning class's default object
	if (PortFlags & PPF_ParsingDefaultProperties)
	{
		for (UObject* SearchStart = OwnerObject; Result == NULL && SearchStart != NULL; SearchStart = SearchStart->GetOuter())
		{
			UObject* ScopedSearchRoot = SearchStart;
			while (Result == NULL && ScopedSearchRoot != NULL)
			{
				Result = StaticFindObject(ObjectClass, ScopedSearchRoot, Text);
				// don't think it's possible to get a non-subobject here, but it doesn't hurt to check
				if (Result != NULL && !Result->IsTemplate(RF_ClassDefaultObject))
				{
					Result = NULL;
				}

				ScopedSearchRoot = ScopedSearchRoot->GetArchetype();
			}
			if (SearchStart->HasAnyFlags(RF_ClassDefaultObject))
			{
				break;
			}
		}
	}
	
	// if we have a parent, look in the parent, then it's outer, then it's outer, ... 
	// this is because exported object properties that point to objects in the level aren't
	// fully qualified, and this will step up the nested object chain to solve any name
	// collisions within a nested object tree
	UObject* ScopedSearchRoot = OwnerObject;
	while (Result == NULL && ScopedSearchRoot != NULL)
	{
		Result = StaticFindObject(ObjectClass, ScopedSearchRoot, Text);
		// disallow class default subobjects here while importing defaults
		// this prevents the use of a subobject name that doesn't exist in the scope of the default object being imported
		// from grabbing some other subobject with the same name and class in some other arbitrary default object
		if (Result != NULL && (PortFlags & PPF_ParsingDefaultProperties) && Result->IsTemplate(RF_ClassDefaultObject))
		{
			Result = NULL;
		}

		ScopedSearchRoot = ScopedSearchRoot->GetOuter();
	}

	if (Result == NULL)
	{
		// attempt to find a fully qualified object
		Result = StaticFindObject(ObjectClass, NULL, Text);

		if (Result == NULL)
		{
			// match any object of the correct class whose path contains the specified path
			Result = StaticFindObject(ObjectClass, ANY_PACKAGE, Text);
			// disallow class default subobjects here while importing defaults
			if (Result != NULL && (PortFlags & PPF_ParsingDefaultProperties) && Result->IsTemplate(RF_ClassDefaultObject))
			{
				Result = NULL;
			}
		}
	}

	// if we haven;t found it yet, then try to find it without a qualified name
	if (!Result)
	{
		const TCHAR* Dot = FCString::Strrchr(Text, '.');
		if (Dot && AttemptNonQualifiedSearch)
		{
			// search with just the object name
			Result = FindImportedObject(Property, OwnerObject, ObjectClass, RequiredMetaClass, Dot + 1);
		}
		FString NewText(Text);
		// if it didn't have a dot, then maybe they just gave a uasset package name
		if (!Dot && !Result)
		{
			int32 LastSlash = NewText.Find(TEXT("/"), ESearchCase::CaseSensitive, ESearchDir::FromEnd);
			if (LastSlash >= 0)
			{
				NewText += TEXT(".");
				NewText += (Text + LastSlash + 1);
				Dot = FCString::Strrchr(*NewText, '.');
			}
		}
		// If we still can't find it, try to load it. (Only try to load fully qualified names)
		if(!Result && Dot)
		{
#if USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING
			FLinkerLoad* Linker = (OwnerObject != nullptr) ? OwnerObject->GetClass()->GetLinker() : nullptr;
			const bool bDeferAssetImports = (Linker != nullptr) && (Linker->LoadFlags & LOAD_DeferDependencyLoads);

			if (bDeferAssetImports)
			{
				Result = Linker->RequestPlaceholderValue(ObjectClass, Text);
			}
			
			if (Result == nullptr)
#endif // USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING
			{
				uint32 LoadFlags = LOAD_NoWarn | LOAD_FindIfFail;

				UE_LOG(LogProperty, Verbose, TEXT("FindImportedObject is attempting to import [%s] (class = %s) with StaticLoadObject"), Text, *GetFullNameSafe(ObjectClass));
				Result = StaticLoadObject(ObjectClass, NULL, Text, NULL, LoadFlags, NULL);

#if USE_DEFERRED_DEPENDENCY_CHECK_VERIFICATION_TESTS
				check(!bDeferAssetImports || !Result || !FBlueprintSupport::IsInBlueprintPackage(Result));
#endif // USE_DEFERRED_DEPENDENCY_CHECK_VERIFICATION_TESTS
			}
		}
	}

	// if we found an object, and we have a parent, make sure we are in the same package if the found object is private, unless it's a cross level property
	if (Result && !Result->HasAnyFlags(RF_Public) && OwnerObject && Result->GetOutermost() != OwnerObject->GetOutermost())
	{
		const UObjectPropertyBase* ObjectProperty = dynamic_cast<const UObjectPropertyBase*>(Property);
		if ( !ObjectProperty || !ObjectProperty->AllowCrossLevel())
		{
			UE_LOG(LogProperty, Warning, TEXT("Illegal TEXT reference to a private object in external package (%s) from referencer (%s).  Import failed..."), *Result->GetFullName(), *OwnerObject->GetFullName());
			Result = NULL;
		}
	}

	check(!Result || Result->IsA(RequiredMetaClass));
	return Result;
}
void FRedirectCollector::ResolveStringAssetReference(FString FilterPackage)
{
    SCOPE_REDIRECT_TIMER(ResolveTimeTotal);


    FName FilterPackageFName = NAME_None;
    if (!FilterPackage.IsEmpty())
    {
        FilterPackageFName = FName(*FilterPackage);
    }

    TMultiMap<FName, FPackagePropertyPair> SkippedReferences;
    SkippedReferences.Empty(StringAssetReferences.Num());
    while ( StringAssetReferences.Num())
    {

        TMultiMap<FName, FPackagePropertyPair> CurrentReferences;
        Swap(StringAssetReferences, CurrentReferences);

        for (const auto& CurrentReference : CurrentReferences)
        {
            const FName& ToLoadFName = CurrentReference.Key;
            const FPackagePropertyPair& RefFilenameAndProperty = CurrentReference.Value;

            if ((FilterPackageFName != NAME_None) && // not using a filter
                    (FilterPackageFName != RefFilenameAndProperty.GetCachedPackageName()) && // this is the package we are looking for
                    (RefFilenameAndProperty.GetCachedPackageName() != NAME_None) // if we have an empty package name then process it straight away
               )
            {
                // If we have a valid filter and it doesn't match, skip this reference
                SkippedReferences.Add(ToLoadFName, RefFilenameAndProperty);
                continue;
            }

            const FString ToLoad = ToLoadFName.ToString();

            if (FCoreDelegates::LoadStringAssetReferenceInCook.IsBound())
            {
                SCOPE_REDIRECT_TIMER(ResolveTimeDelegate);
                if (FCoreDelegates::LoadStringAssetReferenceInCook.Execute(ToLoad) == false)
                {
                    // Skip this reference
                    continue;
                }
            }

            if (ToLoad.Len() > 0 )
            {
                SCOPE_REDIRECT_TIMER(ResolveTimeLoad);

                UE_LOG(LogRedirectors, Verbose, TEXT("String Asset Reference '%s'"), *ToLoad);
                UE_CLOG(RefFilenameAndProperty.GetProperty().ToString().Len(), LogRedirectors, Verbose, TEXT("    Referenced by '%s'"), *RefFilenameAndProperty.GetProperty().ToString());

                StringAssetRefFilenameStack.Push(RefFilenameAndProperty.GetPackage().ToString());

                UObject *Loaded = LoadObject<UObject>(NULL, *ToLoad, NULL, RefFilenameAndProperty.GetReferencedByEditorOnlyProperty() ? LOAD_EditorOnly : LOAD_None, NULL);
                StringAssetRefFilenameStack.Pop();

                UObjectRedirector* Redirector = dynamic_cast<UObjectRedirector*>(Loaded);
                if (Redirector)
                {
                    UE_LOG(LogRedirectors, Verbose, TEXT("    Found redir '%s'"), *Redirector->GetFullName());
                    FRedirection Redir;
                    Redir.PackageFilename = RefFilenameAndProperty.GetPackage().ToString();
                    Redir.RedirectorName = Redirector->GetFullName();
                    Redir.RedirectorPackageFilename = Redirector->GetLinker()->Filename;
                    CA_SUPPRESS(28182)
                    Redir.DestinationObjectName = Redirector->DestinationObject->GetFullName();
                    Redirections.AddUnique(Redir);
                    Loaded = Redirector->DestinationObject;
                }
                if (Loaded)
                {
                    if (FCoreUObjectDelegates::PackageLoadedFromStringAssetReference.IsBound())
                    {
                        FCoreUObjectDelegates::PackageLoadedFromStringAssetReference.Broadcast(Loaded->GetOutermost()->GetFName());
                    }
                    FString Dest = Loaded->GetPathName();
                    UE_LOG(LogRedirectors, Verbose, TEXT("    Resolved to '%s'"), *Dest);
                    if (Dest != ToLoad)
                    {
                        StringAssetRemap.Add(ToLoad, Dest);
                    }
                }
                else
                {
                    const FString Referencer = RefFilenameAndProperty.GetProperty().ToString().Len() ? RefFilenameAndProperty.GetProperty().ToString() : TEXT("Unknown");

                    int32 DotIndex = ToLoad.Find(TEXT("."));

                    FString PackageName = DotIndex != INDEX_NONE ? ToLoad.Left(DotIndex) : ToLoad;

                    if (FLinkerLoad::IsKnownMissingPackage(FName(*PackageName)) == false)
                    {
                        UE_LOG(LogRedirectors, Warning, TEXT("String Asset Reference '%s' was not found! (Referencer '%s')"), *ToLoad, *Referencer);
                    }
                }
            }

        }
    }

    check(StringAssetReferences.Num() == 0);
    // Add any skipped references back into the map for the next time this is called
    Swap(StringAssetReferences, SkippedReferences);
    // we shouldn't have any references left if we decided to resolve them all
    check((StringAssetReferences.Num() == 0) || (FilterPackageFName != NAME_None));
}
void FContentDirectoryMonitor::ProcessModifications(const DirectoryWatcher::FTimeLimit& TimeLimit, TArray<UPackage*>& OutPackagesToSave, FReimportFeedbackContext& Context)
{
	auto* ReimportManager = FReimportManager::Instance();

	for (int32 Index = 0; Index < ModifiedFiles.Num(); ++Index)
	{
		Context.MainTask->EnterProgressFrame();

		auto& Change = ModifiedFiles[Index];
		const FString FullFilename = Cache.GetDirectory() + Change.Filename.Get();

		// Move the asset before reimporting it. We always reimport moved assets to ensure that their import path is up to date
		if (Change.Action == DirectoryWatcher::EFileAction::Moved)
		{
			const FString OldFilename = Cache.GetDirectory() + Change.MovedFromFilename.Get();
			const auto Assets = Utils::FindAssetsPertainingToFile(*Registry, OldFilename);

			if (Assets.Num() == 1)
			{
				UObject* Asset = Assets[0].GetAsset();
				if (Asset && Utils::ExtractSourceFilePaths(Asset).Num() == 1)
				{
					UPackage* ExistingPackage = Asset->GetOutermost();

					const bool bAssetWasDirty = IsAssetDirty(Asset);

					const FString NewAssetName = ObjectTools::SanitizeObjectName(FPaths::GetBaseFilename(Change.Filename.Get()));
					const FString PackagePath = PackageTools::SanitizePackageName(MountedContentPath / FPaths::GetPath(Change.Filename.Get()));
					const FString FullDestPath = PackagePath / NewAssetName;

					if (ExistingPackage && ExistingPackage->FileName.ToString() == FullDestPath)
					{
						// No need to process this asset - it's already been moved to the right location
						Cache.CompleteTransaction(MoveTemp(Change));
						continue;
					}

					const FText SrcPathText = FText::FromString(Assets[0].PackageName.ToString()),
						DstPathText = FText::FromString(FullDestPath);

					if (FPackageName::DoesPackageExist(*FullDestPath))
					{
						Context.AddMessage(EMessageSeverity::Warning, FText::Format(LOCTEXT("MoveWarning_ExistingAsset", "Can't move {0} to {1} - one already exists."), SrcPathText, DstPathText));
					}
					else
					{
						TArray<FAssetRenameData> RenameData;
						RenameData.Emplace(Asset, PackagePath, NewAssetName);

						Context.AddMessage(EMessageSeverity::Info, FText::Format(LOCTEXT("Success_MovedAsset", "Moving asset {0} to {1}."),	SrcPathText, DstPathText));

						FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools").Get().RenameAssets(RenameData);

						TArray<FString> Filenames;
						Filenames.Add(FullFilename);

						// Update the reimport file names
						FReimportManager::Instance()->UpdateReimportPaths(Asset, Filenames);
						Asset->MarkPackageDirty();

						if (!bAssetWasDirty)
						{
							OutPackagesToSave.Add(Asset->GetOutermost());
						}
					}
				}
			}
		}
		else
		{
			// Modifications or additions are treated the same by this point
			for (const auto& AssetData : Utils::FindAssetsPertainingToFile(*Registry, FullFilename))
			{
				if (UObject* Asset = AssetData.GetAsset())
				{
					ReimportAsset(Asset, FullFilename, OutPackagesToSave, Context);
				}
			}
		}

		// Let the cache know that we've dealt with this change
		Cache.CompleteTransaction(MoveTemp(Change));

		if (TimeLimit.Exceeded())
		{
			ModifiedFiles.RemoveAt(0, Index + 1);
			return;
		}
	}

	ModifiedFiles.Empty();
}
/**
 * Exec handler, parsing the passed in command
 *
 * @param InWorld World Context
 * @param Cmd	Command to parse
 * @param Ar	output device used for logging
 */
bool FDebugToolExec::Exec( UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar )
{
	// these commands are only allowed in standalone games
#if UE_BUILD_SHIPPING || UE_BUILD_TEST
	if (GEngine->GetNetMode(InWorld) != NM_Standalone || (GEngine->GetWorldContextFromWorldChecked(InWorld).PendingNetGame != NULL))
	{
		return 0;
	}
	// Edits the class defaults.
	else
#endif
	if( FParse::Command(&Cmd,TEXT("EDITDEFAULT")) )
	{
		// not allowed in the editor as this command can have far reaching effects such as impacting serialization
		if (!GIsEditor)
		{
			UClass* Class = NULL;
			if( ParseObject<UClass>( Cmd, TEXT("CLASS="), Class, ANY_PACKAGE ) == false )
			{
				TCHAR ClassName[256];
				if ( FParse::Token(Cmd,ClassName,ARRAY_COUNT(ClassName), 1) )
				{
					Class = FindObject<UClass>( ANY_PACKAGE, ClassName);
				}
			}

			if (Class)
			{
				EditObject(Class->GetDefaultObject(), true);
			}
			else
			{
				Ar.Logf( TEXT("Missing class") );
			}
		}
		return 1;
	}
	else if (FParse::Command(&Cmd,TEXT("EDITOBJECT")))
	{
		UClass* searchClass = NULL;
		UObject* foundObj = NULL;
		// Search by class.
		if (ParseObject<UClass>(Cmd, TEXT("CLASS="), searchClass, ANY_PACKAGE))
		{
			// pick the first valid object
			for (FObjectIterator It(searchClass); It && foundObj == NULL; ++It) 
			{
				if (!It->IsPendingKill() && !It->IsTemplate())
				{
					foundObj = *It;
				}
			}
		}
		// Search by name.
		else
		{
			FName searchName;
			FString SearchPathName;
			if ( FParse::Value(Cmd, TEXT("NAME="), searchName) )
			{
				// Look for actor by name.
				for( TObjectIterator<UObject> It; It && foundObj == NULL; ++It )
				{
					if (It->GetFName() == searchName) 
					{
						foundObj = *It;
					}
				}
			}
			else if ( FParse::Token(Cmd,SearchPathName, true) )
			{
				foundObj = FindObject<UObject>(ANY_PACKAGE,*SearchPathName);
			}
		}

		// Bring up an property editing window for the found object.
		if (foundObj != NULL)
		{
			// not allowed in the editor unless it is a PIE object as this command can have far reaching effects such as impacting serialization
			if (!GIsEditor || ((!foundObj->IsTemplate() && (foundObj->GetOutermost()->PackageFlags & PKG_PlayInEditor))))
			{
				EditObject(foundObj, true);
			}
		}
		else
		{
			Ar.Logf(TEXT("Target not found"));
		}
		return 1;
	}
	else if (FParse::Command(&Cmd,TEXT("EDITARCHETYPE")))
	{
		UObject* foundObj = NULL;
		// require fully qualified path name
		FString SearchPathName;
		if (FParse::Token(Cmd, SearchPathName, true))
		{
			foundObj = FindObject<UObject>(ANY_PACKAGE,*SearchPathName);
		}

		// Bring up an property editing window for the found object.
		if (foundObj != NULL)
		{
			// not allowed in the editor unless it is a PIE object as this command can have far reaching effects such as impacting serialization
			if (!GIsEditor || ((!foundObj->IsTemplate() && (foundObj->GetOutermost()->PackageFlags & PKG_PlayInEditor))))
			{
				EditObject(foundObj, false);
			}
		}
		else
		{
			Ar.Logf(TEXT("Target not found"));
		}
		return 1;
	}
	// Edits an objects properties or copies them to the clipboard.
	else if( FParse::Command(&Cmd,TEXT("EDITACTOR")) )
	{
		UClass*		Class = NULL;
		AActor*		Found = NULL;

		if (FParse::Command(&Cmd, TEXT("TRACE")))
		{
			APlayerController* PlayerController = InWorld->GetFirstPlayerController();
			if (PlayerController != NULL)
			{
				// Do a trace in the player's facing direction and edit anything that's hit.
				FVector PlayerLocation;
				FRotator PlayerRotation;
				PlayerController->GetPlayerViewPoint(PlayerLocation, PlayerRotation);
				FHitResult Hit(1.0f);
				PlayerController->GetWorld()->LineTraceSingle(Hit, PlayerLocation, PlayerLocation + PlayerRotation.Vector() * 10000.f, ECC_Pawn, FCollisionQueryParams(NAME_None, true, PlayerController->GetPawn()));
				Found = Hit.GetActor();
			}
		}
		// Search by class.
		else if( ParseObject<UClass>( Cmd, TEXT("CLASS="), Class, ANY_PACKAGE ) && Class->IsChildOf(AActor::StaticClass()) )
		{
			UGameEngine* GameEngine = Cast<UGameEngine>(GEngine);
			
			// Look for the closest actor of this class to the player.
			FVector PlayerLocation(0.0f);
			APlayerController* PlayerController = InWorld->GetFirstPlayerController();
			if (PlayerController != NULL)
			{
				FRotator DummyRotation;
				PlayerController->GetPlayerViewPoint(PlayerLocation, DummyRotation);
			}

			float   MinDist = FLT_MAX;
			for( TActorIterator<AActor> It(InWorld, Class); It; ++It )
			{
				if ( !It->IsPendingKill() )
				{
					float const Dist = (PlayerController && It->GetRootComponent()) ? FVector::Dist(It->GetActorLocation(), PlayerLocation) : 0.f;
					if (Dist < MinDist)
					{
						MinDist = Dist;
						Found   = *It;
					}
				}
			}
		}
		// Search by name.
		else
		{
			FName ActorName;
			if( FParse::Value( Cmd, TEXT("NAME="), ActorName ) )
			{
				// Look for actor by name.
				for( FActorIterator It(InWorld); It; ++It )
				{
					if( It->GetFName() == ActorName )
					{
						Found = *It;
						break;
					}
				}
			}
		}

		// Bring up an property editing window for the found object.
		if( Found )
		{
			// not allowed in the editor unless it is a PIE object as this command can have far reaching effects such as impacting serialization
			if (!GIsEditor || ((!Found->IsTemplate() && (Found->GetOutermost()->PackageFlags & PKG_PlayInEditor))))
			{
				EditObject(Found, true);
			}
		}
		else
		{
			Ar.Logf( TEXT("Target not found") );
		}

		return 1;
	}
	else
	{
		return 0;
	}
}