use bevy::{
ecs::{
entity::Entity,
resource::Resource,
system::{Query, Res, SystemParam},
world::{Mut, World},
},
prelude::Deref,
};
use replique::{
dialogue::Value,
host::{HostError, RepliqueHost},
};
use crate::{
call::{args::DialogueArgs, function::DialogueFunctionRegistry},
runner::DialogueRunner,
};
pub mod args;
pub mod command;
pub mod features;
pub mod function;
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct DialogueToken {
runner: Entity,
seq: u64,
}
impl DialogueToken {
pub(crate) fn new(seq: u64, runner: Entity) -> Self {
Self { runner, seq }
}
pub fn runner(&self) -> Entity {
self.runner
}
}
#[derive(Resource, Clone, Copy, Deref)]
pub(crate) struct CurrentDialogueCall(DialogueToken);
#[derive(SystemParam)]
pub struct DialogueCall<'w, 's> {
current: Res<'w, CurrentDialogueCall>,
runners: Query<'w, 's, &'static DialogueRunner>,
}
impl DialogueCall<'_, '_> {
pub fn runner(&self) -> Entity {
self.current.runner()
}
pub fn token(&self) -> DialogueToken {
self.current.0
}
pub fn token_of(&self, runner: Entity) -> Option<DialogueToken> {
self.runners
.get(runner)
.ok()
.map(|r| r.current_token(runner))
}
}
pub(crate) struct DialogueHost<'a> {
world: &'a mut World,
token: DialogueToken,
}
impl<'a> DialogueHost<'a> {
pub fn new(world: &'a mut World, token: DialogueToken) -> Self {
Self { world, token }
}
}
impl<'a> RepliqueHost for DialogueHost<'a> {
fn call(&mut self, name: &str, args: Vec<Value>) -> Result<Value, HostError> {
let token = self.token;
self.world
.resource_scope(|world, registry: Mut<DialogueFunctionRegistry>| {
if let Some(func) = registry.functions.get(name) {
world.insert_resource(CurrentDialogueCall(token));
let answer = func(world, DialogueArgs(args));
world.remove_resource::<CurrentDialogueCall>();
answer
} else {
Err(HostError::UnknownFunction(name.into()))
}
})
}
fn has_feature(&mut self, subject: &str, name: &str) -> Result<bool, HostError> {
features::has_feature(self.world, self.token.runner(), subject, name)
}
}