Exemple #1
0
        public static bool BuildApiSolution(string apiSlnDir, string config)
        {
            string apiSlnFile = Path.Combine(apiSlnDir, $"{ApiAssemblyNames.SolutionName}.sln");

            string coreApiAssemblyDir  = Path.Combine(apiSlnDir, ApiAssemblyNames.Core, "bin", config);
            string coreApiAssemblyFile = Path.Combine(coreApiAssemblyDir, $"{ApiAssemblyNames.Core}.dll");

            string editorApiAssemblyDir  = Path.Combine(apiSlnDir, ApiAssemblyNames.Editor, "bin", config);
            string editorApiAssemblyFile = Path.Combine(editorApiAssemblyDir, $"{ApiAssemblyNames.Editor}.dll");

            if (File.Exists(coreApiAssemblyFile) && File.Exists(editorApiAssemblyFile))
            {
                return(true); // The assemblies are in the output folder; assume the solution is already built
            }
            var apiBuildInfo = new MonoBuildInfo(apiSlnFile, config);

            // TODO Replace this global NoWarn with '#pragma warning' directives on generated files,
            // once we start to actively document manually maintained C# classes
            apiBuildInfo.CustomProperties.Add("NoWarn=1591"); // Ignore missing documentation warnings

            if (Build(apiBuildInfo))
            {
                return(true);
            }

            ShowBuildErrorDialog($"Failed to build {ApiAssemblyNames.SolutionName} solution.");
            return(false);
        }
Exemple #2
0
        private void _MakeApiSolutionsIfNeededImpl()
        {
            // If the project has a solution and C# project make sure the API assemblies are present and up to date

            string api_config       = "Debug";
            string resAssembliesDir = Path.Combine(GodotSharpDirs.ResAssembliesBaseDir, api_config);

            if (!File.Exists(Path.Combine(resAssembliesDir, $"{ApiAssemblyNames.Core}.dll")) ||
                Internal.MetadataIsApiAssemblyInvalidated(ApiAssemblyType.Core))
            {
                if (!GodotSharpBuilds.MakeApiAssembly(ApiAssemblyType.Core, api_config))
                {
                    return;
                }
            }

            if (!File.Exists(Path.Combine(resAssembliesDir, $"{ApiAssemblyNames.Editor}.dll")) ||
                Internal.MetadataIsApiAssemblyInvalidated(ApiAssemblyType.Editor))
            {
                if (!GodotSharpBuilds.MakeApiAssembly(ApiAssemblyType.Editor, api_config))
                {
                    return; // Redundant? I don't think so!
                }
            }
        }
Exemple #3
0
        private static bool CopyApiAssembly(string srcDir, string dstDir, string assemblyName, ApiAssemblyType apiType)
        {
            // Create destination directory if needed
            if (!Directory.Exists(dstDir))
            {
                try
                {
                    Directory.CreateDirectory(dstDir);
                }
                catch (IOException e)
                {
                    ShowBuildErrorDialog($"Failed to create destination directory for the API assemblies. Exception message: {e.Message}");
                    return(false);
                }
            }

            string assemblyFile = assemblyName + ".dll";
            string assemblySrc  = Path.Combine(srcDir, assemblyFile);
            string assemblyDst  = Path.Combine(dstDir, assemblyFile);

            if (!File.Exists(assemblyDst) || File.GetLastWriteTime(assemblySrc) > File.GetLastWriteTime(assemblyDst) ||
                Internal.MetadataIsApiAssemblyInvalidated(apiType))
            {
                string xmlFile = $"{assemblyName}.xml";
                string pdbFile = $"{assemblyName}.pdb";

                try
                {
                    File.Copy(Path.Combine(srcDir, xmlFile), Path.Combine(dstDir, xmlFile));
                }
                catch (IOException e)
                {
                    Godot.GD.PushWarning(e.ToString());
                }

                try
                {
                    File.Copy(Path.Combine(srcDir, pdbFile), Path.Combine(dstDir, pdbFile));
                }
                catch (IOException e)
                {
                    Godot.GD.PushWarning(e.ToString());
                }

                try
                {
                    File.Copy(assemblySrc, assemblyDst);
                }
                catch (IOException e)
                {
                    ShowBuildErrorDialog($"Failed to copy {assemblyFile}. Exception message: {e.Message}");
                    return(false);
                }

                Internal.MetadataSetApiAssemblyInvalidated(apiType, false);
            }

            return(true);
        }
 private void _FileSystemDockFolderMoved(string oldFolder, string newFolder)
 {
     if (File.Exists(GodotSharpDirs.ProjectCsProjPath))
     {
         ProjectUtils.RenameItemsToNewFolderInProjectChecked(GodotSharpDirs.ProjectCsProjPath, "Compile",
                                                             ProjectSettings.GlobalizePath(oldFolder), ProjectSettings.GlobalizePath(newFolder));
     }
 }
 private void _FileSystemDockFolderRemoved(string oldFolder)
 {
     if (File.Exists(GodotSharpDirs.ProjectCsProjPath))
     {
         ProjectUtils.RemoveItemsInFolderFromProjectChecked(GodotSharpDirs.ProjectCsProjPath, "Compile",
                                                            ProjectSettings.GlobalizePath(oldFolder));
     }
 }
        private bool CreateProjectSolutionIfNeeded()
        {
            if (!File.Exists(GodotSharpDirs.ProjectSlnPath) || !File.Exists(GodotSharpDirs.ProjectCsProjPath))
            {
                return(CreateProjectSolution());
            }

            return(true);
        }
        public static bool BuildProjectBlocking(string config, IEnumerable <string> godotDefines)
        {
            if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
            {
                return(true); // No solution to build
            }
            // Make sure the API assemblies are up to date before building the project.
            // We may not have had the chance to update the release API assemblies, and the debug ones
            // may have been deleted by the user at some point after they were loaded by the Godot editor.
            string apiAssembliesUpdateError = Internal.UpdateApiAssembliesFromPrebuilt(config == "ExportRelease" ? "Release" : "Debug");

            if (!string.IsNullOrEmpty(apiAssembliesUpdateError))
            {
                ShowBuildErrorDialog("Failed to update the Godot API assemblies");
                return(false);
            }

            var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings();
            var buildTool      = (BuildTool)editorSettings.GetSetting("mono/builds/build_tool");

            using (var pr = new EditorProgress("mono_project_debug_build", "Building project solution...", 1))
            {
                pr.Step("Building project solution", 0);

                var buildInfo = new BuildInfo(GodotSharpDirs.ProjectSlnPath, targets: new[] { "Restore", "Build" }, config);

                bool escapeNeedsDoubleBackslash = buildTool == BuildTool.MsBuildMono || buildTool == BuildTool.DotnetCli;

                // Add Godot defines
                string constants = !escapeNeedsDoubleBackslash ? "GodotDefineConstants=\"" : "GodotDefineConstants=\\\"";

                foreach (var godotDefine in godotDefines)
                {
                    constants += $"GODOT_{godotDefine.ToUpper().Replace("-", "_").Replace(" ", "_").Replace(";", "_")};";
                }

                if (Internal.GodotIsRealTDouble())
                {
                    constants += "GODOT_REAL_T_IS_DOUBLE;";
                }

                constants += !escapeNeedsDoubleBackslash ? "\"" : "\\\"";

                buildInfo.CustomProperties.Add(constants);

                if (!Build(buildInfo))
                {
                    ShowBuildErrorDialog("Failed to build project solution");
                    return(false);
                }
            }

            return(true);
        }
        private static void RemoveOldIssuesFile(BuildInfo buildInfo)
        {
            var issuesFile = GetIssuesFilePath(buildInfo);

            if (!File.Exists(issuesFile))
            {
                return;
            }

            File.Delete(issuesFile);
        }
Exemple #9
0
        private void _BuildSolutionPressed()
        {
            if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
            {
                if (!CreateProjectSolution())
                {
                    return; // Failed to create solution
                }
            }

            Instance.BottomPanel.BuildProjectPressed();
        }
Exemple #10
0
        public static bool BuildProjectBlocking(string config, IEnumerable <string> godotDefines)
        {
            if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
            {
                return(true); // No solution to build
            }
            string apiConfig = config == "Release" ? "Release" : "Debug";

            if (!MakeApiAssembly(ApiAssemblyType.Core, apiConfig))
            {
                return(false);
            }

            if (!MakeApiAssembly(ApiAssemblyType.Editor, apiConfig))
            {
                return(false);
            }

            using (var pr = new EditorProgress("mono_project_debug_build", "Building project solution...", 1))
            {
                pr.Step("Building project solution", 0);

                var buildInfo = new MonoBuildInfo(GodotSharpDirs.ProjectSlnPath, config);

                // Add Godot defines
                string constants = OS.IsWindows() ? "GodotDefineConstants=\"" : "GodotDefineConstants=\\\"";

                foreach (var godotDefine in godotDefines)
                {
                    constants += $"GODOT_{godotDefine.ToUpper().Replace("-", "_").Replace(" ", "_").Replace(";", "_")};";
                }

                if (Internal.GodotIsRealTDouble())
                {
                    constants += "GODOT_REAL_T_IS_DOUBLE;";
                }

                constants += OS.IsWindows() ? "\"" : "\\\"";

                buildInfo.CustomProperties.Add(constants);

                if (!Build(buildInfo))
                {
                    ShowBuildErrorDialog("Failed to build project solution");
                    return(false);
                }
            }

            return(true);
        }
        public static bool BuildProjectBlocking(string config, IEnumerable <string> godotDefines)
        {
            if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
            {
                return(true); // No solution to build
            }
            // Make sure to update the API assemblies if they happen to be missing. Just in
            // case the user decided to delete them at some point after they were loaded.
            Internal.UpdateApiAssembliesFromPrebuilt();

            var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings();
            var buildTool      = (BuildTool)editorSettings.GetSetting("mono/builds/build_tool");

            using (var pr = new EditorProgress("mono_project_debug_build", "Building project solution...", 1))
            {
                pr.Step("Building project solution", 0);

                var buildInfo = new BuildInfo(GodotSharpDirs.ProjectSlnPath, config);

                // Add Godot defines
                string constants = buildTool == BuildTool.MsBuildVs ? "GodotDefineConstants=\"" : "GodotDefineConstants=\\\"";

                foreach (var godotDefine in godotDefines)
                {
                    constants += $"GODOT_{godotDefine.ToUpper().Replace("-", "_").Replace(" ", "_").Replace(";", "_")};";
                }

                if (Internal.GodotIsRealTDouble())
                {
                    constants += "GODOT_REAL_T_IS_DOUBLE;";
                }

                constants += buildTool == BuildTool.MsBuildVs ? "\"" : "\\\"";

                buildInfo.CustomProperties.Add(constants);

                if (!Build(buildInfo))
                {
                    ShowBuildErrorDialog("Failed to build project solution");
                    return(false);
                }
            }

            return(true);
        }
        public static bool EditorBuildCallback()
        {
            if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
            {
                return(true); // No solution to build
            }
            string editorScriptsMetadataPath = Path.Combine(GodotSharpDirs.ResMetadataDir, "scripts_metadata.editor");
            string playerScriptsMetadataPath = Path.Combine(GodotSharpDirs.ResMetadataDir, "scripts_metadata.editor_player");

            CsProjOperations.GenerateScriptsMetadata(GodotSharpDirs.ProjectCsProjPath, editorScriptsMetadataPath);

            if (File.Exists(editorScriptsMetadataPath))
            {
                File.Copy(editorScriptsMetadataPath, playerScriptsMetadataPath);
            }

            var currentPlayRequest = GodotSharpEditor.Instance.CurrentPlaySettings;

            if (currentPlayRequest != null)
            {
                if (currentPlayRequest.Value.HasDebugger)
                {
                    // Set the environment variable that will tell the player to connect to the IDE debugger
                    // TODO: We should probably add a better way to do this
                    Environment.SetEnvironmentVariable("GODOT_MONO_DEBUGGER_AGENT",
                                                       "--debugger-agent=transport=dt_socket" +
                                                       $",address={currentPlayRequest.Value.DebuggerHost}:{currentPlayRequest.Value.DebuggerPort}" +
                                                       ",server=n");
                }

                if (!currentPlayRequest.Value.BuildBeforePlaying)
                {
                    return(true); // Requested play from an external editor/IDE which already built the project
                }
            }

            var godotDefines = new[]
            {
                Godot.OS.GetName(),
                Internal.GodotIs32Bits() ? "32" : "64"
            };

            return(BuildProjectBlocking("Debug", godotDefines));
        }
Exemple #13
0
        public static bool BuildProjectBlocking(string config, [CanBeNull] string platform = null)
        {
            if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
            {
                return(true); // No solution to build
            }
            // Make sure the API assemblies are up to date before building the project.
            // We may not have had the chance to update the release API assemblies, and the debug ones
            // may have been deleted by the user at some point after they were loaded by the Godot editor.
            string apiAssembliesUpdateError = Internal.UpdateApiAssembliesFromPrebuilt(config == "ExportRelease" ? "Release" : "Debug");

            if (!string.IsNullOrEmpty(apiAssembliesUpdateError))
            {
                ShowBuildErrorDialog("Failed to update the Godot API assemblies");
                return(false);
            }

            using (var pr = new EditorProgress("mono_project_debug_build", "Building project solution...", 1))
            {
                pr.Step("Building project solution", 0);

                var buildInfo = new BuildInfo(GodotSharpDirs.ProjectSlnPath, targets: new[] { "Build" }, config, restore: true);

                // If a platform was not specified, try determining the current one. If that fails, let MSBuild auto-detect it.
                if (platform != null || OS.PlatformNameMap.TryGetValue(Godot.OS.GetName(), out platform))
                {
                    buildInfo.CustomProperties.Add($"GodotTargetPlatform={platform}");
                }

                if (Internal.GodotIsRealTDouble())
                {
                    buildInfo.CustomProperties.Add("GodotRealTIsDouble=true");
                }

                if (!Build(buildInfo))
                {
                    ShowBuildErrorDialog("Failed to build project solution");
                    return(false);
                }
            }

            return(true);
        }
Exemple #14
0
        public static bool EditorBuildCallback()
        {
            if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
            {
                return(true); // No solution to build
            }
            string editorScriptsMetadataPath = Path.Combine(GodotSharpDirs.ResMetadataDir, "scripts_metadata.editor");
            string playerScriptsMetadataPath = Path.Combine(GodotSharpDirs.ResMetadataDir, "scripts_metadata.editor_player");

            CsProjOperations.GenerateScriptsMetadata(GodotSharpDirs.ProjectCsProjPath, editorScriptsMetadataPath);

            if (File.Exists(editorScriptsMetadataPath))
            {
                File.Copy(editorScriptsMetadataPath, playerScriptsMetadataPath);
            }

            if (GodotSharpEditor.Instance.SkipBuildBeforePlaying)
            {
                return(true); // Requested play from an external editor/IDE which already built the project
            }
            return(BuildProjectBlocking("Debug"));
        }
Exemple #15
0
        public static bool EditorBuildCallback()
        {
            if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
            {
                return(true); // No solution to build
            }
            string editorScriptsMetadataPath = Path.Combine(GodotSharpDirs.ResMetadataDir, "scripts_metadata.editor");
            string playerScriptsMetadataPath = Path.Combine(GodotSharpDirs.ResMetadataDir, "scripts_metadata.editor_player");

            CSharpProject.GenerateScriptsMetadata(GodotSharpDirs.ProjectCsProjPath, editorScriptsMetadataPath);

            if (File.Exists(editorScriptsMetadataPath))
            {
                File.Copy(editorScriptsMetadataPath, playerScriptsMetadataPath);
            }

            var godotDefines = new[]
            {
                Godot.OS.GetName(),
                Internal.GodotIs32Bits() ? "32" : "64"
            };

            return(BuildProjectBlocking("Tools", godotDefines));
        }
Exemple #16
0
        public override void EnablePlugin()
        {
            base.EnablePlugin();

            if (Instance != null)
            {
                throw new InvalidOperationException();
            }
            Instance = this;

            var editorInterface   = GetEditorInterface();
            var editorBaseControl = editorInterface.GetBaseControl();

            editorSettings = editorInterface.GetEditorSettings();

            errorDialog = new AcceptDialog();
            editorBaseControl.AddChild(errorDialog);

            BottomPanel = new BottomPanel();

            bottomPanelBtn = AddControlToBottomPanel(BottomPanel, "Mono".TTR());

            AddChild(new HotReloadAssemblyWatcher {
                Name = "HotReloadAssemblyWatcher"
            });

            menuPopup = new PopupMenu();
            menuPopup.Hide();
            menuPopup.SetAsToplevel(true);

            AddToolSubmenuItem("Mono", menuPopup);

            // TODO: Remove or edit this info dialog once Mono support is no longer in alpha
            {
                menuPopup.AddItem("About C# support".TTR(), (int)MenuOptions.AboutCSharp);
                aboutDialog = new AcceptDialog();
                editorBaseControl.AddChild(aboutDialog);
                aboutDialog.WindowTitle = "Important: C# support is not feature-complete";

                // We don't use DialogText as the default AcceptDialog Label doesn't play well with the TextureRect and CheckBox
                // we'll add. Instead we add containers and a new autowrapped Label inside.

                // Main VBoxContainer (icon + label on top, checkbox at bottom)
                var aboutVBox = new VBoxContainer();
                aboutDialog.AddChild(aboutVBox);

                // HBoxContainer for icon + label
                var aboutHBox = new HBoxContainer();
                aboutVBox.AddChild(aboutHBox);

                var aboutIcon = new TextureRect();
                aboutIcon.Texture = aboutIcon.GetIcon("NodeWarning", "EditorIcons");
                aboutHBox.AddChild(aboutIcon);

                var aboutLabel = new Label();
                aboutHBox.AddChild(aboutLabel);
                aboutLabel.RectMinSize       = new Vector2(600, 150) * EditorScale;
                aboutLabel.SizeFlagsVertical = (int)Control.SizeFlags.ExpandFill;
                aboutLabel.Autowrap          = true;
                aboutLabel.Text =
                    "C# support in Godot Engine is in late alpha stage and, while already usable, " +
                    "it is not meant for use in production.\n\n" +
                    "Projects can be exported to Linux, macOS, Windows and Android, but not yet to iOS, HTML5 or UWP. " +
                    "Bugs and usability issues will be addressed gradually over future releases, " +
                    "potentially including compatibility breaking changes as new features are implemented for a better overall C# experience.\n\n" +
                    "If you experience issues with this Mono build, please report them on Godot's issue tracker with details about your system, MSBuild version, IDE, etc.:\n\n" +
                    "        https://github.com/godotengine/godot/issues\n\n" +
                    "Your critical feedback at this stage will play a great role in shaping the C# support in future releases, so thank you!";

                EditorDef("mono/editor/show_info_on_start", true);

                // CheckBox in main container
                aboutDialogCheckBox = new CheckBox {
                    Text = "Show this warning when starting the editor"
                };
                aboutDialogCheckBox.Connect("toggled", this, nameof(_ToggleAboutDialogOnStart));
                aboutVBox.AddChild(aboutDialogCheckBox);
            }

            if (File.Exists(GodotSharpDirs.ProjectSlnPath) && File.Exists(GodotSharpDirs.ProjectCsProjPath))
            {
                // Make sure the existing project has Api assembly references configured correctly
                CsProjOperations.FixApiHintPath(GodotSharpDirs.ProjectCsProjPath);
            }
            else
            {
                bottomPanelBtn.Hide();
                menuPopup.AddItem("Create C# solution".TTR(), (int)MenuOptions.CreateSln);
            }

            menuPopup.Connect("id_pressed", this, nameof(_MenuOptionPressed));

            var buildButton = new ToolButton
            {
                Text        = "Build",
                HintTooltip = "Build solution",
                FocusMode   = Control.FocusModeEnum.None
            };

            buildButton.Connect("pressed", this, nameof(_BuildSolutionPressed));
            AddControlToContainer(CustomControlContainer.Toolbar, buildButton);

            // External editor settings
            EditorDef("mono/editor/external_editor", ExternalEditorId.None);

            string settingsHintStr = "Disabled";

            if (OS.IsWindows)
            {
                settingsHintStr += $",MonoDevelop:{(int)ExternalEditorId.MonoDevelop}" +
                                   $",Visual Studio Code:{(int)ExternalEditorId.VsCode}" +
                                   $",JetBrains Rider:{(int)ExternalEditorId.Rider}";
            }
            else if (OS.IsOSX)
            {
                settingsHintStr += $",Visual Studio:{(int)ExternalEditorId.VisualStudioForMac}" +
                                   $",MonoDevelop:{(int)ExternalEditorId.MonoDevelop}" +
                                   $",Visual Studio Code:{(int)ExternalEditorId.VsCode}" +
                                   $",JetBrains Rider:{(int)ExternalEditorId.Rider}";
            }
            else if (OS.IsUnixLike())
            {
                settingsHintStr += $",MonoDevelop:{(int)ExternalEditorId.MonoDevelop}" +
                                   $",Visual Studio Code:{(int)ExternalEditorId.VsCode}" +
                                   $",JetBrains Rider:{(int)ExternalEditorId.Rider}";
            }

            editorSettings.AddPropertyInfo(new Godot.Collections.Dictionary
            {
                ["type"]        = Variant.Type.Int,
                ["name"]        = "mono/editor/external_editor",
                ["hint"]        = PropertyHint.Enum,
                ["hint_string"] = settingsHintStr
            });

            // Export plugin
            var exportPlugin = new ExportPlugin();

            AddExportPlugin(exportPlugin);
            exportPlugin.RegisterExportSettings();
            exportPluginWeak = WeakRef(exportPlugin);

            BuildManager.Initialize();
            RiderPathManager.Initialize();

            GodotIdeManager = new GodotIdeManager();
            AddChild(GodotIdeManager);
        }
Exemple #17
0
        public Error OpenInExternalEditor(Script script, int line, int col)
        {
            var editor = (ExternalEditorId)editorSettings.GetSetting("mono/editor/external_editor");

            switch (editor)
            {
            case ExternalEditorId.None:
                // Tells the caller to fallback to the global external editor settings or the built-in editor
                return(Error.Unavailable);

            case ExternalEditorId.VisualStudio:
                throw new NotSupportedException();

            case ExternalEditorId.VisualStudioForMac:
                goto case ExternalEditorId.MonoDevelop;

            case ExternalEditorId.Rider:
            {
                string scriptPath = ProjectSettings.GlobalizePath(script.ResourcePath);
                RiderPathManager.OpenFile(GodotSharpDirs.ProjectSlnPath, scriptPath, line);
                return(Error.Ok);
            }

            case ExternalEditorId.MonoDevelop:
            {
                string scriptPath = ProjectSettings.GlobalizePath(script.ResourcePath);

                if (line >= 0)
                {
                    GodotIdeManager.SendOpenFile(scriptPath, line + 1, col);
                }
                else
                {
                    GodotIdeManager.SendOpenFile(scriptPath);
                }

                break;
            }

            case ExternalEditorId.VsCode:
            {
                if (_vsCodePath.Empty() || !File.Exists(_vsCodePath))
                {
                    // Try to search it again if it wasn't found last time or if it was removed from its location
                    _vsCodePath = VsCodeNames.SelectFirstNotNull(OS.PathWhich, orElse: string.Empty);
                }

                var args = new List <string>();

                bool osxAppBundleInstalled = false;

                if (OS.IsOSX)
                {
                    // The package path is '/Applications/Visual Studio Code.app'
                    const string vscodeBundleId = "com.microsoft.VSCode";

                    osxAppBundleInstalled = Internal.IsOsxAppBundleInstalled(vscodeBundleId);

                    if (osxAppBundleInstalled)
                    {
                        args.Add("-b");
                        args.Add(vscodeBundleId);

                        // The reusing of existing windows made by the 'open' command might not choose a wubdiw that is
                        // editing our folder. It's better to ask for a new window and let VSCode do the window management.
                        args.Add("-n");

                        // The open process must wait until the application finishes (which is instant in VSCode's case)
                        args.Add("--wait-apps");

                        args.Add("--args");
                    }
                }

                var resourcePath = ProjectSettings.GlobalizePath("res://");
                args.Add(resourcePath);

                string scriptPath = ProjectSettings.GlobalizePath(script.ResourcePath);

                if (line >= 0)
                {
                    args.Add("-g");
                    args.Add($"{scriptPath}:{line + 1}:{col}");
                }
                else
                {
                    args.Add(scriptPath);
                }

                string command;

                if (OS.IsOSX)
                {
                    if (!osxAppBundleInstalled && _vsCodePath.Empty())
                    {
                        GD.PushError("Cannot find code editor: VSCode");
                        return(Error.FileNotFound);
                    }

                    command = osxAppBundleInstalled ? "/usr/bin/open" : _vsCodePath;
                }
                else
                {
                    if (_vsCodePath.Empty())
                    {
                        GD.PushError("Cannot find code editor: VSCode");
                        return(Error.FileNotFound);
                    }

                    command = _vsCodePath;
                }

                try
                {
                    OS.RunProcess(command, args);
                }
                catch (Exception e)
                {
                    GD.PushError($"Error when trying to run code editor: VSCode. Exception message: '{e.Message}'");
                }

                break;
            }

            default:
                throw new ArgumentOutOfRangeException();
            }

            return(Error.Ok);
        }
Exemple #18
0
        public override void EnablePlugin()
        {
            base.EnablePlugin();

            if (Instance != null)
            {
                throw new InvalidOperationException();
            }
            Instance = this;

            var editorInterface   = GetEditorInterface();
            var editorBaseControl = editorInterface.GetBaseControl();

            editorSettings = editorInterface.GetEditorSettings();

            errorDialog = new AcceptDialog();
            editorBaseControl.AddChild(errorDialog);

            BottomPanel = new BottomPanel();

            bottomPanelBtn = AddControlToBottomPanel(BottomPanel, "Mono".TTR());

            AddChild(new HotReloadAssemblyWatcher {
                Name = "HotReloadAssemblyWatcher"
            });

            menuPopup = new PopupMenu();
            menuPopup.Hide();

            AddToolSubmenuItem("Mono", menuPopup);

            // TODO: Remove or edit this info dialog once Mono support is no longer in alpha
            {
                menuPopup.AddItem("About C# support".TTR(), (int)MenuOptions.AboutCSharp);
                aboutDialog = new AcceptDialog();
                editorBaseControl.AddChild(aboutDialog);
                aboutDialog.Title = "Important: C# support is not feature-complete";

                // We don't use DialogText as the default AcceptDialog Label doesn't play well with the TextureRect and CheckBox
                // we'll add. Instead we add containers and a new autowrapped Label inside.

                // Main VBoxContainer (icon + label on top, checkbox at bottom)
                var aboutVBox = new VBoxContainer();
                aboutDialog.AddChild(aboutVBox);

                // HBoxContainer for icon + label
                var aboutHBox = new HBoxContainer();
                aboutVBox.AddChild(aboutHBox);

                var aboutIcon = new TextureRect();
                aboutIcon.Texture = aboutIcon.GetThemeIcon("NodeWarning", "EditorIcons");
                aboutHBox.AddChild(aboutIcon);

                var aboutLabel = new Label();
                aboutHBox.AddChild(aboutLabel);
                aboutLabel.RectMinSize       = new Vector2(600, 150) * EditorScale;
                aboutLabel.SizeFlagsVertical = (int)Control.SizeFlags.ExpandFill;
                aboutLabel.Autowrap          = true;
                aboutLabel.Text =
                    "C# support in Godot Engine is in late alpha stage and, while already usable, " +
                    "it is not meant for use in production.\n\n" +
                    "Projects can be exported to Linux, macOS, Windows, Android, iOS and HTML5, but not yet to UWP. " +
                    "Bugs and usability issues will be addressed gradually over future releases, " +
                    "potentially including compatibility breaking changes as new features are implemented for a better overall C# experience.\n\n" +
                    "If you experience issues with this Mono build, please report them on Godot's issue tracker with details about your system, MSBuild version, IDE, etc.:\n\n" +
                    "        https://github.com/godotengine/godot/issues\n\n" +
                    "Your critical feedback at this stage will play a great role in shaping the C# support in future releases, so thank you!";

                EditorDef("mono/editor/show_info_on_start", true);

                // CheckBox in main container
                aboutDialogCheckBox = new CheckBox {
                    Text = "Show this warning when starting the editor"
                };
                aboutDialogCheckBox.Toggled += enabled =>
                {
                    bool showOnStart = (bool)editorSettings.GetSetting("mono/editor/show_info_on_start");
                    if (showOnStart != enabled)
                    {
                        editorSettings.SetSetting("mono/editor/show_info_on_start", enabled);
                    }
                };
                aboutVBox.AddChild(aboutDialogCheckBox);
            }

            if (File.Exists(GodotSharpDirs.ProjectSlnPath) && File.Exists(GodotSharpDirs.ProjectCsProjPath))
            {
                try
                {
                    // Migrate solution from old configuration names to: Debug, ExportDebug and ExportRelease
                    DotNetSolution.MigrateFromOldConfigNames(GodotSharpDirs.ProjectSlnPath);

                    var msbuildProject = ProjectUtils.Open(GodotSharpDirs.ProjectCsProjPath)
                                         ?? throw new Exception("Cannot open C# project");

                    // NOTE: The order in which changes are made to the project is important

                    // Migrate csproj from old configuration names to: Debug, ExportDebug and ExportRelease
                    ProjectUtils.MigrateFromOldConfigNames(msbuildProject);

                    // Apply the other fixes only after configurations have been migrated

                    // Make sure the existing project has the ProjectTypeGuids property (for VisualStudio)
                    ProjectUtils.EnsureHasProjectTypeGuids(msbuildProject);

                    // Make sure the existing project has Api assembly references configured correctly
                    ProjectUtils.FixApiHintPath(msbuildProject);

                    // Make sure the existing project references the Microsoft.NETFramework.ReferenceAssemblies nuget package
                    ProjectUtils.EnsureHasNugetNetFrameworkRefAssemblies(msbuildProject);

                    if (msbuildProject.HasUnsavedChanges)
                    {
                        // Save a copy of the project before replacing it
                        FileUtils.SaveBackupCopy(GodotSharpDirs.ProjectCsProjPath);

                        msbuildProject.Save();
                    }
                }
                catch (Exception e)
                {
                    GD.PushError(e.ToString());
                }
            }
            else
            {
                bottomPanelBtn.Hide();
                menuPopup.AddItem("Create C# solution".TTR(), (int)MenuOptions.CreateSln);
            }

            menuPopup.IdPressed += _MenuOptionPressed;

            var buildButton = new Button
            {
                Text        = "Build",
                HintTooltip = "Build solution",
                FocusMode   = Control.FocusModeEnum.None
            };

            buildButton.PressedSignal += _BuildSolutionPressed;
            AddControlToContainer(CustomControlContainer.Toolbar, buildButton);

            // External editor settings
            EditorDef("mono/editor/external_editor", ExternalEditorId.None);

            string settingsHintStr = "Disabled";

            if (OS.IsWindows)
            {
                settingsHintStr += $",Visual Studio:{(int)ExternalEditorId.VisualStudio}" +
                                   $",MonoDevelop:{(int)ExternalEditorId.MonoDevelop}" +
                                   $",Visual Studio Code:{(int)ExternalEditorId.VsCode}" +
                                   $",JetBrains Rider:{(int)ExternalEditorId.Rider}";
            }
            else if (OS.IsOSX)
            {
                settingsHintStr += $",Visual Studio:{(int)ExternalEditorId.VisualStudioForMac}" +
                                   $",MonoDevelop:{(int)ExternalEditorId.MonoDevelop}" +
                                   $",Visual Studio Code:{(int)ExternalEditorId.VsCode}" +
                                   $",JetBrains Rider:{(int)ExternalEditorId.Rider}";
            }
            else if (OS.IsUnixLike)
            {
                settingsHintStr += $",MonoDevelop:{(int)ExternalEditorId.MonoDevelop}" +
                                   $",Visual Studio Code:{(int)ExternalEditorId.VsCode}" +
                                   $",JetBrains Rider:{(int)ExternalEditorId.Rider}";
            }

            editorSettings.AddPropertyInfo(new Godot.Collections.Dictionary
            {
                ["type"]        = Variant.Type.Int,
                ["name"]        = "mono/editor/external_editor",
                ["hint"]        = PropertyHint.Enum,
                ["hint_string"] = settingsHintStr
            });

            // Export plugin
            var exportPlugin = new ExportPlugin();

            AddExportPlugin(exportPlugin);
            exportPlugin.RegisterExportSettings();
            exportPluginWeak = WeakRef(exportPlugin);

            BuildManager.Initialize();
            RiderPathManager.Initialize();

            GodotIdeManager = new GodotIdeManager();
            AddChild(GodotIdeManager);
        }
        public override void EnablePlugin()
        {
            base.EnablePlugin();

            if (Instance != null)
            {
                throw new InvalidOperationException();
            }
            Instance = this;

            var editorInterface   = GetEditorInterface();
            var editorBaseControl = editorInterface.GetBaseControl();

            _editorSettings = editorInterface.GetEditorSettings();

            _errorDialog = new AcceptDialog();
            editorBaseControl.AddChild(_errorDialog);

            MSBuildPanel    = new MSBuildPanel();
            _bottomPanelBtn = AddControlToBottomPanel(MSBuildPanel, "MSBuild".TTR());

            AddChild(new HotReloadAssemblyWatcher {
                Name = "HotReloadAssemblyWatcher"
            });

            _menuPopup = new PopupMenu();
            _menuPopup.Hide();
            _menuPopup.SetAsToplevel(true);

            AddToolSubmenuItem("C#", _menuPopup);

            var buildSolutionShortcut = (ShortCut)EditorShortcut("mono/build_solution");

            _toolBarButton = new ToolButton
            {
                Text              = "Build",
                HintTooltip       = "Build Solution".TTR(),
                FocusMode         = Control.FocusModeEnum.None,
                Shortcut          = buildSolutionShortcut,
                ShortcutInTooltip = true
            };
            _toolBarButton.Connect("pressed", this, nameof(BuildSolutionPressed));
            AddControlToContainer(CustomControlContainer.Toolbar, _toolBarButton);

            if (File.Exists(GodotSharpDirs.ProjectSlnPath) && File.Exists(GodotSharpDirs.ProjectCsProjPath))
            {
                ApplyNecessaryChangesToSolution();
            }
            else
            {
                _bottomPanelBtn.Hide();
                _toolBarButton.Hide();
                _menuPopup.AddItem("Create C# solution".TTR(), (int)MenuOptions.CreateSln);
            }

            _menuPopup.Connect("id_pressed", this, nameof(_MenuOptionPressed));

            // External editor settings
            EditorDef("mono/editor/external_editor", ExternalEditorId.None);

            string settingsHintStr = "Disabled";

            if (OS.IsWindows)
            {
                settingsHintStr += $",Visual Studio:{(int)ExternalEditorId.VisualStudio}" +
                                   $",MonoDevelop:{(int)ExternalEditorId.MonoDevelop}" +
                                   $",Visual Studio Code:{(int)ExternalEditorId.VsCode}" +
                                   $",JetBrains Rider:{(int)ExternalEditorId.Rider}";
            }
            else if (OS.IsOSX)
            {
                settingsHintStr += $",Visual Studio:{(int)ExternalEditorId.VisualStudioForMac}" +
                                   $",MonoDevelop:{(int)ExternalEditorId.MonoDevelop}" +
                                   $",Visual Studio Code:{(int)ExternalEditorId.VsCode}" +
                                   $",JetBrains Rider:{(int)ExternalEditorId.Rider}";
            }
            else if (OS.IsUnixLike)
            {
                settingsHintStr += $",MonoDevelop:{(int)ExternalEditorId.MonoDevelop}" +
                                   $",Visual Studio Code:{(int)ExternalEditorId.VsCode}" +
                                   $",JetBrains Rider:{(int)ExternalEditorId.Rider}";
            }

            _editorSettings.AddPropertyInfo(new Godot.Collections.Dictionary
            {
                ["type"]        = Variant.Type.Int,
                ["name"]        = "mono/editor/external_editor",
                ["hint"]        = PropertyHint.Enum,
                ["hint_string"] = settingsHintStr
            });

            // Export plugin
            var exportPlugin = new ExportPlugin();

            AddExportPlugin(exportPlugin);
            exportPlugin.RegisterExportSettings();
            _exportPluginWeak = WeakRef(exportPlugin);

            BuildManager.Initialize();
            RiderPathManager.Initialize();

            GodotIdeManager = new GodotIdeManager();
            AddChild(GodotIdeManager);
        }
Exemple #20
0
        public static bool MakeApiAssembly(ApiAssemblyType apiType, string config)
        {
            string apiName = apiType == ApiAssemblyType.Core ? ApiAssemblyNames.Core : ApiAssemblyNames.Editor;

            string editorPrebuiltApiDir = Path.Combine(GodotSharpDirs.DataEditorPrebuiltApiDir, config);
            string resAssembliesDir     = Path.Combine(GodotSharpDirs.ResAssembliesBaseDir, config);

            if (File.Exists(Path.Combine(editorPrebuiltApiDir, $"{apiName}.dll")))
            {
                using (var copyProgress = new EditorProgress("mono_copy_prebuilt_api_assembly", $"Copying prebuilt {apiName} assembly...", 1))
                {
                    copyProgress.Step($"Copying {apiName} assembly", 0);
                    return(CopyApiAssembly(editorPrebuiltApiDir, resAssembliesDir, apiName, apiType));
                }
            }

            const string apiSolutionName = ApiAssemblyNames.SolutionName;

            using (var pr = new EditorProgress($"mono_build_release_{apiSolutionName}", $"Building {apiSolutionName} solution...", 3))
            {
                pr.Step($"Generating {apiSolutionName} solution", 0);

                string apiSlnDir  = Path.Combine(GodotSharpDirs.MonoSolutionsDir, _ApiFolderName(ApiAssemblyType.Core));
                string apiSlnFile = Path.Combine(apiSlnDir, $"{apiSolutionName}.sln");

                if (!Directory.Exists(apiSlnDir) || !File.Exists(apiSlnFile))
                {
                    var bindingsGenerator = new BindingsGenerator();

                    if (!Godot.OS.IsStdoutVerbose())
                    {
                        bindingsGenerator.LogPrintEnabled = false;
                    }

                    Error err = bindingsGenerator.GenerateCsApi(apiSlnDir);
                    if (err != Error.Ok)
                    {
                        ShowBuildErrorDialog($"Failed to generate {apiSolutionName} solution. Error: {err}");
                        return(false);
                    }
                }

                pr.Step($"Building {apiSolutionName} solution", 1);

                if (!BuildApiSolution(apiSlnDir, config))
                {
                    return(false);
                }

                pr.Step($"Copying {apiName} assembly", 2);

                // Copy the built assembly to the assemblies directory
                string apiAssemblyDir = Path.Combine(apiSlnDir, apiName, "bin", config);
                if (!CopyApiAssembly(apiAssemblyDir, resAssembliesDir, apiName, apiType))
                {
                    return(false);
                }
            }

            return(true);
        }
Exemple #21
0
        public override void _EnablePlugin()
        {
            base._EnablePlugin();

            if (Instance != null)
            {
                throw new InvalidOperationException();
            }
            Instance = this;

            var editorInterface   = GetEditorInterface();
            var editorBaseControl = editorInterface.GetBaseControl();

            _editorSettings = editorInterface.GetEditorSettings();

            _errorDialog = new AcceptDialog();
            editorBaseControl.AddChild(_errorDialog);

            MSBuildPanel    = new MSBuildPanel();
            _bottomPanelBtn = AddControlToBottomPanel(MSBuildPanel, "MSBuild".TTR());

            AddChild(new HotReloadAssemblyWatcher {
                Name = "HotReloadAssemblyWatcher"
            });

            _menuPopup = new PopupMenu();
            _menuPopup.Hide();

            AddToolSubmenuItem("C#", _menuPopup);

            var buildSolutionShortcut = (Shortcut)EditorShortcut("mono/build_solution");

            _toolBarBuildButton = new Button
            {
                Text              = "Build",
                HintTooltip       = "Build Solution".TTR(),
                FocusMode         = Control.FocusModeEnum.None,
                Shortcut          = buildSolutionShortcut,
                ShortcutInTooltip = true
            };
            _toolBarBuildButton.PressedSignal += BuildSolutionPressed;
            AddControlToContainer(CustomControlContainer.Toolbar, _toolBarBuildButton);

            if (File.Exists(GodotSharpDirs.ProjectSlnPath) && File.Exists(GodotSharpDirs.ProjectCsProjPath))
            {
                ApplyNecessaryChangesToSolution();
            }
            else
            {
                _bottomPanelBtn.Hide();
                _toolBarBuildButton.Hide();
                _menuPopup.AddItem("Create C# solution".TTR(), (int)MenuOptions.CreateSln);
            }

            _menuPopup.IdPressed += _MenuOptionPressed;

            // External editor settings
            EditorDef("mono/editor/external_editor", ExternalEditorId.None);

            string settingsHintStr = "Disabled";

            if (OS.IsWindows)
            {
                settingsHintStr += $",Visual Studio:{(int)ExternalEditorId.VisualStudio}" +
                                   $",MonoDevelop:{(int)ExternalEditorId.MonoDevelop}" +
                                   $",Visual Studio Code:{(int)ExternalEditorId.VsCode}" +
                                   $",JetBrains Rider:{(int)ExternalEditorId.Rider}";
            }
            else if (OS.IsMacOS)
            {
                settingsHintStr += $",Visual Studio:{(int)ExternalEditorId.VisualStudioForMac}" +
                                   $",MonoDevelop:{(int)ExternalEditorId.MonoDevelop}" +
                                   $",Visual Studio Code:{(int)ExternalEditorId.VsCode}" +
                                   $",JetBrains Rider:{(int)ExternalEditorId.Rider}";
            }
            else if (OS.IsUnixLike)
            {
                settingsHintStr += $",MonoDevelop:{(int)ExternalEditorId.MonoDevelop}" +
                                   $",Visual Studio Code:{(int)ExternalEditorId.VsCode}" +
                                   $",JetBrains Rider:{(int)ExternalEditorId.Rider}";
            }

            _editorSettings.AddPropertyInfo(new Godot.Collections.Dictionary
            {
                ["type"]        = Variant.Type.Int,
                ["name"]        = "mono/editor/external_editor",
                ["hint"]        = PropertyHint.Enum,
                ["hint_string"] = settingsHintStr
            });

            // Export plugin
            var exportPlugin = new ExportPlugin();

            AddExportPlugin(exportPlugin);
            exportPlugin.RegisterExportSettings();
            _exportPluginWeak = WeakRef(exportPlugin);

            try
            {
                // At startup we make sure NuGet.Config files have our Godot NuGet fallback folder included
                NuGetUtils.AddFallbackFolderToUserNuGetConfigs(NuGetUtils.GodotFallbackFolderName, NuGetUtils.GodotFallbackFolderPath);
            }
            catch (Exception e)
            {
                GD.PushError("Failed to add Godot NuGet Offline Packages to NuGet.Config: " + e.Message);
            }

            BuildManager.Initialize();
            RiderPathManager.Initialize();

            GodotIdeManager = new GodotIdeManager();
            AddChild(GodotIdeManager);
        }
Exemple #22
0
        public Error OpenInExternalEditor(Script script, int line, int col)
        {
            var editorId = (ExternalEditorId)_editorSettings.GetSetting("mono/editor/external_editor");

            switch (editorId)
            {
            case ExternalEditorId.None:
                // Not an error. Tells the caller to fallback to the global external editor settings or the built-in editor.
                return(Error.Unavailable);

            case ExternalEditorId.VisualStudio:
            {
                string scriptPath = ProjectSettings.GlobalizePath(script.ResourcePath);

                var args = new List <string>
                {
                    GodotSharpDirs.ProjectSlnPath,
                    line >= 0 ? $"{scriptPath};{line + 1};{col + 1}" : scriptPath
                };

                string command = Path.Combine(GodotSharpDirs.DataEditorToolsDir, "GodotTools.OpenVisualStudio.exe");

                try
                {
                    if (Godot.OS.IsStdoutVerbose())
                    {
                        Console.WriteLine($"Running: \"{command}\" {string.Join(" ", args.Select(a => $"\"{a}\""))}");
                    }

                    OS.RunProcess(command, args);
                }
                catch (Exception e)
                {
                    GD.PushError($"Error when trying to run code editor: VisualStudio. Exception message: '{e.Message}'");
                }

                break;
            }

            case ExternalEditorId.VisualStudioForMac:
                goto case ExternalEditorId.MonoDevelop;

            case ExternalEditorId.Rider:
            {
                string scriptPath = ProjectSettings.GlobalizePath(script.ResourcePath);
                RiderPathManager.OpenFile(GodotSharpDirs.ProjectSlnPath, scriptPath, line);
                return(Error.Ok);
            }

            case ExternalEditorId.MonoDevelop:
            {
                string scriptPath = ProjectSettings.GlobalizePath(script.ResourcePath);

                GodotIdeManager.LaunchIdeAsync().ContinueWith(launchTask =>
                    {
                        var editorPick = launchTask.Result;
                        if (line >= 0)
                        {
                            editorPick?.SendOpenFile(scriptPath, line + 1, col);
                        }
                        else
                        {
                            editorPick?.SendOpenFile(scriptPath);
                        }
                    });

                break;
            }

            case ExternalEditorId.VsCode:
            {
                if (string.IsNullOrEmpty(_vsCodePath) || !File.Exists(_vsCodePath))
                {
                    // Try to search it again if it wasn't found last time or if it was removed from its location
                    _vsCodePath = VsCodeNames.SelectFirstNotNull(OS.PathWhich, orElse: string.Empty);
                }

                var args = new List <string>();

                bool osxAppBundleInstalled = false;

                if (OS.IsMacOS)
                {
                    // The package path is '/Applications/Visual Studio Code.app'
                    const string vscodeBundleId = "com.microsoft.VSCode";

                    osxAppBundleInstalled = Internal.IsOsxAppBundleInstalled(vscodeBundleId);

                    if (osxAppBundleInstalled)
                    {
                        args.Add("-b");
                        args.Add(vscodeBundleId);

                        // The reusing of existing windows made by the 'open' command might not choose a wubdiw that is
                        // editing our folder. It's better to ask for a new window and let VSCode do the window management.
                        args.Add("-n");

                        // The open process must wait until the application finishes (which is instant in VSCode's case)
                        args.Add("--wait-apps");

                        args.Add("--args");
                    }
                }

                string resourcePath = ProjectSettings.GlobalizePath("res://");
                args.Add(resourcePath);

                string scriptPath = ProjectSettings.GlobalizePath(script.ResourcePath);

                if (line >= 0)
                {
                    args.Add("-g");
                    args.Add($"{scriptPath}:{line}:{col}");
                }
                else
                {
                    args.Add(scriptPath);
                }

                string command;

                if (OS.IsMacOS)
                {
                    if (!osxAppBundleInstalled && string.IsNullOrEmpty(_vsCodePath))
                    {
                        GD.PushError("Cannot find code editor: VSCode");
                        return(Error.FileNotFound);
                    }

                    command = osxAppBundleInstalled ? "/usr/bin/open" : _vsCodePath;
                }
                else
                {
                    if (string.IsNullOrEmpty(_vsCodePath))
                    {
                        GD.PushError("Cannot find code editor: VSCode");
                        return(Error.FileNotFound);
                    }

                    command = _vsCodePath;
                }

                try
                {
                    OS.RunProcess(command, args);
                }
                catch (Exception e)
                {
                    GD.PushError($"Error when trying to run code editor: VSCode. Exception message: '{e.Message}'");
                }

                break;
            }

            default:
                throw new ArgumentOutOfRangeException();
            }

            return(Error.Ok);
        }