// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. #include "ProjectSettingsViewerPrivatePCH.h" #include "Engine/Console.h" #include "ProjectTargetPlatformEditor.h" #include "ISettingsCategory.h" #include "ISettingsContainer.h" #include "ISettingsEditorModel.h" #include "ISettingsEditorModule.h" #include "ISettingsModule.h" #include "ISettingsViewer.h" #include "ModuleManager.h" #include "SDockTab.h" #include "CookerSettings.h" #include "Runtime/Engine/Classes/Engine/DeveloperSettings.h" #include "Runtime/Engine/Classes/Engine/RendererSettings.h" #include "Runtime/Engine/Classes/Engine/UserInterfaceSettings.h" #include "Runtime/Engine/Classes/Sound/AudioSettings.h" #include "Runtime/AIModule/Classes/Navigation/CrowdManager.h" #include "Runtime/Engine/Classes/Animation/AnimationSettings.h" #include "Editor/UnrealEd/Public/Settings/EditorProjectSettings.h" #include "AISystem.h" #include "GameFramework/InputSettings.h" #include "AI/Navigation/RecastNavMesh.h" #include "Engine/NetworkSettings.h" #include "PhysicsEngine/PhysicsSettings.h" #define LOCTEXT_NAMESPACE "FProjectSettingsViewerModule" static const FName ProjectSettingsTabName("ProjectSettings"); /** Holds auto discovered settings information so that they can be unloaded automatically when refreshing. */ struct FRegisteredSettings { FName ContainerName; FName CategoryName; FName SectionName; }; /** * Implements the ProjectSettingsViewer module. */ class FProjectSettingsViewerModule : public IModuleInterface , public ISettingsViewer , public FTickableEditorObject { public: FProjectSettingsViewerModule() { bTicking = false; bInvalidated = false; } // ISettingsViewer interface virtual void ShowSettings( const FName& CategoryName, const FName& SectionName ) override { FGlobalTabmanager::Get()->InvokeTab(ProjectSettingsTabName); ISettingsEditorModelPtr SettingsEditorModel = SettingsEditorModelPtr.Pin(); if (SettingsEditorModel.IsValid()) { ISettingsCategoryPtr Category = SettingsEditorModel->GetSettingsContainer()->GetCategory(CategoryName); if (Category.IsValid()) { SettingsEditorModel->SelectSection(Category->GetSection(SectionName)); } } } public: // IModuleInterface interface virtual void StartupModule() override { ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings"); if (SettingsModule != nullptr) { RegisterEngineSettings(*SettingsModule); RegisterProjectSettings(*SettingsModule); RegisterEditorSettings(*SettingsModule); RegisterAutoDiscoveredSettings(*SettingsModule); SettingsModule->RegisterViewer("Project", *this); } FGlobalTabmanager::Get()->RegisterNomadTabSpawner(ProjectSettingsTabName, FOnSpawnTab::CreateRaw(this, &FProjectSettingsViewerModule::HandleSpawnSettingsTab)) .SetDisplayName(LOCTEXT("ProjectSettingsTabTitle", "Project Settings")) .SetMenuType(ETabSpawnerMenuType::Hidden); FModuleManager::Get().OnModulesChanged().AddRaw(this, &FProjectSettingsViewerModule::ModulesChangesCallback); bTicking = true; } virtual void ShutdownModule() override { bTicking = false; FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(ProjectSettingsTabName); UnregisterSettings(); FModuleManager::Get().OnModulesChanged().RemoveAll(this); } void ModulesChangesCallback(FName ModuleName, EModuleChangeReason ReasonForChange) { if ( ReasonForChange == EModuleChangeReason::ModuleLoaded ) { bInvalidated = true; } } virtual bool SupportsDynamicReloading() override { return true; } protected: /** * Registers Engine settings. * * @param SettingsModule A reference to the settings module. */ void RegisterEngineSettings( ISettingsModule& SettingsModule ) { // startup settings SettingsModule.RegisterSettings("Project", "Engine", "General", LOCTEXT("GeneralEngineSettingsName", "General Settings"), LOCTEXT("ProjectGeneralSettingsDescription", "General options and defaults for the game engine."), GetMutableDefault() ); // audio settings SettingsModule.RegisterSettings("Project", "Engine", "Audio", LOCTEXT("EngineAudioSettingsName", "Audio"), LOCTEXT("ProjectAudioSettingsDescription", "Audio settings."), GetMutableDefault() ); // collision settings SettingsModule.RegisterSettings("Project", "Engine", "Collision", LOCTEXT("ProjectCollisionSettingsName", "Collision"), LOCTEXT("ProjectCollisionSettingsDescription", "Set up and modify collision settings."), GetMutableDefault() ); // command console settings SettingsModule.RegisterSettings("Project", "Engine", "Console", LOCTEXT("ProjectConsoleSettingsName", "Console"), LOCTEXT("ProjectConsoleSettingsDescription", "Configure the in-game input console."), GetMutableDefault() ); // input settings SettingsModule.RegisterSettings("Project", "Engine", "Input", LOCTEXT("EngineInputSettingsName", "Input"), LOCTEXT("ProjectInputSettingsDescription", "Input settings, including default input action and axis bindings."), GetMutableDefault() ); // navigation system's class can be game specific so we need to find appropriate CDO UNavigationSystem* NavSysCDO = (*GEngine->NavigationSystemClass != nullptr) ? GetMutableDefault(GEngine->NavigationSystemClass) : GetMutableDefault(); SettingsModule.RegisterSettings("Project", "Engine", "NavigationSystem", LOCTEXT("NavigationSystemSettingsName", "Navigation System"), LOCTEXT("NavigationSystemSettingsDescription", "Settings for the navigation system."), NavSysCDO ); // navigation mesh SettingsModule.RegisterSettings("Project", "Engine", "NavigationMesh", LOCTEXT("NavigationMeshSettingsName", "Navigation Mesh"), LOCTEXT("NavigationMeshSettingsDescription", "Settings for the navigation mesh."), GetMutableDefault() ); // AI system SettingsModule.RegisterSettings("Project", "Engine", "AISystem", LOCTEXT("AISystemSettingsName", "AI System"), LOCTEXT("AISystemSettingsDescription", "Settings for the AI System."), GetMutableDefault() ); // Crowd manager SettingsModule.RegisterSettings("Project", "Engine", "CrowdManager", LOCTEXT("CrowdManagerSettingsName", "Crowd Manager"), LOCTEXT("CrowdManagerSettingsDescription", "Settings for the AI Crowd Manager."), GetMutableDefault() ); // Physics settings SettingsModule.RegisterSettings("Project", "Engine", "Animation", LOCTEXT("EngineAnimationSettingsName", "Animation"), LOCTEXT("ProjectAnimationSettingsDescription", "Default animation settings."), GetMutableDefault() ); // network settings SettingsModule.RegisterSettings("Project", "Engine", "Network", LOCTEXT("NetworkSettingsName", "Network"), LOCTEXT("NetworkSettingsDescription", "Network settings."), GetMutableDefault() ); // Physics settings SettingsModule.RegisterSettings("Project", "Engine", "Physics", LOCTEXT("EnginePhysicsSettingsName", "Physics"), LOCTEXT("ProjectPhysicsSettingsDescription", "Default physics settings."), GetMutableDefault() ); // Rendering settings SettingsModule.RegisterSettings("Project", "Engine", "Rendering", LOCTEXT("EngineRenderingSettingsName", "Rendering"), LOCTEXT("ProjectRenderingSettingsDescription", "Rendering settings."), GetMutableDefault() ); // UI settings SettingsModule.RegisterSettings("Project", "Engine", "UI", LOCTEXT("EngineUISettingsName", "User Interface"), LOCTEXT("ProjectUISettingsDescription", "User Interface settings that control Slate and UMG."), GetMutableDefault() ); // Cooker settings SettingsModule.RegisterSettings("Project", "Engine", "Cooker", LOCTEXT("CookerSettingsName", "Cooker"), LOCTEXT("CookerSettingsDescription", "Various cooker settings."), GetMutableDefault() ); } /** * Registers Project settings. * * @param SettingsModule A reference to the settings module. */ void RegisterProjectSettings( ISettingsModule& SettingsModule ) { // general project settings SettingsModule.RegisterSettings("Project", "Project", "General", LOCTEXT("GeneralGameSettingsName", "Description"), LOCTEXT("GeneralGameSettingsDescription", "Descriptions and other information about your project."), GetMutableDefault() ); // map related settings SettingsModule.RegisterSettings("Project", "Project", "Maps", LOCTEXT("GameMapsSettingsName", "Maps & Modes"), LOCTEXT("GameMapsSettingsDescription", "Default maps, game modes and other map related settings."), GetMutableDefault() ); // packaging settings SettingsModule.RegisterSettings("Project", "Project", "Packaging", LOCTEXT("ProjectPackagingSettingsName", "Packaging"), LOCTEXT("ProjectPackagingSettingsDescription", "Fine tune how your project is packaged for release."), GetMutableDefault() ); // platforms settings TWeakPtr ProjectTargetPlatformEditorPanel = FModuleManager::LoadModuleChecked("ProjectTargetPlatformEditor").CreateProjectTargetPlatformEditorPanel(); SettingsModule.RegisterSettings("Project", "Project", "SupportedPlatforms", LOCTEXT("ProjectSupportedPlatformsSettingsName", "Supported Platforms"), LOCTEXT("ProjectSupportedPlatformsSettingsDescription", "Specify which platforms your project supports."), ProjectTargetPlatformEditorPanel.Pin().ToSharedRef() ); // movie settings SettingsModule.RegisterSettings("Project", "Project", "Movies", LOCTEXT("MovieSettingsName", "Movies"), LOCTEXT("MovieSettingsDescription", "Movie player settings"), GetMutableDefault() ); } void RegisterAutoDiscoveredSettings(ISettingsModule& SettingsModule) { // Find game object for ( TObjectIterator SettingsIt(RF_NoFlags); SettingsIt; ++SettingsIt ) { if ( UDeveloperSettings* Settings = *SettingsIt ) { // Only Add the CDO of any UDeveloperSettings objects. if ( Settings->HasAnyFlags(RF_ClassDefaultObject) && !Settings->GetClass()->HasAnyCastFlag(CLASS_Deprecated | CLASS_Abstract) ) { FRegisteredSettings Registered; Registered.ContainerName = Settings->GetContainerName(); Registered.CategoryName = Settings->GetCategoryName(); Registered.SectionName = Settings->GetSectionName(); TSharedPtr CustomWidget = Settings->GetCustomSettingsWidget(); if ( CustomWidget.IsValid() ) { // Add Settings SettingsModule.RegisterSettings(Registered.ContainerName, Registered.CategoryName, Registered.SectionName, Settings->GetSectionText(), Settings->GetSectionDescription(), CustomWidget.ToSharedRef() ); } else { // Add Settings SettingsModule.RegisterSettings(Registered.ContainerName, Registered.CategoryName, Registered.SectionName, Settings->GetSectionText(), Settings->GetSectionDescription(), Settings ); } AutoDiscoveredSettings.Add(Registered); } } } } /** * Registers Editor settings. * * @param SettingsModule A reference to the settings module. */ void RegisterEditorSettings( ISettingsModule& SettingsModule ) { // Appearance settings SettingsModule.RegisterSettings("Project", "Editor", "Appearance", LOCTEXT("AppearanceSettingsName", "Appearance"), LOCTEXT("AppearanceSettingsDescription", "Settings pertaining to the appearance of the editor"), GetMutableDefault() ); // view port settings SettingsModule.RegisterSettings("Project", "Editor", "2D", LOCTEXT("Editor2DSettingsName", "2D"), LOCTEXT("Editor2DSettingsDescription", "Configure the settings for the 2D Level Editor."), GetMutableDefault() ); } /** Unregisters all settings. */ void UnregisterSettings() { ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings"); if (SettingsModule != nullptr) { SettingsModule->UnregisterViewer("Project"); // engine settings SettingsModule->UnregisterSettings("Project", "Engine", "General"); SettingsModule->UnregisterSettings("Project", "Engine", "CrowdManager"); SettingsModule->UnregisterSettings("Project", "Engine", "NavigationSystem"); SettingsModule->UnregisterSettings("Project", "Engine", "NavigationMesh"); SettingsModule->UnregisterSettings("Project", "Engine", "Input"); SettingsModule->UnregisterSettings("Project", "Engine", "Collision"); SettingsModule->UnregisterSettings("Project", "Engine", "Physics"); SettingsModule->UnregisterSettings("Project", "Engine", "Rendering"); // project settings SettingsModule->UnregisterSettings("Project", "Project", "General"); SettingsModule->UnregisterSettings("Project", "Project", "Maps"); SettingsModule->UnregisterSettings("Project", "Project", "Packaging"); SettingsModule->UnregisterSettings("Project", "Project", "SupportedPlatforms"); SettingsModule->UnregisterSettings("Project", "Project", "Movies"); // Editor settings SettingsModule->UnregisterSettings("Editor", "Editor", "Appearance"); UnregisterAutoDiscoveredSettings(*SettingsModule); } } void UnregisterAutoDiscoveredSettings(ISettingsModule& SettingsModule) { // Unregister any auto discovers settings. for ( const FRegisteredSettings& Settings : AutoDiscoveredSettings ) { SettingsModule.UnregisterSettings(Settings.ContainerName, Settings.CategoryName, Settings.SectionName); } AutoDiscoveredSettings.Reset(); } private: /** FTickableEditorObject interface */ void Tick(float DeltaTime) override { if ( bInvalidated ) { ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings"); if ( SettingsModule != nullptr ) { UnregisterAutoDiscoveredSettings(*SettingsModule); RegisterAutoDiscoveredSettings(*SettingsModule); } bInvalidated = false; } } bool IsTickable() const override { return bTicking; } TStatId GetStatId() const override { RETURN_QUICK_DECLARE_CYCLE_STAT(FProjectSettingsViewerModule, STATGROUP_Tickables); } /** FTickableEditorObject interface */ private: /** Handles creating the project settings tab. */ TSharedRef HandleSpawnSettingsTab( const FSpawnTabArgs& SpawnTabArgs ) { TSharedRef SettingsEditor = SNullWidget::NullWidget; ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings"); if (SettingsModule != nullptr) { ISettingsContainerPtr SettingsContainer = SettingsModule->GetContainer("Project"); if (SettingsContainer.IsValid()) { ISettingsEditorModule& SettingsEditorModule = FModuleManager::GetModuleChecked("SettingsEditor"); ISettingsEditorModelRef SettingsEditorModel = SettingsEditorModule.CreateModel(SettingsContainer.ToSharedRef()); SettingsEditor = SettingsEditorModule.CreateEditor(SettingsEditorModel); SettingsEditorModelPtr = SettingsEditorModel; } } return SNew(SDockTab) .TabRole(ETabRole::NomadTab) [ SettingsEditor ]; } private: /** Holds a pointer to the settings editor's view model. */ TWeakPtr SettingsEditorModelPtr; /** The list of auto discovered settings that need to be unregistered. */ TArray AutoDiscoveredSettings; /** When new modules are loaded we invalidate the list of autodiscovered settings and re-discover them. */ bool bInvalidated; /** Should we be ticking? */ bool bTicking; }; IMPLEMENT_MODULE(FProjectSettingsViewerModule, ProjectSettingsViewer); #undef LOCTEXT_NAMESPACE