Added simple world generation for development
parent
aad25db759
commit
34e14900eb
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "adventure_sim"
|
name = "adventure_sim"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,12 @@
|
||||||
[SITE:CAVE]
|
[SITE:CAVE]
|
||||||
[SIZE:1:3]
|
[SIZE:1:3]
|
||||||
# [UNDERGROUND]
|
[UNDERGROUND]
|
||||||
[NATURAL]
|
[NATURAL]
|
||||||
|
|
||||||
|
[SITE:DUNGEON]
|
||||||
|
[SIZE:2:3]
|
||||||
|
[UNDERGROUND]
|
||||||
|
|
||||||
|
[SITE:BANDIT_CAMP]
|
||||||
|
[SIZE:1:1]
|
||||||
|
# [OUTDOORS]
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ pub fn init(app: &mut App) {
|
||||||
// .add_systems(Update, systems::demo_2d);
|
// .add_systems(Update, systems::demo_2d);
|
||||||
|
|
||||||
let definitions = sim::Definitions::from_default_directory().unwrap();
|
let definitions = sim::Definitions::from_default_directory().unwrap();
|
||||||
let game_world = sim::GameWorld::generate_mock(&definitions);
|
let game_world = sim::GameWorld::generate_random(&definitions);
|
||||||
// let game_world = match std::fs::read(sim::SAVE_FILE) {
|
// let game_world = match std::fs::read(sim::SAVE_FILE) {
|
||||||
// Ok(data) => {
|
// Ok(data) => {
|
||||||
// info!("Reading world data from \"{}\"", sim::SAVE_FILE);
|
// info!("Reading world data from \"{}\"", sim::SAVE_FILE);
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ pub mod debug;
|
||||||
pub mod game;
|
pub mod game;
|
||||||
pub mod game_setup;
|
pub mod game_setup;
|
||||||
pub mod sim;
|
pub mod sim;
|
||||||
pub mod sim_runner;
|
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
||||||
|
|
@ -47,11 +47,7 @@ impl Creature {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn patrol_chance(&self) -> f32 {
|
pub fn patrol_chance(&self) -> f32 {
|
||||||
if self.definition.patrols {
|
if self.definition.patrols { 0.5 } else { 0.0 }
|
||||||
0.5
|
|
||||||
} else {
|
|
||||||
0.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn health(&self) -> i32 {
|
pub fn health(&self) -> i32 {
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ impl SiteDef {
|
||||||
match tag.name.as_str() {
|
match tag.name.as_str() {
|
||||||
"SIZE" => (result.min_size, result.max_size) = tag.parse_value().unwrap(),
|
"SIZE" => (result.min_size, result.max_size) = tag.parse_value().unwrap(),
|
||||||
"NATURAL" => result.is_natural = true,
|
"NATURAL" => result.is_natural = true,
|
||||||
|
"UNDERGROUND" => result.is_underground = true,
|
||||||
_ => {
|
_ => {
|
||||||
// warn!("Unknown tag '{}' in SITE defs", tag.name);
|
// warn!("Unknown tag '{}' in SITE defs", tag.name);
|
||||||
return Err(ParseError::UnknownTag {
|
return Err(ParseError::UnknownTag {
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,11 @@ impl Display for SiteId {
|
||||||
#[derive(Debug, Serialize, Deserialize, Reflect)]
|
#[derive(Debug, Serialize, Deserialize, Reflect)]
|
||||||
pub struct Site {
|
pub struct Site {
|
||||||
id: SiteId,
|
id: SiteId,
|
||||||
areas: Vec<SiteArea>,
|
|
||||||
accumulated_time: Duration,
|
accumulated_time: Duration,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub definition: SiteDef,
|
pub definition: SiteDef,
|
||||||
|
pub position: Coords,
|
||||||
|
pub areas: Vec<SiteArea>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Site {
|
impl Site {
|
||||||
|
|
@ -36,11 +37,17 @@ impl Site {
|
||||||
Duration::from_secs(3600)
|
Duration::from_secs(3600)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(definition: SiteDef, name: impl Into<String>, areas: Vec<SiteArea>) -> Self {
|
pub fn new(
|
||||||
|
definition: SiteDef,
|
||||||
|
name: impl Into<String>,
|
||||||
|
position: Coords,
|
||||||
|
areas: Vec<SiteArea>,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id: SiteId::generate(),
|
id: SiteId::generate(),
|
||||||
definition,
|
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
|
definition,
|
||||||
|
position,
|
||||||
areas,
|
areas,
|
||||||
accumulated_time: Duration::default(),
|
accumulated_time: Duration::default(),
|
||||||
}
|
}
|
||||||
|
|
@ -139,10 +146,15 @@ impl Site {
|
||||||
println!("Tick! {self}");
|
println!("Tick! {self}");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_from_def(site_def: &SiteDef) -> Self {
|
pub fn generate_from_def(
|
||||||
|
site_def: &SiteDef,
|
||||||
|
name: impl Into<String>,
|
||||||
|
position: Coords,
|
||||||
|
) -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
site_def.clone(),
|
site_def.clone(),
|
||||||
"Gorbo's cave",
|
name,
|
||||||
|
position,
|
||||||
vec![
|
vec![
|
||||||
SiteArea::default();
|
SiteArea::default();
|
||||||
fastrand::usize(site_def.min_size as usize..=site_def.max_size as usize)
|
fastrand::usize(site_def.min_size as usize..=site_def.max_size as usize)
|
||||||
|
|
@ -150,14 +162,6 @@ impl Site {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn areas(&self) -> &Vec<SiteArea> {
|
|
||||||
self.areas.as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn areas_mut(&mut self) -> &mut Vec<SiteArea> {
|
|
||||||
self.areas.as_mut()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn populate_randomly(&mut self, creature_defs: &[&CreatureDef]) {
|
pub fn populate_randomly(&mut self, creature_defs: &[&CreatureDef]) {
|
||||||
let area_count = self.areas.len();
|
let area_count = self.areas.len();
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ impl Display for TravelGroupId {
|
||||||
|
|
||||||
#[derive(Clone, Copy, Eq, PartialEq, Debug, Serialize, Deserialize, Reflect)]
|
#[derive(Clone, Copy, Eq, PartialEq, Debug, Serialize, Deserialize, Reflect)]
|
||||||
pub enum WorldPoint {
|
pub enum WorldPoint {
|
||||||
Coords(WorldCoords),
|
Coords(Coords),
|
||||||
Site(SiteId),
|
Site(SiteId),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -41,7 +41,7 @@ pub struct TravelGroup {
|
||||||
id: TravelGroupId,
|
id: TravelGroupId,
|
||||||
accumulated_movement: Kilometer,
|
accumulated_movement: Kilometer,
|
||||||
pub creatures: Vec<Creature>,
|
pub creatures: Vec<Creature>,
|
||||||
pub position: WorldCoords,
|
pub position: Coords,
|
||||||
pub origin: Option<WorldPoint>,
|
pub origin: Option<WorldPoint>,
|
||||||
pub destination: Option<WorldPoint>,
|
pub destination: Option<WorldPoint>,
|
||||||
}
|
}
|
||||||
|
|
@ -49,7 +49,7 @@ pub struct TravelGroup {
|
||||||
impl TravelGroup {
|
impl TravelGroup {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
creatures: Vec<Creature>,
|
creatures: Vec<Creature>,
|
||||||
position: WorldCoords,
|
position: Coords,
|
||||||
origin: Option<WorldPoint>,
|
origin: Option<WorldPoint>,
|
||||||
destination: Option<WorldPoint>,
|
destination: Option<WorldPoint>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{fmt::Display, path::PathBuf};
|
use std::{fmt::Display, ops::Range, path::PathBuf};
|
||||||
|
|
||||||
use bevy::prelude::Reflect;
|
use bevy::prelude::Reflect;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
@ -6,12 +6,62 @@ use serde::{Deserialize, Serialize};
|
||||||
pub type Kilometer = f32;
|
pub type Kilometer = f32;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, PartialEq, Eq, Hash, Reflect)]
|
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, PartialEq, Eq, Hash, Reflect)]
|
||||||
pub struct WorldCoords {
|
pub struct Coords {
|
||||||
pub x: i32,
|
pub x: i32,
|
||||||
pub y: i32,
|
pub y: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for WorldCoords {
|
impl Coords {
|
||||||
|
pub fn new(x: i32, y: i32) -> Self {
|
||||||
|
Self { x, y }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, PartialEq, Eq, Hash, Reflect)]
|
||||||
|
pub struct CoordRect {
|
||||||
|
pub origin: Coords,
|
||||||
|
pub size: Coords,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CoordRect {
|
||||||
|
pub fn from_size(center: Coords, size: Coords) -> Self {
|
||||||
|
Self {
|
||||||
|
origin: Coords {
|
||||||
|
x: center.x - size.x / 2,
|
||||||
|
y: center.y - size.y / 2,
|
||||||
|
},
|
||||||
|
size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.size.x <= 0 || self.size.y <= 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn width_range(&self) -> Range<i32> {
|
||||||
|
self.origin.x..(self.origin.x + self.size.x)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn height_range(&self) -> Range<i32> {
|
||||||
|
self.origin.y..(self.origin.y + self.size.y)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return iterator of all possible coordinates in rect, also known as the cartesian product of
|
||||||
|
/// the x and y ranges
|
||||||
|
pub fn iter_coords(&self) -> impl Iterator<Item = Coords> {
|
||||||
|
self.width_range()
|
||||||
|
.flat_map(|x| self.height_range().map(move |y| Coords::new(x, y)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pick_random_coords(&self, count: usize) -> Vec<Coords> {
|
||||||
|
if self.is_empty() {
|
||||||
|
return vec![];
|
||||||
|
}
|
||||||
|
fastrand::choose_multiple(self.iter_coords(), count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Coords {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "({}, {})", self.x, self.y)
|
write!(f, "({}, {})", self.x, self.y)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,33 +5,34 @@ use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::prelude::*;
|
use super::prelude::*;
|
||||||
|
|
||||||
#[derive(Debug, Default, Resource, Serialize, Deserialize, Reflect)]
|
#[derive(Debug, Resource, Serialize, Deserialize, Reflect)]
|
||||||
#[reflect(Resource)]
|
#[reflect(Resource)]
|
||||||
pub struct GameWorld {
|
pub struct GameWorld {
|
||||||
|
pub area: CoordRect,
|
||||||
pub sites: Vec<Site>,
|
pub sites: Vec<Site>,
|
||||||
pub travel_groups: Vec<TravelGroup>,
|
pub travel_groups: Vec<TravelGroup>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GameWorld {
|
impl Default for GameWorld {
|
||||||
pub fn advance_time(&mut self, time: Duration) {
|
fn default() -> Self {
|
||||||
for site in self.sites.iter_mut() {
|
Self {
|
||||||
site.advance_time(time);
|
area: CoordRect::from_size(Coords::new(0, 0), Coords::new(16, 16)),
|
||||||
}
|
sites: vec![],
|
||||||
for travel_group in self.travel_groups.iter_mut() {
|
travel_groups: vec![],
|
||||||
travel_group.advance_time(time);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GameWorld {
|
||||||
pub fn generate_mock(defs: &Definitions) -> Self {
|
pub fn generate_mock(defs: &Definitions) -> Self {
|
||||||
let cave_def = defs.sites.get("CAVE").unwrap();
|
let cave_def = defs.sites.get("CAVE").unwrap();
|
||||||
let mut site = Site::generate_from_def(cave_def);
|
|
||||||
site.populate_randomly(&defs.creatures.values().collect::<Vec<_>>());
|
|
||||||
|
|
||||||
let bandit_def = defs.creatures.get("BANDIT").unwrap();
|
let bandit_def = defs.creatures.get("BANDIT").unwrap();
|
||||||
let spider_def = defs.creatures.get("SPIDER").unwrap();
|
let spider_def = defs.creatures.get("SPIDER").unwrap();
|
||||||
let cave = Site::new(
|
let cave = Site::new(
|
||||||
cave_def.clone(),
|
cave_def.clone(),
|
||||||
"Gorbo's cave",
|
"Gorbo's cave",
|
||||||
|
Coords::new(0, 0),
|
||||||
vec![
|
vec![
|
||||||
SiteArea::from_creatures(&vec![
|
SiteArea::from_creatures(&vec![
|
||||||
Creature::generate_from_def(defs.creatures.get("DRAGON").unwrap().clone()),
|
Creature::generate_from_def(defs.creatures.get("DRAGON").unwrap().clone()),
|
||||||
|
|
@ -61,13 +62,58 @@ impl GameWorld {
|
||||||
Creature::generate_from_def(bandit_def.clone()),
|
Creature::generate_from_def(bandit_def.clone()),
|
||||||
Creature::generate_from_def(bandit_def.clone()),
|
Creature::generate_from_def(bandit_def.clone()),
|
||||||
],
|
],
|
||||||
WorldCoords { x: 0, y: 0 },
|
Coords { x: 0, y: 0 },
|
||||||
Some(WorldPoint::Coords(WorldCoords { x: 0, y: 0 })),
|
Some(WorldPoint::Coords(Coords { x: 0, y: 0 })),
|
||||||
Some(WorldPoint::Site(cave.id())),
|
Some(WorldPoint::Site(cave.id())),
|
||||||
);
|
);
|
||||||
Self {
|
Self {
|
||||||
sites: vec![cave],
|
sites: vec![cave],
|
||||||
travel_groups: vec![group],
|
travel_groups: vec![group],
|
||||||
|
..default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_random(defs: &Definitions) -> Self {
|
||||||
|
let mut world = Self {
|
||||||
|
area: CoordRect::from_size(Coords::new(0, 0), Coords::new(32, 32)),
|
||||||
|
..default()
|
||||||
|
};
|
||||||
|
|
||||||
|
const SITE_COUNT: usize = 30;
|
||||||
|
let site_locations = world.area.pick_random_coords(SITE_COUNT);
|
||||||
|
let site_locations = site_locations.chunks(SITE_COUNT / 3);
|
||||||
|
|
||||||
|
for (chunk, locations) in site_locations.enumerate() {
|
||||||
|
for (i, coords) in locations.iter().enumerate() {
|
||||||
|
world.sites.push(match chunk {
|
||||||
|
0 => Site::generate_from_def(
|
||||||
|
defs.sites.get("DUNGEON").unwrap(),
|
||||||
|
format!("Dungeon #{}", i + 1),
|
||||||
|
*coords,
|
||||||
|
),
|
||||||
|
1 => Site::generate_from_def(
|
||||||
|
defs.sites.get("CAVE").unwrap(),
|
||||||
|
format!("Cave #{}", i + 1),
|
||||||
|
*coords,
|
||||||
|
),
|
||||||
|
_ => Site::generate_from_def(
|
||||||
|
defs.sites.get("BANDIT_CAMP").unwrap(),
|
||||||
|
format!("Bandit camp #{}", i + 1),
|
||||||
|
*coords,
|
||||||
|
),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
world
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn advance_time(&mut self, time: Duration) {
|
||||||
|
for site in self.sites.iter_mut() {
|
||||||
|
site.advance_time(time);
|
||||||
|
}
|
||||||
|
for travel_group in self.travel_groups.iter_mut() {
|
||||||
|
travel_group.advance_time(time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,126 +0,0 @@
|
||||||
use crate::sim;
|
|
||||||
use std::{collections::HashMap, io::BufReader, path::PathBuf, time::Duration};
|
|
||||||
|
|
||||||
use sim::definitions::parser::DefinitionParser;
|
|
||||||
use sim::prelude::*;
|
|
||||||
|
|
||||||
const SAVE_FILE: &str = "world.bin";
|
|
||||||
|
|
||||||
pub fn run_interactive_simulation() {
|
|
||||||
let mut parse_error_files = vec![];
|
|
||||||
let mut site_definitions = HashMap::new();
|
|
||||||
let mut creature_definitions = HashMap::new();
|
|
||||||
for entry in std::fs::read_dir(resources_path()).unwrap().flatten() {
|
|
||||||
if entry.file_name().to_string_lossy().ends_with(".def") {
|
|
||||||
let source = BufReader::new(std::fs::File::open(entry.path()).unwrap());
|
|
||||||
match DefinitionParser::parse(source) {
|
|
||||||
Ok(defs) => {
|
|
||||||
for def in defs.0 {
|
|
||||||
if let Some(prev) = site_definitions.insert(def.id.clone(), def) {
|
|
||||||
eprintln!("Duplicate site definition '{}'", prev.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for def in defs.1 {
|
|
||||||
if let Some(prev) = creature_definitions.insert(def.id.clone(), def) {
|
|
||||||
eprintln!("Duplicate site definition '{}'", prev.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
parse_error_files.push((err, entry.path()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (err, path) in parse_error_files.iter() {
|
|
||||||
eprintln!("Error\t{path:?}\n\t{err:?}")
|
|
||||||
}
|
|
||||||
if !parse_error_files.is_empty() {
|
|
||||||
eprintln!("{} file(s) had parsing errors!", parse_error_files.len())
|
|
||||||
}
|
|
||||||
|
|
||||||
let site_def = site_definitions.get("CAVE").unwrap();
|
|
||||||
let mut world = match std::fs::read(SAVE_FILE) {
|
|
||||||
Ok(data) => bincode::deserialize(&data).expect("Loading world data from file"),
|
|
||||||
Err(_) => {
|
|
||||||
let mut world = GameWorld::default();
|
|
||||||
|
|
||||||
let mut site = Site::generate_from_def(site_def);
|
|
||||||
site.populate_randomly(&creature_definitions.values().collect::<Vec<_>>());
|
|
||||||
|
|
||||||
let bandit_def = creature_definitions.get("BANDIT").unwrap();
|
|
||||||
let spider_def = creature_definitions.get("SPIDER").unwrap();
|
|
||||||
let site = Site::new(
|
|
||||||
site_def.clone(),
|
|
||||||
"Gorbo's cave",
|
|
||||||
vec![
|
|
||||||
SiteArea::from_creatures(&vec![
|
|
||||||
Creature::generate_from_def(
|
|
||||||
creature_definitions.get("DRAGON").unwrap().clone(),
|
|
||||||
),
|
|
||||||
Creature::generate_from_def(
|
|
||||||
creature_definitions.get("INDESTRUCTIBLE").unwrap().clone(),
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
SiteArea::from_creatures(&vec![
|
|
||||||
Creature::generate_from_def(bandit_def.clone()),
|
|
||||||
Creature::generate_from_def(spider_def.clone()),
|
|
||||||
]),
|
|
||||||
SiteArea::from_creatures(&vec![
|
|
||||||
Creature::generate_from_def(bandit_def.clone()),
|
|
||||||
Creature::generate_from_def(bandit_def.clone()),
|
|
||||||
Creature::generate_from_def(bandit_def.clone()),
|
|
||||||
]),
|
|
||||||
SiteArea::from_creatures(&vec![
|
|
||||||
Creature::generate_from_def(spider_def.clone()),
|
|
||||||
Creature::generate_from_def(spider_def.clone()),
|
|
||||||
]),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
let group = TravelGroup::new(
|
|
||||||
vec![
|
|
||||||
Creature::generate_from_def(bandit_def.clone()),
|
|
||||||
Creature::generate_from_def(bandit_def.clone()),
|
|
||||||
Creature::generate_from_def(bandit_def.clone()),
|
|
||||||
],
|
|
||||||
WorldCoords { x: 0, y: 0 },
|
|
||||||
Some(WorldPoint::Coords(WorldCoords { x: 0, y: 0 })),
|
|
||||||
Some(WorldPoint::Site(site.id())),
|
|
||||||
);
|
|
||||||
|
|
||||||
world.sites.push(site);
|
|
||||||
world.travel_groups.push(group);
|
|
||||||
std::fs::write("world.bin", bincode::serialize(&world).unwrap()).unwrap();
|
|
||||||
world
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
for site in world.sites.iter() {
|
|
||||||
println!("{site}");
|
|
||||||
}
|
|
||||||
|
|
||||||
for group in world.travel_groups.iter() {
|
|
||||||
println!("{group}");
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut input = String::new();
|
|
||||||
loop {
|
|
||||||
std::io::stdin().read_line(&mut input).unwrap();
|
|
||||||
if ["q", "quit", "exit"]
|
|
||||||
.iter()
|
|
||||||
.any(|quit_cmd| input.trim() == *quit_cmd)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
let start = std::time::Instant::now();
|
|
||||||
world.advance_time(Duration::from_secs(3600));
|
|
||||||
let end = std::time::Instant::now();
|
|
||||||
println!("World tick: {}us", (end - start).as_micros());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resources_path() -> PathBuf {
|
|
||||||
PathBuf::from(".").join("defs")
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue