Editor/Contracts/EditorRuntime.cs
#nullable enable
using System;
using System.Linq;
using System.Reflection;

namespace Editor.Mcp
{
	internal static class EditorRuntime
	{
		public static bool Trigger(string action)
		{
			var type = FindType("Editor.ActionManager");
			var method = type?.GetMethod("Trigger", BindingFlags.Public | BindingFlags.Static, binder: null, types: new[] { typeof(string) }, modifiers: null);
			if (method is null) return false;
			method.Invoke(null, new object[] { action }); return true;
		}

		public static (bool Available, bool IsPlaying) PlayMode(string action)
		{
			var utility = FindType("Editor.EditorUtility"); var property = utility?.GetProperty("PlayMode", BindingFlags.Public | BindingFlags.Static); var value = property?.GetValue(null); if (value is null) return (false, false);
			var type = value.GetType(); var isPlaying = type.GetProperty("IsPlaying", BindingFlags.Public | BindingFlags.Instance)?.GetValue(value) as bool? ?? false; var methodName = action == "start" ? "Start" : action == "stop" ? "Stop" : null; if (methodName is not null) type.GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance)?.Invoke(value, null); isPlaying = type.GetProperty("IsPlaying", BindingFlags.Public | BindingFlags.Instance)?.GetValue(value) as bool? ?? isPlaying; return (true, isPlaying);
		}

		public static object? GetComponentType(string name)
		{
			var library = FindType("Sandbox.Internal.TypeLibrary"); var editor = library?.GetProperty("Editor", BindingFlags.Public | BindingFlags.Static)?.GetValue(null); var method = editor?.GetType().GetMethod("GetType", new[] { typeof(string), typeof(bool) }); return method?.Invoke(editor, new object[] { name, false });
		}

		public static Type? FindType(string fullName) => AppDomain.CurrentDomain.GetAssemblies().Select(a => a.GetType(fullName, false)).FirstOrDefault(t => t is not null);

		public static object? InvokeStatic(string fullTypeName, string methodName, params object?[] arguments)
		{
			var type = FindType(fullTypeName);
			if (type is null) return null;
			var method = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)
				.FirstOrDefault(candidate => candidate.Name == methodName && candidate.GetParameters().Length == arguments.Length);
			return method?.Invoke(null, arguments);
		}

		public static bool InvokeStaticAction(string fullTypeName, string methodName, params object?[] arguments)
		{
			var type = FindType(fullTypeName);
			if (type is null) return false;
			var method = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)
				.FirstOrDefault(candidate => candidate.Name == methodName && candidate.GetParameters().Length == arguments.Length);
			if (method is null) return false;
			method.Invoke(null, arguments);
			return true;
		}

		public static object? GetStaticProperty(string fullTypeName, string propertyName)
		{
			var type = FindType(fullTypeName);
			return type?.GetProperty(propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)?.GetValue(null);
		}

		public static object? GetStaticField(string fullTypeName, string fieldName)
		{
			var type = FindType(fullTypeName);
			return type?.GetField(fieldName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)?.GetValue(null);
		}

		public static object? GetMember(object? target, string memberName)
		{
			if (target is null) return null;
			var type = target.GetType();
			return type.GetProperty(memberName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase)?.GetValue(target)
				?? type.GetField(memberName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase)?.GetValue(target);
		}

		public static bool SetMember(object? target, string memberName, object? value)
		{
			if (target is null) return false;
			var type = target.GetType();
			var property = type.GetProperty(memberName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase);
			if (property?.SetMethod is not null)
			{
				property.SetValue(target, value);
				return true;
			}
			var field = type.GetField(memberName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase);
			if (field is null || field.IsInitOnly) return false;
			field.SetValue(target, value);
			return true;
		}

		public static object? InvokeInstance(object? target, string methodName, params object?[] arguments)
		{
			if (target is null) return null;
			var method = target.GetType().GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
				.FirstOrDefault(candidate => candidate.Name == methodName && candidate.GetParameters().Length == arguments.Length);
			return method?.Invoke(target, arguments);
		}
	}
}