space_engineers/ActionSequencer/Program.cs

226 lines
8.4 KiB
C#

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<IEnumerator<bool>> _jobs = new List<IEnumerator<bool>>();
private Dictionary<string, ActionGroup> _actionGroups = new Dictionary<string, ActionGroup>();
public Program()
{
Console = new MainConsole(this, "Action Sequencer");
// initialize all the sequencers
List<IMyTerminalBlock> blocks = new List<IMyTerminalBlock>();
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");
}
}
}