From 7a5388b8bb1093066d64f90585ef221731f0e019 Mon Sep 17 00:00:00 2001
From: Avi Weinstock <aweinstock314@gmail.com>
Date: Sun, 27 Jun 2021 15:35:43 -0400
Subject: [PATCH] Use new dungeons in dungeon_voxel_export, remove old dungeon
 sampling function, and add more of world/examples to CI.

---
 .gitlab/CI/check.gitlab-ci.yml                |   2 +-
 .../examples/chunk_compression_benchmarks.rs  | 107 ++++---
 world/examples/dungeon_voxel_export.rs        |  72 ++++-
 world/examples/heightmap_visualization.rs     |  15 +-
 world/src/canvas.rs                           |  38 +++
 world/src/site2/gen.rs                        |   7 +-
 world/src/site2/mod.rs                        |   7 +-
 world/src/site2/plot.rs                       |   2 +
 world/src/site2/plot/dungeon.rs               | 302 +-----------------
 9 files changed, 176 insertions(+), 376 deletions(-)

diff --git a/.gitlab/CI/check.gitlab-ci.yml b/.gitlab/CI/check.gitlab-ci.yml
index 2f5b0a1490..c74f8d6aa1 100644
--- a/.gitlab/CI/check.gitlab-ci.yml
+++ b/.gitlab/CI/check.gitlab-ci.yml
@@ -6,7 +6,7 @@ code-quality:
   script:
     - ln -s /dockercache/target target
     - rm -r target/debug/incremental/* || echo "all good" # TMP FIX FOR 2021-03-22-nightly
-    - cargo clippy --all-targets --locked --features="bin_csv,bin_graphviz,bin_bot,asset_tweak" -- -D warnings
+    - cargo clippy --all-targets --locked --features="bin_compression,bin_csv,bin_graphviz,bin_bot,asset_tweak" -- -D warnings
     # Ensure that the veloren-voxygen default-publish feature builds as it excludes some default features
     - cargo clippy -p veloren-voxygen --locked --no-default-features --features="default-publish" -- -D warnings
     - cargo fmt --all -- --check
diff --git a/world/examples/chunk_compression_benchmarks.rs b/world/examples/chunk_compression_benchmarks.rs
index 2470a69c0a..9ac934b953 100644
--- a/world/examples/chunk_compression_benchmarks.rs
+++ b/world/examples/chunk_compression_benchmarks.rs
@@ -1,3 +1,4 @@
+#![allow(clippy::type_complexity)]
 use common::{
     spiral::Spiral2d,
     terrain::{chonk::Chonk, Block, BlockKind, SpriteKind},
@@ -15,6 +16,7 @@ use common_net::msg::compression::{
 use hashbrown::HashMap;
 use image::ImageBuffer;
 use num_traits::cast::FromPrimitive;
+use rayon::ThreadPoolBuilder;
 use serde::{Deserialize, Serialize};
 use std::{
     collections::BTreeMap,
@@ -56,8 +58,7 @@ fn do_deflate_rle(data: &[u8]) -> Vec<u8> {
 
     let mut encoder = DeflateEncoder::new(Vec::new(), CompressionOptions::rle());
     encoder.write_all(data).expect("Write error!");
-    let compressed_data = encoder.finish().expect("Failed to finish compression!");
-    compressed_data
+    encoder.finish().expect("Failed to finish compression!")
 }
 
 // Separate function so that it shows up differently on the flamegraph
@@ -66,8 +67,7 @@ fn do_deflate_flate2_zero(data: &[u8]) -> Vec<u8> {
 
     let mut encoder = DeflateEncoder::new(Vec::new(), Compression::new(0));
     encoder.write_all(data).expect("Write error!");
-    let compressed_data = encoder.finish().expect("Failed to finish compression!");
-    compressed_data
+    encoder.finish().expect("Failed to finish compression!")
 }
 
 fn do_deflate_flate2<const LEVEL: u32>(data: &[u8]) -> Vec<u8> {
@@ -75,8 +75,7 @@ fn do_deflate_flate2<const LEVEL: u32>(data: &[u8]) -> Vec<u8> {
 
     let mut encoder = DeflateEncoder::new(Vec::new(), Compression::new(LEVEL));
     encoder.write_all(data).expect("Write error!");
-    let compressed_data = encoder.finish().expect("Failed to finish compression!");
-    compressed_data
+    encoder.finish().expect("Failed to finish compression!")
 }
 
 fn chonk_to_dyna<V: Clone, S: RectVolSize, M: Clone, A: Access>(
@@ -489,6 +488,7 @@ impl VoxelImageEncoding for MixedEncodingDenseSprites {
     }
 }
 
+#[allow(clippy::many_single_char_names)]
 fn histogram_to_dictionary(histogram: &HashMap<Vec<u8>, usize>, dictionary: &mut Vec<u8>) {
     let mut tmp: Vec<(Vec<u8>, usize)> = histogram.iter().map(|(k, v)| (k.clone(), *v)).collect();
     tmp.sort_by_key(|(_, count)| *count);
@@ -507,13 +507,17 @@ fn histogram_to_dictionary(histogram: &HashMap<Vec<u8>, usize>, dictionary: &mut
 }
 
 fn main() {
+    let pool = ThreadPoolBuilder::new().build().unwrap();
     common_frontend::init_stdout(None);
     println!("Loading world");
-    let (world, index) = World::generate(59686, WorldOpts {
-        seed_elements: true,
-        world_file: FileOpts::LoadAsset(DEFAULT_WORLD_MAP.into()),
-        ..WorldOpts::default()
-    });
+    let (world, index) = World::generate(
+        59686,
+        WorldOpts {
+            seed_elements: true,
+            world_file: FileOpts::LoadAsset(DEFAULT_WORLD_MAP.into()),
+        },
+        &pool,
+    );
     println!("Loaded world");
     const HISTOGRAMS: bool = false;
     let mut histogram: HashMap<Vec<u8>, usize> = HashMap::new();
@@ -523,45 +527,45 @@ fn main() {
     let k = 32;
     let sz = world.sim().get_size();
 
-    let mut sites = Vec::new();
-
-    sites.push(("center", sz / 2));
-    sites.push((
-        "dungeon",
-        world
-            .civs()
-            .sites()
-            .find(|s| s.is_dungeon())
-            .map(|s| s.center.as_())
-            .unwrap(),
-    ));
-    sites.push((
-        "town",
-        world
-            .civs()
-            .sites()
-            .find(|s| s.is_settlement())
-            .map(|s| s.center.as_())
-            .unwrap(),
-    ));
-    sites.push((
-        "castle",
-        world
-            .civs()
-            .sites()
-            .find(|s| s.is_castle())
-            .map(|s| s.center.as_())
-            .unwrap(),
-    ));
-    sites.push((
-        "tree",
-        world
-            .civs()
-            .sites()
-            .find(|s| matches!(s.kind, SiteKind::Tree))
-            .map(|s| s.center.as_())
-            .unwrap(),
-    ));
+    let sites = vec![
+        ("center", sz / 2),
+        (
+            "dungeon",
+            world
+                .civs()
+                .sites()
+                .find(|s| s.is_dungeon())
+                .map(|s| s.center.as_())
+                .unwrap(),
+        ),
+        (
+            "town",
+            world
+                .civs()
+                .sites()
+                .find(|s| s.is_settlement())
+                .map(|s| s.center.as_())
+                .unwrap(),
+        ),
+        (
+            "castle",
+            world
+                .civs()
+                .sites()
+                .find(|s| s.is_castle())
+                .map(|s| s.center.as_())
+                .unwrap(),
+        ),
+        (
+            "tree",
+            world
+                .civs()
+                .sites()
+                .find(|s| matches!(s.kind, SiteKind::Tree))
+                .map(|s| s.center.as_())
+                .unwrap(),
+        ),
+    ];
 
     const SKIP_DEFLATE_2_5: bool = false;
     const SKIP_DYNA: bool = true;
@@ -600,6 +604,7 @@ fn main() {
                 let lz4chonk_pre = Instant::now();
                 let lz4_chonk = lz4_with_dictionary(&bincode::serialize(&chunk).unwrap(), &[]);
                 let lz4chonk_post = Instant::now();
+                #[allow(clippy::reversed_empty_ranges)]
                 for _ in 0..ITERS {
                     let _deflate0_chonk =
                         do_deflate_flate2_zero(&bincode::serialize(&chunk).unwrap());
@@ -1024,7 +1029,7 @@ fn main() {
                 for (name, value) in totals.iter() {
                     println!("Average {}: {}", name, *value / count as f32);
                 }
-                println!("");
+                println!();
                 for (name, time) in total_timings.iter() {
                     println!("Average {} nanos: {:02}", name, *time / count as f32);
                 }
diff --git a/world/examples/dungeon_voxel_export.rs b/world/examples/dungeon_voxel_export.rs
index 426dc9a80b..e0971c351b 100644
--- a/world/examples/dungeon_voxel_export.rs
+++ b/world/examples/dungeon_voxel_export.rs
@@ -6,28 +6,65 @@ use std::{
 type Result = std::io::Result<()>;
 
 use common::{
-    terrain::{Block, BlockKind},
+    terrain::{Block, BlockKind, SpriteKind},
     vol::{BaseVol, ReadVol, RectSizedVol, WriteVol},
 };
+use rayon::ThreadPoolBuilder;
 use vek::{Vec2, Vec3};
-use veloren_world::{index::Index, IndexOwned, Land};
+use veloren_world::{
+    sim::{FileOpts, WorldOpts, DEFAULT_WORLD_MAP},
+    site2::{plot::PlotKind, Structure},
+    CanvasInfo, Land, World,
+};
 
 /// This exports a dungeon (structure only, no entities or sprites) to a
 /// MagicaVoxel .vox file
 
 fn main() -> Result {
+    common_frontend::init_stdout(None);
+    let pool = ThreadPoolBuilder::new().build().unwrap();
+    println!("Loading world");
+    let (world, index) = World::generate(
+        59686,
+        WorldOpts {
+            seed_elements: true,
+            world_file: FileOpts::LoadAsset(DEFAULT_WORLD_MAP.into()),
+        },
+        &pool,
+    );
+    println!("Loaded world");
     let export_path = "dungeon.vox";
-    let seed = 0;
 
     println!("Saving into {}", export_path);
     let mut volume = ExportVol::new();
-    let index = IndexOwned::new(Index::new(seed));
-    let dungeon = veloren_world::site2::plot::Dungeon::generate(
-        volume.size_xy().map(|p| p as i32 / 2),
-        &Land::empty(),
-        &mut rand::thread_rng(),
-    );
-    dungeon.apply_to(index.as_index_ref(), Vec2::new(0, 0), |_| None, &mut volume);
+    let wpos = volume.size_xy().map(|p| p as i32 / 2);
+    let site =
+        veloren_world::site2::Site::generate_dungeon(&Land::empty(), &mut rand::thread_rng(), wpos);
+    CanvasInfo::with_mock_canvas_info(index.as_index_ref(), world.sim(), |canvas| {
+        for plot in site.plots() {
+            if let PlotKind::Dungeon(dungeon) = plot.kind() {
+                let (prim_tree, fills) = dungeon.render_collect(&site);
+
+                for (prim, fill) in fills {
+                    let aabb = fill.get_bounds(&prim_tree, prim);
+
+                    for x in aabb.min.x..aabb.max.x {
+                        for y in aabb.min.y..aabb.max.y {
+                            for z in aabb.min.z..aabb.max.z {
+                                let pos = Vec3::new(x, y, z);
+
+                                if let Some(block) = fill.sample_at(&prim_tree, prim, pos, &canvas)
+                                {
+                                    let _ = volume.set(pos, block);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    });
+
     volume.write(&mut File::create(export_path)?)
 }
 
@@ -157,7 +194,9 @@ impl ExportVol {
         write_chunk(file, "RGBA", &|file| {
             file.write_all(&[220, 220, 255, 0])?; // Air
             file.write_all(&[100, 100, 100, 0])?; // Rock
-            file.write_all(&[0; 4 * (256 - 2)])
+            file.write_all(&[255, 0, 0, 0])?; // Sprite
+            file.write_all(&[255, 0, 255, 0])?; // GlowingRock
+            file.write_all(&[0; 4 * (256 - 4)])
         })?;
 
         let chunks_end = file.stream_position()?;
@@ -200,9 +239,16 @@ impl WriteVol for ExportVol {
             .entry(model_pos)
             .or_default()
             .extend_from_slice(&[rel_pos.x, rel_pos.y, rel_pos.z, match vox.kind() {
-                BlockKind::Air => 1,
+                BlockKind::Air => {
+                    if !matches!(vox.get_sprite(), Some(SpriteKind::Empty)) {
+                        3
+                    } else {
+                        1
+                    }
+                },
                 BlockKind::Rock => 2,
-                _ => 3,
+                BlockKind::GlowingRock => 4,
+                _ => 5,
             }]);
         Ok(vox)
     }
diff --git a/world/examples/heightmap_visualization.rs b/world/examples/heightmap_visualization.rs
index 96ec9e3fcf..27b99708a2 100644
--- a/world/examples/heightmap_visualization.rs
+++ b/world/examples/heightmap_visualization.rs
@@ -2,6 +2,7 @@ use image::{
     codecs::png::{CompressionType, FilterType, PngEncoder},
     ImageBuffer,
 };
+use rayon::ThreadPoolBuilder;
 use std::{fs::File, io::Write};
 use vek::*;
 use veloren_world::{
@@ -116,12 +117,16 @@ fn image_with_autorange<F: Fn(f32, f32, f32) -> [u8; 3], G: FnMut(u32, u32) -> f
 
 fn main() {
     common_frontend::init_stdout(None);
+    let pool = ThreadPoolBuilder::new().build().unwrap();
     println!("Loading world");
-    let (world, _index) = World::generate(59686, WorldOpts {
-        seed_elements: true,
-        world_file: FileOpts::LoadAsset(DEFAULT_WORLD_MAP.into()),
-        ..WorldOpts::default()
-    });
+    let (world, _index) = World::generate(
+        59686,
+        WorldOpts {
+            seed_elements: true,
+            world_file: FileOpts::LoadAsset(DEFAULT_WORLD_MAP.into()),
+        },
+        &pool,
+    );
     println!("Loaded world");
 
     let land = Land::from_sim(world.sim());
diff --git a/world/src/canvas.rs b/world/src/canvas.rs
index f7a8b22300..12aba6ae19 100644
--- a/world/src/canvas.rs
+++ b/world/src/canvas.rs
@@ -49,6 +49,44 @@ impl<'a> CanvasInfo<'a> {
     pub fn chunks(&self) -> &'a WorldSim { self.chunks }
 
     pub fn land(&self) -> Land<'_> { Land::from_sim(self.chunks) }
+
+    pub fn with_mock_canvas_info<A, F: for<'b> FnOnce(&CanvasInfo<'b>) -> A>(
+        index: IndexRef<'a>,
+        sim: &'a WorldSim,
+        f: F,
+    ) -> A {
+        let zcache_grid = Grid::populate_from(Vec2::broadcast(1), |_| None);
+        let sim_chunk = SimChunk {
+            chaos: 0.0,
+            alt: 0.0,
+            basement: 0.0,
+            water_alt: 0.0,
+            downhill: None,
+            flux: 0.0,
+            temp: 0.0,
+            humidity: 0.0,
+            rockiness: 0.0,
+            tree_density: 0.0,
+            forest_kind: crate::all::ForestKind::Palm,
+            spawn_rate: 0.0,
+            river: Default::default(),
+            surface_veg: 0.0,
+            sites: Vec::new(),
+            place: None,
+            path: Default::default(),
+            cave: Default::default(),
+            cliff_height: 0.0,
+            contains_waypoint: false,
+        };
+        f(&CanvasInfo {
+            wpos: Vec2::broadcast(0),
+            column_grid: &zcache_grid,
+            column_grid_border: 0,
+            chunks: &sim,
+            index,
+            chunk: &sim_chunk,
+        })
+    }
 }
 
 pub struct Canvas<'a> {
diff --git a/world/src/site2/gen.rs b/world/src/site2/gen.rs
index b2192df466..036db08171 100644
--- a/world/src/site2/gen.rs
+++ b/world/src/site2/gen.rs
@@ -157,7 +157,7 @@ impl Fill {
         tree: &Store<Primitive>,
         prim: Id<Primitive>,
         pos: Vec3<i32>,
-        canvas: &Canvas,
+        canvas_info: &crate::CanvasInfo,
     ) -> Option<Block> {
         if self.contains_at(tree, prim, pos) {
             match self {
@@ -169,10 +169,9 @@ impl Fill {
                         % *range as u32) as u8,
                 )),
                 Fill::Prefab(p, tr, seed) => p.get(pos - tr).ok().and_then(|sb| {
-                    let info = canvas.info;
-                    let col_sample = info.col(info.wpos)?;
+                    let col_sample = canvas_info.col(canvas_info.wpos)?;
                     block_from_structure(
-                        canvas.index,
+                        canvas_info.index,
                         *sb,
                         pos - tr,
                         p.get_bounds().center().xy(),
diff --git a/world/src/site2/mod.rs b/world/src/site2/mod.rs
index 73968d8934..5a5490e2ac 100644
--- a/world/src/site2/mod.rs
+++ b/world/src/site2/mod.rs
@@ -2,10 +2,10 @@ mod gen;
 pub mod plot;
 mod tile;
 
-use self::{
+use self::tile::{HazardKind, KeepKind, Ori, RoofKind, Tile, TileGrid, TileKind, TILE_SIZE};
+pub use self::{
     gen::{aabr_with_z, Fill, Primitive, Structure},
     plot::{Plot, PlotKind},
-    tile::{HazardKind, KeepKind, Ori, RoofKind, Tile, TileGrid, TileKind, TILE_SIZE},
 };
 use crate::{
     site::SpawnRules,
@@ -772,7 +772,8 @@ impl Site {
                         for z in aabb.min.z..aabb.max.z {
                             let pos = Vec3::new(x, y, z);
 
-                            if let Some(block) = fill.sample_at(&prim_tree, prim, pos, &canvas) {
+                            if let Some(block) = fill.sample_at(&prim_tree, prim, pos, &canvas.info)
+                            {
                                 canvas.set(pos, block);
                             }
                         }
diff --git a/world/src/site2/plot.rs b/world/src/site2/plot.rs
index cbc79461e0..ff753f9070 100644
--- a/world/src/site2/plot.rs
+++ b/world/src/site2/plot.rs
@@ -24,6 +24,8 @@ impl Plot {
                 b.expanded_to_contain_point(*t)
             })
     }
+
+    pub fn kind(&self) -> &PlotKind { &self.kind }
 }
 
 pub enum PlotKind {
diff --git a/world/src/site2/plot/dungeon.rs b/world/src/site2/plot/dungeon.rs
index 51e40e8c34..43cf4f6917 100644
--- a/world/src/site2/plot/dungeon.rs
+++ b/world/src/site2/plot/dungeon.rs
@@ -1,11 +1,9 @@
 use super::SpawnRules;
 use crate::{
-    block::block_from_structure,
-    column::ColumnSample,
-    site::{namegen::NameGen, BlockMask},
+    site::namegen::NameGen,
     site2::{self, aabr_with_z, Fill, Primitive, Structure as SiteStructure},
     util::{attempt, Grid, RandomField, Sampler, CARDINALS, DIRS},
-    IndexRef, Land,
+    Land,
 };
 
 use common::{
@@ -15,7 +13,7 @@ use common::{
     generation::{ChunkSupplement, EntityInfo},
     store::{Id, Store},
     terrain::{Block, BlockKind, SpriteKind, Structure, StructuresGroup, TerrainChunkSize},
-    vol::{BaseVol, ReadVol, RectSizedVol, RectVolSize, WriteVol},
+    vol::RectVolSize,
 };
 use core::{f32, hash::BuildHasherDefault};
 use fxhash::FxHasher64;
@@ -128,79 +126,6 @@ impl Dungeon {
 
     pub fn difficulty(&self) -> u32 { self.difficulty }
 
-    pub fn apply_to<'a>(
-        &'a self,
-        index: IndexRef,
-        wpos2d: Vec2<i32>,
-        mut get_column: impl FnMut(Vec2<i32>) -> Option<&'a ColumnSample<'a>>,
-        vol: &mut (impl BaseVol<Vox = Block> + RectSizedVol + ReadVol + WriteVol),
-    ) {
-        lazy_static! {
-            pub static ref ENTRANCES: AssetHandle<StructuresGroup> =
-                Structure::load_group("dungeon_entrances");
-        }
-
-        let entrances = ENTRANCES.read();
-        let entrance = &entrances[self.seed as usize % entrances.len()];
-
-        for y in 0..vol.size_xy().y as i32 {
-            for x in 0..vol.size_xy().x as i32 {
-                let offs = Vec2::new(x, y);
-
-                let wpos2d = wpos2d + offs;
-                let rpos = wpos2d - self.origin;
-
-                // Apply the dungeon entrance
-                if let Some(col_sample) = get_column(offs) {
-                    for z in entrance.get_bounds().min.z..entrance.get_bounds().max.z {
-                        let wpos = Vec3::new(offs.x, offs.y, self.alt + z + ALT_OFFSET);
-                        let spos = Vec3::new(rpos.x - TILE_SIZE / 2, rpos.y - TILE_SIZE / 2, z);
-                        if let Some(block) = entrance
-                            .get(spos)
-                            .ok()
-                            .copied()
-                            .map(|sb| {
-                                block_from_structure(
-                                    index,
-                                    sb,
-                                    spos,
-                                    self.origin,
-                                    self.seed,
-                                    col_sample,
-                                    // TODO: Take environment into account.
-                                    Block::air,
-                                )
-                            })
-                            .unwrap_or(None)
-                        {
-                            let _ = vol.set(wpos, block);
-                        }
-                    }
-                };
-
-                // Apply the dungeon internals
-                let mut z = self.alt + ALT_OFFSET;
-                for floor in &self.floors {
-                    z -= floor.total_depth();
-
-                    let mut sampler = floor.col_sampler(
-                        index,
-                        rpos,
-                        z,
-                        // TODO: Take environment into account.
-                        Block::air,
-                    );
-
-                    for rz in 0..floor.total_depth() {
-                        if let Some(block) = sampler(rz).finish() {
-                            let _ = vol.set(Vec3::new(offs.x, offs.y, z + rz), block);
-                        }
-                    }
-                }
-            }
-        }
-    }
-
     #[allow(clippy::or_fun_call)] // TODO: Pending review in #587
     pub fn apply_supplement<'a>(
         &'a self,
@@ -695,10 +620,6 @@ impl Floor {
 
     fn total_depth(&self) -> i32 { self.solid_depth + self.hollow_depth }
 
-    fn nearest_wall(&self, rpos: Vec2<i32>) -> Option<Vec2<i32>> {
-        tilegrid_nearest_wall(&self.tiles, rpos)
-    }
-
     // Find orientation of a position relative to another position
     #[allow(clippy::collapsible_else_if)]
     fn relative_ori(pos1: Vec2<i32>, pos2: Vec2<i32>) -> u8 {
@@ -708,223 +629,6 @@ impl Floor {
             if pos1.x > pos2.x { 2 } else { 6 }
         }
     }
-
-    #[allow(clippy::unnested_or_patterns)] // TODO: Pending review in #587
-    fn col_sampler<'a>(
-        &'a self,
-        index: IndexRef<'a>,
-        pos: Vec2<i32>,
-        _floor_z: i32,
-        mut with_sprite: impl FnMut(SpriteKind) -> Block,
-    ) -> impl FnMut(i32) -> BlockMask + 'a {
-        let rpos = pos - self.tile_offset * TILE_SIZE;
-        let tile_pos = rpos.map(|e| e.div_euclid(TILE_SIZE));
-        let tile_center = tile_pos * TILE_SIZE + TILE_SIZE / 2;
-        let rtile_pos = rpos - tile_center;
-
-        let colors = &index.colors.site.dungeon;
-
-        let vacant = BlockMask::new(with_sprite(SpriteKind::Empty), 1);
-        let stone = BlockMask::new(Block::new(BlockKind::Rock, colors.stone.into()), 5);
-
-        let make_spiral_staircase =
-            move |pos: Vec3<i32>, radius: f32, inner_radius: f32, stretch: f32| {
-                if (pos.xy().magnitude_squared() as f32) < inner_radius.powi(2) {
-                    stone
-                } else if (pos.xy().magnitude_squared() as f32) < radius.powi(2) {
-                    if ((pos.x as f32).atan2(pos.y as f32) / (f32::consts::PI * 2.0) * stretch
-                        + pos.z as f32)
-                        .rem_euclid(stretch)
-                        < 1.5
-                    {
-                        stone
-                    } else {
-                        vacant
-                    }
-                } else {
-                    BlockMask::nothing()
-                }
-            };
-        let make_wall_staircase =
-            move |pos: Vec3<i32>, radius: f32, stretch: f32, height_limit: i32| {
-                if (pos.x.abs().max(pos.y.abs())) as f32 > 0.6 * radius && pos.z <= height_limit {
-                    if ((pos.x as f32).atan2(pos.y as f32) / (f32::consts::PI * 2.0) * stretch
-                        + pos.z as f32)
-                        .rem_euclid(stretch)
-                        < 1.0
-                    {
-                        stone
-                    } else {
-                        vacant
-                    }
-                } else {
-                    vacant
-                }
-            };
-        let make_staircase = move |kind: &StairsKind,
-                                   pos: Vec3<i32>,
-                                   radius: f32,
-                                   inner_radius: f32,
-                                   stretch: f32,
-                                   height_limit: i32| {
-            match kind {
-                StairsKind::Spiral => make_spiral_staircase(pos, radius, inner_radius, stretch),
-                StairsKind::WallSpiral => {
-                    make_wall_staircase(pos, radius, stretch * 3.0, height_limit)
-                },
-            }
-        };
-
-        let wall_thickness = 3.0;
-        let dist_to_wall = self
-            .nearest_wall(rpos)
-            .map(|nearest| (nearest.distance_squared(rpos) as f32).sqrt())
-            .unwrap_or(TILE_SIZE as f32);
-        let tunnel_dist =
-            1.0 - (dist_to_wall - wall_thickness).max(0.0) / (TILE_SIZE as f32 - wall_thickness);
-
-        let floor_sprite = if RandomField::new(7331).chance(Vec3::from(pos), 0.001) {
-            BlockMask::new(
-                with_sprite(
-                    match (RandomField::new(1337).get(Vec3::from(pos)) / 2) % 30 {
-                        0 => SpriteKind::Apple,
-                        1 => SpriteKind::VeloriteFrag,
-                        2 => SpriteKind::Velorite,
-                        3..=8 => SpriteKind::Mushroom,
-                        9..=15 => SpriteKind::FireBowlGround,
-                        _ => SpriteKind::ShortGrass,
-                    },
-                ),
-                1,
-            )
-        } else if let Some(Tile::Room(room)) | Some(Tile::DownStair(room)) =
-            self.tiles.get(tile_pos)
-        {
-            let room = &self.rooms[*room];
-            if RandomField::new(room.seed).chance(Vec3::from(pos), room.loot_density * 0.5) {
-                match room.difficulty {
-                    0 => BlockMask::new(with_sprite(SpriteKind::DungeonChest0), 1),
-                    1 => BlockMask::new(with_sprite(SpriteKind::DungeonChest1), 1),
-                    2 => BlockMask::new(with_sprite(SpriteKind::DungeonChest2), 1),
-                    3 => BlockMask::new(with_sprite(SpriteKind::DungeonChest3), 1),
-                    4 => BlockMask::new(with_sprite(SpriteKind::DungeonChest4), 1),
-                    5 => BlockMask::new(with_sprite(SpriteKind::DungeonChest5), 1),
-                    _ => BlockMask::new(with_sprite(SpriteKind::Chest), 1),
-                }
-            } else {
-                vacant
-            }
-        } else {
-            vacant
-        };
-
-        let tunnel_height = if self.final_level { 16.0 } else { 8.0 };
-        let pillar_thickness: i32 = 4;
-
-        move |z| match self.tiles.get(tile_pos) {
-            Some(Tile::Solid) => BlockMask::nothing(),
-            Some(Tile::Tunnel) => {
-                let light_offset: i32 = 7;
-                if (dist_to_wall - wall_thickness) as i32 == 1
-                    && rtile_pos.map(|e| e % light_offset == 0).reduce_bitxor()
-                    && z == 1
-                {
-                    let ori =
-                        Floor::relative_ori(rpos, self.nearest_wall(rpos).unwrap_or_default());
-                    let furniture = SpriteKind::WallSconce;
-                    BlockMask::new(Block::air(furniture).with_ori(ori).unwrap(), 1)
-                } else if dist_to_wall >= wall_thickness
-                    && (z as f32) < tunnel_height * (1.0 - tunnel_dist.powi(4))
-                {
-                    if z == 0 { floor_sprite } else { vacant }
-                } else {
-                    BlockMask::nothing()
-                }
-            },
-            Some(Tile::Room(room)) | Some(Tile::DownStair(room))
-                if dist_to_wall < wall_thickness
-                    || z as f32
-                        >= self.rooms[*room].height as f32 * (1.0 - tunnel_dist.powi(4)) =>
-            {
-                BlockMask::nothing()
-            },
-
-            Some(Tile::Room(room)) | Some(Tile::DownStair(room))
-                if self.rooms[*room]
-                    .pillars
-                    .map(|pillar_space| {
-                        tile_pos
-                            .map(|e| e.rem_euclid(pillar_space) == 0)
-                            .reduce_and()
-                            && rtile_pos.map(|e| e as f32).magnitude_squared()
-                                < (pillar_thickness as f32 + 0.5).powi(2)
-                    })
-                    .unwrap_or(false) =>
-            {
-                if z == 1 && rtile_pos.product() == 0 && rtile_pos.sum().abs() == pillar_thickness {
-                    let ori = Floor::relative_ori(rtile_pos, Vec2::zero());
-                    let furniture = SpriteKind::WallSconce;
-                    BlockMask::new(Block::air(furniture).with_ori(ori).unwrap(), 1)
-                } else if z < self.rooms[*room].height
-                    && rtile_pos.map(|e| e as f32).magnitude_squared()
-                        > (pillar_thickness as f32 - 0.5).powi(2)
-                {
-                    vacant
-                } else {
-                    BlockMask::nothing()
-                }
-            }
-
-            Some(Tile::Room(_)) => {
-                let light_offset = 7;
-                if z == 0 {
-                    floor_sprite
-                } else if dist_to_wall as i32 == 4
-                    && rtile_pos.map(|e| e % light_offset == 0).reduce_bitxor()
-                    && z == 1
-                {
-                    let ori = Floor::relative_ori(
-                        rpos,
-                        self.nearest_wall(rpos).unwrap_or_else(Vec2::zero),
-                    );
-                    let furniture = SpriteKind::WallSconce;
-                    BlockMask::new(Block::air(furniture).with_ori(ori).unwrap(), 1)
-                } else {
-                    vacant
-                }
-            },
-            Some(Tile::DownStair(_)) => vacant,
-            Some(Tile::UpStair(room, kind)) => {
-                let inner_radius: f32 = 0.5;
-                let stretch = 9;
-                let block = make_staircase(
-                    kind,
-                    Vec3::new(rtile_pos.x, rtile_pos.y, z),
-                    TILE_SIZE as f32 / 2.0,
-                    inner_radius,
-                    stretch as f32,
-                    self.total_depth(),
-                );
-                let furniture = SpriteKind::WallSconce;
-                let ori = Floor::relative_ori(Vec2::zero(), rtile_pos);
-                if z < self.rooms[*room].height {
-                    block.resolve_with(vacant)
-                } else if z % stretch == 0 && rtile_pos.x == 0 && rtile_pos.y == -TILE_SIZE / 2 {
-                    BlockMask::new(Block::air(furniture).with_ori(ori).unwrap(), 1)
-                } else {
-                    make_staircase(
-                        kind,
-                        Vec3::new(rtile_pos.x, rtile_pos.y, z),
-                        TILE_SIZE as f32 / 2.0,
-                        inner_radius,
-                        stretch as f32,
-                        self.total_depth(),
-                    )
-                }
-            },
-            None => BlockMask::nothing(),
-        }
-    }
 }
 
 fn enemy_0(dynamic_rng: &mut impl Rng, entity: EntityInfo) -> EntityInfo {