Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions RasterPropMonitor/Auxiliary modules/JSILabel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ public void Start()

if (oneshot)
{
textObj.text = labels[0].Get();
textObj.text = labels[0].GetFormattedString();

var propBatcher = internalModel.GetComponentInChildren<PropBatcher>();
if (propBatcher != null && canBatch)
Expand Down Expand Up @@ -338,7 +338,7 @@ public void Click()
activeLabel = 0;
}

textObj.text = labels[activeLabel].Get();
textObj.text = labels[activeLabel].GetFormattedString();

// do we need to activate the update loop?
if (labels.Count > 1 && !labels[activeLabel].IsConstant)
Expand Down Expand Up @@ -492,7 +492,7 @@ public override void OnUpdate()

if (UpdateCheck() && JUtil.RasterPropMonitorShouldUpdate(part))
{
textObj.text = labels[activeLabel].Get();
textObj.text = labels[activeLabel].GetFormattedString();
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ public override void OnUpdate()
{
if (UpdateCheck())
{
textObj.text.text = StringProcessor.ProcessString(labelsEx[activeLabel].label, rpmComp);
textObj.text.text = labelsEx[activeLabel].label.GetFormattedString();

if (labelsEx[activeLabel].oneShot)
{
Expand Down Expand Up @@ -232,7 +232,7 @@ void UpdateActiveLabel(int direction)

if (labelsEx[activeLabel].hasText)
{
textObj.text.text = StringProcessor.ProcessString(labelsEx[activeLabel].label, rpmComp);
textObj.text.text = labelsEx[activeLabel].label.GetFormattedString();
}

// Force an update.
Expand Down
2 changes: 1 addition & 1 deletion RasterPropMonitor/Auxiliary modules/JSIVariableLabel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ public override void OnUpdate()

if (UpdateCheck())
{
textObj.text.text = StringProcessor.ProcessString(spf, rpmComp);
textObj.text.text = spf.GetFormattedString();
oneshotComplete = true;
}
}
Expand Down
29 changes: 29 additions & 0 deletions RasterPropMonitor/Core/GenericVariable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System;

namespace JSI
{
public class GenericVariable : IVariable
{
private Func<object> Generator;

internal GenericVariable(Func<object> generator)
{
Generator = generator;
}

object IVariable.GetValue()
{
return Generator();
}

bool IVariable.Changed(object oldValue)
{
return true;
}

bool IVariable.IsConstant()
{
return false;
}
}
}
7 changes: 7 additions & 0 deletions RasterPropMonitor/Core/IPageElement.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace JSI
{
internal interface IPageElement
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this necessary? There's already a lot of ways to customize page behaviors

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The RasterPropMonitor contains the state of which orbital patch is selected instead of RPMVesselComputer, otherwise all screens show the same thing, even if you only change one. Currently there's no way to pass the RasterPropMonitor instance to the pages themselves.

There are two main ways I considered. Either add another config variable into the ConfigNode which exposes it publicly and makes it hard to change later since you don't know if downstream dependencies use it, or use an internal interface. I chose the latter.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure that scansat or vesselviewer page states are not shared between monitors in the same pod. Is there a way to use the same pattern?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those states are local to the page not the monitor. There are other cases like that e.g. the science and target menus. They are not local to the monitor itself. If I switch from one orbital patch on the map screen, on the orbit screen, it will still stay at the old value. Potentially, I could create a "composite" page that contains both pages, but that might require some modification to the page clicking code to allow pages to capture it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, thanks. Let me think about it...

Another example is generic switches; they create persistent variables to track their state per prop. And maybe this state could be stored in the JSIOrbitDisplay? I'm not sure if that's instantiated per monitor or per pod.

Copy link
Author

@andymac-2 andymac-2 Sep 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another example is generic switches

You might have to provide an example, I'm not sure what you mean when you refer to a "generic switch"

Maybe this state could be stored in the JSIOrbitDisplay

We end up with a worse problem where we need to thread the state of the JSIOrbitDisplay everywhere it's needed. Even the text on the map display wouldn't sync up unless you passed it in.

{
void HandlePageCreate(RasterPropMonitor propMonitor);
}
}
13 changes: 13 additions & 0 deletions RasterPropMonitor/Core/IVariable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace JSI
{
/// <summary>
/// This class exists to provide a base class that RasterPropMonitorComputer
/// manages for tracking various built-in plugin action handlers.
/// </summary>
internal interface IVariable
{
object GetValue();
bool Changed(object oldValue);
bool IsConstant();
}
}
29 changes: 25 additions & 4 deletions RasterPropMonitor/Core/MonitorPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine;

namespace JSI
Expand Down Expand Up @@ -80,7 +79,7 @@ public enum BackgroundType
private readonly MonoBehaviour backgroundHandlerModule, pageHandlerModule;
private readonly List<string> techsRequired = new List<string>();
private readonly string fallbackPageName = string.Empty;

private readonly PatchSelector patchSelector;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this stuff be moved to a page handler class somewhere?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did try this, but it ended with the same code duplicated a few times. Here's what I tried:

  • Try to give it it's own handler: doesn't work with ASET 40x20, since they already have the JSIOrbitDisplay BG handler and the Text switcher for the FG, so there's no other slot.
  • Add it to the JSIOrbitDisplay, this works for the map, but then we have to add it somewhere else for the text only page(s)
  • Add it to the text switcher. This doesn't work for the ASET 60x30 since it doesn't use the text switcher.

So this left me with a few options:

  • Duplicate the code/add it to the text switcher, and the map, and maybe somewhere else too
  • Modify the MonitorPage to accept more than two handlers, then we can create our own handler for just the orbit patch switching, but this also means that the PatchSelector class has to inherit InternalModule unnecessarily
  • Modify the MonitorPage the way I did it, which has the disadvantage of having the MonitorPage know something it probably shouldn't

Let me know what you think, I can choose any of those other options whichever fits best in the codebase.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder...how horrible would it be if we just used per-pod variables to start, and then found a better way to do monitor-local ones?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since I'm using this for IVA play, I want to keep them monitor local for personal use and don't have much interest in making them pod local. If monitor local variables are a deal breaker, let me know and I'll leave this unmerged.


private struct HandlerSupportMethods
{
Expand Down Expand Up @@ -136,7 +135,7 @@ public void UpdateText(RasterPropMonitorComputer rpmComp)
allTextConstant = true;
for (int i = 0; i < linesArray.Length; ++i)
{
spf[i] = new StringProcessorFormatter(linesArray[i], rpmComp);
spf[i] = new StringProcessorFormatter(linesArray[i], rpmComp, ourMonitor);

outputLines[i] = spf[i].cachedResult;

Expand All @@ -156,7 +155,7 @@ public void UpdateText(RasterPropMonitorComputer rpmComp)
{
if (spf[i] != null)
{
outputLines[i] = StringProcessor.ProcessString(spf[i], rpmComp);
outputLines[i] = spf[i].GetFormattedString();
}
}
}
Expand Down Expand Up @@ -433,6 +432,13 @@ public MonitorPage(int idNum, ConfigNode node, RasterPropMonitor thatMonitor)
}
}

if (node.HasNode("PATCHSELECTOR"))
{
foreach (ConfigNode patchSelectorNode in node.GetNodes("PATCHSELECTOR"))
{
patchSelector = new PatchSelector(ourMonitor, patchSelectorNode);
}
}
}

private static MethodInfo InstantiateHandler(ConfigNode node, RasterPropMonitor ourMonitor, out MonoBehaviour moduleInstance, out HandlerSupportMethods support)
Expand Down Expand Up @@ -593,6 +599,11 @@ private static MethodInfo InstantiateHandler(ConfigNode node, RasterPropMonitor
}
}

if (thatModule is IPageElement pageElement)
{
pageElement.HandlePageCreate(ourMonitor);
}

moduleInstance = thatModule;
foreach (MethodInfo m in thatModule.GetType().GetMethods())
{
Expand Down Expand Up @@ -626,17 +637,27 @@ public bool GlobalButtonClick(int buttonID)
{
return false;
}

bool actionTaken = false;

if (pageHandlerS.buttonClick != null)
{
pageHandlerS.buttonClick(buttonID);
actionTaken = true;
}

if (backgroundHandlerS.buttonClick != null && pageHandlerS.buttonClick != backgroundHandlerS.buttonClick)
{
backgroundHandlerS.buttonClick(buttonID);
actionTaken = true;
}

if (patchSelector != null)
{
patchSelector.HandleButtonPress(buttonID);
actionTaken = true;
}

return actionTaken;
}

Expand Down
27 changes: 3 additions & 24 deletions RasterPropMonitor/Core/OrbitExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,7 @@ public static Vector3d SwappedOrbitNormal(this Orbit o)
//occurs at a true anomaly that a does not actually ever attain
public static double TimeOfAscendingNode(this Orbit a, Orbit b, double UT)
{
if (a.eccentricity >= 1.0)
{
return UT;
}
else
{
return a.TimeOfTrueAnomaly(Orbit.AscendingNodeTrueAnomaly(a, b), UT);
}
return a.TimeOfTrueAnomaly(Orbit.AscendingNodeTrueAnomaly(a, b), UT);
}
//Returns the next time at which a will cross its descending node with b.
//For elliptical orbits this is a time between UT and UT + a.period.
Expand All @@ -62,14 +55,7 @@ public static double TimeOfAscendingNode(this Orbit a, Orbit b, double UT)
//occurs at a true anomaly that a does not actually ever attain
public static double TimeOfDescendingNode(this Orbit a, Orbit b, double UT)
{
if (a.eccentricity >= 1.0)
{
return UT;
}
else
{
return a.TimeOfTrueAnomaly(Orbit.DescendingNodeTrueAnomaly(a, b), UT);
}
return a.TimeOfTrueAnomaly(Orbit.DescendingNodeTrueAnomaly(a, b), UT);
}
//Returns the next time at which the orbiting object will cross the equator
//moving northward, if o is east-moving, or southward, if o is west-moving.
Expand All @@ -80,14 +66,7 @@ public static double TimeOfDescendingNode(this Orbit a, Orbit b, double UT)
//"ascending node" occurs at a true anomaly that o does not actually ever attain.
public static double TimeOfAscendingNodeEquatorial(this Orbit o, double UT)
{
if (o.eccentricity >= 1.0)
{
return UT;
}
else
{
return o.TimeOfTrueAnomaly(o.AscendingNodeEquatorialTrueAnomaly(), UT);
}
return o.TimeOfTrueAnomaly(o.AscendingNodeEquatorialTrueAnomaly(), UT);
}
//Returns the next time at which the orbiting object will cross the equator
//moving southward, if o is east-moving, or northward, if o is west-moving.
Expand Down
4 changes: 3 additions & 1 deletion RasterPropMonitor/Core/RPMCEvaluators.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1601,6 +1601,8 @@ internal NumericVariableEvaluator GetNumericEvaluator(string input, out Variable
return double.NaN;
};
case "TARGETEXISTS":
return (RPMVesselComputer comp) => comp.target == null ? -1d : 1d;
case "TARGETISVESSEL":
return (RPMVesselComputer comp) =>
{
if (comp.target == null)
Expand Down Expand Up @@ -1673,7 +1675,7 @@ internal NumericVariableEvaluator GetNumericEvaluator(string input, out Variable
if (comp.target is Vessel || comp.target is ModuleDockingNode)
{
return comp.target.GetVessel().mainBody.GetAltitude(comp.target.GetVessel().CoM);
}
}
else
{
return vessel.mainBody.GetAltitude(comp.target.GetTransform().position);
Expand Down
6 changes: 4 additions & 2 deletions RasterPropMonitor/Core/RPMVesselComputer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@
using System.Diagnostics;
using System.Reflection;
using UnityEngine;
using KSP.UI.Screens.Flight;
using static JSI.RasterPropMonitorComputer;

// MOARdV TODO:
// Add callbacks for docking, undocking, staging, vessel switching
Expand All @@ -41,6 +39,10 @@
// ? GameEvents.onKerbalRemoved
namespace JSI
{
/// <summary>
/// The computer for the vessel. This class can be used for shared data
/// across different pods in the same vessel.
/// </summary>
public partial class RPMVesselComputer : VesselModule
{
#region Static Variables
Expand Down
Loading