mirror of
https://github.com/FyroxEngine/Fyrox.git
synced 2026-10-12 02:02:20 +00:00
move some Plugin trait functionality to PluginConstructor
- this change drops `Default` requirement for plugins which considered to be very restrictive - now actual plugin instances created by `PluginConstructor`s - plugin constructor is responsible for script registration and creating plugin instance
This commit is contained in:
+3
-3
@@ -99,7 +99,7 @@ use fyrox::{
|
||||
BuildContext, UiNode, UserInterface, VerticalAlignment,
|
||||
},
|
||||
material::{shader::Shader, Material, PropertyValue},
|
||||
plugin::Plugin,
|
||||
plugin::PluginConstructor,
|
||||
resource::texture::{CompressionOptions, Texture, TextureKind},
|
||||
scene::{
|
||||
camera::Projection,
|
||||
@@ -1693,9 +1693,9 @@ impl Editor {
|
||||
self.asset_browser.update(&mut self.engine);
|
||||
}
|
||||
|
||||
pub fn add_game_plugin<P>(&mut self, plugin: P) -> bool
|
||||
pub fn add_game_plugin<P>(&mut self, plugin: P)
|
||||
where
|
||||
P: Plugin + TypeUuidProvider,
|
||||
P: PluginConstructor + TypeUuidProvider + 'static,
|
||||
{
|
||||
self.engine.add_plugin(plugin)
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
use fyrox::event_loop::EventLoop;
|
||||
use fyroxed_base::{Editor, StartupData};
|
||||
use game::GamePlugin;
|
||||
use game::GameConstructor;
|
||||
|
||||
fn main() {
|
||||
let event_loop = EventLoop::new();
|
||||
@@ -11,6 +11,6 @@ fn main() {
|
||||
scene: "data/scene.rgs".into(),
|
||||
}),
|
||||
);
|
||||
editor.add_game_plugin::<GamePlugin>();
|
||||
editor.add_game_plugin(GameConstructor);
|
||||
editor.run(event_loop)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use fyrox::engine::executor::Executor;
|
||||
use game::GamePlugin;
|
||||
use game::GameConstructor;
|
||||
|
||||
fn main() {
|
||||
let mut executor = Executor::new();
|
||||
executor.add_plugin(GamePlugin::new());
|
||||
executor.add_plugin(GameConstructor);
|
||||
executor.run()
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::{block_on, GamePlugin};
|
||||
use crate::{block_on, GameConstructor};
|
||||
use fyrox::{
|
||||
animation::{
|
||||
machine::{Machine, Parameter, PoseNode, State, Transition},
|
||||
@@ -142,7 +142,7 @@ impl ScriptTrait for Bot {
|
||||
}
|
||||
|
||||
fn plugin_uuid(&self) -> Uuid {
|
||||
GamePlugin::type_uuid()
|
||||
GameConstructor::type_uuid()
|
||||
}
|
||||
|
||||
fn id(&self) -> Uuid {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::bot::Bot;
|
||||
use fyrox::event_loop::ControlFlow;
|
||||
use fyrox::{
|
||||
core::{
|
||||
algebra::{UnitQuaternion, Vector3},
|
||||
@@ -15,8 +16,7 @@ use fyrox::{
|
||||
widget::WidgetBuilder,
|
||||
},
|
||||
impl_component_provider,
|
||||
plugin::{Plugin, PluginContext, PluginRegistrationContext},
|
||||
renderer::ui_renderer::SceneUserInterface,
|
||||
plugin::{Plugin, PluginConstructor, PluginContext, PluginRegistrationContext},
|
||||
scene::{
|
||||
camera::Camera,
|
||||
graph::map::NodeHandleMap,
|
||||
@@ -26,52 +26,38 @@ use fyrox::{
|
||||
},
|
||||
script::{ScriptContext, ScriptTrait},
|
||||
};
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
mod bot;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct GamePlugin {
|
||||
scene: Handle<Scene>,
|
||||
ui: Option<Rc<RefCell<SceneUserInterface>>>,
|
||||
debug_draw: bool,
|
||||
scene: Handle<Scene>,
|
||||
}
|
||||
|
||||
pub struct GameConstructor;
|
||||
|
||||
impl PluginConstructor for GameConstructor {
|
||||
fn register(&self, context: PluginRegistrationContext) {
|
||||
let scripts = &context.serialization_context.script_constructors;
|
||||
|
||||
scripts
|
||||
.add::<GameConstructor, Player, _>("Player")
|
||||
.add::<GameConstructor, Jumper, _>("Jumper")
|
||||
.add::<GameConstructor, Bot, _>("Bot");
|
||||
}
|
||||
|
||||
fn create_instance(
|
||||
&self,
|
||||
override_scene: Handle<Scene>,
|
||||
context: PluginContext,
|
||||
) -> Box<dyn Plugin> {
|
||||
Box::new(GamePlugin::new(override_scene, context))
|
||||
}
|
||||
}
|
||||
|
||||
impl GamePlugin {
|
||||
pub fn set_scene(&mut self, scene: Handle<Scene>, context: PluginContext) {
|
||||
self.scene = scene;
|
||||
|
||||
let mut ui = SceneUserInterface::new(scene);
|
||||
|
||||
let ctx = &mut ui.build_ctx();
|
||||
ButtonBuilder::new(WidgetBuilder::new().with_width(200.0).with_height(32.0))
|
||||
.with_text("Click me")
|
||||
.build(ctx);
|
||||
|
||||
let shared_ui = Rc::new(RefCell::new(ui));
|
||||
|
||||
context.renderer.add_render_pass(shared_ui.clone());
|
||||
|
||||
self.ui = Some(shared_ui);
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeUuidProvider for GamePlugin {
|
||||
fn type_uuid() -> Uuid {
|
||||
uuid!("a9507fb2-0945-4fc1-91ce-115ae7c8a615")
|
||||
}
|
||||
}
|
||||
|
||||
impl Plugin for GamePlugin {
|
||||
fn on_register(&mut self, context: PluginRegistrationContext) {
|
||||
let scripts = &context.serialization_context.script_constructors;
|
||||
|
||||
scripts.add::<GamePlugin, Player, &str>("Player");
|
||||
scripts.add::<GamePlugin, Jumper, &str>("Jumper");
|
||||
scripts.add::<GamePlugin, Bot, &str>("Bot");
|
||||
}
|
||||
|
||||
fn on_init(&mut self, override_scene: Handle<Scene>, context: PluginContext) {
|
||||
fn new(override_scene: Handle<Scene>, context: PluginContext) -> Self {
|
||||
let scene = if override_scene.is_some() {
|
||||
override_scene
|
||||
} else {
|
||||
@@ -92,10 +78,26 @@ impl Plugin for GamePlugin {
|
||||
}
|
||||
}
|
||||
|
||||
self.set_scene(scene, context);
|
||||
}
|
||||
let ctx = &mut context.user_interface.build_ctx();
|
||||
ButtonBuilder::new(WidgetBuilder::new().with_width(200.0).with_height(32.0))
|
||||
.with_text("Click me")
|
||||
.build(ctx);
|
||||
|
||||
fn update(&mut self, context: &mut PluginContext) {
|
||||
Self {
|
||||
scene,
|
||||
debug_draw: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeUuidProvider for GameConstructor {
|
||||
fn type_uuid() -> Uuid {
|
||||
uuid!("a9507fb2-0945-4fc1-91ce-115ae7c8a615")
|
||||
}
|
||||
}
|
||||
|
||||
impl Plugin for GamePlugin {
|
||||
fn update(&mut self, context: &mut PluginContext, _control_flow: &mut ControlFlow) {
|
||||
let scene = &mut context.scenes[self.scene];
|
||||
|
||||
if self.debug_draw {
|
||||
@@ -103,21 +105,10 @@ impl Plugin for GamePlugin {
|
||||
drawing_context.clear_lines();
|
||||
scene.graph.physics.draw(drawing_context);
|
||||
}
|
||||
|
||||
if let Some(mut ui) = self.ui.as_mut().map(|ui| ui.borrow_mut()) {
|
||||
ui.update(context.dt, context.renderer);
|
||||
while ui.poll_message().is_some() {}
|
||||
}
|
||||
}
|
||||
|
||||
fn id(&self) -> Uuid {
|
||||
Self::type_uuid()
|
||||
}
|
||||
|
||||
fn on_os_event(&mut self, event: &Event<()>, _context: PluginContext) {
|
||||
if let Some(mut ui) = self.ui.as_mut().map(|ui| ui.borrow_mut()) {
|
||||
ui.process_event(event);
|
||||
}
|
||||
GameConstructor::type_uuid()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,7 +274,7 @@ impl ScriptTrait for Player {
|
||||
}
|
||||
|
||||
fn plugin_uuid(&self) -> Uuid {
|
||||
GamePlugin::type_uuid()
|
||||
GameConstructor::type_uuid()
|
||||
}
|
||||
|
||||
fn id(&self) -> Uuid {
|
||||
@@ -344,6 +335,6 @@ impl ScriptTrait for Jumper {
|
||||
}
|
||||
|
||||
fn plugin_uuid(&self) -> Uuid {
|
||||
GamePlugin::type_uuid()
|
||||
GameConstructor::type_uuid()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::{
|
||||
engine::{resource_manager::ResourceManager, Engine, EngineInitParams, SerializationContext},
|
||||
event::{Event, WindowEvent},
|
||||
event_loop::{ControlFlow, EventLoop},
|
||||
plugin::Plugin,
|
||||
plugin::PluginConstructor,
|
||||
scene::{node::TypeUuidProvider, SceneLoader},
|
||||
utils::{
|
||||
log::{Log, MessageKind},
|
||||
@@ -72,9 +72,9 @@ impl Executor {
|
||||
Self { event_loop, engine }
|
||||
}
|
||||
|
||||
pub fn add_plugin<P>(&mut self, plugin: P) -> bool
|
||||
pub fn add_plugin<P>(&mut self, plugin: P)
|
||||
where
|
||||
P: Plugin + TypeUuidProvider,
|
||||
P: PluginConstructor + TypeUuidProvider + 'static,
|
||||
{
|
||||
self.engine.add_plugin(plugin)
|
||||
}
|
||||
|
||||
+18
-20
@@ -8,6 +8,7 @@ pub mod executor;
|
||||
pub mod framework;
|
||||
pub mod resource_manager;
|
||||
|
||||
use crate::plugin::PluginConstructor;
|
||||
use crate::{
|
||||
asset::ResourceState,
|
||||
core::{algebra::Vector2, futures::executor::block_on, instant, pool::Handle},
|
||||
@@ -95,6 +96,9 @@ pub struct Engine {
|
||||
// device. For more info see docs for Context.
|
||||
sound_engine: Arc<Mutex<SoundEngine>>,
|
||||
|
||||
// A set of plugin constructors.
|
||||
plugin_constructors: Vec<Box<dyn PluginConstructor>>,
|
||||
|
||||
// A set of plugins used by the engine.
|
||||
plugins: Vec<Box<dyn Plugin>>,
|
||||
|
||||
@@ -408,6 +412,7 @@ impl Engine {
|
||||
serialization_context: node_constructors,
|
||||
scripted_scenes: Default::default(),
|
||||
plugins_enabled: false,
|
||||
plugin_constructors: Default::default(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -779,9 +784,9 @@ impl Engine {
|
||||
self.plugins_enabled = enabled;
|
||||
|
||||
if self.plugins_enabled {
|
||||
for plugin in self.plugins.iter_mut() {
|
||||
// Initialize plugin.
|
||||
plugin.on_init(
|
||||
// Create and initialize instances.
|
||||
for constructor in self.plugin_constructors.iter() {
|
||||
self.plugins.push(constructor.create_instance(
|
||||
override_scene,
|
||||
PluginContext {
|
||||
scenes: &mut self.scenes,
|
||||
@@ -792,12 +797,12 @@ impl Engine {
|
||||
serialization_context: self.serialization_context.clone(),
|
||||
window: get_window!(self),
|
||||
},
|
||||
);
|
||||
));
|
||||
}
|
||||
} else {
|
||||
self.handle_script_messages();
|
||||
|
||||
for plugin in self.plugins.iter_mut() {
|
||||
for mut plugin in self.plugins.drain(..) {
|
||||
// Deinit plugin first.
|
||||
plugin.on_deinit(PluginContext {
|
||||
scenes: &mut self.scenes,
|
||||
@@ -808,29 +813,22 @@ impl Engine {
|
||||
serialization_context: self.serialization_context.clone(),
|
||||
window: get_window!(self),
|
||||
});
|
||||
// Reset plugin state.
|
||||
*plugin = plugin.default_boxed();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds new plugin.
|
||||
pub fn add_plugin<P>(&mut self, mut plugin: P) -> bool
|
||||
/// Adds new plugin plugin constructor. Actual plugin instances will be created on-demand by calling
|
||||
/// [Self::enable_plugins]
|
||||
pub fn add_plugin<P>(&mut self, constructor: P)
|
||||
where
|
||||
P: Plugin + TypeUuidProvider,
|
||||
P: PluginConstructor + TypeUuidProvider + 'static,
|
||||
{
|
||||
if self.plugins.iter().any(|p| p.id() == P::type_uuid()) {
|
||||
false
|
||||
} else {
|
||||
plugin.on_register(PluginRegistrationContext {
|
||||
serialization_context: self.serialization_context.clone(),
|
||||
});
|
||||
constructor.register(PluginRegistrationContext {
|
||||
serialization_context: self.serialization_context.clone(),
|
||||
});
|
||||
|
||||
self.plugins.push(Box::new(plugin));
|
||||
|
||||
true
|
||||
}
|
||||
self.plugin_constructors.push(Box::new(constructor));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+28
-34
@@ -14,6 +14,33 @@ use crate::{
|
||||
};
|
||||
use std::{any::Any, sync::Arc};
|
||||
|
||||
/// Plugin constructor is a first step of 2-stage plugin initialization. It is responsible for plugin script
|
||||
/// registration and for creating actual plugin instance.
|
||||
///
|
||||
/// # Details
|
||||
///
|
||||
/// Why there is a need in 2-state initialization? The editor requires it, it is interested only in plugin
|
||||
/// scripts so editor does not create any plugin instances, it just uses [Self::register] to obtain information
|
||||
/// about scripts.
|
||||
pub trait PluginConstructor {
|
||||
/// The method is called when the plugin constructor was just registered in the engine. The main use of the
|
||||
/// method is to register scripts and custom scene graph nodes in [`SerializationContext`].
|
||||
fn register(&self, context: PluginRegistrationContext);
|
||||
|
||||
/// The method is called when the engine creates plugin instances. It allows to create initialized plugin
|
||||
/// instance.
|
||||
///
|
||||
/// # Important notes
|
||||
///
|
||||
/// `override_scene` is a handle to an override scene that is currently active. It is used only in editor
|
||||
/// when you enter play mode, on other cases it is `Handle::NONE`.
|
||||
fn create_instance(
|
||||
&self,
|
||||
#[allow(unused_variables)] override_scene: Handle<Scene>,
|
||||
context: PluginContext,
|
||||
) -> Box<dyn Plugin>;
|
||||
}
|
||||
|
||||
/// Contains plugin environment for the registration stage.
|
||||
pub struct PluginRegistrationContext {
|
||||
/// A reference to serialization context of the engine. See [`SerializationContext`] for more
|
||||
@@ -57,14 +84,11 @@ pub trait BasePlugin: Any + 'static {
|
||||
|
||||
/// Returns a reference to Any trait. It is used for type casting.
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||
|
||||
/// Returns default state of plugin instance. It is used to reset plugin state.
|
||||
fn default_boxed(&self) -> Box<dyn Plugin>;
|
||||
}
|
||||
|
||||
impl<T> BasePlugin for T
|
||||
where
|
||||
T: Default + Any + Plugin + 'static,
|
||||
T: Any + Plugin + 'static,
|
||||
{
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
@@ -73,10 +97,6 @@ where
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn default_boxed(&self) -> Box<dyn Plugin> {
|
||||
Box::new(T::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl dyn Plugin {
|
||||
@@ -131,17 +151,6 @@ impl dyn Plugin {
|
||||
/// struct MyPlugin {}
|
||||
///
|
||||
/// impl Plugin for MyPlugin {
|
||||
/// fn on_register(&mut self, context: PluginRegistrationContext) {
|
||||
/// // The method is called when the plugin was just registered in the engine.
|
||||
/// // Register your scripts here using `context`.
|
||||
/// // The implementation is optional.
|
||||
/// }
|
||||
///
|
||||
/// fn on_init(&mut self, override_scene: Handle<Scene>, context: PluginContext) {
|
||||
/// // The method is called when the plugin is enabling.
|
||||
/// // The implementation is optional.
|
||||
/// }
|
||||
///
|
||||
/// fn on_deinit(&mut self, context: PluginContext) {
|
||||
/// // The method is called when the plugin is disabling.
|
||||
/// // The implementation is optional.
|
||||
@@ -164,21 +173,6 @@ impl dyn Plugin {
|
||||
/// }
|
||||
/// ```
|
||||
pub trait Plugin: BasePlugin {
|
||||
/// The method is called when the plugin was just registered in the engine. The main use of the
|
||||
/// method is to register scripts and custom scene graph nodes in [`SerializationContext`].
|
||||
fn on_register(&mut self, #[allow(unused_variables)] context: PluginRegistrationContext) {}
|
||||
|
||||
/// The method is called when the plugin is enabling.
|
||||
///
|
||||
/// `override_scene` is a handle to an override scene that is currently active. It is used only in editor
|
||||
/// when you enter play mode, on other cases it is `Handle::NONE`.
|
||||
fn on_init(
|
||||
&mut self,
|
||||
#[allow(unused_variables)] override_scene: Handle<Scene>,
|
||||
#[allow(unused_variables)] context: PluginContext,
|
||||
) {
|
||||
}
|
||||
|
||||
/// The method is called when the plugin is disabling.
|
||||
fn on_deinit(&mut self, #[allow(unused_variables)] context: PluginContext) {}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user