Skip to content

Instantly share code, notes, and snippets.

@thebne
thebne / LeanStackFrameMono.cs
Created December 15, 2023 22:46
Unity: Mono StackFrame with 0 allocations
private readonly struct FrameData : IEquatable<FrameData>
{
public readonly MethodBase method;
public readonly int lineNumber;
public readonly int columnNumber;
// mono internal
private static readonly MethodInfo get_frame_info_methodInfo
= typeof(StackFrame).GetMethod("get_frame_info", BindingFlags.Static | BindingFlags.NonPublic);
@thebne
thebne / FindAssetsByTypeAsync.cs
Last active August 28, 2023 11:59
UnityEditor - FindAssetsByTypeAsync and LoadAssetAsync (UniTask async wrapper, automatically finding localId)
public static class EditorUtils
{
public static async IAsyncEnumerable<T> FindAssetsByTypeAsync<T>() where T : UnityEngine.Object
{
var queue = ListPool<UniTask<T>.Awaiter>.Get();
try
{
foreach (string guid in guids)
{
string assetPath = AssetDatabase.GUIDToAssetPath(guid);
@thebne
thebne / GetSerializationRecursiveReferences.cs
Last active May 2, 2022 15:14
Find recursive references for Serializables to eliminate "Serialization depth limit 10 exceeded ... There may be an object composition cycle in one or more of your serialized classes." warning in Unity
// this helped me trace & eliminate a bug with this warning:
// Serialization depth limit 10 exceeded at '<Type>.<Field>'. There may be an object composition cycle in one or more of your serialized classes.
public static IEnumerable<FieldInfo> GetRecursiveReferences<T>()
{
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (var type in assembly.GetTypes())
{
if (!type.IsDefined(typeof(System.SerializableAttribute), true))
continue;
@thebne
thebne / UnityEditorRightClick.cs
Created March 19, 2022 17:28
Unity: detect arbitrary right click within custom editor
if (Event.current.button == 1
&& GUILayoutUtility.GetLastRect().Contains(Event.current.mousePosition)) {
if (Event.current.type == EventType.MouseUp) {
EditorGUI.DrawRect(GUILayoutUtility.GetLastRect(), new Color(1, 1, 1, 1f));
} else if (Event.current.type == EventType.MouseDown) {
Debug.Log($"Pressed on {propState}!");
}
}
@thebne
thebne / RegisterPropertyChangeCallback_BeforeUnity2020.cs
Created January 4, 2022 13:11
PropertyField.RegisterValueChangeCallback but before 2020
// see https://forum.unity.com/threads/uielements-developer-guide.648043/#post-6073137
void RegisterPropertyChangeCallback(PropertyField field, SerializedProperty property, FieldInfo fieldInfo, Action callback)
{
var propertyType = property.propertyType;
switch (propertyType)
{
case SerializedPropertyType.Integer:
case SerializedPropertyType.LayerMask:
case SerializedPropertyType.ArraySize:
field.RegisterCallback<ChangeEvent<int>>( (evt) => callback());
@thebne
thebne / color_hex_to_unity_color.py
Last active November 14, 2021 09:25
Convert HTML color (#ffff00 or rgb(...) or rgba(...)) to Unity new Color() format
def h2f(h):
h = h.lstrip('#')
return tuple(int(h[i:i+2], 16) / 255 for i in (0, 2, 4))
def r2f(r):
r = r.lstrip("rgb").lstrip("a").lstrip("(").rstrip(")").strip()
return [float(x.strip()) / (255 if i < 3 else 1) for i, x in enumerate(r.split(", "))]
def c2u(s):
f = r2f(s) if "rgb" in s else h2f(s)
@thebne
thebne / unity_rename_managed_reference.py
Created November 11, 2021 13:31
Rename Unity's managed reference (ones created by [SerializeReference] attribute)
import os
import sys
DEFAULT_ASSEMBLY = "Assembly-CSharp"
DEFAULT_NS = ""
def main():
if len(sys.argv) < 3:
print(f"Usage: {sys.argv[0]} <old assembly:?><old ns:?><old name> <new assembly:?><new ns:?><new name>")
print()
@thebne
thebne / UnityEditorGetObjectFromSerializedProperty.cs
Last active October 26, 2021 16:07
Get C# object (or Type) from SerializedProperty - useful for ObjectField type constraint
/// <see cref="https://github.com/lordofduct/spacepuppy-unity-framework/blob/master/SpacepuppyBaseEditor/EditorHelper.cs"/>
public static Type GetTargetTypeOfProperty(SerializedProperty prop)
{
if (prop == null) return null;
var path = prop.propertyPath.Replace(".Array.data[", "[");
path = path.Substring(0, path.LastIndexOf('.'));
object obj = prop.serializedObject.targetObject;
var elements = path.Split('.');
foreach (var element in elements)
@thebne
thebne / find_unused_references.py
Created July 7, 2021 17:33
Find unused Script references in Unity - using meta GUIDs + naïve Regular Expressions
import os, sys
import unityparser
import re
def get_files(folder_path):
return [x for f in os.walk(folder_path) for x in map(lambda x: f"{f[0]}{os.path.sep}{x}", f[2])]
scripts = {d.data[0]['guid']: d for d in [unityparser.UnityDocument.load_yaml(path) for path in get_files(os.path.join('Assets', 'Scripts')) if path.endswith(".meta")]}
assets_paths = [path for path in get_files('Assets') if path.endswith('.unity') or path.endswith('.prefab') or path.endswith('.asset')]
@thebne
thebne / UnityDebug.sh
Created March 14, 2021 13:49
Unity debug commands
# use USB to forward profiling on Android / Quest
adb forward tcp:54999 localabstract:Unity-{insert bundle identifier here}