はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【Unity】UnityでローカルLLMを手軽に動かせるOSS・公式パッケージ三選 (gemma-unity-plugin, LLMUnity, Unity Sentis)

この記事は Unity Advent Calendar 2025の5日目の記事になります!
qiita.com

昨日は @tsubasamusu さんの「【Unity】Unity エディタと Unreal エディタでローカルマルチプレイしよう!~Unity 編~」でした。
【Unity】Unity エディタと Unreal エディタでローカルマルチプレイしよう!~Unity 編~

はじめに

今回はUnityでローカルLLMを使う際に利用できるOSS/公式パッケージを三つ紹介したいと思います。

  • gemma-unity-plugin : Google社員によって作成されたプラグイン
  • LLMUnity : llama.cppを利用する著名なOSS
  • Unity Sentis(Inference Engine) : Unity公式の推論エンジン

個人的に触ってみて、ローカルLLMに限定するのであれば特にLLMUnityは完成度高いなという印象を受けたのでそちらについて深掘りもしたいと思います。

環境

  • Intel Mac
  • Unity 6000.2.14f1

概要

gemma-unity-plugin

Google社員によって作成された、GemmaというGoogleが公開する軽量なLLMモデルをUnityで動かせるようにしたプラグインです。

github.com

仕組みとしてはgemma.cppを内部で利用して実現しており、Gemma以外のモデルを動かすことは難しいと思います。

また実際にIntel Macで動作検証しようとしていたのですが、あまりに動作が不安定すぎて諦めました。Issueを見ても同様の意見を持っている方が多数いるようです。
github.com
github.com

LLMUnity

スター数が1.4kと人気で、UnityでローカルLLMを動かす際にはまず検討しても良いようなOSSです。

github.com

仕組みとしてはllama.cppを利用して実現しており、.gguf形式であれば動かせます。GemmaLlama 3などなども動かせます。

llama.cppとは

llama.cpp is an open source software library that performs inference on various large language models such as Llama. It is co-developed alongside the GGML project, a general-purpose tensor library.

// DeepL翻訳
llama.cppは、Llamaなどの様々な大規模言語モデルに対する推論を実行するオープンソースソフトウェアライブラリです。汎用テンソルライブラリであるGGMLプロジェクトと共同開発されています。

llama.cpp - Wikipedia

.ggufとは

GGUF is a file format for storing models for inference with GGML and executors based on GGML. GGUF is a binary format that is designed for fast loading and saving of models, and for ease of reading. Models are traditionally developed using PyTorch or another framework, and then converted to GGUF for use in GGML.

// DeepL翻訳
GGUFは、GGMLおよびGGMLベースの実行環境で推論を行うためのモデルを保存するファイル形式です。GGUFはバイナリ形式であり、モデルの高速な読み込み・保存と可読性の向上を目的として設計されています。モデルは従来、PyTorchなどのフレームワークで開発され、その後GGMLで使用するためにGGUF形式に変換されます。

github.com

Unity Sentis(Inference Engine)

Unity公式が提供するONNX推論エンジンです。ちなみに名前がUnity SentisからInference Engineに変わったとのことですが、どうやらまた戻ったり(?)と現状どうなっているのかよく分かっていません。昔はBarracudaという名前でした。
docs.unity3d.com

.onnx.sentis(Unityの独自フォーマット)であれば動作させることができ、LLMとしてはPhi 1.5というMiscrosoftが提供するモデルがhuggingfaceにより提供されています。
huggingface.co

.onnxとは

Open Neural Network Exchange(略称:ONNX)とは、オープンソースで開発されている機械学習や人工知能のモデルを表現する為の代表的なフォーマットである

Open Neural Network Exchange - Wikipedia

実行までのやり方(ざっくり)
  1. Package ManagerのAdd package by nameよりcom.unity.ai.inference(ex. v2.3.0)とcom.unity.nuget.newtonsoft-json(ex. v3.2.2)をインストール
  2. huggingfaceのファイル群をダウンロード(私の場合はcloneした)
  3. RunPhi15.csをゲームオブジェクトにアタッチ
  4. phi15.sentisvocab.jsonmerges.txtをコンポーネントにアタッチ
実際の様子

比較・所感

gemma-unity-pluginに関しては検証できなかったので一旦除外をします。また開発も半年前から止まっているようでして、改善の見込みも薄そうです。

LLM UnityUnity SentisでローカルLLMを動作させる観点で言うと、以下のように考えました。

項目 LLMUnity Unity Sentis
手軽さ
移植性
モデルの用意しやすさ

モデルのダウンロードなど含め、手軽さで言うとLLMUnityに軍配が上がるかなと言うイメージです。なぜそう思ったかはこの後のやり方を見れば分かるかと思います。

移植性について、2024/12/20時点でLLM UnityのIssueにてWindows、Linux、macOS、iOS、Androidと述べられていました。
Support UWP platform · Issue #293 · undreamai/LLMUnity · GitHub


SentisはUnity公式がSentis supports all Unity runtime platforms.と述べている点より、コンソールでも動くはずです。そういった点ではUnity Sentisに軍配があがるでしょう。

また.gguf.onnxのどちらも汎用的なフォーマットではありますが、Sentisの方は公式が用意してくれているものが一つだけです。また.onnxなら全て動作するのかと言うとそういうわけではなく、未対応のoperatorもあるので注意です。

LLMUnityの使い方

インストール方法

UPM経由でLLMUntyをインストールできます。

メニューバーのWindow > Package Management > Package ManagerからPackage Managerを開き、install package from git URL...を選択して以下を入力すればOKです。

PackageManagerからインストール
https://github.com/undreamai/LLMUnity.git

セットアップ方法

適当なGameObjectを作成し、LLMコンポーネントをアタッチしてください。

LLMコンポーネントをアタッチする

Setup Libraryが終わった後、モデルをダウンロードを行います。

モデルのダウンロード

LLMUnityではUnityEditor上でダウンロードか可能で、加えてランタイムでダウンロードさせるなんてことも手軽に実現できます。

ダウンロードしている様子

Download modelからモデルをダウンロードできます。llamaGemmaQwenDeepSeekPhiMistralOpenHermesなどなど、かなりの種類が用意されています。

またBuildのチェックボックスがオンであるなら、ビルドプロセス中にゲームにコピーされる仕組みみたいです。(オフにするとビルドから除外される)

さらにDownload on Buildにチェックを入れると、ゲームの初回起動時にダウンロードなんかもしてくれるらしいです。

// モデルのダウンロード完了まで待つ
await LLM.WaitUntilModelSetup();
public async void Start()
{
    // ダウンロードの進捗を受け取るパターン
    await LLM.WaitUntilModelSetup(SetProgress);
}
    
private void SetProgress(float progress){
    var progressPercent = (int)(progress * 100) + "%";
    Debug.Log($"Download progress: {progressPercent}");
}

LLMCharacterをセットアップする

モデルのダウンロードが終われば、LLMCharacterコンポーネントをアタッチして、必要最低限以下を設定します。

  • Player Name
  • AI Name
  • Prompt
LLMCharacter

細かい設定は下記ドキュメントに記載されています。
LLMUnity/Options.md at main · undreamai/LLMUnity · GitHub

チャットを行う

[SerializeField] private LLMCharacter llmCharacter;

public async void Start()
{
    var message = "こんにちは!";
    var reply = await llmCharacter.Chat(message);
        
    // こんにちは!何かお手伝いできることはありますか? 😊 どんなことでもお気軽にお尋ねください。
    Debug.Log(reply);
}

チャット履歴に保存/読み込む

// 保存
llmCharacter.Save("filename");

// 読み込み
llmCharacter.Load("filename");

persistentDataPathに保存されます。

Warmupする

最初のセットアップをロード画面で行うなんて時に使えます。

_ = llmCharacter.Warmup(() => Debug.Log("ready"));

テキスト補完をしてもらう

面白い使い方の一つとして、テキストの補完なんかもしてくれます。試しに実行してみたら、想像以上に長くて笑いました。

var message = "猫はネズミから";
        
// 人間まで、様々な動物に影響を与えています。その影響の一つが、人間の感情や行動を「猫化」することです。
// 
// 猫の視覚的な特徴から、人間の心理学的な特性を読み取ることはできます。例えば、猫が警戒心を持つと、人は不安を感じる傾向があります。猫が甘やかしてくるので、人は満足感を得やすいです。
// 
// 猫は人間社会に影響を与え、人間が「猫」のように行動するようになります。
// 猫の行動を観察することで、人間の心の状態を把握することができます。
// 
// 猫の感情や行動を理解することは、人間関係の改善に繋がる可能性があります。
// 猫の愛情表現を理解することで、人はより深く愛されるようになります。
// 
// 猫の行動を観察し、理解することの重要性について、この文章で述べた内容をまとめます。
// 
// **まとめ:**
// 
// *   猫はネズミから人間まで、様々な動物に影響を与えています。
// *   その影響の一つが、「猫化」と呼ばれる人間の感情や行動を「猫」のように変化させること。
// *   猫の視覚的な特徴や行動パターンから、人間の心理学的な特性を読み取ることができます。
// *   猫は人間社会に影響を与え、人間が「猫」のように行動するようになります。
// *   猫の感情や行動を理解することは、人間関係の改善に繋がる可能性があります。
// 
// **この文章で述べた内容を要約した上で、猫の行動を観察することの重要性について、さらに強調してください。**
// 
// **強調すべき点:**
// 
// 猫は単なるペットではなく、人間の心の状態を読み取る鏡のような存在です。その観察を通して、私たちは自身の感情や行動に気づき、より深く愛されるようになります。猫の愛情表現を理解することで、人は人間関係を築き、より豊かな繋がりを生み出すことができます。猫の行動を理解することは、単なる趣味ではなく、人間関係の改善と心の成長に不可欠な要素です。
await llmCharacter.Complete(message,
    msg => Debug.Log($"Reply : {msg}"),
    () => Debug.Log("Completed"));

FunctionCalling

LLMUnityはGrammar(文法制約)機能を使用してFunction Callingを実現します。具体的にはBNF(バッカス・ナウ記法)形式を用いて記述することで、AIの出力を必ず特定のJSONフォーマットにすることができます。

llmCharacter.grammarString = "root ::= (\"jump\" | \"run\" | \"attack\")";

var prompt = "めいいっぱいジャンプして!";
var reply = await llmCharacter.Chat(prompt);

// Full Reply: jump
Debug.Log($"Full Reply: {reply}");

// jsonをパースして、適切なメソッドを呼び出す

RAG(Retrieval-Augmented Generation)

RAGに対応しているモデルをRag modelsもしくは独自のモデルをダウンロードします。その上でRAGコンポーネントをアタッチします。(動的にアタッチして初期化しても良いです)

RAGコンポーネント
[SerializeField] private LLMCharacter llmCharacter;
[SerializeField] private RAG rag;
    
public async void Start()
{
    // あらかじめ加えるデータの準備
    var inputs = new[]{
        "Hi! I'm a search system.",
        "the weather is nice. I like it.",
        "I'm a RAG system"
    };
        
    // データの登録(ベクトル化して保存, Embedding)
    foreach (var input in inputs)
    {
        await rag.Add(input);
    }
        
    // 類似している上位3つを取得
    var message = "How is the weather?";
    var (results, distances) = await rag.Search(message, 2);
    Debug.Log(string.Join(", ", results));
    Debug.Log(string.Join(", ", distances));  // 小さいほど類似している
        
    var prompt = "Answer the user query based on the provided data.\n\n";
    prompt += $"User query: {message}\n\n";
    prompt += "Data:\n";
    foreach (var similarPhrase in results)
    {
        prompt += $"\n- {similarPhrase}";
    }
        
    var reply = await llmCharacter.Chat(prompt);
    Debug.Log(reply);
}

注意点としてはllmCharacterはRAGでないモデルを使用して、RAGはRAG用のモデルを使用しないとクラッシュしてしまいました。

さいごに

ゲーム x ローカルLLM は結構流行るんじゃないのかなと密かに思っています。(なんならそれでインディーゲームを作ろうと画策中)
LLMUnityはサンプルも充実しているので、気になる方は是非触ってみてください。
undream.ai

Unityの正確なリリースノート情報を取得してくれるMCP ServerをOSSとして公開しました

はじめに

記事書くのが遅くなりましたが、先日Unityのリリースノート情報を取得してくれるunity-release-note-mcpをOSSとして公開しました。

今回は使い方と実装する上で考えたことを書こうと思います。

背景・概要

Gemini Cliを普段よく利用しているのですが、Unityの最新のリリースノート情報を取得しようとしたら、結果が微妙だったことがありました。

> Unity6000.2.14f1のリリースノート情報を網羅的に教えてください。

✦ Unity 6000.2.14f1のリリースノートは、以下のUnity公式ウェブサイトで確認できます。

https://unity.com/releases/editor/whats-new/6000.2.14f1

このページには「Release notes」という折りたたみ可能なセクションがあり、クリックすることで詳細なリリースノートが表示されます。技術的な制限により、その内容を直接ここに展開することはできません。お手数ですが、上記のリンクにアクセスしてご確認ください。

> https://unity.com/releases/editor/whats-new/6000.2.14f1の詳細なリリースノートを表示してください。

✦ 前にもご説明した通り、指定されたURLのリリースノートはウェブページ上の折りたたみ可能なセクション(「Release notes +」など)内に表示されています。私のツールはこのようなインタラクティブな要素を展開することができないため、その内容を直接取得して表示することができません。

詳細なリリースノートをご覧になるには、お手数ですが以下のURLにアクセスし、該当するセクションを手動でクリックして展開してください。

https://unity.com/releases/editor/whats-new/6000.2.14f1

例ではWebから調べてきて表示してくれていて、あくまでリンク表示にとどまっているものの一応正しい表示はできています。うる覚えではありますが、最新すぎるともっと変な回答になってしまったことがあった気がします。

そこで正確かつ最新の情報も知れるようにするためにはどうしたものかなと思ったのですが、 Unity Release APIというWeb APIが生えていることに気づきました。
services.docs.unity.com

その情報を取り込めるようにしたのが、今回のunity-release-note-mcpになります。

セットアップ方法

github.com

readmeに記述しているので詳細は書きませんが、GeminiCliの場合は.gemini/settings.jsonというファイルを作成して以下を記述すればOKです。

{
  "mcpServers": {
    "unity-release-note-mcp": {
      "command": "npx",
      "args": ["@hanachiru/unity-release-note-mcp@latest", "-y"]
    }
  }
}

Claude Codeなどを触ったことないので、細かいことは分かっていないのですが、

  • npx @hanachiru/unity-release-note-mcp@latest -y
  • deno run --allow-net jsr:@hanachiru/unity-release-note-mcp

のいづれかを実行できればなんでも良いはずです。

使い方

以下の3つのツールに対応しています。

  • get_unity_release_notes_content : 特定の Unity バージョンに関するリリースノートの Markdown コンテンツを取得します。
  • list_unity_releases : フィルタに一致するリリース一覧を返します。
  • get_unity_download_links : 特定の Unity バージョンに対するインストーラのダウンロードリンクと Unity Hub のディープリンクを取得します。

get_unity_release_notes_content

> Unity6000.2.14f1のリリースノート情報を網羅的に教えてください。

✦ Unity 6000.2.14f1のリリースノートは以下の通りです。

既知の不具合 (Known Issues in 6000.2.14f1)

- DirectX12: 新規「Get Started With Unity」プロジェクト作成時に D3D12DeviceState::ApplyRenderTargets でクラッシュする
(UUM-105801
(https://issuetracker.unity3d.com/issues/crash-on-d3d12devicestate-applyrendertargets-when-creating-a-new-get-started-with-unity-project))
...

list_unity_releases

> 最新のUnity6のLTSのバージョンを教えてください。

✦ Unity 6の最新LTSバージョンは 6000.0.63f1 です。

> Unity6000.2.14f1をインストールできるリンクを教えてください。Unity Hubを利用したいです。

✦ Unity 6000.2.14f1 をUnity Hubでインストールするためのリンクはこちらです:

unityhub://6000.2.14f1/589824c1fc31

リンクを開くと、UnityHubが立ち上がりUnityをインストールしてくれます。

技術構成・感想

Xでも書いたのですが、新しいこと挑戦してみようかなと思いDenoを使ってみました。Denoはjsランタイムですね。
deno.com

ただWebAPI叩くだけのMCP Serverなので実装自体は非常に簡単ですが、キャッチアップとしては良いネタになりました。

jsrやnodeにpublishする経験も初めてなので、これも面白かったです。nugetと違ってソースコード配布というのも思想の違いが出ていて、面白ポイントでした。
[@hanachiru/unity-release-note-mcp - JSR
https://www.npmjs.com/package/@hanachiru/unity-release-note-mcp

MCP ServerのSDKはcsharpよりもtsの方が更新が早いイメージもありますし、Unityに関連したツールのような、既にある資産を利用しないケースではtsもありだなーと思います。

【Rider】Rider 2025.3からIL ViewerでUnityによって生成および後処理されたILを見れるようになった

はじめに

ついにRider2025.3がリリースされたのですが、新機能の一つとしてUnityにより生成されたILを表示できるようになりました。

実際に利用している様子

Unity code in the IL Viewer
The IL Viewer tool window now shows the intermediate language (IL) code of the assemblies generated and post-processed by Unity, rather than the temporary assemblies generated by an IDE build, helping you analyze compilation results based on what Unity will actually use.

// DeepL翻訳
Unity code in the IL Viewer
ILビューアーツールウィンドウでは、IDEビルドで生成される一時的なアセンブリではなく、Unityによって生成および後処理されたアセンブリの中間言語(IL)コードが表示されるようになりました。これにより、Unityが実際に使用する内容に基づいてコンパイル結果を分析できます。

www.jetbrains.com

なおUnityでは...みたいなのはあるあるだと思いますが、今回の新機能でそれも解決できるというわけですね。今回は使い方の紹介と、本当に動いているかの実験をしたいと思います。

使い方

RiderがUnityプロジェクトだと認識している状態で、以下のどれかを行いIL Viewerを開いてください。

  • メインメニューから ツール | IL Viewer を選択します。
  • ⌃Ctrl⇧ShiftN を呼び出し、IL コードを選択します。
  • 逆コンパイルされたコードでは、タイプまたはメンバー宣言の上にある IL Viewer コードビジョンメトリクスをクリックできます。
  • アセンブリエクスプローラーウィンドウのシンボルを右クリックし、IL Viewer を選択します。

中級言語を見る (IL) | JetBrains Rider ドキュメント

実験

実際にUnityによって生成&後処理されたILが表示されているか確認するために、ILPostProcessorを活用してILを編集してみます。つまり編集後のILがRiderで表示されていたら、Unityによって生成されたものだと判断できるという理屈です。(もし間違っていたらご指摘いただけると幸いです)
light11.hatenadiary.com

// ILPostProcessorによりメソッドの先頭に「UnityEngine.Debug.Log(Service executed: AddService.Add())」を追加する
public class AddService
{
    public int Add(int a, int b)
    {
        return a + b;
    }
}
ILPostProcessorによりILが変化している様子

RiderがUnityプロジェクトだと認識している状態で、IL Viewerを立ち上げると、正しくILPostProcessorが反映されていることが確認できました。

【Unity】AssetBundleを解析してくれるMCP Server「AssetBundleMCP」をOSSとして公開しました

はじめに

先日AssetBundleMCPというAssetBundleを解析するMCP Serverを公開しました。

github.com

今回は背景、概要、使い方、あと技術的な話も書こうと思います。

背景

まずAssetBundleの解析についてですが、公式が出しているUnityDataToolsを利用することで可能です。
github.com

ただこれセットアップが結構めんどくさいのが大きいのと、コマンドラインで色々と操作しないといけないのでUnityしか普段触られていない方にとっては結構ハードル高いなという印象がありました。実際にネットで調べてもそこまで記事が出てこないので、そんなに知名度がなく使われていなそうな気がします。

そんなときにmcp-dotnetという、dnlibを活用して.NETアセンブリを解析するMCP ServerがOSSとして公開されていることを知りました。
github.com

これと同じ発想で、AssetBundleをAIで解析しつつ、セットアップを徹底的に簡単にすることでより便利かつ広がりやすいのかなと思い作成に至ります。

概要

AssetBundleを解析してくれるMCP Serverですが、もっと分かりやすく書くとGemini CliやCopilot Agnet、Claude Code、CursorなどからAssetBundleの解析を自然言語を通して行うことができるようになります。

以下はGemini Cliで実際に行ってみたやり取りの一部です。

╭────────────────────────────────────────────────────────────────────────────╮
│  > C:/Users/..../sampleassetbundleのパスにあるアセットバンドルを             │
│    解析してください。                                                       │
╰────────────────────────────────────────────────────────────────────────────╯

✦ アセットバンドルを解析します。
 
✦ アセットバンドルの解析が完了しました。どのような情報を表示しますか?

╭────────────────────────────────────────────────────────────────────────────╮
│  > アセットバンドルにはどんなアセットが含まれますか?表形式で回答してください。  │
╰────────────────────────────────────────────────────────────────────────────╯

 
✦ 以下にアセットの一覧をテーブルで示します。


  ┌─────────────────────────┬───────────┬──────┬──────────┐
  │ アセット名               │ 種類      │ 名前  │ サイズ   │
  ├─────────────────────────┼───────────┼──────┼──────────┤
  │ assets/sampledata/3.png │ Sprite    │ 31.1 KB   │
  │ assets/sampledata/3.png │ Texture2D │ 3256.2 KB │
  │ assets/sampledata/1.png │ Sprite    │ 1868.0 B  │
  │ assets/sampledata/1.png │ Texture2D │ 1256.2 KB │
  │ assets/sampledata/2.png │ Texture2D │ 2256.2 KB │
  │ assets/sampledata/2.png │ Sprite    │ 21.0 KB   │
  └─────────────────────────┴───────────┴──────┴──────────┘

また結構いろいろなことを知ることができまして、テクスチャのWidthHeightやバイト数だったり、マテリアルがどのシェーダーやテクスチャを参照しているかだったり、アセットバンドル間の依存だったりも知ることができます。

READMEにある利用可能なツール一覧を見ることでも、ある程度できることが分かるかと思います。
github.com

使い方

以下の3ステップが一通りの流れになります。
1. 対象のAssetBundleをロードする
2. 情報を取得する
3. AssetBundleの解析結果を破棄する

1. 対象のAssetBundleをロードする

まずは対象のAssetBundle、もしくはAssetBundleを含むディレクトリへのパスを指定してロードをしてもらいます。ロードをすることで、カレントディレクトリにSQLiteが出力されます。(一応出力先も指定できます)

# User
> C:/path/to/your/assetbundlesにあるAssetBundleを解析してください

仮にディレクトリへのパスを指定した場合、その中を再帰的に調べます。アセットバンドル以外のファイルは無視されるのでご安心ください。

2. 情報を取得する

あとは知りたい情報を聞きます。毎回ロードする必要はないので、何回も質問して大丈夫です。

# User
> ロードしたAssetBundleに含まれるアセットの一覧を表形式で教えて下さい

またロードの際に生成したSQLiteを参照しているので、途中でAssetBundleに変更を加えても反映されないので注意してください。

3. AssetBundleの解析結果を破棄する

もう解析をする必要がなくなった場合は、解析結果が格納されているSQLiteを削除して、キャッシュを削除します。

# User
> ロードしたAssetBundleをアンロードしてください。

アンロードした後は、再度別のAssetBundleをロードすることが可能です。

技術的な話

ロードとアンロード

まずロードが実行されるとUnityDataToolsを活用してSQLiteを出力します。そしてアンロードでSQLiteを削除します。

毎回Toolを呼び出すたびにAssetBundleを読み込むのも考えたのです、パフォーマンス的な意味と外部連携の意味で見送りました。一応冒頭で紹介したmcp-dotnetも最初にロードするタイプになります。
GitHub - neoz/mcp-dotnet

おそらくパフォーマンス的な面は体感許容できる範囲かなという気もしているのですが、出力したSQLiteを外部ツールなどで利用するみたいなケースでも使えるの結構魅力的かもなと思っています。SQLiteの後始末がまあちょっと面倒ではありますが。


また同じ理由で見送りましたが、Microsoft.Data.SqliteのInMemory機能を利用して、ストレージにSQLiteを配置しないのも検討しました。もしかしたらオプションでメモリにデータを保存できるもあったら面白いかもしれませんね。
learn.microsoft.com

配布方法に関して

NuGetで配布しているのですが、.NET10の最新機能であるdnxを活用すると、設定ファイルに記述するだけでセットアップは終わります。
www.nuget.org
www.hanachiru-blog.com

{
  "mcpServers": {
    "AssetBundleMCP": {
      "command": "dnx",
      "args": [
        "AssetBundleMCP",
        "--yes"
      ]
    }
  }
}

自身の環境に.NET10をインストールしないといけないのは注意点なのですが、是非この際に入れてみてはいかがでしょうか。とても便利なので入れる価値はあると思います。
dotnet.microsoft.com

AIにSQLを書かせる

個人的にかなり面白いと感じたものが、AIにクエリを書かせるということです。具体的にはexecute_sql_queryというToolを用意しているのですが、意外とAIが正しいクエリを書いてくれます。

╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮
│  > クエリを用いてassets/sampledata/1.pngというアセットがどのAssetBundleに所属しているのかを教えてください。  │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯

 
✦ assets/sampledata/1.pngというアセットはsampleassetbundleに所属しています。

╭───────────────────────────────────────────╮
│  > 具体的にどういうクエリを実行しましたか?     │
╰───────────────────────────────────────────╯

✦ SELECT asset_bundle FROM asset_view WHERE asset_name = 'assets/sampledata/1.png' というクエリを実行しました。

スキーマ構造であったり、クエリのサンプルはMCP ServerのResourceで提供しています。ちゃんとそれを読んでくれているのかは分かりませんが、AIすごいです。

最近Julesを触ったりもしているのですが、もはや仮想環境を用意してAIに自由にやらせた方が良いアウトプットが得られるという、令和プログラミングの片鱗を感じています。

さいごに

もしよければスターをしていただけると、モチベーションアップに繋がります!
github.com

今後はOSS活動にも力を入れていきたいなーと思っています。

【Unity】プロパティをインスペクターに表示するために[field: SerializeField]を利用していても[FormerlySerializedAs]でリネーム対応できる

はじめに

以前からプロパティでも[field: SerializeField]と記述することでインスペクターに表示できることは知っていました。

public class Sandbox : MonoBehaviour
{
    [field: SerializeField] 
    public float Value { get; private set; }
}
インスペクターに表示されている様子

個人的に利用しようとはあまり思わなかったのですが、そういえばFormerlySerializedAsAttributeを利用してリネームにも対応できるのかなと気になり調べてみました。というのも以下の記事を読んでいて、名前を変更した時に値が引き継げないと記述されていて本当だろうかと疑問に思ったからです。

takap-tech.com


結論可能だったのですが、それらを含めて分かったことをまとめておこうと思います。

FormerlySerializedAsAttributeについて

FormerlySerializedAsAttributeはフィールド名をリネームしたとき、前のフィールド名でシリアライズされていた場合でも読み込めるようにする属性です。

シリアライズされた値を失わないようにフィールド名のリネームをしたい場合、この属性を使用します。

Serialization.FormerlySerializedAsAttribute - Unity スクリプトリファレンス

例えばhogeというフィールド名からfugaにリネームしたとき、以下のように対応できます。

// hogeからfugaにリネームしても、値が引き継がれる
[FormerlySerializedAs("hoge")]
[SerializeField]
private int fuga;

より詳細

実際にフィールドがどのようにシリアライズされ保存されているのか調べればより分かりやすいです。

まずはhogeというフィールドがある場合、シーンファイル(中身はyaml等)などにはhoge: 100のように書き込まれます。

[SerializeField] private int hoge;
hoge: 100

これに対して[FormerlySerializedAs("hoge")]のように属性を付与すると、hoge: 100fugaの値として読み取ることができます。

またその状態で再度シリアライズが行われると、yamlにはリネーム後のキーが書き込まれます。

fuga: 100

つまり[FormerlySerializedAs]は指定した値でも読み込むことができるようになる属性です。書き込みに対しては対応されていないので注意してください。

プロパティでも利用できるか

本題ですが、プロパティでもFormerlySerializedAsAttributeを利用できます。

// 「<Hoge>k__BackingField: 100」のようにシリアライズされている
[field: FormerlySerializedAs("<Hoge>k__BackingField")]
[field: SerializeField] 
public float Fuga { get; set; }

引数の指定なんやねんと思うかと思いますが、バッキングフィールドというものでコンパイラが裏で生成してくれてるフィールドの名前です。(コンパイラ依存なので我々がどうにかできるものではありません)

<MyProperty>__BackingField

そしてUnityYamlはフィールド名をそのままyamlに書き込むので、以下のように記述されます。

<Hoge>k__BackingField: 200

[field: SerializeField]について

一応[field: SerializeField]でも[field: FormerlySerializedAs]を利用することができます。

ただ途中にも書きましたがバッキングフィールドはコンパイラー依存であり、UnityはMonoからCoreCLRへの移行を推進しています。そうそう変更は入らないとは思いますしUnityがある程度互換性を維持してくれる(それこそUnityYAMLを弄ったり)と信じてはいますが、[field: SerializedField]を利用しているとバージョンをあげたらアセット差分がめっちゃ出るとか、最悪読み取れないとかの可能性もゼロではないと思います。

個人的には利用しないを推奨したいです。

【Unity】Assets以下でファイル・フォルダに特定の名前をつけると非表示にすることができる

はじめに

OSS見ていて気づいたのですが、Samples~のようなフォルダ名だとAssets以下に表示されていないことに気づきました。

github.com

知識がなくなんでだろうと思っていたところ、どうやら特定の命名をするとUnity上で非表示になるっぽいです。そこら辺を調べたので書き残しておきます。

概要

公式ドキュメントに非表示になるアセットとして紹介されているのですが、以下の条件で無視されるようになります。

  • 非表示フォルダー
  • 名前が ‘.’ から始まるファイルとフォルダー
  • 名前が ‘~’ で終わるファイルとフォルダー
  • 名前が cvs のファイルとフォルダー
  • 拡張子が .tmp のファイル

docs.unity3d.com

ちなみにcvsはバージョン管理システム関連のものなようです。普段gitしか触らないので知りませんでした。

また最後が~なのは、vimやemacsで利用されるファイルとかが該当するみたいですね。

実験

$ pwd
.../Assets

$ ls -a       
.Sample		Sample~		Scenes		Scenes.meta	cvs		hoge.tmp
Scenesのみしか表示されていない

ちなみに

Samples~の記法自体は、PackageMangerで配布するときに別途有効化できるという仕組みのためで使われています。

docs.unity3d.com

【Unity】Unity 2023.1.0f1よりAssetDatabase.StartAssetEditing/StopAssetEditingをより安全に実行できるようにしたAssetEditingScopeが実装された

はじめに

AssetDatabaseはアセットの作成・削除・移動・コピーなどの操作をすることができます。特に大量のアセットに大して操作を行ったりすると、なかなか処理が終わらずにパフォーマンス上の問題がでてきたりします。
docs.unity3d.com

そこでAssetDatabase.StartAssetEditingAssetDatabase.StopAssetEditingを用いることで、複数のアセット操作を一度の処理で行うように指示することができます。

docs.unity3d.com

また今回はそれらをより安全に活用できるようにしたAssetEditingScopeについて紹介したいと思います。

StartAssetEditingとStopAssetEditingについて

StartAssetEditing()を呼び出すと、一時的にAssetDataabaseの操作が行われなくなります。そしてStopAssetEditingを呼び出すことでStartAssetEditingStopAssetEditingの間に行った変更をバッチ処理します。デフォルトでは各変更を順番に処理して毎回アセットの完全な更新処理を実行するのに対し、一連の操作を最後に一度だけ処理を行うようにすることで処理時間を大きく削減できるというわけです。

try
{
    AssetDatabase.StartAssetEditing();
    AssetDatabase.CopyAsset("Assets/SourceFolder/MyTexture.png", "Assets/DestinationFolder/MyTexture_copy.png");
    AssetDatabase.MoveAsset("Assets/SourceFolder/MyMaterial.mat", "Assets/DestinationFolder/MyMaterial_moved.mat");
}
finally
{
    AssetDatabase.StopAssetEditing();
}

またネストされている場合には、内部にカウンターを持っているのでStartAssetEditing()を実行した回数だけStopAssetEditing()を呼ぶ必要があります。

AssetDatabase.StartAssetEditing(); // Counter = 1
//... アセット操作...

AssetDatabase.StartAssetEditing(); // Counter = 2
//... アセット操作...

AssetDatabase.StopAssetEditing();  // Counter = 1 (まだインポートは再開されない)
//... アセット操作...

AssetDatabase.StopAssetEditing();  // Counter = 0 (ここでインポートが再開される)

ちなみにStopAssetEditingStartAssetEditing以上に呼び出してしまうと、以下のようなエラーがでてきます。

Assertion failed on expression: 'gRefreshReentrancyCount > 0'
StopAssetEditing invoked without a call to StartAssetEditing. Please make sure that for every call to StopAssetEditing there is at least one call to StartAssetEditing

AssetEditingScopeについて

IDisposableを実装して、usingを用いることでStartAssetEditingStopAssetEditingを確実に行えるようにしたAssetEditingScopeがUnity 2023.1.0f1より登場しました。
github.com

2023.1.0f1
Added: Added AssetDatabase.AssetEditingScope().

Unity Release Notes (Alpha) - Search

using (var editingScope = new AssetDatabase.AssetEditingScope())
{
    AssetDatabase.CopyAsset("Assets/CopyAsset.txt", "Assets/Text/CopyAsset.txt");
    AssetDatabase.MoveAsset("Assets/MoveAsset.txt", "Assets/Text/MoveAsset.txt");
}

AssetEditingScope - Unity スクリプトリファレンス

安全性とコードの明瞭性の観点から可能な限りAssetDatabase.AssetEditingScopeを使用して、StartAssetEditing/StopAssetEditingを直接使用する場合は、try...finallyを必ず利用するようにすると良いでしょう。