veloren/world/src/site2/tile.rs

133 lines
4.2 KiB
Rust
Raw Normal View History

2020-12-26 15:53:06 +00:00
use super::*;
use common::spiral::Spiral2d;
2021-02-12 20:30:30 +00:00
use std::ops::Range;
2020-12-26 15:53:06 +00:00
2021-02-04 12:47:46 +00:00
pub const TILE_SIZE: u32 = 7;
pub const ZONE_SIZE: u32 = 16;
pub const ZONE_RADIUS: u32 = 16;
pub const TILE_RADIUS: u32 = ZONE_SIZE * ZONE_RADIUS;
pub const MAX_BLOCK_RADIUS: u32 = TILE_SIZE * TILE_RADIUS;
2020-12-26 15:53:06 +00:00
pub struct TileGrid {
zones: Grid<Option<Grid<Option<Tile>>>>,
}
2021-02-04 12:47:46 +00:00
impl Default for TileGrid {
fn default() -> Self {
2020-12-26 15:53:06 +00:00
Self {
zones: Grid::populate_from(Vec2::broadcast(ZONE_RADIUS as i32 * 2 + 1), |_| None),
}
}
2021-02-04 12:47:46 +00:00
}
2020-12-26 15:53:06 +00:00
2021-02-04 12:47:46 +00:00
impl TileGrid {
pub fn get(&self, tpos: Vec2<i32>) -> &Tile {
static EMPTY: Tile = Tile::empty();
2020-12-26 15:53:06 +00:00
let tpos = tpos + TILE_RADIUS as i32;
self.zones
2021-02-12 20:30:30 +00:00
.get(tpos.map(|e| e.div_euclid(ZONE_SIZE as i32)))
2021-02-06 23:53:25 +00:00
.and_then(|zone| {
zone.as_ref()?
.get(tpos.map(|e| e.rem_euclid(ZONE_SIZE as i32)))
})
2020-12-26 15:53:06 +00:00
.and_then(|tile| tile.as_ref())
.unwrap_or(&EMPTY)
2020-12-26 15:53:06 +00:00
}
pub fn get_mut(&mut self, tpos: Vec2<i32>) -> Option<&mut Tile> {
let tpos = tpos + TILE_RADIUS as i32;
2021-02-12 20:30:30 +00:00
self.zones.get_mut(tpos.map(|e| e.div_euclid(ZONE_SIZE as i32))).and_then(|zone| {
2021-02-06 23:53:25 +00:00
zone.get_or_insert_with(|| {
2021-02-12 20:30:30 +00:00
Grid::populate_from(Vec2::broadcast(ZONE_SIZE as i32), |_| None)
2021-02-06 23:53:25 +00:00
})
.get_mut(tpos.map(|e| e.rem_euclid(ZONE_SIZE as i32)))
.map(|tile| tile.get_or_insert_with(|| Tile::empty()))
})
2020-12-26 15:53:06 +00:00
}
2021-02-04 12:47:46 +00:00
pub fn set(&mut self, tpos: Vec2<i32>, tile: Tile) -> Option<Tile> {
self.get_mut(tpos).map(|t| std::mem::replace(t, tile))
}
2021-02-12 20:30:30 +00:00
pub fn find_near(&self, tpos: Vec2<i32>, f: impl Fn(Vec2<i32>, &Tile) -> bool) -> Option<Vec2<i32>> {
const MAX_SEARCH_RADIUS_BLOCKS: u32 = 256;
2021-02-12 20:30:30 +00:00
const MAX_SEARCH_CELLS: u32 = ((MAX_SEARCH_RADIUS_BLOCKS / TILE_SIZE) * 2 + 1).pow(2);
Spiral2d::new().take(MAX_SEARCH_CELLS as usize).map(|r| tpos + r).find(|tpos| (&f)(*tpos, self.get(*tpos)))
}
pub fn grow_aabr(&self, center: Vec2<i32>, area_range: Range<u32>, min_dims: Extent2<u32>) -> Result<Aabr<i32>, Aabr<i32>> {
let mut aabr = Aabr::new_empty(center);
let mut last_growth = 0;
for i in 0.. {
if i - last_growth >= 4 {
break;
} else if aabr.size().product() + if i % 2 == 0 { aabr.size().h } else { aabr.size().w } > area_range.end as i32 {
break;
} else {
match i % 4 {
0 if (aabr.min.y..aabr.max.y).all(|y| self.get(Vec2::new(aabr.max.x + 1, y)).is_empty()) => {
aabr.max.x += 1;
last_growth = i;
},
1 if (aabr.min.x..aabr.max.x).all(|x| self.get(Vec2::new(x, aabr.max.y + 1)).is_empty()) => {
aabr.max.y += 1;
last_growth = i;
},
2 if (aabr.min.y..aabr.max.y).all(|y| self.get(Vec2::new(aabr.min.x - 1, y)).is_empty()) => {
aabr.min.x -= 1;
last_growth = i;
},
3 if (aabr.min.x..aabr.max.x).all(|x| self.get(Vec2::new(x, aabr.min.y - 1)).is_empty()) => {
aabr.min.y -= 1;
last_growth = i;
},
_ => {},
}
}
}
if aabr.size().product() as u32 >= area_range.start
&& aabr.size().w as u32 >= min_dims.w
&& aabr.size().h as u32 >= min_dims.h
{
Ok(aabr)
} else {
Err(aabr)
}
2021-02-04 12:47:46 +00:00
}
}
2021-02-12 20:30:30 +00:00
#[derive(Clone, PartialEq)]
2021-02-04 12:47:46 +00:00
pub enum TileKind {
Empty,
2021-02-12 20:30:30 +00:00
Farmland { seed: u32 },
2021-02-04 12:47:46 +00:00
Building { levels: u32 },
2020-12-26 15:53:06 +00:00
}
2021-02-12 20:30:30 +00:00
#[derive(Clone)]
2020-12-26 15:53:06 +00:00
pub struct Tile {
2021-02-12 20:30:30 +00:00
pub(crate) kind: TileKind,
pub(crate) plot: Option<Id<Plot>>,
2020-12-26 15:53:06 +00:00
}
impl Tile {
pub const fn empty() -> Self {
2020-12-26 15:53:06 +00:00
Self {
2021-02-04 12:47:46 +00:00
kind: TileKind::Empty,
2020-12-26 15:53:06 +00:00
plot: None,
}
}
2021-02-04 12:47:46 +00:00
2021-02-12 20:30:30 +00:00
/// Create a tile that is not associated with any plot.
pub const fn free(kind: TileKind) -> Self {
Self {
kind,
plot: None,
}
}
2021-02-06 23:53:25 +00:00
pub fn is_empty(&self) -> bool { self.kind == TileKind::Empty }
2020-12-26 15:53:06 +00:00
}