double getOpenCave(double x, double y, double scale, double percentage) { double caveness = Noise.Generate((float)(x / scale), (float)(y / scale)); caveness = ((caveness + 1.0) / 2) * 100; caveness -= (100 - percentage); caveness /= percentage; if (caveness < 0) { caveness = 0; } return(caveness); }
/* * Spawns a new worm */ private void SpawnWorm(string tileID, int layer, int brushBoost, double lifespanBoost = 10f) { Vector2 wormDirection = new Vector2( Mathf.Floor(Utils.RandomFloat(random, -1f, 1f)), Mathf.Floor(Utils.RandomFloat(random, -1f, 1f)) ); float x = Mathf.Floor(Utils.RandomFloat(random, 0f, PlanetSettings.worldSize.x)); Vector2 currentWormPosition = new Vector2( x, Mathf.Floor(Utils.RandomFloat(random, 0f, GenHeight[(int)x])) ); int wormLifetimeMax = (int)Utils.RandomFloat(random, 7 * (float)lifespanBoost, 10 * (float)lifespanBoost); int currentWormSteps = 0; while (currentWormSteps < wormLifetimeMax) { // The amount of steps the worm will take this turn int moveAmount = Utils.RandomInt(random, 5, 11); // Until we have taken the appropriate number of steps, loop for (int currentStep = 0; currentStep < moveAmount; currentStep++) { // Validate worm position and punch blocks if (!IsValidPositionForWorm(currentWormPosition, layer, tileID, currentWormSteps, wormLifetimeMax, brushBoost)) { return; } // Move the worm currentWormPosition += wormDirection; // Increase worm steps currentWormSteps++; } // Decide if the worm will move a negative amount int isNegativeX = 1; int isNegativeY = 1; if (Utils.RandomInt(random, 0, 2) == 1) { isNegativeX = -1; } if (Utils.RandomInt(random, 0, 2) == 1) { isNegativeY = -1; } wormDirection = new Vector2( isNegativeX * Mathf.RoundToInt(Utils.map(Noise.Generate(Utils.RandomFloat(random, 0f, 1f), Utils.RandomFloat(random, 0f, 1f), 0), -1, 1, 0, 1)), isNegativeY * Mathf.RoundToInt(Utils.map(Noise.Generate(Utils.RandomFloat(random, 0f, 1f), Utils.RandomFloat(random, 0f, 1f), 0), -1, 1, 0, 1)) ); } }
double getPathyCave(double x, double y, double scale, double percentage) { double caveness = Noise.Generate((float)(x / (scale / 4.0)), (float)(y / (scale / 4.0))); caveness = (-Math.Abs(caveness) + 1) * 100; caveness -= (100 - percentage); caveness /= percentage; caveness /= 2; if (caveness < 0) { caveness = 0; } return(caveness); }
public void Update(GameTime gameTime, CameraOperator cameraOperator) { TerrainChunk firstChunk = _chunks[0]; if (firstChunk.LastVertex.X.ToPixels() < cameraOperator.Camera.Viewport.Projection.BoundingBox.TopLeft.X) { firstChunk.BodyPosition = _chunks[_chunks.Length - 1].LastVertex; firstChunk.Heights = Noise.Generate(TerrainChunk.HeightCount); Array.Copy(_chunks, 1, _chunks, 0, _chunks.Length - 1); _chunks[_chunks.Length - 1] = firstChunk; } }
public Terrain(GraphicsDevice graphics, World world) { //T_T SAD it doesn't work yet T_T _chunks = new TerrainChunk[graphics.Viewport.Width / TerrainChunk.Dimensions.X.ToPixels() + 20]; _chunks[0] = new TerrainChunk(0, Noise.Generate(TerrainChunk.HeightCount), graphics, world); for (int i = 1; i < _chunks.Length; i++) { _chunks[i] = new TerrainChunk(_chunks[i - 1].LastVertex.X, Noise.Generate(TerrainChunk.HeightCount), graphics, world, _chunks[i - 1].LastVertex.Y); } _blankTexture = new Texture2D(graphics, 1, 1); _blankTexture.SetData(new[] { Color.White }); }
//Generates an integer value that represents the height of a terrain value at a given coordinate, by using noise, //it ensures the same inputed values always get the same result public int generateNoise(int x, int y, int z) { float scale = getScale(); //Scale all the x, y, z coordinates float xScale = x * scale; float yScale = y * scale; float zScale = z * scale; //Generate the noise for the given coordinate, this value is between [-1, 1] so add 1 for it to always be >=0, then //Scale the value by 0.5*the max value achievable (ie the range is [0, 2] so the range of the final value is [0, max]) int noise = Mathf.FloorToInt((Noise.Generate(xScale, yScale, zScale) + 1f) * (max / 2f)); return(noise); }
public void GenerateMap() { blocks = new GameObject[width, height]; spawnedTrees = new GameObject[width, height]; float[,] noiseMap = Noise.Generate(width, height, noiseScale, Random.Range(0, 100000), Random.Range(0, 100000)); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { GameObject block = SpawnBlock(x, y, noiseMap[x, y]); blocks[x, y] = block; } } }
//simplex noise generation method, returns a float public float SimplexNoiseFloat(int x, int y, int z, float scale, float height, float power) { float rValue; rValue = Noise.Generate(((float)x) * scale, ((float)y) * scale, ((float)z) * scale); rValue += 1f; rValue *= height / 2f; if (power != 0) { rValue = Mathf.Pow(rValue, power); } return(rValue); }
public static float Noise2D(float x, float y, int depth, float frequencyFactor = 2f, float amplitudeFactor = 0.5f) { float value = 0f; float amplitude = 1f; for (int i = 0; i < depth; i++) { value += Noise.Generate(x, y) * amplitude; x *= frequencyFactor; y *= frequencyFactor; amplitude *= amplitudeFactor; } return(value); }
void FillChunk(int x, int y, int z) { float value; for (int k = 0; k < Chunk.size.x; ++k) { for (int j = 0; j < Chunk.size.y; ++j) { for (int i = 0; i < Chunk.size.z; ++i) { value = Noise.Generate((x * Chunk.size.x + i) * noiseScale, (y * Chunk.size.y + j) * noiseScale, (z * Chunk.size.z + k) * noiseScale); chunks[new Vector3Int(x, y, z)][i, j, k] = new Voxel(0.5f - value); } } } }
public BlockProvider(int dimensionX, int dimensionZ) { DimensionX = dimensionX; DimensionZ = dimensionZ; _blocks = new Block[dimensionX, dimensionZ]; // Create some dummy tiles for (int x = 0; x < DimensionX; ++x) { for (int z = 0; z < DimensionZ; ++z) { _blocks[x, z] = new Block(x, z, TileType.Grass, (Noise.Generate(x / 1000f, z / 1000f) + 1f) / 2f); } } }
public void GenerateMap() { float[,] noiseMap = Noise.Generate(mapWidth, mapHeight, seed, mapScale, octaves, persistance, lacunarity, offset); MapRenderer mr = FindObjectOfType <MapRenderer>(); if (drawMode == DrawMode.NoiseMap) { mr.DrawTexture(TextureGenerator.TextureFromHeightMap(noiseMap)); } else if (drawMode == DrawMode.ColorMap) { Color[] colorMap = this.ConvertNoiseToRegions(noiseMap); mr.DrawTexture(TextureGenerator.TextureFromColorMap(colorMap, noiseMap.GetLength(0), noiseMap.GetLength(1))); } }
MyColor RandomColor(Point p) { float fScale = .1f; Point pShift = new Point(10, 10); Func <Point, byte> gen = (pos) => Convert.ToByte(Math.Round((Noise.Generate((float)pos.x * fScale, (float)pos.y * fScale) + 1f) / 2 * 255)); //p += pShift; Byte R = gen(p); p += pShift; Byte G = gen(p); p += pShift; Byte B = gen(p); return(new MyColor(R, G, B)); }
private static int CalculateHeightMapValue(Vector3 position) { float x0 = (position.x + offset0.x) * frequency; float z0 = (position.z + offset0.z) * frequency; float x1 = (position.x + offset1.x) * frequency * 2f; float z1 = (position.z + offset1.z) * frequency * 2f; float x2 = (position.x + offset2.x) * frequency * 4f; float z2 = (position.z + offset2.z) * frequency * 4f; float noise0 = Noise.Generate(x0, z0) * amplitude; float noise1 = Noise.Generate(x1, z1) * amplitude / 4f; float noise2 = Noise.Generate(x2, z2) * amplitude / 8f; float noise = noise0 + noise1 + noise2; return(Mathf.FloorToInt(noise + baseHeight)); }
// Noise function private float GetNoise( float x, float y, float frequency, float amplitude, float persistance, int octaves) { float finalValue = 0f; for (int i = 0; i < octaves; ++i) { finalValue += noise.Generate(x * frequency, y * frequency) * amplitude; frequency *= 2.0f; amplitude *= persistance; } return(Mathf.Clamp(finalValue, -1, 1)); }
// Fractal Bronian Motion static float fBM(float x, float z, int oct, float pers) { float total = 0; float frequency = 0.5f; float amplitude = 3f; float maxValue = 0; for (int i = 0; i < oct; i++) { total += Noise.Generate((x + 64) * frequency, (z + 64) * frequency) * amplitude; maxValue += amplitude; amplitude *= pers; frequency *= 2; } return(total / maxValue); }
public MapData GenerateMap(Vector3 MapSize, Vector3 ChunckSize, int seed, float intensity) { var map = new MapData { Chunks = new ChunkData[(int)MapSize.x, (int)MapSize.y, (int)MapSize.z], ChunkHeights = Noise.Generate( (int)((MapSize.x + 1) * ChunckSize.x), (int)((MapSize.z + 1) * ChunckSize.z), seed, intensity) }; this.ForXyz( map.Chunks.GetLength(0), map.Chunks.GetLength(1), map.Chunks.GetLength(2), (x, y, z) => { map.Chunks[x, y, z] = new ChunkData { Blocks = new BlockData[(int)ChunckSize.x, (int)ChunckSize.y, (int)ChunckSize.z], MapPosition = new RVector3(x, y, z) }; var chunk = map.Chunks[x, y, z]; var blocks = chunk.Blocks; this.ForXyz( blocks.GetLength(0), blocks.GetLength(1), blocks.GetLength(2), (cx, cy, cz) => { var h = map.ChunkHeights[cx + x * (int)ChunckSize.x, cz + z * (int)ChunckSize.z]; blocks[cx, cy, cz] = new BlockData { BlockType = GetBlock(h, cx, cy, cz) }; }); }); return(map); }
private int GenerateWaveHeight(float x, float y, float z) { float x0 = (x + Offsets[0].x) * Frequency; float y0 = (y + Offsets[0].y) * Frequency; float z0 = (z + Offsets[0].z) * Frequency; float x1 = (x + Offsets[1].x) * Frequency * 2; float y1 = (y + Offsets[1].y) * Frequency * 2; float z1 = (z + Offsets[1].z) * Frequency * 2; float x2 = (x + Offsets[2].x) * Frequency / 4; float y2 = (y + Offsets[2].y) * Frequency / 4; float z2 = (z + Offsets[2].z) * Frequency / 4; float noise0 = Noise.Generate(x0, y0, z0) * Amplitude; float noise1 = Noise.Generate(x1, y1, z1) * Amplitude / 2; float noise2 = Noise.Generate(x2, y2, z2) * Amplitude / 4; return((int)(noise0 + noise1 + noise2 + MinHeight)); }
/** * @brief SimplexNoise Sampling * @return Sampling 된 3DNoise 값을 반환한다. */ public static float Get3DNoise(int x, int y, int z, float startFrequency, int octave, float persistence) { float noise = 0; float nomalizeFactor = 0; float amplitude = 1.0f; float frequency = startFrequency; for (int i = 0; i < octave; i++) { nomalizeFactor += amplitude; noise += amplitude * Noise.Generate(frequency * x, frequency * y, frequency * z); frequency *= 2; amplitude *= persistence; } return(noise / nomalizeFactor); }
public override void Process() { var generator = new Noise(world.Seed); for (int x = 0; x < Configuration.ChunkBlocks.x; x++) { for (int z = 0; z < Configuration.ChunkBlocks.z; z++) { for (int y = 0; y < Configuration.ChunkBlocks.y; y++) { float blockX = chunk.WorldPosition.x + (x * Configuration.BlockSize); float blockZ = chunk.WorldPosition.z + (z * Configuration.BlockSize); float blockY = chunk.WorldPosition.y + (y * Configuration.BlockSize); var noise = (generator.Generate(blockX / 79f, 0, blockZ / 79f) + 1f) * 0.37f; var limit = Mathf.Lerp(0, 64, noise); if (blockY <= limit) { chunk.SetBlock(x, y, z, BlockType.DIRT); if (chunk.ChunkType == ChunkType.EMPTY) { chunk.ChunkType = ChunkType.FULL; } } else { if (chunk.ChunkType == ChunkType.FULL) { chunk.ChunkType = ChunkType.MIXED; } } } } } chunk.ChunkState = ChunkState.GENERATED; chunk.Working = false; chunk.Attach(); }
double getCaveness(double x, double y, double scale, double percentage) { double biome1 = Noise.Generate((float)(x / (scale * 4)), (float)(y / (scale * 4))); biome1 *= 2; biome1 += 0.5; if (biome1 < 0) { return(getPathyCave(x, y, scale, percentage)); } else if (biome1 > 1) { return(getWideCave(x, y, scale, percentage)); } else { double wide = getWideCave(x, y, scale, percentage); double path = getPathyCave(x, y, scale, percentage); return((biome1 * wide) + ((1 - biome1) * path)); } }
// ---------------------------------------------------------------------------- public static float DensityFunc(Vector3 worldPosition) { float warpx = Noise.Generate(worldPosition.x * 0.0004f); float warpy = Noise.Generate(worldPosition.y * 0.0004f); float warpz = Noise.Generate(worldPosition.z * 0.0004f); Vector3 warp = new Vector3(warpx, warpy, warpz); worldPosition += warp * 8; float sphere = Sphere(worldPosition, new Vector3(0, 0, 0), 500); float noise = sphere; noise += (Noise.Generate(worldPosition * 0.400f)) * 0.5f / 2f; noise += (Noise.Generate(worldPosition * 0.200f)) * 1 / 2f; noise += (Noise.Generate(worldPosition * 0.100f)) * 2 / 2f; noise += (Noise.Generate(worldPosition * 0.050f)) * 4 / 2f; noise += (Noise.Generate(worldPosition * 0.025f)) * 8 / 2f; noise += (Noise.Generate(worldPosition * 0.010f)) * 16 / 2f; noise = Saturate(noise, sphere, worldPosition, 498); return(noise); }
int GenerateHeight(Vector3 wPos) { //让随机种子,振幅,频率,应用于我们的噪音采样结果 float x0 = (wPos.x + offset0.x) * frequency; float y0 = (wPos.y + offset0.y) * frequency; float z0 = (wPos.z + offset0.z) * frequency; float x1 = (wPos.x + offset1.x) * frequency * 2; float y1 = (wPos.y + offset1.y) * frequency * 2; float z1 = (wPos.z + offset1.z) * frequency * 2; float x2 = (wPos.x + offset2.x) * frequency / 4; float y2 = (wPos.y + offset2.y) * frequency / 4; float z2 = (wPos.z + offset2.z) * frequency / 4; float noise0 = Noise.Generate(x0, y0, z0) * amplitude; float noise1 = Noise.Generate(x1, y1, z1) * amplitude / 2; float noise2 = Noise.Generate(x2, y2, z2) * amplitude / 4; //在采样结果上,叠加上baseHeight,限制随机生成的高度下限 return(Mathf.FloorToInt(noise0 + noise1 + noise2 + baseHeight)); }
public static MongoGameState.Terrain GenerateTerrain(int width, int height) { var board = new MongoGameState.Terrain(); StringBuilder sb = new StringBuilder(board.Height * (board.Width + 1)); board.Width = width; board.Height = height; var random = new Random(); Noise.Seed = random.Next(); for (var y = 0; y < board.Height; y++) { for (var x = 0; x < board.Width; x++) { var value = Math.Abs(Noise.Generate(x / 90f, y / 90f)) * 90f; sb.Append(Math.Round(value / 15f)); } sb.Append("|"); } board.BoardStr = sb.ToString(); return(board); }
private MapData Generator() { float[,] noiseMap = Noise.Generate(mapSize, mapSize, noiseScale, coord, octave, lacunarity, percistence, seed); Color[] colorMap = new Color[mapSize * mapSize]; for (int x = 0; x < mapSize; x++) { for (int y = 0; y < mapSize; y++) { float actualPos = noiseMap[x, y]; for (int i = 0; i < biomes.Length; i++) { if (actualPos <= biomes[i].range) { colorMap[y * mapSize + x] = biomes[i].color; break; } } } } return(new MapData(noiseMap, colorMap)); }
/// <summary> /// 1D simplex noise /// </summary> /// <param name="x"></param> /// <returns></returns> /// public static float PerlinNoise(Vector3 position, Vector3 offset, int octaves, float persistance, float frequency, float min, float max) { float noise = 0; float amplitude = 1; float maxValue = 1; for (int i = 1; i < octaves + 1; i++) { Vector3 finPos = Mathf.Pow(frequency, i) / 500 * (position + offset); float curNoise = Noise.Generate(finPos.x, finPos.y, finPos.z); curNoise += 1; curNoise /= 2; noise += curNoise; maxValue += amplitude; frequency *= 2; amplitude *= persistance; } noise = min + (max - min) * (noise / maxValue); return(noise); }
public Rect GetTexture(Chunk chunk, BlockPos pos, Direction direction) { if (usesConnectedTextures) { string blockName = chunk.GetBlock(pos).controller.Name(); bool wn = ConnectedTextures.IsSame(chunk, pos, -1, 1, direction, blockName); bool n = ConnectedTextures.IsSame(chunk, pos, 0, 1, direction, blockName); bool ne = ConnectedTextures.IsSame(chunk, pos, 1, 1, direction, blockName); bool w = ConnectedTextures.IsSame(chunk, pos, -1, 0, direction, blockName); bool e = ConnectedTextures.IsSame(chunk, pos, 1, 0, direction, blockName); bool es = ConnectedTextures.IsSame(chunk, pos, 1, -1, direction, blockName); bool s = ConnectedTextures.IsSame(chunk, pos, 0, -1, direction, blockName); bool sw = ConnectedTextures.IsSame(chunk, pos, -1, -1, direction, blockName); return(connectedTextures[ConnectedTextures.GetTexture(n, e, s, w, wn, ne, es, sw)]); } if (textures.Count == 1) { return(textures[0]); } if (textures.Count > 1) { float randomNumber = noiseGen.Generate(pos.x, pos.y, pos.z); randomNumber += 1; randomNumber /= 2; randomNumber *= textures.Count; return(textures[(int)randomNumber]); } Debug.LogError("There were no textures for " + textureName); return(new Rect()); }
public static Voxel[,,] GenerateChunk(Vector2i i) { var data = new float[ChunkSize.X + 1, ChunkHeight, ChunkSize.Y + 1]; var voxels = new Voxel[ChunkSize.X + 1, ChunkHeight, ChunkSize.Y + 1]; var ns = new Vector3d( NoiseStep * ChunkSize.X * i.X, 0, NoiseStep * ChunkSize.Y * i.Y ); // gen data for (var x = 0; x < data.GetLength(0); x++) { for (var y = 0; y < data.GetLength(1); y++) { for (var z = 0; z < data.GetLength(2); z++) { var density = -y / (float)ChunkHeight / 2f + 0.1f; density += Noise.Generate( (float)(NoiseLocation.X + ns.X + NoiseStep * x * 1), (float)(NoiseLocation.X + ns.Y + NoiseStep * y * 1), (float)(NoiseLocation.X + ns.Z + NoiseStep * z * 1)) / 2f; density += Noise.Generate( (float)(NoiseLocation.X + ns.X * 2 + NoiseStep * x * 2), (float)(NoiseLocation.X + ns.Y * 2 + NoiseStep * y * 2), (float)(NoiseLocation.X + ns.Z * 2 + NoiseStep * z * 2)) / 8f; density += Noise.Generate( (float)(NoiseLocation.X + ns.X * 4 + NoiseStep * x * 4), (float)(NoiseLocation.X + ns.Y * 4 + NoiseStep * y * 4), (float)(NoiseLocation.X + ns.Z * 4 + NoiseStep * z * 4)) / 16f; density += Noise.Generate( (float)(NoiseLocation.X + ns.X * 8 + NoiseStep * x * 8), (float)(NoiseLocation.X + ns.Y * 8 + NoiseStep * y * 8), (float)(NoiseLocation.X + ns.Z * 8 + NoiseStep * z * 8)) / 32f; data[x, y, z] = density; } } } // make voxels for (var x = 0; x < data.GetLength(0); x++) { for (var y = 0; y < data.GetLength(1); y++) { for (var z = 0; z < data.GetLength(2); z++) { var density = data[x, y, z]; var normal = new Vector3( ((x < data.GetLength(0) - 1 ? data[x + 1, y, z] : data[x, y, z]) + (x > 0 ? data[x - 1, y, z] : data[x, y, z])) / 2f, ((y < data.GetLength(0) - 1 ? data[x, y + 1, z] : data[x, y, z]) + (y > 0 ? data[x, y - 1, z] : data[x, y, z])) / 2f, ((z < data.GetLength(0) - 1 ? data[x, y, z + 1] : data[x, y, z]) + (z > 0 ? data[x, y, z - 1] : data[x, y, z])) / 2f ).Normalized(); if (y / (float)ChunkHeight < 0.2f) { voxels[x, y, z] = new Voxel(1d, VoxelType.Blue, normal); } else if (density < 0f) { voxels[x, y, z] = new Voxel(density, VoxelType.None, normal); } else { voxels[x, y, z] = new Voxel(density, VoxelType.DarkGray, normal); } } } } return(voxels); }
public static int GetNoise(int x, int y, int z, float scale, int max) { return(Mathf.FloorToInt((Noise.Generate(x * scale, y * scale, z * scale) + 1f) * (max / 2f))); }
private void March(int3 coord, Mesh mesh) { float4[] points = new float4[terrain.Resolution * terrain.Resolution * terrain.Resolution]; float spacing = terrain.BoundsSize / (terrain.Resolution - 1); float3 center = (float3)coord * terrain.BoundsSize; int3 xyz = 0; for (xyz.x = 0; xyz.x < terrain.Resolution; xyz.x++) for (xyz.y = 0; xyz.y < terrain.Resolution; xyz.y++) for (xyz.z = 0; xyz.z < terrain.Resolution; xyz.z++) { float3 pos = center + (float3)xyz * spacing - terrain.BoundsSize / 2f; float f = noise.Generate(pos); int i = xyz.x * terrain.Resolution * terrain.Resolution + xyz.y * terrain.Resolution + xyz.z; points[i] = new float4(pos, f); } List<float3x3> trianglePoints = new List<float3x3>(); for (xyz.x = 0; xyz.x < terrain.Resolution - 1; xyz.x++) for (xyz.y = 0; xyz.y < terrain.Resolution - 1; xyz.y++) for (xyz.z = 0; xyz.z < terrain.Resolution - 1; xyz.z++) { for (int i = 0; i < 8; i++) { int3 corner = xyz + tables.Value.CubeCorners[i]; cube[i] = points[corner.x * terrain.Resolution * terrain.Resolution + corner.y * terrain.Resolution + corner.z]; } int triangulationIndex = 0; for (int i = 0; i < 8; i++) if (cube[i].w > terrain.Surface) triangulationIndex |= 1 << i; triangulationIndex *= 16; for (int i = 0; tables.Value.TriangulationTable[triangulationIndex + i] != -1; i += 3) { int2 edgeA = tables.Value.EdgeConnections[tables.Value.TriangulationTable[triangulationIndex + i]]; int2 edgeB = tables.Value.EdgeConnections[tables.Value.TriangulationTable[triangulationIndex + i + 1]]; int2 edgeC = tables.Value.EdgeConnections[tables.Value.TriangulationTable[triangulationIndex + i + 2]]; float3x3 triangle = new float3x3 { c0 = interpolate(cube[edgeA.x], cube[edgeA.y]), c1 = interpolate(cube[edgeB.x], cube[edgeB.y]), c2 = interpolate(cube[edgeC.x], cube[edgeC.y]) }; trianglePoints.Add(triangle); } } mesh.Clear(); if (trianglePoints.Count == 0) return; Vector3[] vertices = new Vector3[trianglePoints.Count * 3]; int[] triangles = new int[trianglePoints.Count * 3]; for (int i = 0; i < trianglePoints.Count; i++) for (int j = 0; j < 3; j++) { int idx = i * 3 + j; triangles[idx] = idx; vertices[idx] = trianglePoints[i][j]; } mesh.vertices = vertices; mesh.triangles = triangles; mesh.RecalculateNormals(); }