using
System;
using
System.Collections.Generic;
using
UnityEditor;
using
UnityEditor.SceneManagement;
using
UnityEngine;
using
UnityEngine.SceneManagement;
using
Object
=
UnityEngine.Object;
namespace
Furyu
{
/// <summary>
/// Project内のSceneやPrefabを変更するための便利クラス
/// </summary>
public
class
AssetChangeBase
:
EditorWindow
{
/// <summary>
/// Project内の全てのAssetから指定のファイル形式のObjectを取得
/// </summary>
protected
static
T[]
FindAssets<T>(string
specified
=
"")
where
T
:
Object
{
List<T>
result
=
new
List<T>();
string[]
assetList
=
null;
if
(string.IsNullOrEmpty(specified))
{
assetList
=
AssetDatabase.FindAssets(string.Format("t:{0}",
typeof(T).Name));
}
else
{
assetList
=
AssetDatabase.FindAssets(string.Format("t:{0}",
specified));
}
for
(int
i
=
0;
i
<
assetList.Length;
i++)
{
string
assetPath
=
AssetDatabase.GUIDToAssetPath(assetList[i]);
T
asset
=
AssetDatabase.LoadAssetAtPath<T>(assetPath);
if
(asset
!=
null)
{
result.Add(asset);
}
}
return
result.ToArray();
}
/// <summary>
/// 新しいシーンで全プレハブを生成するだけ
/// </summary>
/// <param name="targetType">Prefab内に指定したComponentがあるものだけを生成する</param>
protected
static
List<Object>
InstantiateAllPrefabs(Type
targetType
=
null)
{
//新しいシーンを作り、そこで全てのプレハブを生成する
EditorSceneManager.NewScene(NewSceneSetup.EmptyScene,
NewSceneMode.Single);
List<Object>
instantiatedPrefabs
=
new
List<Object>();
var
prefabsDic
=
FindAssets<GameObject>("Prefab");
foreach
(var
item
in
prefabsDic)
{
if
(targetType
==
null)
{
instantiatedPrefabs.Add(PrefabUtility.InstantiatePrefab(item));
}
else
{
if
(item.GetComponentsInChildren(targetType,
true)
!=
null
&&
item.GetComponentsInChildren(targetType,
true).Length
>
0)
{
instantiatedPrefabs.Add(PrefabUtility.InstantiatePrefab(item));
}
}
}
return
instantiatedPrefabs;
}
/// <summary>
/// 全てのPrefabを生成してコンポーネントを操作
/// </summary>
/// <param name="callback">生成した全てのGameObjectに対して実行するcallback</param>
/// <param name="isApply">callbackを呼んだ後Applyするかどうか</param>
/// <param name="targetType">Prefab内に指定したComponentがあるものだけをApply対象にする</param>
protected
static
void
ChangeComponentAllPrefabs(Action<GameObject>
callback,
bool
isApply
=
true,
Type
targetType
=
null)
{
//後で戻ってくるので現在のシーンのパスを保存
string
curScenePath
=
SceneManager.GetActiveScene().path;
List<Object>
instantiatedPrefabs
=
InstantiateAllPrefabs(targetType);
ChangeActionForeach(callback);
//PrefabのApply
if
(isApply)
{
int
i
=
0;
foreach
(var
item
in
instantiatedPrefabs)
{
EditorUtility.DisplayProgressBar("Replacing
in
prefab...",
item.name,
(float)i
/
instantiatedPrefabs.Count);
//Unity標準のプレハブでなければApply
if
(!PrefabUtility.IsPartOfImmutablePrefab((GameObject)item))
{
try
{
PrefabUtility.ApplyPrefabInstance((GameObject)item,
InteractionMode.UserAction);
}
catch
(System.Exception
e)
{
Debug.LogError(e);
Debug.LogError("Prefabの更新ができませんでした。対象のPrefabの中身を確かめてください。");
EditorUtility.ClearProgressBar();
EditorSceneManager.OpenScene(curScenePath);
return;
}
}
i++;
}
EditorUtility.ClearProgressBar();
}
if
(!String.IsNullOrEmpty(curScenePath))
{
EditorSceneManager.OpenScene(curScenePath);
}
}
/// <summary>
/// 現在のシーンの全てのコンポーネントを操作
/// </summary>
/// <param name="callback">シーン上の全てのGameObjectに対して実行するcallback</param>
/// <param name="isSave">callbackを呼んだあとシーンをSaveするかどうか</param>
protected
static
void
ChangeComponentCurrentScene(Action<GameObject>
callback,
bool
isSave
=
true)
{
ChangeActionForeach(callback);
if
(isSave)
{
EditorSceneManager.SaveScene(SceneManager.GetActiveScene());
}
}
/// <summary>
/// 全てのシーンの全てのコンポーネントを操作
/// </summary>
/// <param name="callback">シーン上の全てのGameObjectに対して実行するcallback</param>
/// <param name="isSave">callbackを呼んだあとシーンをSaveするかどうか</param>
protected
static
void
ChangeComponentAllScenes(Action<GameObject>
callback,
bool
isSave
=
true)
{
//後で戻ってくるので現在のシーンのパスを保存
string
curScenePath
=
SceneManager.GetActiveScene().path;
//全てのシーンを順々に読み込んでコンポーネントを操作
SceneAsset[]
scenes
=
FindAssets<SceneAsset>();
for
(int
i
=
0;
i
<
scenes.Length;
i++)
{
SceneAsset
scene
=
scenes[i];
Debug.Log("Sceneの読み込み
=
"
+
scene.name);
EditorUtility.DisplayProgressBar("Replacing
in
scene...",
scene.name,
(float)i
/
scenes.Length);
Scene
loadedScene
=
EditorSceneManager.OpenScene(AssetDatabase.GetAssetPath(scene),
OpenSceneMode.Single);
while
(!loadedScene.isLoaded)
{}
ChangeActionForeach(callback);
if
(isSave)
{
EditorSceneManager.SaveScene(loadedScene);
}
}
EditorUtility.ClearProgressBar();
EditorSceneManager.OpenScene(curScenePath);
}
/// <summary>
/// 再起的に子要素に潜る
/// </summary>
private
static
void
DeepSerch(GameObject
root,
System.Action<GameObject>
callback)
{
callback(root);
if
(root.transform.childCount
!=
0)
{
for
(int
j
=
0;
j
<
root.transform.childCount;
j++)
{
GameObject
targetObj
=
root.transform.GetChild(j).gameObject;
DeepSerch(targetObj,
callback);
}
}
}
/// <summary>
/// ルートオブジェクトを回してCallbackを呼ぶ
/// </summary>
private
static
void
ChangeActionForeach(Action<GameObject>
callback)
{
GameObject[]
rootGameObjects
=
SceneManager.GetActiveScene().GetRootGameObjects();
for
(int
i
=
0;
i
<
rootGameObjects.Length;
i++)
{
GameObject
root
=
rootGameObjects[i];
DeepSerch(root,
(targetObj)
=>
{
callback(targetObj);
});
}
}
/// <summary>
/// RootのプレハブをApply
/// </summary>
protected
static
void
AllPrefabsApply()
{
GameObject[]
rootGameObjects
=
SceneManager.GetActiveScene().GetRootGameObjects();
for
(int
i
=
0;
i
<
rootGameObjects.Length;
i++)
{
var
item
=
rootGameObjects[i];
//Unity標準のプレハブでなければApply
if
(!PrefabUtility.IsPartOfImmutablePrefab(item))
{
try
{
PrefabUtility.ApplyPrefabInstance(item,
InteractionMode.UserAction);
}
catch
(System.Exception
e)
{
Debug.LogError(e);
Debug.LogError("Prefabの更新ができませんでした。対象のPrefabの中身を確かめてください。");
EditorUtility.ClearProgressBar();
return;
}
}
}
}
}
}