318 lines
16 KiB
C#
318 lines
16 KiB
C#
using UnityEngine;
|
|
#if UNITY_EDITOR
|
|
using UnityEditor;
|
|
using UnityEngine.UI;
|
|
using UnityEngine.Rendering;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
#endif
|
|
|
|
public class MissingSearcher : MonoBehaviour {
|
|
#if UNITY_EDITOR
|
|
|
|
private Stopwatch stopwatch = new Stopwatch();
|
|
private GameObject[] allObjectArray;
|
|
private int allObjectIndex = 0;
|
|
private List<Camera> cameraList = new List<Camera>();
|
|
|
|
void Start(){
|
|
ResetAllObjectArray();
|
|
}
|
|
|
|
void Update(){
|
|
stopwatch.Start();
|
|
try{
|
|
while(stopwatch.ElapsedMilliseconds < 8){ // およそ 1/120
|
|
UpdateSearch();
|
|
}
|
|
}catch (System.Exception e){
|
|
UnityEngine.Debug.Log("MissingSearcher Update " + e);
|
|
ResetAllObjectArray();
|
|
}
|
|
stopwatch.Stop();
|
|
stopwatch.Reset();
|
|
}
|
|
|
|
private void ResetAllObjectArray(){
|
|
allObjectIndex = 0;
|
|
allObjectArray = UnityEngine.Resources.FindObjectsOfTypeAll<GameObject>();
|
|
cameraList.Clear();
|
|
foreach(var obj in allObjectArray){
|
|
if(obj.GetComponent<Camera>() is var camera && camera != null && camera.cameraType == CameraType.Game){
|
|
cameraList.Add(camera);
|
|
}
|
|
}
|
|
}
|
|
private void UpdateSearch(){
|
|
if(allObjectIndex >= allObjectArray.Length){
|
|
ResetAllObjectArray();
|
|
}
|
|
|
|
string path = AssetDatabase.GetAssetOrScenePath(allObjectArray[allObjectIndex]);
|
|
while(!path.Contains(".unity") && ++allObjectIndex < allObjectArray.Length){
|
|
path = AssetDatabase.GetAssetOrScenePath(allObjectArray[allObjectIndex]);
|
|
}
|
|
|
|
if(allObjectIndex >= allObjectArray.Length) return ;
|
|
bool result = CheckInScene(allObjectArray[allObjectIndex], path, cameraList);
|
|
if(result){
|
|
EditorApplication.isPlaying = false;
|
|
}
|
|
++allObjectIndex;
|
|
}
|
|
|
|
private static string[] extensions = { ".prefab", ".mat", ".controller", ".cs", ".shader", ".mask", ".asset" };
|
|
/// <summary>
|
|
/// Missingがあるアセットを検索してそのリストを表示する
|
|
/// </summary>
|
|
[MenuItem("Assets/MissingSearch")]
|
|
private static void ShowMissingList(){
|
|
// Missingがあるアセットを検索
|
|
Search();
|
|
}
|
|
/// <summary>
|
|
/// Missingがあるアセットを検索
|
|
/// </summary>
|
|
private static void Search(){
|
|
// 全てのアセットのファイルパスを取得
|
|
string[] allPaths = AssetDatabase.GetAllAssetPaths();
|
|
int length = allPaths.Length;
|
|
for(int i = 0; i < length; i++){
|
|
// プログレスバーを表示
|
|
EditorUtility.DisplayProgressBar("Search Missing", string.Format("{0}/{1}", i+1, length), (float)i / length);
|
|
// Missing状態のプロパティを検索
|
|
if(extensions.Contains(Path.GetExtension(allPaths[i]))){
|
|
SearchMissing(allPaths[i]);
|
|
}
|
|
}
|
|
// プログレスバーを消す
|
|
EditorUtility.ClearProgressBar();
|
|
}
|
|
private static void SearchMissing(string path){
|
|
// 指定パスのアセットを全て取得
|
|
IEnumerable<UnityEngine.Object> assets = AssetDatabase.LoadAllAssetsAtPath(path);
|
|
// 各アセットについて、Missingのプロパティがあるかチェック
|
|
foreach(UnityEngine.Object obj in assets){
|
|
if(obj == null) continue;
|
|
if(obj.name == "Deprecated EditorExtensionImpl") continue;
|
|
Check(obj, string.Format("{0} {1}", path, obj.name));
|
|
}
|
|
}
|
|
|
|
private static bool CheckInScene(GameObject obj, string path, List<Camera> cameraList){
|
|
bool result = false;
|
|
string inScenePath = obj.name;
|
|
Transform parent = obj.transform.parent;
|
|
while(parent != null){
|
|
inScenePath = string.Format("{0}/{1}", parent.name, inScenePath);
|
|
parent = parent.parent;
|
|
}
|
|
path = string.Format(@"{0}
|
|
{1}", path, inScenePath);
|
|
if(path.Contains("DebugOption")) return false;
|
|
var components = obj.GetComponents<Component>();
|
|
bool hasCanvasRenderer = false;
|
|
bool hasGraphic = false;
|
|
bool hasMask = false;
|
|
bool hasRectMask = false;
|
|
foreach(var component in components){
|
|
if(component == null){
|
|
result = true;
|
|
UnityEngine.Debug.LogError(string.Format("{0} に不明なコンポーネントがあるので修正して下さい。", path));
|
|
}
|
|
if(component is CanvasRenderer){
|
|
hasCanvasRenderer = true;
|
|
}
|
|
if(component is Graphic){
|
|
hasGraphic = true;
|
|
}
|
|
if(component is SpriteRenderer spriteRenderer){
|
|
if(spriteRenderer.sprite == null){
|
|
result = true;
|
|
UnityEngine.Debug.LogError(string.Format("{0} の SpriteRenderer の Sprite がNoneになっているので修正して下さい。", path));
|
|
}else if(spriteRenderer.drawMode == SpriteDrawMode.Tiled){
|
|
var sprite = spriteRenderer.sprite;
|
|
if((sprite.texture.height <= 10 && spriteRenderer.size.y >= 1.0f) || (sprite.texture.width <= 10 && spriteRenderer.size.x >= 1.0f)){
|
|
result = true;
|
|
UnityEngine.Debug.LogError(string.Format("{0} の SpriteRenderer の DrawMode がTiledなのに {1} を使用しているので修正して下さい。", path, spriteRenderer.sprite.texture.name));
|
|
}
|
|
if(path.Contains("backGround_bank_b_ground_b")){
|
|
result = true;
|
|
UnityEngine.Debug.LogError(spriteRenderer.size.x * sprite.pixelsPerUnit + " " + sprite.texture.width + " " + (sprite.texture.width - sprite.border.x - sprite.border.z));
|
|
}
|
|
var triCount = (spriteRenderer.size.x * sprite.pixelsPerUnit - sprite.texture.width) / (sprite.texture.width - sprite.border.x - sprite.border.z) *
|
|
(spriteRenderer.size.y * sprite.pixelsPerUnit - sprite.texture.height) / (sprite.texture.height - sprite.border.y - sprite.border.w) * 2;
|
|
if(triCount >= 2000){
|
|
result = true;
|
|
UnityEngine.Debug.LogError(string.Format("{0} の SpriteRenderer の DrawMode がTiledなのに狭いBorder設定のSprite {1} が設定されており、ポリゴン数が {2}以上 になっているので修正して下さい。", path, spriteRenderer.sprite.texture.name, (int)triCount));
|
|
}
|
|
}
|
|
if(obj.activeInHierarchy){
|
|
if(Mathf.Approximately(spriteRenderer.color.a, 0.0f)){
|
|
var hasPerspectiveTransparent = false;
|
|
foreach(var camera in cameraList){
|
|
if(camera.orthographic){
|
|
if(camera.cullingMask == -1 || (camera.cullingMask & 1 << obj.layer) > 0){
|
|
var cameraAreaSize = camera.orthographicSize * 2 * (camera.orthographicSize * 2 * (float)Screen.width / (float)Screen.height);
|
|
var spriteAreaSize = spriteRenderer.bounds.size.x * spriteRenderer.bounds.size.y;
|
|
if(spriteAreaSize >= cameraAreaSize * 0.2f){
|
|
result = true;
|
|
UnityEngine.Debug.LogError(string.Format("{0} の SpriteRenderer の Color.a が0なのに有効化されていて、カメラの{1}割を占めているので修正して下さい。", path, (int)(spriteAreaSize / cameraAreaSize * 10.0f)));
|
|
}
|
|
}
|
|
}else{
|
|
hasPerspectiveTransparent = true;
|
|
}
|
|
}
|
|
if(hasPerspectiveTransparent){
|
|
result = true;
|
|
UnityEngine.Debug.LogError(string.Format("{0} の SpriteRenderer の Color.a が0なのに有効化されているので修正して下さい。", path));
|
|
}
|
|
}
|
|
}
|
|
foreach(var material in spriteRenderer.materials){
|
|
if(material.shader.name.Contains("Particle")
|
|
|| material.shader.name.Contains("UGUI")){
|
|
result = true;
|
|
UnityEngine.Debug.LogError(string.Format("{0} の SpriteRenderer のMaterialに3D用以外のShader {1} が設定されているので修正して下さい。", path, material.shader.name));
|
|
}
|
|
}
|
|
}
|
|
if(component is MeshRenderer meshRenderer){
|
|
foreach(var material in meshRenderer.materials){
|
|
if(material.shader.name.Contains("Particle")
|
|
|| material.shader.name.Contains("UGUI")){
|
|
result = true;
|
|
UnityEngine.Debug.LogError(string.Format("{0} の MeshRenderer のMaterialに3D用以外のShader {1} が設定されているので修正して下さい。", path, material.shader.name));
|
|
}
|
|
}
|
|
}
|
|
if(component is Renderer renderer){
|
|
foreach(var material in renderer.materials){
|
|
if(material.shader.name.Contains("UGUI")){
|
|
result = true;
|
|
UnityEngine.Debug.LogError(string.Format("{0} の Renderer のMaterialに3D用以外のShader {1} が設定されているので修正して下さい。", path, material.shader.name));
|
|
}
|
|
}
|
|
}
|
|
if(component is Text text){
|
|
if(!text.enabled){
|
|
result = true;
|
|
UnityEngine.Debug.LogError(string.Format("{0} に無効な Text があるので修正して下さい。", path));
|
|
}
|
|
if(text.font == null){
|
|
result = true;
|
|
UnityEngine.Debug.LogError(string.Format("{0} の Text の Font を設定下さい。", path));
|
|
}
|
|
}
|
|
if(component is Image image){
|
|
if(!image.enabled){
|
|
result = true;
|
|
UnityEngine.Debug.LogError(string.Format("{0} に無効な Image があるので修正して下さい。", path));
|
|
}
|
|
if(image.material != null && !image.material.shader.name.Contains("UI/Default") && !image.material.shader.name.Contains("UGUI") && !image.material.shader.name.Contains("Custom/Fade")){
|
|
result = true;
|
|
UnityEngine.Debug.LogError(string.Format("{0} の Image のMaterialにUI用以外のShader {1} が設定されているので修正して下さい。", path, image.material.shader.name));
|
|
}
|
|
if(image.type == Image.Type.Tiled){
|
|
var size = ((RectTransform)image.transform).sizeDelta;
|
|
if((image.sprite.texture.height <= 10 && size.y >= 100.0f) || (image.sprite.texture.width <= 10 && size.x >= 100.0f)){
|
|
result = true;
|
|
UnityEngine.Debug.LogError(string.Format("{0} の Image の ImageType がTiledなのに{1}を使用しているので修正して下さい。", path, image.sprite.texture.name));
|
|
}
|
|
}
|
|
}
|
|
if(component is SortingGroup sortingGroup){
|
|
if(!sortingGroup.enabled){
|
|
result = true;
|
|
UnityEngine.Debug.LogError(string.Format("{0} に無効な SortingGroup があるので修正して下さい。", path));
|
|
}
|
|
}
|
|
if(component is Mask mask){
|
|
hasMask = true;
|
|
if(!mask.enabled || mask.transform.childCount <= 0){
|
|
result = true;
|
|
UnityEngine.Debug.LogError(string.Format("{0} に無効な Mask があるので修正して下さい。", path));
|
|
}
|
|
}
|
|
if(component is RectMask2D rectMask){
|
|
hasRectMask = true;
|
|
if(!rectMask.enabled || rectMask.transform.childCount <= 0){
|
|
result = true;
|
|
UnityEngine.Debug.LogError(string.Format("{0} に無効な RectMask2D があるので修正して下さい。", path));
|
|
}
|
|
}
|
|
if(component is Animator animator){
|
|
if(animator.runtimeAnimatorController == null){
|
|
result = true;
|
|
UnityEngine.Debug.LogError(string.Format("{0} の Animator の Controller がNoneになっているので修正して下さい。", path));
|
|
}
|
|
}
|
|
if(component is Outline outline){
|
|
if(!outline.enabled){
|
|
result = true;
|
|
UnityEngine.Debug.LogError(string.Format("{0} に無効な Outline があるので修正して下さい。", path));
|
|
}
|
|
}
|
|
if(component is Joint2D joint2d){
|
|
if(!joint2d.enabled){
|
|
result = true;
|
|
UnityEngine.Debug.LogError(string.Format("{0} に無効な Joint2D があるので修正して下さい。", path));
|
|
}
|
|
}
|
|
if(component is PlaySE playSE){
|
|
if(!playSE.enabled){
|
|
result = true;
|
|
UnityEngine.Debug.LogError(string.Format("{0} に無効な PlaySE があるので修正して下さい。", path));
|
|
}
|
|
}
|
|
if(component is RectTransform rectTransform){
|
|
if(rectTransform.GetComponent<Canvas>() == null && !rectTransform.FindParentsComponent<Canvas>(canvas => {})){
|
|
result = true;
|
|
UnityEngine.Debug.LogError(string.Format("RectTransformをCanvasの外に配置しないで下さい。 {0}", path));
|
|
}
|
|
continue ;
|
|
}
|
|
if(component is Transform) continue ;
|
|
result = result || Check(component, path);
|
|
}
|
|
if(hasCanvasRenderer && !hasGraphic){
|
|
result = true;
|
|
UnityEngine.Debug.LogError(string.Format("{0} に無駄な CanvasRenderer があるので修正して下さい。", path));
|
|
}
|
|
if(hasMask && hasRectMask){
|
|
result = true;
|
|
UnityEngine.Debug.LogError(string.Format("{0} に2種の Mask があるので修正して下さい。", path));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static bool Check(UnityEngine.Object obj, string path){
|
|
bool result = false;
|
|
// SerializedObjectを通してアセットのプロパティを取得する
|
|
SerializedObject sobj = new SerializedObject(obj);
|
|
SerializedProperty property = sobj.GetIterator();
|
|
while(property.Next(true)){
|
|
// プロパティの種類がオブジェクト(アセット)への参照で、
|
|
// その参照がnullなのにもかかわらず、参照先インスタンスIDが0でないものはMissing状態
|
|
if(property.propertyType == SerializedPropertyType.ObjectReference &&
|
|
property.objectReferenceValue == null &&
|
|
property.objectReferenceInstanceIDValue != 0 &&
|
|
property.name != "m_PrefabParentObject" &&
|
|
property.name != "m_PrefabInternal" &&
|
|
property.name != "m_CorrespondingSourceObject"){
|
|
|
|
result = true;
|
|
if(obj.GetType().Name.Contains("ParticleSystemRenderer") && property.name.Contains("m_Mesh")){
|
|
UnityEngine.Debug.LogError(string.Format("{0} の {1} の RenderMode を Mesh に変更してMissingを修正して下さい。", path, obj.GetType().Name));
|
|
}else{
|
|
UnityEngine.Debug.LogError(string.Format("{0} の {1} にMissingがあるので修正して下さい。 {2}", path, obj.GetType().Name, property.name));
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
#endif
|
|
} |