ULevelStreaming* FWorldTileModel::CreateAssosiatedStreamingLevel() { ULevelStreaming* AssociatedStreamingLevel = NULL; ULevel* Level = GetLevelObject(); if (Level) { FName PackageName = Level->GetOutermost()->GetFName(); UWorld* PersistentWorld = LevelCollectionModel.GetWorld(); // Try to find existing object first int32 FoundIndex = PersistentWorld->StreamingLevels.FindMatch(ULevelStreaming::FPackageNameMatcher(PackageName)); if (FoundIndex != INDEX_NONE) { AssociatedStreamingLevel = PersistentWorld->StreamingLevels[FoundIndex]; } else { // Create new streaming level AssociatedStreamingLevel = Cast<ULevelStreaming>( StaticConstructObject(ULevelStreamingKismet::StaticClass(), PersistentWorld, NAME_None, RF_Transient, NULL) ); // AssociatedStreamingLevel->PackageName = PackageName; AssociatedStreamingLevel->DrawColor = FColor::MakeRandomColor(); AssociatedStreamingLevel->LevelTransform = FTransform::Identity; AssociatedStreamingLevel->PackageNameToLoad = PackageName; // PersistentWorld->StreamingLevels.Add(AssociatedStreamingLevel); } } return AssociatedStreamingLevel; }
void FLevelModel::SetVisible(bool bVisible) { //don't create unnecessary transactions if (IsVisible() == bVisible) { return; } const bool oldIsDirty = IsDirty(); const FScopedTransaction Transaction(LOCTEXT("ToggleVisibility", "Toggle Level Visibility")); //this call hides all owned actors, etc EditorLevelUtils::SetLevelVisibility( GetLevelObject(), bVisible, false ); if (!oldIsDirty) { // don't set the dirty flag if we're just changing the visibility of the level within the editor ULevel* Level = GetLevelObject(); if (Level) { Level->GetOutermost()->SetDirtyFlag(false); } } }
/** Generates a sub-level Blueprints sub-menu */ static void MakeSubLevelsMenu(FMenuBuilder& InMenuBuilder, TWeakPtr< SLevelEditor > InLvlEditor) { FSlateIcon EditBP(FEditorStyle::Get().GetStyleSetName(), TEXT("LevelEditor.OpenLevelBlueprint")); InMenuBuilder.BeginSection(NAME_None, LOCTEXT("SubLevelsHeading", "Sub-Level Blueprints")); { UWorld* World = InLvlEditor.Pin()->GetWorld(); for (int32 iLevel = 0; iLevel < World->GetNumLevels(); iLevel++) { ULevel* Level = World->GetLevel(iLevel); if (Level != NULL && Level->GetOutermost() != NULL) { if (!Level->IsPersistentLevel()) { FUIAction UIAction ( FExecuteAction::CreateStatic(&FLevelEditorToolBar::OnOpenSubLevelBlueprint, Level) ); FText DisplayName = FText::Format(LOCTEXT("SubLevelBlueprintItem", "Edit {LevelName}"), FText::FromString(FPaths::GetCleanFilename(Level->GetOutermost()->GetName()))); InMenuBuilder.AddMenuEntry(DisplayName, FText::GetEmpty(), EditBP, UIAction); } } } } InMenuBuilder.EndSection(); }
FSlateTextureDataPtr FTileThumbnail::UpdateThumbnail() { // No need images for persistent and always loaded levels if (TileModel.IsPersistent()) { return ToSlateTextureData(nullptr); } // Load image from a package header if (!TileModel.IsVisible() || TileModel.IsSimulating()) { const FName LevelAssetName = TileModel.GetAssetName(); TSet<FName> ObjectFullNames; ObjectFullNames.Add(LevelAssetName); FThumbnailMap ThumbnailMap; if (ThumbnailTools::ConditionallyLoadThumbnailsFromPackage(TileModel.GetPackageFileName(), ObjectFullNames, ThumbnailMap)) { const FObjectThumbnail* ObjectThumbnail = ThumbnailMap.Find(LevelAssetName); return ToSlateTextureData(ObjectThumbnail); } } // Render image from a visible level else { ULevel* TargetLevel = TileModel.GetLevelObject(); if (TargetLevel) { FIntPoint RTSize = ThumbnailRenderTarget->GetSizeXY(); // Set persistent world package as transient to avoid package dirtying during thumbnail rendering FUnmodifiableObject ImmuneWorld(TargetLevel->OwningWorld); FObjectThumbnail NewThumbnail; // Generate the thumbnail ThumbnailTools::RenderThumbnail( TargetLevel, RTSize.X, RTSize.Y, ThumbnailTools::EThumbnailTextureFlushMode::NeverFlush, ThumbnailRenderTarget, &NewThumbnail ); UPackage* MyOutermostPackage = CastChecked<UPackage>(TargetLevel->GetOutermost()); ThumbnailTools::CacheThumbnail(TileModel.GetAssetName().ToString(), &NewThumbnail, MyOutermostPackage); return ToSlateTextureData(&NewThumbnail); } } return ToSlateTextureData(nullptr); }
TArray<UPackage*> FLevelCollectionModel::GetPackagesList(const FLevelModelList& InList) { TArray<UPackage*> ResultList; for (auto It = InList.CreateConstIterator(); It; ++It) { ULevel* Level = (*It)->GetLevelObject(); if (Level) { ResultList.Add(Level->GetOutermost()); } } return ResultList; }
FString FLevelViewModel::GetFileSizeString() const { FString MemorySizeString; ULevel* CurLevel = Level.Get(); if ( CurLevel && GetDefault<ULevelBrowserSettings>()->bDisplayFileSize ) { // Update metrics static const float ByteConversion = 1.0f / 1024.0f; float FileSize = CurLevel->GetOutermost()->GetFileSize() * ByteConversion * ByteConversion; MemorySizeString += FString::Printf( TEXT( "%.2f" ), FileSize ); } return MemorySizeString; }
FString FLevelModel::GetFileSizeString() const { FString MemorySizeString; ULevel* Level = GetLevelObject(); if (Level && Editor->AccessEditorUserSettings().bDisplayFileSizeInLevelBrowser) { // Update metrics static const float ByteConversion = 1.0f / 1024.0f; float FileSize = Level->GetOutermost()->GetFileSize() * ByteConversion * ByteConversion; MemorySizeString += FString::Printf(TEXT( "%.2f" ), FileSize); } return MemorySizeString; }
void FLevelCollectionModel::CacheCanExecuteSourceControlVars() const { bCanExecuteSCCCheckOut = false; bCanExecuteSCCOpenForAdd = false; bCanExecuteSCCCheckIn = false; bCanExecuteSCC = false; ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider(); for (auto It = SelectedLevelsList.CreateConstIterator(); It; ++It) { if (ISourceControlModule::Get().IsEnabled() && SourceControlProvider.IsAvailable()) { bCanExecuteSCC = true; ULevel* Level = (*It)->GetLevelObject(); if (Level) { // Check the SCC state for each package in the selected paths FSourceControlStatePtr SourceControlState = SourceControlProvider.GetState(Level->GetOutermost(), EStateCacheUsage::Use); if (SourceControlState.IsValid()) { if (SourceControlState->CanCheckout()) { bCanExecuteSCCCheckOut = true; } else if (!SourceControlState->IsSourceControlled()) { bCanExecuteSCCOpenForAdd = true; } else if (SourceControlState->IsCheckedOut() || SourceControlState->IsAdded()) { bCanExecuteSCCCheckIn = true; } } } } if (bCanExecuteSCCCheckOut && bCanExecuteSCCOpenForAdd && bCanExecuteSCCCheckIn) { // All options are available, no need to keep iterating break; } } }
/** Check if the object is in a visible level */ bool IsInVisibleLevel( UObject* InObject, UWorld* InWorld ) const { check( InObject ); check( InWorld ); UObject* ObjectPackage = InObject->GetOutermost(); for( int32 LevelIndex=0; LevelIndex<InWorld->GetNumLevels(); LevelIndex++ ) { ULevel* Level = InWorld->GetLevel(LevelIndex); if( Level && Level->GetOutermost() == ObjectPackage ) { return true; } } return false; }
void UUnrealEdEngine::ConvertMatinees() { FVector StartLocation= FVector::ZeroVector; UWorld* World = GWorld; if( World ) { ULevel* Level = World->GetCurrentLevel(); if( !Level ) { Level = World->PersistentLevel; } check(Level); for( TObjectIterator<UInterpData> It; It; ++It ) { UInterpData* InterpData = *It; if( InterpData->IsIn( Level ) ) { // We dont care about renaming references or adding redirectors. References to this will be old seqact_interps GEditor->RenameObject( InterpData, Level->GetOutermost(), *InterpData->GetName() ); AMatineeActor* MatineeActor = Level->OwningWorld->SpawnActor<AMatineeActor>(StartLocation, FRotator::ZeroRotator); StartLocation.Y += 50; MatineeActor->MatineeData = InterpData; UProperty* MatineeDataProp = NULL; for( UProperty* Property = MatineeActor->GetClass()->PropertyLink; Property != NULL; Property = Property->PropertyLinkNext ) { if( Property->GetName() == TEXT("MatineeData") ) { MatineeDataProp = Property; break; } } FPropertyChangedEvent PropertyChangedEvent( MatineeDataProp ); MatineeActor->PostEditChangeProperty( PropertyChangedEvent ); } } } }
void FShadowMapPendingTexture::StartEncoding(UWorld* InWorld) { // Create the shadow-map texture. UShadowMapTexture2D* Texture = new(Outer) UShadowMapTexture2D(FPostConstructInitializeProperties()); Texture->Filter = GUseBilinearLightmaps ? TF_Default : TF_Nearest; // Signed distance field textures get stored in linear space, since they need more precision near .5. Texture->SRGB = false; Texture->LODGroup = TEXTUREGROUP_Shadowmap; Texture->ShadowmapFlags = ShadowmapFlags; Texture->Source.Init2DWithMipChain(GetSizeX(), GetSizeY(), TSF_BGRA8); Texture->MipGenSettings = TMGS_LeaveExistingMips; Texture->CompressionNone = true; int32 TextureSizeX = Texture->Source.GetSizeX(); int32 TextureSizeY = Texture->Source.GetSizeY(); { // Create the uncompressed top mip-level. TArray< TArray<FFourDistanceFieldSamples> > MipData; FShadowMap2D::EncodeSingleTexture(*this, Texture, MipData); // Copy the mip-map data into the UShadowMapTexture2D's mip-map array. for(int32 MipIndex = 0;MipIndex < MipData.Num();MipIndex++) { FColor* DestMipData = (FColor*)Texture->Source.LockMip(MipIndex); uint32 MipSizeX = FMath::Max(1,TextureSizeX >> MipIndex); uint32 MipSizeY = FMath::Max(1,TextureSizeY >> MipIndex); for(uint32 Y = 0;Y < MipSizeY;Y++) { for(uint32 X = 0;X < MipSizeX;X++) { const FFourDistanceFieldSamples& SourceSample = MipData[MipIndex][Y * MipSizeX + X]; DestMipData[ Y * MipSizeX + X ] = FColor(SourceSample.Samples[0].Distance, SourceSample.Samples[1].Distance, SourceSample.Samples[2].Distance, SourceSample.Samples[3].Distance); } } Texture->Source.UnlockMip(MipIndex); } } // Update stats. int32 TextureSize = Texture->CalcTextureMemorySizeEnum( TMC_AllMips ); GNumShadowmapTotalTexels += TextureSizeX * TextureSizeY; GNumShadowmapTextures++; GShadowmapTotalSize += TextureSize; GShadowmapTotalStreamingSize += (ShadowmapFlags & SMF_Streamed) ? TextureSize : 0; UPackage* TexturePackage = Texture->GetOutermost(); for ( int32 LevelIndex=0; TexturePackage && LevelIndex < InWorld->GetNumLevels(); LevelIndex++ ) { ULevel* Level = InWorld->GetLevel(LevelIndex); UPackage* LevelPackage = Level->GetOutermost(); if ( TexturePackage == LevelPackage ) { Level->ShadowmapTotalSize += float(TextureSize) / 1024.0f; break; } } // Update the texture resource. Texture->BeginCachePlatformData(); Texture->FinishCachePlatformData(); Texture->UpdateResource(); }
void FLevelCollectionModel::SaveLevels(const FLevelModelList& InLevelList) { if (IsReadOnly()) { return; } FLevelModelList LevelModelsToSave; TArray<ULevel*> LevelsToSave; for (auto It = InLevelList.CreateConstIterator(); It; ++It) { if ((*It)->GetLevelObject()) { if (!(*It)->IsVisible()) { FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "UnableToSaveInvisibleLevels", "Save aborted. Levels must be made visible before they can be saved.") ); return; } else if ((*It)->IsLocked()) { FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "UnableToSaveLockedLevels", "Save aborted. Level must be unlocked before it can be saved.") ); return; } LevelModelsToSave.Add(*It); LevelsToSave.Add((*It)->GetLevelObject()); } } TArray< UPackage* > PackagesNotNeedingCheckout; // Prompt the user to check out the levels from source control before saving if (FEditorFileUtils::PromptToCheckoutLevels(false, LevelsToSave, &PackagesNotNeedingCheckout)) { for (auto It = LevelsToSave.CreateIterator(); It; ++It) { FEditorFileUtils::SaveLevel(*It); } } else if (PackagesNotNeedingCheckout.Num() > 0) { // The user canceled the checkout dialog but some packages didn't need to be checked out in order to save // For each selected level if the package its in didn't need to be saved, save the level! for (int32 LevelIdx = 0; LevelIdx < LevelsToSave.Num(); ++LevelIdx) { ULevel* Level = LevelsToSave[LevelIdx]; if (PackagesNotNeedingCheckout.Contains(Level->GetOutermost())) { FEditorFileUtils::SaveLevel(Level); } else { //remove it from the list, so that only successfully saved levels are highlighted when saving is complete LevelModelsToSave.RemoveAt(LevelIdx); LevelsToSave.RemoveAt(LevelIdx); } } } // Select tiles that were saved successfully SetSelectedLevels(LevelModelsToSave); }
void FLevelCollectionModel::SCCDiffAgainstDepot(const FLevelModelList& InList, UEditorEngine* InEditor) { // Load the asset registry module FAssetToolsModule& AssetToolsModule = FModuleManager::GetModuleChecked<FAssetToolsModule>("AssetTools"); ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider(); // Iterate over each selected asset for (auto It = InList.CreateConstIterator(); It; ++It) { ULevel* Level = (*It)->GetLevelObject(); if (Level == NULL) { return; } UPackage* OriginalPackage = Level->GetOutermost(); FString PackageName = OriginalPackage->GetName(); // Make sure our history is up to date auto UpdateStatusOperation = ISourceControlOperation::Create<FUpdateStatus>(); UpdateStatusOperation->SetUpdateHistory(true); SourceControlProvider.Execute(UpdateStatusOperation, OriginalPackage); // Get the SCC state FSourceControlStatePtr SourceControlState = SourceControlProvider.GetState( OriginalPackage, EStateCacheUsage::Use ); // If the level is in SCC. if (SourceControlState.IsValid() && SourceControlState->IsSourceControlled()) { // Get the file name of package FString RelativeFileName; if(FPackageName::DoesPackageExist(PackageName, NULL, &RelativeFileName)) { if (SourceControlState->GetHistorySize() > 0) { auto Revision = SourceControlState->GetHistoryItem(0); check(Revision.IsValid()); // Get the head revision of this package from source control FString AbsoluteFileName = FPaths::ConvertRelativePathToFull(RelativeFileName); FString TempFileName; if (Revision->Get(TempFileName)) { // Forcibly disable compile on load in case we are loading old blueprints that might try to update/compile TGuardValue<bool> DisableCompileOnLoad(GForceDisableBlueprintCompileOnLoad, true); // Try and load that package FText NotMapReason; UPackage* OldPackage = LoadPackage(NULL, *TempFileName, LOAD_None); if(OldPackage != NULL && InEditor->PackageIsAMapFile(*TempFileName, NotMapReason)) { /* Set the revision information*/ UPackage* Package = OriginalPackage; FRevisionInfo OldRevision; OldRevision.Changelist = Revision->GetCheckInIdentifier(); OldRevision.Date = Revision->GetDate(); OldRevision.Revision = Revision->GetRevision(); FRevisionInfo NewRevision; NewRevision.Revision = TEXT(""); // Dump assets to temp text files FString OldTextFilename = AssetToolsModule.Get().DumpAssetToTempFile(OldPackage); FString NewTextFilename = AssetToolsModule.Get().DumpAssetToTempFile(OriginalPackage); FString DiffCommand = GetDefault<UEditorLoadingSavingSettings>()->TextDiffToolPath.FilePath; AssetToolsModule.Get().CreateDiffProcess(DiffCommand, OldTextFilename, NewTextFilename); AssetToolsModule.Get().DiffAssets(OldPackage, OriginalPackage, OldRevision, NewRevision); } } } } } } }
/** This will set the StreamingLevels TMap with the current Streaming Level Status and also set which level the player is in **/ void GetLevelStreamingStatus( UWorld* World, TMap<FName,int32>& StreamingLevels, FString& LevelPlayerIsInName ) { FWorldContext &Context = GEngine->WorldContextFromWorld(World); // Iterate over the world info's level streaming objects to find and see whether levels are loaded, visible or neither. for( int32 LevelIndex=0; LevelIndex<World->StreamingLevels.Num(); LevelIndex++ ) { ULevelStreaming* LevelStreaming = World->StreamingLevels[LevelIndex]; if( LevelStreaming && LevelStreaming->PackageName != NAME_None && LevelStreaming->PackageName != World->GetOutermost()->GetFName() ) { ULevel* Level = LevelStreaming->GetLoadedLevel(); if( Level != NULL ) { if( World->ContainsLevel( Level ) == true ) { if( World->CurrentLevelPendingVisibility == Level ) { StreamingLevels.Add( LevelStreaming->PackageName, LEVEL_MakingVisible ); } else { StreamingLevels.Add( LevelStreaming->PackageName, LEVEL_Visible ); } } else { StreamingLevels.Add( LevelStreaming->PackageName, LEVEL_Loaded ); } } else { // See whether the level's world object is still around. UPackage* LevelPackage = Cast<UPackage>(StaticFindObjectFast( UPackage::StaticClass(), NULL, LevelStreaming->PackageName )); UWorld* LevelWorld = NULL; if( LevelPackage ) { LevelWorld = UWorld::FindWorldInPackage(LevelPackage); } if( LevelWorld ) { StreamingLevels.Add( LevelStreaming->PackageName, LEVEL_UnloadedButStillAround ); } else if( GetAsyncLoadPercentage( *LevelStreaming->PackageName.ToString() ) >= 0 ) { StreamingLevels.Add( LevelStreaming->PackageName, LEVEL_Loading ); } else { StreamingLevels.Add( LevelStreaming->PackageName, LEVEL_Unloaded ); } } } } // toss in the levels being loaded by PrepareMapChange for( int32 LevelIndex=0; LevelIndex < Context.LevelsToLoadForPendingMapChange.Num(); LevelIndex++ ) { const FName LevelName = Context.LevelsToLoadForPendingMapChange[LevelIndex]; StreamingLevels.Add(LevelName, LEVEL_Preloading); } ULevel* LevelPlayerIsIn = NULL; for( FConstPlayerControllerIterator Iterator = World->GetPlayerControllerIterator(); Iterator; ++Iterator ) { APlayerController* PlayerController = *Iterator; if( PlayerController->GetPawn() != NULL ) { // need to do a trace down here //TraceActor = Trace( out_HitLocation, out_HitNormal, TraceDest, TraceStart, false, TraceExtent, HitInfo, true ); FHitResult Hit(1.f); // this will not work for flying around :-( static FName NAME_FindLevel = FName(TEXT("FindLevel"), true); PlayerController->GetWorld()->LineTraceSingle(Hit,PlayerController->GetPawn()->GetActorLocation(), (PlayerController->GetPawn()->GetActorLocation()-FVector(0.f, 0.f, 256.f)), FCollisionQueryParams(NAME_FindLevel, true, PlayerController->GetPawn()), FCollisionObjectQueryParams(ECC_WorldStatic)); /** @todo UE4 FIXME if( Hit.Level != NULL ) { LevelPlayerIsIn = Hit.Level; } else */ if( Hit.GetActor() != NULL ) { LevelPlayerIsIn = Hit.GetActor()->GetLevel(); } else if( Hit.Component != NULL && Hit.Component->GetOwner() != NULL ) { AActor* Owner = Hit.Component->GetOwner(); if (Owner) { LevelPlayerIsIn = Owner->GetLevel(); } else { // This happens for BSP where the ModelComponent's outer is the level LevelPlayerIsIn = Hit.Component->GetTypedOuter<ULevel>(); } } } } // this no longer seems to be getting the correct level name :-( LevelPlayerIsInName = LevelPlayerIsIn != NULL ? LevelPlayerIsIn->GetOutermost()->GetName() : TEXT("None"); }
bool FEditorBuildUtils::EditorAutomatedBuildAndSubmit( const FEditorAutomatedBuildSettings& BuildSettings, FText& OutErrorMessages ) { // Assume the build is successful to start bool bBuildSuccessful = true; // Keep a set of packages that should be submitted to source control at the end of a successful build. The build preparation and processing // will add and remove from the set depending on build settings, errors, etc. TSet<UPackage*> PackagesToSubmit; // Perform required preparations for the automated build process bBuildSuccessful = PrepForAutomatedBuild( BuildSettings, PackagesToSubmit, OutErrorMessages ); // If the preparation went smoothly, attempt the actual map building process if ( bBuildSuccessful ) { bBuildSuccessful = EditorBuild( GWorld, EBuildOptions::BuildAllSubmit ); // If the map build failed, log the error if ( !bBuildSuccessful ) { LogErrorMessage( NSLOCTEXT("UnrealEd", "AutomatedBuild_Error_BuildFailed", "The map build failed or was canceled."), OutErrorMessages ); } } // If any map errors resulted from the build, process them according to the behavior specified in the build settings if ( bBuildSuccessful && FMessageLog("MapCheck").NumMessages( EMessageSeverity::Warning ) > 0 ) { bBuildSuccessful = ProcessAutomatedBuildBehavior( BuildSettings.BuildErrorBehavior, NSLOCTEXT("UnrealEd", "AutomatedBuild_Error_MapErrors", "Map errors occurred while building.\n\nAttempt to continue the build?"), OutErrorMessages ); } // If it's still safe to proceed, attempt to save all of the level packages that have been marked for submission if ( bBuildSuccessful ) { UPackage* CurOutermostPkg = GWorld->PersistentLevel->GetOutermost(); FString PackagesThatFailedToSave; // Try to save the p-level if it should be submitted if ( PackagesToSubmit.Contains( CurOutermostPkg ) && !FEditorFileUtils::SaveLevel( GWorld->PersistentLevel ) ) { // If the p-level failed to save, remove it from the set of packages to submit PackagesThatFailedToSave += FString::Printf( TEXT("%s\n"), *CurOutermostPkg->GetName() ); PackagesToSubmit.Remove( CurOutermostPkg ); } // Try to save each streaming level (if they should be submitted) for ( TArray<ULevelStreaming*>::TIterator LevelIter( GWorld->StreamingLevels ); LevelIter; ++LevelIter ) { ULevelStreaming* CurStreamingLevel = *LevelIter; if ( CurStreamingLevel != NULL ) { ULevel* Level = CurStreamingLevel->GetLoadedLevel(); if ( Level != NULL ) { CurOutermostPkg = Level->GetOutermost(); if ( PackagesToSubmit.Contains( CurOutermostPkg ) && !FEditorFileUtils::SaveLevel( Level ) ) { // If a save failed, remove the streaming level from the set of packages to submit PackagesThatFailedToSave += FString::Printf( TEXT("%s\n"), *CurOutermostPkg->GetName() ); PackagesToSubmit.Remove( CurOutermostPkg ); } } } } // If any packages failed to save, process the behavior specified by the build settings to see how the process should proceed if ( PackagesThatFailedToSave.Len() > 0 ) { bBuildSuccessful = ProcessAutomatedBuildBehavior( BuildSettings.FailedToSaveBehavior, FText::Format( NSLOCTEXT("UnrealEd", "AutomatedBuild_Error_FilesFailedSave", "The following assets failed to save and cannot be submitted:\n\n{0}\n\nAttempt to continue the build?"), FText::FromString(PackagesThatFailedToSave) ), OutErrorMessages ); } } // If still safe to proceed, make sure there are actually packages remaining to submit if ( bBuildSuccessful ) { bBuildSuccessful = PackagesToSubmit.Num() > 0; if ( !bBuildSuccessful ) { LogErrorMessage( NSLOCTEXT("UnrealEd", "AutomatedBuild_Error_NoValidLevels", "None of the current levels are valid for submission; automated build aborted."), OutErrorMessages ); } } // Finally, if everything has gone smoothly, submit the requested packages to source control if ( bBuildSuccessful ) { SubmitPackagesForAutomatedBuild( PackagesToSubmit, BuildSettings ); } // Check if the user requested the editor shutdown at the conclusion of the automated build if ( BuildSettings.bShutdownEditorOnCompletion ) { FPlatformMisc::RequestExit( false ); } return bBuildSuccessful; }