using Sandbox.ModAPI.Ingame; using SpaceEngineers.Game.ModAPI.Ingame; using System; using System.Collections.Generic; using VRage.Game.ModAPI.Ingame.Utilities; namespace IngameScript { public partial class Program : MyGridProgram, IConsoleProgram { public MyIni Ini { get; } = new MyIni(); public IConsole Console { get; private set; } private MyCommandLine _cli = new MyCommandLine(); private List> _jobs = new List>(); private Dictionary _actionGroups = new Dictionary(); public Program() { Console = new MainConsole(this, "Action Sequencer"); // initialize all the sequencers List blocks = new List(); GridTerminalSystem.GetBlocksOfType(blocks, blockFilter); foreach (IMyTerminalBlock block in blocks) { Ini.TryParse(block.CustomData); string id = Ini.Get("sequencer", "groupName").ToString().Trim(); if (id == "") { Console.Print($"No groupName found for '{block.CustomName}'. Skipping."); continue; } string actionNames = Ini.Get("sequencer", "actions").ToString().Trim(); ; if (actionNames == "") { Console.Print($"No actions defined for '{block.CustomName}'. Skipping."); continue; } if (!_actionGroups.ContainsKey(id)) _actionGroups[id] = new ActionGroup(Console, id); // Find the custom section for each action and parse the block into it. foreach (string actionName in actionNames.Split(',')) { string key = "action" + actionName.Trim(); if (!MyIni.HasSection(block.CustomData, key)) { Console.Print($"Missing config section '{key}'; skipping action."); continue; } int step = Int32.Parse(Ini.Get(key, "step").ToString("0")); BlockAction blockAction = buildBlockAction(block, key); if (blockAction == null) { Console.Print($"Failed to add '{block.CustomName}' to action '{actionName}'."); continue; } _actionGroups[id].AddActionBlock(actionName.Trim(), step, blockAction); } } Console.Print($"Found {_actionGroups.Count} sequences."); Console.UpdateTickCount(); } public void Main(string argument, UpdateType updateSource) { Console.UpdateTickCount(); if (argument != "") { _cli.TryParse(argument); if (_cli.ArgumentCount != 2) { Console.Print("Must call script with exactly 2 arguments."); } else { if (_actionGroups.ContainsKey(_cli.Argument(0))) { _jobs.Add(_actionGroups[_cli.Argument(0)].RunAction(_cli.Argument(1))); Runtime.UpdateFrequency |= UpdateFrequency.Update10; } else { Console.Print($"Failed to find action group '{_cli.Argument(0)}'"); } } } // Process running jobs for (int i = 0; i < _jobs.Count; i++) { if (_jobs[i].MoveNext()) continue; _jobs[i].Dispose(); _jobs.Remove(_jobs[i]); i--; Console.Print("Operation Complete."); } if (_jobs.Count == 0) Runtime.UpdateFrequency = UpdateFrequency.None; } // Prerequisite: Ini.Parse has already been called for this block. private BlockAction buildBlockAction(IMyTerminalBlock block, string key) { if (block is IMyDoor) { DoorAction action; switch (Ini.Get(key, "action").ToString("open")) { case "open": action = DoorAction.Open; break; case "close": action = DoorAction.Close; break; default: Console.Print($"Invalid door action for '{block.CustomName}'. Defaulting to open."); action = DoorAction.Open; break; } return new BlockActionDoor( block as IMyDoor, action, Ini.Get(key, "lock").ToBoolean(true) ); } else if (block is IMyMotorStator) { MyRotationDirection direction; switch (Ini.Get(key, "direction").ToString("auto")) { case "auto": direction = MyRotationDirection.AUTO; break; case "cw": case "clockwise": direction = MyRotationDirection.CW; break; case "ccw": case "counterclockwise": case "anticlockwise": direction = MyRotationDirection.CCW; break; default: Console.Print($"Invalid direction for '{block.CustomName}'. Defaulting to auto."); direction = MyRotationDirection.AUTO; break; } return new BlockActionRotor( block as IMyMotorStator, Ini.Get(key, "angle").ToSingle(0f), Ini.Get(key, "velocity").ToSingle(5f), direction ); } else if (block is IMyPistonBase) { return new BlockActionPiston( block as IMyPistonBase, Ini.Get(key, "position").ToSingle(0f), Ini.Get(key, "velocity").ToSingle(2f) ); } else if (block is IMyShipMergeBlock) { MergeAction action; string config = Ini.Get(key, "action").ToString("merge").ToLower(); switch (config) { case "merge": action = MergeAction.Merge; break; case "unmerge": action = MergeAction.Unmerge; break; default: Console.Print($"Unknown action '{config}. Defaulting to merge."); action = MergeAction.Merge; break; } return new BlockActionMerge(block as IMyShipMergeBlock, action); } else if (block is IMyLandingGear) { LandingGearAction action; string config = Ini.Get(key, "action").ToString("unlock").ToLower(); switch (config) { case "enable": action = LandingGearAction.Enable; break; case "disable": action = LandingGearAction.Disable; break; case "lock": action = LandingGearAction.Lock; break; case "unlock": action = LandingGearAction.Unlock; break; } return new BlockActionLandingGear(block as IMyLandingGear, action); } // TODO: there are several block types added for other scripts that we should support here. Console.Print($"Can't add unsupported block '{block.CustomName}'"); return null; } public bool blockFilter(IMyTerminalBlock block) { return block.IsSameConstructAs(this.Me) && MyIni.HasSection(block.CustomData, "sequencer"); } } }