mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
blah
This commit is contained in:
parent
e4ab0be63d
commit
ca9c75a499
@ -33,11 +33,16 @@ use crate::{
|
||||
use rand::prelude::*;
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
use tracing::warn;
|
||||
use std::{
|
||||
convert::AsRef,
|
||||
marker::PhantomData,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Deserialize)]
|
||||
pub struct Lottery<T> {
|
||||
items: Vec<(f32, T)>,
|
||||
pub struct Lottery<T, Items: AsRef<[(f32, T)]> = Vec<(f32, T)>> {
|
||||
items: Items,
|
||||
total: f32,
|
||||
phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: DeserializeOwned + Send + Sync + 'static> assets::Asset for Lottery<T> {
|
||||
@ -55,15 +60,29 @@ impl<T> From<Vec<(f32, T)>> for Lottery<T> {
|
||||
*rate = total - *rate;
|
||||
}
|
||||
|
||||
Self { items, total }
|
||||
Self { items, total, phantom: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Lottery<T> {
|
||||
impl<'a, T> Lottery<T, &'a mut [(f32, T)]> {
|
||||
pub fn from_slice(items: &'a mut [(f32, T)]) -> Self {
|
||||
let mut total = 0.0;
|
||||
|
||||
for (rate, _) in items.iter_mut() {
|
||||
total += *rate;
|
||||
*rate = total - *rate;
|
||||
}
|
||||
|
||||
Self { items, total, phantom: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, Items: AsRef<[(f32, T)]>> Lottery<T, Items> {
|
||||
pub fn choose_seeded(&self, seed: u32) -> &T {
|
||||
let x = ((seed % 65536) as f32 / 65536.0) * self.total;
|
||||
&self.items[self
|
||||
&self.items.as_ref()[self
|
||||
.items
|
||||
.as_ref()
|
||||
.binary_search_by(|(y, _)| y.partial_cmp(&x).unwrap())
|
||||
.unwrap_or_else(|i| i.saturating_sub(1))]
|
||||
.1
|
||||
@ -71,7 +90,7 @@ impl<T> Lottery<T> {
|
||||
|
||||
pub fn choose(&self) -> &T { self.choose_seeded(thread_rng().gen()) }
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = &(f32, T)> { self.items.iter() }
|
||||
pub fn iter(&self) -> impl Iterator<Item = &(f32, T)> { self.items.as_ref().iter() }
|
||||
|
||||
pub fn total(&self) -> f32 { self.total }
|
||||
}
|
||||
|
@ -241,7 +241,7 @@ impl Fill {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Structure {
|
||||
pub trait Render {
|
||||
fn render<F: FnMut(Primitive) -> Id<Primitive>, G: FnMut(Id<Primitive>, Fill)>(
|
||||
&self,
|
||||
site: &Site,
|
||||
|
@ -1,9 +1,11 @@
|
||||
mod gen;
|
||||
mod planning;
|
||||
mod plot;
|
||||
mod structure;
|
||||
mod tile;
|
||||
|
||||
use self::{
|
||||
gen::{Fill, Primitive, Structure},
|
||||
gen::{Fill, Primitive, Render},
|
||||
plot::{Plot, PlotKind},
|
||||
tile::{HazardKind, KeepKind, Ori, RoofKind, Tile, TileGrid, TileKind, TILE_SIZE},
|
||||
};
|
||||
@ -166,7 +168,7 @@ impl Site {
|
||||
) -> Option<(Aabr<i32>, Vec2<i32>)> {
|
||||
self.tiles.find_near(search_pos, |center, _| {
|
||||
self.tiles
|
||||
.grow_aabr(center, area_range.clone(), min_dims)
|
||||
.grow_aabr(center, area_range.clone(), min_dims, 0)
|
||||
.ok()
|
||||
.filter(|aabr| {
|
||||
(aabr.min.x..aabr.max.x)
|
||||
@ -285,6 +287,13 @@ impl Site {
|
||||
|
||||
site.demarcate_obstacles(land);
|
||||
|
||||
for _ in 0..100 {
|
||||
site.tick(land, &mut rng);
|
||||
}
|
||||
|
||||
return site;
|
||||
|
||||
/*
|
||||
site.make_plaza(land, &mut rng);
|
||||
|
||||
let build_chance = Lottery::from(vec![(128.0, 1), (5.0, 2), (8.0, 3), (0.75, 4)]);
|
||||
@ -523,6 +532,7 @@ impl Site {
|
||||
}
|
||||
|
||||
site
|
||||
*/
|
||||
}
|
||||
|
||||
pub fn wpos_tile_pos(&self, wpos2d: Vec2<i32>) -> Vec2<i32> {
|
||||
@ -711,6 +721,7 @@ impl Site {
|
||||
|
||||
for plot in plots_to_render {
|
||||
let (prim_tree, fills) = match &self.plots[plot].kind {
|
||||
PlotKind::Hut(hut) => hut.render_collect(self),
|
||||
PlotKind::House(house) => house.render_collect(self),
|
||||
PlotKind::Castle(castle) => castle.render_collect(self),
|
||||
_ => continue,
|
||||
|
35
world/src/site2/planning.rs
Normal file
35
world/src/site2/planning.rs
Normal file
@ -0,0 +1,35 @@
|
||||
use common::lottery::Lottery;
|
||||
use super::{
|
||||
*,
|
||||
structure::{Structure, Hut},
|
||||
};
|
||||
|
||||
// All are weights, must be positive, 1.0 is default.
|
||||
pub struct Values {
|
||||
defence: f32,
|
||||
farming: f32,
|
||||
housing: f32,
|
||||
}
|
||||
|
||||
impl Site {
|
||||
// TODO: How long is a tick? A year?
|
||||
pub fn tick(&mut self, land: &Land, rng: &mut impl Rng) {
|
||||
let values = Values {
|
||||
defence: 1.0,
|
||||
farming: 1.0,
|
||||
housing: 1.0,
|
||||
};
|
||||
|
||||
match *Lottery::from_slice(&mut [
|
||||
(10.0, 0), // Huts
|
||||
])
|
||||
.choose_seeded(rng.gen())
|
||||
{
|
||||
0 => {
|
||||
Hut::choose_location((), land, self, rng)
|
||||
.map(|hut| hut.generate(land, self, rng));
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ mod castle;
|
||||
mod house;
|
||||
|
||||
pub use self::{castle::Castle, house::House};
|
||||
pub use super::structure::Hut;
|
||||
|
||||
use super::*;
|
||||
use crate::util::DHashSet;
|
||||
@ -26,6 +27,7 @@ impl Plot {
|
||||
}
|
||||
|
||||
pub enum PlotKind {
|
||||
Hut(Hut),
|
||||
House(House),
|
||||
Plaza,
|
||||
Castle(Castle),
|
||||
|
@ -41,7 +41,7 @@ impl Castle {
|
||||
}
|
||||
}
|
||||
|
||||
impl Structure for Castle {
|
||||
impl Render for Castle {
|
||||
#[allow(clippy::identity_op)]
|
||||
fn render<F: FnMut(Primitive) -> Id<Primitive>, G: FnMut(Id<Primitive>, Fill)>(
|
||||
&self,
|
||||
|
@ -52,7 +52,7 @@ impl House {
|
||||
}
|
||||
}
|
||||
|
||||
impl Structure for House {
|
||||
impl Render for House {
|
||||
fn render<F: FnMut(Primitive) -> Id<Primitive>, G: FnMut(Id<Primitive>, Fill)>(
|
||||
&self,
|
||||
site: &Site,
|
||||
|
110
world/src/site2/structure/hut.rs
Normal file
110
world/src/site2/structure/hut.rs
Normal file
@ -0,0 +1,110 @@
|
||||
use super::*;
|
||||
use vek::*;
|
||||
|
||||
pub struct Hut {
|
||||
root: Vec2<i32>,
|
||||
tile_aabr: Aabr<i32>,
|
||||
bounds: Aabr<i32>,
|
||||
alt: i32,
|
||||
height: i32,
|
||||
door_dir: Vec2<i32>,
|
||||
}
|
||||
|
||||
impl Structure for Hut {
|
||||
type Config = ();
|
||||
|
||||
fn choose_location<R: Rng>(cfg: Self::Config, land: &Land, site: &Site, rng: &mut R) -> Option<Self> {
|
||||
let (tile_aabr, root) = site.tiles.find_near(
|
||||
Vec2::zero(),
|
||||
|tile, _| if rng.gen_range(0..16) == 0 {
|
||||
site.tiles.grow_aabr(tile, 4..9, (2, 2), 2).ok()
|
||||
} else {
|
||||
None
|
||||
},
|
||||
)?;
|
||||
let center = (tile_aabr.min + (tile_aabr.max - 1)) / 2;
|
||||
|
||||
Some(Self {
|
||||
root,
|
||||
tile_aabr,
|
||||
bounds: Aabr {
|
||||
min: site.tile_wpos(tile_aabr.min),
|
||||
max: site.tile_wpos(tile_aabr.max),
|
||||
},
|
||||
alt: land.get_alt_approx(site.tile_center_wpos(center)) as i32,
|
||||
height: 4,
|
||||
door_dir: match rng.gen_range(0..4) {
|
||||
0 => Vec2::unit_x(),
|
||||
1 => -Vec2::unit_x(),
|
||||
2 => Vec2::unit_y(),
|
||||
3 => -Vec2::unit_y(),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
fn generate<R: Rng>(self, land: &Land, site: &mut Site, rng: &mut R) {
|
||||
let aabr = self.tile_aabr;
|
||||
|
||||
let plot = site.create_plot(Plot {
|
||||
root_tile: self.root,
|
||||
tiles: aabr_tiles(aabr).collect(),
|
||||
seed: rng.gen(),
|
||||
kind: PlotKind::Hut(self),
|
||||
});
|
||||
|
||||
site.blit_aabr(aabr, Tile {
|
||||
kind: TileKind::Building,
|
||||
plot: Some(plot),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for Hut {
|
||||
fn render<F: FnMut(Primitive) -> Id<Primitive>, G: FnMut(Id<Primitive>, Fill)>(
|
||||
&self,
|
||||
site: &Site,
|
||||
mut prim: F,
|
||||
mut fill: G,
|
||||
) {
|
||||
let daub = Fill::Block(Block::new(BlockKind::Wood, Rgb::new(110, 50, 16)));
|
||||
|
||||
let outer = prim(Primitive::Aabb(Aabb {
|
||||
min: (self.bounds.min + 1).with_z(self.alt),
|
||||
max: (self.bounds.max - 1).with_z(self.alt + self.height),
|
||||
}));
|
||||
let inner = prim(Primitive::Aabb(Aabb {
|
||||
min: (self.bounds.min + 2).with_z(self.alt),
|
||||
max: (self.bounds.max - 2).with_z(self.alt + self.height),
|
||||
}));
|
||||
|
||||
let door_pos = site.tile_center_wpos(self.root);
|
||||
let door = prim(Primitive::Aabb(Aabb {
|
||||
min: door_pos.with_z(self.alt),
|
||||
max: (door_pos + self.door_dir * 32).with_z(self.alt + 2),
|
||||
}.made_valid()));
|
||||
|
||||
let space = prim(Primitive::And(inner, door));
|
||||
|
||||
let walls = prim(Primitive::AndNot(outer, space));
|
||||
|
||||
fill(walls, daub);
|
||||
|
||||
let roof_lip = 2;
|
||||
let roof_height = (self.bounds.min - self.bounds.max)
|
||||
.map(|e| e.abs())
|
||||
.reduce_min()
|
||||
.saturating_sub(1)
|
||||
/ 2
|
||||
+ roof_lip
|
||||
+ 1;
|
||||
let roof = prim(Primitive::Pyramid{
|
||||
aabb: Aabb {
|
||||
min: (self.bounds.min + 1 - roof_lip).with_z(self.alt + self.height),
|
||||
max: (self.bounds.max - 1 + roof_lip).with_z(self.alt + self.height + roof_height),
|
||||
},
|
||||
inset: Vec2::broadcast(roof_height),
|
||||
});
|
||||
fill(roof, daub);
|
||||
}
|
||||
}
|
17
world/src/site2/structure/mod.rs
Normal file
17
world/src/site2/structure/mod.rs
Normal file
@ -0,0 +1,17 @@
|
||||
mod hut;
|
||||
|
||||
pub use self::{
|
||||
hut::Hut,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
pub trait Structure: Sized {
|
||||
type Config;
|
||||
|
||||
/// Attempt to choose a location to place this plot in the given site.
|
||||
fn choose_location<R: Rng>(cfg: Self::Config, land: &Land, site: &Site, rng: &mut R) -> Option<Self>;
|
||||
|
||||
/// Generate the plot with the given location information on the given site
|
||||
fn generate<R: Rng>(self, land: &Land, site: &mut Site, rng: &mut R);
|
||||
}
|
@ -75,8 +75,11 @@ impl TileGrid {
|
||||
&self,
|
||||
center: Vec2<i32>,
|
||||
area_range: Range<u32>,
|
||||
min_dims: Extent2<u32>,
|
||||
min_dims: impl Into<Extent2<u32>>,
|
||||
radius: u32,
|
||||
) -> Result<Aabr<i32>, Aabr<i32>> {
|
||||
let min_dims = min_dims.into() + radius * 2;
|
||||
|
||||
let mut aabr = Aabr {
|
||||
min: center,
|
||||
max: center + 1,
|
||||
@ -86,15 +89,16 @@ impl TileGrid {
|
||||
return Err(aabr);
|
||||
};
|
||||
|
||||
let inner_size = |aabr: Aabr<i32>| aabr.size().map(|e| e.saturating_sub(radius as i32 * 2));
|
||||
|
||||
let mut last_growth = 0;
|
||||
for i in 0..32 {
|
||||
if i - last_growth >= 4
|
||||
|| aabr.size().product()
|
||||
+ if i % 2 == 0 {
|
||||
aabr.size().h
|
||||
|| (inner_size(aabr) + if i % 2 == 0 {
|
||||
Extent2::new(0, 1)
|
||||
} else {
|
||||
aabr.size().w
|
||||
}
|
||||
Extent2::new(1, 0)
|
||||
}).product()
|
||||
> area_range.end as i32
|
||||
{
|
||||
break;
|
||||
@ -130,13 +134,19 @@ impl TileGrid {
|
||||
}
|
||||
}
|
||||
|
||||
if aabr.size().product() as u32 >= area_range.start
|
||||
let inner_size = inner_size(aabr);
|
||||
let inner_aabr = Aabr {
|
||||
min: aabr.min + radius as i32,
|
||||
max: aabr.min + radius as i32 + inner_size,
|
||||
};
|
||||
|
||||
if inner_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)
|
||||
Ok(inner_aabr)
|
||||
} else {
|
||||
Err(aabr)
|
||||
Err(inner_aabr)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user