mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
blah
This commit is contained in:
parent
78aa587722
commit
f59ac2f8ee
@ -33,11 +33,16 @@ use crate::{
|
|||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
|
use std::{
|
||||||
|
convert::AsRef,
|
||||||
|
marker::PhantomData,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Deserialize)]
|
||||||
pub struct Lottery<T> {
|
pub struct Lottery<T, Items: AsRef<[(f32, T)]> = Vec<(f32, T)>> {
|
||||||
items: Vec<(f32, T)>,
|
items: Items,
|
||||||
total: f32,
|
total: f32,
|
||||||
|
phantom: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: DeserializeOwned + Send + Sync + 'static> assets::Asset for Lottery<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;
|
*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 {
|
pub fn choose_seeded(&self, seed: u32) -> &T {
|
||||||
let x = ((seed % 65536) as f32 / 65536.0) * self.total;
|
let x = ((seed % 65536) as f32 / 65536.0) * self.total;
|
||||||
&self.items[self
|
&self.items.as_ref()[self
|
||||||
.items
|
.items
|
||||||
|
.as_ref()
|
||||||
.binary_search_by(|(y, _)| y.partial_cmp(&x).unwrap())
|
.binary_search_by(|(y, _)| y.partial_cmp(&x).unwrap())
|
||||||
.unwrap_or_else(|i| i.saturating_sub(1))]
|
.unwrap_or_else(|i| i.saturating_sub(1))]
|
||||||
.1
|
.1
|
||||||
@ -71,7 +90,7 @@ impl<T> Lottery<T> {
|
|||||||
|
|
||||||
pub fn choose(&self) -> &T { self.choose_seeded(thread_rng().gen()) }
|
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 }
|
pub fn total(&self) -> f32 { self.total }
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ impl Fill {
|
|||||||
let inner = Aabr {
|
let inner = Aabr {
|
||||||
min: aabb.min.xy() - 1 + inset,
|
min: aabb.min.xy() - 1 + inset,
|
||||||
max: aabb.max.xy() - inset,
|
max: aabb.max.xy() - inset,
|
||||||
};
|
}.made_valid();
|
||||||
aabb_contains(*aabb, pos)
|
aabb_contains(*aabb, pos)
|
||||||
&& ((inner.projected_point(pos.xy()) - pos.xy())
|
&& ((inner.projected_point(pos.xy()) - pos.xy())
|
||||||
.map(|e| e.abs())
|
.map(|e| e.abs())
|
||||||
@ -241,7 +241,7 @@ impl Fill {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Structure {
|
pub trait Render {
|
||||||
fn render<F: FnMut(Primitive) -> Id<Primitive>, G: FnMut(Id<Primitive>, Fill)>(
|
fn render<F: FnMut(Primitive) -> Id<Primitive>, G: FnMut(Id<Primitive>, Fill)>(
|
||||||
&self,
|
&self,
|
||||||
site: &Site,
|
site: &Site,
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
mod gen;
|
mod gen;
|
||||||
|
mod planning;
|
||||||
mod plot;
|
mod plot;
|
||||||
|
mod structure;
|
||||||
mod tile;
|
mod tile;
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
gen::{Fill, Primitive, Structure},
|
gen::{Fill, Primitive, Render},
|
||||||
plot::{Plot, PlotKind},
|
plot::{Plot, PlotKind},
|
||||||
tile::{HazardKind, KeepKind, Ori, RoofKind, Tile, TileGrid, TileKind, TILE_SIZE},
|
tile::{HazardKind, KeepKind, Ori, RoofKind, Tile, TileGrid, TileKind, TILE_SIZE},
|
||||||
};
|
};
|
||||||
@ -166,7 +168,7 @@ impl Site {
|
|||||||
) -> Option<(Aabr<i32>, Vec2<i32>)> {
|
) -> Option<(Aabr<i32>, Vec2<i32>)> {
|
||||||
self.tiles.find_near(search_pos, |center, _| {
|
self.tiles.find_near(search_pos, |center, _| {
|
||||||
self.tiles
|
self.tiles
|
||||||
.grow_aabr(center, area_range.clone(), min_dims)
|
.grow_aabr(center, area_range.clone(), min_dims, 0)
|
||||||
.ok()
|
.ok()
|
||||||
.filter(|aabr| {
|
.filter(|aabr| {
|
||||||
(aabr.min.x..aabr.max.x)
|
(aabr.min.x..aabr.max.x)
|
||||||
@ -285,6 +287,13 @@ impl Site {
|
|||||||
|
|
||||||
site.demarcate_obstacles(land);
|
site.demarcate_obstacles(land);
|
||||||
|
|
||||||
|
for _ in 0..100 {
|
||||||
|
site.tick(land, &mut rng);
|
||||||
|
}
|
||||||
|
|
||||||
|
return site;
|
||||||
|
|
||||||
|
/*
|
||||||
site.make_plaza(land, &mut rng);
|
site.make_plaza(land, &mut rng);
|
||||||
|
|
||||||
let build_chance = Lottery::from(vec![(128.0, 1), (5.0, 2), (8.0, 3), (0.75, 4)]);
|
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
|
site
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn wpos_tile_pos(&self, wpos2d: Vec2<i32>) -> Vec2<i32> {
|
pub fn wpos_tile_pos(&self, wpos2d: Vec2<i32>) -> Vec2<i32> {
|
||||||
@ -711,6 +721,7 @@ impl Site {
|
|||||||
|
|
||||||
for plot in plots_to_render {
|
for plot in plots_to_render {
|
||||||
let (prim_tree, fills) = match &self.plots[plot].kind {
|
let (prim_tree, fills) = match &self.plots[plot].kind {
|
||||||
|
PlotKind::Hut(hut) => hut.render_collect(self),
|
||||||
PlotKind::House(house) => house.render_collect(self),
|
PlotKind::House(house) => house.render_collect(self),
|
||||||
PlotKind::Castle(castle) => castle.render_collect(self),
|
PlotKind::Castle(castle) => castle.render_collect(self),
|
||||||
_ => continue,
|
_ => 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;
|
mod house;
|
||||||
|
|
||||||
pub use self::{castle::Castle, house::House};
|
pub use self::{castle::Castle, house::House};
|
||||||
|
pub use super::structure::Hut;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::util::DHashSet;
|
use crate::util::DHashSet;
|
||||||
@ -26,6 +27,7 @@ impl Plot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub enum PlotKind {
|
pub enum PlotKind {
|
||||||
|
Hut(Hut),
|
||||||
House(House),
|
House(House),
|
||||||
Plaza,
|
Plaza,
|
||||||
Castle(Castle),
|
Castle(Castle),
|
||||||
|
@ -41,7 +41,7 @@ impl Castle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Structure for Castle {
|
impl Render for Castle {
|
||||||
#[allow(clippy::identity_op)]
|
#[allow(clippy::identity_op)]
|
||||||
fn render<F: FnMut(Primitive) -> Id<Primitive>, G: FnMut(Id<Primitive>, Fill)>(
|
fn render<F: FnMut(Primitive) -> Id<Primitive>, G: FnMut(Id<Primitive>, Fill)>(
|
||||||
&self,
|
&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)>(
|
fn render<F: FnMut(Primitive) -> Id<Primitive>, G: FnMut(Id<Primitive>, Fill)>(
|
||||||
&self,
|
&self,
|
||||||
site: &Site,
|
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,
|
&self,
|
||||||
center: Vec2<i32>,
|
center: Vec2<i32>,
|
||||||
area_range: Range<u32>,
|
area_range: Range<u32>,
|
||||||
min_dims: Extent2<u32>,
|
min_dims: impl Into<Extent2<u32>>,
|
||||||
|
radius: u32,
|
||||||
) -> Result<Aabr<i32>, Aabr<i32>> {
|
) -> Result<Aabr<i32>, Aabr<i32>> {
|
||||||
|
let min_dims = min_dims.into() + radius * 2;
|
||||||
|
|
||||||
let mut aabr = Aabr {
|
let mut aabr = Aabr {
|
||||||
min: center,
|
min: center,
|
||||||
max: center + 1,
|
max: center + 1,
|
||||||
@ -86,15 +89,16 @@ impl TileGrid {
|
|||||||
return Err(aabr);
|
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;
|
let mut last_growth = 0;
|
||||||
for i in 0..32 {
|
for i in 0..32 {
|
||||||
if i - last_growth >= 4
|
if i - last_growth >= 4
|
||||||
|| aabr.size().product()
|
|| (inner_size(aabr) + if i % 2 == 0 {
|
||||||
+ if i % 2 == 0 {
|
Extent2::new(0, 1)
|
||||||
aabr.size().h
|
|
||||||
} else {
|
} else {
|
||||||
aabr.size().w
|
Extent2::new(1, 0)
|
||||||
}
|
}).product()
|
||||||
> area_range.end as i32
|
> area_range.end as i32
|
||||||
{
|
{
|
||||||
break;
|
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().w as u32 >= min_dims.w
|
||||||
&& aabr.size().h as u32 >= min_dims.h
|
&& aabr.size().h as u32 >= min_dims.h
|
||||||
{
|
{
|
||||||
Ok(aabr)
|
Ok(inner_aabr)
|
||||||
} else {
|
} else {
|
||||||
Err(aabr)
|
Err(inner_aabr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user