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); }
/// <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); } } }
public void CreateCurve(Vector2[] curves, bool isClosed, DataQuadTree <int> qTree) { this.points = curves; this.isClosed = isClosed; this.qTree = qTree; }
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)"); }