【Unity】シーン、Prefab内に含む任意の文字列を検索するSearchStringInAssetsを作りました

株式会社サムザップでUnityエンジニアをしている大庭[@ohbashunsuke](https://twitter.com/ohbashunsuke)です。[サムザップ #2 AdventCalendar 2020](https://qiita.com/advent-calendar/2020/sumzap2) の12/12(土)の記事です。

昨日は[＠mikami_akihisa](https://qiita.com/mikami_akihisa)さんの[「SlackのメッセージをGASでGoogleスプレッドシートに集積する」](https://qiita.com/mikami_akihisa/items/ac87ec83458c76b84658)でした。


## 概要

Unity開発をほんの**すこーし便利**にするかも知れないツールを作ったので紹介していきたいと思います。


## この文字列は、どこかで使ってるんだっけ？

ゲーム開発に限りませんが、クライアントエンジニアは**ユーザーが実際に目にする文字**をよく扱います。

- ダイアログの「はい」「いいえ」
- 画面のタイトル
- UI上に表示する何かしらの文字列
- キャラクタの説明文
- スキル名

種類は様々あります。

開発してて困るのは、Prefabやシーン、ScriptableObjectに埋め込んでしまった文字列の使用箇所の特定です。

文字列を置き換えないといけない場面で**影響範囲を調べる**必要が出てきます。


```cs
// キーを渡して実際に使用するテキストを取得
_label.text = Localization.Get("dialog.title.adventcalendar");
```

ソースコードに文字列を直打ちした場合は、**Rider (以下の画像) などのIDE**から全文検索すれば使用箇所を特定出来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/a38cd8d1-6451-0716-8ab1-36e413da2b79.png)


ただしPrefabやシーンに文字列を保存した場合、IDEからの検索はできず使用箇所の特定が出来なくなります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/c9c892c9-1367-e33c-66c1-63c53c3733b1.png)
例えば上図のように`Textコンポーネント`の`textプロパティ`に文字列を代入して、そのシーンファイル、Prefabの中身をテキストエディタで確認してみましょう。

### シーンファイル内の文字列

```yaml
~~~~~~~省略~~~~~~~
    m_HorizontalOverflow: 0
    m_VerticalOverflow: 0
    m_LineSpacing: 1
  m_Text: dialog.title.adventcalendar
--- !u!222 &743252498
CanvasRenderer:
  m_ObjectHideFlags: 0
  m_CorrespondingSourceObject: {fileID: 0}
~~~~~~~省略~~~~~~~
```

### Prefab内の文字列

```yaml
~~~~~~~省略~~~~~~~
    m_RichText: 1
    m_HorizontalOverflow: 0
    m_VerticalOverflow: 0
    m_LineSpacing: 1
  m_Text: dialog.title.adventcalendar
```

このようにシーンファイル、Prefab共に`m_Text: dialog.title.adventcalendar`という記述で保存されていることが分かります。



### grepして検索

使用箇所の確認として `grep`して検索する方法も一応紹介。

```sh
$ grep "dialog.title.adventcalendar" -r .
```
**※以前執筆した記事関連した内容がありますので、こちらもどうぞ**
[Unityでファイルを削除するときに必ずチェックしたい2つのポイント](https://www.shibuya24.info/entry/2015/08/06/115000)


以下のように出力されます。

```
./Text_advent.prefab:  m_Text: dialog.title.adventcalendar
./Sample/SampleScene.unity:  m_Text: dialog.title.adventcalendar
```

- Text_advent.prefab
- Sample/SampleScene.unity

この2箇所で使っているということが分かります。


このように`grep`して探し出すことは可能なのですが、、、**まあ面倒くさい**です。またエンジニアならまだしも非エンジニアにシェルを扱ってもらうというのは **ハードル高め**。


という事で**SearchStringInAssets**というツールをEditor拡張で作ってみました。


## 条件

- 検索キーワードは半角英数文字列のみ(全角文字は対象外)
- 検索パターンを指定できる
- 検索結果のファイル指定が可能  

という条件で作っています。


## 使用イメージ

以下のgif動画をご覧いただければ分かると思いますが、Search keywordsに検索したキーワードをセットしてSearchボタンをクリックすると、ヒットしたオブジェクトが並びます。 

![""](https://user-images.githubusercontent.com/144386/101299365-4da63780-3875-11eb-9b56-b2fe56d95663.gif)


## 検索設定

`Search Setting`に設定ファイル(ScriptableObject)をセットできます。

```cs
public class SearchStringInAssetsSetting : ScriptableObject
{
    /// <summary>
    /// Search Exclusion Class Array
    /// </summary>
    public string[] ignoreTypes;

    /// <summary>
    /// Search Pattern Array
    /// </summary>
    public string[] searchPatterns;
}
```
このような配列を2つ用意しています。

`ignoreTypes`は無視するタイプ、`searchPatterns`は検索キーワードのパターンです。

### 検索結果のファイル形式の指定

検索対象から無視するファイル形式出来るようにしています。

- フォルダ
- テクスチャ [^1]
- TextAsset
- C#スクリプト

これらは検索結果の対象からデフォルト設定ファイルで無視されています。

[^1]: テクスチャが含まれているのはmetaファイルも検索対象のため


### 検索キーワードのパターン

```
m_Text: {0}
value: {0}
```
デフォルト設定ファイルには上記の2パターンが設定しており、Textコンポーネントの`textプロパティの値`、string型の`SerializeFieldの値`にヒットするようになっています。



### 検索パターンを無視する設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328771/f9503440-fac6-6fea-d497-63fb89f3c431.png)

`Ignore Search Pattern`にチェックを入れていると、検索パターンを無視して純粋に検索キーワードで検索します。


## インストール方法

[GitHubリポジトリ](https://github.com/baobao/SearchStringInAssets)の[README](https://github.com/baobao/SearchStringInAssets#readme)参照してください。


## 課題あり

mdfindの`使い方`が悪いのか`仕様`なのか分からないのですが、**「.(ドット)」**が検索キーワードに含まれるとPrefabやシーンがヒットしなくなります。調べても分からないので、「.(ドット)」が検索対象に含まれた場合は**grepで代用**しています。

mdfindはSpotlightでインデックスが構築された状態からの検索処理なので**とても高速**です。しかしgrep検索は**非常に遅い**です。

肥大化しているUnityプロジェクトで使用すると検索結果を取り出すまでとても時間がかかるため注意が必要です。[^2]
[^2]: 肥大化しているプロジェクトでこそ使いたい。。。分かります。


基本的に**自分が欲しかったツールなので作った**というものでしたので満足はしているものの高速化出来る余地があるかどうかは、これからの話ということで。

明日は[@leosuke](https://qiita.com/leosuke)さんの[エンジニアらしく本を整理したい... 「Yahoo Web API を用いたバーコード読み取りによる本整理術」 - Qiita](https://qiita.com/leosuke/items/6b816c70b9fa330932de)です。

## 最後に

先日[サムザップアドベントカレンダー#1](https://qiita.com/advent-calendar/2020/sumzap1)で[【Unity】新規ゲームのUI開発で気をつけた39のTips前編 - Qiita](https://qiita.com/ohbashunsuke/items/0570234362e2e45c0011)という記事を執筆しているので、こちらもどうぞよろしくお願い致します。