174 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			174 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
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<TypeTreeNode> 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<TypeTreeNode> 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<Type, TypeTreeNode> CUITypeTree = new();
 | 
						|
 | 
						|
    public static Dictionary<string, Type> CUILayoutTypes = new();
 | 
						|
    public static Dictionary<string, Type> CUITypes = new Dictionary<string, Type>();
 | 
						|
 | 
						|
    public static void FormCUITypeTree()
 | 
						|
    {
 | 
						|
      List<TypePair> Pustoe = CUITypes.Values.Select(t => new TypePair(t, t.BaseType)).ToList();
 | 
						|
      List<TypePair> Porojnee = new List<TypePair>();
 | 
						|
 | 
						|
      while (Pustoe.Count > 0)
 | 
						|
      {
 | 
						|
        Porojnee = new List<TypePair>();
 | 
						|
        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;
 | 
						|
    }
 | 
						|
  }
 | 
						|
} |