1. This forum is obsolete and read-only. Feel free to contact us at support.keenswh.com

Jump Drive script, (Solved)

Discussion in 'Programming Questions and Suggestions' started by Morphik, Aug 3, 2015.

Thread Status:
This last post in this thread was made more than 31 days old.
  1. Morphik

    Morphik Apprentice Engineer

    Messages:
    186
    Hello once again, I am trying to make a script to get the average total charge levels of jump drives on a grid. I got tired of waiting for keen to put the API functions into the jump drives and this is my first time working with the detailed info of a block.
    I adapted another script I had for measuring the efficiency of solar panels (another persons script, just don't remember who)
    The problem I am running into is the detailed info switches from 5 digits measuring in kWh to 3 digits for MWh. My script only works well once all jump drives are charged into the MWh range.

    Code:
    void Main()   
            {   
                var jumpDrives = new List<IMyTerminalBlock>();   
                GridTerminalSystem.GetBlocksOfType<IMyJumpDrive>(jumpDrives);   
                IMyTextPanel jumpLcd = (IMyTextPanel)GridTerminalSystem.GetBlockWithName("LCD Jump");   
       
                decimal totalCurrentPwr = 0;   
                decimal ideaTotalCurrentPwr = jumpDrives.Count * 300;   
       
            for (int i = 0; i < jumpDrives.Count; i++)   
                {   
                    IMyJumpDrive jPanel = jumpDrives[i] as IMyJumpDrive;   
       
                    string thirdrow = jumpDrives[i].DetailedInfo.ToString().Split('\n')[4];   
                    string powervalue = thirdrow.Split(':')[1];   
       
       
                    for (int j = 0; j < powervalue.Length; j++)   
                    {   
                        if (!Char.IsDigit(powervalue, j))   
                        {   
                            powervalue = powervalue.Remove(j, 1);   
                            j--;   
                        }   
                    }   
       
                    totalCurrentPwr += (Convert.ToDecimal(powervalue));   
       
       
                }
       
                if (jumpLcd == null) Echo("LCD/Text Panel not found, check name."); 
                if (jumpLcd != null) 
                { 
                    decimal charge = totalCurrentPwr / ideaTotalCurrentPwr;   
       
                    jumpLcd.WritePublicText("Total Amount \n of Jump Drives: "   
                        + jumpDrives.Count.ToString()   
                        + "\n\n"   
                        + "Current Power: " + (totalCurrentPwr).ToString() + "kWh"   
                        + "\n\n"   
                        + "Maximum Power: " + ideaTotalCurrentPwr.ToString() + "kWh"   
                        + "\n\n"   
                        + "Charge: " + (charge * 100).ToString("#.##") + "%"   
                        );   
                    jumpLcd.ShowTextureOnScreen();   
                    jumpLcd.ShowPublicTextOnScreen();   
                } 
            }
    If someone could help me figure out how to fix this I would appreciate it.

    Below are screens of what I am having trouble with
    (Jump Drive showing charge in kWh)
    [​IMG]
    (The effect it has on my script)
    [​IMG]
    (Jump Drive showing charge in MWh)
    [​IMG]
    (The effect it has on my script)[​IMG]
     
  2. d4rky1989

    d4rky1989 Apprentice Engineer

    Messages:
    332
    You need to read the scalar value and its unit. Pass the unit to a function that converts it to a decimal value (e.g. MW=10e6, kW=10e3, etc.). Multiply both values to obtain a normalized/non-scaled value.

    I can't give you a code example right now, as I'm sitting in the bus ;)
     
    Last edited: Aug 3, 2015
  3. d4rky1989

    d4rky1989 Apprentice Engineer

    Messages:
    332
    Ok, here's an code example (standard C# code)
    Code:
    namespace Foo
    {
        class Program {
            public static void Main (string[] args) {
                string input1 = "Stored power: 3.00 MWh";
                string input2 = "Stored power: 398.22 kWh";
         
                Decimal totalPower = new Decimal(0);
                totalPower += GetValue (input1);
                totalPower += GetValue (input2);
         
                Console.WriteLine ("Total stored power: " + totalPower);
         
                Console.ReadKey(true);
            }
     
            static Decimal GetValue (string strValue) {
                const string regExpr = @"(?<Num>[0-9.]+) (?<Unit>[a-zA-Z]+)";
                var match = System.Text.RegularExpressions.Regex.Match (strValue, regExpr);
                if (! match.Success)
                    throw new Exception ("Input has an invalid format");
         
                return Decimal.Parse (match.Groups["Num"].Value) * UnitToDecimal (match.Groups["Unit"].Value);
            }
     
            static Decimal UnitToDecimal (string unit) {
                if (unit.StartsWith ("k")) {
                    return new Decimal(10e3);
                }
                if (unit.StartsWith ("M")) {
                    return new Decimal(10e6);
                }
         
                return new Decimal(0);
            }
        }
    }
    All you need to do is to copy both methods "GetValue" and "UnitToDecimal" into your code.
    You can extend "UnitToDecimal" to your needs. "input1" and "input2" are simulated inputs from the DetailedInfo. You have to split the DetailedInfo string by its line delimiters (\n) and pass the line containing your value to the "GetValue" method.
    Here a short usage example (not tested for syntax errors):
    Code:
    void Main (string argument) {
        Decimal storedPower = GetValueFromDetailedInfo ("Stored power", GridTerminalSystem.GetBlockWithName("Jump Drive"));
        Echo ("Stored power: " + storedPower);
    }
    Decimal GetValueFromDetailedInfo (string key, IMyTerminalBlock block) {
        var lines = block.DetailedInfo.Split ('\n');
        for (int i = 0; i < lines.Length; i++) {
            if (lines[i].StartsWith (key))
                return GetValue (lines[i]);
        }
    }
    
    // insert "GetValue" and "UnitToDecimal"
    EDIT:
    You should rename the "GetValue" method to something more meaningful.
     
    Last edited: Aug 3, 2015
  4. Morphik

    Morphik Apprentice Engineer

    Messages:
    186
    You are getting me into stuff that is way over my head, and out of my C# skills.
    I tried piecing your examples together, and there are a few errors that happen. And when I think I figure one out another pops up.
    Is there a more simple way?
     
  5. d4rky1989

    d4rky1989 Apprentice Engineer

    Messages:
    332
    When I'm at home I'll post an tested and working example.
    I don't know if there can be an easier way. Its just calling one method. You'll see when I'll post the new example.
     
    Last edited: Aug 3, 2015
  6. Morphik

    Morphik Apprentice Engineer

    Messages:
    186
    I got this to work. I can use this from here to adapt it to my original plan.

    Code:
    void Main()
    {
        var jumpDrives = new List<IMyTerminalBlock>();
        GridTerminalSystem.GetBlocksOfType<IMyJumpDrive>(jumpDrives);
        IMyTextPanel jumpLcd = (IMyTextPanel)GridTerminalSystem.GetBlockWithName("LCD Jump");
        string input1 = "Stored power: 3.00 MWh"; 
        string input2 = "Stored power: 398.22 kWh";
        decimal ideaTotalCurrentPwr = jumpDrives.Count * 30000000;
        decimal totalPower = new Decimal(0);
        //totalPower += GetNum (input1); 
        //totalPower += GetNum (input2);
        for (int i = 0; i < jumpDrives.Count; i++)
        {
            string thirdrow = jumpDrives[i].DetailedInfo.ToString().Split('\n')[4];
            string powervalue = thirdrow.Split(':')[1];
            totalPower += GetNum (powervalue);
            if (jumpLcd == null) Echo("LCD/Text Panel not found, check name.");
            if (jumpLcd != null)
            {
                decimal charge = totalPower / ideaTotalCurrentPwr;
    
                jumpLcd.WritePublicText("Total Amount \n of Jump Drives: "
                + jumpDrives.Count.ToString()
                + "\n\n"
                + "Current Power: " + totalPower.ToString("#") + " Wh"
                + "\n\n"
                + "Maximum Power: " + ideaTotalCurrentPwr.ToString() + " Wh"
                + "\n\n"
                + "Charge: " + (charge * 100).ToString("#.##") + "%"
                );
                jumpLcd.ShowTextureOnScreen();
                jumpLcd.ShowPublicTextOnScreen();
            }
        }
    }
    static Decimal GetNum (string strValue) { 
        const string regExpr = @"(?<Num>[0-9.]+) (?<Unit>[a-zA-Z]+)"; 
        var match = System.Text.RegularExpressions.Regex.Match (strValue, regExpr); 
        if (! match.Success) 
            throw new Exception ("Input has an invalid format"); 
        return Decimal.Parse (match.Groups["Num"].Value) * UnitToDecimal (match.Groups["Unit"].Value); 
    } 
    static Decimal UnitToDecimal (string unit) { 
        if (unit.StartsWith ("k")) { 
            return new Decimal(10e3); 
        } 
        if (unit.StartsWith ("M")) { 
            return new Decimal(10e6); 
        } 
        return new Decimal(0); 
    }
     
  7. d4rky1989

    d4rky1989 Apprentice Engineer

    Messages:
    332
    Nice,
    some remarks:
    1. I found an error in my "UnitToDecimal" method. Replace the last line "return new Decimal (0);" with "return new Decimal (1);"
    2. "input1" and "input2" (line 6 and 7) were just some test data. You don't need them any more
    3. You should not update the LCD panel in every iteration of you for-loop. Inside the for-loop perform all the computation and update the LCD text afterwards.
    4. You should also compute the maximum power (your value "ideaTotalCurrentPwr"). Hardcoded values are always bad. If these values changes in the future you need to update all your scripts correspondingly.

    Here's a bit more structured code:
    Code:
    const string LCD_NAME = "LCD Jump";
    
    void Main()
    {
        var jumpDrives = new List<IMyTerminalBlock>();
        GridTerminalSystem.GetBlocksOfType<IMyJumpDrive>(jumpDrives);
    
        IMyTextPanel jumpLcd = (IMyTextPanel)GridTerminalSystem.GetBlockWithName(LCD_NAME);
        if (jumpLcd == null)
            throw new Exception ("Can't find block '" + LCD_NAME + "'.");
    
        Decimal totalMaxPower = new Decimal (0);
        Decimal totalPower = new Decimal (0);
    
        jumpDrives.ForEach (drive => {
            var detailedInfoArray = drive.DetailedInfo.Split ('\n');
            totalPower += GetNum (detailedInfoArray[4]);
            totalMaxPower += GetNum (detailedInfoArray[2]);
        });
    
        Decimal chargePercentage = totalPower * 100 / totalMaxPower;
    
        jumpLcd.WritePublicText ( string.Format (
            "Number of jump drives: {0}"
            + "\n\nMax. power: {1} W"
            + "\n\nCurrent power: {2} W"
            + "\n\nPercentage: {3} %",
            jumpDrives.Count, totalMaxPower.ToString ("#"),
            totalPower.ToString ("#"), chargePercentage.ToString ("#.00")));
    }
    
    public static Decimal GetNum (string strValue) { 
        const string regExpr = @"(?<Num>[0-9.]+) (?<Unit>[a-zA-Z]+)"; 
        var match = System.Text.RegularExpressions.Regex.Match (strValue, regExpr); 
        if (! match.Success) 
            throw new Exception ("Input has an invalid format"); 
        return Decimal.Parse (match.Groups["Num"].Value) * UnitToDecimal (match.Groups["Unit"].Value); 
    }
    
    public static Decimal UnitToDecimal (string unit) {
        switch (unit[0]) {
        case 'k': return new Decimal (10e3);
        case 'M': return new Decimal (10e6);
        default: return new Decimal (1);
        }
    }
     
  8. Morphik

    Morphik Apprentice Engineer

    Messages:
    186
    WOW that is much better @d4rky1989.
    One more thing though. My original plan was to have the percentage change the LCD Texture.
    I have a LCD Texture mod on the workshop that adds in 0-100% in 5% increments
    they are named "Percent 000" "Percent 005" "Percent 010" to "Percent 100"

    I have this for other scripts. Like for cargo space.

    Code:
    	int _lastIndex = -1;
    ...
    ...
    ...
    ...
    	int index = (int)(20.0f * usedVolume / maxVolume);
    	if(index > 20 || index < 0)
    		return; //error
    	if(index == _lastIndex)
    		return;
    	lcd.ClearImagesFromSelection();
    	lcd.AddImageToSelection(string.Format("Percent {0}",(index*5).ToString("D3")));
    Any Idea how I can adapt this to work with the percentage off of this script? I know the difference is when working with my cargo space script its working with floats and this is working with decimals.
     
  9. Morphik

    Morphik Apprentice Engineer

    Messages:
    186
    Never mind I figured it out. It was really simple.

    Code:
        lcd.ClearImagesFromSelection();
        lcd.AddImageToSelection(string.Format("Percent {0}", chargePercentage.ToString("000"))); 
     
  10. d4rky1989

    d4rky1989 Apprentice Engineer

    Messages:
    332
    That is perfect. Couldn't have done it better.
    How did you solve the 5% steps? The same way it is calculated in the code example you posted above?
     
    Last edited: Aug 3, 2015
  11. Morphik

    Morphik Apprentice Engineer

    Messages:
    186
    Nope, didn't need any of it, chargePercentage.ToString("000") puts the percentage from 000 to 100 It rounds up to the nearest percent say the drives are at 55.67% that would read 056.
    It's essentially doesn't update the image until a exact 5% increment is hit.

    I do notice one problem, if it isn't a 5% increment the ClearImageFromSelection() hits and does remove the image from the selection, but thanks to how keen refreshes the LCD screens the old texture stays until the LCD is either toggled off and on again or the image selection is changed.
    It's not too big of a deal.
     
  12. Morphik

    Morphik Apprentice Engineer

    Messages:
    186
  13. d4rky1989

    d4rky1989 Apprentice Engineer

    Messages:
    332
    Great. Its looking really nice with the images.
     
Thread Status:
This last post in this thread was made more than 31 days old.