void Add(LightConfigurator settings, MyObjectBuilderType blockType, params string[] subtypes)
        {
            BlockHandling blockHandling;

            if (!monitorTypes.TryGetValue(blockType, out blockHandling))
            {
                blockHandling = new BlockHandling();
                monitorTypes.Add(blockType, blockHandling);
            }

            if (subtypes == null || subtypes.Length == 0)
            {
                blockHandling.ConfiguratorForAll = settings;
            }
            else
            {
                if (blockHandling.ConfiguratorPerSubtype == null)
                {
                    blockHandling.ConfiguratorPerSubtype = new Dictionary <string, LightConfigurator>();
                }

                foreach (var subtype in subtypes)
                {
                    if (blockHandling.ConfiguratorPerSubtype.ContainsKey(subtype))
                    {
                        SimpleLog.Error(this, $"Subtype '{subtype}' for type {blockType.ToString()} was already previously registered!");
                        continue;
                    }

                    blockHandling.ConfiguratorPerSubtype.Add(subtype, settings);
                }
            }
        }
        void FindLightDummies()
        {
            if (scannedForDummies || !Block.IsFunctional)
            {
                return; // only scan once and only if block is functional (has its main model)
            }
            var def = (MyCubeBlockDefinition)Block.SlimBlock.BlockDefinition;

            if (!def.Model.EndsWith(Block.Model.AssetName))
            {
                SimpleLog.Error(this, $"ERROR: block {Block.BlockDefinition.ToString()} is functional model is not the main one...\nBlock model='{Block.Model.AssetName}'\nDefinition model='{def.Model}'");
                return;
            }

            scannedForDummies = true;

            ScanSubparts(Block);

            if (lights == null)
            {
                SimpleLog.Error(this, $"{Block.BlockDefinition.ToString()} has no dummies with '{AttachedLightsSession.DUMMY_PREFIX}' prefix!");
            }
            else
            {
                if (inViewRange)
                {
                    SetLights(Block.IsWorking);
                }
            }
        }
        public override void UpdateAfterSimulation()
        {
            try
            {
                if (ViewDistanceChecks.Count > 0 && ++tick % CHECK_VIEW_DIST_EVERY_TICKS == 0)
                {
                    var cameraPos = MyAPIGateway.Session.Camera.WorldMatrix.Translation;

                    foreach (var action in ViewDistanceChecks.Values)
                    {
                        action(cameraPos);
                    }
                }

                if (UpdateOnce.Count > 0)
                {
                    foreach (var logic in UpdateOnce)
                    {
                        if (logic.Block.MarkedForClose)
                        {
                            continue;
                        }

                        logic.UpdateOnce();
                    }

                    UpdateOnce.Clear();
                }
            }
            catch (Exception e)
            {
                SimpleLog.Error(this, e);
            }
        }
        public override void LoadData()
        {
            try
            {
                if (MyAPIGateway.Utilities.IsDedicated) // DS side doesn't need lights
                {
                    return;
                }

                Instance           = this;
                UpdateOnce         = new List <BlockLogic>();
                monitorTypes       = new Dictionary <MyObjectBuilderType, BlockHandling>();
                blockLogics        = new Dictionary <long, BlockLogic>();
                ViewDistanceChecks = new Dictionary <long, Action <Vector3D> >();

                TempDummies = new Dictionary <string, IMyModelDummy>();

                MyAPIGateway.Entities.OnEntityAdd += EntitySpawned;

                SetUpdateOrder(MyUpdateOrder.AfterSimulation);

                Setup();
            }
            catch (Exception e)
            {
                SimpleLog.Error(this, e);
                UnloadData();
                throw;
            }
        }
        void CreateLogicFor(IMySlimBlock slimBlock, LightConfigurator settings)
        {
            var def = (MyCubeBlockDefinition)slimBlock.BlockDefinition;

            if (def.BlockTopology == MyBlockTopology.Cube && def.Model == null)
            {
                // deformable armor not supported.
                return;
            }

            var block = slimBlock.FatBlock;

            if (block == null)
            {
                SimpleLog.Error(this, $"{slimBlock.BlockDefinition.Id.ToString()} has no fatblock?! buildRatio={slimBlock.BuildLevelRatio.ToString()}; damageRatio={slimBlock.DamageRatio.ToString()}");
                return;
            }

            if (blockLogics.ContainsKey(block.EntityId))
            {
                BlockMarkedForClose(block);
            }

            var logic = new BlockLogic(this, block, settings);

            block.OnMarkForClose       += BlockMarkedForClose;
            blockLogics[block.EntityId] = logic;
        }
        void BlockAdded(IMySlimBlock slimBlock)
        {
            try
            {
                var           defId = slimBlock.BlockDefinition.Id;
                BlockHandling blockHandling;

                if (monitorTypes.TryGetValue(defId.TypeId, out blockHandling))
                {
                    LightConfigurator settings;

                    if (blockHandling.ConfiguratorPerSubtype != null && blockHandling.ConfiguratorPerSubtype.TryGetValue(defId.SubtypeName, out settings))
                    {
                        CreateLogicFor(slimBlock, settings);
                    }
                    else if (blockHandling.ConfiguratorForAll != null)
                    {
                        CreateLogicFor(slimBlock, blockHandling.ConfiguratorForAll);
                    }
                }
            }
            catch (Exception e)
            {
                SimpleLog.Error(this, e);
            }
        }
 void GridClosed(IMyEntity ent)
 {
     try
     {
         var grid = (IMyCubeGrid)ent;
         grid.OnBlockAdded -= BlockAdded;
         grid.OnClose      -= GridClosed;
     }
     catch (Exception e)
     {
         SimpleLog.Error(this, e);
     }
 }
        void BlockMarkedForClose(IMyEntity ent)
        {
            try
            {
                var block = (IMyCubeBlock)ent;
                block.OnMarkForClose -= BlockMarkedForClose;

                blockLogics.GetValueOrDefault(block.EntityId, null)?.Close();
                blockLogics.Remove(block.EntityId);
                ViewDistanceChecks.Remove(block.EntityId);
            }
            catch (Exception e)
            {
                SimpleLog.Error(this, e);
            }
        }
        void WorkingChanged(IMyCubeBlock block)
        {
            try
            {
                if (!inViewRange)
                {
                    return;
                }

                Session.UpdateOnce.Add(this); // update next frame
                SetLights(block.IsWorking);
            }
            catch (Exception e)
            {
                SimpleLog.Error(this, e);
            }
        }
        public void Close()
        {
            try
            {
                if (lights != null)
                {
                    foreach (var light in lights.Values)
                    {
                        MyLights.RemoveLight(light);
                    }

                    lights.Clear();
                }
            }
            catch (Exception e)
            {
                SimpleLog.Error(this, e);
            }
        }
        void EntitySpawned(IMyEntity ent)
        {
            try
            {
                var grid = ent as MyCubeGrid;

                if (grid == null || grid.Physics == null || grid.IsPreview)
                {
                    return;
                }

                grid.OnBlockAdded += BlockAdded;
                grid.OnClose      += GridClosed;

                foreach (IMySlimBlock slim in grid.GetBlocks())
                {
                    BlockAdded(slim);
                }
            }
            catch (Exception e)
            {
                SimpleLog.Error(this, e);
            }
        }