Skip to main content

khora_control/
plugin.rs

1// Copyright 2025 eraflo
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Engine plugins — extensible hooks that inject into the frame pipeline.
16
17use khora_core::agent::ExecutionPhase;
18use khora_data::ecs::World;
19use std::collections::HashMap;
20
21/// Boxed plugin hook executed against the world during a specific
22/// `ExecutionPhase`.
23type PluginHook = Box<dyn Fn(&mut World) + Send>;
24
25/// A plugin that injects callbacks into the frame pipeline.
26pub struct EnginePlugin {
27    name: String,
28    hooks: HashMap<ExecutionPhase, PluginHook>,
29}
30
31impl EnginePlugin {
32    /// Creates a new plugin with the given name.
33    pub fn new(name: &str) -> Self {
34        Self {
35            name: name.to_string(),
36            hooks: HashMap::new(),
37        }
38    }
39
40    /// Registers a callback for a specific execution phase.
41    pub fn on_phase(&mut self, phase: ExecutionPhase, f: impl Fn(&mut World) + Send + 'static) {
42        self.hooks.insert(phase, Box::new(f));
43    }
44
45    /// Executes the hook for a phase, if one is registered.
46    pub fn execute(&mut self, phase: ExecutionPhase, world: &mut World) {
47        if let Some(f) = self.hooks.get(&phase) {
48            f(world);
49        }
50    }
51
52    /// Returns true if this plugin has a hook for the given phase.
53    pub fn wants_phase(&self, phase: ExecutionPhase) -> bool {
54        self.hooks.contains_key(&phase)
55    }
56
57    /// Returns the plugin name.
58    pub fn name(&self) -> &str {
59        &self.name
60    }
61}