mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Moved settlement code to site directory, removed old town generation code
This commit is contained in:
parent
b9cc0f387b
commit
1c6a6cd6cf
@ -2,7 +2,6 @@ mod natural;
|
||||
|
||||
use crate::{
|
||||
column::{ColumnGen, ColumnSample},
|
||||
generator::{Generator, TownGen},
|
||||
util::{RandomField, Sampler, SmallCache},
|
||||
CONFIG,
|
||||
};
|
||||
@ -51,11 +50,7 @@ impl<'a> BlockGen<'a> {
|
||||
cache,
|
||||
Vec2::from(*cliff_pos),
|
||||
) {
|
||||
Some(cliff_sample)
|
||||
if cliff_sample.is_cliffs
|
||||
&& cliff_sample.spawn_rate > 0.5
|
||||
&& cliff_sample.spawn_rules.cliffs =>
|
||||
{
|
||||
Some(cliff_sample) if cliff_sample.is_cliffs && cliff_sample.spawn_rate > 0.5 => {
|
||||
let cliff_pos3d = Vec3::from(*cliff_pos);
|
||||
|
||||
// Conservative range of height: [15.70, 49.33]
|
||||
@ -80,7 +75,7 @@ impl<'a> BlockGen<'a> {
|
||||
0.0
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
_ => max_height,
|
||||
},
|
||||
)
|
||||
@ -397,16 +392,6 @@ impl<'a> BlockGen<'a> {
|
||||
(None, sample.alt)
|
||||
};
|
||||
|
||||
// Structures (like towns)
|
||||
/*
|
||||
let block = chunk
|
||||
.structures
|
||||
.town
|
||||
.as_ref()
|
||||
.and_then(|town| TownGen.get((town, wpos, sample, height)))
|
||||
.or(block);
|
||||
*/
|
||||
|
||||
let block = structures
|
||||
.iter()
|
||||
.find_map(|st| {
|
||||
@ -473,21 +458,6 @@ impl<'a> ZCache<'a> {
|
||||
let min = min + structure_min;
|
||||
let max = (ground_max + structure_max).max(self.sample.water_level + 2.0);
|
||||
|
||||
// Structures
|
||||
/*
|
||||
let (min, max) = self
|
||||
.sample
|
||||
.chunk
|
||||
.structures
|
||||
.town
|
||||
.as_ref()
|
||||
.map(|town| {
|
||||
let (town_min, town_max) = TownGen.get_z_limits(town, self.wpos, &self.sample);
|
||||
(town_min.min(min), town_max.max(max))
|
||||
})
|
||||
.unwrap_or((min, max));
|
||||
*/
|
||||
|
||||
let structures_only_min_z = ground_max.max(self.sample.water_level + 2.0);
|
||||
|
||||
(min, structures_only_min_z, max)
|
||||
|
@ -28,7 +28,6 @@ pub fn structure_gen<'a>(
|
||||
if (st_sample.tree_density as f64) < random_seed
|
||||
|| st_sample.alt < st_sample.water_level
|
||||
|| st_sample.spawn_rate < 0.5
|
||||
|| !st_sample.spawn_rules.trees
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
use crate::{
|
||||
all::ForestKind,
|
||||
block::StructureMeta,
|
||||
generator::{Generator, SpawnRules, TownGen},
|
||||
sim::{
|
||||
local_cells, uniform_idx_as_vec2, vec2_as_uniform_idx, LocationInfo, RiverKind, SimChunk,
|
||||
WorldSim,
|
||||
@ -1102,22 +1101,6 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
||||
stone_col,
|
||||
|
||||
chunk: sim_chunk,
|
||||
/*
|
||||
spawn_rules: sim_chunk
|
||||
.structures
|
||||
.town
|
||||
.as_ref()
|
||||
.map(|town| TownGen.spawn_rules(town, wpos))
|
||||
.unwrap_or(SpawnRules::default())
|
||||
.and(SpawnRules {
|
||||
cliffs: !in_water,
|
||||
trees: true,
|
||||
}),
|
||||
*/
|
||||
spawn_rules: SpawnRules {
|
||||
cliffs: !in_water,
|
||||
trees: true,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1150,7 +1133,6 @@ pub struct ColumnSample<'a> {
|
||||
pub stone_col: Rgb<u8>,
|
||||
|
||||
pub chunk: &'a SimChunk,
|
||||
pub spawn_rules: SpawnRules,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
|
@ -1,710 +0,0 @@
|
||||
mod util;
|
||||
mod vol;
|
||||
|
||||
use super::{Generator, SpawnRules};
|
||||
use crate::{
|
||||
block::{block_from_structure, BlockGen},
|
||||
column::ColumnSample,
|
||||
util::Sampler,
|
||||
CONFIG,
|
||||
};
|
||||
use common::{
|
||||
assets,
|
||||
terrain::{Block, BlockKind, Structure},
|
||||
vol::{ReadVol, Vox, WriteVol},
|
||||
};
|
||||
use hashbrown::HashSet;
|
||||
use lazy_static::lazy_static;
|
||||
use rand::prelude::*;
|
||||
use std::{ops::Add, sync::Arc};
|
||||
use vek::*;
|
||||
|
||||
use self::vol::{CellKind, ColumnKind, Module, TownCell, TownColumn, TownVol};
|
||||
|
||||
const CELL_SIZE: i32 = 9;
|
||||
const CELL_HEIGHT: i32 = 9;
|
||||
|
||||
pub struct TownGen;
|
||||
|
||||
impl<'a> Sampler<'a> for TownGen {
|
||||
type Index = (&'a TownState, Vec3<i32>, &'a ColumnSample<'a>, f32);
|
||||
type Sample = Option<Block>;
|
||||
|
||||
fn get(&self, (town, wpos, sample, height): Self::Index) -> Self::Sample {
|
||||
let cell_pos = (wpos - town.center)
|
||||
.map2(Vec3::new(CELL_SIZE, CELL_SIZE, CELL_HEIGHT), |e, sz| {
|
||||
e.div_euclid(sz)
|
||||
})
|
||||
.add(Vec3::from(town.vol.size() / 2));
|
||||
let inner_pos = (wpos - town.center)
|
||||
.map2(Vec3::new(CELL_SIZE, CELL_SIZE, CELL_HEIGHT), |e, sz| {
|
||||
e.rem_euclid(sz)
|
||||
});
|
||||
|
||||
let cell = town.vol.get(cell_pos).ok()?;
|
||||
|
||||
match (modules_from_kind(&cell.kind), &cell.module) {
|
||||
(Some(module_list), Some(module)) => {
|
||||
let transform = [
|
||||
(Vec2::new(0, 0), Vec2::unit_x(), Vec2::unit_y()),
|
||||
(Vec2::new(0, 1), -Vec2::unit_y(), Vec2::unit_x()),
|
||||
(Vec2::new(1, 1), -Vec2::unit_x(), -Vec2::unit_y()),
|
||||
(Vec2::new(1, 0), Vec2::unit_y(), -Vec2::unit_x()),
|
||||
];
|
||||
|
||||
module_list[module.vol_idx]
|
||||
.0
|
||||
.get(
|
||||
Vec3::from(
|
||||
transform[module.dir].0 * (CELL_SIZE - 1)
|
||||
+ transform[module.dir].1 * inner_pos.x
|
||||
+ transform[module.dir].2 * inner_pos.y,
|
||||
) + Vec3::unit_z() * inner_pos.z,
|
||||
)
|
||||
.ok()
|
||||
.and_then(|sb| {
|
||||
block_from_structure(*sb, BlockKind::Normal, wpos, wpos.into(), 0, sample)
|
||||
})
|
||||
},
|
||||
_ => match cell.kind {
|
||||
CellKind::Empty => None,
|
||||
CellKind::Park => None,
|
||||
CellKind::Rock => Some(Block::new(BlockKind::Normal, Rgb::broadcast(100))),
|
||||
CellKind::Wall => Some(Block::new(BlockKind::Normal, Rgb::broadcast(175))),
|
||||
CellKind::Well => Some(Block::new(BlockKind::Normal, Rgb::broadcast(0))),
|
||||
CellKind::Road => {
|
||||
if (wpos.z as f32) < height - 1.0 {
|
||||
Some(Block::new(
|
||||
BlockKind::Normal,
|
||||
Lerp::lerp(
|
||||
Rgb::new(150.0, 140.0, 50.0),
|
||||
Rgb::new(100.0, 95.0, 30.0),
|
||||
sample.marble_small,
|
||||
)
|
||||
.map(|e| e as u8),
|
||||
))
|
||||
} else {
|
||||
Some(Block::empty())
|
||||
}
|
||||
},
|
||||
CellKind::House(idx) => Some(Block::new(BlockKind::Normal, town.houses[idx].color)),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Generator<'a, TownState> for TownGen {
|
||||
fn get_z_limits(
|
||||
&self,
|
||||
_town: &'a TownState,
|
||||
_wpos: Vec2<i32>,
|
||||
sample: &ColumnSample,
|
||||
) -> (f32, f32) {
|
||||
(sample.alt - 32.0, sample.alt + 75.0)
|
||||
}
|
||||
|
||||
fn spawn_rules(&self, town: &'a TownState, wpos: Vec2<i32>) -> SpawnRules {
|
||||
SpawnRules {
|
||||
trees: wpos.distance_squared(town.center.into()) > (town.radius + 32).pow(2),
|
||||
cliffs: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct House {
|
||||
color: Rgb<u8>,
|
||||
}
|
||||
|
||||
pub struct TownState {
|
||||
center: Vec3<i32>,
|
||||
radius: i32,
|
||||
vol: TownVol,
|
||||
houses: Vec<House>,
|
||||
}
|
||||
|
||||
impl TownState {
|
||||
pub fn generate(center: Vec2<i32>, gen: &mut BlockGen, rng: &mut impl Rng) -> Option<Self> {
|
||||
let radius = rng.gen_range(18, 20) * 9;
|
||||
let size = Vec2::broadcast(radius * 2 / 9 - 2);
|
||||
|
||||
let center_col = BlockGen::sample_column(&gen.column_gen, &mut gen.column_cache, center);
|
||||
|
||||
if center_col.map(|sample| sample.chaos).unwrap_or(0.0) > 0.35
|
||||
|| center_col.map(|sample| sample.alt).unwrap_or(0.0) < CONFIG.sea_level + 10.0
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let alt = center_col.map(|sample| sample.alt).unwrap_or(0.0) as i32;
|
||||
|
||||
let mut vol = TownVol::generate_from(
|
||||
size,
|
||||
|pos| {
|
||||
let wpos = center + (pos - size / 2) * CELL_SIZE + CELL_SIZE / 2;
|
||||
let rel_alt = BlockGen::sample_column(&gen.column_gen, &mut gen.column_cache, wpos)
|
||||
.map(|sample| sample.alt)
|
||||
.unwrap_or(0.0) as i32
|
||||
+ CELL_HEIGHT / 2
|
||||
- alt;
|
||||
|
||||
let col = TownColumn {
|
||||
ground: rel_alt.div_euclid(CELL_HEIGHT),
|
||||
kind: None,
|
||||
};
|
||||
|
||||
(col.ground, col)
|
||||
},
|
||||
|(col, pos)| {
|
||||
if pos.z >= col.ground {
|
||||
TownCell::empty()
|
||||
} else {
|
||||
TownCell::from(CellKind::Rock)
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// Generation passes
|
||||
vol.setup(rng);
|
||||
vol.gen_roads(rng, 30);
|
||||
vol.gen_parks(rng, 3);
|
||||
vol.emplace_columns();
|
||||
let houses = vol.gen_houses(rng, 50);
|
||||
vol.gen_wells(rng, 5);
|
||||
vol.gen_walls(rng);
|
||||
vol.resolve_modules(rng);
|
||||
vol.cull_unused();
|
||||
|
||||
Some(Self {
|
||||
center: Vec3::new(center.x, center.y, alt),
|
||||
radius,
|
||||
vol,
|
||||
houses,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn center(&self) -> Vec3<i32> { self.center }
|
||||
|
||||
pub fn radius(&self) -> i32 { self.radius }
|
||||
}
|
||||
|
||||
impl TownVol {
|
||||
fn floodfill(
|
||||
&self,
|
||||
limit: Option<usize>,
|
||||
mut opens: HashSet<Vec2<i32>>,
|
||||
mut f: impl FnMut(Vec2<i32>, &TownColumn) -> bool,
|
||||
) -> HashSet<Vec2<i32>> {
|
||||
let mut closed = HashSet::new();
|
||||
|
||||
while opens.len() > 0 {
|
||||
let mut new_opens = HashSet::new();
|
||||
|
||||
'search: for open in opens.iter() {
|
||||
for i in -1..2 {
|
||||
for j in -1..2 {
|
||||
let pos = *open + Vec2::new(i, j);
|
||||
|
||||
if let Some(col) = self.col(pos) {
|
||||
if !closed.contains(&pos) && !opens.contains(&pos) && f(pos, col) {
|
||||
match limit {
|
||||
Some(limit)
|
||||
if limit
|
||||
<= new_opens.len() + closed.len() + opens.len() =>
|
||||
{
|
||||
break 'search;
|
||||
}
|
||||
_ => {
|
||||
new_opens.insert(pos);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closed = closed.union(&opens).copied().collect();
|
||||
opens = new_opens;
|
||||
}
|
||||
|
||||
closed
|
||||
}
|
||||
|
||||
fn setup(&mut self, rng: &mut impl Rng) {
|
||||
// Place a single road tile at first
|
||||
let root_road = self
|
||||
.size()
|
||||
.map(|sz| (sz / 8) * 2 + rng.gen_range(0, sz / 4) * 2);
|
||||
self.set_col_kind(root_road, Some(ColumnKind::Road));
|
||||
}
|
||||
|
||||
fn gen_roads(&mut self, rng: &mut impl Rng, n: usize) {
|
||||
const ATTEMPTS: usize = 5;
|
||||
|
||||
let mut junctions = HashSet::new();
|
||||
junctions.insert(self.choose_column(rng, |_, col| col.is_road()).unwrap());
|
||||
|
||||
for _road in 0..n {
|
||||
for _ in 0..ATTEMPTS {
|
||||
let start = *junctions.iter().choose(rng).unwrap();
|
||||
//let start = self.choose_column(rng, |pos, col| pos.map(|e| e % 2 ==
|
||||
// 0).reduce_and() && col.is_road()).unwrap();
|
||||
let dir = util::gen_dir(rng);
|
||||
|
||||
// If the direction we want to paint a path in is obstructed, abandon this
|
||||
// attempt
|
||||
if self
|
||||
.col(start + dir)
|
||||
.map(|col| !col.is_empty())
|
||||
.unwrap_or(true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// How long should this road be?
|
||||
let len = rng.gen_range(1, 10) * 2 + 1;
|
||||
|
||||
// Paint the road until we hit an obstacle
|
||||
let success = (1..len)
|
||||
.map(|i| start + dir * i)
|
||||
.try_for_each(|pos| {
|
||||
if self.col(pos).map(|col| col.is_empty()).unwrap_or(false) {
|
||||
self.set_col_kind(pos, Some(ColumnKind::Road));
|
||||
Ok(())
|
||||
} else {
|
||||
junctions.insert(pos);
|
||||
Err(())
|
||||
}
|
||||
})
|
||||
.is_ok();
|
||||
|
||||
if success {
|
||||
junctions.insert(start + dir * (len - 1));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_parks(&mut self, rng: &mut impl Rng, n: usize) {
|
||||
const ATTEMPTS: usize = 5;
|
||||
|
||||
for _ in 0..n {
|
||||
for _ in 0..ATTEMPTS {
|
||||
let start = self
|
||||
.choose_column(rng, |pos, col| {
|
||||
col.is_empty()
|
||||
&& (0..4).any(|i| {
|
||||
self.col(pos + util::dir(i))
|
||||
.map(|col| col.is_road())
|
||||
.unwrap_or(false)
|
||||
})
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let park = self.floodfill(Some(16), [start].iter().copied().collect(), |_, col| {
|
||||
col.is_empty()
|
||||
});
|
||||
|
||||
if park.len() < 4 {
|
||||
continue;
|
||||
}
|
||||
|
||||
for cell in park {
|
||||
self.set_col_kind(cell, Some(ColumnKind::Internal));
|
||||
let col = self.col(cell).unwrap();
|
||||
let ground = col.ground;
|
||||
let _ = self.set(Vec3::new(cell.x, cell.y, ground), CellKind::Park.into());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_walls(&mut self, _rng: &mut impl Rng) {
|
||||
let mut outer = HashSet::new();
|
||||
for i in 0..self.size().x {
|
||||
outer.insert(Vec2::new(i, 0));
|
||||
outer.insert(Vec2::new(i, self.size().y - 1));
|
||||
}
|
||||
for j in 0..self.size().y {
|
||||
outer.insert(Vec2::new(0, j));
|
||||
outer.insert(Vec2::new(self.size().x - 1, j));
|
||||
}
|
||||
|
||||
let outer = self.floodfill(None, outer, |_, col| col.is_empty());
|
||||
|
||||
let mut walls = HashSet::new();
|
||||
let _inner = self.floodfill(
|
||||
None,
|
||||
[self.size() / 2].iter().copied().collect(),
|
||||
|pos, _| {
|
||||
if outer.contains(&pos) {
|
||||
walls.insert(pos);
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
while let Some(wall) = walls
|
||||
.iter()
|
||||
.filter(|pos| {
|
||||
let lateral_count = (0..4)
|
||||
.filter(|i| walls.contains(&(**pos + util::dir(*i))))
|
||||
.count();
|
||||
let max_quadrant_count = (0..4)
|
||||
.map(|i| {
|
||||
let units = util::unit(i);
|
||||
(0..2)
|
||||
.map(|i| (0..2).map(move |j| (i, j)))
|
||||
.flatten()
|
||||
.filter(|(i, j)| walls.contains(&(**pos + units.0 * *i + units.1 * *j)))
|
||||
.count()
|
||||
})
|
||||
.max()
|
||||
.unwrap();
|
||||
|
||||
lateral_count < 2 || (lateral_count == 2 && max_quadrant_count == 4)
|
||||
})
|
||||
.next()
|
||||
{
|
||||
let wall = *wall;
|
||||
walls.remove(&wall);
|
||||
}
|
||||
|
||||
for wall in walls.iter() {
|
||||
let col = self.col(*wall).unwrap();
|
||||
let ground = col.ground;
|
||||
for z in -1..3 {
|
||||
let _ = self.set(Vec3::new(wall.x, wall.y, ground + z), CellKind::Wall.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn emplace_columns(&mut self) {
|
||||
for i in 0..self.size().x {
|
||||
for j in 0..self.size().y {
|
||||
let col = self.col(Vec2::new(i, j)).unwrap();
|
||||
let ground = col.ground;
|
||||
|
||||
match col.kind {
|
||||
None => {},
|
||||
Some(ColumnKind::Internal) => {},
|
||||
//Some(ColumnKind::External) => {}
|
||||
Some(ColumnKind::Road) => {
|
||||
for z in -1..2 {
|
||||
let _ = self.set(Vec3::new(i, j, ground + z), CellKind::Road.into());
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_wells(&mut self, rng: &mut impl Rng, n: usize) {
|
||||
for _ in 0..n {
|
||||
if let Some(cell) = self.choose_cell(rng, |_, cell| {
|
||||
if let CellKind::Park = cell.kind {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}) {
|
||||
let _ = self.set(cell, CellKind::Well.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_houses(&mut self, rng: &mut impl Rng, n: usize) -> Vec<House> {
|
||||
const ATTEMPTS: usize = 10;
|
||||
|
||||
let mut houses = Vec::new();
|
||||
for _ in 0..n {
|
||||
for _ in 0..ATTEMPTS {
|
||||
let entrance = {
|
||||
let start_col = self.choose_column(rng, |_, col| col.is_road()).unwrap();
|
||||
let start = Vec3::new(
|
||||
start_col.x,
|
||||
start_col.y,
|
||||
self.col(start_col).unwrap().ground,
|
||||
);
|
||||
let dir = Vec3::from(util::gen_dir(rng));
|
||||
|
||||
if self
|
||||
.get(start + dir)
|
||||
.map(|col| !col.is_empty())
|
||||
.unwrap_or(true)
|
||||
|| self
|
||||
.get(start + dir - Vec3::unit_z())
|
||||
.map(|col| !col.is_foundation())
|
||||
.unwrap_or(true)
|
||||
{
|
||||
continue;
|
||||
} else {
|
||||
start + dir
|
||||
}
|
||||
};
|
||||
|
||||
let mut cells = HashSet::new();
|
||||
|
||||
let mut energy = 2300;
|
||||
while energy > 0 {
|
||||
energy -= 1;
|
||||
|
||||
let parent = *cells.iter().choose(rng).unwrap_or(&entrance);
|
||||
let dir = util::UNITS_3D
|
||||
.choose_weighted(rng, |pos| 1 + pos.z.max(0))
|
||||
.unwrap();
|
||||
|
||||
if self
|
||||
.get(parent + dir)
|
||||
.map(|cell| cell.is_empty())
|
||||
.unwrap_or(false)
|
||||
&& self
|
||||
.get(parent + dir - Vec3::unit_z())
|
||||
.map(|cell| {
|
||||
cell.is_foundation()
|
||||
|| cells.contains(&(parent + dir - Vec3::unit_z()))
|
||||
})
|
||||
.unwrap_or(false)
|
||||
&& parent.z + dir.z <= entrance.z + 2
|
||||
// Maximum house height
|
||||
{
|
||||
cells.insert(parent + dir);
|
||||
energy -= 10;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove cells that are too isolated
|
||||
loop {
|
||||
let cells_copy = cells.clone();
|
||||
|
||||
let mut any_removed = false;
|
||||
cells.retain(|pos| {
|
||||
let neighbour_count = (0..6)
|
||||
.filter(|i| {
|
||||
let neighbour = pos + util::dir_3d(*i);
|
||||
cells_copy.contains(&neighbour)
|
||||
})
|
||||
.count();
|
||||
|
||||
if neighbour_count < 3 {
|
||||
any_removed = true;
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
|
||||
if !any_removed {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Get rid of houses that are too small
|
||||
if cells.len() < 6 {
|
||||
continue;
|
||||
}
|
||||
|
||||
for cell in cells {
|
||||
let _ = self.set(cell, CellKind::House(houses.len()).into());
|
||||
self.set_col_kind(Vec2::from(cell), Some(ColumnKind::Internal));
|
||||
}
|
||||
|
||||
houses.push(House {
|
||||
color: Rgb::new(rng.gen(), rng.gen(), rng.gen()),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
houses
|
||||
}
|
||||
|
||||
fn cull_unused(&mut self) {
|
||||
for x in 0..self.size().x {
|
||||
for y in 0..self.size().y {
|
||||
for z in self.col_range(Vec2::new(x, y)).unwrap().rev() {
|
||||
let pos = Vec3::new(x, y, z);
|
||||
|
||||
// Remove foundations that don't have anything on top of them
|
||||
if self.get(pos).unwrap().is_foundation()
|
||||
&& self
|
||||
.get(pos + Vec3::unit_z())
|
||||
.map(TownCell::is_space)
|
||||
.unwrap_or(true)
|
||||
{
|
||||
let _ = self.set(pos, TownCell::empty());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_modules(&mut self, rng: &mut impl Rng) {
|
||||
fn classify(cell: &TownCell, this_cell: &TownCell) -> ModuleKind {
|
||||
match (&cell.kind, &this_cell.kind) {
|
||||
(CellKind::House(a), CellKind::House(b)) if a == b => ModuleKind::This,
|
||||
(CellKind::Wall, CellKind::Wall) => ModuleKind::This,
|
||||
_ => ModuleKind::That,
|
||||
}
|
||||
}
|
||||
|
||||
for x in 0..self.size().x {
|
||||
for y in 0..self.size().y {
|
||||
for z in self.col_range(Vec2::new(x, y)).unwrap() {
|
||||
let pos = Vec3::new(x, y, z);
|
||||
let this_cell = if let Ok(this_cell) = self.get(pos) {
|
||||
this_cell
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let mut signature = [ModuleKind::That; 6];
|
||||
for i in 0..6 {
|
||||
signature[i] = self
|
||||
.get(pos + util::dir_3d(i))
|
||||
.map(|cell| classify(cell, this_cell))
|
||||
.unwrap_or(ModuleKind::That);
|
||||
}
|
||||
|
||||
let module_list = if let Some(modules) = modules_from_kind(&this_cell.kind) {
|
||||
modules
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let module = module_list
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, module)| {
|
||||
let perms = [[0, 1, 2, 3], [3, 0, 1, 2], [2, 3, 0, 1], [1, 2, 3, 0]];
|
||||
|
||||
let mut rotated_signature = [ModuleKind::That; 6];
|
||||
for (dir, perm) in perms.iter().enumerate() {
|
||||
rotated_signature[perm[0]] = signature[0];
|
||||
rotated_signature[perm[1]] = signature[1];
|
||||
rotated_signature[perm[2]] = signature[2];
|
||||
rotated_signature[perm[3]] = signature[3];
|
||||
rotated_signature[4] = signature[4];
|
||||
rotated_signature[5] = signature[5];
|
||||
|
||||
if &module.1[0..6] == &rotated_signature[0..6] {
|
||||
return Some(Module { vol_idx: i, dir });
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
})
|
||||
.choose(rng);
|
||||
|
||||
if let Some(module) = module {
|
||||
let kind = this_cell.kind.clone();
|
||||
let _ = self.set(pos, TownCell {
|
||||
kind,
|
||||
module: Some(module),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum ModuleKind {
|
||||
This,
|
||||
That,
|
||||
}
|
||||
|
||||
fn module(name: &str, sig: [ModuleKind; 6]) -> (Arc<Structure>, [ModuleKind; 6]) {
|
||||
(
|
||||
assets::load(&format!("world.module.{}", name)).unwrap(),
|
||||
sig,
|
||||
)
|
||||
}
|
||||
|
||||
fn modules_from_kind(kind: &CellKind) -> Option<&'static [(Arc<Structure>, [ModuleKind; 6])]> {
|
||||
match kind {
|
||||
CellKind::House(_) => Some(&HOUSE_MODULES),
|
||||
CellKind::Wall => Some(&WALL_MODULES),
|
||||
CellKind::Well => Some(&WELL_MODULES),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref HOUSE_MODULES: Vec<(Arc<Structure>, [ModuleKind; 6])> = {
|
||||
use ModuleKind::*;
|
||||
vec![
|
||||
module("human.floor_ground", [This, This, This, This, This, That]),
|
||||
module("human.stair_ground", [This, This, This, This, This, That]),
|
||||
module("human.corner_ground", [This, This, That, That, This, That]),
|
||||
module("human.window_corner_ground", [
|
||||
This, This, That, That, This, That,
|
||||
]),
|
||||
module("human.wall_ground", [This, This, This, That, This, That]),
|
||||
module("human.door_ground", [This, This, This, That, This, That]),
|
||||
module("human.window_ground", [This, This, This, That, This, That]),
|
||||
module("human.floor_roof", [This, This, This, This, That, This]),
|
||||
module("human.corner_roof", [This, This, That, That, That, This]),
|
||||
module("human.chimney_roof", [This, This, That, That, That, This]),
|
||||
module("human.wall_roof", [This, This, This, That, That, This]),
|
||||
module("human.floor_upstairs", [This, This, This, This, This, This]),
|
||||
module("human.balcony_upstairs", [
|
||||
This, This, This, This, This, This,
|
||||
]),
|
||||
module("human.corner_upstairs", [
|
||||
This, This, That, That, This, This,
|
||||
]),
|
||||
module("human.window_corner_upstairs", [
|
||||
This, This, That, That, This, This,
|
||||
]),
|
||||
module("human.wall_upstairs", [This, This, This, That, This, This]),
|
||||
module("human.window_upstairs", [
|
||||
This, This, This, That, This, This,
|
||||
]),
|
||||
]
|
||||
};
|
||||
pub static ref WALL_MODULES: Vec<(Arc<Structure>, [ModuleKind; 6])> = {
|
||||
use ModuleKind::*;
|
||||
vec![
|
||||
module("wall.edge_ground", [This, That, This, That, This, That]),
|
||||
module("wall.edge_mid", [This, That, This, That, This, This]),
|
||||
module("wall.edge_top", [This, That, This, That, That, This]),
|
||||
module("wall.corner_ground", [This, This, That, That, This, That]),
|
||||
module("wall.corner_mid", [This, This, That, That, This, This]),
|
||||
module("wall.corner_top", [This, This, That, That, That, This]),
|
||||
module("wall.end_top", [That, This, That, That, That, This]),
|
||||
module("wall.single_top", [That, That, That, That, That, This]),
|
||||
]
|
||||
};
|
||||
pub static ref WELL_MODULES: Vec<(Arc<Structure>, [ModuleKind; 6])> = {
|
||||
use ModuleKind::*;
|
||||
vec![module("misc.well", [That; 6])]
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
// TODO
|
||||
struct ModuleModel {
|
||||
near: u64,
|
||||
mask: u64,
|
||||
vol: Arc<Structure>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum NearKind {
|
||||
This,
|
||||
That,
|
||||
}
|
||||
|
||||
impl ModuleModel {
|
||||
pub fn generate_list(_details: &[(&str, &[([i32; 3], NearKind)])]) -> Vec<Self> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
*/
|
@ -1,36 +0,0 @@
|
||||
use rand::prelude::*;
|
||||
use vek::*;
|
||||
|
||||
pub const UNITS: [Vec2<i32>; 4] = [
|
||||
Vec2 { x: 1, y: 0 },
|
||||
Vec2 { x: 0, y: 1 },
|
||||
Vec2 { x: -1, y: 0 },
|
||||
Vec2 { x: 0, y: -1 },
|
||||
];
|
||||
|
||||
pub fn dir(i: usize) -> Vec2<i32> { UNITS[i % 4] }
|
||||
|
||||
pub fn unit(i: usize) -> (Vec2<i32>, Vec2<i32>) { (UNITS[i % 4], UNITS[(i + 1) % 4]) }
|
||||
|
||||
// unused
|
||||
//pub fn gen_unit(rng: &mut impl Rng) -> (Vec2<i32>, Vec2<i32>) {
|
||||
// unit(rng.gen_range(0, 4))
|
||||
//}
|
||||
|
||||
pub fn gen_dir(rng: &mut impl Rng) -> Vec2<i32> { UNITS[rng.gen_range(0, 4)] }
|
||||
|
||||
pub const UNITS_3D: [Vec3<i32>; 6] = [
|
||||
Vec3 { x: 1, y: 0, z: 0 },
|
||||
Vec3 { x: 0, y: 1, z: 0 },
|
||||
Vec3 { x: -1, y: 0, z: 0 },
|
||||
Vec3 { x: 0, y: -1, z: 0 },
|
||||
Vec3 { x: 0, y: 0, z: 1 },
|
||||
Vec3 { x: 0, y: 0, z: -1 },
|
||||
];
|
||||
|
||||
pub fn dir_3d(i: usize) -> Vec3<i32> { UNITS_3D[i % 6] }
|
||||
|
||||
// unused
|
||||
//pub fn gen_dir_3d(rng: &mut impl Rng) -> Vec3<i32> {
|
||||
// UNITS_3D[rng.gen_range(0, 6)]
|
||||
//}
|
@ -1,215 +0,0 @@
|
||||
use crate::util::Grid;
|
||||
use common::vol::{BaseVol, ReadVol, Vox, WriteVol};
|
||||
use rand::prelude::*;
|
||||
use std::ops::Range;
|
||||
use vek::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum ColumnKind {
|
||||
Road,
|
||||
//Wall,
|
||||
Internal,
|
||||
//External, // Outside the boundary wall
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct TownColumn {
|
||||
pub ground: i32,
|
||||
pub kind: Option<ColumnKind>,
|
||||
}
|
||||
|
||||
impl TownColumn {
|
||||
pub fn is_empty(&self) -> bool { self.kind.is_none() }
|
||||
|
||||
pub fn is_road(&self) -> bool {
|
||||
self.kind
|
||||
.as_ref()
|
||||
.map(|kind| match kind {
|
||||
ColumnKind::Road => true,
|
||||
_ => false,
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct Module {
|
||||
pub vol_idx: usize,
|
||||
pub dir: usize,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum CellKind {
|
||||
Empty,
|
||||
Park,
|
||||
Rock,
|
||||
Road,
|
||||
Wall,
|
||||
House(usize),
|
||||
Well,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct TownCell {
|
||||
pub kind: CellKind,
|
||||
pub module: Option<Module>,
|
||||
}
|
||||
|
||||
impl TownCell {
|
||||
pub fn is_space(&self) -> bool {
|
||||
match self.kind {
|
||||
CellKind::Empty => true,
|
||||
CellKind::Park => true,
|
||||
CellKind::Road => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_foundation(&self) -> bool {
|
||||
match self.kind {
|
||||
CellKind::Rock => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Vox for TownCell {
|
||||
fn empty() -> Self {
|
||||
Self {
|
||||
kind: CellKind::Empty,
|
||||
module: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_empty(&self) -> bool {
|
||||
match self.kind {
|
||||
CellKind::Empty => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CellKind> for TownCell {
|
||||
fn from(kind: CellKind) -> Self { Self { kind, module: None } }
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum TownError {
|
||||
OutOfBounds,
|
||||
}
|
||||
|
||||
const HEIGHT: usize = 24;
|
||||
const UNDERGROUND_DEPTH: i32 = 5;
|
||||
|
||||
type GridItem = (i32, TownColumn, Vec<TownCell>);
|
||||
|
||||
pub struct TownVol {
|
||||
grid: Grid<GridItem>,
|
||||
}
|
||||
|
||||
impl TownVol {
|
||||
pub fn generate_from(
|
||||
size: Vec2<i32>,
|
||||
mut f: impl FnMut(Vec2<i32>) -> (i32, TownColumn),
|
||||
mut g: impl FnMut((&TownColumn, Vec3<i32>)) -> TownCell,
|
||||
) -> Self {
|
||||
let mut this = Self {
|
||||
grid: Grid::new(
|
||||
(0, TownColumn::default(), vec![TownCell::empty(); HEIGHT]),
|
||||
size,
|
||||
),
|
||||
};
|
||||
|
||||
for (pos, (base, col, cells)) in this.grid.iter_mut() {
|
||||
let column = f(pos);
|
||||
*base = column.0;
|
||||
*col = column.1;
|
||||
for z in 0..HEIGHT {
|
||||
cells[z] = g((
|
||||
col,
|
||||
Vec3::new(pos.x, pos.y, *base - UNDERGROUND_DEPTH + z as i32),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
this
|
||||
}
|
||||
|
||||
pub fn size(&self) -> Vec2<i32> { self.grid.size() }
|
||||
|
||||
pub fn set_col_kind(&mut self, pos: Vec2<i32>, kind: Option<ColumnKind>) {
|
||||
self.grid.get_mut(pos).map(|col| col.1.kind = kind);
|
||||
}
|
||||
|
||||
pub fn col(&self, pos: Vec2<i32>) -> Option<&TownColumn> {
|
||||
self.grid.get(pos).map(|col| &col.1)
|
||||
}
|
||||
|
||||
pub fn col_range(&self, pos: Vec2<i32>) -> Option<Range<i32>> {
|
||||
self.grid.get(pos).map(|col| {
|
||||
let lower = col.0 - UNDERGROUND_DEPTH;
|
||||
lower..lower + HEIGHT as i32
|
||||
})
|
||||
}
|
||||
|
||||
pub fn choose_column(
|
||||
&self,
|
||||
rng: &mut impl Rng,
|
||||
mut f: impl FnMut(Vec2<i32>, &TownColumn) -> bool,
|
||||
) -> Option<Vec2<i32>> {
|
||||
self.grid
|
||||
.iter()
|
||||
.filter(|(pos, col)| f(*pos, &col.1))
|
||||
.choose(rng)
|
||||
.map(|(pos, _)| pos)
|
||||
}
|
||||
|
||||
pub fn choose_cell(
|
||||
&self,
|
||||
rng: &mut impl Rng,
|
||||
mut f: impl FnMut(Vec3<i32>, &TownCell) -> bool,
|
||||
) -> Option<Vec3<i32>> {
|
||||
self.grid
|
||||
.iter()
|
||||
.map(|(pos, (base, _, cells))| {
|
||||
cells.iter().enumerate().map(move |(i, cell)| {
|
||||
(
|
||||
Vec3::new(pos.x, pos.y, *base - UNDERGROUND_DEPTH + i as i32),
|
||||
cell,
|
||||
)
|
||||
})
|
||||
})
|
||||
.flatten()
|
||||
.filter(|(pos, cell)| f(*pos, *cell))
|
||||
.choose(rng)
|
||||
.map(|(pos, _)| pos)
|
||||
}
|
||||
}
|
||||
|
||||
impl BaseVol for TownVol {
|
||||
type Error = TownError;
|
||||
type Vox = TownCell;
|
||||
}
|
||||
|
||||
impl ReadVol for TownVol {
|
||||
fn get(&self, pos: Vec3<i32>) -> Result<&Self::Vox, Self::Error> {
|
||||
match self.grid.get(Vec2::from(pos)) {
|
||||
Some((base, _, cells)) => cells
|
||||
.get((pos.z + UNDERGROUND_DEPTH - *base) as usize)
|
||||
.ok_or(TownError::OutOfBounds),
|
||||
None => Err(TownError::OutOfBounds),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WriteVol for TownVol {
|
||||
fn set(&mut self, pos: Vec3<i32>, vox: Self::Vox) -> Result<(), Self::Error> {
|
||||
match self.grid.get_mut(Vec2::from(pos)) {
|
||||
Some((base, _, cells)) => cells
|
||||
.get_mut((pos.z + UNDERGROUND_DEPTH - *base) as usize)
|
||||
.map(|cell| *cell = vox)
|
||||
.ok_or(TownError::OutOfBounds),
|
||||
None => Err(TownError::OutOfBounds),
|
||||
}
|
||||
}
|
||||
}
|
@ -6,8 +6,8 @@ mod all;
|
||||
mod block;
|
||||
mod column;
|
||||
pub mod config;
|
||||
pub mod generator;
|
||||
pub mod sim;
|
||||
pub mod site;
|
||||
pub mod util;
|
||||
|
||||
// Reexports
|
||||
|
@ -26,7 +26,7 @@ use crate::{
|
||||
all::ForestKind,
|
||||
block::BlockGen,
|
||||
column::ColumnGen,
|
||||
generator::{Settlement, Site},
|
||||
site::{Settlement, Site},
|
||||
util::{seed_expan, FastNoise, RandomField, Sampler, StructureGen2d},
|
||||
CONFIG,
|
||||
};
|
||||
|
@ -1,11 +1,7 @@
|
||||
pub mod settlement;
|
||||
mod town;
|
||||
mod settlement;
|
||||
|
||||
// Reexports
|
||||
pub use self::{
|
||||
settlement::Settlement,
|
||||
town::{TownGen, TownState},
|
||||
};
|
||||
pub use self::settlement::Settlement;
|
||||
|
||||
use crate::{
|
||||
block::ZCache,
|
||||
@ -52,34 +48,3 @@ impl Site {
|
||||
impl From<Settlement> for Site {
|
||||
fn from(settlement: Settlement) -> Self { Site::Settlement(Arc::new(settlement)) }
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct SpawnRules {
|
||||
pub trees: bool,
|
||||
pub cliffs: bool,
|
||||
}
|
||||
|
||||
impl Default for SpawnRules {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
trees: true,
|
||||
cliffs: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SpawnRules {
|
||||
pub fn and(self, other: Self) -> Self {
|
||||
Self {
|
||||
trees: self.trees && other.trees,
|
||||
cliffs: self.cliffs && other.cliffs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Generator<'a, T: 'a>:
|
||||
Sampler<'a, Index = (&'a T, Vec3<i32>, &'a ColumnSample<'a>, f32), Sample = Option<Block>>
|
||||
{
|
||||
fn get_z_limits(&self, state: &'a T, wpos: Vec2<i32>, sample: &ColumnSample) -> (f32, f32);
|
||||
fn spawn_rules(&self, town: &'a TownState, wpos: Vec2<i32>) -> SpawnRules;
|
||||
}
|
Loading…
Reference in New Issue
Block a user