diff --git a/ActionSequencer/Program.cs b/ActionSequencer/Program.cs index 3def67d..2e0c140 100644 --- a/ActionSequencer/Program.cs +++ b/ActionSequencer/Program.cs @@ -66,7 +66,7 @@ namespace IngameScript continue; } int step = Int32.Parse(Ini.Get(key, "step").ToString("0")); - IBlockAction blockAction = buildBlockAction(block, key); + BlockAction blockAction = buildBlockAction(block, key); if (blockAction == null) { Console.Print($"Failed to add '{block.CustomName}' to action '{actionName}'."); @@ -121,22 +121,22 @@ namespace IngameScript } // Prerequisite: Ini.Parse has already been called for this block. - private IBlockAction buildBlockAction(IMyTerminalBlock block, string key) + private BlockAction buildBlockAction(IMyTerminalBlock block, string key) { if (block is IMyDoor) { - BlockActionDoor.DoorAction action; + DoorAction action; switch (Ini.Get(key, "action").ToString("open")) { case "open": - action = BlockActionDoor.DoorAction.Open; + action = DoorAction.Open; break; case "close": - action = BlockActionDoor.DoorAction.Close; + action = DoorAction.Close; break; default: Console.Print($"Invalid door action for '{block.CustomName}'. Defaulting to open."); - action = BlockActionDoor.DoorAction.Open; + action = DoorAction.Open; break; } diff --git a/DockingController/DockingController.csproj b/DockingController/DockingController.csproj new file mode 100644 index 0000000..4126f8c --- /dev/null +++ b/DockingController/DockingController.csproj @@ -0,0 +1,28 @@ + + + netframework48 + IngameScript + 6 + false + Release;Debug + x64 + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + \ No newline at end of file diff --git a/DockingController/DockingController.mdk.ini b/DockingController/DockingController.mdk.ini new file mode 100644 index 0000000..5add8f4 --- /dev/null +++ b/DockingController/DockingController.mdk.ini @@ -0,0 +1,22 @@ +; This file is project specific and should be checked in to source control. + +[mdk] +; This is a programmable block script project. +; You should not change this. +type=programmableblock + +; Toggle trace (on|off) (verbose output) +trace=off + +; What type of minification to use (none|trim|stripcomments|lite|full) +; none: No minification +; trim: Removes unused types (NOT members). +; stripcomments: trim + removes comments. +; lite: stripcomments + removes leading/trailing whitespace. +; full: lite + renames identifiers to shorter names. +minify=none + +; A list of files and folder to ignore when creating the script. +; This is a comma separated list of glob patterns. +; See https://code.visualstudio.com/docs/editor/glob-patterns +ignores=obj/**/*,MDK/**/*,**/*.debug.cs diff --git a/DockingController/DockingController.mdk.local.ini b/DockingController/DockingController.mdk.local.ini new file mode 100644 index 0000000..4b66820 --- /dev/null +++ b/DockingController/DockingController.mdk.local.ini @@ -0,0 +1,7 @@ +; This file is _local_ to your machine and should not be checked in to source control. + +[mdk] +; Where to output the script to (auto|specific path) +output=auto +; Override the default binary path (auto|specific path) +binarypath=auto \ No newline at end of file diff --git a/DockingController/Instructions.readme b/DockingController/Instructions.readme new file mode 100644 index 0000000..ed30ab7 --- /dev/null +++ b/DockingController/Instructions.readme @@ -0,0 +1,5 @@ +R e a d m e +----------- + +In this file you can include any instructions or other comments you want to have injected onto the +top of your final script. You can safely delete this file if you do not want any such comments. diff --git a/DockingController/Program.cs b/DockingController/Program.cs new file mode 100644 index 0000000..c990a9c --- /dev/null +++ b/DockingController/Program.cs @@ -0,0 +1,91 @@ +using Sandbox.ModAPI.Ingame; +using System.Collections.Generic; +using VRage.Game.ModAPI.Ingame.Utilities; + +namespace IngameScript +{ + public partial class Program : MyGridProgram, IConsoleProgram + { + public IConsole Console { get; private set; } + public MyIni Ini { get; } = new MyIni(); + + private IEnumerator _job = null; + private MyCommandLine _cli = new MyCommandLine(); + + private List dockingPorts = new List(); + private List thrusters = new List(); + private List gasTanks = new List(); + + private ActionGroup actionGroup; + + public Program() + { + Console = new MainConsole(this, "Docking Controller"); + actionGroup = new ActionGroup(Console, "docking"); + + // We store a list of the dockingPorts because we will only dock if one is ready to lock. + GridTerminalSystem.GetBlocksOfType(dockingPorts, blockFilter); + + foreach (IMyShipConnector dockingPort in dockingPorts) + { + actionGroup.AddActionBlock("dock", 0, new BlockActionConnector(dockingPort, ConnectorAction.Connect)); + actionGroup.AddActionBlock("undock", 1, new BlockActionConnector(dockingPort, ConnectorAction.Disconnect)); + } + + List thrusters = new List(); + GridTerminalSystem.GetBlocksOfType(thrusters, blockFilter); + foreach (IMyThrust thruster in thrusters) + { + actionGroup.AddActionBlock("dock", 1, new BlockActionThruster(thruster, ThrusterAction.Disable)); + actionGroup.AddActionBlock("undock", 0, new BlockActionThruster(thruster, ThrusterAction.Enable)); + } + + List gasTanks = new List(); + GridTerminalSystem.GetBlocksOfType(gasTanks, blockFilter); + foreach (IMyGasTank gasTank in gasTanks) + { + actionGroup.AddActionBlock("dock", 1, new BlockActionGasTank(gasTank, GasTankAction.Stockpile)); + actionGroup.AddActionBlock("undock", 0, new BlockActionGasTank(gasTank, GasTankAction.Dispense)); + } + } + + public void Main(string argument, UpdateType updateSource) + { + if (argument != "") + { + _cli.TryParse(argument); + if (_cli.ArgumentCount == 0) + { + Console.Print("Error: Must pass an argument, 'dock' or 'undock'."); + } + else if (_job != null) + { + Console.Print("Already performing a docking action."); + } + else + { + _job = actionGroup.RunAction(_cli.Argument(0).ToLower()); + Runtime.UpdateFrequency = UpdateFrequency.Update10; + } + } + + if (_job != null && !_job.MoveNext()) + { + _job.Dispose(); + _job = null; + Console.Print("Docking action complete."); + Runtime.UpdateFrequency = UpdateFrequency.None; + } + } + + private bool blockFilter(IMyTerminalBlock block) + { + if (MyIni.HasSection(block.CustomData, "docking")) + { + Ini.TryParse(block.CustomData); + return Ini.Get("docking", "ignore").ToBoolean(false); + } + return true; + } + } +} diff --git a/DockingController/thumb.png b/DockingController/thumb.png new file mode 100644 index 0000000..a8dc2ef Binary files /dev/null and b/DockingController/thumb.png differ diff --git a/Mixins/ActionGroups/ActionGroup.cs b/Mixins/ActionGroups/ActionGroup.cs index aa9118b..d73a213 100644 --- a/Mixins/ActionGroups/ActionGroup.cs +++ b/Mixins/ActionGroups/ActionGroup.cs @@ -30,7 +30,7 @@ namespace IngameScript } // Add an action to the sequence called actionName, which will be created if it doesn't already exist. - public void AddActionBlock(string actionName, int step, IBlockAction actionBlock) + public void AddActionBlock(string actionName, int step, BlockAction actionBlock) { if (!_actions.ContainsKey(actionName)) _actions[actionName] = new ActionSequence(actionName); _actions[actionName].Add(step, actionBlock); diff --git a/Mixins/ActionGroups/ActionGroups.projitems b/Mixins/ActionGroups/ActionGroups.projitems index a265255..c9b57b6 100644 --- a/Mixins/ActionGroups/ActionGroups.projitems +++ b/Mixins/ActionGroups/ActionGroups.projitems @@ -8,9 +8,12 @@ + + - + + \ No newline at end of file diff --git a/Mixins/ActionGroups/ActionGroups.shproj b/Mixins/ActionGroups/ActionGroups.shproj index 83aa175..e29dcb1 100644 --- a/Mixins/ActionGroups/ActionGroups.shproj +++ b/Mixins/ActionGroups/ActionGroups.shproj @@ -14,6 +14,6 @@ bin\Release\ - + diff --git a/Mixins/ActionGroups/ActionSequence.cs b/Mixins/ActionGroups/ActionSequence.cs index 15f7b23..acf03be 100644 --- a/Mixins/ActionGroups/ActionSequence.cs +++ b/Mixins/ActionGroups/ActionSequence.cs @@ -14,16 +14,16 @@ namespace IngameScript public string Name { get; private set; } public bool Running { get; private set; } = false; - private SortedDictionary> _steps = new SortedDictionary>(); + private SortedDictionary> _steps = new SortedDictionary>(); public ActionSequence(string name) { Name = name; } - public void Add(int step, IBlockAction action) + public void Add(int step, BlockAction action) { - if (!_steps.ContainsKey(step)) _steps[step] = new List(); + if (!_steps.ContainsKey(step)) _steps[step] = new List(); _steps[step].Add(action); } @@ -33,9 +33,9 @@ namespace IngameScript Running = true; List> jobs = new List>(); - foreach (List step in _steps.Values) + foreach (List step in _steps.Values) { - foreach (IBlockAction action in step) + foreach (BlockAction action in step) { jobs.Add(action.Run()); } diff --git a/Mixins/ActionGroups/BlockAction.cs b/Mixins/ActionGroups/BlockAction.cs new file mode 100644 index 0000000..a4ebff3 --- /dev/null +++ b/Mixins/ActionGroups/BlockAction.cs @@ -0,0 +1,29 @@ +// An interface to represent a pre-configured action performed asynchronously +// on a block. Implements a Run() method that executes the action and provides an +// Enumerator to monitor when the action is complete. + +using System.Collections.Generic; + +namespace IngameScript +{ + partial class Program + { + public abstract class BlockAction + { + public bool Running { get; private set; } = false; + + public IEnumerator Run() + { + if (Running) yield break; + Running = true; + + IEnumerator childRun = onRun(); + while (childRun.MoveNext()) yield return true; + + Running = false; + } + + protected abstract IEnumerator onRun(); + } + } +} \ No newline at end of file diff --git a/Mixins/ActionGroups/BlockActionConnector.cs b/Mixins/ActionGroups/BlockActionConnector.cs new file mode 100644 index 0000000..634f6c6 --- /dev/null +++ b/Mixins/ActionGroups/BlockActionConnector.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; +using Sandbox.ModAPI.Ingame; + +namespace IngameScript +{ + partial class Program + { + public enum ConnectorAction + { + Connect, + Disconnect, + } + + public class BlockActionConnector : BlockAction + { + private IMyShipConnector _connector; + private ConnectorAction _action; + + public BlockActionConnector( + IMyShipConnector connector, + ConnectorAction action + ) + { + _connector = connector; + _action = action; + } + + protected override IEnumerator onRun() + { + switch (_action) + { + case ConnectorAction.Connect: + _connector.Connect(); + while (_connector.Status != MyShipConnectorStatus.Connected) yield return true; + break; + case ConnectorAction.Disconnect: + _connector.Disconnect(); + while (_connector.Status == MyShipConnectorStatus.Connected) yield return true; + break; + } + } + } + } +} \ No newline at end of file diff --git a/Mixins/ActionGroups/BlockActionDoor.cs b/Mixins/ActionGroups/BlockActionDoor.cs index 300b014..f71246b 100644 --- a/Mixins/ActionGroups/BlockActionDoor.cs +++ b/Mixins/ActionGroups/BlockActionDoor.cs @@ -5,16 +5,14 @@ namespace IngameScript { partial class Program { - public class BlockActionDoor : IBlockAction + public enum DoorAction { - public enum DoorAction - { - Open, - Close, - } - - public bool Running { get; private set; } = false; + Open, + Close, + } + public class BlockActionDoor : BlockAction + { private IMyDoor _door; private DoorAction _action; private bool _lockDoor; @@ -30,7 +28,7 @@ namespace IngameScript _lockDoor = lockDoor; } - public IEnumerator Run() + protected override IEnumerator onRun() { switch (_action) { diff --git a/Mixins/ActionGroups/BlockActionGasTank.cs b/Mixins/ActionGroups/BlockActionGasTank.cs new file mode 100644 index 0000000..5595777 --- /dev/null +++ b/Mixins/ActionGroups/BlockActionGasTank.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using Sandbox.ModAPI.Ingame; + +namespace IngameScript +{ + partial class Program + { + public enum GasTankAction + { + Stockpile, + Dispense, + } + + public class BlockActionGasTank : BlockAction + { + private IMyGasTank _gasTank; + private GasTankAction _action; + + public BlockActionGasTank( + IMyGasTank gasTank, + GasTankAction action + ) + { + _gasTank = gasTank; + _action = action; + } + + protected override IEnumerator onRun() + { + switch (_action) + { + case GasTankAction.Stockpile: + _gasTank.Stockpile = true; + break; + case GasTankAction.Dispense: + _gasTank.Stockpile = false; + break; + } + yield return true; + } + } + } +} \ No newline at end of file diff --git a/Mixins/ActionGroups/BlockActionPiston.cs b/Mixins/ActionGroups/BlockActionPiston.cs index 45a8778..22d016c 100644 --- a/Mixins/ActionGroups/BlockActionPiston.cs +++ b/Mixins/ActionGroups/BlockActionPiston.cs @@ -5,7 +5,7 @@ namespace IngameScript { partial class Program { - public class BlockActionPiston : IBlockAction + public class BlockActionPiston : BlockAction { public bool Running { get; private set; } = false; diff --git a/Mixins/ActionGroups/BlockActionRotor.cs b/Mixins/ActionGroups/BlockActionRotor.cs index f752932..d0458d9 100644 --- a/Mixins/ActionGroups/BlockActionRotor.cs +++ b/Mixins/ActionGroups/BlockActionRotor.cs @@ -5,7 +5,7 @@ namespace IngameScript { partial class Program { - public class BlockActionRotor : IBlockAction + public class BlockActionRotor : BlockAction { public bool Running { get; private set; } = false; diff --git a/Mixins/ActionGroups/BlockActionThruster.cs b/Mixins/ActionGroups/BlockActionThruster.cs new file mode 100644 index 0000000..74e6671 --- /dev/null +++ b/Mixins/ActionGroups/BlockActionThruster.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using Sandbox.ModAPI.Ingame; + +namespace IngameScript +{ + partial class Program + { + public enum ThrusterAction + { + Enable, + Disable, + } + + public class BlockActionThruster : BlockAction + { + private IMyThrust _thruster; + private ThrusterAction _action; + + public BlockActionThruster( + IMyThrust thruster, + ThrusterAction action + ) + { + _thruster = thruster; + _action = action; + } + + protected override IEnumerator onRun() + { + switch (_action) + { + case ThrusterAction.Enable: + _thruster.Enabled = true; + break; + case ThrusterAction.Disable: + _thruster.Enabled = false; + break; + } + yield return true; + } + } + } +} \ No newline at end of file diff --git a/Mixins/ActionGroups/IBlockAction.cs b/Mixins/ActionGroups/IBlockAction.cs deleted file mode 100644 index 5b05de5..0000000 --- a/Mixins/ActionGroups/IBlockAction.cs +++ /dev/null @@ -1,17 +0,0 @@ -// An interface to represent a pre-configured action performed asynchronously -// on a block. Implements a Run() method that executes the action and provides an -// Enumerator to monitor when the action is complete. - -using System.Collections.Generic; - -namespace IngameScript -{ - partial class Program - { - public interface IBlockAction - { - bool Running { get; } - IEnumerator Run(); - } - } -} \ No newline at end of file diff --git a/SpaceEngineers.sln b/SpaceEngineers.sln index f7334d0..700cf5e 100644 --- a/SpaceEngineers.sln +++ b/SpaceEngineers.sln @@ -13,6 +13,8 @@ Project("{8A3CDCC5-4B55-4D87-A415-698A0E1FF06F}") = "ActionGroups", "Mixins\Acti EndProject Project("{8A3CDCC5-4B55-4D87-A415-698A0E1FF06F}") = "Console", "Mixins\Console\Console.shproj", "{323E8400-84C2-46A0-B2E9-FCD3B31681DA}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DockingController", "DockingController\DockingController.csproj", "{FDF834C0-D680-4FFA-8238-FE1FBDCF5B9D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -31,6 +33,10 @@ Global {40B352CD-100E-4F87-A7A0-FF00F4B8846C}.Debug|Any CPU.Build.0 = Debug|x64 {40B352CD-100E-4F87-A7A0-FF00F4B8846C}.Release|Any CPU.ActiveCfg = Release|x64 {40B352CD-100E-4F87-A7A0-FF00F4B8846C}.Release|Any CPU.Build.0 = Release|x64 + {FDF834C0-D680-4FFA-8238-FE1FBDCF5B9D}.Debug|Any CPU.ActiveCfg = Debug|x64 + {FDF834C0-D680-4FFA-8238-FE1FBDCF5B9D}.Debug|Any CPU.Build.0 = Debug|x64 + {FDF834C0-D680-4FFA-8238-FE1FBDCF5B9D}.Release|Any CPU.ActiveCfg = Release|x64 + {FDF834C0-D680-4FFA-8238-FE1FBDCF5B9D}.Release|Any CPU.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE