2019-07-03 09:44:53 +02:00
using Godot ;
2020-04-22 14:39:42 +02:00
using GodotTools.Core ;
2019-11-10 17:10:38 +01:00
using GodotTools.Export ;
2019-07-03 09:44:53 +02:00
using GodotTools.Utils ;
using System ;
using System.Collections.Generic ;
2019-07-18 04:08:24 +02:00
using System.Diagnostics.CodeAnalysis ;
2019-07-03 09:44:53 +02:00
using System.IO ;
2019-07-18 04:08:24 +02:00
using GodotTools.Ides ;
2019-12-06 11:30:49 +01:00
using GodotTools.Ides.Rider ;
2019-07-03 09:44:53 +02:00
using GodotTools.Internals ;
using GodotTools.ProjectEditor ;
2019-12-06 11:30:49 +01:00
using JetBrains.Annotations ;
2019-07-11 13:59:06 +02:00
using static GodotTools . Internals . Globals ;
2019-07-03 09:44:53 +02:00
using File = GodotTools . Utils . File ;
using OS = GodotTools . Utils . OS ;
2020-03-18 15:05:50 +01:00
using Path = System . IO . Path ;
2019-07-03 09:44:53 +02:00
namespace GodotTools
{
2019-07-18 04:08:24 +02:00
[SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")]
2019-07-03 09:44:53 +02:00
public class GodotSharpEditor : EditorPlugin , ISerializationListener
{
private EditorSettings editorSettings ;
private PopupMenu menuPopup ;
private AcceptDialog errorDialog ;
private AcceptDialog aboutDialog ;
private CheckBox aboutDialogCheckBox ;
private ToolButton bottomPanelBtn ;
2019-07-18 04:08:24 +02:00
public GodotIdeManager GodotIdeManager { get ; private set ; }
2019-07-03 09:44:53 +02:00
2019-07-11 14:01:25 +02:00
private WeakRef exportPluginWeak ; // TODO Use WeakReference once we have proper serialization
2019-07-10 21:51:43 +02:00
2019-07-18 04:08:24 +02:00
public BottomPanel BottomPanel { get ; private set ; }
2019-07-03 09:44:53 +02:00
2020-05-09 20:45:43 +02:00
public PlaySettings ? CurrentPlaySettings { get ; set ; }
2020-03-18 17:40:04 +01:00
public static string ProjectAssemblyName
{
get
{
var projectAssemblyName = ( string ) ProjectSettings . GetSetting ( "application/config/name" ) ;
if ( string . IsNullOrEmpty ( projectAssemblyName ) )
projectAssemblyName = "UnnamedProject" ;
return projectAssemblyName ;
}
}
2019-07-03 09:44:53 +02:00
private bool CreateProjectSolution ( )
{
2019-10-11 01:23:35 +02:00
using ( var pr = new EditorProgress ( "create_csharp_solution" , "Generating solution..." . TTR ( ) , 3 ) )
2019-07-03 09:44:53 +02:00
{
2019-07-11 13:59:06 +02:00
pr . Step ( "Generating C# project..." . TTR ( ) ) ;
2019-07-03 09:44:53 +02:00
string resourceDir = ProjectSettings . GlobalizePath ( "res://" ) ;
string path = resourceDir ;
2020-03-18 17:40:04 +01:00
string name = ProjectAssemblyName ;
2019-07-03 09:44:53 +02:00
2019-07-18 04:08:24 +02:00
string guid = CsProjOperations . GenerateGameProject ( path , name ) ;
2019-07-03 09:44:53 +02:00
if ( guid . Length > 0 )
{
var solution = new DotNetSolution ( name )
{
DirectoryPath = path
} ;
var projectInfo = new DotNetSolution . ProjectInfo
{
Guid = guid ,
PathRelativeToSolution = name + ".csproj" ,
2020-03-18 15:05:50 +01:00
Configs = new List < string > { "Debug" , "ExportDebug" , "ExportRelease" }
2019-07-03 09:44:53 +02:00
} ;
solution . AddNewProject ( name , projectInfo ) ;
try
{
solution . Save ( ) ;
}
catch ( IOException e )
{
2019-07-11 13:59:06 +02:00
ShowErrorDialog ( "Failed to save solution. Exception message: " . TTR ( ) + e . Message ) ;
2019-07-03 09:44:53 +02:00
return false ;
}
2019-10-11 01:23:35 +02:00
pr . Step ( "Updating Godot API assemblies..." . TTR ( ) ) ;
string debugApiAssembliesError = Internal . UpdateApiAssembliesFromPrebuilt ( "Debug" ) ;
if ( ! string . IsNullOrEmpty ( debugApiAssembliesError ) )
{
ShowErrorDialog ( "Failed to update the Godot API assemblies: " + debugApiAssembliesError ) ;
return false ;
}
string releaseApiAssembliesError = Internal . UpdateApiAssembliesFromPrebuilt ( "Release" ) ;
if ( ! string . IsNullOrEmpty ( releaseApiAssembliesError ) )
{
ShowErrorDialog ( "Failed to update the Godot API assemblies: " + releaseApiAssembliesError ) ;
return false ;
}
2019-07-03 09:44:53 +02:00
2019-07-11 13:59:06 +02:00
pr . Step ( "Done" . TTR ( ) ) ;
2019-07-03 09:44:53 +02:00
// Here, after all calls to progress_task_step
CallDeferred ( nameof ( _RemoveCreateSlnMenuOption ) ) ;
}
else
{
2019-07-11 13:59:06 +02:00
ShowErrorDialog ( "Failed to create C# project." . TTR ( ) ) ;
2019-07-03 09:44:53 +02:00
}
return true ;
}
}
private void _RemoveCreateSlnMenuOption ( )
{
2019-12-11 14:46:28 +01:00
menuPopup . RemoveItem ( menuPopup . GetItemIndex ( ( int ) MenuOptions . CreateSln ) ) ;
2019-07-03 09:44:53 +02:00
bottomPanelBtn . Show ( ) ;
}
private void _ShowAboutDialog ( )
{
2019-12-11 14:46:28 +01:00
bool showOnStart = ( bool ) editorSettings . GetSetting ( "mono/editor/show_info_on_start" ) ;
2019-07-03 09:44:53 +02:00
aboutDialogCheckBox . Pressed = showOnStart ;
2020-04-03 01:38:48 +02:00
aboutDialog . PopupCentered ( ) ;
2019-07-03 09:44:53 +02:00
}
2020-03-14 19:20:17 +01:00
private void _MenuOptionPressed ( int id )
2019-07-03 09:44:53 +02:00
{
2020-03-14 19:20:17 +01:00
switch ( ( MenuOptions ) id )
2019-07-03 09:44:53 +02:00
{
case MenuOptions . CreateSln :
CreateProjectSolution ( ) ;
break ;
case MenuOptions . AboutCSharp :
_ShowAboutDialog ( ) ;
break ;
default :
throw new ArgumentOutOfRangeException ( nameof ( id ) , id , "Invalid menu option" ) ;
}
}
private void _BuildSolutionPressed ( )
{
if ( ! File . Exists ( GodotSharpDirs . ProjectSlnPath ) )
{
if ( ! CreateProjectSolution ( ) )
return ; // Failed to create solution
}
2019-07-18 04:08:24 +02:00
Instance . BottomPanel . BuildProjectPressed ( ) ;
2019-07-03 09:44:53 +02:00
}
public override void _Notification ( int what )
{
base . _Notification ( what ) ;
if ( what = = NotificationReady )
{
2019-12-11 14:46:28 +01:00
bool showInfoDialog = ( bool ) editorSettings . GetSetting ( "mono/editor/show_info_on_start" ) ;
2019-07-03 09:44:53 +02:00
if ( showInfoDialog )
{
2020-04-03 01:38:48 +02:00
aboutDialog . Exclusive = true ;
2019-07-03 09:44:53 +02:00
_ShowAboutDialog ( ) ;
// Once shown a first time, it can be seen again via the Mono menu - it doesn't have to be exclusive from that time on.
2020-04-03 01:38:48 +02:00
aboutDialog . Exclusive = false ;
2019-07-03 09:44:53 +02:00
}
2020-03-18 15:05:50 +01:00
var fileSystemDock = GetEditorInterface ( ) . GetFileSystemDock ( ) ;
fileSystemDock . FilesMoved + = ( file , newFile ) = >
{
if ( Path . GetExtension ( file ) = = Internal . CSharpLanguageExtension )
{
ProjectUtils . RenameItemInProjectChecked ( GodotSharpDirs . ProjectCsProjPath , "Compile" ,
ProjectSettings . GlobalizePath ( file ) , ProjectSettings . GlobalizePath ( newFile ) ) ;
}
} ;
fileSystemDock . FileRemoved + = file = >
{
if ( Path . GetExtension ( file ) = = Internal . CSharpLanguageExtension )
ProjectUtils . RemoveItemFromProjectChecked ( GodotSharpDirs . ProjectCsProjPath , "Compile" ,
ProjectSettings . GlobalizePath ( file ) ) ;
} ;
fileSystemDock . FolderMoved + = ( oldFolder , newFolder ) = >
{
ProjectUtils . RenameItemsToNewFolderInProjectChecked ( GodotSharpDirs . ProjectCsProjPath , "Compile" ,
ProjectSettings . GlobalizePath ( oldFolder ) , ProjectSettings . GlobalizePath ( newFolder ) ) ;
} ;
fileSystemDock . FolderRemoved + = oldFolder = >
{
ProjectUtils . RemoveItemsInFolderFromProjectChecked ( GodotSharpDirs . ProjectCsProjPath , "Compile" ,
ProjectSettings . GlobalizePath ( oldFolder ) ) ;
} ;
2019-07-03 09:44:53 +02:00
}
}
2019-07-18 04:08:24 +02:00
private enum MenuOptions
2019-07-03 09:44:53 +02:00
{
CreateSln ,
AboutCSharp ,
}
public void ShowErrorDialog ( string message , string title = "Error" )
{
2020-04-03 01:38:48 +02:00
errorDialog . Title = title ;
2019-07-03 09:44:53 +02:00
errorDialog . DialogText = message ;
2020-04-03 01:38:48 +02:00
errorDialog . PopupCentered ( ) ;
2019-07-03 09:44:53 +02:00
}
private static string _vsCodePath = string . Empty ;
private static readonly string [ ] VsCodeNames =
{
"code" , "code-oss" , "vscode" , "vscode-oss" , "visual-studio-code" , "visual-studio-code-oss"
} ;
2019-12-06 11:30:49 +01:00
[UsedImplicitly]
2019-07-03 09:44:53 +02:00
public Error OpenInExternalEditor ( Script script , int line , int col )
{
2020-05-09 20:45:43 +02:00
var editorId = ( ExternalEditorId ) editorSettings . GetSetting ( "mono/editor/external_editor" ) ;
2019-07-03 09:44:53 +02:00
2020-05-09 20:45:43 +02:00
switch ( editorId )
2019-07-03 09:44:53 +02:00
{
2019-07-18 04:08:24 +02:00
case ExternalEditorId . None :
2020-05-09 20:45:43 +02:00
// Not an error. Tells the caller to fallback to the global external editor settings or the built-in editor.
2019-07-18 04:08:24 +02:00
return Error . Unavailable ;
case ExternalEditorId . VisualStudio :
throw new NotSupportedException ( ) ;
case ExternalEditorId . VisualStudioForMac :
goto case ExternalEditorId . MonoDevelop ;
2019-12-06 11:30:49 +01:00
case ExternalEditorId . Rider :
{
string scriptPath = ProjectSettings . GlobalizePath ( script . ResourcePath ) ;
RiderPathManager . OpenFile ( GodotSharpDirs . ProjectSlnPath , scriptPath , line ) ;
return Error . Ok ;
2020-03-14 19:20:17 +01:00
}
2019-07-18 04:08:24 +02:00
case ExternalEditorId . MonoDevelop :
{
string scriptPath = ProjectSettings . GlobalizePath ( script . ResourcePath ) ;
2020-05-09 20:45:43 +02:00
GodotIdeManager . LaunchIdeAsync ( ) . ContinueWith ( launchTask = >
{
var editorPick = launchTask . Result ;
if ( line > = 0 )
editorPick ? . SendOpenFile ( scriptPath , line + 1 , col ) ;
else
editorPick ? . SendOpenFile ( scriptPath ) ;
} ) ;
2019-07-18 04:08:24 +02:00
break ;
}
case ExternalEditorId . VsCode :
2019-07-03 09:44:53 +02:00
{
2020-05-09 20:55:50 +02:00
if ( string . IsNullOrEmpty ( _vsCodePath ) | | ! File . Exists ( _vsCodePath ) )
2019-07-03 09:44:53 +02:00
{
// 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 ;
2019-11-10 17:10:38 +01:00
if ( OS . IsOSX )
2019-07-03 09:44:53 +02:00
{
// 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" ) ;
2020-05-09 20:45:43 +02:00
args . Add ( $"{scriptPath}:{line}:{col}" ) ;
2019-07-03 09:44:53 +02:00
}
else
{
args . Add ( scriptPath ) ;
}
string command ;
2019-11-10 17:10:38 +01:00
if ( OS . IsOSX )
2019-07-03 09:44:53 +02:00
{
2020-05-09 20:55:50 +02:00
if ( ! osxAppBundleInstalled & & string . IsNullOrEmpty ( _vsCodePath ) )
2019-07-03 09:44:53 +02:00
{
GD . PushError ( "Cannot find code editor: VSCode" ) ;
return Error . FileNotFound ;
}
command = osxAppBundleInstalled ? "/usr/bin/open" : _vsCodePath ;
}
else
{
2020-05-09 20:55:50 +02:00
if ( string . IsNullOrEmpty ( _vsCodePath ) )
2019-07-03 09:44:53 +02:00
{
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 ;
}
2019-12-06 11:30:49 +01:00
[UsedImplicitly]
2019-07-03 09:44:53 +02:00
public bool OverridesExternalEditor ( )
{
2019-12-11 14:46:28 +01:00
return ( ExternalEditorId ) editorSettings . GetSetting ( "mono/editor/external_editor" ) ! = ExternalEditorId . None ;
2019-07-03 09:44:53 +02:00
}
public override bool Build ( )
{
2019-07-18 04:08:24 +02:00
return BuildManager . EditorBuildCallback ( ) ;
2019-07-03 09:44:53 +02:00
}
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 ) ;
2019-07-18 04:08:24 +02:00
BottomPanel = new BottomPanel ( ) ;
2019-07-03 09:44:53 +02:00
2019-07-18 04:08:24 +02:00
bottomPanelBtn = AddControlToBottomPanel ( BottomPanel , "Mono" . TTR ( ) ) ;
2019-07-03 09:44:53 +02:00
2020-03-18 15:05:50 +01:00
AddChild ( new HotReloadAssemblyWatcher { Name = "HotReloadAssemblyWatcher" } ) ;
2019-07-03 09:44:53 +02:00
menuPopup = new PopupMenu ( ) ;
menuPopup . Hide ( ) ;
AddToolSubmenuItem ( "Mono" , menuPopup ) ;
// TODO: Remove or edit this info dialog once Mono support is no longer in alpha
{
2019-12-11 14:46:28 +01:00
menuPopup . AddItem ( "About C# support" . TTR ( ) , ( int ) MenuOptions . AboutCSharp ) ;
2019-07-03 09:44:53 +02:00
aboutDialog = new AcceptDialog ( ) ;
editorBaseControl . AddChild ( aboutDialog ) ;
2020-04-03 01:38:48 +02:00
aboutDialog . Title = "Important: C# support is not feature-complete" ;
2019-07-03 09:44:53 +02:00
// 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 ( ) ;
2020-04-03 01:38:48 +02:00
aboutIcon . Texture = aboutIcon . GetThemeIcon ( "NodeWarning" , "EditorIcons" ) ;
2019-07-03 09:44:53 +02:00
aboutHBox . AddChild ( aboutIcon ) ;
var aboutLabel = new Label ( ) ;
aboutHBox . AddChild ( aboutLabel ) ;
2019-07-11 13:59:06 +02:00
aboutLabel . RectMinSize = new Vector2 ( 600 , 150 ) * EditorScale ;
2019-12-11 14:46:28 +01:00
aboutLabel . SizeFlagsVertical = ( int ) Control . SizeFlags . ExpandFill ;
2019-07-03 09:44:53 +02:00
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" +
2020-05-26 03:19:45 +02:00
"Projects can be exported to Linux, macOS, Windows, Android, iOS and HTML5, but not yet to UWP. " +
2019-07-03 09:44:53 +02:00
"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!" ;
2019-07-11 13:59:06 +02:00
EditorDef ( "mono/editor/show_info_on_start" , true ) ;
2019-07-03 09:44:53 +02:00
// CheckBox in main container
2020-03-18 15:05:50 +01:00
aboutDialogCheckBox = new CheckBox { Text = "Show this warning when starting the editor" } ;
2020-03-14 19:20:17 +01:00
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 ) ;
} ;
2019-07-03 09:44:53 +02:00
aboutVBox . AddChild ( aboutDialogCheckBox ) ;
}
if ( File . Exists ( GodotSharpDirs . ProjectSlnPath ) & & File . Exists ( GodotSharpDirs . ProjectCsProjPath ) )
{
2020-03-11 17:22:12 +01:00
try
{
2020-03-14 19:01:29 +01:00
// Migrate solution from old configuration names to: Debug, ExportDebug and ExportRelease
DotNetSolution . MigrateFromOldConfigNames ( GodotSharpDirs . ProjectSlnPath ) ;
2020-04-22 14:39:42 +02:00
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
2020-03-14 19:01:29 +01:00
// Migrate csproj from old configuration names to: Debug, ExportDebug and ExportRelease
2020-04-22 14:39:42 +02:00
ProjectUtils . MigrateFromOldConfigNames ( msbuildProject ) ;
2020-03-14 19:01:29 +01:00
2020-04-22 14:39:42 +02:00
// Apply the other fixes only after configurations have been migrated
2020-03-14 19:01:29 +01:00
2020-03-11 17:22:12 +01:00
// Make sure the existing project has Api assembly references configured correctly
2020-04-22 14:39:42 +02:00
ProjectUtils . FixApiHintPath ( msbuildProject ) ;
2020-05-10 22:56:35 +02:00
// Make sure the existing project references the Microsoft.NETFramework.ReferenceAssemblies nuget package
ProjectUtils . EnsureHasNugetNetFrameworkRefAssemblies ( msbuildProject ) ;
2020-04-22 14:39:42 +02:00
if ( msbuildProject . HasUnsavedChanges )
{
// Save a copy of the project before replacing it
FileUtils . SaveBackupCopy ( GodotSharpDirs . ProjectCsProjPath ) ;
msbuildProject . Save ( ) ;
}
2020-03-11 17:22:12 +01:00
}
catch ( Exception e )
{
GD . PushError ( e . ToString ( ) ) ;
}
2019-07-03 09:44:53 +02:00
}
else
{
bottomPanelBtn . Hide ( ) ;
2019-12-11 14:46:28 +01:00
menuPopup . AddItem ( "Create C# solution" . TTR ( ) , ( int ) MenuOptions . CreateSln ) ;
2019-07-03 09:44:53 +02:00
}
2020-03-14 19:20:17 +01:00
menuPopup . IdPressed + = _MenuOptionPressed ;
2019-07-03 09:44:53 +02:00
var buildButton = new ToolButton
{
Text = "Build" ,
HintTooltip = "Build solution" ,
FocusMode = Control . FocusModeEnum . None
} ;
2020-03-14 19:20:17 +01:00
buildButton . PressedSignal + = _BuildSolutionPressed ;
2019-07-03 09:44:53 +02:00
AddControlToContainer ( CustomControlContainer . Toolbar , buildButton ) ;
// External editor settings
2019-07-18 04:08:24 +02:00
EditorDef ( "mono/editor/external_editor" , ExternalEditorId . None ) ;
2019-07-03 09:44:53 +02:00
string settingsHintStr = "Disabled" ;
2019-11-13 20:12:36 +01:00
if ( OS . IsWindows )
2019-07-03 09:44:53 +02:00
{
2019-12-11 14:46:28 +01:00
settingsHintStr + = $",MonoDevelop:{(int)ExternalEditorId.MonoDevelop}" +
$",Visual Studio Code:{(int)ExternalEditorId.VsCode}" +
$",JetBrains Rider:{(int)ExternalEditorId.Rider}" ;
2019-07-03 09:44:53 +02:00
}
2019-11-10 17:10:38 +01:00
else if ( OS . IsOSX )
2019-07-03 09:44:53 +02:00
{
2019-12-11 14:46:28 +01:00
settingsHintStr + = $",Visual Studio:{(int)ExternalEditorId.VisualStudioForMac}" +
$",MonoDevelop:{(int)ExternalEditorId.MonoDevelop}" +
$",Visual Studio Code:{(int)ExternalEditorId.VsCode}" +
$",JetBrains Rider:{(int)ExternalEditorId.Rider}" ;
2019-07-03 09:44:53 +02:00
}
2020-05-09 20:55:50 +02:00
else if ( OS . IsUnixLike )
2019-07-03 09:44:53 +02:00
{
2019-12-11 14:46:28 +01:00
settingsHintStr + = $",MonoDevelop:{(int)ExternalEditorId.MonoDevelop}" +
$",Visual Studio Code:{(int)ExternalEditorId.VsCode}" +
$",JetBrains Rider:{(int)ExternalEditorId.Rider}" ;
2019-07-03 09:44:53 +02:00
}
editorSettings . AddPropertyInfo ( new Godot . Collections . Dictionary
{
["type"] = Variant . Type . Int ,
["name"] = "mono/editor/external_editor" ,
["hint"] = PropertyHint . Enum ,
["hint_string"] = settingsHintStr
} ) ;
// Export plugin
2019-11-10 17:10:38 +01:00
var exportPlugin = new ExportPlugin ( ) ;
2019-07-10 21:51:43 +02:00
AddExportPlugin ( exportPlugin ) ;
2019-11-13 20:12:36 +01:00
exportPlugin . RegisterExportSettings ( ) ;
2019-07-11 14:01:25 +02:00
exportPluginWeak = WeakRef ( exportPlugin ) ;
2019-07-03 09:44:53 +02:00
2019-07-18 04:08:24 +02:00
BuildManager . Initialize ( ) ;
2019-12-06 11:30:49 +01:00
RiderPathManager . Initialize ( ) ;
2019-07-18 04:08:24 +02:00
GodotIdeManager = new GodotIdeManager ( ) ;
AddChild ( GodotIdeManager ) ;
2019-07-03 09:44:53 +02:00
}
2019-07-10 21:51:43 +02:00
protected override void Dispose ( bool disposing )
{
base . Dispose ( disposing ) ;
2019-07-11 14:01:25 +02:00
if ( exportPluginWeak ! = null )
2019-07-10 21:51:43 +02:00
{
// We need to dispose our export plugin before the editor destroys EditorSettings.
// Otherwise, if the GC disposes it at a later time, EditorExportPlatformAndroid
// will be freed after EditorSettings already was, and its device polling thread
// will try to access the EditorSettings singleton, resulting in null dereferencing.
2019-11-10 17:10:38 +01:00
( exportPluginWeak . GetRef ( ) as ExportPlugin ) ? . Dispose ( ) ;
2019-07-11 14:01:25 +02:00
exportPluginWeak . Dispose ( ) ;
2019-07-10 21:51:43 +02:00
}
2019-07-18 04:08:24 +02:00
GodotIdeManager ? . Dispose ( ) ;
2019-07-10 21:51:43 +02:00
}
2019-07-03 09:44:53 +02:00
public void OnBeforeSerialize ( )
{
}
public void OnAfterDeserialize ( )
{
Instance = this ;
}
// Singleton
public static GodotSharpEditor Instance { get ; private set ; }
private GodotSharpEditor ( )
{
}
}
}