Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 25 additions & 53 deletions MechJebLibBindings/FuelFlowSimulation/SimVesselBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -23,11 +22,15 @@ public class SimVesselBuilder
private Dictionary<SimPart, Part> _inversePartMapping => _manager._inversePartMapping;
private Dictionary<SimPartModule, PartModule> _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);

Expand All @@ -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;
Expand Down Expand Up @@ -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<float>(kspEngine);
engine.AutoCutoff = _rfAutoCutoff.GetValue<bool>(kspEngine);
engine.Ullage = _rfUllage.GetValue<bool>(kspEngine);
}
}

return engine;
Expand Down Expand Up @@ -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<float>(kspModule);

return avionics;
}
Expand All @@ -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<float>(kspModule);

return avionics;
}
Expand Down
41 changes: 16 additions & 25 deletions MechJebLibBindings/FuelFlowSimulation/SimVesselUpdater.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -26,27 +25,17 @@ public class SimVesselUpdater
private Dictionary<SimPartModule, PartModule> _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)
Expand Down Expand Up @@ -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<double>(kspEngine);

part.EngineResiduals = Max(part.EngineResiduals, engine.ModuleResiduals);
}
Expand Down Expand Up @@ -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<bool>(kspPartModule);

if (_pfDecoupled.GetValue(kspPartModule) is bool boolVal)
decoupler.IsDecoupled = boolVal;
decoupler.IsDecoupled = boolVal;
}
}
}
Expand Down
34 changes: 14 additions & 20 deletions MechJebLibBindings/PartExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/// <summary>
Expand All @@ -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<ModuleEngines> enginelist = p.FindModulesImplementing<ModuleEngines>();
Expand Down Expand Up @@ -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<bool>(e))
return false;

return false;
return _rfIgnitions.GetValue<int>(e) == 0;
}
}
}
6 changes: 0 additions & 6 deletions MechJebLibBindings/ReflectionUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "";
Expand Down
Loading