diff --git a/DockLoader/Dock.cs b/DockLoader/Dock.cs new file mode 100644 index 0000000..cd56241 --- /dev/null +++ b/DockLoader/Dock.cs @@ -0,0 +1,118 @@ +using Sandbox.ModAPI.Ingame; +using SpaceEngineers.Game.ModAPI.Ingame; +using System.Collections.Generic; +using VRage.Game.ModAPI.Ingame.Utilities; + +namespace IngameScript +{ + partial class Program + { + // We don't really do anything with the modes other than Loading right now, + // but they are nice for consistency. + // TODO: we could have displays that print the current mode... + public enum DockMode + { + Loading, + Unloading, + Off, + } + + public class Dock + { + public string Id { get; private set; } + public DockMode Mode { get; private set; } = DockMode.Off; + + public bool Functional + { + get + { + return _ports.Count > 0 && _inputSorter != null && _outputSorter != null; + } + } + + private IMyConveyorSorter _inputSorter; + private IMyConveyorSorter _outputSorter; + private List _ports = new List(); + private bool _wasDocked = false; // Records whether a ship was docked last time we checked for one. + private IConsole _console; + + public Dock(string id, IConsole console) + { + Id = id; + _console = new PrefixedConsole(console, id); + } + + // Check and update the state of the Dock. + // In particular, this checks whether a ship has undocked since our last check, + // and if so it turns off the loading/unloading mechanism and releases the lock. + public void Update() + { + bool isDocked = false; + foreach (IMyShipConnector port in _ports) + { + if (port.IsConnected) + { + isDocked = true; + break; + } + } + + if (_wasDocked && !isDocked) Reset(); + + _wasDocked = isDocked; + } + + + public void StartLoading() + { + Mode = DockMode.Loading; + _outputSorter.Enabled = false; + _inputSorter.Enabled = true; + } + + public void StartUnloading() + { + Mode = DockMode.Unloading; + _inputSorter.Enabled = false; + _outputSorter.Enabled = true; + } + + public void Reset() + { + Mode = DockMode.Off; + _inputSorter.Enabled = false; + _outputSorter.Enabled = false; + } + + public void AddBlock(IMyTerminalBlock block, MyIni ini) + { + if (block is IMyConveyorSorter) + { + string direction = ini.Get("dockLoader", "direction").ToString(); + switch (direction) + { + case "input": + _inputSorter = block as IMyConveyorSorter; + _inputSorter.Enabled = false; + break; + case "output": + _outputSorter = block as IMyConveyorSorter; + _outputSorter.Enabled = false; + break; + default: + _console.Print($"Invalid direction for '{block.CustomName}'"); + break; + } + } + else if (block is IMyShipConnector) + { + _ports.Add(block as IMyShipConnector); + } + else + { + _console.Print($"Can't add block '{block.CustomName}'"); + } + } + } + } +} \ No newline at end of file diff --git a/DockLoader/DockLoader.csproj b/DockLoader/DockLoader.csproj new file mode 100644 index 0000000..7705310 --- /dev/null +++ b/DockLoader/DockLoader.csproj @@ -0,0 +1,27 @@ + + + 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/DockLoader/DockLoader.mdk.ini b/DockLoader/DockLoader.mdk.ini new file mode 100644 index 0000000..5add8f4 --- /dev/null +++ b/DockLoader/DockLoader.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/DockLoader/DockLoader.mdk.local.ini b/DockLoader/DockLoader.mdk.local.ini new file mode 100644 index 0000000..4b66820 --- /dev/null +++ b/DockLoader/DockLoader.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/DockLoader/Instructions.readme b/DockLoader/Instructions.readme new file mode 100644 index 0000000..ed30ab7 --- /dev/null +++ b/DockLoader/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/DockLoader/Program.cs b/DockLoader/Program.cs new file mode 100644 index 0000000..1c47d4c --- /dev/null +++ b/DockLoader/Program.cs @@ -0,0 +1,124 @@ +using System.Collections.Generic; +using Sandbox.ModAPI.Ingame; +using VRage.Game.ModAPI.Ingame.Utilities; +using System.Linq; + +namespace IngameScript +{ + public partial class Program : MyGridProgram, IConsoleProgram + { + public MyIni Ini { get; private set; } + public IConsole Console { get; private set; } + + private MyCommandLine _cli = new MyCommandLine(); + private Warehouse _warehouse; + private Dictionary _docks = new Dictionary(); + + public Program() + { + Ini = new MyIni(); + Console = new MainConsole(this, "Dock Loader"); + _warehouse = new Warehouse(Console); + + // Find all the blocks with a [dockLoader] config + List blocks = new List(); + GridTerminalSystem.GetBlocksOfType(blocks, blockFilter); + foreach (IMyTerminalBlock block in blocks) + { + Ini.TryParse(block.CustomData); + if (Ini.Get("dockLoader", "warehouse").ToBoolean(false)) _warehouse.AddBlock(block, Ini); + else + { + string id = Ini.Get("dockLoader", "id").ToString(); + if (id == "") + { + Console.Print($"Ignoring invalid block '{block.CustomName}'"); + continue; + } + + if (!_docks.ContainsKey(id)) _docks[id] = new Dock(id, Console); + _docks[id].AddBlock(block, Ini); + } + } + + // Remove any non-functional docks. + foreach (Dock dock in _docks.Values.ToList()) + { + if (!dock.Functional) + { + Console.Print($"Dock '{dock.Id}' not fully configured, ignoring."); + _docks.Remove(dock.Id); + } + } + + Console.Print($"Found {_docks.Count} docks to manage."); + + Runtime.UpdateFrequency |= UpdateFrequency.Update100; + } + + public void Main(string argument, UpdateType updateSource) + { + handleInput(argument); + + // Check on loading state + int loadingCount = 0; + bool timeout = _warehouse.Timeout; + foreach (Dock dock in _docks.Values) + { + dock.Update(); + if (dock.Mode == DockMode.Loading) + { + if (timeout) dock.Reset(); + else loadingCount++; + } + } + + // This will decrement any loading timer, and switch to unloading mode when we do timeout. + // It will also switch to unloading mode if we pass it a 0. + if (updateSource.HasFlag(UpdateType.Update100)) _warehouse.Update(loadingCount); + } + + private bool blockFilter(IMyTerminalBlock block) + { + return block.IsSameConstructAs(this.Me) && MyIni.HasSection(block.CustomData, "dockLoader"); + } + + private void handleInput(string argument) + { + if (argument == "") return; + _cli.TryParse(argument); + if (_cli.ArgumentCount != 2) + { + Console.Print("Must call script with exactly 2 arguments."); + return; + } + + string command = _cli.Argument(0).Trim().ToLower(); + string dockId = _cli.Argument(1).Trim().ToLower(); + + if (!_docks.ContainsKey(dockId)) + { + Console.Print($"Unknown dock '{dockId}'"); + return; + } + + switch (command) + { + case "load": + _docks[dockId].StartLoading(); + _warehouse.StartLoading(); + break; + case "unload": + _docks[dockId].StartUnloading(); + break; + case "reset": + _docks[dockId].Reset(); + break; + default: + Console.Print($"Unknown command '{command}'"); + break; + } + + } + } +} diff --git a/DockLoader/Warehouse.cs b/DockLoader/Warehouse.cs new file mode 100644 index 0000000..576198d --- /dev/null +++ b/DockLoader/Warehouse.cs @@ -0,0 +1,72 @@ +using Sandbox.ModAPI.Ingame; +using VRage.Game.ModAPI.Ingame.Utilities; + +namespace IngameScript +{ + partial class Program + { + public class Warehouse + { + public bool Timeout + { + get + { + return _timeoutTicks == 0; + } + } + + private IMyConveyorSorter _inputSorter; + private IMyConveyorSorter _outputSorter; + private IConsole _console; + private uint _timeoutTicks = 0; + + public Warehouse(IConsole console) + { + _console = new PrefixedConsole(console, "warehouse"); + } + + public void Update(int loadingCount) + { + if (_timeoutTicks > 0) + { + _timeoutTicks--; + if (_timeoutTicks == 0 || loadingCount == 0) + { + _timeoutTicks = 0; + _outputSorter.Enabled = false; + _inputSorter.Enabled = true; + } + } + } + + // A dock has requested loading + public void StartLoading() + { + _inputSorter.Enabled = false; + _outputSorter.Enabled = true; + _timeoutTicks = 75; // This is approximately 2 minutes. + } + + public void AddBlock(IMyTerminalBlock block, MyIni ini) + { + if (!(block is IMyConveyorSorter)) + { + _console.Print($"Ignoring incompatible block '{block.CustomName}'"); + return; + } + switch (ini.Get("dockLoader", "direction").ToString()) + { + case "input": + _inputSorter = block as IMyConveyorSorter; + break; + case "output": + _outputSorter = block as IMyConveyorSorter; + break; + default: + _console.Print($"Invalid direction for '{block.CustomName}'"); + break; + } + } + } + } +} \ No newline at end of file diff --git a/DockLoader/thumb.png b/DockLoader/thumb.png new file mode 100644 index 0000000..a8dc2ef Binary files /dev/null and b/DockLoader/thumb.png differ diff --git a/ScriptTemplate.cs b/ScriptTemplate.cs new file mode 100644 index 0000000..ac4f4e1 --- /dev/null +++ b/ScriptTemplate.cs @@ -0,0 +1,35 @@ +using Sandbox.ModAPI.Ingame; +using VRage.Game.ModAPI.Ingame.Utilities; + +namespace IngameScript +{ + public partial class Program : MyGridProgram, IConsoleProgram + { + public MyIni Ini { get; private set; } + public IConsole Console { get; private set; } + + private MyCommandLine _cli = new MyCommandLine(); + + public Program() + { + Ini = new MyIni(); + Console = new MainConsole(this, "Program Name"); + } + + public void Main(string argument, UpdateType updateSource) + { + handleInput(argument); + } + + private bool blockFilter(IMyTerminalBlock block) + { + return block.IsSameConstructAs(this.Me); + } + + private void handleInput(string argument) + { + if (argument == "") return; + _cli.TryParse(argument); + } + } +} \ No newline at end of file diff --git a/SpaceEngineers.sln b/SpaceEngineers.sln index e1bfe91..f5319b6 100644 --- a/SpaceEngineers.sln +++ b/SpaceEngineers.sln @@ -17,6 +17,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DockingController", "Dockin EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InfoDisplays", "InfoDisplays\InfoDisplays.csproj", "{4C7C8B10-1E43-453E-A9DA-A3626FE85ACC}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DockLoader", "DockLoader\DockLoader.csproj", "{A4D9F936-93B2-423A-BD76-A97A084BD605}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -43,6 +45,10 @@ Global {4C7C8B10-1E43-453E-A9DA-A3626FE85ACC}.Debug|Any CPU.Build.0 = Debug|x64 {4C7C8B10-1E43-453E-A9DA-A3626FE85ACC}.Release|Any CPU.ActiveCfg = Release|x64 {4C7C8B10-1E43-453E-A9DA-A3626FE85ACC}.Release|Any CPU.Build.0 = Release|x64 + {A4D9F936-93B2-423A-BD76-A97A084BD605}.Debug|Any CPU.ActiveCfg = Debug|x64 + {A4D9F936-93B2-423A-BD76-A97A084BD605}.Debug|Any CPU.Build.0 = Debug|x64 + {A4D9F936-93B2-423A-BD76-A97A084BD605}.Release|Any CPU.ActiveCfg = Release|x64 + {A4D9F936-93B2-423A-BD76-A97A084BD605}.Release|Any CPU.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/docking.cs b/docking.cs deleted file mode 100644 index 7522fc9..0000000 --- a/docking.cs +++ /dev/null @@ -1,113 +0,0 @@ -// Docking controller script; handles docking and undocking. -// Specifically, when you activate the script it will: -// * Connect any Connectors whose names start with "Docking Port" that are ready to connect. -// * Turn off all engines. -// * Set all O2 and Hydrogen tanks to Stockpile. -// -// Recharging batteries needs to be done manually, since the script can't finish with the -// batteries disabled. -// -// When you activate the script with "-undock" it will reverse all of these actions. -// -// TODO: None of the below switches work yet. -// You can selectively disable some functionality with switches. -// * "-no-refuel" to disable refueling - -MyCommandLine cli; -IEnumerator state; - -List dockingPorts; -List thrusters; -List tanks; - -public Program() { - cli = new MyCommandLine(); - state = null; - - dockingPorts = new List(); - List allConnectors = new List(); - GridTerminalSystem.GetBlocksOfType(allConnectors); - foreach(IMyShipConnector connector in allConnectors) { - if (connector.CustomName.StartsWith("Docking Port")) { - dockingPorts.Add(connector); - } - } - - thrusters = new List(); - GridTerminalSystem.GetBlocksOfType(thrusters); - - tanks = new List(); - GridTerminalSystem.GetBlocksOfType(tanks); - - Echo($"Found {dockingPorts.Count} docking ports."); - Echo($"Found {thrusters.Count} thrusters"); - Echo($"Found {tanks.Count} tanks"); -} - -public void Main(string argument, UpdateType updateSource) { - if (state == null) { - cli.TryParse(argument); - if (cli.Switch("undock")) state = Undock(); - else state = Dock(); - Runtime.UpdateFrequency = UpdateFrequency.Update100; - return; - } - - if (!state.MoveNext()) { - Runtime.UpdateFrequency = UpdateFrequency.None; - state.Dispose(); - state = null; - } -} - -private IEnumerator Dock() { - Echo("Initiating docking operation."); - - foreach (IMyShipConnector dockingPort in dockingPorts) { - if (dockingPort.Status == MyShipConnectorStatus.Connectable) { - dockingPort.Connect(); - } - } - - bool docked = false; - while (!docked) { - yield return true; - foreach (IMyShipConnector dockingPort in dockingPorts) { - if (dockingPort.Status == MyShipConnectorStatus.Connected) { - docked = true; - break; - } - } - } - - Echo("Docking clamp engaged. Shutting down systems."); - - foreach (IMyThrust thruster in thrusters) { - thruster.Enabled = false; - } - - foreach (IMyGasTank tank in tanks) { - tank.Stockpile = true; - } - - yield return false; -} - -private IEnumerator Undock() { - Echo("Initiating undocking operation."); - foreach (IMyGasTank tank in tanks) { - tank.Stockpile = false; - } - - foreach (IMyThrust thruster in thrusters) { - thruster.Enabled = true; - } - - foreach (IMyShipConnector dockingPort in dockingPorts) { - if (dockingPort.Status == MyShipConnectorStatus.Connected) { - dockingPort.Disconnect(); - } - } - - yield return false; -} \ No newline at end of file