private static Task <Response> HandleDebugPlay(DebugPlayRequest request)
 {
     DispatchToMainThread(() =>
     {
         GodotSharpEditor.Instance.CurrentPlaySettings =
             new PlaySettings(request.DebuggerHost, request.DebuggerPort, request.BuildBeforePlaying ?? true);
         Internal.EditorRunPlay();
         GodotSharpEditor.Instance.CurrentPlaySettings = null;
     });
     return(Task.FromResult <Response>(new DebugPlayResponse()));
 }
예제 #2
0
            private static Task <Response> HandleDebugPlay(DebugPlayRequest request)
            {
                DispatchToMainThread(() =>
                {
                    // Tell the build callback whether the editor already built the solution or not
                    GodotSharpEditor.Instance.SkipBuildBeforePlaying = !(request.BuildBeforePlaying ?? true);

                    // Pass the debugger agent settings to the player via an environment variables
                    // TODO: It would be better if this was an argument in EditorRunPlay instead
                    Environment.SetEnvironmentVariable("GODOT_MONO_DEBUGGER_AGENT",
                                                       "--debugger-agent=transport=dt_socket" +
                                                       $",address={request.DebuggerHost}:{request.DebuggerPort}" +
                                                       ",server=n");

                    // Run the game
                    Internal.EditorRunPlay();

                    // Restore normal settings
                    Environment.SetEnvironmentVariable("GODOT_MONO_DEBUGGER_AGENT", "");
                    GodotSharpEditor.Instance.SkipBuildBeforePlaying = false;
                });
                return(Task.FromResult <Response>(new DebugPlayResponse()));
            }
예제 #3
0
        protected override void OnRun(DebuggerStartInfo startInfo)
        {
            var godotStartInfo = (GodotStartInfo)startInfo;

            var executionType = GodotDebugTargetSelection.Instance.CurrentDebugTarget.ExecutionType;

            switch (executionType)
            {
            case ExecutionType.PlayInEditor:
            {
                _attached = false;
                StartListening(godotStartInfo, out var assignedDebugPort);

                var godotMessagingClient =
                    GodotPackage.Instance.GodotSolutionEventsListener?.GodotMessagingClient;

                if (godotMessagingClient == null || !godotMessagingClient.IsConnected)
                {
                    EndSessionWithError("Play Error", "No Godot editor instance connected");
                    return;
                }

                const string host = "127.0.0.1";

                var playRequest = new DebugPlayRequest
                {
                    DebuggerHost       = host,
                    DebuggerPort       = assignedDebugPort,
                    BuildBeforePlaying = false
                };

                _ = godotMessagingClient.SendRequest <DebugPlayResponse>(playRequest)
                    .ContinueWith(t =>
                    {
                        if (t.Result.Status != MessageStatus.Ok)
                        {
                            EndSessionWithError("Play Error", $"Received Play response with status: {MessageStatus.Ok}");
                        }
                    }, TaskScheduler.Default);

                // TODO: Read the editor player stdout and stderr somehow

                break;
            }

            case ExecutionType.Launch:
            {
                _attached = false;
                StartListening(godotStartInfo, out var assignedDebugPort);

                // Listener to replace the Godot editor remote debugger.
                // We use it to notify the game when assemblies should be reloaded.
                var remoteDebugListener = new TcpListener(IPAddress.Any, 0);
                remoteDebugListener.Start();
                _ = remoteDebugListener.AcceptTcpClientAsync()
                    .ContinueWith(OnGodotRemoteDebuggerConnectedAsync, TaskScheduler.Default);

                string       workingDir      = startInfo.WorkingDirectory;
                const string host            = "127.0.0.1";
                int          remoteDebugPort = ((IPEndPoint)remoteDebugListener.LocalEndpoint).Port;

                // Launch Godot to run the game and connect to our remote debugger

                var processStartInfo = new ProcessStartInfo(GetGodotExecutablePath())
                {
                    Arguments              = $"--path {workingDir} --remote-debug {host}:{remoteDebugPort}", // TODO: Doesn't work with 4.0dev. Should be tcp://host:port which doesn't work in 3.2...
                    WorkingDirectory       = workingDir,
                    RedirectStandardOutput = true,
                    RedirectStandardError  = true,
                    UseShellExecute        = false,
                    CreateNoWindow         = true
                };

                // Tells Godot to connect to the mono debugger we just started
                processStartInfo.EnvironmentVariables["GODOT_MONO_DEBUGGER_AGENT"] =
                    "--debugger-agent=transport=dt_socket" +
                    $",address={host}:{assignedDebugPort}" +
                    ",server=n";

                _process = new Process {
                    StartInfo = processStartInfo
                };

                _process.OutputDataReceived += (sendingProcess, outLine) => OutputData(outLine.Data, false);
                _process.ErrorDataReceived  += (sendingProcess, outLine) => OutputData(outLine.Data, true);

                if (!_process.Start())
                {
                    EndSessionWithError("Launch Error", "Failed to start Godot process");
                    return;
                }

                _process.BeginOutputReadLine();

                if (_process.HasExited)
                {
                    EndSessionWithError("Launch Error", $"Godot process exited with code: {_process.ExitCode}");
                    return;
                }

                _process.Exited += (sender, args) => EndSession();

                OnDebuggerOutput(false, $"Godot PID:{_process.Id}{Environment.NewLine}");

                break;
            }

            case ExecutionType.Attach:
            {
                _attached = true;
                StartConnecting(godotStartInfo);
                break;
            }

            default:
                throw new ArgumentOutOfRangeException(executionType.ToString());
            }

            if (!_attached)
            {
                var options = (GeneralOptionsPage)GodotPackage.Instance.GetDialogPage(typeof(GeneralOptionsPage));

                // If a connection is never established and we try to stop debugging, Visual Studio will freeze
                // for a long time for some reason. I have no idea why this happens. There may be something
                // we're doing wrong. For now we'll limit the time we wait for incoming connections.
                _ = Task.Delay(options.DebuggerListenTimeout).ContinueWith(r =>
                {
                    if (!HasExited && !IsConnected)
                    {
                        EndSession();

                        if (_process != null && !_process.HasExited)
                        {
                            _process.Kill();
                        }
                    }
                }, TaskScheduler.Default);
            }
        }
예제 #4
0
        protected override void OnRun(DebuggerStartInfo startInfo)
        {
            var godotStartInfo = (GodotDebuggerStartInfo)startInfo;

            _godotCmd = godotStartInfo.GodotCmd;

            switch (_godotCmd.ExecutionType)
            {
            case ExecutionType.PlayInEditor:
            {
                _attached = false;
                StartListening(godotStartInfo, out var assignedDebugPort);

                var godotMessagingClient = _godotCmd.GodotIdeClient;

                if (!godotMessagingClient.IsConnected)
                {
                    EndSessionWithError("No Godot editor instance connected");
                    return;
                }

                string host = "127.0.0.1";

                var playRequest = new DebugPlayRequest
                {
                    DebuggerHost       = host,
                    DebuggerPort       = assignedDebugPort,
                    BuildBeforePlaying = false
                };

                _ = godotMessagingClient.SendRequest <DebugPlayResponse>(playRequest)
                    .ContinueWith(t =>
                    {
                        if (t.Result.Status != GodotTools.IdeMessaging.MessageStatus.Ok)
                        {
                            EndSessionWithError($"Received Play response with status: {MessageStatus.Ok}");
                        }
                    });

                // TODO: Read the editor player stdout and stderr somehow

                break;
            }

            case ExecutionType.Launch:
            {
                _attached = false;
                StartListening(godotStartInfo, out var assignedDebugPort);

                // Listener to replace the Godot editor remote debugger.
                // We use it to notify the game when assemblies should be reloaded.
                var remoteDebugListener = new TcpListener(IPAddress.Any, 0);
                remoteDebugListener.Start();
                _ = remoteDebugListener.AcceptTcpClientAsync().ContinueWith(OnGodotRemoteDebuggerConnected);

                string workingDir      = startInfo.WorkingDirectory;
                string host            = "127.0.0.1";
                int    remoteDebugPort = ((IPEndPoint)remoteDebugListener.LocalEndpoint).Port;

                // Launch Godot to run the game and connect to our remote debugger

                var processStartInfo = new ProcessStartInfo(GetGodotExecutablePath())
                {
                    Arguments              = $"--path {workingDir} --remote-debug {host}:{remoteDebugPort}",
                    WorkingDirectory       = workingDir,
                    RedirectStandardOutput = true,
                    RedirectStandardError  = true,
                    UseShellExecute        = false,
                    CreateNoWindow         = true
                };

                // Tells Godot to connect to the mono debugger we just started
                processStartInfo.EnvironmentVariables["GODOT_MONO_DEBUGGER_AGENT"] =
                    "--debugger-agent=transport=dt_socket" +
                    $",address={host}:{assignedDebugPort}" +
                    ",server=n";

                _process = new Process {
                    StartInfo = processStartInfo
                };

                try
                {
                    if (!_process.Start())
                    {
                        EndSessionWithError("Failed to start Godot process");
                        return;
                    }
                }
                catch (System.ComponentModel.Win32Exception e)
                {
                    EndSessionWithError($"Failed to start Godot process: {e.Message}");
                    return;
                }

                if (_process.HasExited)
                {
                    EndSessionWithError($"Godot process exited with code: {_process.ExitCode}");
                    return;
                }

                // Listen for StdOut and StdErr

                var stdOutThread = new Thread(OutputReader)
                {
                    Name         = "Godot StandardOutput Reader",
                    IsBackground = true
                };
                stdOutThread.Start(new ThreadStartArgs
                    {
                        IsStdErr = false,
                        Stream   = _process.StandardOutput
                    });

                var stdErrThread = new Thread(OutputReader)
                {
                    Name         = "Godot StandardError Reader",
                    IsBackground = true
                };
                stdErrThread.Start(new ThreadStartArgs
                    {
                        IsStdErr = true,
                        Stream   = _process.StandardError
                    });

                _process.Exited += (sender, args) => EndSession();

                OnDebuggerOutput(false, $"Godot PID:{_process.Id}{Environment.NewLine}");

                break;
            }

            case ExecutionType.Attach:
            {
                _attached = true;
                StartConnecting(godotStartInfo);
                break;
            }

            default:
                throw new NotImplementedException(_godotCmd.ExecutionType.ToString());
            }
        }