From ee1a9728ce1f0695f8604718bdd3811cb3b8e9a5 Mon Sep 17 00:00:00 2001 From: Lamont Granquist Date: Sat, 13 Jun 2026 23:05:14 -0700 Subject: [PATCH] Add node executor binding Really just a proof of concept at this point --- Directory.Build.props | 5 ++- MechJebKos/Addon.cs | 43 ++++++++++++++++++++++ MechJebKos/ComputerModuleBinding.cs | 52 +++++++++++++++++++++++++++ MechJebKos/MechJebKos.csproj | 11 ++++++ MechJebKos/MechJebKosAddon.cs | 11 ------ MechJebKos/NodeExecutorBinding.cs | 37 +++++++++++++++++++ MechJebKos/Properties/AssemblyInfo.cs | 9 +++++ 7 files changed, 156 insertions(+), 12 deletions(-) create mode 100644 MechJebKos/Addon.cs create mode 100644 MechJebKos/ComputerModuleBinding.cs delete mode 100644 MechJebKos/MechJebKosAddon.cs create mode 100644 MechJebKos/NodeExecutorBinding.cs create mode 100644 MechJebKos/Properties/AssemblyInfo.cs diff --git a/Directory.Build.props b/Directory.Build.props index 0264a58a7..c6a584568 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -37,8 +37,11 @@ $(KspDir)/KSP_Data - + $(KspDir)/GameData/kOS/Plugins/kOS.dll + + $(KspDir)/GameData/kOS/Plugins/kOS.Safe.dll + diff --git a/MechJebKos/Addon.cs b/MechJebKos/Addon.cs new file mode 100644 index 000000000..7b8bf738f --- /dev/null +++ b/MechJebKos/Addon.cs @@ -0,0 +1,43 @@ +/* + * Copyright Lamont Granquist, Sebastien Gaggini and the MechJeb contributors + * SPDX-License-Identifier: LicenseRef-PD-hp OR Unlicense OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT OR LGPL-2.1+ + */ + +using JetBrains.Annotations; +using kOS; +using kOS.AddOns; +using kOS.Safe.Encapsulation; +using kOS.Safe.Encapsulation.Suffixes; +using kOS.Safe.Utilities; + +namespace MuMech.MechJebKos +{ + // The kOS addon entry point, reached from scripts as ADDONS:MECHJEB. + // + // kOS instantiates one Addon per processor (per SharedObjects), so this is inherently + // local to a single vessel: everything resolves through shared.Vessel and we never reach + // for FlightGlobals.activeVessel or a global singleton. Cross-vessel coordination is left + // to kOS itself. + [kOSAddon("MechJeb")] + [KOSNomenclature("MechJebAddon")] + [UsedImplicitly] + public class Addon : kOS.Suffixed.Addon + { + public Addon(SharedObjects shared) : base(shared) => RegisterInitializer(InitializeSuffixes); + + // must never be cached, it can be updated dyanmically + private MechJebCore? _core => shared.Vessel.GetMasterMechJeb(); + + public override BooleanValue Available() => !(_core is null); + + private void InitializeSuffixes() + { + var nodeExecutor = new NodeExecutorBinding(() => _core); + + AddSuffix("RUNNING", new NoArgsSuffix(() => _core?.running ?? false, + "True if MechJeb is present and running on this vessel.")); + AddSuffix(new[] { "NODE", "NODEEXECUTOR" }, new NoArgsSuffix(() => nodeExecutor, + "The maneuver node executor.")); + } + } +} diff --git a/MechJebKos/ComputerModuleBinding.cs b/MechJebKos/ComputerModuleBinding.cs new file mode 100644 index 000000000..887aef0bc --- /dev/null +++ b/MechJebKos/ComputerModuleBinding.cs @@ -0,0 +1,52 @@ +/* + * Copyright Lamont Granquist, Sebastien Gaggini and the MechJeb contributors + * SPDX-License-Identifier: LicenseRef-PD-hp OR Unlicense OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT OR LGPL-2.1+ + */ + +using System; +using kOS.Safe.Encapsulation; +using kOS.Safe.Encapsulation.Suffixes; +using kOS.Safe.Exceptions; +using kOS.Safe.Utilities; + +namespace MuMech.MechJebKos +{ + [KOSNomenclature("MechJebComputerModule")] + public abstract class ComputerModuleBinding : Structure where T : ComputerModule + { + private readonly Func _core; + + protected ComputerModuleBinding(Func core) + { + _core = core; + RegisterInitializer(InitSuffixes); + } + + // the Module deliberately re-evaluates on every call since the core can update dynamically + protected T Module + { + get + { + MechJebCore core = _core() ?? throw new KOSException("MechJeb is not available on this vessel."); + return core.GetComputerModule(); + } + } + + private void InitSuffixes() + { + AddSuffix("ENABLED", new SetSuffix(() => Module.Enabled, value => SetEnabled(value), + "Whether the module is enabled.")); + InitializeSuffixes(); + } + + protected abstract void InitializeSuffixes(); + + protected virtual void SetEnabled(bool enabled) + { + if (enabled) + Module.Enable(); + else + Module.Disable(); + } + } +} diff --git a/MechJebKos/MechJebKos.csproj b/MechJebKos/MechJebKos.csproj index c30537798..e8421f631 100644 --- a/MechJebKos/MechJebKos.csproj +++ b/MechJebKos/MechJebKos.csproj @@ -7,6 +7,7 @@ false $(DefineConstants);UNITY_2017_1 false + enable @@ -24,11 +25,21 @@ False False + + $(KosSafeDll) + False + False + $(KspData)/Managed/Assembly-CSharp.dll False False + + $(KspData)/Managed/Assembly-CSharp-firstpass.dll + False + False + $(KspData)/Managed/UnityEngine.dll False diff --git a/MechJebKos/MechJebKosAddon.cs b/MechJebKos/MechJebKosAddon.cs deleted file mode 100644 index 620b1041a..000000000 --- a/MechJebKos/MechJebKosAddon.cs +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright Lamont Granquist, Sebastien Gaggini and the MechJeb contributors - * SPDX-License-Identifier: LicenseRef-PD-hp OR Unlicense OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT OR LGPL-2.1+ - */ - -namespace MuMech -{ - internal static class MechJebKos - { - } -} diff --git a/MechJebKos/NodeExecutorBinding.cs b/MechJebKos/NodeExecutorBinding.cs new file mode 100644 index 000000000..247e69d5a --- /dev/null +++ b/MechJebKos/NodeExecutorBinding.cs @@ -0,0 +1,37 @@ +/* + * Copyright Lamont Granquist, Sebastien Gaggini and the MechJeb contributors + * SPDX-License-Identifier: LicenseRef-PD-hp OR Unlicense OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT OR LGPL-2.1+ + */ + +using System; +using kOS.Safe.Encapsulation; +using kOS.Safe.Encapsulation.Suffixes; +using kOS.Safe.Utilities; + +namespace MuMech.MechJebKos +{ + // ADDONS:MECHJEB:NODE - drives MechJebModuleNodeExecutor. + [KOSNomenclature("MechJebNodeExecutor")] + public class NodeExecutorBinding : ComputerModuleBinding + { + public NodeExecutorBinding(Func core) : base(core) { } + + protected override void InitializeSuffixes() + { + AddSuffix("STATE", new Suffix(() => Module.State.ToString(), + "Executor state: WARPALIGN, LEAD, BURN, or IDLE.")); + AddSuffix(new[] { "AUTOWARP", "WARP" }, + new SetSuffix(() => Module.Autowarp, value => Module.Autowarp = value, + "Automatically time-warp to the node.")); + } + + // The node executor engages via ExecuteOneNode / Abort rather than the plain Enabled toggle. + protected override void SetEnabled(bool enabled) + { + if (enabled) + Module.ExecuteOneNode(this); + else + Module.Abort(); + } + } +} diff --git a/MechJebKos/Properties/AssemblyInfo.cs b/MechJebKos/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..eaf258fc3 --- /dev/null +++ b/MechJebKos/Properties/AssemblyInfo.cs @@ -0,0 +1,9 @@ +/* + * Copyright Lamont Granquist, Sebastien Gaggini and the MechJeb contributors + * SPDX-License-Identifier: LicenseRef-PD-hp OR Unlicense OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT OR LGPL-2.1+ + */ + +// KSP load-order dependencies. The (major, minor) pair is a *minimum* version requirement; +// KSP refuses to load this assembly unless a matching-or-newer KSPAssembly is present. +[assembly: KSPAssemblyDependency("kOS", 1, 6)] +[assembly: KSPAssemblyDependency("MechJeb2", 2, 16)]