public static T[] GetFields <T>(this object instance) { var declaredFields = AccessTools.GetDeclaredFields(instance.GetType())?.Where(t => t.FieldType == typeof(T)); return(declaredFields?.Select(val => instance.GetField <T>(val.Name)).ToArray()); }
public static void FindSettingsDependentFields() { #if DEBUG Log.Message("Finding settings dependant fields"); #endif var traverses = new List <Traverse>(); var markedTypes = GenTypes.AllTypesWithAttribute <NVHasSettingsDependentFieldAttribute>(); foreach (var type in markedTypes) { var fields = AccessTools.GetDeclaredFields(type) .FindAll(fi => fi.HasAttribute <NVSettingsDependentFieldAttribute>()); #if DEBUG Log.Message($"Type: {type}"); #endif foreach (var info in fields) { var traverse = new Traverse(type); traverse = traverse.Field(info.Name); #if DEBUG Log.Message($"Field: {info.Name}"); #endif traverses.Add(traverse); } } SettingsDependentFieldTraverses = traverses; }
public static IEnumerable <CodeInstruction> Transpiler(IEnumerable <CodeInstruction> instructions, MethodBase method) { //Replace MethodInfo IsForbiddenInfo = AccessTools.Method(typeof(ForbidUtility), "IsForbidden", new Type[] { typeof(Thing), typeof(Pawn) }); //With MethodInfo IsForbiddenByTypeInfo = AccessTools.Method(typeof(DoNotHarvest_Building), "IsForbiddenByType"); //Call with WorkGiver_Grower, which is this.$this since it's compiler generated iterator //.field assembly class RimWorld.WorkGiver_Grower $this FieldInfo ThisThis = AccessTools.GetDeclaredFields(method.DeclaringType).First(f => f.FieldType == typeof(WorkGiver_Grower)); foreach (var i in instructions) { if (i.Calls(IsForbiddenInfo)) { yield return(new CodeInstruction(OpCodes.Ldarg_0)); //this, yield return business yield return(new CodeInstruction(OpCodes.Ldfld, ThisThis)); // WorkGiver_Grower this.$this yield return(new CodeInstruction(OpCodes.Call, IsForbiddenByTypeInfo)); } else { yield return(i); } } }
public static bool CanHandle(SyncType syncType) { var type = syncType.type; if (type == typeof(object)) { return(true); } if (type.IsByRef) { return(true); } if (SyncDictFast.syncWorkers.TryGetValue(type, out _)) { return(true); } if (syncType.expose) { return(typeof(IExposable).IsAssignableFrom(type)); } if (typeof(ISynchronizable).IsAssignableFrom(type)) { return(true); } if (type.IsEnum) { return(CanHandle(Enum.GetUnderlyingType(type))); } if (type.IsArray) { return(type.GetArrayRank() == 1 && CanHandle(type.GetElementType())); } if (type.IsGenericType && type.GetGenericTypeDefinition() is { } gtd) { return ((false || gtd == typeof(List <>) || gtd == typeof(IEnumerable <>) || gtd == typeof(Nullable <>) || gtd == typeof(Dictionary <,>) || gtd == typeof(Pair <,>) || typeof(ITuple).IsAssignableFrom(gtd)) && CanHandleGenericArgs(type)); } if (typeof(ISyncSimple).IsAssignableFrom(type)) { return(AccessTools.GetDeclaredFields(type).All(f => CanHandle(f.FieldType))); } if (typeof(Def).IsAssignableFrom(type)) { return(true); } if (typeof(Designator).IsAssignableFrom(type)) { return(true); } return(SyncDict.syncWorkers.TryGetValue(type, out _)); }
public static T[] GetFields <T>(this object instance) { List <T> fields = new List <T>(); var declaredFields = AccessTools.GetDeclaredFields(instance.GetType())?.Where((t) => t.FieldType == typeof(T)); foreach (var val in declaredFields) { fields.Add(instance.GetField <T>(val.Name)); } return(fields.ToArray()); }
internal static void Initialize() { foreach (var field in AccessTools.GetDeclaredFields(typeof(OS)).Where(x => x.FieldType == typeof(Color))) { var dynMethod = new DynamicMethodDefinition(field.Name, typeof(Color).MakeByRefType(), new Type[] { typeof(OS) }); var p = dynMethod.GetILProcessor(); p.Emit(OpCodes.Ldarg_0); p.Emit(OpCodes.Ldflda, field); p.Emit(OpCodes.Ret); OSColorFieldsFast.Add(field.Name, dynMethod.Generate().CreateDelegate <RefColorFieldDelegate>()); } }
public static To ShallowCopy <From, To>(From from, To to) where To : From { foreach (var f in AccessTools.GetDeclaredFields(typeof(From))) { if (!f.IsStatic) { f.SetValue(to, f.GetValue(from)); } } return(to); }
internal static MethodBase TargetMethod() { Type nestedTypeResult = null; const string targetMethod = "<MakeRecipeProducts>"; foreach (var nestedType in typeof(GenRecipe).GetNestedTypes(AccessTools.all)) { if (!nestedType.Name.Contains(targetMethod)) { continue; } nestedTypeResult = nestedType; } if (nestedTypeResult == null) { throw new Exception($"Could not find {targetMethod} Iterator Class"); } if (ingredientsCompField == null) { var fields = AccessTools.GetDeclaredFields(nestedTypeResult); foreach (var i in fields) { if (i.FieldType == typeof(CompIngredients)) { if (ingredientsCompField == null) { ingredientsCompField = i; } else { throw new Exception("Multiple CompIngredients fields found"); } } } } if (ingredientsCompField == null) { throw new Exception($"Could not find (CompIngredients) in {nestedTypeResult.FullName}.DeclaredFields"); } var result = AccessTools.Method(nestedTypeResult, "MoveNext"); if (result == null) { throw new Exception($"Could not find MoveNext in {nestedTypeResult.FullName}"); } return(result); }
static MethodBase TargetMethod() { index = DeserializeOrDefault <Dictionary <string, string> >("localeIndex.json"); locale = DeserializeOrDefault <Dictionary <string, string> >(InjectorService.LocaleFile); // Taken from de4dot MethodInfo method = null; foreach (var type in ReflectionHelper.MainModule.GetTypes()) { var fields = AccessTools.GetDeclaredFields(type); var methods = AccessTools.GetDeclaredMethods(type); if (type.IsPublic) { continue; } if (fields.Count != 1) { continue; } if (!fields.Any(field => field.FieldType == typeof(byte[]))) { continue; } if (methods.Count != 1 && methods.Count != 2) { continue; } if (type.GetNestedTypes(AccessTools.all).Length > 0) { continue; } foreach (var m in methods) { var parameters = m.GetParameters(); if (m.ReturnType == typeof(string) && parameters.FirstOrDefault()?.ParameterType == typeof(int)) { method = m; continue; } break; } if (method != null) { break; } } return(method); }
public static bool Initialize(Type jd, Type nType = null) { jobDriver = jd; field = null; propGetMethod = null; if (nType != null) { List <FieldInfo> fields = AccessTools.GetDeclaredFields(nType); field = fields.FirstOrDefault(t => t.FieldType == jobDriver); if (field == null) { return(false); } } propGetMethod = AccessTools.PropertyGetter(jobDriver, "Plant"); if (propGetMethod == null) { return(false); } return(true); }
public void PrintData() { Console.WriteLine(new string('=', 40)); if (charaParamData.saved) { Console.WriteLine(nameof(CharaData)); foreach (var field in AccessTools.GetDeclaredFields(typeof(CharaData))) { var target = AccessTools.Field(typeof(CharaData), field.Name); var value = target.GetValue(charaParamData); Console.WriteLine($"{field.Name} = {value}"); } } else { Console.WriteLine($"{nameof(CharaData)} not saved"); } Console.WriteLine(new string('=', 40)); if (sceneParamData.saved) { Console.WriteLine(nameof(SceneData)); foreach (var field in AccessTools.GetDeclaredFields(typeof(SceneData))) { var target = AccessTools.Field(typeof(SceneData), field.Name); var value = target.GetValue(sceneParamData); Console.WriteLine($"{field.Name} = {value}"); } } else { Console.WriteLine($"{nameof(SceneData)} not saved"); } Console.WriteLine(new string('=', 40)); }
static void ClearAssemblyResolve() { var asmResolve = AccessTools.Field(typeof(AppDomain), "AssemblyResolve"); var del = (Delegate)asmResolve.GetValue(AppDomain.CurrentDomain); // Handle MonoMod's internal dynamic assemblies foreach (var d in del.GetInvocationList().ToList()) { if (d.Method.DeclaringType.Namespace.StartsWith("MonoMod.Utils")) { foreach (var f in AccessTools.GetDeclaredFields(d.Method.DeclaringType)) { if (f.FieldType == typeof(Assembly)) { var da = (Assembly)f.GetValue(d.Target); SetReflectionOnly(da, true); } } } } asmResolve.SetValue(AppDomain.CurrentDomain, null); }
public static void WriteSyncObject(ByteWriter data, object obj, SyncType syncType) { MpContext context = data.MpContext(); Type type = syncType.type; var log = (data as LoggingByteWriter)?.Log; log?.Enter($"{type.FullName}: {obj ?? "null"}"); if (obj != null && !type.IsAssignableFrom(obj.GetType())) { throw new SerializationException($"Serializing with type {type} but got object of type {obj.GetType()}"); } try { if (typeof(object) == type) { return; } if (type.IsByRef) { return; } if (SyncDictFast.syncWorkers.TryGetValue(type, out var syncWorkerEntryEarly)) { syncWorkerEntryEarly.Invoke(new WritingSyncWorker(data), ref obj); return; } if (syncType.expose) { if (!typeof(IExposable).IsAssignableFrom(type)) { throw new SerializationException($"Type {type} can't be exposed because it isn't IExposable"); } IExposable exposable = obj as IExposable; byte[] xmlData = ScribeUtil.WriteExposable(exposable); LogXML(log, xmlData); data.WritePrefixedBytes(xmlData); return; } if (typeof(ISynchronizable).IsAssignableFrom(type)) { ((ISynchronizable)obj).Sync(new WritingSyncWorker(data)); return; } if (type.IsEnum) { Type enumType = Enum.GetUnderlyingType(type); WriteSyncObject(data, Convert.ChangeType(obj, enumType), enumType); return; } if (type.IsArray) { if (type.GetArrayRank() != 1) { throw new SerializationException("Multi dimensional arrays aren't supported."); } Type elementType = type.GetElementType(); Array arr = (Array)obj; if (arr == null) { data.WriteUShort(ushort.MaxValue); return; } if (arr.Length >= ushort.MaxValue) { throw new SerializationException($"Tried to serialize a {elementType}[] with too many ({arr.Length}) items."); } data.WriteUShort((ushort)arr.Length); foreach (object e in arr) { WriteSyncObject(data, e, elementType); } return; } if (type.IsGenericType) { Type genericTypeDefinition = type.GetGenericTypeDefinition(); if (genericTypeDefinition == typeof(List <>)) { IList list = (IList)obj; Type listObjType = type.GetGenericArguments()[0]; if (list == null) { data.WriteUShort(ushort.MaxValue); return; } if (list.Count >= ushort.MaxValue) { throw new SerializationException($"Tried to serialize a {type} with too many ({list.Count}) items."); } data.WriteUShort((ushort)list.Count); foreach (object e in list) { WriteSyncObject(data, e, listObjType); } return; } if (genericTypeDefinition == typeof(IEnumerable <>)) { IEnumerable e = (IEnumerable)obj; Type elementType = type.GetGenericArguments()[0]; var listType = typeof(List <>).MakeGenericType(elementType); if (e == null) { WriteSyncObject(data, null, listType); return; } IList list = (IList)Activator.CreateInstance(listType); foreach (var o in e) { list.Add(o); } WriteSyncObject(data, list, listType); return; } if (genericTypeDefinition == typeof(Nullable <>)) { bool isNull = obj == null; data.WriteBool(isNull); if (isNull) { return; } WriteSyncObject(data, obj, Nullable.GetUnderlyingType(type)); return; } if (genericTypeDefinition == typeof(Dictionary <,>)) { IDictionary dictionary = (IDictionary)obj; Type[] arguments = type.GetGenericArguments(); if (dictionary == null) { WriteSyncObject(data, null, arguments[0].MakeArrayType()); return; } Array keyArray = Array.CreateInstance(arguments[0], dictionary.Count); dictionary.Keys.CopyTo(keyArray, 0); Array valueArray = Array.CreateInstance(arguments[1], dictionary.Count); dictionary.Values.CopyTo(valueArray, 0); WriteSyncObject(data, keyArray, keyArray.GetType()); WriteSyncObject(data, valueArray, valueArray.GetType()); return; } if (genericTypeDefinition == typeof(Pair <,>)) { Type[] arguments = type.GetGenericArguments(); WriteSyncObject(data, AccessTools.DeclaredField(type, "first").GetValue(obj), arguments[0]); WriteSyncObject(data, AccessTools.DeclaredField(type, "second").GetValue(obj), arguments[1]); return; } if (typeof(ITuple).IsAssignableFrom(genericTypeDefinition)) // ValueTuple or Tuple { Type[] arguments = type.GetGenericArguments(); ITuple tuple = (ITuple)obj; data.WriteInt32(tuple.Length); for (int i = 0; i < tuple.Length; i++) { WriteSyncObject(data, tuple[i], arguments[i]); } return; } } if (typeof(ISyncSimple).IsAssignableFrom(type)) { foreach (var field in AccessTools.GetDeclaredFields(type)) { WriteSyncObject(data, field.GetValue(obj), field.FieldType); } return; } // Special case if (typeof(Def).IsAssignableFrom(type)) { if (obj is not Def def) { data.WriteUShort(ushort.MaxValue); return; } var defTypeIndex = Array.IndexOf(DefSerialization.DefTypes, def.GetType()); if (defTypeIndex == -1) { throw new SerializationException($"Unknown def type {def.GetType()}"); } data.WriteUShort((ushort)defTypeIndex); data.WriteUShort(def.shortHash); return; } // Special case for Designators to change the type if (typeof(Designator).IsAssignableFrom(type)) { data.WriteUShort((ushort)Array.IndexOf(ImplSerialization.designatorTypes, obj.GetType())); } // Where the magic happens if (SyncDict.syncWorkers.TryGetValue(type, out var syncWorkerEntry)) { syncWorkerEntry.Invoke(new WritingSyncWorker(data), ref obj); return; } log?.Node("No writer for " + type); throw new SerializationException("No writer for type " + type); } catch { Log.Error($"Multiplayer: Error writing type: {type}, obj: {obj}, obj type: {obj?.GetType()}"); throw; } finally { log?.Exit(); } }
private static object ReadSyncObjectInternal(ByteReader data, SyncType syncType) { Type type = syncType.type; try { if (typeof(object) == type) { return(null); } if (type.IsByRef) { return(null); } if (SyncDictFast.syncWorkers.TryGetValue(type, out SyncWorkerEntry syncWorkerEntryEarly)) { object res = null; if (syncWorkerEntryEarly.shouldConstruct || type.IsValueType) { res = Activator.CreateInstance(type); } syncWorkerEntryEarly.Invoke(new ReadingSyncWorker(data), ref res); return(res); } if (syncType.expose) { if (!typeof(IExposable).IsAssignableFrom(type)) { throw new SerializationException($"Type {type} can't be exposed because it isn't IExposable"); } byte[] exposableData = data.ReadPrefixedBytes(); return(ExposableSerialization.ReadExposable(type, exposableData)); } if (typeof(ISynchronizable).IsAssignableFrom(type)) { var obj = Activator.CreateInstance(type); ((ISynchronizable)obj).Sync(new ReadingSyncWorker(data)); return(obj); } if (type.IsEnum) { Type underlyingType = Enum.GetUnderlyingType(type); return(Enum.ToObject(type, ReadSyncObject(data, underlyingType))); } if (type.IsArray) { if (type.GetArrayRank() != 1) { throw new SerializationException("Multi dimensional arrays aren't supported."); } ushort length = data.ReadUShort(); if (length == ushort.MaxValue) { return(null); } Type elementType = type.GetElementType(); Array arr = Array.CreateInstance(elementType, length); for (int i = 0; i < length; i++) { arr.SetValue(ReadSyncObject(data, elementType), i); } return(arr); } if (type.IsGenericType) { var genericTypeDefinition = type.GetGenericTypeDefinition(); if (genericTypeDefinition == typeof(List <>)) { ushort size = data.ReadUShort(); if (size == ushort.MaxValue) { return(null); } Type listObjType = type.GetGenericArguments()[0]; IList list = (IList)Activator.CreateInstance(type, size); for (int j = 0; j < size; j++) { list.Add(ReadSyncObject(data, listObjType)); } return(list); } if (genericTypeDefinition == typeof(IEnumerable <>)) { Type element = type.GetGenericArguments()[0]; return(ReadSyncObject(data, typeof(List <>).MakeGenericType(element))); } if (genericTypeDefinition == typeof(Nullable <>)) { bool isNull = data.ReadBool(); if (isNull) { return(null); } return(Activator.CreateInstance(type, ReadSyncObject(data, Nullable.GetUnderlyingType(type)))); } if (genericTypeDefinition == typeof(Dictionary <,>)) { Type[] arguments = type.GetGenericArguments(); Array keys = (Array)ReadSyncObject(data, arguments[0].MakeArrayType()); if (keys == null) { return(null); } Array values = (Array)ReadSyncObject(data, arguments[1].MakeArrayType()); IDictionary dictionary = (IDictionary)Activator.CreateInstance(type); for (int i = 0; i < keys.Length; i++) { var key = keys.GetValue(i); if (key != null) { dictionary.Add(key, values.GetValue(i)); } } return(dictionary); } if (genericTypeDefinition == typeof(Pair <,>)) { Type[] arguments = type.GetGenericArguments(); object[] parameters = { ReadSyncObject(data, arguments[0]), ReadSyncObject(data, arguments[1]), }; return(type.GetConstructors().First().Invoke(parameters)); } if (typeof(ITuple).IsAssignableFrom(genericTypeDefinition)) // ValueTuple or Tuple { Type[] arguments = type.GetGenericArguments(); int size = data.ReadInt32(); object[] values = new object[size]; for (int i = 0; i < size; i++) { values[i] = ReadSyncObject(data, arguments[i]); } return(type.GetConstructors().First().Invoke(values)); } } if (typeof(ISyncSimple).IsAssignableFrom(type)) { var obj = MpUtil.NewObjectNoCtor(type); foreach (var field in AccessTools.GetDeclaredFields(type)) { field.SetValue(obj, ReadSyncObject(data, field.FieldType)); } return(obj); } // Def is a special case until the workers can read their own type if (typeof(Def).IsAssignableFrom(type)) { ushort defTypeIndex = data.ReadUShort(); if (defTypeIndex == ushort.MaxValue) { return(null); } ushort shortHash = data.ReadUShort(); var defType = DefSerialization.DefTypes[defTypeIndex]; var def = DefSerialization.GetDef(defType, shortHash); if (def == null) { throw new SerializationException($"Couldn't find {defType} with short hash {shortHash}"); } return(def); } // Designators can't be handled by SyncWorkers due to the type change if (typeof(Designator).IsAssignableFrom(type)) { ushort desId = ReadSync <ushort>(data); type = ImplSerialization.designatorTypes[desId]; // Replaces the type! } // Where the magic happens if (SyncDict.syncWorkers.TryGetValue(type, out var syncWorkerEntry)) { object res = null; if (syncWorkerEntry.shouldConstruct || type.IsValueType) { res = Activator.CreateInstance(type); } syncWorkerEntry.Invoke(new ReadingSyncWorker(data), ref res); return(res); } throw new SerializationException("No reader for type " + type); } catch { Log.Error($"Multiplayer: Error reading type: {type}"); throw; } }
public static object GetParameterValueByType(BehaviorNode node, Type type) { var fields = AccessTools.GetDeclaredFields(node.GetType()).Except(AccessTools.GetDeclaredFields(typeof(BehaviorNode))); return(fields.FirstOrDefault(field => field.FieldType == type)?.GetValue(node)); }
static List <NewFieldData> CollectFields(int inCrc, out int outCrc) { outCrc = inCrc; var fieldsToAdd = new List <NewFieldData>(); foreach (var mod in LoadedModManager.RunningModsListForReading) { var assets = DirectXmlLoader.XmlAssetsInModFolder(mod, PrepatchesFolder); foreach (var ass in assets) { if (ass.name != FieldsXmlFile) { continue; } foreach (var e in ass.xmlDoc["Fields"].OfType <XmlElement>()) { var parsed = ParseFieldData(e, out bool success); parsed.ownerMod = mod.Name; if (success) { fieldsToAdd.Add(parsed); } else { ErrorXML($"{mod.Name}: Error parsing {parsed}"); } } outCrc = Gen.HashCombineInt(outCrc, new CRC32().GetCrc32(new MemoryStream(Encoding.UTF8.GetBytes(ass.xmlDoc.InnerXml)))); } } foreach (var fieldsPerType in fieldsToAdd.Where(f => f.isEnum).GroupBy(f => f.targetType)) { var targetType = GenTypes.GetTypeInAnyAssembly(fieldsPerType.Key); var enumType = Enum.GetUnderlyingType(targetType); var max = Util.ToUInt64(enumType.GetField("MaxValue").GetRawConstantValue()); var taken = AccessTools.GetDeclaredFields(targetType).Where(f => f.IsLiteral).Select(f => Util.ToUInt64(f.GetRawConstantValue())).ToHashSet(); foreach (var f in fieldsPerType) { var free = Util.FindNotTaken(f.enumPreferred, max, taken); if (free == null) { ErrorXML($"{f.ownerMod}: Couldn't assign a value for {f}"); fieldsToAdd.Remove(f); continue; } f.defaultValue = Util.FromUInt64(free.Value, enumType); taken.Add(free.Value); } } foreach (var f in fieldsToAdd) { InfoXML($"{f.ownerMod}: Parsed {f}"); } return(fieldsToAdd); }
private static void AdjustMenu(IClickableMenu menu, Point delta, bool first = false) { if (first) { adjustedMenus.Clear(); adjustedComponents.Clear(); } if (menu is null || adjustedMenus.Contains(menu)) { return; } menu.xPositionOnScreen += delta.X; menu.yPositionOnScreen += delta.Y; var types = AccessTools.GetDeclaredFields(menu.GetType()); if (menu is ItemGrabMenu) { types.AddRange(AccessTools.GetDeclaredFields(typeof(MenuWithInventory))); } foreach (var f in types) { if (f.FieldType.IsSubclassOf(typeof(ClickableComponent)) || f.FieldType == typeof(ClickableComponent)) { AdjustComponent((ClickableComponent)f.GetValue(menu), delta); } else if (f.FieldType.IsSubclassOf(typeof(IClickableMenu)) || f.FieldType == typeof(IClickableMenu)) { AdjustMenu((IClickableMenu)f.GetValue(menu), delta); } else if (f.FieldType == typeof(InventoryMenu)) { AdjustMenu((IClickableMenu)f.GetValue(menu), delta); } else if (f.Name == "scrollBarRunner") { var c = (Rectangle)f.GetValue(menu); c = new Rectangle(c.X + delta.X, c.Y + delta.Y, c.Width, c.Height); f.SetValue(menu, c); } else if (f.FieldType == typeof(List <ClickableComponent>)) { var ol = (List <ClickableComponent>)f.GetValue(menu); if (ol is null) { continue; } foreach (var o in ol) { AdjustComponent(o, delta); } } else if (f.FieldType == typeof(List <IClickableMenu>)) { var ol = (List <IClickableMenu>)f.GetValue(menu); if (ol is null) { continue; } foreach (var o in ol) { AdjustMenu(o, delta); } } else if (f.FieldType == typeof(Dictionary <int, ClickableTextureComponent>)) { var ol = (Dictionary <int, ClickableTextureComponent>)f.GetValue(menu); if (ol is null) { continue; } foreach (var o in ol.Values) { AdjustComponent(o, delta); } } else if (f.FieldType == typeof(Dictionary <int, ClickableComponent>)) { var ol = (Dictionary <int, ClickableComponent>)f.GetValue(menu); if (ol is null) { continue; } foreach (var o in ol.Values) { AdjustComponent(o, delta); } } else if (f.FieldType == typeof(Dictionary <int, List <List <ClickableTextureComponent> > >)) { var ol = (Dictionary <int, List <List <ClickableTextureComponent> > >)f.GetValue(menu); if (ol is null) { continue; } foreach (var o in ol.Values) { foreach (var o2 in o) { foreach (var o3 in o2) { AdjustComponent(o3, delta); } } } } else if (f.FieldType == typeof(Dictionary <int, List <List <ClickableComponent> > >)) { var ol = (Dictionary <int, List <List <ClickableComponent> > >)f.GetValue(menu); if (ol is null) { continue; } foreach (var o in ol.Values) { foreach (var o2 in o) { foreach (var o3 in o2) { AdjustComponent(o3, delta); } } } } else if (f.FieldType == typeof(List <ClickableTextureComponent>)) { var ol = (List <ClickableTextureComponent>)f.GetValue(menu); if (ol is null) { continue; } foreach (var o in ol) { AdjustComponent(o, delta); } } } if (menu is GameMenu) { for (int i = 0; i < (menu as GameMenu).pages.Count; i++) { if (i != (menu as GameMenu).currentTab) { AdjustMenu((menu as GameMenu).pages[i], delta); } } } AdjustComponent(menu.upperRightCloseButton, delta); adjustedMenus.Add(menu); }