sescripts/PML/Program.cs
Greg Burri 6bd32cf48d New project: PML.
To manage the spaceship "Pifou Missile Launcher".
2025-08-30 23:39:00 +02:00

402 lines
16 KiB
C#

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.ComponentModel;
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 VRage.ObjectBuilders;
using VRageMath;
namespace IngameScript
{
partial class Program : MyGridProgram
{
const int NUMBER_OF_MISSILES = 52; // The quantity of components will be created to build this quantity of missiles.
const int NUMBER_OF_CANNON_SHELL = 160;
const int NUMBER_OF_ARTILLERY_SHELL = 40;
const int CONSOLE_NB_LINES = 14;
const string GRID_PREFIX = "[PML]";
const float EPSILON = 0.05f;
readonly IMyCubeGrid grid;
readonly Output output;
readonly Output topPanel;
readonly Output bottomPanel;
readonly IMyAssembler assembler;
readonly List<ComponentQuantity> missileComponents = new List<ComponentQuantity>{
new ComponentQuantity(MyItemType.MakeComponent("SteelPlate"), MyDefinitionId.Parse("MyObjectBuilder_BlueprintDefinition/SteelPlate"), 256),
new ComponentQuantity(MyItemType.MakeComponent("Construction"), MyDefinitionId.Parse("MyObjectBuilder_BlueprintDefinition/ConstructionComponent"), 166),
new ComponentQuantity(MyItemType.MakeComponent("Motor"), MyDefinitionId.Parse("MyObjectBuilder_BlueprintDefinition/MotorComponent"), 18),
new ComponentQuantity(MyItemType.MakeComponent("InteriorPlate"), MyDefinitionId.Parse("MyObjectBuilder_BlueprintDefinition/InteriorPlate"), 40),
new ComponentQuantity(MyItemType.MakeComponent("Computer"), MyDefinitionId.Parse("MyObjectBuilder_BlueprintDefinition/ComputerComponent"), 48),
new ComponentQuantity(MyItemType.MakeComponent("PowerCell"), MyDefinitionId.Parse("MyObjectBuilder_BlueprintDefinition/PowerCell"), 2),
new ComponentQuantity(MyItemType.MakeComponent("Display"), MyDefinitionId.Parse("MyObjectBuilder_BlueprintDefinition/Display"), 1),
new ComponentQuantity(MyItemType.MakeComponent("SmallTube"), MyDefinitionId.Parse("MyObjectBuilder_BlueprintDefinition/SmallTube"), 29),
new ComponentQuantity(MyItemType.MakeComponent("MetalGrid"), MyDefinitionId.Parse("MyObjectBuilder_BlueprintDefinition/MetalGrid"), 48),
new ComponentQuantity(MyItemType.MakeComponent("LargeTube"), MyDefinitionId.Parse("MyObjectBuilder_BlueprintDefinition/LargeTube"), 16),
new ComponentQuantity(MyItemType.MakeComponent("Detector"), MyDefinitionId.Parse("MyObjectBuilder_BlueprintDefinition/DetectorComponent"), 8),
new ComponentQuantity(MyItemType.MakeComponent("Girder"), MyDefinitionId.Parse("MyObjectBuilder_BlueprintDefinition/GirderComponent"), 12),
new ComponentQuantity(MyItemType.MakeComponent("Explosives"), MyDefinitionId.Parse("MyObjectBuilder_BlueprintDefinition/ExplosivesComponent"), 24),
};
public Program()
{
this.grid = this.Me.CubeGrid;
var output = this.Me.GetSurface(0);
this.output = new Output(output, CONSOLE_NB_LINES);
this.output.Print("PML system starting...");
this.topPanel = new Output(this.GridTerminalSystem.GetBlock<IMyTextPanel>("LCD Panel - Main 02", this.grid));
this.assembler = this.GridTerminalSystem.GetBlock<IMyAssembler>("Assembler Main", this.grid);
Runtime.UpdateFrequency = UpdateFrequency.Update100;
}
public void Save()
{
}
public void Main(string argument, UpdateType updateSource)
{
if ((updateSource & UpdateType.Update100) != 0)
{
this.UpdateState();
}
else if ((updateSource & (UpdateType.Terminal | UpdateType.Trigger)) != 0)
{
switch (argument)
{
case "COMMAND":
this.output.Print("BLA...");
break;
case "START_MINING":
default:
this.output.Print($"Uknown command: {argument}");
break;
}
}
}
void UpdateState()
{
this.BuildComponentForMissiles();
this.BuildAmmo();
this.DisplayStatus();
}
void BuildComponentForMissiles()
{
var existingAmounts = this.GetCurrentItemQuantity(missileComponents.Select(quantity => quantity.ItemType));
int i = 0;
foreach (var missileComponent in this.missileComponents)
{
var existing = existingAmounts[i];
var queue = new List<MyProductionItem>();
this.assembler.GetQueue(queue);
foreach (var item in queue)
{
if (item.BlueprintId == missileComponent.blueprintId)
existing += item.Amount;
}
var desired = missileComponent.Quantity * NUMBER_OF_MISSILES;
if (existing < desired)
{
var toBuild = desired - existing;
this.output.Print($"Requesting {toBuild} of {missileComponent.blueprintId.SubtypeName}");
this.assembler.AddQueueItem(missileComponent.blueprintId, toBuild);
}
i += 1;
}
}
void BuildAmmo()
{
//var ammoDefinitionIds = new List<MyDefinitionId>
//{
// MyDefinitionId.Parse("MyObjectBuilder_AmmoMagazine/Missile200mm"),
// MyDefinitionId.Parse("MyObjectBuilder_AmmoMagazine/Missile400mm"),
// MyDefinitionId.Parse("MyObjectBuilder_AmmoMagazine/Missile800mm"),
// MyDefinitionId.Parse("MyObjectBuilder_AmmoMagazine/Missile1200mm"),
// MyDefinitionId.Parse("MyObjectBuilder_AmmoMagazine/Projectile200mm"),
// MyDefinitionId.Parse("MyObjectBuilder_AmmoMagazine/Projectile400mm"),
// MyDefinitionId.Parse("MyObjectBuilder_AmmoMagazine/Projectile800mm"),
// MyDefinitionId.Parse("MyObjectBuilder_AmmoMagazine/Projectile1200mm"),
// MyDefinitionId.Parse("MyObjectBuilder_AmmoMagazine/ArtilleryShell"),
//};
//var existingAmounts = this.GetCurrentItemQuantity(ammoDefinitionIds);
//var desiredAmounts = new List<MyFixedPoint>
//{
// (MyFixedPoint)(NUMBER_OF_MISSILES * 4), // Missile200mm
// (MyFixedPoint)(NUMBER_OF_MISSILES * 4), // Missile400mm
// (MyFixedPoint)(NUMBER_OF_MISSILES * 2), // Missile800mm
// (MyFixedPoint)(NUMBER_OF_MISSILES * 2), // Missile1200mm
// (MyFixedPoint)(NUMBER_OF_CANNON_SHELL / 4), // Projectile200mm
// (MyFixedPoint)(NUMBER_OF_CANNON_SHELL / 4), // Projectile400mm
// (MyFixedPoint)(NUMBER_OF_CANNON_SHELL / 4), // Projectile800mm
// (MyFixedPoint)(NUMBER_OF_CANNON_SHELL / 4), // Projectile1200mm
// (MyFixedPoint)(NUMBER_OF_ARTILLERY_SHELL), // ArtilleryShell
//};
//foreach (var tuple in ammoDefinitionIds.Zip(existingAmounts, desiredAmounts, (id, existing, desired) => (id, existing, desired)))
//{
// if (tuple.existing < tuple.desired - EPSILON)
// {
// var toBuild = tuple.desired - tuple.existing;
// this.assembler.AddQueueItem(tuple.id, toBuild);
// this.output.Print($"Requesting {toBuild} of {tuple.id.SubtypeName}");
// }
//}
}
void DisplayStatus()
{
var cargoSpace = this.GetCargoSpace();
var energyState = this.GetEnergyState();
var hydrogenVolume = this.GetHydrogenVolume();
var oxygenVolume = this.GetOxygenVolume();
this.topPanel.Display(
$@"
{cargoSpace.ToString("Cargo volume", "kL")}
{energyState.ToString("Energy", "MWh")}
{hydrogenVolume.ToString("Hydrogen", "L")}
{oxygenVolume.ToString("Oxygen", "L")}"
);
}
List<MyFixedPoint> GetCurrentItemQuantity(IEnumerable<MyItemType> itemTypes)
{
var total = new List<MyFixedPoint>(new MyFixedPoint[itemTypes.Count()]);
foreach (var container in this.GridTerminalSystem.GetBlocks<IMyCargoContainer>(null, this.grid))
{
//this.output.Print($"Container: {container.CustomName}");
int i = 0;
foreach (var itemType in itemTypes)
{
var items = container.GetInventory().FindItem(itemType);
//this.output.Print($"{itemType}: {items}");
if (items.HasValue)
total[i] += items.Value.Amount;
i += 1;
}
}
foreach (var assembler in this.GridTerminalSystem.GetBlocks<IMyAssembler>(null, this.grid))
{
int i = 0;
foreach (var itemType in itemTypes)
{
var items = assembler.OutputInventory.FindItem(itemType);
if (items.HasValue)
total[i] += items.Value.Amount;
i += 1;
}
}
foreach (var sorter in this.GridTerminalSystem.GetBlocks<IMyConveyorSorter>(null, this.grid))
{
int i = 0;
foreach (var itemType in itemTypes)
{
var items = sorter.GetInventory().FindItem(itemType);
if (items.HasValue)
total[i] += items.Value.Amount;
i += 1;
}
}
foreach (var welder in this.GridTerminalSystem.GetBlocks<IMyShipWelder>(null, this.grid))
{
int i = 0;
foreach (var itemType in itemTypes)
{
var items = welder.GetInventory().FindItem(itemType);
if (items.HasValue)
total[i] += items.Value.Amount;
i += 1;
}
}
foreach (var turret in this.GridTerminalSystem.GetBlocks<IMyLargeTurretBase>(null, this.grid))
{
int i = 0;
foreach (var itemType in itemTypes)
{
var items = turret.GetInventory().FindItem(itemType);
if (items.HasValue)
total[i] += items.Value.Amount;
i += 1;
}
}
return total;
}
class ComponentQuantity
{
public ComponentQuantity(MyItemType itemType, MyDefinitionId blueprintId, MyFixedPoint quantity)
{
this.ItemType = itemType;
this.blueprintId = blueprintId;
//if (!MyDefinitionId.TryParse("MyObjectBuilder_BlueprintDefinition", this.ItemType.SubtypeId, out this.Id))
// throw new ArgumentException($"Cannot parse {this.ItemType} into a MyDefinitionId");
this.Quantity = quantity;
}
public readonly MyItemType ItemType;
public readonly MyDefinitionId blueprintId;
public readonly MyFixedPoint Quantity;
}
struct Quantity
{
public Quantity(double current, double total)
{
this.Current = current;
this.Total = total;
}
public readonly double Current;
public readonly double Total;
public string ToString(string name, string unit)
{
var firstLineLength = 50;
var secondLineLength = 50;
var firstLine = new StringBuilder();
firstLine.Append(name).Append(": ");
var values = $"{this.Current:N1} {unit} / {this.Total:N1} {unit}";
firstLine.Append(values.PadLeft(firstLineLength - firstLine.Length));
var secondLine = new StringBuilder();
secondLine.Append("[");
var ratio = this.Current / this.Total;
var percentStr = $"{ratio * 100.0,8:N1}%";
// "-2" because of the starting and ending characters: '[', ']'.
var gaugeSize = secondLineLength - percentStr.Length - 2;
var n = (int)((double)gaugeSize * ratio);
secondLine.Append(new string('|', n));
secondLine.Append(new string(' ', gaugeSize - n)).Append("]");
secondLine.Append(percentStr);
return $"{firstLine}\n{secondLine}";
}
}
Quantity GetCargoSpace()
{
var containers = this.GridTerminalSystem.GetBlocks<IMyCargoContainer>(null, this.grid);
double currentVolume = 0;
double totalVolume = 0;
foreach (var container in containers)
{
var inventory = container.GetInventory();
currentVolume += (double)inventory.CurrentVolume;
totalVolume += (double)inventory.MaxVolume;
}
return new Quantity(currentVolume, totalVolume);
}
Quantity GetEnergyState()
{
double currentkWh = 0;
double maxkWh = 0;
var batteries = this.GridTerminalSystem.GetBlocks<IMyBatteryBlock>(null, this.grid);
foreach (var battery in batteries)
{
currentkWh += (double)battery.CurrentStoredPower;
maxkWh += (double)battery.MaxStoredPower;
}
return new Quantity(currentkWh, maxkWh);
}
Quantity GetHydrogenVolume()
{
double currentVolume = 0;
double totalVolume = 0;
var tanks = this.GridTerminalSystem.GetBlocks<IMyGasTank>(null, this.grid, tank => tank.CustomName.Contains("Hydrogen"));
//var tanks = new List<IMyGasTank>();
//GridTerminalSystem.GetBlocksOfType<IMyGasTank>(tanks,
// (IMyGasTank tank) =>
// {
// return tank.CustomName.Contains("Mammouth") && tank.CustomName.Contains("hydro");
// }
//);
foreach (var tank in tanks)
{
currentVolume += (double)tank.Capacity * (double)tank.FilledRatio;
totalVolume += (double)tank.Capacity;
}
return new Quantity(currentVolume, totalVolume);
}
Quantity GetOxygenVolume()
{
double currentVolume = 0;
double totalVolume = 0;
var tanks = this.GridTerminalSystem.GetBlocks<IMyGasTank>(null, this.grid, tank => tank.CustomName.Contains("Oxygen"));
//var tanks = new List<IMyGasTank>();
//GridTerminalSystem.GetBlocksOfType<IMyGasTank>(tanks,
// (IMyGasTank tank) =>
// {
// return tank.CustomName.Contains("Mammouth") && tank.CustomName.Contains("oxygène");
// }
//);
foreach (var tank in tanks)
{
currentVolume += (double)tank.Capacity * (double)tank.FilledRatio;
totalVolume += (double)tank.Capacity;
}
return new Quantity(currentVolume, totalVolume);
}
}
}