<commit_before>//! Utilities for text input support
//!
//! This module provides you with utilities to handle text input from multiple text input clients,
//! it must be used in conjunction with the input method module to work.
//! See the input method module for more information.
//!
//! ## How to use
//! ```
//! # extern crate wayland_server;
//! # #[macro_use] extern crate smithay;
//! # use smithay::wayland::compositor::compositor_init;
//!
//! use std::borrow::BorrowMut;
//!
//! use wayland_server::protocol::wl_surface::WlSurface;
//! use smithay::wayland::seat::{Seat};
//! use smithay::wayland::text_input::{init_text_input_manager_global, TextInputSeatTrait, TextInputHandle};
//!
//! # let mut display = wayland_server::Display::new();
//! # compositor_init(&mut display, |_, _| {}, None);
//! // First we need a regular seat
//! let (seat, seat_global) = Seat::new(
//!     &mut display,
//!     "seat-0".into(),
//!     None
//! );
//!
//! // Insert the manager into your event loop
//! init_text_input_manager_global(&mut display.borrow_mut());
//!
//! // Add the input method handle to the seat
//! let text_input = seat.add_text_input();
//! ```
//! ## Run usage
//! // Once a handle has been added to the seat you need to use to use the set_focus function to
//! // tell the text input handle which surface should receive text input.
//!

use std::{cell::RefCell, convert::TryInto, rc::Rc};

use wayland_protocols::unstable::text_input::v3::server::{
    zwp_text_input_manager_v3::{self, ZwpTextInputManagerV3},
    zwp_text_input_v3::{self, ZwpTextInputV3},
};
use wayland_server::{protocol::wl_surface::WlSurface, Display, Filter, Global, Main};

use crate::{wayland::seat::Seat, utils::{Logical, Point}};

use super::input_method::InputMethodHandle;

const TEXT_INPUT_VERSION: u32 = 1;

#[derive(Clone, Debug)]
struct Instance {
    handle: Main<ZwpTextInputV3>,
    serial: u32,
    x: i32,
    y: i32,
    width: i32,
    height: i32,
    l_x: i32,
    l_y: i32
}

/// Contains all the text input instances
#[derive(Default, Clone, Debug)]
struct TextInput {
    instances: Vec<Instance>,
    focus: Option<WlSurface>,
    old_focus: Option<WlSurface>,
}

impl TextInput {
    fn set_focus(&mut self, focus: Option<&WlSurface>) {
        let same = self
            .focus
            .as_ref()
            .and_then(|f| focus.map(|s| s.as_ref().equals(f.as_ref())))
            .unwrap_or(false);
        if !same {
            if let Some(focus) = self.focus.as_ref() {
                if let Some(old_instance) = self
                    .instances
                    .iter()
                    .find(|i| i.handle.as_ref().same_client_as(self.focus.as_ref().unwrap().as_ref()))
                {
                    old_instance.handle.leave(focus);
                    self.old_focus = Some(focus.clone());
                }
            }
            self.focus = None;
            // set new focus
            self.focus = focus.cloned();

            if self.old_focus.is_none() {
                if let Some(focus) = &self.focus {
                    if let Some(instance) = &self
                        .instances
                        .iter()
                        .find(|i| i.handle.as_ref().same_client_as(focus.as_ref()))
                    {
                        instance.handle.enter(focus);
                    }
                }
            }
        }
    }

    fn set_point(&mut self, point: &Point<i32, Logical>){
        if let Some(instance) = self.focused_text_input(){
            instance.l_x = point.x;
            instance.l_y = point.y;
        }
    }

    fn increment(&mut self){
        if let Some(old_focus) = &self.old_focus {
            if let Some(old_instance) = self
                .instances
                .iter_mut()
                .find(|i| i.handle.as_ref().same_client_as(old_focus.as_ref()))
            {
                old_instance.serial += 1;
                self.old_focus = None;
                if let Some(focus) = &self.focus {
                    if let Some(instance) = &self
                        .instances
                        .iter()
                        .find(|i| i.handle.as_ref().same_client_as(focus.as_ref()))
                    {
                        instance.handle.enter(focus);
                    }
                }
            }
        } else if let Some(focus) = &self.focus {
            if let Some(instance) = self.instances
                .iter_mut()
                .find(|i| i.handle.as_ref().same_client_as(focus.as_ref()))
            {
                instance.serial += 1;
            }
        }
    }

    fn focused_text_input(&mut self) -> Option<&mut Instance> {
        if let Some(old_focus) = &self.old_focus {
            self.instances
                .iter_mut()
                .find(|i| i.handle.as_ref().same_client_as(old_focus.as_ref()))
        } else if let Some(focus) = &self.focus {
            self.instances
                .iter_mut()
                .find(|i| i.handle.as_ref().same_client_as(focus.as_ref()))
        } else {
            None
        }
    }
}

///Handle to a text input
#[derive(Default, Debug, Clone)]
pub struct TextInputHandle {
    inner: Rc<RefCell<TextInput>>,
}

impl TextInputHandle {
    fn add_instance(&self, instance: Instance) {
        let mut inner = self.inner.borrow_mut();
        inner.instances.push(instance);
    }

    fn add_coordinates(&self, x: i32, y:i32, width: i32, height: i32) {
        let mut inner = self.inner.borrow_mut();
        let focused_instance = inner.focused_text_input();
        if let Some(instance) = focused_instance{
            instance.x = x;
            instance.y = y;
            instance.width = width;
            instance.height = height;
        }
    }

    /// Used to access the relative location of an input popup surface
    pub fn coordinates(&self) ->(i32, i32, i32, i32) {
        let mut inner = self.inner.borrow_mut();
        let focused_instance = inner.focused_text_input();
        if let Some(instance) = focused_instance {
            (instance.x+instance.l_x, instance.y+instance.l_y, instance.width, instance.height)
        } else {
            (0, 0, 0, 0)
        }
    }

    /// Activates a text input when a surface is focused and deactivates it when
    /// the current surface goes out of focus.
    pub fn set_focus(&mut self, focus: Option<&WlSurface>, location: Option<&Point<i32, Logical>>) {
        let mut inner = self.inner.borrow_mut();
        inner.set_focus(focus);
        if let Some(point) = location{
            inner.set_point(point);
        }
    }

    /// Used to access the Main handle from an input method
    pub fn handle(&self) -> Option<Main<ZwpTextInputV3>> {
        self.inner.borrow_mut().focused_text_input().map(|i| i.handle.clone())
    }

    /// Used to access serial for each individual text input.
    /// It is the compositors responsibility to increment a separate serial on each
    /// text input.
    pub fn serial(&self) -> u32 {
        self.inner.borrow_mut().focused_text_input().map(|i| i.serial)
            .expect("Got a message from a text input that does not exist!")
    }

    fn increment_serial(&mut self) {
        let mut inner = self.inner.borrow_mut();
        inner.increment();
    }
}

/// Extend [Seat] with text input specific functionality
pub trait TextInputSeatTrait {
    /// Get text input associated with this seat
    fn add_text_input(&self) -> TextInputHandle;
}

impl TextInputSeatTrait for Seat {
    fn add_text_input(&self) -> TextInputHandle {
        let user_data = self.user_data();
        user_data.insert_if_missing(TextInputHandle::default);
        user_data.get::<TextInputHandle>().unwrap().clone()
    }
}

/// Initialize a text input global
pub fn init_text_input_manager_global(display: &mut Display) -> Global<ZwpTextInputManagerV3> {
    display.create_global::<ZwpTextInputManagerV3, _>(
        TEXT_INPUT_VERSION,
        Filter::new(
            move |(manager, _version): (Main<ZwpTextInputManagerV3>, u32), _, _| {
                manager.quick_assign(|_manager, req, _| match req {
                    zwp_text_input_manager_v3::Request::GetTextInput { seat, id } => {
                        let seat = Seat::from_resource(&seat).unwrap();
                        let user_data = seat.user_data();
                        user_data.insert_if_missing(TextInputHandle::default);
                        let mut ti = user_data.get::<TextInputHandle>().unwrap().clone();
                        ti.add_instance(Instance {
                            handle: id.clone(),
                            serial: 0,
                            x: 0,
                            y: 0,
                            width: 0,
                            height: 0,
                            l_x: 0,
                            l_y: 0
                        });
                        let input_method = user_data.get::<InputMethodHandle>().unwrap().clone();
                        let text_input_handle = ti.clone();
                        id.quick_assign(move |_text_input, req, _| match req {
                            zwp_text_input_v3::Request::Enable => {
                                if let Some(input_method) = input_method.handle() {
                                    input_method.activate();
                                }
                            }
                            zwp_text_input_v3::Request::Disable => {
                                if let Some(input_method) = input_method.handle() {
                                    input_method.deactivate();
                                }
                            }
                            zwp_text_input_v3::Request::SetSurroundingText { text, cursor, anchor } => {
                                if let Some(input_method) = input_method.handle() {
                                    input_method.surrounding_text(
                                        text,
                                        cursor.try_into().unwrap(),
                                        anchor.try_into().unwrap(),
                                    );
                                }
                            }
                            zwp_text_input_v3::Request::SetContentType { hint, purpose } => {
                                if let Some(input_method) = input_method.handle() {
                                    input_method.content_type(hint, purpose);
                                }
                            }
                            zwp_text_input_v3::Request::SetTextChangeCause { cause } => {
                                if let Some(input_method) = input_method.handle() {
                                    input_method.text_change_cause(cause);
                                }
                            }
                            zwp_text_input_v3::Request::SetCursorRectangle { x, y, width, height } => {
                                ti.add_coordinates(x, y, width, height);
                                if let Some(popup_surface) = input_method.popup_surface_handle() {
                                    popup_surface.text_input_rectangle(x, y, width, height);
                                }
                            }
                            zwp_text_input_v3::Request::Commit => {
                                if let Some(input_method) = input_method.handle() {
                                    ti.increment_serial();
                                    input_method.done();
                                }
                            }
                            zwp_text_input_v3::Request::Destroy => {}
                            _ => {}
                        });
                        id.assign_destructor(Filter::new(move |text_input: ZwpTextInputV3, _, _| {
                            text_input_handle.inner
                                .borrow_mut()
                                .instances
                                .retain(|ti| !ti.handle.as_ref().equals(text_input.as_ref()))
                        }));
                    }
                    zwp_text_input_manager_v3::Request::Destroy => {
                        //Nothing to do
                    }
                    _ => {}
                })
            },
        ),
    )
}
<commit_msg>Make serial incrementing not rely on an input method<commit_after>//! Utilities for text input support
//!
//! This module provides you with utilities to handle text input from multiple text input clients,
//! it must be used in conjunction with the input method module to work.
//! See the input method module for more information.
//!
//! ## How to use
//! ```
//! # extern crate wayland_server;
//! # #[macro_use] extern crate smithay;
//! # use smithay::wayland::compositor::compositor_init;
//!
//! use std::borrow::BorrowMut;
//!
//! use wayland_server::protocol::wl_surface::WlSurface;
//! use smithay::wayland::seat::{Seat};
//! use smithay::wayland::text_input::{init_text_input_manager_global, TextInputSeatTrait, TextInputHandle};
//!
//! # let mut display = wayland_server::Display::new();
//! # compositor_init(&mut display, |_, _| {}, None);
//! // First we need a regular seat
//! let (seat, seat_global) = Seat::new(
//!     &mut display,
//!     "seat-0".into(),
//!     None
//! );
//!
//! // Insert the manager into your event loop
//! init_text_input_manager_global(&mut display.borrow_mut());
//!
//! // Add the input method handle to the seat
//! let text_input = seat.add_text_input();
//! ```
//! ## Run usage
//! // Once a handle has been added to the seat you need to use to use the set_focus function to
//! // tell the text input handle which surface should receive text input.
//!

use std::{cell::RefCell, convert::TryInto, rc::Rc};

use wayland_protocols::unstable::text_input::v3::server::{
    zwp_text_input_manager_v3::{self, ZwpTextInputManagerV3},
    zwp_text_input_v3::{self, ZwpTextInputV3},
};
use wayland_server::{protocol::wl_surface::WlSurface, Display, Filter, Global, Main};

use crate::{wayland::seat::Seat, utils::{Logical, Point}};

use super::input_method::InputMethodHandle;

const TEXT_INPUT_VERSION: u32 = 1;

#[derive(Clone, Debug)]
struct Instance {
    handle: Main<ZwpTextInputV3>,
    serial: u32,
    x: i32,
    y: i32,
    width: i32,
    height: i32,
    l_x: i32,
    l_y: i32
}

/// Contains all the text input instances
#[derive(Default, Clone, Debug)]
struct TextInput {
    instances: Vec<Instance>,
    focus: Option<WlSurface>,
    old_focus: Option<WlSurface>,
}

impl TextInput {
    fn set_focus(&mut self, focus: Option<&WlSurface>) {
        let same = self
            .focus
            .as_ref()
            .and_then(|f| focus.map(|s| s.as_ref().equals(f.as_ref())))
            .unwrap_or(false);
        if !same {
            if let Some(focus) = self.focus.as_ref() {
                if let Some(old_instance) = self
                    .instances
                    .iter()
                    .find(|i| i.handle.as_ref().same_client_as(self.focus.as_ref().unwrap().as_ref()))
                {
                    old_instance.handle.leave(focus);
                    self.old_focus = Some(focus.clone());
                }
            }
            self.focus = None;
            // set new focus
            self.focus = focus.cloned();

            if self.old_focus.is_none() {
                if let Some(focus) = &self.focus {
                    if let Some(instance) = &self
                        .instances
                        .iter()
                        .find(|i| i.handle.as_ref().same_client_as(focus.as_ref()))
                    {
                        instance.handle.enter(focus);
                    }
                }
            }
        }
    }

    fn set_point(&mut self, point: &Point<i32, Logical>){
        if let Some(instance) = self.focused_text_input(){
            instance.l_x = point.x;
            instance.l_y = point.y;
        }
    }

    fn increment(&mut self){
        if let Some(old_focus) = &self.old_focus {
            if let Some(old_instance) = self
                .instances
                .iter_mut()
                .find(|i| i.handle.as_ref().same_client_as(old_focus.as_ref()))
            {
                old_instance.serial += 1;
                self.old_focus = None;
                if let Some(focus) = &self.focus {
                    if let Some(instance) = &self
                        .instances
                        .iter()
                        .find(|i| i.handle.as_ref().same_client_as(focus.as_ref()))
                    {
                        instance.handle.enter(focus);
                    }
                }
            }
        } else if let Some(focus) = &self.focus {
            if let Some(instance) = self.instances
                .iter_mut()
                .find(|i| i.handle.as_ref().same_client_as(focus.as_ref()))
            {
                instance.serial += 1;
            }
        }
    }

    fn focused_text_input(&mut self) -> Option<&mut Instance> {
        if let Some(old_focus) = &self.old_focus {
            self.instances
                .iter_mut()
                .find(|i| i.handle.as_ref().same_client_as(old_focus.as_ref()))
        } else if let Some(focus) = &self.focus {
            self.instances
                .iter_mut()
                .find(|i| i.handle.as_ref().same_client_as(focus.as_ref()))
        } else {
            None
        }
    }
}

///Handle to a text input
#[derive(Default, Debug, Clone)]
pub struct TextInputHandle {
    inner: Rc<RefCell<TextInput>>,
}

impl TextInputHandle {
    fn add_instance(&self, instance: Instance) {
        let mut inner = self.inner.borrow_mut();
        inner.instances.push(instance);
    }

    fn add_coordinates(&self, x: i32, y:i32, width: i32, height: i32) {
        let mut inner = self.inner.borrow_mut();
        let focused_instance = inner.focused_text_input();
        if let Some(instance) = focused_instance{
            instance.x = x;
            instance.y = y;
            instance.width = width;
            instance.height = height;
        }
    }

    /// Used to access the relative location of an input popup surface
    pub fn coordinates(&self) ->(i32, i32, i32, i32) {
        let mut inner = self.inner.borrow_mut();
        let focused_instance = inner.focused_text_input();
        if let Some(instance) = focused_instance {
            (instance.x+instance.l_x, instance.y+instance.l_y, instance.width, instance.height)
        } else {
            (0, 0, 0, 0)
        }
    }

    /// Activates a text input when a surface is focused and deactivates it when
    /// the current surface goes out of focus.
    pub fn set_focus(&mut self, focus: Option<&WlSurface>, location: Option<&Point<i32, Logical>>) {
        let mut inner = self.inner.borrow_mut();
        inner.set_focus(focus);
        if let Some(point) = location{
            inner.set_point(point);
        }
    }

    /// Used to access the Main handle from an input method
    pub fn handle(&self) -> Option<Main<ZwpTextInputV3>> {
        self.inner.borrow_mut().focused_text_input().map(|i| i.handle.clone())
    }

    /// Used to access serial for each individual text input.
    /// It is the compositors responsibility to increment a separate serial on each
    /// text input.
    pub fn serial(&self) -> u32 {
        self.inner.borrow_mut().focused_text_input().map(|i| i.serial)
            .expect("Got a message from a text input that does not exist!")
    }

    fn increment_serial(&mut self) {
        let mut inner = self.inner.borrow_mut();
        inner.increment();
    }
}

/// Extend [Seat] with text input specific functionality
pub trait TextInputSeatTrait {
    /// Get text input associated with this seat
    fn add_text_input(&self) -> TextInputHandle;
}

impl TextInputSeatTrait for Seat {
    fn add_text_input(&self) -> TextInputHandle {
        let user_data = self.user_data();
        user_data.insert_if_missing(TextInputHandle::default);
        user_data.get::<TextInputHandle>().unwrap().clone()
    }
}

/// Initialize a text input global
pub fn init_text_input_manager_global(display: &mut Display) -> Global<ZwpTextInputManagerV3> {
    display.create_global::<ZwpTextInputManagerV3, _>(
        TEXT_INPUT_VERSION,
        Filter::new(
            move |(manager, _version): (Main<ZwpTextInputManagerV3>, u32), _, _| {
                manager.quick_assign(|_manager, req, _| match req {
                    zwp_text_input_manager_v3::Request::GetTextInput { seat, id } => {
                        let seat = Seat::from_resource(&seat).unwrap();
                        let user_data = seat.user_data();
                        user_data.insert_if_missing(TextInputHandle::default);
                        let mut ti = user_data.get::<TextInputHandle>().unwrap().clone();
                        ti.add_instance(Instance {
                            handle: id.clone(),
                            serial: 0,
                            x: 0,
                            y: 0,
                            width: 0,
                            height: 0,
                            l_x: 0,
                            l_y: 0
                        });
                        let input_method = user_data.get::<InputMethodHandle>().unwrap().clone();
                        let text_input_handle = ti.clone();
                        id.quick_assign(move |_text_input, req, _| match req {
                            zwp_text_input_v3::Request::Enable => {
                                if let Some(input_method) = input_method.handle() {
                                    input_method.activate();
                                }
                            }
                            zwp_text_input_v3::Request::Disable => {
                                if let Some(input_method) = input_method.handle() {
                                    input_method.deactivate();
                                }
                            }
                            zwp_text_input_v3::Request::SetSurroundingText { text, cursor, anchor } => {
                                if let Some(input_method) = input_method.handle() {
                                    input_method.surrounding_text(
                                        text,
                                        cursor.try_into().unwrap(),
                                        anchor.try_into().unwrap(),
                                    );
                                }
                            }
                            zwp_text_input_v3::Request::SetContentType { hint, purpose } => {
                                if let Some(input_method) = input_method.handle() {
                                    input_method.content_type(hint, purpose);
                                }
                            }
                            zwp_text_input_v3::Request::SetTextChangeCause { cause } => {
                                if let Some(input_method) = input_method.handle() {
                                    input_method.text_change_cause(cause);
                                }
                            }
                            zwp_text_input_v3::Request::SetCursorRectangle { x, y, width, height } => {
                                ti.add_coordinates(x, y, width, height);
                                if let Some(popup_surface) = input_method.popup_surface_handle() {
                                    popup_surface.text_input_rectangle(x, y, width, height);
                                }
                            }
                            zwp_text_input_v3::Request::Commit => {
                                ti.increment_serial();
                                if let Some(input_method) = input_method.handle() {
                                    input_method.done();
                                }
                            }
                            zwp_text_input_v3::Request::Destroy => {}
                            _ => {}
                        });
                        id.assign_destructor(Filter::new(move |text_input: ZwpTextInputV3, _, _| {
                            text_input_handle.inner
                                .borrow_mut()
                                .instances
                                .retain(|ti| !ti.handle.as_ref().equals(text_input.as_ref()))
                        }));
                    }
                    zwp_text_input_manager_v3::Request::Destroy => {
                        //Nothing to do
                    }
                    _ => {}
                })
            },
        ),
    )
}
<|endoftext|>


<commit_before>use crate::location::Location;
use crate::map::Map;
use crate::spec::{self, EntitySpawn};
use crate::terrain::Terrain;
use crate::vaults;
use crate::{Distribution, Rng};
use calx::{self, die, CellVector, RngExt, WeightedChoice};
use euclid::{vec3, Vector3D};
use log::{debug, warn};
use rand::seq::SliceRandom;
use serde_derive::{Deserialize, Serialize};
use std::collections::HashMap;
use std::error::Error;
use std::ops::{Add, Deref, DerefMut};
use std::str::FromStr;
use std::sync::Arc;

pub const SECTOR_WIDTH: i32 = 38;
pub const SECTOR_HEIGHT: i32 = 18;

pub struct SectorSpace;
pub type SectorVector = Vector3D<i16, SectorSpace>;

/// Non-scrolling screen.
///
/// A sector represents a rectangular chunk of locations that fit on the visual screen. Sector
/// coordinates form their own sector space that tiles the location space with sectors.
#[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
pub struct Sector {
    pub x: i16,
    pub y: i16,
    pub z: i16,
}

impl Add<SectorVector> for Sector {
    type Output = Sector;
    fn add(self, other: SectorVector) -> Sector {
        Sector {
            x: self.x + other.x,
            y: self.y + other.y,
            z: self.z + other.z,
        }
    }
}

impl Sector {
    pub const fn new(x: i16, y: i16, z: i16) -> Sector { Sector { x, y, z } }

    pub fn origin(self) -> Location { self.rect_coord_loc(0, 0) }

    pub fn rect_coord_loc(self, u: i32, v: i32) -> Location {
        Location::from_rect_coords(
            self.x as i32 * SECTOR_WIDTH + u,
            self.y as i32 * SECTOR_HEIGHT + v,
            self.z,
        )
    }

    /// Center location for this sector.
    ///
    /// Usually you want the camera positioned here.
    pub fn center(self) -> Location {
        // XXX: If the width/height are even (as they currently are), there isn't a centered cell.
        self.rect_coord_loc(SECTOR_WIDTH / 2 - 1, SECTOR_HEIGHT / 2 - 1)
    }

    pub fn iter(self) -> impl Iterator<Item = Location> {
        let n = SECTOR_WIDTH * SECTOR_HEIGHT;
        let pitch = SECTOR_WIDTH;
        (0..n).map(move |i| self.rect_coord_loc(i % pitch, i / pitch))
    }

    /// Iterate offset points for a generic `Sector`.
    pub fn points() -> impl Iterator<Item = CellVector> {
        let sector = Sector::new(0, 0, 0);
        let sector_origin = sector.origin();
        sector
            .iter()
            .map(move |loc| sector_origin.v2_at(loc).unwrap())
    }

    pub fn taxicab_distance(self, other: Sector) -> i32 {
        ((self.x as i32) - (other.x as i32)).abs()
            + ((self.y as i32) - (other.y as i32)).abs()
            + ((self.z as i32) - (other.z as i32)).abs()
    }
}

#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)]
pub enum Biome {
    Dungeon,
    Grassland,
    Forest,
    Mountain,
    Desert,
    Water,
    City,
}

/// Specification for generating a Sector's map.
///
/// This serves as the top-level entry point to map generation routines.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SectorSpec {
    // TODO: Sectors can be predefined maps.
    // TODO: flags for blocked connection to N,E,W,S,up and down neighbor sectors
    // By default create path/stairs if adjacent sector exists.
    pub depth: i32,
    pub biome: Biome,
}

#[derive(Clone, Default, Serialize, Deserialize)]
pub struct WorldSkeleton(HashMap<Sector, SectorSpec>);

impl Deref for WorldSkeleton {
    type Target = HashMap<Sector, SectorSpec>;

    fn deref(&self) -> &Self::Target { &self.0 }
}

impl DerefMut for WorldSkeleton {
    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}

impl WorldSkeleton {
    pub fn dungeon_dive() -> WorldSkeleton {
        let mut ret = WorldSkeleton::default();
        for depth in 0..10 {
            let sector = Sector::new(0, 0, -(depth as i16));
            let spec = SectorSpec {
                depth,
                biome: Biome::Dungeon,
            };
            ret.insert(sector, spec);
        }
        ret
    }

    pub fn overworld_sprawl() -> WorldSkeleton {
        use calx::{DenseTextMap, IntoPrefab};
        const OVERWORLD_MAP: &str = "\
             ~ ~ ~ ~ ~ ~ ^ ^ ^ ^
             ~ ~ ~ ~ . % %|- - ^
             ~ ~ . # . . %L- - ^
             ~ . . . 0 . . .|- ^
             ~ . . . . % ._-_- ^
             ~ . . . . . . . . ^
             ~ . . . # # . . . ^
             ~ ~ . . # . . . . ^
             ~ ~ . . . . . . . ^
             ~ ~ ~ ~ ~ ~ ~ ^ ^ ^";

        // Legend (sector centers):
        // 0: player start sector
        // ~: sea
        // .: grassland
        // %: forest
        // -: desert
        // ^: mountain
        // #: city
        //
        // Legend (sector edges):
        // I, L, _: Edges between sectors to left, right and lower right

        let mut ret = WorldSkeleton::default();
        // Overworld
        for y in -4..=4i16 {
            for x in -4..=4i16 {
                let is_edge = y.abs() == 4 || x.abs() == 4;
                // TODO: Use overworld map to configure sectors
                let sector = Sector::new(x, y, 0);
                let spec = SectorSpec {
                    depth: 0,
                    biome: if is_edge {
                        Biome::Water
                    } else {
                        Biome::Grassland
                    },
                };

                ret.insert(sector, spec);
            }
        }

        // Dungeons
        for depth in 1..10 {
            let sector = Sector::new(0, 0, -(depth as i16));
            let spec = SectorSpec {
                depth,
                biome: Biome::Dungeon,
            };
            ret.insert(sector, spec);
        }

        ret
    }
}

/// Generate the map for a sector given the 3D world skeleton.
///
/// Note that this function does not take a rng. The idea is that map generation should be
/// perfectly deterministic given a world seed and the sector position, so new sectors can be
/// lazily generated at any point of the game.
pub fn generate(seed: u32, pos: Sector, world_skeleton: &WorldSkeleton) -> Map {
    ConnectedSectorSpec::new(pos, world_skeleton).sample(&mut calx::seeded_rng(&(seed, pos)))
}

/// Wrapper for `SectorSpec` with references to neighboring sectors.
///
/// This is needed for map generation where connections or terrain transition tiles on the edge
/// will be placed based on the neighboring sectors. Map generation will try to build connective
/// pathways to traversable neighboring sectors unless the central spec specifically forbids it.
pub struct ConnectedSectorSpec<'a> {
    pub spec: &'a SectorSpec,
    pub north: Option<&'a SectorSpec>,
    pub east: Option<&'a SectorSpec>,
    pub south: Option<&'a SectorSpec>,
    pub west: Option<&'a SectorSpec>,
    pub up: Option<&'a SectorSpec>,
    pub down: Option<&'a SectorSpec>,
}

impl<'a> ConnectedSectorSpec<'a> {
    pub fn new(spec_location: Sector, world_skeleton: &'a WorldSkeleton) -> Self {
        ConnectedSectorSpec {
            spec: world_skeleton.get(&spec_location).unwrap(),
            north: world_skeleton.get(&(spec_location + vec3(0, -1, 0))),
            east: world_skeleton.get(&(spec_location + vec3(1, 0, 0))),
            south: world_skeleton.get(&(spec_location + vec3(0, 1, 0))),
            west: world_skeleton.get(&(spec_location + vec3(-1, 0, 0))),
            up: world_skeleton.get(&(spec_location + vec3(0, 0, 1))),
            down: world_skeleton.get(&(spec_location + vec3(0, 0, -1))),
        }
    }
}

impl<'a> Deref for ConnectedSectorSpec<'a> {
    type Target = SectorSpec;

    fn deref(&self) -> &SectorSpec { self.spec }
}

impl<'a> Distribution<Map> for ConnectedSectorSpec<'a> {
    fn sample(&self, rng: &mut Rng) -> Map {
        use Biome::*;
        match self.biome {
            Dungeon => self.build_dungeon(rng),
            Grassland => self.build_grassland(rng),
            Forest => unimplemented!(),
            Mountain => self.base_map(Terrain::Rock),
            Desert => unimplemented!(),
            Water => self.base_map(Terrain::Water),
            City => unimplemented!(),
        }
    }
}

impl<'a> ConnectedSectorSpec<'a> {
    fn dungeon_gen(&self, rng: &mut Rng) -> Result<Map, Box<dyn Error>> {
        // TODO: Connect to side levels if they exist

        debug!("Starting mapgen");
        let mut map = self.dungeon_base_map();

        self.place_stairs(rng, &mut map)?;

        loop {
            let room: Room = self.sample(rng);
            debug!("Adding room");
            if map.place_room(rng, &*room.0).is_err() {
                break;
            }
        }

        if let Some(map) = map.join_disjoint_regions(rng) {
            Ok(map)
        } else {
            die!("Failed to join map");
        }
    }

    fn place_stairs(&self, rng: &mut Rng, map: &mut Map) -> Result<(), Box<dyn Error>> {
        // TODO: Biome affects vault distribution
        if self.up.is_some() {
            let room: Entrance = self.sample(rng);
            debug!("Placing upstairs");
            map.place_room(rng, &*room.0)?;
        }

        if self.down.is_some() {
            // TODO: Make exit use a sampled type like Entrance does
            debug!("Placing downstairs");
            let room = vaults::EXITS.choose(rng).unwrap();
            map.place_room(rng, &*room)?;
        }
        Ok(())
    }

    fn build_dungeon(&self, rng: &mut Rng) -> Map {
        const NUM_RETRIES: usize = 16;

        if let Ok(map) = calx::retry_gen(NUM_RETRIES, rng, |rng| self.dungeon_gen(rng)) {
            map
        } else {
            // Fallback, couldn't generate map, let's do something foolproof.
            warn!("Repeated dungeon generation failure, falling back to bigroom");
            self.build_bigroom(rng)
        }
    }

    fn build_bigroom(&self, rng: &mut Rng) -> Map {
        let mut map = self.dungeon_base_map();
        for p in map.find_positions(|_, _| true) {
            map.dig(p);
        }

        self.place_stairs(rng, &mut map).unwrap();

        for &pos in &map.open_ground() {
            if let Some(spawn) = self.sample(rng) {
                map.push_spawn(pos, spawn);
            }
        }

        map
    }

    fn dungeon_base_map(&self) -> Map {
        Map::new_base(
            Terrain::Rock,
            Sector::points()
                .filter(|p| !Location::new(p.x as i16, p.y as i16, 0).is_next_to_diagonal_sector()),
        )
    }

    fn base_map(&self, terrain: Terrain) -> Map { Map::new_base(terrain, Sector::points()) }

    fn build_grassland(&self, rng: &mut Rng) -> Map {
        let mut map = self.base_map(Terrain::Grass);
        self.place_stairs(rng, &mut map).unwrap();

        for &pos in &map.open_ground() {
            if let Some(spawn) = self.sample(rng) {
                map.push_spawn(pos, spawn);
            }
        }

        map
    }
}

impl Distribution<EntitySpawn> for ConnectedSectorSpec<'_> {
    fn sample(&self, rng: &mut Rng) -> EntitySpawn {
        let item = spec::iter_specs()
            .weighted_choice(rng, |item| {
                if item.rarity() == 0.0 || item.min_depth() > self.depth {
                    0.0
                } else {
                    1.0 / item.rarity()
                }
            })
            .unwrap();

        EntitySpawn::from_str(item.name()).unwrap()
    }
}

/// Include spawn density of entities, can be run over all open cells.
///
/// XXX: You maybe want something smarter than this to handle clustering of mobs etc.
impl Distribution<Option<EntitySpawn>> for ConnectedSectorSpec<'_> {
    fn sample(&self, rng: &mut Rng) -> Option<EntitySpawn> {
        use Biome::*;
        let spawn_one_in = match self.biome {
            Dungeon => 10,
            _ => 100,
        };

        if rng.one_chance_in(spawn_one_in) {
            Some(self.sample(rng))
        } else {
            None
        }
    }
}

struct Entrance(Arc<Map>);

impl Distribution<Entrance> for ConnectedSectorSpec<'_> {
    fn sample(&self, rng: &mut Rng) -> Entrance {
        Entrance(vaults::ENTRANCES.choose(rng).unwrap().clone())
    }
}

struct Room(Arc<Map>);

impl Distribution<Room> for ConnectedSectorSpec<'_> {
    fn sample(&self, rng: &mut Rng) -> Room {
        if rng.one_chance_in(12) {
            // Make a vault sometimes.
            Room(vaults::VAULTS.choose(rng).unwrap().clone())
        } else {
            // Make a procgen room normally.
            let mut map = Map::new_plain_room(rng);
            for &pos in &map.open_ground() {
                if let Some(spawn) = self.sample(rng) {
                    map.push_spawn(pos, spawn);
                }
            }

            Room(Arc::new(map))
        }
    }
}

struct Exit(Arc<Map>);

impl Distribution<Exit> for ConnectedSectorSpec<'_> {
    fn sample(&self, rng: &mut Rng) -> Exit { Exit(vaults::EXITS.choose(rng).unwrap().clone()) }
}
<commit_msg>Fix depths for overland gen<commit_after>use crate::location::Location;
use crate::map::Map;
use crate::spec::{self, EntitySpawn};
use crate::terrain::Terrain;
use crate::vaults;
use crate::{Distribution, Rng};
use calx::{self, die, CellVector, RngExt, WeightedChoice};
use euclid::{vec3, Vector3D};
use log::{debug, warn};
use rand::seq::SliceRandom;
use serde_derive::{Deserialize, Serialize};
use std::collections::HashMap;
use std::error::Error;
use std::ops::{Add, Deref, DerefMut};
use std::str::FromStr;
use std::sync::Arc;

pub const SECTOR_WIDTH: i32 = 38;
pub const SECTOR_HEIGHT: i32 = 18;

pub struct SectorSpace;
pub type SectorVector = Vector3D<i16, SectorSpace>;

/// Non-scrolling screen.
///
/// A sector represents a rectangular chunk of locations that fit on the visual screen. Sector
/// coordinates form their own sector space that tiles the location space with sectors.
#[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
pub struct Sector {
    pub x: i16,
    pub y: i16,
    pub z: i16,
}

impl Add<SectorVector> for Sector {
    type Output = Sector;
    fn add(self, other: SectorVector) -> Sector {
        Sector {
            x: self.x + other.x,
            y: self.y + other.y,
            z: self.z + other.z,
        }
    }
}

impl Sector {
    pub const fn new(x: i16, y: i16, z: i16) -> Sector { Sector { x, y, z } }

    pub fn origin(self) -> Location { self.rect_coord_loc(0, 0) }

    pub fn rect_coord_loc(self, u: i32, v: i32) -> Location {
        Location::from_rect_coords(
            self.x as i32 * SECTOR_WIDTH + u,
            self.y as i32 * SECTOR_HEIGHT + v,
            self.z,
        )
    }

    /// Center location for this sector.
    ///
    /// Usually you want the camera positioned here.
    pub fn center(self) -> Location {
        // XXX: If the width/height are even (as they currently are), there isn't a centered cell.
        self.rect_coord_loc(SECTOR_WIDTH / 2 - 1, SECTOR_HEIGHT / 2 - 1)
    }

    pub fn iter(self) -> impl Iterator<Item = Location> {
        let n = SECTOR_WIDTH * SECTOR_HEIGHT;
        let pitch = SECTOR_WIDTH;
        (0..n).map(move |i| self.rect_coord_loc(i % pitch, i / pitch))
    }

    /// Iterate offset points for a generic `Sector`.
    pub fn points() -> impl Iterator<Item = CellVector> {
        let sector = Sector::new(0, 0, 0);
        let sector_origin = sector.origin();
        sector
            .iter()
            .map(move |loc| sector_origin.v2_at(loc).unwrap())
    }

    pub fn taxicab_distance(self, other: Sector) -> i32 {
        ((self.x as i32) - (other.x as i32)).abs()
            + ((self.y as i32) - (other.y as i32)).abs()
            + ((self.z as i32) - (other.z as i32)).abs()
    }
}

#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)]
pub enum Biome {
    Dungeon,
    Grassland,
    Forest,
    Mountain,
    Desert,
    Water,
    City,
}

/// Specification for generating a Sector's map.
///
/// This serves as the top-level entry point to map generation routines.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SectorSpec {
    // TODO: Sectors can be predefined maps.
    // TODO: flags for blocked connection to N,E,W,S,up and down neighbor sectors
    // By default create path/stairs if adjacent sector exists.
    pub depth: i32,
    pub biome: Biome,
}

#[derive(Clone, Default, Serialize, Deserialize)]
pub struct WorldSkeleton(HashMap<Sector, SectorSpec>);

impl Deref for WorldSkeleton {
    type Target = HashMap<Sector, SectorSpec>;

    fn deref(&self) -> &Self::Target { &self.0 }
}

impl DerefMut for WorldSkeleton {
    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}

impl WorldSkeleton {
    pub fn dungeon_dive() -> WorldSkeleton {
        let mut ret = WorldSkeleton::default();
        for depth in 0..10 {
            let sector = Sector::new(0, 0, -(depth as i16));
            let spec = SectorSpec {
                depth,
                biome: Biome::Dungeon,
            };
            ret.insert(sector, spec);
        }
        ret
    }

    pub fn overworld_sprawl() -> WorldSkeleton {
        use calx::{DenseTextMap, IntoPrefab};
        const OVERWORLD_MAP: &str = "\
             ~ ~ ~ ~ ~ ~ ^ ^ ^ ^
             ~ ~ ~ ~ . % %|- - ^
             ~ ~ . # . . %L- - ^
             ~ . . . 0 . . .|- ^
             ~ . . . . % ._-_- ^
             ~ . . . . . . . . ^
             ~ . . . # # . . . ^
             ~ ~ . . # . . . . ^
             ~ ~ . . . . . . . ^
             ~ ~ ~ ~ ~ ~ ~ ^ ^ ^";

        // Legend (sector centers):
        // 0: player start sector
        // ~: sea
        // .: grassland
        // %: forest
        // -: desert
        // ^: mountain
        // #: city
        //
        // Legend (sector edges):
        // I, L, _: Edges between sectors to left, right and lower right

        let mut ret = WorldSkeleton::default();
        // Overworld
        for y in -4..=4i16 {
            for x in -4..=4i16 {
                let is_edge = y.abs() == 4 || x.abs() == 4;
                let dist = x.abs() + y.abs();
                // TODO: Use overworld map to configure sectors
                let sector = Sector::new(x, y, 0);
                let spec = SectorSpec {
                    depth: dist as i32,
                    biome: if is_edge {
                        Biome::Water
                    } else {
                        Biome::Grassland
                    },
                };

                ret.insert(sector, spec);
            }
        }

        // Dungeons
        for depth in 0..10 {
            let sector = Sector::new(0, 0, -(depth as i16 + 1));
            let spec = SectorSpec {
                depth,
                biome: Biome::Dungeon,
            };
            ret.insert(sector, spec);
        }

        ret
    }
}

/// Generate the map for a sector given the 3D world skeleton.
///
/// Note that this function does not take a rng. The idea is that map generation should be
/// perfectly deterministic given a world seed and the sector position, so new sectors can be
/// lazily generated at any point of the game.
pub fn generate(seed: u32, pos: Sector, world_skeleton: &WorldSkeleton) -> Map {
    ConnectedSectorSpec::new(pos, world_skeleton).sample(&mut calx::seeded_rng(&(seed, pos)))
}

/// Wrapper for `SectorSpec` with references to neighboring sectors.
///
/// This is needed for map generation where connections or terrain transition tiles on the edge
/// will be placed based on the neighboring sectors. Map generation will try to build connective
/// pathways to traversable neighboring sectors unless the central spec specifically forbids it.
pub struct ConnectedSectorSpec<'a> {
    pub spec: &'a SectorSpec,
    pub north: Option<&'a SectorSpec>,
    pub east: Option<&'a SectorSpec>,
    pub south: Option<&'a SectorSpec>,
    pub west: Option<&'a SectorSpec>,
    pub up: Option<&'a SectorSpec>,
    pub down: Option<&'a SectorSpec>,
}

impl<'a> ConnectedSectorSpec<'a> {
    pub fn new(spec_location: Sector, world_skeleton: &'a WorldSkeleton) -> Self {
        ConnectedSectorSpec {
            spec: world_skeleton.get(&spec_location).unwrap(),
            north: world_skeleton.get(&(spec_location + vec3(0, -1, 0))),
            east: world_skeleton.get(&(spec_location + vec3(1, 0, 0))),
            south: world_skeleton.get(&(spec_location + vec3(0, 1, 0))),
            west: world_skeleton.get(&(spec_location + vec3(-1, 0, 0))),
            up: world_skeleton.get(&(spec_location + vec3(0, 0, 1))),
            down: world_skeleton.get(&(spec_location + vec3(0, 0, -1))),
        }
    }
}

impl<'a> Deref for ConnectedSectorSpec<'a> {
    type Target = SectorSpec;

    fn deref(&self) -> &SectorSpec { self.spec }
}

impl<'a> Distribution<Map> for ConnectedSectorSpec<'a> {
    fn sample(&self, rng: &mut Rng) -> Map {
        use Biome::*;
        match self.biome {
            Dungeon => self.build_dungeon(rng),
            Grassland => self.build_grassland(rng),
            Forest => unimplemented!(),
            Mountain => self.base_map(Terrain::Rock),
            Desert => unimplemented!(),
            Water => self.base_map(Terrain::Water),
            City => unimplemented!(),
        }
    }
}

impl<'a> ConnectedSectorSpec<'a> {
    fn dungeon_gen(&self, rng: &mut Rng) -> Result<Map, Box<dyn Error>> {
        // TODO: Connect to side levels if they exist

        debug!("Starting mapgen");
        let mut map = self.dungeon_base_map();

        self.place_stairs(rng, &mut map)?;

        loop {
            let room: Room = self.sample(rng);
            debug!("Adding room");
            if map.place_room(rng, &*room.0).is_err() {
                break;
            }
        }

        if let Some(map) = map.join_disjoint_regions(rng) {
            Ok(map)
        } else {
            die!("Failed to join map");
        }
    }

    fn place_stairs(&self, rng: &mut Rng, map: &mut Map) -> Result<(), Box<dyn Error>> {
        // TODO: Biome affects vault distribution
        if self.up.is_some() {
            let room: Entrance = self.sample(rng);
            debug!("Placing upstairs");
            map.place_room(rng, &*room.0)?;
        }

        if self.down.is_some() {
            // TODO: Make exit use a sampled type like Entrance does
            debug!("Placing downstairs");
            let room = vaults::EXITS.choose(rng).unwrap();
            map.place_room(rng, &*room)?;
        }
        Ok(())
    }

    fn build_dungeon(&self, rng: &mut Rng) -> Map {
        const NUM_RETRIES: usize = 16;

        if let Ok(map) = calx::retry_gen(NUM_RETRIES, rng, |rng| self.dungeon_gen(rng)) {
            map
        } else {
            // Fallback, couldn't generate map, let's do something foolproof.
            warn!("Repeated dungeon generation failure, falling back to bigroom");
            self.build_bigroom(rng)
        }
    }

    fn build_bigroom(&self, rng: &mut Rng) -> Map {
        let mut map = self.dungeon_base_map();
        for p in map.find_positions(|_, _| true) {
            map.dig(p);
        }

        self.place_stairs(rng, &mut map).unwrap();

        for &pos in &map.open_ground() {
            if let Some(spawn) = self.sample(rng) {
                map.push_spawn(pos, spawn);
            }
        }

        map
    }

    fn dungeon_base_map(&self) -> Map {
        Map::new_base(
            Terrain::Rock,
            Sector::points()
                .filter(|p| !Location::new(p.x as i16, p.y as i16, 0).is_next_to_diagonal_sector()),
        )
    }

    fn base_map(&self, terrain: Terrain) -> Map { Map::new_base(terrain, Sector::points()) }

    fn build_grassland(&self, rng: &mut Rng) -> Map {
        let mut map = self.base_map(Terrain::Grass);
        self.place_stairs(rng, &mut map).unwrap();

        for &pos in &map.open_ground() {
            if let Some(spawn) = self.sample(rng) {
                map.push_spawn(pos, spawn);
            }
        }

        map
    }
}

impl Distribution<EntitySpawn> for ConnectedSectorSpec<'_> {
    fn sample(&self, rng: &mut Rng) -> EntitySpawn {
        let item = spec::iter_specs()
            .weighted_choice(rng, |item| {
                if item.rarity() == 0.0 || item.min_depth() > self.depth {
                    0.0
                } else {
                    1.0 / item.rarity()
                }
            })
            .unwrap();

        EntitySpawn::from_str(item.name()).unwrap()
    }
}

/// Include spawn density of entities, can be run over all open cells.
///
/// XXX: You maybe want something smarter than this to handle clustering of mobs etc.
impl Distribution<Option<EntitySpawn>> for ConnectedSectorSpec<'_> {
    fn sample(&self, rng: &mut Rng) -> Option<EntitySpawn> {
        use Biome::*;
        let spawn_one_in = match self.biome {
            Dungeon => 10,
            _ => 100,
        };

        if rng.one_chance_in(spawn_one_in) {
            Some(self.sample(rng))
        } else {
            None
        }
    }
}

struct Entrance(Arc<Map>);

impl Distribution<Entrance> for ConnectedSectorSpec<'_> {
    fn sample(&self, rng: &mut Rng) -> Entrance {
        Entrance(vaults::ENTRANCES.choose(rng).unwrap().clone())
    }
}

struct Room(Arc<Map>);

impl Distribution<Room> for ConnectedSectorSpec<'_> {
    fn sample(&self, rng: &mut Rng) -> Room {
        if rng.one_chance_in(12) {
            // Make a vault sometimes.
            Room(vaults::VAULTS.choose(rng).unwrap().clone())
        } else {
            // Make a procgen room normally.
            let mut map = Map::new_plain_room(rng);
            for &pos in &map.open_ground() {
                if let Some(spawn) = self.sample(rng) {
                    map.push_spawn(pos, spawn);
                }
            }

            Room(Arc::new(map))
        }
    }
}

struct Exit(Arc<Map>);

impl Distribution<Exit> for ConnectedSectorSpec<'_> {
    fn sample(&self, rng: &mut Rng) -> Exit { Exit(vaults::EXITS.choose(rng).unwrap().clone()) }
}
<|endoftext|>


<commit_before>//! Top level world generation logic

use crate::location::Location;
use crate::map::Map;
use crate::spec::{self, EntitySpawn, Spec};
use crate::terrain::Terrain;
use crate::vaults;
use crate::{Distribution, Rng};
use calx::{self, die, CellVector, RngExt, WeightedChoice};
use euclid::{vec3, Vector3D};
use log::{debug, warn};
use rand::seq::SliceRandom;
use serde_derive::{Deserialize, Serialize};
use std::collections::HashMap;
use std::error::Error;
use std::ops::{Add, Deref, DerefMut};
use std::str::FromStr;
use std::sync::Arc;

pub const SECTOR_WIDTH: i32 = 38;
pub const SECTOR_HEIGHT: i32 = 18;

pub struct SectorSpace;
pub type SectorVector = Vector3D<i16, SectorSpace>;

/// Non-scrolling screen.
///
/// A sector represents a rectangular chunk of locations that fit on the visual screen. Sector
/// coordinates form their own sector space that tiles the location space with sectors.
#[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
pub struct Sector {
    pub x: i16,
    pub y: i16,
    pub z: i16,
}

impl Add<SectorVector> for Sector {
    type Output = Sector;
    fn add(self, other: SectorVector) -> Sector {
        Sector {
            x: self.x + other.x,
            y: self.y + other.y,
            z: self.z + other.z,
        }
    }
}

impl Sector {
    pub const fn new(x: i16, y: i16, z: i16) -> Sector { Sector { x, y, z } }

    pub fn origin(self) -> Location { self.rect_coord_loc(0, 0) }

    pub fn rect_coord_loc(self, u: i32, v: i32) -> Location {
        Location::from_rect_coords(
            self.x as i32 * SECTOR_WIDTH + u,
            self.y as i32 * SECTOR_HEIGHT + v,
            self.z,
        )
    }

    /// Center location for this sector.
    ///
    /// Usually you want the camera positioned here.
    pub fn center(self) -> Location {
        // XXX: If the width/height are even (as they currently are), there isn't a centered cell.
        self.rect_coord_loc(SECTOR_WIDTH / 2 - 1, SECTOR_HEIGHT / 2 - 1)
    }

    pub fn iter(self) -> impl Iterator<Item = Location> {
        let n = SECTOR_WIDTH * SECTOR_HEIGHT;
        let pitch = SECTOR_WIDTH;
        (0..n).map(move |i| self.rect_coord_loc(i % pitch, i / pitch))
    }

    /// Iterate offset points for a generic `Sector`.
    pub fn points() -> impl Iterator<Item = CellVector> {
        let sector = Sector::new(0, 0, 0);
        let sector_origin = sector.origin();
        sector
            .iter()
            .map(move |loc| sector_origin.v2_at(loc).unwrap())
    }

    pub fn taxicab_distance(self, other: Sector) -> i32 {
        ((self.x as i32) - (other.x as i32)).abs()
            + ((self.y as i32) - (other.y as i32)).abs()
            + ((self.z as i32) - (other.z as i32)).abs()
    }
}

#[derive(Eq, PartialEq, Copy, Clone, Debug, Serialize, Deserialize)]
pub enum Biome {
    Dungeon = 1,
    Grassland,
    Forest,
    Mountain,
    Desert,
    Water,
    City,
}

/// Specification for generating a Sector's map.
///
/// This serves as the top-level entry point to map generation routines.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SectorSpec {
    // TODO: Sectors can be predefined maps.
    // TODO: flags for blocked connection to N,E,W,S,up and down neighbor sectors
    // By default create path/stairs if adjacent sector exists.
    pub depth: i32,
    pub biome: Biome,
}

#[derive(Clone, Default, Serialize, Deserialize)]
pub struct WorldSkeleton(HashMap<Sector, SectorSpec>);

impl Deref for WorldSkeleton {
    type Target = HashMap<Sector, SectorSpec>;

    fn deref(&self) -> &Self::Target { &self.0 }
}

impl DerefMut for WorldSkeleton {
    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}

impl WorldSkeleton {
    pub fn dungeon_dive() -> WorldSkeleton {
        let mut ret = WorldSkeleton::default();
        for depth in 0..10 {
            let sector = Sector::new(0, 0, -(depth as i16));
            let spec = SectorSpec {
                depth,
                biome: Biome::Dungeon,
            };
            ret.insert(sector, spec);
        }
        ret
    }

    pub fn overworld_sprawl() -> WorldSkeleton {
        use calx::{DenseTextMap, IntoPrefab};
        const OVERWORLD_MAP: &str = "\
             ~ ~ ~ ~ ~ ~ ^ ^ ^ ^
             ~ ~ ~ ~ . % %|- - ^
             ~ ~ . # . . %L- - ^
             ~ . . . 0 . . .|- ^
             ~ . . . . % ._-_- ^
             ~ . . . . . . . . ^
             ~ . . . # # . . . ^
             ~ ~ . . # . . . . ^
             ~ ~ . . . . . . . ^
             ~ ~ ~ ~ ~ ~ ~ ^ ^ ^";

        // Legend (sector centers):
        // 0: player start sector
        // ~: sea
        // .: grassland
        // %: forest
        // -: desert
        // ^: mountain
        // #: city
        //
        // Legend (sector edges):
        // I, L, _: Edges between sectors to left, right and lower right

        let mut ret = WorldSkeleton::default();
        // Overworld
        for y in -4..=4i16 {
            for x in -4..=4i16 {
                let is_edge = y.abs() == 4 || x.abs() == 4;
                let dist = x.abs() + y.abs();
                // TODO: Use overworld map to configure sectors
                let sector = Sector::new(x, y, 0);
                let spec = SectorSpec {
                    depth: dist as i32,
                    biome: if is_edge {
                        Biome::Water
                    } else {
                        Biome::Grassland
                    },
                };

                ret.insert(sector, spec);
            }
        }

        // Dungeons
        for depth in 0..10 {
            let sector = Sector::new(0, 0, -(depth as i16 + 1));
            let spec = SectorSpec {
                depth,
                biome: Biome::Dungeon,
            };
            ret.insert(sector, spec);
        }

        ret
    }
}

/// Generate the map for a sector given the 3D world skeleton.
///
/// Note that this function does not take a rng. The idea is that map generation should be
/// perfectly deterministic given a world seed and the sector position, so new sectors can be
/// lazily generated at any point of the game.
pub fn generate(seed: u32, pos: Sector, world_skeleton: &WorldSkeleton) -> Map {
    ConnectedSectorSpec::new(pos, world_skeleton).sample(&mut calx::seeded_rng(&(seed, pos)))
}

/// Wrapper for `SectorSpec` with references to neighboring sectors.
///
/// This is needed for map generation where connections or terrain transition tiles on the edge
/// will be placed based on the neighboring sectors. Map generation will try to build connective
/// pathways to traversable neighboring sectors unless the central spec specifically forbids it.
pub struct ConnectedSectorSpec<'a> {
    pub spec: &'a SectorSpec,
    pub north: Option<&'a SectorSpec>,
    pub east: Option<&'a SectorSpec>,
    pub south: Option<&'a SectorSpec>,
    pub west: Option<&'a SectorSpec>,
    pub up: Option<&'a SectorSpec>,
    pub down: Option<&'a SectorSpec>,
}

impl<'a> ConnectedSectorSpec<'a> {
    pub fn new(spec_location: Sector, world_skeleton: &'a WorldSkeleton) -> Self {
        ConnectedSectorSpec {
            spec: world_skeleton.get(&spec_location).unwrap(),
            north: world_skeleton.get(&(spec_location + vec3(0, -1, 0))),
            east: world_skeleton.get(&(spec_location + vec3(1, 0, 0))),
            south: world_skeleton.get(&(spec_location + vec3(0, 1, 0))),
            west: world_skeleton.get(&(spec_location + vec3(-1, 0, 0))),
            up: world_skeleton.get(&(spec_location + vec3(0, 0, 1))),
            down: world_skeleton.get(&(spec_location + vec3(0, 0, -1))),
        }
    }
}

impl<'a> Deref for ConnectedSectorSpec<'a> {
    type Target = SectorSpec;

    fn deref(&self) -> &SectorSpec { self.spec }
}

impl<'a> Distribution<Map> for ConnectedSectorSpec<'a> {
    fn sample(&self, rng: &mut Rng) -> Map {
        use Biome::*;
        match self.biome {
            Dungeon => self.build_dungeon(rng),
            Grassland => self.build_grassland(rng),
            Forest => unimplemented!(),
            Mountain => self.base_map(Terrain::Rock),
            Desert => unimplemented!(),
            Water => self.base_map(Terrain::Water),
            City => unimplemented!(),
        }
    }
}

impl<'a> ConnectedSectorSpec<'a> {
    fn dungeon_gen(&self, rng: &mut Rng) -> Result<Map, Box<dyn Error>> {
        // TODO: Connect to side levels if they exist

        debug!("Starting mapgen");
        let mut map = self.dungeon_base_map();

        self.place_stairs(rng, &mut map)?;

        loop {
            let room: Room = self.sample(rng);
            debug!("Adding room");
            if map.place_room(rng, &*room.0).is_err() {
                break;
            }
        }

        if let Some(map) = map.join_disjoint_regions(rng) {
            Ok(map)
        } else {
            die!("Failed to join map");
        }
    }

    fn place_stairs(&self, rng: &mut Rng, map: &mut Map) -> Result<(), Box<dyn Error>> {
        // TODO: Biome affects vault distribution
        if self.up.is_some() {
            let room: Entrance = self.sample(rng);
            debug!("Placing upstairs");
            map.place_room(rng, &*room.0)?;
        }

        if self.down.is_some() {
            // TODO: Make exit use a sampled type like Entrance does
            debug!("Placing downstairs");
            let room = vaults::EXITS.choose(rng).unwrap();
            map.place_room(rng, &*room)?;
        }
        Ok(())
    }

    fn build_dungeon(&self, rng: &mut Rng) -> Map {
        const NUM_RETRIES: usize = 16;

        if let Ok(map) = calx::retry_gen(NUM_RETRIES, rng, |rng| self.dungeon_gen(rng)) {
            map
        } else {
            // Fallback, couldn't generate map, let's do something foolproof.
            warn!("Repeated dungeon generation failure, falling back to bigroom");
            self.build_bigroom(rng)
        }
    }

    fn build_bigroom(&self, rng: &mut Rng) -> Map {
        let mut map = self.dungeon_base_map();
        for p in map.find_positions(|_, _| true) {
            map.dig(p);
        }

        self.place_stairs(rng, &mut map).unwrap();

        for &pos in &map.open_ground() {
            if let Some(spawn) = self.sample(rng) {
                map.push_spawn(pos, spawn);
            }
        }

        map
    }

    fn dungeon_base_map(&self) -> Map {
        Map::new_base(
            Terrain::Rock,
            Sector::points()
                .filter(|p| !Location::new(p.x as i16, p.y as i16, 0).is_next_to_diagonal_sector()),
        )
    }

    fn base_map(&self, terrain: Terrain) -> Map { Map::new_base(terrain, Sector::points()) }

    fn build_grassland(&self, rng: &mut Rng) -> Map {
        let mut map = self.base_map(Terrain::Grass);
        self.place_stairs(rng, &mut map).unwrap();

        for &pos in &map.open_ground() {
            if let Some(spawn) = self.sample(rng) {
                map.push_spawn(pos, spawn);
            }
        }

        map
    }

    fn can_spawn(&self, spec: &dyn Spec) -> bool {
        spec.min_depth() <= self.depth && (spec.habitat() & (1 << self.biome as u64)) != 0
    }
}

impl Distribution<EntitySpawn> for ConnectedSectorSpec<'_> {
    fn sample(&self, rng: &mut Rng) -> EntitySpawn {
        let item = spec::iter_specs()
            .weighted_choice(rng, |item| {
                if item.rarity() == 0.0 || !self.can_spawn(&**item) {
                    0.0
                } else {
                    1.0 / item.rarity()
                }
            })
            .unwrap();

        EntitySpawn::from_str(item.name()).unwrap()
    }
}

/// Include spawn density of entities, can be run over all open cells.
///
/// XXX: You maybe want something smarter than this to handle clustering of mobs etc.
impl Distribution<Option<EntitySpawn>> for ConnectedSectorSpec<'_> {
    fn sample(&self, rng: &mut Rng) -> Option<EntitySpawn> {
        use Biome::*;
        let spawn_one_in = match self.biome {
            Dungeon => 10,
            _ => 100,
        };

        if rng.one_chance_in(spawn_one_in) {
            Some(self.sample(rng))
        } else {
            None
        }
    }
}

struct Entrance(Arc<Map>);

impl Distribution<Entrance> for ConnectedSectorSpec<'_> {
    fn sample(&self, rng: &mut Rng) -> Entrance {
        Entrance(vaults::ENTRANCES.choose(rng).unwrap().clone())
    }
}

struct Room(Arc<Map>);

impl Distribution<Room> for ConnectedSectorSpec<'_> {
    fn sample(&self, rng: &mut Rng) -> Room {
        if rng.one_chance_in(12) {
            // Make a vault sometimes.
            Room(vaults::VAULTS.choose(rng).unwrap().clone())
        } else {
            // Make a procgen room normally.
            let mut map = Map::new_plain_room(rng);
            for &pos in &map.open_ground() {
                if let Some(spawn) = self.sample(rng) {
                    map.push_spawn(pos, spawn);
                }
            }

            Room(Arc::new(map))
        }
    }
}

struct Exit(Arc<Map>);

impl Distribution<Exit> for ConnectedSectorSpec<'_> {
    fn sample(&self, rng: &mut Rng) -> Exit { Exit(vaults::EXITS.choose(rng).unwrap().clone()) }
}
<commit_msg>Store more stuff in SectorSpec<commit_after>//! Top level world generation logic

use crate::location::Location;
use crate::map::Map;
use crate::spec::{self, EntitySpawn, Spec};
use crate::terrain::Terrain;
use crate::vaults;
use crate::{Distribution, Rng};
use calx::{self, die, CellVector, RngExt, WeightedChoice};
use euclid::{vec3, Vector3D};
use log::{debug, warn};
use rand::seq::SliceRandom;
use serde_derive::{Deserialize, Serialize};
use std::collections::HashMap;
use std::error::Error;
use std::ops::{Add, Deref, DerefMut};
use std::str::FromStr;
use std::sync::Arc;

pub const SECTOR_WIDTH: i32 = 38;
pub const SECTOR_HEIGHT: i32 = 18;

pub struct SectorSpace;
pub type SectorVector = Vector3D<i16, SectorSpace>;

/// Non-scrolling screen.
///
/// A sector represents a rectangular chunk of locations that fit on the visual screen. Sector
/// coordinates form their own sector space that tiles the location space with sectors.
#[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
pub struct Sector {
    pub x: i16,
    pub y: i16,
    pub z: i16,
}

impl Add<SectorVector> for Sector {
    type Output = Sector;
    fn add(self, other: SectorVector) -> Sector {
        Sector {
            x: self.x + other.x,
            y: self.y + other.y,
            z: self.z + other.z,
        }
    }
}

impl Sector {
    pub const fn new(x: i16, y: i16, z: i16) -> Sector { Sector { x, y, z } }

    pub fn origin(self) -> Location { self.rect_coord_loc(0, 0) }

    pub fn rect_coord_loc(self, u: i32, v: i32) -> Location {
        Location::from_rect_coords(
            self.x as i32 * SECTOR_WIDTH + u,
            self.y as i32 * SECTOR_HEIGHT + v,
            self.z,
        )
    }

    /// Center location for this sector.
    ///
    /// Usually you want the camera positioned here.
    pub fn center(self) -> Location {
        // XXX: If the width/height are even (as they currently are), there isn't a centered cell.
        self.rect_coord_loc(SECTOR_WIDTH / 2 - 1, SECTOR_HEIGHT / 2 - 1)
    }

    pub fn iter(self) -> impl Iterator<Item = Location> {
        let n = SECTOR_WIDTH * SECTOR_HEIGHT;
        let pitch = SECTOR_WIDTH;
        (0..n).map(move |i| self.rect_coord_loc(i % pitch, i / pitch))
    }

    /// Iterate offset points for a generic `Sector`.
    pub fn points() -> impl Iterator<Item = CellVector> {
        let sector = Sector::new(0, 0, 0);
        let sector_origin = sector.origin();
        sector
            .iter()
            .map(move |loc| sector_origin.v2_at(loc).unwrap())
    }

    pub fn taxicab_distance(self, other: Sector) -> i32 {
        ((self.x as i32) - (other.x as i32)).abs()
            + ((self.y as i32) - (other.y as i32)).abs()
            + ((self.z as i32) - (other.z as i32)).abs()
    }
}

#[derive(Eq, PartialEq, Copy, Clone, Debug, Serialize, Deserialize)]
pub enum Biome {
    Dungeon = 1,
    Grassland,
    Forest,
    Mountain,
    Desert,
    Water,
    City,
}

/// Specification for generating a Sector's map.
///
/// This serves as the top-level entry point to map generation routines.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SectorSpec {
    // TODO: Sectors can be predefined maps.
    // TODO: flags for blocked connection to N,E,W,S,up and down neighbor sectors
    // By default create path/stairs if adjacent sector exists.
    pub depth: i32,
    pub biome: Biome,
}

#[derive(Clone, Default, Serialize, Deserialize)]
pub struct WorldSkeleton(HashMap<Sector, SectorSpec>);

impl Deref for WorldSkeleton {
    type Target = HashMap<Sector, SectorSpec>;

    fn deref(&self) -> &Self::Target { &self.0 }
}

impl DerefMut for WorldSkeleton {
    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}

impl WorldSkeleton {
    pub fn dungeon_dive() -> WorldSkeleton {
        let mut ret = WorldSkeleton::default();
        for depth in 0..10 {
            let sector = Sector::new(0, 0, -(depth as i16));
            let spec = SectorSpec {
                depth,
                biome: Biome::Dungeon,
            };
            ret.insert(sector, spec);
        }
        ret
    }

    pub fn overworld_sprawl() -> WorldSkeleton {
        use calx::{DenseTextMap, IntoPrefab};
        const OVERWORLD_MAP: &str = "\
             ~ ~ ~ ~ ~ ~ ^ ^ ^ ^
             ~ ~ ~ ~ . % %|- - ^
             ~ ~ . # . . %L- - ^
             ~ . . . 0 . . .|- ^
             ~ . . . . % ._-_- ^
             ~ . . . . . . . . ^
             ~ . . . # # . . . ^
             ~ ~ . . # . . . . ^
             ~ ~ . . . . . . . ^
             ~ ~ ~ ~ ~ ~ ~ ^ ^ ^";

        // Legend (sector centers):
        // 0: player start sector
        // ~: sea
        // .: grassland
        // %: forest
        // -: desert
        // ^: mountain
        // #: city
        //
        // Legend (sector edges):
        // I, L, _: Edges between sectors to left, right and lower right

        let mut ret = WorldSkeleton::default();
        // Overworld
        for y in -4..=4i16 {
            for x in -4..=4i16 {
                let is_edge = y.abs() == 4 || x.abs() == 4;
                let dist = x.abs() + y.abs();
                // TODO: Use overworld map to configure sectors
                let sector = Sector::new(x, y, 0);
                let spec = SectorSpec {
                    depth: dist as i32,
                    biome: if is_edge {
                        Biome::Water
                    } else {
                        Biome::Grassland
                    },
                };

                ret.insert(sector, spec);
            }
        }

        // Dungeons
        for depth in 0..10 {
            let sector = Sector::new(0, 0, -(depth as i16 + 1));
            let spec = SectorSpec {
                depth,
                biome: Biome::Dungeon,
            };
            ret.insert(sector, spec);
        }

        ret
    }
}

/// Generate the map for a sector given the 3D world skeleton.
///
/// Note that this function does not take a rng. The idea is that map generation should be
/// perfectly deterministic given a world seed and the sector position, so new sectors can be
/// lazily generated at any point of the game.
pub fn generate(seed: u32, pos: Sector, world_skeleton: &WorldSkeleton) -> Map {
    ConnectedSectorSpec::new(seed, pos, world_skeleton).sample(&mut calx::seeded_rng(&(seed, pos)))
}

/// Wrapper for `SectorSpec` with references to neighboring sectors.
///
/// This is needed for map generation where connections or terrain transition tiles on the edge
/// will be placed based on the neighboring sectors. Map generation will try to build connective
/// pathways to traversable neighboring sectors unless the central spec specifically forbids it.
pub struct ConnectedSectorSpec<'a> {
    pub seed: u32,
    pub sector: Sector,
    pub spec: &'a SectorSpec,
    pub north: Option<&'a SectorSpec>,
    pub east: Option<&'a SectorSpec>,
    pub south: Option<&'a SectorSpec>,
    pub west: Option<&'a SectorSpec>,
    pub up: Option<&'a SectorSpec>,
    pub down: Option<&'a SectorSpec>,
}

impl<'a> ConnectedSectorSpec<'a> {
    pub fn new(seed: u32, sector: Sector, world_skeleton: &'a WorldSkeleton) -> Self {
        ConnectedSectorSpec {
            seed,
            sector,
            spec: world_skeleton.get(&sector).unwrap(),
            north: world_skeleton.get(&(sector + vec3(0, -1, 0))),
            east: world_skeleton.get(&(sector + vec3(1, 0, 0))),
            south: world_skeleton.get(&(sector + vec3(0, 1, 0))),
            west: world_skeleton.get(&(sector + vec3(-1, 0, 0))),
            up: world_skeleton.get(&(sector + vec3(0, 0, 1))),
            down: world_skeleton.get(&(sector + vec3(0, 0, -1))),
        }
    }
}

impl<'a> Deref for ConnectedSectorSpec<'a> {
    type Target = SectorSpec;

    fn deref(&self) -> &SectorSpec { self.spec }
}

impl<'a> Distribution<Map> for ConnectedSectorSpec<'a> {
    fn sample(&self, rng: &mut Rng) -> Map {
        use Biome::*;
        match self.biome {
            Dungeon => self.build_dungeon(rng),
            Grassland => self.build_grassland(rng),
            Forest => unimplemented!(),
            Mountain => self.base_map(Terrain::Rock),
            Desert => unimplemented!(),
            Water => self.base_map(Terrain::Water),
            City => unimplemented!(),
        }
    }
}

impl<'a> ConnectedSectorSpec<'a> {
    fn dungeon_gen(&self, rng: &mut Rng) -> Result<Map, Box<dyn Error>> {
        // TODO: Connect to side levels if they exist

        debug!("Starting mapgen");
        let mut map = self.dungeon_base_map();

        self.place_stairs(rng, &mut map)?;

        loop {
            let room: Room = self.sample(rng);
            debug!("Adding room");
            if map.place_room(rng, &*room.0).is_err() {
                break;
            }
        }

        if let Some(map) = map.join_disjoint_regions(rng) {
            Ok(map)
        } else {
            die!("Failed to join map");
        }
    }

    fn place_stairs(&self, rng: &mut Rng, map: &mut Map) -> Result<(), Box<dyn Error>> {
        // TODO: Biome affects vault distribution
        if self.up.is_some() {
            let room: Entrance = self.sample(rng);
            debug!("Placing upstairs");
            map.place_room(rng, &*room.0)?;
        }

        if self.down.is_some() {
            // TODO: Make exit use a sampled type like Entrance does
            debug!("Placing downstairs");
            let room = vaults::EXITS.choose(rng).unwrap();
            map.place_room(rng, &*room)?;
        }
        Ok(())
    }

    fn build_dungeon(&self, rng: &mut Rng) -> Map {
        const NUM_RETRIES: usize = 16;

        if let Ok(map) = calx::retry_gen(NUM_RETRIES, rng, |rng| self.dungeon_gen(rng)) {
            map
        } else {
            // Fallback, couldn't generate map, let's do something foolproof.
            warn!("Repeated dungeon generation failure, falling back to bigroom");
            self.build_bigroom(rng)
        }
    }

    fn build_bigroom(&self, rng: &mut Rng) -> Map {
        let mut map = self.dungeon_base_map();
        for p in map.find_positions(|_, _| true) {
            map.dig(p);
        }

        self.place_stairs(rng, &mut map).unwrap();

        for &pos in &map.open_ground() {
            if let Some(spawn) = self.sample(rng) {
                map.push_spawn(pos, spawn);
            }
        }

        map
    }

    fn dungeon_base_map(&self) -> Map {
        Map::new_base(
            Terrain::Rock,
            Sector::points()
                .filter(|p| !Location::new(p.x as i16, p.y as i16, 0).is_next_to_diagonal_sector()),
        )
    }

    fn base_map(&self, terrain: Terrain) -> Map { Map::new_base(terrain, Sector::points()) }

    fn build_grassland(&self, rng: &mut Rng) -> Map {
        let mut map = self.base_map(Terrain::Grass);
        self.place_stairs(rng, &mut map).unwrap();

        for &pos in &map.open_ground() {
            if let Some(spawn) = self.sample(rng) {
                map.push_spawn(pos, spawn);
            }
        }

        map
    }

    fn can_spawn(&self, spec: &dyn Spec) -> bool {
        spec.min_depth() <= self.depth && (spec.habitat() & (1 << self.biome as u64)) != 0
    }
}

impl Distribution<EntitySpawn> for ConnectedSectorSpec<'_> {
    fn sample(&self, rng: &mut Rng) -> EntitySpawn {
        let item = spec::iter_specs()
            .weighted_choice(rng, |item| {
                if item.rarity() == 0.0 || !self.can_spawn(&**item) {
                    0.0
                } else {
                    1.0 / item.rarity()
                }
            })
            .unwrap();

        EntitySpawn::from_str(item.name()).unwrap()
    }
}

/// Include spawn density of entities, can be run over all open cells.
///
/// XXX: You maybe want something smarter than this to handle clustering of mobs etc.
impl Distribution<Option<EntitySpawn>> for ConnectedSectorSpec<'_> {
    fn sample(&self, rng: &mut Rng) -> Option<EntitySpawn> {
        use Biome::*;
        let spawn_one_in = match self.biome {
            Dungeon => 10,
            _ => 100,
        };

        if rng.one_chance_in(spawn_one_in) {
            Some(self.sample(rng))
        } else {
            None
        }
    }
}

struct Entrance(Arc<Map>);

impl Distribution<Entrance> for ConnectedSectorSpec<'_> {
    fn sample(&self, rng: &mut Rng) -> Entrance {
        Entrance(vaults::ENTRANCES.choose(rng).unwrap().clone())
    }
}

struct Room(Arc<Map>);

impl Distribution<Room> for ConnectedSectorSpec<'_> {
    fn sample(&self, rng: &mut Rng) -> Room {
        if rng.one_chance_in(12) {
            // Make a vault sometimes.
            Room(vaults::VAULTS.choose(rng).unwrap().clone())
        } else {
            // Make a procgen room normally.
            let mut map = Map::new_plain_room(rng);
            for &pos in &map.open_ground() {
                if let Some(spawn) = self.sample(rng) {
                    map.push_spawn(pos, spawn);
                }
            }

            Room(Arc::new(map))
        }
    }
}

struct Exit(Arc<Map>);

impl Distribution<Exit> for ConnectedSectorSpec<'_> {
    fn sample(&self, rng: &mut Rng) -> Exit { Exit(vaults::EXITS.choose(rng).unwrap().clone()) }
}
<|endoftext|>


<commit_before>//! Iterators that are sources (produce elements from parameters,
//! not from another iterator).

use std::mem;

/// See [`repeat_call`](../fn.repeat_call.html) for more information.
pub struct RepeatCall<F> {
    f: F,
}

/// An iterator source that produces elements indefinitely by calling
/// a given closure.
///
/// Iterator element type is the return type of the closure.
///
/// ```
/// use itertools::repeat_call;
/// use itertools::Itertools;
/// use std::collections::BinaryHeap;
///
/// let mut heap = BinaryHeap::from(vec![2, 5, 3, 7, 8]);
///
/// // extract each element in sorted order
/// for element in repeat_call(|| heap.pop()).while_some() {
///     print!("{}", element);
/// }
///
/// itertools::assert_equal(
///     repeat_call(|| 1).take(5),
///     vec![1, 1, 1, 1, 1]
/// );
/// ```
pub fn repeat_call<F>(function: F) -> RepeatCall<F> {
    RepeatCall { f: function }
}

impl Iterator for RepeatCall<F>
    where F: FnMut() -> A
{
    type Item = A;

    #[inline]
    fn next(&mut self) -> Option {
        Some((self.f)())
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (usize::max_value(), None)
    }
}

/// Creates a new unfold source with the specified closure as the "iterator
/// function" and an initial state to eventually pass to the closure
///
/// `unfold` is a general iterator builder: it has a mutable state value,
/// and a closure with access to the state that produces the next value.
///
/// This more or less equivalent to a regular struct with an `Iterator`
/// implementation, and is useful for one-off iterators.
///
/// ```
/// // an iterator that yields sequential Fibonacci numbers,
/// // and stops at the maximum representable value.
///
/// use itertools::unfold;
///
/// let mut fibonacci = unfold((1_u32, 1_u32), |state| {
///     let (ref mut x1, ref mut x2) = *state;
///
///     // Attempt to get the next Fibonacci number
///     let next = x1.saturating_add(*x2);
///
///     // Shift left: ret <- x1 <- x2 <- next
///     let ret = *x1;
///     *x1 = *x2;
///     *x2 = next;
///
///     // If addition has saturated at the maximum, we are finished
///     if ret == *x1 && ret > 1 {
///         return None;
///     }
///
///     Some(ret)
/// });
///
/// itertools::assert_equal(fibonacci.by_ref().take(8),
///                         vec![1, 1, 2, 3, 5, 8, 13, 21]);
/// assert_eq!(fibonacci.last(), Some(2_971_215_073))
/// ```
pub fn unfold(initial_state: St, f: F) -> Unfold<St, F>
    where F: FnMut(&mut St) -> Option
{
    Unfold {
        f: f,
        state: initial_state,
    }
}

/// See [`unfold`](../fn.unfold.html) for more information.
#[derive(Clone)]
pub struct Unfold<St, F> {
    f: F,
    /// Internal state that will be passed to the closure on the next iteration
    pub state: St,
}

impl Iterator for Unfold<St, F>
    where F: FnMut(&mut St) -> Option
{
    type Item = A;

    #[inline]
    fn next(&mut self) -> Option {
        (self.f)(&mut self.state)
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        // no possible known bounds at this point
        (0, None)
    }
}

/// An iterator that infinitely applies function to value and yields results.
///
/// This `struct` is created by the [`iterate()`] function. See its documentation for more.
///
/// [`iterate()`]: ../fn.iterate.html
#[derive(Clone)]
pub struct Iterate<St, F> {
    state: St,
    f: F,
}

impl<St, F> Iterator for Iterate<St, F>
    where F: FnMut(&St) -> St
{
    type Item = St;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        let next_state = (self.f)(&self.state);
        Some(mem::replace(&mut self.state, next_state))
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        (usize::max_value(), None)
    }
}

/// Creates a new iterator that infinitely applies function to value and yields results.
///
/// ```
/// use itertools::iterate;
///
/// itertools::assert_equal(iterate(1, |&i| i * 3).take(5), vec![1, 3, 9, 27, 81]);
/// ```
pub fn iterate<St, F>(initial_value: St, f: F) -> Iterate<St, F>
    where F: FnMut(&St) -> St
{
    Iterate {
        state: initial_value,
        f: f,
    }
}
<commit_msg>impl Debug for sources<commit_after>//! Iterators that are sources (produce elements from parameters,
//! not from another iterator).

use std::fmt;
use std::mem;

/// See [`repeat_call`](../fn.repeat_call.html) for more information.
pub struct RepeatCall<F> {
    f: F,
}

impl<F> fmt::Debug for RepeatCall<F>
{
    debug_fmt_fields!(RepeatCall, );
}

/// An iterator source that produces elements indefinitely by calling
/// a given closure.
///
/// Iterator element type is the return type of the closure.
///
/// ```
/// use itertools::repeat_call;
/// use itertools::Itertools;
/// use std::collections::BinaryHeap;
///
/// let mut heap = BinaryHeap::from(vec![2, 5, 3, 7, 8]);
///
/// // extract each element in sorted order
/// for element in repeat_call(|| heap.pop()).while_some() {
///     print!("{}", element);
/// }
///
/// itertools::assert_equal(
///     repeat_call(|| 1).take(5),
///     vec![1, 1, 1, 1, 1]
/// );
/// ```
pub fn repeat_call<F>(function: F) -> RepeatCall<F> {
    RepeatCall { f: function }
}

impl Iterator for RepeatCall<F>
    where F: FnMut() -> A
{
    type Item = A;

    #[inline]
    fn next(&mut self) -> Option {
        Some((self.f)())
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (usize::max_value(), None)
    }
}

/// Creates a new unfold source with the specified closure as the "iterator
/// function" and an initial state to eventually pass to the closure
///
/// `unfold` is a general iterator builder: it has a mutable state value,
/// and a closure with access to the state that produces the next value.
///
/// This more or less equivalent to a regular struct with an `Iterator`
/// implementation, and is useful for one-off iterators.
///
/// ```
/// // an iterator that yields sequential Fibonacci numbers,
/// // and stops at the maximum representable value.
///
/// use itertools::unfold;
///
/// let mut fibonacci = unfold((1_u32, 1_u32), |state| {
///     let (ref mut x1, ref mut x2) = *state;
///
///     // Attempt to get the next Fibonacci number
///     let next = x1.saturating_add(*x2);
///
///     // Shift left: ret <- x1 <- x2 <- next
///     let ret = *x1;
///     *x1 = *x2;
///     *x2 = next;
///
///     // If addition has saturated at the maximum, we are finished
///     if ret == *x1 && ret > 1 {
///         return None;
///     }
///
///     Some(ret)
/// });
///
/// itertools::assert_equal(fibonacci.by_ref().take(8),
///                         vec![1, 1, 2, 3, 5, 8, 13, 21]);
/// assert_eq!(fibonacci.last(), Some(2_971_215_073))
/// ```
pub fn unfold(initial_state: St, f: F) -> Unfold<St, F>
    where F: FnMut(&mut St) -> Option
{
    Unfold {
        f: f,
        state: initial_state,
    }
}

impl<St, F> fmt::Debug for Unfold<St, F>
    where St: fmt::Debug,
{
    debug_fmt_fields!(Unfold, state);
}

/// See [`unfold`](../fn.unfold.html) for more information.
#[derive(Clone)]
pub struct Unfold<St, F> {
    f: F,
    /// Internal state that will be passed to the closure on the next iteration
    pub state: St,
}

impl Iterator for Unfold<St, F>
    where F: FnMut(&mut St) -> Option
{
    type Item = A;

    #[inline]
    fn next(&mut self) -> Option {
        (self.f)(&mut self.state)
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        // no possible known bounds at this point
        (0, None)
    }
}

/// An iterator that infinitely applies function to value and yields results.
///
/// This `struct` is created by the [`iterate()`] function. See its documentation for more.
///
/// [`iterate()`]: ../fn.iterate.html
#[derive(Clone)]
pub struct Iterate<St, F> {
    state: St,
    f: F,
}

impl<St, F> fmt::Debug for Iterate<St, F>
    where St: fmt::Debug,
{
    debug_fmt_fields!(Iterate, state);
}

impl<St, F> Iterator for Iterate<St, F>
    where F: FnMut(&St) -> St
{
    type Item = St;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        let next_state = (self.f)(&self.state);
        Some(mem::replace(&mut self.state, next_state))
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        (usize::max_value(), None)
    }
}

/// Creates a new iterator that infinitely applies function to value and yields results.
///
/// ```
/// use itertools::iterate;
///
/// itertools::assert_equal(iterate(1, |&i| i * 3).take(5), vec![1, 3, 9, 27, 81]);
/// ```
pub fn iterate<St, F>(initial_value: St, f: F) -> Iterate<St, F>
    where F: FnMut(&St) -> St
{
    Iterate {
        state: initial_value,
        f: f,
    }
}
<|endoftext|>


<commit_before>
#![allow(dead_code)]
#![allow(deprecated)]
use protobuf;
use proto::raftpb::{HardState, ConfState, Entry, Snapshot};
use raft::errors::{Result, Error, StorageError};

#[derive(Debug, Clone)]
pub struct RaftState {
    hard_state: HardState,
    conf_state: ConfState,
}

pub trait Storage {
    fn initial_state(&self) -> Result<RaftState>;
    fn entries(&self, low: u64, high: u64, max_size: u64) -> Result<&[Entry]>;
    fn term(&self, idx: u64) -> Result<u64>;
    fn first_index(&self) -> Result<u64>;
    fn last_index(&self) -> Result<u64>;
    fn snapshot(&self) -> Result<&Snapshot>;
}

pub struct MemStorage {
    hard_state: HardState,
    snapshot: Snapshot,
    // TODO: maybe vec_deque
    entries: Vec<Entry>,
}

impl MemStorage {
    pub fn new() -> MemStorage {
        MemStorage {
            // When starting from scratch populate the list with a dummy entry at term zero.
            entries: vec![Entry::new()],
            hard_state: HardState::new(),
            snapshot: Snapshot::new(),
        }
    }

    pub fn set_hardstate(&mut self, hs: HardState) {
        self.hard_state = hs;
    }

    fn inner_last_index(&self) -> u64 {
        return self.entries[0].get_Index() + self.entries.len() as u64 - 1;
    }

    fn limit_size(entries: &[Entry], max: u64) -> Result<&[Entry]> {
        if entries.len() == 0 {
            return Ok(entries);
        }

        let mut size = protobuf::Message::compute_size(&entries[0]) as u64;
        let mut limit = 1u64;
        while limit < entries.len() as u64 {
            size += protobuf::Message::compute_size(&entries[limit as usize]) as u64;
            if size > max {
                break;
            }
            limit += 1;
        }
        let ents = &entries[..limit as usize];
        Ok(ents)
    }

    fn apply_snapshot(&mut self, snapshot: Snapshot) -> Result<()> {
        let mut e = Entry::new();
        e.set_Term(snapshot.get_metadata().get_term());
        e.set_Index(snapshot.get_metadata().get_index());
        self.entries = vec![e];
        self.snapshot = snapshot;
        Ok(())
    }

    fn create_snapshot(&mut self,
                       idx: u64,
                       cs: Option<ConfState>,
                       data: Vec<u8>)
                       -> Result<&Snapshot> {
        if idx <= self.snapshot.get_metadata().get_index() {
            return Err(Error::Store(StorageError::SnapshotOutOfDate));
        }

        let offset = self.entries[0].get_Index();
        if idx > self.last_index().unwrap() {
            panic!("snapshot {} is out of bound lastindex({})",
                   idx,
                   self.last_index().unwrap())
        }
        self.snapshot.mut_metadata().set_index(idx);
        self.snapshot.mut_metadata().set_term(self.entries[(idx - offset) as usize].get_Term());
        match cs {
            Some(cs) => self.snapshot.mut_metadata().set_conf_state(cs),
            None => {}
        }
        self.snapshot.set_data(data);
        Ok(&self.snapshot)
    }

    pub fn compact(&mut self, compact_index: u64) -> Result<()> {
        let offset = self.entries[0].get_Index();
        if compact_index <= offset {
            return Err(Error::Store(StorageError::Compacted));
        }
        if compact_index > self.last_index().unwrap() {
            panic!("compact {} is out of bound lastindex({})",
                   compact_index,
                   self.last_index().unwrap())
        }

        let i = (compact_index - offset) as usize;
        let new_length = self.entries.len() + 1 - i;
        let mut entries: Vec<Entry> = Vec::with_capacity(new_length);
        entries.push(Entry::new());
        entries[0].set_Index(self.entries[i].get_Index());
        entries[0].set_Term(self.entries[i].get_Term());
        entries.append(&mut self.entries[i + 1..].to_vec());
        self.entries = entries;
        Ok(())
    }

    pub fn append(&mut self, ents: &[Entry]) -> Result<()> {
        if ents.len() == 0 {
            return Ok(());
        }
        let first: u64 = self.entries[0].get_Index() + 1;
        let last: u64 = ents[0].get_Index() + ents.len() as u64 - 1;

        if last < first {
            return Ok(());
        }
        // truncate compacted entries
        let mut te: &[Entry] = ents;
        if first > ents[0].get_Index() {
            let start = (first - ents[0].get_Index()) as usize;
            te = &ents[start..ents.len()];
        }

        let offset = te[0].get_Index() - self.entries[0].get_Index();
        if self.entries.len() as u64 > offset {
            let mut new_entries: Vec<Entry> = vec![];
            new_entries.extend_from_slice(&self.entries[..offset as usize]);
            new_entries.extend_from_slice(te);
            self.entries = new_entries;
        } else if self.entries.len() as u64 == offset {
            self.entries.extend_from_slice(te);
        } else {
            panic!("missing log entry [last: {}, append at: {}]",
                   self.last_index().unwrap(),
                   te[0].get_Index())
        }

        Ok(())
    }
}

impl Storage for MemStorage {
    fn initial_state(&self) -> Result<RaftState> {
        Ok(RaftState {
            hard_state: self.hard_state.clone(),
            conf_state: self.snapshot.get_metadata().get_conf_state().clone(),
        })
    }

    fn entries(&self, low: u64, high: u64, max_size: u64) -> Result<&[Entry]> {
        let offset = self.entries[0].get_Index();
        if low <= offset {
            return Err(Error::Store(StorageError::Compacted));
        }

        if high > self.inner_last_index() + 1 {
            panic!("index out of bound")
        }
        // only contains dummy entries.
        if self.entries.len() == 1 {
            return Err(Error::Store(StorageError::Unavailable));
        }

        let lo = (low - offset) as usize;
        let hi = (high - offset) as usize;
        let ents: &[Entry] = &self.entries[lo..hi];
        return MemStorage::limit_size(ents, max_size);
    }

    fn term(&self, idx: u64) -> Result<u64> {
        let offset = self.entries[0].get_Index();
        if idx < offset {
            return Err(Error::Store(StorageError::Compacted));
        }
        Ok(self.entries[(idx - offset) as usize].get_Term())
    }

    fn first_index(&self) -> Result<u64> {
        Ok(self.entries[0].get_Index() + 1)
    }

    fn last_index(&self) -> Result<u64> {
        Ok(self.inner_last_index())
    }

    fn snapshot(&self) -> Result<&Snapshot> {
        Ok(&self.snapshot)
    }
}
<commit_msg>address comment: drain<commit_after>
#![allow(dead_code)]
#![allow(deprecated)]
use protobuf;
use proto::raftpb::{HardState, ConfState, Entry, Snapshot};
use raft::errors::{Result, Error, StorageError};

#[derive(Debug, Clone)]
pub struct RaftState {
    hard_state: HardState,
    conf_state: ConfState,
}

pub trait Storage {
    fn initial_state(&self) -> Result<RaftState>;
    fn entries(&self, low: u64, high: u64, max_size: u64) -> Result<&[Entry]>;
    fn term(&self, idx: u64) -> Result<u64>;
    fn first_index(&self) -> Result<u64>;
    fn last_index(&self) -> Result<u64>;
    fn snapshot(&self) -> Result<&Snapshot>;
}

pub struct MemStorage {
    hard_state: HardState,
    snapshot: Snapshot,
    // TODO: maybe vec_deque
    entries: Vec<Entry>,
}

impl MemStorage {
    pub fn new() -> MemStorage {
        MemStorage {
            // When starting from scratch populate the list with a dummy entry at term zero.
            entries: vec![Entry::new()],
            hard_state: HardState::new(),
            snapshot: Snapshot::new(),
        }
    }

    pub fn set_hardstate(&mut self, hs: HardState) {
        self.hard_state = hs;
    }

    fn inner_last_index(&self) -> u64 {
        return self.entries[0].get_Index() + self.entries.len() as u64 - 1;
    }

    fn limit_size(entries: &[Entry], max: u64) -> Result<&[Entry]> {
        if entries.len() == 0 {
            return Ok(entries);
        }

        let mut size = protobuf::Message::compute_size(&entries[0]) as u64;
        let mut limit = 1u64;
        while limit < entries.len() as u64 {
            size += protobuf::Message::compute_size(&entries[limit as usize]) as u64;
            if size > max {
                break;
            }
            limit += 1;
        }
        let ents = &entries[..limit as usize];
        Ok(ents)
    }

    fn apply_snapshot(&mut self, snapshot: Snapshot) -> Result<()> {
        let mut e = Entry::new();
        e.set_Term(snapshot.get_metadata().get_term());
        e.set_Index(snapshot.get_metadata().get_index());
        self.entries = vec![e];
        self.snapshot = snapshot;
        Ok(())
    }

    fn create_snapshot(&mut self,
                       idx: u64,
                       cs: Option<ConfState>,
                       data: Vec<u8>)
                       -> Result<&Snapshot> {
        if idx <= self.snapshot.get_metadata().get_index() {
            return Err(Error::Store(StorageError::SnapshotOutOfDate));
        }

        let offset = self.entries[0].get_Index();
        if idx > self.last_index().unwrap() {
            panic!("snapshot {} is out of bound lastindex({})",
                   idx,
                   self.last_index().unwrap())
        }
        self.snapshot.mut_metadata().set_index(idx);
        self.snapshot.mut_metadata().set_term(self.entries[(idx - offset) as usize].get_Term());
        match cs {
            Some(cs) => self.snapshot.mut_metadata().set_conf_state(cs),
            None => {}
        }
        self.snapshot.set_data(data);
        Ok(&self.snapshot)
    }

    pub fn compact(&mut self, compact_index: u64) -> Result<()> {
        let offset = self.entries[0].get_Index();
        if compact_index <= offset {
            return Err(Error::Store(StorageError::Compacted));
        }
        if compact_index > self.last_index().unwrap() {
            panic!("compact {} is out of bound lastindex({})",
                   compact_index,
                   self.last_index().unwrap())
        }

        let i = (compact_index - offset) as usize;
        let entries = self.entries.drain(i..).collect();
        self.entries = entries;
        Ok(())
    }

    pub fn append(&mut self, ents: &[Entry]) -> Result<()> {
        if ents.len() == 0 {
            return Ok(());
        }
        let first: u64 = self.entries[0].get_Index() + 1;
        let last: u64 = ents[0].get_Index() + ents.len() as u64 - 1;

        if last < first {
            return Ok(());
        }
        // truncate compacted entries
        let mut te: &[Entry] = ents;
        if first > ents[0].get_Index() {
            let start = (first - ents[0].get_Index()) as usize;
            te = &ents[start..ents.len()];
        }

        let offset = te[0].get_Index() - self.entries[0].get_Index();
        if self.entries.len() as u64 > offset {
            let mut new_entries: Vec<Entry> = vec![];
            new_entries.extend_from_slice(&self.entries[..offset as usize]);
            new_entries.extend_from_slice(te);
            self.entries = new_entries;
        } else if self.entries.len() as u64 == offset {
            self.entries.extend_from_slice(te);
        } else {
            panic!("missing log entry [last: {}, append at: {}]",
                   self.last_index().unwrap(),
                   te[0].get_Index())
        }

        Ok(())
    }
}

impl Storage for MemStorage {
    fn initial_state(&self) -> Result<RaftState> {
        Ok(RaftState {
            hard_state: self.hard_state.clone(),
            conf_state: self.snapshot.get_metadata().get_conf_state().clone(),
        })
    }

    fn entries(&self, low: u64, high: u64, max_size: u64) -> Result<&[Entry]> {
        let offset = self.entries[0].get_Index();
        if low <= offset {
            return Err(Error::Store(StorageError::Compacted));
        }

        if high > self.inner_last_index() + 1 {
            panic!("index out of bound")
        }
        // only contains dummy entries.
        if self.entries.len() == 1 {
            return Err(Error::Store(StorageError::Unavailable));
        }

        let lo = (low - offset) as usize;
        let hi = (high - offset) as usize;
        let ents: &[Entry] = &self.entries[lo..hi];
        return MemStorage::limit_size(ents, max_size);
    }

    fn term(&self, idx: u64) -> Result<u64> {
        let offset = self.entries[0].get_Index();
        if idx < offset {
            return Err(Error::Store(StorageError::Compacted));
        }
        Ok(self.entries[(idx - offset) as usize].get_Term())
    }

    fn first_index(&self) -> Result<u64> {
        Ok(self.entries[0].get_Index() + 1)
    }

    fn last_index(&self) -> Result<u64> {
        Ok(self.inner_last_index())
    }

    fn snapshot(&self) -> Result<&Snapshot> {
        Ok(&self.snapshot)
    }
}
<|endoftext|>