void UAIGraph::RemoveOrphanedNodes() { TSet<UObject*> NodeInstances; CollectAllNodeInstances(NodeInstances); NodeInstances.Remove(nullptr); // Obtain a list of all nodes actually in the asset and discard unused nodes TArray<UObject*> AllInners; const bool bIncludeNestedObjects = false; GetObjectsWithOuter(GetOuter(), AllInners, bIncludeNestedObjects); for (auto InnerIt = AllInners.CreateConstIterator(); InnerIt; ++InnerIt) { UObject* TestObject = *InnerIt; if (!NodeInstances.Contains(TestObject) && CanRemoveNestedObject(TestObject)) { TestObject->SetFlags(RF_Transient); TestObject->Rename(NULL, GetTransientPackage(), REN_DontCreateRedirectors | REN_NonTransactional | REN_ForceNoResetLoaders); } } }
void UActorRecording::SyncTrackedComponents(bool bIncludeNonCDO/*=true*/) { TArray<USceneComponent*> NewComponentArray; GetSceneComponents(NewComponentArray, bIncludeNonCDO); // Expire section recorders that are watching components no longer attached to our actor TSet<USceneComponent*> ExpiredComponents; for (TWeakObjectPtr<USceneComponent>& WeakComponent : TrackedComponents) { if (USceneComponent* Component = WeakComponent.Get()) { ExpiredComponents.Add(Component); } } for (USceneComponent* Component : NewComponentArray) { ExpiredComponents.Remove(Component); } for (TSharedPtr<IMovieSceneSectionRecorder>& SectionRecorder : SectionRecorders) { if (USceneComponent* Component = Cast<USceneComponent>(SectionRecorder->GetSourceObject())) { if (ExpiredComponents.Contains(Component)) { SectionRecorder->InvalidateObjectToRecord(); } } } TrackedComponents.Reset(NewComponentArray.Num()); for(USceneComponent* SceneComponent : NewComponentArray) { TrackedComponents.Add(SceneComponent); } }
void FUserDefinedStructureCompilerUtils::CompileStruct(class UUserDefinedStruct* Struct, class FCompilerResultsLog& MessageLog, bool bForceRecompile) { if (FStructureEditorUtils::UserDefinedStructEnabled() && Struct) { TSet<UBlueprint*> BlueprintsThatHaveBeenRecompiled; TSet<UBlueprint*> BlueprintsToRecompile; TArray<UUserDefinedStruct*> ChangedStructs; if (FUserDefinedStructureCompilerInner::ShouldBeCompiled(Struct) || bForceRecompile) { ChangedStructs.Add(Struct); } for (int32 StructIdx = 0; StructIdx < ChangedStructs.Num(); ++StructIdx) { UUserDefinedStruct* ChangedStruct = ChangedStructs[StructIdx]; if (ChangedStruct) { FStructureEditorUtils::BroadcastPreChange(ChangedStruct); FUserDefinedStructureCompilerInner::ReplaceStructWithTempDuplicate(ChangedStruct, BlueprintsToRecompile, ChangedStructs); ChangedStruct->Status = EUserDefinedStructureStatus::UDSS_Dirty; } } // COMPILE IN PROPER ORDER FUserDefinedStructureCompilerInner::BuildDependencyMapAndCompile(ChangedStructs, MessageLog); // UPDATE ALL THINGS DEPENDENT ON COMPILED STRUCTURES for (TObjectIterator<UK2Node> It(RF_Transient | RF_PendingKill | RF_ClassDefaultObject, true); It && ChangedStructs.Num(); ++It) { bool bReconstruct = false; UK2Node* Node = *It; if (Node && !Node->HasAnyFlags(RF_Transient | RF_PendingKill)) { // If this is a struct operation node operation on the changed struct we must reconstruct if (UK2Node_StructOperation* StructOpNode = Cast<UK2Node_StructOperation>(Node)) { UUserDefinedStruct* StructInNode = Cast<UUserDefinedStruct>(StructOpNode->StructType); if (StructInNode && ChangedStructs.Contains(StructInNode)) { bReconstruct = true; } } if (!bReconstruct) { // Look through the nodes pins and if any of them are split and the type of the split pin is a user defined struct we need to reconstruct for (UEdGraphPin* Pin : Node->Pins) { if (Pin->SubPins.Num() > 0) { UUserDefinedStruct* StructType = Cast<UUserDefinedStruct>(Pin->PinType.PinSubCategoryObject.Get()); if (StructType && ChangedStructs.Contains(StructType)) { bReconstruct = true; break; } } } } } if (bReconstruct) { if (UBlueprint* FoundBlueprint = Node->GetBlueprint()) { // The blueprint skeleton needs to be updated before we reconstruct the node // or else we may have member references that point to the old skeleton if (!BlueprintsThatHaveBeenRecompiled.Contains(FoundBlueprint)) { BlueprintsThatHaveBeenRecompiled.Add(FoundBlueprint); BlueprintsToRecompile.Remove(FoundBlueprint); FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(FoundBlueprint); } Node->ReconstructNode(); } } } for (auto BPIter = BlueprintsToRecompile.CreateIterator(); BPIter; ++BPIter) { FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(*BPIter); } for (auto ChangedStruct : ChangedStructs) { if (ChangedStruct) { FStructureEditorUtils::BroadcastPostChange(ChangedStruct); ChangedStruct->MarkPackageDirty(); } } } }
void UMaterialParameterCollection::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) { // If the array counts have changed, an element has been added or removed, and we need to update the uniform buffer layout, // Which also requires recompiling any referencing materials if (ScalarParameters.Num() != PreviousScalarParameters.Num() || VectorParameters.Num() != PreviousVectorParameters.Num()) { // Limit the count of parameters to fit within uniform buffer limits const uint32 MaxScalarParameters = 1024; if (ScalarParameters.Num() > MaxScalarParameters) { ScalarParameters.RemoveAt(MaxScalarParameters, ScalarParameters.Num() - MaxScalarParameters); } const uint32 MaxVectorParameters = 1024; if (VectorParameters.Num() > MaxVectorParameters) { VectorParameters.RemoveAt(MaxVectorParameters, VectorParameters.Num() - MaxVectorParameters); } // Generate a new Id so that unloaded materials that reference this collection will update correctly on load StateId = FGuid::NewGuid(); // Update the uniform buffer layout CreateBufferStruct(); // Recreate each instance of this collection for (TObjectIterator<UWorld> It; It; ++It) { UWorld* CurrentWorld = *It; CurrentWorld->AddParameterCollectionInstance(this, false); } // Build set of changed parameter names TSet<FName> ParameterNames; for (const FCollectionVectorParameter& Param : PreviousVectorParameters) { ParameterNames.Add(Param.ParameterName); } for (const FCollectionScalarParameter& Param : PreviousScalarParameters) { ParameterNames.Add(Param.ParameterName); } for (const FCollectionVectorParameter& Param : VectorParameters) { ParameterNames.Remove(Param.ParameterName); } for (const FCollectionScalarParameter& Param : ScalarParameters) { ParameterNames.Remove(Param.ParameterName); } // Create a material update context so we can safely update materials using this parameter collection. { FMaterialUpdateContext UpdateContext; // Go through all materials in memory and recompile them if they use this material parameter collection for (TObjectIterator<UMaterial> It; It; ++It) { UMaterial* CurrentMaterial = *It; bool bRecompile = false; // Preview materials often use expressions for rendering that are not in their Expressions array, // And therefore their MaterialParameterCollectionInfos are not up to date. if (CurrentMaterial->bIsPreviewMaterial) { bRecompile = true; } else { for (int32 FunctionIndex = 0; FunctionIndex < CurrentMaterial->MaterialParameterCollectionInfos.Num() && !bRecompile; FunctionIndex++) { if (CurrentMaterial->MaterialParameterCollectionInfos[FunctionIndex].ParameterCollection == this) { TArray<UMaterialExpressionCollectionParameter*> CollectionParameters; CurrentMaterial->GetAllExpressionsInMaterialAndFunctionsOfType(CollectionParameters); for (UMaterialExpressionCollectionParameter* CollectionParameter : CollectionParameters) { if (ParameterNames.Contains(CollectionParameter->ParameterName)) { bRecompile = true; break; } } } } } if (bRecompile) { UpdateContext.AddMaterial(CurrentMaterial); // Propagate the change to this material CurrentMaterial->PreEditChange(NULL); CurrentMaterial->PostEditChange(); CurrentMaterial->MarkPackageDirty(); } } } } // Update each world's scene with the new instance, and update each instance's uniform buffer to reflect the changes made by the user for (TObjectIterator<UWorld> It; It; ++It) { UWorld* CurrentWorld = *It; CurrentWorld->UpdateParameterCollectionInstances(true); } PreviousScalarParameters.Empty(); PreviousVectorParameters.Empty(); Super::PostEditChangeProperty(PropertyChangedEvent); }
bool FPluginManager::ConfigureEnabledPlugins() { if(!bHaveConfiguredEnabledPlugins) { // Don't need to run this again bHaveConfiguredEnabledPlugins = true; // If a current project is set, check that we know about any plugin that's explicitly enabled const FProjectDescriptor *Project = IProjectManager::Get().GetCurrentProject(); const bool bHasProjectFile = Project != nullptr; // Get all the enabled plugin names TArray< FString > EnabledPluginNames; #if IS_PROGRAM // Programs can also define the list of enabled plugins in ini GConfig->GetArray(TEXT("Plugins"), TEXT("ProgramEnabledPlugins"), EnabledPluginNames, GEngineIni); #endif #if !IS_PROGRAM || HACK_HEADER_GENERATOR if (!FParse::Param(FCommandLine::Get(), TEXT("NoEnginePlugins"))) { FProjectManager::Get().GetEnabledPlugins(EnabledPluginNames); } #endif // Build a set from the array TSet< FString > AllEnabledPlugins; AllEnabledPlugins.Append(MoveTemp(EnabledPluginNames)); // Enable all the plugins by name for (const TSharedRef< FPlugin > Plugin : AllPlugins) { if (AllEnabledPlugins.Contains(Plugin->Name)) { Plugin->bEnabled = (!IS_PROGRAM || !bHasProjectFile) || IsPluginSupportedByCurrentTarget(Plugin); if (!Plugin->bEnabled) { AllEnabledPlugins.Remove(Plugin->Name); } } } if (bHasProjectFile) { // Take a copy of the Project's plugins as we may remove some TArray<FPluginReferenceDescriptor> PluginsCopy = Project->Plugins; for(const FPluginReferenceDescriptor& Plugin: PluginsCopy) { if ((Plugin.bEnabled && !FindPluginInstance(Plugin.Name).IsValid()) && (!IS_PROGRAM || AllEnabledPlugins.Contains(Plugin.Name))) // skip if this is a program and the plugin is not enabled { FText Caption(LOCTEXT("PluginMissingCaption", "Plugin missing")); if(Plugin.MarketplaceURL.Len() > 0) { if(FMessageDialog::Open(EAppMsgType::YesNo, FText::Format(LOCTEXT("PluginMissingError", "This project requires the {0} plugin.\n\nWould you like to download it from the the Marketplace?"), FText::FromString(Plugin.Name)), &Caption) == EAppReturnType::Yes) { FString Error; FPlatformProcess::LaunchURL(*Plugin.MarketplaceURL, nullptr, &Error); if(Error.Len() > 0) FMessageDialog::Open(EAppMsgType::Ok, FText::FromString(Error)); return false; } } else { FString Description = (Plugin.Description.Len() > 0) ? FString::Printf(TEXT("\n\n%s"), *Plugin.Description) : FString(); FMessageDialog::Open(EAppMsgType::Ok, FText::Format(LOCTEXT("PluginRequiredError", "This project requires the {0} plugin. {1}"), FText::FromString(Plugin.Name), FText::FromString(Description)), &Caption); if (FMessageDialog::Open(EAppMsgType::YesNo, FText::Format(LOCTEXT("PluginMissingDisable", "Would you like to disable {0}? You will no longer be able to open any assets created using it."), FText::FromString(Plugin.Name)), &Caption) == EAppReturnType::No) { return false; } FText FailReason; if (!IProjectManager::Get().SetPluginEnabled(*Plugin.Name, false, FailReason)) { FMessageDialog::Open(EAppMsgType::Ok, FailReason); } } } } } // If we made it here, we have all the required plugins bHaveAllRequiredPlugins = true; for(const TSharedRef<FPlugin>& Plugin: AllPlugins) { if (Plugin->bEnabled) { // Add the plugin binaries directory const FString PluginBinariesPath = FPaths::Combine(*FPaths::GetPath(Plugin->FileName), TEXT("Binaries"), FPlatformProcess::GetBinariesSubdirectory()); FModuleManager::Get().AddBinariesDirectory(*PluginBinariesPath, Plugin->LoadedFrom == EPluginLoadedFrom::GameProject); #if !IS_MONOLITHIC // Only check this when in a non-monolithic build where modules could be in separate binaries if (Project != NULL && Project->Modules.Num() == 0) { // Content only project - check whether any plugins are incompatible and offer to disable instead of trying to build them later TArray<FString> IncompatibleFiles; if (!FModuleDescriptor::CheckModuleCompatibility(Plugin->Descriptor.Modules, Plugin->LoadedFrom == EPluginLoadedFrom::GameProject, IncompatibleFiles)) { // Ask whether to disable plugin if incompatible FText Caption(LOCTEXT("IncompatiblePluginCaption", "Plugin missing or incompatible")); if (FMessageDialog::Open(EAppMsgType::YesNo, FText::Format(LOCTEXT("IncompatiblePluginText", "Missing or incompatible modules in {0} plugin - would you like to disable it? You will no longer be able to open any assets created using it."), FText::FromString(Plugin->Name)), &Caption) == EAppReturnType::No) { return false; } FText FailReason; if (!IProjectManager::Get().SetPluginEnabled(*Plugin->Name, false, FailReason)) { FMessageDialog::Open(EAppMsgType::Ok, FailReason); } } } #endif //!IS_MONOLITHIC // Build the list of content folders if (Plugin->Descriptor.bCanContainContent) { if (auto EngineConfigFile = GConfig->Find(GEngineIni, false)) { if (auto CoreSystemSection = EngineConfigFile->Find(TEXT("Core.System"))) { CoreSystemSection->AddUnique("Paths", Plugin->GetContentDir()); } } } // Load Default<PluginName>.ini config file if it exists FString PluginConfigDir = FPaths::GetPath(Plugin->FileName) / TEXT("Config/"); FConfigFile PluginConfig; FConfigCacheIni::LoadExternalIniFile(PluginConfig, *Plugin->Name, *FPaths::EngineConfigDir(), *PluginConfigDir, true); if (PluginConfig.Num() > 0) { FString PlaformName = FPlatformProperties::PlatformName(); FString PluginConfigFilename = FString::Printf(TEXT("%s%s/%s.ini"), *FPaths::GeneratedConfigDir(), *PlaformName, *Plugin->Name); FConfigFile& NewConfigFile = GConfig->Add(PluginConfigFilename, FConfigFile()); NewConfigFile.AddMissingProperties(PluginConfig); NewConfigFile.Write(PluginConfigFilename); } } } // Mount all the plugin content folders and pak files TArray<FString> FoundPaks; FPakFileSearchVisitor PakVisitor(FoundPaks); IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile(); for(TSharedRef<IPlugin> Plugin: GetEnabledPlugins()) { if (Plugin->CanContainContent() && ensure(RegisterMountPointDelegate.IsBound())) { FString ContentDir = Plugin->GetContentDir(); RegisterMountPointDelegate.Execute(Plugin->GetMountedAssetPath(), ContentDir); // Pak files are loaded from <PluginName>/Content/Paks/<PlatformName> if (FPlatformProperties::RequiresCookedData()) { FoundPaks.Reset(); PlatformFile.IterateDirectoryRecursively(*(ContentDir / TEXT("Paks") / FPlatformProperties::PlatformName()), PakVisitor); for (const auto& PakPath : FoundPaks) { if (FCoreDelegates::OnMountPak.IsBound()) { FCoreDelegates::OnMountPak.Execute(PakPath, 0); } } } } } } return bHaveAllRequiredPlugins; }
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; }
/** * Helper method designed to perform the necessary preparations required to complete an automated editor build * * @param BuildSettings Build settings that will be used for the editor build * @param OutPkgsToSubmit Set of packages that need to be saved and submitted after a successful build * @param OutErrorMessages Errors that resulted from the preparation (may or may not force the build to stop, depending on build settings) * * @return true if the preparation was successful and the build should continue; false if the preparation failed and the build should be aborted */ bool FEditorBuildUtils::PrepForAutomatedBuild( const FEditorAutomatedBuildSettings& BuildSettings, TSet<UPackage*>& OutPkgsToSubmit, FText& OutErrorMessages ) { // Assume the preparation is successful to start bool bBuildSuccessful = true; OutPkgsToSubmit.Empty(); ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider(); // Source control is required for the automated build, so ensure that SCC support is compiled in and // that the server is enabled and available for use if ( !ISourceControlModule::Get().IsEnabled() || !SourceControlProvider.IsAvailable() ) { bBuildSuccessful = false; LogErrorMessage( NSLOCTEXT("UnrealEd", "AutomatedBuild_Error_SCCError", "Cannot connect to source control; automated build aborted."), OutErrorMessages ); } // Empty changelists aren't allowed; abort the build if one wasn't provided if ( bBuildSuccessful && BuildSettings.ChangeDescription.Len() == 0 ) { bBuildSuccessful = false; LogErrorMessage( NSLOCTEXT("UnrealEd", "AutomatedBuild_Error_NoCLDesc", "A changelist description must be provided; automated build aborted."), OutErrorMessages ); } TArray<UPackage*> PreviouslySavedWorldPackages; TArray<UPackage*> PackagesToCheckout; TArray<ULevel*> LevelsToSave; if ( bBuildSuccessful ) { TArray<UWorld*> AllWorlds; FString UnsavedWorlds; EditorLevelUtils::GetWorlds( GWorld, AllWorlds, true ); // Check all of the worlds that will be built to ensure they have been saved before and have a filename // associated with them. If they don't, they won't be able to be submitted to source control. FString CurWorldPkgFileName; for ( TArray<UWorld*>::TConstIterator WorldIter( AllWorlds ); WorldIter; ++WorldIter ) { const UWorld* CurWorld = *WorldIter; check( CurWorld ); UPackage* CurWorldPackage = CurWorld->GetOutermost(); check( CurWorldPackage ); if ( FPackageName::DoesPackageExist( CurWorldPackage->GetName(), NULL, &CurWorldPkgFileName ) ) { PreviouslySavedWorldPackages.AddUnique( CurWorldPackage ); // Add all packages which have a corresponding file to the set of packages to submit for now. As preparation continues // any packages that can't be submitted due to some error will be removed. OutPkgsToSubmit.Add( CurWorldPackage ); } else { UnsavedWorlds += FString::Printf( TEXT("%s\n"), *CurWorldPackage->GetName() ); } } // If any of the worlds haven't been saved before, process the build setting's behavior to see if the build // should proceed or not if ( UnsavedWorlds.Len() > 0 ) { bBuildSuccessful = ProcessAutomatedBuildBehavior( BuildSettings.NewMapBehavior, FText::Format( NSLOCTEXT("UnrealEd", "AutomatedBuild_Error_UnsavedMap", "The following levels have never been saved before and cannot be submitted:\n\n{0}\n\nAttempt to continue the build?"), FText::FromString(UnsavedWorlds) ), OutErrorMessages ); } } // Load the asset tools module FAssetToolsModule& AssetToolsModule = FModuleManager::GetModuleChecked<FAssetToolsModule>("AssetTools"); if ( bBuildSuccessful ) { // Update the source control status of any relevant world packages in order to determine which need to be // checked out, added to the depot, etc. SourceControlProvider.Execute( ISourceControlOperation::Create<FUpdateStatus>(), SourceControlHelpers::PackageFilenames(PreviouslySavedWorldPackages) ); FString PkgsThatCantBeCheckedOut; for ( TArray<UPackage*>::TConstIterator PkgIter( PreviouslySavedWorldPackages ); PkgIter; ++PkgIter ) { UPackage* CurPackage = *PkgIter; const FString CurPkgName = CurPackage->GetName(); FSourceControlStatePtr SourceControlState = SourceControlProvider.GetState(CurPackage, EStateCacheUsage::ForceUpdate); if( !SourceControlState.IsValid() || (!SourceControlState->IsSourceControlled() && !SourceControlState->IsUnknown() && !SourceControlState->IsIgnored())) { FString CurFilename; if ( FPackageName::DoesPackageExist( CurPkgName, NULL, &CurFilename ) ) { if ( IFileManager::Get().IsReadOnly( *CurFilename ) ) { PkgsThatCantBeCheckedOut += FString::Printf( TEXT("%s\n"), *CurPkgName ); OutPkgsToSubmit.Remove( CurPackage ); } } } else if(SourceControlState->CanCheckout()) { PackagesToCheckout.Add( CurPackage ); } else { PkgsThatCantBeCheckedOut += FString::Printf( TEXT("%s\n"), *CurPkgName ); OutPkgsToSubmit.Remove( CurPackage ); } } // If any of the packages can't be checked out or are read-only, process the build setting's behavior to see if the build // should proceed or not if ( PkgsThatCantBeCheckedOut.Len() > 0 ) { bBuildSuccessful = ProcessAutomatedBuildBehavior( BuildSettings.UnableToCheckoutFilesBehavior, FText::Format( NSLOCTEXT("UnrealEd", "AutomatedBuild_Error_UnsaveableFiles", "The following assets cannot be checked out of source control (or are read-only) and cannot be submitted:\n\n{0}\n\nAttempt to continue the build?"), FText::FromString(PkgsThatCantBeCheckedOut) ), OutErrorMessages ); } } if ( bBuildSuccessful ) { // Check out all of the packages from source control that need to be checked out if ( PackagesToCheckout.Num() > 0 ) { TArray<FString> PackageFilenames = SourceControlHelpers::PackageFilenames(PackagesToCheckout); SourceControlProvider.Execute( ISourceControlOperation::Create<FCheckOut>(), PackageFilenames ); // Update the package status of the packages that were just checked out to confirm that they // were actually checked out correctly SourceControlProvider.Execute( ISourceControlOperation::Create<FUpdateStatus>(), PackageFilenames ); FString FilesThatFailedCheckout; for ( TArray<UPackage*>::TConstIterator CheckedOutIter( PackagesToCheckout ); CheckedOutIter; ++CheckedOutIter ) { UPackage* CurPkg = *CheckedOutIter; FSourceControlStatePtr SourceControlState = SourceControlProvider.GetState(CurPkg, EStateCacheUsage::ForceUpdate); // If any of the packages failed to check out, remove them from the set of packages to submit if ( !SourceControlState.IsValid() || (!SourceControlState->IsCheckedOut() && !SourceControlState->IsAdded() && SourceControlState->IsSourceControlled()) ) { FilesThatFailedCheckout += FString::Printf( TEXT("%s\n"), *CurPkg->GetName() ); OutPkgsToSubmit.Remove( CurPkg ); } } // If any of the packages failed to check out correctly, process the build setting's behavior to see if the build // should proceed or not if ( FilesThatFailedCheckout.Len() > 0 ) { bBuildSuccessful = ProcessAutomatedBuildBehavior( BuildSettings.UnableToCheckoutFilesBehavior, FText::Format( NSLOCTEXT("UnrealEd", "AutomatedBuild_Error_FilesFailedCheckout", "The following assets failed to checkout of source control and cannot be submitted:\n{0}\n\nAttempt to continue the build?"), FText::FromString(FilesThatFailedCheckout)), OutErrorMessages ); } } } // Verify there are still actually any packages left to submit. If there aren't, abort the build and warn the user of the situation. if ( bBuildSuccessful ) { bBuildSuccessful = OutPkgsToSubmit.Num() > 0; if ( !bBuildSuccessful ) { LogErrorMessage( NSLOCTEXT("UnrealEd", "AutomatedBuild_Error_NoValidLevels", "None of the current levels are valid for submission; automated build aborted."), OutErrorMessages ); } } // If the build is safe to commence, force all of the levels visible to make sure the build operates correctly if ( bBuildSuccessful ) { bool bVisibilityToggled = false; if ( !FLevelUtils::IsLevelVisible( GWorld->PersistentLevel ) ) { EditorLevelUtils::SetLevelVisibility( GWorld->PersistentLevel, true, false ); bVisibilityToggled = true; } for ( TArray<ULevelStreaming*>::TConstIterator LevelIter( GWorld->StreamingLevels ); LevelIter; ++LevelIter ) { ULevelStreaming* CurStreamingLevel = *LevelIter; if ( CurStreamingLevel && !FLevelUtils::IsLevelVisible( CurStreamingLevel ) ) { CurStreamingLevel->bShouldBeVisibleInEditor = true; bVisibilityToggled = true; } } if ( bVisibilityToggled ) { GWorld->FlushLevelStreaming(); } } return bBuildSuccessful; }
void CheckTextureStreamingBuild(ULevel* InLevel) { #if WITH_EDITORONLY_DATA if (!InLevel) return; int32 NumTextureStreamingUnbuiltComponents = 0; TSet<FGuid> BuildGuilds; for (const FGuid& Guid : InLevel->TextureStreamingBuildGuids) { BuildGuilds.Add(Guid); } TArray<UPrimitiveComponent*> Components; GetTextureStreamingPrimitives(InLevel, Components); for (UPrimitiveComponent* Primitive : Components) { //@todo : Non transactional primitives, like the one created from blueprints, fail to save/load their built data. const bool bHasMissingData = !!(Primitive->GetFlags() & RF_Transactional) && !Primitive->HasStreamingTextureData(); TArray<UTexture*> Textures; TArray<UMaterialInterface*> Materials; Primitive->GetUsedMaterials(Materials); for (const UMaterialInterface* MaterialInterface : Materials) { if (MaterialInterface) { TArray<FGuid> MaterialGuids; MaterialInterface->GetLightingGuidChain(false, MaterialGuids); for (const FGuid& MaterialGuid : MaterialGuids) { BuildGuilds.Remove(MaterialGuid); } // If there is no data, then we will have to parse the texture to check whether there are streaming textures there. if (bHasMissingData) { MaterialInterface->GetUsedTextures(Textures, EMaterialQualityLevel::Num, false, GMaxRHIFeatureLevel, false); } } } // If there is no data, check that the material actually uses streaming textures before marking the Texture Streaming Build invalid. if (bHasMissingData && Textures.Num() > 0) { for (UTexture* Texture : Textures) { if (IsStreamingTexture(Cast<UTexture2D>(Texture))) { ++NumTextureStreamingUnbuiltComponents; break; } } } const UStaticMeshComponent* StaticMeshComponent = Cast<UStaticMeshComponent>(Primitive); if (StaticMeshComponent && StaticMeshComponent->StaticMesh) { BuildGuilds.Remove(StaticMeshComponent->StaticMesh->GetLightingGuid()); } } // All guids must have been found, otherwise, it means the resource changed. if (NumTextureStreamingUnbuiltComponents != InLevel->NumTextureStreamingUnbuiltComponents || BuildGuilds.Num() != InLevel->NumTextureStreamingDirtyResources) { InLevel->NumTextureStreamingUnbuiltComponents = NumTextureStreamingUnbuiltComponents; InLevel->NumTextureStreamingDirtyResources = BuildGuilds.Num(); // Don't mark package dirty as we avoid marking package dirty unless user changes something. // InLevel->MarkPackageDirty(); } #endif }
void AHUD::UpdateHitBoxCandidates( TArray<FVector2D> InContactPoints ) { HitBoxHits.Reset(); for (FHUDHitBox& HitBox : HitBoxMap) { bool bAdded = false; for (int32 ContactPointIndex = InContactPoints.Num() - 1; ContactPointIndex >= 0; --ContactPointIndex) { if (HitBox.Contains(InContactPoints[ContactPointIndex])) { if (!bAdded) { HitBoxHits.Add(&HitBox); bAdded = true; } if (HitBox.ConsumesInput()) { InContactPoints.RemoveAtSwap(ContactPointIndex); } else { break; } } } if (InContactPoints.Num() == 0) { break; } } TSet<FName> NotOverHitBoxes = HitBoxesOver; TArray<FName> NewlyOverHitBoxes; // Now figure out which boxes we are over and deal with begin/end cursor over messages for (FHUDHitBox* HitBox : HitBoxHits) { const FName HitBoxName = HitBox->GetName(); if (HitBoxesOver.Contains(HitBoxName)) { NotOverHitBoxes.Remove(HitBoxName); } else { NewlyOverHitBoxes.AddUnique(HitBoxName); } } // Dispatch the end cursor over messages for (const FName HitBoxName : NotOverHitBoxes) { NotifyHitBoxEndCursorOver(HitBoxName); HitBoxesOver.Remove(HitBoxName); } // Dispatch the newly over hitbox messages for (const FName HitBoxName : NewlyOverHitBoxes) { NotifyHitBoxBeginCursorOver(HitBoxName); HitBoxesOver.Add(HitBoxName); } }