diff --git a/InfoDisplays/InfoDisplays.csproj b/InfoDisplays/InfoDisplays.csproj
new file mode 100644
index 0000000..7705310
--- /dev/null
+++ b/InfoDisplays/InfoDisplays.csproj
@@ -0,0 +1,27 @@
+
+
+ netframework48
+ IngameScript
+ 6
+ false
+ Release;Debug
+ x64
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/InfoDisplays/InfoDisplays.mdk.ini b/InfoDisplays/InfoDisplays.mdk.ini
new file mode 100644
index 0000000..5add8f4
--- /dev/null
+++ b/InfoDisplays/InfoDisplays.mdk.ini
@@ -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
diff --git a/InfoDisplays/InfoDisplays.mdk.local.ini b/InfoDisplays/InfoDisplays.mdk.local.ini
new file mode 100644
index 0000000..4b66820
--- /dev/null
+++ b/InfoDisplays/InfoDisplays.mdk.local.ini
@@ -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
\ No newline at end of file
diff --git a/InfoDisplays/Instructions.readme b/InfoDisplays/Instructions.readme
new file mode 100644
index 0000000..ed30ab7
--- /dev/null
+++ b/InfoDisplays/Instructions.readme
@@ -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.
diff --git a/InfoDisplays/OreReport.cs b/InfoDisplays/OreReport.cs
new file mode 100644
index 0000000..32644a1
--- /dev/null
+++ b/InfoDisplays/OreReport.cs
@@ -0,0 +1,113 @@
+// Keeps track of all construction materials (ingots) on the grid
+// TODO: also track unprocessed stuff?
+using System.Collections.Generic;
+using System.Text;
+using Sandbox.ModAPI.Ingame;
+using VRage;
+using VRage.Game.GUI.TextPanel;
+using VRage.Game.ModAPI.Ingame;
+
+namespace IngameScript
+{
+ partial class Program
+ {
+ // TODO: factor out the display code once it is more complex
+ public class OreReport
+ {
+ private Program _program;
+ private IConsole _console;
+ private IMyTextSurface _display;
+ private StringBuilder _builder = new StringBuilder();
+ private List _inventories = new List();
+
+ private Dictionary _ingotTypes = new Dictionary
+ {
+ ["Iron"] = MyItemType.MakeIngot("Ingot_Iron"),
+ ["Silicon"] = MyItemType.MakeIngot("Silicon"),
+ ["Nickel"] = MyItemType.MakeIngot("Nickel"),
+ ["Cobalt"] = MyItemType.MakeIngot("Cobalt"),
+ ["Gold"] = MyItemType.MakeIngot("Gold"),
+ ["Silver"] = MyItemType.MakeIngot("Silver"),
+ ["Platinum"] = MyItemType.MakeIngot("Platinum"),
+ ["Magnesium"] = MyItemType.MakeIngot("Magnesium"),
+ ["Uranium"] = MyItemType.MakeIngot("Uranium"),
+ ["Gravel"] = MyItemType.MakeIngot("Gravel"),
+ };
+ private Dictionary _supply = new Dictionary();
+
+ public OreReport(IMyTextSurface display, Program program)
+ {
+ _program = program;
+ _display = display;
+ _console = new PrefixedConsole(_program.Console, "OreReport");
+
+ // Configure display
+ _display.ContentType = ContentType.TEXT_AND_IMAGE;
+ _display.WriteText("Initializing...");
+
+ // initialize the supply map
+ // initializeIngotTypes();
+ foreach (string key in _ingotTypes.Keys)
+ {
+ _supply[key] = 0f;
+ }
+
+ // find all the inventories
+ List invBlocks = new List();
+ program.GridTerminalSystem.GetBlocksOfType(invBlocks, blockFilter);
+ foreach (IMyTerminalBlock block in invBlocks)
+ {
+ IMyInventory inv = block.GetInventory();
+ _inventories.Add(inv);
+ }
+
+ _console.Print($"Scanning {_inventories.Count} inventories.");
+ }
+
+ public void Update()
+ {
+ foreach (string key in _ingotTypes.Keys)
+ {
+ _supply[key] = 0f;
+ }
+ foreach (IMyInventory inv in _inventories)
+ {
+ foreach (KeyValuePair kvp in _ingotTypes)
+ {
+ _supply[kvp.Key] += (float)inv.GetItemAmount(kvp.Value);
+ }
+ }
+ }
+
+ // TODO: just text for now; turn this into a nice graphical display eventually
+ public void Draw()
+ {
+ _builder.Clear();
+ _builder.AppendLine("INGOT REPORT");
+ _builder.AppendLine();
+ foreach (string key in _supply.Keys)
+ {
+ _builder.Append(key);
+ _builder.Append(" ");
+ _builder.Append(_supply[key].ToString());
+ _builder.AppendLine();
+ }
+ _display.WriteText(_builder.ToString());
+ }
+
+ // private void initializeIngotTypes()
+ // {
+ // string[] types = { "Iron", "Silicon", "Nickel", "Cobalt", "Gold", "Silver", "Platinum", "Magnesium", "Uranium", "Gravel" };
+ // foreach (string type in types)
+ // {
+ // _ingotTypes[type] = new MyItemType("Ingot", type);
+ // }
+ // }
+
+ private bool blockFilter(IMyTerminalBlock block)
+ {
+ return block.IsSameConstructAs(_program.Me) && block.InventoryCount > 0;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/InfoDisplays/Program.cs b/InfoDisplays/Program.cs
new file mode 100644
index 0000000..d463ffc
--- /dev/null
+++ b/InfoDisplays/Program.cs
@@ -0,0 +1,83 @@
+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; private set; }
+
+ private OreReport _oreReport = null;
+
+ public Program()
+ {
+ Ini = new MyIni();
+ Console = new MainConsole(this, "Info Displays");
+
+ // find displays that are configured to show info, create the necessary objects.
+ // TODO: currently we only support one display per report, and we just use the first one
+ List displays = new List();
+ GridTerminalSystem.GetBlocksOfType(displays, blockFilter);
+ foreach (IMyTerminalBlock display in displays)
+ {
+ Ini.TryParse(display.CustomData);
+ List keys = new List();
+ Ini.GetKeys("infoDisplay", keys);
+ foreach (MyIniKey key in keys)
+ {
+ switch (key.Name)
+ {
+ case "ingotReport":
+ if (_oreReport != null) break;
+ int index = Ini.Get(key).ToInt32();
+ // extract text surface
+ if (display is IMyTextSurface)
+ {
+ _oreReport = new OreReport(display as IMyTextSurface, this);
+ Console.Print($"Showing Ore Report on '{display.CustomName}'");
+ }
+ else if (display is IMyTextSurfaceProvider)
+ {
+ _oreReport = new OreReport(((IMyTextSurfaceProvider)display).GetSurface(index), this);
+ Console.Print($"Showing Ore Report on '{display.CustomName}'");
+ }
+ else
+ {
+ Console.Print("Tried to configure object without display surface.");
+ }
+ break;
+ default:
+ Console.Print($"Display type '{key.Name}' not defined.");
+ break;
+ }
+ }
+ }
+
+ Console.UpdateTickCount();
+ if (_oreReport == null)
+ {
+ Console.Print("No configured displays found. Shutting down.");
+ return;
+ }
+ Runtime.UpdateFrequency = UpdateFrequency.Update100;
+ }
+
+ public void Main(string argument, UpdateType updateSource)
+ {
+ Console.UpdateTickCount();
+
+ if (_oreReport != null)
+ {
+ _oreReport.Update();
+ _oreReport.Draw();
+ }
+ }
+
+ private bool blockFilter(IMyTerminalBlock block)
+ {
+ return block.IsSameConstructAs(this.Me) && MyIni.HasSection(block.CustomData, "infoDisplay");
+ }
+ }
+}
diff --git a/InfoDisplays/thumb.png b/InfoDisplays/thumb.png
new file mode 100644
index 0000000..a8dc2ef
Binary files /dev/null and b/InfoDisplays/thumb.png differ
diff --git a/SpaceEngineers.sln b/SpaceEngineers.sln
index 700cf5e..e1bfe91 100644
--- a/SpaceEngineers.sln
+++ b/SpaceEngineers.sln
@@ -15,6 +15,8 @@ Project("{8A3CDCC5-4B55-4D87-A415-698A0E1FF06F}") = "Console", "Mixins\Console\C
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DockingController", "DockingController\DockingController.csproj", "{FDF834C0-D680-4FFA-8238-FE1FBDCF5B9D}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InfoDisplays", "InfoDisplays\InfoDisplays.csproj", "{4C7C8B10-1E43-453E-A9DA-A3626FE85ACC}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -37,6 +39,10 @@ Global
{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
+ {4C7C8B10-1E43-453E-A9DA-A3626FE85ACC}.Debug|Any CPU.ActiveCfg = Debug|x64
+ {4C7C8B10-1E43-453E-A9DA-A3626FE85ACC}.Debug|Any CPU.Build.0 = Debug|x64
+ {4C7C8B10-1E43-453E-A9DA-A3626FE85ACC}.Release|Any CPU.ActiveCfg = Release|x64
+ {4C7C8B10-1E43-453E-A9DA-A3626FE85ACC}.Release|Any CPU.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE