From ae4a3766244208f13289325e180b74a88950acbf Mon Sep 17 00:00:00 2001
From: siimav <1120038+siimav@users.noreply.github.com>
Date: Thu, 20 Jun 2024 01:15:18 +0300
Subject: [PATCH] Integrate with the RP-1 config validation feature (#17)
---
.../RealAntennasCommNetParams.cfg | 20 +--
GameData/RealAntennas/RealismOverhaul.cfg | 20 +--
src/RealAntennasProject/ModuleRealAntenna.cs | 126 +++++++++++++++++-
src/RealAntennasProject/TechLevelInfo.cs | 17 ++-
src/RealAntennasProject/Tools.cs | 14 ++
5 files changed, 168 insertions(+), 29 deletions(-)
diff --git a/GameData/RealAntennas/RealAntennasCommNetParams.cfg b/GameData/RealAntennas/RealAntennasCommNetParams.cfg
index 46bd264..eba23ea 100644
--- a/GameData/RealAntennas/RealAntennasCommNetParams.cfg
+++ b/GameData/RealAntennas/RealAntennasCommNetParams.cfg
@@ -99,7 +99,7 @@ RealAntennasCommNetParams
}
TechLevelInfo
{
- name = TL0
+ name = commsTL0
Level = 0
Description = WW2-era
PowerEfficiency = 0.0555
@@ -116,7 +116,7 @@ RealAntennasCommNetParams
}
TechLevelInfo
{
- name = TL1
+ name = commsTL1
Level = 1
Description = Lunar Range Comms, 1956: 26m antenna 1958
PowerEfficiency = 0.0769
@@ -133,7 +133,7 @@ RealAntennasCommNetParams
}
TechLevelInfo
{
- name = TL2
+ name = commsTL2
Level = 2
Description = Digital Comms, 1959-1960
PowerEfficiency = 0.1
@@ -150,7 +150,7 @@ RealAntennasCommNetParams
}
TechLevelInfo
{
- name = TL3
+ name = commsTL3
Level = 3
Description = Interplanetary Comms, 1961-1963: Maser 1962, S/C noise reduction 1961 (300-3000K=10dB noise temp)
PowerEfficiency = 0.1304
@@ -167,7 +167,7 @@ RealAntennasCommNetParams
}
TechLevelInfo
{
- name = TL4
+ name = commsTL4
Level = 4
Description = Improved Comms, 1964-1966: 64m Antenna 1967
PowerEfficiency = 0.1667
@@ -184,7 +184,7 @@ RealAntennasCommNetParams
}
TechLevelInfo
{
- name = TL5
+ name = commsTL5
Level = 5
Description = Advanced Comms, 1967-1971: Noise reduction 1968, block coding 1969
PowerEfficiency = 0.2222
@@ -201,7 +201,7 @@ RealAntennasCommNetParams
}
TechLevelInfo
{
- name = TL6
+ name = commsTL6
Level = 6
Description = Deep Space Comms, 1971-1974: Antenna improvements 1971-1972, Convolutional coding ~1973
PowerEfficiency = 0.25
@@ -218,7 +218,7 @@ RealAntennasCommNetParams
}
TechLevelInfo
{
- name = TL7
+ name = commsTL7
Level = 7
Description = High Data Rate Comms, 1976-1980: X-Band ~1975, concatenated coding, MW noise reduction ~1980
PowerEfficiency = 0.3
@@ -235,7 +235,7 @@ RealAntennasCommNetParams
}
TechLevelInfo
{
- name = TL8
+ name = commsTL8
Level = 8
Description = Massive Scale Comms, 1986-1997: 70m antennas 1988
PowerEfficiency = 0.3724
@@ -252,7 +252,7 @@ RealAntennasCommNetParams
}
TechLevelInfo
{
- name = TL9
+ name = commsTL9
Level = 9
Description = Efficient Comms, 1998-2008: Super-cooled maser & feed 1995, Ka-band 2004
PowerEfficiency = 0.4397
diff --git a/GameData/RealAntennas/RealismOverhaul.cfg b/GameData/RealAntennas/RealismOverhaul.cfg
index 80f48c4..62a37da 100644
--- a/GameData/RealAntennas/RealismOverhaul.cfg
+++ b/GameData/RealAntennas/RealismOverhaul.cfg
@@ -153,7 +153,7 @@
!TechLevelInfo,* {}
TechLevelInfo
{
- name = TL0
+ name = commsTL0
Level = 0
Description = WW2-era
PowerEfficiency = 0.0555
@@ -170,7 +170,7 @@
}
TechLevelInfo
{
- name = TL1
+ name = commsTL1
Level = 1
Description = Lunar Range Comms, 1956: 26m antenna 1958
PowerEfficiency = 0.0769
@@ -187,7 +187,7 @@
}
TechLevelInfo
{
- name = TL2
+ name = commsTL2
Level = 2
Description = Digital Comms, 1959-1960
PowerEfficiency = 0.1
@@ -204,7 +204,7 @@
}
TechLevelInfo
{
- name = TL3
+ name = commsTL3
Level = 3
Description = Interplanetary Comms, 1961-1963: Maser 1962, S/C noise reduction 1961 (300-3000K=10dB noise temp)
PowerEfficiency = 0.1304
@@ -221,7 +221,7 @@
}
TechLevelInfo
{
- name = TL4
+ name = commsTL4
Level = 4
Description = Improved Comms, 1964-1966: 64m Antenna 1967
PowerEfficiency = 0.1667
@@ -238,7 +238,7 @@
}
TechLevelInfo
{
- name = TL5
+ name = commsTL5
Level = 5
Description = Advanced Comms, 1967-1971: Noise reduction 1968, block coding 1969
PowerEfficiency = 0.2222
@@ -255,7 +255,7 @@
}
TechLevelInfo
{
- name = TL6
+ name = commsTL6
Level = 6
Description = Deep Space Comms, 1971-1974: Antenna improvements 1971-1972, Convolutional coding ~1973
PowerEfficiency = 0.25
@@ -272,7 +272,7 @@
}
TechLevelInfo
{
- name = TL7
+ name = commsTL7
Level = 7
Description = High Data Rate Comms, 1976-1980: X-Band ~1975, concatenated coding, MW noise reduction ~1980
PowerEfficiency = 0.3
@@ -289,7 +289,7 @@
}
TechLevelInfo
{
- name = TL8
+ name = commsTL8
Level = 8
Description = Massive Scale Comms, 1986-1997: 70m antennas 1988
PowerEfficiency = 0.3724
@@ -306,7 +306,7 @@
}
TechLevelInfo
{
- name = TL9
+ name = commsTL9
Level = 9
Description = Efficient Comms, 1998-2008: Super-cooled maser & feed 1995, Ka-band 2004
PowerEfficiency = 0.4397
diff --git a/src/RealAntennasProject/ModuleRealAntenna.cs b/src/RealAntennasProject/ModuleRealAntenna.cs
index 7fef1d4..6bf760d 100644
--- a/src/RealAntennasProject/ModuleRealAntenna.cs
+++ b/src/RealAntennasProject/ModuleRealAntenna.cs
@@ -11,7 +11,7 @@ public class ModuleRealAntenna : ModuleDataTransmitter, IPartCostModifier, IPart
private const string PAWGroup = "RealAntennas";
private const string PAWGroupPlanner = "Antenna Planning";
[KSPField(guiActiveEditor = true, guiName = "Antenna", isPersistant = true, groupName = PAWGroup, groupDisplayName = PAWGroup),
- UI_Toggle(disabledText = "Disabled", enabledText = "Enabled", scene =UI_Scene.Editor)]
+ UI_Toggle(disabledText = "Disabled", enabledText = "Enabled", scene = UI_Scene.Editor)]
public bool _enabled = true;
[KSPField(guiActive = true, guiActiveEditor = true, guiName = "Gain", guiUnits = " dBi", guiFormat = "F1", groupName = PAWGroup, groupDisplayName = PAWGroup)]
@@ -70,6 +70,7 @@ public class ModuleRealAntenna : ModuleDataTransmitter, IPartCostModifier, IPart
public static float InactivePowerConsumptionMult = 0.1f;
private float DefaultPacketInterval = 1.0f;
private bool scienceMonitorActive = false;
+ private int actualMaxTechLevel = 0;
public float PowerDraw => RATools.LogScale(PowerDrawLinear);
public float PowerDrawLinear => RATools.LinearScale(TxPower) / RAAntenna.PowerEfficiency;
@@ -117,6 +118,7 @@ public override void OnSave(ConfigNode node)
public void OnDestroy()
{
GameEvents.OnGameSettingsApplied.Remove(ApplyGameSettings);
+ GameEvents.OnPartUpgradePurchased.Remove(OnPartUpgradePurchased);
}
public void Configure(ConfigNode node)
@@ -134,14 +136,19 @@ public override void OnStart(StartState state)
Fields[nameof(_enabled)].uiControlEditor.onFieldChanged = OnAntennaEnableChange;
(Fields[nameof(TxPower)].uiControlEditor as UI_FloatRange).maxValue = MaxTxPower;
- if (HighLogic.CurrentGame.Mode != Game.Modes.CAREER) maxTechLevel = HighLogic.CurrentGame.Parameters.CustomParams().MaxTechLevel;
- if (Fields[nameof(TechLevel)].uiControlEditor is UI_FloatRange fr)
+ actualMaxTechLevel = maxTechLevel; // maxTechLevel value can come from applied PartUpgrades
+ int maxLvlFromParams = HighLogic.CurrentGame.Parameters.CustomParams().MaxTechLevel;
+ if (HighLogic.CurrentGame.Mode != Game.Modes.CAREER)
{
- fr.maxValue = maxTechLevel;
- if (fr.maxValue == fr.minValue)
- fr.maxValue += 0.001f;
+ maxTechLevel = actualMaxTechLevel = maxLvlFromParams;
}
- if (TechLevel < 0) TechLevel = maxTechLevel;
+ else if (RATools.RP1Found)
+ {
+ // With RP-1 present, always allow selecting all TLs but validate the user choice on vessel getting built
+ maxTechLevel = maxLvlFromParams;
+ }
+ UpdateMaxTechLevelInUI();
+ if (TechLevel < 0) TechLevel = actualMaxTechLevel;
RAAntenna.Name = part.partInfo.title;
if (!RAAntenna.CanTarget)
@@ -158,6 +165,7 @@ public override void OnStart(StartState state)
SetupIdlePower();
RecalculateFields();
SetFieldVisibility(_enabled);
+ ApplyTLColoring();
if (HighLogic.LoadedSceneIsFlight)
{
@@ -165,6 +173,10 @@ public override void OnStart(StartState state)
if (_enabled)
GameEvents.OnGameSettingsApplied.Add(ApplyGameSettings);
}
+ else if (HighLogic.LoadedSceneIsEditor)
+ {
+ GameEvents.OnPartUpgradePurchased.Add(OnPartUpgradePurchased);
+ }
}
private void SetupIdlePower()
@@ -240,17 +252,29 @@ private void SetupUICallbacks()
Fields[nameof(plannerActiveTxTime)].uiControlEditor.onFieldChanged += OnPlannerActiveTxTimeChanged;
}
+ private void UpdateMaxTechLevelInUI()
+ {
+ if (Fields[nameof(TechLevel)].uiControlEditor is UI_FloatRange fr)
+ {
+ fr.maxValue = maxTechLevel;
+ if (fr.maxValue == fr.minValue)
+ fr.maxValue += 0.001f;
+ }
+ }
+
private void OnPlannerActiveTxTimeChanged(BaseField field, object obj) => RecalculatePlannerECConsumption();
private void OnAntennaEnableChange(BaseField field, object obj) { SetFieldVisibility(_enabled); RecalculatePlannerECConsumption(); }
private void OnRFBandChange(BaseField f, object obj) => RecalculateFields();
private void OnTxPowerChange(BaseField f, object obj) => RecalculateFields();
private void OnTechLevelChange(BaseField f, object obj) // obj is the OLD value
{
+ ApplyTLColoring();
string oldBand = RFBand;
ConfigBandOptions();
RecalculateFields();
if (!oldBand.Equals(RFBand)) MonoUtilities.RefreshPartContextWindow(part);
}
+
private void OnTechLevelChangeSymmetry(BaseField f, object obj) => ConfigBandOptions();
private void ApplyGameSettings()
@@ -258,6 +282,32 @@ private void ApplyGameSettings()
StockRateModifier = HighLogic.CurrentGame.Parameters.CustomParams().StockRateModifier;
}
+ ///
+ /// Handles TL PartUpgrade getting purchased in Editor scene
+ ///
+ ///
+ private void OnPartUpgradePurchased(PartUpgradeHandler.Upgrade upgd)
+ {
+ var tlInf = TechLevelInfo.GetTechLevel(upgd.name);
+ if (tlInf != null && tlInf.Level > actualMaxTechLevel)
+ {
+ actualMaxTechLevel = tlInf.Level;
+ if (!RATools.RP1Found) maxTechLevel = actualMaxTechLevel;
+ UpdateMaxTechLevelInUI();
+ ApplyTLColoring();
+ }
+ }
+
+ private void ApplyTLColoring()
+ {
+ if (HighLogic.LoadedSceneIsEditor)
+ {
+ BaseField f = Fields[nameof(TechLevel)];
+ f.guiFormat = techLevel > actualMaxTechLevel ? "''#''" : "N0";
+ f.guiName = techLevel > actualMaxTechLevel ? "Tech Level" : "Tech Level";
+ }
+ }
+
private void ConfigBandOptions()
{
List availableBands = new List();
@@ -389,5 +439,67 @@ private void RecalculatePlannerECConsumption()
double ec = _enabled ? RAAntenna.IdlePowerDraw + (RAAntenna.PowerDrawLinear * 1e-6 * plannerActiveTxTime) : 0;
plannerECConsumption = new KeyValuePair("ElectricCharge", -ec);
}
+
+ #region RP-1 integration
+ ///
+ /// Called from RP-1 VesselBuildValidator
+ ///
+ ///
+ ///
+ ///
+ ///
+ public virtual bool Validate(out string validationError, out bool canBeResolved, out float costToResolve, out string techToResolve)
+ {
+ validationError = null;
+ canBeResolved = false;
+ costToResolve = 0;
+ techToResolve = string.Empty;
+
+ if (!_enabled || techLevel <= actualMaxTechLevel) return true;
+
+ PartUpgradeHandler.Upgrade upgd = GetUpgradeForTL(techLevel);
+ if (PartUpgradeManager.Handler.IsAvailableToUnlock(upgd.name))
+ {
+ canBeResolved = true;
+ costToResolve = upgd.entryCost;
+ validationError = $"purchase {upgd.title}";
+ }
+ else
+ {
+ techToResolve = upgd.techRequired;
+ validationError = $"unlock tech {ResearchAndDevelopment.GetTechnologyTitle(upgd.techRequired)}";
+ }
+
+ return false;
+ }
+
+ ///
+ /// Called from RP-1 VesselBuildValidator
+ ///
+ ///
+ public virtual bool ResolveValidationError()
+ {
+ PartUpgradeHandler.Upgrade upgd = GetUpgradeForTL(techLevel);
+ if (upgd == null)
+ return false;
+ return PurchaseConfig(upgd);
+ }
+
+ private static bool PurchaseConfig(PartUpgradeHandler.Upgrade upgd)
+ {
+ CurrencyModifierQuery cmq = CurrencyModifierQuery.RunQuery(TransactionReasons.RnDPartPurchase, -upgd.entryCost, 0, 0);
+ if (!cmq.CanAfford())
+ return false;
+ PartUpgradeManager.Handler.SetUnlocked(upgd.name, true);
+ GameEvents.OnPartUpgradePurchased.Fire(upgd);
+ return true;
+ }
+
+ private static PartUpgradeHandler.Upgrade GetUpgradeForTL(int techLevel)
+ {
+ TechLevelInfo tlInf = TechLevelInfo.GetTechLevel(techLevel);
+ return PartUpgradeManager.Handler.GetUpgrade(tlInf.name);
+ }
+ #endregion
}
}
\ No newline at end of file
diff --git a/src/RealAntennasProject/TechLevelInfo.cs b/src/RealAntennasProject/TechLevelInfo.cs
index 8b3bf1f..6b106a7 100644
--- a/src/RealAntennasProject/TechLevelInfo.cs
+++ b/src/RealAntennasProject/TechLevelInfo.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using UniLinq;
using UnityEngine;
namespace RealAntennas
@@ -48,8 +49,7 @@ public static void Init(ConfigNode config)
public static TechLevelInfo GetTechLevel(int i)
{
- if (!initialized)
- Init(GameDatabase.Instance.GetConfigNode("RealAntennas/RealAntennasCommNetParams/RealAntennasCommNetParams"));
+ EnsureInitialized();
i = Mathf.Clamp(i, 0, MaxTL);
if (All.TryGetValue(i, out TechLevelInfo info))
{
@@ -57,5 +57,18 @@ public static TechLevelInfo GetTechLevel(int i)
}
return All[0];
}
+
+ public static TechLevelInfo GetTechLevel(string name)
+ {
+ EnsureInitialized();
+ // Note: consider a separate dictionary if the lookups start getting called from hot paths
+ return All.Values.FirstOrDefault(inf => inf.name == name);
+ }
+
+ private static void EnsureInitialized()
+ {
+ if (!initialized)
+ Init(GameDatabase.Instance.GetConfigNode("RealAntennas/RealAntennasCommNetParams/RealAntennasCommNetParams"));
+ }
}
}
diff --git a/src/RealAntennasProject/Tools.cs b/src/RealAntennasProject/Tools.cs
index 83a8ac2..2ab5172 100644
--- a/src/RealAntennasProject/Tools.cs
+++ b/src/RealAntennasProject/Tools.cs
@@ -8,6 +8,20 @@ namespace RealAntennas
{
public class RATools : object
{
+ private static bool? _RP1Found = null;
+ public static bool RP1Found
+ {
+ get
+ {
+ if (!_RP1Found.HasValue)
+ {
+ var assembly = AssemblyLoader.loadedAssemblies.FirstOrDefault(a => a.assembly.GetName().Name == "RP0")?.assembly;
+ _RP1Found = assembly != null;
+ }
+ return _RP1Found.Value;
+ }
+ }
+
public static double LinearScale(double x) => math.pow(10, x / 10);
public static float LinearScale(float x) => math.pow(10, x / 10);
public static double LogScale(double x) => 10 * math.log10(x);