エフアンダーバー

個人開発の記録

【Unity】 誰得なEditorPrefs操作スクリプト

前回の記事でEditorPrefsの値をレジストリエディタでいじるのが面倒だったので書いた、誰得なPowerShellスクリプトを公開。 正直このスクリプト書くのが一番面倒だった。

ちなみに取得・削除はできますが、作成・変更はできません(必要だという稀有な方は自分で改造してください)。

www.f-sp.com

EditorPrefs の仕様 (Windows)

スクリプトリファレンスに記述されているように、 EditorPrefsに保存した値はWindowsではレジストリに記録されます。 正確にはHKCU\Software\Unity Technologies\UnityEditor #.x(#はUnityのメジャーバージョン)のエントリとして記録されます。

この際、エントリ名にはEditorPrefsで指定した文字列(キー)にハッシュを連結したものが使われます。 フォーマットは{key}_h{hash}です(ハッシュはパディングなしの十進数)。 ハッシュで何か特殊な検査でもしているのかと思ったのですが、 少し調べてみたところキー自体のハッシュのようです(何に使用しているのか不明)。

ハッシュの計算方法は多分こんな感じ。

static uint GetHash(string key)
{
    uint hash = 5381;
    foreach(char c in key)
    {
        hash = (hash * 33) ^ c;
    }

    return hash;
}

EditorPrefsはBool/Int/Float/Stringの四種類の値が扱えますが、 Bool/IntではREG_DWORDで32bit値、 FloatではREG_DWORDで64bit値(!?)、 StringではREG_BINARYでヌル文字を含む任意長の値(詳しく調べてないけどUTF-8かな?)を保存しています。 Floatはもともと32bit値のはずなので、doubleに変換したうえでBitConverter.DoubleToInt64Bitsをかけているようです。

地味にこの仕様がやっかいで、 Floatに対して普通にGet-ItemPropertyGet-ItemPropertyValueを呼び出すと、 不正なDWORD値ということで内部でInvalidCastExceptionが発生して死にます。 Stringも普通に変換するとヌル文字を含むstring型に変換されて、そのまま別のコマンドに渡すとやっぱり死にます。

使い方

普通にスクリプトを読み込むといくつかのコマンドレットが読み込まれます。

.\UnityEditorPrefs.ps1

値の取得

Get-UnityEditorPrefコマンドレットにEditorPrefsのキーの値を指定する(複数可)とPSCustomObjectが返ってきます。

Get-UnityEditorPref MyKey

このPSCustomObjectには次の三つのプロパティが設定されています。

プロパティ 説明
Key EditorPrefsのキー
Value EditorPrefsに保存された値
Name 対応するレジストリエントリ名

キーの指定にはワイルドカードが使用できます。

Get-UnityEditorPref MyKey_*

-Jsonスイッチを使用すると、EditorPrefsに保存された値がJSONとして解釈できる場合にConvertFrom-Jsonされた状態で返ってきます。 JSONの値を確認したい場合にはConvertTo-Jsonで再度フォーマットしてやると見やすくなります。

Get-UnityEditorPref -Key My*Settings -Json | % { ConvertTo-Json $_.Value }

値の削除

Remove-UnityEditorPrefコマンドレットにEditorPrefsのキーの値を指定する(複数可)と指定したキーが削除できます。

Remove-UnityEditorPref MyKey

キーの指定にはワイルドカードが使用できます。

Remove-UnityEditorPref MyKey_*

Get-UnityEditorPrefとパイプで繋いでも削除できます。

Get-UnityEditorPref MyKey_* | Remove-UnityEditorPref

その他の操作

Get-UnityEditorPrefPathコマンドレットでEditorPrefsが書き込むレジストリキーのパスが取得できます。

Get-UnityEditorPrefPath -Version 5

ConvertTo-UnityEditorPrefEntryNameコマンドレットでEditorPrefsのキーをレジストリエントリ名に変換できます。

ConvertTo-UnityEditorPrefEntryName MyKey

Get-UnityEditorPrefEntryコマンドレットで存在するEditorPrefsのエントリを列挙できます(ワイルドカードによるフィルタリングも可)。

Get-UnityEditorPrefEntry MyKey_*

これらのコマンドはPowerShellでのプライベートな関数の書き方がよくわからなかったので、体裁を整えて公開してあるだけです。 多分、拡張しようとでも思わない限りは使い道はないはず。

メジャーバージョンの指定

各コマンドレットの-VersionオプションにUnityのメジャーバージョンを指定すると、そのバージョンの値を操作できます。

メジャーバージョンの初期値は5です。 これを変更するにはスクリプト最上部の定数の値をテキストエディタで直接書き換えてください。

ソースコード

Gist: UnityEditorPrefs.ps1

おわりに

PowerShellの練習がてら書いたのですが、結構難しいですね。 スクリプト言語である以上、ある程度柔軟に変換するのは必要だと思うのですが、 勝手に変換しすぎてくれるおかげで型がよくわからなくなることがしばしば。 一方で、スコープとか固定長整数とか細かいところで融通が利かなかったり。 あとVSCodeが何故かタブ保持の設定を無視してくれたり(PowerShellのせいじゃないけど)。

ところで、PowerShellオープンソース化するそうですね。 LinuxやMacでも使えるようになるんだとか。 .NET Coreとかbashの輸入とか最近Microsoftの動きが激しくて混乱中。



執筆時のUnityのバージョン:5.4.0f3