Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

updates to proc avi from master #669

Merged
merged 8 commits into from
Jun 1, 2017
Binary file modified GameData/RP-0/Plugins/RP0.dll
Binary file not shown.
13 changes: 12 additions & 1 deletion GameData/RP-0/ProceduralAvionics.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,18 @@
AVIONICSCONFIG
{
name = probeCore


TECHLIMIT # Early controllable core
{
name = stability
tonnageToMassRatio = 3.072
costPerControlledTon = 4998
enabledProceduralW = 250
disabledProceduralW = 5
standardAvionicsDensity = 1.24
SASServiceLevel = 1
hasScienceContainer = true
}
TECHLIMIT # Ranger Block I Core
{
name = basicScience
Expand Down
179 changes: 110 additions & 69 deletions Source/ProceduralAvionics/ModuleProceduralAvionics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ class ModuleProceduralAvionics : ModuleAvionics, IPartMassModifier, IPartCostMod
// This controls how much the current part can control (in metric tons)
[KSPField(isPersistant = true, guiName = "Tonnage", guiActive = false, guiActiveEditor = true, guiUnits = "T"),
UI_FloatEdit(scene = UI_Scene.Editor, minValue = 0f, incrementLarge = 10f, incrementSmall = 1f, incrementSlide = 0.05f, sigFigs = 2, unit = "T")]
public float proceduralMassLimit = 1;
private float oldProceduralMassLimit = 1;
public float proceduralMassLimit = 0;
private float oldProceduralMassLimit = 0;

// We can have multiple configurations of avionics, for example:
// boosters can have a high EC usage, but lower cost and mass
Expand Down Expand Up @@ -90,6 +90,16 @@ private float GetCurrentDensity()

protected override float GetInternalMassLimit()
{
var max = GetMaximumControllableTonnage();
var min = GetMinimumControllableTonnage();
if (proceduralMassLimit > max) {
Log("Resetting procedural mass limit to max of ", max.ToString());
proceduralMassLimit = max;
}
if (proceduralMassLimit < min) {
proceduralMassLimit = min;
Log("Resetting procedural mass limit to min of ", min.ToString());
}
return proceduralMassLimit;
}

Expand All @@ -115,7 +125,6 @@ protected override string GetTonnageString()

private ProceduralAvionicsConfig currentProceduralAvionicsConfig;
private UI_FloatEdit proceduralMassLimitEdit;
private bool needsTechInit = true;

[SerializeField]
public byte[] proceduralAvionicsConfigsSerialized; //public so it will persist from loading to using it
Expand All @@ -137,17 +146,51 @@ public override void OnLoad(ConfigNode node)
}
}

public void FixedUpdate()
public new void Start()
{
if (HighLogic.LoadedSceneIsEditor) {
DeserializeObjects();
UpdateMaxValues();
UpdateCurrentConfig();
VerifyPart();
Log("Start called");
DeserializeObjects();
InitializeTechLimits();
UpdateConfigSliders();
BindUIChangeCallbacks();


UpdateMaxValues();
UpdateCurrentConfig();
VerifyPart();

SetInternalKSPFields();

SetInternalKSPFields();
base.Start();
Log("Start finished");
}

private bool callbacksBound = false;
private void BindUIChangeCallbacks()
{
if (!callbacksBound) {
string[] editorNames = new string[] { "proceduralMassLimit", "avionicsConfigName" };
foreach (var editorName in editorNames) {
Fields[editorName].uiControlEditor.onFieldChanged += UIChanged;
}
callbacksBound = true;
}
else {

}

private void UIChanged(BaseField arg1, object arg2)
{
GetInternalMassLimit(); //reset within bounds
UpdateMaxValues();
UpdateCurrentConfig();
VerifyPart();

SetInternalKSPFields();
}

public void FixedUpdate()
{
if (!HighLogic.LoadedSceneIsEditor) {
SetSASServiceLevel();
SetScienceContainer();
}
Expand Down Expand Up @@ -187,7 +230,6 @@ private void DeserializeObjects()
proceduralAvionicsConfigs.Add(item.name, item);
}
Log("Deserialized ", proceduralAvionicsConfigs.Count.ToString(), " configs");

}
}

Expand Down Expand Up @@ -226,12 +268,13 @@ private float CalculateNewMass()
}
if (CurrentProceduralAvionicsConfig != null) {
//Standard density is 4/3s of maximum density
//Log("Current Tech node standard density: ", CurrentProceduralAvionicsTechNode.standardAvionicsDensity.ToString());
maxDensityOfAvionics = (CurrentProceduralAvionicsTechNode.standardAvionicsDensity * 4) / 3;
tonnageToMassRatio = CurrentProceduralAvionicsTechNode.tonnageToMassRatio;
return DoMassCalculation();
}
else {
//Log("Cannot compute mass yet");
Log("Cannot compute mass yet");
return 0;
}
}
Expand All @@ -240,12 +283,12 @@ private float DoMassCalculation()
{
float controllablePercentage = GetControllableUtilizationPercentage();
float massPercentage = (-1 * controllablePercentage * controllablePercentage) + (2 * controllablePercentage);
return massPercentage * GetCurrentVolume() * GetCurrentDensity();
float result = massPercentage * cachedVolume * GetCurrentDensity();
return result;
}

private float CalculateCost()
{

if (HighLogic.LoadedSceneIsFlight) {
return DoCostCalculation();
}
Expand All @@ -254,7 +297,7 @@ private float CalculateCost()
return DoCostCalculation();
}
else {
//Log("Cannot compute cost yet");
Log("Cannot compute cost yet");
return 0;
}
}
Expand All @@ -263,7 +306,7 @@ private float DoCostCalculation()
{
float controllablePercentage = GetControllableUtilizationPercentage();
float costPercentage = controllablePercentage * controllablePercentage;
return costPerControlledTon * 4 * costPercentage * proceduralMassLimit;
return costPerControlledTon * 4 * costPercentage * GetInternalMassLimit();
}

private float GetResourceRateMultiplier()
Expand All @@ -275,18 +318,23 @@ private float GetResourceRateMultiplier()
#region private utiliy functions
private float GetControllableUtilizationPercentage()
{
return proceduralMassLimit / (GetCurrentVolume() * maxDensityOfAvionics * tonnageToMassRatio * 2);
return GetInternalMassLimit() / (cachedVolume * maxDensityOfAvionics * tonnageToMassRatio * 2);
}

private float GetMaximumControllableTonnage()
{
var maxAvionicsMass = GetCurrentVolume() * maxDensityOfAvionics;
var maxForVolume = maxAvionicsMass * tonnageToMassRatio * 2;
return Math.Min(maxForVolume, maximumTonnage);
var maxAvionicsMass = cachedVolume * maxDensityOfAvionics;
var maxForVolume = UtilMath.RoundToPlaces(maxAvionicsMass * tonnageToMassRatio * 2, 2);
var maxControllableTonnage = Math.Min(maxForVolume, maximumTonnage);
//Log("Max contrallabe Tonnage is ", maxControllableTonnage.ToString());
return maxControllableTonnage;
}

private float GetMinimumControllableTonnage()
{
if (CurrentProceduralAvionicsTechNode != null) {
return CurrentProceduralAvionicsTechNode.minimumTonnage;
}
return minimumTonnage;
}

Expand All @@ -298,36 +346,40 @@ private void UpdateMaxValues()
proceduralMassLimitEdit = (UI_FloatEdit)Fields["proceduralMassLimit"].uiControlEditor;
}

if (needsTechInit) {
InitializeTechLimits();
UpdateConfigSliders();
}

if (CurrentProceduralAvionicsConfig != null) {

tonnageToMassRatio = CurrentProceduralAvionicsTechNode.tonnageToMassRatio;
proceduralMassLimitEdit.maxValue = GetMaximumControllableTonnage();
proceduralMassLimitEdit.minValue = GetMinimumControllableTonnage();

// Set slide, small, and large slider increments to be 0.025%, 1%, and 10%
// Set slide, small, and large slider increments to be (at most) 0.025%, 1%, and 10%
var procMassDelta = proceduralMassLimitEdit.maxValue - proceduralMassLimitEdit.minValue;
proceduralMassLimitEdit.incrementSlide = procMassDelta / 4000;
proceduralMassLimitEdit.incrementSmall = procMassDelta / 100;
proceduralMassLimitEdit.incrementLarge = procMassDelta / 10;

//we'll start at a large incerement of 1, and work up from there
int largeIncrement = 1;
while (largeIncrement < procMassDelta) {
largeIncrement *= 2;
}

float largeIncFloat = (float)largeIncrement;

proceduralMassLimitEdit.incrementSlide = largeIncFloat / 4000;
proceduralMassLimitEdit.incrementSmall = largeIncFloat / 100;
proceduralMassLimitEdit.incrementLarge = largeIncFloat / 10;

//There's some weirdness going on here that makes the slider not match up with min and max values,
//but it's so small i don't think i need to investigate it further
}
else {
//Log("Cannot update max value yet");
Log("Cannot update max value yet, CurrentProceduralAvionicsConfig is null");
proceduralMassLimitEdit.maxValue = float.MaxValue;
proceduralMassLimitEdit.minValue = 0;
}
if (proceduralMassLimit > proceduralMassLimitEdit.maxValue) {
Log("Lowering procedural mass limit to new max value of ", proceduralMassLimitEdit.maxValue.ToString());
proceduralMassLimit = proceduralMassLimitEdit.maxValue;
// Don't know how to force the gui to refresh this
}
}

private void UpdateConfigSliders()
{
Log("Updating Config Slider");
BaseField avionicsConfigField = Fields["avionicsConfigName"];
avionicsConfigField.guiActiveEditor = true;
UI_ChooseOption range = (UI_ChooseOption)avionicsConfigField.uiControlEditor;
Expand All @@ -337,7 +389,6 @@ private void UpdateConfigSliders()
avionicsConfigName = proceduralAvionicsConfigs.Keys.First();
Log("Defaulted config to ", avionicsConfigName);
}

}

private void InitializeTechLimits()
Expand Down Expand Up @@ -372,7 +423,7 @@ private void InitializeTechLimits()
}

}
needsTechInit = false;
Log("Tech limits initialized");
}

private ProceduralAvionicsTechNode GetBestTechConfig(Dictionary<String, ProceduralAvionicsTechNode> techNodes, bool limitToCurrentTech)
Expand All @@ -393,50 +444,42 @@ private ProceduralAvionicsTechNode GetBestTechConfig(Dictionary<String, Procedur

private void VerifyPart()
{
if (proceduralMassLimit == oldProceduralMassLimit) {
if (GetInternalMassLimit() == oldProceduralMassLimit) {
return;
}
Log("verifying part");

var maxAvionicsMass = GetCurrentVolume() * maxDensityOfAvionics;
Log("Volume: ", cachedVolume.ToString());

//This has a side effect of setting maxDensityOfAvionics, so we need to call that first
CalculateNewMass();
Log("maxDensityOfAvionics: ", maxDensityOfAvionics.ToString());
var maxAvionicsMass = cachedVolume * maxDensityOfAvionics;
Log("new mass would be ", CalculateNewMass().ToString(), ", max avionics mass is ", maxAvionicsMass.ToString());
if (maxAvionicsMass < CalculateNewMass()) {
proceduralMassLimit = oldProceduralMassLimit;
Log("resetting part");
}
else {
oldProceduralMassLimit = proceduralMassLimit;
oldProceduralMassLimit = GetInternalMassLimit();
Log("part verified");
}
}

private float cachedVolume = 0;
private float cachedVolume = float.MaxValue;

// Using reflection to see if this is a procedural part (that way, we don't need to have procedur parts as a dependency
private float GetCurrentVolume()
[KSPEvent]
public void OnPartVolumeChanged(BaseEventData eventData)
{
// Volume won't change in flight, so we'll cache this, so we're not using reflection all the time
if (HighLogic.LoadedSceneIsFlight && cachedVolume > 0) {
return cachedVolume;
Log("OnPartVolumeChanged called");
try {
cachedVolume = (float)eventData.Get<double>("newTotalVolume");
//Log("cached total volume set from eventData: ", cachedVolume.ToString());
UIChanged(null, null);
}

// Honestly, if you're not using procedural parts, then this is going to do some really funky things.
// It's going to look like you have all this room to put stuff in, and thus aren't really worried
// about "efficiency". Your cost will be low, but your mass will be a lot higher than it would be expected.
float currentShapeVolume = float.MaxValue;

foreach (var module in part.Modules) {
var moduleType = module.GetType();
if (moduleType.FullName == "ProceduralParts.ProceduralPart") {
// This would spam the logs unless we do some old/current caching.
//Log("Procedural Parts detected");
var reflectedShape = moduleType.GetProperty("CurrentShape").GetValue(module, null);
currentShapeVolume = (float)reflectedShape.GetType().GetProperty("Volume").GetValue(reflectedShape, null);
}
catch (Exception ex) {
Log("error getting changed volume: ", ex.ToString());
}

cachedVolume = currentShapeVolume;
return currentShapeVolume;
}

private void SetInternalKSPFields()
Expand Down Expand Up @@ -493,7 +536,6 @@ private void SetSASServiceLevel()
}
}


private bool scienceContainerFiltered = false;
private void SetScienceContainer()
{
Expand All @@ -516,13 +558,13 @@ private void SetScienceContainer()
private void UpdateCostAndMassDisplays()
{
if (!ppFieldsHidden) {
ppFieldsHidden = HideField(TCSmoduleName, "massDisplay") && HideField(TCSmoduleName , "volumeDisplay");
ppFieldsHidden = HideField(TCSmoduleName, "massDisplay") && HideField(TCSmoduleName, "volumeDisplay");
}

float baseCost = GetBaseCost();
float baseMass = GetBaseMass();
massDisplay = MathUtils.FormatMass(baseMass + GetModuleMass(0, ModifierStagingSituation.CURRENT));
costDisplay = (baseCost + GetModuleCost(0, ModifierStagingSituation.CURRENT)).ToString();
massDisplay = MathUtils.FormatMass(baseMass + CalculateNewMass());
costDisplay = (baseCost + CalculateCost()).ToString();
}

private bool HideField(string moduleName, string fieldName)
Expand Down Expand Up @@ -570,7 +612,6 @@ private float GetBaseMass()
if (tcsModule != null) {
var tcsMassModule = (IPartMassModifier)tcsModule;
return tcsMassModule.GetModuleMass(0, ModifierStagingSituation.CURRENT);

}
else {
Log("Module ", TCSmoduleName, " not found");
Expand Down