forked from Shardstone/trail-into-darkness
Added a bunch of utilities and modfief the character data structue
This commit is contained in:
@@ -0,0 +1,299 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Debug = UnityEngine.Debug;
|
||||
using Object = UnityEngine.Object;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace Jovian.Utilities {
|
||||
public static class AssetUtility {
|
||||
|
||||
public static TAsset FindAssetInProject<TAsset>(string assetName = "") where TAsset : Object {
|
||||
#if UNITY_EDITOR
|
||||
var filter = $"t:{typeof(TAsset).Name} {assetName}";
|
||||
var guids = AssetDatabase.FindAssets(filter);
|
||||
foreach (var guid in guids)
|
||||
{
|
||||
var path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
var asset = AssetDatabase.LoadAssetAtPath<TAsset>(path);
|
||||
if (asset != null)
|
||||
{
|
||||
return asset;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ShouldUnloadAsset(asset))
|
||||
{
|
||||
Resources.UnloadAsset(asset);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
Debug.LogError("AssetUtility should not be called in non-Editor mode");
|
||||
#endif
|
||||
return default(TAsset);
|
||||
}
|
||||
|
||||
public static Object FindAssetInProject(Type assetType, string assetName = "") {
|
||||
#if UNITY_EDITOR
|
||||
var filter = $"t:{assetType.Name} {assetName}";
|
||||
var guids = AssetDatabase.FindAssets(filter);
|
||||
foreach (var guid in guids)
|
||||
{
|
||||
var path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
var asset = AssetDatabase.LoadAssetAtPath<Object>(path);
|
||||
if (asset != null)
|
||||
{
|
||||
return asset;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ShouldUnloadAsset(asset))
|
||||
{
|
||||
Resources.UnloadAsset(asset);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
Debug.LogError("AssetUtility should not be called in non-Editor mode");
|
||||
#endif
|
||||
return default(Object);
|
||||
}
|
||||
|
||||
public static List<TAsset> FindAllAssetsInProject<TAsset>(string assetName = "") where TAsset : Object {
|
||||
var list = new List<TAsset>();
|
||||
#if UNITY_EDITOR
|
||||
var filter = $"t:{typeof(TAsset).Name} {assetName}";
|
||||
var guids = AssetDatabase.FindAssets(filter);
|
||||
foreach (var guid in guids)
|
||||
{
|
||||
var path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
var asset = AssetDatabase.LoadAssetAtPath<TAsset>(path);
|
||||
if (asset != null)
|
||||
{
|
||||
list.Add(asset);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ShouldUnloadAsset(asset))
|
||||
{
|
||||
Resources.UnloadAsset(asset);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
Debug.LogError("AssetUtility should not be called in non-Editor mode");
|
||||
#endif
|
||||
return list;
|
||||
}
|
||||
|
||||
public static List<Object> FindAllAssetsInProject(Type assetType, string assetName = "") {
|
||||
var list = new List<Object>();
|
||||
#if UNITY_EDITOR
|
||||
var filter = $"t:{assetType.Name} {assetName}";
|
||||
var guids = AssetDatabase.FindAssets(filter);
|
||||
foreach (var guid in guids)
|
||||
{
|
||||
var path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
var asset = AssetDatabase.LoadAssetAtPath<Object>(path);
|
||||
if (asset != null)
|
||||
{
|
||||
list.Add(asset);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ShouldUnloadAsset(asset))
|
||||
{
|
||||
Resources.UnloadAsset(asset);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
Debug.LogError("AssetUtility should not be called in non-Editor mode");
|
||||
#endif
|
||||
return list;
|
||||
}
|
||||
|
||||
public static List<Object> FindAllObjectsInProject(Type objectType, string filter) {
|
||||
List<Object> list = new List<Object>();
|
||||
#if UNITY_EDITOR
|
||||
string[] guids = AssetDatabase.FindAssets(filter);
|
||||
foreach (var guid in guids)
|
||||
{
|
||||
string path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
Object asset = AssetDatabase.LoadAssetAtPath<Object>(path);
|
||||
|
||||
if (typeof(Component).IsAssignableFrom(objectType) &&
|
||||
TryGetTypeObjectWithPrefab(asset, objectType, out Component _))
|
||||
{
|
||||
list.Add(asset);
|
||||
}
|
||||
else if (asset.GetType().IsAssignableFrom(objectType))
|
||||
{
|
||||
list.Add(asset);
|
||||
}
|
||||
else if (ShouldUnloadAsset(asset))
|
||||
{
|
||||
Resources.UnloadAsset(asset);
|
||||
}
|
||||
}
|
||||
#else
|
||||
Debug.LogError("AssetUtility should not be called in non-Editor mode");
|
||||
#endif
|
||||
return list;
|
||||
}
|
||||
|
||||
// Prefabs
|
||||
public static TAsset FindPrefabInProject<TAsset>(string assetName = "") where TAsset : Component {
|
||||
#if UNITY_EDITOR
|
||||
var filter = $"t:Prefab {assetName}";
|
||||
var guids = AssetDatabase.FindAssets(filter);
|
||||
foreach (var guid in guids)
|
||||
{
|
||||
var path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
var asset = AssetDatabase.LoadAssetAtPath<TAsset>(path);
|
||||
if (TryGetTypeObjectWithPrefab(asset, out TAsset component))
|
||||
{
|
||||
return component;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ShouldUnloadAsset(asset))
|
||||
{
|
||||
Resources.UnloadAsset(asset);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
Debug.LogError("AssetUtility should not be called in non-Editor mode");
|
||||
#endif
|
||||
Debug.LogError($"Failed to find asset '{assetName}' <{typeof(TAsset)}>");
|
||||
return default(TAsset);
|
||||
}
|
||||
|
||||
public static Object FindPrefabInProject(Type assetType, string assetName = "") {
|
||||
#if UNITY_EDITOR
|
||||
var filter = $"t:Prefab {assetName}";
|
||||
var guids = AssetDatabase.FindAssets(filter);
|
||||
foreach (var guid in guids)
|
||||
{
|
||||
var path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
var asset = AssetDatabase.LoadAssetAtPath<Object>(path);
|
||||
if (TryGetTypeObjectWithPrefab(asset, assetType, out Component component))
|
||||
{
|
||||
return component;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ShouldUnloadAsset(asset))
|
||||
{
|
||||
Resources.UnloadAsset(asset);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
Debug.LogError("AssetUtility should not be called in non-Editor mode");
|
||||
#endif
|
||||
return default(Object);
|
||||
}
|
||||
|
||||
public static List<TAsset> FindAllPrefabsInProject<TAsset>(string assetName = "") where TAsset : Component {
|
||||
var list = new List<TAsset>();
|
||||
#if UNITY_EDITOR
|
||||
var filter = $"t:Prefab {assetName}";
|
||||
var guids = AssetDatabase.FindAssets(filter);
|
||||
foreach (var guid in guids)
|
||||
{
|
||||
var path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
var asset = AssetDatabase.LoadAssetAtPath<TAsset>(path);
|
||||
if (TryGetTypeObjectWithPrefab(asset, out TAsset component))
|
||||
{
|
||||
list.Add(component);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ShouldUnloadAsset(asset))
|
||||
{
|
||||
Resources.UnloadAsset(asset);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
Debug.LogError("AssetUtility should not be called in non-Editor mode");
|
||||
#endif
|
||||
return list;
|
||||
}
|
||||
|
||||
public static List<Object> FindAllPrefabsInProject(Type assetType, string assetName = "") {
|
||||
var list = new List<Object>();
|
||||
#if UNITY_EDITOR
|
||||
var filter = $"t:Prefab {assetName}";
|
||||
var guids = AssetDatabase.FindAssets(filter);
|
||||
foreach (var guid in guids)
|
||||
{
|
||||
var path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
var asset = AssetDatabase.LoadAssetAtPath<Object>(path);
|
||||
if (TryGetTypeObjectWithPrefab(asset, assetType, out Component component))
|
||||
{
|
||||
list.Add(component);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ShouldUnloadAsset(asset))
|
||||
{
|
||||
Resources.UnloadAsset(asset);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
Debug.LogError("AssetUtility should not be called in non-Editor mode");
|
||||
#endif
|
||||
return list;
|
||||
}
|
||||
|
||||
// Util
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public static bool ShouldUnloadAsset(Object asset) {
|
||||
if (asset == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return !(asset is GameObject or Component or AssetBundle ||
|
||||
PrefabUtility.GetPrefabAssetType(asset) != PrefabAssetType.NotAPrefab);
|
||||
}
|
||||
|
||||
private static bool TryGetTypeObjectWithPrefab(Object prefab, Type type, out Component component) {
|
||||
if (prefab != null && prefab is GameObject gameObject && gameObject.TryGetComponent(type, out component))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
component = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool TryGetTypeObjectWithPrefab<TComponent>(Object prefab, out TComponent component)
|
||||
where TComponent : Component {
|
||||
if (prefab != null && prefab is TComponent prefabAsComponent)
|
||||
{
|
||||
component = prefabAsComponent;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (prefab != null && prefab is GameObject gameObject && gameObject.TryGetComponent(out component))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
component = default;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8f53e63ec5b4b3744bda48fb1159ac40
|
||||
@@ -0,0 +1,154 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using UnityEngine;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace Jovian.Utilities {
|
||||
/// <summary>
|
||||
/// <b>Editor use-only.</b><br/>
|
||||
/// Allows easy access between different instances. Supports 1 instance per type. <br/>
|
||||
/// Add instances and retrieve elsewhere.<br/><br/>
|
||||
/// Read more: https://en.wikipedia.org/wiki/Service_locator_pattern
|
||||
/// </summary>
|
||||
public static class EditorServiceLocator {
|
||||
private sealed class ServiceNotFoundException : Exception {
|
||||
public ServiceNotFoundException(Type type) : base($"ServiceNotFoundException. Type={type}") { }
|
||||
}
|
||||
|
||||
private static Dictionary<Type, object> serviceContainer = new();
|
||||
public static bool IsDirty { get; private set; }
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public static Dictionary<Type, object> ServiceContainer => serviceContainer;
|
||||
#endif
|
||||
|
||||
[RuntimeInitializeOnLoadMethod]
|
||||
public static void Init() {
|
||||
serviceContainer = new();
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[InitializeOnEnterPlayMode]
|
||||
private static void Reset(EnterPlayModeOptions options) {
|
||||
serviceContainer?.Clear();
|
||||
IsDirty = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Add an instance to the locator. Will throw an exception if a type already exists in the locator.
|
||||
/// <seealso cref="AddOrReplace{T}"/>
|
||||
/// </summary>
|
||||
[Conditional("UNITY_EDITOR")]
|
||||
public static void Add<T>(T service) {
|
||||
#if UNITY_EDITOR
|
||||
if (service == null) {
|
||||
throw new NullReferenceException($"Service is null. Expected instance of type '{typeof(T)}'");
|
||||
}
|
||||
|
||||
serviceContainer.Add(typeof(T), service);
|
||||
IsDirty = true;
|
||||
#else
|
||||
UnityEngine.Debug.LogWarning($"EditorServiceLocator should not be used outside of the Editor");
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add an instance to the locator. Will replace any existing instance without an exception.
|
||||
/// An alias for <see cref="Set{T}"/>
|
||||
/// </summary>
|
||||
[Conditional("UNITY_EDITOR")]
|
||||
public static void AddOrReplace<T>(T service) {
|
||||
Set(service);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add an instance to the locator. Will replace any existing instance without an exception.
|
||||
/// An alias for <see cref="AddOrReplace{T}"/>
|
||||
/// </summary>
|
||||
[Conditional("UNITY_EDITOR")]
|
||||
public static void Set<T>(T service) {
|
||||
#if UNITY_EDITOR
|
||||
if (service == null) {
|
||||
throw new NullReferenceException($"Service is null. Expected instance of type '{typeof(T)}'");
|
||||
}
|
||||
|
||||
serviceContainer[typeof(T)] = service;
|
||||
IsDirty = true;
|
||||
#else
|
||||
UnityEngine.Debug.LogWarning($"EditorServiceLocator should not be used outside of the Editor");
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes any type matching the instance passed in from the locator. This is good practice.
|
||||
/// </summary>
|
||||
/// <param name="service"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <exception cref="NullReferenceException"></exception>
|
||||
[Conditional("UNITY_EDITOR")]
|
||||
public static void Remove<T>(T service) {
|
||||
#if UNITY_EDITOR
|
||||
if (service == null) {
|
||||
throw new NullReferenceException($"Service is null. Expected instance of type '{typeof(T)}'");
|
||||
}
|
||||
|
||||
serviceContainer.Remove(typeof(T));
|
||||
IsDirty = true;
|
||||
#else
|
||||
UnityEngine.Debug.LogWarning($"EditorServiceLocator should not be used outside of the Editor");
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves an instance from the locator matching the type. Will throw an exception if nothing is found.
|
||||
/// <seealso cref="TryGet{T}(out T)"/>
|
||||
/// </summary>
|
||||
public static T Get<T>() {
|
||||
#if UNITY_EDITOR
|
||||
if (serviceContainer.TryGetValue(typeof(T), out object service)) {
|
||||
return (T)service;
|
||||
}
|
||||
#endif
|
||||
throw new ServiceNotFoundException(typeof(T));
|
||||
}
|
||||
|
||||
[Obsolete("Use Get<T> or TryGet<T>(out T) since they follow the C# conventions for TryGet")]
|
||||
public static T TryGet<T>() {
|
||||
#if UNITY_EDITOR
|
||||
if (serviceContainer.TryGetValue(typeof(T), out object service)) {
|
||||
return (T)service;
|
||||
}
|
||||
#endif
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves an instance from the locator matching the type. Returns true/false based on success.
|
||||
/// </summary>
|
||||
public static bool TryGet<T>(out T instance) {
|
||||
#if UNITY_EDITOR
|
||||
if (serviceContainer.TryGetValue(typeof(T), out object service)) {
|
||||
instance = (T)service;
|
||||
return instance != null;
|
||||
}
|
||||
#endif
|
||||
instance = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
[Conditional("UNITY_EDITOR")]
|
||||
public static void Clear() {
|
||||
serviceContainer.Clear();
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
[Conditional("UNITY_EDITOR")]
|
||||
public static void Clean() {
|
||||
IsDirty = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f8316472f7c700f4a9e908d3abde1d1d
|
||||
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace Jovian.Utilities.Utilities {
|
||||
public static class GizmosUtility {
|
||||
|
||||
public static bool IsGameObjectOrChildSelected(GameObject gameObject) {
|
||||
#if UNITY_EDITOR
|
||||
return GameObjectUtilities.IsGameObjectAChildOfGameObject(Selection.activeGameObject, gameObject);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void DrawColliders(IEnumerable<Collider> colliders) {
|
||||
foreach(Collider collider in colliders) {
|
||||
if(collider != null) {
|
||||
DrawCollider(collider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void DrawWireColliders(IEnumerable<Collider> colliders) {
|
||||
foreach(Collider collider in colliders) {
|
||||
if(collider != null) {
|
||||
DrawWireCollider(collider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void DrawCollider(Collider collider)
|
||||
=> DrawColliderInternal(collider, Gizmos.DrawSphere, Gizmos.DrawCube, Gizmos.DrawMesh);
|
||||
|
||||
public static void DrawWireCollider(Collider collider)
|
||||
=> DrawColliderInternal(collider, Gizmos.DrawWireSphere, Gizmos.DrawWireCube, Gizmos.DrawWireMesh);
|
||||
|
||||
private static void DrawColliderInternal(Collider collider, Action<Vector3, float> drawSphere, Action<Vector3, Vector3> drawCube,
|
||||
Action<Mesh> drawMesh) {
|
||||
Gizmos.matrix = collider.transform.localToWorldMatrix;
|
||||
switch(collider) {
|
||||
case BoxCollider boxCollider:
|
||||
drawCube(boxCollider.center, boxCollider.size);
|
||||
break;
|
||||
case SphereCollider sphereCollider:
|
||||
drawSphere(sphereCollider.center, sphereCollider.radius);
|
||||
break;
|
||||
case CapsuleCollider capsuleCollider: {
|
||||
Vector3 direction = GetAxis(capsuleCollider.direction);
|
||||
drawSphere(capsuleCollider.center + direction * capsuleCollider.height * 0.5f, capsuleCollider.radius);
|
||||
drawSphere(capsuleCollider.center - direction * capsuleCollider.height * 0.5f, capsuleCollider.radius);
|
||||
break;
|
||||
}
|
||||
case MeshCollider meshCollider:
|
||||
drawMesh(meshCollider.sharedMesh);
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException($"Cannot draw collider of type '{typeof(Collider)}'");
|
||||
}
|
||||
}
|
||||
|
||||
private static Vector3 GetAxis(int direction) {
|
||||
switch(direction) {
|
||||
case 0:
|
||||
return Vector3.right;
|
||||
case 1:
|
||||
return Vector3.up;
|
||||
case 2:
|
||||
return Vector3.forward;
|
||||
default:
|
||||
throw new NotSupportedException($"Direction '{direction}' does not map to an axis.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e2ce31502182718488f21bcf6137096f
|
||||
@@ -0,0 +1,32 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
#if UNITY_EDITOR
|
||||
using System;
|
||||
using UnityEditor.SceneManagement;
|
||||
#endif
|
||||
|
||||
namespace Jovian.Utilities {
|
||||
public static class HierarchyUtility {
|
||||
#if UNITY_EDITOR
|
||||
public static List<TComponent> FindComponentsInHierarchy<TComponent>(bool includeInactive = false) where TComponent : Component {
|
||||
PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
if(prefabStage == null) {
|
||||
return SceneUtility.FindComponentsInActiveScene<TComponent>(includeInactive);
|
||||
}
|
||||
else {
|
||||
return new List<TComponent>(prefabStage.prefabContentsRoot.GetComponentsInChildren<TComponent>(includeInactive));
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Component> FindComponentsInHierarchy(Type componentType, bool includeInactive = false) {
|
||||
PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
if(prefabStage == null) {
|
||||
return SceneUtility.FindComponentsInActiveScene(componentType, includeInactive);
|
||||
}
|
||||
else {
|
||||
return new List<Component>(prefabStage.prefabContentsRoot.GetComponentsInChildren(componentType, includeInactive));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fce733b284594854aaf7c9720f440333
|
||||
@@ -0,0 +1,68 @@
|
||||
#if UNITY_EDITOR
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace Jovian.Utilities {
|
||||
|
||||
public static class InspectorGUIUtility {
|
||||
public static object DrawField(string name, Type type, object value) {
|
||||
GUIContent label = new(name, $"<{type.Name}> = {value}");
|
||||
if(type == typeof(string)) {
|
||||
return EditorGUILayout.TextField(label, (string)value);
|
||||
}
|
||||
if(type == typeof(bool)) {
|
||||
return EditorGUILayout.Toggle(label, (bool)value);
|
||||
}
|
||||
if(type == typeof(float)) {
|
||||
return EditorGUILayout.FloatField(label, (float)value);
|
||||
}
|
||||
if(type == typeof(int)) {
|
||||
return EditorGUILayout.IntField(label, (int)value);
|
||||
}
|
||||
if(type == typeof(byte)) {
|
||||
return (byte)EditorGUILayout.IntField(label, (byte)value);
|
||||
}
|
||||
if(type == typeof(Vector2)) {
|
||||
return EditorGUILayout.Vector2Field(label, (Vector2)value);
|
||||
}
|
||||
if(type == typeof(Vector3)) {
|
||||
return EditorGUILayout.Vector3Field(label, (Vector3)value);
|
||||
}
|
||||
if(type == typeof(Vector4)) {
|
||||
return EditorGUILayout.Vector4Field(label, (Vector4)value);
|
||||
}
|
||||
if(type == typeof(Bounds)) {
|
||||
return EditorGUILayout.BoundsField(label, (Bounds)value);
|
||||
}
|
||||
if(type == typeof(BoundsInt)) {
|
||||
return EditorGUILayout.BoundsIntField(label, (BoundsInt)value);
|
||||
}
|
||||
if(type == typeof(Color)) {
|
||||
return EditorGUILayout.ColorField(label, (Color)value);
|
||||
}
|
||||
if(type == typeof(AnimationCurve)) {
|
||||
return EditorGUILayout.CurveField(label, (AnimationCurve)value);
|
||||
}
|
||||
if (type == typeof(double)) {
|
||||
return EditorGUILayout.DoubleField(label, (double)value);
|
||||
}
|
||||
if (type == typeof(Gradient)) {
|
||||
return EditorGUILayout.GradientField(label, (Gradient)value);
|
||||
}
|
||||
if (type == typeof(long)) {
|
||||
return EditorGUILayout.LongField(label, (long)value);
|
||||
}
|
||||
if(type.IsEnum) {
|
||||
return EditorGUILayout.EnumPopup(label, (Enum)value);
|
||||
}
|
||||
if(type.IsSubclassOf(typeof(UnityEngine.Object)) || value is UnityEngine.Object) {
|
||||
return EditorGUILayout.ObjectField(label, (UnityEngine.Object)value, type, true);
|
||||
}
|
||||
string stringValue = value == null ? "<NULL>" : value.ToString();
|
||||
EditorGUILayout.TextField(label, stringValue);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8b62c711143ba3e4a8d4e941f00a8d2c
|
||||
@@ -0,0 +1,203 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Jovian.Utilities {
|
||||
public static class SceneUtility {
|
||||
|
||||
public static List<GameObject> FindGameObjectsInScene(this Scene scene, bool includeInactive = false, Func<GameObject, bool> predicate = null) {
|
||||
if (scene.IsValid() == false)
|
||||
{
|
||||
Debug.LogError("Scene is invalid");
|
||||
return null;
|
||||
}
|
||||
|
||||
var list = new List<GameObject>();
|
||||
GameObject[] sceneObjects = scene.GetRootGameObjects();
|
||||
GameObject[] loadedObjects = FindDontDestroyOnLoadObjects();
|
||||
GameObject[] combinedGameobjects = new GameObject[sceneObjects.Length + loadedObjects.Length];
|
||||
sceneObjects.CopyTo(combinedGameobjects, 0);
|
||||
loadedObjects.CopyTo(combinedGameobjects, sceneObjects.Length);
|
||||
foreach (var rootObject in combinedGameobjects)
|
||||
{
|
||||
var allChildTransforms = rootObject.GetComponentsInChildren<Transform>(includeInactive);
|
||||
var allGameObjects = allChildTransforms.Select(transform => transform.gameObject);
|
||||
if (predicate != null)
|
||||
{
|
||||
allGameObjects = allGameObjects.Where(predicate);
|
||||
}
|
||||
|
||||
list.AddRange(allGameObjects);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public static List<GameObject> FindGameObjectsInActiveScene(bool includeInactive = false, Func<GameObject, bool> predicate = null)
|
||||
=> FindGameObjectsInScene(SceneManager.GetActiveScene(), includeInactive, predicate);
|
||||
|
||||
// Adding support for finding objects not in the main scenes but in DontDestroyOnLoad
|
||||
// From https://forum.unity.com/threads/editor-script-how-to-access-objects-under-dontdestroyonload-while-in-play-mode.442014/#post-3570916
|
||||
private static GameObject[] FindDontDestroyOnLoadObjects() {
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
return new GameObject[] { }; // return an empty array as this method creates issues in edit mode
|
||||
}
|
||||
|
||||
GameObject temp = null;
|
||||
try
|
||||
{
|
||||
temp = new GameObject();
|
||||
Object.DontDestroyOnLoad(temp);
|
||||
UnityEngine.SceneManagement.Scene dontDestroyOnLoad = temp.scene;
|
||||
Object.DestroyImmediate(temp);
|
||||
temp = null;
|
||||
|
||||
return dontDestroyOnLoad.GetRootGameObjects();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (temp != null)
|
||||
Object.DestroyImmediate(temp);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<TComponent> FindComponentsInScene<TComponent>(this Scene scene, bool includeInactive = false) where TComponent : Component {
|
||||
if (scene.IsValid() == false)
|
||||
{
|
||||
Debug.LogError("Scene is invalid");
|
||||
return null;
|
||||
}
|
||||
|
||||
var list = new List<TComponent>();
|
||||
|
||||
foreach (var rootObject in scene.GetRootGameObjects())
|
||||
{
|
||||
list.AddRange(rootObject.GetComponentsInChildren<TComponent>(includeInactive));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public static List<Component> FindComponentsInScene(this Scene scene, Type componentType, bool includeInactive = false) {
|
||||
if (scene.IsValid() == false)
|
||||
{
|
||||
Debug.LogError("Scene is invalid");
|
||||
return null;
|
||||
}
|
||||
|
||||
var list = new List<Component>();
|
||||
foreach (GameObject rootObject in scene.GetRootGameObjects())
|
||||
{
|
||||
list.AddRange(rootObject.GetComponentsInChildren(componentType, includeInactive));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public static List<TComponent> FindComponentsInActiveScene<TComponent>(bool includeInactive = false) where TComponent : Component
|
||||
=> FindComponentsInScene<TComponent>(SceneManager.GetActiveScene(), includeInactive);
|
||||
|
||||
public static List<Component> FindComponentsInActiveScene(Type componentType, bool includeInactive = false)
|
||||
=> FindComponentsInScene(SceneManager.GetActiveScene(), componentType, includeInactive);
|
||||
|
||||
public static List<TComponent> FindComponentsInAllScenes<TComponent>(bool includeInactive = false) where TComponent : Component {
|
||||
List<TComponent> allComponents = new();
|
||||
for (int i = 0, c = SceneManager.sceneCount; i < c; i++)
|
||||
{
|
||||
allComponents.AddRange(FindComponentsInScene<TComponent>(SceneManager.GetSceneAt(i), includeInactive));
|
||||
}
|
||||
|
||||
return allComponents;
|
||||
}
|
||||
|
||||
public static TComponent FindComponentInScene<TComponent>(this Scene scene, bool includeInactive = false) where TComponent : Component {
|
||||
if (scene.IsValid() == false)
|
||||
{
|
||||
Debug.LogError("Scene is invalid");
|
||||
return null;
|
||||
}
|
||||
|
||||
var list = new List<TComponent>();
|
||||
|
||||
foreach (var rootObject in scene.GetRootGameObjects())
|
||||
{
|
||||
list.AddRange(rootObject.GetComponentsInChildren<TComponent>(includeInactive));
|
||||
}
|
||||
|
||||
return list.FirstOrDefault();
|
||||
}
|
||||
|
||||
public static Component FindComponentInScene(this Scene scene, Type componentType, bool includeInactive = false) {
|
||||
if (scene.IsValid() == false)
|
||||
{
|
||||
Debug.LogError("Scene is invalid");
|
||||
return null;
|
||||
}
|
||||
|
||||
var list = new List<Component>();
|
||||
|
||||
foreach (GameObject rootObject in scene.GetRootGameObjects())
|
||||
{
|
||||
list.AddRange(rootObject.GetComponentsInChildren(componentType, includeInactive));
|
||||
}
|
||||
|
||||
return list.FirstOrDefault();
|
||||
}
|
||||
|
||||
public static TComponent FindComponentInActiveScene<TComponent>(bool includeInactive = false) where TComponent : Component
|
||||
=> FindComponentInScene<TComponent>(SceneManager.GetActiveScene(), includeInactive);
|
||||
|
||||
public static Component FindComponentInActiveScene(Type componentType, bool includeInactive = false)
|
||||
=> FindComponentInScene(SceneManager.GetActiveScene(), componentType, includeInactive);
|
||||
|
||||
public static TComponent FindComponentInAllScenes<TComponent>(bool includeInactive = false) where TComponent : Component
|
||||
=> FindComponentsInAllScenes<TComponent>(includeInactive).FirstOrDefault();
|
||||
|
||||
|
||||
public static GameObject FindGameObject(string nameQuery) {
|
||||
char delimiter = '/';
|
||||
string[] querySegments = nameQuery.Split(delimiter);
|
||||
|
||||
return FindGameObjectsInActiveScene(true, (gameObject) => {
|
||||
int queryIndex = querySegments.Length - 1;
|
||||
Transform compareTransform = gameObject.transform;
|
||||
do
|
||||
{
|
||||
if (compareTransform != null && compareTransform.name.Equals(querySegments[queryIndex]))
|
||||
{
|
||||
compareTransform = compareTransform.parent;
|
||||
queryIndex--;
|
||||
}
|
||||
// if compare is null and string is null that means the first query segment was /, so that's the root element - then our parent MUST be null
|
||||
else if (compareTransform == null && string.IsNullOrEmpty(querySegments[queryIndex]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} while (queryIndex >= 0);
|
||||
|
||||
return true;
|
||||
}).FirstOrDefault();
|
||||
}
|
||||
|
||||
private static Transform GetChildWithName(this Transform transform, string childName) {
|
||||
foreach (Transform child in transform.transform)
|
||||
{
|
||||
if (child.name.Equals(childName))
|
||||
{
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d2e17c945fb193744abb8d14866b11c0
|
||||
@@ -0,0 +1,211 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Diagnostics;
|
||||
using System.Text.RegularExpressions;
|
||||
using UnityEngine;
|
||||
using Debug = UnityEngine.Debug;
|
||||
using Object = UnityEngine.Object;
|
||||
using Type = System.Type;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using System.Reflection;
|
||||
#endif
|
||||
|
||||
namespace Jovian.Utilities {
|
||||
|
||||
public static class SerializedObjectUtility {
|
||||
[Conditional("UNITY_EDITOR")]
|
||||
public static void SaveObjectProperties(Object targetObject, params object[] args) {
|
||||
#if UNITY_EDITOR
|
||||
EditorSerializedObjectUtility.SaveObjectProperties(targetObject, args);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if UNITY_EDITOR
|
||||
public static class EditorSerializedObjectUtility {
|
||||
|
||||
//https://answers.unity.com/questions/929293/get-field-type-of-serializedproperty.html
|
||||
public static Type GetTypeFromProperty(SerializedProperty property) {
|
||||
//gets parent type info
|
||||
string[] slices = property.propertyPath.Split('.');
|
||||
System.Type type = property.serializedObject.targetObject.GetType();
|
||||
|
||||
for(int i = 0; i < slices.Length; i++)
|
||||
if (slices[i] == "Array")
|
||||
{
|
||||
i++; //skips "data[x]"
|
||||
type = type.GetElementType(); //gets info on array elements
|
||||
}
|
||||
|
||||
//gets info on field and its type
|
||||
else type = type.GetField(slices[i], BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Instance).FieldType;
|
||||
|
||||
//type is now the type of the property
|
||||
return type;
|
||||
}
|
||||
|
||||
private static readonly Regex isArrayElementRegex = new Regex("Array.data\\[\\d+\\]$");
|
||||
|
||||
public static bool IsPropertyAnArrayElement(SerializedProperty property) {
|
||||
return isArrayElementRegex.IsMatch(property.propertyPath);
|
||||
}
|
||||
|
||||
public static SerializedProperty GetArrayPropertyWithElementProperty(SerializedProperty property) {
|
||||
SerializedObject serializedObject = property.serializedObject;
|
||||
string propertyPath = property.propertyPath;
|
||||
int arrayDataIndex = propertyPath.LastIndexOf(".Array.data", StringComparison.Ordinal);
|
||||
string propertyPathWithoutArray = propertyPath.Substring(0, arrayDataIndex);
|
||||
int pathDividerIndex = propertyPathWithoutArray.LastIndexOf(".", StringComparison.Ordinal);
|
||||
|
||||
string parentPropertyName = propertyPathWithoutArray;
|
||||
if(pathDividerIndex != -1) {
|
||||
parentPropertyName = propertyPathWithoutArray.Substring(pathDividerIndex);
|
||||
}
|
||||
return serializedObject.FindProperty(parentPropertyName);;
|
||||
}
|
||||
|
||||
public static void SaveObjectProperties(Object targetObject, params object[] args) {
|
||||
SerializedObject serializedObject = new SerializedObject(targetObject);
|
||||
|
||||
for(int i = 0; i < args.Length; i += 2) {
|
||||
var keyArg = args[i];
|
||||
var keyType = keyArg.GetType();
|
||||
|
||||
if((keyType == typeof(string)) == false) {
|
||||
throw new System.NotSupportedException(string.Format("Key must be string. {0} is {1}", args[i], keyType));
|
||||
}
|
||||
else {
|
||||
var property = serializedObject.FindProperty((string)keyArg);
|
||||
object argValue = args[i + 1];
|
||||
|
||||
if(property == null) {
|
||||
throw new System.Exception(string.Format("No property found for key {0}", keyArg));
|
||||
}
|
||||
|
||||
if(argValue == null) {
|
||||
property.objectReferenceValue = null;
|
||||
}
|
||||
else {
|
||||
if(property.isArray) {
|
||||
property.arraySize = 0;
|
||||
IEnumerable argArray = (IEnumerable)argValue;
|
||||
IEnumerator enumerator = argArray.GetEnumerator();
|
||||
|
||||
int index = 0;
|
||||
while(enumerator.MoveNext()) {
|
||||
property.InsertArrayElementAtIndex(index);
|
||||
var arrayProperty = property.GetArrayElementAtIndex(index);
|
||||
SetSerializedPropertyValue(arrayProperty, enumerator.Current);
|
||||
index++;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
SetSerializedPropertyValue(property, argValue);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
private static void SetSerializedPropertyValue(SerializedProperty property, object value) {
|
||||
if(property == null) {
|
||||
UnityEngine.Debug.LogError("SetSerializedPropertyValue failed, property is null");
|
||||
return;
|
||||
}
|
||||
switch(property.propertyType) {
|
||||
case SerializedPropertyType.AnimationCurve:
|
||||
property.animationCurveValue = (AnimationCurve)value;
|
||||
break;
|
||||
case SerializedPropertyType.Boolean:
|
||||
property.boolValue = (bool)value;
|
||||
break;
|
||||
case SerializedPropertyType.BoundsInt:
|
||||
property.boundsIntValue = (BoundsInt)value;
|
||||
break;
|
||||
case SerializedPropertyType.Character:
|
||||
property.intValue = (int)(char)value;
|
||||
break;
|
||||
case SerializedPropertyType.Color: {
|
||||
if(value is Color32) {
|
||||
property.colorValue = (Color)(Color32)value;
|
||||
}
|
||||
else {
|
||||
property.colorValue = (Color)value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SerializedPropertyType.ExposedReference:
|
||||
case SerializedPropertyType.ObjectReference:
|
||||
property.objectReferenceValue = (Object)value;
|
||||
break;
|
||||
case SerializedPropertyType.Float:
|
||||
property.floatValue = (float)value;
|
||||
break;
|
||||
case SerializedPropertyType.Integer:
|
||||
property.intValue = (int)value;
|
||||
break;
|
||||
case SerializedPropertyType.LayerMask:
|
||||
property.intValue = ((LayerMask)value).value;
|
||||
break;
|
||||
case SerializedPropertyType.Quaternion:
|
||||
property.quaternionValue = (Quaternion)value;
|
||||
break;
|
||||
case SerializedPropertyType.Rect:
|
||||
property.rectValue = (Rect)value;
|
||||
break;
|
||||
case SerializedPropertyType.RectInt:
|
||||
property.rectIntValue = (RectInt)value;
|
||||
break;
|
||||
case SerializedPropertyType.String:
|
||||
property.stringValue = (string)value;
|
||||
break;
|
||||
case SerializedPropertyType.Vector2:
|
||||
property.vector2Value = (Vector2)value;
|
||||
break;
|
||||
case SerializedPropertyType.Vector2Int:
|
||||
property.vector2IntValue = (Vector2Int)value;
|
||||
break;
|
||||
case SerializedPropertyType.Vector3:
|
||||
property.vector3Value = (Vector3)value;
|
||||
break;
|
||||
case SerializedPropertyType.Vector3Int:
|
||||
property.vector3IntValue = (Vector3Int)value;
|
||||
break;
|
||||
case SerializedPropertyType.Vector4:
|
||||
property.vector4Value = (Vector4)value;
|
||||
break;
|
||||
case SerializedPropertyType.Enum:
|
||||
property.enumValueIndex = (int)value; // need to test this
|
||||
// flags???
|
||||
break;
|
||||
case SerializedPropertyType.Generic:
|
||||
SaveGenericProperty(property, value);
|
||||
break;
|
||||
default:
|
||||
throw new System.NotSupportedException($"PropertyType {property.propertyType} is not supported - yet. Array? {property.isArray} Path: {property.propertyPath}");
|
||||
}
|
||||
}
|
||||
|
||||
private static void SaveGenericProperty(SerializedProperty property, object instance) {
|
||||
Type type = instance.GetType();
|
||||
var fields = type.GetRuntimeFields();
|
||||
foreach(FieldInfo field in fields) {
|
||||
if(field.IsNotSerialized || field.IsStatic) {
|
||||
continue;
|
||||
}
|
||||
SerializedProperty fieldProperty = property.FindPropertyRelative(field.Name);
|
||||
if(fieldProperty != null) {
|
||||
SetSerializedPropertyValue(property.FindPropertyRelative(field.Name), field.GetValue(instance));
|
||||
}
|
||||
else {
|
||||
UnityEngine.Debug.Log($"SaveGenericProperty cannot field serializedProperty named '{field.Name}'");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 51917079be732084cbaae41d702e72ce
|
||||
Reference in New Issue
Block a user