diff --git a/server/src/lib.rs b/server/src/lib.rs index c9fc9484a4..c72ff68331 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -297,17 +297,26 @@ impl Server { // but are needed to be explicit about casting (and to make the compiler stop // complaining) - // spawn in the chunk, that is in the middle of the world - let center_chunk: Vec2 = world.sim().map_size_lg().chunks().map(i32::from) / 2; - - // Find a town to spawn in that's close to the centre of the world - let spawn_chunk = world - .civs() - .sites() - .filter(|site| matches!(site.kind, world::civ::SiteKind::Settlement)) - .map(|site| site.center) - .min_by_key(|site_pos| site_pos.distance_squared(center_chunk)) - .unwrap_or(center_chunk); + // Search for town defined by spawn_town server setting. If this fails, or is + // None, set spawn to the nearest town to the centre of the world + let spawn_chunk = match settings.spawn_town.as_ref().and_then(|spawn_town| { + world.civs().sites().find(|site| { + site.site_tmp + .map_or(false, |id| index.sites[id].name() == spawn_town) + }) + }) { + Some(t) => t.center, + None => { + let center_chunk = world.sim().map_size_lg().chunks().map(i32::from) / 2; + world + .civs() + .sites() + .filter(|site| matches!(site.kind, world::civ::SiteKind::Settlement)) + .map(|site| site.center) + .min_by_key(|site_pos| site_pos.distance_squared(center_chunk)) + .unwrap_or(center_chunk) + }, + }; // Calculate the middle of the chunk in the world let spawn_wpos = TerrainChunkSize::center_wpos(spawn_chunk); diff --git a/server/src/settings.rs b/server/src/settings.rs index 121c7fd4b6..44b418a27c 100644 --- a/server/src/settings.rs +++ b/server/src/settings.rs @@ -42,6 +42,7 @@ pub struct Settings { pub banned_words_files: Vec, pub max_player_group_size: u32, pub client_timeout: Duration, + pub spawn_town: Option, } impl Default for Settings { @@ -59,6 +60,7 @@ impl Default for Settings { banned_words_files: Vec::new(), max_player_group_size: 6, client_timeout: Duration::from_secs(40), + spawn_town: None, } } }