Add an air monitor script and necessary additions to the Sequencer.

This commit is contained in:
Anna Rose 2025-02-11 00:20:39 -05:00
parent 85ce54ad1d
commit 1f33b7fbb4
10 changed files with 323 additions and 0 deletions

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\Sequencer\Sequencer.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

22
AirMonitor/AirMonitor.sln Normal file
View File

@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AirMonitor", "AirMonitor.csproj", "{DAD911E6-670F-4AA0-8F00-5D239BC5F732}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{DAD911E6-670F-4AA0-8F00-5D239BC5F732}.Debug|Any CPU.ActiveCfg = Debug|x64
{DAD911E6-670F-4AA0-8F00-5D239BC5F732}.Debug|Any CPU.Build.0 = Debug|x64
{DAD911E6-670F-4AA0-8F00-5D239BC5F732}.Release|Any CPU.ActiveCfg = Release|x64
{DAD911E6-670F-4AA0-8F00-5D239BC5F732}.Release|Any CPU.Build.0 = Release|x64
EndGlobalSection
EndGlobal

73
AirMonitor/AirZone.cs Normal file
View File

@ -0,0 +1,73 @@
using Sandbox.ModAPI.Ingame;
using SpaceEngineers.Game.ModAPI.Ingame;
using System.Collections.Generic;
using VRage.Game.ModAPI.Ingame.Utilities;
namespace IngameScript {
partial class Program {
public class AirZone
{
public bool Triggered = false;
private MyIni _ini;
private List<IMyAirVent> _vents;
private PrefixedConsole _console;
private Sequencer _sequencer;
private const float TriggerLevel = 0.75F;
public AirZone(string zoneName, MyIni ini, IConsole console)
{
_ini = ini;
_console = new PrefixedConsole(console, zoneName);
_sequencer = new Sequencer(zoneName, _console);
_vents = new List<IMyAirVent>();
}
public void AddBlock(IMyTerminalBlock block)
{
if (block is IMyAirVent)
{
_vents.Add(block as IMyAirVent);
} else if (block is IMyDoor) {
SequenceableDoor wrapped = SequenceableFactory.MakeSequenceable(block as IMyDoor, _ini, "") as SequenceableDoor;
wrapped.Step = 0;
wrapped.DeployOpen = false;
wrapped.LockOpen = false;
wrapped.LockClosed = true;
_sequencer.AddBlock(wrapped);
} else {
_console.Print("Tried to add incompatible block '{block.CustomName}'");
}
// TODO: support for arbitrary (sub-)sequences here could be powerful
}
// This enumerator should run forever.
public IEnumerator<bool> Monitor()
{
while (true)
{
foreach (IMyAirVent vent in _vents)
{
if (vent.GetOxygenLevel() < TriggerLevel) Triggered = true;
}
if (Triggered == true)
{
// close the doors
IEnumerator<bool> job = _sequencer.RunSequence(true);
while (job.MoveNext()) yield return true;
// noop until manually reset
while (Triggered) yield return true;
// open the doors
job = _sequencer.RunSequence(false);
while (job.MoveNext()) yield return true;
}
yield return true;
}
}
}
}
}

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.

96
AirMonitor/Program.cs Normal file
View File

@ -0,0 +1,96 @@
using Sandbox.Game.EntityComponents;
using Sandbox.ModAPI.Ingame;
using Sandbox.ModAPI.Interfaces;
using SpaceEngineers.Game.ModAPI.Ingame;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Text;
using VRage;
using VRage.Collections;
using VRage.Game;
using VRage.Game.Components;
using VRage.Game.GUI.TextPanel;
using VRage.Game.ModAPI.Ingame;
using VRage.Game.ModAPI.Ingame.Utilities;
using VRage.Game.ObjectBuilders.Definitions;
using VRageMath;
namespace IngameScript
{
public partial class Program : MyGridProgram
{
private MyIni _ini;
private Console _console;
private MyCommandLine _cli;
private Dictionary<string, AirZone> _zones;
private List<IEnumerator<bool>> _jobs;
public Program()
{
_cli = new MyCommandLine();
_ini = new MyIni();
_console = new Console(this, _ini);
_zones = new Dictionary<string, AirZone>();
_jobs = new List<IEnumerator<bool>>();
// Find all tagged objects and build out zones
List<IMyTerminalBlock> blocks = new List<IMyTerminalBlock>();
GridTerminalSystem.GetBlocksOfType(blocks, block => MyIni.HasSection(block.CustomData, "airMonitor"));
foreach (IMyTerminalBlock block in blocks)
{
_ini.TryParse(block.CustomData);
string[] zones = new string[] { };
if (_ini.Get("airMonitor", "zones").ToString() != "")
{
zones = _ini.Get("airMonitor", "zones").ToString().Split(',');
}
else if (_ini.Get("airMonitor", "zone").ToString() != "")
{
zones = new string[] { _ini.Get("airMonitor", "zone").ToString() };
}
foreach (string zone in zones)
{
if (!_zones.ContainsKey(zone))
{
_zones[zone] = new AirZone(zone, _ini, _console);
}
_zones[zone].AddBlock(block);
}
}
foreach (AirZone zone in _zones.Values)
{
_jobs.Add(zone.Monitor());
}
Runtime.UpdateFrequency |= UpdateFrequency.Update100;
}
public void Main(string argument, UpdateType updateSource)
{
if (argument != "")
{
_cli.TryParse(argument);
if (_cli.Switch("reset"))
{
for (int i = 0; i < _cli.ArgumentCount; i++)
{
if (_zones.ContainsKey(_cli.Argument(i)))
{
_zones[_cli.Argument(i)].Triggered = false;
}
}
}
}
foreach (IEnumerator job in _jobs)
{
if (job.MoveNext()) continue;
_console.Print("WARNING: Monitoring job exited. Zone no longer being monitored.");
}
}
}
}

BIN
AirMonitor/thumb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 389 KiB

View File

@ -0,0 +1,66 @@
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; }
public int Step { get; set; }
private IMyDoor _door;
public bool DeployOpen { get; set; }
public bool LockOpen { get; set; }
public bool LockClosed { get; set; }
public SequenceableDoor(
IMyDoor door,
MyIni ini,
string sectionName)
{
_door = door;
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 (deploy && DeployOpen || !deploy && !DeployOpen)
{
foreach (bool tick in _openDoor()) yield return true;
}
else
{
foreach (bool tick in _closeDoor()) yield return true;
}
}
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;
}
}
}
}
}

View File

@ -27,6 +27,10 @@ namespace IngameScript
{
// return new SequenceableMergeBlock(block as IMyShipMergeBlock, step);
}
if (block is IMyDoor)
{
return new SequenceableDoor(block as IMyDoor, ini, sectionName);
}
return null;
}
}