Skip to content

Commit

Permalink
Add on-pad vessel repairs (#2327)
Browse files Browse the repository at this point in the history
Creates a new option into the vessel recovery dialog that allows queueing up a repair of all failures. Only available for VAB-built vessels while in prelaunch state. This operation is blocking (i.e cannot build another vessel at the same time in that LC) and takes 1/7.5 of rollout time. No additional cost other than what is paid for engineer salary.
  • Loading branch information
siimav authored Feb 4, 2024
1 parent 335b0e4 commit adebe39
Show file tree
Hide file tree
Showing 14 changed files with 404 additions and 65 deletions.
Binary file added GameData/RP-1/Resources/KCT_repair.truecolor
Binary file not shown.
22 changes: 22 additions & 0 deletions Source/RP0/Harmony/FlightInputHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using HarmonyLib;

namespace RP0.Harmony
{
[HarmonyPatch(typeof(FlightInputHandler))]
internal class PatchFlightInputHandler
{
/// <summary>
/// Makes sure that throttle stays at 0 when repairs were done and vessel comes off rails.
/// </summary>
[HarmonyPostfix]
[HarmonyPatch("SetLaunchCtrlState")]
internal static void Postfix_SetLaunchCtrlState()
{
bool b = SpaceCenterManagement.Instance?.DoingVesselRepair ?? false;
if (b)
{
FlightInputHandler.state.mainThrottle = 0;
}
}
}
}
70 changes: 70 additions & 0 deletions Source/RP0/ModIntegrations/TFInterop.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using System;
using System.Linq;
using System.Reflection;

namespace RP0
{
public static class TFInterop
{
private static bool? _isTestFlightInstalled = null;
private static bool? _hasSupportForReset = null;
private static Assembly _assembly;
private static MethodInfo _miGetVesselStatus;
private static MethodInfo _miResetAllFailuresOnVessel;
private static MethodInfo _miResetAllRunTimesOnVessel;

public static bool IsTestFlightInstalled
{
get
{
EnsureReflectionInitialized();
return _isTestFlightInstalled.Value;
}
}
public static bool HasSupportForReset
{
get
{
EnsureReflectionInitialized();
return _hasSupportForReset.Value;
}
}

public static bool VesselHasFailedParts(Vessel v)
{
if (v == null) return false;

EnsureReflectionInitialized();
var res = (int)_miGetVesselStatus.Invoke(null, new object[] { v });
// 0 = OK, 1 = Has failure, -1 = Could not find TestFlight Core on Part
return res > 0;
}

public static void ResetAllFailures(Vessel v)
{
if (v == null) return;

EnsureReflectionInitialized();
_miResetAllFailuresOnVessel.Invoke(null, new object[] { v });
_miResetAllRunTimesOnVessel.Invoke(null, new object[] { v });
}

private static void EnsureReflectionInitialized()
{
if (_isTestFlightInstalled.HasValue) return;

_assembly = AssemblyLoader.loadedAssemblies.FirstOrDefault((AssemblyLoader.LoadedAssembly la) => string.Equals(la.name, "TestFlightCore", StringComparison.OrdinalIgnoreCase))?.assembly;
_isTestFlightInstalled = _assembly != null;
_hasSupportForReset = false;

if (_isTestFlightInstalled.Value)
{
var type = _assembly.GetType("TestFlightCore.TestFlightInterface");
_miGetVesselStatus = type.GetMethod("GetVesselStatus", BindingFlags.Public | BindingFlags.Static);
_miResetAllFailuresOnVessel = type.GetMethod("ResetAllFailuresOnVessel", BindingFlags.Public | BindingFlags.Static);
_miResetAllRunTimesOnVessel = type.GetMethod("ResetAllRunTimesOnVessel", BindingFlags.Public | BindingFlags.Static);
_hasSupportForReset = _miResetAllRunTimesOnVessel != null;
}
}
}
}
45 changes: 16 additions & 29 deletions Source/RP0/RP0.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@
<ItemGroup>
<Compile Include="Avionics\ControlLockerUtils.cs" />
<Compile Include="Avionics\EditorBinder.cs" />
<Compile Include="Harmony\FlightInputHandler.cs" />
<Compile Include="Harmony\ModuleRCS.cs" />
<Compile Include="ModIntegrations\TFInterop.cs" />
<Compile Include="SpaceCenter\Projects\VesselRepairProject.cs" />
<Compile Include="UI\ProceduralAvionicsWindow.cs" />
<Compile Include="CareerLog\CareerEvent.cs" />
<Compile Include="CareerLog\CareerEventScope.cs" />
Expand Down Expand Up @@ -283,24 +286,20 @@
</Reference>
<Reference Include="ContractConfigurator, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\ContractConfigurator\source\ContractConfigurator\bin\Release\ContractConfigurator.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="ferramGraph">
<Private>False</Private>
</Reference>
<Reference Include="Ionic.Zip, Version=1.9.1.8, Culture=neutral, PublicKeyToken=edbe51ad942a3f5c, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\Games\R112\KSP_x64_Data\Managed\Ionic.Zip.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Kerbalism112, Version=3.17.0.0, Culture=neutral, processorArchitecture=AMD64">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\temp\dlls\Kerbalism112.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="KSPCommunityFixes">
<HintPath>..\..\..\..\..\..\Games\R112\GameData\KSPCommunityFixes\Plugins\KSPCommunityFixes.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="ModularFlightIntegrator">
Expand All @@ -310,7 +309,9 @@
<Private>False</Private>
</Reference>
<Reference Include="ROUtils">
<HintPath>..\..\..\..\..\..\..\Games\R112\GameData\ROUtils\Plugins\ROUtils.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="SolverEngines">
<Private>False</Private>
</Reference>
<Reference Include="System">
Expand All @@ -322,51 +323,37 @@
<Reference Include="UnityEngine">
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.AnimationModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<Reference Include="UnityEngine.AnimationModule">
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.AssetBundleModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\KSP DLL\1.12.3\UnityEngine.AssetBundleModule.dll</HintPath>
<Reference Include="UnityEngine.AssetBundleModule">
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<Reference Include="UnityEngine.CoreModule">
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.ImageConversionModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\Games\R112\KSP_x64_Data\Managed\UnityEngine.ImageConversionModule.dll</HintPath>
<Reference Include="UnityEngine.ImageConversionModule">
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.IMGUIModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<Reference Include="UnityEngine.IMGUIModule">
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.InputLegacyModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<Reference Include="UnityEngine.InputLegacyModule">
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.PhysicsModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<Reference Include="UnityEngine.PhysicsModule">
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.ScreenCaptureModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\Games\R112\KSP_x64_Data\Managed\UnityEngine.ScreenCaptureModule.dll</HintPath>
<Reference Include="UnityEngine.ScreenCaptureModule">
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.TextRenderingModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<Reference Include="UnityEngine.TextRenderingModule">
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.UI">
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.UIModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\ContractConfigurator\source\ContractConfigurator\bin\Release\UnityEngine.UIModule.dll</HintPath>
<Reference Include="UnityEngine.UIModule">
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.UnityWebRequestModule">
Expand Down
39 changes: 29 additions & 10 deletions Source/RP0/SpaceCenter/LaunchComplex/LaunchComplex.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
using System;
using ROUtils.DataTypes;
using System;
using System.Collections.Generic;
using UniLinq;
using UnityEngine;
using ROUtils.DataTypes;

namespace RP0
{
Expand Down Expand Up @@ -44,6 +45,8 @@ public class LaunchComplex : IConfigNode
public PersistentObservableList<PadConstructionProject> PadConstructions = new PersistentObservableList<PadConstructionProject>();
[Persistent]
public PersistentObservableList<ReconRolloutProject> Recon_Rollout = new PersistentObservableList<ReconRolloutProject>();
[Persistent]
public PersistentObservableList<VesselRepairProject> VesselRepairs = new PersistentObservableList<VesselRepairProject>();

private double _rate;
private double _rateHRCapped;
Expand Down Expand Up @@ -142,6 +145,7 @@ void AddListeners()
BuildList.Updated += updated;
Warehouse.Updated += updated;
Recon_Rollout.Updated += lcpUpdated;
VesselRepairs.Updated += lcpUpdated;
}
#endregion

Expand Down Expand Up @@ -207,10 +211,12 @@ public int LaunchPadCount

public bool IsEmpty => LCType == LaunchComplexType.Hangar && BuildList.Count == 0 && Warehouse.Count == 0 && Engineers == 0 && LCData.StartingHangar.Compare(this);

public bool IsActive => BuildList.Count > 0 || Recon_Rollout.Any(rr => !rr.IsComplete());
public bool CanDismantle => BuildList.Count == 0 && Warehouse.Count == 0 && !Recon_Rollout.Any(r => r.RRType != ReconRolloutProject.RolloutReconType.Reconditioning);
public bool CanModifyButton => BuildList.Count == 0 && Warehouse.Count == 0 && Recon_Rollout.Count == 0;
public bool CanModifyReal => Recon_Rollout.Count == 0;
public bool IsActive => BuildList.Count > 0 || GetAllLCOps().Any(op => !op.IsComplete());
public bool CanDismantle => BuildList.Count == 0 && Warehouse.Count == 0 &&
!Recon_Rollout.Any(r => r.RRType != ReconRolloutProject.RolloutReconType.Reconditioning) &&
VesselRepairs.Count == 0;
public bool CanModifyButton => BuildList.Count == 0 && Warehouse.Count == 0 && Recon_Rollout.Count == 0 && VesselRepairs.Count == 0;
public bool CanModifyReal => Recon_Rollout.Count == 0 && VesselRepairs.Count == 0;
public bool CanIntegrate => ProjectBPTotal == 0d;

private double _projectBPTotal = -1d;
Expand All @@ -219,7 +225,7 @@ public int LaunchPadCount
public double RecalculateProjectBP()
{
_projectBPTotal = 0d;
foreach (var r in Recon_Rollout)
foreach (var r in GetAllLCOps())
{
if (!r.IsBlocking || r.IsComplete())
continue;
Expand Down Expand Up @@ -250,8 +256,8 @@ public void RecalculateBuildRates()
foreach (var vp in BuildList)
vp.UpdateBuildRate();

foreach (var rr in Recon_Rollout)
rr.UpdateBuildRate();
foreach (var op in GetAllLCOps())
op.UpdateBuildRate();

RecalculateProjectBP();

Expand Down Expand Up @@ -418,7 +424,7 @@ public void Load(ConfigNode node)
}
}

foreach (var rr in Recon_Rollout)
foreach (var rr in GetAllLCOps())
rr.LC = this;

foreach (var vp in BuildList)
Expand Down Expand Up @@ -447,6 +453,19 @@ public void PostLoad(LCSpaceCenter ksc)
}
}

public IEnumerable<LCOpsProject> GetAllLCOps()
{
foreach (var item in Recon_Rollout)
{
yield return item;
}

foreach (var item in VesselRepairs)
{
yield return item;
}
}

private void CalculateAndSetRates()
{
_strategyRateMultiplier = CurrencyUtils.Rate(LCType == LaunchComplexType.Pad ? TransactionReasonsRP0.RateIntegrationVAB : TransactionReasonsRP0.RateIntegrationSPH);
Expand Down
3 changes: 2 additions & 1 deletion Source/RP0/SpaceCenter/Projects/ISpaceCenterProject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ public enum ProjectType
Reconditioning,
KSC,
AirLaunch,
Crew
Crew,
VesselRepair
};

public interface ISpaceCenterProject
Expand Down
16 changes: 13 additions & 3 deletions Source/RP0/SpaceCenter/Projects/LCOpsProject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ public abstract class LCOpsProject : ConfigNodePersistenceBase, ISpaceCenterProj
private bool _wasComplete;
protected double _buildRate = -1;

public Guid AssociatedIdAsGuid => new Guid(associatedID);

public abstract TransactionReasonsRP0 TransactionReason { get; }
protected abstract TransactionReasonsRP0 transactionReasonTime { get; }

public VesselProject AssociatedVP => KCTUtilities.FindVPByID(LC, new Guid(associatedID));
public VesselProject AssociatedVP => KCTUtilities.FindVPByID(LC, AssociatedIdAsGuid);

protected LaunchComplex _lc = null;
public LaunchComplex LC
Expand All @@ -42,6 +44,14 @@ public LaunchComplex LC
break;
}
}
else if (this is VesselRepairProject vr)
{
if (lc.VesselRepairs.Contains(vr))
{
_lc = lc;
break;
}
}
}
}
}
Expand Down Expand Up @@ -239,7 +249,7 @@ public double GetTimeLeftEstAll()

public static double GetTotalBlockingProjectTime(LaunchComplex lc)
{
foreach (var r in lc.Recon_Rollout)
foreach (var r in lc.GetAllLCOps())
{
if (r.IsBlocking && !r.IsComplete())
AddLCP(r);
Expand Down Expand Up @@ -288,7 +298,7 @@ public static LCOpsProject GetFirstCompleting(LaunchComplex lc)
LCOpsProject lcp = null;
// The blocking LCP with the lowest time left
// doesn't have to worry about build rate changing
foreach (var r in lc.Recon_Rollout)
foreach (var r in lc.GetAllLCOps())
{
if (r.IsComplete())
continue;
Expand Down
4 changes: 2 additions & 2 deletions Source/RP0/SpaceCenter/Projects/ReconRolloutProject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ public class ReconRolloutProject : LCOpsProject
{
public enum RolloutReconType { Reconditioning, Rollout, Rollback, Recovery, None, AirlaunchMount, AirlaunchUnmount };

public override string Name => KSP.Localization.Localizer.Format("#rp0_LCOps_Type_" + RRType.ToString())
;
public override string Name => KSP.Localization.Localizer.Format("#rp0_LCOps_Type_" + RRType.ToString());

[Persistent]
public string launchPadID = "LaunchPad";
[Persistent]
Expand Down
Loading

0 comments on commit adebe39

Please sign in to comment.