Added authorize role attributes to AdminController where missing

--- JustPressPlay/JustPressPlay/Controllers/AdminController.cs
+++ JustPressPlay/JustPressPlay/Controllers/AdminController.cs
@@ -580,6 +580,7 @@
         /// </summary>
         /// <returns>GET: /Admin/ManageHighlights</returns>
         [HttpGet]
+        [Authorize(Roles = JPPConstants.Roles.HandleHighlightedAchievements + "," + JPPConstants.Roles.FullAdmin)]
         public ActionResult ManageHighlights()
         {
             ManageHighlightsViewModel model = ManageHighlightsViewModel.Populate();
@@ -587,6 +588,7 @@
         }

         [HttpPost]
+        [Authorize(Roles = JPPConstants.Roles.HandleHighlightedAchievements + "," + JPPConstants.Roles.FullAdmin)]
         public ActionResult ManageHighlights(ManageHighlightsViewModel model)
         {
             // TODO: implement editing
@@ -616,6 +618,7 @@
         /// </summary>
         /// <returns></returns>
         [HttpGet]
+        [Authorize(Roles = JPPConstants.Roles.ManageSiteSettings + "," + JPPConstants.Roles.FullAdmin)]
         public ActionResult ManageSiteSettings()
         {
             ManageSiteSettingsViewModel model = ManageSiteSettingsViewModel.Populate();
@@ -623,6 +626,7 @@
         }

         [HttpPost]
+        [Authorize(Roles = JPPConstants.Roles.ManageSiteSettings + "," + JPPConstants.Roles.FullAdmin)]
         public ActionResult ManageSiteSettings(ManageSiteSettingsViewModel model)
         {
             if (model.SiteLogo != null)
@@ -707,6 +711,7 @@
         #endregion

         [HttpGet]
+        [Authorize(Roles = JPPConstants.Roles.CreateEditNews + "," + JPPConstants.Roles.FullAdmin)]
         public ActionResult AddNewsItem()
         {
             AddNewsItemViewModel model = new AddNewsItemViewModel();
@@ -714,6 +719,7 @@
         }

         [HttpPost]
+        [Authorize(Roles = JPPConstants.Roles.CreateEditNews + "," + JPPConstants.Roles.FullAdmin)]
         public ActionResult AddNewsItem(AddNewsItemViewModel model)
         {
             model.CreatorID = WebSecurity.CurrentUserId;
@@ -734,8 +740,8 @@
             return View(model);
         }

-        // TODO: Add tags to all the funcs missing role requirements
         [HttpGet]
+        [Authorize(Roles = JPPConstants.Roles.CreateEditNews + "," + JPPConstants.Roles.FullAdmin)]
         public ActionResult EditNewsItem(int id)
         {
             EditNewsItemViewModel model = EditNewsItemViewModel.Populate(id);
@@ -743,6 +749,7 @@
         }

         [HttpPost]
+        [Authorize(Roles = JPPConstants.Roles.CreateEditNews + "," + JPPConstants.Roles.FullAdmin)]
         public ActionResult EditNewsItem(int id, EditNewsItemViewModel model)
         {
             if (ModelState.IsValid)
@@ -762,6 +769,7 @@
         }

         [HttpGet]
+        [Authorize(Roles = JPPConstants.Roles.CreateEditNews + "," + JPPConstants.Roles.FullAdmin)]
         public ActionResult EditNewsItemList()
         {
             EditNewsItemListViewModel model = EditNewsItemListViewModel.Populate();


load the textures

load the textures

--- ksp_plugin_adapter/ksp_plugin_adapter.cs
+++ ksp_plugin_adapter/ksp_plugin_adapter.cs
@@ -115,6 +115,8 @@
   private UnityEngine.Texture compass_navball_texture_;
   private UnityEngine.Texture inertial_navball_texture_;
   private UnityEngine.Texture barycentric_navball_texture_;
+  private UnityEngine.Texture body_direction_navball_texture_;
+  private UnityEngine.Texture surface_navball_texture_;
   private bool navball_changed_ = true;
   private FlightGlobals.SpeedDisplayModes previous_display_mode_;

@@ -353,6 +355,9 @@
     LoadTextureOrDie(out inertial_navball_texture_, "navball_inertial.png");
     LoadTextureOrDie(out barycentric_navball_texture_,
                      "navball_barycentric.png");
+    LoadTextureOrDie(out body_direction_navball_texture_,
+                     "navball_body_direction.png");
+    LoadTextureOrDie(out surface_navball_texture_, "navball_surface.png");

     if (unmodified_orbits_ == null) {
       unmodified_orbits_ = new Dictionary<CelestialBody, Orbit>();
@@ -575,8 +580,6 @@
         // Texture the ball.
         navball_changed_ = false;
         previous_display_mode_ = FlightGlobals.speedDisplayMode;
-        // TODO(egg): switch over all frame types and have more navball textures
-        // when more frames are available.
         if (FlightGlobals.speedDisplayMode !=
                 FlightGlobals.SpeedDisplayModes.Orbit ||
             !PluginRunning()) {
@@ -584,14 +587,16 @@
         } else {
           switch (plotting_frame_selector_.get().frame_type) {
             case ReferenceFrameSelector.FrameType.BODY_SURFACE:
-              set_navball_texture(compass_navball_texture_);
+              set_navball_texture(surface_navball_texture_);
               break;
             case ReferenceFrameSelector.FrameType.BODY_CENTRED_NON_ROTATING:
               set_navball_texture(inertial_navball_texture_);
               break;
             case ReferenceFrameSelector.FrameType.BARYCENTRIC_ROTATING:
+              set_navball_texture(barycentric_navball_texture_);
+              break;
             case ReferenceFrameSelector.FrameType.BODY_CENTRED_PARENT_DIRECTION:
-              set_navball_texture(barycentric_navball_texture_);
+              set_navball_texture(body_direction_navball_texture_);
               break;
           }
         }


will this work?

will this work?

--- ksp_plugin_adapter/ksp_plugin_adapter.cs
+++ ksp_plugin_adapter/ksp_plugin_adapter.cs
@@ -999,13 +999,11 @@
     }

     if (PluginRunning()) {
-      double universal_time = Planetarium.GetUniversalTime();
-
       plugin_.SetMainBody(
           (FlightGlobals.currentMainBody
                ?? FlightGlobals.GetHomeBody()).flightGlobalsIndex);

-      plugin_.ForgetAllHistoriesBefore(universal_time -
+      plugin_.ForgetAllHistoriesBefore(plugin_.CurrentTime() -
                                        history_lengths_[history_length_index_]);
       // TODO(egg): Set the degrees of freedom of the origin of |World| (by
       // toying with Krakensbane and FloatingOrigin) here.
@@ -1014,8 +1012,7 @@
       // the FashionablyLate callbacks, including ReportNonConservativeForces,
       // then the FlightIntegrator's FixedUpdate will run, then the Vessel's,
       // and eventually the physics simulation.
-      StartCoroutine(
-          AdvanceAndNudgeVesselsAfterPhysicsSimulation(universal_time));
+      StartCoroutine(WaitedForFixedUpdate());
     }
   }

@@ -1050,8 +1047,7 @@

   #endregion

-  private System.Collections.IEnumerator
-  AdvanceAndNudgeVesselsAfterPhysicsSimulation(double universal_time) {
+  private System.Collections.IEnumerator WaitedForFixedUpdate() {
     yield return new UnityEngine.WaitForFixedUpdate();

   try {
@@ -1334,7 +1330,7 @@
                          (XYZ)FlightGlobals.ActiveVessel.mainBody.position,
                      reference_part_id =
                          FlightGlobals.ActiveVessel.rootPart.flightID},
-          universal_time);
+          plugin_.CurrentTime());
       krakensbane.FrameVel = -(Vector3d)main_body_dof.p;
       Vector3d offset = (Vector3d)main_body_dof.q -
                         FlightGlobals.ActiveVessel.mainBody.position;


Update DefaultBuild.

Update DefaultBuild.

--- bootstrapping/DefaultBuild.cs
+++ bootstrapping/DefaultBuild.cs
@@ -3,10 +3,11 @@
 using Nuke.Common;
 using Nuke.Common.Tools.MSBuild;
 using Nuke.Core;
-using static Nuke.Common.IO.FileSystemTasks;
 using static Nuke.Common.Tools.DotNet.DotNetTasks;
 using static Nuke.Common.Tools.MSBuild.MSBuildTasks;
 using static Nuke.Common.Tools.NuGet.NuGetTasks;
+using static Nuke.Core.IO.FileSystemTasks;
+using static Nuke.Core.IO.PathConstruction;
 using static Nuke.Core.EnvironmentInfo;

 class DefaultBuild : GitHubBuild
@@ -19,7 +20,7 @@
             // Disabled for safety.
             .OnlyWhen(() => false)
             .Executes(() => DeleteDirectories(GlobDirectories(SolutionDirectory, "**/bin", "**/obj")))
-            .Executes(() => PrepareCleanDirectory(OutputDirectory));
+            .Executes(() => EnsureCleanDirectory(OutputDirectory));

     Target Restore => _ => _
             .DependsOn(Clean)


Improved some error messages

Improved some error messages

--- bridge/NumCIL/NumCIL/Shape.cs
+++ bridge/NumCIL/NumCIL/Shape.cs
@@ -85,9 +85,9 @@
             if (lengths == null)
                 throw new ArgumentNullException("dimensionsizes");
             if (lengths.LongLength <= 0 || lengths.Any(x => x <= 0))
-                throw new ArgumentOutOfRangeException("dimensionsizes");
+                throw new ArgumentOutOfRangeException("dimensionsizes", string.Format("The lengths have a zero size element: {0}", lengths));
             if (offset < 0)
-                throw new ArgumentOutOfRangeException("offset");
+                throw new ArgumentOutOfRangeException("offset", string.Format("The offset cannot be negative: {0}", offset));

             if (strides == null)
             {


Actually implemented random wallpapers

Actually implemented random wallpapers

Multiple wallpapers can be specified in the config file. The program
will pick a random wallpaper and use it.

--- Multiscreen-Wallpaper-Management/frmWallpaperManagement.cs
+++ Multiscreen-Wallpaper-Management/frmWallpaperManagement.cs
@@ -45,8 +45,11 @@
         const uint SPIF_UPDATEINIFILE = 0x01;
         string appPath = Path.GetDirectoryName(Application.ExecutablePath);

+        //USED TO SET WALLPAPER
         public void SetDWallpaper(string path)
         {
+
+            //Set wallpaper to image at given path
             SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, path, SPIF_UPDATEINIFILE);
         }

@@ -54,14 +57,20 @@
         {

             InitializeComponent();
+
+            //Add event to run when display settings change
             Microsoft.Win32.SystemEvents.DisplaySettingsChanged += new EventHandler(ScreenHandler);
         }

+        //RUNS WHEN DISPLAY SETTINGS CHANGE
         private void ScreenHandler(object sender, EventArgs e)
         {
+
+            //Generates the wallpaper and applies it
             loadWallpaper();
         }

+        //CALCULATE TOTAL WALLPAPER SIZE
         private void wallpaperTotalSize(ref int wallpaperTotalWidth, ref int wallpaperTotalHeight, configClass config)
         {
             foreach (var displayScreen in Screen.AllScreens)
@@ -80,22 +89,9 @@
                     }
                 }
             }
-
-
-            /*
-            foreach (var screen in Screen.AllScreens)
-            {
-                wallpaperTotalWidth = wallpaperTotalWidth + screen.Bounds.Width;
-
-                if (screen.Bounds.Height > wallpaperTotalHeight)
-                {
-                    wallpaperTotalHeight = screen.Bounds.Height;
-                }
-            }
-            */
-        }
-
-        //Gets the greatest common divisor of a and b
+        }
+
+        //GETS THE GREATEST COMMON DIVISOR OF A AND B
         static int GCD(int a, int b)
         {
             int Remainder;
@@ -108,20 +104,23 @@
             return a;
         }

+        //CLASS USED TO STORE SCREEN CONFIG
         public class configScreenClass
+        {
+            public string name { get; set; }
+            public List<string> wallpaper { get; set; }
+            public int padding_top { get; set; }
+        }
+
+        //CLASS USED TO STORE MISC CONFIG
+        public class configMiscClass
         {
             public string name { get; set; }
             public string wallpaper { get; set; }
             public int padding_top { get; set; }
         }

-        public class configMiscClass
-        {
-            public string name { get; set; }
-            public string wallpaper { get; set; }
-            public int padding_top { get; set; }
-        }
-
+        //CLASS USED TO STORE CONFIG
         public class configClass
         {
             public List<configScreenClass> screens { get; set; }
@@ -140,18 +139,16 @@
         //GENERATES THE WALLPAPER AND APPLIES IT
         private void loadWallpaper()
         {
-            int i;                          //Declare variable used for an index
-            int wallpaperTotalWidth = 0;    //Declare variable used for total wallpaper width
-            int wallpaperTotalHeight = 0;   //Declare variable used for total wallpaper height
-            string sJson = "";              //Declare variable used to store json from config
-
-            var config = new configClass();

             //If the config.json file exists
             if (File.Exists(Application.StartupPath + @"\config.json"))
             {
-                //Declare variable used to open config
-                StreamReader streamReaderJson;
+                int i;                          //Declare variable used for an index
+                int wallpaperTotalWidth = 0;    //Declare variable used for total wallpaper width
+                int wallpaperTotalHeight = 0;   //Declare variable used for total wallpaper height
+                string sJson = "";              //Declare variable used to store json from config
+                var config = new configClass(); //Declare variable used to store configuration
+                StreamReader streamReaderJson;  //Declare variable used to open config

                 //Read config
                 streamReaderJson = new StreamReader(Application.StartupPath + @"\config.json");
@@ -187,12 +184,16 @@
                 foreach (var screens in config.screens)
                 {

+                    Random randomNumber = new Random();                         //Declare variable used to generate random number for random wallpaper
+                    int wallpaperCount = screens.wallpaper.Count;               //Declare integer and store wallpaper count in it
+                    int wallpaperRandom = randomNumber.Next(0, wallpaperCount); //Generate a random number for random wallpaper
+
                     //If image file exists
-                    if (File.Exists(screens.wallpaper))
+                    if (File.Exists(screens.wallpaper[wallpaperRandom]))
                     {

                         //Store wallpaper image to variable
-                        imgwallpapers.Add(Image.FromFile(screens.wallpaper));
+                        imgwallpapers.Add(Image.FromFile(screens.wallpaper[wallpaperRandom]));
                     }

                     //Add one to index
@@ -279,7 +280,7 @@
         {

             //Make form invisible
-            Opacity = 0;
+            ////////////Opacity = 0;////////////////////////////////////////////////////////////////////////////////////////

             //Generates the wallpaper and applies it
             loadWallpaper();
@@ -290,8 +291,8 @@
         {

             //Make form invisible
-            Visible = false;
-            Opacity = 100;
+            ////////////Visible = false;////////////////////////////////////////////////////////////////////////////////////
+            ////////////Opacity = 100;//////////////////////////////////////////////////////////////////////////////////////
         }
     }
 }


Grid detection rewrite

Grid detection rewrite

--- BARABAS.cs
+++ BARABAS.cs
@@ -294,6 +294,8 @@
 List < IMyCubeGrid > local_grids = null;
 List < IMyCubeGrid > remote_base_grids = null;
 List < IMyCubeGrid > remote_ship_grids = null;
+Dictionary<IMyCubeGrid, GridData> remote_grid_data = null;
+GridData local_grid_data = null;

 // alert levels, in priority order
 const int RED_ALERT = 0;
@@ -420,6 +422,105 @@
   public int Index;
 }

+// data we store about a grid
+// technically, while we use this class to store data about grids, what we
+// really want is to have an instance of this class per grid collection, i.e.
+// all grids that are local to each other (connected by rotors or pistons)
+public class GridData {
+  public bool has_thrusters;
+  public bool has_wheels;
+  public bool has_welders;
+  public bool has_grinders;
+  public bool has_drills;
+  public bool override_ship;
+  public bool override_base;
+}
+
+// grid graph edge class, represents a connection point between two grids, noting
+// if this connection is via a connector (i.e. if it's an external grid connection)
+public class GridGraphEdge {
+  public GridGraphEdge(IMyCubeGrid src_in, IMyCubeGrid dst_in, bool connector_in) {
+    src = src_in;
+    dst = dst_in;
+    is_connector = connector_in;
+  }
+  public IMyCubeGrid src;
+  public IMyCubeGrid dst;
+  public bool is_connector;
+}
+
+// comparer for graph edges
+public class GridGraphEdgeComparer : IEqualityComparer<GridGraphEdge> {
+  public int GetHashCode(GridGraphEdge e) {
+    int hash = 13;
+    hash = (hash * 7) + (e.src.GetHashCode() * e.dst.GetHashCode());
+    hash = (hash * 7) + e.is_connector.GetHashCode();
+    return hash;
+  }
+  public bool Equals(GridGraphEdge e1, GridGraphEdge e2) {
+    if (e1.is_connector != e2.is_connector) {
+      return false;
+    }
+    if (e1.src == e2.src && e1.dst == e2.dst) {
+      return true;
+    }
+    if (e1.src == e2.dst && e1.dst == e2.src) {
+      return true;
+    }
+    return false;
+  }
+}
+
+// our grid graph
+public class GridGraph {
+  public GridGraph() {
+    edges = new HashSet<GridGraphEdge>(new GridGraphEdgeComparer());
+  }
+  // add an edge to the graph
+  public bool addEdge(IMyCubeGrid src, IMyCubeGrid dst, bool is_connector) {
+    var t = new GridGraphEdge(src, dst, is_connector);
+    // avoid adding the same edge twice
+    if (!edges.Contains(t)) {
+      edges.Add(t);
+      return true;
+    }
+    return false;
+  }
+  // get all grids that are local to source grid (i.e. all grids connected by
+  // rotors or pistons)
+  public List<IMyCubeGrid> getLocalGrids(IMyCubeGrid src) {
+    var grids = new List<IMyCubeGrid>();
+    var seen = new HashSet<IMyCubeGrid>();
+    grids.Add(src);
+    seen.Add(src);
+    foreach (var edge in edges) {
+      if (!edge.is_connector && seen.Contains(edge.src) && !seen.Contains(edge.dst)) {
+        grids.Add(edge.dst);
+        seen.Add(edge.dst);
+      }
+      if (!edge.is_connector && seen.Contains(edge.dst) && !seen.Contains(edge.src)) {
+        grids.Add(edge.src);
+        seen.Add(edge.src);
+      }
+    }
+    return grids;
+  }
+  // get all neighboring (connected by connectors) grid entry points
+  public List<GridGraphEdge> getGridConnections() {
+    var list = new List<GridGraphEdge>();
+
+    // now, go through the list and see if there are any connector edges
+    foreach (var edge in edges) {
+      if (!edge.is_connector) {
+        continue;
+      }
+      list.Add(edge);
+    }
+    return list;
+  }
+  HashSet<GridGraphEdge> edges;
+}
+
 // just have a method to indicate that this exception comes from BARABAS
 class BarabasException: Exception {
   public BarabasException(string msg, Program p): base("BARABAS: " + msg) {
@@ -454,21 +555,11 @@
   return false;
 }

-// this includes ALL local blocks, used for purposes of calculating max power consumption
-bool localGridDumbFilter(IMyTerminalBlock block) {
-  if (!(block as IMyCubeBlock).IsFunctional) {
+bool localGridFilter(IMyTerminalBlock block) {
+  if (excludeBlock(block)) {
     return false;
   }
   return getLocalGrids().Contains(block.CubeGrid);
-}
-bool localGridFilter(IMyTerminalBlock block) {
-  if (block.CustomName.StartsWith("X")) {
-    return false;
-  }
-  return getLocalGrids().Contains(block.CubeGrid);
-}
-bool pbGridDumbFilter(IMyTerminalBlock block) {
-  return block.CubeGrid == Me.CubeGrid;
 }
 /*
  * Difference between remoteGridFilter and remoteGridDumbFilter is that
@@ -483,13 +574,6 @@
   }
   return getRemoteGrids().Contains(block.CubeGrid);
 }
-// this filter is not supposed to be used in normal code
-bool remoteGridDumbFilter(IMyTerminalBlock block) {
-  if (excludeBlock(block)) {
-    return false;
-  }
-  return !getLocalGrids().Contains(block.CubeGrid);
-}
 // this filter only gets remote ships - used for tug mode
 bool shipFilter(IMyTerminalBlock block) {
   if (excludeBlock(block)) {
@@ -501,20 +585,6 @@
 /**
  * Grid and block functions
  */
-// template functions for filtering blocks
-public void filterBlocks < T > (List < IMyTerminalBlock > list, string name_filter = null, string definition_filter = null) {
-  for (int i = list.Count - 1; i >= 0; i--) {
-    var block = list[i];
-    if (!(block is T)) {
-      list.RemoveAt(i);
-    } else if (name_filter != null && block.CustomName != name_filter) {
-      list.RemoveAt(i);
-    } else if (definition_filter != null && !block.BlockDefinition.ToString().Contains(definition_filter)) {
-      list.RemoveAt(i);
-    }
-  }
-}
-
 public void filterLocalGrid < T > (List < IMyTerminalBlock > blocks) {
   var grids = getLocalGrids();
   for (int i = blocks.Count - 1; i >= 0; i--) {
@@ -528,17 +598,14 @@

 // remove null blocks from list
 HashSet<List<IMyTerminalBlock>> null_list;
-List<IMyTerminalBlock> removeNulls(List<IMyTerminalBlock> list, int invCount) {
-  if (invCount == 0) {
-    return list;
-  }
+List<IMyTerminalBlock> removeNulls(List<IMyTerminalBlock> list) {
   if (null_list.Contains(list)) {
     return list;
   }
   null_list.Add(list);
   for (int i = list.Count - 1; i >= 0; i--) {
    var block = list[i];
-   if (block.GetInventoryCount() != invCount) {
+   if (!block.IsFunctional) {
      blocks_to_alerts.Remove(block);
      list.RemoveAt(i);
    }
@@ -548,15 +615,6 @@

 IMySlimBlock slimBlock(IMyTerminalBlock block) {
   return block.CubeGrid.GetCubeBlock(block.Position);
-}
-
-IMyTerminalBlock findBlockById(IMyTerminalBlock block, List<IMyTerminalBlock> blocks) {
-  foreach (var cur in blocks) {
-    if (cur.ToString() == block.ToString()) {
-      return cur;
-    }
-  }
-  return null;
 }

 List<IMyTerminalBlock> randomSubset(List<IMyTerminalBlock> list, int limit) {
@@ -586,11 +644,10 @@
 // get local blocks
 List < IMyTerminalBlock > getBlocks(bool force_update = false) {
   if (local_blocks != null && !force_update) {
-    return local_blocks;
-  }
-  local_blocks = new List < IMyTerminalBlock > ();
-  GridTerminalSystem.GetBlocksOfType
-          < IMyTerminalBlock > (local_blocks, localGridFilter);
+    return removeNulls(local_blocks);
+  }
+  filterLocalGrid < IMyTerminalBlock > (local_blocks);
+
   bool alert = false;
   // check if we have unfinished blocks
   for (int i = local_blocks.Count - 1; i >= 0; i--) {
@@ -598,9 +655,6 @@
     if (!slimBlock(block).IsFullIntegrity) {
       alert = true;
       addBlockAlert(block, ALERT_DAMAGED);
-      if (!block.IsFunctional) {
-        local_blocks.RemoveAt(i);
-      }
     } else {
       removeBlockAlert(block, ALERT_DAMAGED);
     }
@@ -616,10 +670,9 @@

 List < IMyTerminalBlock > getReactors(bool force_update = false) {
   if (local_reactors != null && !force_update) {
-    return removeNulls(local_reactors, 1);
-  }
-  local_reactors = new List < IMyTerminalBlock > (getBlocks());
-  filterBlocks < IMyReactor > (local_reactors);
+    return removeNulls(local_reactors);
+  }
+  filterLocalGrid < IMyReactor > (local_reactors);
   foreach (var reactor in local_reactors) {
     var inv = reactor.GetInventory(0);
     if (inv.GetItems().Count > 1) {
@@ -631,10 +684,9 @@

 List < IMyTerminalBlock > getBatteries(bool force_update = false) {
   if (local_batteries != null && !force_update) {
-    return local_batteries;
-  }
-  local_batteries = new List < IMyTerminalBlock > (getBlocks());
-  filterBlocks < IMyBatteryBlock > (local_batteries);
+    return removeNulls(local_batteries);
+  }
+  filterLocalGrid < IMyBatteryBlock > (local_batteries);
   for (int i = local_batteries.Count - 1; i >= 0; i--) {
     if ((local_batteries[i] as IMyBatteryBlock).OnlyRecharge) {
       local_batteries.RemoveAt(i);
@@ -645,10 +697,9 @@

 List < IMyTerminalBlock > getStorage(bool force_update = false) {
   if (local_storage != null && !force_update) {
-    return removeNulls(local_storage, 1);
-  }
-  local_storage = new List < IMyTerminalBlock > (getBlocks());
-  filterBlocks < IMyCargoContainer > (local_storage);
+    return removeNulls(local_storage);
+  }
+  filterLocalGrid < IMyCargoContainer > (local_storage);
   foreach (var storage in local_storage) {
     var inv = storage.GetInventory(0);
     consolidate(inv);
@@ -662,11 +713,10 @@
     if (!null_list.Contains(local_refineries_subset)) {
       local_refineries_subset = randomSubset(local_refineries, 50);
     }
-    return removeNulls(local_refineries_subset, 2);
+    return removeNulls(local_refineries_subset);
   }
   refineries_clogged = false;
-  local_refineries = new List < IMyTerminalBlock > (getBlocks());
-  filterBlocks < IMyRefinery > (local_refineries, null, "LargeRefinery");
+  filterLocalGrid < IMyRefinery > (local_refineries);
   foreach (IMyRefinery refinery in local_refineries) {
     var input_inv = refinery.GetInventory(0);
     var output_inv = refinery.GetInventory(1);
@@ -692,11 +742,10 @@
     if (!null_list.Contains(local_arc_furnaces_subset)) {
       local_arc_furnaces_subset = randomSubset(local_arc_furnaces, 30);
     }
-    return removeNulls(local_arc_furnaces_subset, 2);
+    return removeNulls(local_arc_furnaces_subset);
   }
   arc_furnaces_clogged = false;
-  local_arc_furnaces = new List < IMyTerminalBlock > (getBlocks());
-  filterBlocks < IMyRefinery > (local_arc_furnaces, null, "Blast Furnace");
+  filterLocalGrid < IMyRefinery > (local_arc_furnaces);
   foreach (IMyRefinery furnace in local_arc_furnaces) {
     var input_inv = furnace.GetInventory(0);
     var output_inv = furnace.GetInventory(1);
@@ -725,16 +774,15 @@
     local_all_refineries.AddRange(getRefineries());
     local_all_refineries.AddRange(getArcFurnaces());
   }
-  return removeNulls(local_all_refineries, 2);
+  return removeNulls(local_all_refineries);
 }

 List < IMyTerminalBlock > getAssemblers(bool force_update = false) {
   if (local_assemblers != null && !force_update) {
-    return removeNulls(local_assemblers, 2);
+    return removeNulls(local_assemblers);
   }
   assemblers_clogged = false;
-  local_assemblers = new List < IMyTerminalBlock > (getBlocks());
-  filterBlocks < IMyAssembler > (local_assemblers);
+  filterLocalGrid < IMyAssembler > (local_assemblers);
   for (int i = local_assemblers.Count - 1; i >= 0; i--) {
     var block = local_assemblers[i] as IMyAssembler;
     if (block.DisassembleEnabled) {
@@ -764,10 +812,9 @@

 List < IMyTerminalBlock > getConnectors(bool force_update = false) {
   if (local_connectors != null && !force_update) {
-    return removeNulls(local_connectors, 1);
-  }
-  local_connectors = new List < IMyTerminalBlock > (getBlocks());
-  filterBlocks < IMyShipConnector > (local_connectors);
+    return removeNulls(local_connectors);
+  }
+  filterLocalGrid < IMyShipConnector > (local_connectors);
   foreach (IMyShipConnector connector in local_connectors) {
     consolidate(connector.GetInventory(0));
     // prepare the connector
@@ -785,54 +832,41 @@
 // get notification lights
 List < IMyTerminalBlock > getLights(bool force_update = false) {
   if (local_lights != null && !force_update) {
-    return local_lights;
+    return removeNulls(local_lights);
   }
   // find our group
   local_lights = new List < IMyTerminalBlock > ();
-  var groups = new List<IMyBlockGroup>();
-  GridTerminalSystem.GetBlockGroups(groups);
-  foreach (var group in groups) {
-    // skip groups we don't want
-    if (group.Name != "BARABAS Notify") {
-      continue;
-    }
-    group.GetBlocks(local_lights);
-
-    // we may find multiple Notify groups, as we may have a BARABAS-driven
-    // ships connected, so let's filter lights
-    filterLocalGrid < IMyLightingBlock > (local_lights);
-
-    break;
-  }
+  var group = GridTerminalSystem.GetBlockGroupWithName("BARABAS Notify");
+  if (group != null) {
+    group.GetBlocks(local_lights, localGridFilter);
+  }
+  filterLocalGrid < IMyLightingBlock > (local_lights);
   return local_lights;
 }

 // get status report text panels
 List < IMyTerminalBlock > getTextPanels(bool force_update = false) {
   if (local_text_panels != null && !force_update) {
-    return local_text_panels;
+    return removeNulls(local_text_panels);
   }
   // find our group
   local_text_panels = new List < IMyTerminalBlock > ();
-  var groups = new List<IMyBlockGroup>();
-  GridTerminalSystem.GetBlockGroups(groups);
-  foreach (var group in groups) {
-    // skip groups we don't want
-    if (group.Name != "BARABAS Notify") {
-      continue;
-    }
-    group.GetBlocks(local_text_panels);
-    // we may find multiple Status groups, as we may have a BARABAS-driven
-    // ships connected, so let's filter text panels
-    filterLocalGrid < IMyTextPanel > (local_text_panels);
-
-    // if the user accidentally included a config block into this group,
-    // notify him immediately
-    if (local_text_panels.Contains(getConfigBlock() as IMyTerminalBlock)) {
-      throw new BarabasException("Configuration text panel should not " +
-        "be part of BARABAS Notify group", this);
-    }
-    break;
+
+  var group = GridTerminalSystem.GetBlockGroupWithName("BARABAS Notify");
+
+  if (group != null) {
+    group.GetBlocks(local_text_panels, localGridFilter);
+  }
+
+  // we may find multiple Status groups, as we may have a BARABAS-driven
+  // ships connected, so let's filter text panels
+  filterLocalGrid < IMyTextPanel > (local_text_panels);
+
+  // if the user accidentally included a config block into this group,
+  // notify him immediately
+  if (local_text_panels.Contains(getConfigBlock() as IMyTerminalBlock)) {
+    throw new BarabasException("Configuration text panel should not " +
+      "be part of BARABAS Notify group", this);
   }
   return local_text_panels;
 }
@@ -840,17 +874,13 @@
 // get status report text panels
 List < IMyTerminalBlock > getAntennas(bool force_update = false) {
   if (local_text_panels != null && !force_update) {
-    return local_antennas;
+    return removeNulls(local_antennas);
   }
   // find our group
   local_antennas = new List < IMyTerminalBlock > ();
-  var groups = new List<IMyBlockGroup>();
-  GridTerminalSystem.GetBlockGroups(groups);
-  foreach (var group in groups) {
-    // skip groups we don't want
-    if (group.Name != "BARABAS Notify") {
-      continue;
-    }
+  var group = GridTerminalSystem.GetBlockGroupWithName("BARABAS Notify");
+
+  if (group != null) {
     var tmp_antennas = new List<IMyTerminalBlock>();
     var tmp_beacons = new List<IMyTerminalBlock>();
     var tmp_laser = new List<IMyTerminalBlock>();
@@ -868,17 +898,16 @@
     local_antennas.AddRange(tmp_beacons);
     local_antennas.AddRange(tmp_antennas);
     local_antennas.AddRange(tmp_laser);
-
-    break;
-  }
+  }
+
   return local_antennas;
 }

 List < IMyTerminalBlock > getDrills(bool force_update = false) {
   if (local_drills != null && !force_update) {
-    return removeNulls(local_drills, 1);
-  }
-  filterBlocks < IMyShipDrill > (local_drills);
+    return removeNulls(local_drills);
+  }
+  filterLocalGrid < IMyShipDrill > (local_drills);
   foreach (var drill in local_drills) {
     consolidate(drill.GetInventory(0));
   }
@@ -887,9 +916,9 @@

 List < IMyTerminalBlock > getGrinders(bool force_update = false) {
   if (local_grinders != null && !force_update) {
-    return removeNulls(local_grinders, 1);
-  }
-  filterBlocks < IMyShipGrinder > (local_grinders);
+    return removeNulls(local_grinders);
+  }
+  filterLocalGrid < IMyShipGrinder > (local_grinders);
   foreach (var grinder in local_grinders) {
     consolidate(grinder.GetInventory(0));
   }
@@ -897,101 +926,46 @@
 }

 List < IMyTerminalBlock > getWelders(bool force_update = false) {
-	if (local_welders != null && !force_update) {
-		return removeNulls(local_welders, 1);
-	}
-	local_welders = new List < IMyTerminalBlock > (getBlocks());
-	filterBlocks < IMyShipWelder > (local_welders);
-	foreach (var welder in local_welders) {
-		consolidate(welder.GetInventory(0));
-	}
-	return local_welders;
-}
-
-List<IMyTerminalBlock> getTanks(string type) {
-	var list = new List < IMyTerminalBlock > (getBlocks());
-	filterBlocks < IMyOxygenTank > (list, null, type);
-	return list;
+  if (local_welders != null && !force_update) {
+    return removeNulls(local_welders);
+  }
+  filterLocalGrid < IMyShipWelder > (local_welders);
+  foreach (var welder in local_welders) {
+    consolidate(welder.GetInventory(0));
+  }
+  return local_welders;
 }

 List < IMyTerminalBlock > getAirVents(bool force_update = false) {
   if (local_air_vents != null && !force_update) {
-    return local_air_vents;
-  }
-  local_air_vents = new List < IMyTerminalBlock > (getBlocks());
-  filterBlocks < IMyAirVent > (local_air_vents);
+    return removeNulls(local_air_vents);
+  }
+  filterLocalGrid < IMyAirVent > (local_air_vents);
   return local_air_vents;
 }

 List < IMyTerminalBlock > getOxygenTanks(bool force_update = false) {
-	if (local_oxygen_tanks != null && !force_update) {
-		return local_oxygen_tanks;
-	}
-	local_oxygen_tanks = getTanks("Oxygen");
-	// hydrogen tanks are counted as oxygen tanks here, so filter them out
-	for (int i = local_oxygen_tanks.Count - 1; i >= 0; i--) {
-		var block = local_oxygen_tanks[i];
-		if (block.BlockDefinition.ToString().Contains("Hydrogen")) {
-			local_oxygen_tanks.RemoveAt(i);
-		}
-	}
-	return local_oxygen_tanks;
+  if (local_oxygen_tanks != null && !force_update) {
+    return removeNulls(local_oxygen_tanks);
+  }
+  filterLocalGrid < IMyOxygenTank >(local_oxygen_tanks);
+  return local_oxygen_tanks;
 }

 List < IMyTerminalBlock > getHydrogenTanks(bool force_update = false) {
-	if (local_hydrogen_tanks != null && !force_update) {
-		return local_hydrogen_tanks;
-	}
-	local_hydrogen_tanks = getTanks("Hydrogen");
-	return local_hydrogen_tanks;
+  if (local_hydrogen_tanks != null && !force_update) {
+    return removeNulls(local_hydrogen_tanks);
+  }
+  filterLocalGrid < IMyOxygenTank >(local_hydrogen_tanks);
+  return local_hydrogen_tanks;
 }

 List < IMyTerminalBlock > getOxygenGenerators(bool force_update = false) {
-	if (local_oxygen_generators != null && !force_update) {
-		return removeNulls(local_oxygen_generators, 1);
-	}
-	local_oxygen_generators = new List < IMyTerminalBlock > (getBlocks());
-	filterBlocks < IMyOxygenGenerator > (local_oxygen_generators);
-	return local_oxygen_generators;
-}
-
-string getGridId(string val) {
-	var regex = new System.Text.RegularExpressions.Regex("\\{([\\dA-F]+)\\}");
-	var match = regex.Match(val);
-	if (!match.Success || !match.Groups[1].Success) {
-		throw new BarabasException("Unknown grid id format", this);
-	}
-	return match.Groups[1].Value;
-}
-
-void loadLocalGrids(List < IMyCubeGrid > grids) {
-	grids.Add(Me.CubeGrid);
-	if (Storage.Length > 0) {
-		var tentative_grids = new List < IMyCubeGrid > ();
-		var blocks = new List < IMyTerminalBlock > ();
-		string[] ids = Storage.Split(':');
-		GridTerminalSystem.GetBlocksOfType < IMyTerminalBlock > (blocks);
-		foreach (var block in blocks) {
-			var grid = block.CubeGrid;
-			if (!tentative_grids.Contains(grid)) {
-				tentative_grids.Add(grid);
-				// check if we know this grid
-				var str = getGridId(grid.ToString());
-				if (Array.IndexOf(ids, str) != -1) {
-					grids.Add(grid);
-				}
-			}
-		}
-	}
-}
-
-void saveLocalGrids(List < IMyCubeGrid > grids) {
-	StringBuilder sb = new StringBuilder();
-	foreach (var grid in grids) {
-		sb.Append(getGridId(grid.ToString()));
-		sb.Append(":");
-	}
-	Storage = sb.ToString();
+  if (local_oxygen_generators != null && !force_update) {
+    return removeNulls(local_oxygen_generators);
+  }
+  filterLocalGrid < IMyOxygenGenerator > (local_oxygen_generators);
+  return local_oxygen_generators;
 }

 IMyCubeGrid findGrid(Vector3D world_pos, IMyCubeGrid self, List<IMyCubeGrid> grids) {
@@ -1008,7 +982,15 @@
 }

 IMyCubeGrid getConnectedGrid(IMyShipConnector connector) {
-	return connector.IsConnected ? connector.OtherConnector.CubeGrid : null;
+  if (!connector.IsConnected) {
+    return null;
+  }
+  // skip connectors connecting to the same grid
+  var other = connector.OtherConnector;
+  if (other.CubeGrid == connector.CubeGrid) {
+    return null;
+  }
+  return other.CubeGrid;
 }

 IMyCubeGrid getConnectedGrid(IMyMotorBase rotor, List<IMyCubeGrid> grids) {
@@ -1043,177 +1025,220 @@

 // getting local grids is not trivial, we're basically doing some heuristics
 List < IMyCubeGrid > getLocalGrids(bool force_update = false) {
-	if (local_grids != null && !force_update) {
-		return local_grids;
-	}
-	var tentative_grids = new List < IMyCubeGrid > ();
-	tentative_grids.Add(Me.CubeGrid);
-
-	// get all connectors
-	List < IMyTerminalBlock > list = new List < IMyTerminalBlock > ();
-	GridTerminalSystem.GetBlocksOfType < IMyShipConnector > (list);
-	// assume any grid we will find is local, unless we encounter a locked
-	// connector, in which case we either don't update the list at all, or, if
-	// this is our first time, go with guaranteed-local grid only
-	foreach (IMyShipConnector connector in list) {
-		if (connector.IsConnected) {
-			// see if it's on the same grid
-			var other = connector.OtherConnector;
-			if (!local_grids.Contains(other.CubeGrid)) {
-				return local_grids;
-			}
-		}
-		if (!tentative_grids.Contains(connector.CubeGrid)) {
-			tentative_grids.Add(connector.CubeGrid);
-		}
-	}
-	var blocks = new List < IMyTerminalBlock > ();
-	GridTerminalSystem.GetBlocksOfType < IMyLightingBlock > (blocks);
-	foreach (var block in blocks) {
-		if (!tentative_grids.Contains(block.CubeGrid)) {
-			tentative_grids.Add(block.CubeGrid);
-		}
-	}
-	local_grids = tentative_grids;
-	return local_grids;
+  if (local_grids != null && !force_update) {
+    return local_grids;
+  }
+
+  // clear all lists
+  local_blocks = new List<IMyTerminalBlock>();
+  local_reactors = new List<IMyTerminalBlock>();
+  local_batteries = new List<IMyTerminalBlock>();
+  local_refineries = new List<IMyTerminalBlock>();
+  local_arc_furnaces = new List<IMyTerminalBlock>();
+  local_assemblers = new List<IMyTerminalBlock>();
+  local_connectors = new List<IMyTerminalBlock>();
+  local_storage = new List<IMyTerminalBlock>();
+  local_drills = new List<IMyTerminalBlock>();
+  local_grinders = new List<IMyTerminalBlock>();
+  local_welders = new List<IMyTerminalBlock>();
+  local_air_vents = new List<IMyTerminalBlock>();
+  local_oxygen_tanks = new List<IMyTerminalBlock>();
+  local_hydrogen_tanks = new List<IMyTerminalBlock>();
+  local_oxygen_generators = new List<IMyTerminalBlock>();
+  var pistons = new List<IMyTerminalBlock>();
+  var rotors = new List<IMyTerminalBlock>();
+
+  var tmp_grid_data = new Dictionary<IMyCubeGrid, GridData>();
+
+  GridTerminalSystem.GetBlocks(local_blocks);
+
+  foreach (var block in local_blocks) {
+    GridData data;
+    if (!tmp_grid_data.TryGetValue(block.CubeGrid, out data)) {
+      data = new GridData();
+      tmp_grid_data.Add(block.CubeGrid, data);
+    }
+
+    // fill all lists
+    if (block is IMyReactor) {
+      local_reactors.Add(block);
+    } else if (block is IMyBatteryBlock) {
+      local_batteries.Add(block);
+    } else if (block is IMyRefinery) {
+      if (block.BlockDefinition.ToString().Contains("LargeRefinery")) {
+        local_refineries.Add(block);
+      } else {
+        local_arc_furnaces.Add(block);
+      }
+    } else if (block is IMyAssembler) {
+      local_assemblers.Add(block);
+    } else if (block is IMyShipConnector) {
+      local_connectors.Add(block);
+    } else if (block is IMyCargoContainer) {
+      local_storage.Add(block);
+    } else if (block is IMyShipDrill) {
+      local_drills.Add(block);
+      data.has_drills = true;
+    } else if (block is IMyShipGrinder) {
+      local_grinders.Add(block);
+      data.has_grinders = true;
+    } else if (block is IMyShipWelder) {
+      local_welders.Add(block);
+      data.has_welders = true;
+    } else if (block is IMyAirVent) {
+      local_air_vents.Add(block);
+    } else if (block is IMyOxygenTank) {
+      if (block.BlockDefinition.ToString().Contains("Hydrogen")) {
+        local_hydrogen_tanks.Add(block);
+      } else {
+        local_oxygen_tanks.Add(block);
+      }
+    } else if (block is IMyOxygenGenerator) {
+      local_oxygen_generators.Add(block);
+    } else if (block is IMyPistonBase) {
+      pistons.Add(block);
+    } else if (block is IMyMotorBase) {
+      rotors.Add(block);
+    } else if (block is IMyMotorSuspension) {
+      data.has_wheels = true;
+    } else if (block is IMyThrust) {
+      data.has_thrusters = true;
+    } else if (block is IMyProgrammableBlock && block != Me && block.CubeGrid != Me.CubeGrid) {
+      if (block.CustomName == "BARABAS Ship CPU") {
+        data.override_ship = true;
+      } else if (block.CustomName == "BARABAS Base CPU") {
+        data.override_base = true;
+      }
+    }
+  }
+
+  // bool is
+  var graph = new GridGraph();
+  var grids = new List<IMyCubeGrid>(tmp_grid_data.Keys);
+
+  // first, go through all pistons
+  foreach (IMyPistonBase piston in pistons) {
+    var connected_grid = getConnectedGrid(piston, grids);
+
+    if (connected_grid != null) {
+      graph.addEdge(piston.CubeGrid, connected_grid, false).ToString();
+    }
+  }
+
+  // do the same for rotors
+  foreach (IMyMotorBase rotor in rotors) {
+    var connected_grid = getConnectedGrid(rotor, grids);
+
+    if (connected_grid != null) {
+      graph.addEdge(rotor.CubeGrid, connected_grid, false).ToString();
+    }
+  }
+
+  // do the same for connectors
+  foreach (IMyShipConnector connector in local_connectors) {
+    var connected_grid = getConnectedGrid(connector);
+
+    if (connected_grid != null) {
+      graph.addEdge(connector.CubeGrid, connected_grid, true).ToString();
+    }
+  }
+
+  // now, get our actual local grid
+  local_grids = new List<IMyCubeGrid>();
+  local_grids = graph.getLocalGrids(Me.CubeGrid);
+
+  // store our new local grid data
+  local_grid_data = new GridData();
+  foreach (var grid in local_grids) {
+    local_grid_data.has_wheels |= tmp_grid_data[grid].has_wheels;
+    local_grid_data.has_thrusters |= tmp_grid_data[grid].has_thrusters;
+    local_grid_data.has_drills |= tmp_grid_data[grid].has_drills;
+    local_grid_data.has_grinders |= tmp_grid_data[grid].has_grinders;
+    local_grid_data.has_welders |= tmp_grid_data[grid].has_welders;
+    local_grid_data.override_base |= tmp_grid_data[grid].override_base;
+    local_grid_data.override_ship |= tmp_grid_data[grid].override_ship;
+  }
+
+  var connections = graph.getGridConnections();
+  var seen = new HashSet<IMyCubeGrid>(local_grids);
+
+  Echo("seen: " + seen.Count);
+  Echo("connections: " + connections.Count);
+
+  remote_grid_data = new Dictionary<IMyCubeGrid, GridData>();
+
+  foreach (var e in connections) {
+    GridData data;
+    if (!seen.Contains(e.src)) {
+      var r_grids = graph.getLocalGrids(e.src);
+      if (!remote_grid_data.TryGetValue(e.src, out data)) {
+        data = new GridData();
+      }
+      foreach (var g in r_grids) {
+        data.has_wheels |= tmp_grid_data[g].has_wheels;
+        data.has_thrusters |= tmp_grid_data[g].has_thrusters;
+        data.has_drills |= tmp_grid_data[g].has_drills;
+        data.has_grinders |= tmp_grid_data[g].has_grinders;
+        data.has_welders |= tmp_grid_data[g].has_welders;
+        data.override_base |= tmp_grid_data[g].override_base;
+        data.override_ship |= tmp_grid_data[g].override_ship;
+        remote_grid_data.Add(g, data);
+        seen.Add(g);
+      }
+    }
+    if (!seen.Contains(e.dst)) {
+      var r_grids = graph.getLocalGrids(e.dst);
+      if (!remote_grid_data.TryGetValue(e.dst, out data)) {
+        data = new GridData();
+      }
+      foreach (var g in r_grids) {
+        data.has_wheels |= tmp_grid_data[g].has_wheels;
+        data.has_thrusters |= tmp_grid_data[g].has_thrusters;
+        data.override_base |= tmp_grid_data[g].override_base;
+        data.override_ship |= tmp_grid_data[g].override_ship;
+        remote_grid_data.Add(g, data);
+        seen.Add(g);
+      }
+    }
+  }
+
+  return local_grids;
 }

 // a process of getting remote grids comprises getting all non-local storage
 // containers and determining whether they are ship grids or base grids by checking
 // if there are thrusters on the same grid
 void findRemoteGrids() {
-	var base_grids = new List < IMyCubeGrid > ();
-	var ship_grids = new List < IMyCubeGrid > ();
-	var skip_grids = new List < IMyCubeGrid > ();
-
-	// first, get all remote storage
-	List < IMyTerminalBlock > list = new List < IMyTerminalBlock > ();
-	GridTerminalSystem.GetBlocksOfType < IMyCargoContainer > (list, remoteGridDumbFilter);
-
-	// reset all grids
-	if (list.Count == 0) {
-		remote_base_grids = new List < IMyCubeGrid > ();
-		remote_ship_grids = new List < IMyCubeGrid > ();
-		connected_to_base = false;
-		connected_to_ship = false;
-		connected = false;
-		return;
-	}
-
-	// find all remote thrusters
-	List < IMyTerminalBlock > thrusters = new List < IMyTerminalBlock > ();
-	List < IMyTerminalBlock > wheels = new List < IMyTerminalBlock > ();
-	List < IMyTerminalBlock > pb = new List < IMyTerminalBlock > ();
-	GridTerminalSystem.GetBlocksOfType < IMyThrust > (thrusters, remoteGridDumbFilter);
-	GridTerminalSystem.GetBlocksOfType < IMyMotorSuspension > (wheels, remoteGridDumbFilter);
-	GridTerminalSystem.GetBlocksOfType < IMyProgrammableBlock > (pb, remoteGridDumbFilter);
-
-	// find any thruster grids that also have storage on the same grid
-	foreach (var thruster in thrusters) {
-		var thruster_grid = thruster.CubeGrid;
-		bool found = false;
-		// if we already seen this grid, skip
-		if (skip_grids.Contains(thruster_grid) || ship_grids.Contains(thruster_grid)) {
-			continue;
-		}
-		for (int j = list.Count - 1; j >= 0; j--) {
-			var grid = list[j].CubeGrid;
-			if (thruster_grid == grid) {
-				// assume it's a ship
-				if (!ship_grids.Contains(thruster_grid)) {
-					ship_grids.Add(thruster_grid);
-				}
-				list.RemoveAt(j);
-				found = true;
-				// go on and see if any other block in the list is on the same grid
-			}
-		}
-		// we don't know what the hell it is
-		if (!found) {
-			skip_grids.Add(thruster_grid);
-		}
-	}
-	skip_grids.Clear();
-	foreach (var wheel in wheels) {
-		var wheel_grid = wheel.CubeGrid;
-		bool found = false;
-		// if we already seen this grid, skip
-		if (skip_grids.Contains(wheel_grid) || ship_grids.Contains(wheel_grid)) {
-			continue;
-		}
-		for (int j = list.Count - 1; j >= 0; j--) {
-			var grid = list[j].CubeGrid;
-			if (wheel_grid == grid) {
-				// assume it's a ship
-				if (!ship_grids.Contains(wheel_grid)) {
-					ship_grids.Add(wheel_grid);
-				}
-				list.RemoveAt(j);
-				found = true;
-				// go on and see if any other block in the list is on the same grid
-			}
-		}
-		// we don't know what the hell it is
-		if (!found) {
-			skip_grids.Add(wheel_grid);
-		}
-	}
-
-	// if we're a ship, anything that wasn't filtered out previously, is a base
-	// grid, otherwise assume it's a ship.
-	var add_list = isShipMode() ? base_grids : ship_grids;
-	foreach (var block in list) {
-		var grid = block.CubeGrid;
-		if (!add_list.Contains(grid)) {
-			add_list.Add(grid);
-		}
-	}
-
-	// now, override anything we've found if there are BARABAS instances on those grids
-	for (int i = base_grids.Count - 1; i >= 0; i--) {
-		var grid = base_grids[i];
-		// now go through programmable blocks
-		for (int j = 0; j < pb.Count; j++) {
-			var pb_grid = pb[j].CubeGrid;
-			if (pb_grid == grid) {
-				var name = pb[j].CustomName;
-				if (name == "BARABAS Ship CPU") {
-					ship_grids.Add(grid);
-					base_grids.RemoveAt(i);
-					break;
-				}
-			}
-		}
-	}
-	for (int i = ship_grids.Count - 1; i >= 0; i--) {
-		var grid = ship_grids[i];
-		// now go through programmable blocks
-		for (int j = 0; j < pb.Count; j++) {
-			var pb_grid = pb[j].CubeGrid;
-			if (pb_grid == grid) {
-				var name = pb[j].CustomName;
-				if (name == "BARABAS Base CPU") {
-					base_grids.Add(grid);
-					ship_grids.RemoveAt(i);
-					break;
-				}
-			}
-		}
-	}
-
-	// having multiple bases is not supported
-	if ((isBaseMode() && base_grids.Count != 0) || base_grids.Count > 1) {
-		throw new BarabasException("Connecting to multiple bases is not supported!", this);
-	}
-	remote_base_grids = base_grids;
-	remote_ship_grids = ship_grids;
-	connected_to_base = base_grids.Count > 0;
-	connected_to_ship = ship_grids.Count > 0;
-	connected = connected_to_base || connected_to_ship;
-}
-
-List < IMyCubeGrid > getBaseGrids() {
-  return remote_base_grids;
+  if (remote_grid_data.Count == 0) {
+    remote_base_grids = new List < IMyCubeGrid > ();
+    remote_ship_grids = new List < IMyCubeGrid > ();
+    connected_to_base = false;
+    connected_to_ship = false;
+    connected = false;
+    return;
+  }
+  var base_grids = new List < IMyCubeGrid > ();
+  var ship_grids = new List < IMyCubeGrid > ();
+
+  foreach (var pair in remote_grid_data) {
+    var grid = pair.Key;
+    var data = pair.Value;
+    if (data.override_ship) {
+      ship_grids.Add(grid);
+    } else if (data.override_base) {
+      base_grids.Add(grid);
+    }
+    // if we're a base, assume every other grid is a ship unless we're explicitly
+    // told that it's another base
+    if (data.has_thrusters || data.has_wheels || isBaseMode()) {
+      ship_grids.Add(grid);
+    }
+  }
+  remote_base_grids = base_grids;
+  remote_ship_grids = ship_grids;
+  connected_to_base = base_grids.Count > 0;
+  connected_to_ship = ship_grids.Count > 0;
+  connected = connected_to_base || connected_to_ship;
 }

 List < IMyCubeGrid > getShipGrids() {
@@ -1230,7 +1255,7 @@

 List < IMyTerminalBlock > getRemoteStorage(bool force_update = false) {
   if (remote_storage != null && !force_update) {
-    return removeNulls(remote_storage, 1);
+    return removeNulls(remote_storage);
   }
   remote_storage = new List < IMyTerminalBlock > ();
   GridTerminalSystem.GetBlocksOfType < IMyCargoContainer > (remote_storage, remoteGridFilter);
@@ -1242,7 +1267,7 @@

 List < IMyTerminalBlock > getRemoteShipStorage(bool force_update = false) {
   if (remote_ship_storage != null && !force_update) {
-    return removeNulls(remote_ship_storage, 1);
+    return removeNulls(remote_ship_storage);
   }
   remote_ship_storage = new List < IMyTerminalBlock > ();
   GridTerminalSystem.GetBlocksOfType < IMyCargoContainer > (remote_ship_storage, shipFilter);
@@ -1255,29 +1280,25 @@
 // get local trash disposal connector
 List<IMyTerminalBlock> getTrashConnectors(bool force_update = false) {
   if (local_trash_connectors != null && !force_update) {
-    return removeNulls(local_trash_connectors, 1);
+    return removeNulls(local_trash_connectors);
   }

   // find our group
   local_trash_connectors = new List < IMyTerminalBlock > ();
-  var groups = new List<IMyBlockGroup>();
-  GridTerminalSystem.GetBlockGroups(groups);
-  foreach (var group in groups) {
-    // skip groups we don't want
-    if (group.Name != "BARABAS Trash") {
-      continue;
-    }
+
+  var group = GridTerminalSystem.GetBlockGroupWithName("BARABAS Trash");
+
+  if (group != null) {
     group.GetBlocks(local_trash_connectors);
-
-    // we may find multiple Trash groups, as we may have a BARABAS-driven
-    // ships connected, so let's filter connectors
-    filterLocalGrid < IMyShipConnector > (local_trash_connectors);
-    break;
-  }
+  }
+
+  // we may find multiple Trash groups, as we may have a BARABAS-driven
+  // ships connected, so let's filter connectors
+  filterLocalGrid < IMyShipConnector > (local_trash_connectors);

   // backwards compatibility: add old-style trash connectors as well
-  var blocks = new List<IMyTerminalBlock>(getConnectors());
-  filterBlocks < IMyShipConnector > (blocks, "BARABAS Trash");
+  var blocks = new List<IMyTerminalBlock>();
+  GridTerminalSystem.SearchBlocksOfName("BARABAS Trash", blocks, localGridFilter);

   foreach (var block in blocks) {
     if (!local_trash_connectors.Contains(block)) {
@@ -1287,7 +1308,7 @@

   // if we still have no trash connectors, use the first one available
   if (local_trash_connectors.Count == 0 && getConnectors().Count > 0) {
-    local_trash_connectors.Add(local_connectors[0]);
+    local_trash_connectors.Add(getConnectors()[0]);
   }

   return local_trash_connectors;
@@ -1296,29 +1317,25 @@
 // get local trash disposal sensors
 List<IMyTerminalBlock> getTrashSensors(bool force_update = false) {
   if (local_trash_sensors != null && !force_update) {
-    return removeNulls(local_trash_sensors, 1);
+    return removeNulls(local_trash_sensors);
   }

   // find our group
   local_trash_sensors = new List < IMyTerminalBlock > ();
-  var groups = new List<IMyBlockGroup>();
-  GridTerminalSystem.GetBlockGroups(groups);
-  foreach (var group in groups) {
-    // skip groups we don't want
-    if (group.Name != "BARABAS Trash") {
-      continue;
-    }
+
+  var group = GridTerminalSystem.GetBlockGroupWithName("BARABAS Trash");
+
+  if (group != null) {
     group.GetBlocks(local_trash_sensors);
-
-    // we may find multiple Trash groups, as we may have a BARABAS-driven
-    // ships connected, so let's filter sensors
-    filterLocalGrid < IMySensorBlock > (local_trash_sensors);
-    break;
-  }
+  }
+
+  // we may find multiple Trash groups, as we may have a BARABAS-driven
+  // ships connected, so let's filter sensors
+  filterLocalGrid < IMySensorBlock > (local_trash_sensors);

   // backwards compatibility: add old-style BARABAS trash sensors as well
-  var blocks = new List<IMyTerminalBlock>(getBlocks());
-  filterBlocks < IMySensorBlock > (blocks, "BARABAS Trash Sensor");
+  var blocks = new List<IMyTerminalBlock>();
+  GridTerminalSystem.SearchBlocksOfName("BARABAS Trash Sensor", blocks, localGridFilter);

   foreach (var block in blocks) {
     if (!local_trash_sensors.Contains(block)) {
@@ -1331,17 +1348,21 @@

 IMyTextPanel getConfigBlock(bool force_update = false) {
   if (!force_update && config_block != null) {
+    if (!config_block.IsFunctional) {
+      return null;
+    }
     return config_block;
   }
-  var blocks = new List < IMyTerminalBlock> (getBlocks());
-  filterBlocks < IMyTextPanel > (blocks, "BARABAS Config");
+  var blocks = new List < IMyTerminalBlock > ();
+  GridTerminalSystem.SearchBlocksOfName("BARABAS Config", blocks, localGridFilter);
   if (blocks.Count < 1) {
     return null;
   } else if (blocks.Count > 1) {
     Echo("Multiple config blocks found.");
     if (config_block != null) {
       // find our previous config block, ignore the rest
-      config_block = findBlockById(config_block, blocks) as IMyTextPanel;
+      var id = config_block.EntityId;
+      config_block = GridTerminalSystem.GetBlockWithId(id) as IMyTextPanel;
     }
     if (config_block == null) {
       // if we didn't find our config block, just use the first one
@@ -2214,7 +2235,7 @@

   // go through all the blocks
   List < IMyTerminalBlock > blocks = new List < IMyTerminalBlock > ();
-  GridTerminalSystem.GetBlocksOfType < IMyTerminalBlock > (blocks, localGridDumbFilter);
+  GridTerminalSystem.GetBlocksOfType < IMyTerminalBlock > (blocks, localGridFilter);

   foreach (var block in blocks) {
     if (block is IMyReactor) {
@@ -2239,7 +2260,7 @@

   // go through all the blocks
   List < IMyTerminalBlock > blocks = new List < IMyTerminalBlock > ();
-  GridTerminalSystem.GetBlocksOfType < IMyTerminalBlock > (blocks, localGridDumbFilter);
+  GridTerminalSystem.GetBlocksOfType < IMyTerminalBlock > (blocks, localGridFilter);

   foreach (var block in blocks) {
     if (block is IMyBatteryBlock)
@@ -3240,23 +3261,18 @@

 // select operation mode
 void selectOperationMode() {
-  var list = new List < IMyTerminalBlock > ();
-  var wlist = new List < IMyTerminalBlock > ();
-  // get a list of local thrusters and wheels
-  GridTerminalSystem.GetBlocksOfType < IMyThrust > (list, localGridDumbFilter);
-  GridTerminalSystem.GetBlocksOfType < IMyMotorSuspension > (wlist, localGridDumbFilter);
   // if we found some thrusters or wheels, assume we're a ship
-  if (list.Count > 0 || wlist.Count > 0) {
+  if (local_grid_data.has_thrusters || local_grid_data.has_wheels) {
     // this is likely a drill ship
-    if (has_drills && !has_welders && !has_grinders) {
+    if (local_grid_data.has_drills && !local_grid_data.has_welders && !local_grid_data.has_grinders) {
       setMode(OP_MODE_DRILL);
     }
     // this is likely a welder ship
-    else if (has_welders && !has_drills && !has_grinders) {
+    else if (local_grid_data.has_welders && !local_grid_data.has_drills && !local_grid_data.has_grinders) {
       setMode(OP_MODE_WELDER);
     }
     // this is likely a grinder ship
-    else if (has_grinders && !has_drills && !has_welders) {
+    else if (local_grid_data.has_grinders && !local_grid_data.has_drills && !local_grid_data.has_welders) {
       setMode(OP_MODE_GRINDER);
     }
     // we don't know what the hell this is, so don't adjust the defaults
@@ -4414,11 +4430,6 @@
 int cur_cycle_count = 0;
 int cur_fn_count = 0;

-// saving state
-public void Save() {
-	saveLocalGrids(local_grids);
-}
-
 bool canContinue() {
   var prev_state = current_state == 0 ? states.Length - 1 : current_state - 1;
   var next_state = (current_state + 1) % states.Length;
@@ -4468,7 +4479,7 @@
 bool canRun() {
   bool isDisabled = Me.CustomName.Contains("DISABLED");
   var pbs = new List<IMyTerminalBlock>();
-  GridTerminalSystem.GetBlocksOfType < IMyProgrammableBlock > (pbs, pbGridDumbFilter);
+  GridTerminalSystem.GetBlocksOfType < IMyProgrammableBlock > (pbs, localGridFilter);

   foreach (var block in pbs) {
     if (block == Me) {
@@ -4485,6 +4496,13 @@
     }
   }
   return true;
+}
+
+public void Save() {
+  // save config block ID to storage
+  if (config_block != null) {
+    Storage = config_block.EntityId.ToString();
+  }
 }

 // constructor
@@ -4525,8 +4543,16 @@
   }

   // determine grid size
-  var id = Me.BlockDefinition.ToString();
-  large_grid = id.Contains("Large");
+  var bd = Me.BlockDefinition.ToString();
+  large_grid = bd.Contains("Large");
+
+  // find config block
+  if (Storage.Length > 0) {
+    long id;
+    if (long.TryParse(Storage, out id)) {
+      config_block = GridTerminalSystem.GetBlockWithId(id) as IMyTextPanel;
+    }
+  }
 }

 public void Main() {


Foreach loops everywhere!

Foreach loops everywhere!

--- BARABAS.cs
+++ BARABAS.cs
@@ -567,8 +567,8 @@
 	}
 	local_reactors = new List < IMyTerminalBlock > (getBlocks());
 	filterBlocks < IMyReactor > (local_reactors);
-	for (int i = 0; i < local_reactors.Count; i++) {
-		var inv = local_reactors[i].GetInventory(0);
+	foreach (var reactor in local_reactors) {
+		var inv = reactor.GetInventory(0);
 		if (inv.GetItems().Count > 1) {
 			consolidate(inv);
 		}
@@ -596,8 +596,8 @@
 	}
 	local_storage = new List < IMyTerminalBlock > (getBlocks());
 	filterBlocks < IMyCargoContainer > (local_storage);
-	for (int i = 0; i < local_storage.Count; i++) {
-		var inv = local_storage[i].GetInventory(0);
+	foreach (var storage in local_storage) {
+		var inv = storage.GetInventory(0);
 		consolidate(inv);
 	}
 	return local_storage;
@@ -610,8 +610,7 @@
 	refineries_clogged = false;
 	local_refineries = new List < IMyTerminalBlock > (getBlocks());
 	filterBlocks < IMyRefinery > (local_refineries, null, "LargeRefinery");
-	for (int i = 0; i < local_refineries.Count; i++) {
-		var refinery = local_refineries[i] as IMyRefinery;
+	foreach (IMyRefinery refinery in local_refineries) {
 		var input_inv = refinery.GetInventory(0);
 		var output_inv = refinery.GetInventory(1);
 		Decimal input_load = (Decimal) input_inv.CurrentVolume / (Decimal) input_inv.MaxVolume;
@@ -635,19 +634,18 @@
 	local_arc_furnaces = new List < IMyTerminalBlock > (getBlocks());
 	filterBlocks < IMyRefinery > (local_arc_furnaces, null, "Blast Furnace");
 	bool alert = false;
-	for (int i = 0; i < local_arc_furnaces.Count; i++) {
-		var refinery = local_arc_furnaces[i] as IMyRefinery;
-		var input_inv = refinery.GetInventory(0);
-		var output_inv = refinery.GetInventory(1);
+	foreach (IMyRefinery furnace in local_arc_furnaces) {
+		var input_inv = furnace.GetInventory(0);
+		var output_inv = furnace.GetInventory(1);
 		Decimal input_load = (Decimal) input_inv.CurrentVolume / (Decimal) input_inv.MaxVolume;
 		Decimal output_load = (Decimal) output_inv.CurrentVolume / (Decimal) output_inv.MaxVolume;
-		if (!refinery.IsQueueEmpty && !refinery.IsProducing) {
-			addBlockAlert(refinery, ALERT_CLOGGED);
+		if (!furnace.IsQueueEmpty && !furnace.IsProducing) {
+			addBlockAlert(furnace, ALERT_CLOGGED);
 			arc_furnaces_clogged = true;
 		} else {
-			removeBlockAlert(refinery, ALERT_CLOGGED);
-		}
-		displayBlockAlerts(refinery);
+			removeBlockAlert(furnace, ALERT_CLOGGED);
+		}
+		displayBlockAlerts(furnace);
 	}
 	return local_arc_furnaces;
 }
@@ -700,8 +698,8 @@
 	}
 	local_connectors = new List < IMyTerminalBlock > (getBlocks());
 	filterBlocks < IMyShipConnector > (local_connectors);
-	for (int i = 0; i < local_connectors.Count; i++) {
-		consolidate(local_connectors[i].GetInventory(0));
+	foreach (var connector in local_connectors) {
+		consolidate(connector.GetInventory(0));
 	}
 	return local_connectors;
 }
@@ -715,8 +713,7 @@
 	local_lights = new List < IMyTerminalBlock > ();
 	var groups = new List<IMyBlockGroup>();
 	GridTerminalSystem.GetBlockGroups(groups);
-	for (int i = 0; i < groups.Count; i++) {
-		var group = groups[i];
+	foreach (var group in groups) {
 		// skip groups we don't want
 		if (group.Name != "BARABAS Notify") {
 			continue;
@@ -742,8 +739,7 @@
 	local_text_panels = new List < IMyTerminalBlock > ();
 	var groups = new List<IMyBlockGroup>();
 	GridTerminalSystem.GetBlockGroups(groups);
-	for (int i = 0; i < groups.Count; i++) {
-		var group = groups[i];
+	foreach (var group in groups) {
 		// skip groups we don't want
 		if (group.Name != "BARABAS Notify") {
 			continue;
@@ -776,8 +772,7 @@
 	local_antennas = new List < IMyTerminalBlock > ();
 	var groups = new List<IMyBlockGroup>();
 	GridTerminalSystem.GetBlockGroups(groups);
-	for (int i = 0; i < groups.Count; i++) {
-		var group = groups[i];
+	foreach (var group in groups) {
 		// skip groups we don't want
 		if (group.Name != "BARABAS Notify") {
 			continue;
@@ -793,14 +788,14 @@
 		filterLocalGrid < IMyLaserAntenna > (tmp_laser);

 		// populate the list
-		for (int j = 0; j < tmp_beacons.Count; j++) {
-			local_antennas.Add(tmp_beacons[j]);
-		}
-		for (int j = 0; j < tmp_antennas.Count; j++) {
-			local_antennas.Add(tmp_antennas[j]);
-		}
-		for (int j = 0; j < tmp_laser.Count; j++) {
-			local_antennas.Add(tmp_laser[j]);
+		foreach (var beacon in tmp_beacons) {
+			local_antennas.Add(beacon);
+		}
+		foreach (var antenna in tmp_antennas) {
+			local_antennas.Add(antenna);
+		}
+		foreach (var laser in tmp_laser) {
+			local_antennas.Add(laser);
 		}
 		break;
 	}
@@ -813,8 +808,8 @@
 	}
 	local_drills = new List < IMyTerminalBlock > (getBlocks());
 	filterBlocks < IMyShipDrill > (local_drills);
-	for (int i = 0; i < local_drills.Count; i++) {
-		consolidate(local_drills[i].GetInventory(0));
+	foreach (var drill in local_drills) {
+		consolidate(drill.GetInventory(0));
 	}
 	return local_drills;
 }
@@ -825,8 +820,8 @@
 	}
 	local_grinders = new List < IMyTerminalBlock > (getBlocks());
 	filterBlocks < IMyShipGrinder > (local_grinders);
-	for (int i = 0; i < local_grinders.Count; i++) {
-		consolidate(local_grinders[i].GetInventory(0));
+	foreach (var grinder in local_grinders) {
+		consolidate(grinder.GetInventory(0));
 	}
 	return local_grinders;
 }
@@ -837,8 +832,8 @@
 	}
 	local_welders = new List < IMyTerminalBlock > (getBlocks());
 	filterBlocks < IMyShipWelder > (local_welders);
-	for (int i = 0; i < local_welders.Count; i++) {
-		consolidate(local_welders[i].GetInventory(0));
+	foreach (var welder in local_welders) {
+		consolidate(welder.GetInventory(0));
 	}
 	return local_welders;
 }
@@ -906,8 +901,8 @@
 		var blocks = new List < IMyTerminalBlock > ();
 		string[] ids = Storage.Split(':');
 		GridTerminalSystem.GetBlocksOfType < IMyTerminalBlock > (blocks);
-		for (int j = 0; j < blocks.Count; j++) {
-			var grid = blocks[j].CubeGrid;
+		foreach (var block in blocks) {
+			var grid = block.CubeGrid;
 			if (!tentative_grids.Contains(grid)) {
 				tentative_grids.Add(grid);
 				// check if we know this grid
@@ -922,8 +917,7 @@

 void saveLocalGrids(List < IMyCubeGrid > grids) {
 	StringBuilder sb = new StringBuilder();
-	for (int i = 0; i < grids.Count; i++) {
-		var grid = grids[i];
+	foreach (var grid in grids) {
 		sb.Append(getGridId(grid.ToString()));
 		sb.Append(":");
 	}
@@ -944,8 +938,7 @@
 	// assume any grid we will find is local, unless we encounter a locked
 	// connector, in which case we either don't update the list at all, or, if
 	// this is our first time, go with guaranteed-local grid only
-	for (int i = 0; i < list.Count; i++) {
-		var connector = list[i] as IMyShipConnector;
+	foreach (IMyShipConnector connector in list) {
 		if (connector.IsConnected) {
 			// see if it's on the same grid
 			var other = connector.OtherConnector;
@@ -958,8 +951,7 @@
 	}
 	var blocks = new List < IMyTerminalBlock > ();
 	GridTerminalSystem.GetBlocksOfType < IMyLightingBlock > (blocks);
-	for (int i = 0; i < blocks.Count; i++) {
-		var block = blocks[i];
+	foreach (var block in blocks) {
 		if (!tentative_grids.Contains(block.CubeGrid)) {
 			tentative_grids.Add(block.CubeGrid);
 		}
@@ -997,14 +989,14 @@
 	GridTerminalSystem.GetBlocksOfType < IMyProgrammableBlock > (pb, remoteGridDumbFilter);

 	// find any thruster grids that also have a connector or storage on the same grid
-	for (int i = 0; i < thrusters.Count; i++) {
-		var thruster_grid = thrusters[i].CubeGrid;
+	foreach (var thruster in thrusters) {
+		var thruster_grid = thruster.CubeGrid;
 		bool found = false;
 		// if we already seen this grid, skip
 		if (skip_grids.Contains(thruster_grid) || ship_grids.Contains(thruster_grid)) {
 			continue;
 		}
-		for (int j = 0; j < list.Count; j++) {
+		for (int j = list.Count - 1; j >= 0; j--) {
 			var grid = list[j].CubeGrid;
 			if (thruster_grid == grid) {
 				// assume it's a ship
@@ -1012,7 +1004,6 @@
 					ship_grids.Add(thruster_grid);
 				}
 				list.RemoveAt(j);
-				j--;
 				found = true;
 				// go on and see if any other block in the list is on the same grid
 			}
@@ -1025,10 +1016,10 @@

 	// anything that wasn't filtered out previously, is a base grid. at least
 	// we hope it is.
-	for (int i = 0; i < list.Count; i++) {
-		var grid = list[i].CubeGrid;
+	foreach (var block in list) {
+		var grid = block.CubeGrid;
 		if (!base_grids.Contains(grid)) {
-			base_grids.Add(list[i].CubeGrid);
+			base_grids.Add(grid);
 		}
 	}

@@ -1097,8 +1088,8 @@
 	}
 	remote_storage = new List < IMyTerminalBlock > ();
 	GridTerminalSystem.GetBlocksOfType < IMyCargoContainer > (remote_storage, remoteGridFilter);
-	for (int i = 0; i < remote_storage.Count; i++) {
-		consolidate(remote_storage[i].GetInventory(0));
+	foreach (var storage in remote_storage) {
+		consolidate(storage.GetInventory(0));
 	}
 	return remote_storage;
 }
@@ -1109,8 +1100,8 @@
 	}
 	remote_ship_storage = new List < IMyTerminalBlock > ();
 	GridTerminalSystem.GetBlocksOfType < IMyCargoContainer > (remote_ship_storage, shipFilter);
-	for (int i = 0; i < remote_ship_storage.Count; i++) {
-		consolidate(remote_ship_storage[i].GetInventory(0));
+	foreach (var storage in remote_ship_storage) {
+		consolidate(storage.GetInventory(0));
 	}
 	return remote_ship_storage;
 }
@@ -1200,8 +1191,7 @@
 List < ItemHelper > getAllInventories() {
 	List < ItemHelper > list = new List < ItemHelper > ();
 	var blocks = getBlocks();
-	for (int i = 0; i < blocks.Count; i++) {
-		var block = blocks[i];
+	foreach (var block in blocks) {
 		// skip blocks that don't have inventory
 		if ((block as IMyInventoryOwner) != null && !block.HasInventory()) {
 			continue;
@@ -1253,8 +1243,8 @@
 List < ItemHelper > getAllIngots(string name) {
 	List < ItemHelper > list = new List < ItemHelper > ();
 	var inventories = getAllInventories();
-	for (int i = 0; i < inventories.Count; i++) {
-		var inv = inventories[i].Inventory;
+	foreach (var item in inventories) {
+		var inv = item.Inventory;
 		getAllIngots(inv, name, list);
 	}
 	return list;
@@ -1264,8 +1254,8 @@
 List < ItemHelper > getAllOre(string name) {
 	List < ItemHelper > list = new List < ItemHelper > ();
 	var inventories = getAllInventories();
-	for (int a = 0; a < inventories.Count; a++) {
-		var inv = inventories[a].Inventory;
+	foreach (var entry in inventories) {
+		var inv = entry.Inventory;
 		var items = inv.GetItems();
 		for (int i = items.Count - 1; i >= 0; i--) {
 			var item = items[i];
@@ -1289,8 +1279,8 @@
 List < ItemHelper > getAllStorageIngots(string name = null) {
 	List < ItemHelper > list = new List < ItemHelper > ();
 	var blocks = getStorage();
-	for (int i = 0; i < blocks.Count; i++) {
-		var inv = blocks[i].GetInventory(0);
+	foreach (var block in blocks) {
+		var inv = block.GetInventory(0);
 		getAllIngots(inv, name, list);
 	}
 	return list;
@@ -1319,8 +1309,7 @@
 	var entries = new List < ItemHelper > ();
 	getAllIngots(inv, name, entries);
 	Decimal ingots = 0;
-	for (int i = 0; i < entries.Count; i++) {
-		var entry = entries[i];
+	foreach (var entry in entries) {
 		var item = entry.Item;
 		ingots += (Decimal) item.Amount;
 	}
@@ -1428,8 +1417,7 @@
 	Decimal cur_volume = 0M;
 	Decimal max_volume = 0M;
 	Decimal ratio;
-	for (int i = 0; i < storage.Count; i++) {
-		var container = storage[i] as IMyCargoContainer;
+	foreach (var container in storage) {
 		cur_volume += (Decimal) container.GetInventory(0).CurrentVolume;
 		max_volume += (Decimal) container.GetInventory(0).MaxVolume;
 	}
@@ -1453,8 +1441,8 @@
 		throw new BarabasException("Unknown mode");
 	}
 	Decimal maxLoad = 0M;
-	for (int i = 0; i < storage.Count; i++) {
-		var inv = storage[i].GetInventory(0);
+	foreach (var container in storage) {
+		var inv = container.GetInventory(0);
 		var load = (Decimal) inv.CurrentVolume / (Decimal) inv.MaxVolume;
 		if (load > maxLoad) {
 			maxLoad = load;
@@ -1472,8 +1460,7 @@
  storage = getStorage();

  Decimal cur_mass = 0M;
-	for (int i = 0; i < storage.Count; i++) {
-		var container = storage[i] as IMyCargoContainer;
+ foreach (var container in storage) {
 		cur_mass += (Decimal) container.GetInventory(0).CurrentMass;
 	}
 	bool isSpecialized = (op_mode & (OP_MODE_DRILL | OP_MODE_WELDER | OP_MODE_GRINDER)) != 0;
@@ -1490,8 +1477,8 @@
 	} else {
 		throw new BarabasException("Unknown mode");
 	}
-	for (int i = 0; i < storage.Count; i++) {
-		var inv = storage[i].GetInventory(0);
+	foreach (var container in storage) {
+		var inv = container.GetInventory(0);
 		cur_mass += (Decimal) inv.CurrentMass;
 	}
 	return cur_mass;
@@ -1519,11 +1506,11 @@
 	Dictionary < string, Decimal > ores = new Dictionary < string, Decimal > ();
 	var items = inv.GetItems();
 	bool seenCurrent = false;
-	for (int i = 0; i < items.Count; i++) {
-		var ore = items[i].Content.SubtypeName;
+	foreach (var item in items) {
+		var ore = item.Content.SubtypeName;
 		Decimal amount;
 		ores.TryGetValue(ore, out amount);
-		ores[ore] = amount + (Decimal) items[i].Amount;
+		ores[ore] = amount + (Decimal) item.Amount;
 		if (ore == name) {
 			seenCurrent = true;
 		}
@@ -1548,8 +1535,7 @@

 bool hasOnlyOre(IMyInventory inv) {
 	var items = inv.GetItems();
-	for (int i = 0; i < items.Count; i++) {
-		var item = items[i];
+	foreach (var item in items) {
 		if (!isOre(item)) {
 			return false;
 		}
@@ -1559,8 +1545,7 @@

 bool hasOnlyIngots(IMyInventory inv) {
 	var items = inv.GetItems();
-	for (int i = 0; i < items.Count; i++) {
-		var item = items[i];
+	foreach (var item in items) {
 		if (!isIngot(item)) {
 			return false;
 		}
@@ -1570,8 +1555,7 @@

 bool hasOnlyComponents(IMyInventory inv) {
 	var items = inv.GetItems();
-	for (int i = 0; i < items.Count; i++) {
-		var item = items[i];
+	foreach (var item in items) {
 		// we don't care about components specifically; rather, we care if it
 		// has ore or ingots
 		if (isOre(item) || isIngot(item)) {
@@ -1709,8 +1693,8 @@
 	 */

 	if (containers.Count < 3 || !sort_storage) {
-		for (int i = 0; i < containers.Count; i++) {
-			var container_inv = containers[i].GetInventory(0);
+		foreach (var storage in containers) {
+			var container_inv = storage.GetInventory(0);
 			// try pushing to this container
 			if (Transfer(src, container_inv, srcIndex, null, true, amount)) {
 				return true;
@@ -1814,8 +1798,8 @@
 // try pushing something to one of the remote storage containers
 bool pushToRemoteStorage(IMyInventory src, int srcIndex, Nullable < VRage.MyFixedPoint > amount) {
 	var containers = getRemoteStorage();
-	for (int i = 0; i < containers.Count; i++) {
-		var container_inv = containers[i].GetInventory(0);
+	foreach (var container in containers) {
+		var container_inv = container.GetInventory(0);
 		Decimal freeVolume = ((Decimal) container_inv.MaxVolume - (Decimal) container_inv.CurrentVolume) * 1000M;
 		if (freeVolume < 1M) {
 			continue;
@@ -1832,8 +1816,8 @@
 // try pushing something to one of the remote storage containers
 bool pushToRemoteShipStorage(IMyInventory src, int srcIndex, Nullable < VRage.MyFixedPoint > amount) {
 	var containers = getRemoteShipStorage();
-	for (int i = 0; i < containers.Count; i++) {
-		var container_inv = containers[i].GetInventory(0);
+	foreach (var container in containers) {
+		var container_inv = container.GetInventory(0);
 		// try pushing to this container
 		if (Transfer(src, container_inv, srcIndex, null, true, amount)) {
 			return true;
@@ -1844,8 +1828,7 @@

 void pushAllToRemoteStorage() {
 	var storage = getStorage();
-	for (int i = 0; i < storage.Count; i++) {
-		var container = storage[i];
+	foreach (var container in storage) {
 		var inv = container.GetInventory(0);
 		var items = inv.GetItems();
 		for (int j = items.Count - 1; j >= 0; j--) {
@@ -1868,8 +1851,7 @@

 void pullFromRemoteShipStorage() {
 	var storage = getRemoteShipStorage();
-	for (int i = 0; i < storage.Count; i++) {
-		var container = storage[i];
+	foreach (var container in storage) {
 		var inv = container.GetInventory(0);
 		var items = inv.GetItems();
 		for (int j = items.Count - 1; j >= 0; j--) {
@@ -1893,8 +1875,7 @@

 void pushToRemoteShipStorage() {
 	var storage = getStorage();
-	for (int i = 0; i < storage.Count; i++) {
-		var container = storage[i];
+	foreach (var container in storage) {
 		var inv = container.GetInventory(0);
 		var items = inv.GetItems();
 		for (int j = items.Count - 1; j >= 0; j--) {
@@ -1920,8 +1901,7 @@
 		return;
 	}
 	var storage = getRemoteStorage();
-	for (int i = 0; i < storage.Count; i++) {
-		var container = storage[i];
+	foreach (var container in storage) {
 		var inv = container.GetInventory(0);
 		var items = inv.GetItems();
 		for (int j = items.Count - 1; j >= 0; j--) {
@@ -1946,8 +1926,8 @@
 }

 void emptyBlocks(List < IMyTerminalBlock > blocks) {
-	for (int i = 0; i < blocks.Count; i++) {
-		var inv = blocks[i].GetInventory(0);
+	foreach (var block in blocks) {
+		var inv = block.GetInventory(0);
 		var items = inv.GetItems();
 		for (int j = items.Count - 1; j >= 0; j--) {
 			pushToStorage(inv, j, null);
@@ -1959,14 +1939,14 @@
 	var welders = getWelders();
 	int s_index = 0;

-	for (int i = 0; i < welders.Count; i++) {
-		Decimal cur_vol = (Decimal) welders[i].GetInventory(0).CurrentVolume * 1000M;
-		Decimal max_vol = (Decimal) welders[i].GetInventory(0).MaxVolume * 1000M;
+	foreach (var welder in welders) {
+		Decimal cur_vol = (Decimal) welder.GetInventory(0).CurrentVolume * 1000M;
+		Decimal max_vol = (Decimal) welder.GetInventory(0).MaxVolume * 1000M;
 		Decimal target_volume = max_vol - 400M - cur_vol;
 		if (target_volume <= 0) {
 			continue;
 		}
-		var dst_inv = welders[i].GetInventory(0);
+		var dst_inv = welder.GetInventory(0);
 		var storage = getStorage();
 		for (; s_index < storage.Count; s_index++) {
 			var container = storage[s_index];
@@ -2007,8 +1987,8 @@

 void pushOreToStorage() {
 	var refineries = getAllRefineries();
-	for (int i = 0; i < refineries.Count; i++) {
-		var inv = refineries[i].GetInventory(0);
+	foreach (var refinery in refineries) {
+		var inv = refinery.GetInventory(0);
 		for (int j = inv.GetItems().Count - 1; j >= 0; j--) {
 			pushToStorage(inv, j, null);
 		}
@@ -2025,8 +2005,8 @@

 	max_reactor_output = 0;
 	var reactors = getReactors();
-	for (int i = 0; i < reactors.Count; i++) {
-		max_reactor_output += (Decimal) (reactors[i] as IMyReactor).MaxOutput * 1000M;
+	foreach (IMyReactor reactor in reactors) {
+		max_reactor_output += (Decimal) reactor.MaxOutput * 1000M;
 	}

 	return max_reactor_output;
@@ -2039,9 +2019,9 @@

  cur_reactor_output = 0;
  var reactors = getReactors();
- for (int i = 0; i < reactors.Count; i++) {
-	 if (reactors[i].IsWorking)
-	 	cur_reactor_output += (Decimal) (reactors[i] as IMyReactor).MaxOutput * 1000M;
+ foreach (IMyReactor reactor in reactors) {
+	 if (reactor.IsWorking)
+	 	cur_reactor_output += (Decimal) reactor.MaxOutput * 1000M;
  }

  return cur_reactor_output;
@@ -2054,9 +2034,9 @@

  max_battery_output = 0;
  var batteries = getBatteries();
- for (int i = 0; i < batteries.Count; i++) {
-	 if ((batteries[i] as IMyBatteryBlock).HasCapacityRemaining)
-		 max_battery_output += getMaxOutput(batteries[i]);
+ foreach (IMyBatteryBlock battery in batteries) {
+	 if (battery.HasCapacityRemaining)
+		 max_battery_output += getMaxOutput(battery);
  }

  return max_battery_output;
@@ -2065,8 +2045,7 @@
 Decimal getBatteryStoredPower() {
 	var batteries = getBatteries();
 	Decimal stored_power = 0;
-	for (int i = 0; i < batteries.Count; i++) {
-		var battery = batteries[i] as IMyBatteryBlock;
+  foreach (IMyBatteryBlock battery in batteries) {
 		// unlike reactors, batteries' kWh are _actual_ kWh, not kWm
 		stored_power += (Decimal) battery.CurrentStoredPower * 1000M * 60M;
 	}
@@ -2091,8 +2070,7 @@
 	List < IMyTerminalBlock > blocks = new List < IMyTerminalBlock > ();
 	GridTerminalSystem.GetBlocksOfType < IMyTerminalBlock > (blocks, localGridDumbFilter);

-	for (int i = 0; i < blocks.Count; i++) {
-		var block = blocks[i];
+	foreach (var block in blocks) {
 		if (!(block is IMyBatteryBlock) && !(block is IMyReactor))
 			continue;
 		power_draw += getBlockPowerOutput(block);
@@ -2114,8 +2092,7 @@
 	List < IMyTerminalBlock > blocks = new List < IMyTerminalBlock > ();
 	GridTerminalSystem.GetBlocksOfType < IMyTerminalBlock > (blocks, localGridDumbFilter);

-	for (int i = 0; i < blocks.Count; i++) {
-		var block = blocks[i];
+	foreach (var block in blocks) {
 		if (block is IMyBatteryBlock)
 			continue;
 		// if this is a thruster
@@ -2286,8 +2263,7 @@
 	int s_index = 0;
 	// check if we can put some more uranium into reactors
 	var reactors = getReactors();
-	for (int i = 0; i < reactors.Count; i++) {
-		var reactor = reactors[i] as IMyReactor;
+	foreach (IMyReactor reactor in reactors) {
 		var rinv = reactor.GetInventory(0);
 		Decimal reactor_proportion = (Decimal) reactor.MaxOutput * 1000M / getMaxReactorPowerOutput();
 		Decimal reactor_power_draw = getMaxPowerDraw() * (reactor_proportion);
@@ -2350,8 +2326,7 @@

 void pushSpareUraniumToStorage() {
 	var reactors = getReactors();
-	for (int i = 0; i < reactors.Count; i++) {
-		var reactor = reactors[i] as IMyReactor;
+	foreach (IMyReactor reactor in reactors) {
 		var inv = reactor.GetInventory(0);
 		if (inv.GetItems().Count > 1) {
 			consolidate(inv);
@@ -2422,8 +2397,8 @@
 		List < ItemHelper > list = new List < ItemHelper > ();
 		var inv = getTrashConnector().GetInventory(0);
 		getAllItems(inv, list);
-		for (int i = 0; i < list.Count; i++) {
-			bool isStone = list[i].Item.Content.SubtypeName == STONE;
+		foreach (var item in list) {
+			bool isStone = item.Item.Content.SubtypeName == STONE;
 			if (!throw_out_stone || !isStone) {
 				return true;
 			}
@@ -2450,8 +2425,7 @@
 	Decimal target_amount = orig_target;

 	var entries = getAllOre(name);
-	for (int i = 0; i < entries.Count; i++) {
-		var entry = entries[i];
+	foreach (var entry in entries) {
 		var item = entry.Item;
 		var srcInv = entry.Inventory;
 		var index = entry.Index;
@@ -2488,8 +2462,8 @@
 void refineOre() {
 	bool alert = false;
 	var storage = getStorage();
-	for (int i = 0; i < storage.Count; i++) {
-		var inv = storage[i].GetInventory(0);
+	foreach (var s in storage) {
+		var inv = s.GetInventory(0);
 		var items = inv.GetItems();
 		for (int j = 0; j < items.Count; j++) {
 			List < IMyTerminalBlock > refineries;
@@ -2557,8 +2531,7 @@
 	if (prioritize_uranium && ore_status[URANIUM] > 0) {
 		low_wm_ore = URANIUM;
 	}
-	for (int o = 0; o < ore_types.Count; o++) {
-		var ore = ore_types[o];
+	foreach (var ore in ore_types) {
 		if (ore == ICE) {
 			continue;
 		}
@@ -2581,8 +2554,7 @@
 		var ore = low_wm_ore != null ? low_wm_ore : high_wm_ore;
 		List < IMyTerminalBlock > refineries;
 		refineries = getRefineries();
-		for (int i = 0; i < refineries.Count; i++) {
-			var refinery = refineries[i];
+		foreach (var refinery in refineries) {
 			var inv = refinery.GetInventory(0);
 			var items = inv.GetItems();
 			for (int j = 0; j < items.Count; j++) {
@@ -2602,8 +2574,7 @@
 		var ore = low_wm_arc_ore != null ? low_wm_arc_ore : high_wm_arc_ore;
 		List < IMyTerminalBlock > refineries;
 		refineries = getArcFurnaces();
-		for (int i = 0; i < refineries.Count; i++) {
-			var refinery = refineries[i];
+		foreach (var refinery in refineries) {
 			var inv = refinery.GetInventory(0);
 			var items = inv.GetItems();
 			for (int j = 0; j < items.Count; j++) {
@@ -2638,17 +2609,18 @@
 	Decimal minL = Decimal.MaxValue, maxL = 0, minAL = Decimal.MaxValue, maxAL = 0;

 	for (int i = 0; i < blocks.Count; i++) {
-		var inv = blocks[i].GetInventory(0);
+		var block = blocks[i];
+		var inv = block.GetInventory(0);
 		rebalance(inv);
 		Decimal arcload = 0M;
 		var items = inv.GetItems();
-		for (int j = 0; j < items.Count; j++) {
-			var name = items[j].Content.SubtypeName;
+		foreach (var item in items) {
+			var name = item.Content.SubtypeName;
 			if (name == SCRAP) {
 				name = IRON;
 			}
 			if (arc_furnace_ores.Contains(name)) {
-				arcload += (Decimal) items[j].Amount * VOLUME_ORE;
+				arcload += (Decimal) item.Amount * VOLUME_ORE;
 			}
 		}
 		Decimal load = (Decimal) inv.CurrentVolume * 1000M;
@@ -2792,8 +2764,7 @@
 string getBiggestOre() {
 	Decimal max = 0;
 	string name = "";
-	for (int i = 0; i < ore_types.Count; i++) {
-		var ore = ore_types[i];
+	foreach (var ore in ore_types) {
 		// skip uranium
 		if (ore == URANIUM) {
 			continue;
@@ -2813,8 +2784,7 @@

 bool refineriesClogged() {
 	var refineries = getAllRefineries();
-	for (int i = 0; i < refineries.Count; i++) {
-		var refinery = refineries[i] as IMyRefinery;
+	foreach (IMyRefinery refinery in refineries) {
 		if (refinery.IsQueueEmpty || refinery.IsProducing) {
 			return false;
 		}
@@ -2827,8 +2797,7 @@
  */
 void declogAssemblers() {
 	var assemblers = getAssemblers();
-	for (int i = 0; i < assemblers.Count; i++) {
-		var assembler = assemblers[i] as IMyAssembler;
+	foreach (IMyAssembler assembler in assemblers) {
 		var inv = assembler.GetInventory(0);

 		// empty assembler input if it's not doing anything
@@ -2854,8 +2823,7 @@

 void declogRefineries() {
 	var refineries = getAllRefineries();
-	for (int i = 0; i < refineries.Count; i++) {
-		var refinery = refineries[i] as IMyRefinery;
+	foreach (var refinery in refineries) {
 		var inv = refinery.GetInventory(1);
 		var items = inv.GetItems();
 		for (int j = items.Count - 1; j >= 0; j--) {
@@ -2918,17 +2886,16 @@
 void checkOxygenLeaks() {
 	var blocks = getAirVents();
 	bool alert = false;
-	for (int i = 0; i < blocks.Count; i++) {
-		var block = blocks[i] as IMyAirVent;
+	foreach (IMyAirVent vent in blocks) {
 		StringBuilder builder = new StringBuilder();
-		block.GetActionWithName("Depressurize").WriteValue(block, builder);
-		if (builder.ToString() == "Off" && !block.IsPressurized()) {
-			addBlockAlert(block, ALERT_OXYGEN_LEAK);
+		vent.GetActionWithName("Depressurize").WriteValue(vent, builder);
+		if (builder.ToString() == "Off" && !vent.IsPressurized()) {
+			addBlockAlert(vent, ALERT_OXYGEN_LEAK);
 			alert = true;
 		} else {
-			removeBlockAlert(block, ALERT_OXYGEN_LEAK);
-		}
-		displayBlockAlerts(block);
+			removeBlockAlert(vent, ALERT_OXYGEN_LEAK);
+		}
+		displayBlockAlerts(vent);
 	}
 	if (alert) {
 		addAlert(BROWN_ALERT);
@@ -3426,8 +3393,8 @@
 	// check if the text is empty
 	if (text.Trim().Length != 0) {
 		var lines = text.Split('\n');
-		for (int i = 0; i < lines.Length; i++) {
-			var line = lines[i].Trim();
+		foreach (var l in lines) {
+			var line = l.Trim();

 			// skip comments and empty lines
 			if (line.StartsWith("#") || line.Length == 0) {
@@ -3533,8 +3500,7 @@
 		return;
 	}
 	var antennas = getAntennas();
-	for (int i = 0; i < antennas.Count; i++) {
-		var antenna = antennas[i];
+	foreach (var antenna in antennas) {
 		displayBlockAlerts(antenna);
 	}
 }
@@ -3544,8 +3510,7 @@
 		return;
 	}
 	var antennas = getAntennas();
-	for (int i = 0; i < antennas.Count; i++) {
-		var antenna = antennas[i];
+	foreach (var antenna in antennas) {
 		addBlockAlert(antenna, id);
 	}
 }
@@ -3555,16 +3520,14 @@
 		return;
 	}
 	var antennas = getAntennas();
-	for (int i = 0; i < antennas.Count; i++) {
-		var antenna = antennas[i];
+	foreach (var antenna in antennas) {
 		removeBlockAlert(antenna, id);
 	}
 }

 void showAlertColor(Color c) {
 	var lights = getLights();
-	for (int i = 0; i < lights.Count; i++) {
-		var light = lights[i] as IMyLightingBlock;
+	foreach (IMyLightingBlock light in lights) {
 		if (light.GetValue < Color > ("Color").Equals(c) && light.Enabled) {
 			continue;
 		}
@@ -3577,8 +3540,7 @@

 void hideAlertColor() {
 	var lights = getLights();
-	for (int i = 0; i < lights.Count; i++) {
-		var light = lights[i] as IMyLightingBlock;
+	foreach (IMyLightingBlock light in lights) {
 		if (!light.Enabled) {
 			continue;
 		}
@@ -3589,8 +3551,7 @@
 void turnOffConveyors() {
 	var blocks = getBlocks();
 	// go through all blocks and set "use conveyor" to off
-	for (int i = 0; i < blocks.Count; i++) {
-		var block = blocks[i];
+	foreach (var block in blocks) {
 		if (block is IMyAssembler) {
 			continue;
 		}
@@ -3627,8 +3588,7 @@
 		}
 		panel_text += item.Key + ": " + item.Value + "\n";
 	}
-	for (int i = 0; i < panels.Count; i++) {
-		var panel = panels[i] as IMyTextPanel;
+	foreach (IMyTextPanel panel in panels) {
 		panel.WritePublicText(panel_text);
 		panel.WritePublicTitle("BARABAS Notify Report");
 		panel.ShowTextureOnScreen();
@@ -3932,20 +3892,18 @@
 void s_updateMaterialStats() {
 	Decimal uranium_in_reactors = 0;
 	// clear stats
-	for (int i = 0; i < ore_types.Count; i++) {
-		ore_status[ore_types[i]] = 0;
-		storage_ore_status[ore_types[i]] = 0;
-		ingot_status[ore_types[i]] = 0;
-		storage_ingot_status[ore_types[i]] = 0;
+	foreach (var ore in ore_types) {
+		ore_status[ore] = 0;
+		storage_ore_status[ore] = 0;
+		ingot_status[ore] = 0;
+		storage_ingot_status[ore] = 0;
 	}
 	var blocks = getBlocks();
-	for (int b = 0; b < blocks.Count; b++) {
-		var block = blocks[b];
+	foreach (var block in blocks) {
 		for (int i = 0; i < block.GetInventoryCount(); i++) {
 			var inv = block.GetInventory(i);
 			var items = inv.GetItems();
-			for (int j = 0; j < items.Count; j++) {
-				var item = items[j];
+			foreach (var item in items) {
 				bool isStorage = block is IMyCargoContainer;
 				bool isReactor = block is IMyReactor;
 				if (isOre(item)) {
@@ -3973,8 +3931,7 @@
 	}
 	bool alert = false;
 	StringBuilder sb = new StringBuilder();
-	for (int i = 0; i < ore_types.Count; i++) {
-		string ore = ore_types[i];
+	foreach (var ore in ore_types) {
 		Decimal total_ingots = 0;
 		Decimal total_ore = ore_status[ore];
 		Decimal total = 0;
@@ -4026,14 +3983,12 @@
 		Decimal oxy_cur = 0, oxy_total = 0;
 		Decimal hydro_cur = 0, hydro_total = 0;
 		var tanks = getOxygenTanks();
-		for (int i = 0; i < tanks.Count; i++) {
-			var tank = tanks[i] as IMyOxygenTank;
+		foreach (IMyOxygenTank tank in tanks) {
 			oxy_cur += (Decimal) tank.GetOxygenLevel();
 			oxy_total += 1M;
 		}
 		tanks = getHydrogenTanks();
-		for (int i = 0; i < tanks.Count; i++) {
-			var tank = tanks[i] as IMyOxygenTank;
+		foreach (IMyOxygenTank tank in tanks) {
 			hydro_cur += (Decimal) tank.GetOxygenLevel();
 			hydro_total += 1M;
 		}


Tag version 1.7-pre1

Tag version 1.7-pre1

--- BARABAS.cs
+++ BARABAS.cs
@@ -17,7 +17,7 @@
 #endif
         #endregion
         /*
-         * BARABAS v1.65c
+         * BARABAS v1.7-pre1
          *
          * (Burillo's Automatic Resource Administration for BAses and Ships)
          *
@@ -63,7 +63,7 @@
          *
          */

-        const string VERSION = "1.65c";
+        const string VERSION = "1.7-pre1";

         #region CONFIGVARS
         // configuration


Extend SphereCollider support

Extend SphereCollider support

Save PhysicsMaterial

--- Assets/Plugins/whydoidoit.com/Serialization/UnitySerializationExtensions.cs
+++ Assets/Plugins/whydoidoit.com/Serialization/UnitySerializationExtensions.cs
@@ -253,14 +253,14 @@
 [ComponentSerializerFor(typeof(SphereCollider))]
 public class SerializeSphereCollider : ComponentSerializerExtensionBase<SphereCollider> {
     public override IEnumerable<object> Save(SphereCollider target) {
-        return new object[] { target.isTrigger, target.radius, target.center.x, target.center.y, target.center.z, target.enabled };
+        return new object[] { target.isTrigger, target.radius, target.center.x, target.center.y, target.center.z, target.enabled, target.sharedMaterial };
     }
     public override void LoadInto(object[] data, SphereCollider instance) {
         instance.isTrigger = (bool)data[0];
         instance.radius = (float)data[1];
         instance.center = new Vector3((float)data[2], (float)data[3], (float)data[4]);
         instance.enabled = (bool)data[5];
-
+        instance.sharedMaterial = (PhysicMaterial)data[6];
     }
 }


Code Analysis and Documentation - 3 warnings left.

--- PcapDotNet/src/PcapDotNet.Packets/Transport/TcpDatagram.cs
+++ PcapDotNet/src/PcapDotNet.Packets/Transport/TcpDatagram.cs
@@ -54,6 +54,9 @@
             get { return ReadUInt(Offset.SequenceNumber, Endianity.Big); }
         }

+        /// <summary>
+        /// The sequence number of the data that will come after this data.
+        /// </summary>
         public uint NextSequenceNumber
         {
             get { return (uint)(SequenceNumber + PayloadLength); }
@@ -171,6 +174,9 @@
             get { return new Datagram(Buffer, StartOffset + HeaderLength, PayloadLength); }
         }

+        /// <summary>
+        /// The length of the TCP payload.
+        /// </summary>
         public int PayloadLength
         {
             get { return Length - HeaderLength; }


Grid内にマウスカーソルがあった場合にドライバを読み込めるように対応

Grid内にマウスカーソルがあった場合にドライバを読み込めるように対応

--- Project/RM.Friendly.WPFStandardControls.4.0/WPFDataGrid.cs
+++ Project/RM.Friendly.WPFStandardControls.4.0/WPFDataGrid.cs
@@ -341,6 +341,74 @@
 #endif
         [ItemDriverGetter(ActiveItemKeyProperty = "CurrentCell")]
         public WPFDataGridCell GetCell(int itemIndex, int col)
+        {
+            return new WPFDataGridCell(App.Type(typeof(WPFDataGrid)).GetCell(this, itemIndex, col));
+        }
+
+        static DataGridCell GetFeaturedCell(DataGrid grid)
+        {
+            if (grid.IsMouseOver)
+            {
+                grid.UpdateLayout();
+                for (var row = 0; row < grid.Items.Count; row++)
+                {
+                    DataGridRow rowInfo = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(row);
+                    if (!rowInfo.IsMouseOver)
+                    {
+                        continue;
+                    }
+                    for (var column = 0; column < grid.Columns.Count; column++)
+                    {
+                        DataGridCell cell = grid.Columns[column].GetCellContent(rowInfo).Parent as DataGridCell;
+                        if (!cell.IsMouseOver)
+                        {
+                            continue;
+                        }
+                        return cell;
+                    }
+                }
+            }
+
+            return null;
+        }
+
+#if ENG
+        /// <summary>
+        /// Featured Cell.
+        /// This is used when capturing with TestAssistant Pro.
+        /// </summary>
+#else
+        /// <summary>
+        /// 注目されたセル
+        /// TestAssistantProでのキャプチャ時に使われます。
+        /// </summary>
+#endif
+        public WPFDataGridCell FeaturedCell
+        {
+            get
+            {
+                AppVar cell = App.Type<WPFDataGrid>().GetFeaturedCell(this);
+                return cell.IsNull ? null : cell.Dynamic();
+            }
+        }
+
+#if ENG
+        /// <summary>
+        /// Get item's UserControlDriver.
+        /// </summary>
+        /// <param name="itemIndex">Item index.</param>
+        /// <param name="col">Item column No.</param>
+        /// <returns>UserControlDriver.</returns>
+#else
+        /// <summary>
+        /// 指定の位置のセルに割当たったUserControlDriverを取得
+        /// </summary>
+        /// <param name="itemIndex">アイテムインデックス。</param>
+        /// <param name="col">列。</param>
+        /// <returns>UserControlDriver</returns>
+#endif
+        [ItemDriverGetter(ActiveItemKeyProperty = "FeaturedCell")]
+        public WPFDataGridCell GetFeaturedCell(int itemIndex, int col)
         {
             return new WPFDataGridCell(App.Type(typeof(WPFDataGrid)).GetCell(this, itemIndex, col));
         }


112 - added lock to prevent send message overlap, but Dispose must change the state of the writer to prevent further oprations

--- SemanticDataSolution/DataManagement/ProducerAssociation.cs
+++ SemanticDataSolution/DataManagement/ProducerAssociation.cs
@@ -67,6 +67,8 @@
     #endregion

     #region private
+    private object mLockObject = new object();
+    bool m_Busy = false;
     protected override void InitializeCommunication()
     {
       //Do nothing;
@@ -89,8 +91,13 @@
     private IProducerBinding[] m_ProcessDataBindings;
     private void ProcessDataBindings_CollectionChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
     {
+      if (m_Busy)
+        return;
+      m_Busy = true;
       foreach (IMessageWriter _mwx in m_MessageWriter)
-        _mwx.Send(x => m_ProcessDataBindings[x], m_ProcessDataBindings.Length, UInt64.MaxValue, DataDescriptor);
+        lock (mLockObject)
+          _mwx.Send(x => m_ProcessDataBindings[x], m_ProcessDataBindings.Length, UInt64.MaxValue, DataDescriptor);
+      m_Busy = false;
     }
     #endregion


Fixed AjaxFileUpload CleanAllTemporaryData method

--- Server/AjaxControlToolkit/AjaxFileUpload/AjaxFileUpload.cs
+++ Server/AjaxControlToolkit/AjaxFileUpload/AjaxFileUpload.cs
@@ -286,7 +286,7 @@
         /// </summary>
         public void CleanAllTemporaryData()
         {
-            var dirInfo = new DirectoryInfo(Path.GetDirectoryName(_uploadedFilePath));
+            var dirInfo = new DirectoryInfo(BuildRootTempFolder());
             foreach (var dir in dirInfo.GetDirectories())
             {
                 dir.Delete(true);


move getting the length to play function

--- SimpleMusicPlayer/SimpleMusicPlayer/Common/PlayerEngine.cs
+++ SimpleMusicPlayer/SimpleMusicPlayer/Common/PlayerEngine.cs
@@ -46,7 +46,6 @@
     private void PlayTimerCallback(object sender, EventArgs e) {
       FMOD.RESULT result;
       uint ms = 0;
-      uint lenms = 0;
       bool playing = false;
       bool paused = false;

@@ -61,20 +60,14 @@
           this.ERRCHECK(result);
         }

-        result = this.sound.getLength(ref lenms, FMOD.TIMEUNIT.MS);
-        if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) {
-          this.ERRCHECK(result);
-        }
-
         result = this.channel.getPosition(ref ms, FMOD.TIMEUNIT.MS);
         if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) {
           this.ERRCHECK(result);
         }
       }

-      this.Length = TimeSpan.FromMilliseconds(lenms);
       this.CurrentPosition = TimeSpan.FromMilliseconds(ms);
-      this.RemainingPosition = TimeSpan.FromMilliseconds(lenms - ms);
+      this.RemainingPosition = TimeSpan.FromMilliseconds(Length.TotalMilliseconds - ms);

       //statusBar.Text = "Time " + (ms / 1000 / 60) + ":" + (ms / 1000 % 60) + ":" + (ms / 10 % 100) + "/" + (lenms / 1000 / 60) + ":" + (lenms / 1000 % 60) + ":" + (lenms / 10 % 100) + " : " + (paused ? "Paused " : playing ? "Playing" : "Stopped");

@@ -138,6 +131,11 @@

       var result = this.system.createSound(file.FullFileName, (FMOD.MODE._2D | FMOD.MODE.HARDWARE | FMOD.MODE.CREATESTREAM), ref this.sound);
       this.ERRCHECK(result);
+
+      uint lenms = 0;
+      result = this.sound.getLength(ref lenms, FMOD.TIMEUNIT.MS);
+      this.ERRCHECK(result);
+      this.Length = TimeSpan.FromMilliseconds(lenms);

       result = this.system.playSound(FMOD.CHANNELINDEX.FREE, this.sound, false, ref this.channel);
       this.ERRCHECK(result);


Green, now with breaking API changes

Green, now with breaking API changes


.Net gui batch updates

.Net gui batch updates

--- dotnet/gui/MainForm.cs
+++ dotnet/gui/MainForm.cs
@@ -276,9 +276,9 @@
                 while (client.NextRecord() && !cancelExecuteFlag)
                 {
                     dataset.ProcessRow(client);
-                    listView.VirtualListSize = dataset.RowCount;
-                    Application.DoEvents();
-                }
+                }
+                listView.VirtualListSize = dataset.RowCount;
+                Application.DoEvents();
             }
             if (client.Failed())
             {
@@ -323,7 +323,6 @@
                 if (i == 0)
                 {
                     item.Text = str;
-                    item.BackColor = cellBackColor;
                 }
                 else
                 {


Update inventory type and status mappings

--- api-example-csharp/Inventory.cs
+++ api-example-csharp/Inventory.cs
@@ -12,19 +12,19 @@

     public sealed class InventoryStatus
     {
-        public static string Active = "active";
-        public static string OnHold = "onhold";
-        public static string Inactive = "inactive";
+        public static string Active = 0;
+        public static string OnHold = 1;
+        public static string Inactive = 2;
     }

     public sealed class InventoryType
     {
-        public static string Normal = "normal";
-        public static string NonPhysical = "nonPhysical";
-        public static string Manufactured = "manufactured";
-        public static string Kitted = "kitted";
-        public static string RawMaterial = "rawMaterial";
+        public static string Normal = "N";
+        public static string NonPhysical = "V";
+        public static string Manufactured = "M";
+        public static string Kitted = "K";
+        public static string RawMaterial = "R";
     }

@@ -55,4 +55,4 @@
             }
         }
     }
-}+}