using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Diagnostics; using System.Runtime.CompilerServices; using System.IO; using Barotrauma; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Graphics; using HarmonyLib; using System.Xml; using System.Xml.Linq; namespace QICrabUI { public class TypeTreeNode { public Type T; public TypeTreeNode Parent; public List Children = new(); public CUITypeMetaData Meta => CUITypeMetaData.Get(T); public void Add(TypeTreeNode child) { child.Parent = this; Children.Add(child); } public TypeTreeNode(Type t) => T = t; public override string ToString() => T?.ToString() ?? "null"; public void RunRecursive(Action action) { action(this); foreach (TypeTreeNode child in Children) { child.RunRecursive(action); } } } [CUIInternal] public class CUIReflection { internal static void InitStatic() { CUI.OnInit += () => { Stopwatch sw = Stopwatch.StartNew(); FindCUITypes(); FormCUITypeTree(); CUIDebug.Log($"CUIReflection.Initialize took {sw.ElapsedMilliseconds}ms"); }; CUI.OnDispose += () => { CUITypes.Clear(); CUILayoutTypes.Clear(); CUITypeTree.Clear(); }; } public record TypePair(Type type, Type baseType); public static Dictionary CUITypeTree = new(); public static Dictionary CUILayoutTypes = new(); public static Dictionary CUITypes = new Dictionary(); public static void FormCUITypeTree() { List Pustoe = CUITypes.Values.Select(t => new TypePair(t, t.BaseType)).ToList(); List Porojnee = new List(); while (Pustoe.Count > 0) { Porojnee = new List(); foreach (TypePair pair in Pustoe) { // Tree root CUIComponent if (pair.baseType == typeof(object)) { CUITypeTree[pair.type] = new TypeTreeNode(pair.type); continue; } // Derived class if (CUITypeTree.ContainsKey(pair.baseType)) { CUITypeTree[pair.type] = new TypeTreeNode(pair.type); CUITypeTree[pair.baseType].Add(CUITypeTree[pair.type]); continue; } // Base class not in tree yet Porojnee.Add(pair); } Pustoe.Clear(); Pustoe = Porojnee; } //foreach (TypeTreeNode node in CUITypeTree.Values) CUI.Log(node); } public static void FindCUITypes() { Assembly CUIAssembly = Assembly.GetAssembly(typeof(CUI)); Assembly CallingAssembly = Assembly.GetCallingAssembly(); CUITypes["CUIComponent"] = typeof(CUIComponent); CUILayoutTypes["CUILayout"] = typeof(CUILayout); //TODO Nested types might have same name, think how to separate them // lua and style resolver uses them // string name = t.Name; // if (t.DeclaringType != null) name = $"{t.DeclaringType.Name}.{t.Name}"; // CUITypes[name] = t; foreach (Type t in CallingAssembly.GetTypes()) { if (t.IsSubclassOf(typeof(CUIComponent))) CUITypes[t.Name] = t; if (t.IsSubclassOf(typeof(CUILayout))) CUILayoutTypes[t.Name] = t; } foreach (Type t in CUIAssembly.GetTypes()) { if (t.IsSubclassOf(typeof(CUIComponent))) CUITypes[t.Name] = t; if (t.IsSubclassOf(typeof(CUILayout))) CUILayoutTypes[t.Name] = t; } } public static Type GetComponentTypeByName(string name) { return CUITypes.GetValueOrDefault(name); } public static object GetDefault(object obj) { FieldInfo defField = obj.GetType().GetField("Default", BindingFlags.Static | BindingFlags.Public); if (defField == null) return null; return defField.GetValue(null); } public static object GetNestedValue(object obj, string nestedName) { string[] names = nestedName.Split('.'); foreach (string name in names) { FieldInfo fi = obj.GetType().GetField(name, AccessTools.all); PropertyInfo pi = obj.GetType().GetProperty(name, AccessTools.all); if (fi != null) { obj = fi.GetValue(obj); continue; } if (pi != null) { obj = pi.GetValue(obj); continue; } return null; } return obj; } } }