changed directory structure

This commit is contained in:
Sebastian Bularca
2026-04-02 07:22:33 +02:00
parent 101a7ae81a
commit 81b8eadaf1
323 changed files with 5 additions and 5 deletions

View File

@@ -0,0 +1,36 @@
using System.Collections;
using System.Text;
namespace Jovian.Utilities {
public static class ArrayUtility {
public static string ListToString(this IList list, bool newLinePerEntry = false) {
if(list == null) {
return "<NULL>";
}
StringBuilder sb = new();
sb.Append("[");
sb.Append(list.Count);
sb.Append("]{");
if(newLinePerEntry) {
sb.AppendLine();
}
for(int i = 0, c = list.Count; i < c; i++) {
sb.Append(list[i]);
if(i < c - 1) {
if(newLinePerEntry) {
sb.AppendLine(",");
}
else {
sb.Append(", ");
}
}
}
if(newLinePerEntry) {
sb.AppendLine();
}
sb.Append("}");
return sb.ToString();
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: fff0c7e092c6f6a44ba792b369a382dd

View File

@@ -0,0 +1,38 @@
using UnityEngine;
namespace Jovian.Utilities {
public static class CachedMainCamera {
private static int lastFrame = -1;
private static Camera mainCamera;
private static Transform mainCameraTransform;
public static Camera MainCamera {
get {
if(mainCamera) {
return mainCamera;
}
AssignCameraReferences();
return mainCamera;
}
}
public static Transform MainCameraTransform {
get {
if(mainCameraTransform) {
return mainCameraTransform;
}
AssignCameraReferences();
return mainCameraTransform;
}
}
private static void AssignCameraReferences() {
int frame = Time.frameCount;
if(lastFrame != frame) {
mainCamera = Camera.main;
mainCameraTransform = (mainCamera ? mainCamera.transform : null);
lastFrame = frame;
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 0701523b57a704b4780d0a226f0d0d1b

View File

@@ -0,0 +1,24 @@
using UnityEngine;
namespace Jovian.Utilities {
[RequireComponent(typeof(Canvas))]
public class CanvasAutoAssignWorldCamera : MonoBehaviour {
public Canvas canvas;
public bool autoDisableOnceCameraFound = false;
#if UNITY_EDITOR
public void Reset() {
SerializedObjectUtility.SaveObjectProperties(this, nameof(canvas), GetComponent<Canvas>());
}
#endif
private void Update() {
if(canvas && !canvas.worldCamera) {
canvas.worldCamera = CachedMainCamera.MainCamera;
if(canvas.worldCamera && autoDisableOnceCameraFound) {
enabled = false;
}
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 59842e0a1599f854cae803d724ecb1e7

View File

@@ -0,0 +1,99 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Random = UnityEngine.Random;
namespace Jovian.Utilities.Utilities {
public static class CollectionUtility {
public static T RandomElementFromCollection<T>(this ICollection<T> enumerableObject) {
int count = enumerableObject.Count;
if (count == 0) {
throw new IndexOutOfRangeException("Cannot get RandomElement, collection size is 0.");
}
int index = Random.Range(0, count);
return enumerableObject.ElementAt(index);
}
}
}
public static class EnumerableUtility {
private static System.Random random;
public static T RandomElement<T>(this IEnumerable<T> source) {
random ??= new System.Random();
return source.RandomElement(random);
}
//https://stackoverflow.com/a/648240/584774
public static T RandomElement<T>(this IEnumerable<T> source, System.Random rng) {
T current = default(T);
int count = 0;
foreach (T element in source) {
count++;
if (rng.Next(count) == 0) {
current = element;
}
}
if (count == 0) {
throw new InvalidOperationException("Sequence was empty");
}
return current;
}
public static bool TryGetRandomElement<T>(this IEnumerable<T> source, out T outElement) {
random ??= new System.Random();
return source.TryGetRandomElement(random, out outElement);
}
public static bool TryGetRandomElement<T>(this IEnumerable<T> source, System.Random rng, out T outElement) {
T current = default(T);
int count = 0;
foreach (T element in source) {
count++;
if (rng.Next(count) == 0) {
current = element;
}
}
outElement = current;
if (count == 0) {
return false;
}
return true;
}
public static string EnumerableToString(this IEnumerable enumerable, bool newLinePerEntry = false) {
if (enumerable == null) {
return "<NULL>";
}
StringBuilder sb = new();
sb.Append("{");
if (newLinePerEntry) {
sb.AppendLine();
}
foreach (object item in enumerable) {
sb.Append(item);
if (newLinePerEntry) {
sb.AppendLine(",");
}
else {
sb.Append(", ");
}
}
if (newLinePerEntry) {
sb.AppendLine();
}
sb.Append("}");
return sb.ToString();
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 9a6194020ff13054597ed18112a7acff

View File

@@ -0,0 +1,9 @@
using UnityEngine;
namespace Jovian.Utilities {
public static class ColliderUtilities {
public static bool ContainsPoint(this Collider collider, Vector3 point) {
return (collider.ClosestPoint(point) - point).sqrMagnitude < Mathf.Epsilon;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 033c7401511b25948be41b7ab4774a03

View File

@@ -0,0 +1,18 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Jovian.Utilities {
public class CollisionExtractor : MonoBehaviour {
public GameObject root;
public GameObject targetPrefab;
// Script only used inside the editor
private void Awake() {
if(!Application.isEditor) {
Destroy(this);
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 1db2adf065c60df4d89c324e77eba81d

View File

@@ -0,0 +1,64 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Jovian.Utilities {
public class CustomRenderQueueMaterialList : MonoBehaviour {
[System.Serializable]
public class MaterialRenderQueue {
public Material material;
public int renderQueue;
public int storedRenderQueue;
}
public bool updateMaterialsInEditor;
[SerializeField]
private MaterialRenderQueue[] materialRenderQueueList;
private void Awake() {
#if UNITY_EDITOR
if(updateMaterialsInEditor) {
Debug.LogWarning("Updating Materials will cause asset files to change. Please review your change log to ensure only valid changes are submitted.");
}
else {
return;
}
#endif
foreach(var materialRenderQueue in materialRenderQueueList) {
if(materialRenderQueue.material) {
materialRenderQueue.storedRenderQueue = materialRenderQueue.material.renderQueue; // store the materials original render queue
materialRenderQueue.material.renderQueue = materialRenderQueue.renderQueue; // overwrite the render queue
}
}
}
private void OnDestroy() {
#if UNITY_EDITOR
if(updateMaterialsInEditor) {
Debug.LogWarning("Updating Materials will cause asset files to change. Please review your change log to ensure only valid changes are submitted.");
}
else {
return;
}
#endif
foreach(var materialRenderQueue in materialRenderQueueList) {
if(materialRenderQueue.material) {
materialRenderQueue.material.renderQueue = materialRenderQueue.storedRenderQueue;
}
}
}
public bool DoesMaterialExistInList(Material material) {
foreach(var materialRenderQueue in materialRenderQueueList) {
if(materialRenderQueue.material == material) {
return true;
}
}
return false;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: a49f06b9d6f75f04fa4ae4f6ee714a83

View File

@@ -0,0 +1,43 @@
using UnityEngine;
namespace Jovian.Utilities {
public class CustomRenderQueueRenderer : MonoBehaviour {
[SerializeField, Tooltip("Override RenderQueue for shader, 2000 = Opaque, 3000 = Transparent, -1 = Shader Default")]
private int renderQueue = -1;
[SerializeField]
private MeshRenderer meshRenderer;
[SerializeField, Tooltip("If true, only this renderer is affected because a new material is created.")]
private bool createMaterialInstance;
private void Awake() {
var material = createMaterialInstance ? meshRenderer.material : meshRenderer.sharedMaterial;
material.renderQueue = renderQueue;
}
#if UNITY_EDITOR
private void Reset() {
var serializedObject = new UnityEditor.SerializedObject(this);
var meshRendererProperty = serializedObject.FindProperty("meshRenderer");
var meshRenderer = gameObject.GetComponent<MeshRenderer>();
if(meshRenderer != null) {
meshRendererProperty.objectReferenceValue = meshRenderer;
serializedObject.ApplyModifiedProperties();
CopyRenderQueueFromMaterial(); // applies serializedObject modified properties
}
}
[ContextMenu("Copy RenderQueue from Material")]
private void CopyRenderQueueFromMaterial() {
if(meshRenderer == null) {
Debug.LogError(@"MeshRenderer is null, cannot copy RenderQueue", this);
return;
}
var serializedObject = new UnityEditor.SerializedObject(this);
var renderQueueProperty = serializedObject.FindProperty("renderQueue");
renderQueueProperty.intValue = meshRenderer.sharedMaterial.renderQueue;
serializedObject.ApplyModifiedProperties();
}
#endif
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: c20f17639e020c0448b1481fad636678

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 45fad90effb685541beabcc012dca7f5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 8f53e63ec5b4b3744bda48fb1159ac40

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: f8316472f7c700f4a9e908d3abde1d1d

View File

@@ -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.");
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: e2ce31502182718488f21bcf6137096f

View File

@@ -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
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: fce733b284594854aaf7c9720f440333

View File

@@ -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

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 8b62c711143ba3e4a8d4e941f00a8d2c

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: d2e17c945fb193744abb8d14866b11c0

View File

@@ -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
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 51917079be732084cbaae41d702e72ce

View File

@@ -0,0 +1,45 @@
using System;
using UnityEngine;
namespace Jovian.Utilities {
public abstract class NumberRange<T> {
public T min;
public T max;
public abstract float Lerp(float t);
public abstract float LerpUnclamped(float t);
// returns 0 to 1
public abstract float InverseLerp(float t);
// returns values -1 to 1
public abstract float InverseLerpSigned(float t);
public abstract T Random();
}
[Serializable]
public class FloatRange : NumberRange<float> {
public FloatRange(float min, float max) {
this.min = min;
this.max = max;
}
public override float Lerp(float t) => Mathf.Lerp(min, max, t);
public override float LerpUnclamped(float t) => Mathf.LerpUnclamped(min, max, t);
public override float InverseLerp(float t) => Mathf.InverseLerp(min, max, t);
public override float InverseLerpSigned(float t) => Mathf.InverseLerp(min, max, t) * 2f - 1f;
public override float Random() => UnityEngine.Random.Range(min, max);
}
[Serializable]
public class IntRange : NumberRange<int> {
public IntRange(int min, int max) {
this.min = min;
this.max = max;
}
public override float Lerp(float t) => Mathf.Lerp(min, max, t);
public override float LerpUnclamped(float t) => Mathf.LerpUnclamped(min, max, t);
public override float InverseLerp(float t) => Mathf.InverseLerp(min, max, t);
public override float InverseLerpSigned(float t) => Mathf.InverseLerp(min, max, t) * 2f - 1f;
public override int Random() => UnityEngine.Random.Range(min, max);
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 01901fe75ec22104b866b8a243adf3c3

View File

@@ -0,0 +1,59 @@
using System;
using UnityEngine;
using Object = UnityEngine.Object;
namespace Jovian.Utilities {
public static class GameObjectUtilities {
public static void DestroyGameObjectsOfType<T>() where T : MonoBehaviour {
T[] objects = Object.FindObjectsOfType<T>();
for (int i = 0; i < objects.Length; ++i) {
Object.Destroy(objects[i].gameObject);
}
}
public static bool IsGameObjectAChildOfGameObject(this GameObject targetGameObject, GameObject potentialParentGameObject) {
if (targetGameObject == null) {
return false;
}
Transform potentialParentTransform = potentialParentGameObject.transform;
Transform checkTransform = targetGameObject.transform;
do {
if (checkTransform == potentialParentTransform) {
return true;
}
checkTransform = checkTransform.parent;
} while (checkTransform != null);
return false;
}
public static bool TryFindChildByName(this GameObject gameObject,
string name,
out GameObject childGameObject,
bool includeInactive = false,
bool allowPartialMatch = false,
StringComparison stringComparison = StringComparison.Ordinal) {
childGameObject = null;
if (gameObject == null) {
return false;
}
Transform[] children = gameObject.GetComponentsInChildren<Transform>(includeInactive);
foreach (Transform child in children) {
if (allowPartialMatch && child.name.Contains(name, stringComparison)) {
childGameObject = child.gameObject;
return true;
}
if (!allowPartialMatch && child.name.Equals(name, stringComparison)) {
childGameObject = child.gameObject;
return true;
}
}
return false;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 42dbc9bd96270ef4fb84e4df2590e3ad

View File

@@ -0,0 +1,14 @@
{
"name": "JovianUtilities",
"rootNamespace": "",
"references": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 6c878acd8a48e2d48ad42c741bc8551d
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Jovian.Utilities
{
public interface ILoadingProcess {
bool HasLoaded { get; }
}
public class LoadingProcessHandler {
private readonly HashSet<ILoadingProcess> allProcesses = new();
private readonly HashSet<ILoadingProcess> anyProcesses = new();
public event Action OnLoadComplete;
public bool IsLoadingComplete() {
foreach(ILoadingProcess loadingProcess in anyProcesses) {
if(loadingProcess.HasLoaded) {
return true;
}
}
bool areAllProcessesComplete = true;
foreach(ILoadingProcess loadingProcess in allProcesses) {
if(loadingProcess.HasLoaded == false) {
areAllProcessesComplete = false;
break;
}
}
return areAllProcessesComplete;
}
public void AddAllProcess(ILoadingProcess loadingProcess) {
allProcesses.Add(loadingProcess);
}
public void AddAnyProcess(ILoadingProcess loadingProcess) {
anyProcesses.Add(loadingProcess);
}
public void Complete() {
OnLoadComplete?.Invoke();
}
}
public class TimeElapsedLoadingProcess : ILoadingProcess {
private readonly float endTime;
public bool HasLoaded => Time.realtimeSinceStartup > endTime;
public TimeElapsedLoadingProcess(float duration) {
endTime = Time.realtimeSinceStartup + duration;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 65bcc9fd235ddb54e991d2799a5e2e2d