Addressed feedback

This commit is contained in:
Joshua Barretto 2023-04-03 19:29:37 +01:00
parent 1fcb46ae0c
commit 9f025de27d
10 changed files with 41 additions and 126 deletions

View File

@ -227,6 +227,8 @@ pub enum NpcAction {
Say(Cow<'static, str>), Say(Cow<'static, str>),
} }
// Note: the `serde(name = "...")` is to minimise the length of field
// identifiers for the sake of rtsim persistence
#[derive(Copy, Clone, Debug, Serialize, Deserialize, enum_map::Enum)] #[derive(Copy, Clone, Debug, Serialize, Deserialize, enum_map::Enum)]
pub enum ChunkResource { pub enum ChunkResource {
#[serde(rename = "0")] #[serde(rename = "0")]
@ -253,6 +255,8 @@ pub enum ChunkResource {
Ore, // Iron, copper, etc. Ore, // Iron, copper, etc.
} }
// Note: the `serde(name = "...")` is to minimise the length of field
// identifiers for the sake of rtsim persistence
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub enum Profession { pub enum Profession {
#[serde(rename = "0")] #[serde(rename = "0")]

View File

@ -528,15 +528,15 @@ where
/// ///
/// The inner function will be run every tick to decide on an action. When an /// The inner function will be run every tick to decide on an action. When an
/// action is chosen, it will be performed until completed unless a different /// action is chosen, it will be performed until completed unless a different
/// action is chosen in a subsequent tick. [`watch`] is very unfocussed and will /// action of the same or higher priority is chosen in a subsequent tick.
/// happily switch between actions rapidly between ticks if conditions change. /// [`watch`] is very unfocussed and will happily switch between actions
/// If you want something that tends to commit to actions until they are /// rapidly between ticks if conditions change. If you want something that
/// completed, see [`choose`]. /// tends to commit to actions until they are completed, see [`choose`].
/// ///
/// # Example /// # Example
/// ///
/// ```ignore /// ```ignore
/// choose(|ctx| { /// watch(|ctx| {
/// if ctx.npc.is_being_attacked() { /// if ctx.npc.is_being_attacked() {
/// urgent(combat()) // If we're in danger, do something! /// urgent(combat()) // If we're in danger, do something!
/// } else if ctx.npc.is_hungry() { /// } else if ctx.npc.is_hungry() {

View File

@ -42,8 +42,10 @@ pub struct Chunk {
/// this chunk. /// this chunk.
/// ///
/// 0.0 => None of the resources generated by terrain generation should be /// 0.0 => None of the resources generated by terrain generation should be
/// present 1.0 => All of the resources generated by terrain generation /// present
/// should be present ///
/// 1.0 => All of the resources generated by terrain generation should be
/// present
/// ///
/// It's important to understand this this number does not represent the /// It's important to understand this this number does not represent the
/// total amount of a resource present in a chunk, nor is it even /// total amount of a resource present in a chunk, nor is it even

View File

@ -83,8 +83,8 @@ pub struct Brain {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct Npc { pub struct Npc {
// Persisted state // Persisted state
/// Represents the location of the NPC.
pub seed: u32, pub seed: u32,
/// Represents the location of the NPC.
pub wpos: Vec3<f32>, pub wpos: Vec3<f32>,
pub body: comp::Body, pub body: comp::Body,

View File

@ -310,7 +310,7 @@ fn goto_2d(wpos2d: Vec2<f32>, speed_factor: f32, goal_dist: f32) -> impl Action
}) })
} }
fn traverse_points<F>(mut next_point: F) -> impl Action fn traverse_points<F>(mut next_point: F, speed_factor: f32) -> impl Action
where where
F: FnMut(&mut NpcCtx) -> Option<Vec2<f32>> + Send + Sync + 'static, F: FnMut(&mut NpcCtx) -> Option<Vec2<f32>> + Send + Sync + 'static,
{ {
@ -333,33 +333,40 @@ where
if let Some(path) = path_site(wpos, site_exit, site, ctx.index) { if let Some(path) = path_site(wpos, site_exit, site, ctx.index) {
Some(itertools::Either::Left( Some(itertools::Either::Left(
seq(path.into_iter().map(|wpos| goto_2d(wpos, 1.0, 8.0))) seq(path.into_iter().map(|wpos| goto_2d(wpos, 1.0, 8.0))).then(goto_2d(
.then(goto_2d(site_exit, 1.0, 8.0)), site_exit,
speed_factor,
8.0,
)),
)) ))
} else { } else {
Some(itertools::Either::Right(goto_2d(site_exit, 1.0, 8.0))) Some(itertools::Either::Right(goto_2d(
site_exit,
speed_factor,
8.0,
)))
} }
} else { } else {
Some(itertools::Either::Right(goto_2d(wpos, 1.0, 8.0))) Some(itertools::Either::Right(goto_2d(wpos, speed_factor, 8.0)))
} }
}) })
} }
/// Try to travel to a site. Where practical, paths will be taken. /// Try to travel to a site. Where practical, paths will be taken.
fn travel_to_point(wpos: Vec2<f32>) -> impl Action { fn travel_to_point(wpos: Vec2<f32>, speed_factor: f32) -> impl Action {
now(move |ctx| { now(move |ctx| {
const WAYPOINT: f32 = 48.0; const WAYPOINT: f32 = 48.0;
let start = ctx.npc.wpos.xy(); let start = ctx.npc.wpos.xy();
let diff = wpos - start; let diff = wpos - start;
let n = (diff.magnitude() / WAYPOINT).max(1.0); let n = (diff.magnitude() / WAYPOINT).max(1.0);
let mut points = (1..n as usize + 1).map(move |i| start + diff * (i as f32 / n)); let mut points = (1..n as usize + 1).map(move |i| start + diff * (i as f32 / n));
traverse_points(move |_| points.next()) traverse_points(move |_| points.next(), speed_factor)
}) })
.debug(|| "travel to point") .debug(|| "travel to point")
} }
/// Try to travel to a site. Where practical, paths will be taken. /// Try to travel to a site. Where practical, paths will be taken.
fn travel_to_site(tgt_site: SiteId) -> impl Action { fn travel_to_site(tgt_site: SiteId, speed_factor: f32) -> impl Action {
now(move |ctx| { now(move |ctx| {
let sites = &ctx.state.data().sites; let sites = &ctx.state.data().sites;
@ -397,7 +404,7 @@ fn travel_to_site(tgt_site: SiteId) -> impl Action {
} else { } else {
None None
} }
}) }, speed_factor)
.boxed() .boxed()
// For every track in the path we discovered between the sites... // For every track in the path we discovered between the sites...
@ -438,7 +445,7 @@ fn travel_to_site(tgt_site: SiteId) -> impl Action {
// .boxed() // .boxed()
} else if let Some(site) = sites.get(tgt_site) { } else if let Some(site) = sites.get(tgt_site) {
// If all else fails, just walk toward the target site in a straight line // If all else fails, just walk toward the target site in a straight line
travel_to_point(site.wpos.map(|e| e as f32 + 0.5)).boxed() travel_to_point(site.wpos.map(|e| e as f32 + 0.5), speed_factor).boxed()
} else { } else {
// If we can't find a way to get to the site at all, there's nothing more to be done // If we can't find a way to get to the site at all, there's nothing more to be done
finish().boxed() finish().boxed()
@ -512,7 +519,7 @@ fn adventure() -> impl Action {
.unwrap_or_default(); .unwrap_or_default();
// Travel to the site // Travel to the site
important(just(move |ctx| ctx.controller.say(format!("I've spent enough time here, onward to {}!", site_name))) important(just(move |ctx| ctx.controller.say(format!("I've spent enough time here, onward to {}!", site_name)))
.then(travel_to_site(tgt_site)) .then(travel_to_site(tgt_site, 0.6))
// Stop for a few minutes // Stop for a few minutes
.then(villager(tgt_site).repeat().stop_if(timeout(wait_time))) .then(villager(tgt_site).repeat().stop_if(timeout(wait_time)))
.map(|_| ()) .map(|_| ())
@ -572,7 +579,7 @@ fn villager(visiting_site: SiteId) -> impl Action {
} else if ctx.npc.current_site != Some(visiting_site) { } else if ctx.npc.current_site != Some(visiting_site) {
let npc_home = ctx.npc.home; let npc_home = ctx.npc.home;
// Travel to the site we're supposed to be in // Travel to the site we're supposed to be in
return urgent(travel_to_site(visiting_site).debug(move || { return urgent(travel_to_site(visiting_site, 1.0).debug(move || {
if npc_home == Some(visiting_site) { if npc_home == Some(visiting_site) {
"travel home".to_string() "travel home".to_string()
} else { } else {
@ -602,7 +609,7 @@ fn villager(visiting_site: SiteId) -> impl Action {
}) })
{ {
just(|ctx| ctx.controller.say("It's dark, time to go home")) just(|ctx| ctx.controller.say("It's dark, time to go home"))
.then(travel_to_point(house_wpos)) .then(travel_to_point(house_wpos, 0.65))
.debug(|| "walk to house") .debug(|| "walk to house")
.then(socialize().repeat().debug(|| "wait in house")) .then(socialize().repeat().debug(|| "wait in house"))
.stop_if(|ctx| DayPeriod::from(ctx.time_of_day.0).is_light()) .stop_if(|ctx| DayPeriod::from(ctx.time_of_day.0).is_light())
@ -621,7 +628,7 @@ fn villager(visiting_site: SiteId) -> impl Action {
{ {
if let Some(forest_wpos) = find_forest(ctx) { if let Some(forest_wpos) = find_forest(ctx) {
return casual( return casual(
travel_to_point(forest_wpos) travel_to_point(forest_wpos, 0.5)
.debug(|| "walk to forest") .debug(|| "walk to forest")
.then({ .then({
let wait_time = thread_rng().gen_range(10.0..30.0); let wait_time = thread_rng().gen_range(10.0..30.0);
@ -636,7 +643,7 @@ fn villager(visiting_site: SiteId) -> impl Action {
if let Some(forest_wpos) = find_forest(ctx) { if let Some(forest_wpos) = find_forest(ctx) {
return casual( return casual(
just(|ctx| ctx.controller.say("Time to go hunting!")) just(|ctx| ctx.controller.say("Time to go hunting!"))
.then(travel_to_point(forest_wpos)) .then(travel_to_point(forest_wpos, 0.75))
.debug(|| "walk to forest") .debug(|| "walk to forest")
.then({ .then({
let wait_time = thread_rng().gen_range(30.0..60.0); let wait_time = thread_rng().gen_range(30.0..60.0);
@ -685,7 +692,7 @@ fn villager(visiting_site: SiteId) -> impl Action {
}) })
{ {
// Walk to the plaza... // Walk to the plaza...
travel_to_point(plaza_wpos) travel_to_point(plaza_wpos, 0.5)
.debug(|| "walk to plaza") .debug(|| "walk to plaza")
// ...then wait for some time before moving on // ...then wait for some time before moving on
.then({ .then({

View File

@ -549,17 +549,6 @@ impl Server {
let connection_handler = ConnectionHandler::new(network, &runtime); let connection_handler = ConnectionHandler::new(network, &runtime);
// Initiate real-time world simulation
/*
#[cfg(feature = "worldgen")]
{
rtsim::init(&mut state, &world, index.as_index_ref());
weather::init(&mut state, &world);
}
#[cfg(not(feature = "worldgen"))]
rtsim::init(&mut state);
*/
// Init rtsim, loading it from disk if possible // Init rtsim, loading it from disk if possible
#[cfg(feature = "worldgen")] #[cfg(feature = "worldgen")]
{ {
@ -738,13 +727,6 @@ impl Server {
add_local_systems(dispatcher_builder); add_local_systems(dispatcher_builder);
sys::msg::add_server_systems(dispatcher_builder); sys::msg::add_server_systems(dispatcher_builder);
sys::add_server_systems(dispatcher_builder); sys::add_server_systems(dispatcher_builder);
/*
#[cfg(feature = "worldgen")]
{
rtsim::add_server_systems(dispatcher_builder);
weather::add_server_systems(dispatcher_builder);
}
*/
#[cfg(feature = "worldgen")] #[cfg(feature = "worldgen")]
{ {
rtsim::add_server_systems(dispatcher_builder); rtsim::add_server_systems(dispatcher_builder);

View File

@ -22,7 +22,7 @@ use std::{
path::PathBuf, path::PathBuf,
time::Instant, time::Instant,
}; };
use tracing::{debug, error, info, warn}; use tracing::{debug, error, info, trace, warn};
use vek::*; use vek::*;
use world::{IndexRef, World}; use world::{IndexRef, World};
@ -175,10 +175,10 @@ impl RtSim {
} }
pub fn save(&mut self, /* slowjob_pool: &SlowJobPool, */ wait_until_finished: bool) { pub fn save(&mut self, /* slowjob_pool: &SlowJobPool, */ wait_until_finished: bool) {
info!("Saving rtsim data..."); debug!("Saving rtsim data...");
let file_path = self.file_path.clone(); let file_path = self.file_path.clone();
let data = self.state.data().clone(); let data = self.state.data().clone();
debug!("Starting rtsim data save job..."); trace!("Starting rtsim data save job...");
// TODO: Use slow job // TODO: Use slow job
// slowjob_pool.spawn("RTSIM_SAVE", move || { // slowjob_pool.spawn("RTSIM_SAVE", move || {
let handle = std::thread::spawn(move || { let handle = std::thread::spawn(move || {

View File

@ -29,7 +29,6 @@ impl<'a> System<'a> for Sys {
Read<'a, EventBus<ServerEvent>>, Read<'a, EventBus<ServerEvent>>,
WriteStorage<'a, Agent>, WriteStorage<'a, Agent>,
WriteStorage<'a, Controller>, WriteStorage<'a, Controller>,
//WriteExpect<'a, RtSim>,
); );
const NAME: &'static str = "agent"; const NAME: &'static str = "agent";
@ -38,9 +37,8 @@ impl<'a> System<'a> for Sys {
fn run( fn run(
job: &mut Job<Self>, job: &mut Job<Self>,
(read_data, event_bus, mut agents, mut controllers /* mut rtsim */): Self::SystemData, (read_data, event_bus, mut agents, mut controllers): Self::SystemData,
) { ) {
//let rtsim = &mut *rtsim;
job.cpu_stats.measure(ParMode::Rayon); job.cpu_stats.measure(ParMode::Rayon);
( (
@ -187,12 +185,6 @@ impl<'a> System<'a> for Sys {
can_fly: moving_body.map_or(false, |b| b.fly_thrust().is_some()), can_fly: moving_body.map_or(false, |b| b.fly_thrust().is_some()),
}; };
let health_fraction = health.map_or(1.0, Health::fraction); let health_fraction = health.map_or(1.0, Health::fraction);
/*
let rtsim_entity = read_data
.rtsim_entities
.get(entity)
.and_then(|rtsim_ent| rtsim.get_entity(rtsim_ent.0));
*/
if traversal_config.can_fly && matches!(moving_body, Some(Body::Ship(_))) { if traversal_config.can_fly && matches!(moving_body, Some(Body::Ship(_))) {
// hack (kinda): Never turn off flight airships // hack (kinda): Never turn off flight airships
@ -255,7 +247,6 @@ impl<'a> System<'a> for Sys {
// inputs. // inputs.
let mut behavior_data = BehaviorData { let mut behavior_data = BehaviorData {
agent, agent,
// rtsim_entity,
agent_data: data, agent_data: data,
read_data: &read_data, read_data: &read_data,
event_emitter: &mut event_emitter, event_emitter: &mut event_emitter,
@ -269,25 +260,5 @@ impl<'a> System<'a> for Sys {
debug_assert!(controller.inputs.look_dir.map(|e| !e.is_nan()).reduce_and()); debug_assert!(controller.inputs.look_dir.map(|e| !e.is_nan()).reduce_and());
}, },
); );
/*
for (agent, rtsim_entity) in (&mut agents, &read_data.rtsim_entities).join() {
// Entity must be loaded in as it has an agent component :)
// React to all events in the controller
for event in core::mem::take(&mut agent.rtsim_controller.events) {
match event {
RtSimEvent::AddMemory(memory) => {
rtsim.insert_entity_memory(rtsim_entity.0, memory.clone());
},
RtSimEvent::ForgetEnemy(name) => {
rtsim.forget_entity_enemy(rtsim_entity.0, &name);
},
RtSimEvent::SetMood(memory) => {
rtsim.set_entity_mood(rtsim_entity.0, memory.clone());
},
RtSimEvent::PrintMemories => {},
}
}
}
*/
} }
} }

View File

@ -244,55 +244,6 @@ pub fn handle_inbox_talk(bdata: &mut BehaviorData) -> bool {
}, },
Subject::Mood => { Subject::Mood => {
// TODO: Reimplement in rtsim2 // TODO: Reimplement in rtsim2
/*
if let Some(rtsim_entity) = &bdata.rtsim_entity {
if !rtsim_entity.brain.remembers_mood() {
// TODO: the following code will need a rework to
// implement more mood contexts
// This require that town NPCs becomes rtsim_entities to
// work fully.
match rand::random::<u32>() % 3 {
0 => agent.rtsim_controller.events.push(
RtSimEvent::SetMood(Memory {
item: MemoryItem::Mood {
state: MoodState::Good(
MoodContext::GoodWeather,
),
},
time_to_forget: read_data.time.0 + 21200.0,
}),
),
1 => agent.rtsim_controller.events.push(
RtSimEvent::SetMood(Memory {
item: MemoryItem::Mood {
state: MoodState::Neutral(
MoodContext::EverydayLife,
),
},
time_to_forget: read_data.time.0 + 21200.0,
}),
),
2 => agent.rtsim_controller.events.push(
RtSimEvent::SetMood(Memory {
item: MemoryItem::Mood {
state: MoodState::Bad(
MoodContext::GoodWeather,
),
},
time_to_forget: read_data.time.0 + 86400.0,
}),
),
_ => {}, // will never happen
}
}
if let Some(memory) = rtsim_entity.brain.get_mood() {
let msg = match &memory.item {
MemoryItem::Mood { state } => state.describe(),
_ => "".to_string(),
};
agent_data.chat_npc(msg, event_emitter);
}
}*/
}, },
Subject::Location(location) => { Subject::Location(location) => {
if let Some(tgt_pos) = read_data.positions.get(target) { if let Some(tgt_pos) = read_data.positions.get(target) {

View File

@ -74,7 +74,6 @@ impl<'a> System<'a> for Sys {
WriteExpect<'a, TerrainGrid>, WriteExpect<'a, TerrainGrid>,
Write<'a, TerrainChanges>, Write<'a, TerrainChanges>,
Write<'a, Vec<ChunkRequest>>, Write<'a, Vec<ChunkRequest>>,
//WriteExpect<'a, RtSim>,
RtSimData<'a>, RtSimData<'a>,
TerrainPersistenceData<'a>, TerrainPersistenceData<'a>,
WriteStorage<'a, Pos>, WriteStorage<'a, Pos>,
@ -107,7 +106,6 @@ impl<'a> System<'a> for Sys {
mut terrain, mut terrain,
mut terrain_changes, mut terrain_changes,
mut chunk_requests, mut chunk_requests,
//mut rtsim,
mut rtsim, mut rtsim,
mut _terrain_persistence, mut _terrain_persistence,
mut positions, mut positions,