You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-12 13:20:55 +00:00
C#: Add VisualStudio support
This commit is contained in:
@@ -15,7 +15,9 @@ def build_godot_tools(source, target, env):
|
|||||||
|
|
||||||
from .solution_builder import build_solution
|
from .solution_builder import build_solution
|
||||||
|
|
||||||
build_solution(env, solution_path, build_config)
|
extra_msbuild_args = ["/p:GodotPlatform=" + env["platform"]]
|
||||||
|
|
||||||
|
build_solution(env, solution_path, build_config, extra_msbuild_args)
|
||||||
# No need to copy targets. The GodotTools csproj takes care of copying them.
|
# No need to copy targets. The GodotTools csproj takes care of copying them.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,9 +19,12 @@ namespace GodotTools.IdeMessaging
|
|||||||
private readonly string identity;
|
private readonly string identity;
|
||||||
|
|
||||||
private string MetaFilePath { get; }
|
private string MetaFilePath { get; }
|
||||||
|
private DateTime? metaFileModifiedTime;
|
||||||
private GodotIdeMetadata godotIdeMetadata;
|
private GodotIdeMetadata godotIdeMetadata;
|
||||||
private readonly FileSystemWatcher fsWatcher;
|
private readonly FileSystemWatcher fsWatcher;
|
||||||
|
|
||||||
|
public string GodotEditorExecutablePath => godotIdeMetadata.EditorExecutablePath;
|
||||||
|
|
||||||
private readonly IMessageHandler messageHandler;
|
private readonly IMessageHandler messageHandler;
|
||||||
|
|
||||||
private Peer peer;
|
private Peer peer;
|
||||||
@@ -123,7 +126,7 @@ namespace GodotTools.IdeMessaging
|
|||||||
MetaFilePath = Path.Combine(projectMetadataDir, GodotIdeMetadata.DefaultFileName);
|
MetaFilePath = Path.Combine(projectMetadataDir, GodotIdeMetadata.DefaultFileName);
|
||||||
|
|
||||||
// FileSystemWatcher requires an existing directory
|
// FileSystemWatcher requires an existing directory
|
||||||
if (!File.Exists(projectMetadataDir))
|
if (!Directory.Exists(projectMetadataDir))
|
||||||
Directory.CreateDirectory(projectMetadataDir);
|
Directory.CreateDirectory(projectMetadataDir);
|
||||||
|
|
||||||
fsWatcher = new FileSystemWatcher(projectMetadataDir, GodotIdeMetadata.DefaultFileName);
|
fsWatcher = new FileSystemWatcher(projectMetadataDir, GodotIdeMetadata.DefaultFileName);
|
||||||
@@ -142,6 +145,13 @@ namespace GodotTools.IdeMessaging
|
|||||||
if (!File.Exists(MetaFilePath))
|
if (!File.Exists(MetaFilePath))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
var lastWriteTime = File.GetLastWriteTime(MetaFilePath);
|
||||||
|
|
||||||
|
if (lastWriteTime == metaFileModifiedTime)
|
||||||
|
return;
|
||||||
|
|
||||||
|
metaFileModifiedTime = lastWriteTime;
|
||||||
|
|
||||||
var metadata = ReadMetadataFile();
|
var metadata = ReadMetadataFile();
|
||||||
|
|
||||||
if (metadata != null && metadata != godotIdeMetadata)
|
if (metadata != null && metadata != godotIdeMetadata)
|
||||||
@@ -173,6 +183,13 @@ namespace GodotTools.IdeMessaging
|
|||||||
if (IsConnected || !File.Exists(MetaFilePath))
|
if (IsConnected || !File.Exists(MetaFilePath))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
var lastWriteTime = File.GetLastWriteTime(MetaFilePath);
|
||||||
|
|
||||||
|
if (lastWriteTime == metaFileModifiedTime)
|
||||||
|
return;
|
||||||
|
|
||||||
|
metaFileModifiedTime = lastWriteTime;
|
||||||
|
|
||||||
var metadata = ReadMetadataFile();
|
var metadata = ReadMetadataFile();
|
||||||
|
|
||||||
if (metadata != null)
|
if (metadata != null)
|
||||||
@@ -185,7 +202,8 @@ namespace GodotTools.IdeMessaging
|
|||||||
|
|
||||||
private GodotIdeMetadata? ReadMetadataFile()
|
private GodotIdeMetadata? ReadMetadataFile()
|
||||||
{
|
{
|
||||||
using (var reader = File.OpenText(MetaFilePath))
|
using (var fileStream = new FileStream(MetaFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||||
|
using (var reader = new StreamReader(fileStream))
|
||||||
{
|
{
|
||||||
string portStr = reader.ReadLine();
|
string portStr = reader.ReadLine();
|
||||||
|
|
||||||
@@ -272,6 +290,7 @@ namespace GodotTools.IdeMessaging
|
|||||||
// ReSharper disable once UnusedMember.Global
|
// ReSharper disable once UnusedMember.Global
|
||||||
public async void Start()
|
public async void Start()
|
||||||
{
|
{
|
||||||
|
fsWatcher.Created += OnMetaFileChanged;
|
||||||
fsWatcher.Changed += OnMetaFileChanged;
|
fsWatcher.Changed += OnMetaFileChanged;
|
||||||
fsWatcher.Deleted += OnMetaFileDeleted;
|
fsWatcher.Deleted += OnMetaFileDeleted;
|
||||||
fsWatcher.EnableRaisingEvents = true;
|
fsWatcher.EnableRaisingEvents = true;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
<LangVersion>7.2</LangVersion>
|
<LangVersion>7.2</LangVersion>
|
||||||
<PackageId>GodotTools.IdeMessaging</PackageId>
|
<PackageId>GodotTools.IdeMessaging</PackageId>
|
||||||
<Version>1.1.0</Version>
|
<Version>1.1.1</Version>
|
||||||
<AssemblyVersion>$(Version)</AssemblyVersion>
|
<AssemblyVersion>$(Version)</AssemblyVersion>
|
||||||
<Authors>Godot Engine contributors</Authors>
|
<Authors>Godot Engine contributors</Authors>
|
||||||
<Company />
|
<Company />
|
||||||
|
|||||||
@@ -103,8 +103,6 @@ namespace GodotTools.IdeMessaging
|
|||||||
|
|
||||||
Logger.LogDebug($"Received message: {msg}");
|
Logger.LogDebug($"Received message: {msg}");
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (msg.Kind == MessageKind.Request)
|
if (msg.Kind == MessageKind.Request)
|
||||||
@@ -139,17 +137,15 @@ namespace GodotTools.IdeMessaging
|
|||||||
Logger.LogError($"Message handler for '{msg}' failed with exception", e);
|
Logger.LogError($"Message handler for '{msg}' failed with exception", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.LogError($"Exception thrown from message handler. Message: {msg}", e);
|
if (!IsDisposed || !(e is SocketException || e.InnerException is SocketException))
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
{
|
||||||
Logger.LogError("Unhandled exception in the peer loop", e);
|
Logger.LogError("Unhandled exception in the peer loop", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<bool> DoHandshake(string identity)
|
public async Task<bool> DoHandshake(string identity)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -67,6 +67,19 @@ namespace GodotTools.IdeMessaging.Requests
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public sealed class StopPlayRequest : Request
|
||||||
|
{
|
||||||
|
public new const string Id = "StopPlay";
|
||||||
|
|
||||||
|
public StopPlayRequest() : base(Id)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class StopPlayResponse : Response
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public sealed class DebugPlayRequest : Request
|
public sealed class DebugPlayRequest : Request
|
||||||
{
|
{
|
||||||
public string DebuggerHost { get; set; }
|
public string DebuggerHost { get; set; }
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<ProjectGuid>{EAFFF236-FA96-4A4D-BD23-0E51EF988277}</ProjectGuid>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net472</TargetFramework>
|
||||||
|
<LangVersion>7.2</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" />
|
||||||
|
<PackageReference Include="EnvDTE" Version="8.0.2" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,270 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Runtime.InteropServices.ComTypes;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using EnvDTE;
|
||||||
|
|
||||||
|
namespace GodotTools.OpenVisualStudio
|
||||||
|
{
|
||||||
|
internal static class Program
|
||||||
|
{
|
||||||
|
[DllImport("ole32.dll")]
|
||||||
|
private static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable pprot);
|
||||||
|
|
||||||
|
[DllImport("ole32.dll")]
|
||||||
|
private static extern void CreateBindCtx(int reserved, out IBindCtx ppbc);
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
private static extern bool SetForegroundWindow(IntPtr hWnd);
|
||||||
|
|
||||||
|
private static void ShowHelp()
|
||||||
|
{
|
||||||
|
Console.WriteLine("Opens the file(s) in a Visual Studio instance that is editing the specified solution.");
|
||||||
|
Console.WriteLine("If an existing instance for the solution is not found, a new one is created.");
|
||||||
|
Console.WriteLine();
|
||||||
|
Console.WriteLine("Usage:");
|
||||||
|
Console.WriteLine(@" GodotTools.OpenVisualStudio.exe solution [file[;line[;col]]...]");
|
||||||
|
Console.WriteLine();
|
||||||
|
Console.WriteLine("Lines and columns begin at one. Zero or lower will result in an error.");
|
||||||
|
Console.WriteLine("If a line is specified but a column is not, the line is selected in the text editor.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// STAThread needed, otherwise CoRegisterMessageFilter may return CO_E_NOT_SUPPORTED.
|
||||||
|
[STAThread]
|
||||||
|
private static int Main(string[] args)
|
||||||
|
{
|
||||||
|
if (args.Length == 0 || args[0] == "--help" || args[0] == "-h")
|
||||||
|
{
|
||||||
|
ShowHelp();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
string solutionFile = NormalizePath(args[0]);
|
||||||
|
|
||||||
|
var dte = FindInstanceEditingSolution(solutionFile);
|
||||||
|
|
||||||
|
if (dte == null)
|
||||||
|
{
|
||||||
|
// Open a new instance
|
||||||
|
|
||||||
|
var visualStudioDteType = Type.GetTypeFromProgID("VisualStudio.DTE.16.0", throwOnError: true);
|
||||||
|
dte = (DTE)Activator.CreateInstance(visualStudioDteType);
|
||||||
|
|
||||||
|
dte.UserControl = true;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
dte.Solution.Open(solutionFile);
|
||||||
|
}
|
||||||
|
catch (ArgumentException)
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine("Solution.Open: Invalid path or file not found");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dte.MainWindow.Visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageFilter.Register();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Open files
|
||||||
|
|
||||||
|
for (int i = 1; i < args.Length; i++)
|
||||||
|
{
|
||||||
|
// Both the line number and the column begin at one
|
||||||
|
|
||||||
|
string[] fileArgumentParts = args[i].Split(';');
|
||||||
|
|
||||||
|
string filePath = NormalizePath(fileArgumentParts[0]);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
dte.ItemOperations.OpenFile(filePath);
|
||||||
|
}
|
||||||
|
catch (ArgumentException)
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine("ItemOperations.OpenFile: Invalid path or file not found");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileArgumentParts.Length > 1)
|
||||||
|
{
|
||||||
|
if (int.TryParse(fileArgumentParts[1], out int line))
|
||||||
|
{
|
||||||
|
var textSelection = (TextSelection)dte.ActiveDocument.Selection;
|
||||||
|
|
||||||
|
if (fileArgumentParts.Length > 2)
|
||||||
|
{
|
||||||
|
if (int.TryParse(fileArgumentParts[2], out int column))
|
||||||
|
{
|
||||||
|
textSelection.MoveToLineAndOffset(line, column);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine("The column part of the argument must be a valid integer");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
textSelection.GotoLine(line, Select: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine("The line part of the argument must be a valid integer");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
var mainWindow = dte.MainWindow;
|
||||||
|
mainWindow.Activate();
|
||||||
|
SetForegroundWindow(new IntPtr(mainWindow.HWnd));
|
||||||
|
|
||||||
|
MessageFilter.Revoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DTE FindInstanceEditingSolution(string solutionPath)
|
||||||
|
{
|
||||||
|
if (GetRunningObjectTable(0, out IRunningObjectTable pprot) != 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
pprot.EnumRunning(out IEnumMoniker ppenumMoniker);
|
||||||
|
ppenumMoniker.Reset();
|
||||||
|
|
||||||
|
var moniker = new IMoniker[1];
|
||||||
|
|
||||||
|
while (ppenumMoniker.Next(1, moniker, IntPtr.Zero) == 0)
|
||||||
|
{
|
||||||
|
string ppszDisplayName;
|
||||||
|
|
||||||
|
CreateBindCtx(0, out IBindCtx ppbc);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
moniker[0].GetDisplayName(ppbc, null, out ppszDisplayName);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Marshal.ReleaseComObject(ppbc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ppszDisplayName == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// The digits after the colon are the process ID
|
||||||
|
if (!Regex.IsMatch(ppszDisplayName, "!VisualStudio.DTE.16.0:[0-9]"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (pprot.GetObject(moniker[0], out object ppunkObject) == 0)
|
||||||
|
{
|
||||||
|
if (ppunkObject is DTE dte && dte.Solution.FullName.Length > 0)
|
||||||
|
{
|
||||||
|
if (NormalizePath(dte.Solution.FullName) == solutionPath)
|
||||||
|
return dte;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Marshal.ReleaseComObject(pprot);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static string NormalizePath(string path)
|
||||||
|
{
|
||||||
|
return new Uri(Path.GetFullPath(path)).LocalPath
|
||||||
|
.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
|
||||||
|
.ToUpperInvariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
#region MessageFilter. See: http: //msdn.microsoft.com/en-us/library/ms228772.aspx
|
||||||
|
|
||||||
|
private class MessageFilter : IOleMessageFilter
|
||||||
|
{
|
||||||
|
// Class containing the IOleMessageFilter
|
||||||
|
// thread error-handling functions
|
||||||
|
|
||||||
|
private static IOleMessageFilter _oldFilter;
|
||||||
|
|
||||||
|
// Start the filter
|
||||||
|
public static void Register()
|
||||||
|
{
|
||||||
|
IOleMessageFilter newFilter = new MessageFilter();
|
||||||
|
int ret = CoRegisterMessageFilter(newFilter, out _oldFilter);
|
||||||
|
if (ret != 0)
|
||||||
|
Console.Error.WriteLine($"CoRegisterMessageFilter failed with error code: {ret}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Done with the filter, close it
|
||||||
|
public static void Revoke()
|
||||||
|
{
|
||||||
|
int ret = CoRegisterMessageFilter(_oldFilter, out _);
|
||||||
|
if (ret != 0)
|
||||||
|
Console.Error.WriteLine($"CoRegisterMessageFilter failed with error code: {ret}");
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// IOleMessageFilter functions
|
||||||
|
// Handle incoming thread requests
|
||||||
|
int IOleMessageFilter.HandleInComingCall(int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo)
|
||||||
|
{
|
||||||
|
// Return the flag SERVERCALL_ISHANDLED
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Thread call was rejected, so try again.
|
||||||
|
int IOleMessageFilter.RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType)
|
||||||
|
{
|
||||||
|
if (dwRejectType == 2)
|
||||||
|
// flag = SERVERCALL_RETRYLATER
|
||||||
|
{
|
||||||
|
// Retry the thread call immediately if return >= 0 & < 100
|
||||||
|
return 99;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Too busy; cancel call
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IOleMessageFilter.MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType)
|
||||||
|
{
|
||||||
|
// Return the flag PENDINGMSG_WAITDEFPROCESS
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement the IOleMessageFilter interface
|
||||||
|
[DllImport("ole32.dll")]
|
||||||
|
private static extern int CoRegisterMessageFilter(IOleMessageFilter newFilter, out IOleMessageFilter oldFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ComImport(), Guid("00000016-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
|
private interface IOleMessageFilter
|
||||||
|
{
|
||||||
|
[PreserveSig]
|
||||||
|
int HandleInComingCall(int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType);
|
||||||
|
|
||||||
|
[PreserveSig]
|
||||||
|
int MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,6 +12,11 @@ namespace GodotTools.ProjectEditor
|
|||||||
private const string CoreApiProjectName = "GodotSharp";
|
private const string CoreApiProjectName = "GodotSharp";
|
||||||
private const string EditorApiProjectName = "GodotSharpEditor";
|
private const string EditorApiProjectName = "GodotSharpEditor";
|
||||||
|
|
||||||
|
public const string CSharpProjectTypeGuid = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}";
|
||||||
|
public const string GodotProjectTypeGuid = "{8F3E2DF0-C35C-4265-82FC-BEA011F4A7ED}";
|
||||||
|
|
||||||
|
public static readonly string GodotDefaultProjectTypeGuids = $"{GodotProjectTypeGuid};{CSharpProjectTypeGuid}";
|
||||||
|
|
||||||
public static string GenGameProject(string dir, string name, IEnumerable<string> compileItems)
|
public static string GenGameProject(string dir, string name, IEnumerable<string> compileItems)
|
||||||
{
|
{
|
||||||
string path = Path.Combine(dir, name + ".csproj");
|
string path = Path.Combine(dir, name + ".csproj");
|
||||||
@@ -19,6 +24,7 @@ namespace GodotTools.ProjectEditor
|
|||||||
ProjectPropertyGroupElement mainGroup;
|
ProjectPropertyGroupElement mainGroup;
|
||||||
var root = CreateLibraryProject(name, "Debug", out mainGroup);
|
var root = CreateLibraryProject(name, "Debug", out mainGroup);
|
||||||
|
|
||||||
|
mainGroup.SetProperty("ProjectTypeGuids", GodotDefaultProjectTypeGuids);
|
||||||
mainGroup.SetProperty("OutputPath", Path.Combine(".mono", "temp", "bin", "$(Configuration)"));
|
mainGroup.SetProperty("OutputPath", Path.Combine(".mono", "temp", "bin", "$(Configuration)"));
|
||||||
mainGroup.SetProperty("BaseIntermediateOutputPath", Path.Combine(".mono", "temp", "obj"));
|
mainGroup.SetProperty("BaseIntermediateOutputPath", Path.Combine(".mono", "temp", "obj"));
|
||||||
mainGroup.SetProperty("IntermediateOutputPath", Path.Combine("$(BaseIntermediateOutputPath)", "$(Configuration)"));
|
mainGroup.SetProperty("IntermediateOutputPath", Path.Combine("$(BaseIntermediateOutputPath)", "$(Configuration)"));
|
||||||
|
|||||||
@@ -165,6 +165,21 @@ namespace GodotTools.ProjectEditor
|
|||||||
return result.ToArray();
|
return result.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void EnsureHasProjectTypeGuids(MSBuildProject project)
|
||||||
|
{
|
||||||
|
var root = project.Root;
|
||||||
|
|
||||||
|
bool found = root.PropertyGroups.Any(pg =>
|
||||||
|
string.IsNullOrEmpty(pg.Condition) && pg.Properties.Any(p => p.Name == "ProjectTypeGuids"));
|
||||||
|
|
||||||
|
if (found)
|
||||||
|
return;
|
||||||
|
|
||||||
|
root.AddProperty("ProjectTypeGuids", ProjectGenerator.GodotDefaultProjectTypeGuids);
|
||||||
|
|
||||||
|
project.HasUnsavedChanges = true;
|
||||||
|
}
|
||||||
|
|
||||||
/// Simple function to make sure the Api assembly references are configured correctly
|
/// Simple function to make sure the Api assembly references are configured correctly
|
||||||
public static void FixApiHintPath(MSBuildProject project)
|
public static void FixApiHintPath(MSBuildProject project)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotTools.BuildLogger", "G
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotTools.IdeMessaging", "GodotTools.IdeMessaging\GodotTools.IdeMessaging.csproj", "{92600954-25F0-4291-8E11-1FEE9FC4BE20}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotTools.IdeMessaging", "GodotTools.IdeMessaging\GodotTools.IdeMessaging.csproj", "{92600954-25F0-4291-8E11-1FEE9FC4BE20}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotTools.OpenVisualStudio", "GodotTools.OpenVisualStudio\GodotTools.OpenVisualStudio.csproj", "{EAFFF236-FA96-4A4D-BD23-0E51EF988277}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -37,5 +39,9 @@ Global
|
|||||||
{92600954-25F0-4291-8E11-1FEE9FC4BE20}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{92600954-25F0-4291-8E11-1FEE9FC4BE20}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{92600954-25F0-4291-8E11-1FEE9FC4BE20}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{92600954-25F0-4291-8E11-1FEE9FC4BE20}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{92600954-25F0-4291-8E11-1FEE9FC4BE20}.Release|Any CPU.Build.0 = Release|Any CPU
|
{92600954-25F0-4291-8E11-1FEE9FC4BE20}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{EAFFF236-FA96-4A4D-BD23-0E51EF988277}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{EAFFF236-FA96-4A4D-BD23-0E51EF988277}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{EAFFF236-FA96-4A4D-BD23-0E51EF988277}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{EAFFF236-FA96-4A4D-BD23-0E51EF988277}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using GodotTools.Ides;
|
using GodotTools.Ides;
|
||||||
using GodotTools.Ides.Rider;
|
using GodotTools.Ides.Rider;
|
||||||
using GodotTools.Internals;
|
using GodotTools.Internals;
|
||||||
@@ -238,7 +239,31 @@ namespace GodotTools
|
|||||||
// Not an error. Tells the caller to fallback to the global external editor settings or the built-in editor.
|
// Not an error. Tells the caller to fallback to the global external editor settings or the built-in editor.
|
||||||
return Error.Unavailable;
|
return Error.Unavailable;
|
||||||
case ExternalEditorId.VisualStudio:
|
case ExternalEditorId.VisualStudio:
|
||||||
throw new NotSupportedException();
|
{
|
||||||
|
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:
|
case ExternalEditorId.VisualStudioForMac:
|
||||||
goto case ExternalEditorId.MonoDevelop;
|
goto case ExternalEditorId.MonoDevelop;
|
||||||
case ExternalEditorId.Rider:
|
case ExternalEditorId.Rider:
|
||||||
@@ -458,6 +483,9 @@ namespace GodotTools
|
|||||||
|
|
||||||
// Apply the other fixes only after configurations have been migrated
|
// 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
|
// Make sure the existing project has Api assembly references configured correctly
|
||||||
ProjectUtils.FixApiHintPath(msbuildProject);
|
ProjectUtils.FixApiHintPath(msbuildProject);
|
||||||
|
|
||||||
@@ -501,7 +529,8 @@ namespace GodotTools
|
|||||||
|
|
||||||
if (OS.IsWindows)
|
if (OS.IsWindows)
|
||||||
{
|
{
|
||||||
settingsHintStr += $",MonoDevelop:{(int)ExternalEditorId.MonoDevelop}" +
|
settingsHintStr += $",Visual Studio:{(int)ExternalEditorId.VisualStudio}" +
|
||||||
|
$",MonoDevelop:{(int)ExternalEditorId.MonoDevelop}" +
|
||||||
$",Visual Studio Code:{(int)ExternalEditorId.VsCode}" +
|
$",Visual Studio Code:{(int)ExternalEditorId.VsCode}" +
|
||||||
$",JetBrains Rider:{(int)ExternalEditorId.Rider}";
|
$",JetBrains Rider:{(int)ExternalEditorId.Rider}";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,5 +33,7 @@
|
|||||||
<ProjectReference Include="..\GodotTools.IdeMessaging\GodotTools.IdeMessaging.csproj" />
|
<ProjectReference Include="..\GodotTools.IdeMessaging\GodotTools.IdeMessaging.csproj" />
|
||||||
<ProjectReference Include="..\GodotTools.ProjectEditor\GodotTools.ProjectEditor.csproj" />
|
<ProjectReference Include="..\GodotTools.ProjectEditor\GodotTools.ProjectEditor.csproj" />
|
||||||
<ProjectReference Include="..\GodotTools.Core\GodotTools.Core.csproj" />
|
<ProjectReference Include="..\GodotTools.Core\GodotTools.Core.csproj" />
|
||||||
|
<!-- Include it if this is an SCons build targeting Windows, or if it's not an SCons build but we're on Windows -->
|
||||||
|
<ProjectReference Include="..\GodotTools.OpenVisualStudio\GodotTools.OpenVisualStudio.csproj" Condition=" '$(GodotPlatform)' == 'windows' Or ( '$(GodotPlatform)' == '' And '$(OS)' == 'Windows_NT' ) " />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -307,6 +307,11 @@ namespace GodotTools.Ides
|
|||||||
var request = JsonConvert.DeserializeObject<DebugPlayRequest>(content.Body);
|
var request = JsonConvert.DeserializeObject<DebugPlayRequest>(content.Body);
|
||||||
return await HandleDebugPlay(request);
|
return await HandleDebugPlay(request);
|
||||||
},
|
},
|
||||||
|
[StopPlayRequest.Id] = async (peer, content) =>
|
||||||
|
{
|
||||||
|
var request = JsonConvert.DeserializeObject<StopPlayRequest>(content.Body);
|
||||||
|
return await HandleStopPlay(request);
|
||||||
|
},
|
||||||
[ReloadScriptsRequest.Id] = async (peer, content) =>
|
[ReloadScriptsRequest.Id] = async (peer, content) =>
|
||||||
{
|
{
|
||||||
_ = JsonConvert.DeserializeObject<ReloadScriptsRequest>(content.Body);
|
_ = JsonConvert.DeserializeObject<ReloadScriptsRequest>(content.Body);
|
||||||
@@ -343,6 +348,12 @@ namespace GodotTools.Ides
|
|||||||
return Task.FromResult<Response>(new DebugPlayResponse());
|
return Task.FromResult<Response>(new DebugPlayResponse());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Task<Response> HandleStopPlay(StopPlayRequest request)
|
||||||
|
{
|
||||||
|
DispatchToMainThread(Internal.EditorRunStop);
|
||||||
|
return Task.FromResult<Response>(new StopPlayResponse());
|
||||||
|
}
|
||||||
|
|
||||||
private static Task<Response> HandleReloadScripts()
|
private static Task<Response> HandleReloadScripts()
|
||||||
{
|
{
|
||||||
DispatchToMainThread(Internal.ScriptEditorDebugger_ReloadScripts);
|
DispatchToMainThread(Internal.ScriptEditorDebugger_ReloadScripts);
|
||||||
|
|||||||
@@ -75,7 +75,6 @@ LONG _RegKeyQueryString(HKEY hKey, const String &p_value_name, String &r_value)
|
|||||||
|
|
||||||
if (res == ERROR_MORE_DATA) {
|
if (res == ERROR_MORE_DATA) {
|
||||||
// dwBufferSize now contains the actual size
|
// dwBufferSize now contains the actual size
|
||||||
Vector<WCHAR> buffer;
|
|
||||||
buffer.resize(dwBufferSize);
|
buffer.resize(dwBufferSize);
|
||||||
res = RegQueryValueExW(hKey, p_value_name.c_str(), 0, nullptr, (LPBYTE)buffer.ptr(), &dwBufferSize);
|
res = RegQueryValueExW(hKey, p_value_name.c_str(), 0, nullptr, (LPBYTE)buffer.ptr(), &dwBufferSize);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user