clear command stack in the editor when hot-reloading plugins

- this affects only scenes that has something (node, script) from the plugin being reloaded
This commit is contained in:
Dmitry Stepanov
2024-03-22 20:02:08 +03:00
parent 6b72a35d34
commit 8ecd3e75d0
5 changed files with 62 additions and 25 deletions
+40 -14
View File
@@ -1693,7 +1693,7 @@ impl Editor {
current_scene_entry.controller.clear_command_stack(
&mut current_scene_entry.command_stack,
&mut current_scene_entry.selection,
engine,
&mut engine.scenes,
);
true
} else {
@@ -2783,11 +2783,29 @@ fn update(editor: &mut Editor, window_target: &EventLoopWindowTarget<()>) {
editor
.engine
.post_update(FIXED_TIMESTEP, &Default::default());
editor.engine.handle_plugins_hot_reloading(
FIXED_TIMESTEP,
window_target,
&mut editor.game_loop_data.lag,
|plugin| {
let before_reload =
|plugin: &dyn Plugin,
affected_scenes: Vec<Handle<Scene>>,
scenes: &mut fyrox::scene::SceneContainer| {
// Clear command stacks for affected scenes. This is mandatory step, because command stack
// could contain objects from plugins and any attempt to use them after the plugin is
// unloaded will cause crash.
for i in 0..editor.scenes.entries.len() {
let entry = &mut editor.scenes.entries[i];
if let Some(game_scene) = entry.controller.downcast_ref::<GameScene>() {
if affected_scenes.contains(&game_scene.scene) {
entry.controller.clear_command_stack(
&mut entry.command_stack,
&mut entry.selection,
scenes,
);
}
}
}
editor.message_sender.send(Message::ForceSync);
// Remove property editors that were created from the plugin.
let mut definitions = editor.inspector.property_editors.definitions_mut();
let mut to_be_removed = Vec::new();
@@ -2800,14 +2818,22 @@ fn update(editor: &mut Editor, window_target: &EventLoopWindowTarget<()>) {
for type_id in to_be_removed {
definitions.remove(&type_id);
}
},
|plugin| {
*editor.inspector.property_editors.context_type_id.lock() = plugin.type_id();
editor
.inspector
.property_editors
.merge(plugin.register_property_editors());
},
};
let on_plugin_reloaded = |plugin: &dyn Plugin| {
*editor.inspector.property_editors.context_type_id.lock() = plugin.type_id();
editor
.inspector
.property_editors
.merge(plugin.register_property_editors());
};
editor.engine.handle_plugins_hot_reloading(
FIXED_TIMESTEP,
window_target,
&mut editor.game_loop_data.lag,
before_reload,
on_plugin_reloaded,
);
editor.post_update();
+1 -1
View File
@@ -115,7 +115,7 @@ pub trait SceneController: 'static {
&mut self,
command_stack: &mut CommandStack,
selection: &mut Selection,
engine: &mut Engine,
scenes: &mut SceneContainer,
);
fn on_before_render(&mut self, editor_selection: &Selection, engine: &mut Engine);
+11 -4
View File
@@ -71,9 +71,12 @@ use crate::{
world::graph::selection::GraphSelection,
Message, Settings,
};
use fyrox::asset::manager::ResourceManager;
use fyrox::engine::SerializationContext;
use std::cell::RefCell;
use std::fmt::Debug;
use std::rc::Rc;
use std::sync::Arc;
use std::{any::Any, fs::File, io::Write, path::Path};
pub mod clipboard;
@@ -106,6 +109,8 @@ pub struct GameScene {
pub camera_state: Vec<(Handle<Node>, bool)>,
pub node_property_changed_handler: SceneNodePropertyChangedHandler,
pub highlighter: Option<Rc<RefCell<HighlightRenderPass>>>,
pub resource_manager: ResourceManager,
pub serialization_context: Arc<SerializationContext>,
}
impl GameScene {
@@ -159,6 +164,8 @@ impl GameScene {
camera_state: Default::default(),
node_property_changed_handler: SceneNodePropertyChangedHandler,
highlighter,
resource_manager: engine.resource_manager.clone(),
serialization_context: engine.serialization_context.clone(),
}
}
@@ -743,16 +750,16 @@ impl SceneController for GameScene {
&mut self,
command_stack: &mut CommandStack,
selection: &mut Selection,
engine: &mut Engine,
scenes: &mut SceneContainer,
) {
GameSceneContext::exec(
selection,
&mut engine.scenes[self.scene],
&mut scenes[self.scene],
&mut self.scene_content_root,
&mut self.clipboard,
self.sender.clone(),
engine.resource_manager.clone(),
engine.serialization_context.clone(),
self.resource_manager.clone(),
self.serialization_context.clone(),
|ctx| command_stack.clear(ctx),
);
}
+1 -1
View File
@@ -328,7 +328,7 @@ impl SceneController for UiScene {
&mut self,
command_stack: &mut CommandStack,
selection: &mut Selection,
_engine: &mut Engine,
_scenes: &mut SceneContainer,
) {
UiSceneContext::exec(
&mut self.ui,
+9 -5
View File
@@ -1608,7 +1608,7 @@ impl Engine {
self.handle_async_scene_loading(dt, lag, window_target);
self.pre_update(dt, window_target, lag, switches);
self.post_update(dt, &Default::default());
self.handle_plugins_hot_reloading(dt, window_target, lag, |_| {}, |_| {});
self.handle_plugins_hot_reloading(dt, window_target, lag, |_, _, _| {}, |_| {});
}
/// Tries to hot-reload dynamic plugins marked for reloading.
@@ -1626,8 +1626,8 @@ impl Engine {
#[allow(unused_variables)] before_reload: B,
#[allow(unused_variables)] on_reloaded: F,
) where
B: FnMut(&dyn Plugin, Vec<Handle<Scene>>, &mut SceneContainer),
F: FnMut(&dyn Plugin),
B: FnMut(&dyn Plugin),
{
#[cfg(any(unix, windows))]
{
@@ -2525,7 +2525,7 @@ impl Engine {
before_reload: &mut F,
) -> Result<(), String>
where
F: FnMut(&dyn Plugin),
F: FnMut(&dyn Plugin, Vec<Handle<Scene>>, &mut SceneContainer),
{
let plugin_container = &mut self.plugins[plugin_index];
let PluginContainer::Dynamic {
@@ -2665,7 +2665,11 @@ impl Engine {
.remove(*type_uuid);
}
before_reload(state.as_loaded_ref().plugin());
before_reload(
state.as_loaded_ref().plugin(),
scenes_state.iter().map(|s| s.scene).collect::<Vec<_>>(),
&mut self.scenes,
);
// Unload the plugin.
if let DynamicPluginState::Loaded(dynamic) = state {
@@ -2802,8 +2806,8 @@ impl Engine {
mut on_reloaded: F,
) -> Result<(), String>
where
B: FnMut(&dyn Plugin, Vec<Handle<Scene>>, &mut SceneContainer),
F: FnMut(&dyn Plugin),
B: FnMut(&dyn Plugin),
{
for plugin_index in 0..self.plugins.len() {
if let PluginContainer::Dynamic {