Skip to content

Commit

Permalink
fixed deadlock + fixed incorrect reloading of prefabs
Browse files Browse the repository at this point in the history
  • Loading branch information
mrDIMAS committed May 17, 2024
1 parent 0a2a680 commit 4456e88
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 31 deletions.
64 changes: 58 additions & 6 deletions fyrox-impl/src/engine/hotreload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,18 @@ use crate::{
engine::SerializationContext,
gui::constructor::WidgetConstructorContainer,
plugin::Plugin,
resource::model::ModelResource,
scene::{
base::visit_opt_script,
base::{visit_opt_script, NodeScriptMessage},
node::{container::NodeContainer, Node},
Scene,
},
script::Script,
};
use std::{ops::Deref, sync::Arc};
use std::{
ops::Deref,
sync::{mpsc::Sender, Arc},
};

pub struct ScriptState {
index: usize,
Expand Down Expand Up @@ -112,11 +116,59 @@ impl SceneState {
resource_manager: &ResourceManager,
widget_constructors: &Arc<WidgetConstructorContainer>,
) -> Result<(), String> {
// SAFETY: Scene is guaranteed to be used only once per inner loop.
let scene2 = unsafe { &mut *(scene as *mut Scene) };

let script_message_sender = scene.graph.script_message_sender.clone();
self.deserialize_into_scene_internal(
|handle: Handle<Node>, index, script| {
scene.graph[handle].scripts[index].script = script;
},
|handle: Handle<Node>, node| {
scene2.graph[handle] = node;
},
script_message_sender,
serialization_context,
resource_manager,
widget_constructors,
)
}

for node_state in self.nodes {
let node = &mut scene.graph[node_state.node];
pub fn deserialize_into_prefab_scene(
self,
prefab: &ModelResource,
serialization_context: &Arc<SerializationContext>,
resource_manager: &ResourceManager,
widget_constructors: &Arc<WidgetConstructorContainer>,
) -> Result<(), String> {
self.deserialize_into_scene_internal(
|handle: Handle<Node>, index, script| {
prefab.data_ref().scene.graph[handle].scripts[index].script = script;
},
|handle: Handle<Node>, node| {
prefab.data_ref().scene.graph[handle] = node;
},
prefab.data_ref().scene.graph.script_message_sender.clone(),
serialization_context,
resource_manager,
widget_constructors,
)
}

pub fn deserialize_into_scene_internal<S, N>(
self,
mut set_script: S,
mut set_node: N,
script_message_sender: Sender<NodeScriptMessage>,
serialization_context: &Arc<SerializationContext>,
resource_manager: &ResourceManager,
widget_constructors: &Arc<WidgetConstructorContainer>,
) -> Result<(), String>
where
S: FnMut(Handle<Node>, usize, Option<Script>),
N: FnMut(Handle<Node>, Node),
{
for node_state in self.nodes {
if node_state.binary_blob.is_empty() {
// Only scripts needs to be reloaded.
for script in node_state.scripts {
Expand All @@ -130,7 +182,7 @@ impl SceneState {
let mut opt_script: Option<Script> = None;
visit_opt_script("Script", &mut opt_script, &mut visitor)
.map_err(|e| e.to_string())?;
node.scripts[script.index].script = opt_script;
set_script(node_state.node, script.index, opt_script);

Log::info(format!(
"Script {} of node {} was successfully deserialized.",
Expand All @@ -151,7 +203,7 @@ impl SceneState {
.map_err(|e| e.to_string())?;
if let Some(mut new_node) = container.take() {
new_node.script_message_sender = Some(script_message_sender.clone());
*node = new_node;
set_node(node_state.node, new_node);

Log::info(format!(
"Node {} was successfully deserialized.",
Expand Down
49 changes: 24 additions & 25 deletions fyrox-impl/src/engine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2624,6 +2624,26 @@ impl Engine {
}
}

// Check every prefab for plugin content.
let mut prefab_scenes = Vec::new();
let rm_state = self.resource_manager.state();
for resource in rm_state.resources().iter() {
if let Some(model) = resource.try_cast::<Model>() {
let mut model_state = model.state();
if let Some(data) = model_state.data() {
if let Some(scene_state) = hotreload::SceneState::try_create_from_plugin(
Handle::NONE,
&mut data.scene,
&self.serialization_context,
state.as_loaded_ref().plugin(),
)? {
prefab_scenes.push((model.clone(), scene_state));
}
}
}
}
drop(rm_state);

// Search for script constructors, that belongs to dynamic plugins and remove them.
let mut constructors = FxHashSet::default();
for (type_uuid, constructor) in self.serialization_context.script_constructors.map().iter()
Expand Down Expand Up @@ -2691,26 +2711,6 @@ impl Engine {
block_on(join_all(resources_to_reload));
}

// Check every prefab for plugin content.
let mut prefab_scenes = Vec::new();
let rm_state = self.resource_manager.state();
for resource in rm_state.resources().iter() {
if let Some(model) = resource.try_cast::<Model>() {
let mut model_state = model.state();
if let Some(data) = model_state.data() {
if let Some(scene_state) = hotreload::SceneState::try_create_from_plugin(
Handle::NONE,
&mut data.scene,
&self.serialization_context,
state.as_loaded_ref().plugin(),
)? {
prefab_scenes.push((model.clone(), scene_state));
}
}
}
}
drop(rm_state);

// Unload custom render passes (if any).
if let GraphicsContext::Initialized(ref mut graphics_context) = self.graphics_context {
let render_passes = graphics_context.renderer.render_passes().to_vec();
Expand Down Expand Up @@ -2793,15 +2793,14 @@ impl Engine {

// Deserialize prefab scene content.
for (model, scene_state) in prefab_scenes {
let mut model_state = model.state();
if let Some(data) = model_state.data() {
scene_state.deserialize_into_scene(
&mut data.scene,
Log::info(format!("Deserializing {} prefab content...", model.kind()));

scene_state.deserialize_into_prefab_scene(
&model,
&self.serialization_context,
&self.resource_manager,
&self.widget_constructors,
)?;
}
}

// Deserialize scene content.
Expand Down

0 comments on commit 4456e88

Please sign in to comment.