use crate::plugin::error::GameResult;
use crate::plugin::PluginContainer;
use crate::{
core::{
pool::Handle,
task::{AsyncTask, AsyncTaskResult, TaskPool},
uuid::Uuid,
},
plugin::{Plugin, PluginContext},
scene::{node::Node, Scene},
script::{ScriptContext, ScriptTrait},
};
use fxhash::FxHashMap;
use std::sync::Arc;
pub(crate) type NodeTaskHandlerClosure = Box<
dyn for<'a, 'b, 'c> FnOnce(
Box<dyn AsyncTaskResult>,
&mut dyn ScriptTrait,
&mut ScriptContext<'a, 'b, 'c>,
) -> GameResult,
>;
pub(crate) type PluginTaskHandler = Box<
dyn for<'a, 'b> FnOnce(
Box<dyn AsyncTaskResult>,
&'a mut [PluginContainer],
&mut PluginContext<'a, 'b>,
) -> GameResult,
>;
pub(crate) struct NodeTaskHandler {
pub(crate) scene_handle: Handle<Scene>,
pub(crate) node_handle: Handle<Node>,
pub(crate) script_index: usize,
pub(crate) closure: NodeTaskHandlerClosure,
}
pub struct TaskPoolHandler {
task_pool: Arc<TaskPool>,
plugin_task_handlers: FxHashMap<Uuid, PluginTaskHandler>,
node_task_handlers: FxHashMap<Uuid, NodeTaskHandler>,
}
impl TaskPoolHandler {
pub(crate) fn new(task_pool: Arc<TaskPool>) -> Self {
Self {
task_pool,
plugin_task_handlers: Default::default(),
node_task_handlers: Default::default(),
}
}
#[inline]
pub fn spawn_plugin_task<F, T, P, C>(&mut self, future: F, on_complete: C)
where
F: AsyncTask<T>,
T: AsyncTaskResult,
P: Plugin,
for<'a, 'b> C: FnOnce(T, &mut P, &mut PluginContext<'a, 'b>) -> GameResult + 'static,
{
let task_id = self.task_pool.spawn_with_result(future);
self.plugin_task_handlers.insert(
task_id,
Box::new(move |result, plugins, context| {
let plugin = plugins
.iter_mut()
.find_map(|p| p.cast_mut::<P>())
.expect("Plugin must be present!");
let typed = result.downcast::<T>().expect("Types must match!");
on_complete(*typed, plugin, context)
}),
);
}
#[inline]
pub fn spawn_script_task<F, T, C, S>(
&mut self,
scene_handle: Handle<Scene>,
node_handle: Handle<Node>,
script_index: usize,
future: F,
on_complete: C,
) where
F: AsyncTask<T>,
T: AsyncTaskResult,
for<'a, 'b, 'c> C:
FnOnce(T, &mut S, &mut ScriptContext<'a, 'b, 'c>) -> GameResult + 'static,
S: ScriptTrait,
{
let task_id = self.task_pool.spawn_with_result(future);
self.node_task_handlers.insert(
task_id,
NodeTaskHandler {
scene_handle,
node_handle,
script_index,
closure: Box::new(move |result, script, context| {
let script = script
.as_any_ref_mut()
.downcast_mut::<S>()
.expect("Types must match");
let result = result.downcast::<T>().expect("Types must match");
on_complete(*result, script, context)
}),
},
);
}
#[inline]
pub fn inner(&self) -> &Arc<TaskPool> {
&self.task_pool
}
#[inline]
pub(crate) fn pop_plugin_task_handler(&mut self, id: Uuid) -> Option<PluginTaskHandler> {
self.plugin_task_handlers.remove(&id)
}
#[inline]
pub(crate) fn pop_node_task_handler(&mut self, id: Uuid) -> Option<NodeTaskHandler> {
self.node_task_handlers.remove(&id)
}
}