public static bool ApplyZoning(ZoneTool z, ushort blockIndex, ref ZoneBlock zoneBlock, Quad2 quad2)
 {
     var parameters = new object[] { blockIndex, zoneBlock, quad2 };
     bool b = (bool)z.GetType().GetMethod("ApplyZoning", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance, null, new Type[] { typeof(ushort), typeof(ZoneBlock).MakeByRefType(), typeof(Quad2) }, null).Invoke(z, parameters);
     zoneBlock = (ZoneBlock)parameters[1];
     return b;
 }
Exemple #2
0
        public static ItemClass.Zone GetBlockZoneOverride(ref ZoneBlock block, int x, int z, ItemClass.Zone zone1, ItemClass.Zone zone2)
        {
            ItemClass.Zone targetZone = block.GetZone(x, z);
            switch ((int)targetZone)
            {
            case 8:
            case 9:
            case 10:
            case 11:
            case 12:
            case 13:
            case 14:
                if (ZMController.m_ghostMode)
                {
                    ItemClass.Zone newValue = CustomZoneData.Instance[targetZone].HasZone(zone1) ? zone1 : CustomZoneData.Instance[targetZone].HasZone(zone2) ? zone2 : CustomZoneData.Instance[targetZone].GetLowerestZone();
                    block.SetZone(x, z, newValue);
                    block.RefreshZoning(0);
                    return(newValue);
                }
                else
                {
                    return(CustomZoneData.Instance[targetZone].HasZone(zone1) ? zone1 : CustomZoneData.Instance[targetZone].HasZone(zone2) ? zone2 : targetZone);
                }

            default:
                return(targetZone);
            }
        }
        private static bool ApplyZoning(ZoneTool _this, ushort blockIndex, ref ZoneBlock data, Quad2 quad2)
        {
            int rowCount    = data.RowCount;
            int columnCount = ZoneBlockDetour.GetColumnCount(ref data); // modified

            Vector2 vector2_1 = new Vector2(Mathf.Cos(data.m_angle), Mathf.Sin(data.m_angle)) * 8f;
            Vector2 vector2_2 = new Vector2(vector2_1.y, -vector2_1.x);
            Vector2 vector2_3 = VectorUtils.XZ(data.m_position);

            if (!new Quad2()
            {
                a = (vector2_3 - 4f * vector2_1 - 4f * vector2_2),
                b = (vector2_3 + 4f * vector2_1 - 4f * vector2_2),
                c = (vector2_3 + 4f * vector2_1 + (float)(rowCount - 4) * vector2_2),
                d = (vector2_3 - 4f * vector2_1 + (float)(rowCount - 4) * vector2_2)
            }.Intersect(quad2))
            {
                return(false);
            }
            bool flag = false;

            var m_zoning   = IsZoningEnabled(_this);                // custom
            var m_dezoning = IsDezoningEnabled(_this);              // custom
            var blockID    = ZoneBlockDetour.FindBlockId(ref data); // modified

            for (int z = 0; z < rowCount; ++z)
            {
                Vector2 vector2_4 = ((float)z - 3.5f) * vector2_2;
                for (int x = 0; x < columnCount; ++x) // custom
                {
                    Vector2 vector2_5 = ((float)x - 3.5f) * vector2_1;
                    Vector2 p         = vector2_3 + vector2_5 + vector2_4;
                    if (quad2.Intersect(p))
                    {
                        if (m_zoning)
                        {
                            if ((_this.m_zone == ItemClass.Zone.Unzoned || ZoneBlockDetour.GetZoneDeep(ref data, blockID, x, z) == ItemClass.Zone.Unzoned) &&
                                ZoneBlockDetour.SetZoneDeep(ref data, blockID, x, z, _this.m_zone))
                            {
                                flag = true;
                            }
                        }
                        else if (m_dezoning && ZoneBlockDetour.SetZoneDeep(ref data, blockID, x, z, ItemClass.Zone.Unzoned))
                        {
                            flag = true;
                        }
                    }
                }
            }
            if (!flag)
            {
                return(false);
            }
            data.RefreshZoning(blockIndex);
            return(true);
        }
        private static bool ApplyFillBuffer(ZoneTool _this, Vector3 position, Vector3 direction, float angle, ushort blockIndex, ref ZoneBlock block)
        {
            var m_zoning = IsZoningEnabled(_this); // custom
            var m_dezoning = IsDezoningEnabled(_this); // custom
            var blockID = ZoneBlockDetour.FindBlockId(ref block); // modified

            int rowCount = block.RowCount;
            int columnCount = ZoneBlockDetour.GetColumnCount(ref block); // modified

            Vector3 vector3_1 = new Vector3(Mathf.Cos(block.m_angle), 0.0f, Mathf.Sin(block.m_angle)) * 8f;
            Vector3 vector3_2 = new Vector3(vector3_1.z, 0.0f, -vector3_1.x);
            bool flag1 = false;
            for (int z = 0; z < rowCount; ++z)
            {
                Vector3 vector3_3 = ((float)z - 3.5f) * vector3_2;
                for (int x = 0; x < columnCount; ++x) // custom
                {
                    Vector3 vector3_4 = ((float)x - 3.5f) * vector3_1;
                    Vector3 vector3_5 = block.m_position + vector3_4 + vector3_3 - position;
                    float f1 = (float)(((double)vector3_5.x * (double)direction.x + (double)vector3_5.z * (double)direction.z) * 0.125 + 32.0);
                    float f2 = (float)(((double)vector3_5.x * (double)direction.z - (double)vector3_5.z * (double)direction.x) * 0.125 + 32.0);
                    int num1 = Mathf.Clamp(Mathf.RoundToInt(f1), 0, 63);
                    int num2 = Mathf.Clamp(Mathf.RoundToInt(f2), 0, 63);
                    bool flag2 = false;

                    var m_fillBuffer1 = GetFillBuffer(_this); // modified

                    for (int index1 = -1; index1 <= 1 && !flag2; ++index1)
                    {
                        for (int index2 = -1; index2 <= 1 && !flag2; ++index2)
                        {
                            int num3 = num1 + index2;
                            int index3 = num2 + index1;
                            if (num3 >= 0 && num3 < 64 && (index3 >= 0 && index3 < 64) && (((double)f1 - (double)num3) * ((double)f1 - (double)num3)
                                + ((double)f2 - (double)index3) * ((double)f2 - (double)index3) < 9.0 / 16.0 && ((long)m_fillBuffer1[index3] & 1L << num3) != 0L))
                            {
                                if (m_zoning)
                                {
                                    if ((_this.m_zone == ItemClass.Zone.Unzoned || ZoneBlockDetour.GetZoneDeep(ref block, blockID, x, z) == ItemClass.Zone.Unzoned)
                                        && ZoneBlockDetour.SetZoneDeep(ref block, blockID, x, z, _this.m_zone))
                                        flag1 = true;
                                }
                                else if (m_dezoning && ZoneBlockDetour.SetZoneDeep(ref block, blockID, x, z, ItemClass.Zone.Unzoned))
                                    flag1 = true;
                                flag2 = true;
                            }
                        }
                    }
                }
            }
            if (!flag1)
                return false;
            block.RefreshZoning(blockIndex);
            return true;
        }
 public static void CalculateBlock2(ref ZoneBlock z, ushort blockID)
 {
     if (((int)z.m_flags & 3) != 1)
         return;
     int rowCount = z.RowCount;
     Vector2 vector2_1 = new Vector2(Mathf.Cos(z.m_angle), Mathf.Sin(z.m_angle)) * 8f;
     Vector2 vector2_2 = new Vector2(vector2_1.y, -vector2_1.x);
     Vector2 vector2_3 = VectorUtils.XZ(z.m_position);
     Vector2 vector2_4 = vector2_3 - 4f * vector2_1 - 4f * vector2_2;
     Vector2 vector2_5 = vector2_3 + 0.0f * vector2_1 - 4f * vector2_2;
     Vector2 vector2_6 = vector2_3 + 0.0f * vector2_1 + (float)(rowCount - 4) * vector2_2;
     Vector2 vector2_7 = vector2_3 - 4f * vector2_1 + (float)(rowCount - 4) * vector2_2;
     float minX = Mathf.Min(Mathf.Min(vector2_4.x, vector2_5.x), Mathf.Min(vector2_6.x, vector2_7.x));
     float minZ = Mathf.Min(Mathf.Min(vector2_4.y, vector2_5.y), Mathf.Min(vector2_6.y, vector2_7.y));
     float maxX = Mathf.Max(Mathf.Max(vector2_4.x, vector2_5.x), Mathf.Max(vector2_6.x, vector2_7.x));
     float maxZ = Mathf.Max(Mathf.Max(vector2_4.y, vector2_5.y), Mathf.Max(vector2_6.y, vector2_7.y));
     ulong valid = z.m_valid;
     ulong shared = 0UL;
     ZoneManager instance = Singleton<ZoneManager>.instance;
     for (int index = 0; index < instance.m_cachedBlocks.m_size; ++index)
         CalculateImplementation2(ref z, blockID, ref instance.m_cachedBlocks.m_buffer[index], ref valid, ref shared, minX, minZ, maxX, maxZ);
     int num1 = Mathf.Max((int)(((double)minX - 46.0) / 64f + FakeZoneManager.HALFGRID), 0);
     int num2 = Mathf.Max((int)(((double)minZ - 46.0) / 64f + FakeZoneManager.HALFGRID), 0);
     int num3 = Mathf.Min((int)(((double)maxX + 46.0) / 64f + FakeZoneManager.HALFGRID), FakeZoneManager.GRIDSIZE - 1);
     int num4 = Mathf.Min((int)(((double)maxZ + 46.0) / 64f + FakeZoneManager.HALFGRID), FakeZoneManager.GRIDSIZE - 1);
     for (int index1 = num2; index1 <= num4; ++index1)
     {
         for (int index2 = num1; index2 <= num3; ++index2)
         {
             ushort num5 = FakeZoneManager.zoneGrid[index1 * FakeZoneManager.GRIDSIZE + index2];
             int num6 = 0;
             while ((int)num5 != 0)
             {
                 Vector3 vector3 = instance.m_blocks.m_buffer[(int)num5].m_position;
                 if ((double)Mathf.Max(Mathf.Max(minX - 46f - vector3.x, minZ - 46f - vector3.z), Mathf.Max((float)((double)vector3.x - (double)maxX - 46.0), (float)((double)vector3.z - (double)maxZ - 46.0))) < 0.0 && (int)num5 != (int)blockID)
                     CalculateImplementation2(ref z, blockID, ref instance.m_blocks.m_buffer[(int)num5], ref valid, ref shared, minX, minZ, maxX, maxZ);
                 num5 = instance.m_blocks.m_buffer[(int)num5].m_nextGridBlock;
                 if (++num6 >= 32768)
                 {
                     CODebugBase<LogChannel>.Error(LogChannel.Core, "Invalid list detected!\n" + System.Environment.StackTrace);
                     break;
                 }
             }
         }
     }
     ulong num7 = 144680345676153346UL;
     for (int index = 0; index < 7; ++index)
     {
         valid = (ulong)((long)valid & ~(long)num7 | (long)valid & (long)valid << 1 & (long)num7);
         num7 <<= 1;
     }
     z.m_valid = valid;
     z.m_shared = shared;
 }
        private static void ApplyBrush(ZoneTool _this, ushort blockIndex, ref ZoneBlock data, Vector3 position, float brushRadius)
        {
            Vector3 vector3_1 = data.m_position - position;

            if ((double)Mathf.Abs(vector3_1.x) > 46.0 + (double)brushRadius || (double)Mathf.Abs(vector3_1.z) > 46.0 + (double)brushRadius)
            {
                return;
            }
            int     num         = (int)((data.m_flags & 65280U) >> 8);
            int     columnCount = ZoneBlockDetour.GetColumnCount(ref data); // modified
            Vector3 vector3_2   = new Vector3(Mathf.Cos(data.m_angle), 0.0f, Mathf.Sin(data.m_angle)) * 8f;
            Vector3 vector3_3   = new Vector3(vector3_2.z, 0.0f, -vector3_2.x);
            bool    flag        = false;

            var m_zoning   = IsZoningEnabled(_this);                // custom
            var m_dezoning = IsDezoningEnabled(_this);              // custom
            var blockID    = ZoneBlockDetour.FindBlockId(ref data); // modified

            for (int z = 0; z < num; ++z)
            {
                Vector3 vector3_4 = ((float)z - 3.5f) * vector3_3;
                for (int x = 0; x < columnCount; ++x) // modified
                {
                    Vector3 vector3_5 = ((float)x - 3.5f) * vector3_2;
                    Vector3 vector3_6 = vector3_1 + vector3_5 + vector3_4;
                    if ((double)vector3_6.x * (double)vector3_6.x + (double)vector3_6.z * (double)vector3_6.z <= (double)brushRadius * (double)brushRadius)
                    {
                        if (m_zoning)
                        {
                            if ((_this.m_zone == ItemClass.Zone.Unzoned || ZoneBlockDetour.GetZoneDeep(ref data, blockID, x, z) == ItemClass.Zone.Unzoned) &&
                                ZoneBlockDetour.SetZoneDeep(ref data, blockID, x, z, _this.m_zone))
                            {
                                flag = true;
                            }
                        }
                        else if (m_dezoning && ZoneBlockDetour.SetZoneDeep(ref data, blockID, x, z, ItemClass.Zone.Unzoned))
                        {
                            flag = true;
                        }
                    }
                }
            }
            if (!flag)
            {
                return;
            }
            data.RefreshZoning(blockIndex);
            if (!m_zoning)
            {
                return;
            }
            UsedZone(_this, _this.m_zone);
        }
Exemple #7
0
        private static void ApplyBrush(ZoneTool z, ushort blockIndex, ref ZoneBlock data, Vector3 position, float brushRadius)
        {
            Vector3 a = data.m_position - position;

            if (Mathf.Abs(a.x) > 46f + brushRadius || Mathf.Abs(a.z) > 46f + brushRadius)
            {
                return;
            }

            bool    m_zoning   = (bool)z.GetType().GetField("m_zoning", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(z);
            bool    m_dezoning = (bool)z.GetType().GetField("m_dezoning", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(z);
            int     num        = (int)((data.m_flags & 65280u) >> 8);
            Vector3 a2         = new Vector3(Mathf.Cos(data.m_angle), 0f, Mathf.Sin(data.m_angle)) * 8f;
            Vector3 a3         = new Vector3(a2.z, 0f, -a2.x);
            bool    flag       = false;

            for (int i = 0; i < num; i++)
            {
                Vector3 b = ((float)i - 3.5f) * a3;
                for (int j = 0; j < 4; j++)
                {
                    Vector3 b2     = ((float)j - 3.5f) * a2;
                    Vector3 vector = a + b2 + b;
                    float   num2   = vector.x * vector.x + vector.z * vector.z;
                    if (num2 <= brushRadius * brushRadius)
                    {
                        if (m_zoning)
                        {
                            if ((z.m_zone == ItemClass.Zone.Unzoned || data.GetZone(j, i) == ItemClass.Zone.Unzoned) && data.SetZone(j, i, z.m_zone))
                            {
                                flag = true;
                            }
                        }
                        else if (m_dezoning && data.SetZone(j, i, ItemClass.Zone.Unzoned))
                        {
                            flag = true;
                        }
                    }
                }
            }
            if (!flag)
            {
                return;
            }
            data.RefreshZoning(blockIndex);
            if (!m_zoning)
            {
                return;
            }
            UsedZone(z, z.m_zone);
        }
Exemple #8
0
        private void PlayerDied(ZoneBlock zone, IMyPlayer player, IMyFaction faction)
        {
            if (zone.PointsRemovedOnDeath.Value == 0 || !MyAPIGateway.Multiplayer.IsServer)
            {
                return;
            }

            long   facId      = faction.FactionId;
            string planetName = zone.GetClosestPlanet();

            if (!Planets.Any(description => description.Name == planetName))
            {
                var world = new PlanetDescription()
                {
                    Name   = planetName,
                    Scores = new List <ScoreDescription>()
                };
                Planets.Add(world);
            }

            PlanetDescription planet = Planets.Find(p => p.Name == planetName);

            if (!planet.Scores.Any(s => s.FactionId == facId))
            {
                planet.Scores.Add(new ScoreDescription()
                {
                    FactionId   = facId,
                    FactionName = faction.Name,
                    FactionTag  = faction.Tag,
                    Points      = 1,
                    PlanetId    = planetName,
                    GridName    = (zone.Entity as IMyCubeBlock).CubeGrid.DisplayName,
                });
            }

            ScoreDescription score = planet.Scores.Find(s => s.FactionId == facId);
            int original           = score.Points;

            if (original - zone.PointsRemovedOnDeath.Value < 1)
            {
                score.Points = 1;
            }
            else
            {
                score.Points = original - zone.PointsRemovedOnDeath.Value;
            }

            string message = $"[{faction.Tag}] {player.DisplayName} Died: {score.Points - original} Points";

            Network.Say(message);
        }
        private static void FindClosestZone(BuildingTool _this, BuildingInfo info, ushort block, Vector3 refPos, ref float minD, ref float min2, ref Vector3 minPos, ref float minAngle)
        {
            if ((int)block == 0)
            {
                return;
            }
            ZoneBlock zoneBlock = Singleton <ZoneManager> .instance.m_blocks.m_buffer[(int)block];

            if ((double)Mathf.Abs(zoneBlock.m_position.x - refPos.x) >= 52.0 || (double)Mathf.Abs(zoneBlock.m_position.z - refPos.z) >= 52.0)
            {
                return;
            }
            int     rowCount    = zoneBlock.RowCount;
            int     columnCount = ZoneBlockDetour.GetColumnCount(ref zoneBlock); // modified
            Vector3 lhs         = new Vector3(Mathf.Cos(zoneBlock.m_angle), 0.0f, Mathf.Sin(zoneBlock.m_angle)) * 8f;
            Vector3 vector3_1   = new Vector3(lhs.z, 0.0f, -lhs.x);

            for (int row = 0; row < rowCount; ++row)
            {
                Vector3 vector3_2 = ((float)row - 3.5f) * vector3_1;
                for (int column = 0; (long)column < columnCount; ++column) // modified
                {
                    if (((long)zoneBlock.m_valid & 1L << (row << 3 | column)) != 0L)
                    {
                        Vector3 vector3_3 = ((float)column - 3.5f) * lhs;
                        Vector3 vector3_4 = zoneBlock.m_position + vector3_3 + vector3_2;
                        float   num1      = Mathf.Sqrt((float)(((double)vector3_4.x - (double)refPos.x) * ((double)vector3_4.x - (double)refPos.x) + ((double)vector3_4.z - (double)refPos.z) * ((double)vector3_4.z - (double)refPos.z)));
                        float   num2      = Vector3.Dot(lhs, refPos - zoneBlock.m_position);
                        if ((double)num1 <= (double)minD - 0.200000002980232 || (double)num1 < (double)minD + 0.200000002980232 && (double)num2 < (double)min2)
                        {
                            minD = num1;
                            min2 = num2;
                            if ((info.m_cellWidth & 1) == 0)
                            {
                                Vector3 vector3_5 = vector3_4 + vector3_1 * 0.5f;
                                Vector3 vector3_6 = vector3_4 - vector3_1 * 0.5f;
                                minPos = ((double)vector3_5.x - (double)refPos.x) * ((double)vector3_5.x - (double)refPos.x) + ((double)vector3_5.z - (double)refPos.z) * ((double)vector3_5.z - (double)refPos.z) >= ((double)vector3_6.x - (double)refPos.x) * ((double)vector3_6.x - (double)refPos.x) + ((double)vector3_6.z - (double)refPos.z) * ((double)vector3_6.z - (double)refPos.z) ? zoneBlock.m_position + (float)((double)info.m_cellLength * 0.5 - 4.0) * lhs + ((float)row - 4f) * vector3_1 : zoneBlock.m_position + (float)((double)info.m_cellLength * 0.5 - 4.0) * lhs + ((float)row - 3f) * vector3_1;
                            }
                            else
                            {
                                minPos = zoneBlock.m_position + (float)((double)info.m_cellLength * 0.5 - 4.0) * lhs + ((float)row - 3.5f) * vector3_1;
                            }
                            minPos.y = refPos.y;
                            minAngle = zoneBlock.m_angle + 1.570796f;
                        }
                    }
                }
            }
        }
 private static void CheckZoning(ref Building _this, ItemClass.Zone zone1, ItemClass.Zone zone2, ref uint validCells, ref bool secondary, ref ZoneBlock block)
 {
     BuildingInfo.ZoningMode zoningMode = _this.Info.m_zoningMode;
     int width = _this.Width;
     int length = _this.Length;
     Vector3 vector3_1 = new Vector3(Mathf.Cos(_this.m_angle), 0.0f, Mathf.Sin(_this.m_angle)) * 8f;
     Vector3 vector3_2 = new Vector3(vector3_1.z, 0.0f, -vector3_1.x);
     int rowCount = block.RowCount;
     int columnCount = ZoneBlockDetour.GetColumnCount(ref block); // modified
     Vector3 vector3_3 = new Vector3(Mathf.Cos(block.m_angle), 0.0f, Mathf.Sin(block.m_angle)) * 8f;
     Vector3 vector3_4 = new Vector3(vector3_3.z, 0.0f, -vector3_3.x);
     Vector3 vector3_5 = block.m_position - _this.m_position + vector3_1 * (float)((double)width * 0.5 - 0.5) + vector3_2 * (float)((double)length * 0.5 - 0.5);
     for (int z = 0; z < rowCount; ++z)
     {
         Vector3 vector3_6 = ((float)z - 3.5f) * vector3_4;
         for (int x = 0; (long)x < columnCount; ++x) // modified
         {
             if (((long)block.m_valid & ~(long)block.m_shared & 1L << (z << 3 | x)) != 0L)
             {
                 ItemClass.Zone zone = block.GetZone(x, z);
                 bool flag1 = zone == zone1;
                 if (zone == zone2 && zone2 != ItemClass.Zone.None)
                 {
                     flag1 = true;
                     secondary = true;
                 }
                 if (flag1)
                 {
                     Vector3 vector3_7 = ((float)x - 3.5f) * vector3_3;
                     Vector3 vector3_8 = vector3_5 + vector3_7 + vector3_6;
                     float num1 = (float)((double)vector3_1.x * (double)vector3_8.x + (double)vector3_1.z * (double)vector3_8.z);
                     float num2 = (float)((double)vector3_2.x * (double)vector3_8.x + (double)vector3_2.z * (double)vector3_8.z);
                     int num3 = Mathf.RoundToInt(num1 / 64f);
                     int num4 = Mathf.RoundToInt(num2 / 64f);
                     bool flag2 = false;
                     if (zoningMode == BuildingInfo.ZoningMode.Straight)
                         flag2 = num4 == 0;
                     else if (zoningMode == BuildingInfo.ZoningMode.CornerLeft)
                         flag2 = num4 == 0 && num3 >= width - 2 || num4 <= 1 && num3 == width - 1;
                     else if (zoningMode == BuildingInfo.ZoningMode.CornerRight)
                         flag2 = num4 == 0 && num3 <= 1 || num4 <= 1 && num3 == 0;
                     if ((!flag2 || x == 0) && (num3 >= 0 && num4 >= 0) && (num3 < width && num4 < length))
                         validCells = validCells | (uint)(1 << (num4 << 3) + num3);
                 }
             }
         }
     }
 }
 private static void CheckZoning(Building bz, ItemClass.Zone zone, ref uint validCells, ref ZoneBlock block)
 {
     BuildingInfo.ZoningMode zoningMode = bz.Info.m_zoningMode;
     int width = bz.Width;
     int length = bz.Length;
     Vector3 a = new Vector3(Mathf.Cos(bz.m_angle), 0f, Mathf.Sin(bz.m_angle)) * 8f;
     Vector3 a2 = new Vector3(a.z, 0f, -a.x);
     int rowCount = block.RowCount;
     Vector3 a3 = new Vector3(Mathf.Cos(block.m_angle), 0f, Mathf.Sin(block.m_angle)) * 8f;
     Vector3 a4 = new Vector3(a3.z, 0f, -a3.x);
     Vector3 a5 = block.m_position - bz.m_position + a * ((float)width * 0.5f - 0.5f) + a2 * ((float)length * 0.5f - 0.5f);
     for (int i = 0; i < rowCount; i++)
     {
         Vector3 b = ((float)i - 3.5f) * a4;
         int num = 0;
         while ((long)num < 4L)
         {
             if ((block.m_valid & ~block.m_shared & 1uL << (i << 3 | num)) != 0uL && block.GetZone(num, i) == zone)
             {
                 Vector3 b2 = ((float)num - 3.5f) * a3;
                 Vector3 vector = a5 + b2 + b;
                 float num2 = a.x * vector.x + a.z * vector.z;
                 float num3 = a2.x * vector.x + a2.z * vector.z;
                 int num4 = Mathf.RoundToInt(num2 / 64f);
                 int num5 = Mathf.RoundToInt(num3 / 64f);
                 bool flag = false;
                 if (zoningMode == BuildingInfo.ZoningMode.Straight)
                 {
                     flag = (num5 == 0);
                 }
                 else if (zoningMode == BuildingInfo.ZoningMode.CornerLeft)
                 {
                     flag = ((num5 == 0 && num4 >= width - 2) || (num5 <= 1 && num4 == width - 1));
                 }
                 else if (zoningMode == BuildingInfo.ZoningMode.CornerRight)
                 {
                     flag = ((num5 == 0 && num4 <= 1) || (num5 <= 1 && num4 == 0));
                 }
                 if ((!flag || num == 0) && num4 >= 0 && num5 >= 0 && num4 < width && num5 < length)
                 {
                     validCells |= 1u << (num5 << 3) + num4;
                 }
             }
             num++;
         }
     }
 }
        private static void ApplyBrush(ZoneTool z,ushort blockIndex, ref ZoneBlock data, Vector3 position, float brushRadius)
        {
            Vector3 a = data.m_position - position;
            if (Mathf.Abs(a.x) > 46f + brushRadius || Mathf.Abs(a.z) > 46f + brushRadius)
            {
                return;
            }

            bool m_zoning = (bool)z.GetType().GetField("m_zoning", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(z);
            bool m_dezoning = (bool)z.GetType().GetField("m_dezoning", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(z);
            int num = (int)((data.m_flags & 65280u) >> 8);
            Vector3 a2 = new Vector3(Mathf.Cos(data.m_angle), 0f, Mathf.Sin(data.m_angle)) * 8f;
            Vector3 a3 = new Vector3(a2.z, 0f, -a2.x);
            bool flag = false;
            for (int i = 0; i < num; i++)
            {
                Vector3 b = ((float)i - 3.5f) * a3;
                for (int j = 0; j < 4; j++)
                {
                    Vector3 b2 = ((float)j - 3.5f) * a2;
                    Vector3 vector = a + b2 + b;
                    float num2 = vector.x * vector.x + vector.z * vector.z;
                    if (num2 <= brushRadius * brushRadius)
                    {
                        if (m_zoning)
                        {
                            if ((z.m_zone == ItemClass.Zone.Unzoned || data.GetZone(j, i) == ItemClass.Zone.Unzoned) && data.SetZone(j, i, z.m_zone))
                            {
                                flag = true;
                            }
                        }
                        else if (m_dezoning && data.SetZone(j, i, ItemClass.Zone.Unzoned))
                        {
                            flag = true;
                        }
                    }
                }
            }
            if (flag)
            {
                data.RefreshZoning(blockIndex);
                if (m_zoning)
                {
                    UsedZone(z.m_zone);
                }
            }
        }
        private static void ApplyBrush(ZoneTool _this, ushort blockIndex, ref ZoneBlock data, Vector3 position, float brushRadius)
        {
            Vector3 vector3_1 = data.m_position - position;
            if ((double)Mathf.Abs(vector3_1.x) > 46.0 + (double)brushRadius || (double)Mathf.Abs(vector3_1.z) > 46.0 + (double)brushRadius)
                return;
            int num = (int)((data.m_flags & 65280U) >> 8);
            int columnCount = ZoneBlockDetour.GetColumnCount(ref data); // modified
            Vector3 vector3_2 = new Vector3(Mathf.Cos(data.m_angle), 0.0f, Mathf.Sin(data.m_angle)) * 8f;
            Vector3 vector3_3 = new Vector3(vector3_2.z, 0.0f, -vector3_2.x);
            bool flag = false;

            var m_zoning = IsZoningEnabled(_this); // custom
            var m_dezoning = IsDezoningEnabled(_this); // custom
            var blockID = ZoneBlockDetour.FindBlockId(ref data); // modified

            for (int z = 0; z < num; ++z)
            {
                Vector3 vector3_4 = ((float)z - 3.5f) * vector3_3;
                for (int x = 0; x < columnCount; ++x) // modified
                {
                    Vector3 vector3_5 = ((float)x - 3.5f) * vector3_2;
                    Vector3 vector3_6 = vector3_1 + vector3_5 + vector3_4;
                    if ((double)vector3_6.x * (double)vector3_6.x + (double)vector3_6.z * (double)vector3_6.z <= (double)brushRadius * (double)brushRadius)
                    {
                        if (m_zoning)
                        {
                            if ((_this.m_zone == ItemClass.Zone.Unzoned || ZoneBlockDetour.GetZoneDeep(ref data, blockID, x, z) == ItemClass.Zone.Unzoned)
                                && ZoneBlockDetour.SetZoneDeep(ref data, blockID, x, z, _this.m_zone))
                                flag = true;
                        }
                        else if (m_dezoning && ZoneBlockDetour.SetZoneDeep(ref data, blockID, x, z, ItemClass.Zone.Unzoned))
                            flag = true;
                    }
                }
            }
            if (!flag)
                return;
            data.RefreshZoning(blockIndex);
            if (!m_zoning)
                return;
            UsedZone(_this, _this.m_zone);
        }
        private static void InitializeBlock(ZoneManager zm, ushort block, ref ZoneBlock data)
        {
            //begin mod
            int num   = Mathf.Clamp((int)(data.m_position.x / 64.0 + HALFGRID), 0, GRIDSIZE - 1);
            int index = Mathf.Clamp((int)(data.m_position.z / 64.0 + HALFGRID), 0, GRIDSIZE - 1) * GRIDSIZE + num;

            //end mod
            while (!Monitor.TryEnter(zm.m_zoneGrid, SimulationManager.SYNCHRONIZE_TIMEOUT))
            {
            }
            try
            {
                zm.m_blocks.m_buffer[block].m_nextGridBlock = zm.m_zoneGrid[index];
                zm.m_zoneGrid[index] = block;
            }
            finally
            {
                Monitor.Exit(zm.m_zoneGrid);
            }
        }
Exemple #15
0
 public static bool GetBlockZoneSanitize(ref ZoneBlock block, int x, int z)
 {
     ItemClass.Zone targetZone = block.GetZone(x, z);
     switch ((int)targetZone)
     {
     case 8:
     case 9:
     case 10:
     case 11:
     case 12:
     case 13:
     case 14:
         if (ZMController.m_ghostMode)
         {
             ItemClass.Zone newValue = CustomZoneData.Instance[targetZone].GetLowerestZone();
             block.SetZone(x, z, newValue);
             return(true);
         }
         break;
     }
     return(false);
 }
        public static bool SetZoneDeep(ref ZoneBlock _this, ushort blockID, int x, int z, ItemClass.Zone zone)
        {
            if (zone == ItemClass.Zone.Distant)
            {
                zone = ItemClass.Zone.Unzoned;
            }
            // 0000 0000 0000 0000 0000 0000 00zz zx00
            // 0|0, 2|0 --> 0
            // 0|1, 2|1 --> 4
            // 1|0, 1|2 --> 8
            // 1|1, 3|1 --> 12
            // 0|2, 2|2 --> 16
            int posShift = z << 3 | (x & 1) << 2;

            // 4 bits for every cell to store the zone type
            // that means 16 zone types are the maximum
            // this mask resets the 4 bits of the cell
            ulong invertedCellMask = ~(15UL << posShift);
            if (x < 2) // use zone1
            {
                ulong newZoneMask = _this.m_zone1 & invertedCellMask | (ulong)zone << posShift;
                if (newZoneMask != _this.m_zone1)
                {
                    _this.m_zone1 = newZoneMask;
                    return true;
                }
            }
            else if (x < 4) // use zone2
            {
                ulong newZoneMask = _this.m_zone2 & invertedCellMask | (ulong)zone << posShift;
                if (newZoneMask != _this.m_zone2)
                {
                    _this.m_zone2 = newZoneMask;
                    return true;
                }
            }

            // --- support for deeper zones ---
            else if (x < 6) // use zone3
            {
                if (DataExtension.zones3 != null)
                {
                    ulong newZoneMask = DataExtension.zones3[blockID] & invertedCellMask | (ulong)zone << posShift;
                    if (newZoneMask != DataExtension.zones3[blockID])
                    {
                        DataExtension.zones3[blockID] = newZoneMask;
                        return true;
                    }
                }
            }
            else if (x < 8) // use zone4
            {
                if (DataExtension.zones4 != null)
                {
                    ulong newZoneMask = DataExtension.zones4[blockID] & invertedCellMask | (ulong)zone << posShift;
                    if (newZoneMask != DataExtension.zones4[blockID])
                    {
                        DataExtension.zones4[blockID] = newZoneMask;
                        return true;
                    }
                }
            }
            return false;
        }
 public static void SetColumnCount(ref ZoneBlock block, int value)
 {
     block.m_flags = block.m_flags & ~FLAG_COLUMNS | (uint)Mathf.Clamp(value, 1, 8) << 24;
 }
        public static ItemClass.Zone GetZoneDeep(ref ZoneBlock _this, ushort blockID, int x, int z)
        {
            if(x >= ZoneBlockDetour.GetColumnCount(ref _this)) return ItemClass.Zone.Distant;

            int num = z << 3 | (x & 1) << 2;

            if (x < 2) return (ItemClass.Zone)(_this.m_zone1 >> num & 15L);
            else if (x < 4) return (ItemClass.Zone)(_this.m_zone2 >> num & 15L);

            // --- support for deeper zones ---
            else if (x < 6 && DataExtension.zones3 != null) return (ItemClass.Zone)(DataExtension.zones3[blockID] >> num & 15L);
            else if (x < 8 && DataExtension.zones4 != null) return (ItemClass.Zone)(DataExtension.zones4[blockID] >> num & 15L);

            return ItemClass.Zone.Distant;
        }
 public static int GetColumnCount(ref ZoneBlock block)
 {
     var count = (int) ((block.m_flags & FLAG_COLUMNS) >> 24);
     return count > 0 ? count : 4; // return 4 (vanilla depth) for blocks with unset column count
 }
        public static void CalculateBlock3(ref ZoneBlock _this, ushort blockID)
        {
            // skip zone blocks which are not in use
            if (((int)_this.m_flags & 3) != ZoneBlock.FLAG_CREATED) return;

            // width of the zone block
            int rowCount = _this.RowCount;
            int columnCount = ZoneBlockDetour.GetColumnCount(ref _this); // modified

            Vector2 columnDirection = new Vector2(Mathf.Cos(_this.m_angle), Mathf.Sin(_this.m_angle)) * 8f;
            Vector2 rowDirection = new Vector2(columnDirection.y, -columnDirection.x);
            Vector2 positionXZ = VectorUtils.XZ(_this.m_position);

            // bounds of the zone block
            Vector2 a = positionXZ - 4f * columnDirection - 4f * rowDirection;
            Vector2 b = positionXZ + (columnCount - 4f) * columnDirection - 4f * rowDirection;
            Vector2 c = positionXZ + (columnCount - 4f) * columnDirection + (float)(rowCount - 4) * rowDirection;
            Vector2 d = positionXZ - 4f * columnDirection + (float)(rowCount - 4) * rowDirection;
            float minX = Mathf.Min(Mathf.Min(a.x, b.x), Mathf.Min(c.x, d.x));
            float minZ = Mathf.Min(Mathf.Min(a.y, b.y), Mathf.Min(c.y, d.y));
            float maxX = Mathf.Max(Mathf.Max(a.x, b.x), Mathf.Max(c.x, d.x));
            float maxZ = Mathf.Max(Mathf.Max(a.y, b.y), Mathf.Max(c.y, d.y));

            BuildingManager buildingManager = Singleton<BuildingManager>.instance;

            // calculate which building grid cells are touched by this zone block
            int gridMinX = Mathf.Max((int)(((double)minX - 72.0) / 64.0 + 135.0), 0);
            int gridMinZ = Mathf.Max((int)(((double)minZ - 72.0) / 64.0 + 135.0), 0);
            int gridMaxX = Mathf.Min((int)(((double)maxX + 72.0) / 64.0 + 135.0), 269);
            int gridMaxZ = Mathf.Min((int)(((double)maxZ + 72.0) / 64.0 + 135.0), 269);

            // masks for zones and occupation
            ulong occupied1 = 0;
            ulong occupied2 = 0;
            ulong zone1 = _this.m_zone1;
            ulong zone2 = _this.m_zone2;

            // --- support for deeper zones ---
            ulong zone3 = DataExtension.zones3 != null ? DataExtension.zones3[blockID] : 0;
            ulong zone4 = DataExtension.zones4 != null ? DataExtension.zones4[blockID] : 0;

            // Cycle through all touched grid cells
            for (int gridZ = gridMinZ; gridZ <= gridMaxZ; ++gridZ)
            {
                for (int gridX = gridMinX; gridX <= gridMaxX; ++gridX)
                {
                    // Cycle through all buildings in grid cell
                    ushort buildingID = buildingManager.m_buildingGrid[gridZ * 270 + gridX];
                    int counter = 0;
                    while ((int)buildingID != 0)
                    {
                        BuildingInfo info;
                        int width;
                        int length;
                        buildingManager.m_buildings.m_buffer[(int)buildingID].GetInfoWidthLength(out info, out width, out length);
                        if (info.m_class.m_layer == ItemClass.Layer.Default)
                        {
                            Vector3 buildingPosition = buildingManager.m_buildings.m_buffer[(int)buildingID].m_position;

                            // check if the zone block can touch the building
                            float num7 = Mathf.Min(72f, (float)(width + length) * 4f);
                            if ((double)Mathf.Max(Mathf.Max(minX - num7 - buildingPosition.x, minZ - num7 - buildingPosition.z), Mathf.Max(buildingPosition.x - maxX - num7, buildingPosition.z - maxZ - num7)) < 0.0)
                            {
                                // Mark cells colliding with the building as occupied (and remove the zoning)
                                CalculateImplementation3(ref _this, ref zone3, ref zone4, blockID, info, ref buildingManager.m_buildings.m_buffer[(int)buildingID], ref occupied1, ref occupied2, ref zone1, ref zone2, minX, minZ, maxX, maxZ);
                            }
                        }

                        // next building in grid cell (linked list)
                        buildingID = buildingManager.m_buildings.m_buffer[(int)buildingID].m_nextGridBuilding;

                        if (++counter >= 49152)
                        {
                            CODebugBase<LogChannel>.Error(LogChannel.Core, "Invalid list detected!\n" + System.Environment.StackTrace);
                            break;
                        }
                    }
                }
            }

            // apply new masks
            _this.m_occupied1 = occupied1;
            _this.m_occupied2 = occupied2;
            _this.m_zone1 = zone1;
            _this.m_zone2 = zone2;

            // --- support for deeper zones ---
            if (DataExtension.zones3 != null) DataExtension.zones3[blockID] = zone3;
            if (DataExtension.zones4 != null) DataExtension.zones4[blockID] = zone4;
        }
        private static void Snap(ZoneTool _this, ref Vector3 point, ref Vector3 direction, ref ItemClass.Zone zone, ref bool occupied1, ref bool occupied2, ref ZoneBlock block)
        {
            direction = new Vector3(Mathf.Cos(block.m_angle), 0.0f, Mathf.Sin(block.m_angle));
            Vector3 vector3_1 = direction * 8f;
            Vector3 vector3_2 = new Vector3(vector3_1.z, 0.0f, -vector3_1.x);
            Vector3 vector3_3 = block.m_position + vector3_1 * 0.5f + vector3_2 * 0.5f;
            Vector2 vector2   = new Vector2(point.x - vector3_3.x, point.z - vector3_3.z);
            int     num1      = Mathf.RoundToInt((float)(((double)vector2.x * (double)vector3_1.x + (double)vector2.y * (double)vector3_1.z) * (1.0 / 64.0)));
            int     num2      = Mathf.RoundToInt((float)(((double)vector2.x * (double)vector3_2.x + (double)vector2.y * (double)vector3_2.z) * (1.0 / 64.0)));

            point.x = (float)((double)vector3_3.x + (double)num1 * (double)vector3_1.x + (double)num2 * (double)vector3_2.x);
            point.z = (float)((double)vector3_3.z + (double)num1 * (double)vector3_1.z + (double)num2 * (double)vector3_2.z);
            // changed from:
            // if (num1 < -4 || num1 >= 0 || (num2 < -4 || num2 >= 4))
            if (num1 < -4 || num1 >= 4 || (num2 < -4 || num2 >= 4))
            {
                return;
            }
            zone      = block.GetZone(num1 + 4, num2 + 4); // keep old method (it's only a single call)
            occupied1 = block.IsOccupied1(num1 + 4, num2 + 4);
            occupied2 = block.IsOccupied2(num1 + 4, num2 + 4);
        }
Exemple #22
0
        private void AwardPoints(ZoneBlock zone, IMyFaction faction, int enemies, bool displayHeader)
        {
            if (!MyAPIGateway.Multiplayer.IsServer)
            {
                return;
            }

            string planetName = zone.GetClosestPlanet();

            if (!Planets.Any(description => description.Name == planetName))
            {
                PlanetDescription p = new PlanetDescription()
                {
                    Name   = planetName,
                    Scores = new List <ScoreDescription>()
                };

                Planets.Add(p);
            }

            long facId = faction.FactionId;
            PlanetDescription planet   = Planets.Find(w => w.Name == planetName);
            IMyCubeGrid       kothGrid = (zone.Entity as IMyCubeBlock).CubeGrid;

            if (!planet.Scores.Any(s => s.FactionId == facId))
            {
                planet.Scores.Add(new ScoreDescription()
                {
                    FactionId   = facId,
                    FactionName = faction.Name,
                    FactionTag  = faction.Tag,
                    Points      = 1,
                    PlanetId    = planetName,
                    GridName    = kothGrid.DisplayName
                });
            }

            int total = GetTotalScore(planet);
            ScoreDescription score = planet.Scores.Find(s => s.FactionId == facId);
            int current            = score.Points;

            int points;

            if (zone.PointsOnCap.Value == 0)
            {
                points = (int)(((float)(total - current) / (float)total) * 5f * enemies) + 1 + enemies;
            }
            else
            {
                points = zone.PointsOnCap.Value;
            }

            planet.Scores.Find(s => s.FactionId == facId).Points += points;
            zone.PointsEarnedSincePrize += points;


            if (zone.AwardPointsAsCredits.Value)
            {
                faction.RequestChangeBalance(points * zone.CreditsPerPoint.Value);
            }


            if (zone.PointsEarnedSincePrize >= zone.PointsForPrize.Value)
            {
                zone.PointsEarnedSincePrize -= zone.PointsForPrize.Value;

                IMyCargoContainer   prizebox = null;
                List <IMySlimBlock> temp     = new List <IMySlimBlock>();
                kothGrid.GetBlocks(temp, s => {
                    if (prizebox == null &&
                        s.FatBlock != null &&
                        s.FatBlock is IMyCargoContainer &&
                        s.FatBlock.BlockDefinition.SubtypeId == "Prizebox")
                    {
                        prizebox = s.FatBlock as IMyCargoContainer;
                    }

                    return(false);
                });

                if (zone.UseComponentReward.Value)
                {
                    string prizeType = (zone.AdvancedComponentSelection.Value) ? zone.PrizeComponentSubtypeId.Value : zone.SelectedComponentString.Value;
                    int    amount    = zone.PrizeAmountComponent.Value;

                    MyDefinitionId                definitionId  = new MyDefinitionId(typeof(MyObjectBuilder_Component), prizeType);
                    MyObjectBuilder_Component     content       = (MyObjectBuilder_Component)MyObjectBuilderSerializer.CreateNewObject(definitionId);
                    MyObjectBuilder_InventoryItem inventoryItem = new MyObjectBuilder_InventoryItem {
                        Amount = amount, Content = content
                    };

                    if (zone.SpawnIntoPrizeBox.Value)
                    {
                        if (prizebox == null)
                        {
                            Tools.Log(MyLogSeverity.Error, $"Could not find prize box on grid: {kothGrid.DisplayName} - {kothGrid.EntityId}");
                        }
                        else if (prizebox.GetInventory().CanItemsBeAdded(amount, definitionId))
                        {
                            prizebox.GetInventory().AddItems(amount, inventoryItem.Content);
                        }
                    }
                    else
                    {
                        if (zone.Entity.GetInventory().CanItemsBeAdded(amount, definitionId))
                        {
                            zone.Entity.GetInventory().AddItems(amount, inventoryItem.Content);
                        }
                    }
                }

                if (zone.UseIngotReward.Value)
                {
                    string prizeType = (zone.AdvancedIngotSelection.Value) ? zone.PrizeIngotSubtypeId.Value : zone.SelectedIngotString.Value;
                    int    amount    = zone.PrizeAmountIngot.Value;

                    MyDefinitionId                definitionId  = new MyDefinitionId(typeof(MyObjectBuilder_Ingot), prizeType);
                    MyObjectBuilder_Ingot         content       = (MyObjectBuilder_Ingot)MyObjectBuilderSerializer.CreateNewObject(definitionId);
                    MyObjectBuilder_InventoryItem inventoryItem = new MyObjectBuilder_InventoryItem {
                        Amount = amount, Content = content
                    };

                    if (zone.SpawnIntoPrizeBox.Value)
                    {
                        if (prizebox == null)
                        {
                            Tools.Log(MyLogSeverity.Error, $"Could not find prize box on grid: {kothGrid.DisplayName} - {kothGrid.EntityId}");
                        }
                        else if (prizebox.GetInventory().CanItemsBeAdded(amount, definitionId))
                        {
                            prizebox.GetInventory().AddItems(amount, inventoryItem.Content);
                        }
                    }
                    else
                    {
                        if (zone.Entity.GetInventory().CanItemsBeAdded(amount, definitionId))
                        {
                            zone.Entity.GetInventory().AddItems(amount, inventoryItem.Content);
                        }
                    }
                }

                if (zone.UseOreReward.Value)
                {
                    string prizeType = (zone.AdvancedOreSelection.Value) ? zone.PrizeOreSubtypeId.Value : zone.SelectedOreString.Value;
                    int    amount    = zone.PrizeAmountOre.Value;

                    MyDefinitionId                definitionId  = new MyDefinitionId(typeof(MyObjectBuilder_Ore), prizeType);
                    MyObjectBuilder_Ore           content       = (MyObjectBuilder_Ore)MyObjectBuilderSerializer.CreateNewObject(definitionId);
                    MyObjectBuilder_InventoryItem inventoryItem = new MyObjectBuilder_InventoryItem {
                        Amount = amount, Content = content
                    };

                    if (zone.SpawnIntoPrizeBox.Value)
                    {
                        if (prizebox == null)
                        {
                            Tools.Log(MyLogSeverity.Error, $"Could not find prize box on grid: {kothGrid.DisplayName} - {kothGrid.EntityId}");
                        }
                        else if (prizebox.GetInventory().CanItemsBeAdded(amount, definitionId))
                        {
                            prizebox.GetInventory().AddItems(amount, inventoryItem.Content);
                        }
                    }
                    else
                    {
                        if (zone.Entity.GetInventory().CanItemsBeAdded(amount, definitionId))
                        {
                            zone.Entity.GetInventory().AddItems(amount, inventoryItem.Content);
                        }
                    }
                }
            }

            StringBuilder message = new StringBuilder();

            if (displayHeader && zone.IsLocationNamed.Value)
            {
                if (zone.EncampmentMode.Value)
                {
                    message.Append($"{kothGrid.DisplayName} on {planetName} Encampment Payout");
                }
                else
                {
                    message.Append($"{kothGrid.DisplayName} on {planetName} under attack");
                }
            }

            byte[] bytes = Encoding.ASCII.GetBytes(message.ToString());
            MyAPIGateway.Multiplayer.SendMessageToServer(8008, bytes);
            Network.Say(message.ToString());

            message.Clear();
            if (zone.AwardPointsAsCredits.Value)
            {
                message.Append($"{faction.Name} Scored {points} Points! ({points * zone.CreditsPerPoint.Value} credits)");
            }
            else
            {
                message.Append($"{faction.Name} Scored {points} Points!");
            }


            SaveData();

            //NEXUS: if nexus is initialized, broadcast the message to nexus (and all other sectors in that way)
            //NEXUS: KotH should work normally if nexus is not initialized
            if (nexusInit)
            {
                //NEXUS: sends the message this sector displays in the chat to all the other sectors
                byte[] nexMessage = Encoding.ASCII.GetBytes(message.ToString());
                Nexus.SendMessageToAllServers(nexMessage);

                //NEXUS: score is broadcasted to other sectors, this basically triggers the save not just on this sector but on all the others with the same score
                var serializedScore = MyAPIGateway.Utilities.SerializeToBinary <List <PlanetDescription> >(Planets);
                Nexus2.SendMessageToAllServers(serializedScore);
            }

            bytes = Encoding.ASCII.GetBytes(message.ToString());
            MyAPIGateway.Multiplayer.SendMessageToServer(8008, bytes);
            Network.Say(message.ToString());
        }
Exemple #23
0
        /// <summary>
        /// Loads the file from the specified stream.
        /// </summary>
        /// <param name="stream">The stream to read from.</param>
        public override void Load(Stream stream)
        {
            BinaryReader reader = new BinaryReader(stream, Encoding.GetEncoding("us-ascii"));

            int blockCount = reader.ReadInt32();

            for (int i = 0; i < blockCount; i++)
            {
                ZoneBlock type   = (ZoneBlock)reader.ReadInt32();
                int       offset = reader.ReadInt32();

                long nextBlock = stream.Position;
                stream.Seek(offset, SeekOrigin.Begin);

                switch (type)
                {
                case ZoneBlock.Info:
                    Type          = (ZoneType)reader.ReadInt32();
                    Width         = reader.ReadInt32();
                    Height        = reader.ReadInt32();
                    GridCount     = reader.ReadInt32();
                    GridSize      = reader.ReadSingle();
                    StartPosition = new IntVector2(reader.ReadInt32(), reader.ReadInt32());

                    for (int w = 0; w < Width; w++)
                    {
                        for (int h = 0; h < Height; h++)
                        {
                            Positions[w, h].IsUsed   = reader.ReadBoolean();
                            Positions[w, h].Position = reader.ReadVector2();
                        }
                    }
                    break;

                case ZoneBlock.SpawnPoints:
                    int spawnCount = reader.ReadInt32();

                    for (int j = 0; j < spawnCount; j++)
                    {
                        SpawnPoint spawnPoint = new SpawnPoint();
                        spawnPoint.Position = reader.ReadVector3();
                        spawnPoint.Name     = reader.ReadByteString();

                        SpawnPoints.Add(spawnPoint);
                    }
                    break;

                case ZoneBlock.Textures:
                    int textureCount = reader.ReadInt32();

                    for (int j = 0; j < textureCount; j++)
                    {
                        Textures.Add(reader.ReadByteString());
                    }
                    break;

                case ZoneBlock.Tiles:
                    int tileCount = reader.ReadInt32();

                    for (int j = 0; j < tileCount; j++)
                    {
                        ZoneTile tile = new ZoneTile();
                        tile.Layer1          = reader.ReadInt32();
                        tile.Layer2          = reader.ReadInt32();
                        tile.Offset1         = reader.ReadInt32();
                        tile.Offset2         = reader.ReadInt32();
                        tile.BlendingEnabled = reader.ReadInt32() != 0;
                        tile.Rotation        = (TileRotation)reader.ReadInt32();
                        tile.TileType        = reader.ReadInt32();

                        Tiles.Add(tile);
                    }
                    break;

                case ZoneBlock.Economy:
                    Name                    = reader.ReadByteString();
                    IsUnderground           = reader.ReadInt32() != 0;
                    BackgroundMusicFilePath = reader.ReadByteString();
                    SkyFilePath             = reader.ReadByteString();
                    EconomyCheckRate        = reader.ReadInt32();
                    PopulationBase          = reader.ReadInt32();
                    PopulationGrowthRate    = reader.ReadInt32();
                    MetalConsumption        = reader.ReadInt32();
                    StoneConsumption        = reader.ReadInt32();
                    WoodConsumption         = reader.ReadInt32();
                    LeatherConsumption      = reader.ReadInt32();
                    ClothConsumption        = reader.ReadInt32();
                    AlchemyConsumption      = reader.ReadInt32();
                    ChemicalConsumption     = reader.ReadInt32();
                    IndustrialConsumption   = reader.ReadInt32();
                    MedicineConsumption     = reader.ReadInt32();
                    FoodConsumption         = reader.ReadInt32();
                    break;
                }

                if (i < blockCount - 1)
                {
                    stream.Seek(nextBlock, SeekOrigin.Begin);
                }
            }
        }
        public static void CheckSpace(ZoneManager _this, ushort block, Vector3 position, float angle, int width, int length, ref ulong space1, ref ulong space2, ref ulong space3, ref ulong space4)
        {
            ZoneBlock zoneBlock = _this.m_blocks.m_buffer[(int)block];

            // difference of 2 radian angles (360 deg = 2*PI * 0.6366197f = 4f)
            // that means an angle difference of 90 deg would result in 1f
            float angleDiff      = Mathf.Abs(zoneBlock.m_angle - angle) * 0.6366197f;
            float rightAngleDiff = angleDiff - Mathf.Floor(angleDiff);

            // check if the input angle and the zone block are in right angle (0 90 180 270 deg), otherwise return
            if ((double)rightAngleDiff >= 0.0199999995529652 && (double)rightAngleDiff <= 0.980000019073486)
            {
                return;
            }

            float searchRadius = Mathf.Min(72f, (float)(width + length) * 4f) + 6f;

            float minX = position.x - searchRadius;
            float minZ = position.z - searchRadius;
            float maxX = position.x + searchRadius;
            float maxZ = position.z + searchRadius;

            // check if the zone block is in the area of interest, otherwise return
            if ((double)zoneBlock.m_position.x + 46.0 < (double)minX || (double)zoneBlock.m_position.x - 46.0 > (double)maxX ||
                ((double)zoneBlock.m_position.z + 46.0 < (double)minZ || (double)zoneBlock.m_position.z - 46.0 > (double)maxZ))
            {
                return;
            }

            // width of the zone block
            int rowCount    = zoneBlock.RowCount;
            int columnCount = ZoneBlockDetour.GetColumnCount(ref zoneBlock); // modified

            // orientation of the zone block
            Vector3 columnDirection = new Vector3(Mathf.Cos(zoneBlock.m_angle), 0.0f, Mathf.Sin(zoneBlock.m_angle)) * 8f;
            Vector3 rowDirection    = new Vector3(columnDirection.z, 0.0f, -columnDirection.x);

            // direction vectors for the given angle
            Vector3 angleParallelDirection   = new Vector3(Mathf.Cos(angle), 0.0f, Mathf.Sin(angle)) * 8f;
            Vector3 angleOrthogonalDirection = new Vector3(angleParallelDirection.z, 0.0f, -angleParallelDirection.x);

            for (int row = 0; row < rowCount; ++row)
            {
                Vector3 rowMiddleLength = ((float)row - 3.5f) * rowDirection;

                for (int column = 0; (long)column < columnCount; ++column)
                {
                    // check if the current cell is valid (not shared, not occupied)
                    if (((long)zoneBlock.m_valid & ~(long)zoneBlock.m_shared & ~((long)zoneBlock.m_occupied1 | (long)zoneBlock.m_occupied2) & 1L << (row << 3 | column)) != 0L)
                    {
                        Vector3 columnMiddleLength = ((float)column - 3.5f) * columnDirection;

                        // absolute position of the zone block cell
                        Vector3 cellPosition = zoneBlock.m_position + columnMiddleLength + rowMiddleLength;

                        // check if the cell is in search radius
                        if ((double)Mathf.Abs(position.x - cellPosition.x) < (double)searchRadius && (double)Mathf.Abs(position.z - cellPosition.z) < (double)searchRadius)
                        {
                            // cycle through every cell of the building plot
                            // find the cell that is in the same position as the zone block cell
                            bool cellsMatch = false;
                            for (int plotColumn = 0; plotColumn < length && !cellsMatch; ++plotColumn)
                            {
                                Vector3 plotColumnMiddleLength = (float)((double)plotColumn - (double)length * 0.5 + 0.5) * angleOrthogonalDirection;

                                for (int plotRow = 0; plotRow < width && !cellsMatch; ++plotRow)
                                {
                                    Vector3 plotRowMiddleLength = (float)((double)plotRow - (double)width * 0.5 + 0.5) * angleParallelDirection;

                                    // absolute position of the building plot cell
                                    Vector3 plotCellPosition = position + plotRowMiddleLength + plotColumnMiddleLength;

                                    // check if zone block cell and building plot cell positions match
                                    if ((double)Mathf.Abs(plotCellPosition.x - cellPosition.x) < 0.200000002980232 && (double)Mathf.Abs(plotCellPosition.z - cellPosition.z) < 0.200000002980232)
                                    {
                                        cellsMatch = true;
                                        // depending on column, use one of the 4 masks to report that a cell was found
                                        if (plotColumn < 4)
                                        {
                                            space1 = space1 | (ulong)(1L << (plotColumn << 4 | plotRow));
                                        }
                                        else if (plotColumn < 8)
                                        {
                                            space2 = space2 | (ulong)(1L << (plotColumn - 4 << 4 | plotRow));
                                        }
                                        else if (plotColumn < 12)
                                        {
                                            space3 = space3 | (ulong)(1L << (plotColumn - 8 << 4 | plotRow));
                                        }
                                        else
                                        {
                                            space4 = space4 | (ulong)(1L << (plotColumn - 12 << 4 | plotRow));
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Exemple #25
0
        public static void CalculateBlock2(ref ZoneBlock block, ushort blockID)
        {
            if (((int)block.m_flags & 3) != 1)
            {
                return;
            }
            int         rowCount  = block.RowCount;
            Vector2     vector2_1 = new Vector2(Mathf.Cos(block.m_angle), Mathf.Sin(block.m_angle)) * 8f;
            Vector2     vector2_2 = new Vector2(vector2_1.y, -vector2_1.x);
            Vector2     vector2_3 = VectorUtils.XZ(block.m_position);
            Vector2     vector2_4 = vector2_3 - 4f * vector2_1 - 4f * vector2_2;
            Vector2     vector2_5 = vector2_3 + 0.0f * vector2_1 - 4f * vector2_2;
            Vector2     vector2_6 = vector2_3 + 0.0f * vector2_1 + (float)(rowCount - 4) * vector2_2;
            Vector2     vector2_7 = vector2_3 - 4f * vector2_1 + (float)(rowCount - 4) * vector2_2;
            float       minX      = Mathf.Min(Mathf.Min(vector2_4.x, vector2_5.x), Mathf.Min(vector2_6.x, vector2_7.x));
            float       minZ      = Mathf.Min(Mathf.Min(vector2_4.y, vector2_5.y), Mathf.Min(vector2_6.y, vector2_7.y));
            float       maxX      = Mathf.Max(Mathf.Max(vector2_4.x, vector2_5.x), Mathf.Max(vector2_6.x, vector2_7.x));
            float       maxZ      = Mathf.Max(Mathf.Max(vector2_4.y, vector2_5.y), Mathf.Max(vector2_6.y, vector2_7.y));
            ulong       valid     = block.m_valid;
            ulong       shared    = 0UL;
            ZoneManager instance  = Singleton <ZoneManager> .instance;

            for (int index = 0; index < instance.m_cachedBlocks.m_size; ++index)
            {
                //begin mod
                CalculateImplementation2(ref block, blockID, ref instance.m_cachedBlocks.m_buffer[index], ref valid, ref shared, minX, minZ, maxX, maxZ);
            }
            //end mod
            //begin mod
            int num1 = Mathf.Max((int)(((double)minX - 46.0) / 64f + FakeZoneManager.HALFGRID), 0);
            int num2 = Mathf.Max((int)(((double)minZ - 46.0) / 64f + FakeZoneManager.HALFGRID), 0);
            int num3 = Mathf.Min((int)(((double)maxX + 46.0) / 64f + FakeZoneManager.HALFGRID), FakeZoneManager.GRIDSIZE - 1);
            int num4 = Mathf.Min((int)(((double)maxZ + 46.0) / 64f + FakeZoneManager.HALFGRID), FakeZoneManager.GRIDSIZE - 1);

            //end mod
            for (int index1 = num2; index1 <= num4; ++index1)
            {
                for (int index2 = num1; index2 <= num3; ++index2)
                {
                    //begin mod
                    ushort num5 = instance.m_zoneGrid[index1 * FakeZoneManager.GRIDSIZE + index2];
                    //end mod
                    int num6 = 0;
                    while ((int)num5 != 0)
                    {
                        Vector3 vector3 = instance.m_blocks.m_buffer[(int)num5].m_position;
                        if ((double)Mathf.Max(Mathf.Max(minX - 46f - vector3.x, minZ - 46f - vector3.z), Mathf.Max((float)((double)vector3.x - (double)maxX - 46.0), (float)((double)vector3.z - (double)maxZ - 46.0))) < 0.0 && (int)num5 != (int)blockID)
                        {
                            //begin mod
                            CalculateImplementation2(ref block, blockID, ref instance.m_blocks.m_buffer[(int)num5], ref valid, ref shared, minX, minZ, maxX, maxZ);
                        }
                        //end mod
                        num5 = instance.m_blocks.m_buffer[(int)num5].m_nextGridBlock;
                        if (++num6 >= ZoneManager.MAX_BLOCK_COUNT)
                        {
                            CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + System.Environment.StackTrace);

                            break;
                        }
                    }
                }
            }
            ulong num7 = 144680345676153346UL;

            for (int index = 0; index < 7; ++index)
            {
                valid  = (ulong)((long)valid & ~(long)num7 | (long)valid & (long)valid << 1 & (long)num7);
                num7 <<= 1;
            }
            block.m_valid  = valid;
            block.m_shared = shared;
        }
Exemple #26
0
 private static bool ApplyFillBuffer(ZoneTool z, Vector3 position, Vector3 direction, float angle, ushort blockIndex, ref ZoneBlock block)
 {
     UnityEngine.Debug.Log($"{z}-{position}-{direction}-{angle}-{blockIndex}-{block}");
     return(false);
 }
Exemple #27
0
        private static void CalculateFillBuffer(ZoneTool zt, Vector3 position, Vector3 direction, float angle, ushort blockIndex, ref ZoneBlock block, ItemClass.Zone requiredZone, bool occupied1, bool occupied2)
        {
            var m_fillBuffer1 = (ulong[])typeof(ZoneTool).GetField("m_fillBuffer1", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(zt);

            float f1   = Mathf.Abs(block.m_angle - angle) * 0.6366197f;
            float num1 = f1 - Mathf.Floor(f1);

            if ((double)num1 >= 0.00999999977648258 && (double)num1 <= 0.990000009536743)
            {
                return;
            }
            int     rowCount  = block.RowCount;
            Vector3 vector3_1 = new Vector3(Mathf.Cos(block.m_angle), 0.0f, Mathf.Sin(block.m_angle)) * 8f;
            Vector3 vector3_2 = new Vector3(vector3_1.z, 0.0f, -vector3_1.x);

            for (int z = 0; z < rowCount; ++z)
            {
                Vector3 vector3_3 = ((float)z - 3.5f) * vector3_2;
                for (int x = 0; x < 4; ++x)
                {
                    if (((long)block.m_valid & 1L << (z << 3 | x)) != 0L && block.GetZone(x, z) == requiredZone)
                    {
                        if (occupied1)
                        {
                            if (requiredZone == ItemClass.Zone.Unzoned && ((long)block.m_occupied1 & 1L << (z << 3 | x)) == 0L)
                            {
                                continue;
                            }
                        }
                        else if (occupied2)
                        {
                            if (requiredZone == ItemClass.Zone.Unzoned && ((long)block.m_occupied2 & 1L << (z << 3 | x)) == 0L)
                            {
                                continue;
                            }
                        }
                        else if ((((long)block.m_occupied1 | (long)block.m_occupied2) & 1L << (z << 3 | x)) != 0L)
                        {
                            continue;
                        }
                        Vector3 vector3_4 = ((float)x - 3.5f) * vector3_1;
                        Vector3 vector3_5 = block.m_position + vector3_4 + vector3_3 - position;
                        float   f2        = (float)(((double)vector3_5.x * (double)direction.x + (double)vector3_5.z * (double)direction.z) * 0.125 + 32.0);
                        float   f3        = (float)(((double)vector3_5.x * (double)direction.z - (double)vector3_5.z * (double)direction.x) * 0.125 + 32.0);
                        int     num2      = Mathf.RoundToInt(f2);
                        int     index     = Mathf.RoundToInt(f3);
                        if (num2 >= 0 && num2 < 64 && (index >= 0 && index < 64) && ((double)Mathf.Abs(f2 - (float)num2) < 0.0125000001862645 && (double)Mathf.Abs(f3 - (float)index) < 0.0125000001862645))
                        {
                            m_fillBuffer1[index] |= (ulong)(1L << num2);
                        }
                    }
                }
            }
        }
Exemple #28
0
 private static bool ApplyZoning(ZoneTool z, ushort blockIndex, ref ZoneBlock data, Quad2 quad2)
 {
     UnityEngine.Debug.Log($"{z}-{blockIndex}-{data}-{quad2}");
     return(false);
 }
 private static bool ApplyFillBuffer(ZoneTool z, Vector3 position, Vector3 direction, float angle, ushort blockIndex, ref ZoneBlock zoneBlock)
 {
     var parameters = new object[] { position, direction, angle, blockIndex, zoneBlock };
     bool b = (bool)z.GetType().GetMethod("ApplyFillBuffer", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance, null, new Type[] { typeof(Vector3), typeof(Vector3), typeof(float), typeof(ushort), typeof(ZoneBlock).MakeByRefType() }, null).Invoke(z, parameters);
     zoneBlock = (ZoneBlock)parameters[4];
     return b;
 }
Exemple #30
0
 private static void CalculateImplementation2(ref ZoneBlock zoneBlock, ushort blockID, ref ZoneBlock other, ref ulong valid, ref ulong shared, float minX, float minZ, float maxX, float maxZ)
 {
     UnityEngine.Debug.Log($"{zoneBlock}-{blockID}-{other}-{valid}-{shared}-{minX}-{minZ}-{maxX}-{maxZ}");
 }
Exemple #31
0
        // Detours

        public static void SimulationStep(ref ZoneBlock zoneBlock, ushort blockID)
        {
            // This is the decompiled ZoneBlock.SimulationStep() method
            // Segments which were changed are marked with "begin mod" and "end mod"

            if (Debugger.Enabled && debugCount < 10)
            {
                debugCount++;
                Debugger.LogFormat("Building Themes: Detoured ZoneBlock.SimulationStep was called. blockID: {0}, position: {1}.", blockID, zoneBlock.m_position);
            }

            ZoneManager zoneManager = Singleton <ZoneManager> .instance;
            int         rowCount    = zoneBlock.RowCount;
            float       m_angle     = zoneBlock.m_angle;

            Vector2 xDirection    = new Vector2(Mathf.Cos(m_angle), Mathf.Sin(m_angle)) * 8f;
            Vector2 zDirection    = new Vector2(xDirection.y, -xDirection.x);
            ulong   num           = zoneBlock.m_valid & ~(zoneBlock.m_occupied1 | zoneBlock.m_occupied2);
            int     spawnpointRow = 0;

            ItemClass.Zone zone = ItemClass.Zone.Unzoned;
            int            num3 = 0;

            while (num3 < 4 && zone == ItemClass.Zone.Unzoned)
            {
                spawnpointRow = Singleton <SimulationManager> .instance.m_randomizer.Int32((uint)rowCount);

                if ((num & 1uL << (spawnpointRow << 3)) != 0uL)
                {
                    zone = zoneBlock.GetZone(0, spawnpointRow);
                }
                num3++;
            }
            DistrictManager instance2 = Singleton <DistrictManager> .instance;

            Vector3 m_position = (Vector3)zoneBlock.m_position;

            byte district = instance2.GetDistrict(m_position);
            int  num4;

            switch (zone)
            {
            case ItemClass.Zone.ResidentialLow:
                num4  = zoneManager.m_actualResidentialDemand;
                num4 += instance2.m_districts.m_buffer[(int)district].CalculateResidentialLowDemandOffset();
                break;

            case ItemClass.Zone.ResidentialHigh:
                num4  = zoneManager.m_actualResidentialDemand;
                num4 += instance2.m_districts.m_buffer[(int)district].CalculateResidentialHighDemandOffset();
                break;

            case ItemClass.Zone.CommercialLow:
                num4  = zoneManager.m_actualCommercialDemand;
                num4 += instance2.m_districts.m_buffer[(int)district].CalculateCommercialLowDemandOffset();
                break;

            case ItemClass.Zone.CommercialHigh:
                num4  = zoneManager.m_actualCommercialDemand;
                num4 += instance2.m_districts.m_buffer[(int)district].CalculateCommercialHighDemandOffset();
                break;

            case ItemClass.Zone.Industrial:
                num4  = zoneManager.m_actualWorkplaceDemand;
                num4 += instance2.m_districts.m_buffer[(int)district].CalculateIndustrialDemandOffset();
                break;

            case ItemClass.Zone.Office:
                num4  = zoneManager.m_actualWorkplaceDemand;
                num4 += instance2.m_districts.m_buffer[(int)district].CalculateOfficeDemandOffset();
                break;

            default:
                return;
            }
            Vector2 a       = VectorUtils.XZ(m_position);
            Vector2 vector3 = a - 3.5f * xDirection + ((float)spawnpointRow - 3.5f) * zDirection;

            int[] tmpXBuffer = zoneManager.m_tmpXBuffer;
            for (int i = 0; i < 13; i++)
            {
                tmpXBuffer[i] = 0;
            }

            Quad2 quad = default(Quad2);

            quad.a = a - 4f * xDirection + ((float)spawnpointRow - 10f) * zDirection;
            quad.b = a + 3f * xDirection + ((float)spawnpointRow - 10f) * zDirection;
            quad.c = a + 3f * xDirection + ((float)spawnpointRow + 2f) * zDirection;
            quad.d = a - 4f * xDirection + ((float)spawnpointRow + 2f) * zDirection;
            Vector2 vector4 = quad.Min();
            Vector2 vector5 = quad.Max();

            //begin mod
            int num5 = Mathf.Max((int)((vector4.x - 46f) / 64f + _zoneGridHalfResolution), 0);
            int num6 = Mathf.Max((int)((vector4.y - 46f) / 64f + _zoneGridHalfResolution), 0);
            int num7 = Mathf.Min((int)((vector5.x + 46f) / 64f + _zoneGridHalfResolution), _zoneGridResolution - 1);
            int num8 = Mathf.Min((int)((vector5.y + 46f) / 64f + _zoneGridHalfResolution), _zoneGridResolution - 1);

            //end mod
            for (int j = num6; j <= num8; j++)
            {
                for (int k = num5; k <= num7; k++)
                {
                    //begin mod
                    ushort num9 = zoneManager.m_zoneGrid[j * _zoneGridResolution + k];
                    //end mod
                    int num10 = 0;
                    while (num9 != 0)
                    {
                        Vector3 positionVar = zoneManager.m_blocks.m_buffer[(int)num9].m_position;
                        float   num11       = Mathf.Max(Mathf.Max(vector4.x - 46f - positionVar.x, vector4.y - 46f - positionVar.z),
                                                        Mathf.Max(positionVar.x - vector5.x - 46f, positionVar.z - vector5.y - 46f));

                        if (num11 < 0f)
                        {
                            _CheckBlock.Invoke(zoneBlock, new object[] { zoneManager.m_blocks.m_buffer[(int)num9], tmpXBuffer, zone, vector3, xDirection, zDirection, quad });
                        }
                        num9 = zoneManager.m_blocks.m_buffer[(int)num9].m_nextGridBlock;
                        if (++num10 >= 49152)
                        {
                            CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace);

                            break;
                        }
                    }
                }
            }

            for (int l = 0; l < 13; l++)
            {
                uint num12 = (uint)tmpXBuffer[l];
                int  num13 = 0;
                bool flag  = (num12 & 196608u) == 196608u;
                bool flag2 = false;
                while ((num12 & 1u) != 0u)
                {
                    num13++;
                    flag2   = ((num12 & 65536u) != 0u);
                    num12 >>= 1;
                }
                if (num13 == 5 || num13 == 6)
                {
                    if (flag2)
                    {
                        num13 -= Singleton <SimulationManager> .instance.m_randomizer.Int32(2u) + 2;
                    }
                    else
                    {
                        num13 = 4;
                    }
                    num13 |= 131072;
                }
                else if (num13 == 7)
                {
                    num13  = 4;
                    num13 |= 131072;
                }
                if (flag)
                {
                    num13 |= 65536;
                }
                tmpXBuffer[l] = num13;
            }
            int num14 = tmpXBuffer[6] & 65535;

            if (num14 == 0)
            {
                return;
            }

            bool flag3 = (bool)_IsGoodPlace.Invoke(zoneBlock, new object[] { vector3 });

            if (Singleton <SimulationManager> .instance.m_randomizer.Int32(100u) >= num4)
            {
                if (flag3)
                {
                    zoneManager.m_goodAreaFound[(int)zone] = 1024;
                }
                return;
            }
            if (!flag3 && zoneManager.m_goodAreaFound[(int)zone] > -1024)
            {
                if (zoneManager.m_goodAreaFound[(int)zone] == 0)
                {
                    zoneManager.m_goodAreaFound[(int)zone] = -1;
                }
                return;
            }
            int  num15 = 6;
            int  num16 = 6;
            bool flag4 = true;

            while (true)
            {
                if (flag4)
                {
                    while (num15 != 0)
                    {
                        if ((tmpXBuffer[num15 - 1] & 65535) != num14)
                        {
                            break;
                        }
                        num15--;
                    }
                    while (num16 != 12)
                    {
                        if ((tmpXBuffer[num16 + 1] & 65535) != num14)
                        {
                            break;
                        }
                        num16++;
                    }
                }
                else
                {
                    while (num15 != 0)
                    {
                        if ((tmpXBuffer[num15 - 1] & 65535) < num14)
                        {
                            break;
                        }
                        num15--;
                    }
                    while (num16 != 12)
                    {
                        if ((tmpXBuffer[num16 + 1] & 65535) < num14)
                        {
                            break;
                        }
                        num16++;
                    }
                }
                int num17 = num15;
                int num18 = num16;
                while (num17 != 0)
                {
                    if ((tmpXBuffer[num17 - 1] & 65535) < 2)
                    {
                        break;
                    }
                    num17--;
                }
                while (num18 != 12)
                {
                    if ((tmpXBuffer[num18 + 1] & 65535) < 2)
                    {
                        break;
                    }
                    num18++;
                }
                bool flag5 = num17 != 0 && num17 == num15 - 1;
                bool flag6 = num18 != 12 && num18 == num16 + 1;
                if (flag5 && flag6)
                {
                    if (num16 - num15 > 2)
                    {
                        break;
                    }
                    if (num14 <= 2)
                    {
                        if (!flag4)
                        {
                            goto Block_34;
                        }
                    }
                    else
                    {
                        num14--;
                    }
                }
                else if (flag5)
                {
                    if (num16 - num15 > 1)
                    {
                        goto Block_36;
                    }
                    if (num14 <= 2)
                    {
                        if (!flag4)
                        {
                            goto Block_38;
                        }
                    }
                    else
                    {
                        num14--;
                    }
                }
                else if (flag6)
                {
                    if (num16 - num15 > 1)
                    {
                        goto Block_40;
                    }
                    if (num14 <= 2)
                    {
                        if (!flag4)
                        {
                            goto Block_42;
                        }
                    }
                    else
                    {
                        num14--;
                    }
                }
                else
                {
                    if (num15 != num16)
                    {
                        goto IL_884;
                    }
                    if (num14 <= 2)
                    {
                        if (!flag4)
                        {
                            goto Block_45;
                        }
                    }
                    else
                    {
                        num14--;
                    }
                }
                flag4 = false;
            }
            num15++;
            num16--;
Block_34:
            goto IL_891;
Block_36:
            num15++;
Block_38:
            goto IL_891;
Block_40:
            num16--;
Block_42:
Block_45:
IL_884:
IL_891:
            int num19;
            int num20;

            if (num14 == 1 && num16 - num15 >= 1)
            {
                num15 += Singleton <SimulationManager> .instance.m_randomizer.Int32((uint)(num16 - num15));

                num16 = num15 + 1;
                num19 = num15 + Singleton <SimulationManager> .instance.m_randomizer.Int32(2u);

                num20 = num19;
            }
            else
            {
                do
                {
                    num19 = num15;
                    num20 = num16;
                    if (num16 - num15 == 2)
                    {
                        if (Singleton <SimulationManager> .instance.m_randomizer.Int32(2u) == 0)
                        {
                            num20--;
                        }
                        else
                        {
                            num19++;
                        }
                    }
                    else if (num16 - num15 == 3)
                    {
                        if (Singleton <SimulationManager> .instance.m_randomizer.Int32(2u) == 0)
                        {
                            num20 -= 2;
                        }
                        else
                        {
                            num19 += 2;
                        }
                    }
                    else if (num16 - num15 == 4)
                    {
                        if (Singleton <SimulationManager> .instance.m_randomizer.Int32(2u) == 0)
                        {
                            num16 -= 2;
                            num20 -= 3;
                        }
                        else
                        {
                            num15 += 2;
                            num19 += 3;
                        }
                    }
                    else if (num16 - num15 == 5)
                    {
                        if (Singleton <SimulationManager> .instance.m_randomizer.Int32(2u) == 0)
                        {
                            num16 -= 3;
                            num20 -= 2;
                        }
                        else
                        {
                            num15 += 3;
                            num19 += 2;
                        }
                    }
                    else if (num16 - num15 >= 6)
                    {
                        if (num15 == 0 || num16 == 12)
                        {
                            if (num15 == 0)
                            {
                                num15 = 3;
                                num19 = 2;
                            }
                            if (num16 == 12)
                            {
                                num16 = 9;
                                num20 = 10;
                            }
                        }
                        else if (Singleton <SimulationManager> .instance.m_randomizer.Int32(2u) == 0)
                        {
                            num16 = num15 + 3;
                            num20 = num19 + 2;
                        }
                        else
                        {
                            num15 = num16 - 3;
                            num19 = num20 - 2;
                        }
                    }
                }while (num16 - num15 > 3 || num20 - num19 > 3);
            }
            int depth_A = 4;
            int width_A = num16 - num15 + 1;

            BuildingInfo.ZoningMode zoningMode = BuildingInfo.ZoningMode.Straight;
            bool flag7 = true;

            for (int m = num15; m <= num16; m++)
            {
                depth_A = Mathf.Min(depth_A, tmpXBuffer[m] & 65535);
                if ((tmpXBuffer[m] & 131072) == 0)
                {
                    flag7 = false;
                }
            }
            if (num16 > num15)
            {
                if ((tmpXBuffer[num15] & 65536) != 0)
                {
                    zoningMode = BuildingInfo.ZoningMode.CornerLeft;
                    num20      = num15 + num20 - num19;
                    num19      = num15;
                }
                if ((tmpXBuffer[num16] & 65536) != 0 && (zoningMode != BuildingInfo.ZoningMode.CornerLeft || Singleton <SimulationManager> .instance.m_randomizer.Int32(2u) == 0))
                {
                    zoningMode = BuildingInfo.ZoningMode.CornerRight;
                    num19      = num16 + num19 - num20;
                    num20      = num16;
                }
            }
            int depth_B = 4;
            int width_B = num20 - num19 + 1;

            BuildingInfo.ZoningMode zoningMode2 = BuildingInfo.ZoningMode.Straight;
            bool flag8 = true;

            for (int n = num19; n <= num20; n++)
            {
                depth_B = Mathf.Min(depth_B, tmpXBuffer[n] & 65535);
                if ((tmpXBuffer[n] & 131072) == 0)
                {
                    flag8 = false;
                }
            }
            if (num20 > num19)
            {
                if ((tmpXBuffer[num19] & 65536) != 0)
                {
                    zoningMode2 = BuildingInfo.ZoningMode.CornerLeft;
                }
                if ((tmpXBuffer[num20] & 65536) != 0 && (zoningMode2 != BuildingInfo.ZoningMode.CornerLeft || Singleton <SimulationManager> .instance.m_randomizer.Int32(2u) == 0))
                {
                    zoningMode2 = BuildingInfo.ZoningMode.CornerRight;
                }
            }
            ItemClass.SubService subService = ItemClass.SubService.None;
            ItemClass.Level      level      = ItemClass.Level.Level1;
            ItemClass.Service    service;
            switch (zone)
            {
            case ItemClass.Zone.ResidentialLow:
                service    = ItemClass.Service.Residential;
                subService = ItemClass.SubService.ResidentialLow;
                break;

            case ItemClass.Zone.ResidentialHigh:
                service    = ItemClass.Service.Residential;
                subService = ItemClass.SubService.ResidentialHigh;
                break;

            case ItemClass.Zone.CommercialLow:
                service    = ItemClass.Service.Commercial;
                subService = ItemClass.SubService.CommercialLow;
                break;

            case ItemClass.Zone.CommercialHigh:
                service    = ItemClass.Service.Commercial;
                subService = ItemClass.SubService.CommercialHigh;
                break;

            case ItemClass.Zone.Industrial:
                service = ItemClass.Service.Industrial;
                break;

            case ItemClass.Zone.Office:
                service    = ItemClass.Service.Office;
                subService = ItemClass.SubService.None;
                break;

            default:
                return;
            }
            BuildingInfo buildingInfo = null;
            Vector3      vector6      = Vector3.zero;
            int          num25_row    = 0;
            int          length       = 0;
            int          width        = 0;

            BuildingInfo.ZoningMode zoningMode3 = BuildingInfo.ZoningMode.Straight;
            int num28 = 0;

            // begin mod
            int depth_alt = Mathf.Min(depth_A, 4);
            int width_alt = width_A;

            // end mod

            while (num28 < 8) // while (num28 < 6)
            {
                switch (num28)
                {
                // Corner cases

                case 0:
                    if (zoningMode != BuildingInfo.ZoningMode.Straight)
                    {
                        num25_row   = num15 + num16 + 1;
                        length      = depth_A;
                        width       = width_A;
                        zoningMode3 = zoningMode;
                        goto IL_D6A;
                    }
                    break;

                case 1:
                    if (zoningMode2 != BuildingInfo.ZoningMode.Straight)
                    {
                        num25_row   = num19 + num20 + 1;
                        length      = depth_B;
                        width       = width_B;
                        zoningMode3 = zoningMode2;
                        goto IL_D6A;
                    }
                    break;

                case 2:
                    if (zoningMode != BuildingInfo.ZoningMode.Straight)
                    {
                        if (depth_A >= 4)
                        {
                            num25_row   = num15 + num16 + 1;
                            length      = ((!flag7) ? 2 : 3);
                            width       = width_A;
                            zoningMode3 = zoningMode;
                            goto IL_D6A;
                        }
                    }
                    break;

                case 3:
                    if (zoningMode2 != BuildingInfo.ZoningMode.Straight)
                    {
                        if (depth_B >= 4)
                        {
                            num25_row   = num19 + num20 + 1;
                            length      = ((!flag8) ? 2 : 3);
                            width       = width_B;
                            zoningMode3 = zoningMode2;
                            goto IL_D6A;
                        }
                    }
                    break;

                // begin mod
                case 4:
                    if (zoningMode != BuildingInfo.ZoningMode.Straight)
                    {
                        if (width_alt > 1)
                        {
                            width_alt--;
                        }
                        else if (depth_alt > 1)
                        {
                            depth_alt--;
                            width_alt = width_A;
                        }
                        else
                        {
                            break;
                        }

                        if (width_alt == width_A)
                        {
                            num25_row = num15 + num16 + 1;
                        }
                        else
                        {
                            if (zoningMode == BuildingInfo.ZoningMode.CornerLeft)
                            {
                                num25_row = num15 + num16 + 1 - (width_A - width_alt);
                            }
                            else
                            {
                                num25_row = num15 + num16 + 1 + (width_A - width_alt);
                            }
                        }

                        length = depth_alt;
                        width  = width_alt;

                        zoningMode3 = zoningMode;

                        num28--;
                        goto IL_D6A;
                    }
                    break;

                // end mod
                // Straight cases
                case 5:
                    num25_row   = num15 + num16 + 1;
                    length      = depth_A;
                    width       = width_A;
                    zoningMode3 = BuildingInfo.ZoningMode.Straight;
                    goto IL_D6A;

                case 6:
                    // begin mod

                    // reset variables
                    depth_alt = Mathf.Min(depth_A, 4);
                    width_alt = width_A;

                    // end mod

                    //int width_B = num20 - num19 + 1;
                    num25_row   = num19 + num20 + 1;
                    length      = depth_B;
                    width       = width_B;
                    zoningMode3 = BuildingInfo.ZoningMode.Straight;
                    goto IL_D6A;

                // begin mod
                case 7:

                    if (width_alt > 1)
                    {
                        width_alt--;
                    }
                    else
                    {
                        break;
                    }

                    if (width_alt == width_A)
                    {
                        num25_row = num15 + num16 + 1;
                    }
                    else if (width_A % 2 != width_alt % 2)
                    {
                        num25_row = num15 + num16;
                    }
                    else
                    {
                        num25_row = num15 + num16 + 1;
                    }

                    length = depth_alt;
                    width  = width_alt;

                    zoningMode3 = BuildingInfo.ZoningMode.Straight;

                    num28--;
                    goto IL_D6A;

                // end mod
                default:
                    goto IL_D6A;
                }
IL_DF0:
                num28++;
                continue;
IL_D6A:
                vector6 = m_position + VectorUtils.X_Y(((float)length * 0.5f - 4f) * xDirection + ((float)num25_row * 0.5f + (float)spawnpointRow - 10f) * zDirection);
                if (zone == ItemClass.Zone.Industrial)
                {
                    ZoneBlock.GetIndustryType(vector6, out subService, out level);
                }
                else if (zone == ItemClass.Zone.CommercialLow || zone == ItemClass.Zone.CommercialHigh)
                {
                    ZoneBlock.GetCommercialType(vector6, zone, width, length, out subService, out level);
                }

                byte   district2 = instance2.GetDistrict(vector6);
                ushort style     = instance2.m_districts.m_buffer[(int)district2].m_Style;

                // begin mod

                // Here we are calling a custom getRandomBuildingInfo method

                buildingInfo = BuildingManagerDetour.GetRandomBuildingInfo_Spawn(vector6, ref Singleton <SimulationManager> .instance.m_randomizer, service, subService, level, width, length, zoningMode3, style);

                // end mod

                if (buildingInfo != null)
                {
                    // begin mod

                    // If the depth of the found prefab is smaller than the one we were looking for, recalculate the size
                    // This is done by checking the position of every prop
                    // Plots only get shrinked when no assets are placed on the extra space

                    // This is needed for themes which only contain small buildings (e.g. 1x2)
                    // because those buildings would occupy more space than needed!

                    if (buildingInfo.GetWidth() == width && buildingInfo.GetLength() != length)
                    {
                        // Calculate the z position of the furthest away prop
                        float biggestPropPosZ = 0;

                        if (buildingInfo.m_props != null)
                        {
                            foreach (var prop in buildingInfo.m_props)
                            {
                                if (prop == null)
                                {
                                    continue;
                                }

                                biggestPropPosZ = Mathf.Max(biggestPropPosZ, buildingInfo.m_expandFrontYard ? prop.m_position.z : -prop.m_position.z);
                            }
                        }

                        // Check if the furthest away prop is outside of the bounds of the prefab
                        float occupiedExtraSpace = biggestPropPosZ - buildingInfo.GetLength() * 4;
                        if (occupiedExtraSpace <= 0)
                        {
                            // No? Then shrink the plot to the prefab length so no space is wasted!
                            length = buildingInfo.GetLength();
                        }
                        else
                        {
                            // Yes? Shrink the plot so all props are in the bounds
                            int newLength = buildingInfo.GetLength() + Mathf.CeilToInt(occupiedExtraSpace / 8);
                            length = Mathf.Min(length, newLength);
                        }

                        vector6 = m_position + VectorUtils.X_Y(((float)length * 0.5f - 4f) * xDirection + ((float)num25_row * 0.5f + (float)spawnpointRow - 10f) * zDirection);
                    }

                    // This block handles Corner buildings. We always shrink them
                    else if (buildingInfo.GetLength() == width && buildingInfo.GetWidth() != length)
                    {
                        length  = buildingInfo.GetWidth();
                        vector6 = m_position + VectorUtils.X_Y(((float)length * 0.5f - 4f) * xDirection + ((float)num25_row * 0.5f + (float)spawnpointRow - 10f) * zDirection);
                    }

                    // end mod

                    if (Debugger.Enabled)
                    {
                        Debugger.LogFormat("Found prefab: {5} - {0}, {1}, {2}, {3} x {4}", service, subService, level, width, length, buildingInfo.name);
                    }
                    break;
                }
                if (Debugger.Enabled)
                {
                }
                goto IL_DF0;
            }
            if (buildingInfo == null)
            {
                if (Debugger.Enabled)
                {
                    Debugger.LogFormat("No prefab found: {0}, {1}, {2}, {3} x {4}", service, subService, level, width, length);
                }
                return;
            }
            float num29 = Singleton <TerrainManager> .instance.WaterLevel(VectorUtils.XZ(vector6));

            if (num29 > vector6.y)
            {
                return;
            }
            float num30 = m_angle + 1.57079637f;

            if (zoningMode3 == BuildingInfo.ZoningMode.CornerLeft && buildingInfo.m_zoningMode == BuildingInfo.ZoningMode.CornerRight)
            {
                num30 -= 1.57079637f;
                length = width;
            }
            else if (zoningMode3 == BuildingInfo.ZoningMode.CornerRight && buildingInfo.m_zoningMode == BuildingInfo.ZoningMode.CornerLeft)
            {
                num30 += 1.57079637f;
                length = width;
            }
            ushort num31;

            if (Singleton <BuildingManager> .instance.CreateBuilding(out num31, ref Singleton <SimulationManager> .instance.m_randomizer, buildingInfo, vector6, num30, length, Singleton <SimulationManager> .instance.m_currentBuildIndex))
            {
                Singleton <SimulationManager> .instance.m_currentBuildIndex += 1u;
                switch (service)
                {
                case ItemClass.Service.Residential:
                    zoneManager.m_actualResidentialDemand = Mathf.Max(0, zoneManager.m_actualResidentialDemand - 5);
                    break;

                case ItemClass.Service.Commercial:
                    zoneManager.m_actualCommercialDemand = Mathf.Max(0, zoneManager.m_actualCommercialDemand - 5);
                    break;

                case ItemClass.Service.Industrial:
                    zoneManager.m_actualWorkplaceDemand = Mathf.Max(0, zoneManager.m_actualWorkplaceDemand - 5);
                    break;

                case ItemClass.Service.Office:
                    zoneManager.m_actualWorkplaceDemand = Mathf.Max(0, zoneManager.m_actualWorkplaceDemand - 5);
                    break;
                }

                switch (zone)
                {
                case ItemClass.Zone.ResidentialHigh:
                case ItemClass.Zone.CommercialHigh:
                {
                    Building[] expr_FD7_cp_0 = Singleton <BuildingManager> .instance.m_buildings.m_buffer;
                    ushort     expr_FD7_cp_1 = num31;
                    expr_FD7_cp_0[(int)expr_FD7_cp_1].m_flags = (expr_FD7_cp_0[(int)expr_FD7_cp_1].m_flags | Building.Flags.HighDensity);
                    break;
                }
                }
            }
            zoneManager.m_goodAreaFound[(int)zone] = 1024;
        }
Exemple #32
0
 private static bool IsGoodPlace(ref ZoneBlock zoneBlock, Vector2 position)
 {
     UnityEngine.Debug.Log($"{zoneBlock}-{position}");
     return(false);
 }
Exemple #33
0
 public static void UnRegisterZone(ZoneBlock zone)
 {
     Zones.Remove(zone);
 }
 private static void CheckZoning(ref Building b, ItemClass.Zone zone1, ItemClass.Zone zone2, ref uint validCells, ref bool secondary, ref ZoneBlock block)
 {
     UnityEngine.Debug.LogError("FakeBuilding - Failed to redirect reverse CheckZoning()");
 }
        public static void CalculateBlock1(ref ZoneBlock _this, ushort blockID)
        {
            // skip zone blocks which are not in use
            if (((int)_this.m_flags & 3) != ZoneBlock.FLAG_CREATED) return;

            // width of the zone block
            int rowCount = _this.RowCount;
            int columnCount = ZoneBlockDetour.GetColumnCount(ref _this); // modified

            // directions of the rows and columns based on zone block angle, multiplied by 8 (cell size)
            Vector2 columnDirection = new Vector2(Mathf.Cos(_this.m_angle), Mathf.Sin(_this.m_angle)) * 8f;
            Vector2 rowDirection = new Vector2(columnDirection.y, -columnDirection.x);

            // origin of the zone block
            // this position is in the center of the 8x8 zone block (4 columns and 4 rows away from the lower corner)
            Vector2 positionXZ = VectorUtils.XZ(_this.m_position);

            // area of the zone block (8x4 cells)
            Quad2 zoneBlockQuad = new Quad2()
            {
                a = positionXZ - 4f * columnDirection - 4f * rowDirection,
                b = positionXZ + (columnCount - 4f) * columnDirection - 4f * rowDirection,
                c = positionXZ + (columnCount - 4f) * columnDirection + (float)(rowCount - 4) * rowDirection,
                d = positionXZ - 4f * columnDirection + (float)(rowCount - 4) * rowDirection
            };

            Vector2 quadMin = zoneBlockQuad.Min();
            Vector2 quadMax = zoneBlockQuad.Max();

            NetManager netManager = Singleton<NetManager>.instance;

            // calculate which net segment grid cells are touched by this zone block
            int gridMinX = Mathf.Max((int)(((double)quadMin.x - 64.0) / 64.0 + 135.0), 0);
            int gridMinY = Mathf.Max((int)(((double)quadMin.y - 64.0) / 64.0 + 135.0), 0);
            int gridMaxX = Mathf.Min((int)(((double)quadMax.x + 64.0) / 64.0 + 135.0), 269);
            int gridMaxY = Mathf.Min((int)(((double)quadMax.y + 64.0) / 64.0 + 135.0), 269);

            // This bitmask stores which which cells are "valid" and which are "invalid"
            // (e.g. colliding with existing buildings or height too steep)
            // This mask limits the maximum size of a zone block to 64 cells (e.g. 8x8)
            // Sort order: (row 8|col 8)(row 8|col 7)...(row 8|col 2)(row 8|col 1)(row 7|col 4)(row 7|col 3)...(row 1|col 1)
            ulong valid = ulong.MaxValue;
            bool quadOutOfArea = Singleton<GameAreaManager>.instance.QuadOutOfArea(zoneBlockQuad);

            // Mark cells which are on too steep terrain or outside of the purchased tiles as invalid
            for (int row = 0; row < rowCount; ++row)
            {
                // calculate 3 relative row positions:
                // * One in between 2 cell grid points
                // * one 0.1m from previous row
                // * one 0.1m from next row
                Vector2 rowMiddleLength = ((float)row - 3.5f) * rowDirection;
                Vector2 rowNearPreviousLength = ((float)row - 3.9f) * rowDirection;
                Vector2 rowNearNextLength = ((float)row - 3.1f) * rowDirection;

                // calculate terrain height of the row (5 columns away from zone block origin)
                // that's where the road is
                float height = Singleton<TerrainManager>.instance.SampleRawHeightSmooth(VectorUtils.X_Y(positionXZ + rowMiddleLength - 5f * columnDirection));

                for (int column = 0; column < columnCount; ++column)
                {
                    // calculate 2 relative column positions:
                    // * one 0.1m from previous column
                    // * one 0.1m from next column
                    Vector2 columnNearPreviousLength = ((float)column - 3.9f) * columnDirection;
                    Vector2 columnNearNextLength = ((float)column - 3.1f) * columnDirection;

                    // calculate terrain height of the cell (row middle, side away from road)
                    float cellHeight = Singleton<TerrainManager>.instance.SampleRawHeightSmooth(VectorUtils.X_Y(positionXZ + rowMiddleLength + columnNearNextLength));

                    // if the height difference between road and cell is greater than 8m, mark the cell as invalid
                    if ((double)Mathf.Abs(cellHeight - height) > 8.0) // TODO maybe this should be raised for 8 cell deep zones?
                    {
                        valid &= ~(1UL << (row << 3 | column));
                    }
                    else if (quadOutOfArea)
                    {
                        // if the cell is outside of the purchased tiles, mark the cell as invalid
                        if (Singleton<GameAreaManager>.instance.QuadOutOfArea(new Quad2()
                        {
                            a = positionXZ + columnNearPreviousLength + rowNearPreviousLength,
                            b = positionXZ + columnNearNextLength + rowNearPreviousLength,
                            c = positionXZ + columnNearNextLength + rowNearNextLength,
                            d = positionXZ + columnNearPreviousLength + rowNearNextLength
                        }))
                            valid &= ~(1UL << (row << 3 | column));
                    }
                }
            }

            // Mark cells which are overlapped by network segments as invalid
            for (int gridY = gridMinY; gridY <= gridMaxY; ++gridY)
            {
                for (int gridX = gridMinX; gridX <= gridMaxX; ++gridX)
                {
                    // cycle through all net segments in the grid cell
                    ushort segmentID = netManager.m_segmentGrid[gridY * 270 + gridX];
                    int counter = 0;
                    while ((int)segmentID != 0)
                    {
                        if (netManager.m_segments.m_buffer[(int)segmentID].Info.m_class.m_layer == ItemClass.Layer.Default)
                        {
                            ushort startNode = netManager.m_segments.m_buffer[(int)segmentID].m_startNode;
                            ushort endNode = netManager.m_segments.m_buffer[(int)segmentID].m_endNode;
                            Vector3 startNodePos = netManager.m_nodes.m_buffer[(int)startNode].m_position;
                            Vector3 endNodePos = netManager.m_nodes.m_buffer[(int)endNode].m_position;

                            // check if the segment (one of its nodes) is in the area of zone block
                            if ((double)Mathf.Max(Mathf.Max(quadMin.x - 64f - startNodePos.x, quadMin.y - 64f - startNodePos.z), Mathf.Max((float)((double)startNodePos.x - (double)quadMax.x - 64.0), (float)((double)startNodePos.z - (double)quadMax.y - 64.0))) < 0.0
                                || (double)Mathf.Max(Mathf.Max(quadMin.x - 64f - endNodePos.x, quadMin.y - 64f - endNodePos.z), Mathf.Max((float)((double)endNodePos.x - (double)quadMax.x - 64.0), (float)((double)endNodePos.z - (double)quadMax.y - 64.0))) < 0.0)
                            {
                                // Mark zone cells overlapped by network segments as invalid
                                CalculateImplementation1(ref _this, blockID, segmentID, ref netManager.m_segments.m_buffer[(int)segmentID], ref valid, quadMin.x, quadMin.y, quadMax.x, quadMax.y);
                            }
                        }
                        // next segment in grid cell (linked list)
                        segmentID = netManager.m_segments.m_buffer[(int)segmentID].m_nextGridSegment;
                        if (++counter >= 36864)
                        {
                            CODebugBase<LogChannel>.Error(LogChannel.Core, "Invalid list detected!\n" + System.Environment.StackTrace);
                            break;
                        }
                    }
                }
            }

            // This part marks all cells as invalid which are behind existing invalid cells (so that there are no cells with no road access)
            // 0000 0100 0000 0100 0000 0100 0000 0100
            // 0000 0100 0000 0100 0000 0100 0000 0100
            ulong mask = 144680345676153346;
            for (int iteration = 0; iteration < 7; ++iteration)
            {
                valid = valid & ~mask | valid & valid << 1 & mask;
                mask <<= 1;
            }

            // apply the new mask, reset shared mask
            _this.m_valid = valid;
            _this.m_shared = 0UL;
        }
Exemple #36
0
        private static void CheckZoning(ref Building _this, ItemClass.Zone zone1, ItemClass.Zone zone2, ref uint validCells, ref bool secondary, ref ZoneBlock block)
        {
            BuildingInfo.ZoningMode zoningMode = _this.Info.m_zoningMode;
            int     width       = _this.Width;
            int     length      = _this.Length;
            Vector3 vector3_1   = new Vector3(Mathf.Cos(_this.m_angle), 0.0f, Mathf.Sin(_this.m_angle)) * 8f;
            Vector3 vector3_2   = new Vector3(vector3_1.z, 0.0f, -vector3_1.x);
            int     rowCount    = block.RowCount;
            int     columnCount = ZoneBlockDetour.GetColumnCount(ref block); // modified
            Vector3 vector3_3   = new Vector3(Mathf.Cos(block.m_angle), 0.0f, Mathf.Sin(block.m_angle)) * 8f;
            Vector3 vector3_4   = new Vector3(vector3_3.z, 0.0f, -vector3_3.x);
            Vector3 vector3_5   = block.m_position - _this.m_position + vector3_1 * (float)((double)width * 0.5 - 0.5) + vector3_2 * (float)((double)length * 0.5 - 0.5);

            for (int z = 0; z < rowCount; ++z)
            {
                Vector3 vector3_6 = ((float)z - 3.5f) * vector3_4;
                for (int x = 0; (long)x < columnCount; ++x) // modified
                {
                    if (((long)block.m_valid & ~(long)block.m_shared & 1L << (z << 3 | x)) != 0L)
                    {
                        ItemClass.Zone zone  = block.GetZone(x, z);
                        bool           flag1 = zone == zone1;
                        if (zone == zone2 && zone2 != ItemClass.Zone.None)
                        {
                            flag1     = true;
                            secondary = true;
                        }
                        if (flag1)
                        {
                            Vector3 vector3_7 = ((float)x - 3.5f) * vector3_3;
                            Vector3 vector3_8 = vector3_5 + vector3_7 + vector3_6;
                            float   num1      = (float)((double)vector3_1.x * (double)vector3_8.x + (double)vector3_1.z * (double)vector3_8.z);
                            float   num2      = (float)((double)vector3_2.x * (double)vector3_8.x + (double)vector3_2.z * (double)vector3_8.z);
                            int     num3      = Mathf.RoundToInt(num1 / 64f);
                            int     num4      = Mathf.RoundToInt(num2 / 64f);
                            bool    flag2     = false;
                            if (zoningMode == BuildingInfo.ZoningMode.Straight)
                            {
                                flag2 = num4 == 0;
                            }
                            else if (zoningMode == BuildingInfo.ZoningMode.CornerLeft)
                            {
                                flag2 = num4 == 0 && num3 >= width - 2 || num4 <= 1 && num3 == width - 1;
                            }
                            else if (zoningMode == BuildingInfo.ZoningMode.CornerRight)
                            {
                                flag2 = num4 == 0 && num3 <= 1 || num4 <= 1 && num3 == 0;
                            }
                            if ((!flag2 || x == 0) && (num3 >= 0 && num4 >= 0) && (num3 < width && num4 < length))
                            {
                                validCells = validCells | (uint)(1 << (num4 << 3) + num3);
                            }
                        }
                    }
                }
            }
        }
        // helper method
        public static ushort FindBlockId(ref ZoneBlock data)
        {
            var zoneManager = ZoneManager.instance;

            int gridX = Mathf.Clamp((int)((double)data.m_position.x / 64.0 + 75.0), 0, 149);
            int gridZ = Mathf.Clamp((int)((double)data.m_position.z / 64.0 + 75.0), 0, 149) * 150 + gridX;

            ushort blockID = zoneManager.m_zoneGrid[gridZ];
            int counter = 0;
            while (blockID != 0)
            {
                ushort nextBlockID = zoneManager.m_blocks.m_buffer[(int)blockID].m_nextGridBlock;

                if (nextBlockID == data.m_nextGridBlock) return blockID;

                blockID = nextBlockID;

                if (++counter >= 49152)
                {
                    CODebugBase<LogChannel>.Error(LogChannel.Core, "Invalid list detected!\n" + System.Environment.StackTrace);
                    break;
                }
            }

            return 0;
        }
        public static void ZonesUpdated(ref ZoneBlock _this, ushort blockID, float minX, float minZ, float maxX, float maxZ)
        {
            // skip zone blocks which are not in use
            if (((int)_this.m_flags & 3) != ZoneBlock.FLAG_CREATED) return;

            // width of the zone block
            int rowCount = _this.RowCount;
            int columnCount = ZoneBlockDetour.GetColumnCount(ref _this); // modified

            Vector2 columnDirection = new Vector2(Mathf.Cos(_this.m_angle), Mathf.Sin(_this.m_angle)) * 8f;
            Vector2 rowDirection = new Vector2(columnDirection.y, -columnDirection.x);

            Vector2 positionXZ = VectorUtils.XZ(_this.m_position);

            // bounds of the zone block
            Vector2 a = positionXZ - 4f * columnDirection - 4f * rowDirection;
            Vector2 b = positionXZ + 0.0f * columnDirection - 4f * rowDirection;
            Vector2 c = positionXZ + 0.0f * columnDirection + (float)(rowCount - 4) * rowDirection;
            Vector2 d = positionXZ - 4f * columnDirection + (float)(rowCount - 4) * rowDirection;
            float minX2 = Mathf.Min(Mathf.Min(a.x, b.x), Mathf.Min(c.x, d.x));
            float minZ2 = Mathf.Min(Mathf.Min(a.y, b.y), Mathf.Min(c.y, d.y));
            float maxX2 = Mathf.Max(Mathf.Max(a.x, b.x), Mathf.Max(c.x, d.x));
            float maxZ2 = Mathf.Max(Mathf.Max(a.y, b.y), Mathf.Max(c.y, d.y));

            // return if the area is not in hitbox range of this block
            if ((double)maxX2 < (double)minX || (double)minX2 > (double)maxX || ((double)maxZ2 < (double)minZ || (double)minZ2 > (double)maxZ))
            {
                return;
            }

            bool isAssetEditor = (Singleton<ToolManager>.instance.m_properties.m_mode & ItemClass.Availability.AssetEditor) != ItemClass.Availability.None;

            // absolute position of cell at row 5, column 5
            Vector2 positionR5C5 = positionXZ + columnDirection * 0.5f + rowDirection * 0.5f;

            // combined masks for valid and occupied
            ulong validMask = _this.m_valid & ~_this.m_shared;
            ulong occupiedMask = _this.m_occupied1 | _this.m_occupied2;

            for (int row = 0; row < rowCount; ++row)
            {
                int row2 = row;

                // calculate relative position between previous row and current row
                Vector2 rowPreviousLength = ((float)row - 4f) * rowDirection;

                for (; row + 1 < rowCount; ++row) // continue cycling through rows
                {
                    int column;
                    for (column = 0; column < columnCount; ++column)
                    {
                        ulong bitOfOuterRow = 1UL << (row2 << 3 | column);
                        ulong bitOfInnerRow = 1UL << (row + 1 << 3 | column);

                        // if the cell (row2) differs from the other cell (row) in any way, break
                        if ((validMask & bitOfOuterRow) != 0UL != ((validMask & bitOfInnerRow) != 0UL)
                            || (occupiedMask & bitOfOuterRow) != 0UL != ((occupiedMask & bitOfInnerRow) != 0UL)
                            || !isAssetEditor && GetZoneDeep(ref _this, blockID, column, row + 1) != GetZoneDeep(ref _this, blockID, column, row2))
                        {
                            break;
                        }
                    }
                    if (column < columnCount) break; // no idea what this does
                }

                // calculate relative position between current row and next row
                Vector2 rowNextLength = ((float)row - 3f) * rowDirection;

                for (int column = 0; column < columnCount; ++column)
                {
                    ulong bitOfOuterColumn = 1UL << (row2 << 3 | column);

                    if ((validMask & bitOfOuterColumn) != 0UL) // if cell is valid
                    {
                        bool occupied = (occupiedMask & bitOfOuterColumn) != 0UL; // is cell occupied?
                        int column2 = column;
                        ItemClass.Zone zone = !isAssetEditor ? GetZoneDeep(ref _this, blockID, column, row2) : ItemClass.Zone.ResidentialLow;

                        // calculate relative position between previous column and current column
                        Vector2 columnPreviousLength = ((float)column - 4f) * columnDirection;

                        for (; column != 3 && column + 1 < 8; ++column)
                        {
                            ulong bitOfInnerColumn = 1UL << (row2 << 3 | column + 1);

                            // break if cell is invalid or occupied status differs from other cell or zone differs
                            if ((validMask & bitOfInnerColumn) == 0UL
                                || (occupiedMask & bitOfInnerColumn) != 0UL != occupied
                                || !isAssetEditor && GetZoneDeep(ref _this, blockID, column + 1, row2) != zone)
                            {
                                break;
                            }
                        }

                        // calculate relative position between current column and next column
                        Vector2 columnNextLength = ((float)column - 3f) * columnDirection;

                        // Send zone cell to rendering pipeline
                        TerrainModify.ApplyQuad(positionXZ + columnPreviousLength + rowPreviousLength, positionXZ + columnNextLength + rowPreviousLength,
                            positionXZ + columnNextLength + rowNextLength, positionXZ + columnPreviousLength + rowNextLength,
                            zone, occupied, _this.m_angle, positionR5C5, columnDirection, rowDirection, 4 - column, 4 - column2, 4 - row, 4 - row2);
                    }
                }
            }
        }
        public static ItemClass.Zone GetZone(ref ZoneBlock _this, int x, int z)
        {
            // Calling this method should be avoided! Use GetZoneDeep instead

            return GetZoneDeep(ref _this, FindBlockId(ref _this), x, z);
        }
        /// <summary>
        /// This method marks zone cells overlapped by network segments as invalid. Called by CalculateBlock1.
        /// </summary>
        /// <param name="_this"></param>
        /// <param name="blockID"></param>
        /// <param name="segmentID"></param>
        /// <param name="data"></param>
        /// <param name="valid"></param>
        /// <param name="minX"></param>
        /// <param name="minZ"></param>
        /// <param name="maxX"></param>
        /// <param name="maxZ"></param>
        private static void CalculateImplementation1(ref ZoneBlock _this, ushort blockID, ushort segmentID, ref NetSegment data, ref ulong valid, float minX, float minZ, float maxX, float maxZ)
        {
            // do nothing if the block belongs to the network segment
            if ((int)data.m_blockStartLeft == (int)blockID || (int)data.m_blockStartRight == (int)blockID ||
                ((int)data.m_blockEndLeft == (int)blockID || (int)data.m_blockEndRight == (int)blockID))
            {
                return;
            }

            NetInfo info = data.Info;
            if (!info.m_canCollide) return; // water pipes etc.

            float collisionHalfWidth = info.m_netAI.GetCollisionHalfWidth();

            NetNode[] netNodeArray = Singleton<NetManager>.instance.m_nodes.m_buffer;

            // calculate network bezier curve
            Bezier3 bezier = new Bezier3();
            bezier.a = netNodeArray[(int)data.m_startNode].m_position;
            bezier.d = netNodeArray[(int)data.m_endNode].m_position;
            NetSegment.CalculateMiddlePoints(bezier.a, data.m_startDirection, bezier.d, data.m_endDirection, true, true, out bezier.b, out bezier.c);

            // remove vertical component
            Bezier2 bezierXZ = Bezier2.XZ(bezier);

            // do nothing if the collision hitbox is outside of the hitbox of the zone block
            Vector2 collisionAreaMin = bezierXZ.Min() + new Vector2(-collisionHalfWidth, -collisionHalfWidth);
            Vector2 collisionAreaMax = bezierXZ.Max() + new Vector2(collisionHalfWidth, collisionHalfWidth);
            if ((double)collisionAreaMin.x > (double)maxX || (double)collisionAreaMin.y > (double)maxZ
                || ((double)minX > (double)collisionAreaMax.x || (double)minZ > (double)collisionAreaMax.y))
            {
                return;
            }

            // width of the zone block
            int rowCount = _this.RowCount;

            // directions of the rows and columns based on zone block angle, multiplied by 8 (cell size)
            Vector2 columnDirection = new Vector2(Mathf.Cos(_this.m_angle), Mathf.Sin(_this.m_angle)) * 8f;
            Vector2 rowDirection = new Vector2(columnDirection.y, -columnDirection.x);

            // origin of the zone block
            // this position is in the center of the 8x8 zone block (4 columns and 4 rows away from the lower corner)
            Vector2 positionXZ = VectorUtils.XZ(_this.m_position);

            // area of the zone block (8x8 cells)
            Quad2 zoneBlockQuad = new Quad2
            {
                a = positionXZ - 4f * columnDirection - 4f * rowDirection,
                b = positionXZ + 4f * columnDirection - 4f * rowDirection,
                c = positionXZ + 4f * columnDirection + (float)(rowCount - 4) * rowDirection,
                d = positionXZ - 4f * columnDirection + (float)(rowCount - 4) * rowDirection
            };

            // Calculate the bounds of the network segment at the start node
            float start;
            float end;
            info.m_netAI.GetTerrainModifyRange(out start, out end);
            float halfStart = start * 0.5f; // e.g. 0.25f ---> 0.125f
            float halfEnd = (float)(1.0 - (1.0 - (double)end) * 0.5); // e.g. 0.75f --> 0.875f
            float t = halfStart;
            Vector2 startBezierPos = bezierXZ.Position(halfStart);
            Vector2 startBezierTan = bezierXZ.Tangent(halfStart);
            Vector2 startOrthogonalNormalized = new Vector2(-startBezierTan.y, startBezierTan.x).normalized; // tangent rotated by -90 deg = orthogonal

            Quad2 bezierQuad = new Quad2();

            // set the initial a/b bounds
            if ((double)t < 0.00999999977648258 && (info.m_clipSegmentEnds || (netNodeArray[(int)data.m_startNode].m_flags & NetNode.Flags.Bend) != NetNode.Flags.None))
            {
                Vector2 ortho4m = startOrthogonalNormalized * 4f;
                bezierQuad.a = startBezierPos + ortho4m - VectorUtils.XZ(data.m_startDirection) * 4f;
                bezierQuad.d = startBezierPos - ortho4m - VectorUtils.XZ(data.m_startDirection) * 4f;
            }
            else
            {
                Vector2 orthoHalfWidth = startOrthogonalNormalized * collisionHalfWidth;
                bezierQuad.a = startBezierPos + orthoHalfWidth;
                bezierQuad.d = startBezierPos - orthoHalfWidth;
            }

            // overlap 8 quads describing the position
            int steps = 8;
            for (int step = 1; step <= steps; ++step)
            {
                float interp = halfStart + (halfEnd - halfStart) * (float)step / (float)steps;
                Vector2 interpBezierPos = bezierXZ.Position(interp);
                Vector2 interpBezierTangent = bezierXZ.Tangent(interp);
                interpBezierTangent = new Vector2(-interpBezierTangent.y, interpBezierTangent.x).normalized;

                // set the c/d bounds
                if ((double)interp > 0.990000009536743 && (info.m_clipSegmentEnds || (netNodeArray[(int)data.m_endNode].m_flags & NetNode.Flags.Bend) != NetNode.Flags.None))
                {
                    interpBezierTangent *= 4f;
                    bezierQuad.b = interpBezierPos + interpBezierTangent - VectorUtils.XZ(data.m_endDirection) * 4f;
                    bezierQuad.c = interpBezierPos - interpBezierTangent - VectorUtils.XZ(data.m_endDirection) * 4f;
                }
                else
                {
                    interpBezierTangent *= collisionHalfWidth;
                    bezierQuad.b = interpBezierPos + interpBezierTangent;
                    bezierQuad.c = interpBezierPos - interpBezierTangent;
                }
                Vector2 quadMin = bezierQuad.Min();
                Vector2 quadMax = bezierQuad.Max();

                // Overlap the quad with the zone block quad
                if ((double)quadMin.x <= (double)maxX && (double)quadMin.y <= (double)maxZ && ((double)minX <= (double)quadMax.x && (double)minZ <= (double)quadMax.y) && zoneBlockQuad.Intersect(bezierQuad))
                {
                    // mark colliding cells as invalid
                    valid = valid & ~OverlapQuad(ref _this, bezierQuad);
                }

                // set the a/b bounds for the next quad
                bezierQuad.a = bezierQuad.b;
                bezierQuad.d = bezierQuad.c;
            }
        }
        public static float PointDistanceSq(ref ZoneBlock _this, Vector3 point, float minDistanceSq)
        {
            // width of the zone
            int rowCount = _this.RowCount;
            int columnCount = ZoneBlockDetour.GetColumnCount(ref _this); // modified

            // directions of the rows and columns based on zone block angle, multiplied by 8 (cell size)
            Vector3 columnDirection = new Vector3(Mathf.Cos(_this.m_angle), 0.0f, Mathf.Sin(_this.m_angle)) * 8f;
            Vector3 rowDirection = new Vector3(columnDirection.z, 0.0f, -columnDirection.x);

            float minDistance = Mathf.Sqrt(minDistanceSq);

            // bounds of the zone block
            Vector3 a = _this.m_position - 4f * columnDirection - 4f * rowDirection;
            Vector3 b = _this.m_position + (columnCount - 4f) * columnDirection - 4f * rowDirection;
            Vector3 c = _this.m_position + (columnCount - 4f) * columnDirection + (float)(rowCount - 4) * rowDirection;
            Vector3 d = _this.m_position - 4f * columnDirection + (float)(rowCount - 4) * rowDirection;

            // note the minDistance tolerance
            float minX = Mathf.Min(Mathf.Min(a.x, b.x), Mathf.Min(c.x, d.x)) - minDistance;
            float minZ = Mathf.Min(Mathf.Min(a.z, b.z), Mathf.Min(c.z, d.z)) - minDistance;
            float maxX = Mathf.Max(Mathf.Max(a.x, b.x), Mathf.Max(c.x, d.x)) + minDistance;
            float maxZ = Mathf.Max(Mathf.Max(a.z, b.z), Mathf.Max(c.z, d.z)) + minDistance;

            // check if point is in the zone block (+ minDistance tolerance)
            if ((double)point.x <= (double)maxX && (double)point.z <= (double)maxZ && ((double)minX <= (double)point.x && (double)minZ <= (double)point.z))
            {
                for (int row = 0; row < rowCount; ++row)
                {
                    // Calculate distance between row (center) and point
                    Vector3 distancePointToRow = _this.m_position - point + ((float)row - 3.5f) * rowDirection;
                    for (int column = 0; column < columnCount; ++column)
                    {
                        if ((_this.m_valid & 1uL << (row << 3 | column)) != 0uL)
                        {
                            // relative column position
                            Vector3 columnMiddleLength = ((float)column - 3.5f) * columnDirection;

                            // total distance between cell and point
                            Vector3 distancePointToCell = distancePointToRow + columnMiddleLength;

                            // increase distance if cell is shared by adding y component (so that the cell of the other zone block is closer), otherwise set y = 0
                            distancePointToCell.y = (_this.m_shared & 1uL << (row << 3 | column)) == 0uL ? 0.0f : 4f;

                            float newDistance = Vector3.SqrMagnitude(distancePointToCell);

                            // set as new minDistance if it is shorter
                            if ((double)newDistance < (double)minDistanceSq)
                            {
                                minDistanceSq = newDistance;
                            }
                        }
                    }
                }
            }
            return minDistanceSq;
        }
        private static void CalculateFillBuffer(ZoneTool zt, Vector3 position, Vector3 direction, float angle, ushort blockIndex, ref ZoneBlock block, ItemClass.Zone requiredZone, bool occupied1, bool occupied2)
        {
            var m_fillBuffer1 = (ulong[])typeof(ZoneTool).GetField("m_fillBuffer1", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(zt);

            float f1 = Mathf.Abs(block.m_angle - angle) * 0.6366197f;
            float num1 = f1 - Mathf.Floor(f1);
            if ((double)num1 >= 0.00999999977648258 && (double)num1 <= 0.990000009536743)
                return;
            int rowCount = block.RowCount;
            Vector3 vector3_1 = new Vector3(Mathf.Cos(block.m_angle), 0.0f, Mathf.Sin(block.m_angle)) * 8f;
            Vector3 vector3_2 = new Vector3(vector3_1.z, 0.0f, -vector3_1.x);
            for (int z = 0; z < rowCount; ++z)
            {
                Vector3 vector3_3 = ((float)z - 3.5f) * vector3_2;
                for (int x = 0; x < 4; ++x)
                {
                    if (((long)block.m_valid & 1L << (z << 3 | x)) != 0L && block.GetZone(x, z) == requiredZone)
                    {
                        if (occupied1)
                        {
                            if (requiredZone == ItemClass.Zone.Unzoned && ((long)block.m_occupied1 & 1L << (z << 3 | x)) == 0L)
                                continue;
                        }
                        else if (occupied2)
                        {
                            if (requiredZone == ItemClass.Zone.Unzoned && ((long)block.m_occupied2 & 1L << (z << 3 | x)) == 0L)
                                continue;
                        }
                        else if ((((long)block.m_occupied1 | (long)block.m_occupied2) & 1L << (z << 3 | x)) != 0L)
                            continue;
                        Vector3 vector3_4 = ((float)x - 3.5f) * vector3_1;
                        Vector3 vector3_5 = block.m_position + vector3_4 + vector3_3 - position;
                        float f2 = (float)(((double)vector3_5.x * (double)direction.x + (double)vector3_5.z * (double)direction.z) * 0.125 + 32.0);
                        float f3 = (float)(((double)vector3_5.x * (double)direction.z - (double)vector3_5.z * (double)direction.x) * 0.125 + 32.0);
                        int num2 = Mathf.RoundToInt(f2);
                        int index = Mathf.RoundToInt(f3);
                        if (num2 >= 0 && num2 < 64 && (index >= 0 && index < 64) && ((double)Mathf.Abs(f2 - (float)num2) < 0.0125000001862645 && (double)Mathf.Abs(f3 - (float)index) < 0.0125000001862645))
                            m_fillBuffer1[index] |= (ulong)(1L << num2);
                    }
                }
            }
        }
        public static bool SetZone(ref ZoneBlock _this, int x, int z, ItemClass.Zone zone)
        {
            // Calling this method should be avoided! Use SetZoneDeep instead

            return SetZoneDeep(ref _this, FindBlockId(ref _this), x, z, zone);
        }
 private static void InitializeBlock(ZoneManager zm, ushort block, ref ZoneBlock data)
 {
     int num = Mathf.Clamp((int)(data.m_position.x / 64f + HALFGRID), 0, GRIDSIZE - 1);
     int num2 = Mathf.Clamp((int)(data.m_position.z / 64f + HALFGRID), 0, GRIDSIZE - 1);
     int num3 = num2 * GRIDSIZE + num;
     while (!Monitor.TryEnter(zoneGrid, SimulationManager.SYNCHRONIZE_TIMEOUT))
     {
     }
     try
     {
         ZoneManager.instance.m_blocks.m_buffer[(int)block].m_nextGridBlock = zoneGrid[num3];
         zoneGrid[num3] = block;
     }
     finally
     {
         Monitor.Exit(zoneGrid);
     }
 }
        public static void SimulationStep(ref ZoneBlock _this, ushort blockID)
        {
            ZoneManager zoneManager = Singleton<ZoneManager>.instance;

            // width of the zone block
            int rowCount = _this.RowCount;

            // directions of the rows and columns based on zone block angle, multiplied by 8 (cell size)
            Vector2 columnDirection = new Vector2(Mathf.Cos(_this.m_angle), Mathf.Sin(_this.m_angle)) * 8f;
            Vector2 rowDirection = new Vector2(columnDirection.y, -columnDirection.x);

            // bitmask of valid cells that are not occupied
            ulong validFreeCellMask = _this.m_valid & ~(_this.m_occupied1 | _this.m_occupied2);

            // select a random zoned, unoccupied row and get its zone type
            // this will be our seed row
            int seedRow = 0;
            ItemClass.Zone zone = ItemClass.Zone.Unzoned;
            for (int index = 0; index < 4 && zone == ItemClass.Zone.Unzoned; ++index)
            {
                seedRow = Singleton<SimulationManager>.instance.m_randomizer.Int32((uint)rowCount);
                if ((validFreeCellMask & 1UL << (seedRow << 3)) != 0UL)
                {
                    zone = GetZoneDeep(ref _this, blockID, 0, seedRow);
                }
            }

            // get the demand for the given zone type in the district
            DistrictManager districtManager = Singleton<DistrictManager>.instance;
            byte district = districtManager.GetDistrict(_this.m_position);
            int demand;
            switch (zone)
            {
                case ItemClass.Zone.ResidentialLow:
                    demand = zoneManager.m_actualResidentialDemand + districtManager.m_districts.m_buffer[(int)district].CalculateResidentialLowDemandOffset();
                    break;
                case ItemClass.Zone.ResidentialHigh:
                    demand = zoneManager.m_actualResidentialDemand + districtManager.m_districts.m_buffer[(int)district].CalculateResidentialHighDemandOffset();
                    break;
                case ItemClass.Zone.CommercialLow:
                    demand = zoneManager.m_actualCommercialDemand + districtManager.m_districts.m_buffer[(int)district].CalculateCommercialLowDemandOffset();
                    break;
                case ItemClass.Zone.CommercialHigh:
                    demand = zoneManager.m_actualCommercialDemand + districtManager.m_districts.m_buffer[(int)district].CalculateCommercialHighDemandOffset();
                    break;
                case ItemClass.Zone.Industrial:
                    demand = zoneManager.m_actualWorkplaceDemand + districtManager.m_districts.m_buffer[(int)district].CalculateIndustrialDemandOffset();
                    break;
                case ItemClass.Zone.Office:
                    demand = zoneManager.m_actualWorkplaceDemand + districtManager.m_districts.m_buffer[(int)district].CalculateOfficeDemandOffset();
                    break;
                default:
                    return;
            }

            // origin of the zone block
            Vector2 positionXZ = VectorUtils.XZ(_this.m_position);

            // middle position of random row (roadside seed cell)
            Vector2 seedCellMiddlePosition = positionXZ - 3.5f * columnDirection + ((float)seedRow - 3.5f) * rowDirection;

            // This buffer contains 13 masks (for 13 rows)
            // The masks are split into two 16-bit segments
            // The higher 16 bits store which columns have road access
            // The lower 16 bits store which columns are unoccupied
            int[] xBuffer = zoneManager.m_tmpXBuffer; // TODO maybe use a bigger buffer?
            for (int index = 0; index < 13; ++index) xBuffer[index] = 0; // reset the buffer

            // put the surrounding area of the seed cell into a quad
            // TODO maybe check a bigger area?
            Quad2 seedPointAreaQuad = new Quad2
            {
                a = positionXZ - 4f * columnDirection + ((float)seedRow - 10f) * rowDirection,
                b = positionXZ + 3f * columnDirection + ((float)seedRow - 10f) * rowDirection,
                c = positionXZ + 3f * columnDirection + ((float)seedRow + 2f) * rowDirection,
                d = positionXZ - 4f * columnDirection + ((float)seedRow + 2f) * rowDirection
            };
            Vector2 seedPointAreaMin = seedPointAreaQuad.Min();
            Vector2 seedPointAreaMax = seedPointAreaQuad.Max();

            // calculate which zone block grid cells are touched by this zone block
            int gridMinX = Mathf.Max((int)(((double)seedPointAreaMin.x - 46.0) / 64.0 + 75.0), 0);
            int gridMinZ = Mathf.Max((int)(((double)seedPointAreaMin.y - 46.0) / 64.0 + 75.0), 0);
            int gridMaxX = Mathf.Min((int)(((double)seedPointAreaMax.x + 46.0) / 64.0 + 75.0), 149);
            int gridMaxZ = Mathf.Min((int)(((double)seedPointAreaMax.y + 46.0) / 64.0 + 75.0), 149);

            // Cycle through all touched grid cells
            for (int gridZ = gridMinZ; gridZ <= gridMaxZ; ++gridZ)
            {
                for (int gridX = gridMinX; gridX <= gridMaxX; ++gridX)
                {
                    // Cycle through all zone blocks in grid cell
                    ushort otherBlockID = zoneManager.m_zoneGrid[gridZ * 150 + gridX];
                    int counter = 0;
                    while ((int)otherBlockID != 0)
                    {
                        Vector3 otherPosition = zoneManager.m_blocks.m_buffer[(int)otherBlockID].m_position;

                        // check if other zone block is in range
                        if ((double)Mathf.Max(Mathf.Max(seedPointAreaMin.x - 46f - otherPosition.x, seedPointAreaMin.y - 46f - otherPosition.z),
                            Mathf.Max((float)((double)otherPosition.x - (double)seedPointAreaMax.x - 46.0), (float)((double)otherPosition.z - (double)seedPointAreaMax.y - 46.0))) < 0.0)
                        {
                            // Checks if the other block intersects and extends this block (orthogonal) and marks unoccupied cells and cells with road access in the XBuffer
                            CheckBlock(ref _this, otherBlockID, ref zoneManager.m_blocks.m_buffer[(int)otherBlockID], xBuffer, zone, seedCellMiddlePosition, columnDirection, rowDirection, seedPointAreaQuad);
                        }

                        // next zone block in grid cell (linked list)
                        otherBlockID = zoneManager.m_blocks.m_buffer[(int)otherBlockID].m_nextGridBlock;

                        if (++counter >= 49152)
                        {
                            CODebugBase<LogChannel>.Error(LogChannel.Core, "Invalid list detected!\n" + System.Environment.StackTrace);
                            break;
                        }
                    }
                }
            }
            for (int row = 0; row < 13; ++row)
            {
                uint columnMask = (uint)xBuffer[row];
                int columnCount = 0; // counts the unoccupied columns

                // check if the first the 2 cells in the column have road access
                // that means the area is suitable for corner buildings
                // 196608 = 0000 0000 0000 0011 0000 0000 0000 0000
                bool cornerRoadAccess = ((int)columnMask & 196608) == 196608;

                // stores if the last checked cell has road access
                bool backsideRoadAccess = false;

                // count unoccupied cells in this column
                while (((int)columnMask & 1) != 0)
                {
                    ++columnCount;

                    // check if the cell has road access
                    // 65536 = 0000 0000 0000 0001 0000 0000 0000 0000
                    backsideRoadAccess = ((int)columnMask & 65536) != 0;

                    // move on to the next cell
                    columnMask >>= 1;
                }

                if (columnCount == 5 || columnCount == 6)
                {
                    // if the last checked cell has road access, decrease max depth to number between 2 and 4, otherwise set it to 4
                    // always set the "depth shortened flag" (131072)
                    columnCount = (!backsideRoadAccess ? 4 : columnCount - (Singleton<SimulationManager>.instance.m_randomizer.Int32(2U) + 2)) | 131072;
                }
                else if (columnCount == 7)
                {
                    // 131072 = 0000 0000 0000 0010 0000 0000 0000 0000
                    // set the "depth shortened flag" and and set max depth to 4
                    columnCount = 4 | 131072;
                }
                // TODO add support for larger lots! (8,9,10,11,12,13,14,15)
                if (cornerRoadAccess)
                {
                    // set corner flag
                    // 65536 = 0000 0000 0000 0001 0000 0000 0000 0000
                    columnCount |= 65536;
                }

                // store result in buffer
                xBuffer[row] = columnCount;
            }

            // use bitmask to read depth at seed row
            // 0000 0000 0000 0000 1111 1111 1111 1111
            int targetColumnCount = xBuffer[6] & 65535;

            // all columns at seed row occupied? bad seed row!
            if (targetColumnCount == 0) return;

            // checks if there is electricity available
            bool isGoodPlace = IsGoodPlace(ref _this, seedCellMiddlePosition);

            // if demand is too low, only report that a good area was found and return
            // (or instantly return if area is bad)
            if (Singleton<SimulationManager>.instance.m_randomizer.Int32(100U) >= demand)
            {
                if (isGoodPlace) // no electricity? f**k this.
                {
                    zoneManager.m_goodAreaFound[(int)zone] = (short)1024; // note that a good area was found
                }
                return;
            }
            // if area is bad but a good area was found some time ago
            else if (!isGoodPlace && (int)zoneManager.m_goodAreaFound[(int)zone] > -1024)
            {
                if ((int)zoneManager.m_goodAreaFound[(int)zone] == 0)
                {
                    zoneManager.m_goodAreaFound[(int)zone] = (short)-1; // note that no good area was found today
                }
                return;
            }
            // let's spawn a building!
            // STEP 1: this calculates a left and right row range for the building to spawn
            else
            {
                int calculatedLeftRow = 6;
                int calculatedRightRow = 6;
                bool firstTry = true;

                // search loop for plot size finding
                // The goal is to avoid one cell width holes in the zone grid
                // the minimum targeted width is 2
                while (true)
                {
                    if (firstTry) // in first try search for exact matching rows
                    {
                        // search for rows left and right of seed row with a similar depth
                        while (calculatedLeftRow != 0 && (xBuffer[calculatedLeftRow - 1] & 65535) == targetColumnCount)
                            --calculatedLeftRow;
                        while (calculatedRightRow != 12 && (xBuffer[calculatedRightRow + 1] & 65535) == targetColumnCount)
                            ++calculatedRightRow;
                    }
                    else // in the second/third try search for any matching rows
                    {
                        // search for rows left and right of seed row with a similar or larger depth
                        while (calculatedLeftRow != 0 && (xBuffer[calculatedLeftRow - 1] & 65535) >= targetColumnCount)
                            --calculatedLeftRow;
                        while (calculatedRightRow != 12 && (xBuffer[calculatedRightRow + 1] & 65535) >= targetColumnCount)
                            ++calculatedRightRow;
                    }

                    int extraLeftRange = calculatedLeftRow;
                    int extraRightRange = calculatedRightRow;
                    // search for further rows with a min depth of 2
                    while (extraLeftRange != 0 && (xBuffer[extraLeftRange - 1] & 65535) >= 2)
                        --extraLeftRange;
                    while (extraRightRange != 12 && (xBuffer[extraRightRange + 1] & 65535) >= 2)
                        ++extraRightRange;

                    // checks if a exactly one single extra row with min depth of 2 was found
                    // if that is the case, the algorithm will try to preserve space on that side so a 2 cells width building can fit
                    bool exactlyOneRowLeftFound = extraLeftRange != 0 && extraLeftRange == calculatedLeftRow - 1;
                    bool exactlyOneRowRightFound = extraRightRange != 12 && extraRightRange == calculatedRightRow + 1;

                    // 1-cell space found on both sides
                    // goal: preserve space on both sides
                    if (exactlyOneRowLeftFound && exactlyOneRowRightFound)
                    {
                        // if 3 or less regular rows found
                        if (calculatedRightRow - calculatedLeftRow <= 2)
                        {
                            // if target depth 2 or less
                            if (targetColumnCount <= 2)
                            {
                                if (!firstTry) // if second try
                                {
                                    // 1x1, 1x2, 2x1, 2x2, 3x1, 3x2
                                    goto selectRandomRows;  // --> next step
                                }

                                // --> search again (exact mode off)
                            }
                            // if target depth is at least 3 (but only 3 or less rows found)
                            else
                            {
                                // decrease target depth by one
                                --targetColumnCount;

                                // --> search again (exact mode off)
                            }
                        }
                        // 4 regular rows found
                        else
                        {
                            // reserve space on both sides for 2-cell wide buildings
                            // (++rowLeft;--rowRight;)
                            break; // --> next step
                        }
                    }

                    // 1-cell space found on left side only
                    else if (exactlyOneRowLeftFound)
                    {
                        // if 2 or less regular rows found
                        if (calculatedRightRow - calculatedLeftRow <= 1)
                        {
                            // if target depth 2 or less
                            if (targetColumnCount <= 2)
                            {
                                if (!firstTry) // if second try
                                {
                                    goto selectRandomRows;  // --> next step
                                }

                                // --> search again (exact mode off)
                            }
                            // if target depth is at least 3 (but only 2 or less rows found)
                            else
                            {
                                // decrease target depth by one
                                --targetColumnCount;

                                // --> search again (exact mode off)
                            }
                        }
                        // 4 regular rows found
                        else
                        {
                            // reserve space on left side for 2-cell wide buildings
                            // (++rowLeft;)
                            goto selectRandomRowsPreserveL;  // --> next step
                        }
                    }

                    // 1-cell space found on right side only
                    else if (exactlyOneRowRightFound)
                    {
                        // if 2 or less regular rows found
                        if (calculatedRightRow - calculatedLeftRow <= 1)
                        {
                            // if target depth 2 or less
                            if (targetColumnCount <= 2)
                            {
                                if (!firstTry) // if second try
                                {
                                    goto selectRandomRows;  // --> next step
                                }
                            }
                            // if target depth is at least 3 (but only 2 or less rows found)
                            else
                            {
                                // decrease target depth by one
                                --targetColumnCount;

                                // --> search again (exact mode off)
                            }
                        }
                        // 4 regular rows found
                        else
                        {
                            // reserve space on right side for 2-cell wide buildings
                            // (--rowRight;)
                            goto selectRandomRowsPreserveR;  // --> next step
                        }
                    }
                    // only one row found
                    // we don't want 1-cell wide buildings!
                    else if (calculatedLeftRow == calculatedRightRow)
                    {
                        // if target depth 2 or less
                        if (targetColumnCount <= 2)
                        {
                            if (!firstTry) // if second try
                            {
                                goto selectRandomRows;  // --> next step
                            }

                            // --> search again (exact mode off)
                        }
                        // if target depth is at least 3 (but only 1 row found)
                        else
                        {
                            --targetColumnCount;

                            // --> search again (exact mode off)
                        }
                    }
                    // no 1-cell spaces found. Everything is ok!
                    else
                    {
                        goto selectRandomRows;  // --> next step
                    }

                    firstTry = false; // turn off exact mode and search again
                }

                // fix 1-cell space on both sides
                // selectRandomRowsPreserveBoth:
                ++calculatedLeftRow;
                --calculatedRightRow;
                goto selectRandomRows;

                // fix 1-cell space on left side
                selectRandomRowsPreserveL:
                ++calculatedLeftRow;
                goto selectRandomRows;

                // fix 1-cell space on right side
                selectRandomRowsPreserveR:
                --calculatedRightRow;

                // NEXT STEP: Create an alternative randomized row range for the building to spawn
                // (alternative width and spawn position)
                // Goal: Leave no small gaps
                selectRandomRows:

                // the randomized row values
                int randomozedLeftRow;
                int randomizedRightRow;

                // if only one cell deep, but 2 or more cells wide
                // select one of the rows and set the width to 1
                if (targetColumnCount == 1 && calculatedRightRow - calculatedLeftRow >= 1)
                {
                    // select a random row in the valid range
                    calculatedLeftRow += Singleton<SimulationManager>.instance.m_randomizer.Int32((uint)(calculatedRightRow - calculatedLeftRow));
                    calculatedRightRow = calculatedLeftRow + 1;
                    randomozedLeftRow = calculatedLeftRow + Singleton<SimulationManager>.instance.m_randomizer.Int32(2U);
                    randomizedRightRow = randomozedLeftRow;
                }
                else
                {
                    do
                    {
                        randomozedLeftRow = calculatedLeftRow;
                        randomizedRightRow = calculatedRightRow;
                        if (calculatedRightRow - calculatedLeftRow == 2) // 3 cells wide
                        {
                            // coin toss: reduce width by 1 (taking only from one side)
                            if (Singleton<SimulationManager>.instance.m_randomizer.Int32(2U) == 0)
                                --randomizedRightRow;
                            else
                                ++randomozedLeftRow;
                        }
                        else if (calculatedRightRow - calculatedLeftRow == 3) // 4 cells wide
                        {
                            // coin toss: reduce width by 2 (taking only from one side)
                            if (Singleton<SimulationManager>.instance.m_randomizer.Int32(2U) == 0)
                                randomizedRightRow -= 2;
                            else
                                randomozedLeftRow += 2;
                        }
                        else if (calculatedRightRow - calculatedLeftRow == 4) // 5 cells wide
                        {
                            // coin toss: reduce width by 2 from one side and 3 from the other
                            if (Singleton<SimulationManager>.instance.m_randomizer.Int32(2U) == 0)
                            {
                                calculatedRightRow -= 2;
                                randomizedRightRow -= 3;
                            }
                            else
                            {
                                calculatedLeftRow += 2;
                                randomozedLeftRow += 3;
                            }
                        }
                        else if (calculatedRightRow - calculatedLeftRow == 5) // 6 cells wide
                        {
                            // coin toss: reduce width by 2 from one side and 3 from the other
                            if (Singleton<SimulationManager>.instance.m_randomizer.Int32(2U) == 0)
                            {
                                calculatedRightRow -= 3;
                                randomizedRightRow -= 2;
                            }
                            else
                            {
                                calculatedLeftRow += 3;
                                randomozedLeftRow += 2;
                            }
                        }
                        else if (calculatedRightRow - calculatedLeftRow >= 6) // 7 cells wide
                        {
                            // check if one range is far away from seed point
                            // reduce width by 2 from that side, also reduce that range by 3
                            if (calculatedLeftRow == 0 || calculatedRightRow == 12)
                            {
                                if (calculatedLeftRow == 0)
                                {
                                    calculatedLeftRow = 3;
                                    randomozedLeftRow = 2;
                                }
                                if (calculatedRightRow == 12)
                                {
                                    calculatedRightRow = 9;
                                    randomizedRightRow = 10;
                                }
                            }

                            // otherwise:
                            // coin toss: reduce width by 2 from one side and 3 from the other
                            else if (Singleton<SimulationManager>.instance.m_randomizer.Int32(2U) == 0)
                            {
                                calculatedRightRow = calculatedLeftRow + 3;
                                randomizedRightRow = randomozedLeftRow + 2;
                            }
                            else
                            {
                                calculatedLeftRow = calculatedRightRow - 3;
                                randomozedLeftRow = randomizedRightRow - 2;
                            }
                        }
                    }

                    // do this while the selected width or the width range are greater than 4
                    // TODO this needs to be changed to 8
                    while (calculatedRightRow - calculatedLeftRow > 3 || randomizedRightRow - randomozedLeftRow > 3);
                }

                // STEP 3: Calculate final position, width, depth and zoning mode based on calculated row range
                int calculatedDepth = 4;
                int calculatedWidth = calculatedRightRow - calculatedLeftRow + 1;
                BuildingInfo.ZoningMode calculatedZoningMode = BuildingInfo.ZoningMode.Straight;

                // stores if there is reserve space for a higher depth
                bool calculatedSpaceBehindAllColumns = true;

                for (int row = calculatedLeftRow; row <= calculatedRightRow; ++row)
                {
                    // calculate the maximum possible depth in the range
                    calculatedDepth = Mathf.Min(calculatedDepth, xBuffer[row] & 65535);
                    if ((xBuffer[row] & 131072) == 0) // check for depth shortened flag
                    {
                        calculatedSpaceBehindAllColumns = false;
                    }
                }

                if (calculatedRightRow > calculatedLeftRow) // width at least 2
                {
                    // check for left corner flag
                    if ((xBuffer[calculatedLeftRow] & 65536) != 0)
                    {
                        // move building to left side, set corner mode
                        calculatedZoningMode = BuildingInfo.ZoningMode.CornerLeft;
                        randomizedRightRow = calculatedLeftRow + randomizedRightRow - randomozedLeftRow;
                        randomozedLeftRow = calculatedLeftRow;
                    }

                    // check for right corner flag (coin toss if left corner flag found)
                    if ((xBuffer[calculatedRightRow] & 65536) != 0 && (calculatedZoningMode != BuildingInfo.ZoningMode.CornerLeft || Singleton<SimulationManager>.instance.m_randomizer.Int32(2U) == 0))
                    {
                        // move building to right side, set corner mode
                        calculatedZoningMode = BuildingInfo.ZoningMode.CornerRight;
                        randomozedLeftRow = calculatedRightRow + randomozedLeftRow - randomizedRightRow;
                        randomizedRightRow = calculatedRightRow;
                    }
                }

                // STEP 4: Calculate final position, width, depth and zoning mode based on randomized row range

                int randomizedDepth = 4;
                int randomizedWidth = randomizedRightRow - randomozedLeftRow + 1;
                BuildingInfo.ZoningMode randomizedZoningMode = BuildingInfo.ZoningMode.Straight;

                // stores if there is reserve space for a higher depth
                bool randomizedSpaceBehindAllColumns = true;

                for (int row = randomozedLeftRow; row <= randomizedRightRow; ++row)
                {
                    // calculate the maximum possible depth in the range
                    randomizedDepth = Mathf.Min(randomizedDepth, xBuffer[row] & (int)ushort.MaxValue);

                    if ((xBuffer[row] & 131072) == 0) // check for depth shortened flag
                    {
                        randomizedSpaceBehindAllColumns = false;
                    }
                }
                if (randomizedRightRow > randomozedLeftRow) // width at least 2
                {
                    // check for left corner flag
                    if ((xBuffer[randomozedLeftRow] & 65536) != 0)
                    {
                        randomizedZoningMode = BuildingInfo.ZoningMode.CornerLeft; // set corner mode
                    }

                    // check for right corner flag (coin toss if left corner flag found)
                    if ((xBuffer[randomizedRightRow] & 65536) != 0 && (randomizedZoningMode != BuildingInfo.ZoningMode.CornerLeft || Singleton<SimulationManager>.instance.m_randomizer.Int32(2U) == 0))
                    {
                        randomizedZoningMode = BuildingInfo.ZoningMode.CornerRight; // set corner mode
                    }
                }

                // STEP 5: Assemble ItemClass information
                ItemClass.SubService subService = ItemClass.SubService.None;
                ItemClass.Level level = ItemClass.Level.Level1;
                ItemClass.Service service;
                switch (zone)
                {
                    case ItemClass.Zone.ResidentialLow:
                        service = ItemClass.Service.Residential;
                        subService = ItemClass.SubService.ResidentialLow;
                        break;
                    case ItemClass.Zone.ResidentialHigh:
                        service = ItemClass.Service.Residential;
                        subService = ItemClass.SubService.ResidentialHigh;
                        break;
                    case ItemClass.Zone.CommercialLow:
                        service = ItemClass.Service.Commercial;
                        subService = ItemClass.SubService.CommercialLow;
                        break;
                    case ItemClass.Zone.CommercialHigh:
                        service = ItemClass.Service.Commercial;
                        subService = ItemClass.SubService.CommercialHigh;
                        break;
                    case ItemClass.Zone.Industrial:
                        service = ItemClass.Service.Industrial;
                        break;
                    case ItemClass.Zone.Office:
                        service = ItemClass.Service.Office;
                        subService = ItemClass.SubService.None;
                        break;
                    default:
                        return;
                }

                // STEP 6: Find a prefab using either calculated or randomized size, spawn position and zoning mode
                // The fallback if no corner was found is always straight mode

                BuildingInfo info = (BuildingInfo)null;
                Vector3 buildingSpawnPos = Vector3.zero;

                int finalSpawnRowDouble = 0; // this is the doubled relative spawn position
                int finalDepth = 0;
                int finalWidth = 0;
                BuildingInfo.ZoningMode finalZoningMode = BuildingInfo.ZoningMode.Straight;

                for (int iteration = 0; iteration < 6; ++iteration)
                {
                    switch (iteration)
                    {
                        case 0: //corner, calculated
                            if (calculatedZoningMode != BuildingInfo.ZoningMode.Straight)
                            {
                                finalSpawnRowDouble = calculatedLeftRow + calculatedRightRow + 1;
                                finalDepth = calculatedDepth;
                                finalWidth = calculatedWidth;
                                finalZoningMode = calculatedZoningMode;
                                goto default;
                            }
                            else
                                break;
                        case 1: //corner, randomized
                            if (randomizedZoningMode != BuildingInfo.ZoningMode.Straight)
                            {
                                finalSpawnRowDouble = randomozedLeftRow + randomizedRightRow + 1;
                                finalDepth = randomizedDepth;
                                finalWidth = randomizedWidth;
                                finalZoningMode = randomizedZoningMode;
                                goto default;
                            }
                            else
                                break;
                        case 2: //corner, calculated, limited depth
                            if (calculatedZoningMode != BuildingInfo.ZoningMode.Straight && calculatedDepth >= 4)
                            {
                                finalSpawnRowDouble = calculatedLeftRow + calculatedRightRow + 1;
                                finalDepth = !calculatedSpaceBehindAllColumns ? 2 : 3; // prevent 1-cell gaps
                                finalWidth = calculatedWidth;
                                finalZoningMode = calculatedZoningMode;
                                goto default;
                            }
                            else
                                break;
                        case 3: //corner, randomized, limited depth
                            if (randomizedZoningMode != BuildingInfo.ZoningMode.Straight && randomizedDepth >= 4)
                            {
                                finalSpawnRowDouble = randomozedLeftRow + randomizedRightRow + 1;
                                finalDepth = !randomizedSpaceBehindAllColumns ? 2 : 3; // prevent 1-cell gaps
                                finalWidth = randomizedWidth;
                                finalZoningMode = randomizedZoningMode;
                                goto default;
                            }
                            else
                                break;
                        case 4: // straight, calculated
                            finalSpawnRowDouble = calculatedLeftRow + calculatedRightRow + 1;
                            finalDepth = calculatedDepth;
                            finalWidth = calculatedWidth;
                            finalZoningMode = BuildingInfo.ZoningMode.Straight;
                            goto default;
                        case 5: // straight, randomized
                            finalSpawnRowDouble = randomozedLeftRow + randomizedRightRow + 1;
                            finalDepth = randomizedDepth;
                            finalWidth = randomizedWidth;
                            finalZoningMode = BuildingInfo.ZoningMode.Straight;
                            goto default;
                        default:
                            // calculate building spawn position (plot center)
                            buildingSpawnPos = _this.m_position + VectorUtils.X_Y(
                                (float)((double)finalDepth * 0.5 - 4.0) * columnDirection +
                                (float)((double)finalSpawnRowDouble * 0.5 + ((double)seedRow - 6) - 4) * rowDirection);

                            // industrial specialisations
                            if (zone == ItemClass.Zone.Industrial)
                            {
                                ZoneBlock.GetIndustryType(buildingSpawnPos, out subService, out level);
                            }
                            // commercial specialisations
                            else if (zone == ItemClass.Zone.CommercialLow || zone == ItemClass.Zone.CommercialHigh)
                            {
                                ZoneBlock.GetCommercialType(buildingSpawnPos, zone, finalWidth, finalDepth, out subService, out level);
                            }

                            // get district style
                            byte buildingDistrict = districtManager.GetDistrict(buildingSpawnPos);
                            ushort style = districtManager.m_districts.m_buffer[(int)buildingDistrict].m_Style;

                            // find random building
                            info = Singleton<BuildingManager>.instance.GetRandomBuildingInfo(ref Singleton<SimulationManager>.instance.m_randomizer, service, subService, level, finalWidth, finalDepth, finalZoningMode, (int)style);

                            // no building found? go back to switch statement and use different calculations
                            if (info == null) break;

                            // spawn the building!
                            goto spawnBuilding;
                    }
                }

                // STEP 7: Spawn the building!
                spawnBuilding:

                // No underwater buildings!
                if (info == null || (double)Singleton<TerrainManager>.instance.WaterLevel(VectorUtils.XZ(buildingSpawnPos)) > (double)buildingSpawnPos.y) return;

                // Rotate corner buildings correctly
                float angle = _this.m_angle + 1.570796f; // 0.5*PI = 180 deg
                if (finalZoningMode == BuildingInfo.ZoningMode.CornerLeft && info.m_zoningMode == BuildingInfo.ZoningMode.CornerRight)
                {
                    angle -= 1.570796f;
                    finalDepth = finalWidth;
                }
                else if (finalZoningMode == BuildingInfo.ZoningMode.CornerRight && info.m_zoningMode == BuildingInfo.ZoningMode.CornerLeft)
                {
                    angle += 1.570796f;
                    finalDepth = finalWidth;
                }

                // Try to spawn the building
                ushort buildingID;
                if (Singleton<BuildingManager>.instance.CreateBuilding(out buildingID, ref Singleton<SimulationManager>.instance.m_randomizer, info, buildingSpawnPos, angle, finalDepth, Singleton<SimulationManager>.instance.m_currentBuildIndex))
                {
                    ++Singleton<SimulationManager>.instance.m_currentBuildIndex;

                    // Lower demand
                    switch (service)
                    {
                        case ItemClass.Service.Residential:
                            zoneManager.m_actualResidentialDemand = Mathf.Max(0, zoneManager.m_actualResidentialDemand - 5);
                            break;
                        case ItemClass.Service.Commercial:
                            zoneManager.m_actualCommercialDemand = Mathf.Max(0, zoneManager.m_actualCommercialDemand - 5);
                            break;
                        case ItemClass.Service.Industrial:
                            zoneManager.m_actualWorkplaceDemand = Mathf.Max(0, zoneManager.m_actualWorkplaceDemand - 5);
                            break;
                        case ItemClass.Service.Office:
                            zoneManager.m_actualWorkplaceDemand = Mathf.Max(0, zoneManager.m_actualWorkplaceDemand - 5);
                            break;
                    }

                    // Apply high-density building flag
                    switch (zone)
                    {
                        case ItemClass.Zone.ResidentialHigh:
                        case ItemClass.Zone.CommercialHigh:
                            Singleton<BuildingManager>.instance.m_buildings.m_buffer[(int)buildingID].m_flags |= Building.Flags.HighDensity;
                            break;
                    }
                }
                zoneManager.m_goodAreaFound[(int)zone] = (short)1024; // note that a good area was found and a building was spawned
            }
        }
        public override void SimulationStep(ushort buildingID, ref Building buildingData, ref Building.Frame frameData)
        {
            base.SimulationStep(buildingID, ref buildingData, ref frameData);
            if (Singleton <SimulationManager> .instance.m_randomizer.Int32(10U) == 0)
            {
                DistrictManager instance = Singleton <DistrictManager> .instance;
                byte            district = instance.GetDistrict(buildingData.m_position);
                ushort          num      = instance.m_districts.m_buffer[(int)district].m_Style;
                if ((int)num > 0 && (int)num - 1 < instance.m_Styles.Length)
                {
                    DistrictStyle districtStyle = instance.m_Styles[(int)num - 1];
                    if (districtStyle != null && (UnityEngine.Object) this.m_info.m_class != (UnityEngine.Object)null && (districtStyle.AffectsService(this.m_info.GetService(), this.m_info.GetSubService(), this.m_info.m_class.m_level) && !districtStyle.Contains(this.m_info)) && (int)Singleton <ZoneManager> .instance.m_lastBuildIndex == (int)Singleton <SimulationManager> .instance.m_currentBuildIndex)
                    {
                        buildingData.m_flags |= Building.Flags.Demolishing;
                        ++Singleton <SimulationManager> .instance.m_currentBuildIndex;
                    }
                }
            }
            if ((buildingData.m_flags & Building.Flags.ZonesUpdated) != Building.Flags.None)
            {
                SimulationManager instance = Singleton <SimulationManager> .instance;
                if ((int)buildingData.m_fireIntensity != 0 || instance.m_randomizer.Int32(10U) != 0 || (int)Singleton <ZoneManager> .instance.m_lastBuildIndex != (int)instance.m_currentBuildIndex)
                {
                    return;
                }
                buildingData.m_flags &= ~Building.Flags.ZonesUpdated;
                if (buildingData.CheckZoning(this.m_info.m_class.GetZone(), this.m_info.m_class.GetSecondaryZone()))
                {
                    return;
                }
                buildingData.m_flags |= Building.Flags.Demolishing;
                PrivateBuildingAIDetour.CheckNearbyBuildingZones(buildingData.m_position);
                ++instance.m_currentBuildIndex;
            }
            else
            {
                if ((buildingData.m_flags & (Building.Flags.Abandoned | Building.Flags.Downgrading)) == Building.Flags.None || (int)buildingData.m_majorProblemTimer != (int)byte.MaxValue && (buildingData.m_flags & Building.Flags.Abandoned) != Building.Flags.None)
                {
                    return;
                }
                SimulationManager instance1 = Singleton <SimulationManager> .instance;
                ZoneManager       instance2 = Singleton <ZoneManager> .instance;
                int num1;
                switch (this.m_info.m_class.m_service)
                {
                case ItemClass.Service.Residential:
                    num1 = instance2.m_actualResidentialDemand;
                    break;

                case ItemClass.Service.Commercial:
                    num1 = instance2.m_actualCommercialDemand;
                    break;

                case ItemClass.Service.Industrial:
                    num1 = instance2.m_actualWorkplaceDemand;
                    break;

                case ItemClass.Service.Office:
                    num1 = instance2.m_actualWorkplaceDemand;
                    break;

                default:
                    num1 = 0;
                    break;
                }
                if (instance1.m_randomizer.Int32(100U) >= num1 || (int)instance2.m_lastBuildIndex != (int)instance1.m_currentBuildIndex || (double)Singleton <TerrainManager> .instance.WaterLevel(VectorUtils.XZ(buildingData.m_position)) > (double)buildingData.m_position.y)
                {
                    return;
                }
                ItemClass.SubService subService = this.m_info.m_class.m_subService;
                ItemClass.Level      level      = ItemClass.Level.Level1;
                int width = buildingData.Width;
                int num2  = buildingData.Length;
                if (this.m_info.m_class.m_service == ItemClass.Service.Industrial)
                {
                    ZoneBlock.GetIndustryType(buildingData.m_position, out subService, out level);
                }
                else if (this.m_info.m_class.m_service == ItemClass.Service.Commercial)
                {
                    ZoneBlock.GetCommercialType(buildingData.m_position, this.m_info.m_class.GetZone(), width, num2, out subService, out level);
                }
                DistrictManager instance3          = Singleton <DistrictManager> .instance;
                byte            district           = instance3.GetDistrict(buildingData.m_position);
                ushort          num3               = instance3.m_districts.m_buffer[(int)district].m_Style;
                BuildingInfo    randomBuildingInfo = Singleton <BuildingManager> .instance.GetRandomBuildingInfo(ref Singleton <SimulationManager> .instance.m_randomizer, this.m_info.m_class.m_service, subService, level, width, num2, this.m_info.m_zoningMode, (int)num3);

                if (randomBuildingInfo == null)
                {
                    return;
                }
                buildingData.m_flags |= Building.Flags.Demolishing;
                float num4 = buildingData.m_angle + 1.570796f;
                float num5;
                if (this.m_info.m_zoningMode == BuildingInfo.ZoningMode.CornerLeft && randomBuildingInfo.m_zoningMode == BuildingInfo.ZoningMode.CornerRight)
                {
                    num5 = num4 - 1.570796f;
                    num2 = width;
                }
                else if (this.m_info.m_zoningMode == BuildingInfo.ZoningMode.CornerRight && randomBuildingInfo.m_zoningMode == BuildingInfo.ZoningMode.CornerLeft)
                {
                    num5 = num4 + 1.570796f;
                    num2 = width;
                }
                ushort building;
                if (Singleton <BuildingManager> .instance.CreateBuilding(out building, ref Singleton <SimulationManager> .instance.m_randomizer, randomBuildingInfo, buildingData.m_position, buildingData.m_angle, num2, Singleton <SimulationManager> .instance.m_currentBuildIndex))
                {
                    ++Singleton <SimulationManager> .instance.m_currentBuildIndex;
                    switch (this.m_info.m_class.m_service)
                    {
                    case ItemClass.Service.Residential:
                        instance2.m_actualResidentialDemand = Mathf.Max(0, instance2.m_actualResidentialDemand - 5);
                        break;

                    case ItemClass.Service.Commercial:
                        instance2.m_actualCommercialDemand = Mathf.Max(0, instance2.m_actualCommercialDemand - 5);
                        break;

                    case ItemClass.Service.Industrial:
                        instance2.m_actualWorkplaceDemand = Mathf.Max(0, instance2.m_actualWorkplaceDemand - 5);
                        break;

                    case ItemClass.Service.Office:
                        instance2.m_actualWorkplaceDemand = Mathf.Max(0, instance2.m_actualWorkplaceDemand - 5);
                        break;
                    }
                }
                ++instance1.m_currentBuildIndex;
            }
        }
Exemple #47
0
        public static void SimulationStep(ref ZoneBlock block, ushort blockID)
        {
            ZoneManager instance1 = Singleton <ZoneManager> .instance;
            int         rowCount  = block.RowCount;
            Vector2     xDir      = new Vector2(Mathf.Cos(block.m_angle), Mathf.Sin(block.m_angle)) * 8f;
            Vector2     zDir      = new Vector2(xDir.y, -xDir.x);
            ulong       num1      = block.m_valid & (ulong)~((long)block.m_occupied1 | (long)block.m_occupied2);
            int         z         = 0;

            ItemClass.Zone zone = ItemClass.Zone.Unzoned;
            for (int index = 0; index < 4 && zone == ItemClass.Zone.Unzoned; ++index)
            {
                z = Singleton <SimulationManager> .instance.m_randomizer.Int32((uint)rowCount);

                if (((long)num1 & 1L << (z << 3)) != 0L)
                {
                    zone = block.GetZone(0, z);
                }
            }
            DistrictManager instance2 = Singleton <DistrictManager> .instance;
            byte            district1 = instance2.GetDistrict(block.m_position);
            int             num2;

            switch (zone)
            {
            case ItemClass.Zone.ResidentialLow:
                num2 = instance1.m_actualResidentialDemand + instance2.m_districts.m_buffer[(int)district1].CalculateResidentialLowDemandOffset();
                break;

            case ItemClass.Zone.ResidentialHigh:
                num2 = instance1.m_actualResidentialDemand + instance2.m_districts.m_buffer[(int)district1].CalculateResidentialHighDemandOffset();
                break;

            case ItemClass.Zone.CommercialLow:
                num2 = instance1.m_actualCommercialDemand + instance2.m_districts.m_buffer[(int)district1].CalculateCommercialLowDemandOffset();
                break;

            case ItemClass.Zone.CommercialHigh:
                num2 = instance1.m_actualCommercialDemand + instance2.m_districts.m_buffer[(int)district1].CalculateCommercialHighDemandOffset();
                break;

            case ItemClass.Zone.Industrial:
                num2 = instance1.m_actualWorkplaceDemand + instance2.m_districts.m_buffer[(int)district1].CalculateIndustrialDemandOffset();
                break;

            case ItemClass.Zone.Office:
                num2 = instance1.m_actualWorkplaceDemand + instance2.m_districts.m_buffer[(int)district1].CalculateOfficeDemandOffset();
                break;

            default:
                return;
            }
            Vector2 vector2_1 = VectorUtils.XZ(block.m_position);
            Vector2 vector2_2 = vector2_1 - 3.5f * xDir + ((float)z - 3.5f) * zDir;

            int[] xBuffer = instance1.m_tmpXBuffer;
            for (int index = 0; index < 13; ++index)
            {
                xBuffer[index] = 0;
            }
            Quad2 quad = new Quad2();

            quad.a = vector2_1 - 4f * xDir + ((float)z - 10f) * zDir;
            quad.b = vector2_1 + 3f * xDir + ((float)z - 10f) * zDir;
            quad.c = vector2_1 + 3f * xDir + ((float)z + 2f) * zDir;
            quad.d = vector2_1 - 4f * xDir + ((float)z + 2f) * zDir;
            Vector2 vector2_3 = quad.Min();
            Vector2 vector2_4 = quad.Max();
            //begin mod
            int num3 = Mathf.Max((int)(((double)vector2_3.x - 46.0) / 64.0 + FakeZoneManager.HALFGRID), 0);
            int num4 = Mathf.Max((int)(((double)vector2_3.y - 46.0) / 64.0 + FakeZoneManager.HALFGRID), 0);
            int num5 = Mathf.Min((int)(((double)vector2_4.x + 46.0) / 64.0 + FakeZoneManager.HALFGRID), FakeZoneManager.GRIDSIZE - 1);
            int num6 = Mathf.Min((int)(((double)vector2_4.y + 46.0) / 64.0 + FakeZoneManager.HALFGRID), FakeZoneManager.GRIDSIZE - 1);

            //end mod
            for (int index1 = num4; index1 <= num6; ++index1)
            {
                for (int index2 = num3; index2 <= num5; ++index2)
                {
                    //begin mod
                    ushort num7 = instance1.m_zoneGrid[index1 * FakeZoneManager.GRIDSIZE + index2];
                    //end mod
                    int num8 = 0;
                    while ((int)num7 != 0)
                    {
                        Vector3 vector3 = instance1.m_blocks.m_buffer[(int)num7].m_position;
                        if ((double)Mathf.Max(Mathf.Max(vector2_3.x - 46f - vector3.x, vector2_3.y - 46f - vector3.z), Mathf.Max((float)((double)vector3.x - (double)vector2_4.x - 46.0), (float)((double)vector3.z - (double)vector2_4.y - 46.0))) < 0.0)
                        {
                            //begin mod
                            CheckBlock(ref block, ref instance1.m_blocks.m_buffer[(int)num7], xBuffer, zone, vector2_2, xDir, zDir, quad);
                        }
                        //end mod
                        num7 = instance1.m_blocks.m_buffer[(int)num7].m_nextGridBlock;
                        if (++num8 >= 49152)
                        {
                            CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + System.Environment.StackTrace);

                            break;
                        }
                    }
                }
            }
            for (int index = 0; index < 13; ++index)
            {
                uint num7  = (uint)xBuffer[index];
                int  num8  = 0;
                bool flag1 = ((int)num7 & 196608) == 196608;
                bool flag2 = false;
                while (((int)num7 & 1) != 0)
                {
                    ++num8;
                    flag2  = ((int)num7 & 65536) != 0;
                    num7 >>= 1;
                }
                if (num8 == 5 || num8 == 6)
                {
                    num8 = (!flag2 ? 4 : num8 - (Singleton <SimulationManager> .instance.m_randomizer.Int32(2U) + 2)) | 131072;
                }
                else if (num8 == 7)
                {
                    num8 = 4 | 131072;
                }
                if (flag1)
                {
                    num8 |= 65536;
                }
                xBuffer[index] = num8;
            }
            int num9 = xBuffer[6] & (int)ushort.MaxValue;

            if (num9 == 0)
            {
                return;
            }
            //begin mod
            bool flag3 = IsGoodPlace(ref block, vector2_2);

            //end mod
            if (Singleton <SimulationManager> .instance.m_randomizer.Int32(100U) >= num2)
            {
                if (!flag3)
                {
                    return;
                }
                instance1.m_goodAreaFound[(int)zone] = (short)1024;
            }
            else if (!flag3 && (int)instance1.m_goodAreaFound[(int)zone] > -1024)
            {
                if ((int)instance1.m_goodAreaFound[(int)zone] != 0)
                {
                    return;
                }
                instance1.m_goodAreaFound[(int)zone] = (short)-1;
            }
            else
            {
                int  index1 = 6;
                int  index2 = 6;
                bool flag1  = true;
                while (true)
                {
                    if (flag1)
                    {
                        while (index1 != 0 && (xBuffer[index1 - 1] & (int)ushort.MaxValue) == num9)
                        {
                            --index1;
                        }
                        while (index2 != 12 && (xBuffer[index2 + 1] & (int)ushort.MaxValue) == num9)
                        {
                            ++index2;
                        }
                    }
                    else
                    {
                        while (index1 != 0 && (xBuffer[index1 - 1] & (int)ushort.MaxValue) >= num9)
                        {
                            --index1;
                        }
                        while (index2 != 12 && (xBuffer[index2 + 1] & (int)ushort.MaxValue) >= num9)
                        {
                            ++index2;
                        }
                    }
                    int num7 = index1;
                    int num8 = index2;
                    while (num7 != 0 && (xBuffer[num7 - 1] & (int)ushort.MaxValue) >= 2)
                    {
                        --num7;
                    }
                    while (num8 != 12 && (xBuffer[num8 + 1] & (int)ushort.MaxValue) >= 2)
                    {
                        ++num8;
                    }
                    bool flag2 = num7 != 0 && num7 == index1 - 1;
                    bool flag4 = num8 != 12 && num8 == index2 + 1;
                    if (flag2 && flag4)
                    {
                        if (index2 - index1 <= 2)
                        {
                            if (num9 <= 2)
                            {
                                if (!flag1)
                                {
                                    goto label_88;
                                }
                            }
                            else
                            {
                                --num9;
                            }
                        }
                        else
                        {
                            break;
                        }
                    }
                    else if (flag2)
                    {
                        if (index2 - index1 <= 1)
                        {
                            if (num9 <= 2)
                            {
                                if (!flag1)
                                {
                                    goto label_88;
                                }
                            }
                            else
                            {
                                --num9;
                            }
                        }
                        else
                        {
                            goto label_73;
                        }
                    }
                    else if (flag4)
                    {
                        if (index2 - index1 <= 1)
                        {
                            if (num9 <= 2)
                            {
                                if (!flag1)
                                {
                                    goto label_88;
                                }
                            }
                            else
                            {
                                --num9;
                            }
                        }
                        else
                        {
                            goto label_79;
                        }
                    }
                    else if (index1 == index2)
                    {
                        if (num9 <= 2)
                        {
                            if (!flag1)
                            {
                                goto label_88;
                            }
                        }
                        else
                        {
                            --num9;
                        }
                    }
                    else
                    {
                        goto label_88;
                    }
                    flag1 = false;
                }
                ++index1;
                --index2;
                goto label_88;
label_73:
                ++index1;
                goto label_88;
label_79:
                --index2;
label_88:
                int index3;
                int index4;
                if (num9 == 1 && index2 - index1 >= 1)
                {
                    index1 += Singleton <SimulationManager> .instance.m_randomizer.Int32((uint)(index2 - index1));

                    index2 = index1 + 1;
                    index3 = index1 + Singleton <SimulationManager> .instance.m_randomizer.Int32(2U);

                    index4 = index3;
                }
                else
                {
                    do
                    {
                        index3 = index1;
                        index4 = index2;
                        if (index2 - index1 == 2)
                        {
                            if (Singleton <SimulationManager> .instance.m_randomizer.Int32(2U) == 0)
                            {
                                --index4;
                            }
                            else
                            {
                                ++index3;
                            }
                        }
                        else if (index2 - index1 == 3)
                        {
                            if (Singleton <SimulationManager> .instance.m_randomizer.Int32(2U) == 0)
                            {
                                index4 -= 2;
                            }
                            else
                            {
                                index3 += 2;
                            }
                        }
                        else if (index2 - index1 == 4)
                        {
                            if (Singleton <SimulationManager> .instance.m_randomizer.Int32(2U) == 0)
                            {
                                index2 -= 2;
                                index4 -= 3;
                            }
                            else
                            {
                                index1 += 2;
                                index3 += 3;
                            }
                        }
                        else if (index2 - index1 == 5)
                        {
                            if (Singleton <SimulationManager> .instance.m_randomizer.Int32(2U) == 0)
                            {
                                index2 -= 3;
                                index4 -= 2;
                            }
                            else
                            {
                                index1 += 3;
                                index3 += 2;
                            }
                        }
                        else if (index2 - index1 >= 6)
                        {
                            if (index1 == 0 || index2 == 12)
                            {
                                if (index1 == 0)
                                {
                                    index1 = 3;
                                    index3 = 2;
                                }
                                if (index2 == 12)
                                {
                                    index2 = 9;
                                    index4 = 10;
                                }
                            }
                            else if (Singleton <SimulationManager> .instance.m_randomizer.Int32(2U) == 0)
                            {
                                index2 = index1 + 3;
                                index4 = index3 + 2;
                            }
                            else
                            {
                                index1 = index2 - 3;
                                index3 = index4 - 2;
                            }
                        }
                    }while (index2 - index1 > 3 || index4 - index3 > 3);
                }
                int a1    = 4;
                int num10 = index2 - index1 + 1;
                BuildingInfo.ZoningMode zoningMode1 = BuildingInfo.ZoningMode.Straight;
                bool flag5 = true;
                for (int index5 = index1; index5 <= index2; ++index5)
                {
                    a1 = Mathf.Min(a1, xBuffer[index5] & (int)ushort.MaxValue);
                    if ((xBuffer[index5] & 131072) == 0)
                    {
                        flag5 = false;
                    }
                }
                if (index2 > index1)
                {
                    if ((xBuffer[index1] & 65536) != 0)
                    {
                        zoningMode1 = BuildingInfo.ZoningMode.CornerLeft;
                        index4      = index1 + index4 - index3;
                        index3      = index1;
                    }
                    if ((xBuffer[index2] & 65536) != 0 && (zoningMode1 != BuildingInfo.ZoningMode.CornerLeft || Singleton <SimulationManager> .instance.m_randomizer.Int32(2U) == 0))
                    {
                        zoningMode1 = BuildingInfo.ZoningMode.CornerRight;
                        index3      = index2 + index3 - index4;
                        index4      = index2;
                    }
                }
                int a2    = 4;
                int num11 = index4 - index3 + 1;
                BuildingInfo.ZoningMode zoningMode2 = BuildingInfo.ZoningMode.Straight;
                bool flag6 = true;
                for (int index5 = index3; index5 <= index4; ++index5)
                {
                    a2 = Mathf.Min(a2, xBuffer[index5] & (int)ushort.MaxValue);
                    if ((xBuffer[index5] & 131072) == 0)
                    {
                        flag6 = false;
                    }
                }
                if (index4 > index3)
                {
                    if ((xBuffer[index3] & 65536) != 0)
                    {
                        zoningMode2 = BuildingInfo.ZoningMode.CornerLeft;
                    }
                    if ((xBuffer[index4] & 65536) != 0 && (zoningMode2 != BuildingInfo.ZoningMode.CornerLeft || Singleton <SimulationManager> .instance.m_randomizer.Int32(2U) == 0))
                    {
                        zoningMode2 = BuildingInfo.ZoningMode.CornerRight;
                    }
                }
                ItemClass.SubService subService = ItemClass.SubService.None;
                ItemClass.Level      level      = ItemClass.Level.Level1;
                ItemClass.Service    service;
                switch (zone)
                {
                case ItemClass.Zone.ResidentialLow:
                    service    = ItemClass.Service.Residential;
                    subService = ItemClass.SubService.ResidentialLow;
                    break;

                case ItemClass.Zone.ResidentialHigh:
                    service    = ItemClass.Service.Residential;
                    subService = ItemClass.SubService.ResidentialHigh;
                    break;

                case ItemClass.Zone.CommercialLow:
                    service    = ItemClass.Service.Commercial;
                    subService = ItemClass.SubService.CommercialLow;
                    break;

                case ItemClass.Zone.CommercialHigh:
                    service    = ItemClass.Service.Commercial;
                    subService = ItemClass.SubService.CommercialHigh;
                    break;

                case ItemClass.Zone.Industrial:
                    service = ItemClass.Service.Industrial;
                    break;

                case ItemClass.Zone.Office:
                    service = ItemClass.Service.Office;
                    break;

                default:
                    return;
                }
                BuildingInfo            info        = (BuildingInfo)null;
                Vector3                 vector3     = Vector3.zero;
                int                     num12       = 0;
                int                     num13       = 0;
                int                     width       = 0;
                BuildingInfo.ZoningMode zoningMode3 = BuildingInfo.ZoningMode.Straight;
                for (int index5 = 0; index5 < 6; ++index5)
                {
                    switch (index5)
                    {
                    case 0:
                        if (zoningMode1 != BuildingInfo.ZoningMode.Straight)
                        {
                            num12       = index1 + index2 + 1;
                            num13       = a1;
                            width       = num10;
                            zoningMode3 = zoningMode1;
                            goto default;
                        }
                        else
                        {
                            break;
                        }

                    case 1:
                        if (zoningMode2 != BuildingInfo.ZoningMode.Straight)
                        {
                            num12       = index3 + index4 + 1;
                            num13       = a2;
                            width       = num11;
                            zoningMode3 = zoningMode2;
                            goto default;
                        }
                        else
                        {
                            break;
                        }

                    case 2:
                        if (zoningMode1 != BuildingInfo.ZoningMode.Straight && a1 >= 4)
                        {
                            num12       = index1 + index2 + 1;
                            num13       = !flag5 ? 2 : 3;
                            width       = num10;
                            zoningMode3 = zoningMode1;
                            goto default;
                        }
                        else
                        {
                            break;
                        }

                    case 3:
                        if (zoningMode2 != BuildingInfo.ZoningMode.Straight && a2 >= 4)
                        {
                            num12       = index3 + index4 + 1;
                            num13       = !flag6 ? 2 : 3;
                            width       = num11;
                            zoningMode3 = zoningMode2;
                            goto default;
                        }
                        else
                        {
                            break;
                        }

                    case 4:
                        num12       = index1 + index2 + 1;
                        num13       = a1;
                        width       = num10;
                        zoningMode3 = BuildingInfo.ZoningMode.Straight;
                        goto default;

                    case 5:
                        num12       = index3 + index4 + 1;
                        num13       = a2;
                        width       = num11;
                        zoningMode3 = BuildingInfo.ZoningMode.Straight;
                        goto default;

                    default:
                        vector3 = block.m_position + VectorUtils.X_Y((float)((double)num13 * 0.5 - 4.0) * xDir + (float)((double)num12 * 0.5 + (double)z - 10.0) * zDir);
                        if (zone == ItemClass.Zone.Industrial)
                        {
                            ZoneBlock.GetIndustryType(vector3, out subService, out level);
                        }
                        else if (zone == ItemClass.Zone.CommercialLow || zone == ItemClass.Zone.CommercialHigh)
                        {
                            ZoneBlock.GetCommercialType(vector3, zone, width, num13, out subService, out level);
                        }
                        else if (zone == ItemClass.Zone.ResidentialLow || zone == ItemClass.Zone.ResidentialHigh)
                        {
                            ZoneBlock.GetResidentialType(vector3, zone, width, num13, out subService, out level);
                        }
                        else if (zone == ItemClass.Zone.Office)
                        {
                            ZoneBlock.GetOfficeType(vector3, zone, width, num13, out subService, out level);
                        }
                        byte   district2 = instance2.GetDistrict(vector3);
                        ushort style     = instance2.m_districts.m_buffer[(int)district2].m_Style;
                        if (Singleton <BuildingManager> .instance.m_BuildingWrapper != null)
                        {
                            Singleton <BuildingManager> .instance.m_BuildingWrapper.OnCalculateSpawn(vector3, ref service, ref subService, ref level, ref style);
                        }
                        info = Singleton <BuildingManager> .instance.GetRandomBuildingInfo(ref Singleton <SimulationManager> .instance.m_randomizer, service, subService, level, width, num13, zoningMode3, (int)style);

                        if (info == null)
                        {
                            break;
                        }
                        goto label_169;
                    }
                }
label_169:
                if (info == null || (double)Singleton <TerrainManager> .instance.WaterLevel(VectorUtils.XZ(vector3)) > (double)vector3.y || Singleton <DisasterManager> .instance.IsEvacuating(vector3))
                {
                    return;
                }
                float angle = block.m_angle + 1.570796f;
                if (zoningMode3 == BuildingInfo.ZoningMode.CornerLeft && info.m_zoningMode == BuildingInfo.ZoningMode.CornerRight)
                {
                    angle -= 1.570796f;
                    num13  = width;
                }
                else if (zoningMode3 == BuildingInfo.ZoningMode.CornerRight && info.m_zoningMode == BuildingInfo.ZoningMode.CornerLeft)
                {
                    angle += 1.570796f;
                    num13  = width;
                }
                ushort building;
                if (Singleton <BuildingManager> .instance.CreateBuilding(out building, ref Singleton <SimulationManager> .instance.m_randomizer, info, vector3, angle, num13, Singleton <SimulationManager> .instance.m_currentBuildIndex))
                {
                    ++Singleton <SimulationManager> .instance.m_currentBuildIndex;
                    switch (service)
                    {
                    case ItemClass.Service.Residential:
                        instance1.m_actualResidentialDemand = Mathf.Max(0, instance1.m_actualResidentialDemand - 5);
                        break;

                    case ItemClass.Service.Commercial:
                        instance1.m_actualCommercialDemand = Mathf.Max(0, instance1.m_actualCommercialDemand - 5);
                        break;

                    case ItemClass.Service.Industrial:
                        instance1.m_actualWorkplaceDemand = Mathf.Max(0, instance1.m_actualWorkplaceDemand - 5);
                        break;

                    case ItemClass.Service.Office:
                        instance1.m_actualWorkplaceDemand = Mathf.Max(0, instance1.m_actualWorkplaceDemand - 5);
                        break;
                    }
                    switch (zone)
                    {
                    case ItemClass.Zone.ResidentialHigh:
                    case ItemClass.Zone.CommercialHigh:
                        Singleton <BuildingManager> .instance.m_buildings.m_buffer[(int)building].m_flags |= Building.Flags.HighDensity;
                        break;
                    }
                }
                instance1.m_goodAreaFound[(int)zone] = (short)1024;
            }
        }
        private static void CalculateFillBuffer(ZoneTool _this, Vector3 position, Vector3 direction, float angle, ushort blockIndex, ref ZoneBlock block, ItemClass.Zone requiredZone, bool occupied1, bool occupied2)
        {
            float f1   = Mathf.Abs(block.m_angle - angle) * 0.6366197f;
            float num1 = f1 - Mathf.Floor(f1);

            if ((double)num1 >= 0.00999999977648258 && (double)num1 <= 0.990000009536743)
            {
                return;
            }
            int     rowCount    = block.RowCount;
            int     columnCount = ZoneBlockDetour.GetColumnCount(ref block); // modified
            Vector3 vector3_1   = new Vector3(Mathf.Cos(block.m_angle), 0.0f, Mathf.Sin(block.m_angle)) * 8f;
            Vector3 vector3_2   = new Vector3(vector3_1.z, 0.0f, -vector3_1.x);

            var m_fillBuffer1 = GetFillBuffer(_this);                   // modified
            var blockID       = ZoneBlockDetour.FindBlockId(ref block); // modified

            for (int z = 0; z < rowCount; ++z)
            {
                Vector3 vector3_3 = ((float)z - 3.5f) * vector3_2;
                for (int x = 0; x < columnCount; ++x) // modifed
                {
                    if (((long)block.m_valid & 1L << (z << 3 | x)) != 0L && ZoneBlockDetour.GetZoneDeep(ref block, blockID, x, z) == requiredZone)
                    {
                        if (occupied1)
                        {
                            if (requiredZone == ItemClass.Zone.Unzoned && ((long)block.m_occupied1 & 1L << (z << 3 | x)) == 0L)
                            {
                                continue;
                            }
                        }
                        else if (occupied2)
                        {
                            if (requiredZone == ItemClass.Zone.Unzoned && ((long)block.m_occupied2 & 1L << (z << 3 | x)) == 0L)
                            {
                                continue;
                            }
                        }
                        else if ((((long)block.m_occupied1 | (long)block.m_occupied2) & 1L << (z << 3 | x)) != 0L)
                        {
                            continue;
                        }
                        Vector3 vector3_4 = ((float)x - 3.5f) * vector3_1;
                        Vector3 vector3_5 = block.m_position + vector3_4 + vector3_3 - position;
                        float   f2        = (float)(((double)vector3_5.x * (double)direction.x + (double)vector3_5.z * (double)direction.z) * 0.125 + 32.0);
                        float   f3        = (float)(((double)vector3_5.x * (double)direction.z - (double)vector3_5.z * (double)direction.x) * 0.125 + 32.0);
                        int     num2      = Mathf.RoundToInt(f2);
                        int     index     = Mathf.RoundToInt(f3);
                        if (num2 >= 0 && num2 < 64 && (index >= 0 && index < 64) && ((double)Mathf.Abs(f2 - (float)num2) < 0.0125000001862645 && (double)Mathf.Abs(f3 - (float)index) < 0.0125000001862645))
                        {
                            m_fillBuffer1[index] |= (ulong)(1L << num2);
                        }
                    }
                }
            }
        }
Exemple #49
0
 private static void CheckBlock(ref ZoneBlock zoneBlock, ref ZoneBlock other, int[] xBuffer, ItemClass.Zone zone, Vector2 startPos, Vector2 xDir,
                                Vector2 zDir, Quad2 quad)
 {
     UnityEngine.Debug.Log($"{zoneBlock}-{other}-{xBuffer}-{zone}-{startPos}-{xDir}-{zDir}-{quad}");
 }
        /// <summary>
        /// Marks cells colliding with buildings as occupied and removes the zoning if the building is plopable.
        /// </summary>
        /// <param name="_this"></param>
        /// <param name="blockID"></param>
        /// <param name="info"></param>
        /// <param name="building"></param>
        /// <param name="occupied1"></param>
        /// <param name="occupied2"></param>
        /// <param name="zone1"></param>
        /// <param name="zone2"></param>
        /// <param name="minX"></param>
        /// <param name="minZ"></param>
        /// <param name="maxX"></param>
        /// <param name="maxZ"></param>
        private static void CalculateImplementation3(ref ZoneBlock _this, ref ulong zone3, ref ulong zone4, ushort blockID, BuildingInfo info, ref Building building, ref ulong occupied1, ref ulong occupied2, ref ulong zone1, ref ulong zone2, float minX, float minZ, float maxX, float maxZ)
        {
            // width of the zone block
            int rowCount = _this.RowCount;
            int columnCount = ZoneBlockDetour.GetColumnCount(ref _this); // modified

            // directions of the rows and columns based on zone block angle, multiplied by 8 (cell size)
            Vector2 columnDirection = new Vector2(Mathf.Cos(_this.m_angle), Mathf.Sin(_this.m_angle)) * 8f;
            Vector2 rowDirection = new Vector2(columnDirection.y, -columnDirection.x);

            // size of the building
            int width = building.Width;
            int length = building.Length;

            // direction of building width and length vectors
            Vector2 widthDirection = new Vector2(Mathf.Cos(building.m_angle), Mathf.Sin(building.m_angle));
            Vector2 lengthDirection = new Vector2(widthDirection.y, -widthDirection.x);

            // building width and length vectors (-0.8m tolerance)
            Vector2 halfWidthVector = widthDirection * (float)((double)width * 4.0 - 0.800000011920929);
            Vector2 halfLengthVector = lengthDirection * (float)((double)length * 4.0 - 0.800000011920929);
            if (info.m_circular)
            {
                halfWidthVector *= 0.7f;
                halfLengthVector *= 0.7f;
            }

            // position of the building
            Vector2 buildingPositionXZ = VectorUtils.XZ(building.m_position);

            // quad of the building lot
            Quad2 buildingQuad = new Quad2
            {
                a = buildingPositionXZ - halfWidthVector - halfLengthVector,
                b = buildingPositionXZ + halfWidthVector - halfLengthVector,
                c = buildingPositionXZ + halfWidthVector + halfLengthVector,
                d = buildingPositionXZ - halfWidthVector + halfLengthVector
            };

            Vector2 quadMin = buildingQuad.Min();
            Vector2 quadMax = buildingQuad.Max();

            // return if building not in collision range
            if ((double)quadMin.x > (double)maxX || (double)quadMin.y > (double)maxZ || ((double)minX > (double)quadMax.x || (double)minZ > (double)quadMax.y))
            {
                return;
            }

            // zone block position
            Vector2 positionXZ = VectorUtils.XZ(_this.m_position);

            // return if zone block quad does not intersect with building quad
            if (!new Quad2()
            {
                a = (positionXZ - 4f * columnDirection - 4f * rowDirection),
                b = (positionXZ + (columnCount - 4f) * columnDirection - 4f * rowDirection),
                c = (positionXZ + (columnCount - 4f) * columnDirection + (float)(rowCount - 4) * rowDirection),
                d = (positionXZ - 4f * columnDirection + (float)(rowCount - 4) * rowDirection)
            }.Intersect(buildingQuad))
            {
                return;
            }

            // Calculate which cells are colliding with the building
            ulong overlapCellMask = OverlapQuad(ref _this, buildingQuad);

            if (info.m_buildingAI.ClearOccupiedZoning()) // for non-growables
            {
                // set cells as occupied (use occupied2 mask)
                occupied2 = occupied2 | overlapCellMask;

                // Use zone1 mask for cells close to road (column 1 and 2)
                // 72340172838076673 - do not shift
                // 0000 0001 0000 0001 0000 0001 0000 0001
                // 0000 0001 0000 0001 0000 0001 0000 0001
                // 144680345676153346 - shift 3 to left
                // 0000 0010 0000 0010 0000 0010 0000 0010
                // 0000 0010 0000 0010 0000 0010 0000 0010
                ulong zoneClearMask = overlapCellMask & 72340172838076673UL | (overlapCellMask & 144680345676153346UL) << 3;
                zoneClearMask = zoneClearMask | zoneClearMask << 1;
                zoneClearMask = zoneClearMask | zoneClearMask << 2; // clear all 4 bits of each cell

                zone1 = zone1 & ~zoneClearMask;

                // Use zone2 mask for cells away to road (column 3 and 4)
                // 289360691352306692 - shift 2 to right
                // 0000 0100 0000 0100 0000 0100 0000 0100
                // 0000 0100 0000 0100 0000 0100 0000 0100
                // 578721382704613384 - shift 1 to left
                // 0000 1000 0000 1000 0000 1000 0000 1000
                // 0000 1000 0000 1000 0000 1000 0000 1000
                zoneClearMask = (overlapCellMask & 289360691352306692UL) >> 2 | (overlapCellMask & 578721382704613384UL) << 1;
                zoneClearMask = zoneClearMask | zoneClearMask << 1;
                zoneClearMask = zoneClearMask | zoneClearMask << 2; // clear all 4 bits of each cell

                zone2 = zone2 & ~zoneClearMask;

                // --- support for deeper zones ---

                // Use zone3 mask for cells away to road (column 5 and 6)
                // 1157442765409226768 - shift 4 to right
                // 0001 0000 0001 0000 0001 0000 0001 0000
                // 0001 0000 0001 0000 0001 0000 0001 0000
                // 2314885530818453536 - shift 1 to right
                // 0010 0000 0010 0000 0010 0000 0010 0000
                // 0010 0000 0010 0000 0010 0000 0010 0000
                zoneClearMask = (overlapCellMask & 1157442765409226768UL) >> 4 | (overlapCellMask & 2314885530818453536UL) >> 1;
                zoneClearMask = zoneClearMask | zoneClearMask << 1;
                zoneClearMask = zoneClearMask | zoneClearMask << 2; // clear all 4 bits of each cell

                zone3 = zone3 & ~zoneClearMask;

                // Use zone4 mask for cells away to road (column 7 and 8)
                // 4629771061636907072 - shift 6 to right
                // 0100 0000 0100 0000 0100 0000 0100 0000
                // 0100 0000 0100 0000 0100 0000 0100 0000
                // 0x8080808080808080 - shift 3 to right
                // 1000 0000 1000 0000 1000 0000 1000 0000
                // 1000 0000 1000 0000 1000 0000 1000 0000
                zoneClearMask = (overlapCellMask & 4629771061636907072UL) >> 6 | (overlapCellMask & 0x8080808080808080UL) >> 3;
                zoneClearMask = zoneClearMask | zoneClearMask << 1;
                zoneClearMask = zoneClearMask | zoneClearMask << 2; // clear all 4 bits of each cell

                zone4 = zone4 & ~zoneClearMask;
            }
            else
                // set cells as occupied (use occupied1 mask)
                occupied1 = occupied1 | overlapCellMask;
        }
 private void ReleaseBlockImplementation(ushort block, ref ZoneBlock data)
 {
     var zm = ZoneManager.instance;
     if (data.m_flags != 0u)
     {
         data.m_flags |= 2u;
         zm.m_cachedBlocks.Add(data);
         data.m_flags = 0u;
         int num = Mathf.Clamp((int)(data.m_position.x / 64f + HALFGRID), 0, GRIDSIZE - 1);
         int num2 = Mathf.Clamp((int)(data.m_position.z / 64f + HALFGRID), 0, GRIDSIZE - 1);
         int num3 = num2 * GRIDSIZE + num;
         while (!Monitor.TryEnter(zoneGrid, SimulationManager.SYNCHRONIZE_TIMEOUT))
         {
         }
         try
         {
             ushort num4 = 0;
             ushort num5 = zoneGrid[num3];
             int num6 = 0;
             while (num5 != 0)
             {
                 if (num5 == block)
                 {
                     if (num4 == 0)
                     {
                         zoneGrid[num3] = data.m_nextGridBlock;
                     }
                     else
                     {
                         zm.m_blocks.m_buffer[(int)num4].m_nextGridBlock = data.m_nextGridBlock;
                     }
                     break;
                 }
                 num4 = num5;
                 num5 = zm.m_blocks.m_buffer[(int)num5].m_nextGridBlock;
                 if (++num6 > 32768)
                 {
                     CODebugBase<LogChannel>.Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace);
                     break;
                 }
             }
             data.m_nextGridBlock = 0;
         }
         finally
         {
             Monitor.Exit(zoneGrid);
         }
         zm.m_blocks.ReleaseItem(block);
         zm.m_blockCount = (int)(zm.m_blocks.ItemCount() - 1u);
     }
 }
        /// <summary>
        /// Compares zone block with other block.
        /// </summary>
        /// <param name="_this"></param>
        /// <param name="other"></param>
        /// <param name="xBuffer"></param>
        /// <param name="zone"></param>
        /// <param name="startPos"></param>
        /// <param name="xDir"></param>
        /// <param name="zDir"></param>
        /// <param name="quad"></param>
        private static void CheckBlock(ref ZoneBlock _this, ushort otherBlockID, ref ZoneBlock other, int[] xBuffer, ItemClass.Zone zone, Vector2 startPos, Vector2 xDir, Vector2 zDir, Quad2 quad)
        {
            // difference of 2 radian angles (360 deg = 2*PI * 0.6366197f = 4f)
            // that means an angle difference of 90 deg would result in 1f
            float angleDiff = Mathf.Abs(other.m_angle - _this.m_angle) * 0.6366197f;
            float rightAngleDiff = angleDiff - Mathf.Floor(angleDiff);

            // check if the zone block and the other zone block are in right angle (0 90 180 270 deg), otherwise return
            if ((double)rightAngleDiff >= 0.00999999977648258 && (double)rightAngleDiff <= 0.990000009536743) return;

            // width of other block
            int otherRowCount = other.RowCount;
            int otherColumnCount = ZoneBlockDetour.GetColumnCount(ref other); // modified

            Vector2 otherColumnDirection = new Vector2(Mathf.Cos(other.m_angle), Mathf.Sin(other.m_angle)) * 8f;
            Vector2 otherRowDirection = new Vector2(otherColumnDirection.y, -otherColumnDirection.x);

            ulong otherValidFreeCellMask = other.m_valid & ~(other.m_occupied1 | other.m_occupied2);

            Vector2 otherPositionXZ = VectorUtils.XZ(other.m_position);

            // check if the zone block quad of the other block intersects with the zone block, otherwise return
            if (!quad.Intersect(new Quad2()
            {
                a = otherPositionXZ - 4f * otherColumnDirection - 4f * otherRowDirection,
                b = otherPositionXZ + (otherColumnCount - 4f) * otherColumnDirection - 4f * otherRowDirection,
                c = otherPositionXZ + (otherColumnCount - 4f) * otherColumnDirection + (float)(otherRowCount - 4) * otherRowDirection,
                d = otherPositionXZ - 4f * otherColumnDirection + (float)(otherRowCount - 4) * otherRowDirection
            }))
            {
                return;
            }

            // Cycle through all cells of the other block
            for (int row = 0; row < otherRowCount; ++row)
            {
                Vector2 rowMiddleLength = ((float)row - 3.5f) * otherRowDirection;
                for (int column = 0; column < otherColumnCount; ++column)
                {
                    // check if the cell is unoccupied and zoned correctly
                    if ((otherValidFreeCellMask & 1UL << (row << 3 | column)) != 0UL && GetZoneDeep(ref other, otherBlockID, column, row) == zone)
                    {
                        Vector2 columnMiddleLength = ((float)column - 3.5f) * otherColumnDirection;

                        // Calculate the distance between the seed point and the current cell
                        Vector2 cellStartPosDistance = otherPositionXZ + columnMiddleLength + rowMiddleLength - startPos;

                        // dot product divided by 8*8 (normalized to cell size)
                        // cell distance in x direction between the seed cell and the current cell
                        float distColumnDirection = (float)(((double)cellStartPosDistance.x * (double)xDir.x + (double)cellStartPosDistance.y * (double)xDir.y) * (1.0 / 64.0));

                        // cell distance in z direction (rowDirection between the seed cell and the current cell
                        float distRowDirection = (float)(((double)cellStartPosDistance.x * (double)zDir.x + (double)cellStartPosDistance.y * (double)zDir.y) * (1.0 / 64.0));

                        // rounded distances
                        int roundedDistColumnDirection = Mathf.RoundToInt(distColumnDirection); // must be >=0 (behind road) and <=6 (7 cells to the back)
                        int roundedDistRowDirection = Mathf.RoundToInt(distRowDirection); // must be >=-6 and <=6 (6 cells to the left or 6 cells to the right)

                        // TODO raise numbers and array size for 8x8 lot support

                        if (roundedDistColumnDirection >= 0 && roundedDistColumnDirection <= 6 && (roundedDistRowDirection >= -6 && roundedDistRowDirection <= 6)
                            // cells must be aligned in the same grid + 1% tolerance
                            && ((double)Mathf.Abs(distColumnDirection - (float)roundedDistColumnDirection) < 0.0125000001862645
                            && (double)Mathf.Abs(distRowDirection - (float)roundedDistRowDirection) < 0.0125000001862645
                            // must have road access or be behind one of the cells touching the road of the seed block
                            // column == 0 means access to the road belonging to the zone block
                            // roundedDistColumnDirection != 0
                            && (column == 0 || roundedDistColumnDirection != 0)))
                        {
                            // Mark the cell in the column mask (in the row buffer array)
                            xBuffer[roundedDistRowDirection + 6] |= 1 << roundedDistColumnDirection;

                            // If the column touches the road, also mark it in the second part of the int mask
                            if (column == 0)
                            {
                                xBuffer[roundedDistRowDirection + 6] |= 1 << roundedDistColumnDirection + 16; // shift by 16
                            }
                        }
                    }
                }
            }
        }
        private Vector3 GetSnapDelta(Vector3 moveDelta, float angleDelta, Vector3 center, out bool autoCurve)
        {
            autoCurve = false;

            if (VectorUtils.XZ(moveDelta) == Vector2.zero)
            {
                return(moveDelta);
            }

            Vector3 newMoveDelta = moveDelta;

            NetManager netManager = NetManager.instance;

            NetSegment[] segmentBuffer  = netManager.m_segments.m_buffer;
            NetNode[]    nodeBuffer     = netManager.m_nodes.m_buffer;
            Building[]   buildingBuffer = BuildingManager.instance.m_buildings.m_buffer;

            Matrix4x4 matrix4x = default;

            matrix4x.SetTRS(center, Quaternion.AngleAxis(angleDelta * Mathf.Rad2Deg, Vector3.down), Vector3.one);

            bool snap = false;

            HashSet <InstanceState> newStates = null;

            if (ActionQueue.instance.current is TransformAction transformAction)
            {
                newStates = transformAction.CalculateStates(moveDelta, angleDelta, center, followTerrain);
            }

            if (ActionQueue.instance.current is CloneAction cloneAction)
            {
                newStates = cloneAction.CalculateStates(moveDelta, angleDelta, center, followTerrain);
            }

            // Snap to direction
            if (newStates.Count == 1)
            {
                foreach (InstanceState state in newStates)
                {
                    if (state.instance.id.Type == InstanceType.NetSegment)
                    {
                        return(SnapSegmentDirections(state.instance.id.NetSegment, state.position, moveDelta));
                    }
                    else if (state.instance.id.Type == InstanceType.NetNode)
                    {
                        if (TrySnapNodeDirections(state.instance.id.NetNode, state.position, moveDelta, out newMoveDelta, out autoCurve))
                        {
                            DebugUtils.Log("Snap to direction: " + moveDelta + ", " + newMoveDelta);
                            return(newMoveDelta);
                        }
                    }
                }
            }

            HashSet <ushort> ingnoreSegments = new HashSet <ushort>();
            HashSet <ushort> segmentList     = new HashSet <ushort>();

            ushort[] closeSegments = new ushort[16];

            // Get list of closest segments
            foreach (InstanceState state in newStates)
            {
                netManager.GetClosestSegments(state.position, closeSegments, out int closeSegmentCount);
                segmentList.UnionWith(closeSegments);

                if (ToolState != ToolStates.Cloning)
                {
                    ingnoreSegments.UnionWith(state.instance.segmentList);
                }
            }

            float distanceSq = float.MaxValue;

            // Snap to node
            foreach (ushort segment in segmentList)
            {
                if (!ingnoreSegments.Contains(segment))
                {
                    foreach (InstanceState state in newStates)
                    {
                        if (state.instance.id.Type == InstanceType.NetNode)
                        {
                            float minSqDistance = segmentBuffer[segment].Info.GetMinNodeDistance() / 2f;
                            minSqDistance *= minSqDistance;

                            ushort startNode = segmentBuffer[segment].m_startNode;
                            ushort endNode   = segmentBuffer[segment].m_endNode;

                            snap = TrySnapping(nodeBuffer[startNode].m_position, state.position, minSqDistance, ref distanceSq, moveDelta, ref newMoveDelta) || snap;
                            snap = TrySnapping(nodeBuffer[endNode].m_position, state.position, minSqDistance, ref distanceSq, moveDelta, ref newMoveDelta) || snap;
                        }
                    }
                }
            }

            if (snap)
            {
                DebugUtils.Log("Snap to node: " + moveDelta + ", " + newMoveDelta);
                return(newMoveDelta);
            }

            // Snap to segment
            foreach (ushort segment in segmentList)
            {
                if (!ingnoreSegments.Contains(segment))
                {
                    foreach (InstanceState state in newStates)
                    {
                        if (state.instance.id.Type == InstanceType.NetNode)
                        {
                            float minSqDistance = segmentBuffer[segment].Info.GetMinNodeDistance() / 2f;
                            minSqDistance *= minSqDistance;

                            segmentBuffer[segment].GetClosestPositionAndDirection(state.position, out Vector3 testPos, out Vector3 direction);

                            snap = TrySnapping(testPos, state.position, minSqDistance, ref distanceSq, moveDelta, ref newMoveDelta) || snap;
                        }
                    }
                }
            }

            if (snap)
            {
                DebugUtils.Log("Snap to segment: " + moveDelta + ", " + newMoveDelta);
                return(newMoveDelta);
            }

            // Snap to grid
            ushort  block         = 0;
            ushort  previousBlock = 0;
            Vector3 refPosition   = Vector3.zero;
            bool    smallRoad     = false;

            foreach (ushort segment in segmentList)
            {
                bool hasBlocks = segment != 0 && (segmentBuffer[segment].m_blockStartLeft != 0 || segmentBuffer[segment].m_blockStartRight != 0 || segmentBuffer[segment].m_blockEndLeft != 0 || segmentBuffer[segment].m_blockEndRight != 0);
                if (hasBlocks && !ingnoreSegments.Contains(segment))
                {
                    foreach (InstanceState state in newStates)
                    {
                        if (state.instance.id.Type != InstanceType.NetSegment)
                        {
                            Vector3 testPosition = state.position;

                            if (state.instance.id.Type == InstanceType.Building)
                            {
                                ushort building = state.instance.id.Building;
                                testPosition = GetBuildingSnapPoint(state.position, state.angle, buildingBuffer[building].Length, buildingBuffer[building].Width);
                            }

                            segmentBuffer[segment].GetClosestZoneBlock(testPosition, ref distanceSq, ref block);

                            if (block != previousBlock)
                            {
                                refPosition = testPosition;

                                if (state.instance.id.Type == InstanceType.NetNode)
                                {
                                    if (nodeBuffer[state.instance.id.NetNode].Info.m_halfWidth <= 4f)
                                    {
                                        smallRoad = true;
                                    }
                                }

                                previousBlock = block;
                            }
                        }
                    }
                }
            }

            if (block != 0)
            {
                Vector3   newPosition = refPosition;
                ZoneBlock zoneBlock   = ZoneManager.instance.m_blocks.m_buffer[block];
                SnapToBlock(ref newPosition, zoneBlock.m_position, zoneBlock.m_angle, smallRoad);

                DebugUtils.Log("Snap to grid: " + moveDelta + ", " + (moveDelta + newPosition - refPosition));
                return(moveDelta + newPosition - refPosition);
            }

            // Snap to editor grid
            if ((ToolManager.instance.m_properties.m_mode & ItemClass.Availability.AssetEditor) != ItemClass.Availability.None)
            {
                Vector3 assetGridPosition = Vector3.zero;
                float   testMagnitude     = 0;

                foreach (InstanceState state in newStates)
                {
                    Vector3 testPosition = state.position;

                    if (state.instance.id.Type == InstanceType.Building)
                    {
                        ushort building = state.instance.id.Building;
                        testPosition = GetBuildingSnapPoint(state.position, state.angle, buildingBuffer[building].Length, buildingBuffer[building].Width);
                    }


                    float x = Mathf.Round(testPosition.x / 8f) * 8f;
                    float z = Mathf.Round(testPosition.z / 8f) * 8f;

                    Vector3 newPosition    = new Vector3(x, testPosition.y, z);
                    float   deltaMagnitude = (newPosition - testPosition).sqrMagnitude;

                    if (assetGridPosition == Vector3.zero || deltaMagnitude < testMagnitude)
                    {
                        refPosition       = testPosition;
                        assetGridPosition = newPosition;
                        deltaMagnitude    = testMagnitude;
                    }
                }

                DebugUtils.Log("Snap to grid: " + moveDelta + ", " + (moveDelta + assetGridPosition - refPosition));
                return(moveDelta + assetGridPosition - refPosition);
            }

            return(moveDelta);
        }
        /// <summary>
        /// Checks if position has access to electricity.
        /// </summary>
        /// <param name="_this"></param>
        /// <param name="position"></param>
        /// <returns></returns>
        private static bool IsGoodPlace(ref ZoneBlock _this, Vector2 position)
        {
            // calculate which building grid cells are in range of this position
            int gridMinX = Mathf.Max((int)(((double)position.x - 104.0) / 64.0 + 135.0), 0);
            int gridMinZ = Mathf.Max((int)(((double)position.y - 104.0) / 64.0 + 135.0), 0);
            int gridMaxX = Mathf.Min((int)(((double)position.x + 104.0) / 64.0 + 135.0), 269);
            int gridMaxZ = Mathf.Min((int)(((double)position.y + 104.0) / 64.0 + 135.0), 269);

            Array16<Building> buildings = Singleton<BuildingManager>.instance.m_buildings;
            ushort[] buildingGrid = Singleton<BuildingManager>.instance.m_buildingGrid;

            // Cycle through all relevant grid cells
            for (int gridZ = gridMinZ; gridZ <= gridMaxZ; ++gridZ)
            {
                for (int gridX = gridMinX; gridX <= gridMaxX; ++gridX)
                {
                    // Cycle through all buildings in grid cell
                    ushort buildingID = buildingGrid[gridZ * 270 + gridX];
                    int counter = 0;
                    while ((int)buildingID != 0)
                    {
                        // only look at existing buildings
                        if ((buildings.m_buffer[(int)buildingID].m_flags & (Building.Flags.Created | Building.Flags.Deleted)) == Building.Flags.Created)
                        {
                            BuildingInfo info;
                            int width;
                            int length;
                            buildings.m_buffer[(int)buildingID].GetInfoWidthLength(out info, out width, out length);

                            if (info != null)
                            {
                                // check if spot has access to electricity
                                float electricityGridRadius = info.m_buildingAI.ElectricityGridRadius();
                                if ((double)electricityGridRadius > 0.100000001490116 || info.m_class.m_service == ItemClass.Service.Electricity)
                                {
                                    Vector2 buildingPositionXZ = VectorUtils.XZ(buildings.m_buffer[(int)buildingID].m_position);
                                    float radius2 = Mathf.Max(8f, electricityGridRadius) + 32f;
                                    if ((double)Vector2.SqrMagnitude(position - buildingPositionXZ) < (double)radius2 * (double)radius2)
                                        return true;
                                }
                            }
                        }
                        // next building in grid cell (linked list)
                        buildingID = buildings.m_buffer[(int)buildingID].m_nextGridBuilding;

                        if (++counter >= 49152)
                        {
                            CODebugBase<LogChannel>.Error(LogChannel.Core, "Invalid list detected!\n" + System.Environment.StackTrace);
                            break;
                        }
                    }
                }
            }
            return false;
        }
Exemple #55
0
 public static void RegisterZone(ZoneBlock zone)
 {
     Zones.Add(zone);
 }
        /// <summary>
        /// Overlaps the quad of the zone block with a colliding quad and returns a "invalid" bitmask for the colliding cells. Internal helper method.
        /// </summary>
        /// <param name="_this"></param>
        /// <param name="quad"></param>
        /// <returns></returns>
        private static ulong OverlapQuad(ref ZoneBlock _this, Quad2 quad)
        {
            // width of the zone block
            int rowCount = _this.RowCount;
            int columnCount = ZoneBlockDetour.GetColumnCount(ref _this); // modified

            // directions of the rows and columns based on zone block angle, multiplied by 8 (cell size)
            Vector2 columnDirection = new Vector2(Mathf.Cos(_this.m_angle), Mathf.Sin(_this.m_angle)) * 8f;
            Vector2 rowDirection = new Vector2(columnDirection.y, -columnDirection.x);

            // bounds of the colliding quad
            Vector2 collidingQuadMin = quad.Min();
            Vector2 collidingQuadMax = quad.Max();

            // origin of the zone block
            // this position is in the center of the 8x8 zone block (4 columns and 4 rows away from the lower corner)
            Vector2 positionXZ = VectorUtils.XZ(_this.m_position);

            // the "invalid" bitmask ("0" = valid, "1" = invalid)
            ulong invalid = 0;

            for (int row = 0; row < rowCount; ++row)
            {
                // calculate 2 relative row positions:
                // * one 0.1m from previous row
                // * one 0.1m from next row
                Vector2 rowNearPreviousLength = ((float)row - 3.9f) * rowDirection;
                Vector2 rowNearNextLength = ((float)row - 3.1f) * rowDirection;

                for (int column = 0; column < columnCount; ++column)
                {
                    // calculate 2 relative column positions:
                    // * one 0.1m from previous column
                    // * one 0.1m from next column
                    Vector2 columnNearPreviousLength = ((float)column - 3.9f) * columnDirection;
                    Vector2 columnNearNextLength = ((float)column - 3.1f) * columnDirection;

                    // middle position of the cell
                    Vector2 cellMiddlePos = positionXZ + (columnNearNextLength + columnNearPreviousLength + rowNearNextLength + rowNearPreviousLength) * 0.5f;

                    if ((double)collidingQuadMin.x <= (double)cellMiddlePos.x + 6.0 && (double)collidingQuadMin.y <= (double)cellMiddlePos.y + 6.0
                        && ((double)cellMiddlePos.x - 6.0 <= (double)collidingQuadMax.x && (double)cellMiddlePos.y - 6.0 <= (double)collidingQuadMax.y))
                    {
                        // Create a quad for the cell and intersect it with the colliding quad
                        if (quad.Intersect(new Quad2()
                        {
                            a = positionXZ + columnNearPreviousLength + rowNearPreviousLength,
                            b = positionXZ + columnNearNextLength + rowNearPreviousLength,
                            c = positionXZ + columnNearNextLength + rowNearNextLength,
                            d = positionXZ + columnNearPreviousLength + rowNearNextLength
                        }))
                        {
                            // if the cell is colliding, mark it as "1"
                            invalid |= 1uL << (row << 3 | column);
                        }
                    }
                }
            }
            return invalid;
        }
        /// <summary>
        /// Intersects zone block with other zone block, updates "valid" and "shared" masks.
        /// </summary>
        /// <param name="_this"></param>
        /// <param name="blockID"></param>
        /// <param name="other"></param>
        /// <param name="valid"></param>
        /// <param name="shared"></param>
        /// <param name="minX"></param>
        /// <param name="minZ"></param>
        /// <param name="maxX"></param>
        /// <param name="maxZ"></param>
        private static void CalculateImplementation2(ref ZoneBlock _this, ushort otherBlockID, ushort blockID, ref ZoneBlock other, ref ulong valid, ref ulong shared, float minX, float minZ, float maxX, float maxZ)
        {
            // 92 = sqrt(64^2+64^2)
            // if the other zone block is not marked as "created" or too far away, do nothing
            if (((int)other.m_flags & ZoneBlock.FLAG_CREATED) == 0 || (double)Mathf.Abs(other.m_position.x - _this.m_position.x) >= 92.0 || (double)Mathf.Abs(other.m_position.z - _this.m_position.z) >= 92.0)
            {
                return;
            }

            // checks if the other zone block is marked as "deleted"
            bool deleted = ((int)other.m_flags & ZoneBlock.FLAG_DELETED) != 0;

            // width of block and other block
            int rowCount = _this.RowCount;
            int columnCount = ZoneBlockDetour.GetColumnCount(ref _this); // modified
            int otherRowCount = other.RowCount;
            int otherColumnCount = ZoneBlockDetour.GetColumnCount(ref other); // modified

            // directions of the rows and columns of the block, multiplied by 8 (cell size)
            Vector2 columnDirection = new Vector2(Mathf.Cos(_this.m_angle), Mathf.Sin(_this.m_angle)) * 8f;
            Vector2 rowDirection = new Vector2(columnDirection.y, -columnDirection.x);

            // directions of the rows and columns of the other block, multiplied by 8 (cell size)
            Vector2 otherColumnDirection = new Vector2(Mathf.Cos(other.m_angle), Mathf.Sin(other.m_angle)) * 8f;
            Vector2 otherRowDirection = new Vector2(otherColumnDirection.y, -otherColumnDirection.x);

            // origin of the other block
            Vector2 otherPositionXZ = VectorUtils.XZ(other.m_position);

            // area of the other zone block
            Quad2 otherZoneBlockQuad = new Quad2
            {
                a = otherPositionXZ - 4f * otherColumnDirection - 4f * otherRowDirection,
                b = otherPositionXZ + (otherColumnCount - 4f) * otherColumnDirection - 4f * otherRowDirection,
                c = otherPositionXZ + (otherColumnCount - 4f) * otherColumnDirection + (float)(otherRowCount - 4) * otherRowDirection,
                d = otherPositionXZ - 4f * otherColumnDirection + (float)(otherRowCount - 4) * otherRowDirection
            };

            Vector2 otherQuadMin = otherZoneBlockQuad.Min();
            Vector2 otherQuadMax = otherZoneBlockQuad.Max();

            // return if there is no chance that the 2 quads collide
            if ((double)otherQuadMin.x > (double)maxX || (double)otherQuadMin.y > (double)maxZ || ((double)minX > (double)otherQuadMax.x || (double)minZ > (double)otherQuadMax.y))
            {
                return;
            }

            // origin of the block
            Vector2 positionXZ = VectorUtils.XZ(_this.m_position);

            // area of the zone block (8x4 cells)
            Quad2 zoneBlockQuad = new Quad2
            {
                a = positionXZ - 4f * columnDirection - 4f * rowDirection,
                b = positionXZ + (columnCount - 4f) * columnDirection - 4f * rowDirection,
                c = positionXZ + (columnCount - 4f) * columnDirection + (float)(rowCount - 4) * rowDirection,
                d = positionXZ - 4f * columnDirection + (float)(rowCount - 4) * rowDirection
            };

            // return if the quads are not intersecting
            if (!zoneBlockQuad.Intersect(otherZoneBlockQuad)) return;

            for (int row = 0; row < rowCount; ++row)
            {
                // calculate 2 relative row positions:
                // * one 0.01m from previous row
                // * one 0.01m from next row
                Vector2 rowNearPreviousLength = ((float)row - 3.99f) * rowDirection;
                Vector2 rowNearNextLength = ((float)row - 3.01f) * rowDirection;

                // set the quad to the row (4 cells)
                zoneBlockQuad.a = positionXZ - 4f * columnDirection + rowNearPreviousLength;
                zoneBlockQuad.b = positionXZ + (columnCount - 4f) * columnDirection + rowNearPreviousLength;
                zoneBlockQuad.c = positionXZ + (columnCount - 4f) * columnDirection + rowNearNextLength;
                zoneBlockQuad.d = positionXZ - 4f * columnDirection + rowNearNextLength;

                // Intersect the row quad with the other zone block quad
                if (zoneBlockQuad.Intersect(otherZoneBlockQuad))
                {
                    for (int column = 0; column < columnCount && (valid & 1uL << (row << 3 | column)) != 0uL; ++column)
                    {
                        // calculate 2 relative column positions:
                        // * one 0.01m from previous column
                        // * one 0.01m from next column
                        Vector2 columnNearPreviousLength = ((float)column - 3.99f) * columnDirection;
                        Vector2 columnNearNextLength = ((float)column - 3.01f) * columnDirection;

                        // middle position of the cell
                        Vector2 cellMiddlePos = positionXZ + (columnNearNextLength + columnNearPreviousLength + rowNearNextLength + rowNearPreviousLength) * 0.5f;

                        // check if the middle position of the cell is contained in the quad of the other zone block (1 cell tolerance)
                        if (Quad2.Intersect(otherZoneBlockQuad.a - otherColumnDirection - otherRowDirection, otherZoneBlockQuad.b + otherColumnDirection - otherRowDirection,
                            otherZoneBlockQuad.c + otherColumnDirection + otherRowDirection, otherZoneBlockQuad.d - otherColumnDirection + otherRowDirection, cellMiddlePos))
                        {
                            // Create a quad for the cell
                            Quad2 cellQuad = new Quad2
                            {
                                a = positionXZ + columnNearPreviousLength + rowNearPreviousLength,
                                b = positionXZ + columnNearNextLength + rowNearPreviousLength,
                                c = positionXZ + columnNearNextLength + rowNearNextLength,
                                d = positionXZ + columnNearPreviousLength + rowNearNextLength
                            };

                            // cycle through the cells of the other zone block
                            bool cellIsValid = true;
                            bool shareCell = false;
                            for (int otherRow = 0; otherRow < otherRowCount && cellIsValid; ++otherRow)
                            {
                                // calculate 2 relative row positions for the cell in the other zone block:
                                // * one 0.01m from previous row
                                // * one 0.01m from next row
                                Vector2 otherRowNearPreviousLength = ((float)otherRow - 3.99f) * otherRowDirection;
                                Vector2 otherRowNearNextLength = ((float)otherRow - 3.01f) * otherRowDirection;

                                for (int otherColumn = 0; otherColumn < otherColumnCount && cellIsValid; ++otherColumn)
                                {
                                    // checks if the cell is marked as valid in the valid mask of the other block, and that it is not contained in the shared mask
                                    if ((other.m_valid & ~other.m_shared & 1uL << (otherRow << 3 | otherColumn)) != 0uL)
                                    {
                                        // calculate 2 relative column positions for the cell in the other zone block:
                                        // * one 0.01m from previous column
                                        // * one 0.01m from next column
                                        Vector2 otherColumnNearPreviousLength = ((float)otherColumn - 3.99f) * otherColumnDirection;
                                        Vector2 otherColumnNearNextLength = ((float)otherColumn - 3.01f) * otherColumnDirection;

                                        // squared distance between the 2 cell middle positions
                                        float cellMiddleDist = Vector2.SqrMagnitude(otherPositionXZ + (otherColumnNearNextLength + otherColumnNearPreviousLength +
                                            otherRowNearNextLength + otherRowNearPreviousLength) * 0.5f - cellMiddlePos);

                                        // check if the 2 cells can touch
                                        if ((double)cellMiddleDist < 144.0)
                                        {
                                            if (!deleted) // other zone block not deleted:
                                            {
                                                // difference of 2 radian angles (360 deg = 2*PI * 0.6366197f = 4f)
                                                // that means an angle difference of 90 deg would result in 1f
                                                float angleDiff = Mathf.Abs(other.m_angle - _this.m_angle) * 0.6366197f;
                                                float rightAngleDiff = angleDiff - Mathf.Floor(angleDiff); // difference from 90 deg

                                                // if the 2 cells are almost in the same spot with an angle difference of 0 90 180 270 deg, mark one of them as shared
                                                if ((double)cellMiddleDist < 0.00999999977648258 && ((double)rightAngleDiff < 0.00999999977648258 || (double)rightAngleDiff > 0.990000009536743))
                                                {
                                                    // The cell closer to road (or that was created earler) is kept, the other marked as shared
                                                    if (column < otherColumn || column == otherColumn && _this.m_buildIndex < other.m_buildIndex)
                                                        other.m_shared |= 1UL << (otherRow << 3 | otherColumn);
                                                    else
                                                        shareCell = true;
                                                }
                                                // angles not right or not in the same place: Intersect the 2 cells
                                                else if (cellQuad.Intersect(new Quad2()
                                                {
                                                    a = otherPositionXZ + otherColumnNearPreviousLength + otherRowNearPreviousLength,
                                                    b = otherPositionXZ + otherColumnNearNextLength + otherRowNearPreviousLength,
                                                    c = otherPositionXZ + otherColumnNearNextLength + otherRowNearNextLength,
                                                    d = otherPositionXZ + otherColumnNearPreviousLength + otherRowNearNextLength
                                                }))
                                                {
                                                    // mark the cell which is further away from the road (or was created later) as invalid
                                                    // TODO adapt for 8 cell zones (low priority)
                                                    if (otherColumn >= 4 && column >= 4 || otherColumn < 4 && column < 4)
                                                    {
                                                        if (otherColumn >= 2 && column >= 2 || otherColumn < 2 && column < 2)
                                                        {
                                                            if (_this.m_buildIndex < other.m_buildIndex)
                                                                other.m_valid &= ~(1UL << (otherRow << 3 | otherColumn));
                                                            else
                                                                cellIsValid = false;
                                                        }
                                                        else if (otherColumn < 2)
                                                            cellIsValid = false;
                                                        else
                                                            other.m_valid &= ~(1UL << (otherRow << 3 | otherColumn));
                                                    }
                                                    else if (otherColumn < 4)
                                                        cellIsValid = false;
                                                    else
                                                        other.m_valid &= ~(1UL << (otherRow << 3 | otherColumn));
                                                }
                                            }
                                            // distance between cell middle pos < 6 = cells colliding
                                            // if the cell is unzoned, take over the zone type of the other one
                                            if ((double)cellMiddleDist < 36.0 && column < 8 && otherColumn < 8) // modifed 4 --> 8
                                            {
                                                ItemClass.Zone zone1 = GetZoneDeep(ref _this, blockID, column, row);
                                                ItemClass.Zone zone2 = GetZoneDeep(ref other, otherBlockID, otherColumn, otherRow);
                                                if (zone1 == ItemClass.Zone.Unzoned)
                                                    SetZoneDeep(ref _this, blockID, column, row, zone2);
                                                else if (zone2 == ItemClass.Zone.Unzoned && !deleted)
                                                    SetZoneDeep(ref other, otherBlockID, otherColumn, otherRow, zone1);
                                            }
                                        }
                                    }
                                }
                            }
                            if (!cellIsValid)
                            {
                                valid = valid & ~(1UL << (row << 3 | column));
                                break;
                            }
                            if (shareCell)
                                shared = shared | 1UL << (row << 3 | column);
                        }
                    }
                }
            }
        }
        private static bool ApplyFillBuffer(ZoneTool _this, Vector3 position, Vector3 direction, float angle, ushort blockIndex, ref ZoneBlock block)
        {
            var m_zoning   = IsZoningEnabled(_this);                 // custom
            var m_dezoning = IsDezoningEnabled(_this);               // custom
            var blockID    = ZoneBlockDetour.FindBlockId(ref block); // modified

            int rowCount    = block.RowCount;
            int columnCount = ZoneBlockDetour.GetColumnCount(ref block); // modified

            Vector3 vector3_1 = new Vector3(Mathf.Cos(block.m_angle), 0.0f, Mathf.Sin(block.m_angle)) * 8f;
            Vector3 vector3_2 = new Vector3(vector3_1.z, 0.0f, -vector3_1.x);
            bool    flag1     = false;

            for (int z = 0; z < rowCount; ++z)
            {
                Vector3 vector3_3 = ((float)z - 3.5f) * vector3_2;
                for (int x = 0; x < columnCount; ++x) // custom
                {
                    Vector3 vector3_4 = ((float)x - 3.5f) * vector3_1;
                    Vector3 vector3_5 = block.m_position + vector3_4 + vector3_3 - position;
                    float   f1        = (float)(((double)vector3_5.x * (double)direction.x + (double)vector3_5.z * (double)direction.z) * 0.125 + 32.0);
                    float   f2        = (float)(((double)vector3_5.x * (double)direction.z - (double)vector3_5.z * (double)direction.x) * 0.125 + 32.0);
                    int     num1      = Mathf.Clamp(Mathf.RoundToInt(f1), 0, 63);
                    int     num2      = Mathf.Clamp(Mathf.RoundToInt(f2), 0, 63);
                    bool    flag2     = false;

                    var m_fillBuffer1 = GetFillBuffer(_this); // modified

                    for (int index1 = -1; index1 <= 1 && !flag2; ++index1)
                    {
                        for (int index2 = -1; index2 <= 1 && !flag2; ++index2)
                        {
                            int num3   = num1 + index2;
                            int index3 = num2 + index1;
                            if (num3 >= 0 && num3 < 64 && (index3 >= 0 && index3 < 64) && (((double)f1 - (double)num3) * ((double)f1 - (double)num3)
                                                                                           + ((double)f2 - (double)index3) * ((double)f2 - (double)index3) < 9.0 / 16.0 && ((long)m_fillBuffer1[index3] & 1L << num3) != 0L))
                            {
                                if (m_zoning)
                                {
                                    if ((_this.m_zone == ItemClass.Zone.Unzoned || ZoneBlockDetour.GetZoneDeep(ref block, blockID, x, z) == ItemClass.Zone.Unzoned) &&
                                        ZoneBlockDetour.SetZoneDeep(ref block, blockID, x, z, _this.m_zone))
                                    {
                                        flag1 = true;
                                    }
                                }
                                else if (m_dezoning && ZoneBlockDetour.SetZoneDeep(ref block, blockID, x, z, ItemClass.Zone.Unzoned))
                                {
                                    flag1 = true;
                                }
                                flag2 = true;
                            }
                        }
                    }
                }
            }
            if (!flag1)
            {
                return(false);
            }
            block.RefreshZoning(blockIndex);
            return(true);
        }
        private void ReleaseBlockImplementation(ushort block, ref ZoneBlock data)
        {
            if ((int)data.m_flags == 0)
            {
                return;
            }
            data.m_flags |= 2U;
            this.m_cachedBlocks.Add(data);
            int     rowCount  = data.RowCount;
            float   f         = data.m_angle;
            Vector2 vector2_1 = new Vector2(Mathf.Cos(f), Mathf.Sin(f)) * 8f;
            Vector2 vector2_2 = new Vector2(vector2_1.y, -vector2_1.x);
            Vector2 vector2_3 = VectorUtils.XZ(data.m_position);

            this.UpdateBlocks(new Quad2()
            {
                a = vector2_3 - 4f * vector2_1 - 4f * vector2_2,
                b = vector2_3 + 0.0f * vector2_1 - 4f * vector2_2,
                c = vector2_3 + 0.0f * vector2_1 + (float)(rowCount - 4) * vector2_2,
                d = vector2_3 - 4f * vector2_1 + (float)(rowCount - 4) * vector2_2
            });
            data.m_flags = 0U;
            //begin mod
            int num1  = Mathf.Clamp((int)((double)data.m_position.x / 64.0 + HALFGRID), 0, GRIDSIZE - 1);
            int index = Mathf.Clamp((int)((double)data.m_position.z / 64.0 + HALFGRID), 0, GRIDSIZE - 1) * GRIDSIZE + num1;

            //end mod
            do
            {
                ;
            }while (!Monitor.TryEnter((object)this.m_zoneGrid, SimulationManager.SYNCHRONIZE_TIMEOUT));
            try
            {
                ushort num2 = (ushort)0;
                ushort num3 = this.m_zoneGrid[index];
                int    num4 = 0;
                while ((int)num3 != 0)
                {
                    if ((int)num3 == (int)block)
                    {
                        if ((int)num2 == 0)
                        {
                            this.m_zoneGrid[index] = data.m_nextGridBlock;
                            break;
                        }
                        this.m_blocks.m_buffer[(int)num2].m_nextGridBlock = data.m_nextGridBlock;
                        break;
                    }
                    num2 = num3;
                    num3 = this.m_blocks.m_buffer[(int)num3].m_nextGridBlock;
                    if (++num4 > 49152)
                    {
                        CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + System.Environment.StackTrace);

                        break;
                    }
                }
                data.m_nextGridBlock = (ushort)0;
            }
            finally
            {
                Monitor.Exit((object)this.m_zoneGrid);
            }
            this.m_blocks.ReleaseItem(block);
            this.m_blockCount = (int)this.m_blocks.ItemCount() - 1;
        }
        public static void CalculateBlock2(ref ZoneBlock _this, ushort blockID)
        {
            // skip zone blocks which are not in use
            if (((int)_this.m_flags & 3) != ZoneBlock.FLAG_CREATED) return;

            // width of the zone block
            int rowCount = _this.RowCount;
            int columnCount = ZoneBlockDetour.GetColumnCount(ref _this); // modified

            // directions of the rows and columns based on zone block angle, multiplied by 8 (cell size)
            Vector2 columnDirection = new Vector2(Mathf.Cos(_this.m_angle), Mathf.Sin(_this.m_angle)) * 8f;
            Vector2 rowDirection = new Vector2(columnDirection.y, -columnDirection.x);

            Vector2 positionXZ = VectorUtils.XZ(_this.m_position);

            // bounds of the zone block
            Vector2 a = positionXZ - 4f * columnDirection - 4f * rowDirection;
            Vector2 b = positionXZ + (columnCount - 4f) * columnDirection - 4f * rowDirection;
            Vector2 c = positionXZ + (columnCount - 4f) * columnDirection + (float)(rowCount - 4) * rowDirection;
            Vector2 d = positionXZ - 4f * columnDirection + (float)(rowCount - 4) * rowDirection;
            float minX = Mathf.Min(Mathf.Min(a.x, b.x), Mathf.Min(c.x, d.x));
            float minZ = Mathf.Min(Mathf.Min(a.y, b.y), Mathf.Min(c.y, d.y));
            float maxX = Mathf.Max(Mathf.Max(a.x, b.x), Mathf.Max(c.x, d.x));
            float maxZ = Mathf.Max(Mathf.Max(a.y, b.y), Mathf.Max(c.y, d.y));

            // "valid" mask
            ulong valid = _this.m_valid;

            // "shared" mask
            ulong shared = 0;

            ZoneManager zoneManager = Singleton<ZoneManager>.instance;

            // check if cached zone blocks are intersecting (updates valid and shared masks)
            for (int i = 0; i < zoneManager.m_cachedBlocks.m_size; ++i)
            {
                ushort otherBlockID = ZoneManagerDetour.cachedBlockIDs[i]; // custom
                CalculateImplementation2(ref _this, otherBlockID, blockID, ref zoneManager.m_cachedBlocks.m_buffer[i], ref valid, ref shared, minX, minZ, maxX, maxZ);
            }

            // calculate which zone block grid cells are touched by this zone block
            int gridMinX = Mathf.Max((int)(((double)minX - 46.0) / 64.0 + 75.0), 0);
            int gridMinZ = Mathf.Max((int)(((double)minZ - 46.0) / 64.0 + 75.0), 0);
            int gridMaxX = Mathf.Min((int)(((double)maxX + 46.0) / 64.0 + 75.0), 149);
            int gridMaxZ = Mathf.Min((int)(((double)maxZ + 46.0) / 64.0 + 75.0), 149);

            // Cycle through all zone blocks in touched grid cells
            for (int gridZ = gridMinZ; gridZ <= gridMaxZ; ++gridZ)
            {
                for (int gridX = gridMinX; gridX <= gridMaxX; ++gridX)
                {
                    // Cycle through all zone blocks in grid cell
                    ushort otherBlockId = zoneManager.m_zoneGrid[gridZ * 150 + gridX];
                    int counter = 0;
                    while ((int)otherBlockId != 0)
                    {
                        Vector3 otherPosition = zoneManager.m_blocks.m_buffer[(int)otherBlockId].m_position;
                        // 46 = 0.5 * sqrt(64^2+64^2)
                        // if the block is not too far away and not the same instance, intersect it (updates valid and shared masks)
                        if ((double)Mathf.Max(Mathf.Max(minX - 46f - otherPosition.x, minZ - 46f - otherPosition.z),
                            Mathf.Max((float)((double)otherPosition.x - (double)maxX - 46.0), (float)((double)otherPosition.z - (double)maxZ - 46.0))) < 0.0
                            && (int)otherBlockId != (int)blockID)
                        {
                            CalculateImplementation2(ref _this, otherBlockId, blockID, ref zoneManager.m_blocks.m_buffer[(int)otherBlockId], ref valid, ref shared, minX, minZ, maxX, maxZ);
                        }

                        // next zone block in grid cell (linked list)
                        otherBlockId = zoneManager.m_blocks.m_buffer[(int)otherBlockId].m_nextGridBlock;

                        if (++counter >= 49152)
                        {
                            CODebugBase<LogChannel>.Error(LogChannel.Core, "Invalid list detected!\n" + System.Environment.StackTrace);
                            break;
                        }
                    }
                }
            }
            // This part marks all cells as invalid which are behind existing invalid cells (so that there are no cells with no road access)
            // 0000 0100 0000 0100 0000 0100 0000 0100
            // 0000 0100 0000 0100 0000 0100 0000 0100
            ulong mask = 144680345676153346;
            for (int iteration = 0; iteration < 7; ++iteration)
            {
                valid = valid & ~mask | valid & valid << 1 & mask;
                mask <<= 1;
            }

            // apply the new masks
            _this.m_valid = valid;
            _this.m_shared = shared;
        }