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); }
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! } } }
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); }
private void _BuildSolutionPressed() { if (!File.Exists(GodotSharpDirs.ProjectSlnPath)) { if (!CreateProjectSolution()) { return; // Failed to create solution } } Instance.BottomPanel.BuildProjectPressed(); }
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)); }
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); }
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")); }
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)); }
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); }
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); }
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); }
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); }
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); }
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); }