mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'tormod/worldgen-refactorings' into 'master'
Make sure location hint calculation is only done once See merge request veloren/veloren!3967
This commit is contained in:
commit
f7688462a1
@ -107,20 +107,22 @@ impl ProximitySpec {
|
||||
}
|
||||
}
|
||||
|
||||
struct ProximityRequirements {
|
||||
struct ProximityRequirementsBuilder {
|
||||
all_of: Vec<ProximitySpec>,
|
||||
any_of: Vec<ProximitySpec>,
|
||||
}
|
||||
|
||||
impl ProximityRequirements {
|
||||
pub fn satisfied_by(&self, site: Vec2<i32>) -> bool {
|
||||
let all_of_compliance = self.all_of.iter().all(|spec| spec.satisfied_by(site));
|
||||
let any_of_compliance =
|
||||
self.any_of.is_empty() || self.any_of.iter().any(|spec| spec.satisfied_by(site));
|
||||
all_of_compliance && any_of_compliance
|
||||
impl ProximityRequirementsBuilder {
|
||||
pub fn finalize(self, world_dims: &Aabr<i32>) -> ProximityRequirements {
|
||||
let location_hint = self.location_hint(world_dims);
|
||||
ProximityRequirements {
|
||||
all_of: self.all_of,
|
||||
any_of: self.any_of,
|
||||
location_hint,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn location_hint(&self, world_dims: &Aabr<i32>) -> Aabr<i32> {
|
||||
fn location_hint(&self, world_dims: &Aabr<i32>) -> Aabr<i32> {
|
||||
let bounding_box_of_point = |point: Vec2<i32>, max_distance: i32| Aabr {
|
||||
min: Vec2 {
|
||||
x: point.x - max_distance,
|
||||
@ -162,7 +164,7 @@ impl ProximityRequirements {
|
||||
}
|
||||
|
||||
pub fn new() -> Self {
|
||||
ProximityRequirements {
|
||||
Self {
|
||||
all_of: Vec::new(),
|
||||
any_of: Vec::new(),
|
||||
}
|
||||
@ -189,6 +191,25 @@ impl ProximityRequirements {
|
||||
}
|
||||
}
|
||||
|
||||
struct ProximityRequirements {
|
||||
all_of: Vec<ProximitySpec>,
|
||||
any_of: Vec<ProximitySpec>,
|
||||
location_hint: Aabr<i32>,
|
||||
}
|
||||
|
||||
impl ProximityRequirements {
|
||||
pub fn satisfied_by(&self, site: Vec2<i32>) -> bool {
|
||||
if self.location_hint.contains_point(site) {
|
||||
let all_of_compliance = self.all_of.iter().all(|spec| spec.satisfied_by(site));
|
||||
let any_of_compliance =
|
||||
self.any_of.is_empty() || self.any_of.iter().any(|spec| spec.satisfied_by(site));
|
||||
all_of_compliance && any_of_compliance
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, R: Rng> GenCtx<'a, R> {
|
||||
pub fn reseed(&mut self) -> GenCtx<'_, impl Rng> {
|
||||
let mut entropy = self.rng.gen::<[u8; 32]>();
|
||||
@ -235,16 +256,18 @@ impl Civs {
|
||||
info!(?initial_civ_count, "all civilisations created");
|
||||
|
||||
prof_span!(guard, "find locations and establish sites");
|
||||
let world_dims = ctx.sim.get_aabr();
|
||||
for _ in 0..initial_civ_count * 3 {
|
||||
attempt(5, || {
|
||||
let (loc, kind) = match ctx.rng.gen_range(0..64) {
|
||||
0..=5 => (
|
||||
find_site_loc(
|
||||
&mut ctx,
|
||||
&ProximityRequirements::new()
|
||||
&ProximityRequirementsBuilder::new()
|
||||
.avoid_all_of(this.castle_enemies(), 40)
|
||||
.close_to_one_of(this.towns(), 20),
|
||||
SiteKind::Castle,
|
||||
.close_to_one_of(this.towns(), 20)
|
||||
.finalize(&world_dims),
|
||||
&SiteKind::Castle,
|
||||
)?,
|
||||
SiteKind::Castle,
|
||||
),
|
||||
@ -253,9 +276,10 @@ impl Civs {
|
||||
(
|
||||
find_site_loc(
|
||||
&mut ctx,
|
||||
&ProximityRequirements::new()
|
||||
.avoid_all_of(this.tree_enemies(), 40),
|
||||
SiteKind::GiantTree,
|
||||
&ProximityRequirementsBuilder::new()
|
||||
.avoid_all_of(this.tree_enemies(), 40)
|
||||
.finalize(&world_dims),
|
||||
&SiteKind::GiantTree,
|
||||
)?,
|
||||
SiteKind::GiantTree,
|
||||
)
|
||||
@ -263,9 +287,10 @@ impl Civs {
|
||||
(
|
||||
find_site_loc(
|
||||
&mut ctx,
|
||||
&ProximityRequirements::new()
|
||||
.avoid_all_of(this.tree_enemies(), 40),
|
||||
SiteKind::Tree,
|
||||
&ProximityRequirementsBuilder::new()
|
||||
.avoid_all_of(this.tree_enemies(), 40)
|
||||
.finalize(&world_dims),
|
||||
&SiteKind::Tree,
|
||||
)?,
|
||||
SiteKind::Tree,
|
||||
)
|
||||
@ -274,8 +299,10 @@ impl Civs {
|
||||
32..=37 => (
|
||||
find_site_loc(
|
||||
&mut ctx,
|
||||
&ProximityRequirements::new().avoid_all_of(this.gnarling_enemies(), 40),
|
||||
SiteKind::Gnarling,
|
||||
&ProximityRequirementsBuilder::new()
|
||||
.avoid_all_of(this.gnarling_enemies(), 40)
|
||||
.finalize(&world_dims),
|
||||
&SiteKind::Gnarling,
|
||||
)?,
|
||||
SiteKind::Gnarling,
|
||||
),
|
||||
@ -283,25 +310,30 @@ impl Civs {
|
||||
38..=43 => (
|
||||
find_site_loc(
|
||||
&mut ctx,
|
||||
&ProximityRequirements::new()
|
||||
.avoid_all_of(this.chapel_site_enemies(), 40),
|
||||
SiteKind::ChapelSite,
|
||||
&ProximityRequirementsBuilder::new()
|
||||
.avoid_all_of(this.chapel_site_enemies(), 40)
|
||||
.finalize(&world_dims),
|
||||
&SiteKind::ChapelSite,
|
||||
)?,
|
||||
SiteKind::ChapelSite,
|
||||
),
|
||||
44..=49 => (
|
||||
find_site_loc(
|
||||
&mut ctx,
|
||||
&ProximityRequirements::new().avoid_all_of(this.gnarling_enemies(), 40),
|
||||
SiteKind::Adlet,
|
||||
&ProximityRequirementsBuilder::new()
|
||||
.avoid_all_of(this.gnarling_enemies(), 40)
|
||||
.finalize(&world_dims),
|
||||
&SiteKind::Adlet,
|
||||
)?,
|
||||
SiteKind::Adlet,
|
||||
),
|
||||
_ => (
|
||||
find_site_loc(
|
||||
&mut ctx,
|
||||
&ProximityRequirements::new().avoid_all_of(this.dungeon_enemies(), 40),
|
||||
SiteKind::Dungeon,
|
||||
&ProximityRequirementsBuilder::new()
|
||||
.avoid_all_of(this.dungeon_enemies(), 40)
|
||||
.finalize(&world_dims),
|
||||
&SiteKind::Dungeon,
|
||||
)?,
|
||||
SiteKind::Dungeon,
|
||||
),
|
||||
@ -763,10 +795,12 @@ impl Civs {
|
||||
13..=18 => SiteKind::SavannahPit,
|
||||
_ => SiteKind::Refactor,
|
||||
};
|
||||
let world_dims = ctx.sim.get_aabr();
|
||||
let site = attempt(100, || {
|
||||
let avoid_town_enemies =
|
||||
ProximityRequirements::new().avoid_all_of(self.town_enemies(), 60);
|
||||
let loc = find_site_loc(ctx, &avoid_town_enemies, kind)?;
|
||||
let avoid_town_enemies = ProximityRequirementsBuilder::new()
|
||||
.avoid_all_of(self.town_enemies(), 60)
|
||||
.finalize(&world_dims);
|
||||
let loc = find_site_loc(ctx, &avoid_town_enemies, &kind)?;
|
||||
Some(self.establish_site(ctx, loc, |place| Site {
|
||||
kind,
|
||||
site_tmp: None,
|
||||
@ -1497,20 +1531,13 @@ fn loc_suitable_for_walking(sim: &WorldSim, loc: Vec2<i32>) -> bool {
|
||||
fn find_site_loc(
|
||||
ctx: &mut GenCtx<impl Rng>,
|
||||
proximity_reqs: &ProximityRequirements,
|
||||
site_kind: SiteKind,
|
||||
site_kind: &SiteKind,
|
||||
) -> Option<Vec2<i32>> {
|
||||
prof_span!("find_site_loc");
|
||||
const MAX_ATTEMPTS: usize = 10000;
|
||||
let mut loc = None;
|
||||
let location_hint = proximity_reqs.location_hint;
|
||||
for _ in 0..MAX_ATTEMPTS {
|
||||
let world_dims = Aabr {
|
||||
min: Vec2 { x: 0, y: 0 },
|
||||
max: Vec2 {
|
||||
x: ctx.sim.get_size().x as i32,
|
||||
y: ctx.sim.get_size().y as i32,
|
||||
},
|
||||
};
|
||||
let location_hint = proximity_reqs.location_hint(&world_dims);
|
||||
let test_loc = loc.unwrap_or_else(|| {
|
||||
Vec2::new(
|
||||
ctx.rng.gen_range(location_hint.min.x..location_hint.max.x),
|
||||
@ -1868,22 +1895,51 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn empty_proximity_requirements() {
|
||||
let reqs = ProximityRequirements::new();
|
||||
let world_dims = Aabr {
|
||||
min: Vec2 { x: 0, y: 0 },
|
||||
max: Vec2 {
|
||||
x: 200_i32,
|
||||
y: 200_i32,
|
||||
},
|
||||
};
|
||||
let reqs = ProximityRequirementsBuilder::new().finalize(&world_dims);
|
||||
assert!(reqs.satisfied_by(Vec2 { x: 0, y: 0 }));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn avoid_proximity_requirements() {
|
||||
let reqs =
|
||||
ProximityRequirements::new().avoid_all_of(vec![Vec2 { x: 0, y: 0 }].into_iter(), 10);
|
||||
let world_dims = Aabr {
|
||||
min: Vec2 {
|
||||
x: -200_i32,
|
||||
y: -200_i32,
|
||||
},
|
||||
max: Vec2 {
|
||||
x: 200_i32,
|
||||
y: 200_i32,
|
||||
},
|
||||
};
|
||||
let reqs = ProximityRequirementsBuilder::new()
|
||||
.avoid_all_of(vec![Vec2 { x: 0, y: 0 }].into_iter(), 10)
|
||||
.finalize(&world_dims);
|
||||
assert!(reqs.satisfied_by(Vec2 { x: 8, y: -8 }));
|
||||
assert!(!reqs.satisfied_by(Vec2 { x: -1, y: 1 }));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn near_proximity_requirements() {
|
||||
let reqs =
|
||||
ProximityRequirements::new().close_to_one_of(vec![Vec2 { x: 0, y: 0 }].into_iter(), 10);
|
||||
let world_dims = Aabr {
|
||||
min: Vec2 {
|
||||
x: -200_i32,
|
||||
y: -200_i32,
|
||||
},
|
||||
max: Vec2 {
|
||||
x: 200_i32,
|
||||
y: 200_i32,
|
||||
},
|
||||
};
|
||||
let reqs = ProximityRequirementsBuilder::new()
|
||||
.close_to_one_of(vec![Vec2 { x: 0, y: 0 }].into_iter(), 10)
|
||||
.finalize(&world_dims);
|
||||
assert!(reqs.satisfied_by(Vec2 { x: 1, y: -1 }));
|
||||
assert!(!reqs.satisfied_by(Vec2 { x: -8, y: 8 }));
|
||||
}
|
||||
@ -1891,16 +1947,24 @@ mod tests {
|
||||
#[test]
|
||||
fn complex_proximity_requirements() {
|
||||
let a_site = Vec2 { x: 572, y: 724 };
|
||||
let reqs = ProximityRequirements::new()
|
||||
let world_dims = Aabr {
|
||||
min: Vec2 { x: 0, y: 0 },
|
||||
max: Vec2 {
|
||||
x: 1000_i32,
|
||||
y: 1000_i32,
|
||||
},
|
||||
};
|
||||
let reqs = ProximityRequirementsBuilder::new()
|
||||
.close_to_one_of(vec![a_site].into_iter(), 60)
|
||||
.avoid_all_of(vec![a_site].into_iter(), 40);
|
||||
.avoid_all_of(vec![a_site].into_iter(), 40)
|
||||
.finalize(&world_dims);
|
||||
assert!(reqs.satisfied_by(Vec2 { x: 572, y: 774 }));
|
||||
assert!(!reqs.satisfied_by(a_site));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn location_hint() {
|
||||
let reqs = ProximityRequirements::new().close_to_one_of(
|
||||
let reqs = ProximityRequirementsBuilder::new().close_to_one_of(
|
||||
vec![Vec2 { x: 1, y: 0 }, Vec2 { x: 13, y: 12 }].into_iter(),
|
||||
10,
|
||||
);
|
||||
|
@ -1581,6 +1581,17 @@ impl WorldSim {
|
||||
|
||||
pub fn get_size(&self) -> Vec2<u32> { self.map_size_lg().chunks().map(u32::from) }
|
||||
|
||||
pub fn get_aabr(&self) -> Aabr<i32> {
|
||||
let size = self.get_size();
|
||||
Aabr {
|
||||
min: Vec2 { x: 0, y: 0 },
|
||||
max: Vec2 {
|
||||
x: size.x as i32,
|
||||
y: size.y as i32,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_oob_chunk(&self) -> TerrainChunk {
|
||||
TerrainChunk::water(CONFIG.sea_level as i32)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user