private void Awake()
 {
     foreach (CurveScriptObject curve in curvesSO)
     {
         DataQuadTree <int> qt = new DataQuadTree <int>(minBound, maxBound);
         for (int i = 0; i < curve.points.Length; i++)
         {
             qt.Insert(curve.points[i], i);
         }
         curve.qTree = qt;
     }
     onCurvesRdy.Invoke();
 }
        /// <summary>
        /// Backup Algorithm to place Villages
        /// </summary>
        /// <param name="acceptableMap">Acceptable Map</param>
        /// <param name="villageMap">Vilage Map</param>
        /// <param name="radius">Village Radius for placement</param>
        /// <param name="expectedVillageSize">Expected Village Size</param>
        /// <param name="villageCount">Expected amount of villages placed</param>
        /// <param name="numberOfTries">Number of Tries to place a new village</param>
        /// <returns>Village Markers Placed</returns>
        private static List <VillageMarker> BackUpPlacement(
            bool[][] acceptableMap, int[][] villageMap,
            int radius, int expectedVillageSize, int villageCount, int numberOfTries)
        {
            int zSize = acceptableMap.Length;
            int xSize = acceptableMap[0].Length;
            List <VillageMarker> villages = new List <VillageMarker>(villageCount);

            DataQuadTree <VillageMarker> placedVillages
                = new DataQuadTree <VillageMarker>(Vector2Int.Zero, new Vector2Int(zSize, xSize));

            Random     rand        = new Random();
            int        minDistance = (int)((float)expectedVillageSize * kVillageSeparationPercentage);
            int        z;
            int        x;
            Vector2Int currPoint = new Vector2Int();

            DataQuadTree <VillageMarker> .DistanceToDataPoint closest;
            int id = 1;

            while (villageCount != 0 && numberOfTries != 0)
            {
                z           = rand.Next(0, zSize);
                x           = rand.Next(0, xSize);
                currPoint.Z = z;
                currPoint.X = x;
                closest     = placedVillages.NearestNeighbor(currPoint);
                if (
                    acceptableMap[z][x] && villageMap[z][x] <= 0 &&
                    (closest.DataNode == null || Vector2Int.Manhattan(closest.DataNode.Point, currPoint) > minDistance)
                    )
                {
                    VillageMarker village = VillageMarkerPlacer.CreateVillage(acceptableMap, villageMap, z, x, expectedVillageSize, radius, id);
                    if (village.Points.Count >= expectedVillageSize * kVillageSizePercentage)
                    {
                        ++id;
                        --villageCount;
                        villages.Add(village);
                        placedVillages.Insert(village.Seed, village);
                    }
                    else
                    {
                        VillageMarkerPlacer.EliminateVillageMarker(village, villageMap);
                    }
                }
                --numberOfTries;
            }
            return(villages);
        }
Esempio n. 3
0
        /// <summary>
        /// Place the blocks in the marked roads and bridges
        /// </summary>
        /// <param name="roads">Roads to place</param>
        /// <param name="roadMap">Road Map</param>
        /// <param name="heightMap">Height Map</param>
        /// <param name="waterMap">Water Map</param>
        /// <param name="biomes">Biomes</param>
        /// <param name="world">World</param>
        public static void RoadsPlacer(
            List <List <Vector2Int> > roads, int[][] roadMap, int[][] heightMap, int[][] waterMap, Biomes[][] biomes,
            Differ world)
        {
            RectInt            rectCover = new RectInt(Vector2Int.Zero, new Vector2Int(roadMap.Length - 1, roadMap[0].Length - 1));
            HashSet <ZPoint2D> bridges   = new HashSet <ZPoint2D>();

            int maxY = world.World.Length;

            List <Vector2Int> road;
            List <int>        newHeight = new List <int>();
            List <Vector2Int> torchPoint = new List <Vector2Int>();
            int   nz, nx, ny;
            float averageHeight;
            bool  torchPlaced;

            DataQuadTree <int> .DistanceToDataPoint closestLight;
            Random                     sharedRnd   = new Random();
            DataQuadTree <int>         lights      = new DataQuadTree <int>(rectCover.Min, rectCover.Max);
            Dictionary <ZPoint2D, int> lightPoints = new Dictionary <ZPoint2D, int>();

            // Ugly code but dumb fast
            for (int j = 0; j < roads.Count; j++)
            {
                road = roads[j];

                if (road.Count < 1)
                {
                    continue;
                }

                newHeight.Capacity  = Math.Max(newHeight.Capacity, road.Count);
                torchPoint.Capacity = Math.Max(newHeight.Capacity, road.Count);

                int diff = road.Count - newHeight.Count;
                for (int i = 0; i < diff; i++)
                {
                    newHeight.Add(0);
                    torchPoint.Add(Vector2Int.Zero);
                }

                // Pre Pass for land roads
                Parallel.For(0, road.Count, () => new Random(),
                             (int i, ParallelLoopState _, Random rnd) =>
                {
                    if (roadMap[road[i].Z][road[i].X] == RoadGenerator.MainRoadMarker)
                    {
                        // Road
                        int count           = 0;
                        float averageHeight = 0;
                        if (0 <= i - 2 && roadMap[road[i - 2].Z][road[i - 2].X] == RoadGenerator.MainRoadMarker)
                        {
                            averageHeight += (float)heightMap[road[i - 2].Z][road[i - 2].X];
                            ++count;
                        }

                        if (i + 2 < road.Count && roadMap[road[i + 2].Z][road[i + 2].X] == RoadGenerator.MainRoadMarker)
                        {
                            averageHeight += (float)heightMap[road[i + 2].Z][road[i + 2].X];
                            ++count;
                        }

                        List <Vector2Int> sides = new List <Vector2Int>(8);

                        int nz, nx;
                        for (int dz = -1; dz <= 1; dz++)
                        {
                            for (int dx = -1; dx <= 1; dx++)
                            {
                                nz = road[i].Z + dz;
                                nx = road[i].X + dx;
                                if (rectCover.IsInside(nz, nx))
                                {
                                    if (roadMap[nz][nx] == RoadGenerator.MainRoadMarker)
                                    {
                                        averageHeight += (float)heightMap[nz][nx];
                                        ++count;
                                    }
                                    else if (roadMap[nz][nx] == RoadGenerator.RoadMarker)
                                    {
                                        sides.Add(new Vector2Int(dz, dx));
                                    }
                                }
                            }
                        }
                        if (sides.Count > 0)
                        {
                            torchPoint[i] = sides[rnd.Next(0, sides.Count - 1)];
                        }
                        else
                        {
                            torchPoint[i] = new Vector2Int(-2, -2);
                        }
                        averageHeight /= (float)count;
                        newHeight[i]   = (int)Math.Round((double)averageHeight);
                    }
                    return(rnd);
                },
                             (Random rnd) => { return; }
                             );

                for (int i = 0; i < road.Count; i++)
                {
                    if (roadMap[road[i].Z][road[i].X] == RoadGenerator.MainRoadMarker)
                    {
                        // Normal Road
                        #region ROAD_PLACEMENT
                        for (int dz = -1; dz <= 1; dz++)
                        {
                            for (int dx = -1; dx <= 1; dx++)
                            {
                                nz = road[i].Z + dz;
                                nx = road[i].X + dx;
                                if (
                                    rectCover.IsInside(nz, nx) &&
                                    (roadMap[nz][nx] == RoadGenerator.MainRoadMarker || roadMap[nz][nx] == RoadGenerator.RoadMarker))
                                {
                                    world.ChangeBlock(newHeight[i], nz, nx, GetBiomeRoadBlock(biomes[nz][nx]));
                                    heightMap[nz][nx] = newHeight[i];
                                    // Clear top
                                    for (int dy = 1; dy <= 2; dy++)
                                    {
                                        ny = newHeight[i] + dy;
                                        if (ny < maxY)
                                        {
                                            world.ChangeBlock(ny, nz, nx, AlphaMaterials.Air_0_0);
                                        }
                                    }
                                }
                            }

                            closestLight = lights.NearestNeighbor(road[i]);
                            torchPlaced  = closestLight.DataNode != null && closestLight.ManClosestDistance <= kLightMinDistance;
                            if (!torchPlaced && torchPoint[i].Z != -2)
                            {
                                ZPoint2D tPoint = new ZPoint2D {
                                    RealPoint = road[i] + torchPoint[i]
                                };
                                lights.Insert(tPoint.RealPoint, 0);
                                lightPoints[tPoint] = newHeight[i];
                            }
                        }
                        #endregion // ROAD_PLACEMENT
                    }
                    else
                    {
                        // Bridge
                        #region BRIDGE_PLACEMENT

                        ZPoint2D curr = new ZPoint2D {
                            RealPoint = road[i]
                        };
                        ZPoint2D temp;

                        if (bridges.Contains(curr))
                        {
                            // Already processed
                            continue;
                        }
                        Stack <ZPoint2D>   bridgeStack = new Stack <ZPoint2D>();   // DFS of bridges
                        List <Vector2Int>  pivots      = new List <Vector2Int>();  // Bridge land connections
                        List <Vector2Int>  bridgeParts = new List <Vector2Int>();  // All parts of the bridge
                        HashSet <ZPoint2D> currBridge  = new HashSet <ZPoint2D>(); // Avoid parts repetitions
                        bridgeStack.Push(curr);
                        averageHeight = 0;

                        while (bridgeStack.Count != 0)
                        {
                            curr = bridgeStack.Pop();

                            closestLight = lights.NearestNeighbor(curr.RealPoint);
                            torchPlaced  = closestLight.DataNode != null && closestLight.ManClosestDistance <= kLightMinDistance;

                            for (int dz = -1; dz <= 1; dz++)
                            {
                                for (int dx = -1; dx <= 1; dx++)
                                {
                                    nz   = curr.RealPoint.Z + dz;
                                    nx   = curr.RealPoint.X + dx;
                                    temp = new ZPoint2D {
                                        RealPoint = new Vector2Int(nz, nx)
                                    };
                                    if (rectCover.IsInside(nz, nx) && !currBridge.Contains(temp))
                                    {
                                        if (roadMap[nz][nx] == RoadGenerator.MainRoadMarker)
                                        {
                                            averageHeight += heightMap[nz][nx];
                                            pivots.Add(new Vector2Int(nz, nx));
                                            currBridge.Add(temp);
                                        }
                                        else if (roadMap[nz][nx] == RoadGenerator.MainBridgeMarker)
                                        {
                                            bridges.Add(temp);
                                            bridgeParts.Add(temp.RealPoint);
                                            bridgeStack.Push(temp);
                                            currBridge.Add(temp);
                                        }
                                        else if (roadMap[nz][nx] == RoadGenerator.BridgeMarker)
                                        {
                                            bridgeParts.Add(new Vector2Int(nz, nx));
                                            bridgeStack.Push(temp);
                                            currBridge.Add(temp);
                                        }
                                    }
                                }
                            }
                        }

                        if (pivots.Count == 0)
                        {
                            // Bad Bridge
                            continue;
                        }

                        // Get Bridge Average Height, add 1 to put it above water
                        averageHeight /= (float)pivots.Count;
                        averageHeight += 3;

                        Parallel.ForEach(bridgeParts, () => new Tuple <Differ.ChangeCollector, Random>(world.CreateCollector(), new Random()),
                                         (Vector2Int point, ParallelLoopState _, Tuple <Differ.ChangeCollector, Random> tData) =>
                        {
                            Differ.ChangeCollector collector = tData.Item1;
                            Random rnd   = tData.Item2;
                            float height = 1.0f * Math.Max(heightMap[point.Z][point.X] + 1, averageHeight);
                            float factor = 1.0f;
                            float temp;
                            for (int k = 0; k < pivots.Count; k++)
                            {
                                temp    = 1.0f / (float)Vector2Int.Manhattan(point, pivots[k]);
                                factor += temp;
                                height += temp * heightMap[pivots[k].Z][pivots[k].X];
                            }
                            height         /= factor;
                            int finalHeight = (int)height;
                            collector.ChangeBlock(finalHeight, point.Z, point.X, AlphaMaterials.WoodenDoubleSlab_Seamed_43_2);
                            // Clear top
                            for (int dy = 1; dy <= 3; dy++)
                            {
                                ny = finalHeight + dy;
                                if (ny < maxY)
                                {
                                    collector.ChangeBlock(ny, point.Z, point.X, AlphaMaterials.Air_0_0);
                                }
                            }

                            if (roadMap[point.Z][point.X] == RoadGenerator.BridgeMarker)
                            {
                                if (
                                    (rectCover.IsInside(point.Z + 1, point.X + 0) && waterMap[point.Z + 1][point.X + 0] == 1 && roadMap[point.Z + 1][point.X + 0] == 0) ||
                                    (rectCover.IsInside(point.Z + 0, point.X + 1) && waterMap[point.Z + 0][point.X + 1] == 1 && roadMap[point.Z + 0][point.X + 1] == 0) ||
                                    (rectCover.IsInside(point.Z - 1, point.X + 0) && waterMap[point.Z - 1][point.X + 0] == 1 && roadMap[point.Z - 1][point.X + 0] == 0) ||
                                    (rectCover.IsInside(point.Z + 0, point.X - 1) && waterMap[point.Z + 0][point.X - 1] == 1 && roadMap[point.Z + 0][point.X - 1] == 0)
                                    )
                                {
                                    int ny = finalHeight + 1;
                                    if (ny < maxY)
                                    {
                                        collector.ChangeBlock(ny, point.Z, point.X, AlphaMaterials.AcaciaFence_192_0);
                                    }

                                    if (rnd.Next(0, 5) == 0)
                                    {
                                        ny = finalHeight + 2;
                                        if (ny < maxY)
                                        {
                                            collector.ChangeBlock(ny, point.Z, point.X, AlphaMaterials.Torch_Up_50_5);
                                        }
                                    }
                                }
                            }
                            return(tData);
                        },
                                         (Tuple <Differ.ChangeCollector, Random> tData) => { world.ApplyChangeCollector(tData.Item1); }
                                         );

                        #endregion
                    }
                }
            }

            // Place Lights
            foreach (var iter in lightPoints)
            {
                // Place Base
                nz = iter.Key.RealPoint.Z;
                nx = iter.Key.RealPoint.X;
                ny = heightMap[nz][nx] + 1;
                if (ny < maxY)
                {
                    world.ChangeBlock(ny, nz, nx, AlphaMaterials.AcaciaFence_192_0);
                }
                // Place Torch
                ny += 1;
                if (ny < maxY)
                {
                    world.ChangeBlock(ny, nz, nx, AlphaMaterials.Torch_Up_50_5);
                }
            }
        }
Esempio n. 4
0
 public void CreateCurve(Vector2[] curves, bool isClosed, DataQuadTree <int> qTree)
 {
     this.points   = curves;
     this.isClosed = isClosed;
     this.qTree    = qTree;
 }
Esempio n. 5
0
        static void Main(string[] args)
        {
            // Launch Debugger
            Debugger();
            Clocker.AddAndStartClock("TotalClock");
            Clocker.AddAndStartClock("PipeClock");

            if (args.Length != 1)
            {
                Console.WriteLine("Pipe requires only one argument");
                return;
            }

            PipeClient pipeClient = new PipeClient(args[0]);

            pipeClient.Init();

            int    ySize;
            int    zSize;
            int    xSize;
            Differ differ;

            // Biome, HeightMap, WaterMask and TreeMask arrays/bitmap
            Biomes[][] biomes;
            int[][]    heightMap;
            int[][]    waterMap;
            int[][]    treeMap;
            float[][]  deltaMap;
            bool[][]   acceptableMap;
            int[][]    villageMap;
            int[][]    houseMap;
            int[][]    roadMap;
            int[][]    mainRoadMap;
            bool[][]   lavaMap;

            using (BinaryReader reader = pipeClient.ReadMemoryBlock())
            {
                Material[][][] blocks;
                ySize = reader.ReadInt16();
                zSize = reader.ReadInt16();
                xSize = reader.ReadInt16();
                Console.WriteLine($"Y: {ySize} Z: {zSize} X: {xSize}");
                blocks = new Material[ySize][][];
                for (int y = 0; y < ySize; y++)
                {
                    blocks[y] = new Material[zSize][];
                    for (int z = 0; z < zSize; z++)
                    {
                        blocks[y][z] = new Material[xSize];
                        for (int x = 0; x < xSize; x++)
                        {
                            blocks[y][z][x] = AlphaMaterials.Set.GetMaterial(reader.ReadInt16(), reader.ReadInt16());
                        }
                    }
                }
                differ = new Differ(blocks);

                // Biome, HeightMap, WaterMask and TreeMask arrays/bitmap
                biomes        = new Biomes[zSize][];
                heightMap     = new int[zSize][];
                waterMap      = new int[zSize][];
                treeMap       = new int[zSize][];
                deltaMap      = new float[zSize][];
                acceptableMap = new bool[zSize][];
                villageMap    = new int[zSize][];
                houseMap      = new int[zSize][];
                roadMap       = new int[zSize][];
                mainRoadMap   = new int[zSize][];
                lavaMap       = new bool[zSize][];

                for (int z = 0; z < zSize; z++)
                {
                    biomes[z]        = new Biomes[xSize];
                    heightMap[z]     = new int[xSize];
                    waterMap[z]      = new int[xSize];
                    treeMap[z]       = new int[xSize];
                    deltaMap[z]      = new float[xSize];
                    acceptableMap[z] = new bool[xSize];
                    villageMap[z]    = new int[xSize];
                    houseMap[z]      = new int[xSize];
                    roadMap[z]       = new int[xSize];
                    mainRoadMap[z]   = new int[xSize];
                    lavaMap[z]       = new bool[xSize];
                    for (int x = 0; x < xSize; x++)
                    {
                        biomes[z][x]    = (Biomes)reader.ReadInt16();
                        heightMap[z][x] = reader.ReadInt16();
                        waterMap[z][x]  = reader.ReadInt16();
                        treeMap[z][x]   = 0;
                        deltaMap[z][x]  = 0;
                    }
                }
            }
            Clocker.PauseClock("PipeClock");
            Console.WriteLine("Ora pro nobis");
            Clocker.AddAndStartClock("AlgorithmClock");
            {
                Tasker.WorkChunk[] workChunks =
                {
                    (int zStart, int zEnd,  int xStart, int xEnd) =>
                    { HeightMap.FixBoxHeights(differ.World,heightMap, treeMap,    zStart,                         xStart, zEnd, xEnd); }
                };

                Tasker.Run2DTasks(zSize, xSize, workChunks, null);
            }

            {
                // Delta Map & Lava Map
                Tasker.WorkBlock[] workBlocks = { (int z,                                   int x) =>
                                                  {
                                                      DeltaMap.CalculateDeltaMap(heightMap, waterMap,     deltaMap, z, x);
                                                      TreeMap.ExpandTreeBlock(z,            x,            treeMap);
                                                      lavaMap[z][x] = LavaMap.isAcceptableLavaMapBlock(heightMap,differ.World, z,        x);
                                                  } };

                Tasker.Run2DTasks(zSize, xSize, null, workBlocks);
            }

            {
                // Acceptable Map
                Tasker.WorkBlock[] isAcceptable = { (int z,                                                               int x) =>
                                                    {
                                                        acceptableMap[z][x] = DeltaMap.IsAcceptableBlock(deltaMap,        z, x) &&
                                                                              HeightMap.IsAcceptableTreeMapBlock(treeMap, z, x) &&
                                                                              waterMap[z][x] != 1 &&
                                                                              !lavaMap[z][x];
                                                    } };

                Tasker.Run2DTasks(zSize, xSize, null, isAcceptable);
            }

            WaterAnalyzer.WaterAnalysis waterAnalysis;
            {
                int minWaterSize = 20;
                waterAnalysis = WaterAnalyzer.AnalyzeWater(waterMap, minWaterSize);
                Console.WriteLine($"Min Water Body Size {minWaterSize}");
                Console.WriteLine($"Found {waterAnalysis.WaterBodies.Count} valid Water Bodies and {waterAnalysis.InvalidWaterBodies.Count} Invalid ones");
                Console.WriteLine("Valid Water Bodies Sizes");
                foreach (var waterBody in waterAnalysis.WaterBodies)
                {
                    Console.WriteLine($"\tSize {waterBody.Points.Count}");
                }
                Console.WriteLine("Invalid Water Bodies Sizes");
                foreach (var waterBody in waterAnalysis.InvalidWaterBodies)
                {
                    Console.WriteLine($"\tSize {waterBody.Points.Count}");
                }
            }

            DataQuadTree <Vector2Int> roadQT = new DataQuadTree <Vector2Int>(new Vector2Int(), new Vector2Int(zSize - 1, xSize - 1));
            List <VillageMarker>      villages;
            List <List <Vector2Int> > roads = new List <List <Vector2Int> >();
            {
                int numberOfTries       = 1000;
                int expectedVillageSize = 2500;
                int radius          = 4;
                int villageCount    = 3;
                int maxVillageCount = 3;
                villages = VillageDistributor.DistributeVillageMarkers(
                    acceptableMap, villageMap, waterAnalysis,
                    villageCount, maxVillageCount, numberOfTries, radius, expectedVillageSize
                    );

                bool mainRoadPlaced = false;
                int  mainRoadVillageStart = -1, mainRoadVillageEnd = -1;
                if (villages.Count > 1)
                {
                    for (int i = 0; i < villages.Count - 1; i++)
                    {
                        for (int j = i + 1; j < villages.Count; j++)
                        {
                            List <Vector2Int> road = RoadGenerator.FirstRoad(
                                villages[i].Seed.Z, villages[i].Seed.X,
                                villages[j].Seed.Z, villages[j].Seed.X,
                                acceptableMap, deltaMap, waterMap, roadMap, treeMap, houseMap
                                );
                            if (road.Count > 0)
                            {
                                mainRoadPlaced       = true;
                                mainRoadVillageStart = i;
                                mainRoadVillageEnd   = j;
                                Console.WriteLine("Main Road length: " + road.Count);
                                roads.Add(road);
                                foreach (Vector2Int roadPoint in road)
                                {
                                    roadQT.Insert(roadPoint, roadPoint);
                                    mainRoadMap[roadPoint.Z][roadPoint.X] = 1;
                                }
                                break;
                            }
                        }
                        if (mainRoadPlaced)
                        {
                            break;
                        }
                    }
                }

                if (mainRoadPlaced)
                {
                    for (int i = 0; i < villages.Count; ++i)
                    {
                        if (i != mainRoadVillageStart && i != mainRoadVillageEnd)
                        {
                            Console.WriteLine($"Connecting village: {i} to roads");
                            List <Vector2Int> road = RoadGenerator.PointToRoad(
                                villages[i].Seed.Z, villages[i].Seed.X,
                                acceptableMap, deltaMap, waterMap, roadMap, treeMap, houseMap,
                                roadQT
                                );
                            roads.Add(road);
                            foreach (Vector2Int roadPoint in road)
                            {
                                roadQT.Insert(roadPoint, roadPoint);
                            }
                        }
                    }

                    //RoadPlacer.RoadsPlacer(roads, roadMap, heightMap, waterMap, biomes, differ);
                }
                else
                {
                    Console.WriteLine("Failed to Place all the roads");
                }
            }


            DataQuadTree <RectInt> villagesQT = new DataQuadTree <RectInt>(new Vector2Int(0, 0), new Vector2Int(zSize, xSize));

            foreach (VillageMarker village in villages)
            {
                HouseDistributor.FillVillage(deltaMap, heightMap, acceptableMap, houseMap, roadMap, villageMap,
                                             waterMap, treeMap, biomes, village, differ.World, new Vector2Int(8, 8), differ,
                                             villagesQT, roadQT, ref roads);
            }

            RoadPlacer.RoadsPlacer(roads, roadMap, heightMap, waterMap, biomes, differ);

            {
                // Drawing
                Mapper.SaveMapInfo[] saveMapInfos =
                {
                    new Mapper.SaveMapInfo {
                        zSize     = zSize, xSize = xSize, name = "villagemap",
                        colorWork = (int z, int x) =>{
                            if (villageMap[z][x] >= 1)
                            {
                                return(Color.Yellow);
                            }
                            else if (acceptableMap[z][x] && villageMap[z][x] <= 0)
                            {
                                return(Color.Orange);
                            }
                            return(Color.Transparent);
                        },
                        specialColors = (Mapper.ColorApplier colorApplier) =>
                        {
                            for (int i = 0; i < villages.Count; i++)
                            {
                                colorApplier.Invoke(villages[i].Seed.Z, villages[i].Seed.X, Color.Blue);
                            }
                        }
                    },
                    new Mapper.SaveMapInfo {
                        zSize     = zSize, xSize = xSize, name = "acceptablemap",
                        colorWork = (int z, int x) =>{
                            if (acceptableMap[z][x])
                            {
                                return(Color.Green);
                            }
                            else
                            {
                                return(Color.Red);
                            }
                        },
                        specialColors = null
                    },
                    new Mapper.SaveMapInfo {
                        zSize     = zSize, xSize = xSize, name = "deltamap",
                        colorWork = (int z, int x) =>{
                            if (0 <= deltaMap[z][x] && deltaMap[z][x] <= DeltaMap.kMaxDelta)
                            {
                                float tVal = 1.0f - deltaMap[z][x] / DeltaMap.kMaxDelta;
                                return(Color.FromRgba(0, (byte)(255.0f * tVal + 100.0f * (1.0f - tVal)), 0, 255));
                            }
                            else if (deltaMap[z][x] > DeltaMap.kMaxDelta)
                            {
                                return(Color.Red);
                            }
                            return(Color.Transparent);
                        },
                        specialColors = null
                    },
                    new Mapper.SaveMapInfo {
                        zSize     = zSize, xSize = xSize, name = "treemap",
                        colorWork = (int z, int x) =>{
                            if (treeMap[z][x] == 1)
                            {
                                return(Color.Green);
                            }
                            else if (treeMap[z][x] == 2)
                            {
                                return(Color.Brown);
                            }
                            else if (treeMap[z][x] == 3)
                            {
                                return(Color.DarkSeaGreen);
                            }
                            return(Color.Transparent);
                        },
                        specialColors = null
                    },
                    new Mapper.SaveMapInfo {
                        zSize     = zSize, xSize = xSize, name = "heightmap",
                        colorWork = (int z, int x) =>{
                            if (heightMap[z][x] >= 0)
                            {
                                return(Color.FromRgba((byte)heightMap[z][x], (byte)heightMap[z][x], (byte)heightMap[z][x], 255));
                            }
                            else
                            {
                                return(Color.Red);
                            }
                        },
                        specialColors = null
                    },
                    new Mapper.SaveMapInfo {
                        zSize     = zSize, xSize = xSize, name = "watermap",
                        colorWork = (int z, int x) =>{
                            if (waterMap[z][x] == 1)
                            {
                                return(Color.Blue);
                            }
                            return(Color.Transparent);
                        },
                        specialColors = null
                    },
                    new Mapper.SaveMapInfo {
                        zSize     = zSize, xSize = xSize, name = "houseMap",
                        colorWork = (int z, int x) =>{
                            if (houseMap[z][x] == 1)
                            {
                                return(Color.Brown);
                            }
                            return(Color.Transparent);
                        },
                        specialColors = null
                    },
                    new Mapper.SaveMapInfo {
                        zSize     = zSize, xSize = xSize, name = "roadMap",
                        colorWork = (int z, int x) =>{
                            switch (roadMap[z][x])
                            {
                            case RoadGenerator.MainRoadMarker:
                                return(Color.PaleVioletRed);

                            case RoadGenerator.RoadMarker:
                                return(Color.Purple);

                            case RoadGenerator.BridgeMarker:
                                return(Color.Brown);

                            case RoadGenerator.MainBridgeMarker:
                                return(Color.BurlyWood);

                            default:
                                return(Color.Transparent);
                            }
                        },
                        specialColors = null
                    },
                    new Mapper.SaveMapInfo {
                        zSize     = zSize, xSize = xSize, name = "mainRoadMap",
                        colorWork = (int z, int x) =>{
                            if (mainRoadMap[z][x] == 1)
                            {
                                return(Color.Turquoise);
                            }
                            return(Color.Transparent);
                        },
                        specialColors = null
                    },
                    new Mapper.SaveMapInfo {
                        zSize     = zSize, xSize = xSize, name = "lavaMap",
                        colorWork = (int z, int x) =>{
                            if (lavaMap[z][x])
                            {
                                return(Color.DarkRed);
                            }
                            return(Color.Transparent);
                        },
                        specialColors = null
                    }
                };

                Mapper.SaveMaps(saveMapInfos);
            }

            // Write Data Back to Python
            {
                using (BinaryWriter writer = new BinaryWriter(new MemoryStream()))
                {
                    differ.SerializeChanges(writer);

                    // Return data To Python
                    Console.WriteLine(writer.BaseStream.Length);
                    pipeClient.WriteMemoryBlock((MemoryStream)writer.BaseStream);
                }
            }

            // Close Pipe
            pipeClient.DeInit();
            Clocker.PauseClock("AlgorithmClock");
            Clocker.PauseClock("TotalClock");
            double pipeTime  = Clocker.GetTime("PipeClock", true);
            double algoTime  = Clocker.GetTime("AlgorithmClock", true);
            double totalTime = Clocker.GetTime("TotalClock", true);

            Clocker.PrintAllTime(true, true, true);
            Clocker.RemoveClock("PipeClock", true, true, true);
            Clocker.RemoveClock("AlgorithmClock", true, true, true);
            Clocker.RemoveClock("TotalClock", true, true, true);
            Console.WriteLine($"Pipe Percentage of Time: {pipeTime / totalTime * 100.0}% ({pipeTime} secs)");
            Console.WriteLine($"Algorithm Percentage of Time: {algoTime / totalTime * 100.0}% ({algoTime} secs)");
        }