Add a docking controller script using some new Block Actions.

This commit is contained in:
Anna Rose 2025-02-19 19:41:53 -05:00
parent 54f04a7cf0
commit 11298083e7
20 changed files with 344 additions and 42 deletions

View File

@ -66,7 +66,7 @@ namespace IngameScript
continue; continue;
} }
int step = Int32.Parse(Ini.Get(key, "step").ToString("0")); int step = Int32.Parse(Ini.Get(key, "step").ToString("0"));
IBlockAction blockAction = buildBlockAction(block, key); BlockAction blockAction = buildBlockAction(block, key);
if (blockAction == null) if (blockAction == null)
{ {
Console.Print($"Failed to add '{block.CustomName}' to action '{actionName}'."); 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. // 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) if (block is IMyDoor)
{ {
BlockActionDoor.DoorAction action; DoorAction action;
switch (Ini.Get(key, "action").ToString("open")) switch (Ini.Get(key, "action").ToString("open"))
{ {
case "open": case "open":
action = BlockActionDoor.DoorAction.Open; action = DoorAction.Open;
break; break;
case "close": case "close":
action = BlockActionDoor.DoorAction.Close; action = DoorAction.Close;
break; break;
default: default:
Console.Print($"Invalid door action for '{block.CustomName}'. Defaulting to open."); Console.Print($"Invalid door action for '{block.CustomName}'. Defaulting to open.");
action = BlockActionDoor.DoorAction.Open; action = DoorAction.Open;
break; break;
} }

View File

@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netframework48</TargetFramework>
<RootNamespace>IngameScript</RootNamespace>
<LangVersion>6</LangVersion>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<Configurations>Release;Debug</Configurations>
<Platforms>x64</Platforms>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Mal.Mdk2.PbAnalyzers" Version="2.1.11">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Mal.Mdk2.PbPackager" Version="2.1.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Mal.Mdk2.References" Version="2.2.4" />
</ItemGroup>
<ItemGroup>
<None Remove="Instructions.readme" />
<AdditionalFiles Include="Instructions.readme" />
<AdditionalFiles Include="thumb.png" />
</ItemGroup>
<Import Project="..\Mixins\Console\Console.projitems" Label="shared" />
<Import Project="..\Mixins\ActionGroups\ActionGroups.projitems" Label="shared" />
</Project>

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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<bool> _job = null;
private MyCommandLine _cli = new MyCommandLine();
private List<IMyShipConnector> dockingPorts = new List<IMyShipConnector>();
private List<IMyThrust> thrusters = new List<IMyThrust>();
private List<IMyGasTank> gasTanks = new List<IMyGasTank>();
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<IMyThrust> thrusters = new List<IMyThrust>();
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<IMyGasTank> gasTanks = new List<IMyGasTank>();
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;
}
}
}

BIN
DockingController/thumb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 389 KiB

View File

@ -30,7 +30,7 @@ namespace IngameScript
} }
// Add an action to the sequence called actionName, which will be created if it doesn't already exist. // 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); if (!_actions.ContainsKey(actionName)) _actions[actionName] = new ActionSequence(actionName);
_actions[actionName].Add(step, actionBlock); _actions[actionName].Add(step, actionBlock);

View File

@ -8,9 +8,12 @@
<ItemGroup> <ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)ActionGroup.cs" /> <Compile Include="$(MSBuildThisFileDirectory)ActionGroup.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ActionSequence.cs" /> <Compile Include="$(MSBuildThisFileDirectory)ActionSequence.cs" />
<Compile Include="$(MSBuildThisFileDirectory)BlockActionConnector.cs" />
<Compile Include="$(MSBuildThisFileDirectory)BlockActionDoor.cs" /> <Compile Include="$(MSBuildThisFileDirectory)BlockActionDoor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)BlockActionGasTank.cs" />
<Compile Include="$(MSBuildThisFileDirectory)BlockActionPiston.cs" /> <Compile Include="$(MSBuildThisFileDirectory)BlockActionPiston.cs" />
<Compile Include="$(MSBuildThisFileDirectory)BlockActionRotor.cs" /> <Compile Include="$(MSBuildThisFileDirectory)BlockActionRotor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)IBlockAction.cs" /> <Compile Include="$(MSBuildThisFileDirectory)BlockAction.cs" />
<Compile Include="$(MSBuildThisFileDirectory)BlockActionThruster.cs" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -14,6 +14,6 @@
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<OutputPath>bin\Release\</OutputPath> <OutputPath>bin\Release\</OutputPath>
</PropertyGroup> </PropertyGroup>
<Import Project="Sequencer.projitems" Label="Shared"/> <Import Project="ActionGroups.projitems" Label="Shared"/>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets"/> <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets"/>
</Project> </Project>

View File

@ -14,16 +14,16 @@ namespace IngameScript
public string Name { get; private set; } public string Name { get; private set; }
public bool Running { get; private set; } = false; public bool Running { get; private set; } = false;
private SortedDictionary<int, List<IBlockAction>> _steps = new SortedDictionary<int, List<IBlockAction>>(); private SortedDictionary<int, List<BlockAction>> _steps = new SortedDictionary<int, List<BlockAction>>();
public ActionSequence(string name) public ActionSequence(string name)
{ {
Name = 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<IBlockAction>(); if (!_steps.ContainsKey(step)) _steps[step] = new List<BlockAction>();
_steps[step].Add(action); _steps[step].Add(action);
} }
@ -33,9 +33,9 @@ namespace IngameScript
Running = true; Running = true;
List<IEnumerator<bool>> jobs = new List<IEnumerator<bool>>(); List<IEnumerator<bool>> jobs = new List<IEnumerator<bool>>();
foreach (List<IBlockAction> step in _steps.Values) foreach (List<BlockAction> step in _steps.Values)
{ {
foreach (IBlockAction action in step) foreach (BlockAction action in step)
{ {
jobs.Add(action.Run()); jobs.Add(action.Run());
} }

View File

@ -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<bool> Run()
{
if (Running) yield break;
Running = true;
IEnumerator<bool> childRun = onRun();
while (childRun.MoveNext()) yield return true;
Running = false;
}
protected abstract IEnumerator<bool> onRun();
}
}
}

View File

@ -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<bool> 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;
}
}
}
}
}

View File

@ -4,8 +4,6 @@ using Sandbox.ModAPI.Ingame;
namespace IngameScript namespace IngameScript
{ {
partial class Program partial class Program
{
public class BlockActionDoor : IBlockAction
{ {
public enum DoorAction public enum DoorAction
{ {
@ -13,8 +11,8 @@ namespace IngameScript
Close, Close,
} }
public bool Running { get; private set; } = false; public class BlockActionDoor : BlockAction
{
private IMyDoor _door; private IMyDoor _door;
private DoorAction _action; private DoorAction _action;
private bool _lockDoor; private bool _lockDoor;
@ -30,7 +28,7 @@ namespace IngameScript
_lockDoor = lockDoor; _lockDoor = lockDoor;
} }
public IEnumerator<bool> Run() protected override IEnumerator<bool> onRun()
{ {
switch (_action) switch (_action)
{ {

View File

@ -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<bool> onRun()
{
switch (_action)
{
case GasTankAction.Stockpile:
_gasTank.Stockpile = true;
break;
case GasTankAction.Dispense:
_gasTank.Stockpile = false;
break;
}
yield return true;
}
}
}
}

View File

@ -5,7 +5,7 @@ namespace IngameScript
{ {
partial class Program partial class Program
{ {
public class BlockActionPiston : IBlockAction public class BlockActionPiston : BlockAction
{ {
public bool Running { get; private set; } = false; public bool Running { get; private set; } = false;

View File

@ -5,7 +5,7 @@ namespace IngameScript
{ {
partial class Program partial class Program
{ {
public class BlockActionRotor : IBlockAction public class BlockActionRotor : BlockAction
{ {
public bool Running { get; private set; } = false; public bool Running { get; private set; } = false;

View File

@ -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<bool> onRun()
{
switch (_action)
{
case ThrusterAction.Enable:
_thruster.Enabled = true;
break;
case ThrusterAction.Disable:
_thruster.Enabled = false;
break;
}
yield return true;
}
}
}
}

View File

@ -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<bool> Run();
}
}
}

View File

@ -13,6 +13,8 @@ Project("{8A3CDCC5-4B55-4D87-A415-698A0E1FF06F}") = "ActionGroups", "Mixins\Acti
EndProject EndProject
Project("{8A3CDCC5-4B55-4D87-A415-698A0E1FF06F}") = "Console", "Mixins\Console\Console.shproj", "{323E8400-84C2-46A0-B2E9-FCD3B31681DA}" Project("{8A3CDCC5-4B55-4D87-A415-698A0E1FF06F}") = "Console", "Mixins\Console\Console.shproj", "{323E8400-84C2-46A0-B2E9-FCD3B31681DA}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DockingController", "DockingController\DockingController.csproj", "{FDF834C0-D680-4FFA-8238-FE1FBDCF5B9D}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU 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}.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.ActiveCfg = Release|x64
{40B352CD-100E-4F87-A7A0-FF00F4B8846C}.Release|Any CPU.Build.0 = 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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE