diff --git a/assets/voxygen/shaders/include/cloud/regular.glsl b/assets/voxygen/shaders/include/cloud/regular.glsl
index 5bbd262112..f6b6c80d41 100644
--- a/assets/voxygen/shaders/include/cloud/regular.glsl
+++ b/assets/voxygen/shaders/include/cloud/regular.glsl
@@ -24,7 +24,7 @@ vec3 cloud_at(vec3 pos, float dist) {
     // Mist sits close to the ground in valleys (TODO: use base_alt to put it closer to water)
     float MIST_MIN = 300;
     const float MIST_FADE_HEIGHT = 250;
-    float mist = 0.00025 * pow(clamp(1.0 - (pos.z - MIST_MIN) / MIST_FADE_HEIGHT, 0.0, 1), 2) / (1.0 + pow(1.0 + dist / 20000.0, 2.0));
+    float mist = 0.0003 * pow(clamp(1.0 - (pos.z - MIST_MIN) / MIST_FADE_HEIGHT, 0.0, 1), 2) / (1.0 + pow(1.0 + dist / 20000.0, 2.0));
 
     vec3 wind_pos = vec3(pos.xy + wind_offset, pos.z);
 
diff --git a/assets/voxygen/shaders/lod-terrain-frag.glsl b/assets/voxygen/shaders/lod-terrain-frag.glsl
index 16fee17483..4e65cdbf0d 100644
--- a/assets/voxygen/shaders/lod-terrain-frag.glsl
+++ b/assets/voxygen/shaders/lod-terrain-frag.glsl
@@ -278,8 +278,8 @@ void main() {
     //   return true;
     // }
 
-    bvec3 hit_yz_xz_xy;
-    vec3 dist_yz_xz_xy;
+    //bvec3 hit_yz_xz_xy;
+    //vec3 dist_yz_xz_xy;
     /* {
         // vec3 rDotn = -f_orig_view_dir * -sides;
         // vec3 rDotn = f_orig_view_dir * sides;
@@ -301,8 +301,8 @@ void main() {
         // vec3 s = -sides * (f_pos + delta_sides - cam_pos.xyz) / (-f_orig_view_dir * -sides);
         // vec3 s = (f_pos + delta_sides - cam_pos.xyz) / -f_orig_view_dir;
         // dist_yz_xz_xy = abs(s);
-        hit_yz_xz_xy = greaterThanEqual(f_orig_view_dir * sides, vec3(0.000001));
-        dist_yz_xz_xy = abs((f_pos + delta_sides - cam_pos.xyz) / f_orig_view_dir);
+        //hit_yz_xz_xy = greaterThanEqual(f_orig_view_dir * sides, vec3(0.000001));
+        //dist_yz_xz_xy = abs((f_pos + delta_sides - cam_pos.xyz) / f_orig_view_dir);
     }
 
     // vec3 xy_point = f_pos, xz_point = f_pos, yz_point = f_pos;
@@ -310,11 +310,12 @@ void main() {
     // bool hit_xz = (/*ao_xy < 1.0 || ao_yz < 1.0*//*min(f_ao_vec.x, f_ao_vec.z)*//*f_ao_vec.y < 1.0*/true/*min(corner_xy.y, corner_yz.x) < 1.0*//*min(corner_xz.x, corner_xz.y) < 1.0*/) && IntersectRayPlane(cam_pos.xyz, -f_orig_view_dir, vec3(f_pos.x, f_pos.y + delta_sides.y/* - sides.y*/, f_pos.z), vec3(0.0, -sides.y, 0.0), xz_point);
     // bool hit_yz = (/*ao_xy < 1.0 || ao_xz < 1.0*//*min(f_ao_vec.y, f_ao_vec.z) < 1.0*//*f_ao_vec.x < 1.0*/true/*true*//*min(corner_xy.x, corner_xz.x) < 1.0*//*min(corner_yz.x, corner_yz.y) < 1.0*/) && IntersectRayPlane(cam_pos.xyz, -f_orig_view_dir, vec3(f_pos.x + delta_sides.x/* - sides.x*/, f_pos.y, f_pos.z), vec3(-sides.x, 0.0, 0.0), yz_point);
     // float xy_dist = distance(cam_pos.xyz, xy_point), xz_dist = distance(cam_pos.xyz, xz_point), yz_dist = distance(cam_pos.xyz, yz_point);
-    bool hit_xy = hit_yz_xz_xy.z, hit_xz = hit_yz_xz_xy.y, hit_yz = hit_yz_xz_xy.x;
-    float xy_dist = dist_yz_xz_xy.z, xz_dist = dist_yz_xz_xy.y, yz_dist = dist_yz_xz_xy.x;
+    //bool hit_xy = hit_yz_xz_xy.z, hit_xz = hit_yz_xz_xy.y, hit_yz = hit_yz_xz_xy.x;
+    //float xy_dist = dist_yz_xz_xy.z, xz_dist = dist_yz_xz_xy.y, yz_dist = dist_yz_xz_xy.x;
     // hit_xy = hit_xy && distance(f_pos.xy + delta_sides.xy, xy_point.xy) <= 1.0;
     // hit_xz = hit_xz && distance(f_pos.xz + delta_sides.xz, xz_point.xz) <= 1.0;
     // hit_yz = hit_yz && distance(f_pos.yz + delta_sides.yz, yz_point.yz) <= 1.0;
+    /*
     vec3 voxel_norm =
         hit_yz ?
             hit_xz ?
@@ -325,8 +326,10 @@ void main() {
             hit_xz ?
                 hit_xy ? xz_dist < xy_dist ? vec3(0.0, sides.y, 0.0) : vec3(0.0, 0.0, sides.z) : vec3(0.0, sides.y, 0.0) :
                 hit_xy ? vec3(0.0, 0.0, sides.z) : vec3(0.0, 0.0, 0.0);
+    */
+    vec3 voxel_norm;
 
-    const float VOXELIZE_DIST = 2500;
+    const float VOXELIZE_DIST = 2000;
     float voxelize_factor = clamp(1.0 - (distance(focus_pos.xy, f_pos.xy) - view_distance.x) / VOXELIZE_DIST, 0, 1);
     vec3 cam_dir = normalize(cam_pos.xyz - f_pos.xyz);
     vec3 side_norm = normalize(vec3(my_norm.xy, 0));
diff --git a/client/src/lib.rs b/client/src/lib.rs
index 231a2b6e36..a2124406d6 100644
--- a/client/src/lib.rs
+++ b/client/src/lib.rs
@@ -29,6 +29,7 @@ use common::{
         ClientType, DisconnectReason, InviteAnswer, Notification, PingMsg, PlayerInfo,
         PlayerListUpdate, PresenceKind, RegisterError, ServerGeneral, ServerInfo, ServerInit,
         ServerRegisterAnswer, MAX_BYTES_CHAT_MSG,
+        world_msg::SiteInfo,
     },
     outcome::Outcome,
     recipe::RecipeBook,
@@ -101,6 +102,7 @@ pub struct Client {
     pub world_map: (Arc<DynamicImage>, Vec2<u16>, Vec2<f32>),
     pub player_list: HashMap<Uid, PlayerInfo>,
     pub character_list: CharacterList,
+    sites: Vec<SiteInfo>,
     recipe_book: RecipeBook,
     available_recipes: HashSet<String>,
 
@@ -191,6 +193,7 @@ impl Client {
             lod_alt,
             lod_horizon,
             world_map,
+            sites,
             recipe_book,
             max_group_size,
             client_timeout,
@@ -255,7 +258,7 @@ impl Client {
                 let horizons = [unzip_horizons(&west), unzip_horizons(&east)];
 
                 // Redraw map (with shadows this time).
-                let mut world_map = vec![0u32; rgba.len()];
+                let mut world_map_rgba = vec![0u32; rgba.len()];
                 let mut map_config = common::terrain::map::MapConfig::orthographic(
                     map_size_lg,
                     core::ops::RangeInclusive::new(0.0, max_height),
@@ -322,13 +325,13 @@ impl Client {
                         })
                     },
                     |pos, (r, g, b, a)| {
-                        world_map[pos.y * map_size.x as usize + pos.x] =
+                        world_map_rgba[pos.y * map_size.x as usize + pos.x] =
                             u32::from_le_bytes([r, g, b, a]);
                     },
                 );
                 ping_stream.send(PingMsg::Ping)?;
                 let make_raw = |rgba| -> Result<_, Error> {
-                    let mut raw = vec![0u8; 4 * world_map.len()];
+                    let mut raw = vec![0u8; 4 * world_map_rgba.len()];
                     LittleEndian::write_u32_into(rgba, &mut raw);
                     Ok(Arc::new(
                         image::DynamicImage::ImageRgba8({
@@ -345,7 +348,7 @@ impl Client {
                 ping_stream.send(PingMsg::Ping)?;
                 let lod_base = rgba;
                 let lod_alt = alt;
-                let world_map = make_raw(&world_map)?;
+                let world_map_img = make_raw(&world_map_rgba)?;
                 let horizons = (west.0, west.1, east.0, east.1)
                     .into_par_iter()
                     .map(|(wa, wh, ea, eh)| u32::from_le_bytes([wa, wh, ea, eh]))
@@ -360,7 +363,8 @@ impl Client {
                     lod_base,
                     lod_alt,
                     lod_horizon,
-                    (world_map, map_size, map_bounds),
+                    (world_map_img, map_size, map_bounds),
+                    world_map.sites,
                     recipe_book,
                     max_group_size,
                     client_timeout,
@@ -389,6 +393,7 @@ impl Client {
             lod_horizon,
             player_list: HashMap::new(),
             character_list: CharacterList::default(),
+            sites,
             recipe_book,
             available_recipes: HashSet::default(),
 
@@ -640,6 +645,11 @@ impl Client {
             .collect();
     }
 
+    /// Unstable, likely to be removed in a future release
+    pub fn sites(&self) -> &[SiteInfo] {
+        &self.sites
+    }
+
     pub fn enable_lantern(&mut self) {
         self.send_msg(ClientGeneral::ControlEvent(ControlEvent::EnableLantern));
     }
diff --git a/common/src/msg/world_msg.rs b/common/src/msg/world_msg.rs
index c19c855166..6126ed9d06 100644
--- a/common/src/msg/world_msg.rs
+++ b/common/src/msg/world_msg.rs
@@ -120,4 +120,20 @@ pub struct WorldMapMsg {
     /// angles, or that we don't need as much precision as we currently have
     /// (256 possible angles).
     pub horizons: [(Vec<u8>, Vec<u8>); 2],
+    pub sites: Vec<SiteInfo>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct SiteInfo {
+    pub kind: SiteKind,
+    pub wpos: Vec2<i32>,
+    pub name: Option<String>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+#[repr(u8)]
+pub enum SiteKind {
+    Town,
+    Dungeon,
+    Castle,
 }
diff --git a/server/src/lib.rs b/server/src/lib.rs
index 99f9e73c67..26048289c0 100644
--- a/server/src/lib.rs
+++ b/server/src/lib.rs
@@ -53,6 +53,7 @@ use common::{
     event::{EventBus, ServerEvent},
     msg::{
         ClientType, DisconnectReason, ServerGeneral, ServerInfo, ServerInit, ServerMsg, WorldMapMsg,
+        world_msg::{SiteInfo, SiteKind},
     },
     outcome::Outcome,
     recipe::default_recipe_book,
@@ -83,7 +84,6 @@ use uvth::{ThreadPool, ThreadPoolBuilder};
 use vek::*;
 #[cfg(feature = "worldgen")]
 use world::{
-    civ::SiteKind,
     sim::{FileOpts, WorldOpts, DEFAULT_WORLD_MAP},
     IndexOwned, World,
 };
@@ -256,6 +256,7 @@ impl Server {
             horizons: [(vec![0], vec![0]), (vec![0], vec![0])],
             sea_level: 0.0,
             alt: vec![30],
+            sites: Vec::new(),
         };
 
         #[cfg(feature = "worldgen")]
@@ -272,7 +273,7 @@ impl Server {
             let spawn_chunk = world
                 .civs()
                 .sites()
-                .filter(|site| matches!(site.kind, SiteKind::Settlement))
+                .filter(|site| matches!(site.kind, world::civ::SiteKind::Settlement))
                 .map(|site| site.center)
                 .min_by_key(|site_pos| site_pos.distance_squared(center_chunk))
                 .unwrap_or(center_chunk);
diff --git a/server/src/rtsim/mod.rs b/server/src/rtsim/mod.rs
index 81cd7e82a9..2aa5cf0ef3 100644
--- a/server/src/rtsim/mod.rs
+++ b/server/src/rtsim/mod.rs
@@ -55,12 +55,12 @@ impl RtSim {
     }
 
     pub fn assimilate_entity(&mut self, entity: RtSimId) {
-        tracing::info!("Assimilated rtsim entity {}", entity);
+        // tracing::info!("Assimilated rtsim entity {}", entity);
         self.entities.get_mut(entity).map(|e| e.is_loaded = false);
     }
 
     pub fn reify_entity(&mut self, entity: RtSimId) {
-        tracing::info!("Reified rtsim entity {}", entity);
+        // tracing::info!("Reified rtsim entity {}", entity);
         self.entities.get_mut(entity).map(|e| e.is_loaded = true);
     }
 
@@ -69,7 +69,7 @@ impl RtSim {
     }
 
     pub fn destroy_entity(&mut self, entity: RtSimId) {
-        tracing::info!("Destroyed rtsim entity {}", entity);
+        // tracing::info!("Destroyed rtsim entity {}", entity);
         self.entities.remove(entity);
     }
 }
@@ -102,7 +102,7 @@ pub fn init(state: &mut State, world: &world::World) {
             brain: Default::default(),
         });
 
-        tracing::info!("Spawned rtsim NPC {} at {:?}", id, pos);
+        // tracing::info!("Spawned rtsim NPC {} at {:?}", id, pos);
     }
 
     state.ecs_mut().insert(rtsim);
diff --git a/voxygen/src/hud/img_ids.rs b/voxygen/src/hud/img_ids.rs
index 48a42cd860..30a2940e64 100644
--- a/voxygen/src/hud/img_ids.rs
+++ b/voxygen/src/hud/img_ids.rs
@@ -193,6 +193,8 @@ image_ids! {
         mmap_minus: "voxygen.element.buttons.min_plus.mmap_button-min",
         mmap_minus_hover: "voxygen.element.buttons.min_plus.mmap_button-min_hover",
         mmap_minus_press: "voxygen.element.buttons.min_plus.mmap_button-min_press",
+        mmap_site_town: "voxygen.element.map.town",
+        mmap_site_dungeon: "voxygen.element.map.dungeon",
 
         // Window Parts
         window_3: "voxygen.element.frames.window_3",
diff --git a/voxygen/src/hud/minimap.rs b/voxygen/src/hud/minimap.rs
index d897fa3074..18ebb4213c 100644
--- a/voxygen/src/hud/minimap.rs
+++ b/voxygen/src/hud/minimap.rs
@@ -4,7 +4,7 @@ use super::{
 };
 use crate::ui::{fonts::Fonts, img_ids};
 use client::{self, Client};
-use common::{comp, terrain::TerrainChunkSize, vol::RectVolSize};
+use common::{comp, terrain::TerrainChunkSize, vol::RectVolSize, msg::world_msg::SiteKind};
 use conrod_core::{
     color, position,
     widget::{self, Button, Image, Rectangle, Text},
@@ -28,6 +28,7 @@ widget_ids! {
         mmap_east,
         mmap_south,
         mmap_west,
+        mmap_site_icons[],
     }
 }
 
@@ -222,6 +223,41 @@ impl<'a> Widget for MiniMap<'a> {
                 .parent(ui.window)
                 .set(state.ids.indicator, ui);
 
+            // Map icons
+            if state.ids.mmap_site_icons.len() < self.client.sites().len() {
+                state.update(|state| {
+                    state.ids.mmap_site_icons.resize(
+                        self.client.sites().len(),
+                        &mut ui.widget_id_generator(),
+                    )
+                });
+            }
+            for (i, site) in self.client.sites().iter().enumerate() {
+                let rwpos = site.wpos.map(|e| e as f32) - player_pos;
+                let rcpos = rwpos.map2(TerrainChunkSize::RECT_SIZE, |e, sz| e / sz as f32) * state.zoom as f32 / 4.0;
+                let rpos = Vec2::unit_x().rotated_z(self.ori.x) * rcpos.x
+                    + Vec2::unit_y().rotated_z(self.ori.x) * rcpos.y;
+
+                // TODO: Why does this require the magic constant 0.73? This this related to scaling issues?
+                if rpos.map2(map_size, |e, sz| e.abs() > sz as f32 / 0.73 / 2.0).reduce_or() {
+                    continue;
+                }
+
+                Image::new(match &site.kind {
+                    SiteKind::Town => self.imgs.mmap_site_town,
+                    SiteKind::Dungeon => self.imgs.mmap_site_dungeon,
+                    SiteKind::Castle => continue,
+                })
+                    .x_y_position_relative_to(
+                        state.ids.grid,
+                        position::Relative::Scalar(rpos.x as f64),
+                        position::Relative::Scalar(rpos.y as f64),
+                    )
+                    .floating(true)
+                    .parent(ui.window)
+                    .set(state.ids.mmap_site_icons[i], ui);
+            }
+
             // Compass directions
             let dirs = [
                 (Vec2::new(0.0, 1.0), state.ids.mmap_north, "N", true),
diff --git a/world/src/lib.rs b/world/src/lib.rs
index 0bca796afc..944653450f 100644
--- a/world/src/lib.rs
+++ b/world/src/lib.rs
@@ -41,7 +41,7 @@ use crate::{
 };
 use common::{
     generation::{ChunkSupplement, EntityInfo},
-    msg::WorldMapMsg,
+    msg::{WorldMapMsg, world_msg},
     terrain::{Block, BlockKind, SpriteKind, TerrainChunk, TerrainChunkMeta, TerrainChunkSize},
     vol::{ReadVol, RectVolSize, WriteVol},
 };
@@ -90,7 +90,26 @@ impl World {
         // TODO
     }
 
-    pub fn get_map_data(&self, index: IndexRef) -> WorldMapMsg { self.sim.get_map(index) }
+    pub fn get_map_data(&self, index: IndexRef) -> WorldMapMsg {
+        WorldMapMsg {
+            sites: self.civs().sites
+                .iter()
+                .map(|(_, site)| {
+                    world_msg::SiteInfo {
+                        // TODO: Probably unify these, at some point
+                        kind: match &site.kind {
+                            civ::SiteKind::Settlement => world_msg::SiteKind::Town,
+                            civ::SiteKind::Dungeon => world_msg::SiteKind::Dungeon,
+                            civ::SiteKind::Castle => world_msg::SiteKind::Castle,
+                        },
+                        wpos: site.center * TerrainChunkSize::RECT_SIZE.map(|e| e as i32),
+                        name: None,
+                    }
+                })
+                .collect(),
+            ..self.sim.get_map(index)
+        }
+    }
 
     pub fn sample_columns(
         &self,
diff --git a/world/src/sim/map.rs b/world/src/sim/map.rs
index 02254e01a1..f71888bfad 100644
--- a/world/src/sim/map.rs
+++ b/world/src/sim/map.rs
@@ -247,9 +247,9 @@ pub fn sample_pos(
         ),
     };
     // TODO: Make principled.
-    let rgb = if near_site {
+    let rgb = /*if near_site {
         Rgb::new(0x57, 0x39, 0x33)
-    } else if is_path {
+    } else*/ if is_path {
         Rgb::new(0x37, 0x29, 0x23)
     } else if is_cave {
         Rgb::new(0x37, 0x37, 0x37)
diff --git a/world/src/sim/mod.rs b/world/src/sim/mod.rs
index 3d49b60c92..0339efc3a9 100644
--- a/world/src/sim/mod.rs
+++ b/world/src/sim/mod.rs
@@ -1501,6 +1501,7 @@ impl WorldSim {
             rgba: v,
             alt: alts,
             horizons,
+            sites: Vec::new(), // Will be substituted later
         }
     }