浏览代码

Feature/check window (#21)

* Base Files

* Check Results display + First implementation

* Added Selection of Object in the list

* Added Result Sorting

* Added Filtering for Info/Warn/Error

* Added Check for external references

* Moved Search SceneObjects to Check Window so it's shared among all Checks

* Work on Ignored Results

* Added checking to UnityEvent fields / Resolve now ignores corrrectly

* Use ShowIgnored as Preference + Ensure correct scene change.

* Recheck after resolve / Null Material Check / Empty Game Object Check

* Added Icon

* Updated Changelog
/main
GitHub 4 年前
当前提交
9c54b406
共有 22 个文件被更改,包括 1044 次插入3 次删除
  1. 1
      CHANGELOG.md
  2. 14
      Editor/SceneViewToolbar.cs
  3. 8
      Editor/CheckWindow.meta
  4. 8
      Runtime/CheckWIndow.meta
  5. 91
      Editor/CheckWindow/Check.cs
  6. 11
      Editor/CheckWindow/Check.cs.meta
  7. 116
      Editor/CheckWindow/CheckResult.cs
  8. 11
      Editor/CheckWindow/CheckResult.cs.meta
  9. 511
      Editor/CheckWindow/CheckWindow.cs
  10. 11
      Editor/CheckWindow/CheckWindow.cs.meta
  11. 8
      Editor/CheckWindow/Implementations.meta
  12. 82
      Editor/CheckWindow/Implementations/EmptyGameObjectCheck.cs
  13. 11
      Editor/CheckWindow/Implementations/EmptyGameObjectCheck.cs.meta
  14. 55
      Editor/CheckWindow/Implementations/InvalidTransformCheck.cs
  15. 11
      Editor/CheckWindow/Implementations/InvalidTransformCheck.cs.meta
  16. 61
      Editor/CheckWindow/Implementations/NullMaterialCheck.cs
  17. 11
      Editor/CheckWindow/Implementations/NullMaterialCheck.cs.meta
  18. 15
      Runtime/CheckWIndow/IgnoredCheckResults.cs
  19. 11
      Runtime/CheckWIndow/IgnoredCheckResults.cs.meta

1
CHANGELOG.md


- Added Valid/Invalid paths for Platform Logic
- Added Local Space control for ReachPositionRig
- Added "Update SetStateAction" Button in State Machine components to populate the game object with Set State Actions
- Added **Check/Resolve** Window and API : The check window enables performing scriptable checks and resolution actions in your scene for maintenance purposes.
#### Fixed

14
Editor/SceneViewToolbar.cs


SceneViewPOV.ShowPopup(btnrect, sceneView);
}
GUILayout.FlexibleSpace();
// Check Window
GUILayout.Space(16);
if (GUILayout.Button(Contents.checkWindow, EditorStyles.toolbarButton))
{
EditorWindow.GetWindow<CheckWindow>();
}
GUILayout.FlexibleSpace();
// Saving Space not to overlap view controls
GUILayout.Space(96);

public static GUIContent lockLinkGameView;
public static GUIContent linkGameView;
public static GUIContent linkGameViewCinemachine;
public static GUIContent checkWindow;
static Contents()
{

linkGameViewCinemachine = new GUIContent(EditorGUIUtility.Load("Packages/net.peeweek.gameplay-ingredients/Icons/GUI/Camera16x16.png") as Texture);
linkGameViewCinemachine.text = " Cine";
checkWindow = new GUIContent(EditorGUIUtility.IconContent("Valid"));
checkWindow.text = "Check";
}
}

8
Editor/CheckWindow.meta


fileFormatVersion: 2
guid: 288b8d771acd0ca4c844250d148bd1e6
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
Runtime/CheckWIndow.meta


fileFormatVersion: 2
guid: d39bd230a7fe2ea46a39fd939b52e5d5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

91
Editor/CheckWindow/Check.cs


using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Linq;
namespace GameplayIngredients.Editor
{
public abstract class Check
{
public abstract string name { get; }
public abstract bool defaultEnabled { get; }
public abstract IEnumerable<CheckResult> GetResults(SceneObjects sceneObjects);
public abstract void Resolve(CheckResult result);
public abstract string[] ResolutionActions { get; }
public abstract int defaultResolutionActionIndex { get; }
#region STATIC
public static List<Check> allChecks {
get {
if (s_Checks == null)
Initialize();
return s_Checks.Values.ToList();
}
}
static Dictionary<Type, Check> s_Checks;
[InitializeOnLoadMethod]
static void Initialize()
{
s_Checks = new Dictionary<Type, Check>();
var types = GetAllTypes();
foreach(var type in types)
{
Check check = (Check)Activator.CreateInstance(type);
s_Checks.Add(type, check);
}
}
public static T Get<T>() where T : Check
{
if (s_Checks.ContainsKey(typeof(T)))
return (T)s_Checks[typeof(T)];
else
{
Debug.LogError($"Check of type '{typeof(T)}' could not be accessed.");
return null;
}
}
public static bool Has<T>() where T : Check
{
return (s_Checks.ContainsKey(typeof(T)));
}
static Type[] GetAllTypes()
{
List<Type> types = new List<Type>();
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
Type[] assemblyTypes = null;
try
{
assemblyTypes = assembly.GetTypes();
}
catch
{
Debug.LogError($"Could not load types from assembly : {assembly.FullName}");
}
if (assemblyTypes != null)
{
foreach (Type t in assemblyTypes)
{
if (typeof(Check).IsAssignableFrom(t) && !t.IsAbstract)
{
types.Add(t);
}
}
}
}
return types.ToArray();
}
#endregion
}
}

11
Editor/CheckWindow/Check.cs.meta


fileFormatVersion: 2
guid: f8d1edf29462baa488e148ff457a806e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

116
Editor/CheckWindow/CheckResult.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEngine.SceneManagement;
using System.Linq;
namespace GameplayIngredients.Editor
{
public class CheckResult
{
public enum Result
{
Notice,
Warning,
Failed
}
public Check check { get; private set; }
public Result result { get; private set; }
public Object mainObject { get { if (objects != null && objects.Length > 0) return objects[0]; else return null; } }
Object[] objects;
public GUIContent message;
public int resolutionActionIndex;
public string action { get { return check.ResolutionActions[resolutionActionIndex]; } }
public CheckResult(Check check, Result result, string message, params Object[] objects)
{
this.check = check;
this.result = result;
this.message = new GUIContent(message, GetIcon(result));
this.objects = objects;
}
public static Texture GetIcon(Result r)
{
switch (r)
{
default:
case Result.Notice:
return Contents.notice;
case Result.Warning:
return Contents.warning;
case Result.Failed:
return Contents.failed;
}
}
static class Contents
{
public static Texture notice;
public static Texture warning;
public static Texture failed;
static Contents()
{
notice = EditorGUIUtility.IconContent("console.infoicon.sml").image;
warning = EditorGUIUtility.IconContent("console.warnicon.sml").image;
failed = EditorGUIUtility.IconContent("console.erroricon.sml").image;
}
}
public void SetIgnored(bool ignored = true)
{
if (!(mainObject is GameObject))
return;
GameObject go = mainObject as GameObject;
Scene scene = go.scene;
var ignoredResults = Object.FindObjectsOfType<IgnoredCheckResults>();
IgnoredCheckResults targetResults = null;
foreach(var result in ignoredResults)
{
if(result.gameObject.scene == scene)
{
targetResults = result;
break;
}
}
if(targetResults == null)
{
var newGo = new GameObject("__IGNORED_CHECK_RESULTS__");
newGo.hideFlags = HideFlags.HideInHierarchy;
SceneManager.MoveGameObjectToScene(newGo,scene);
targetResults = newGo.AddComponent<IgnoredCheckResults>();
}
if (targetResults.ignoredCheckResults == null)
targetResults.ignoredCheckResults = new List<IgnoredCheckResults.IgnoredCheckResult>();
if(ignored)
{
if(!targetResults.ignoredCheckResults.Any(o => o.gameObject == go && o.check == check.GetType().ToString()))
{
IgnoredCheckResults.IgnoredCheckResult r = new IgnoredCheckResults.IgnoredCheckResult()
{
check = check.GetType().ToString(),
gameObject = go
};
targetResults.ignoredCheckResults.Add(r);
}
}
else
{
if (targetResults.ignoredCheckResults.Any(o => o.gameObject == go && o.check == check.GetType().ToString()))
{
targetResults.ignoredCheckResults.Remove(targetResults.ignoredCheckResults.FirstOrDefault(o => o.gameObject == go && o.check == check.GetType().ToString()));
}
}
}
}
}

11
Editor/CheckWindow/CheckResult.cs.meta


fileFormatVersion: 2
guid: eda144a76a8766c4eafbd6c68392adbc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

511
Editor/CheckWindow/CheckWindow.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Linq;
using System.Reflection;
using System;
using UnityEngine.SceneManagement;
using GameplayIngredients.Rigs;
using UnityEngine.Events;
using UnityEditor.SceneManagement;
namespace GameplayIngredients.Editor
{
public class CheckWindow : EditorWindow
{
[MenuItem("Window/Gameplay Ingredients/Check and Resolve")]
static void OpenWindow()
{
GetWindow<CheckWindow>(false);
}
private void OnEnable()
{
titleContent = new GUIContent(EditorGUIUtility.IconContent("Valid"));
titleContent.text = "Check/Resolve";
minSize = new Vector2(640, 180);
InitializeCheckStates();
}
void InitializeCheckStates()
{
s_CheckStates = new Dictionary<Check, bool>();
foreach (var check in Check.allChecks)
{
s_CheckStates.Add(check, EditorPrefs.GetBool(kPreferencePrefix + check.name, check.defaultEnabled));
}
}
void SetCheckState(Check check, bool value)
{
s_CheckStates[check] = value;
EditorPrefs.SetBool(kPreferencePrefix + check.name, value);
}
const string kPreferencePrefix = "GameplayIngredients.Check.";
const string kShowIgnoredPreference = "GameplayIngredients.ShowIgnored";
bool showIgnored
{
get {
return EditorPrefs.GetBool(kShowIgnoredPreference, true);
}
set {
EditorPrefs.SetBool(kShowIgnoredPreference, value);
}
}
Vector2 Scroll = new Vector2();
Dictionary<Check, bool> s_CheckStates;
enum SortMode
{
None,
CheckType,
ObjectName,
Message,
Resolution,
Ignored
}
SortMode sortMode = SortMode.None;
bool invertSort = false;
string filterString = "";
bool showNotice
{
get
{
return EditorPrefs.GetBool(kPreference + "showNotice", true);
}
set
{
if (value != showNotice)
EditorPrefs.SetBool(kPreference + "showNotice", value);
}
}
bool showWarning
{
get
{
return EditorPrefs.GetBool(kPreference + "showWarning", true);
}
set
{
if (value != showWarning)
EditorPrefs.SetBool(kPreference + "showWarning", value);
}
}
bool showError
{
get
{
return EditorPrefs.GetBool(kPreference + "showError", true);
}
set
{
if (value != showError)
EditorPrefs.SetBool(kPreference + "showError", value);
}
}
string kPreference = "GameplayIngredients.CheckResolve.";
private void SortButton(string label, SortMode sortMode, params GUILayoutOption[] options)
{
if (GUILayout.Button(label, this.sortMode == sortMode ? Styles.sortHeader : Styles.header, options))
{
if (this.sortMode == sortMode)
invertSort = !invertSort;
else
{
this.sortMode = sortMode;
invertSort = false;
}
if(m_Results != null)
{
switch (sortMode)
{
default:
case SortMode.None:
break;
case SortMode.CheckType:
m_Results = m_Results.OrderBy((a) => a.check.name).ToList();
break;
case SortMode.ObjectName:
m_Results = m_Results.OrderBy((a) => a.mainObject == null? "" : a.mainObject.name).ToList();
break;
case SortMode.Message:
m_Results = m_Results.OrderBy((a) => a.message.text).OrderBy((a) => a.result).ToList();
break;
case SortMode.Resolution:
m_Results = m_Results.OrderBy((a) => a.check.ResolutionActions[a.resolutionActionIndex]).ToList();
break;
case SortMode.Ignored:
m_Results = m_Results.OrderBy((a) => IsIgnored(a)).ToList();
break;
}
if(invertSort)
{
m_Results.Reverse();
}
Repaint();
}
}
}
private void OnGUI()
{
using(new GUILayout.HorizontalScope(EditorStyles.toolbar, GUILayout.Height(22)))
{
if (GUILayout.Button("Check", EditorStyles.toolbarButton))
PerformChecks();
if(GUILayout.Button("", EditorStyles.toolbarPopup))
{
Rect r = new Rect(0, 0, 16, 20);
GenericMenu menu = new GenericMenu();
foreach (Check check in s_CheckStates.Keys)
{
menu.AddItem(new GUIContent(check.name), s_CheckStates[check], () => SetCheckState(check, !s_CheckStates[check]));
}
menu.DropDown(r);
}
if (GUILayout.Button("Resolve", EditorStyles.toolbarButton))
Resolve();
GUILayout.FlexibleSpace();
filterString = EditorGUILayout.DelayedTextField(filterString, EditorStyles.toolbarSearchField, GUILayout.Width(180));
showIgnored = GUILayout.Toggle(showIgnored, "Ignored", EditorStyles.toolbarButton);
showNotice = GUILayout.Toggle(showNotice, new GUIContent(m_Results.Where(o => o.result == CheckResult.Result.Notice).Count().ToString(), CheckResult.GetIcon(CheckResult.Result.Notice)), EditorStyles.toolbarButton);
showWarning = GUILayout.Toggle(showWarning, new GUIContent(m_Results.Where(o => o.result == CheckResult.Result.Warning).Count().ToString(), CheckResult.GetIcon(CheckResult.Result.Warning)), EditorStyles.toolbarButton);
showError = GUILayout.Toggle(showError, new GUIContent(m_Results.Where(o => o.result == CheckResult.Result.Failed).Count().ToString(), CheckResult.GetIcon(CheckResult.Result.Failed)), EditorStyles.toolbarButton);
}
using(new GUILayout.VerticalScope())
{
GUI.backgroundColor = Color.white * 1.3f;
using (new GUILayout.HorizontalScope(EditorStyles.toolbar))
{
SortButton("Check Type", SortMode.CheckType, GUILayout.Width(128));
SortButton("Object", SortMode.ObjectName, GUILayout.Width(128));
SortButton("Message", SortMode.Message, GUILayout.ExpandWidth(true));
SortButton("Resolution", SortMode.Resolution, GUILayout.Width(128));
if(showIgnored)
SortButton("Ignored", SortMode.Ignored, GUILayout.Width(64));
GUILayout.Space(12);
}
Scroll = GUILayout.BeginScrollView(Scroll, false,true);
if (m_Results != null && m_Results.Count > 0)
{
bool odd = true;
foreach (var result in m_Results)
{
if (!showIgnored && IsIgnored(result) || result.mainObject == null)
continue;
if (result.result == CheckResult.Result.Notice && !showNotice)
continue;
if (result.result == CheckResult.Result.Warning && !showWarning)
continue;
if (result.result == CheckResult.Result.Failed && !showError)
continue;
if (!string.IsNullOrEmpty(filterString) && !result.message.text.Contains(filterString))
continue;
GUI.backgroundColor = Color.white * (odd ? 0.9f : 0.8f);
odd = !odd;
using (new GUILayout.HorizontalScope(EditorStyles.toolbar))
{
EditorGUI.BeginDisabledGroup(showIgnored && IsIgnored(result));
GUILayout.Label(result.check.name, Styles.line, GUILayout.Width(128));
if(GUILayout.Button(result.mainObject != null? result.mainObject.name : "Null", Styles.line, GUILayout.Width(128)))
{
Selection.activeObject = result.mainObject;
}
GUILayout.Label(result.message, Styles.line, GUILayout.ExpandWidth(true));
ShowMenu(result);
EditorGUI.EndDisabledGroup();
if(showIgnored)
{
GUILayout.Space(18);
EditorGUI.BeginChangeCheck();
var ignored = GUILayout.Toggle(IsIgnored(result),"", EditorStyles.toggle ,GUILayout.Width(24));
if (EditorGUI.EndChangeCheck())
{
SetIgnored(result, ignored);
}
GUILayout.Space(18);
}
}
}
}
else
{
GUILayout.Label("No Results");
}
GUI.backgroundColor = Color.white;
GUILayout.FlexibleSpace();
GUILayout.EndScrollView();
}
}
Dictionary<Scene,IgnoredCheckResults> m_IgnoredLists;
void BuildIgnoredList()
{
if (m_IgnoredLists == null)
m_IgnoredLists = new Dictionary<Scene, IgnoredCheckResults>();
else
m_IgnoredLists.Clear();
var all = FindObjectsOfType<IgnoredCheckResults>().ToList();
foreach(var one in all)
{
if (!m_IgnoredLists.ContainsKey(one.gameObject.scene))
m_IgnoredLists.Add(one.gameObject.scene, one);
else
Debug.LogWarning($"Found at least two IgnoredCheckResults objects in scene {one.gameObject.scene.name}");
}
}
bool IsIgnored(CheckResult result)
{
if (result.mainObject == null || !(result.mainObject is GameObject))
return false;
GameObject go = result.mainObject as GameObject;
if (!m_IgnoredLists.ContainsKey(go.scene))
return false;
var igl = m_IgnoredLists[go.scene];
return igl.ignoredCheckResults.Any(o => (o.check == result.check.GetType().ToString()) && (o.gameObject == go));
}
void SetIgnored(CheckResult result, bool ignored)
{
result.SetIgnored(ignored);
if(result.mainObject is GameObject)
{
var go = result.mainObject as GameObject;
EditorSceneManager.MarkSceneDirty(go.scene);
}
BuildIgnoredList();
}
void ShowMenu(CheckResult result)
{
if (s_IntValues == null)
s_IntValues = new Dictionary<Check, int[]>();
if(!s_IntValues.ContainsKey(result.check))
{
int count = result.check.ResolutionActions.Length;
int[] values = new int[count];
for(int i = 0; i < count; i++)
{
values[i] = i;
}
s_IntValues.Add(result.check, values);
}
result.resolutionActionIndex = EditorGUILayout.IntPopup(result.resolutionActionIndex, result.check.ResolutionActions, s_IntValues[result.check], EditorStyles.toolbarDropDown, GUILayout.Width(128));
}
static Dictionary<Check, int[]> s_IntValues;
List<CheckResult> m_Results = new List<CheckResult>();
void Resolve()
{
foreach(var result in m_Results)
{
if(!IsIgnored(result))
result.check.Resolve(result);
}
PerformChecks();
}
void PerformChecks()
{
List<CheckResult> results = new List<CheckResult>();
bool canceled = false;
try
{
var so = new SceneObjects();
int count = s_CheckStates.Count;
int i = 0;
foreach (var kvp in s_CheckStates)
{
float t = (float)i / count;
if (EditorUtility.DisplayCancelableProgressBar("Performing Checks", kvp.Key.name, t))
{
canceled = true;
break;
}
if (kvp.Value)
results.AddRange(kvp.Key.GetResults(so));
i++;
}
}
finally
{
EditorUtility.ClearProgressBar();
}
if(!canceled)
m_Results = results;
sortMode = SortMode.None;
BuildIgnoredList();
Repaint();
}
static class Styles
{
public static GUIStyle header;
public static GUIStyle sortHeader;
public static GUIStyle line;
static Styles()
{
header = new GUIStyle(EditorStyles.toolbarButton);
header.alignment = TextAnchor.MiddleLeft;
header.fontStyle = FontStyle.Bold;
sortHeader = new GUIStyle(EditorStyles.toolbarDropDown);
sortHeader.alignment = TextAnchor.MiddleLeft;
sortHeader.fontStyle = FontStyle.Bold;
line = new GUIStyle(EditorStyles.toolbarButton);
line.alignment = TextAnchor.MiddleLeft;
}
}
}
public class SceneObjects
{
public GameObject[] sceneObjects;
public List<GameObject> referencedGameObjects;
public List<Component> referencedComponents;
public List<UnityEngine.Object> referencedObjects;
public SceneObjects()
{
sceneObjects = GameObject.FindObjectsOfType<GameObject>();
referencedGameObjects = new List<GameObject>();
referencedComponents = new List<Component>();
referencedObjects = new List<UnityEngine.Object>();
if (sceneObjects == null || sceneObjects.Length == 0)
return;
try
{
int count = sceneObjects.Length;
int i = 0;
foreach (var sceneObject in sceneObjects)
{
float progress = ++i / (float)count;
if (EditorUtility.DisplayCancelableProgressBar("Building Reference Table...", $"{sceneObject.name}", progress))
{
referencedComponents.Clear();
referencedGameObjects.Clear();
referencedObjects.Clear();
break;
}
var components = sceneObject.GetComponents<Component>();
foreach (var component in components)
{
if (!(component is Transform))
{
Type t = component.GetType();
FieldInfo[] fields = t.GetFields(BindingFlags.Public
| BindingFlags.Instance
| BindingFlags.NonPublic);
foreach (var f in fields)
{
if (f.FieldType == typeof(GameObject))
{
var go = f.GetValue(component) as GameObject;
if (go != null && go != component.gameObject)
{
referencedGameObjects.Add(go);
}
}
else if (f.FieldType == typeof(Transform))
{
var tr = f.GetValue(component) as Transform;
if (tr != null && tr.gameObject != component.gameObject)
{
referencedGameObjects.Add(tr.gameObject);
}
}
else if (f.FieldType.IsSubclassOf(typeof(Component)))
{
var comp = f.GetValue(component) as Component;
if (comp != null && comp.gameObject != component.gameObject)
{
referencedComponents.Add(comp);
}
}
else if (f.FieldType == typeof(UnityEvent))
{
var ue = f.GetValue(component) as UnityEvent;
int evtCount = ue.GetPersistentEventCount();
for(int k = 0; k< evtCount; k++)
{
var target = ue.GetPersistentTarget(k);
if (target is GameObject)
referencedGameObjects.Add(target as GameObject);
else if(target.GetType().IsSubclassOf(typeof(Component)))
referencedGameObjects.Add((target as Component).gameObject);
}
}
else if (f.FieldType.IsSubclassOf(typeof(UnityEngine.Object)))
{
var obj = f.GetValue(component) as UnityEngine.Object;
referencedObjects.Add(obj);
}
}
}
}
}
}
finally
{
EditorUtility.ClearProgressBar();
}
}
}
}

11
Editor/CheckWindow/CheckWindow.cs.meta


fileFormatVersion: 2
guid: c176a67ddfd8cf741b242b56de664c83
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

8
Editor/CheckWindow/Implementations.meta


fileFormatVersion: 2
guid: 35f64cba36fa7f648aabe0906a871c71
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

82
Editor/CheckWindow/Implementations/EmptyGameObjectCheck.cs


using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using Object = UnityEngine.Object;
namespace GameplayIngredients.Editor
{
public class EmptyGameObjectCheck : Check
{
public override string name => "GameObject/Empty";
public override bool defaultEnabled => true;
public override string[] ResolutionActions => new string[] { "Set Static", "Delete Object" };
public override int defaultResolutionActionIndex => 0;
public override IEnumerable<CheckResult> GetResults(SceneObjects so)
{
try
{
int count = so.sceneObjects.Length;
int i = 0;
foreach (var go in so.sceneObjects)
{
float progress = ++i / count;
if (EditorUtility.DisplayCancelableProgressBar("Finding Empty Game Objects...", $"{go.name}", progress))
{
break;
}
var allComps = go.GetComponents<Component>();
if (allComps.Length == 1)
{
if (!go.isStatic)
{
if(!so.referencedGameObjects.Contains(go))
{
var result = new CheckResult(this, CheckResult.Result.Warning, $"Empty Game Object {go.name} is not static", go);
result.resolutionActionIndex = 0;
yield return result;
}
}
else
{
if (go.transform.childCount == 0)
{
if (!so.referencedGameObjects.Contains(go) && !so.referencedComponents.Contains(go.transform))
{
var result = new CheckResult(this, CheckResult.Result.Notice, "Empty Static Game Object has no children and could be deleted if unused.", go);
result.resolutionActionIndex = 1;
yield return result;
}
}
}
}
}
}
finally
{
EditorUtility.ClearProgressBar();
}
}
public override void Resolve(CheckResult result)
{
switch (result.resolutionActionIndex)
{
case 0:
default:
(result.mainObject as GameObject).isStatic = true;
break;
case 1:
Object.DestroyImmediate(result.mainObject as GameObject);
break;
}
}
}
}

11
Editor/CheckWindow/Implementations/EmptyGameObjectCheck.cs.meta


fileFormatVersion: 2
guid: 14cd4032eb6693645968d03dc1318cf4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

55
Editor/CheckWindow/Implementations/InvalidTransformCheck.cs


using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using Object = UnityEngine.Object;
using UnityEngine.Events;
namespace GameplayIngredients.Editor
{
public class InvalidTransformCheck : Check
{
public override string name => "GameObject/Invalid Transform";
public override bool defaultEnabled => true;
public override string[] ResolutionActions => new string[] { "Do Nothing", "Reset", "Delete Object" };
public override int defaultResolutionActionIndex => 0;
public override IEnumerable<CheckResult> GetResults(SceneObjects so)
{
try
{
int count = so.sceneObjects.Length;
int i = 0;
foreach (var go in so.sceneObjects)
{
float progress = ++i / count;
if (EditorUtility.DisplayCancelableProgressBar("Finding Transforms...", $"{go.name}", progress))
{
break;
}
Transform t = go.transform;
if(t.localScale.sqrMagnitude == 0)
{
yield return new CheckResult(this, CheckResult.Result.Warning, $"Transform of Game Object \"{go.name}\" has zero Scale.", go);
}
}
}
finally
{
EditorUtility.ClearProgressBar();
}
}
public override void Resolve(CheckResult result)
{
throw new System.NotImplementedException();
}
}
}

11
Editor/CheckWindow/Implementations/InvalidTransformCheck.cs.meta


fileFormatVersion: 2
guid: 90282888ae2e5d44db5119f5cd3a5de1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

61
Editor/CheckWindow/Implementations/NullMaterialCheck.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace GameplayIngredients.Editor
{
public class NullMaterialCheck : Check
{
public override string name => "Renderer/Null Material";
public override bool defaultEnabled => true;
public override string[] ResolutionActions => new string[] { "Assign Default Material" };
public override int defaultResolutionActionIndex => 0;
public override IEnumerable<CheckResult> GetResults(SceneObjects sceneObjects)
{
foreach(var obj in sceneObjects.sceneObjects)
{
if(obj.TryGetComponent(out Renderer r))
{
foreach(var mat in r.sharedMaterials)
{
if(mat == null)
{
yield return new CheckResult(this, CheckResult.Result.Failed, $"Missing Material for Object {obj.name}", obj);
break;
}
}
}
}
}
static Material s_DefaultMaterial;
public override void Resolve(CheckResult result)
{
if(s_DefaultMaterial == null)
{
var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
s_DefaultMaterial = cube.GetComponent<Renderer>().sharedMaterial;
Object.DestroyImmediate(cube);
}
switch (result.resolutionActionIndex)
{
default:
var renderer = (result.mainObject as GameObject).GetComponent<Renderer>();
for(int i = 0; i<renderer.sharedMaterials.Length; i++)
{
if(renderer.sharedMaterials[i] == null)
{
renderer.materials[i] = s_DefaultMaterial;
}
}
break;
}
}
}
}

11
Editor/CheckWindow/Implementations/NullMaterialCheck.cs.meta


fileFormatVersion: 2
guid: 512974ea9d269c8429756e4b07a4386e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

15
Runtime/CheckWIndow/IgnoredCheckResults.cs


using System.Collections.Generic;
using UnityEngine;
public class IgnoredCheckResults : MonoBehaviour
{
[System.Serializable]
public struct IgnoredCheckResult
{
public string check;
public GameObject gameObject;
}
public List<IgnoredCheckResult> ignoredCheckResults;
}

11
Runtime/CheckWIndow/IgnoredCheckResults.cs.meta


fileFormatVersion: 2
guid: d6d90fb7f3ef6bc4e84c5c6bc7a7e3f8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
正在加载...
取消
保存