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:
Dmitry
2022-07-03 11:05:11 +03:00
parent 3d72e2043c
commit 230bf996d6
9 changed files with 105 additions and 122 deletions
+3 -3
View File
@@ -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.
+2 -2
View File
@@ -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)
}
+2 -2
View File
@@ -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()
}
+2 -2
View File
@@ -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 {
+47 -56
View File
@@ -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()
}
}
+3 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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) {}