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
3 changes: 3 additions & 0 deletions GameData/KSPCommunityFixes/Settings.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,9 @@ KSP_COMMUNITY_FIXES
// and on other occasions, wasting a ton of CPU processing time.
PQSCoroutineLeak = true

/// Prevent KSP from restarting PQS for the current planet multiple times when launching a new ship.
PQSOnlyStartOnce = true

// Remove unused ProgressTracking update handlers. Provides a very noticeable performance uplift in
// career games having a large amount of celestial bodies and/or vessels.
ProgressTrackingSpeedBoost = true
Expand Down
1 change: 1 addition & 0 deletions KSPCommunityFixes/KSPCommunityFixes.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@
<Compile Include="Performance\ModuleDockingNodeFindOtherNodesFaster.cs" />
<Compile Include="Performance\OptimizedModuleRaycasts.cs" />
<Compile Include="Performance\PQSCoroutineLeak.cs" />
<Compile Include="Performance\PQSOnlyStartOnce.cs" />
<Compile Include="Performance\PQSUpdateNoMemoryAlloc.cs" />
<Compile Include="Performance\ProgressTrackingSpeedBoost.cs" />
<Compile Include="QoL\AutostrutActions.cs" />
Expand Down
70 changes: 70 additions & 0 deletions KSPCommunityFixes/Performance/PQSOnlyStartOnce.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@

using System.Collections.Generic;
using System.Reflection.Emit;
using HarmonyLib;

namespace KSPCommunityFixes.Performance
{
class PQSOnlyStartOnce : BasePatch
{

protected override void ApplyPatches()
{
AddPatch(PatchType.Transpiler, typeof(FlightDriver), nameof(FlightDriver.setStartupNewVessel));
}


static IEnumerable<CodeInstruction> FlightDriver_setStartupNewVessel_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator gen)
{
var method1 = SymbolExtensions.GetMethodInfo<PSystemSetup>(p => p.SetPQSActive(null));
var method2 = SymbolExtensions.GetMethodInfo<PSystemSetup>(p => p.SetPQSActive());

var matcher = new CodeMatcher(instructions);
var state = gen.DeclareLocal(typeof(State));

matcher
.MatchStartForward(new CodeMatch(OpCodes.Callvirt, method1))
.Repeat(
matcher =>
{
matcher.RemoveInstruction();
matcher.InsertAndAdvance(new CodeInstruction(OpCodes.Ldloca, state));
matcher.InsertAndAdvance(CodeInstruction.Call<State>(s => SetPQSActive(null, null, ref s)));
}
);

matcher.Start();
matcher
.MatchStartForward(new CodeMatch(OpCodes.Callvirt, method2))
.Repeat(
matcher =>
{
matcher.RemoveInstruction();
matcher.InsertAndAdvance(new CodeInstruction(OpCodes.Ldloca, state));
matcher.InsertAndAdvance(CodeInstruction.Call<State>(s => SetPQSActive(null, ref s)));
}
);

return matcher.Instructions();
}

struct State
{
public bool activated;
}

static void SetPQSActive(PSystemSetup psystem, PQS pqs, ref State state)
{
psystem.SetPQSActive(pqs);
state.activated = true;
}

static void SetPQSActive(PSystemSetup psystem, ref State state)
{
if (state.activated)
return;

psystem.SetPQSActive();
}
}
}