private void AddSectorEntities(MySectorObjectCounts asteroidCounts, MyMwcVector3Int sectorPosition, Random random, float entityMinimalSize, int maxEntityCount,  List<MySolarSystemMapEntity> entities, bool onlyStaticAsteroids)
        {
                      
            // Space around asteroid should be at least 1.2x - 2x it's size
            float asteroidSpacingCoeficient = 0.7f;

            // Asteroid count mean is 40%
            float asteroidCountMean = 0.4f;

            Dictionary<int, int> entityCounts = new Dictionary<int, int>();
            foreach (MySolarSystemEntityEnum t in Enum.GetValues(typeof(MySolarSystemEntityEnum)))
            {
                entityCounts.Add((int)t, 0);
            }

            MyDynamicAABBTree prunningStructure = new MyDynamicAABBTree(Vector3.Zero);

            foreach (BoundingSphere boundingSphere in m_safeAreas)
            {
                BoundingBox bb = BoundingBox.CreateFromSphere(boundingSphere);
                prunningStructure.AddProxy(ref bb, new Render.MyRenderObject(null, null), 0);
            }


            // Generate asteroids, check collisions (order asteroids by size)
            //var asteroids = GetAsteroids(asteroidCounts, entityMinimalSize);
            var asteroids = GetAsteroids(asteroidCounts, entityMinimalSize);

            foreach (var info in asteroids)
            {
                if (info.EntityType != MySolarSystemEntityEnum.StaticAsteroid && onlyStaticAsteroids)
                    continue;

                float radius = info.SizeInMeters / 2;
                float count = info.ObjectCount;
                float positionOffset = 1.3f;
                count = (float)Math.Round(count * random.Float(1 - asteroidCountMean, 1 + asteroidCountMean));

                if (info.EntityType == MySolarSystemEntityEnum.VoxelAsteroid)
                {
                    positionOffset = 0.6f; //generate voxels more in center
                }

                while (entityCounts[(int)info.EntityType] < count && entityCounts[(int)info.EntityType] < maxEntityCount)
                {
                    Vector3? pos = FindEntityPosition(prunningStructure, random, radius, positionOffset, asteroidSpacingCoeficient);

                    if (pos.HasValue)
                    {
                        MySolarSystemMapEntity entity = new MySolarSystemMapEntity(sectorPosition, pos.Value, info.SizeInMeters, info.EntityType.ToString(), info.EntityType);
                        entities.Add(entity);

                        if (!MySectorGenerator.IsOutsideSector(pos.Value, radius))
                        {
                            entityCounts[(int)info.EntityType]++;
                        }
                        
                        BoundingBox bb = new BoundingBox(pos.Value - new Vector3(radius), pos.Value + new Vector3(radius));
                        prunningStructure.AddProxy(ref bb, new Render.MyRenderObject(null, null), 0);
                    }
                    else
                        entityCounts[(int)info.EntityType]++;
                }
            }
        }
        private void GenerateBots(MySolarSystemMapSectorData sectorData, List<MyMwcObjectBuilder_Base> addToList, Random rnd, MyDynamicAABBTree prunningStructure)
        {
            int spawnPt = (int)(rnd.Float(0, 50) /** sectorData.AreaInfluenceMultiplier*/  );
            float radius = 100;
            for (int i = 0; i < spawnPt; i++)
            {
                Vector3? pos = FindEntityPosition(prunningStructure, rnd, radius, 0.8f, 0.8f);

                if (pos.HasValue)
                {
                    //MyMwcObjectBuilder_FactionEnum faction = MyMwcObjectBuilder_FactionEnum.None;
                    var faction = MyFactions.GetFactionBySector(sectorData.SectorPosition);

                    //var builder = new MyMwcObjectBuilder_;
                    MyMwcObjectBuilder_SpawnPoint spobj = MyMwcObjectBuilder_Base.CreateNewObject(MyMwcObjectBuilderTypeEnum.SpawnPoint, null) as MyMwcObjectBuilder_SpawnPoint;
                    spobj.BoundingRadius = radius;
                    spobj.RespawnTimer = 1;
                    spobj.SpawnCount = 5;
                    spobj.PositionAndOrientation.Position = pos.Value;
                    spobj.PositionAndOrientation.Forward = Vector3.Forward;
                    spobj.PositionAndOrientation.Up = Vector3.Up;
                    spobj.Faction = faction;

                    List<MyMwcObjectBuilder_SmallShip_Weapon> weapons = new List<MyMwcObjectBuilder_SmallShip_Weapon>();
                    List<MyMwcObjectBuilder_SmallShip_Ammo> ammo = new List<MyMwcObjectBuilder_SmallShip_Ammo>();
                    List<MyMwcObjectBuilder_AssignmentOfAmmo> assignments = new List<MyMwcObjectBuilder_AssignmentOfAmmo>();

                    weapons.Add(new MyMwcObjectBuilder_SmallShip_Weapon(MyMwcObjectBuilder_SmallShip_Weapon_TypesEnum.Autocanon));
                    weapons.Add(new MyMwcObjectBuilder_SmallShip_Weapon(MyMwcObjectBuilder_SmallShip_Weapon_TypesEnum.Autocanon));
                    weapons.Add(new MyMwcObjectBuilder_SmallShip_Weapon(MyMwcObjectBuilder_SmallShip_Weapon_TypesEnum.Cannon));
                    weapons.Add(new MyMwcObjectBuilder_SmallShip_Weapon(MyMwcObjectBuilder_SmallShip_Weapon_TypesEnum.Cannon));
                    weapons.Add(new MyMwcObjectBuilder_SmallShip_Weapon(MyMwcObjectBuilder_SmallShip_Weapon_TypesEnum.Shotgun));
                    weapons.Add(new MyMwcObjectBuilder_SmallShip_Weapon(MyMwcObjectBuilder_SmallShip_Weapon_TypesEnum.Drilling_Device_Crusher));
                    weapons.Add(new MyMwcObjectBuilder_SmallShip_Weapon(MyMwcObjectBuilder_SmallShip_Weapon_TypesEnum.Universal_Launcher_Front));
                    assignments.Add(new MyMwcObjectBuilder_AssignmentOfAmmo(MyMwcObjectBuilder_FireKeyEnum.Primary, MyMwcObjectBuilder_AmmoGroupEnum.Bullet, MyMwcObjectBuilder_SmallShip_Ammo_TypesEnum.Autocannon_Basic));
                    assignments.Add(new MyMwcObjectBuilder_AssignmentOfAmmo(MyMwcObjectBuilder_FireKeyEnum.Secondary, MyMwcObjectBuilder_AmmoGroupEnum.Cannon, MyMwcObjectBuilder_SmallShip_Ammo_TypesEnum.Cannon_Basic));

                    List<MyMwcObjectBuilder_InventoryItem> inventoryItems = new List<MyMwcObjectBuilder_InventoryItem>();
                    inventoryItems.Add(new MyMwcObjectBuilder_InventoryItem(new MyMwcObjectBuilder_SmallShip_Ammo(MyMwcObjectBuilder_SmallShip_Ammo_TypesEnum.Autocannon_Basic), 1000f));
                    inventoryItems.Add(new MyMwcObjectBuilder_InventoryItem(new MyMwcObjectBuilder_SmallShip_Ammo(MyMwcObjectBuilder_SmallShip_Ammo_TypesEnum.Cannon_Basic), 25));                

                    //spobj.m_shipTemplates.Add(
                    int numships = rnd.Next(1, 10);
                    for (int x = 0; x < numships; x++)
                    {
                        spobj.ShipTemplates.Add(
                            //new MyMwcObjectBuilder_SmallShip_Bot(
                            //    MyMwcObjectBuilder_SmallShip_TypesEnum.LIBERATOR,
                            //    weapons,
                            //    new MyMwcObjectBuilder_SmallShip_Engine(MyMwcObjectBuilder_SmallShip_Engine_TypesEnum.Chemical_1),
                            //    ammo,
                            //    assignments,
                            //    null,
                            //    faction
                            //    ) as MyMwcObjectBuilder_SmallShip_Bot
                            new MyMwcObjectBuilder_SmallShip_Bot(
                                MyMwcObjectBuilder_SmallShip_TypesEnum.LIBERATOR,
                                new MyMwcObjectBuilder_Inventory(inventoryItems, 32),
                                weapons,
                                new MyMwcObjectBuilder_SmallShip_Engine(MyMwcObjectBuilder_SmallShip_Engine_TypesEnum.Chemical_1),
                                assignments,
                                null,
                                null,
                                null,
                                MyGameplayConstants.HEALTH_RATIO_MAX,
                                100f,
                                float.MaxValue,
                                float.MaxValue,
                                true,
                                false,
                                faction,
                                MyAITemplateEnum.DEFAULT,
                                0,
                                1000,
                                1000,
                                MyPatrolMode.CYCLE,
                                null,
                                BotBehaviorType.IDLE,
                                MyLightsConstants.MAX_SPOTLIGHT_SHADOW_RANGE,
                                0, false, true) as MyMwcObjectBuilder_SmallShip_Bot
                            );
                    }

                    addToList.Add(spobj);

                    /*
                    MySolarSystemMapEntity entity = new MySolarSystemMapEntity(sectorData.SectorPosition, pos, size, "Asteroid", MySolarSystemEntityEnum.Asteroid);
                    sectorData.Entities.Add(entity);
                    */
                }
            }
        }
        public void GenerateSectorObjectBuildersFromSolarEntities(List<MySolarSystemMapEntity> entities, List<MyMwcObjectBuilder_Base> addToList, Random rnd, MyWeightDictionary<MyMwcVoxelMaterialsEnum> primaryMaterials, MyWeightDictionary<MyMwcVoxelMaterialsEnum> secondaryMaterials, MyStaticAsteroidTypeSetEnum staticAsteroidTypesets, MyMwcVoxelMaterialsEnum? fieldMaterial = null, MySolarSystemArea.AreaEnum? areaType = null)
        {
            List<MyMwcObjectBuilder_StaticAsteroid_TypesEnum> asteroids = new List<MyMwcObjectBuilder_StaticAsteroid_TypesEnum>(5);
            List<MyMwcVoxelFilesEnum> voxelAsteroids = new List<MyMwcVoxelFilesEnum>(10);

            int count = addToList.Count;

            foreach (var e in entities)
            {
                if (e.EntityType == MySolarSystemEntityEnum.VoxelAsteroid)
                {
                    int voxelAsteroidSize = FindAsteroidSize(e.Radius, MyVoxelMap.AsteroidSizes);

                    int rndIndex = rnd.Next(0, voxelAsteroids.Count);

                    MyVoxelMap.GetAsteroidsBySizeInMeters(voxelAsteroidSize, voxelAsteroids, false);

                    MyMwcObjectBuilder_VoxelMap builder = GenerateVoxelMap(voxelAsteroidSize, e.PositionInSector, rnd, voxelAsteroids, primaryMaterials, secondaryMaterials);

                    addToList.Add(builder);
                }
                else if (e.EntityType == MySolarSystemEntityEnum.StaticAsteroid)
                {
                    float radius = 100;
                    if (e.Radius == 10000)
                        radius = rnd.Next(2000, 11000);
                    if (e.Radius == 1000)
                        radius = rnd.Next(100, 1100);
                    if (e.Radius == 100)
                        radius = rnd.Next(10, 100);


                    MyMwcVoxelMaterialsEnum asteroidMaterial = MyMwcVoxelMaterialsEnum.Stone_01;
                    if (primaryMaterials.Count > 0)
                        primaryMaterials.GetRandomItem(rnd);

                    MyStaticAsteroidTypeSetEnum asteroidType = MyStaticAsteroidTypeSetEnum.A;

                    //for (int i = 0; i < 40000000; i++)
                    {
                        asteroidType = (MyStaticAsteroidTypeSetEnum)rnd.Item(Enum.GetValues(typeof(MyStaticAsteroidTypeSetEnum)));
                    }

                    if ((staticAsteroidTypesets & MyStaticAsteroidTypeSetEnum.A) == MyStaticAsteroidTypeSetEnum.A)
                        asteroidType = MyStaticAsteroidTypeSetEnum.A;
                    if ((staticAsteroidTypesets & MyStaticAsteroidTypeSetEnum.B) == MyStaticAsteroidTypeSetEnum.B)
                        asteroidType = MyStaticAsteroidTypeSetEnum.B;
                    if ((staticAsteroidTypesets & MyStaticAsteroidTypeSetEnum.All) == MyStaticAsteroidTypeSetEnum.All)
                        asteroidType = rnd.Float(0, 1) > 0.5f ? MyStaticAsteroidTypeSetEnum.A : MyStaticAsteroidTypeSetEnum.B;

                    var builder = GenerateStaticAsteroid(radius, asteroidType, asteroidMaterial, e.PositionInSector, rnd, asteroids);

  
                    builder.AsteroidMaterial1 = fieldMaterial;
                    if (areaType == MySolarSystemArea.AreaEnum.Sun)
                    {
                        builder.FieldDir = MinerWars.AppCode.Game.GUI.MyGuiScreenGamePlay.Static.GetDirectionToSunNormalized();
                    }

                    builder.Generated = true;
                    addToList.Add(builder);

                 
                    //MyEntity ent = MyEntities.CreateFromObjectBuilderAndAdd(null, new MyMwcObjectBuilder_StaticAsteroid(asteroids[rndIndex], mat),
                    //    Matrix.CreateWorld(e.PositionInSector, rnd.Vector(1), rnd.Vector(1)));
                }
                else if (e.EntityType == MySolarSystemEntityEnum.LargeShip)
                {
                    var shipType = rnd.Enum<MyMwcObjectBuilder_PrefabLargeShip_TypesEnum>();
                    MyMwcObjectBuilder_Prefab_AppearanceEnum appearance = rnd.Enum<MyMwcObjectBuilder_Prefab_AppearanceEnum>();

                    var ship = new MyMwcObjectBuilder_PrefabLargeShip(shipType, appearance, new MyMwcVector3Short(0, 0, 0), rnd.Vector(1), null, rnd.FloatNormal(), "Abandoned large ship", 0, false, 0);                    
                    var gamePlayProperties = MyGameplayConstants.GetGameplayProperties(MyMwcObjectBuilderTypeEnum.PrefabLargeShip, (int)shipType, MyMwcObjectBuilder_FactionEnum.Euroamerican);
                    ship.PrefabHealthRatio = MyGameplayConstants.HEALTH_RATIO_MAX;
                    ship.PrefabMaxHealth = gamePlayProperties.MaxHealth;
                    var prefabs = new List<MyMwcObjectBuilder_PrefabBase>();
                    prefabs.Add(ship);
                    var container = new MyMwcObjectBuilder_PrefabContainer(0, MyMwcObjectBuilder_PrefabContainer_TypesEnum.INSTANCE, prefabs, 0, rnd.Enum<MyMwcObjectBuilder_FactionEnum>(), null);
                    container.PositionAndOrientation = new MyMwcPositionAndOrientation(e.PositionInSector, Vector3.Forward, Vector3.Up);
                    addToList.Add(container);
                }
                else if (e.EntityType == MySolarSystemEntityEnum.DebrisField)
                {
                    MyMwcObjectBuilder_LargeDebrisField objectBuilder = new MyMwcObjectBuilder_LargeDebrisField(MyMwcObjectBuilder_LargeDebrisField_TypesEnum.Debris84);
                    objectBuilder.PositionAndOrientation = new MyMwcPositionAndOrientation(e.PositionInSector, rnd.Vector(1), rnd.Vector(1));
                    addToList.Add(objectBuilder);
                }
            }
        }
        private void GenerateStations(MyMwcVector3Int sector, MySolarSystemMapData solarData, MySolarSystemMapSectorData sectorData, List<MyMwcObjectBuilder_Base> addToList, Random rnd, MyDynamicAABBTree prunningStructure)
        {
            Dictionary<MyMwcVector3Int, MyMwcObjectBuilder_SectorObjectGroups> groupCache = new Dictionary<MyMwcVector3Int, MyMwcObjectBuilder_SectorObjectGroups>();

            //List<MyImportantSolarObject>
            var objects = solarData.ImportantObjects.Where(o => o.NavigationMark.Sector.Equals(sector));

            foreach(var obj in objects)
            {
                var size = MyPrefabContainerConstants.MAX_DISTANCE_FROM_CONTAINER_CENTER / 1000;
                Vector3? pos = FindEntityPosition(prunningStructure, rnd, size);
                if (pos.HasValue)
                {
                    var templateSector = MyTemplateGroups.GetGroupSector(obj.TemplateGroup);
                    MyMwcObjectBuilder_SectorObjectGroups groups;
                    if (!groupCache.TryGetValue(templateSector, out groups))
                    {
                        groups = LoadObjectGroups(templateSector);
                        if (groups == null)
                        {
                            return;
                        }
                        groupCache.Add(templateSector, groups);
                    }

                    sectorData.Entities.Add(new MySolarSystemMapEntity(sector, pos.Value, size, "", MySolarSystemEntityEnum.OutpostIcon));

                    var group = rnd.Item(groups.Groups);
                    IEnumerable<MyMwcObjectBuilder_PrefabBase> prefabs = group.GetPrefabBuilders(groups.Entities);
                    IEnumerable<MyMwcObjectBuilder_Base> rootObjects = group.GetRootBuilders(groups.Entities);
                    var objects3d = rootObjects.OfType<MyMwcObjectBuilder_Object3dBase>();

                    var faction = MyFactions.GetFactionBySector(sector);

                    var objectPos = pos.Value;
                    if (objects3d.Any())
                    {
                        var firstPos = objects3d.First().PositionAndOrientation.Position;
                        var offset = objectPos - firstPos;

                        foreach (var o in objects3d)
                        {
                            // Clone
                            var clone = o.Clone() as MyMwcObjectBuilder_Object3dBase;
                            clone.PositionAndOrientation.Position += offset;
                            clone.ClearEntityId();
                            if (clone is MyMwcObjectBuilder_PrefabContainer)
                            {
                                ((MyMwcObjectBuilder_PrefabContainer)clone).Faction = faction;
                            }
                            if (clone is MyMwcObjectBuilder_SpawnPoint)
                            {
                                ((MyMwcObjectBuilder_SpawnPoint)clone).Faction = faction;
                            }
                            addToList.Add(clone);
                        }
                    }
                    else if(prefabs.Any())
                    {
                        MyMwcObjectBuilder_PrefabContainer container = new MyMwcObjectBuilder_PrefabContainer(null, MyMwcObjectBuilder_PrefabContainer_TypesEnum.INSTANCE,
                            prefabs.ToList(), 0, faction, null);

                        var clone = container.Clone() as MyMwcObjectBuilder_PrefabContainer; // To clone children easily
                        clone.ClearEntityId(); // Clear childs ids
                        clone.PositionAndOrientation = new MyMwcPositionAndOrientation(objectPos, Vector3.Forward, Vector3.Up);
                        addToList.Add(clone);
                    }
                } //end of station generation

                if (pos.HasValue && rnd.Float(0, 1) < 0.5f)
                { //Create mysterious cube at 1% of stations
                    var sizeMyst = size * 1.5f;
                    Vector3? posMyst = FindEntityPosition(prunningStructure, rnd, sizeMyst, 1.0f, 1.0f, pos.Value);
                    if (posMyst.HasValue)
                    {
                        CreateMysteriousCubes(posMyst.Value, addToList, rnd);
                    }

                    //Create some more
                    int count = rnd.Next(5);
                    for (int i = 0; i < count; i++)
                    {
                        var size2 = MyMwcSectorConstants.SECTOR_SIZE / 2;
                        Vector3? pos2 = FindEntityPosition(prunningStructure, rnd, size2);
                        if (pos2.HasValue)
                        {
                            CreateMysteriousCubes(pos2.Value, addToList, rnd);
                        }
                    }
                }
            }
        }
        public override void AddUniverseEntities(MySolarSystemMapData data)
        {
            if (MyMissions.ActiveMission == null && MyMissions.GetAvailableMissions().Count == 0)
            {
                AddTemplateGroups(data);
            }

            const float maxObjCenterFromOrbit = 0.25f;

            Random rnd = new Random(0);
            float orbitRadius = OrbitProperties.AreaCenter.Length();
            float baseAngle = MyMath.AngleTo(OrbitProperties.AreaCenter, Vector3.UnitZ).Y;

            //count of groups per orbit side 
            float step = CalculateStep((OrbitProperties.MaxDistanceFromOrbitHigh + OrbitProperties.MaxDistanceFromOrbitLow) / 2);

            int testMaxCount = 0;

            for (float i = baseAngle - HalfAngle; i < baseAngle + HalfAngle; i += step)
            {
                float interpolator = 1 - Math.Abs((i - baseAngle) / HalfAngle); // (i + halfLen) / halfLen / 2;
                float maxDistFromOrbitAtAngle = MathHelper.SmoothStep(OrbitProperties.MaxDistanceFromOrbitLow, OrbitProperties.MaxDistanceFromOrbitHigh, interpolator);

                step = CalculateStep((OrbitProperties.MaxDistanceFromOrbitHigh + maxDistFromOrbitAtAngle) / 2);

                //Vector3 centerPos = new Vector3((float)Math.Sin(i) * distance, 0, (float)Math.Cos(i) * distance);

                //5 = billboards count in smaller group
                for (int j = 0; j < 2; j++)
                {
                    Vector2 distFromOrbit = Vector2.Normalize(new Vector2(rnd.Float(-1, 1), rnd.Float(-1, 1)));
                    //distFromOrbit = new Vector2();
                    distFromOrbit *= maxDistFromOrbitAtAngle * maxObjCenterFromOrbit;
                    float dist = orbitRadius + distFromOrbit.X;

                    float i2 = i + rnd.FloatCubic(-step * maxObjCenterFromOrbit, step * maxObjCenterFromOrbit);

                    float x = (float)Math.Sin(i2) * dist;
                    float z = (float)Math.Cos(i2) * dist;
                    float y = distFromOrbit.Y;
                    Vector3 pos = OrbitProperties.OrbitCenter + new Vector3(x, y, z);

                    Vector3 offset;
                    MyMwcVector3Int sector = MySolarSystemUtils.KmToSectors(pos, out offset);

                    float size = maxDistFromOrbitAtAngle * (1 - maxObjCenterFromOrbit);

                    if (this.SolarMapData != null)
                    {
                        Vector4 clr = new Vector4(this.SolarMapData.DustColor, 1.0f);
                        Color color = rnd.Color(new Color(clr - this.SolarMapData.DustColorVariability), new Color(clr + this.SolarMapData.DustColorVariability));

                        data.Entities.Add(new MySolarSystemMapEntity(sector, offset, 2 * size, "Dust", MySolarSystemEntityEnum.DustField, color));
                        testMaxCount++;
                    }
                    if ((AreaType & AreaEnum.PostPlanet) != 0 && j % 2 == 0)
                    {
                        data.Entities.Add(new MySolarSystemMapEntity(sector, offset, size * (1 - maxObjCenterFromOrbit), "Asteroids", MySolarSystemEntityEnum.AsteroidField, Color.White));
                        testMaxCount++;
                    }

                    //AddEntity(m_data, pos, radius * wide * 4, name + " dust", MySolarSystemEntityEnum.Test1_Dust, rnd.Color(baseColor, colorVariation));
                }
            }

            //Do not allow to solar area to add more than 1000 objects
            //System.Diagnostics.Debug.Assert(testMaxCount < 3000);

            MySolarAreaBorderLine newLine = new MySolarAreaBorderLine();
            newLine.AreaCenter = OrbitProperties.AreaCenter;
            newLine.DistanceHigh = OrbitProperties.MaxDistanceFromOrbitHigh;
            newLine.DistanceLow = OrbitProperties.MaxDistanceFromOrbitLow;
            newLine.Spread = OrbitProperties.LongSpread;
            newLine.col = new Vector4(SolarMapData.DustColor, 1f);
            data.AreasBorderLines.Add(newLine);
        }