LerpedWeightedIndex2DMap GetOrLoadLerpedLandformMap(IMapChunk mapchunk, int regionX, int regionZ) { LerpedWeightedIndex2DMap map; // 1. Load? LandformMapByRegion.TryGetValue(regionZ * regionMapSize + regionX, out map); if (map != null) { return(map); } // 2. Create map = LandformMapByRegion[regionZ * regionMapSize + regionX] = new LerpedWeightedIndex2DMap(mapchunk.MapRegion.LandformMap.Data, mapchunk.MapRegion.LandformMap.Size, TerraGenConfig.landFormSmothingRadius); return(map); }
public void preLoad(IServerChunk[] chunks, int chunkX, int chunkZ) { mapChunk = chunks[0].MapChunk; heightMap = mapChunk.WorldGenTerrainHeightMap; rdx = chunkX % regionChunkSize; rdz = chunkZ % regionChunkSize; stratum = null; step = 0; strataThickness = 0; map = GetOrLoadLerpedProvinceMap(chunks[0].MapChunk, chunkX, chunkZ); lerpMapInv = 1f / TerraGenConfig.geoProvMapScale; chunkInRegionX = (chunkX % regionChunkSize) * lerpMapInv * chunksize; chunkInRegionZ = (chunkZ % regionChunkSize) * lerpMapInv * chunksize; provinces = NoiseGeoProvince.provinces; grp = 0; }
LerpedWeightedIndex2DMap GetOrLoadLerpedLandformMap(IMapChunk mapchunk, int regionX, int regionZ) { LerpedWeightedIndex2DMap map; // 1. Load? LandformMapByRegion.TryGetValue(regionZ * regionMapSize + regionX, out map); if (map != null) { return(map); } IntDataMap2D lmap = mapchunk.MapRegion.LandformMap; // 2. Create map = LandformMapByRegion[regionZ * regionMapSize + regionX] = new LerpedWeightedIndex2DMap(lmap.Data, lmap.Size, TerraGenConfig.landFormSmoothingRadius, lmap.TopLeftPadding, lmap.BottomRightPadding); return(map); }
LerpedWeightedIndex2DMap CreateLerpedProvinceMap(IntMap geoMap, int regionX, int regionZ) { int index2d = regionZ * regionMapSize + regionX; return(ProvinceMapByRegion[index2d] = new LerpedWeightedIndex2DMap(geoMap.Data, geoMap.Size, TerraGenConfig.geoProvSmoothingRadius)); }
internal void GenChunkColumn(IServerChunk[] chunks, int chunkX, int chunkZ) { ushort[] heightMap = chunks[0].MapChunk.RainHeightMap; float lerpMapInv = 1f / TerraGenConfig.geoProvMapScale; float chunkInRegionX = (chunkX % regionChunkSize) * lerpMapInv * chunksize; float chunkInRegionZ = (chunkZ % regionChunkSize) * lerpMapInv * chunksize; LerpedWeightedIndex2DMap map = GetOrLoadLerpedProvinceMap(chunks[0].MapChunk, chunkX, chunkZ); int localIndex3D; float chunkSizeFloat = chunksize; int absX, absZ; for (int x = 0; x < chunksize; x++) { for (int z = 0; z < chunksize; z++) { int surfaceY = heightMap[z * chunksize + x]; absX = chunkX * chunksize + x; absZ = chunkZ * chunksize + z; // Todo: lerp these 3 noise gens for performance double distortX = (float)distort2dX.Noise(absX, absZ) * 160f; double distortZ = (float)distort2dZ.Noise(absX, absZ) * 160f; double noiseValue = noiseGen.Noise( absX + distortX, absZ + distortZ ); WeightedIndex[] indices = map[ TerraGenConfig.geoProvMapPadding + chunkInRegionX + x * lerpMapInv, TerraGenConfig.geoProvMapPadding + chunkInRegionZ + z * lerpMapInv ]; LoadInterpolatedLayerBlockIds(noiseValue, indices, surfaceY); int i = 0; while (surfaceY >= 0) { int chunkY = surfaceY / chunksize; int lY = Math.Min(chunksize - 1, surfaceY - chunkY * chunksize); localIndex3D = (chunksize * lY + z) * chunksize + x; if (chunks[chunkY].Blocks[localIndex3D] == rockBlockId && finalBlockIds.Count > i) { chunks[chunkY].Blocks[localIndex3D] = finalBlockIds[i++]; } surfaceY--; } } } }
private void OnChunkColumnGen(IServerChunk[] chunks, int chunkX, int chunkZ) { landforms = NoiseLandforms.landforms; IntMap regionMap = chunks[0].MapChunk.MapRegion.LandformMap; // Amount of pixels for each chunk (probably 1, 2, or 4) float chunkPixelSize = regionMap.InnerSize / regionChunkSize; // Adjusted lerp for the noiseWidth float chunkPixelStep = chunkPixelSize / noiseWidth; // Start coordinates for the chunk in the region map float baseX = regionMap.TopLeftPadding + (chunkX % regionChunkSize) * chunkPixelSize; float baseZ = regionMap.TopLeftPadding + (chunkZ % regionChunkSize) * chunkPixelSize; LerpedWeightedIndex2DMap landLerpMap = GetOrLoadLerpedLandformMap(chunks[0].MapChunk, chunkX / regionChunkSize, chunkZ / regionChunkSize); // Terrain octaves double[] octNoiseX0, octNoiseX1, octNoiseX2, octNoiseX3; double[] octThX0, octThX1, octThX2, octThX3; GetInterpolatedOctaves(landLerpMap[baseX, baseZ], out octNoiseX0, out octThX0); GetInterpolatedOctaves(landLerpMap[baseX + chunkPixelSize, baseZ], out octNoiseX1, out octThX1); GetInterpolatedOctaves(landLerpMap[baseX, baseZ + chunkPixelSize], out octNoiseX2, out octThX2); GetInterpolatedOctaves(landLerpMap[baseX + chunkPixelSize, baseZ + chunkPixelSize], out octNoiseX3, out octThX3); double[] terrainNoise3d = GetTerrainNoise3D(octNoiseX0, octNoiseX1, octNoiseX2, octNoiseX3, octThX0, octThX1, octThX2, octThX3, chunkX * noiseWidth, 0, chunkZ * noiseWidth); // Store heightmap in the map chunk ushort[] rainheightmap = chunks[0].MapChunk.RainHeightMap; ushort[] terrainheightmap = chunks[0].MapChunk.WorldGenTerrainHeightMap; // Terrain thresholds double tnoiseY0; double tnoiseY1; double tnoiseY2; double tnoiseY3; double tnoiseGainY0; double tnoiseGainY1; double tnoiseGainY2; double tnoiseGainY3; double thNoiseX0; double thNoiseX1; double thNoiseGainX0; double thNoiseGainX1; double thNoiseGainZ0; double thNoiseZ0; float[] terrainThresholdsX0 = new float[api.WorldManager.MapSizeY]; float[] terrainThresholdsX1 = new float[api.WorldManager.MapSizeY]; float[] terrainThresholdsX2 = new float[api.WorldManager.MapSizeY]; float[] terrainThresholdsX3 = new float[api.WorldManager.MapSizeY]; for (int xN = 0; xN < noiseWidth; xN++) { for (int zN = 0; zN < noiseWidth; zN++) { // Landform thresholds LoadInterpolatedThresholds(landLerpMap[baseX + xN * chunkPixelStep, baseZ + zN * chunkPixelStep], terrainThresholdsX0); LoadInterpolatedThresholds(landLerpMap[baseX + (xN + 1) * chunkPixelStep, baseZ + zN * chunkPixelStep], terrainThresholdsX1); LoadInterpolatedThresholds(landLerpMap[baseX + xN * chunkPixelStep, baseZ + (zN + 1) * chunkPixelStep], terrainThresholdsX2); LoadInterpolatedThresholds(landLerpMap[baseX + (xN + 1) * chunkPixelStep, baseZ + (zN + 1) * chunkPixelStep], terrainThresholdsX3); for (int yN = 0; yN < noiseHeight; yN++) { // Terrain noise tnoiseY0 = terrainNoise3d[NoiseIndex3d(xN, yN, zN)]; tnoiseY1 = terrainNoise3d[NoiseIndex3d(xN, yN, zN + 1)]; tnoiseY2 = terrainNoise3d[NoiseIndex3d(xN + 1, yN, zN)]; tnoiseY3 = terrainNoise3d[NoiseIndex3d(xN + 1, yN, zN + 1)]; tnoiseGainY0 = (terrainNoise3d[NoiseIndex3d(xN, yN + 1, zN)] - tnoiseY0) * lerpDeltaVert; tnoiseGainY1 = (terrainNoise3d[NoiseIndex3d(xN, yN + 1, zN + 1)] - tnoiseY1) * lerpDeltaVert; tnoiseGainY2 = (terrainNoise3d[NoiseIndex3d(xN + 1, yN + 1, zN)] - tnoiseY2) * lerpDeltaVert; tnoiseGainY3 = (terrainNoise3d[NoiseIndex3d(xN + 1, yN + 1, zN + 1)] - tnoiseY3) * lerpDeltaVert; for (int y = 0; y < lerpVer; y++) { int posY = yN * lerpVer + y; int chunkY = posY / chunksize; int localY = posY % chunksize; // For Terrain noise double tnoiseX0 = tnoiseY0; double tnoiseX1 = tnoiseY1; double tnoiseGainX0 = (tnoiseY2 - tnoiseY0) * lerpDeltaHor; double tnoiseGainX1 = (tnoiseY3 - tnoiseY1) * lerpDeltaHor; // Landform thresholds lerp thNoiseX0 = terrainThresholdsX0[posY]; thNoiseX1 = terrainThresholdsX2[posY]; thNoiseGainX0 = (terrainThresholdsX1[posY] - thNoiseX0) * lerpDeltaHor; thNoiseGainX1 = (terrainThresholdsX3[posY] - thNoiseX1) * lerpDeltaHor; for (int x = 0; x < lerpHor; x++) { // For terrain noise double tnoiseZ0 = tnoiseX0; double tnoiseGainZ0 = (tnoiseX1 - tnoiseX0) * lerpDeltaHor; // Landform thNoiseZ0 = thNoiseX0; thNoiseGainZ0 = (thNoiseX1 - thNoiseX0) * lerpDeltaHor; for (int z = 0; z < lerpHor; z++) { int lX = xN * lerpHor + x; int lZ = zN * lerpHor + z; int mapIndex = ChunkIndex2d(lX, lZ); int chunkIndex = ChunkIndex3d(lX, localY, lZ); chunks[chunkY].Blocks[chunkIndex] = 0; if (posY == 0) { chunks[chunkY].Blocks[chunkIndex] = GlobalConfig.mantleBlockId; continue; } if (tnoiseZ0 > thNoiseZ0) { terrainheightmap[mapIndex] = rainheightmap[mapIndex] = (ushort)Math.Max(rainheightmap[mapIndex], posY); chunks[chunkY].Blocks[chunkIndex] = GlobalConfig.defaultRockId; } else { if (posY < TerraGenConfig.seaLevel) { terrainheightmap[mapIndex] = rainheightmap[mapIndex] = (ushort)Math.Max(rainheightmap[mapIndex], posY); chunks[chunkY].Blocks[chunkIndex] = GlobalConfig.waterBlockId; } else { chunks[chunkY].Blocks[chunkIndex] = 0; } } tnoiseZ0 += tnoiseGainZ0; thNoiseZ0 += thNoiseGainZ0; } tnoiseX0 += tnoiseGainX0; tnoiseX1 += tnoiseGainX1; thNoiseX0 += thNoiseGainX0; thNoiseX1 += thNoiseGainX1; } tnoiseY0 += tnoiseGainY0; tnoiseY1 += tnoiseGainY1; tnoiseY2 += tnoiseGainY2; tnoiseY3 += tnoiseGainY3; } } } } int ymax = 0; for (int i = 0; i < rainheightmap.Length; i++) { ymax = Math.Max(ymax, rainheightmap[i]); } chunks[0].MapChunk.YMax = (ushort)ymax; }
void ReadPos(IServerPlayer player, CmdArgs arguments) { if (arguments.Length < 2) { player.SendMessage(groupId, "/wgen pos [gprov|landform|climate|height]", EnumChatType.CommandError); return; } int chunkSize = api.WorldManager.ChunkSize; BlockPos pos = player.Entity.Pos.AsBlockPos; IServerChunk serverchunk = api.WorldManager.GetChunk(pos); if (serverchunk == null) { player.SendMessage(groupId, "Can't check here, beyond chunk boundaries!", EnumChatType.CommandError); return; } IMapRegion mapRegion = serverchunk.MapChunk.MapRegion; IMapChunk mapchunk = serverchunk.MapChunk; int regionChunkSize = api.WorldManager.RegionSize / chunkSize; int lx = pos.X % chunkSize; int lz = pos.Z % chunkSize; int chunkX = pos.X / chunkSize; int chunkZ = pos.Z / chunkSize; int regionX = pos.X / regionSize; int regionZ = pos.Z / regionSize; switch (arguments[1]) { case "coords": player.SendMessage(groupId, string.Format("Chunk X/Z: {0}/{1}, Region X/Z: {2},{3}", chunkX, chunkZ, regionX, regionZ), EnumChatType.CommandSuccess); break; case "structures": bool found = false; api.World.BlockAccessor.WalkStructures(pos, (struc) => { found = true; player.SendMessage(groupId, "Structure with code " + struc.Code + " at this position", EnumChatType.CommandSuccess); }); if (!found) { player.SendMessage(groupId, "No structures at this position", EnumChatType.CommandSuccess); } return; case "height": { string str = string.Format("Rain y={0}, Worldgen terrain y={1}", serverchunk.MapChunk.RainHeightMap[lz * chunkSize + lx], serverchunk.MapChunk.WorldGenTerrainHeightMap[lz * chunkSize + lx]); player.SendMessage(groupId, str, EnumChatType.CommandSuccess); } break; case "cavedistort": Bitmap bmp = new Bitmap(chunkSize, chunkSize); for (int x = 0; x < chunkSize; x++) { for (int z = 0; z < chunkSize; z++) { byte color = mapchunk.CaveHeightDistort[z * chunkSize + x]; bmp.SetPixel(x, z, Color.FromArgb((color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff)); } } bmp.Save("cavedistort" + chunkX + "-" + chunkZ + ".png"); player.SendMessage(groupId, "saved bitmap cavedistort" + chunkX + "-" + chunkZ + ".png", EnumChatType.CommandSuccess); break; case "gprov": { int noiseSizeGeoProv = mapRegion.GeologicProvinceMap.InnerSize; float posXInRegion = ((float)pos.X / regionSize - regionX) * noiseSizeGeoProv; float posZInRegion = ((float)pos.Z / regionSize - regionZ) * noiseSizeGeoProv; GeologicProvinceVariant[] provincesByIndex = NoiseGeoProvince.provinces.Variants; IntMap intmap = mapRegion.GeologicProvinceMap; LerpedWeightedIndex2DMap map = new LerpedWeightedIndex2DMap(intmap.Data, mapRegion.GeologicProvinceMap.Size, TerraGenConfig.geoProvSmoothingRadius, mapRegion.GeologicProvinceMap.TopLeftPadding, mapRegion.GeologicProvinceMap.BottomRightPadding); WeightedIndex[] indices = map[posXInRegion, posZInRegion]; string text = ""; foreach (WeightedIndex windex in indices) { if (text.Length > 0) { text += ", "; } text += (100 * windex.Weight).ToString("#.#") + "% " + provincesByIndex[windex.Index].Code; } player.SendMessage(groupId, text, EnumChatType.CommandSuccess); break; } case "rockstrata": { GenRockStrataNew rockstratagen = api.ModLoader.GetModSystem <GenRockStrataNew>(); int noiseSizeGeoProv = mapRegion.GeologicProvinceMap.InnerSize; float posXInRegion = ((float)pos.X / regionSize - pos.X / regionSize) * noiseSizeGeoProv; float posZInRegion = ((float)pos.Z / regionSize - pos.Z / regionSize) * noiseSizeGeoProv; GeologicProvinceVariant[] provincesByIndex = NoiseGeoProvince.provinces.Variants; IntMap intmap = mapRegion.GeologicProvinceMap; LerpedWeightedIndex2DMap map = new LerpedWeightedIndex2DMap(intmap.Data, mapRegion.GeologicProvinceMap.Size, TerraGenConfig.geoProvSmoothingRadius, mapRegion.GeologicProvinceMap.TopLeftPadding, mapRegion.GeologicProvinceMap.BottomRightPadding); WeightedIndex[] indices = map[posXInRegion, posZInRegion]; float[] rockGroupMaxThickness = new float[4]; rockGroupMaxThickness[0] = rockGroupMaxThickness[1] = rockGroupMaxThickness[2] = rockGroupMaxThickness[3] = 0; int rdx = chunkX % regionChunkSize; int rdz = chunkZ % regionChunkSize; IntMap rockMap; float step = 0; float distx = (float)rockstratagen.distort2dx.Noise(pos.X, pos.Z); float distz = (float)rockstratagen.distort2dz.Noise(pos.X, pos.Z); for (int i = 0; i < indices.Length; i++) { float w = indices[i].Weight; GeologicProvinceVariant var = NoiseGeoProvince.provinces.Variants[indices[i].Index]; rockGroupMaxThickness[0] += var.RockStrataIndexed[0].MaxThickness * w; rockGroupMaxThickness[1] += var.RockStrataIndexed[1].MaxThickness * w; rockGroupMaxThickness[2] += var.RockStrataIndexed[2].MaxThickness * w; rockGroupMaxThickness[3] += var.RockStrataIndexed[3].MaxThickness * w; } System.Text.StringBuilder sb = new System.Text.StringBuilder(); sb.AppendLine("Sedimentary max thickness: " + rockGroupMaxThickness[(int)EnumRockGroup.Sedimentary]); sb.AppendLine("Metamorphic max thickness: " + rockGroupMaxThickness[(int)EnumRockGroup.Metamorphic]); sb.AppendLine("Igneous max thickness: " + rockGroupMaxThickness[(int)EnumRockGroup.Igneous]); sb.AppendLine("Volcanic max thickness: " + rockGroupMaxThickness[(int)EnumRockGroup.Volcanic]); sb.AppendLine("========"); for (int id = 0; id < rockstratagen.strata.Variants.Length; id++) { rockMap = mapchunk.MapRegion.RockStrata[id]; step = (float)rockMap.InnerSize / regionChunkSize; float dist = 1 + GameMath.Clamp((distx + distz) / 30, 0.9f, 1.1f); sb.AppendLine(rockstratagen.strata.Variants[id].BlockCode.ToShortString() + " max thickness: " + rockMap.GetIntLerpedCorrectly(rdx * step + step * (float)(lx + distx) / chunkSize, rdz * step + step * (float)(lz + distz) / chunkSize)); } sb.AppendLine("======"); int surfaceY = api.World.BlockAccessor.GetTerrainMapheightAt(pos); int ylower = 1; int yupper = surfaceY; int rockStrataId = -1; float strataThickness = 0; RockStratum stratum = null; OrderedDictionary <int, int> stratathicknesses = new OrderedDictionary <int, int>(); while (ylower <= yupper) { if (--strataThickness <= 0) { rockStrataId++; if (rockStrataId >= rockstratagen.strata.Variants.Length) { break; } stratum = rockstratagen.strata.Variants[rockStrataId]; rockMap = mapchunk.MapRegion.RockStrata[rockStrataId]; step = (float)rockMap.InnerSize / regionChunkSize; int grp = (int)stratum.RockGroup; float dist = 1 + GameMath.Clamp((distx + distz) / 30, 0.9f, 1.1f); strataThickness = Math.Min(rockGroupMaxThickness[grp] * dist, rockMap.GetIntLerpedCorrectly(rdx * step + step * (float)(lx + distx) / chunkSize, rdz * step + step * (float)(lz + distz) / chunkSize)); strataThickness -= (stratum.RockGroup == EnumRockGroup.Sedimentary) ? Math.Max(0, yupper - TerraGenConfig.seaLevel) * 0.5f : 0; if (strataThickness < 2) { strataThickness = -1; continue; } } if (!stratathicknesses.ContainsKey(stratum.BlockId)) { stratathicknesses[stratum.BlockId] = 0; } stratathicknesses[stratum.BlockId]++; if (stratum.GenDir == EnumStratumGenDir.BottomUp) { ylower++; } else { yupper--; } } foreach (var val in stratathicknesses) { sb.AppendLine(api.World.Blocks[val.Key].Code.ToShortString() + " : " + val.Value + " blocks"); } player.SendMessage(groupId, sb.ToString(), EnumChatType.CommandSuccess); break; } case "landform": { int noiseSizeLandform = mapRegion.LandformMap.InnerSize; float posXInRegion = ((float)pos.X / regionSize - pos.X / regionSize) * noiseSizeLandform; float posZInRegion = ((float)pos.Z / regionSize - pos.Z / regionSize) * noiseSizeLandform; LandformVariant[] landforms = NoiseLandforms.landforms.LandFormsByIndex; IntMap intmap = mapRegion.LandformMap; LerpedWeightedIndex2DMap map = new LerpedWeightedIndex2DMap(intmap.Data, mapRegion.LandformMap.Size, TerraGenConfig.landFormSmoothingRadius, intmap.TopLeftPadding, intmap.BottomRightPadding); WeightedIndex[] indices = map[posXInRegion, posZInRegion]; string text = ""; foreach (WeightedIndex windex in indices) { if (text.Length > 0) { text += ", "; } text += (100 * windex.Weight).ToString("#.#") + "% " + landforms[windex.Index].Code; } player.SendMessage(groupId, text, EnumChatType.CommandSuccess); break; } case "climate": { ClimateCondition climate = api.World.BlockAccessor.GetClimateAt(pos); string text = string.Format("Temperature: {0}°, Rainfall: {1}%, Fertility: {2}%, Forest: {3}%, Shrub: {4}%, Sealevel dist: {5}%", climate.Temperature.ToString("0.#"), (int)(climate.Rainfall * 100f), (int)(climate.Fertility * 100f), (int)(climate.ForestDensity * 100f), (int)(climate.ShrubDensity * 100f), (int)(100f * pos.Y / 255f)); player.SendMessage(groupId, text, EnumChatType.CommandSuccess); break; } } }
private void ReadRegion(IServerPlayer player, CmdArgs arguments) { if (arguments.Length < 1) { player.SendMessage(groupId, "/wgen region [climate|ore|forest|wind|gprov|gprovi|landform|landformi]", EnumChatType.CommandError); return; } int chunkSize = api.WorldManager.ChunkSize; BlockPos pos = player.Entity.Pos.AsBlockPos; IServerChunk serverchunk = api.WorldManager.GetChunk(pos); if (serverchunk == null) { player.SendMessage(groupId, "Can't check here, beyond chunk boundaries!", EnumChatType.CommandError); return; } IMapRegion mapRegion = serverchunk.MapChunk.MapRegion; int regionX = pos.X / regionSize; int regionZ = pos.Z / regionSize; string arg = arguments.PopWord(); string subarg = arguments.PopWord(); bool dolerp = subarg == "nolerp"; NoiseBase.Debug = true; switch (arg) { case "climate": DrawMapRegion(0, player, mapRegion.ClimateMap, "climate", dolerp, regionX, regionZ, TerraGenConfig.climateMapScale); break; case "ore": string type = dolerp ? arguments.PopWord("limonite") : subarg; if (type == null) { type = "limonite"; } if (!mapRegion.OreMaps.ContainsKey(type)) { player.SendMessage(groupId, "Mapregion does not contain an ore map for ore " + type, EnumChatType.CommandError); return; } DrawMapRegion(DebugDrawMode.RGB, player, mapRegion.OreMaps[type], "ore-" + type, dolerp, regionX, regionZ, TerraGenConfig.oreMapScale); break; case "forest": DrawMapRegion(DebugDrawMode.FirstByteGrayscale, player, mapRegion.ForestMap, "forest", dolerp, regionX, regionZ, TerraGenConfig.forestMapScale); break; case "oretopdistort": DrawMapRegion(DebugDrawMode.FirstByteGrayscale, player, mapRegion.OreMapVerticalDistortTop, "oretopdistort", dolerp, regionX, regionZ, TerraGenConfig.depositVerticalDistortScale); break; //case "depdist": //DrawMapRegion(0, player, mapRegion.DepositDistortionMap, "depositdistortion", dolerp, regionX, regionZ, TerraGenConfig.depositDistortionScale); //break; case "rockstrata": for (int i = 0; i < mapRegion.RockStrata.Length; i++) { DrawMapRegion(DebugDrawMode.FirstByteGrayscale, player, mapRegion.RockStrata[i], "rockstrata" + i, dolerp, regionX, regionZ, TerraGenConfig.rockStrataScale); } break; case "wind": { } break; case "gprov": DrawMapRegion(DebugDrawMode.ProvinceRGB, player, mapRegion.GeologicProvinceMap, "province", dolerp, regionX, regionZ, TerraGenConfig.geoProvMapScale); break; case "gprovi": { int[] gprov = mapRegion.GeologicProvinceMap.Data; int noiseSizeGeoProv = mapRegion.GeologicProvinceMap.InnerSize; int outSize = (noiseSizeGeoProv + TerraGenConfig.geoProvMapPadding - 1) * TerraGenConfig.geoProvMapScale; GeologicProvinceVariant[] provincesByIndex = NoiseGeoProvince.provinces.Variants; LerpedWeightedIndex2DMap map = new LerpedWeightedIndex2DMap(gprov, noiseSizeGeoProv + 2 * TerraGenConfig.geoProvMapPadding, 2, mapRegion.GeologicProvinceMap.TopLeftPadding, mapRegion.GeologicProvinceMap.BottomRightPadding); int[] outColors = new int[outSize * outSize]; for (int x = 0; x < outSize; x++) { for (int z = 0; z < outSize; z++) { WeightedIndex[] indices = map[(float)x / TerraGenConfig.geoProvMapScale, (float)z / TerraGenConfig.geoProvMapScale]; for (int i = 0; i < indices.Length; i++) { indices[i].Index = provincesByIndex[indices[i].Index].ColorInt; } int[] colors; float[] weights; map.Split(indices, out colors, out weights); outColors[z * outSize + x] = ColorUtil.ColorAverage(colors, weights); } } NoiseBase.DebugDrawBitmap(DebugDrawMode.ProvinceRGB, outColors, outSize, outSize, "geoprovince-lerped-" + regionX + "-" + regionZ); player.SendMessage(groupId, "done", EnumChatType.CommandSuccess); break; } case "landform": DrawMapRegion(DebugDrawMode.LandformRGB, player, mapRegion.LandformMap, "landform", dolerp, regionX, regionZ, TerraGenConfig.landformMapScale); break; case "landformi": { int[] data = mapRegion.LandformMap.Data; int noiseSizeLandform = mapRegion.LandformMap.InnerSize; int outSize = (noiseSizeLandform + TerraGenConfig.landformMapPadding - 1) * TerraGenConfig.landformMapScale; LandformVariant[] landformsByIndex = NoiseLandforms.landforms.LandFormsByIndex; LerpedWeightedIndex2DMap map = new LerpedWeightedIndex2DMap(data, mapRegion.LandformMap.Size, 1, mapRegion.LandformMap.TopLeftPadding, mapRegion.LandformMap.BottomRightPadding); int[] outColors = new int[outSize * outSize]; for (int x = 0; x < outSize; x++) { for (int z = 0; z < outSize; z++) { WeightedIndex[] indices = map[(float)x / TerraGenConfig.landformMapScale, (float)z / TerraGenConfig.landformMapScale]; for (int i = 0; i < indices.Length; i++) { indices[i].Index = landformsByIndex[indices[i].Index].ColorInt; } int[] colors; float[] weights; map.Split(indices, out colors, out weights); outColors[z * outSize + x] = ColorUtil.ColorAverage(colors, weights); } } NoiseBase.DebugDrawBitmap(DebugDrawMode.LandformRGB, outColors, outSize, outSize, "landform-lerped-" + regionX + "-" + regionZ); player.SendMessage(groupId, "Landform map done", EnumChatType.CommandSuccess); break; } default: player.SendMessage(groupId, "/wgen region [climate|ore|forest|wind|gprov|landform]", EnumChatType.CommandError); break; } NoiseBase.Debug = false; }
private void OnChunkColumnGen(IServerChunk[] chunks, int chunkX, int chunkZ, ITreeAttribute chunkGenParams = null) { landforms = NoiseLandforms.landforms; IMapChunk mapchunk = chunks[0].MapChunk; int climateUpLeft; int climateUpRight; int climateBotLeft; int climateBotRight; IntDataMap2D climateMap = chunks[0].MapChunk.MapRegion.ClimateMap; int regionChunkSize = api.WorldManager.RegionSize / chunksize; float fac = (float)climateMap.InnerSize / regionChunkSize; int rlX = chunkX % regionChunkSize; int rlZ = chunkZ % regionChunkSize; climateUpLeft = climateMap.GetUnpaddedInt((int)(rlX * fac), (int)(rlZ * fac)); climateUpRight = climateMap.GetUnpaddedInt((int)(rlX * fac + fac), (int)(rlZ * fac)); climateBotLeft = climateMap.GetUnpaddedInt((int)(rlX * fac), (int)(rlZ * fac + fac)); climateBotRight = climateMap.GetUnpaddedInt((int)(rlX * fac + fac), (int)(rlZ * fac + fac)); int freezingTemp = -17; IntDataMap2D landformMap = mapchunk.MapRegion.LandformMap; // Amount of pixels for each chunk (probably 1, 2, or 4) in the land form map float chunkPixelSize = landformMap.InnerSize / regionChunkSize; // Adjusted lerp for the noiseWidth float chunkPixelStep = chunkPixelSize / noiseWidth; // Start coordinates for the chunk in the region map float baseX = (chunkX % regionChunkSize) * chunkPixelSize; float baseZ = (chunkZ % regionChunkSize) * chunkPixelSize; LerpedWeightedIndex2DMap landLerpMap = GetOrLoadLerpedLandformMap(chunks[0].MapChunk, chunkX / regionChunkSize, chunkZ / regionChunkSize); // Terrain octaves double[] octNoiseX0, octNoiseX1, octNoiseX2, octNoiseX3; double[] octThX0, octThX1, octThX2, octThX3; // So it seems we have some kind of off-by-one error here? // When the slope of a mountain goes up (in positive z or x direction), particularly at large word heights (512+) // then the last blocks (again in postive x/z dir) are below of where they should be? // I have no idea why, but this offset seems to greatly mitigate the issue float weirdOffset = 0.25f; chunkPixelSize += weirdOffset; GetInterpolatedOctaves(landLerpMap[baseX, baseZ], out octNoiseX0, out octThX0); GetInterpolatedOctaves(landLerpMap[baseX + chunkPixelSize, baseZ], out octNoiseX1, out octThX1); GetInterpolatedOctaves(landLerpMap[baseX, baseZ + chunkPixelSize], out octNoiseX2, out octThX2); GetInterpolatedOctaves(landLerpMap[baseX + chunkPixelSize, baseZ + chunkPixelSize], out octNoiseX3, out octThX3); double[] terrainNoise3d = GetTerrainNoise3D(octNoiseX0, octNoiseX1, octNoiseX2, octNoiseX3, octThX0, octThX1, octThX2, octThX3, chunkX * noiseWidth, 0, chunkZ * noiseWidth); // Store heightmap in the map chunk ushort[] rainheightmap = chunks[0].MapChunk.RainHeightMap; ushort[] terrainheightmap = chunks[0].MapChunk.WorldGenTerrainHeightMap; // Terrain thresholds double tnoiseY0; double tnoiseY1; double tnoiseY2; double tnoiseY3; double tnoiseGainY0; double tnoiseGainY1; double tnoiseGainY2; double tnoiseGainY3; double thNoiseX0; double thNoiseX1; double thNoiseGainX0; double thNoiseGainX1; double thNoiseGainZ0; double thNoiseZ0; float[] terrainThresholdsX0 = new float[api.WorldManager.MapSizeY]; float[] terrainThresholdsX1 = new float[api.WorldManager.MapSizeY]; float[] terrainThresholdsX2 = new float[api.WorldManager.MapSizeY]; float[] terrainThresholdsX3 = new float[api.WorldManager.MapSizeY]; for (int xN = 0; xN < noiseWidth; xN++) { for (int zN = 0; zN < noiseWidth; zN++) { // Landform thresholds LoadInterpolatedThresholds(landLerpMap[baseX + xN * chunkPixelStep, baseZ + zN * chunkPixelStep], terrainThresholdsX0); LoadInterpolatedThresholds(landLerpMap[baseX + (xN + 1) * chunkPixelStep, baseZ + zN * chunkPixelStep], terrainThresholdsX1); LoadInterpolatedThresholds(landLerpMap[baseX + xN * chunkPixelStep, baseZ + (zN + 1) * chunkPixelStep], terrainThresholdsX2); LoadInterpolatedThresholds(landLerpMap[baseX + (xN + 1) * chunkPixelStep, baseZ + (zN + 1) * chunkPixelStep], terrainThresholdsX3); for (int yN = 0; yN < noiseHeight; yN++) { // Terrain noise tnoiseY0 = terrainNoise3d[NoiseIndex3d(xN, yN, zN)]; tnoiseY1 = terrainNoise3d[NoiseIndex3d(xN, yN, zN + 1)]; tnoiseY2 = terrainNoise3d[NoiseIndex3d(xN + 1, yN, zN)]; tnoiseY3 = terrainNoise3d[NoiseIndex3d(xN + 1, yN, zN + 1)]; tnoiseGainY0 = (terrainNoise3d[NoiseIndex3d(xN, yN + 1, zN)] - tnoiseY0) * lerpDeltaVert; tnoiseGainY1 = (terrainNoise3d[NoiseIndex3d(xN, yN + 1, zN + 1)] - tnoiseY1) * lerpDeltaVert; tnoiseGainY2 = (terrainNoise3d[NoiseIndex3d(xN + 1, yN + 1, zN)] - tnoiseY2) * lerpDeltaVert; tnoiseGainY3 = (terrainNoise3d[NoiseIndex3d(xN + 1, yN + 1, zN + 1)] - tnoiseY3) * lerpDeltaVert; for (int y = 0; y < lerpVer; y++) { int posY = yN * lerpVer + y; int chunkY = posY / chunksize; int localY = posY % chunksize; // For Terrain noise double tnoiseX0 = tnoiseY0; double tnoiseX1 = tnoiseY1; double tnoiseGainX0 = (tnoiseY2 - tnoiseY0) * lerpDeltaHor; double tnoiseGainX1 = (tnoiseY3 - tnoiseY1) * lerpDeltaHor; // Landform thresholds lerp thNoiseX0 = terrainThresholdsX0[posY]; thNoiseX1 = terrainThresholdsX2[posY]; thNoiseGainX0 = (terrainThresholdsX1[posY] - thNoiseX0) * lerpDeltaHor; thNoiseGainX1 = (terrainThresholdsX3[posY] - thNoiseX1) * lerpDeltaHor; for (int x = 0; x < lerpHor; x++) { // For terrain noise double tnoiseZ0 = tnoiseX0; double tnoiseGainZ0 = (tnoiseX1 - tnoiseX0) * lerpDeltaHor; // Landform thNoiseZ0 = thNoiseX0; thNoiseGainZ0 = (thNoiseX1 - thNoiseX0) * lerpDeltaHor; for (int z = 0; z < lerpHor; z++) { int lX = xN * lerpHor + x; int lZ = zN * lerpHor + z; int mapIndex = ChunkIndex2d(lX, lZ); int chunkIndex = ChunkIndex3d(lX, localY, lZ); chunks[chunkY].Blocks[chunkIndex] = 0; if (posY == 0) { chunks[chunkY].Blocks[chunkIndex] = GlobalConfig.mantleBlockId; continue; } if (tnoiseZ0 > thNoiseZ0) { terrainheightmap[mapIndex] = rainheightmap[mapIndex] = (ushort)Math.Max(rainheightmap[mapIndex], posY); chunks[chunkY].Blocks[chunkIndex] = GlobalConfig.defaultRockId; } else { if (posY < TerraGenConfig.seaLevel) { terrainheightmap[mapIndex] = rainheightmap[mapIndex] = (ushort)Math.Max(rainheightmap[mapIndex], posY); if (posY == TerraGenConfig.seaLevel - 1) { int temp = (GameMath.BiLerpRgbColor(((float)lX) / chunksize, ((float)lZ) / chunksize, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight) >> 16) & 0xff; float distort = (float)distort2dx.Noise(chunkX * chunksize + lX, chunkZ * chunksize + lZ) / 20f; float tempf = TerraGenConfig.GetScaledAdjustedTemperatureFloat(temp, 0) + distort; chunks[chunkY].Blocks[chunkIndex] = (tempf < freezingTemp) ? GlobalConfig.lakeIceBlockId : GlobalConfig.waterBlockId; } else { chunks[chunkY].Blocks[chunkIndex] = GlobalConfig.waterBlockId; } } else { chunks[chunkY].Blocks[chunkIndex] = 0; } } tnoiseZ0 += tnoiseGainZ0; thNoiseZ0 += thNoiseGainZ0; } tnoiseX0 += tnoiseGainX0; tnoiseX1 += tnoiseGainX1; thNoiseX0 += thNoiseGainX0; thNoiseX1 += thNoiseGainX1; } tnoiseY0 += tnoiseGainY0; tnoiseY1 += tnoiseGainY1; tnoiseY2 += tnoiseGainY2; tnoiseY3 += tnoiseGainY3; } } } } ushort ymax = 0; for (int i = 0; i < rainheightmap.Length; i++) { ymax = Math.Max(ymax, rainheightmap[i]); } chunks[0].MapChunk.YMax = ymax; }
void ReadPos(IServerPlayer player, CmdArgs arguments) { if (arguments.Length < 2) { player.SendMessage(groupId, "/wgen pos [gprov|landform|climate|height]", EnumChatType.CommandError); return; } int chunkSize = api.WorldManager.ChunkSize; BlockPos pos = player.Entity.Pos.AsBlockPos; IServerChunk serverchunk = api.WorldManager.GetChunk(pos); if (serverchunk == null) { player.SendMessage(groupId, "Can check here, beyond chunk boundaries!", EnumChatType.CommandError); return; } IMapRegion mapRegion = serverchunk.MapChunk.MapRegion; int regionChunkSize = api.WorldManager.RegionSize / chunkSize; int lx = pos.X % chunkSize; int lz = pos.Z % chunkSize; int chunkX = pos.X / chunkSize; int chunkZ = pos.Z / chunkSize; int regionX = pos.X / regionSize; int regionZ = pos.Z / regionSize; switch (arguments[1]) { case "height": { string str = string.Format("Rain y={0}, Worldgen terrain y={1}", serverchunk.MapChunk.RainHeightMap[lz * chunkSize + lx], serverchunk.MapChunk.WorldGenTerrainHeightMap[lz * chunkSize + lx]); player.SendMessage(groupId, str, EnumChatType.CommandSuccess); } break; case "gprov": { int noiseSizeGeoProv = mapRegion.GeologicProvinceMap.InnerSize; float posXInRegion = ((float)pos.X / regionSize - pos.X / regionSize) * noiseSizeGeoProv; float posZInRegion = ((float)pos.Z / regionSize - pos.Z / regionSize) * noiseSizeGeoProv; GeologicProvinceVariant[] provincesByIndex = NoiseGeoProvince.provinces.Variants; IntMap intmap = mapRegion.GeologicProvinceMap; LerpedWeightedIndex2DMap map = new LerpedWeightedIndex2DMap(intmap.Data, mapRegion.GeologicProvinceMap.Size, TerraGenConfig.geoProvSmoothingRadius); WeightedIndex[] indices = map[intmap.TopLeftPadding + posXInRegion, intmap.TopLeftPadding + posZInRegion]; string text = ""; foreach (WeightedIndex windex in indices) { if (text.Length > 0) { text += ", "; } text += (100 * windex.weight).ToString("#.#") + "% " + provincesByIndex[windex.index].Code; } player.SendMessage(groupId, text, EnumChatType.CommandSuccess); break; } case "landform": { int noiseSizeLandform = mapRegion.LandformMap.InnerSize; float posXInRegion = ((float)pos.X / regionSize - pos.X / regionSize) * noiseSizeLandform; float posZInRegion = ((float)pos.Z / regionSize - pos.Z / regionSize) * noiseSizeLandform; LandformVariant[] landforms = NoiseLandforms.landforms.LandFormsByIndex; IntMap intmap = mapRegion.LandformMap; LerpedWeightedIndex2DMap map = new LerpedWeightedIndex2DMap(intmap.Data, mapRegion.LandformMap.Size, TerraGenConfig.landFormSmothingRadius); WeightedIndex[] indices = map[intmap.TopLeftPadding + posXInRegion, intmap.TopLeftPadding + posZInRegion]; string text = ""; foreach (WeightedIndex windex in indices) { if (text.Length > 0) { text += ", "; } text += (100 * windex.weight).ToString("#.#") + "% " + landforms[windex.index].Code; } player.SendMessage(groupId, text, EnumChatType.CommandSuccess); break; } case "climate": { ClimateCondition climate = api.World.BlockAccessor.GetClimateAt(pos); string text = string.Format("Temperature: {0}°, Rainfall: {1}%, Fertility: {2}%, Forest: {3}%, Shrub: {4}%, Sealevel dist: {5}%", climate.Temperature.ToString("0.#"), (int)(climate.Rainfall * 100f), (int)(climate.Fertility * 100f), (int)(climate.ForestDensity * 100f), (int)(climate.ShrubDensity * 100f), (int)(100f * pos.Y / 255f)); player.SendMessage(groupId, text, EnumChatType.CommandSuccess); break; } } }
LerpedWeightedIndex2DMap CreateLerpedProvinceMap(IntDataMap2D geoMap, int regionX, int regionZ) { int index2d = regionZ * regionMapSize + regionX; return(ProvinceMapByRegion[index2d] = new LerpedWeightedIndex2DMap(geoMap.Data, geoMap.Size, TerraGenConfig.geoProvSmoothingRadius, geoMap.TopLeftPadding, geoMap.BottomRightPadding)); }