Parallelised rtsim NPC AI

This commit is contained in:
Joshua Barretto 2023-01-05 21:31:20 +00:00
parent 077da13a5f
commit c4032ee024
4 changed files with 85 additions and 75 deletions

1
Cargo.lock generated
View File

@ -6952,6 +6952,7 @@ dependencies = [
"hashbrown 0.12.3", "hashbrown 0.12.3",
"itertools", "itertools",
"rand 0.8.5", "rand 0.8.5",
"rayon",
"rmp-serde", "rmp-serde",
"ron 0.8.0", "ron 0.8.0",
"serde", "serde",

View File

@ -19,3 +19,4 @@ slotmap = { version = "1.0.6", features = ["serde"] }
rand = { version = "0.8", features = ["small_rng"] } rand = { version = "0.8", features = ["small_rng"] }
fxhash = "0.2.1" fxhash = "0.2.1"
itertools = "0.10.3" itertools = "0.10.3"
rayon = "1.5"

View File

@ -89,7 +89,7 @@ impl Data {
.with_z(world.sim().get_alt_approx(wpos2d).unwrap_or(0.0)) .with_z(world.sim().get_alt_approx(wpos2d).unwrap_or(0.0))
}; };
if good_or_evil { if good_or_evil {
for _ in 0..32 { for _ in 0..250 {
this.npcs.create( this.npcs.create(
Npc::new(rng.gen(), rand_wpos(&mut rng)) Npc::new(rng.gen(), rand_wpos(&mut rng))
.with_faction(site.faction) .with_faction(site.faction)
@ -107,7 +107,7 @@ impl Data {
); );
} }
} else { } else {
for _ in 0..5 { for _ in 0..15 {
this.npcs.create( this.npcs.create(
Npc::new(rng.gen(), rand_wpos(&mut rng)) Npc::new(rng.gen(), rand_wpos(&mut rng))
.with_faction(site.faction) .with_faction(site.faction)

View File

@ -21,6 +21,7 @@ use common::{
use fxhash::FxHasher64; use fxhash::FxHasher64;
use itertools::Itertools; use itertools::Itertools;
use rand::prelude::*; use rand::prelude::*;
use rayon::iter::{IntoParallelRefMutIterator, ParallelIterator};
use std::{ use std::{
any::{Any, TypeId}, any::{Any, TypeId},
marker::PhantomData, marker::PhantomData,
@ -230,84 +231,91 @@ const MAX_STEP: f32 = 32.0;
impl Rule for NpcAi { impl Rule for NpcAi {
fn start(rtstate: &mut RtState) -> Result<Self, RuleError> { fn start(rtstate: &mut RtState) -> Result<Self, RuleError> {
rtstate.bind::<Self, OnTick>(|mut ctx| { rtstate.bind::<Self, OnTick>(|mut ctx| {
let npc_ids = ctx.state.data().npcs.keys().collect::<Vec<_>>(); let mut npc_data = {
let mut data = ctx.state.data_mut();
for npc_id in npc_ids { data.npcs
let mut brain = ctx.state.data_mut().npcs[npc_id] .iter_mut()
.brain .map(|(npc_id, npc)| {
.take() let controller = Controller { goto: npc.goto };
.unwrap_or_else(|| Brain { let brain = npc.brain.take().unwrap_or_else(|| Brain {
action: Box::new(think().repeat()), action: Box::new(think().repeat()),
});
let controller = {
let data = &*ctx.state.data();
let npc = &data.npcs[npc_id];
let mut controller = Controller { goto: npc.goto };
brain.action.tick(&mut NpcCtx {
state: ctx.state,
world: ctx.world,
index: ctx.index,
time_of_day: ctx.event.time_of_day,
time: ctx.event.time,
npc,
npc_id,
controller: &mut controller,
});
/*
let action: ControlFlow<()> = try {
brain.tick(&mut NpcData {
ctx: &ctx,
npc,
npc_id,
controller: &mut controller,
}); });
/* (npc_id, controller, brain)
// // Choose a random plaza in the npcs home site (which should be the })
// // current here) to go to. .collect::<Vec<_>>()
let task = };
generate(move |(_, npc, ctx): &(NpcId, &Npc, &EventCtx<_, _>)| {
let data = ctx.state.data();
let site2 =
npc.home.and_then(|home| data.sites.get(home)).and_then(
|home| match &ctx.index.sites.get(home.world_site?).kind
{
SiteKind::Refactor(site2)
| SiteKind::CliffTown(site2)
| SiteKind::DesertCity(site2) => Some(site2),
_ => None,
},
);
let wpos = site2 {
.and_then(|site2| { let data = &*ctx.state.data();
let plaza = &site2.plots
[site2.plazas().choose(&mut thread_rng())?];
Some(site2.tile_center_wpos(plaza.root_tile()).as_())
})
.unwrap_or(npc.wpos.xy());
TravelTo { npc_data
wpos, .par_iter_mut()
use_paths: true, .for_each(|(npc_id, controller, brain)| {
} let npc = &data.npcs[*npc_id];
})
.repeat();
task_state.perform(task, &(npc_id, &*npc, &ctx), &mut controller)?; brain.action.tick(&mut NpcCtx {
*/ state: ctx.state,
}; world: ctx.world,
*/ index: ctx.index,
time_of_day: ctx.event.time_of_day,
controller time: ctx.event.time,
}; npc,
npc_id: *npc_id,
ctx.state.data_mut().npcs[npc_id].goto = controller.goto; controller,
ctx.state.data_mut().npcs[npc_id].brain = Some(brain); });
});
} }
let mut data = ctx.state.data_mut();
for (npc_id, controller, brain) in npc_data {
data.npcs[npc_id].goto = controller.goto;
data.npcs[npc_id].brain = Some(brain);
}
/*
let action: ControlFlow<()> = try {
brain.tick(&mut NpcData {
ctx: &ctx,
npc,
npc_id,
controller: &mut controller,
});
/*
// // Choose a random plaza in the npcs home site (which should be the
// // current here) to go to.
let task =
generate(move |(_, npc, ctx): &(NpcId, &Npc, &EventCtx<_, _>)| {
let data = ctx.state.data();
let site2 =
npc.home.and_then(|home| data.sites.get(home)).and_then(
|home| match &ctx.index.sites.get(home.world_site?).kind
{
SiteKind::Refactor(site2)
| SiteKind::CliffTown(site2)
| SiteKind::DesertCity(site2) => Some(site2),
_ => None,
},
);
let wpos = site2
.and_then(|site2| {
let plaza = &site2.plots
[site2.plazas().choose(&mut thread_rng())?];
Some(site2.tile_center_wpos(plaza.root_tile()).as_())
})
.unwrap_or(npc.wpos.xy());
TravelTo {
wpos,
use_paths: true,
}
})
.repeat();
task_state.perform(task, &(npc_id, &*npc, &ctx), &mut controller)?;
*/
};
*/
}); });
Ok(Self) Ok(Self)