Skip to content

Instantly share code, notes, and snippets.

@forestrf
Created July 14, 2023 20:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save forestrf/d5d9eb583d17c4922db2ef1bc5fbf0a7 to your computer and use it in GitHub Desktop.
Save forestrf/d5d9eb583d17c4922db2ef1bc5fbf0a7 to your computer and use it in GitHub Desktop.
List thread-safe Unity API to the console. Read more at https://www.jacksondunstan.com/articles/5029
// https://www.jacksondunstan.com/articles/5029
// Fix by AshKatchap to support Windows
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using UnityEngine;
using UnityEditor;
public static class JobSafeMenuItem {
[MenuItem("Help/List Job Safe APIs")]
private static void JobSafe() {
#if UNITY_EDITOR_OSX
string managedDirPath = Path.Combine(
Path.Combine(
EditorApplication.applicationPath,
"Contents"),
"Managed");
#elif UNITY_EDITOR_WIN
string managedDirPath = Path.Combine(EditorApplication.applicationContentsPath, "Managed");
#else
string managedDirPath = Path.Combine(EditorApplication.applicationContentsPath, "Managed");
throw new Exception("Only macOS is supported at this time");
#endif
Type nativeMethodAttribute = Assembly.LoadFile(
Path.Combine(
Path.Combine(
managedDirPath,
"UnityEngine"),
"UnityEngine.SharedInternalsModule.dll"))
.GetType("UnityEngine.Bindings.NativeMethodAttribute");
string[] paths = Directory.GetFiles(
managedDirPath,
"*.dll",
SearchOption.AllDirectories);
var methodsByType = new Dictionary<Type, List<string>>(512);
object[] emptyParameters = { };
void AddIfThreadSafe(Type type, Attribute attribute, string method) {
if (nativeMethodAttribute.IsInstanceOfType(attribute)
&& (bool) nativeMethodAttribute
.GetProperty("IsThreadSafe")
.GetGetMethod()
.Invoke(attribute, emptyParameters)) {
List<string> list;
if (!methodsByType.TryGetValue(type, out list)) {
list = new List<string>(32);
methodsByType[type] = list;
}
list.Add(method);
}
}
BindingFlags allFlags =
BindingFlags.NonPublic
| BindingFlags.Static
| BindingFlags.Instance;
foreach (var path in paths) {
Assembly assembly = Assembly.LoadFile(path);
foreach (Type type in assembly.GetTypes()) {
foreach (MethodInfo meth in type.GetMethods(allFlags)) {
foreach (Attribute attribute in meth.GetCustomAttributes()) {
AddIfThreadSafe(type, attribute, meth.ToString());
}
}
foreach (PropertyInfo prop in type.GetProperties(allFlags)) {
foreach (Attribute attribute in prop.GetCustomAttributes()) {
AddIfThreadSafe(type, attribute, prop.ToString());
}
}
}
}
StringBuilder builder = new StringBuilder(1024 * 10);
var sortedMethodsByType = new List<KeyValuePair<Type, List<string>>>(
methodsByType);
sortedMethodsByType.Sort((a, b) => a.Key.Name.CompareTo(b.Key.Name));
foreach (var pair in sortedMethodsByType) {
pair.Value.Sort();
foreach (string method in pair.Value) {
builder.Append(pair.Key.Name);
builder.Append(": ");
builder.AppendLine(method);
}
}
Debug.Log(builder.ToString());
EditorGUIUtility.systemCopyBuffer = builder.ToString();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment