Fixed messaging with the Godot editor not working on Windows

This commit is contained in:
Ignacio Etcheverry
2020-05-26 02:14:45 +02:00
parent 84e77e0364
commit 7b0b5ab6b4
9 changed files with 120 additions and 50 deletions

2
.vscode/launch.json vendored
View File

@@ -12,7 +12,7 @@
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"preLaunchTask": "npm: compile-tsc-debug"
"preLaunchTask": "npm: webpack-debug"
}
]
}

View File

@@ -13,43 +13,41 @@ namespace GodotDebugSession
private static readonly string LogPath = $"{ThisAppPathWithoutExtension}.log";
internal static readonly string NewLogPath = $"{ThisAppPathWithoutExtension}.new.log";
private static StreamWriter NewWriter() => new StreamWriter(LogPath, append: true, Encoding.UTF8);
private static StreamWriter _writer;
private static void Log(StreamWriter writer, string message)
{
writer.WriteLine($"{DateTime.Now:HH:mm:ss.ffffff}: {message}");
}
private static StreamWriter Writer =>
_writer ?? (_writer = new StreamWriter(LogPath, append: true, Encoding.UTF8));
public static void Log(string message)
private static void WriteLog(string message)
{
using (var writer = NewWriter())
try
{
Log(writer, message);
var writer = Writer;
writer.WriteLine($"{DateTime.Now:HH:mm:ss.ffffff}: {message}");
writer.Flush();
}
catch (IOException e)
{
Console.Error.WriteLine(e);
}
}
public static void LogError(string message)
{
using (var writer = NewWriter())
{
Log(writer, message);
}
}
public static void Log(string message) =>
WriteLog(message);
public static void LogError(string message, Exception ex)
{
using (var writer = NewWriter())
{
Log(writer, $"{message}\n{ex}");
}
}
public static void LogError(string message) =>
WriteLog(message);
public static void LogError(Exception ex)
public static void LogError(string message, Exception ex) =>
WriteLog($"{message}\n{ex}");
public static void LogError(Exception ex) =>
WriteLog(ex.ToString());
public static void Close()
{
using (var writer = NewWriter())
{
Log(writer, ex.ToString());
}
_writer?.Close();
_writer = null;
}
}
}

View File

@@ -20,6 +20,10 @@ namespace GodotDebugSession
{
Logger.LogError(ex);
}
finally
{
Logger.Close();
}
}
}
}

View File

@@ -2,17 +2,35 @@
Debugger and utilities for working with Godot C# projects in VSCode.
## Requirements
**Godot 3.2.2** or greater. Older versions of Godot are not supported.
## Features
- Debugging.
- Launch a game directly from the Godot editor.
- Code completion for Node paths, Input actions, Resource paths, Scene paths and Signal names.
- Launch a game directly in the Godot editor from VSCode.
- Additional code completion for Node paths, Input actions, Resource paths, Scene paths and Signal names.
## Requirements
**NOTES:**
- A running Godot instance must be editing the project in order for `Play in Editor` and the code completion to work.
- Node path suggestions are provided from the currently edited scene in the Godot editor.
- Currently Signal suggestions are only provided using the information from the project build
results, not from the information in the edited document. This will change in the future.
Godot 3.2.3 or 4.0 or greater is required (both versions are currently unreleaded).
## Debugger launch configurations
A Godot editor instance must be running for the project in order for code completion to work.
By default the extension creates the following launch configurations:
- **Play in Editor**\
Launches the game in the Godot editor for debugging in VSCode.\
For this option to work, a running Godot instance must be editing the project.
- **Launch**\
Launches the game with a Godot executable for debugging in VSCode.\
Before using this option, the value of the _"executable"_ property must be changed
to a path that points to the Godot executable that will be launched launched.
- **Attach**\
Attaches to a running Godot instance that was configured to listen for a debugger connection.
## Screenshots

View File

@@ -27,7 +27,10 @@
"compile": "make build",
"compile-tsc": "make tsc",
"compile-tsc-debug": "make tsc-debug",
"watch": "tsc -watch -p ./"
"watch": "tsc -watch -p ./",
"webpack": "webpack --mode production",
"webpack-debug": "webpack --mode development",
"webpack-watch": "webpack --mode development --watch"
},
"dependencies": {
"chokidar": "^3.4.0",
@@ -46,7 +49,7 @@
"glob": "^7.1.4",
"make": "^0.8.1",
"mocha": "^6.1.4",
"ts-loader": "^7.0.3",
"ts-loader": "^7.0.5",
"tslint": "^5.12.1",
"typescript": "^3.3.1",
"vsce": "^1.20.0",

View File

@@ -1,5 +1,6 @@
import * as vscode from 'vscode';
import { Client, MessageStatus } from './godot-tools-messaging/client';
import { fixPathForGodot } from './godot-utils';
enum CompletionKind {
InputActions = 0,
@@ -49,7 +50,7 @@ export class GodotCompletionProvider implements vscode.CompletionItemProvider {
return undefined;
}
let filePath = document.uri.fsPath;
let filePath = fixPathForGodot(document.uri.fsPath);
let [lines, character] = this.getPrefixLines(document, position);
let linePrefix = lines.substr(0, character);

View File

@@ -2,6 +2,7 @@ import * as vscode from 'vscode';
import { DebugProtocol } from 'vscode-debugprotocol';
import { Client, Peer, MessageContent, MessageStatus, ILogger, IMessageHandler } from './godot-tools-messaging/client';
import * as completion_provider from './completion-provider';
import { fixPathForGodot } from './godot-utils';
import * as path from 'path';
import * as fs from 'fs';
@@ -91,7 +92,13 @@ export function activate(context: vscode.ExtensionContext) {
let godotProjectFile = path.join(rootPath, 'project.godot');
return fs.existsSync(godotProjectFile);
})!.uri.path;
})?.uri.fsPath;
if (godotProjectDir === undefined) {
return;
}
godotProjectDir = fixPathForGodot(godotProjectDir);
client = new Client('VisualStudioCode', godotProjectDir, new MessageHandler(), new Logger());
client.start();
@@ -129,7 +136,9 @@ class GodotMonoDebugConfigProvider implements vscode.DebugConfigurationProvider
debugConfiguration.__exceptionOptions = convertToExceptionOptions(getModel());
}
debugConfiguration['godotProjectDir'] = folder?.uri.fsPath;
if (folder !== undefined) {
debugConfiguration['godotProjectDir'] = folder.uri.fsPath;
}
return debugConfiguration;
}

View File

@@ -4,7 +4,6 @@ import * as path from 'path';
import * as chokidar from 'chokidar';
import PromiseSocket from 'promise-socket';
import { Disposable } from 'vscode';
import { throws } from 'assert';
async function timeout(ms: number) {
return new Promise(resolve => {
@@ -35,7 +34,8 @@ class CustomSocket extends PromiseSocket<net.Socket> {
let indexOfLineBreak = this.buffer.indexOf('\n');
if (indexOfLineBreak >= 0) {
let line = this.buffer.substring(0, indexOfLineBreak);
let hasCR = indexOfLineBreak !== 0 && this.buffer.charAt(indexOfLineBreak - 1) === '\r';
let line = this.buffer.substring(0, hasCR ? indexOfLineBreak - 1 : indexOfLineBreak);
this.buffer = this.buffer.substring(indexOfLineBreak + 1);
return line;
}
@@ -269,24 +269,46 @@ export class Client implements Disposable {
return;
}
const socket = new CustomSocket();
const attempts = 3;
let attemptsLeft = attempts;
this.logger.logInfo('Connecting to Godot Ide Server');
while (attemptsLeft-- > 0) {
if (attemptsLeft < (attempts - 1)) {
this.logger.logInfo(`Waiting 3 seconds... (${attemptsLeft + 1} attempts left)`);
await timeout(5000);
}
await socket.connect(this.metadata!.port, 'localhost');
const socket = new CustomSocket();
this.logger.logInfo('Connection open with Godot Ide Server');
this.logger.logInfo('Connecting to Godot Ide Server');
this.peer = new Peer(socket, new ClientHandshake(), this.messageHandler, this.logger);
try {
await socket.connect(this.metadata!.port, 'localhost');
}
catch (err) {
this.logger.logError('Failed to connect to Godot Ide Server', err);
continue;
}
this.logger.logInfo('Connection open with Godot Ide Server');
this.peer?.dispose();
this.peer = new Peer(socket, new ClientHandshake(), this.messageHandler, this.logger);
if (!await this.peer.doHandshake(this.identity)) {
this.logger.logError('Handshake failed');
this.peer.dispose();
continue;
}
await this.peer.process();
this.logger.logInfo('Connection closed with Ide Client');
if (!await this.peer.doHandshake(this.identity)) {
this.logger.logError('Handshake failed');
return;
}
await this.peer.process();
this.logger.logInfo('Connection closed with Ide Client');
this.logger.logInfo(`Failed to connect to Godot Ide Server after ${attempts} attempts`);
}
startWatching(): void {

15
src/godot-utils.ts Normal file
View File

@@ -0,0 +1,15 @@
export function fixPathForGodot(path: string): string {
if (process.platform === "win32") {
// Godot expects the drive letter to be upper case
if (path && path.charAt(1) === ':') {
let drive = path[0];
let driveUpper = drive.toUpperCase();
if (driveUpper !== drive) {
path = driveUpper + path.substr(1);
}
}
}
return path;
}