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>),
}
// 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)]
pub enum ChunkResource {
#[serde(rename = "0")]
@ -253,6 +255,8 @@ pub enum ChunkResource {
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)]
pub enum Profession {
#[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
/// 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
/// happily switch between actions rapidly between ticks if conditions change.
/// If you want something that tends to commit to actions until they are
/// completed, see [`choose`].
/// action of the same or higher priority is chosen in a subsequent tick.
/// [`watch`] is very unfocussed and will happily switch between actions
/// rapidly between ticks if conditions change. If you want something that
/// tends to commit to actions until they are completed, see [`choose`].
///
/// # Example
///
/// ```ignore
/// choose(|ctx| {
/// watch(|ctx| {
/// if ctx.npc.is_being_attacked() {
/// urgent(combat()) // If we're in danger, do something!
/// } else if ctx.npc.is_hungry() {

View File

@ -42,8 +42,10 @@ pub struct Chunk {
/// this chunk.
///
/// 0.0 => None of the resources generated by terrain generation should be
/// present 1.0 => All of the resources generated by terrain generation
/// should be present
/// 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
/// 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)]
pub struct Npc {
// Persisted state
/// Represents the location of the NPC.
pub seed: u32,
/// Represents the location of the NPC.
pub wpos: Vec3<f32>,
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
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) {
Some(itertools::Either::Left(
seq(path.into_iter().map(|wpos| goto_2d(wpos, 1.0, 8.0)))
.then(goto_2d(site_exit, 1.0, 8.0)),
seq(path.into_iter().map(|wpos| goto_2d(wpos, 1.0, 8.0))).then(goto_2d(
site_exit,
speed_factor,
8.0,
)),
))
} 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 {
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.
fn travel_to_point(wpos: Vec2<f32>) -> impl Action {
fn travel_to_point(wpos: Vec2<f32>, speed_factor: f32) -> impl Action {
now(move |ctx| {
const WAYPOINT: f32 = 48.0;
let start = ctx.npc.wpos.xy();
let diff = wpos - start;
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));
traverse_points(move |_| points.next())
traverse_points(move |_| points.next(), speed_factor)
})
.debug(|| "travel to point")
}
/// 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| {
let sites = &ctx.state.data().sites;
@ -397,7 +404,7 @@ fn travel_to_site(tgt_site: SiteId) -> impl Action {
} else {
None
}
})
}, speed_factor)
.boxed()
// 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()
} else if let Some(site) = sites.get(tgt_site) {
// 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 {
// If we can't find a way to get to the site at all, there's nothing more to be done
finish().boxed()
@ -512,7 +519,7 @@ fn adventure() -> impl Action {
.unwrap_or_default();
// Travel to the site
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
.then(villager(tgt_site).repeat().stop_if(timeout(wait_time)))
.map(|_| ())
@ -572,7 +579,7 @@ fn villager(visiting_site: SiteId) -> impl Action {
} else if ctx.npc.current_site != Some(visiting_site) {
let npc_home = ctx.npc.home;
// 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) {
"travel home".to_string()
} else {
@ -602,7 +609,7 @@ fn villager(visiting_site: SiteId) -> impl Action {
})
{
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")
.then(socialize().repeat().debug(|| "wait in house"))
.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) {
return casual(
travel_to_point(forest_wpos)
travel_to_point(forest_wpos, 0.5)
.debug(|| "walk to forest")
.then({
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) {
return casual(
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")
.then({
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...
travel_to_point(plaza_wpos)
travel_to_point(plaza_wpos, 0.5)
.debug(|| "walk to plaza")
// ...then wait for some time before moving on
.then({

View File

@ -549,17 +549,6 @@ impl Server {
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
#[cfg(feature = "worldgen")]
{
@ -738,13 +727,6 @@ impl Server {
add_local_systems(dispatcher_builder);
sys::msg::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")]
{
rtsim::add_server_systems(dispatcher_builder);

View File

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

View File

@ -29,7 +29,6 @@ impl<'a> System<'a> for Sys {
Read<'a, EventBus<ServerEvent>>,
WriteStorage<'a, Agent>,
WriteStorage<'a, Controller>,
//WriteExpect<'a, RtSim>,
);
const NAME: &'static str = "agent";
@ -38,9 +37,8 @@ impl<'a> System<'a> for Sys {
fn run(
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);
(
@ -187,12 +185,6 @@ impl<'a> System<'a> for Sys {
can_fly: moving_body.map_or(false, |b| b.fly_thrust().is_some()),
};
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(_))) {
// hack (kinda): Never turn off flight airships
@ -255,7 +247,6 @@ impl<'a> System<'a> for Sys {
// inputs.
let mut behavior_data = BehaviorData {
agent,
// rtsim_entity,
agent_data: data,
read_data: &read_data,
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());
},
);
/*
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 => {
// 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) => {
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>,
Write<'a, TerrainChanges>,
Write<'a, Vec<ChunkRequest>>,
//WriteExpect<'a, RtSim>,
RtSimData<'a>,
TerrainPersistenceData<'a>,
WriteStorage<'a, Pos>,
@ -107,7 +106,6 @@ impl<'a> System<'a> for Sys {
mut terrain,
mut terrain_changes,
mut chunk_requests,
//mut rtsim,
mut rtsim,
mut _terrain_persistence,
mut positions,