From dee4537f23297f6e567b8505b10d72bc3840fb14 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 16 Aug 2021 22:49:51 +0200 Subject: [PATCH] Add `-new` command line arg to create a new project --- Source/Editor/Editor.cpp | 99 +++++++++++++++++++++++ Source/Editor/Editor.cs | 31 ++++++- Source/Editor/Managed/ManagedEditor.cpp | 6 +- Source/Engine/Core/Config/GameSettings.cs | 2 +- Source/Engine/Engine/CommandLine.cpp | 1 + Source/Engine/Engine/CommandLine.h | 5 ++ 6 files changed, 140 insertions(+), 4 deletions(-) diff --git a/Source/Editor/Editor.cpp b/Source/Editor/Editor.cpp index f33d27dbe..ce42154da 100644 --- a/Source/Editor/Editor.cpp +++ b/Source/Editor/Editor.cpp @@ -388,6 +388,105 @@ int32 Editor::LoadProduct() projectPath.Clear(); } + // Create new project option + if (CommandLine::Options.NewProject) + { + if (projectPath.IsEmpty()) + projectPath = Platform::GetWorkingDirectory(); + else if (!FileSystem::DirectoryExists(projectPath)) + FileSystem::CreateDirectory(projectPath); + FileSystem::NormalizePath(projectPath); + + String folderName = StringUtils::GetFileName(projectPath); + String tmpName; + for (int32 i = 0; i < folderName.Length(); i++) + { + Char c = folderName[i]; + if (StringUtils::IsAlnum(c) && c != ' ' && c != '.') + tmpName += c; + } + + // Create project file + ProjectInfo newProject; + newProject.Name = MoveTemp(tmpName); + newProject.ProjectPath = projectPath / newProject.Name + TEXT(".flaxproj"); + newProject.ProjectFolderPath = projectPath; + newProject.Version = Version(1, 0); + newProject.Company = TEXT("My Company"); + newProject.MinEngineVersion = FLAXENGINE_VERSION; + newProject.GameTarget = TEXT("GameTarget"); + newProject.EditorTarget = TEXT("GameEditorTarget"); + auto& flaxRef = newProject.References.AddOne(); + flaxRef.Name = TEXT("$(EnginePath)/Flax.flaxproj"); + flaxRef.Project = nullptr; + if (newProject.SaveProject()) + return 10; + + // Generate source files + if (FileSystem::CreateDirectory(projectPath / TEXT("Content"))) + return 11; + if (FileSystem::CreateDirectory(projectPath / TEXT("Source/Game"))) + return 11; + bool failed = File::WriteAllText(projectPath / TEXT("Source/GameTarget.Build.cs"),TEXT( + "using Flax.Build;\n" + "\n" + "public class GameTarget : GameProjectTarget\n" + "{\n" + " /// \n" + " public override void Init()\n" + " {\n" + " base.Init();\n" + "\n" + " // Reference the modules for game\n" + " Modules.Add(\"Game\");\n" + " }\n" + "}\n"), Encoding::Unicode); + failed |= File::WriteAllText(projectPath / TEXT("Source/GameEditorTarget.Build.cs"),TEXT( + "using Flax.Build;\n" + "\n" + "public class GameEditorTarget : GameProjectEditorTarget\n" + "{\n" + " /// \n" + " public override void Init()\n" + " {\n" + " base.Init();\n" + "\n" + " // Reference the modules for editor\n" + " Modules.Add(\"Game\");\n" + " }\n" + "}\n"), Encoding::Unicode); + failed |= File::WriteAllText(projectPath / TEXT("Source/Game/Game.Build.cs"),TEXT( + "using Flax.Build;\n" + "using Flax.Build.NativeCpp;\n" + "\n" + "public class Game : GameModule\n" + "{\n" + " /// \n" + " public override void Init()\n" + " {\n" + " base.Init();\n" + "\n" + " // C#-only scripting\n" + " BuildNativeCode = false;\n" + " }\n" + "\n" + " /// \n" + " public override void Setup(BuildOptions options)\n" + " {\n" + " base.Setup(options);\n" + "\n" + " options.ScriptingAPI.IgnoreMissingDocumentationWarnings = true;\n" + "\n" + " // Here you can modify the build options for your game module\n" + " // To reference another module use: options.PublicDependencies.Add(\"Audio\");\n" + " // To add C++ define use: options.PublicDefinitions.Add(\"COMPILE_WITH_FLAX\");\n" + " // To learn more see scripting documentation.\n" + " }\n" + "}\n"), Encoding::Unicode); + if (failed) + return 12; + } + // Missing project case if (projectPath.IsEmpty()) { diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs index 19d699726..4831b9958 100644 --- a/Source/Editor/Editor.cs +++ b/Source/Editor/Editor.cs @@ -272,8 +272,10 @@ namespace FlaxEditor module.OnEndInit(); } - internal void Init(bool isHeadless, bool skipCompile, Guid startupScene) + internal void Init(bool isHeadless, bool skipCompile, bool newProject, Guid startupScene) { + if (newProject) + InitProject(); EnsureState(); _isHeadlessMode = isHeadless; _startupSceneCmdLine = startupScene; @@ -473,6 +475,33 @@ namespace FlaxEditor } } + private void InitProject() + { + // Initialize empty project with default game configuration + Log("Initialize new project"); + var project = GameProject; + var gameSettings = new GameSettings + { + ProductName = project.Name, + CompanyName = project.Company, + }; + GameSettings.Save(gameSettings); + GameSettings.Save(new TimeSettings()); + GameSettings.Save(new AudioSettings()); + GameSettings.Save(new PhysicsSettings()); + GameSettings.Save(new LayersAndTagsSettings()); + GameSettings.Save(new InputSettings()); + GameSettings.Save(new GraphicsSettings()); + GameSettings.Save(new NavigationSettings()); + GameSettings.Save(new LocalizationSettings()); + GameSettings.Save(new BuildSettings()); + GameSettings.Save(new StreamingSettings()); + GameSettings.Save(new WindowsPlatformSettings()); + GameSettings.Save(new LinuxPlatformSettings()); + GameSettings.Save(new AndroidPlatformSettings()); + GameSettings.Save(new UWPPlatformSettings()); + } + internal void OnPlayBeginning() { for (int i = 0; i < _modules.Count; i++) diff --git a/Source/Editor/Managed/ManagedEditor.cpp b/Source/Editor/Managed/ManagedEditor.cpp index 6a83ceeb5..089faeb7f 100644 --- a/Source/Editor/Managed/ManagedEditor.cpp +++ b/Source/Editor/Managed/ManagedEditor.cpp @@ -175,7 +175,7 @@ ManagedEditor::~ManagedEditor() void ManagedEditor::Init() { // Note: editor modules should perform quite fast init, any longer things should be done in async during 'editor splash screen time - void* args[3]; + void* args[4]; MClass* mclass = GetClass(); if (mclass == nullptr) { @@ -194,14 +194,16 @@ void ManagedEditor::Init() MonoObject* exception = nullptr; bool isHeadless = CommandLine::Options.Headless.IsTrue(); bool skipCompile = CommandLine::Options.SkipCompile.IsTrue(); + bool newProject = CommandLine::Options.NewProject.IsTrue(); args[0] = &isHeadless; args[1] = &skipCompile; + args[2] = &newProject; Guid sceneId; if (!CommandLine::Options.Play.HasValue() || (CommandLine::Options.Play.HasValue() && Guid::Parse(CommandLine::Options.Play.GetValue(), sceneId))) { sceneId = Guid::Empty; } - args[2] = &sceneId; + args[3] = &sceneId; initMethod->Invoke(instance, args, &exception); if (exception) { diff --git a/Source/Engine/Core/Config/GameSettings.cs b/Source/Engine/Core/Config/GameSettings.cs index b9ba4e110..d5dfd3726 100644 --- a/Source/Engine/Core/Config/GameSettings.cs +++ b/Source/Engine/Core/Config/GameSettings.cs @@ -296,7 +296,7 @@ namespace FlaxEditor.Content.Settings } // Create new settings asset and link it to the game settings - var path = StringUtils.CombinePaths(Globals.ProjectContentFolder, CustomEditors.CustomEditorsUtil.GetPropertyNameUI(typeof(T).Name) + ".json"); + var path = StringUtils.CombinePaths(Globals.ProjectContentFolder, "Settings", CustomEditors.CustomEditorsUtil.GetPropertyNameUI(typeof(T).Name) + ".json"); if (Editor.SaveJsonAsset(path, obj)) return true; asset = FlaxEngine.Content.LoadAsync(path); diff --git a/Source/Engine/Engine/CommandLine.cpp b/Source/Engine/Engine/CommandLine.cpp index 9f5078c64..e7fe07fb5 100644 --- a/Source/Engine/Engine/CommandLine.cpp +++ b/Source/Engine/Engine/CommandLine.cpp @@ -150,6 +150,7 @@ bool CommandLine::Parse(const Char* cmdLine) PARSE_BOOL_SWITCH("-clearcache ", ClearCache); PARSE_BOOL_SWITCH("-clearcooker ", ClearCookerCache); PARSE_ARG_SWITCH("-project ", Project); + PARSE_BOOL_SWITCH("-new ", NewProject); PARSE_BOOL_SWITCH("-genprojectfiles ", GenProjectFiles); PARSE_ARG_SWITCH("-build ", Build); PARSE_BOOL_SWITCH("-skipcompile ", SkipCompile); diff --git a/Source/Engine/Engine/CommandLine.h b/Source/Engine/Engine/CommandLine.h index d9d3547d3..41f985dee 100644 --- a/Source/Engine/Engine/CommandLine.h +++ b/Source/Engine/Engine/CommandLine.h @@ -134,6 +134,11 @@ public: /// String Project; + /// + /// -new (generates the project files inside the specified project folder or uses current workspace folder) + /// + Nullable NewProject; + /// /// -genprojectfiles (generates the scripts project files) ///