public virtual void GenerateTerrain(Chunk chunk, int seed) { System.Random rng = new System.Random(unchecked (seed + chunk.Position.GetHashCode())); Vector3Int worldPosition = chunk.Position * Chunk.CHUNK_SIZE; var biomeLocker = chunk.GetBiomeLock(); biomeLocker.EnterReadLock(); var locker = chunk.GetLock(); locker.EnterWriteLock(); for (int x = 0; x < Chunk.CHUNK_SIZE; x++) { for (int z = 0; z < Chunk.CHUNK_SIZE; z++) { int globalX = x + worldPosition.x; int globalZ = z + worldPosition.z; (double temperature, double humidity) = GetBiomeValues(globalX, globalZ); Biome primaryBiome = GetPrimaryAndHeight(chunk, x, z, globalX, globalZ, out double height); int terrainHeight = (int)height; Block lastBlock = null; for (int y = 0; y < Chunk.CHUNK_SIZE; y++) { int globalY = y + worldPosition.y; int index = x + y * Chunk.CHUNK_SIZE + z * Chunk.CHUNK_SIZE_SQR; Block newBlock = Air; if (globalY > terrainHeight) { if (globalY <= WATER_LEVEL) { newBlock = Water; } else if (globalY - 1 == terrainHeight) { if (lastBlock != null && GetFloral(lastBlock, temperature, humidity, globalY, rng, out Block floral)) { newBlock = floral; } } } else if (globalY <= terrainHeight) { newBlock = primaryBiome.GetBlock(terrainHeight, globalY, rng); } lastBlock = newBlock; chunk.SetBlock(newBlock, index, true, false); } } } biomeLocker.ExitReadLock(); locker.ExitWriteLock(); }