Skip to content

Commit

Permalink
Merge pull request #45 from KSP-RO/ModuleEnginesSolverProfiling
Browse files Browse the repository at this point in the history
Module Engines Solver Optimizations
  • Loading branch information
NathanKell authored Feb 14, 2022
2 parents 273dc85 + 34525f6 commit 2662bdb
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 44 deletions.
90 changes: 90 additions & 0 deletions SolverEngines/DeferredEngineExhaustDamage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;

namespace SolverEngines
{
[DefaultExecutionOrder(1)]
public class DeferredEngineExhaustDamage : MonoBehaviour
{
private int layerMask;
private readonly List<ModuleEngines> engines = new List<ModuleEngines>(128);
private readonly List<Transform> thrustTransforms = new List<Transform>(128);
private readonly List<float> multipliers = new List<float>(128);
private readonly Dictionary<Part,Part> damagedParts = new Dictionary<Part,Part>(16);

public void Start()
{
layerMask = LayerUtil.DefaultEquivalent | (1 << LayerMask.NameToLayer("Parts"));
}

public void AddEngine(ModuleEngines engine)
{
if (engine.exhaustDamage)
{
foreach (var thrustTransform in engine.thrustTransforms)
{
engines.Add(engine);
thrustTransforms.Add(thrustTransform);
}
multipliers.AddRange(engine.thrustTransformMultipliers);
}
}

public void FixedUpdate()
{
int raysCount = engines.Count;
if (raysCount == 0) return;

var results = new NativeArray<RaycastHit>(raysCount, Allocator.Temp);
var commands = new NativeArray<RaycastCommand>(raysCount, Allocator.Temp);

for (int index = 0; index < raysCount; index++)
{
Transform thrustTransform = thrustTransforms[index];
ModuleEngines engine = engines[index];
commands[index++] = new RaycastCommand(thrustTransform.position, thrustTransform.forward, engine.exhaustDamageMaxRange, layerMask, maxHits: 1);
}
RaycastCommand.ScheduleBatch(commands, results, 1).Complete();

for (int index = 0; index < raysCount; index++)
{
Transform thrustTransform = thrustTransforms[index];
ModuleEngines engine = engines[index];
RaycastHit hit = results[index];
double mult = multipliers[index];
if (hit.collider != null)
{
Transform transform = hit.collider.transform;
Part partUpwardsCached = FlightGlobals.GetPartUpwardsCached(transform.gameObject);
if (partUpwardsCached != null && partUpwardsCached != engine.part && !transform.GetComponentInChildren<physicalObject>())
{
double flux = engine.finalThrust * mult * engine.exhaustDamageMultiplier;
double x = Math.Max(0.001, hit.distance + engine.exhaustDamageDistanceOffset);
double falloff = Math.Pow(x, -engine.exhaustDamageFalloffPower);
double splashback = Math.Pow(x, -engine.exhaustDamageSplashbackFallofPower) * engine.exhaustDamageSplashbackMult;
falloff = Math.Min(falloff, engine.exhaustDamageMaxMutliplier);
splashback = Math.Min(splashback, engine.exhaustDamageSplashbackMaxMutliplier);
partUpwardsCached.AddSkinThermalFlux(flux * falloff);
engine.part.AddSkinThermalFlux(flux * splashback);
partUpwardsCached.AddForceAtPosition(thrustTransform.forward * engine.finalThrust * multipliers[index], hit.point);
if (engine.exhaustDamageLogEvent)
damagedParts.Add(engine.part, partUpwardsCached);
}
}
}
if (damagedParts.Count > 0)
foreach (var srcDest in damagedParts)
GameEvents.onSplashDamage.Fire(new EventReport(FlightEvents.SPLASHDAMAGE, srcDest.Key, srcDest.Value.partInfo.title, srcDest.Key.partInfo.title));

results.Dispose();
commands.Dispose();
engines.Clear();
thrustTransforms.Clear();
multipliers.Clear();
damagedParts.Clear();
}
}
}
84 changes: 44 additions & 40 deletions SolverEngines/EngineModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using UnityEngine;
using KSP.UI.Screens;
using SolverEngines.EngineFitting;
using UnityEngine.Profiling;

namespace SolverEngines
{
Expand All @@ -14,19 +15,19 @@ public abstract class ModuleEnginesSolver : ModuleEnginesFX, IModuleInfo, IEngin
{
// base fields

[KSPField(isPersistant = false, guiActiveEditor = true, guiFormat = "F3")]
[KSPField(guiActiveEditor = true, guiFormat = "F3")]
public float Need_Area;

[KSPField(isPersistant = false, guiActive = true, guiName = "Current Throttle", guiFormat = "N2", guiUnits = "%")]
[KSPField(guiActive = true, guiName = "Current Throttle", guiFormat = "N2", guiUnits = "%")]
public float actualThrottle;

[KSPField(guiActive = true, guiName = "Mass Flow", guiUnits = " kg/s", guiFormat = "F5")]
public float massFlowGui;

[KSPField(isPersistant = false)]
[KSPField]
public double thrustUpperLimit = double.MaxValue;

[KSPField(isPersistant = false)]
[KSPField]
public bool multiplyThrustByFuelFrac = true;

[KSPField]
Expand All @@ -44,15 +45,15 @@ public abstract class ModuleEnginesSolver : ModuleEnginesFX, IModuleInfo, IEngin

// engine temp stuff
// fields
[KSPField(isPersistant = false)]
[KSPField]
public double maxEngineTemp;
[KSPField(isPersistant = false, guiActive = true, guiName = "Eng. Internal Temp")]
public string engineTempString;
[KSPField(guiActive = true, guiName = "Eng. Internal Temp", guiFormat = "N0")]
public double engineTemp = 288.15d;
[KSPField]
public double tempGaugeMin = 0.8d;

// internals
protected double tempRatio = 0d, engineTemp = 288.15d;
protected double tempRatio = 0d;

public double GetEngineTemp => engineTemp;

Expand All @@ -66,6 +67,7 @@ public abstract class ModuleEnginesSolver : ModuleEnginesFX, IModuleInfo, IEngin

// protected internals
protected EngineSolver engineSolver = null;
protected DeferredEngineExhaustDamage exhaustDamager = null;

protected EngineThermodynamics ambientTherm = new EngineThermodynamics();
protected EngineThermodynamics inletTherm = new EngineThermodynamics();
Expand Down Expand Up @@ -105,13 +107,14 @@ virtual public void Start()
{
CreateEngine();
Need_Area = RequiredIntakeArea();
Fields["Need_Area"].guiActiveEditor = Need_Area > 0f;
Fields[nameof(Need_Area)].guiActiveEditor = Need_Area > 0f;
currentThrottle = 0f;
flameout = false;
SetUnflameout();
Fields["fuelFlowGui"].guiActive = false;
Fields["massFlowGui"].guiUnits = " kg/s";
Fields[nameof(fuelFlowGui)].guiActive = false;
Fields[nameof(massFlowGui)].guiUnits = " kg/s";
flowKG = true;
Fields[nameof(engineTemp)].guiUnits = $" K / {maxEngineTemp:N0} K";
}

public override void OnStart(PartModule.StartState state)
Expand All @@ -127,12 +130,13 @@ public override void OnStart(PartModule.StartState state)

// Get emissives
emissiveAnims = new List<ModuleAnimateHeat>();
int mCount = part.Modules.Count;
for (int i = 0; i < mCount; ++i)
if (part.Modules[i] is ModuleAnimateHeat)
emissiveAnims.Add(part.Modules[i] as ModuleAnimateHeat);
foreach (var pm in part.Modules)
if (pm is ModuleAnimateHeat)
emissiveAnims.Add(pm as ModuleAnimateHeat);

CreateEngineIfNecessary();
if (HighLogic.LoadedSceneIsFlight && !vessel.TryGetComponent<DeferredEngineExhaustDamage>(out exhaustDamager))
exhaustDamager = vessel.gameObject.AddComponent<DeferredEngineExhaustDamage>();
}

public override void OnLoad(ConfigNode node)
Expand All @@ -147,12 +151,9 @@ public override void OnLoad(ConfigNode node)
{
if (trfNode.name != "THRUST_TRANSFORM") continue;

ThrustTransformInfo info;

try
{
info = new ThrustTransformInfo(trfNode);
thrustTransformInfos.Add(info);
thrustTransformInfos.Add(new ThrustTransformInfo(trfNode));
}
catch (Exception e)
{
Expand Down Expand Up @@ -291,7 +292,7 @@ protected void InitializeThrustTransforms()
part.AddForceAtPosition(thrustRot * (axis * thrustTransformMultipliers[i] * finalThrust), t.position + t.rotation * thrustOffset);
}
}
EngineExhaustDamage();
DeferredEngineExhaustDamage();

double thermalFlux = tempRatio * tempRatio * heatProduction * vessel.VesselValues.HeatProduction.value * PhysicsGlobals.InternalHeatProductionFactor * part.thermalMass;
part.AddThermalFlux(thermalFlux);
Expand All @@ -303,24 +304,30 @@ protected void InitializeThrustTransforms()
}
}

public virtual void DeferredEngineExhaustDamage() => exhaustDamager?.AddEngine(this);

public override bool CanStart()
{
return base.CanStart() || flameout;
}

public override void FXUpdate()
{
Profiler.BeginSample("EngineSolver.FXUpdate");
part.Effect(directThrottleEffectName, engineSolver.GetFXThrottle());
part.Effect(spoolEffectName, engineSolver.GetFXSpool());
part.Effect(runningEffectName, engineSolver.GetFXRunning());
Profiler.BeginSample("EngineSolver.FXUpdate.GetFXPower");
part.Effect(powerEffectName, engineSolver.GetFXPower());
Profiler.EndSample();
Profiler.EndSample();
}

virtual protected void UpdateTemp()
{
if (tempRatio > 1d && !CheatOptions.IgnoreMaxTemperature)
{
FlightLogger.eventLog.Add("[" + FormatTime(vessel.missionTime) + "] " + part.partInfo.title + " melted its internals from heat.");
FlightLogger.eventLog.Add($"[{FormatTime(vessel.missionTime)}] {part.partInfo.title} melted its internals from heat.");
part.explode();
}
else
Expand All @@ -338,7 +345,6 @@ virtual public void UpdateInletEffects(EngineThermodynamics inletTherm, double a

this.inletTherm = inletTherm;
this.areaRatio = areaRatio;

}

public override void UpdateThrottle()
Expand All @@ -355,20 +361,24 @@ virtual public void UpdateFlightCondition()
virtual public void UpdateSolver(EngineThermodynamics ambientTherm, double altitude, Vector3d vel, double mach, bool ignited, bool oxygen, bool underwater)
{
// In flight, these are the same and this will just return
Profiler.BeginSample("EngineSolver.UpdateSolver");
this.ambientTherm = ambientTherm;

engineSolver.SetEngineState(ignited, lastPropellantFraction);
engineSolver.SetFreestreamAndInlet(ambientTherm, inletTherm, altitude, mach, vel, oxygen, underwater);
Profiler.BeginSample("EngineSolver.UpdateSolver.CalculatePerformance");
engineSolver.CalculatePerformance(areaRatio, currentThrottle, flowMult * multFlow, ispMult * multIsp);
Profiler.EndSample();
Profiler.EndSample();
}

virtual public void CalculateEngineParams()
{
Profiler.BeginSample("EngineSolver.CalculateEngineParams");
SetEmissive(engineSolver.GetEmissive());
// Heat
engineTemp = engineSolver.GetEngineTemp();
tempRatio = engineTemp / maxEngineTemp;
engineTempString = engineTemp.ToString("N0") + " K / " + maxEngineTemp.ToString("n0") + " K";

double thrustIn = engineSolver.GetThrust(); //in N
double isp = engineSolver.GetIsp();
Expand Down Expand Up @@ -399,6 +409,7 @@ virtual public void CalculateEngineParams()
}
else
{
Profiler.BeginSample("EngineSolver.CalculateEngineParams.RunningEngine");
// calc flow
double vesselValue = vessel.VesselValues.FuelUsage.value;
if (vesselValue == 0d)
Expand All @@ -416,14 +427,17 @@ virtual public void CalculateEngineParams()
{
if (massFlow > 0d)
{
Profiler.BeginSample("EngineSolver.CalculateEngineParams.RunningEngine.RequestPropellant");
lastPropellantFraction = RequestPropellant(massFlow);
Profiler.EndSample();
}
else
{
lastPropellantFraction = PropellantAvailable() ? 1d : 0d;
}
}
this.propellantReqMet = (float)this.lastPropellantFraction * 100;
Profiler.EndSample();

// set produced thrust
if (multiplyThrustByFuelFrac)
Expand All @@ -438,30 +452,20 @@ virtual public void CalculateEngineParams()

// set fuel flow
fuelFlowGui = (float)(fuelFlow * 0.001d * mixtureDensityRecip / ratioSum); // Also in tons
if (fuelFlow > 1000d)
// If we're displaying in the wrong mode, swap
if (flowKG != (fuelFlow <= 1000))
{
fuelFlow *= 0.001d;
if (flowKG)
{
Fields["massFlowGui"].guiUnits = " ton/s";
flowKG = false;
}
}
else
{
if (!flowKG)
{
Fields["massFlowGui"].guiUnits = " kg/s";
flowKG = true;
}
flowKG = fuelFlow <= 1000;
Fields[nameof(massFlowGui)].guiUnits = flowKG ? " kg/s" : " ton/s";
}
if (fuelFlow > 1000d)
fuelFlow *= 0.001d;
massFlowGui = (float)fuelFlow;


realIsp = (float)isp;
}

finalThrust = (float)producedThrust * vessel.VesselValues.EnginePower.value;
Profiler.EndSample();
}

virtual public bool PropellantAvailable()
Expand Down
6 changes: 3 additions & 3 deletions SolverEngines/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("3.3.0.0")] // Don't change until breaking changes occur
[assembly: AssemblyFileVersion("3.12.0.0")]
[assembly: AssemblyVersion("3.13.0.0")] // Don't change until breaking changes occur
[assembly: AssemblyFileVersion("3.13.0.0")]

[assembly: KSPAssembly("SolverEngines", 3, 12, 0)]
[assembly: KSPAssembly("SolverEngines", 3, 13, 0)]
3 changes: 2 additions & 1 deletion SolverEngines/SolverEngines.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<DebugType>portable</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\GameData\SolverEngines\Plugins\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DefineConstants>TRACE;DEBUG;ENABLE_PROFILER</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
Expand All @@ -37,6 +37,7 @@
<ItemGroup>
<Compile Include="AJEInlet.cs" />
<Compile Include="AssemblyExtensions.cs" />
<Compile Include="DeferredEngineExhaustDamage.cs" />
<Compile Include="EngineAnimation.cs" />
<Compile Include="EngineFitting\AssemblyChecksumCache.cs" />
<Compile Include="EngineFitting\EngineDatabase.cs" />
Expand Down

0 comments on commit 2662bdb

Please sign in to comment.