From 63c4393562f246cce98c7f57e87d90a1337108d5 Mon Sep 17 00:00:00 2001 From: Lamont Granquist Date: Sun, 21 Jun 2026 12:24:30 -0700 Subject: [PATCH] Clean up some uses of reflection --- .../FuelFlowSimulation/SimVesselBuilder.cs | 78 ++++++------------- .../FuelFlowSimulation/SimVesselUpdater.cs | 41 ++++------ MechJebLibBindings/PartExtensions.cs | 34 ++++---- MechJebLibBindings/ReflectionUtils.cs | 6 -- 4 files changed, 55 insertions(+), 104 deletions(-) diff --git a/MechJebLibBindings/FuelFlowSimulation/SimVesselBuilder.cs b/MechJebLibBindings/FuelFlowSimulation/SimVesselBuilder.cs index 7918e6240..5a707b00c 100644 --- a/MechJebLibBindings/FuelFlowSimulation/SimVesselBuilder.cs +++ b/MechJebLibBindings/FuelFlowSimulation/SimVesselBuilder.cs @@ -3,15 +3,14 @@ * SPDX-License-Identifier: LicenseRef-PD-hp OR Unlicense OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT OR LGPL-2.1+ */ -using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.Reflection; using KSP.UI; using KSP.UI.Screens; using MechJebLib.FuelFlowSimulation; using MechJebLib.FuelFlowSimulation.PartModules; using UnityEngine; +using static MechJebLibBindings.ReflectionUtils; namespace MechJebLibBindings.FuelFlowSimulation { @@ -23,11 +22,15 @@ public class SimVesselBuilder private Dictionary _inversePartMapping => _manager._inversePartMapping; private Dictionary _inversePartModuleMapping => _manager._inversePartModuleMapping; - private static readonly FieldInfo? _rfSpoolUpTime; - private static readonly FieldInfo? _rfAutoCutoff; - private static readonly FieldInfo? _rfUllage; - private static readonly FieldInfo? _rp0ControllableMass; - private static readonly FieldInfo? _rp0MassLimit; + private static readonly ClassContext _rfModuleEnginesRf = Assembly("RealFuels").Class("RealFuels.ModuleEnginesRF"); + private static readonly FieldContext _rfSpoolUpTime = Assembly("RealFuels").Class("RealFuels.ModuleEnginesRF").Field("effectiveSpoolUpTime"); + private static readonly FieldContext _rfAutoCutoff = Assembly("RealFuels").Class("RealFuels.ModuleEnginesRF").Field("autoCutoff"); + private static readonly FieldContext _rfUllage = Assembly("RealFuels").Class("RealFuels.ModuleEnginesRF").Field("ullage"); + private static readonly FieldContext _rp0ControllableMass = Assembly("RP0").Class("RP0.ProceduralAvionics.ModuleProceduralAvionics").Field("controllableMass"); + private static readonly FieldContext _rp0MassLimit = Assembly("RP0").Class("RP0.ModuleAvionics").Field("massLimit"); + + private static readonly bool _isRealFuelsLoadedCorrectly; + private static readonly bool _isRP0LoadedCorrectly; private delegate double CrewMass(ProtoCrewMember crew); @@ -46,43 +49,14 @@ private IShipconstruct _kspVessel } private readonly SimVesselManager _manager; - private static readonly Type? _rfType; static SimVesselBuilder() { _crewMassDelegate = Versioning.version_major == 1 && Versioning.version_minor < 11 ? (CrewMass)CrewMassOld : CrewMassNew; - if (ReflectionUtils.IsLoadedRealFuels) - { - _rfSpoolUpTime = ReflectionUtils.GetFieldByReflection("RealFuels", "RealFuels.ModuleEnginesRF", "effectiveSpoolUpTime"); - if (_rfSpoolUpTime == null) - Debug.Log( - "MechJeb BUG: RealFuels loaded, but RealFuels.ModuleEnginesRF has no effectiveSpoolUpTime field, disabling spoolup."); - - _rfType = Type.GetType("RealFuels.ModuleEnginesRF, RealFuels"); - - _rfAutoCutoff = ReflectionUtils.GetFieldByReflection("RealFuels", "RealFuels.ModuleEnginesRF", "autoCutoff"); - if (_rfAutoCutoff == null) - Debug.Log( - "MechJeb BUG: RealFuels loaded, but RealFuels.ModuleEnginesRF has no autoCutoff field, disabling symmetric flameout."); - - _rfUllage = ReflectionUtils.GetFieldByReflection("RealFuels", "RealFuels.ModuleEnginesRF", "ullage"); - if (_rfUllage == null) - Debug.Log( - "MechJeb BUG: RealFuels loaded, but RealFuels.ModuleEnginesRF has no ullage field, disabling RCS Ullage Time calculation."); - } - - if (ReflectionUtils.IsLoadedRP0) - { - _rp0ControllableMass = ReflectionUtils.GetFieldByReflection("RP0", "RP0.ProceduralAvionics.ModuleProceduralAvionics", "controllableMass"); - if (_rp0ControllableMass == null) - Debug.Log( - "MechJeb BUG: RP0 loaded, but RP0.ProceduralAvionics.ModuleProceduralAvionics has no controllableMass field, disabling proc avionics support."); - _rp0MassLimit = ReflectionUtils.GetFieldByReflection("RP0", "RP0.ModuleAvionics", "massLimit"); - if (_rp0MassLimit == null) - Debug.Log( - "MechJeb BUG: RP0 loaded, but RP0.ModuleAvionics has no massLimit field, disabling proc avionics support."); - } + _isRealFuelsLoadedCorrectly = IsLoadedRealFuels && _rfModuleEnginesRf.IsValid && _rfSpoolUpTime.IsValid && + _rfAutoCutoff.IsValid && _rfUllage.IsValid; + _isRP0LoadedCorrectly = IsLoadedRP0 && _rp0ControllableMass.IsValid && _rp0MassLimit.IsValid; } private static double CrewMassOld(ProtoCrewMember crew) => PhysicsGlobals.KerbalCrewMass; @@ -299,18 +273,16 @@ private SimModuleEngines BuildModuleEngines(SimPart part, ModuleEngines kspEngin engine.ModuleSpoolupTime = 0; engine.IsModuleEnginesRf = false; - if (ReflectionUtils.IsLoadedRealFuels) + if (_isRealFuelsLoadedCorrectly) { - engine.IsModuleEnginesRf = _rfType != null && _rfType.IsInstanceOfType(kspEngine); - - if (engine.IsModuleEnginesRf && _rfSpoolUpTime?.GetValue(kspEngine) is float floatVal) - engine.ModuleSpoolupTime = floatVal; - - if (engine.IsModuleEnginesRf && _rfAutoCutoff?.GetValue(kspEngine) is bool boolVal) - engine.AutoCutoff = boolVal; + engine.IsModuleEnginesRf = _rfModuleEnginesRf.IsInstance(kspEngine); - if (engine.IsModuleEnginesRf && _rfUllage?.GetValue(kspEngine) is bool boolVal2) - engine.Ullage = boolVal2; + if (engine.IsModuleEnginesRf) + { + engine.ModuleSpoolupTime = _rfSpoolUpTime.GetValue(kspEngine); + engine.AutoCutoff = _rfAutoCutoff.GetValue(kspEngine); + engine.Ullage = _rfUllage.GetValue(kspEngine); + } } return engine; @@ -344,8 +316,8 @@ private SimModuleAvionics BuildProceduralAvionics(SimPart part, PartModule kspMo { var avionics = SimModuleAvionics.Borrow(part); - if (_rp0ControllableMass?.GetValue(kspModule) is float floatVal) - avionics.ControllableMass = floatVal; + if (_isRP0LoadedCorrectly) + avionics.ControllableMass = _rp0ControllableMass.GetValue(kspModule); return avionics; } @@ -354,8 +326,8 @@ private SimModuleAvionics BuildModuleAvionics(SimPart part, PartModule kspModule { var avionics = SimModuleAvionics.Borrow(part); - if (_rp0MassLimit?.GetValue(kspModule) is float floatVal) - avionics.ControllableMass = floatVal; + if (_isRP0LoadedCorrectly) + avionics.ControllableMass = _rp0MassLimit.GetValue(kspModule); return avionics; } diff --git a/MechJebLibBindings/FuelFlowSimulation/SimVesselUpdater.cs b/MechJebLibBindings/FuelFlowSimulation/SimVesselUpdater.cs index e0c27473c..36cb0096b 100644 --- a/MechJebLibBindings/FuelFlowSimulation/SimVesselUpdater.cs +++ b/MechJebLibBindings/FuelFlowSimulation/SimVesselUpdater.cs @@ -4,14 +4,13 @@ */ using System.Collections.Generic; -using System.Reflection; using System.Runtime.CompilerServices; using KSP.UI.Screens; using MechJebLib.FuelFlowSimulation; using MechJebLib.FuelFlowSimulation.PartModules; -using UnityEngine; using static MechJebLib.Utils.Statics; using static System.Math; +using static MechJebLibBindings.ReflectionUtils; namespace MechJebLibBindings.FuelFlowSimulation { @@ -26,27 +25,17 @@ public class SimVesselUpdater private Dictionary _inversePartModuleMapping => _manager._inversePartModuleMapping; private SimVessel _vessel => _manager._vessel; - private static readonly FieldInfo? _pfDecoupled; - private static readonly FieldInfo? _rfPredictedMaximumResiduals; + private static readonly FieldContext _pfDecoupled = Assembly("ProceduralFairings").Class("Keramzit.ProceduralFairingDecoupler").Field("decoupled"); + private static readonly FieldContext _rfPredictedMaximumResiduals = Assembly("RealFuels").Class("RealFuels.ModuleEnginesRF").Field("predictedMaximumResiduals"); + + private static readonly bool _isProcFairingsLoadedCorrectly; + private static readonly bool _isRealFuelsLoadedCorrectly; + static SimVesselUpdater() { - if (ReflectionUtils.IsAssemblyLoaded("ProceduralFairings")) - { - _pfDecoupled = ReflectionUtils.GetFieldByReflection("ProceduralFairings", "Keramzit.ProceduralFairingDecoupler", - "decoupled"); - if (_pfDecoupled == null) - Debug.Log("MechJeb BUG: ProceduralFairings loaded, but ProceduralFairings.ProceduralFairingDecoupler has no decoupled field"); - } - - if (ReflectionUtils.IsAssemblyLoaded("RealFuels")) - { - _rfPredictedMaximumResiduals = - ReflectionUtils.GetFieldByReflection("RealFuels", "RealFuels.ModuleEnginesRF", "predictedMaximumResiduals"); - if (_rfPredictedMaximumResiduals == null) - Debug.Log( - "MechJeb BUG: RealFuels loaded, but RealFuels.ModuleEnginesRF has no predictedMaximumResiduals field, disabling residuals"); - } + _isProcFairingsLoadedCorrectly = IsLoadedProceduralFairing && _pfDecoupled.IsValid; + _isRealFuelsLoadedCorrectly = IsLoadedRealFuels && _rfPredictedMaximumResiduals.IsValid; } public SimVesselUpdater(SimVesselManager manager) @@ -173,8 +162,8 @@ private void UpdateModuleEngines(SimPart part, SimModuleEngines engine, ModuleEn engine.NoPropellants = kspEngine is { flameout: true, statusL2: "No propellants" }; engine.ModuleResiduals = 0; - if (engine.IsModuleEnginesRf && _rfPredictedMaximumResiduals!.GetValue(kspEngine) is double doubleVal) - engine.ModuleResiduals = doubleVal; + if (engine.IsModuleEnginesRf && _isRealFuelsLoadedCorrectly) + engine.ModuleResiduals = _rfPredictedMaximumResiduals.GetValue(kspEngine); part.EngineResiduals = Max(part.EngineResiduals, engine.ModuleResiduals); } @@ -242,10 +231,12 @@ private static void UpdateModuleRCS(SimModuleRCS rcs, ModuleRCS? kspModuleRCS) [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void UpdateProceduralFairingDecoupler(SimProceduralFairingDecoupler decoupler, PartModule kspPartModule) { - if (_pfDecoupled == null) return; + if (!_isProcFairingsLoadedCorrectly) + return; + + bool boolVal = _pfDecoupled.GetValue(kspPartModule); - if (_pfDecoupled.GetValue(kspPartModule) is bool boolVal) - decoupler.IsDecoupled = boolVal; + decoupler.IsDecoupled = boolVal; } } } diff --git a/MechJebLibBindings/PartExtensions.cs b/MechJebLibBindings/PartExtensions.cs index feb46d219..3a3994a3f 100644 --- a/MechJebLibBindings/PartExtensions.cs +++ b/MechJebLibBindings/PartExtensions.cs @@ -3,25 +3,23 @@ * SPDX-License-Identifier: LicenseRef-PD-hp OR Unlicense OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT OR LGPL-2.1+ */ -using System; using System.Collections.Generic; using System.Reflection; +using static MechJebLibBindings.ReflectionUtils; namespace MechJebLibBindings { public static class PartExtensions { - private static readonly FieldInfo? _rfIgnited; - private static readonly FieldInfo? _rfIgnitions; + private static readonly ClassContext _rfModuleEnginesRf = Assembly("RealFuels").Class("RealFuels.ModuleEnginesRF"); + private static readonly FieldContext _rfIgnited = Assembly("RealFuels").Class("RealFuels.ModuleEnginesRF").Field("ignited", BindingFlags.NonPublic | BindingFlags.Instance); + private static readonly FieldContext _rfIgnitions = Assembly("RealFuels").Class("RealFuels.ModuleEnginesRF").Field("ignitions"); + + private static readonly bool _isRealFuelsLoadedCorrectly; static PartExtensions() { - if (!ReflectionUtils.IsAssemblyLoaded("RealFuels")) - return; - - _rfIgnited = ReflectionUtils.GetFieldByReflection("RealFuels", "RealFuels.ModuleEnginesRF", "ignited", - BindingFlags.NonPublic | BindingFlags.Instance); - _rfIgnitions = ReflectionUtils.GetFieldByReflection("RealFuels", "RealFuels.ModuleEnginesRF", "ignitions"); + _isRealFuelsLoadedCorrectly = IsLoadedRealFuels && _rfModuleEnginesRf.IsValid && _rfIgnited.IsValid && _rfIgnitions.IsValid; } /// @@ -36,7 +34,7 @@ public static bool IsUnrestartableDeadEngine(this Part p) { if (CheatOptions.InfinitePropellant) return false; - if (_rfIgnited is null || _rfIgnitions is null) // stock doesn't have this concept + if (!_isRealFuelsLoadedCorrectly) // stock doesn't have this concept return false; List enginelist = p.FindModulesImplementing(); @@ -64,21 +62,17 @@ public static bool IsUnrestartableDeadEngine(this ModuleEngines e) { if (CheatOptions.InfinitePropellant) return false; - if (_rfIgnited is null || _rfIgnitions is null) // stock doesn't have this concept + if (!_isRealFuelsLoadedCorrectly) // stock doesn't have this concept return false; if (e.finalThrust > 0) return false; + if (!_rfModuleEnginesRf.IsInstance(e)) + return false; - try - { - if (_rfIgnited.GetValue(e) is bool ignited && ignited) - return false; - if (_rfIgnitions.GetValue(e) is int ignitions) - return ignitions == 0; - } - catch (ArgumentException) { } + if (_rfIgnited.GetValue(e)) + return false; - return false; + return _rfIgnitions.GetValue(e) == 0; } } } diff --git a/MechJebLibBindings/ReflectionUtils.cs b/MechJebLibBindings/ReflectionUtils.cs index f93af8bd9..bcfa53015 100644 --- a/MechJebLibBindings/ReflectionUtils.cs +++ b/MechJebLibBindings/ReflectionUtils.cs @@ -46,12 +46,6 @@ public static bool IsAssemblyLoaded(string assemblyName) return false; } - public static FieldInfo? GetFieldByReflection(string assemblyString, string className, string fieldName, - BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static) => - Assembly(assemblyString).Class(className).Field(fieldName, flags).FieldInfo(); - - public static MethodInfo? GetMethodByReflection(string assemblyString, string className, string methodName, BindingFlags flags, Type[] args) => Assembly(assemblyString).Class(className).Method(methodName, flags, args).MethodInfo(); - public static AssemblyContext Assembly(string assemblyString) { string assemblyName = "";