Move the AI logic to its own module file.
This commit is contained in:
parent
d2ed246b8b
commit
336a4231a0
|
@ -0,0 +1,265 @@
|
||||||
|
use crate::db::Database;
|
||||||
|
use crate::kobold_api::Client as KoboldClient;
|
||||||
|
use crate::models::commands::{
|
||||||
|
CommandExecution, Commands, ExecutionConversionResult, RawCommandExecution,
|
||||||
|
};
|
||||||
|
use crate::models::world::items::{Category, Item, Rarity};
|
||||||
|
use crate::models::world::people::{Gender, Person, Sex};
|
||||||
|
use crate::models::world::raw::{ItemSeed, PersonSeed, SceneSeed};
|
||||||
|
use crate::models::world::scenes::{Exit, Scene, SceneStub, Stage};
|
||||||
|
use crate::models::{new_uuid_string, Content, ContentContainer, ContentRelation};
|
||||||
|
use anyhow::{bail, Result};
|
||||||
|
use itertools::Itertools;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use super::generator::AiClient;
|
||||||
|
|
||||||
|
use super::coherence::AiCoherence;
|
||||||
|
|
||||||
|
/// Highest-level AI/LLM construct, which returns fully converted game
|
||||||
|
/// objects to us. Basically, call the mid-level `client` to create
|
||||||
|
/// seed objects, then call the mid level client again to detail the
|
||||||
|
/// entities from their seeds. Then, stick a DB ID on them and put
|
||||||
|
/// them in the database(?).
|
||||||
|
pub struct AiLogic {
|
||||||
|
generator: Rc<AiClient>,
|
||||||
|
coherence: AiCoherence,
|
||||||
|
db: Rc<Database>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AiLogic {
|
||||||
|
pub fn new(api_client: Rc<KoboldClient>, db: &Rc<Database>) -> AiLogic {
|
||||||
|
let generator = Rc::new(AiClient::new(api_client));
|
||||||
|
let coherence = AiCoherence::new(generator.clone());
|
||||||
|
|
||||||
|
AiLogic {
|
||||||
|
generator,
|
||||||
|
coherence,
|
||||||
|
db: db.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn execute(
|
||||||
|
&mut self,
|
||||||
|
stage: &Stage,
|
||||||
|
cmd: &str,
|
||||||
|
) -> Result<(Commands, CommandExecution)> {
|
||||||
|
let parsed_cmd = self.generator.parse(cmd).await?;
|
||||||
|
let execution = self.execute_parsed(stage, &parsed_cmd).await?;
|
||||||
|
Ok((parsed_cmd, execution))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn execute_parsed(
|
||||||
|
&mut self,
|
||||||
|
stage: &Stage,
|
||||||
|
parsed_cmd: &Commands,
|
||||||
|
) -> Result<CommandExecution> {
|
||||||
|
//TODO handle multiple commands in list
|
||||||
|
if parsed_cmd.commands.is_empty() {
|
||||||
|
return Ok(CommandExecution::empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
let cmd = &parsed_cmd.commands[0];
|
||||||
|
let raw_exec: RawCommandExecution = self.generator.execute_raw(stage, cmd).await?;
|
||||||
|
|
||||||
|
// Coherence check:
|
||||||
|
// Set aside any events that are not in the enum
|
||||||
|
// Set aside anything with correct event, but wrong parameters.
|
||||||
|
// Ask LLM to fix them, if possible
|
||||||
|
//TODO make a aiclient::fix_execution
|
||||||
|
let converted = crate::commands::convert_raw_execution(raw_exec, &self.db).await;
|
||||||
|
|
||||||
|
self.generator.reset_commands();
|
||||||
|
|
||||||
|
//TODO handle the errored events aside from yeeting them out
|
||||||
|
match converted {
|
||||||
|
ExecutionConversionResult::Success(execution) => Ok(execution),
|
||||||
|
ExecutionConversionResult::PartialSuccess(execution, _) => Ok(execution),
|
||||||
|
ExecutionConversionResult::Failure(failures) => {
|
||||||
|
bail!("unhandled command execution failure: {:?}", failures)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn create_person(&mut self, scene: &SceneSeed, seed: &PersonSeed) -> Result<Person> {
|
||||||
|
self.generator.reset_person_creation();
|
||||||
|
let details = self.generator.create_person_details(scene, seed).await?;
|
||||||
|
|
||||||
|
let gender = match details.gender.to_lowercase().as_ref() {
|
||||||
|
"male" | "man" | "boy" | "transmasc" => Gender::Male,
|
||||||
|
"female" | "woman" | "girl" | "transfem" => Gender::Female,
|
||||||
|
"nonbinary" => Gender::NonBinary,
|
||||||
|
// fall back to using sex
|
||||||
|
_ => match details.sex.to_lowercase().as_ref() {
|
||||||
|
"male" | "man" | "boy" | "transmasc" => Gender::Male,
|
||||||
|
"female" | "woman" | "girl" | "transfem" => Gender::Female,
|
||||||
|
_ => Gender::NonBinary, // TODO 1/3 chance!
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let sex = match details.sex.to_lowercase().as_ref() {
|
||||||
|
"male" | "man" | "boy" | "transfem" => Sex::Male,
|
||||||
|
"female" | "woman" | "girl" | "transmasc" => Sex::Female,
|
||||||
|
_ => match gender {
|
||||||
|
Gender::Male => Sex::Male,
|
||||||
|
Gender::Female => Sex::Male,
|
||||||
|
_ => Sex::Male, // TODO 50/50 chance!
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
self.generator.reset_person_creation();
|
||||||
|
|
||||||
|
Ok(Person {
|
||||||
|
_key: Some(new_uuid_string()),
|
||||||
|
name: seed.name.to_string(),
|
||||||
|
description: details.description,
|
||||||
|
age: details.age,
|
||||||
|
residence: details.residence,
|
||||||
|
current_activity: details.current_activity,
|
||||||
|
occupation: seed.occupation.to_string(),
|
||||||
|
race: seed.race.clone(),
|
||||||
|
sex,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn create_item(&mut self, scene: &SceneSeed, seed: &ItemSeed) -> Result<Item> {
|
||||||
|
let details = self.generator.create_item_details(scene, seed).await?;
|
||||||
|
|
||||||
|
// TODO these have to be sent to the AI
|
||||||
|
let category = Category::Other;
|
||||||
|
let rarity = Rarity::Common;
|
||||||
|
|
||||||
|
Ok(Item {
|
||||||
|
_key: Some(new_uuid_string()),
|
||||||
|
name: seed.name.to_string(),
|
||||||
|
description: details.description,
|
||||||
|
attributes: details.attributes,
|
||||||
|
secret_attributes: details.secret_attributes,
|
||||||
|
category,
|
||||||
|
rarity,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn create_scene_with_id(
|
||||||
|
&mut self,
|
||||||
|
scene_type: &str,
|
||||||
|
fantasticalness: &str,
|
||||||
|
scene_id: &str,
|
||||||
|
) -> Result<ContentContainer> {
|
||||||
|
let mut content = self.create_scene(scene_type, fantasticalness).await?;
|
||||||
|
let scene = content.owner.as_scene_mut();
|
||||||
|
scene._key = Some(scene_id.to_string());
|
||||||
|
|
||||||
|
Ok(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn create_scene_from_stub(
|
||||||
|
&mut self,
|
||||||
|
stub: SceneStub,
|
||||||
|
connected_scene: &Scene,
|
||||||
|
) -> Result<ContentContainer> {
|
||||||
|
self.generator.reset_world_creation();
|
||||||
|
|
||||||
|
let seed = self
|
||||||
|
.generator
|
||||||
|
.create_scene_seed_from_stub(&stub, connected_scene)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// There are two coherence steps: the first fixes up exit
|
||||||
|
// directions and stuff, while the second is the normal scene
|
||||||
|
// coherence (that can invoke the LLM).
|
||||||
|
let mut content = self.fill_in_scene_from_stub(seed, stub).await?;
|
||||||
|
self.coherence
|
||||||
|
.make_scene_from_stub_coherent(&mut content, connected_scene);
|
||||||
|
self.coherence.make_scene_coherent(&mut content).await?;
|
||||||
|
|
||||||
|
self.generator.reset_world_creation();
|
||||||
|
|
||||||
|
Ok(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn create_scene(
|
||||||
|
&mut self,
|
||||||
|
scene_type: &str,
|
||||||
|
fantasticalness: &str,
|
||||||
|
) -> Result<ContentContainer> {
|
||||||
|
self.generator.reset_world_creation();
|
||||||
|
|
||||||
|
let scene_seed = self
|
||||||
|
.generator
|
||||||
|
.create_scene_seed(scene_type, fantasticalness)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let mut content = self.fill_in_scene(scene_seed).await?;
|
||||||
|
self.coherence.make_scene_coherent(&mut content).await?;
|
||||||
|
|
||||||
|
self.generator.reset_world_creation();
|
||||||
|
Ok(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn fill_in_scene_from_stub(
|
||||||
|
&mut self,
|
||||||
|
seed: SceneSeed,
|
||||||
|
stub: SceneStub,
|
||||||
|
) -> Result<ContentContainer> {
|
||||||
|
let mut content = self.fill_in_scene(seed).await?;
|
||||||
|
let new_scene = content.owner.as_scene_mut();
|
||||||
|
new_scene._id = stub._id;
|
||||||
|
new_scene._key = stub._key;
|
||||||
|
|
||||||
|
Ok(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn fill_in_scene(&mut self, mut scene_seed: SceneSeed) -> Result<ContentContainer> {
|
||||||
|
let mut content_in_scene = vec![];
|
||||||
|
|
||||||
|
// People in scene
|
||||||
|
let mut people = vec![];
|
||||||
|
for person_seed in scene_seed.people.as_slice() {
|
||||||
|
let person = self.create_person(&scene_seed, person_seed).await?;
|
||||||
|
people.push(ContentRelation::person(person));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Items in scene
|
||||||
|
let mut items = vec![];
|
||||||
|
for item_seed in scene_seed.items.as_slice() {
|
||||||
|
let item = self.create_item(&scene_seed, item_seed).await?;
|
||||||
|
items.push(ContentRelation::item(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO items on people, which will require 'recursive' ContentContainers.
|
||||||
|
|
||||||
|
let exits: Vec<_> = scene_seed
|
||||||
|
.exits
|
||||||
|
.drain(0..)
|
||||||
|
.map(|seed| Exit::from(seed))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut stubs: Vec<_> = exits
|
||||||
|
.iter()
|
||||||
|
.map(|exit| ContentRelation::scene_stub(SceneStub::from(exit)))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut scene = Scene {
|
||||||
|
_key: Some(new_uuid_string()),
|
||||||
|
name: scene_seed.name,
|
||||||
|
region: scene_seed.region,
|
||||||
|
description: scene_seed.description,
|
||||||
|
props: scene_seed.props.drain(0..).map_into().collect(),
|
||||||
|
is_stub: false,
|
||||||
|
exits,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
content_in_scene.append(&mut people);
|
||||||
|
content_in_scene.append(&mut items);
|
||||||
|
content_in_scene.append(&mut stubs);
|
||||||
|
|
||||||
|
Ok(ContentContainer {
|
||||||
|
owner: Content::Scene(scene),
|
||||||
|
contained: content_in_scene,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
270
src/ai/mod.rs
270
src/ai/mod.rs
|
@ -1,271 +1,5 @@
|
||||||
use crate::db::Database;
|
pub(self) mod coherence;
|
||||||
use crate::kobold_api::Client as KoboldClient;
|
|
||||||
use crate::models::commands::{
|
|
||||||
CommandExecution, Commands, ExecutionConversionResult, RawCommandExecution,
|
|
||||||
};
|
|
||||||
use crate::models::world::items::{Category, Item, Rarity};
|
|
||||||
use crate::models::world::people::{Gender, Person, Sex};
|
|
||||||
use crate::models::world::raw::{ItemSeed, PersonSeed, SceneSeed};
|
|
||||||
use crate::models::world::scenes::{Exit, Scene, SceneStub, Stage};
|
|
||||||
use crate::models::{new_uuid_string, Content, ContentContainer, ContentRelation};
|
|
||||||
use anyhow::{bail, Result};
|
|
||||||
use itertools::Itertools;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
mod coherence;
|
|
||||||
pub mod convo;
|
pub mod convo;
|
||||||
pub mod generator;
|
pub mod generator;
|
||||||
pub mod prompts;
|
pub mod prompts;
|
||||||
|
pub mod logic;
|
||||||
use convo::AiPrompt;
|
|
||||||
use generator::AiClient;
|
|
||||||
|
|
||||||
use self::coherence::AiCoherence;
|
|
||||||
|
|
||||||
/// Highest-level AI/LLM construct, which returns fully converted game
|
|
||||||
/// objects to us. Basically, call the mid-level `client` to create
|
|
||||||
/// seed objects, then call the mid level client again to detail the
|
|
||||||
/// entities from their seeds. Then, stick a DB ID on them and put
|
|
||||||
/// them in the database(?).
|
|
||||||
pub struct AiLogic {
|
|
||||||
generator: Rc<AiClient>,
|
|
||||||
coherence: AiCoherence,
|
|
||||||
db: Rc<Database>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AiLogic {
|
|
||||||
pub fn new(api_client: Rc<KoboldClient>, db: &Rc<Database>) -> AiLogic {
|
|
||||||
let generator = Rc::new(AiClient::new(api_client));
|
|
||||||
let coherence = AiCoherence::new(generator.clone());
|
|
||||||
|
|
||||||
AiLogic {
|
|
||||||
generator,
|
|
||||||
coherence,
|
|
||||||
db: db.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn execute(
|
|
||||||
&mut self,
|
|
||||||
stage: &Stage,
|
|
||||||
cmd: &str,
|
|
||||||
) -> Result<(Commands, CommandExecution)> {
|
|
||||||
let parsed_cmd = self.generator.parse(cmd).await?;
|
|
||||||
let execution = self.execute_parsed(stage, &parsed_cmd).await?;
|
|
||||||
Ok((parsed_cmd, execution))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn execute_parsed(
|
|
||||||
&mut self,
|
|
||||||
stage: &Stage,
|
|
||||||
parsed_cmd: &Commands,
|
|
||||||
) -> Result<CommandExecution> {
|
|
||||||
//TODO handle multiple commands in list
|
|
||||||
if parsed_cmd.commands.is_empty() {
|
|
||||||
return Ok(CommandExecution::empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
let cmd = &parsed_cmd.commands[0];
|
|
||||||
let raw_exec: RawCommandExecution = self.generator.execute_raw(stage, cmd).await?;
|
|
||||||
|
|
||||||
// Coherence check:
|
|
||||||
// Set aside any events that are not in the enum
|
|
||||||
// Set aside anything with correct event, but wrong parameters.
|
|
||||||
// Ask LLM to fix them, if possible
|
|
||||||
//TODO make a aiclient::fix_execution
|
|
||||||
let converted = crate::commands::convert_raw_execution(raw_exec, &self.db).await;
|
|
||||||
|
|
||||||
self.generator.reset_commands();
|
|
||||||
|
|
||||||
//TODO handle the errored events aside from yeeting them out
|
|
||||||
match converted {
|
|
||||||
ExecutionConversionResult::Success(execution) => Ok(execution),
|
|
||||||
ExecutionConversionResult::PartialSuccess(execution, _) => Ok(execution),
|
|
||||||
ExecutionConversionResult::Failure(failures) => {
|
|
||||||
bail!("unhandled command execution failure: {:?}", failures)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn create_person(&mut self, scene: &SceneSeed, seed: &PersonSeed) -> Result<Person> {
|
|
||||||
self.generator.reset_person_creation();
|
|
||||||
let details = self.generator.create_person_details(scene, seed).await?;
|
|
||||||
|
|
||||||
let gender = match details.gender.to_lowercase().as_ref() {
|
|
||||||
"male" | "man" | "boy" | "transmasc" => Gender::Male,
|
|
||||||
"female" | "woman" | "girl" | "transfem" => Gender::Female,
|
|
||||||
"nonbinary" => Gender::NonBinary,
|
|
||||||
// fall back to using sex
|
|
||||||
_ => match details.sex.to_lowercase().as_ref() {
|
|
||||||
"male" | "man" | "boy" | "transmasc" => Gender::Male,
|
|
||||||
"female" | "woman" | "girl" | "transfem" => Gender::Female,
|
|
||||||
_ => Gender::NonBinary, // TODO 1/3 chance!
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let sex = match details.sex.to_lowercase().as_ref() {
|
|
||||||
"male" | "man" | "boy" | "transfem" => Sex::Male,
|
|
||||||
"female" | "woman" | "girl" | "transmasc" => Sex::Female,
|
|
||||||
_ => match gender {
|
|
||||||
Gender::Male => Sex::Male,
|
|
||||||
Gender::Female => Sex::Male,
|
|
||||||
_ => Sex::Male, // TODO 50/50 chance!
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
self.generator.reset_person_creation();
|
|
||||||
|
|
||||||
Ok(Person {
|
|
||||||
_key: Some(new_uuid_string()),
|
|
||||||
name: seed.name.to_string(),
|
|
||||||
description: details.description,
|
|
||||||
age: details.age,
|
|
||||||
residence: details.residence,
|
|
||||||
current_activity: details.current_activity,
|
|
||||||
occupation: seed.occupation.to_string(),
|
|
||||||
race: seed.race.clone(),
|
|
||||||
sex,
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn create_item(&mut self, scene: &SceneSeed, seed: &ItemSeed) -> Result<Item> {
|
|
||||||
let details = self.generator.create_item_details(scene, seed).await?;
|
|
||||||
|
|
||||||
// TODO these have to be sent to the AI
|
|
||||||
let category = Category::Other;
|
|
||||||
let rarity = Rarity::Common;
|
|
||||||
|
|
||||||
Ok(Item {
|
|
||||||
_key: Some(new_uuid_string()),
|
|
||||||
name: seed.name.to_string(),
|
|
||||||
description: details.description,
|
|
||||||
attributes: details.attributes,
|
|
||||||
secret_attributes: details.secret_attributes,
|
|
||||||
category,
|
|
||||||
rarity,
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn create_scene_with_id(
|
|
||||||
&mut self,
|
|
||||||
scene_type: &str,
|
|
||||||
fantasticalness: &str,
|
|
||||||
scene_id: &str,
|
|
||||||
) -> Result<ContentContainer> {
|
|
||||||
let mut content = self.create_scene(scene_type, fantasticalness).await?;
|
|
||||||
let scene = content.owner.as_scene_mut();
|
|
||||||
scene._key = Some(scene_id.to_string());
|
|
||||||
|
|
||||||
Ok(content)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn create_scene_from_stub(
|
|
||||||
&mut self,
|
|
||||||
stub: SceneStub,
|
|
||||||
connected_scene: &Scene,
|
|
||||||
) -> Result<ContentContainer> {
|
|
||||||
self.generator.reset_world_creation();
|
|
||||||
|
|
||||||
let seed = self
|
|
||||||
.generator
|
|
||||||
.create_scene_seed_from_stub(&stub, connected_scene)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// There are two coherence steps: the first fixes up exit
|
|
||||||
// directions and stuff, while the second is the normal scene
|
|
||||||
// coherence (that can invoke the LLM).
|
|
||||||
let mut content = self.fill_in_scene_from_stub(seed, stub).await?;
|
|
||||||
self.coherence
|
|
||||||
.make_scene_from_stub_coherent(&mut content, connected_scene);
|
|
||||||
self.coherence.make_scene_coherent(&mut content).await?;
|
|
||||||
|
|
||||||
self.generator.reset_world_creation();
|
|
||||||
|
|
||||||
Ok(content)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn create_scene(
|
|
||||||
&mut self,
|
|
||||||
scene_type: &str,
|
|
||||||
fantasticalness: &str,
|
|
||||||
) -> Result<ContentContainer> {
|
|
||||||
self.generator.reset_world_creation();
|
|
||||||
|
|
||||||
let scene_seed = self
|
|
||||||
.generator
|
|
||||||
.create_scene_seed(scene_type, fantasticalness)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let mut content = self.fill_in_scene(scene_seed).await?;
|
|
||||||
self.coherence.make_scene_coherent(&mut content).await?;
|
|
||||||
|
|
||||||
self.generator.reset_world_creation();
|
|
||||||
Ok(content)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn fill_in_scene_from_stub(
|
|
||||||
&mut self,
|
|
||||||
seed: SceneSeed,
|
|
||||||
stub: SceneStub,
|
|
||||||
) -> Result<ContentContainer> {
|
|
||||||
let mut content = self.fill_in_scene(seed).await?;
|
|
||||||
let new_scene = content.owner.as_scene_mut();
|
|
||||||
new_scene._id = stub._id;
|
|
||||||
new_scene._key = stub._key;
|
|
||||||
|
|
||||||
Ok(content)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn fill_in_scene(&mut self, mut scene_seed: SceneSeed) -> Result<ContentContainer> {
|
|
||||||
let mut content_in_scene = vec![];
|
|
||||||
|
|
||||||
// People in scene
|
|
||||||
let mut people = vec![];
|
|
||||||
for person_seed in scene_seed.people.as_slice() {
|
|
||||||
let person = self.create_person(&scene_seed, person_seed).await?;
|
|
||||||
people.push(ContentRelation::person(person));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Items in scene
|
|
||||||
let mut items = vec![];
|
|
||||||
for item_seed in scene_seed.items.as_slice() {
|
|
||||||
let item = self.create_item(&scene_seed, item_seed).await?;
|
|
||||||
items.push(ContentRelation::item(item));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO items on people, which will require 'recursive' ContentContainers.
|
|
||||||
|
|
||||||
let exits: Vec<_> = scene_seed
|
|
||||||
.exits
|
|
||||||
.drain(0..)
|
|
||||||
.map(|seed| Exit::from(seed))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let mut stubs: Vec<_> = exits
|
|
||||||
.iter()
|
|
||||||
.map(|exit| ContentRelation::scene_stub(SceneStub::from(exit)))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let mut scene = Scene {
|
|
||||||
_key: Some(new_uuid_string()),
|
|
||||||
name: scene_seed.name,
|
|
||||||
region: scene_seed.region,
|
|
||||||
description: scene_seed.description,
|
|
||||||
props: scene_seed.props.drain(0..).map_into().collect(),
|
|
||||||
is_stub: false,
|
|
||||||
exits,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
content_in_scene.append(&mut people);
|
|
||||||
content_in_scene.append(&mut items);
|
|
||||||
content_in_scene.append(&mut stubs);
|
|
||||||
|
|
||||||
Ok(ContentContainer {
|
|
||||||
owner: Content::Scene(scene),
|
|
||||||
contained: content_in_scene,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::ai::AiPrompt;
|
use crate::ai::convo::AiPrompt;
|
||||||
use crate::models::commands::{Command, CommandEvent, EventConversionFailures};
|
use crate::models::commands::{Command, CommandEvent, EventConversionFailures};
|
||||||
use crate::models::world::scenes::{Scene, Stage};
|
use crate::models::world::scenes::{Scene, Stage};
|
||||||
use strum::VariantNames;
|
use strum::VariantNames;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::ai::AiPrompt;
|
use crate::ai::convo::AiPrompt;
|
||||||
|
|
||||||
pub const COMMAND_BNF: &str = r#"
|
pub const COMMAND_BNF: &str = r#"
|
||||||
root ::= Commands
|
root ::= Commands
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
ai::AiPrompt,
|
ai::convo::AiPrompt,
|
||||||
models::world::{
|
models::world::{
|
||||||
raw::{PersonSeed, SceneSeed},
|
raw::{PersonSeed, SceneSeed},
|
||||||
scenes::{Exit, Scene, SceneStub},
|
scenes::{Exit, Scene, SceneStub},
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use config::Config;
|
use config::Config;
|
||||||
use game_loop::GameLoop;
|
use game_loop::GameLoop;
|
||||||
|
use ai::logic::AiLogic;
|
||||||
use models::world::scenes::{root_scene_id, Stage};
|
use models::world::scenes::{root_scene_id, Stage};
|
||||||
use state::GameState;
|
use state::GameState;
|
||||||
use std::{io::stdout, rc::Rc, time::Duration};
|
use std::{io::stdout, rc::Rc, time::Duration};
|
||||||
|
@ -101,7 +102,7 @@ async fn main() -> Result<()> {
|
||||||
base_client,
|
base_client,
|
||||||
));
|
));
|
||||||
let db = Rc::new(Database::new(conn, "test_world").await?);
|
let db = Rc::new(Database::new(conn, "test_world").await?);
|
||||||
let logic = ai::AiLogic::new(client, &db);
|
let logic = AiLogic::new(client, &db);
|
||||||
|
|
||||||
let mut state = GameState {
|
let mut state = GameState {
|
||||||
logic,
|
logic,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::models::Insertable;
|
use crate::models::Insertable;
|
||||||
use crate::{
|
use crate::{
|
||||||
ai::AiLogic,
|
ai::logic::AiLogic,
|
||||||
db::Database,
|
db::Database,
|
||||||
models::{
|
models::{
|
||||||
commands::CommandEvent,
|
commands::CommandEvent,
|
||||||
|
|
Loading…
Reference in New Issue