VisualStudioでの依存ファイルを自動で設定する。

いつもすぐ忘れてしまうのでメモ。

    <ItemGroup>
        <Compile Update="**\*.Static.cs">
            <DependentUpon>$([System.String]::Copy(%(Filename)).Replace('.Static', '.cs'))</DependentUpon>
        </Compile>
        <Compile Update="**\*.Private.cs">
            <DependentUpon>$([System.String]::Copy(%(Filename)).Replace('.Private', '.cs'))</DependentUpon>
        </Compile>
    </ItemGroup>

.Net Core でのコマンドライン解析

コマンドラインのパースがしたいぞ

昔はコマンドライン(CLI)アプリを作ることが多くて,色々コマンドラインを解析するためのライブラリを作ったり探したりしていたのだけれど,久しぶりにコマンドラインで動作するアプリを作る際に,コマンドライン解析してくれるの何か無いかなと探したのでメモ.

ConsoleAppFramework

おなじみCysharpのやつ.Generic Host の上に乗っかってて,構成やらロギング,DIなど ASP.NET Core 周りでおなじみのやり方を使える.コマンド周りは,おなじみのメタプログラミング全開の構成.以前CLIアプリを作った際にはお世話になったが今回はパス.

command-line-api

 何度もコマンドライン解析のライブラリを作ってきては捨てていった Microsoft さん.リポジトリを見ると,なんと名前空間が System.CommandLine .これは本気なのかとちょっと漁ると System.CommandLine の概要 | Microsoft Learn ってすごいところにドキュメント作ってるな,息長く続くのかなとちょっとサンプルを写経してみた.

準備

dotnet new console --use-program-main
dotnet add package System.CommandLine --prerelease
namespace CliSample;

class Program
{
    static void Main(string[] args) {
        Console.WriteLine("Hello, World!");
    }
}

簡単なCatみたいなプログラムを書いてみる.

using System.CommandLine;

namespace CliSample;

class Program
{
    static async Task<int> Main(string[] args) {
        var lineNumbersOption = new Option<bool>(new[] { "--number", "-n" }, "行番号を表示");
        var filesArgument = new Argument<List<FileInfo>>("file", "ファイル");
        var rootCommand = new RootCommand("CliSample") {
            filesArgument,
            lineNumbersOption
        };
        rootCommand.SetHandler(ReadFile, filesArgument, lineNumbersOption);
        return await rootCommand.InvokeAsync(args);
    }

    static void ReadFile(List<FileInfo> files, bool lineNumbers) {
        files.ForEach(ReadFile);
        void ReadFile(FileInfo file) {
            File.ReadLines(file.FullName).Select(Format).ToList().ForEach(Console.WriteLine);
            string Format(string l, int n) {
                return string.Format("{0}{1}", lineNumbers ? $"{n + 1:D4} : " : "", l);
            }
        }
    }
}

オプションとか,引数のオブジェクトを作って,コマンドに渡してあげてハンドラを作って Invoke するのね.なるほど.

$ dotnet run -- --help
Description:
  CliSample

Usage:
  CliSample [<file>...] [options]

Arguments:
  <file>  ファイル

Options:
  -n, --number    行番号を表示
  --version       Show version information
  -?, -h, --help  Show help and usage information

ConsoleAppFramework はパブリッシュするときにトリムすると色々な事になっていたのが, こいつはトリム対応を正式に謳ってるだけあって,プロパティに属性を付けて自動で設定されるとか, クラスに属性を付けて自動でディスパッチされて呼び出されるとかそういった使い方では無く,素直な印象だった.

リポジトリ全体を覗いてみると,引数を解析するだけで無く, コンソールアプリケーションを作成する基本的な仕組みを提供しようとしているように感じられる.

System.CommandLine.Rendering や System.CommandLine.Hosting といった名前空間も見受けられるので もっと色々出来そうだけれど,ひとまずはサクッと作るには良い感じで出来た.

System.CommandLine.DragonFruit がなにげにすごいのだけれど, それは別で紹介してた人が居たので割愛.

.NET MAUI Windows で起動時のウインドウを何とかする.

なんかすぐに忘れてしまうのでメモ.

App.xaml.cs に以下を追加.

public partial class App : Application
{
    public App() {
        InitializeComponent();
        MainPage = new AppShell();
    }

    protected override Window CreateWindow(IActivationState activationState) {
        var window = base.CreateWindow(activationState);
        window.Title = "MauiAppTest";
        window.Width = 800;
        window.Height = 600;
        return window;
    }
}

マインクラフト的なゲームのメッシュ生成

MagicaVoxel から,OBJ を介さずに UE4 に,VOX ファイルをそのままインポート出来る VOX4U というプラグインでのメッシュ生成を行うときに最適化を行ったのでそれのメモ.

本当は,昔作ったのだけれど誰も使ってないよねと放置状態だったのを,イシューとプルリクエストが連続で来て慌ててマージと機能追加を行ったのが本当のところ.

元ネタおよび,参考にしたソースはMeshing in a Minecraft Game (Part 2) | 0 FPS.パート1ではそのまま描画,カリングする,隣接するセルを結合して四角形ポリゴンを作って描画するというところまで.

四角形ポリゴンから三角形ポリゴン

多角形の三角形分割 - Wikipediaでもあるように,色々あるのだけれど単調多角形による三角形分割をしてから,あとはまあ普通に三角形に分割しようね.そして,単調多角形に分割するアルゴリズムは O(n log n) 1 になるんだけれど,真面目にするとボクセルの数ってのは頂点数なんかより遙かに多いわけで,これはボクセルのスライスした面を走査することで O(n) 2 で単調多角形を作ることでそれをカバーできるねというお話.

モノトーン化する

アルゴリズムはざっくりと

  • 垂直方向分
    • 水平方向にスキャンして,面を探す
      • 上のポリゴンがあるか,スキャンした面がある間
        • スキャンした面が上のポリゴンとくっついてる
          • 面を上のポリゴンとくっつける
          • 次の上のポリゴンにする
          • 上のポリゴンと,面を進める
        • 面が上のポリゴンより進んでる
          • 上のポリゴンは閉じる
          • 上のポリゴンを進める
        • 上のポリゴンが面より進んでる
          • 面をポリゴンにして,次の上のポリゴンにする
          • 面を進める
      • 上のポリゴンの残りを閉じる
      • 面をポリゴンにして,次の上のポリゴンにする
      • 上のポリゴンは次の上のポリゴン
  • 上のポリゴンを閉じる

シンプルで実際に書いてみるとミスする場所もなくすっきり仕上がる感じ.

三角形ポリゴンに分割する

教科書通り.めっちゃでかい字で書いてあってめっちゃわかりやすい.

  • リスト = 最初の2頂点
  • モノトーンポリゴンの左右がある間
    • P = 左右の垂直方向が小さい方
    • 同一周り
      • リストが1より大きい間
        • 三角形作成 リスト,リスト+1,P
        • リストの先頭を削除
    • 逆回り
      • リストが1より大きい間
        • リストの最後,リストの最後の前,P が 凹
          • 終了
        • リストの最後,リストの最後の前,P が 凸
          • リストの最後,リストの最後の前,P が まっすぐじゃない
            • 三角形作成 リストの最後,リストの最後の前,P
          • リストの最後を削除
    • P をリストに追加

階段状になっている箇所があるので,そこをスキップするところを追加って感じになる.

雑感


  1. 頂点の数をnとして

  2. ボクセルのスライスした面の数をnとして

定義/宣言へのジャンプ + 関連箇所へのジャンプ

VAX入ってない環境だと,F12でしょうか.Alt+F12はインラインで確認できたりして非常に便利ですが,重い.Ctrl+Alt+F12は宣言へのジャンプで自力で使い分けないといけない.Visual Studio 非常にお気に入りなのですが,重いのです.そのための速いマシンにSSDなのですが Visual Assist を入れるともっと速い.F12を押す代わりに,Alt+Gでさくっとソースをクルーズです.

Alt+G

VAssistX のメニュー,コンテキストメニュー,から Goto Implementation,関数の上で Alt+G を押すと,さくっと,実装へジャンプしてくれます.複数箇所で見つかった場合は,定義箇所,実装箇所と一覧で出てくれる上に,実装箇所なら {...} とついていて色々と一目瞭然な結果になっています.と,この機能に関しては詳しく説明するほどもなく便利な機能なので詳しくは GoTo Implementation を参照してください.

Shift+Alt+G

いや,シンプルなのは便利で良いのですよ.Visual Studio の標準だと,定義へ宣言へと頭を切り換えないと駄目なのが1つの機能で可能で脳への負荷が低い.でも,推していきたいのは関連箇所へのジャンプ Shift+Alt+G .VAssistX メニューにもある.いつからだ.いや,長年使っているのに最近まで気がついていなかった機能なのです.行ソートとかする機会もあるので,VAssistX メニューは開いていたつもりなのになあ.何がすごいか.関連メニューだけあって,インテリジェントにメニューに項目が追加される.カーソル位置のオブジェクトによって表示項目が変わるのですが,今までだと何ステップか踏まなければ行けなかった操作の1回でできてしまうようになったり.こっちのショートカットが標準になっても良いぐらいナノだが,Alt+G がまだあるのは,少しメニューが出てくるのが遅いとか,わかりきってる場合はすぐジャンプできるとかで棲み分けでって感じなのか.

メソッド

通常のメソッドであれば,定義へ,宣言へ,クラスのメンバへ.クラスのメンバへ機能は,VAXのおなじみインクリメンタルサーチ可能なダイアログが.便利なのは,オーバーライドされているメソッドの場合.基底 / 派生 しているシンボルへのメニューが追加されること.

変数

定義へがあるのに加え,シンボルの型へのメニューが追加される.これで,定義へジャンプ.型へジャンプの今まで2ステップかかっていたのがメニュー選択だけで行える.同じく型のメンバ一覧も勿論.

クラス

同じく定義へがあるのだが,クラスの場合は,基底クラス,派生クラスがメニューに表示されるようになる.それも基底,派生クラスのメニューは階層構造になっていて,ちゃんと途中で埋め込まれているインターフェイスも表示されている.これ,本当に便利で,宣言へ飛んで,基底クラスに飛んでを繰り返すのを一発で出来ちゃう.それに加えクラス階層が目で理解できるのもポイント.

推していきたい

そんな感じで,Shift+Alt+G 大いには推して行きたい.詳しくは GoTo Related で.Shift+Alt+[ O | F | G ] はほんと有能.

一番便利な機能

堕落しているので,一番のお気に入りは . を -> に置き換えてくれる機能だったり.

ソリューションのファイルを開く

リファクタリング機能がメインで語られそうなのだけれど,それと同じくらい Visual Assist X を使用している際に重要なのがナビゲーション機能.これ,あるのと無いのではソースコードを追っかける速さが倍ぐらい違う.いつの間にか C# にも対応しているので,他のリファクタリングプラグインと併用もお勧め.頻繁に使うので,ナビゲーション機能を使った際にちょことこと書いてみる.

Shift+Alt+O

Open File in Solution ダイアログがオープンし,インクリメンタルにソリューション中のファイルを絞り込みを行える.

Solution Explorer で,ファイル選択なんてかったるくてやってられない.Search Solution Explorer (Ctrl+;) なんてデータベース持ってないからプログレスバー出てるだけでもう待ってられないって感じ.UE4のエンジンソースは完全にクラスとファイルが対になってるわけではないけれど,クラスヘッダを探すときにもざっくり,まず Shift+Alt+O で.部分文字列で検索なので,うろ覚えのファイル名でも問題なし.機能としてわかっている場合は,先頭に「.」で.目的のファイルオープン.リストの時点で,お,こんな機能もあるのかなどの発見も.どんなコンポーネントあるのかな,とふと思ったときも「component.」で.だいたい Unreal Engine でどのモジュールのどの場所に目的のファイルがあって,それを Solution Explorer で検索するのなんて,探すだけで一苦労なんだよ.などの問題もさくっと解決してくれます.

詳しい使い方は Open File in Solution を見れば良いのだけれど,ダイアログをオープンした際に,検索文字列を入力する箇所に出ている説明を読めばだいたいのしたいことは出来る.でも,ファイル名を右クリックは知らなかったので,一度読んでおくのも良いかも.あとは,エディタでのショートカットになっているため,何かファイルをオープンしていないとショートカットが効かないので,グローバルに変更しておいても良いかも.

なぜUE4カテゴリがついているのか

アンリアルエディタでも同様のショートカットで,ほぼ同様の機能が使えたりします.リファレンスも見るところとか少し違うのですが.そら,毎日使ってたら押しちゃうよね.同じ機能実装したくなるよねって感じです.

ReSharper C++

ちょっと前に知った,ReSharper C++ : Visual Studio Extension for C++ development.機能比較などはReSharper C++ vs. Visual Assist X comparisonに書いてある.確かに VAX は多機能って訳ではなくて,リファクタリング関連については,他の言語用のツールに比べると物足りない点も多いけれど,必要な機能がコンパクトにまとまってる感じ.昔のIDEもサポートしているのも強みかな.あとは初回は確かにデータベースの構築に時間がかかるけれど,その後は速い.使用感についてちょっと Reddit に書かれていたのがこちらVisual Assists vs. ReSharper C++ for UE4 : unrealengineUE4だと毎回20分ソリューションオープンするのにかかるのは辛いなとか.乗り換えるのかー,俺も検討するかー,とか.ずっと昔にリファクタリングツールをまとめたのはVisual Assist X Build 1849 - 開発一課@はてなで.あれ?個人向けのライセンスだと年間の更新って必要無かった?昔からそうだっけ.$99で買い切りか.買い直ししようかな.

まとめ

C++erなら迷わずVAX使おうぜ.いやReSharper C++もかなり気になるのだけれど.