Inventory Display and Management 3.33/5 (3)

posted in: Scripts | 2

This script is an evolution of my previous scripts. It requires a little setup to work, but is completely worth the work. EDIT: Fixed a small bug where it would only auto-produce components when there was at least one of the specific component already in stock.

The first thing it does is display a consolidated list of your component inventory on an LCD Panel. The second thing it does is maintain a certain level of stock for each component that you specify in the script. Example: if you always want to have 50,000 Steel Plates, it will automatically produce Steel Plates, whenever your inventory falls below that threshold.

The only drawback is that, since we currently cannot control the assembler queue via programmable block, we have to have a dedicated Assembler for each of the components that we want to control the inventory.

So… Setup…

1. Create an LCD Panel to show the inventory, name it whatever you want, but change the constant on the first line of the script to match.

2. Change the constant on the second line of the script to match the name that you use for your component storage. You might need to use the Component Sorting script to have all your components in similarly named containers.

3. Lines 10-27 of the script specify your inventory thresholds. Adjust according to your preferences.

4. Create an Assembler for each component you want to maintain inventory. Name them using the sames names used in lines 10-27 of the script, with the suffix “Assembler”. i.e. “Computer Assembler”, “Bulletproof Glass Assembler”, etc.

5. Turn all of the component specific assemblers off in the terminal

6. Set all of the component specific assemblers to repeat, and queue up one of the specific item in the assembler.

7. Set a timer to run this script every few seconds (I suggest 1 to 5 seconds).

The actual amount that the script will produce will be “close” to your threshold, but never below. This is due to the face that it works by turning the specific assemblers on and off, based on whether you need more of a specific component or not. If your script is running every 5 seconds, it might have already produced enough to meet your quota, before the timer runs the script again to turn off the assembler.

const string PANEL_NAME = "Comp Panel";  
const string CONTAINER_NAME = "Components"; 
const int PANEL_LINES = 22; 
int lineOffset = 0;
Dictionary<String,float> minimums = new Dictionary<String, float>();

void Main() 
{ 
    InitDebug();

    if (minimums.Count == 0) {
        minimums.Add("Bulletproof Glass", 100000);
        minimums.Add("Computer", 30000);
        minimums.Add("Construction Component", 360000);
        minimums.Add("Detector Component", 1000);
        minimums.Add("Display", 30000);
        minimums.Add("Girder", 6000);
        minimums.Add("GravGen Component", 1000);
        minimums.Add("Interior Plate", 1500000); 
        minimums.Add("Large Steel Tube", 180000);
        minimums.Add("Metal Grid", 300000);
        minimums.Add("Motor", 50000);
        minimums.Add("Radio Component", 1000);
        minimums.Add("Reactor Component", 8000);
        minimums.Add("Small Steel Tube", 300000);
        minimums.Add("Steel Plate", 3000000);
        minimums.Add("Thruster Component", 10000);
        minimums.Add("Solar Cell", 1000);
        minimums.Add("Power Cell", 1000);
    }
    List<IMyTerminalBlock> work = new List<IMyTerminalBlock>(); 
    Dictionary<String,float> consolidated = new Dictionary<String,float>();
    GridTerminalSystem.SearchBlocksOfName(PANEL_NAME, work);      
    IMyTextPanel panel = null;
    for (int i = 0; i < work.Count; i++)   
    {   
        if (work[i] is IMyTextPanel) {
           panel = (IMyTextPanel)work[i];  
           break;
        }
    }
    List<IMyTerminalBlock> containerList = new List<IMyTerminalBlock>(); 
    GridTerminalSystem.SearchBlocksOfName(CONTAINER_NAME, containerList);      

    float maxVolume = 0.0f;
    float currentVolume = 0.0f;
    for (int i = 0; i < containerList.Count; i++)   
    {   
        if (containerList[i] is IMyCargoContainer) {
            var containerInvOwner = containerList[i] as VRage.ModAPI.Ingame.IMyInventoryOwner;
            var containerInventory = containerInvOwner.GetInventory(0);
            maxVolume += (float)containerInventory.MaxVolume;
            currentVolume += (float)containerInventory.CurrentVolume;
            var containerItems = containerInventory.GetItems();   
            for(int j = containerItems.Count - 1; j >= 0; j--)    
            {    
                String itemName = decodeItemName(containerItems[j].Content.SubtypeName, 
                                  containerItems[j].Content.TypeId.ToString()) + "|" + 
                                  containerItems[j].Content.TypeId.ToString();
                float amount = (float)containerItems[j].Amount;
                if (!consolidated.ContainsKey(itemName)) {
                   consolidated.Add(itemName, amount);
                } else {
                   consolidated[itemName] += amount;
                }
            }  
        }
    }

    Dictionary<String,float> working = new Dictionary<String,float>();
    working.Clear();
    var enumerator3 = minimums.GetEnumerator();
    while (enumerator3.MoveNext())
    {      
        var pair = enumerator3.Current;
        String itemKey = pair.Key;
        working.Add(itemKey,0);
    }     

    List<String> list = new List<String>();
    var enumerator = consolidated.GetEnumerator();
    while (enumerator.MoveNext())
    {      
        var pair = enumerator.Current;
        String itemKey = pair.Key;
        float itemValue = pair.Value;
        checkStock(itemKey.Split('|')[0], itemValue);
        String txt = itemKey.Split('|')[0] + "  -  "; 
        String amt = amountFormatter(itemValue,itemKey.Split('|')[1]); 
        working[txt] += itemValue;
        txt += amt; 
        list.Add(txt);
    }     
    var enumerator2 = minimums.GetEnumerator();
    while (enumerator2.MoveNext())
    {      
        var pair = enumerator2.Current;
        String itemKey = pair.Key;
        float itemValue = pair.Value;
        checkStock(itemKey, working[itemKey]);
    }     
    list.Sort();
    list.Insert(0,"------------------------------------------------------");
    float percentageFull = (float)Math.Round(currentVolume / maxVolume * 100,2);
    list.Insert(0,CONTAINER_NAME + " Inventory       " + percentageFull.ToString("##0.00") + "%k full");
    for (int o=0; o < lineOffset; o++) {
        String shiftedItem = list[0];
        list.RemoveAt(0);
        list.Add(shiftedItem);
    }
    panel.WritePublicText(String.Join("\n",list.ToArray()), false);
 
    panel.ShowTextureOnScreen();  
    panel.ShowPublicTextOnScreen(); 
    if (list.Count > PANEL_LINES) {
        lineOffset++;
        if (list.Count - lineOffset < PANEL_LINES) {
           lineOffset = 0;
        }
    }
} 

private IMyTextPanel debugScreen;
public void InitDebug()
{
    debugScreen = (IMyTextPanel)GridTerminalSystem.GetBlockWithName("Debug");
    if (debugScreen == null) return;
    debugScreen.WritePublicText(String.Format("{0:dd MMM HH:mm}\n", DateTime.Now));
}

public void WriteDebug(string message, params object[] args)
{
    if (debugScreen == null) return;
    debugScreen.WritePublicText(String.Format(message, args), true);
    debugScreen.WritePublicText("\n", true);
}



 
void checkStock(String item, float qty) {
     if (minimums.ContainsKey(item)) {
        List<IMyTerminalBlock> assemblerList = new List<IMyTerminalBlock>(); 
        GridTerminalSystem.SearchBlocksOfName(item + " Assembler", assemblerList);      
        if (minimums[item] > qty) {
            WriteDebug("{0}: {1} > {2}", item, minimums[item], qty);
            for (int i = 0; i < assemblerList.Count; i++)   
            {   
                if (assemblerList[i] is IMyAssembler) {
                    ((IMyAssembler)assemblerList[i]).GetActionWithName("OnOff_On").Apply(((IMyAssembler)assemblerList[i])); 
                }
            }             
        } else {
            WriteDebug("{0}: {1} <= {2}", item, minimums[item], qty);
            for (int i = 0; i < assemblerList.Count; i++)   
            {   
                if (assemblerList[i] is IMyAssembler) {
                    ((IMyAssembler)assemblerList[i]).GetActionWithName("OnOff_Off").Apply(((IMyAssembler)assemblerList[i])); 
                }
            }             
        }
     }
}

String amountFormatter(float amt, String typeId) { 
    if (typeId.EndsWith("_Ore") || typeId.EndsWith("_Ingot")) {
        if (amt > 1000.0f) {
          return "" + Math.Round((float)amt/1000,2).ToString("###,###,##0.00") + "K"; 
        } else {
          return "" + Math.Round((float)amt,2).ToString("###,###,##0.00"); 
        }
    }
    return "" + Math.Round((float)amt,0).ToString("###,###,##0"); 
} 
 
String decodeItemName(String name, String typeId)  
{ 
    if (name.Equals("Construction")) { return "Construction Component"; } 
    if (name.Equals("MetalGrid")) { return "Metal Grid"; } 
    if (name.Equals("InteriorPlate")) { return "Interior Plate"; } 
    if (name.Equals("SteelPlate")) { return "Steel Plate"; } 
    if (name.Equals("SmallTube")) { return "Small Steel Tube"; } 
    if (name.Equals("LargeTube")) { return "Large Steel Tube"; } 
    if (name.Equals("BulletproofGlass")) { return "Bulletproof Glass"; } 
    if (name.Equals("Reactor")) { return "Reactor Component"; } 
    if (name.Equals("Thrust")) { return "Thruster Component"; } 
    if (name.Equals("GravityGenerator")) { return "GravGen Component"; } 
    if (name.Equals("Medical")) { return "Medical Component"; } 
    if (name.Equals("RadioCommunication")) { return "Radio Component"; } 
    if (name.Equals("Detector")) { return "Detector Component"; } 
    if (name.Equals("SolarCell")) { return "Solar Cell"; } 
    if (name.Equals("PowerCell")) { return "Power Cell"; } 
    if (name.Equals("AutomaticRifleItem")) { return "Rifle"; } 
    if (name.Equals("AutomaticRocketLauncher")) { return "Rocket Launcher"; } 
    if (name.Equals("WelderItem")) { return "Welder"; } 
    if (name.Equals("AngleGrinderItem")) { return "Grinder"; } 
    if (name.Equals("HandDrillItem")) { return "Hand Drill"; } 
    if (typeId.EndsWith("_Ore")) {
        if (name.Equals("Stone")) {
            return name;
        }
        return name + " Ore";
    }
    if (typeId.EndsWith("_Ingot")) {
        if (name.Equals("Stone")) {
            return "Gravel";
        }
        if (name.Equals("Magnesium")) {
            return name + " Powder";
        }
        if (name.Equals("Silicon")) {
            return name + " Wafer";
        }
       return name + " Ingot";
    }
    return name; 
}

Please rate this post

2 Responses

  1. Hello,

    First off I just want to thank you for posting the script. It’s exactly what I am looking for. With that said, I can’t get it to work for me. Im glad you kept your debugging code in their because it helped me find the exact line of code that’s breaking.

    Here’s the error I get in the Programming Block, “The given key was not present in the dictionary” It happens at line 90. For some reason the enum that ‘working’ getting its keys populated with doesn’t seem to match, specifically with “GravGen Component”. checkStock() runs fine.

    My question, and where I think the error may be, is that in the while loop at line 82 we’re using the keys from ‘consolidated’ as opposed to ‘working’. The keys in ‘consolidated’ all have “|MyObjectBuilder_Component” prepended to the end of them. While ‘working’ uses the keys from ‘minimus’.

    Does that make sense? Have I messed something up?

    Thanks,
    GW

  2. Hi,

    First off I just want to thank you for posting the script. It’s exactly what I am looking for. With that said, I can’t get it to work for me. Im glad you kept your debugging code in their because it helped me find the exact line of code that’s breaking.

    Here’s the error I get in the Programming Block, “The given key was not present in the dictionary” It happens at line 90. For some reason the enum that ‘working’ getting its keys populated with doesn’t seem to match, specifically with “GravGen Component”. checkStock() runs fine.

    My question, and where I think the error may be, is that in the while loop at line 82 we’re using the keys from ‘consolidated’ as opposed to ‘working’. The keys in ‘consolidated’ all have “|MyObjectBuilder_Component” prepended to the end of them. While ‘working’ uses the keys from ‘minimus’.

    Does that make sense? Have I messed something up?

    Thanks,
    GW

Leave a Reply