From 55425dce9fddba3f69b92335581f242d0d44e69a Mon Sep 17 00:00:00 2001 From: kinrezc Date: Fri, 2 Feb 2024 13:14:36 -0500 Subject: [PATCH] cleanup: improve agent docs, handle world.run() fallback behavior if no agents were added --- arbiter-engine/src/agent.rs | 23 ++--------------------- arbiter-engine/src/lib.rs | 1 + arbiter-engine/src/world.rs | 33 +++++++++------------------------ 3 files changed, 12 insertions(+), 45 deletions(-) diff --git a/arbiter-engine/src/agent.rs b/arbiter-engine/src/agent.rs index d73d1e2c2..9b4af1abb 100644 --- a/arbiter-engine/src/agent.rs +++ b/arbiter-engine/src/agent.rs @@ -17,27 +17,8 @@ use thiserror::Error; /// dependency. /// /// # How it works -/// The [`Agent`] works by implementing the [`StateMachine`] trait. When the -/// [`World`] that owns the [`Agent`] is asked to enter into a new state, the -/// [`World`] will ask each [`Agent`] it owns to run that state transition by -/// calling [`StateMachine::run_state`]. All of the [`Agent`]s at once will then -/// will be able to be asked to block and wait to finish their state transition -/// by calling [`StateMachine::transition`]. Ultimately, the [`Agent`] will -/// transition through the following states: -/// 1. [`State::Uninitialized`]: The [`Agent`] has been created, but has not -/// been started. -/// 2. [`State::Syncing`]: The [`Agent`] is syncing with the world. This is -/// where the [`Agent`] can be brought up to date with the latest state of the -/// world. This could be used if the world was stopped and later restarted. -/// 3. [`State::Startup`]: The [`Agent`] is starting up. This is where the -/// [`Agent`] can be initialized and setup. -/// 4. [`State::Processing`]: The [`Agent`] is processing. This is where the -/// [`Agent`] can process events and produce actions. The [`State::Processing`] -/// stage may run for a long time before all [`Agent`]s are finished processing. -/// This is the main stage of the [`Agent`] that predominantly runs automation. -/// 5. [`State::Stopped`]: The [`Agent`] is stopped. This is where the [`Agent`] -/// can be stopped and state of the [`World`] and its [`Agent`]s can be -/// offloaded and saved. +/// When the [`World`] that owns the [`Agent`] is ran, it has each [`Agent`] run each of its [`Behavior`]s `startup()` methods. +/// The [`Behavior`]s themselves will return a stream of events that then let the [`Behavior`] move into the `State::Processing` stage. pub struct Agent { /// Identifier for this agent. /// Used for routing messages. diff --git a/arbiter-engine/src/lib.rs b/arbiter-engine/src/lib.rs index 1a2869242..52106e5a2 100644 --- a/arbiter-engine/src/lib.rs +++ b/arbiter-engine/src/lib.rs @@ -7,6 +7,7 @@ use std::collections::HashMap; +use anyhow::{anyhow, Result}; use serde::{Deserialize, Serialize}; #[allow(unused)] use tracing::{debug, trace, warn}; diff --git a/arbiter-engine/src/world.rs b/arbiter-engine/src/world.rs index 34a62b140..e1635e3e5 100644 --- a/arbiter-engine/src/world.rs +++ b/arbiter-engine/src/world.rs @@ -30,27 +30,9 @@ use crate::{agent::Agent, machine::State, messager::Messager}; /// responsible for managing the agents and their state transitions. /// /// # How it works -/// The [`World`] works by implementing the [`StateMachine`] trait. When the -/// [`World`] is asked to enter into a new state, it will ask each [`Agent`] it -/// owns to run that state transition by calling [`StateMachine::run_state`]. -/// All of the [`Agent`]s at once will then be able to be asked to block and -/// wait to finish their state transition by calling -/// [`StateMachine::transition`]. Ultimately, the [`World`] will transition -/// through the following states: -/// 1. [`State::Uninitialized`]: The [`World`] has been created, but has not -/// been started. -/// 2. [`State::Syncing`]: The [`World`] is syncing with the agents. This is -/// where the [`World`] can be brought up to date with the latest state of the -/// agents. This could be used if the world was stopped and later restarted. -/// 3. [`State::Startup`]: The [`World`] is starting up. This is where the -/// [`World`] can be initialized and setup. -/// 4. [`State::Processing`]: The [`World`] is processing. This is where the -/// [`World`] can process events and produce actions. The [`State::Processing`] -/// stage may run for a long time before all [`World`]s are finished processing. -/// This is the main stage of the [`World`] that predominantly runs automation. -/// 5. [`State::Stopped`]: The [`World`] is stopped. This is where the [`World`] -/// can be stopped and state of the [`World`] and its [`Agent`]s can be -/// offloaded and saved. +/// The [`World`] holds on to a collection of [`Agent`]s and can run them all concurrently when the +/// [`run`] method is called. The [`World`] takes in [`AgentBuilder`]s and when it does so, it creates [`Agent`]s that are now +/// connected to the world via a client ([`Arc`]) and a messager ([`Messager`]). pub struct World { /// The identifier of the world. pub id: String, @@ -91,10 +73,12 @@ impl World { } /// Runs the world through up to the [`State::Processing`] stage. - pub async fn run(&mut self) { + pub async fn run(&mut self) -> Result<()> { let mut tasks = vec![]; - // TODO: This unwrap should be checked. - let agents = self.agents.take().unwrap(); + let agents = self + .agents + .take() + .ok_or_else(|| anyhow!("No agents found! Has the world already been run?"))?; let mut messagers = VecDeque::new(); for (_, agent) in agents.iter() { for _ in &agent.behavior_engines { @@ -113,6 +97,7 @@ impl World { } } join_all(tasks).await; + Ok(()) } }