Skip to content

Commit

Permalink
Support permanently disabling antennas in-flight (#28)
Browse files Browse the repository at this point in the history
* Add Antenna Condition enum to be used in place of `_enabled`

* Add UI options for permanently disabling antennas
  • Loading branch information
siimav authored Aug 18, 2024
1 parent fb11f6e commit 5dc8e13
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 24 deletions.
4 changes: 4 additions & 0 deletions GameData/RealAntennas/KSPCommunityFixes.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
@KSP_COMMUNITY_FIXES:FOR[RealAntennas]
{
@ModUpgradePipeline = true
}
94 changes: 73 additions & 21 deletions src/RealAntennasProject/ModuleRealAntenna.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,27 @@

namespace RealAntennas
{
[Flags]
public enum AntennaCondition
{
Enabled = 1 << 0,
Disabled = 1 << 1,
PermanentShutdown = 1 << 2,
Broken = 1 << 3
}

public class ModuleRealAntenna : ModuleDataTransmitter, IPartCostModifier, IPartMassModifier
{
private const string PAWGroup = "RealAntennas";
private const string PAWGroupPlanner = "Antenna Planning";
[KSPField(guiActiveEditor = true, guiName = "Antenna", isPersistant = true, groupName = PAWGroup, groupDisplayName = PAWGroup),

[KSPField(guiActiveEditor = true, guiName = "Antenna", groupName = PAWGroup, groupDisplayName = PAWGroup),
UI_Toggle(disabledText = "<color=red><b>Disabled</b></color>", enabledText = "<color=green>Enabled</color>", scene = UI_Scene.Editor)]
public bool _enabled = true;

[KSPField(guiActiveEditor = false, guiActive = true, guiName = "Condition", isPersistant = true, groupName = PAWGroup, groupDisplayName = PAWGroup)]
public AntennaCondition Condition = AntennaCondition.Enabled;

[KSPField(guiActive = true, guiActiveEditor = true, guiName = "Gain", guiUnits = " dBi", guiFormat = "F1", groupName = PAWGroup, groupDisplayName = PAWGroup)]
public float Gain; // Physical directionality, measured in dBi

Expand Down Expand Up @@ -136,6 +149,8 @@ public override void OnStart(StartState state)
Fields[nameof(_enabled)].uiControlEditor.onFieldChanged = OnAntennaEnableChange;
(Fields[nameof(TxPower)].uiControlEditor as UI_FloatRange).maxValue = MaxTxPower;

_enabled = Condition != AntennaCondition.Disabled;

actualMaxTechLevel = maxTechLevel; // maxTechLevel value can come from applied PartUpgrades
int maxLvlFromParams = HighLogic.CurrentGame.Parameters.CustomParams<RAParameters>().MaxTechLevel;
if (HighLogic.CurrentGame.Mode != Game.Modes.CAREER)
Expand Down Expand Up @@ -164,13 +179,13 @@ public override void OnStart(StartState state)
ConfigBandOptions();
SetupIdlePower();
RecalculateFields();
SetFieldVisibility(_enabled);
SetFieldVisibility();
ApplyTLColoring();

if (HighLogic.LoadedSceneIsFlight)
{
isEnabled = _enabled;
if (_enabled)
isEnabled = Condition != AntennaCondition.Disabled;
if (isEnabled)
GameEvents.OnGameSettingsApplied.Add(ApplyGameSettings);
}
else if (HighLogic.LoadedSceneIsEditor)
Expand All @@ -181,18 +196,18 @@ public override void OnStart(StartState state)

private void SetupIdlePower()
{
if (HighLogic.LoadedSceneIsFlight && _enabled)
if (HighLogic.LoadedSceneIsFlight && Condition != AntennaCondition.Disabled)
{
var electricCharge = resHandler.inputResources.First(x => x.id == PartResourceLibrary.ElectricityHashcode);
electricCharge.rate = (Kerbalism.Kerbalism.KerbalismAssembly is null) ? RAAntenna.IdlePowerDraw : 0;
electricCharge.rate = Condition != AntennaCondition.PermanentShutdown && (Kerbalism.Kerbalism.KerbalismAssembly is null) ? RAAntenna.IdlePowerDraw : 0;
string err = "";
resHandler.UpdateModuleResourceInputs(ref err, 1, 1, false, false);
}
}

public void FixedUpdate()
{
if (HighLogic.LoadedSceneIsFlight && _enabled)
if (HighLogic.LoadedSceneIsFlight && Condition != AntennaCondition.Disabled && Condition != AntennaCondition.PermanentShutdown)
{
RAAntenna.AMWTemp = (AMWTemp > 0) ? AMWTemp : Convert.ToSingle(part.temperature);
//part.AddThermalFlux(req / Time.fixedDeltaTime);
Expand Down Expand Up @@ -231,16 +246,24 @@ private void SetupBaseFields()
if (Fields[nameof(powerText)] is BaseField bf) bf.guiActive = bf.guiActiveEditor = false; // "Antenna Rating"
}

private void SetFieldVisibility(bool en)
private void SetFieldVisibility()
{
Fields[nameof(Gain)].guiActiveEditor = Fields[nameof(Gain)].guiActive = en;
Fields[nameof(TxPower)].guiActiveEditor = Fields[nameof(TxPower)].guiActive = en;
Fields[nameof(TechLevel)].guiActiveEditor = Fields[nameof(TechLevel)].guiActive = en;
Fields[nameof(RFBand)].guiActiveEditor = Fields[nameof(RFBand)].guiActive = en;
Fields[nameof(sActivePowerConsumed)].guiActiveEditor = Fields[nameof(sActivePowerConsumed)].guiActive = en;
Fields[nameof(sIdlePowerConsumed)].guiActiveEditor = Fields[nameof(sIdlePowerConsumed)].guiActive = en;
Fields[nameof(sAntennaTarget)].guiActive = en;
bool showFields = Condition != AntennaCondition.Disabled && Condition != AntennaCondition.PermanentShutdown;
Fields[nameof(Gain)].guiActiveEditor = Fields[nameof(Gain)].guiActive = showFields;
Fields[nameof(TxPower)].guiActiveEditor = Fields[nameof(TxPower)].guiActive = showFields;
Fields[nameof(TechLevel)].guiActiveEditor = Fields[nameof(TechLevel)].guiActive = showFields;
Fields[nameof(RFBand)].guiActiveEditor = Fields[nameof(RFBand)].guiActive = showFields;
Fields[nameof(sActivePowerConsumed)].guiActiveEditor = Fields[nameof(sActivePowerConsumed)].guiActive = showFields;
Fields[nameof(sIdlePowerConsumed)].guiActiveEditor = Fields[nameof(sIdlePowerConsumed)].guiActive = showFields;
Fields[nameof(sAntennaTarget)].guiActive = showFields;
Fields[nameof(plannerActiveTxTime)].guiActiveEditor = Kerbalism.Kerbalism.KerbalismAssembly is System.Reflection.Assembly;
Actions[nameof(PermanentShutdownAction)].active = showFields;
Events[nameof(PermanentShutdownEvent)].guiActive = showFields;
Events[nameof(PermanentShutdownEvent)].active = showFields;
Events[nameof(AntennaPlanningGUI)].active = showFields;
Events[nameof(AntennaPlanningGUI)].guiActive = showFields;
Events[nameof(DebugAntenna)].active = showFields;
Events[nameof(DebugAntenna)].guiActive = showFields;
}

private void SetupUICallbacks()
Expand All @@ -263,7 +286,12 @@ private void UpdateMaxTechLevelInUI()
}

private void OnPlannerActiveTxTimeChanged(BaseField field, object obj) => RecalculatePlannerECConsumption();
private void OnAntennaEnableChange(BaseField field, object obj) { SetFieldVisibility(_enabled); RecalculatePlannerECConsumption(); }
private void OnAntennaEnableChange(BaseField field, object obj)
{
Condition = _enabled ? AntennaCondition.Enabled : AntennaCondition.Disabled;
SetFieldVisibility();
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
Expand All @@ -277,6 +305,29 @@ private void OnTechLevelChange(BaseField f, object obj) // obj is the OLD va

private void OnTechLevelChangeSymmetry(BaseField f, object obj) => ConfigBandOptions();

[KSPEvent(guiActive = true, guiActiveEditor = false, guiName = "Disable antenna permanently", groupName = PAWGroup)]
public void PermanentShutdownEvent()
{
var options = new DialogGUIBase[] {
new DialogGUIButton("Yes", () => PermanentShutdownAction(null)),
new DialogGUIButton("No", () => {})
};
var dialog = new MultiOptionDialog("ConfirmDisableAntenna", "Are you sure you want to permanently disable the antenna? Doing this will prevent it from consuming power but the operation is irreversible.", "Disable antenna", HighLogic.UISkin, 300, options);
PopupDialog.SpawnPopupDialog(dialog, true, HighLogic.UISkin);
}

[KSPAction("Disable antenna permanently")]
public void PermanentShutdownAction(KSPActionParam _)
{
_enabled = false;
Condition = AntennaCondition.PermanentShutdown;
SetFieldVisibility();
SetupIdlePower();
GameEvents.onVesselWasModified.Fire(vessel); // Need to notify RACommNetVessel about disabling antennas
RACommNetScenario scen = RACommNetScenario.Instance as RACommNetScenario;
scen?.Network?.ResetNetwork();
}

private void ApplyGameSettings()
{
StockRateModifier = HighLogic.CurrentGame.Parameters.CustomParams<RAParameters>().StockRateModifier;
Expand Down Expand Up @@ -343,7 +394,7 @@ public override string GetInfo()
return res;
}

public override bool CanComm() => base.CanComm() && (!Deployable || Deployed);
public override bool CanComm() => Condition == AntennaCondition.Enabled && (!Deployable || Deployed) && base.CanComm();

public override string ToString() => RAAntenna.ToString();

Expand Down Expand Up @@ -419,9 +470,9 @@ private IEnumerator StockScienceFixer()

#region Cost and Mass Modifiers
public float GetModuleCost(float defaultCost, ModifierStagingSituation sit) =>
_enabled ? RAAntenna.TechLevelInfo.BaseCost + (RAAntenna.TechLevelInfo.CostPerWatt * RATools.LinearScale(TxPower)/1000) : 0;
Condition != AntennaCondition.Disabled ? RAAntenna.TechLevelInfo.BaseCost + (RAAntenna.TechLevelInfo.CostPerWatt * RATools.LinearScale(TxPower)/1000) : 0;
public float GetModuleMass(float defaultMass, ModifierStagingSituation sit) =>
_enabled && applyMassModifier ? (RAAntenna.TechLevelInfo.BaseMass + (RAAntenna.TechLevelInfo.MassPerWatt * RATools.LinearScale(TxPower) / 1000)) / 1000 : 0;
Condition != AntennaCondition.Disabled && applyMassModifier ? (RAAntenna.TechLevelInfo.BaseMass + (RAAntenna.TechLevelInfo.MassPerWatt * RATools.LinearScale(TxPower) / 1000)) / 1000 : 0;
public ModifierChangeWhen GetModuleCostChangeWhen() => ModifierChangeWhen.FIXED;
public ModifierChangeWhen GetModuleMassChangeWhen() => ModifierChangeWhen.FIXED;
#endregion
Expand All @@ -435,8 +486,9 @@ public string PlannerUpdate(List<KeyValuePair<string, double>> resources, Celest
}
private void RecalculatePlannerECConsumption()
{
bool consumesPower = Condition != AntennaCondition.Disabled && Condition != AntennaCondition.PermanentShutdown;
// RAAntenna.IdlePowerDraw is in kW (ec/s), PowerDrawLinear is in mW
double ec = _enabled ? RAAntenna.IdlePowerDraw + (RAAntenna.PowerDrawLinear * 1e-6 * plannerActiveTxTime) : 0;
double ec = consumesPower ? RAAntenna.IdlePowerDraw + (RAAntenna.PowerDrawLinear * 1e-6 * plannerActiveTxTime) : 0;
plannerECConsumption = new KeyValuePair<string, double>("ElectricCharge", -ec);
}

Expand All @@ -455,7 +507,7 @@ public virtual bool Validate(out string validationError, out bool canBeResolved,
costToResolve = 0;
techToResolve = string.Empty;

if (!_enabled || techLevel <= actualMaxTechLevel) return true;
if (Condition == AntennaCondition.Disabled || techLevel <= actualMaxTechLevel) return true;

PartUpgradeHandler.Upgrade upgd = GetUpgradeForTL(techLevel);
if (PartUpgradeManager.Handler.IsAvailableToUnlock(upgd.name))
Expand Down
2 changes: 1 addition & 1 deletion src/RealAntennasProject/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("2.4.0.0")]
[assembly: AssemblyVersion("2.6.0.0")]
#if CIBUILD
[assembly: AssemblyFileVersion("@MAJOR@.@MINOR@.@PATCH@.@BUILD@")]
[assembly: KSPAssembly("RealAntennas", @MAJOR@, @MINOR@)]
Expand Down
7 changes: 5 additions & 2 deletions src/RealAntennasProject/RACommNetVessel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ protected List<RealAntenna> DiscoverAntennas()
{
foreach (ModuleRealAntenna ant in Vessel.FindPartModulesImplementing<ModuleRealAntenna>().ToList())
{
if (ant._enabled)
if (ant.Condition == AntennaCondition.Enabled)
{
ant.RAAntenna.ParentNode = Comm;
if (DeployedLoaded(ant.part)) antennaList.Add(ant.RAAntenna);
Expand All @@ -192,7 +192,10 @@ protected List<RealAntenna> DiscoverAntennas()
foreach (ProtoPartModuleSnapshot snap in part.modules.Where(x => x.moduleName == ModuleRealAntenna.ModuleName))
{
bool _enabled = true;
snap.moduleValues.TryGetValue(nameof(ModuleRealAntenna._enabled), ref _enabled);
string sState = null;
if (snap.moduleValues.TryGetValue(nameof(ModuleRealAntenna.Condition), ref sState))
_enabled = sState == AntennaCondition.Enabled.ToString();

// Doesn't get the correct PartModule if multiple, but the only impact is the name, which defaults to the part anyway.
if (_enabled && part.partInfo.partPrefab.FindModuleImplementing<ModuleRealAntenna>() is ModuleRealAntenna mra && mra.CanCommUnloaded(snap))
{
Expand Down
1 change: 1 addition & 0 deletions src/RealAntennasProject/RealAntennas.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
<Compile Include="Tools.cs" />
<Compile Include="Network\RACommNetNetwork.cs" />
<Compile Include="RACommNode.cs" />
<Compile Include="UpgradeScripts\v2_6_AntennaState.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="Assembly-CSharp" />
Expand Down
65 changes: 65 additions & 0 deletions src/RealAntennasProject/UpgradeScripts/v2_6_AntennaState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using SaveUpgradePipeline;
using System;

namespace RealAntennas.UpgradeScripts
{
[UpgradeModule(LoadContext.SFS | LoadContext.Craft, sfsNodeUrl = "GAME/FLIGHTSTATE/VESSEL/PART", craftNodeUrl = "PART")]
public class v2_6_AntennaState : UpgradeScript
{
public override string Name => "RealAntennas Antenna Condition upgrader";
public override string Description => "Update crafts to use new condition enum";
public override Version EarliestCompatibleVersion => new Version(1, 0, 0);
public override Version TargetVersion => new Version(2, 6, 0);

public override TestResult OnTest(ConfigNode node, LoadContext loadContext, ref string nodeName)
{
nodeName = NodeUtil.GetPartNodeNameValue(node, loadContext);
if (node.GetNode("MODULE", "name", nameof(ModuleRealAntenna)) is ConfigNode mecNode)
return TestResult.Upgradeable;
return TestResult.Pass;
}

public override void OnUpgrade(ConfigNode node, LoadContext loadContext, ConfigNode parentNode)
{
var pmNode = node.GetNode("MODULE", "name", nameof(ModuleRealAntenna));
var v = pmNode.GetValue("_enabled");
var newState = string.Equals(v, "false", StringComparison.OrdinalIgnoreCase) ? AntennaCondition.Disabled : AntennaCondition.Enabled;
pmNode.AddValue(nameof(ModuleRealAntenna.Condition), newState.ToString());
pmNode.RemoveValue("_enabled");
}
}

public class v2_6_AntennaState_KCTBase : v2_6_AntennaState
{
public override string Name { get => $"{base.Name} KCT-{nodeUrlSFS}"; }
public override TestResult OnTest(ConfigNode node, LoadContext loadContext, ref string nodeName) =>
loadContext == LoadContext.Craft ? TestResult.Pass : base.OnTest(node, loadContext, ref nodeName);
}

[UpgradeModule(LoadContext.SFS, sfsNodeUrl = "GAME/SCENARIO/KSC/VABList/KCTVessel/ShipNode/PART")]
public class v2_6_AntennaState_KCT1 : v2_6_AntennaState_KCTBase { }

[UpgradeModule(LoadContext.SFS, sfsNodeUrl = "GAME/SCENARIO/KSC/SPHList/KCTVessel/ShipNode/PART")]
public class v2_6_AntennaState_KCT2 : v2_6_AntennaState_KCTBase { }

[UpgradeModule(LoadContext.SFS, sfsNodeUrl = "GAME/SCENARIO/KSC/VABWarehouse/KCTVessel/ShipNode/PART")]
public class v2_6_AntennaState_KCT3 : v2_6_AntennaState_KCTBase { }

[UpgradeModule(LoadContext.SFS, sfsNodeUrl = "GAME/SCENARIO/KSC/SPHWarehouse/KCTVessel/ShipNode/PART")]
public class v2_6_AntennaState_KCT4 : v2_6_AntennaState_KCTBase { }

[UpgradeModule(LoadContext.SFS, sfsNodeUrl = "GAME/SCENARIO/KSC/VABPlans/KCTVessel/ShipNode/PART")]
public class v2_6_AntennaState_KCT5 : v2_6_AntennaState_KCTBase { }

[UpgradeModule(LoadContext.SFS, sfsNodeUrl = "GAME/SCENARIO/KSC/SPHPlans/KCTVessel/ShipNode/PART")]
public class v2_6_AntennaState_KCT6 : v2_6_AntennaState_KCTBase { }

[UpgradeModule(LoadContext.SFS, sfsNodeUrl = "GAME/SCENARIO/KSC/LaunchComplex/BuildList/KCTVessel/ShipNode/PART")]
public class v2_6_AntennaState_KCT7 : v2_6_AntennaState_KCTBase { }

[UpgradeModule(LoadContext.SFS, sfsNodeUrl = "GAME/SCENARIO/KSC/LaunchComplex/Warehouse/KCTVessel/ShipNode/PART")]
public class v2_6_AntennaState_KCT8 : v2_6_AntennaState_KCTBase { }

[UpgradeModule(LoadContext.SFS, sfsNodeUrl = "GAME/SCENARIO/KSC/LaunchComplex/Plans/KCTVessel/ShipNode/PART")]
public class v2_6_AntennaState_KCT9 : v2_6_AntennaState_KCTBase { }
}

0 comments on commit 5dc8e13

Please sign in to comment.