Completely rework the Sequencery library and abandon MechDoor in favor of just using the action sequencer script.
This commit is contained in:
62
Mixins/Sequencer/ActionGroup.cs
Normal file
62
Mixins/Sequencer/ActionGroup.cs
Normal file
@ -0,0 +1,62 @@
|
||||
// Represents a series of ActionSequences
|
||||
// that are mutually exclusive. Typically
|
||||
// this is designed to represent multiple ActionSequences
|
||||
// that act on the same set of blocks, such as an
|
||||
// "Extend" and "Retract" action for a multi-stage mechanical
|
||||
// construction, or perhaps "Open" and "Close" sequences for a set of
|
||||
// mechanical doors.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace IngameScript
|
||||
{
|
||||
partial class Program
|
||||
{
|
||||
public class ActionGroup
|
||||
{
|
||||
public string Name { get; private set; }
|
||||
|
||||
public bool Running { get; private set; } = false;
|
||||
|
||||
private Dictionary<string, ActionSequence> _actions = new Dictionary<string, ActionSequence>();
|
||||
private IConsole _console;
|
||||
|
||||
public ActionGroup(IConsole console, string name)
|
||||
{
|
||||
// Todo: use a PrefixedConsole here?
|
||||
_console = console;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
if (!_actions.ContainsKey(actionName)) _actions[actionName] = new ActionSequence(actionName);
|
||||
_actions[actionName].Add(step, actionBlock);
|
||||
}
|
||||
|
||||
public IEnumerator<bool> RunAction(string actionName)
|
||||
{
|
||||
if (Running)
|
||||
{
|
||||
_console.Print($"Ignoring action '{actionName}' on '{Name}'. Already running an action.");
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (!_actions.ContainsKey(actionName))
|
||||
{
|
||||
_console.Print($"No action '{actionName}' defined for '{Name}'");
|
||||
yield break;
|
||||
}
|
||||
|
||||
Running = true;
|
||||
|
||||
IEnumerator<bool> job = _actions[actionName].Run();
|
||||
while (job.MoveNext()) yield return true;
|
||||
|
||||
Running = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
65
Mixins/Sequencer/ActionSequence.cs
Normal file
65
Mixins/Sequencer/ActionSequence.cs
Normal file
@ -0,0 +1,65 @@
|
||||
// An ActionSequence encapsulates a series of IBlockActions to perform.
|
||||
// It represents a single logical coordinated "action". The action may have
|
||||
// multiple steps, each with multiple actions. It provides a method to asynchronously
|
||||
// perform those steps in sequence.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace IngameScript
|
||||
{
|
||||
partial class Program
|
||||
{
|
||||
public class ActionSequence
|
||||
{
|
||||
public string Name { get; private set; }
|
||||
public bool Running { get; private set; } = false;
|
||||
|
||||
private SortedDictionary<int, List<IBlockAction>> _steps = new SortedDictionary<int, List<IBlockAction>>();
|
||||
|
||||
public ActionSequence(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public void Add(int step, IBlockAction action)
|
||||
{
|
||||
if (!_steps.ContainsKey(step)) _steps[step] = new List<IBlockAction>();
|
||||
_steps[step].Add(action);
|
||||
}
|
||||
|
||||
public IEnumerator<bool> Run()
|
||||
{
|
||||
if (Running) yield break;
|
||||
Running = true;
|
||||
|
||||
List<IEnumerator<bool>> jobs = new List<IEnumerator<bool>>();
|
||||
foreach (List<IBlockAction> step in _steps.Values)
|
||||
{
|
||||
foreach (IBlockAction action in step)
|
||||
{
|
||||
jobs.Add(action.Run());
|
||||
}
|
||||
|
||||
bool stepRunning = true;
|
||||
while (stepRunning)
|
||||
{
|
||||
stepRunning = false;
|
||||
foreach (IEnumerator<bool> job in jobs)
|
||||
{
|
||||
if (job.MoveNext()) stepRunning = true;
|
||||
}
|
||||
yield return true;
|
||||
}
|
||||
|
||||
foreach (IEnumerator<bool> job in jobs)
|
||||
{
|
||||
job.Dispose();
|
||||
}
|
||||
jobs.Clear();
|
||||
}
|
||||
|
||||
Running = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
52
Mixins/Sequencer/BlockActionDoor.cs
Normal file
52
Mixins/Sequencer/BlockActionDoor.cs
Normal file
@ -0,0 +1,52 @@
|
||||
using System.Collections.Generic;
|
||||
using Sandbox.ModAPI.Ingame;
|
||||
|
||||
namespace IngameScript
|
||||
{
|
||||
partial class Program
|
||||
{
|
||||
public class BlockActionDoor : IBlockAction
|
||||
{
|
||||
public enum DoorAction
|
||||
{
|
||||
Open,
|
||||
Close,
|
||||
}
|
||||
|
||||
public bool Running { get; private set; } = false;
|
||||
|
||||
private IMyDoor _door;
|
||||
private DoorAction _action;
|
||||
private bool _lockDoor;
|
||||
|
||||
public BlockActionDoor(
|
||||
IMyDoor door,
|
||||
DoorAction action,
|
||||
bool lockDoor = true
|
||||
)
|
||||
{
|
||||
_door = door;
|
||||
_action = action;
|
||||
_lockDoor = lockDoor;
|
||||
}
|
||||
|
||||
public IEnumerator<bool> Run()
|
||||
{
|
||||
switch (_action)
|
||||
{
|
||||
case DoorAction.Open:
|
||||
_door.Enabled = true;
|
||||
_door.OpenDoor();
|
||||
while (_door.Status != DoorStatus.Open) yield return true;
|
||||
break;
|
||||
case DoorAction.Close:
|
||||
_door.Enabled = true;
|
||||
_door.CloseDoor();
|
||||
while (_door.Status != DoorStatus.Closed) yield return true;
|
||||
break;
|
||||
}
|
||||
if (_lockDoor) _door.Enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
40
Mixins/Sequencer/BlockActionPiston.cs
Normal file
40
Mixins/Sequencer/BlockActionPiston.cs
Normal file
@ -0,0 +1,40 @@
|
||||
using System.Collections.Generic;
|
||||
using Sandbox.ModAPI.Ingame;
|
||||
|
||||
namespace IngameScript
|
||||
{
|
||||
partial class Program
|
||||
{
|
||||
public class BlockActionPiston : IBlockAction
|
||||
{
|
||||
public bool Running { get; private set; } = false;
|
||||
|
||||
private IMyPistonBase _piston;
|
||||
private float _position;
|
||||
private float _velocity;
|
||||
|
||||
public BlockActionPiston(
|
||||
IMyPistonBase piston,
|
||||
float position,
|
||||
float velocity = 2f
|
||||
)
|
||||
{
|
||||
_piston = piston;
|
||||
_position = position;
|
||||
_velocity = velocity;
|
||||
}
|
||||
|
||||
public IEnumerator<bool> Run()
|
||||
{
|
||||
_piston.MoveToPosition(_position, _velocity);
|
||||
|
||||
float lastValue = -1f;
|
||||
while (lastValue != _piston.CurrentPosition)
|
||||
{
|
||||
lastValue = _piston.CurrentPosition;
|
||||
yield return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
46
Mixins/Sequencer/BlockActionRotor.cs
Normal file
46
Mixins/Sequencer/BlockActionRotor.cs
Normal file
@ -0,0 +1,46 @@
|
||||
using System.Collections.Generic;
|
||||
using Sandbox.ModAPI.Ingame;
|
||||
|
||||
namespace IngameScript
|
||||
{
|
||||
partial class Program
|
||||
{
|
||||
public class BlockActionRotor : IBlockAction
|
||||
{
|
||||
public bool Running { get; private set; } = false;
|
||||
|
||||
private IMyMotorStator _rotor;
|
||||
private float _angle;
|
||||
private float _velocity;
|
||||
private MyRotationDirection _direction;
|
||||
|
||||
public BlockActionRotor(
|
||||
IMyMotorStator rotor,
|
||||
float angle,
|
||||
float velocity = 5f,
|
||||
MyRotationDirection direction = MyRotationDirection.AUTO
|
||||
)
|
||||
{
|
||||
_rotor = rotor;
|
||||
_angle = angle;
|
||||
_velocity = velocity;
|
||||
_direction = direction;
|
||||
}
|
||||
|
||||
public IEnumerator<bool> Run()
|
||||
{
|
||||
_rotor.RotorLock = false;
|
||||
_rotor.RotateToAngle(_direction, _angle, _velocity);
|
||||
|
||||
float _lastAngle = -1;
|
||||
while (_rotor.Angle != _lastAngle)
|
||||
{
|
||||
_lastAngle = _rotor.Angle;
|
||||
yield return true;
|
||||
}
|
||||
|
||||
_rotor.RotorLock = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
36
Mixins/Sequencer/BlockActionTemplate.cs
Normal file
36
Mixins/Sequencer/BlockActionTemplate.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Sandbox.ModAPI.Ingame;
|
||||
|
||||
namespace IngameScript
|
||||
{
|
||||
partial class Program
|
||||
{
|
||||
public class BlockActionRotor : IBlockAction
|
||||
{
|
||||
private IMyMotorRotor _rotor;
|
||||
private float _targetAngle;
|
||||
private float _velocity = 5f;
|
||||
private RotationDirection _direction = RotationDirection.AUTO;
|
||||
|
||||
public BlockActionRotor(
|
||||
IMyMotorRotor rotor,
|
||||
float targetAngle,
|
||||
float velocity = 5f,
|
||||
|
||||
)
|
||||
{
|
||||
_rotor = rotor;
|
||||
}
|
||||
|
||||
public IEnumerator<bool> Run()
|
||||
{
|
||||
// code to actually execute the action goes here
|
||||
// any loops that wait for a condition to be true should
|
||||
// `yield return true` inside the loop.
|
||||
// If the action ends prematurely, use `yield break`
|
||||
yield return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
17
Mixins/Sequencer/IBlockAction.cs
Normal file
17
Mixins/Sequencer/IBlockAction.cs
Normal file
@ -0,0 +1,17 @@
|
||||
// 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<bool> Run();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace IngameScript
|
||||
{
|
||||
partial class Program
|
||||
{
|
||||
public interface ISequenceable
|
||||
{
|
||||
bool Running { get; }
|
||||
int Step { get; set; }
|
||||
IEnumerator<bool> Run(bool deploy);
|
||||
}
|
||||
}
|
||||
}
|
9
Mixins/Sequencer/ISequenceableAction.cs
Normal file
9
Mixins/Sequencer/ISequenceableAction.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace IngameScript
|
||||
{
|
||||
partial class Program
|
||||
{
|
||||
|
||||
}
|
||||
}
|
132
Mixins/Sequencer/SequenceableBlock.cs
Normal file
132
Mixins/Sequencer/SequenceableBlock.cs
Normal file
@ -0,0 +1,132 @@
|
||||
// A SequenceableBlock holds a reference to a compatible block type,
|
||||
// and a list of available actions sorted by name.
|
||||
// It provides a RunAction() method that allows the caller to
|
||||
// run the configured actions.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Sandbox.ModAPI.Ingame;
|
||||
using VRage.Game.ModAPI.Ingame.Utilities;
|
||||
|
||||
namespace IngameScript
|
||||
{
|
||||
partial class Program
|
||||
{
|
||||
public interface ISequenceableAction
|
||||
{
|
||||
string Name { get; }
|
||||
IEnumerator<bool> Run();
|
||||
}
|
||||
|
||||
public class SequenceableBlock
|
||||
{
|
||||
private IConsole _console;
|
||||
private IMyTerminalBlock _block;
|
||||
private Dictionary<string, ISequenceableAction> _actions = new Dictionary<string, ISequenceableAction>();
|
||||
|
||||
public SequenceableBlock(IConsole console, IMyTerminalBlock block)
|
||||
{
|
||||
_console = console;
|
||||
if (!(_block is IMyDoor || _block is IMyPistonBase || _block is IMyMotorRotor))
|
||||
{
|
||||
_console.Print("ERROR: Incompatible block '{_block.CustomName}' being sequenced.");
|
||||
}
|
||||
_block = block;
|
||||
}
|
||||
|
||||
// We employ a pseudo-factory pattern to parse the settings
|
||||
// into ISequenceableAction objects.
|
||||
public void Parse(MyIni ini, string sectionName = "sequencer")
|
||||
{
|
||||
ini.TryParse(_block.CustomData, sectionName);
|
||||
List<MyIniKey> keys = new List<MyIniKey>();
|
||||
ini.GetKeys(sectionName, keys);
|
||||
|
||||
if (_block is IMyDoor)
|
||||
{
|
||||
parseDoor(ini, keys);
|
||||
}
|
||||
else if (_block is IMyPistonBase)
|
||||
{
|
||||
parsePiston(ini, keys);
|
||||
}
|
||||
else if (_block is IMyMotorRotor)
|
||||
{
|
||||
parseRotor(ini, keys);
|
||||
}
|
||||
}
|
||||
|
||||
// Alternatively, the user can parse manually and override anything they
|
||||
// need to.
|
||||
public void AddAction(ISequenceableAction action, string name)
|
||||
{
|
||||
_actions.Add(action.Name, action);
|
||||
}
|
||||
|
||||
private void parseDoor(MyIni ini, List<MyIniKey> keys)
|
||||
{
|
||||
foreach (MyIniKey key in keys)
|
||||
{
|
||||
string[] values = ini.Get(key).ToString().Split(',');
|
||||
string actionType = values[1];
|
||||
bool lockDoor = true;
|
||||
if (values.Length >= 3) lockDoor = values[2] == "true" ? true : false;
|
||||
|
||||
SequenceableActionDoor action = new SequenceableActionDoor(
|
||||
_console,
|
||||
key.Name,
|
||||
_block as IMyDoor,
|
||||
actionType,
|
||||
lockDoor
|
||||
);
|
||||
_actions.Add(key.Name, action);
|
||||
}
|
||||
}
|
||||
|
||||
private void parsePiston(MyIni ini, List<MyIniKey> keys)
|
||||
{
|
||||
foreach (MyIniKey key in keys)
|
||||
{
|
||||
string[] values = ini.Get(key).ToString().Split(',');
|
||||
float angle = Single.Parse(values[1]);
|
||||
float velocity = 5f;
|
||||
if (values.Length >= 3) velocity = Single.Parse(values[2]);
|
||||
|
||||
MyRotationDirection dir = MyRotationDirection.AUTO;
|
||||
if (values.Length >= 4)
|
||||
{
|
||||
switch (values[3])
|
||||
{
|
||||
case "cw":
|
||||
dir = MyRotationDirection.CW;
|
||||
break;
|
||||
case "ccw":
|
||||
dir = MyRotationDirection.CCW;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SequenceableActionPiston action = new SequenceableActionPiston(
|
||||
_console,
|
||||
key.Name,
|
||||
_block as IMyPistonBase,
|
||||
|
||||
);
|
||||
_actions.Add(key.Name, action);
|
||||
}
|
||||
}
|
||||
|
||||
private void parseRotor(MyIni ini, List<MyIniKey> keys)
|
||||
{
|
||||
foreach (MyIniKey key in keys)
|
||||
{
|
||||
string[] values = ini.Get(key).ToString().Split(',');
|
||||
|
||||
SequenceableActionRotor action = new SequenceableActionRotor();
|
||||
_actions.Add(key.Name, action);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
using Sandbox.ModAPI.Ingame;
|
||||
using System.Collections.Generic;
|
||||
using VRage.Game.ModAPI.Ingame.Utilities;
|
||||
|
||||
namespace IngameScript
|
||||
{
|
||||
partial class Program
|
||||
{
|
||||
public class SequenceableDoor : ISequenceable
|
||||
{
|
||||
public bool Running { get; private set; } = false;
|
||||
public int Step { get; set; }
|
||||
|
||||
public bool DeployOpen { get; set; }
|
||||
public bool LockOpen { get; set; }
|
||||
public bool LockClosed { get; set; }
|
||||
|
||||
private IMyDoor _door;
|
||||
|
||||
public SequenceableDoor(
|
||||
IConsoleProgram _program,
|
||||
IMyDoor door,
|
||||
string sectionName)
|
||||
{
|
||||
_door = door;
|
||||
|
||||
MyIni ini = _program.Ini;
|
||||
ini.TryParse(door.CustomData);
|
||||
DeployOpen = ini.Get(sectionName, "deployOpen").ToBoolean(true);
|
||||
LockOpen = ini.Get(sectionName, "lockOpen").ToBoolean(true);
|
||||
LockClosed = ini.Get(sectionName, "lockClosed").ToBoolean(true);
|
||||
Step = ini.Get(sectionName, "step").ToInt32(0);
|
||||
}
|
||||
|
||||
public IEnumerator<bool> Run(bool deploy)
|
||||
{
|
||||
if (Running) yield break;
|
||||
Running = true;
|
||||
|
||||
if (deploy && DeployOpen || !deploy && !DeployOpen)
|
||||
{
|
||||
foreach (bool tick in _openDoor()) yield return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (bool tick in _closeDoor()) yield return true;
|
||||
}
|
||||
Running = false;
|
||||
}
|
||||
|
||||
public IEnumerable<bool> _openDoor()
|
||||
{
|
||||
_door.Enabled = true;
|
||||
_door.OpenDoor();
|
||||
while (_door.Status != DoorStatus.Open) yield return true;
|
||||
if (LockOpen)
|
||||
{
|
||||
_door.Enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<bool> _closeDoor()
|
||||
{
|
||||
_door.Enabled = true;
|
||||
_door.CloseDoor();
|
||||
while (_door.Status != DoorStatus.Closed) yield return true;
|
||||
if (LockClosed)
|
||||
{
|
||||
_door.Enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
// I hate Factories, but when the shoe fits...
|
||||
|
||||
using Sandbox.ModAPI.Ingame;
|
||||
using SpaceEngineers.Game.ModAPI.Ingame;
|
||||
using VRage.Game.ModAPI.Ingame.Utilities;
|
||||
|
||||
namespace IngameScript
|
||||
{
|
||||
partial class Program
|
||||
{
|
||||
public class SequenceableFactory
|
||||
{
|
||||
public static ISequenceable MakeSequenceable(
|
||||
IConsoleProgram program,
|
||||
IMyTerminalBlock block,
|
||||
string sectionName = "sequence")
|
||||
{
|
||||
if (block is IMyMotorStator)
|
||||
{
|
||||
return new SequenceableRotor(program, block as IMyMotorStator, sectionName);
|
||||
}
|
||||
if (block is IMyPistonBase)
|
||||
{
|
||||
return new SequenceablePiston(program, block as IMyPistonBase, sectionName);
|
||||
}
|
||||
if (block is IMyShipMergeBlock)
|
||||
{
|
||||
// return new SequenceableMergeBlock(block as IMyShipMergeBlock, step);
|
||||
}
|
||||
if (block is IMyDoor)
|
||||
{
|
||||
return new SequenceableDoor(program, block as IMyDoor, sectionName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
using Sandbox.ModAPI.Ingame;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using VRage.Game.ModAPI.Ingame.Utilities;
|
||||
|
||||
namespace IngameScript
|
||||
{
|
||||
partial class Program
|
||||
{
|
||||
public class SequenceablePiston : ISequenceable
|
||||
{
|
||||
public bool Running { get; private set; } = false;
|
||||
public int Step { get; set; }
|
||||
|
||||
private IConsoleProgram _program;
|
||||
private IMyPistonBase _piston;
|
||||
private float _deployPosition;
|
||||
private float _stowPosition;
|
||||
private float _velocity;
|
||||
|
||||
public SequenceablePiston(IConsoleProgram program, IMyPistonBase piston, string sectionName)
|
||||
{
|
||||
_program = program;
|
||||
_piston = piston;
|
||||
|
||||
MyIni ini = _program.Ini;
|
||||
ini.TryParse(piston.CustomData);
|
||||
|
||||
_deployPosition = ini.Get(sectionName, "deployPosition").ToSingle(10F);
|
||||
_stowPosition = ini.Get(sectionName, "stowPosition").ToSingle(0F);
|
||||
_velocity = ini.Get(sectionName, "velocity").ToSingle(5F);
|
||||
Step = ini.Get(sectionName, "step").ToInt32(0);
|
||||
}
|
||||
|
||||
public IEnumerator<bool> Run(bool deploy)
|
||||
{
|
||||
if (Running) yield break;
|
||||
Running = true;
|
||||
|
||||
float targetValue = _stowPosition;
|
||||
float lastValue = -1;
|
||||
if (deploy) targetValue = _deployPosition;
|
||||
_piston.MoveToPosition(targetValue, _velocity);
|
||||
|
||||
while (lastValue != _piston.CurrentPosition)
|
||||
{
|
||||
lastValue = _piston.CurrentPosition;
|
||||
yield return true;
|
||||
}
|
||||
|
||||
Running = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
using Sandbox.ModAPI.Ingame;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using VRage.Game.ModAPI.Ingame.Utilities;
|
||||
|
||||
namespace IngameScript
|
||||
{
|
||||
partial class Program
|
||||
{
|
||||
public class SequenceableRotor : ISequenceable
|
||||
{
|
||||
public bool Running { get; private set; } = false;
|
||||
public int Step { get; set; }
|
||||
|
||||
private IConsoleProgram _program;
|
||||
private float _velocity;
|
||||
private float _deployAngle;
|
||||
private float _stowAngle;
|
||||
private IMyMotorStator _rotor;
|
||||
private MyRotationDirection _deployDirection;
|
||||
private MyRotationDirection _stowDirection;
|
||||
|
||||
public SequenceableRotor(
|
||||
IConsoleProgram program,
|
||||
IMyMotorStator rotor,
|
||||
string sectionName)
|
||||
{
|
||||
_program = program;
|
||||
_rotor = rotor;
|
||||
|
||||
MyIni ini = _program.Ini;
|
||||
ini.TryParse(rotor.CustomData);
|
||||
|
||||
_deployAngle = ini.Get(sectionName, "deployAngle").ToSingle(90F);
|
||||
_stowAngle = ini.Get(sectionName, "stowAngle").ToSingle(0F);
|
||||
_velocity = ini.Get(sectionName, "velocity").ToSingle(5F);
|
||||
switch (ini.Get(sectionName, "deployDirection").ToString("auto"))
|
||||
{
|
||||
case "auto":
|
||||
_deployDirection = MyRotationDirection.AUTO;
|
||||
_stowDirection = MyRotationDirection.AUTO;
|
||||
break;
|
||||
case "cw":
|
||||
_deployDirection = MyRotationDirection.CW;
|
||||
_stowDirection = MyRotationDirection.CCW;
|
||||
break;
|
||||
case "ccw":
|
||||
_deployDirection = MyRotationDirection.CCW;
|
||||
_stowDirection = MyRotationDirection.CW;
|
||||
break;
|
||||
}
|
||||
Step = ini.Get(sectionName, "step").ToInt32(0);
|
||||
}
|
||||
|
||||
public IEnumerator<bool> Run(bool deploy = true)
|
||||
{
|
||||
Running = true;
|
||||
float degAngle = deploy ? _deployAngle : _stowAngle;
|
||||
MyRotationDirection dir = deploy ? _deployDirection : _stowDirection;
|
||||
|
||||
_rotor.RotorLock = false;
|
||||
_rotor.RotateToAngle(dir, degAngle, _velocity);
|
||||
|
||||
float _lastAngle = -1;
|
||||
while (_rotor.Angle != _lastAngle)
|
||||
{
|
||||
_lastAngle = _rotor.Angle;
|
||||
yield return true;
|
||||
}
|
||||
|
||||
_rotor.RotorLock = true;
|
||||
Running = false;
|
||||
}
|
||||
|
||||
private float degToRad(float degrees)
|
||||
{
|
||||
return degrees * ((float)Math.PI / 180F);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
// Represents a single set of blocks to run in order, waiting for each group's completion before
|
||||
// moving on to the next one.
|
||||
|
||||
using Sandbox.ModAPI.Ingame;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace IngameScript
|
||||
{
|
||||
partial class Program
|
||||
{
|
||||
public class Sequencer
|
||||
{
|
||||
public bool Running { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
|
||||
private IConsole _console;
|
||||
|
||||
private SortedDictionary<int, List<ISequenceable>> _sequence = new SortedDictionary<int, List<ISequenceable>>();
|
||||
|
||||
public Sequencer(IConsoleProgram program, string name)
|
||||
{
|
||||
Name = name;
|
||||
_console = new PrefixedConsole(program.Console, Name);
|
||||
}
|
||||
|
||||
public void AddBlock(ISequenceable block)
|
||||
{
|
||||
if (!_sequence.ContainsKey(block.Step)) _sequence[block.Step] = new List<ISequenceable>();
|
||||
_sequence[block.Step].Add(block);
|
||||
}
|
||||
|
||||
// To activate the Sequencer, call this once, then call `MoveNext()` once per tick
|
||||
// on the returned object until it returns false.
|
||||
// (then be sure to call `Dispose() on that object`)
|
||||
public IEnumerator<bool> RunSequence(bool deploy = true)
|
||||
{
|
||||
if (Running)
|
||||
{
|
||||
_console.Print("Already running, ignoring invocation.");
|
||||
yield break;
|
||||
}
|
||||
|
||||
// This is a bit convoluted, but we're extracting the iterator for use in the foreach directly.
|
||||
// This allows us to iterate in reverse when reversing/"closing" the sequence.
|
||||
IEnumerable<KeyValuePair<int, List<ISequenceable>>> steps = deploy ? _sequence : _sequence.Reverse();
|
||||
foreach (KeyValuePair<int, List<ISequenceable>> kvp in steps)
|
||||
{
|
||||
List<ISequenceable> blocks = kvp.Value;
|
||||
List<IEnumerator<bool>> subJobs = new List<IEnumerator<bool>>();
|
||||
Running = true;
|
||||
|
||||
foreach (ISequenceable block in blocks)
|
||||
{
|
||||
// TODO: add some sort of handling for block.Running == true, maybe?
|
||||
// It *should* be an impossible case, but...
|
||||
subJobs.Add(block.Run(deploy));
|
||||
}
|
||||
|
||||
while (Running)
|
||||
{
|
||||
Running = false;
|
||||
foreach (IEnumerator<bool> subJob in subJobs)
|
||||
{
|
||||
if (subJob.MoveNext()) Running = true;
|
||||
}
|
||||
yield return true;
|
||||
}
|
||||
foreach (IEnumerator<bool> subJob in subJobs) subJob.Dispose(); // clean up after ourselves
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -6,6 +6,11 @@
|
||||
<SharedGUID>8a3cdcc5-4b55-4d87-a415-698a0e1ff06f</SharedGUID>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)/**/*.cs" Visible=" '$(ShowCommonFiles)' == 'true' " />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ActionGroup.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ActionSequence.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)BlockActionDoor.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)BlockActionPiston.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)BlockActionRotor.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)IBlockAction.cs" />
|
||||
</ItemGroup>
|
||||
</Project>
|
Reference in New Issue
Block a user