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

[SNIPPETS/REQUESTS] Helpful snippets of code for our scripting.

Discussion in 'Programming Guides and Tools' started by Phoera, Jan 14, 2015.

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

    Phoera Senior Engineer

    Messages:
    1,713
    I decide to start snippet thread.

    Snippet is small piece of code with simple purpose.
    it must be one function with helpers, or class which encapsulates functional in it.

    Snippet posting must contain it name, description, dependency from other snippets, and better if it will contain snippets.
    Also they must be bolded to determine that it is a snippet, not just post.
    (if posting someones code, better to point on author)

    Also anyone here can ask for snippets(snippets, not program!)
    Best wishes, Phoenix.

    List(i will update it as long as i can):
    Get This[Obsolete]
    Blocks of the same grid
    Take out numbers
    GetDirectionTo
    Some usings of filter function
    Change States/Action on a group of blocks
    Get Slim Block from Fat Block
    List.ForEach sample
    Reactor Uranium mass
    Consolidate inventory
    determine if something is an ammo, an ore, an ingot or a component
    Consolidation that preserves item positions in the inventory
    ActionHelper. A little utility library. Makes calls to block- and group actions shorter and more readable.
    simple scalable sequential state machine
    splitting strings across multiple screens (only counts number of lines, does not take width into account!)
    ParseDetailValues
     
    Last edited: May 25, 2016
  2. Phoera

    Phoera Senior Engineer

    Messages:
    1,713
    SNIPPET: Get This[OBSOLETE]
    use Me property instread.

     
    Last edited: May 25, 2016
  3. Phoera

    Phoera Senior Engineer

    Messages:
    1,713
    SNIPPET: Blocks of the same grid

    This snippet show how to get all terminal blocks of the same grid of some block.(remember that rotors/pistons/connectors split grids)
    Code:
    List<IMyTerminalBlock> GetBlocksInTheSameGrid(IMyTerminalBlock block)
    {  
        var blocks=GridTerminalSystem.Blocks;
        var lst=new List<IMyTerminalBlock>();
        for(int i=0;i<blocks.Count;i++)
        {
            if(blocks[i].CubeGrid==block.CubeGrid)
                lst.Add(blocks[i]);
        }
        return lst;
    } 
    
    Sample
    For sample i will get all blocks on the same grid of our programmable block
    Code:
    var blocks=GetBlocksInTheSameGrid(Me);
     
    Last edited: May 25, 2016
  4. Phoera

    Phoera Senior Engineer

    Messages:
    1,713
    SNIPPET: Take out numbers

    This snippet deletes numbers(from default name) from blocks of given type
    Code:
    void TakeOutNumbers<T>()
    {
        GridTerminalSystem.GetBlocksOfType<T>(null,TakeOutNumbersFilter);
    }
    bool TakeOutNumbersFilter(IMyTerminalBlock block)
    {
        var str=block.CustomName;
        var num=block.NumberInGrid.ToString();
        var ind=str.IndexOf(num);
        if(ind>=0)
        {
            block.SetCustomName(str.Remove(ind,num.Length).Trim());
        }
        return false;
    }
    
    Samples
    Code:
    TakeOutNumbers<IMyThrust>();//For thrusters
    
    Code:
    TakeOutNumbers<IMyLightingBlock>();//For all lights
    
    Code:
    TakeOutNumbers<IMyTerminalBlock>();//For all
    
     
    Last edited: May 25, 2016
  5. robbym

    robbym Trainee Engineer

    Messages:
    10
    SNIPPET: GetDirectionTo

    Takes in 4 reference blocks and a target vector and sets the Pitch and Yaw to the target.
    I have a separate thread for this, but might as well post it here.
    Code:
    /*
    VRageMath.Vector3D TV         This is the target vector.
    IMyTerminalBlock Origin       Origin block.
    IMyTerminalBlock Forward      Block directly in front of the origin.
    IMyTerminalBlock Up           Block directly above the origin.
    IMyTerminalBlock Right        Block directly to the right of the origin.
    ref double Pitch              Reference to Pitch.
    ref double Yaw                Reference to Yaw.
    */
    void GetDirectionTo(VRageMath.Vector3D TV, IMyTerminalBlock Origin, IMyTerminalBlock Forward, IMyTerminalBlock Up, IMyTerminalBlock Right, ref double Pitch, ref double Yaw)
    {
      VRageMath.Vector3D OV = Origin.GetPosition();     //Get positions of reference blocks.
      VRageMath.Vector3D FV = Forward.GetPosition();
      VRageMath.Vector3D UV = Up.GetPosition();
      VRageMath.Vector3D RV = Right.GetPosition();
    
      double TVOV = (OV - TV).Length();     //Get magnitudes of vectors.
    
      double TVFV = (FV - TV).Length();
      double TVUV = (UV - TV).Length();
      double TVRV = (RV - TV).Length();
    
      double OVFV = (FV - OV).Length();
      double OVUV = (UV - OV).Length();
      double OVRV = (RV - OV).Length();
      
      double ThetaP = Math.Acos((TVUV * TVUV - OVUV * OVUV - TVOV * TVOV) / (-2 * OVUV * TVOV));     //Use law of cosines to determine angles.
      double ThetaY = Math.Acos((TVRV * TVRV - OVRV * OVRV - TVOV * TVOV) / (-2 * OVRV * TVOV));
    
      double RPitch = 90 - (ThetaP * 180 / Math.PI);     //Convert from radians to degrees.
      double RYaw = 90 - (ThetaY * 180 / Math.PI);
    
      if (TVOV &lt; TVFV) RPitch = 180 - RPitch;     //Normalize angles to -180 to 180 degrees.
      if (RPitch > 180) RPitch = -1 * (360 - RPitch);
    
      if (TVOV &lt; TVFV) RYaw = 180 - RYaw;
      if (RYaw > 180) RYaw = -1 * (360 - RYaw);
    
      Pitch = RPitch;     //Set Pitch and Yaw outputs.
      Yaw = RYaw;
    }
    
     
  6. hellokeith

    hellokeith Apprentice Engineer

    Messages:
    335
    Code:
    GridTerminalSystem.GetBlocksOfType&lt;IMyProgrammableBlock>(blocks,GetThisFilter);
    Could you make another example or two of using the filter option with GetBlocksOfType.
     
  7. Phoera

    Phoera Senior Engineer

    Messages:
    1,713
    which one filter you need?
     
  8. Phoera

    Phoera Senior Engineer

    Messages:
    1,713
    SNIPPETS: some usings of filter function.

    will return all enabled functional blocks
    Code:
    GridTerminalSystem.GetBlocksOfType<IMyFunctionalBlock>(blocks, EnabledFilter );
    //----------------------------------
            private bool EnabledFilter(IMyTerminalBlock block)
            {
                if (block is IMyFunctionalBlock)
                {
                    return (block as IMyFunctionalBlock).Enabled;
                }
                return false;
            }
    
    will return all disabled functional blocks
    Code:
    GridTerminalSystem.GetBlocksOfType<IMyFunctionalBlock>(blocks, EnabledFilter );
    //----------------------------------
            private bool DisabledFilter(IMyTerminalBlock block)
            {
                if (block is IMyFunctionalBlock)
                {
                    return !(block as IMyFunctionalBlock).Enabled;
                }
                return false;
            }
    
    will return all blocks being hacked
    Code:
    GridTerminalSystem.GetBlocksOfType<IMyTerminalBlock>(blocks, EnabledFilter );
    //----------------------------------
            private bool HackedFilter(IMyTerminalBlock block)
            {
                return block.IsBeingHacked;
            }
    
    must take all moving rotors(i didn't test it)
    Code:
    GridTerminalSystem.GetBlocksOfType<IMyMotorStator>(blocks, MovingRotorFilter );
    //----------------------------------
    private bool MovingRotorFilter(IMyTerminalBlock block)
    {
        if (block is IMyMotorStator)
        {
            return Math.Abs((block as IMyMotorStator).Velocity) > 0.01;
        }
        return false;
    }
    
     
    Last edited: May 25, 2016
  9. Znurf

    Znurf Trainee Engineer

    Messages:
    14
    Snippet: Change States/Action on a group of blocks. (For example OnOff_On, SwitchLock, Open_On or whatever the ActionName is)

    Will return nothing :) If you spell things wrong, or the group doesnt exist, i dont know what happens :p And if you have a group with mixed blocks that has different Actions, i dont know what happens either :p For example if you try to Open a Thruster, who knows, perhaps it opens a wormhole? :p

    Code:
    //Function for applying actions to an entire group of modules.
    void ChangeGroupAction( String GroupName , String Action )  {
        var Group = new List &lt;IMyBlockGroup>();
        Group = GridTerminalSystem.BlockGroups;
     
        // Loop through the entire list of groups...
        for ( int i = 0 ; i &lt; Group.Count ; i++ ) {
     
            // ...and find the group you are looking for.
            if ( Group[i].Name == GroupName ) {
                var GroupCont = Group[i].Blocks;
           
                // Loop through all blocks in the group and apply the new action
                for ( int c = 0 ; c &lt; GroupCont.Count ; c++ ) {
                    GroupCont[c].GetActionWithName ( Action ).Apply ( GroupCont[c] );
                }
            }
        }
    }
    
    You would use it like this:

    Code:
    String Lights = "TheNameOfMyGroupOfLights";
    String Off = "OnOff_Off";
    String On = "OnOff_On";
    
    ChangeGroupAction( Lights , Off );
    
    ChangeGroupAction( Lights, On );
    -----
    
    //You can ofcourse skip using String variables and just type it in too;
    //But it isnt as neat ;P
    
    ChangeGroupAction( "TheNameOfMyGroupOfLights", "OnOff_Off" );
     
  10. Phoera

    Phoera Senior Engineer

    Messages:
    1,713
    Snippet: Get Slim Block from Fat Block.

    this short function allow you to get slim block(physical block) from fat block(terminal block).
    This will allow you to get integrity or some other things.
    Code:
    IMySlimBlock GetSlimBlockFromFat(IMyTerminalBlock block) { return block.CubeGrid.GetCubeBlock(block.Position); } 
    
    Example:
    Lets print build level into name of our PB(i use GetThis snippet)
    Code:
     var fat= GetThis();
     var slim=GetSlimBlockFromFat(fat);
     fat.SetCustomName(string.Format("PB: {0:0.00}%"),slim.BuildLevelRatio)
    
    Example has writen here, so i didn't check it.
     
    Last edited by a moderator: Jan 22, 2015
  11. TheBarret

    TheBarret Trainee Engineer

    Messages:
    17
    I know there are some tight limitation but i wanna add my 2 cents to this.
    Might be a small addition but i find it quite usefull.

    The for-each can give some issues ive read and im not sure if you all are aware that the list instance has a specific List.ForEach([delegate]) method, allows you to branch out per item in that collection.
    Ive tested this in SE and it gave me no errors or problems.

    Example:
    Code:
    void SomeMethod() {
      SomeCollection.ForEach(this.Iteration);
    }
    void Iteration(string item) {
      // do something with item...
    }
    
    Remark:
    The ForEach parameter desires a method signature that corresponds to the type that is contained in the collection.

    MSDN Reference:
    https://msdn.microsoft.com/en-us/library/bwabdf9z(v=vs.110).aspx
     
    Last edited by a moderator: Jan 23, 2015
  12. hellokeith

    hellokeith Apprentice Engineer

    Messages:
    335
    For a named reactor, this gets the total mass of the inventory.. i.e. the cumulative number of Uranium ingots that you see in the reactor inventory (could be stacked or could be multiple U items).

    MyFixedPoint is cast to a Decimal, and the Math.Round function rounds it to one decimal place. Set the rounding per your preference.

    Code:
    void Main()
    {
        var reactor = GridTerminalSystem.GetBlockWithName("reactor") as IMyInventoryOwner;
        var reactor_items = reactor.GetInventory(0) as IMyInventory;
        var reactor_mass_mfp = reactor_items.CurrentMass;
        Decimal reactor_mass = (Decimal)reactor_mass_mfp;
        reactor_mass = Math.Round(reactor_mass, 1);
        var beacon = GridTerminalSystem.GetBlockWithName("beacon") as IMyTerminalBlock;
        beacon.SetCustomName("reactor mass is " + reactor_mass.ToString());
    }
    
     
  13. TheBarret

    TheBarret Trainee Engineer

    Messages:
    17
    I would go for a double instead of a decimal.

    Let me sum up why that is. they use less memory, they are faster in computations because they are by design (native) supported by the cpu and they can hold alote more range then a decimal.


    - Barret
     
    Last edited by a moderator: Jan 23, 2015
  14. hellokeith

    hellokeith Apprentice Engineer

    Messages:
    335
    With Double, 4.95 gets rounded to 5 with no decimal places. With Decimal, the decimal places are retained. IMO, if I specify that I want one or two or x number of decimal positions, I want them regardless if the digits are 0.
     
  15. TheBarret

    TheBarret Trainee Engineer

    Messages:
    17
    Code:
    Double.ToString("N2");
    
    Problem solved.
     
    Last edited by a moderator: Jan 23, 2015
  16. Burillo

    Burillo Junior Engineer

    Messages:
    648
    My small contribution:

    Consolidate inventory (i.e. make everything appear only once in an inventory)

    Code:
    void consolidate(IMyInventory inv) {
      var items = inv.GetItems();
      // start from end as the list may get smaller with each transfer
      // going down to 1 is intentional
      for (int i = items.Count - 1; i > 0; i--) {
        inv.TransferItemTo(inv, i, null, true, null);
      }
    }
    
    can be used as

    Code:
    IMyReactor block; // a reactor
    consolidate(block.GetInventory(0));
    
    now you have all ingots in one spot.

    same with multiple inventories:

    Code:
    IMyRefinery block; // a refinery
    // consolidate each inventory
    for (int i = 0; i &lt; block.GetInventoryCount(); i++) {
       consolidate(block.GetInventory(i));
    }
    
     
    Last edited by a moderator: Feb 16, 2015
  17. Burillo

    Burillo Junior Engineer

    Messages:
    648
    SNIPPET: determine if something is an ammo, an ore, an ingot or a component

    Code:
    bool isOre(IMyInventoryItem item) {
        return item.Content is Sandbox.Common.ObjectBuilders.MyObjectBuilder_Ore;
    }
    bool isIngot(IMyInventoryItem item) {
        return item.Content is Sandbox.Common.ObjectBuilders.MyObjectBuilder_Ingot;
    }
    bool isComponent(IMyInventoryItem item) {
        return item.Content is Sandbox.Common.ObjectBuilders.MyObjectBuilder_Component;
    }
    bool isAmmo(IMyInventoryItem item) {
        return item.Content is Sandbox.Common.ObjectBuilders.MyObjectBuilder_AmmoMagazine;
    }
    
    Example of usage:

    Code:
    // get all ore of a certain type from a particular inventory
    void getAllOre(IMyInventory inv, string name, List&lt;IMyInventoryItem> list) 
      var items = inv.GetItems();
      for (int ii = 0; ii &lt; items.Count; ii++) {
        var item = items[ii];
        if (!isOre(item))
          continue;
        if (item.Content.SubtypeName != name)
          continue;
        list.Add(item);
      }
    }
    
    
    void Main {
       ...
       List&lt;IMyInventoryItem> uranium = new List&lt;IMyInventoryItem>();
       IMyRefinery r; // a refinery
       getAllOre(r.GetInventory(0), "Uranium", uranium); // get all uranium from that particular refinery into our list
    }
    
     
    Last edited by a moderator: Mar 12, 2015
  18. Burillo

    Burillo Junior Engineer

    Messages:
    648
    SNIPPET: Consolidation that preserves item positions in the inventory

    Code:
    void consolidate(IMyInventory inv) {
      Dictionary&lt;string, int> posmap = new Dictionary&lt;string, int>();
      var items = inv.GetItems();
      bool needs_consolidation = false;
      // go through all items and note the first time they appear in the inventory
      for (int i = 0; i &lt; items.Count; i++) {
        var item = items[i];
        string str = item.Content.TypeId.ToString() + item.Content.SubtypeName;
        if (!posmap.ContainsKey(str)) {
          posmap[str] = i;
        }
        else
          needs_consolidation = true;
      }
      // make sure we don't touch already consolidated inventories
      if (!needs_consolidation)
        return;
      // now, consolidate all items
      for (int i = items.Count - 1; i >= 0; i--) {
        var item = items[i];
        string str = item.Content.TypeId.ToString() + item.Content.SubtypeName;
        int dstIndex = posmap[str];
        inv.TransferItemTo(inv, i, dstIndex, true, item.Amount);
      }
    }
    
    usage similar to previous consolidation example.
     
  19. Brenner

    Brenner Junior Engineer

    Messages:
    609
    SNIPPET: ActionHelper. A little utility library. Makes calls to block- and group actions shorter and more readable.


    IMHO the code required to get a block, then execute a action is way too long and difficult to remember.
    Therefor I created a little utility library named "Action Helper", which helps to make action calls much shorter and readable.

    Example Usage


    Code:
    ApplyAction("Stop Firing Timer Block","Start");  // Tell the Timer Block named "Stop Firing Timer Block" to start its countdown 
    TurnOff("Lock Torpedo"); // Tell the "Lock Torpedo" Merge Block to turn itself off
    TurnOn("Gun Grav Gens");  // Tell the "Gun Grav Gens" to turn on 
    
    ApplyAction has 2 parameters:

    1. can be either a string containing the name of a block or group, or a reference to a IMyBlockGroup or to a IMyTerminalBlock.
    2. Name of the action you want to call, for example "Start" to start a timer block or "OnOff_On" to turn something on.

    If you use the string version, it will execute the action for all groups and blocks that use this exact name.
    For example: ApplyAction("Test","OnOff_Off") wil turn off all groups and blocks named "Test".
    The other versions with IMyBlockGroup or IMyTerminalBlock will exceute only for this group or block (obviously).

    TurnOff and TurnOn are just shortcuts to
    ApplyAction(groupOrBlockName,"OnOff_Off") and ApplyAction(groupOrBlockName,"OnOff_On") respectivly, created because I need them a lot in my code. Add your own shortcuts to your most frequently used actions, if you want.

    Full code

    Code:
    // ACTION HELPER  
    // By Brenner V. 2015-03-08 
    // ================================================================================  
      
    void ApplyAction(IMyTerminalBlock block, string actionName) 
    { 
      var action = block.GetActionWithName(actionName);   
      if(action == null) {throw new Exception("Block '"+block.CustomName + "' has no "+actionName+" Action!");}   
        
       action.Apply(block);  
    } 
     
    void ApplyAction(IMyBlockGroup group,string actionName) 
    { 
     for(var i = 0;i &lt; group.Blocks.Count;i++) 
     {  
       var block = group.Blocks[i] as IMyTerminalBlock; 
       if(block == null) {continue;} 
       ApplyAction(block,actionName);   
     } 
    } 
     
    void ApplyAction(string groupOrBlockName,string actionName) 
    { 
     bool foundSomething = false; 
     // 1. Groups 
     var allGroups = GridTerminalSystem.BlockGroups; 
     for(var i = 0;i&lt;allGroups.Count;i++) 
     { 
       if(groupOrBlockName == allGroups[i].Name)  
       {ApplyAction(allGroups[i],actionName); 
         foundSomething = true; 
        }  
     } 
     // 2. Blocks  
     var blocks = new List&lt;IMyTerminalBlock>(); 
     GridTerminalSystem.SearchBlocksOfName(groupOrBlockName,blocks); 
     for(var i = 0;i &lt; blocks.Count;i++) 
     { 
       ApplyAction(blocks[i],actionName); 
       foundSomething = true; 
     } 
     if(! foundSomething)  
     { 
      throw new Exception("There is no group or block named "+groupOrBlockName+"!");  
     } 
    } 
     
    void TurnOn(string groupOrBlockName)  
    {   
      ApplyAction(groupOrBlockName,"OnOff_On"); 
    } 
     
    void TurnOff(string groupOrBlockName) 
    { 
     ApplyAction(groupOrBlockName,"OnOff_Off"); 
    } 
    
    
     
    Last edited by a moderator: Mar 8, 2015
  20. Burillo

    Burillo Junior Engineer

    Messages:
    648
    This thread is a bit outdated, but i'll post it here anyway.

    Snippet: simple scalable sequential state machine

    This is for those who want to write complex scripts with multiple states. What this does is, it stores IL count for all states, and checks if you still have headroom to run some more. It needs a little set up, but the end result is a state machine that automatically scales to accommodate for growing/shrinking script execution times.

    Code:
    // storage for states
    Action [] states;
    
    // current state
    int current_state;
    
    // persistent IL counters
    int[] state_cycle_counts;
    int[] state_fn_counts;
    
    // per-execution IL counters
    int cur_cycle_count;
    int cur_fn_count;
    
    bool canContinue() {
    	// get next state
    	var next_state = (current_state + 1) % states.Length;
    	
    	// get current cycle/fn count information
    	var cur_i = Runtime.CurrentInstructionCount;
    	var cur_fn = Runtime.CurrentMethodCallCount;
    	
    	// check if we ever executed the next state and therefore can estimate how
    	// much cycle/fn count it will likely take
    	bool canEstimate = state_cycle_counts[next_state] != 0;
    
    	// store how many cycles/fn calls we've used during this state
    	state_cycle_counts[current_state] = cur_i - cur_cycle_count;
    	state_fn_counts[current_state] = cur_fn - cur_fn_count;
    
    	// how many cycles/fn did the next state take when it was last executed?
    	var last_cycle_count = state_cycle_counts[next_state];
    	var last_fn_count = state_fn_counts[next_state];
    
    	// estimate cycle/fn count after executing the next state
    	int projected_cycle_count = cur_i + last_cycle_count;
    	int projected_fn_count = cur_fn + last_fn_count;
    	
    	// given our estimate, how are we doing with regards to IL count limits?
    	Decimal cycle_p = (Decimal) projected_cycle_count / Runtime.MaxInstructionCount;
    	Decimal fn_p = (Decimal) projected_fn_count / Runtime.MaxMethodCallCount;
    
    	// if we never executed the next state, we leave 60% headroom for our next
    	// state (for all we know it could be a big state), otherwise leave at 20%
    	// because we already know how much it usually takes and it's unlikely to
    	// suddenly become much bigger than what we've seen before
    	var cycle_thresh = canEstimate ? 0.8M : 0.4M;
    	var fn_thresh = canEstimate ? 0.8M : 0.4M;
    
    	// check if we are exceeding our stated thresholds (projected 80% cycle/fn
    	// count for known states, or 40% up to this point for unknown states)
    	bool haveEnoughHeadroom = cycle_p <= cycle_thresh && fn_p <= fn_thresh;
    
    	// advance current state and store IL count values
    	current_state = next_state;
    	cur_cycle_count = cur_i;
    	cur_fn_count = cur_fn;
    
    	return haveEnoughHeadroom;
    }
    
    // put this into your Program() function, this is initialization stage
    public Program() {
    	// initialize states array with your states
    	states = new Action [] {
    		state1,
    		state2
    		// ...however many states you have
    	};
    	// start with first state
    	current_state = 0;
    	
    	// initialize state IL/fn counters
    	state_cycle_counts = new int[states.Length];
    	state_fn_counts = new int[states.Length];
    }
    
    public void Main() {
    	// state counter, to make sure we don't execute the same state twice even if
    	// we have enough cycle/fn count headroom for it
    	int num_states = 0;
    	
    	// zero out per-execution IL counters
    	cur_cycle_count = 0;
    	cur_fn_count = 0;
    	
    	// run the state machine
    	do {
    		states[current_state]();
    	} while (canContinue() && ++num_states < states.Length);
    
    	// show execution info
    	string il_str = String.Format("IL Count: {0}/{1} ({2:0.0}%)",
    				Runtime.CurrentInstructionCount,
    				Runtime.MaxInstructionCount,
    				(Decimal) Runtime.CurrentInstructionCount / Runtime.MaxInstructionCount * 100M);
    	string fn_str = String.Format("Call count: {0}/{1} ({2:0.0}%)",
    				Runtime.CurrentMethodCallCount,
    				Runtime.MaxMethodCallCount,
    				(Decimal) Runtime.CurrentMethodCallCount / Runtime.MaxMethodCallCount * 100M);
    	Echo(String.Format("States executed: {0}", num_states));
    	Echo(il_str);
    	Echo(fn_str);
    }
    
    States for this state machine are declared as simple void functions:

    Code:
    void state1() {
    	// do something
    }
    
    void state2() {
    	// do something else
    }
    
    What happens is, suppose executing state1 and state2 takes 30% of IL count on a small base, and 90% on a big base. Due to our threshold being set at 80% IL count (which is a safe estimate IMO), both states will get executed in one go on a small base, but on a big base the execution will now take two timer cycles. This works regardless of how many states you might have.
     
    Last edited: May 5, 2016
  21. Wicorel

    Wicorel Senior Engineer

    Messages:
    1,263
    Nice.

    Can you put the definition of 'Action' in the snippet?
     
  22. Phoera

    Phoera Senior Engineer

    Messages:
    1,713
    this is System.Action.
    just delegate void()
     
  23. Burillo

    Burillo Junior Engineer

    Messages:
    648
    https://msdn.microsoft.com/en-us/library/system.action(v=vs.110).aspx
    --- Automerge ---
    Snippet: splitting strings across multiple screens (only counts number of lines, does not take width into account!)

    Code:
    public class SplitScreenText {
      private List<string> _screens = new List<string>();
      private int _limit;
    
      public int Limit {
        get {return _limit;}
        set {_limit = value;}
      }
    
      public int ScreenCount {
        get {return _screens.Count;}
      }
    
      // get offsets into string where screens start
      private List<int> GetScreenIdxes(string str) {
        // add a 0 right from the start
        List<int> idxes = new List<int>(){0};
        var regex = new System.Text.RegularExpressions.Regex("\\r?\\n");
        var matches = regex.Matches(str);
        int curLines = 0;
    
        for (int i = 0; i < matches.Count; i++) {
          // we found ourselves a new screen!
          if (++curLines == _limit) {
            var group = matches[i].Groups[0];
            int idx = group.Index + group.Length;
            idxes.Add(idx);
            curLines = 0;
          }
        }
        return idxes;
      }
    
      // splitting string based on indexes of screens
      private void PopulateScreens(List<int> screenIdxes, string str) {
        for (int i = 0; i < screenIdxes.Count; i++) {
          int start = screenIdxes[i];
          if (i == screenIdxes.Count - 1) {
            _screens.Add(str.Substring(start));
          } else {
            int length = screenIdxes[i + 1] - start;
            _screens.Add(str.Substring(start, length));
          }
        }
      }
    
      public void SetString(string str) {
        _screens.Clear();
    
        List<int> screenIdxes = GetScreenIdxes(str);
    
        PopulateScreens(screenIdxes, str);
      }
    
      public string GetScreen(int idx) {
        return _screens[idx];
      }
    };
    
    usage:
    Code:
    SplitScreenText t = new SplitScreenText();
    t.Limit = 20; // or however many lines you want on a single screen
    t.SetString(your_text);
    t.GetScreen(1); // get string for a second screen
    
     
    • Agree Agree x 1
  24. Maddo

    Maddo Trainee Engineer

    Messages:
    41
    SNIPPET: ParseDetailValues

    This parses the DetailedInfo section of a block, according to the default format most blocks use.

    For example:
    [key]: [value double] [optional unit]
    Type: Solar Panel // This line is skipped since it has no value of the type double
    Max Output: 74.07 kW
    Current Output: 1.13 kW

    Code:
    // Parses Detail values
    // May need to add more case statements
    public Dictionary<string, double> ParseDetailValues(string DetailedInfo)
    {
        Dictionary<string, double> DetailValues = new Dictionary<string, double>();
        var lines = DetailedInfo.Split('\n');
    
        for(int i=0; i<lines.Length; i++)
        {
            lines[i] = lines[i].Replace("%"," %");
            var tokens = lines[i].Split(':');
            if( tokens.Length<2 ) { continue; }
            var valueTokens = tokens[1].Trim().Split(' ');
            if( valueTokens.Length<2 ) { continue; }
    
            string key = tokens[0].Trim();
            string value = valueTokens[0];
            string units = valueTokens[1];
            var result = .0;
    
            if (!double.TryParse(value, out result))
            {
                continue;
            }
    
            switch(units)
            {
                case "W":
                    result *= 1.0f;
                    break;
                case "kW":
                    result *= 1000.0f;
                    break;
                case "MW":
                    result *= 1000000.0f;
                    break;
                case "Wh":
                    result *= 1.0f;
                    break;
                case "kWh":
                    result *= 1000.0f;
                    break;
                case "MWh":
                    result *= 1000000.0f;
                    break;
                case "sec":
                    result *= 1.0f;
                    break;
                case "min":
                    result *= 60.0f;
                    break;
                case "hours":
                    result *= 360.0f;
                    break;
                case "days":
                    result *= 216000.0f;
                    break;
                case "%":
                    result *= 0.01f;
                    break;
            }
    
            DetailValues[key] = result;
        }
    
        return DetailValues;
    }
    usage:
    Code:
    var blocks = new List<IMyTerminalBlock>();
    GridTerminalSystem.GetBlocksOfType<IMyBatteryBlock>(blocks);
    double charge=0;
    
    for(int i=0;i<blocks.Count;i++)
    {
        var data = ParseDetailValues(blocks[i].DetailedInfo);
        charge += data["Stored power"];
    }
    
    Echo("Batteries total charge is "+charge/1000.0f+" kWh");
     
    Last edited: May 23, 2016
  25. Malware

    Malware Master Engineer

    Messages:
    9,867
    @phoenixcorp13 You should perhaps either delete or tag the GetThis snippet as obsolete, since it's now available directly through the Me property.
     
  26. Phoera

    Phoera Senior Engineer

    Messages:
    1,713
    done.
    also updated first post.
    all other looks like still usefull.
     
    • Agree Agree x 1
  27. Regn

    Regn Trainee Engineer

    Messages:
    74
    Snippet: SwitchOnOff
    Useful in power saving scripts as it also avoids redundant method calls. Creating static "on" and "off" strings limits character usage.
    PHP:
    // Power switch
    void SwitchOnOff(IMyFunctionalBlock bstring o) {
        if (
    == "OnOff_On") {
            if (!
    b.Enabledb.ApplyAction(o);
        } else if (
    == "OnOff_Off") {
            if (
    b.Enabledb.ApplyAction(o);
        }
    }
    Example usage:
    PHP:
    string on "OnOff_On";
    string off "OnOff_Off";
    // Assembler procedure
    void AssemblerProcedure(IMyTerminalBlock block) {
        if (
    block is IMyAssembler) {
            var 
    block as IMyAssembler;
            if (!
    b.IsQueueEmpty) {
                
    // Items in queue
                
    SwitchOnOff(bon);
            } else {
                
    // Avoid power drainage
                
    SwitchOnOff(boff);
            }
        }
    }
    --- Automerge ---
    Snippet: MergeInventories (function)
    Puts all the items found on the grid into a single comprehensive list.
    PHP:
    void MergeInventories(List<IMyTerminalBlockblocks, List<IMyInventoryItemitems) {
        foreach (var 
    block in blocks) {
            if (
    blockCubeGrid == Me.CubeGrid && block.InventoryCount 0) {
                for (
    int i 0<= (block.InventoryCount 1); i++) {
                    foreach (var 
    t in block.GetInventory(i).GetItems()) {
                        
    items.Add(t);
                    }
                }
            }
        }
    }
    Snippet: IngotDB (class), AddIngotsToDB (function)
    Establishes a database for counting ingot values. Beware that AddIngotsToDB counts as roughly 2000 instructions, and can be reduced by writing the list in manually, which in return takes up more characters.
    PHP:
    public class IngotDB {
        private 
    string name;
        private 
    string abbr;
        private 
    float val;
        private 
    float conversion;

        public 
    IngotDB(string namestring abbrfloat valfloat conversion) {
            
    this.name name;
            
    this.abbr abbr;
            
    this.val val;
            
    this.conversion conversion;
        }

        public 
    string Name {
            
    get { return name; }
            
    set name value; }
            }
        public 
    string Abbr {
            
    get { return abbr; }
            
    set abbr value; }
            }
        public 
    float Value {
            
    get { return val; }
            
    set val value; }
            }
        public 
    float Conversion {
            
    get { return conversion; }
            
    set conversion value; }
            }
        }

        
    void AddIngotsToDB(List<IngotDBl) {
            
    string[] names = { "Iron""Nickel""Cobalt""Magnesium""Silicon""Silver""Gold""Platinum""Uranium""Stone""Ice" };
            
    string[] abbrs = { "Fe""Ni""Co""Mg""Si""Ag""Au""Pt""U""Gravel""Ice" };
            
    float[] conversion = { 0.7f0.4f0.3f0.007f0.7f0.1f0.01f0.005f0.007f0.9f1f };
            for (
    int i 0names.Count<string>(); i++) {
                
    l.Add(new IngotDB(names[i], abbrs[i], 0conversion[i]));
            }
        }
    }
    Snippet: CountIngots (function)
    Counts ores and ingots as ingots.
    PHP:
    float CountIngots(IMyInventoryItem itemstring namefloat valuefloat conversion) {
        if (
    item.Content.SubtypeName == name) {
            var 
    item.Content.TypeId.ToString();
            if (
    i.Contains("_Ore")) {
                
    value value + ((float)item.Amount conversion);
            }
            if (
    i.Contains("_Ingot")) {
                
    value value + (float)item.Amount;
            }
        }
        return 
    value;
    }
    Example usage to setup blocks, items, and ingots:
    PHP:
    // Setup blocks
    var blocks = new List<IMyTerminalBlock>(); GridTerminalSystem.GetBlocksOfType(blocks);
    // Setup items
    var items = new List<IMyInventoryItem>(); MergeInventories(blocksitems);
    // Setup ingot database
    var ingots = new List<IngotDB>(); AddIngotsToDB(ingots);
    Example usage to calculate ingot values:
    PHP:
    foreach (var ingot in ingots) {
        foreach (var 
    item in items) {
            
    ingot.Value CountIngots(itemingot.Nameingot.Valueingot.Conversion);
        }
    }
    Example usage to retrieve ingot values and display on screen:
    PHP:
    foreach (var ingot in ingots) {
        
    myStringBuilder.AppendLine(ingot.Value.ToString("0.00"), " " ingot.Abbr);
    }
    Should print:
    Code:
    0.00 Fe
    0.00 Ni
    0.00 Co
    0.00 Mg
    0.00 Si
    0.00 Ag
    0.00 Au
    0.00 Pt
    0.00 U
    0.00 Gravel
    0.00 Ice
     
    Last edited: Aug 11, 2017
  28. krypt-lynx

    krypt-lynx Apprentice Engineer

    Messages:
    175
    • Like Like x 1
  29. Regn

    Regn Trainee Engineer

    Messages:
    74
    Snippet: PrintToScreen
    Should print to any LCD that has the specified tag in its CustomData. If you have for instance oxygen and hydrogen information in separate stringbuilders, you can make them appear in any order you want, on any screen you want, without causing a "can't find object" error. I modified this snippet a bit before posting it so if it has any errors that's probably why. It works the way it's written in my current script, though.
    PHP:
    void PrintToScreens() {
        List<
    IMyTextPanelscreens = new List<IMyTextPanel>();
        
    GridTerminalSystem.GetBlocksOfType(screens);
        foreach (
    IMyTextPanel screen in screens) {
            
    StringBuilder sb = new StringBuilder();
            
    string[] tags screen.CustomData.Split(';');
            
    bool print = false;
            foreach (
    string tag in tags) {
                
    tag.Trim();
                if (
    tag != "") {
                    
    tag.ToLower();
                    if (
    tag == "tag1"sb.Append(sb1); print = true;
                    if (
    tag == "tag2"sb.Append(sb2); print = true;
                    if (
    tag == "tag3"sb.Append(sb3); print = true;
                }
            }
            if (print) {
                
    screen.WritePublicText(sb);
                
    screen.ShowPublicTextOnScreen();
            }
        }
    }
     
  30. Regn

    Regn Trainee Engineer

    Messages:
    74
    Snippet: NewRegex + static decleration tip
    When many regular expressions are needed this method of declaring variables and using functions can drastically reduce number of characters written. As you can see, there's no need to write "System.Text.RegularExpressions.Regex" and "System.Text.RegularExpressions.Match" over and over again.
    PHP:
    System.Text.RegularExpressions.Regex regIdregPosXregPosYregPosZregElevregMinGregMaxG;
    System.Text.RegularExpressions.Match matchIdmatchPosXmatchPosYmatchPosZmatchElevmatchMinGmatchMaxG;

    System.Text.RegularExpressions.Regex NewRegex(string r){
        return new 
    System.Text.RegularExpressions.Regex(r);
    }

    // I use MatchCollection in my script, with lots of loops, TryParse and nonsense.
    // This is just to show why the method can be handy.
    public Program(){
        var 
    log lcd.GetPublicText();
        
    regId NewRegex(@"(?<=Id: {).*(?=} Pos)");
        
    regPosX NewRegex(@"(?<={X:)\d+.\d+(?= Y:\d+.\d+ Z:\d+.\d+})");
        
    regPosY NewRegex(@"(?<={X:\d+.\d+ Y:)\d+.\d+(?= Z:\d+.\d+})");
        
    regPosZ NewRegex(@"(?<=Y:\d+.\d+ Z:)\d+.\d+(?=} Elev)");
        
    regElev NewRegex(@"(?<=Elevation: {)\d+.\d+(?=} Min)");
        
    regMinG NewRegex(@"(?<=Min-gravity: {)\d+.\d+(?=} Max)");
        
    regMaxG NewRegex(@"(?<=Max-gravity: {)\d+.\d+(?=})");
        
    matchId regId.Matches(log);
        
    matchPosX regPosX.Match(log);
        
    matchPosY regPosY.Match(log);
        
    matchPosZ regPosZ.Match(log);
        
    matchElev regElev.Match(log);
        
    matchMinG regMinG.Match(log);
        
    matchMaxG regMaxG.Match(log);
    }
     
    Last edited: Aug 11, 2017
Thread Status:
This last post in this thread was made more than 31 days old.