Skip to content

Commit 6c4e88c

Browse files
authored
perf: Optimize ModuleSystemHeatHarvester (#168)
* perf: Optimize ModuleSystemHeatHarvester SystemHeat is actually pretty good here, and most of the overhead is in the stock module. The main thing we can optimize is to entirely disable the module when it is not active. Other than that I have gone through and changed stuff to make better use of the hooks that stock provides: * systemEfficency is used to replace GetHeatThrottle. This makes it so that it actually changes the converter rate like it is supposed to. Before the changes written to outputList and inputList were stomped over in PrepareRecipe. * We do UpdateFlux in PostProcess and reuse the TimeFactor. * Properly handle AlwaysActive
1 parent 08cfb4f commit 6c4e88c

1 file changed

Lines changed: 93 additions & 78 deletions

File tree

Source/Modules/ModuleSystemHeatHarvester.cs

Lines changed: 93 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Text;
55
using UnityEngine;
66
using KSP.Localization;
7+
using Unity.Profiling;
78

89
namespace SystemHeat
910
{
@@ -49,128 +50,142 @@ public void ToggleEditorThermalSim()
4950
[KSPField(isPersistant = false, guiActive = true, guiActiveEditor = true, guiName = "Harvester Efficiency")]
5051
public string HarvesterEfficiency = "-1%";
5152

52-
// base paramters
53-
private List<ResourceBaseRatio> inputs;
54-
private List<ResourceBaseRatio> outputs;
5553
protected ModuleSystemHeat heatModule;
54+
55+
private static readonly ProfilerMarker BaseFixedUpdateMarker = new("ModuleResourceHarvester.FixedUpdate");
56+
5657
public override string GetInfo()
5758
{
5859
string info = base.GetInfo();
5960

6061
int pos = info.IndexOf("\n\n");
6162
if (pos < 0)
6263
return info;
63-
else
64-
return info.Substring(0, pos) + Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatHarvester_PartInfoAdd",
65-
Utils.ToSI(systemPower, "F0"),
66-
systemOutletTemperature.ToString("F0"),
67-
shutdownTemperature.ToString("F0")
68-
) + info.Substring(pos);
64+
65+
var extraInfo = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatHarvester_PartInfoAdd",
66+
Utils.ToSI(systemPower, "F0"),
67+
systemOutletTemperature.ToString("F0"),
68+
shutdownTemperature.ToString("F0")
69+
);
70+
return info.Substring(0, pos) + extraInfo + info.Substring(pos);
6971
}
72+
7073
public void Start()
7174
{
75+
heatModule = ModuleUtils.FindHeatModule(part, systemHeatModuleID);
7276

73-
heatModule = ModuleUtils.FindHeatModule(this.part, systemHeatModuleID);
77+
Utils.Log("[ModuleSystemHeatHarvester] Setup completed", LogType.Modules);
78+
Events["ToggleEditorThermalSim"].guiName = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatHarvester_Field_SimulateEditor", ConverterName);
79+
Fields["HarvesterEfficiency"].guiName = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatHarvester_Field_Efficiency", ConverterName);
80+
}
7481

82+
public override void FixedUpdate()
83+
{
7584
if (HighLogic.LoadedSceneIsFlight)
7685
{
77-
SetupResourceRatios();
86+
FixedUpdateFlight();
7887
}
7988
else
8089
{
81-
SetupResourceRatios();
90+
UpdateFlux();
91+
Fields["HarvesterEfficiency"].guiActiveEditor = editorThermalSim;
8292
}
93+
}
8394

84-
Utils.Log("[ModuleSystemHeatHarvester] Setup completed", LogType.Modules);
85-
Events["ToggleEditorThermalSim"].guiName = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatHarvester_Field_SimulateEditor", base.ConverterName);
86-
Fields["HarvesterEfficiency"].guiName = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatHarvester_Field_Efficiency", base.ConverterName);
95+
void Update()
96+
{
97+
if (!part.IsPAWVisible())
98+
return;
99+
100+
HarvesterEfficiency = Localizer.Format(
101+
"#LOC_SystemHeat_ModuleSystemHeatHarvester_Field_Efficiency_Value",
102+
(GetHeatThrottle() * 100f).ToString("F1")
103+
);
87104
}
88-
public override void FixedUpdate()
105+
106+
void OnDisable()
89107
{
90-
base.FixedUpdate();
91-
if (heatModule != null)
92-
{
93-
if (HighLogic.LoadedSceneIsFlight)
94-
{
95-
GenerateHeatFlight();
96-
UpdateSystemHeatFlight();
97-
}
98-
else if (HighLogic.LoadedSceneIsEditor)
99-
{
100-
GenerateHeatEditor();
101-
102-
Fields["HarvesterEfficiency"].guiActiveEditor = editorThermalSim;
103-
}
104-
}
108+
heatModule?.AddFlux(moduleID, 0f, 0f, false);
109+
HarvesterEfficiency = "-";
105110
}
106111

107-
void Update()
112+
void FixedUpdateFlight()
108113
{
109-
if (heatModule != null && part.IsPAWVisible())
114+
if (heatModule == null)
110115
{
111-
HarvesterEfficiency = Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatHarvester_Field_Efficiency_Value", (systemEfficiency.Evaluate(heatModule.currentLoopTemperature) * 100f).ToString("F1"));
116+
// This disables this module entirely, so it won't be called every frame.
117+
enabled = false;
118+
return;
112119
}
113-
}
114120

115-
protected void GenerateHeatEditor()
116-
{
117-
if (base.IsActivated)
118-
heatModule.AddFlux(moduleID, systemOutletTemperature, systemPower, true);
119-
else
120-
heatModule.AddFlux(moduleID, 0f, 0f, false);
121+
CheckOverheat();
122+
123+
if (!IsActivated && !AlwaysActive)
124+
enabled = false;
125+
126+
using (BaseFixedUpdateMarker.ConditionalAuto())
127+
base.FixedUpdate();
121128
}
122129

123-
protected void GenerateHeatFlight()
130+
void UpdateFlux() => UpdateFlux(lastTimeFactor);
131+
void UpdateFlux(double timeFactor)
124132
{
125-
if (base.ModuleIsActive())
133+
if (heatModule == null)
134+
return;
135+
136+
if (ModuleIsActive())
126137
{
127-
float fluxScale = 1f;
128-
if (base.lastTimeFactor == 0d)
129-
{
130-
fluxScale = 0f;
131-
}
132-
heatModule.AddFlux(moduleID, systemOutletTemperature, systemPower * fluxScale, true);
138+
float scale = timeFactor != 0.0 ? 1f : 0f;
139+
if (HighLogic.LoadedSceneIsEditor)
140+
scale = 1f;
141+
142+
heatModule.AddFlux(moduleID, systemOutletTemperature, systemPower * scale, true);
133143
}
134144
else
135145
{
136146
heatModule.AddFlux(moduleID, 0f, 0f, false);
137147
}
138148
}
139-
protected void UpdateSystemHeatFlight()
149+
150+
void CheckOverheat()
140151
{
141-
if (base.ModuleIsActive())
142-
{
143-
if (heatModule.currentLoopTemperature > shutdownTemperature)
144-
{
145-
ScreenMessages.PostScreenMessage(
146-
new ScreenMessage(
147-
Localizer.Format("#LOC_SystemHeat_ModuleSystemHeatHarvester_Message_Shutdown",
148-
part.partInfo.title),
149-
3.0f,
150-
ScreenMessageStyle.UPPER_CENTER));
151-
ToggleResourceConverterAction(new KSPActionParam(0, KSPActionType.Activate));
152-
153-
Utils.Log("[ModuleSystemHeatConverter]: Overheated, shutdown fired", LogType.Modules);
154-
155-
}
156-
base.recipe = ModuleUtils.RecalculateRatios(systemEfficiency.Evaluate(heatModule.currentLoopTemperature), inputs, outputs, inputList, outputList, base.recipe);
157-
}
152+
if (!ModuleIsActive())
153+
return;
154+
if (heatModule.currentLoopTemperature <= shutdownTemperature)
155+
return;
156+
157+
ScreenMessages.PostScreenMessage(
158+
new ScreenMessage(
159+
Localizer.Format(
160+
"#LOC_SystemHeat_ModuleSystemHeatHarvester_Message_Shutdown",
161+
part.partInfo.title),
162+
3.0f,
163+
ScreenMessageStyle.UPPER_CENTER));
164+
StopResourceConverter();
165+
166+
Utils.Log("[ModuleSystemHeatConverter]: Overheated, shutdown fired", LogType.Modules);
158167
}
159168

160-
private void SetupResourceRatios()
169+
public override void StartResourceConverter()
161170
{
171+
enabled = true;
172+
base.StartResourceConverter();
173+
}
162174

163-
inputs = new List<ResourceBaseRatio>();
164-
outputs = new List<ResourceBaseRatio>();
175+
// In stock this would use the ModuleCoreHeat on the same part. We don't
176+
// want that, and just override it to point to our own efficiency multiplier.
177+
public override float GetHeatThrottle()
178+
{
179+
if (heatModule == null)
180+
return 1f;
165181

166-
for (int i = 0; i < inputList.Count; i++)
167-
{
168-
inputs.Add(new ResourceBaseRatio(inputList[i].ResourceName, inputList[i].Ratio));
169-
}
170-
for (int i = 0; i < outputList.Count; i++)
171-
{
172-
outputs.Add(new ResourceBaseRatio(outputList[i].ResourceName, outputList[i].Ratio));
173-
}
182+
return systemEfficiency.Evaluate(heatModule.currentLoopTemperature);
183+
}
184+
185+
protected override void PostProcess(ConverterResults result, double deltaTime)
186+
{
187+
base.PostProcess(result, deltaTime);
188+
UpdateFlux(result.TimeFactor);
174189
}
175190
}
176191
}

0 commit comments

Comments
 (0)