Compare commits

..

10 Commits

21 changed files with 168 additions and 506 deletions

View File

@ -1,38 +1,40 @@
using UnityEditor; using System;
using UnityEditor;
using UnityEngine; using UnityEngine;
namespace Utils namespace Utils.Editor
{ {
[CustomEditor(typeof(EventManager), true)] [CustomEditor(typeof(EventManager), true)]
public class EventManagerEditor : Editor public class EventManagerEditor : UnityEditor.Editor
{ {
public override void OnInspectorGUI() public override void OnInspectorGUI()
{ {
var eventManager = (EventManager)target; Event("EarlyUpdate", EventManager.EarlyUpdateLength, EventManager.EarlyUpdateDelegates);
GUILayout.BeginHorizontal(); EditorGUILayout.Space();
GUILayout.Label("Update"); Event("Update", EventManager.UpdateLength, EventManager.UpdateDelegates);
if (Application.isPlaying) EditorGUILayout.Space();
Event("LateUpdate", EventManager.LateUpdateLength, EventManager.LateUpdateDelegates);
EditorGUILayout.Space();
Event("LastUpdate", EventManager.LastUpdateLength, EventManager.LastUpdateDelegates);
}
private void Event(string title, int length, Delegate[] delegates)
{ {
GUILayout.FlexibleSpace();
GUILayout.Label(EventManager.UpdateLength.ToString());
}
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label("FixedUpdate");
if (Application.isPlaying)
{ {
GUILayout.FlexibleSpace();
GUILayout.Label(EventManager.FixedUpdateLength.ToString());
}
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
GUILayout.Label("LateUpdate");
if (Application.isPlaying) GUILayout.Label(title, EditorStyles.boldLabel);
{
GUILayout.FlexibleSpace(); GUILayout.FlexibleSpace();
GUILayout.Label(EventManager.LateUpdateLength.ToString()); GUILayout.Label(length.ToString());
}
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
if (length == 0) return;
foreach (var d in delegates)
{
GUILayout.Label($"{d.Method.DeclaringType}.{d.Method.Name}", EditorStyles.miniLabel);
}
}
} }
} }
} }

View File

@ -1,51 +0,0 @@
using System.IO;
using UnityEditor;
using UnityEngine;
namespace Utils
{
public class PackgeUpdater
{
private static string ManifestPath
{
get
{
var projectPath = Directory.GetParent(Application.dataPath).FullName;
var manifestPath = Path.Combine(projectPath, "Packages", "manifest.json");
return manifestPath;
}
}
public static string GetIdentifier(string input, char charFrom, char charTo)
{
var first = input.IndexOf(charFrom);
var second = input.IndexOf(charTo, first + 1);
var posFrom = input.IndexOf(charFrom, second + 1);
if (posFrom != -1) //if found char
{
var posTo = input.IndexOf(charTo, posFrom + 1);
if (posTo != -1) //if found char
{
return input.Substring(posFrom + 1, posTo - posFrom - 1);
}
}
return string.Empty;
}
[MenuItem("Assets/Update Git Packages", false, 1000)]
private static void UpdateGitPackages()
{
var lines = File.ReadAllLines(ManifestPath);
foreach (var line in lines)
{
if (line.Contains("git"))
{
var identifier = GetIdentifier(line, '"', '"');
Debug.Log("Checking for updates " + identifier);
UnityEditor.PackageManager.Client.Add(identifier);
}
}
}
}
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: ce75a6f4e95d89b4eba151eb7d16a6ff
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,34 @@
using System;
using UnityEditor;
using UnityEngine;
namespace Utils.Editor
{
[CustomEditor(typeof(PhysicsEventManager), true)]
public class PhysicsEventManagerEditor : UnityEditor.Editor
{
public override void OnInspectorGUI()
{
Event("FixedUpdate", PhysicsEventManager.FixedUpdateLength, PhysicsEventManager.FixedUpdateDelegates);
}
private void Event(string title, int length, Delegate[] delegates)
{
{
GUILayout.BeginHorizontal();
GUILayout.Label(title, EditorStyles.boldLabel);
GUILayout.FlexibleSpace();
GUILayout.Label(length.ToString());
GUILayout.EndHorizontal();
if (length == 0) return;
foreach (var d in delegates)
{
GUILayout.Label($"{d.Method.DeclaringType}.{d.Method.Name}", EditorStyles.miniLabel);
}
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2dc65e2b44db4ae5ac60ad4ecf343e82
timeCreated: 1713873473

View File

@ -1,7 +1,7 @@
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;
namespace Utils namespace Utils.Editor
{ {
[CustomPropertyDrawer(typeof(ReadOnlyFieldAttribute))] [CustomPropertyDrawer(typeof(ReadOnlyFieldAttribute))]
public class ReadOnlyFieldDrawer : PropertyDrawer public class ReadOnlyFieldDrawer : PropertyDrawer

View File

@ -1,7 +1,7 @@
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;
namespace Utils namespace Utils.Editor
{ {
[CustomPropertyDrawer(typeof(ReadOnlyOnPlayFieldAttribute))] [CustomPropertyDrawer(typeof(ReadOnlyOnPlayFieldAttribute))]
public class ReadOnlyOnPlayFieldDrawer : PropertyDrawer public class ReadOnlyOnPlayFieldDrawer : PropertyDrawer

View File

@ -1,170 +0,0 @@
#if COM_UNITY_MODULES_PHYSICS
using UnityEditor;
using UnityEngine;
namespace Utils
{
public class ReflectionProbeVolumeEditor : MonoBehaviour
{
[CustomEditor(typeof(ReflectionProbeVolume), true)]
public class EventManagerEditor : Editor
{
private SerializedProperty resolution;
private SerializedProperty offset;
private SerializedProperty threshold;
private SerializedProperty blendDistance;
private void OnEnable()
{
resolution = serializedObject.FindProperty("resolution");
offset = serializedObject.FindProperty("offset");
threshold = serializedObject.FindProperty("threshold");
blendDistance = serializedObject.FindProperty("blendDistance");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUILayout.PropertyField(resolution);
EditorGUILayout.PropertyField(offset);
EditorGUILayout.PropertyField(threshold);
EditorGUILayout.PropertyField(blendDistance);
serializedObject.ApplyModifiedProperties();
EditorGUILayout.Space();
if (GUILayout.Button("Place"))
{
Place();
}
}
private void Place()
{
var voxelSize = resolution.intValue;
var offset = this.offset.floatValue;
var threshold = this.threshold.floatValue;
var blendDistance = this.blendDistance.floatValue;
ReflectionProbeVolume reflectionProbeVolume = (ReflectionProbeVolume)target;
var transform = reflectionProbeVolume.transform;
//Gizmos.DrawWireCube(transform.position, transform.localScale);
var startPos = transform.position + transform.right * transform.localScale.x / 2 + transform.up * transform.localScale.y / 2 + transform.forward * transform.localScale.z / 2;
var xVar = transform.localScale.x / voxelSize / 2f;
var zVar = transform.localScale.z / voxelSize / 2f;
var data = new Vector3[voxelSize, voxelSize];
//Gizmos.color = Color.blue;
for (int x = 0; x < voxelSize; x++)
{
for (int z = 0; z < voxelSize; z++)
{
var rayPos = startPos - transform.right * xVar - transform.forward * zVar;
if (Physics.Raycast(rayPos, Vector2.down, out RaycastHit hit))
{
var point = hit.point + Vector3.up * offset;
data[x, z] = point;
}
zVar += transform.localScale.z / voxelSize;
}
xVar += transform.localScale.x / voxelSize;
zVar = transform.localScale.z / voxelSize / 2f;
}
CheckSquare(data, 5, voxelSize, threshold, blendDistance, transform);
CheckSquare(data, 4, voxelSize, threshold, blendDistance, transform);
CheckSquare(data, 3, voxelSize, threshold, blendDistance, transform);
CheckSquare(data, 2, voxelSize, threshold, blendDistance, transform);
for (int x = 0; x < voxelSize; x++)
{
for (int z = 0; z < voxelSize; z++)
{
if (data[x, z].x != float.PositiveInfinity)
{
var go = new GameObject("Reflection Probe Size: 1");
go.transform.SetParent(transform);
go.transform.position = data[x, z];
var reflectionProbe = go.AddComponent(typeof(ReflectionProbe)) as ReflectionProbe;
reflectionProbe.resolution = 16;
reflectionProbe.center = new Vector3(0f, transform.position.y - data[x, z].y, 0f);
reflectionProbe.size = new Vector3(transform.localScale.x / voxelSize + blendDistance, transform.localScale.y, transform.localScale.z / voxelSize + blendDistance);
}
}
}
}
private void CheckSquare(Vector3[,] data, int size, int voxelSize, float threshold, float blendDistance, Transform transform)
{
for (int x = 0; x < voxelSize; x++)
{
for (int z = 0; z < voxelSize; z++)
{
if (x + size <= voxelSize && z + size <= voxelSize)
{
bool valid = true;
var point = Vector3.zero;
for (int i = 0; i < size; i++)
{
for (int k = 0; k < size; k++)
{
var pos = data[x + i, z + k];
if (pos != Vector3.positiveInfinity)
{
if (Compare(data[x, z].y, pos.y, threshold))
{
point += pos;
}
else
{
valid = false;
}
}
}
}
if (valid)
{
point /= size * size;
var go = new GameObject("Reflection Probe Size: " + size);
go.transform.SetParent(transform);
go.transform.position = point;
var reflectionProbe = go.AddComponent(typeof(ReflectionProbe)) as ReflectionProbe;
if (size == 2)
{
reflectionProbe.resolution = 16;
}
else if (size == 3)
{
reflectionProbe.resolution = 32;
}
else if (size == 4)
{
reflectionProbe.resolution = 32;
}
else if (size == 5)
{
reflectionProbe.resolution = 64;
}
reflectionProbe.center = new Vector3(0f, transform.position.y - point.y, 0f);
reflectionProbe.size = new Vector3(transform.localScale.x / voxelSize * size + blendDistance, transform.localScale.y, transform.localScale.z / voxelSize * size + blendDistance);
for (int i = 0; i < size; i++)
{
for (int k = 0; k < size; k++)
{
data[x + i, z + k] = Vector3.positiveInfinity;
}
}
}
}
}
}
}
private bool Compare(float arg0, float arg1, float threshold)
{
return Mathf.Abs(arg0 - arg1) < threshold;
}
}
}
}
#endif

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: a77b3177fd3b4754cb1b855b831c5424
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,7 +1,7 @@
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;
namespace Utils namespace Utils.Editor
{ {
[InitializeOnLoad] [InitializeOnLoad]
public static class SceneViewRotation public static class SceneViewRotation

View File

@ -3,11 +3,11 @@ Unity package with utility useful for almost any project.
## Features ## Features
* Hide the script field. * Hide the script field.
* C# Event based Event Manager * More attributes for disabling fields without interfering with existing attributes.
* Call Update, FixedUpdate and LateUpdate from anywhere. * C# event based EventManager.
* Subscribe to Update, FixedUpdate and LateUpdate from anywhere.
* Better performance than Unity methods. * Better performance than Unity methods.
* Automatic volume based reflection probe placer. * FixedUpdate is the separate PhysicsEventManager which makes it entirely optional.
* View usage an editor inspector.
* Check how much time has passed with the TimeSince struct. * Check how much time has passed with the TimeSince struct.
* Camera Blender controls in the scene view. * Camera Blender controls in the scene view.
* Package Manager Git updater.
* Append to an array.

View File

@ -12,11 +12,6 @@
"autoReferenced": true, "autoReferenced": true,
"defineConstraints": [], "defineConstraints": [],
"versionDefines": [ "versionDefines": [
{
"name": "com.unity.modules.physics",
"expression": "",
"define": "COM_UNITY_MODULES_PHYSICS"
},
{ {
"name": "com.unity.netcode.gameobjects", "name": "com.unity.netcode.gameobjects",
"expression": "", "expression": "",

View File

@ -1,22 +0,0 @@
namespace Utils
{
public static class ArrayExtensions
{
public static T[] Append<T>(this T[] array, T item)
{
if (array == null)
{
return new T[] { item };
}
var result = new T[array.Length + 1];
for (var i = 0; i < array.Length; i++)
{
result[i] = array[i];
}
result[array.Length] = item;
return result;
}
}
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 6e14f8172d2e1b345bd36b974bcaeb61
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,58 +1,61 @@
using UnityEngine; using System;
using UnityEngine;
namespace Utils namespace Utils
{ {
public class EventManager : MonoBehaviour public class EventManager : MonoBehaviour
{ {
public delegate void UpdateAction(); public delegate void UpdateAction();
public static event UpdateAction Updated; public static event UpdateAction Updated;
public delegate void FixedUpdateAction();
public static event FixedUpdateAction FixedUpdated;
public delegate void LateUpdateAction(); public delegate void LateUpdateAction();
public static event LateUpdateAction LateUpdated; public static event LateUpdateAction LateUpdated;
public delegate void EarlyUpdateAction();
public static event EarlyUpdateAction EarlyUpdated;
public delegate void LastUpdateAction();
public static event LastUpdateAction LastUpdated;
private void Update() private void Update()
{ {
EarlyUpdated?.Invoke();
Updated?.Invoke(); Updated?.Invoke();
} }
private void FixedUpdate()
{
FixedUpdated?.Invoke();
}
private void LateUpdate() private void LateUpdate()
{ {
LateUpdated?.Invoke(); LateUpdated?.Invoke();
LastUpdated?.Invoke();
} }
public static int UpdateLength private void OnApplicationQuit()
{ {
get Updated = null;
{ LateUpdated = null;
var list = Updated?.GetInvocationList(); EarlyUpdated = null;
return list?.Length ?? 0; LastUpdated = null;
}
} }
public static int FixedUpdateLength public static Delegate[] EarlyUpdateDelegates => EarlyUpdated?.GetInvocationList();
{
get
{
var list = FixedUpdated?.GetInvocationList();
return list?.Length ?? 0;
}
}
public static int LateUpdateLength public static int EarlyUpdateLength => EarlyUpdateDelegates?.Length ?? 0;
{
get public static Delegate[] UpdateDelegates => Updated?.GetInvocationList();
{
var list = LateUpdated?.GetInvocationList(); public static int UpdateLength => UpdateDelegates?.Length ?? 0;
return list?.Length ?? 0;
} public static Delegate[] LateUpdateDelegates => LateUpdated?.GetInvocationList();
}
public static int LateUpdateLength => LateUpdateDelegates?.Length ?? 0;
public static Delegate[] LastUpdateDelegates => LastUpdated?.GetInvocationList();
public static int LastUpdateLength => LastUpdateDelegates?.Length ?? 0;
} }
} }

View File

@ -0,0 +1,26 @@
using System;
using UnityEngine;
namespace Utils
{
public class PhysicsEventManager : MonoBehaviour
{
public delegate void FixedUpdateAction();
public static event FixedUpdateAction FixedUpdated;
private void FixedUpdate()
{
FixedUpdated?.Invoke();
}
private void OnApplicationQuit()
{
FixedUpdated = null;
}
public static Delegate[] FixedUpdateDelegates => FixedUpdated?.GetInvocationList();
public static int FixedUpdateLength => FixedUpdateDelegates?.Length ?? 0;
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c65e51916058437493fa66f8382a06c6
timeCreated: 1713872175

View File

@ -1,110 +0,0 @@
#if COM_UNITY_MODULES_PHYSICS
using System.Diagnostics;
using UnityEngine;
namespace Utils
{
public class ReflectionProbeVolume : MonoBehaviour
{
[Min(1)]
public int resolution = 4;
public float offset = 2;
public float blendDistance = 1;
[Min(0)]
public float threshold = .5f;
[Conditional("UNITY_EDITOR")]
private void OnDrawGizmosSelected()
{
Gizmos.DrawWireCube(transform.position, transform.localScale);
var startPos = transform.position + transform.right * transform.localScale.x / 2 + transform.up * transform.localScale.y / 2 + transform.forward * transform.localScale.z / 2;
var xVar = transform.localScale.x / resolution / 2f;
var zVar = transform.localScale.z / resolution / 2f;
var data = new Vector3[resolution, resolution];
Gizmos.color = Color.blue;
for (int x = 0; x < resolution; x++)
{
for (int z = 0; z < resolution; z++)
{
var rayPos = startPos - transform.right * xVar - transform.forward * zVar;
if (Physics.Raycast(rayPos, Vector2.down, out RaycastHit hit))
{
var point = hit.point + Vector3.up * offset;
data[x, z] = point;
}
zVar += transform.localScale.z / resolution;
}
xVar += transform.localScale.x / resolution;
zVar = transform.localScale.z / resolution / 2f;
}
CheckSquare(data, 5);
CheckSquare(data, 4);
CheckSquare(data, 3);
CheckSquare(data, 2);
for (int x = 0; x < resolution; x++)
{
for (int z = 0; z < resolution; z++)
{
if (data[x, z] != Vector3.positiveInfinity)
{
Gizmos.DrawSphere(data[x, z], .1f);
}
}
}
}
private void CheckSquare(Vector3[,] data, int size)
{
for (int x = 0; x < resolution; x++)
{
for (int z = 0; z < resolution; z++)
{
if (x + size <= resolution && z + size <= resolution)
{
bool valid = true;
var point = Vector3.zero;
for (int i = 0; i < size; i++)
{
for (int k = 0; k < size; k++)
{
var pos = data[x + i, z + k];
if (pos != Vector3.positiveInfinity)
{
if (Compare(data[x, z].y, pos.y))
{
point += pos;
}
else
{
valid = false;
}
}
}
}
if (valid)
{
point /= size * size;
Gizmos.DrawSphere(point, size * .1f);
for (int i = 0; i < size; i++)
{
for (int k = 0; k < size; k++)
{
data[x + i, z + k] = Vector3.positiveInfinity;
}
}
}
}
}
}
}
private bool Compare(float arg0, float arg1)
{
return Mathf.Abs(arg0 - arg1) < threshold;
}
}
}
#endif

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: a740d05cae346654fbd4dc576e6405ab
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -2,35 +2,27 @@ using UnityEngine;
namespace Utils namespace Utils
{ {
/// <summary>
/// https://garry.tv/timesince
/// </summary>
/// <example>
/// Do something after 10 seconds.
/// <code>
/// TimeSince ts;
/// void Start() => ts = 0;
/// void Update()
/// {
/// if (ts > 10)
/// Something();
/// }
/// </code>
/// </example>
public struct TimeSince public struct TimeSince
{ {
private float time; private float time;
public static implicit operator float(TimeSince ts) public static implicit operator float(TimeSince ts) => Time.time - ts.time;
{
return Time.time - ts.time;
}
public static implicit operator TimeSince(float ts) public static implicit operator TimeSince(float ts) => new() { time = Time.time - ts };
{
return new TimeSince { time = Time.time - ts };
} }
} }
}
// https://garry.tv/timesince
//TimeSince ts;
//void Start()
//{
// ts = 0;
//}
//void Update()
//{
// if (ts > 10)
// {
// DoSomethingAfterTenSeconds();
// }
//}

View File

@ -1,11 +1,12 @@
{ {
"name": "ru.shazbot.utils", "name": "ru.shazbot.utils",
"version": "4.1.0", "version": "6.1.1",
"displayName": "Utils", "displayName": "Utils",
"description": "Utility useful for almost any project.", "description": "Utility useful for almost any project.",
"licensesUrl": "https://git.shazbot.ru/Utils.git/tree/LICENSE.md", "licensesUrl": "https://git.shazbot.ru/shazbot/Utils/src/LICENSE.md",
"keywords": [ "keywords": [
"utility" "utility",
"utils"
], ],
"author": { "author": {
"name": "Alexander Filippov", "name": "Alexander Filippov",