diff --git a/RasterPropMonitor/Handlers/JSICameraStatusPage.cs b/RasterPropMonitor/Handlers/JSICameraStatusPage.cs
new file mode 100644
index 00000000..3d910845
--- /dev/null
+++ b/RasterPropMonitor/Handlers/JSICameraStatusPage.cs
@@ -0,0 +1,171 @@
+/*****************************************************************************
+ * RasterPropMonitor
+ * =================
+ * Plugin for Kerbal Space Program
+ *
+ * by Mihara (Eugene Medvedev), MOARdV, and other contributors
+ *
+ * RasterPropMonitor is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, revision
+ * date 29 June 2007, or (at your option) any later version.
+ *
+ * RasterPropMonitor is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RasterPropMonitor. If not, see .
+ ****************************************************************************/
+using System.Text;
+using UnityEngine;
+
+namespace JSI
+{
+ ///
+ /// Page handler that reports camera status from the current page's background
+ /// JSISteerableCamera instance. This avoids global PLUGIN_*/PERSISTENT_*
+ /// resolution ambiguity when multiple MFDs exist in the same cockpit.
+ ///
+ public class JSICameraStatusPage : InternalModule
+ {
+ private const string CameraStatusToken = "__CAMERA_STATUS__";
+ private static readonly string DefaultOverlayTemplate = @"[font0][@y+2][hw] __CAMERA_STATUS__";
+
+ [KSPField]
+ public string prefix = "";
+ [KSPField]
+ public string idLabel = "ID";
+ [KSPField]
+ public string nameLabel = "CAMERA";
+ [KSPField]
+ public string unknownText = "N/A";
+ [KSPField]
+ public bool showId = true;
+ [KSPField]
+ public bool showName = true;
+ [KSPField]
+ public string statusColor = "[#FFFF0066]";
+ [KSPField]
+ public string statusSuffix = "[#FFFFFF55]";
+ [KSPField]
+ public string overlayTemplate = string.Empty;
+ [KSPField]
+ public string overlayTemplatePath = string.Empty;
+ [KSPField]
+ public string cameraStatusToken = CameraStatusToken;
+
+ private JSISteerableCamera steerableCamera;
+ private string resolvedTemplate;
+
+ public void GetHandlerReferences(MonoBehaviour pageHandler, MonoBehaviour backgroundHandler)
+ {
+ steerableCamera = backgroundHandler as JSISteerableCamera;
+ }
+
+ // Analysis disable UnusedParameter
+ public string ShowStatus(int width, int height)
+ {
+ if (steerableCamera == null)
+ {
+ // Fallback: if handler references were not wired for some reason,
+ // try to resolve a camera from the current prop only.
+ foreach (InternalModule module in internalProp.internalModules)
+ {
+ steerableCamera = module as JSISteerableCamera;
+ if (steerableCamera != null)
+ {
+ break;
+ }
+ }
+ }
+
+ string statusLine = BuildStatusLine();
+ string template = GetTemplate();
+ return InjectStatusLine(template, statusLine);
+ }
+ // Analysis restore UnusedParameter
+
+ private string GetTemplate()
+ {
+ if (!string.IsNullOrEmpty(resolvedTemplate))
+ {
+ return resolvedTemplate;
+ }
+
+ if (!string.IsNullOrEmpty(overlayTemplate))
+ {
+ resolvedTemplate = overlayTemplate;
+ return resolvedTemplate;
+ }
+
+ if (!string.IsNullOrEmpty(overlayTemplatePath))
+ {
+ resolvedTemplate = JUtil.LoadPageDefinition(overlayTemplatePath);
+ if (!string.IsNullOrEmpty(resolvedTemplate))
+ {
+ return resolvedTemplate;
+ }
+ }
+
+ resolvedTemplate = DefaultOverlayTemplate;
+ return resolvedTemplate;
+ }
+
+ private string InjectStatusLine(string template, string statusLine)
+ {
+ string token = string.IsNullOrEmpty(cameraStatusToken) ? CameraStatusToken : cameraStatusToken;
+
+ if (template.Contains(token))
+ {
+ return template.Replace(token, statusLine);
+ }
+
+ // Final fallback if no marker is present.
+ return statusLine + "\n" + template;
+ }
+
+ private string BuildStatusLine()
+ {
+ if (steerableCamera == null)
+ {
+ return string.Format("{0}{1} {2}{3}", statusColor, prefix, unknownText, statusSuffix);
+ }
+
+ double activeId = steerableCamera.GetActiveCameraID();
+ string activeName = steerableCamera.GetActiveCameraTransform();
+ bool validId = activeId >= 1.0;
+ if (string.IsNullOrEmpty(activeName))
+ {
+ activeName = unknownText;
+ }
+
+ StringBuilder sb = new StringBuilder();
+ sb.Append(statusColor);
+ sb.Append(prefix);
+
+ if (showId)
+ {
+ sb.Append(' ');
+ sb.Append(idLabel);
+ sb.Append(':');
+ sb.Append(validId ? ((int)activeId).ToString() : unknownText);
+ }
+
+ if (showName)
+ {
+ if (showId)
+ {
+ sb.Append(' ');
+ }
+ sb.Append(nameLabel);
+ sb.Append(':');
+ sb.Append(validId ? activeName : unknownText);
+ }
+
+ sb.Append(statusSuffix);
+ return sb.ToString();
+ }
+ }
+}
diff --git a/RasterPropMonitor/Handlers/JSISteerableCamera.cs b/RasterPropMonitor/Handlers/JSISteerableCamera.cs
index db61468f..94cf4f61 100644
--- a/RasterPropMonitor/Handlers/JSISteerableCamera.cs
+++ b/RasterPropMonitor/Handlers/JSISteerableCamera.cs
@@ -508,10 +508,7 @@ void PointCamera(int incrementDirection)
if (!skipMissingCameras)
{
- //if (rpmComp != null)
- //{
- // rpmComp.SetPropVar(cameraInfoVarName + "_ID", internalProp.propID, currentCamera + 1);
- //}
+
return;
}
@@ -525,10 +522,6 @@ void PointCamera(int incrementDirection)
gotCamera = cameraObject.PointCamera(cameras[currentCamera]);
}
- //if (rpmComp != null)
- //{
- // rpmComp.SetPropVar(cameraInfoVarName + "_ID", internalProp.propID, currentCamera + 1);
- //}
}
private void SelectNextCamera()
@@ -632,19 +625,6 @@ public void Start()
homeCrosshairMaterial = new Material(Shader.Find("KSP/Alpha/Unlit Transparent"));
homeCrosshairMaterial.color = ConfigNode.ParseColor32(homeCrosshairColor);
- if (!string.IsNullOrEmpty(cameraInfoVarName))
- {
- //rpmComp = RasterPropMonitorComputer.Instantiate(internalProp);
- //if (rpmComp.HasPropVar(cameraInfoVarName + "_ID", internalProp.propID))
- //{
- // currentCamera = rpmComp.GetPropVar(cameraInfoVarName + "_ID", internalProp.propID) - 1;
- //}
- //else
- //{
- // rpmComp.SetPropVar(cameraInfoVarName + "_ID", internalProp.propID, currentCamera + 1);
- //}
- }
-
if (!string.IsNullOrEmpty(cameraEffectShader))
{
cameraEffectMaterial = new Material(JUtil.LoadInternalShader(cameraEffectShader));
@@ -705,6 +685,30 @@ public void Start()
}
}
}
+
+ ///
+ /// Returns the active camera id (1-based). Intended for plugin variable access
+ /// via VARIABLE = PLUGIN_JSISteerableCamera:GetActiveCameraID
+ ///
+ /// camera id (1-based) or -1 if none
+ public double GetActiveCameraID()
+ {
+ if (cameras == null || cameras.Count == 0) return -1.0;
+ return cameras[currentCamera].cameraId;
+ }
+
+ ///
+ /// Returns the active camera transform/name as a string.
+ /// Intended for plugin variable access via
+ /// VARIABLE = PLUGIN_JSISteerableCamera:GetActiveCameraTransform
+ /// Note: depending on evaluator support, numeric ID may be more reliable.
+ ///
+ /// camera transform/name or empty string
+ public string GetActiveCameraTransform()
+ {
+ if (cameras == null || cameras.Count == 0) return string.Empty;
+ return cameras[currentCamera].cameraTransform ?? string.Empty;
+ }
}
// Prep for switchable steerable cameras.