4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

コピペだけでUnity C#の構文エラーチェックをTCP通信でリクエストする

Last updated at Posted at 2025-11-21

はじめに

LLMなどでUnity C#を扱う際、構文エラー情報、必要ですよね。
ただUnityスクリプトに対応したRoslynを用意するのも煩雑だし正確性が怪しい。

そこで、TCP通信経由でUnityエディタにコンパイル(というより構文エラーチェック)をリクエストして、構文エラー情報を返してもらいましょう。

このレポジトリについて話します
https://github.com/konbraphat51/UnityCompilerTcpServer

導入

CompilerServer.csをコピペするだけ

使い方

1. Window -> Compiler TCP Serverを開く

image.png

2. サーバーを走らせる

ボタンを押してください
image.png

3. TCP通信を送る

下記のPythonスクリプトがテスト用途で便利だと思います。

import socket


def main():
    with socket.create_connection(("localhost", 5000)) as sock:
        sock.sendall(b"testing")
        response = sock.recv(1024)
        print(response.decode("utf-8", errors="replace"))


if __name__ == "__main__":
    main()

結果

エラー情報がJSONで得られます。

{
	"messages": [
		{
			"type":"Error",
			"message":"Assets\\Dodgeball\\Scripts\\AgentCubeGroundCheck.cs(14,94): error CS1585: Member modifier 'public' must precede the member type and name",
			"file":"Assets\\Dodgeball\\Scripts\\AgentCubeGroundCheck.cs",
			"line":14,
			"column":94
		}
	]
}

実装上の書き残し

Unityのコンパイルを巡る仕様と戦う後世、あるいは自分自身のための書き残し

基本アイデア

  1. TCP通信はEditorTcpServerを踏襲
    参考: (ほぼコピペだけで)Unityエディタ内にTCPサーバーを作成する(ほぼコピペだけで)Unityエディタ内にTCPサーバーを作成する

  2. コンパイル開始はCompilationPipeline.RequestScriptCompilation()

  3. エラーが無い時はCompilationPipeline.assemblyCompilationNotRequiredでイベント駆動

  4. エラーが有る時はCompilationPipeline.assemblyCompilationFinishedCompilationPipeline.assemblyCompilationFinishedでイベント駆動

環境

Unity 2022.3.62f3

コンパイルを開始させる方法

こんな関数を書いています

private static void RequestRecompilation(NetworkStream stream)
{
    // hold the stream to send response after compilation
    pendingStream = stream;

    // assets will not be updated in background
    AssetDatabase.Refresh();

    // recompilation
    CompilationPipeline.RequestScriptCompilation();

    Debug.Log("Recompilation requested");
}

Unityエディタをクリックしてフォーカスするときに、Unityエディタは

  • アセット変更を検知して
  • コンパイル

をします。

そのため、コンパイル前のAssetDatabase.Refresh()を忘れてはいけません。

コンパイル時のドメインリロードについて

コンパイルを扱うUnityエディタコーディングの一番の厄介者です。

コンパイルが完了すると、多くの変数がリセットされます。

リセットされないのは、Serializeされた変数です。今回の場合、EditorWindowのSerialize変数でステートを保持します。

が、ドメインリロードのせいでTCPソケットが消失し、TCP通信が打ち切られてしまいます。なので、ドメインリロードの前までにレスポンスを返す必要があります。

コンパイルに関するイベント駆動

こんな感じで書きました。

// when there is a compilation error (ex. syntax error)
CompilationPipeline.assemblyCompilationFinished += OnCompileError;

// when compilation starts because of no error
CompilationPipeline.assemblyCompilationNotRequired += OnCompileSuccess;
AssemblyReloadEvents.beforeAssemblyReload += OnCompileSuccess;

構文エラーが有る場合

構文エラーが存在する場合、コンパイルは完遂せず、ドメインリロードは行われません。なので、TCPソケットは消失されず、CompilationPipeline.assemblyCompilationFinishedでレスポンスを返せばいいだけです。

構文エラー内容の取得

CompilationPipeline.assemblyCompilationFinishedに対して下記の形式の関数を登録すればいいだけです。

using UnityEditor.Compilation;

void Hoge(string assemblyPath, CompilerMessage[] compilerMessages)

参考: CompilerMessage

構文エラーが無い場合

コードに変更がある場合

構文エラーが無い場合、そのままコンパイルが完遂し、ドメインリロードが始まってしまいます。なのでCompilationPipeline.assemblyCompilationFinishedは使えません。(というよりも、ドメインリロードでCompilationPipeline.assemblyCompilationFinishedすらリセットされ呼び出しすらされない様子が見られました)

ドメインリロードが始まる直前にレスポンスを返さないといけません
そのイベントトリガーがAssemblyReloadEvents.beforeAssemblyReloadです。

コードに変更がない場合

この場合、コンパイルすらされません。これを検知できるイベントトリガーがCompilationPipeline.assemblyCompilationNotRequiredです。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?