mirror of
https://github.com/FyroxEngine/Fyrox.git
synced 2026-10-12 02:02:20 +00:00
Preventing deadlock by replacing lock with safe_lock (#852)
* Preventing deadlock by replacing `lock` with `safe_lock` * Fixing unused code warnings in wasm SafeLock
This commit is contained in:
@@ -24,7 +24,7 @@ use crate::{
|
||||
manager::ResourceManager,
|
||||
untyped::{ResourceKind, UntypedResource},
|
||||
},
|
||||
core::{log::Log, make_pretty_type_name, pool::Handle, Uuid},
|
||||
core::{log::Log, make_pretty_type_name, pool::Handle, SafeLock, Uuid},
|
||||
engine::Engine,
|
||||
gui::{
|
||||
button::{ButtonBuilder, ButtonMessage},
|
||||
@@ -59,7 +59,7 @@ pub struct ResourceCreator {
|
||||
impl ResourceCreator {
|
||||
pub fn new(ctx: &mut BuildContext, resource_manager: &ResourceManager) -> Self {
|
||||
let rm_state = resource_manager.state();
|
||||
let mut constructors = rm_state.constructors_container.map.lock();
|
||||
let mut constructors = rm_state.constructors_container.map.safe_lock();
|
||||
let mut items = Vec::new();
|
||||
let mut supported_resource_data_uuids = Vec::new();
|
||||
for (uuid, constructor) in constructors.iter_mut() {
|
||||
@@ -196,7 +196,7 @@ impl ResourceCreator {
|
||||
.supported_resource_data_uuids
|
||||
.get(self.selected.unwrap_or_default())
|
||||
{
|
||||
let loaders = resource_manager_state.loaders.lock();
|
||||
let loaders = resource_manager_state.loaders.safe_lock();
|
||||
if let Some(loader) = loaders
|
||||
.iter()
|
||||
.find(|loader| &loader.data_type_uuid() == data_type_uuid)
|
||||
@@ -222,7 +222,10 @@ impl ResourceCreator {
|
||||
} else if let Some(ButtonMessage::Click) = message.data() {
|
||||
if message.destination() == self.ok {
|
||||
let resource_manager_state = engine.resource_manager.state();
|
||||
let mut constructors = resource_manager_state.constructors_container.map.lock();
|
||||
let mut constructors = resource_manager_state
|
||||
.constructors_container
|
||||
.map
|
||||
.safe_lock();
|
||||
|
||||
if let Some(mut instance) = self
|
||||
.supported_resource_data_uuids
|
||||
|
||||
@@ -33,7 +33,7 @@ use crate::{
|
||||
asset::{manager::ResourceManager, options::BaseImportOptions},
|
||||
core::{
|
||||
append_extension, err, futures::executor::block_on, log::Log, make_relative_path,
|
||||
ok_or_continue, pool::Handle, some_or_continue,
|
||||
ok_or_continue, pool::Handle, some_or_continue, SafeLock,
|
||||
},
|
||||
engine::Engine,
|
||||
graph::{BaseSceneGraph, SceneGraph},
|
||||
@@ -175,7 +175,7 @@ pub struct AssetBrowser {
|
||||
|
||||
fn is_path_in_registry(path: &Path, resource_manager: &ResourceManager) -> bool {
|
||||
let rm_state = resource_manager.state();
|
||||
let registry = rm_state.resource_registry.lock();
|
||||
let registry = rm_state.resource_registry.safe_lock();
|
||||
if let Some(registry_directory) = registry.directory() {
|
||||
if let Ok(canonical_registry_path) = registry_directory.canonicalize() {
|
||||
if let Ok(canonical_path) = path.canonicalize() {
|
||||
@@ -200,7 +200,7 @@ fn is_supported_resource(ext: &OsStr, resource_manager: &ResourceManager) -> boo
|
||||
resource_manager
|
||||
.state()
|
||||
.loaders
|
||||
.lock()
|
||||
.safe_lock()
|
||||
.iter()
|
||||
.any(|loader| loader.supports_extension(ext))
|
||||
}
|
||||
@@ -812,7 +812,7 @@ impl AssetBrowser {
|
||||
let search_text = search_text.to_lowercase();
|
||||
|
||||
let registry = engine.resource_manager.state().resource_registry.clone();
|
||||
let registry = registry.lock();
|
||||
let registry = registry.safe_lock();
|
||||
let mut paths = Vec::new();
|
||||
for resource_path in registry.inner().values() {
|
||||
let file_stem = some_or_continue!(resource_path
|
||||
@@ -885,7 +885,7 @@ impl AssetBrowser {
|
||||
resource_manager: &ResourceManager,
|
||||
) -> Option<Box<dyn BaseImportOptions>> {
|
||||
let rm_state = resource_manager.state();
|
||||
let loaders = rm_state.loaders.lock();
|
||||
let loaders = rm_state.loaders.safe_lock();
|
||||
for loader in loaders.iter() {
|
||||
if loader.supports_extension(&extension.to_string_lossy()) {
|
||||
return loader.default_import_options();
|
||||
|
||||
@@ -25,7 +25,7 @@ use crate::{
|
||||
},
|
||||
fyrox::{
|
||||
asset::untyped::UntypedResource,
|
||||
core::{futures::executor::block_on, parking_lot::Mutex, pool::Handle, Uuid},
|
||||
core::{futures::executor::block_on, parking_lot::Mutex, pool::Handle, SafeLock, Uuid},
|
||||
engine::Engine,
|
||||
fxhash::FxHashMap,
|
||||
gui::{message::MessageDirection, UiNode},
|
||||
@@ -57,7 +57,7 @@ impl AssetPreviewCache {
|
||||
for request in receiver.iter() {
|
||||
let resource = request.resource.clone();
|
||||
if block_on(resource).is_ok() {
|
||||
queue.lock().push_back(request);
|
||||
queue.safe_lock().push_back(request);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -108,7 +108,7 @@ impl AssetPreviewCache {
|
||||
) {
|
||||
let mut generated = 0;
|
||||
let queue = self.queue.clone();
|
||||
let mut queue = queue.lock();
|
||||
let mut queue = queue.safe_lock();
|
||||
while let Some(request) = queue.pop_back() {
|
||||
let IconRequest {
|
||||
widget_handle,
|
||||
|
||||
@@ -23,7 +23,7 @@ use crate::{
|
||||
command::{make_command, Command, SetPropertyCommand},
|
||||
fyrox::{
|
||||
asset::{manager::ResourceManager, options::BaseImportOptions, ResourceData},
|
||||
core::{futures::executor::block_on, reflect::Reflect},
|
||||
core::{futures::executor::block_on, reflect::Reflect, SafeLock},
|
||||
engine::Engine,
|
||||
gui::inspector::PropertyChanged,
|
||||
scene::SceneContainer,
|
||||
@@ -59,7 +59,7 @@ struct SaveResourceCommand {
|
||||
|
||||
impl SaveResourceCommand {
|
||||
fn save(&self) {
|
||||
let mut guard = self.resource.0.lock();
|
||||
let mut guard = self.resource.0.safe_lock();
|
||||
if let Some(data) = guard.state.data_mut() {
|
||||
Log::verify(data.save(&self.path));
|
||||
}
|
||||
@@ -98,7 +98,7 @@ fn load_import_options_or_default(
|
||||
) -> Option<Box<dyn BaseImportOptions>> {
|
||||
if let Some(extension) = resource_path.extension() {
|
||||
let rm_state = resource_manager.state();
|
||||
let loaders = rm_state.loaders.lock();
|
||||
let loaders = rm_state.loaders.safe_lock();
|
||||
for loader in loaders.iter() {
|
||||
if loader.supports_extension(&extension.to_string_lossy()) {
|
||||
return if let Some(import_options) = block_on(loader.try_load_import_settings(
|
||||
@@ -163,7 +163,7 @@ impl SelectionContainer for AssetSelection {
|
||||
block_on(self.resource_manager.request_untyped(&resource.path))
|
||||
{
|
||||
if !self.resource_manager.is_built_in_resource(&resource) {
|
||||
let guard = resource.0.lock();
|
||||
let guard = resource.0.safe_lock();
|
||||
if let Some(data) = guard.state.data_ref() {
|
||||
callback(&*data.0 as &dyn Reflect, false)
|
||||
}
|
||||
@@ -205,7 +205,7 @@ impl SelectionContainer for AssetSelection {
|
||||
let resource2 = resource.clone();
|
||||
if !self.resource_manager.is_built_in_resource(&resource) {
|
||||
if let Some(command) = make_command(args, move |_| {
|
||||
let mut guard = resource.0.lock();
|
||||
let mut guard = resource.0.safe_lock();
|
||||
let data = &mut **guard.state.data_mut()?;
|
||||
// SAFETY: This is safe, because the closure owns its own copy of
|
||||
// resource strong ref, and the entity getter is used only once per
|
||||
@@ -264,7 +264,7 @@ impl SelectionContainer for AssetSelection {
|
||||
path.to_string(),
|
||||
value,
|
||||
move |_| {
|
||||
let mut guard = resource.0.lock();
|
||||
let mut guard = resource.0.safe_lock();
|
||||
let data = &mut **guard.state.data_mut()?;
|
||||
// SAFETY: This is safe, because the closure owns its own copy of
|
||||
// resource strong ref, and the entity getter is used only once per
|
||||
|
||||
@@ -28,7 +28,7 @@ use crate::{
|
||||
asset::{manager::ResourceManager, untyped::UntypedResource, TypedResourceData},
|
||||
core::{
|
||||
algebra::Vector2, log::Log, pool::Handle, reflect::prelude::*, type_traits::prelude::*,
|
||||
visitor::prelude::*,
|
||||
visitor::prelude::*, SafeLock,
|
||||
},
|
||||
graph::SceneGraph,
|
||||
gui::{
|
||||
@@ -307,8 +307,8 @@ impl<'a> AssetSelectorBuilder<'a> {
|
||||
ctx: &mut BuildContext,
|
||||
) -> Handle<UiNode> {
|
||||
let state = resource_manager.state();
|
||||
let loaders = state.loaders.lock();
|
||||
let registry = state.resource_registry.lock();
|
||||
let loaders = state.loaders.safe_lock();
|
||||
let registry = state.resource_registry.safe_lock();
|
||||
|
||||
let mut supported_resource_paths = loaders
|
||||
.iter()
|
||||
@@ -337,7 +337,7 @@ impl<'a> AssetSelectorBuilder<'a> {
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
supported_resource_paths.extend(state.built_in_resources.values().filter_map(|res| {
|
||||
let resource_state = res.resource.0.lock();
|
||||
let resource_state = res.resource.0.safe_lock();
|
||||
if self
|
||||
.asset_types
|
||||
.contains(&resource_state.state.data_ref()?.type_uuid())
|
||||
|
||||
@@ -23,7 +23,9 @@
|
||||
use crate::export::utils;
|
||||
use fyrox::{
|
||||
asset::manager::ResourceManager,
|
||||
core::{futures::executor, futures::future::join_all, log::Log, platform::TargetPlatform},
|
||||
core::{
|
||||
futures::executor, futures::future::join_all, log::Log, platform::TargetPlatform, SafeLock,
|
||||
},
|
||||
};
|
||||
use std::{fs, io, path::Path};
|
||||
|
||||
@@ -38,7 +40,7 @@ pub fn copy_and_convert_assets(
|
||||
if convert {
|
||||
let rm = resource_manager.state();
|
||||
let io = rm.resource_io.clone();
|
||||
let loaders = rm.loaders.lock();
|
||||
let loaders = rm.loaders.safe_lock();
|
||||
let mut tasks = Vec::new();
|
||||
|
||||
// Iterate over the file system and try to convert all the supported resources.
|
||||
|
||||
+11
-11
@@ -78,7 +78,7 @@ use crate::{
|
||||
task::TaskPool,
|
||||
uuid::Uuid,
|
||||
watcher::FileSystemWatcher,
|
||||
TypeUuidProvider,
|
||||
SafeLock, TypeUuidProvider,
|
||||
},
|
||||
dpi::{PhysicalPosition, PhysicalSize},
|
||||
engine::{
|
||||
@@ -232,7 +232,7 @@ lazy_static! {
|
||||
}
|
||||
|
||||
pub fn load_texture_internal(data: &[u8]) -> Option<TextureResource> {
|
||||
let mut cache = EDITOR_TEXTURE_CACHE.lock();
|
||||
let mut cache = EDITOR_TEXTURE_CACHE.safe_lock();
|
||||
|
||||
// Editor use data that is embedded in the binary, so each such piece of data will have fixed
|
||||
// location in memory. This fact allows us to cache the resources and skip redundant loading if
|
||||
@@ -2095,7 +2095,7 @@ impl Editor {
|
||||
}
|
||||
}
|
||||
|
||||
let mut loading_scenes = self.loading_scenes.lock();
|
||||
let mut loading_scenes = self.loading_scenes.safe_lock();
|
||||
if loading_scenes.contains(&scene_path) {
|
||||
return;
|
||||
}
|
||||
@@ -2121,7 +2121,7 @@ impl Editor {
|
||||
resource_manager,
|
||||
)
|
||||
.await;
|
||||
loading_scenes.lock().remove(&scene_path);
|
||||
loading_scenes.safe_lock().remove(&scene_path);
|
||||
match result {
|
||||
Ok(loader) => {
|
||||
let scene = loader.0.finish().await;
|
||||
@@ -2145,7 +2145,7 @@ impl Editor {
|
||||
&FsResourceIo,
|
||||
)
|
||||
.await;
|
||||
loading_scenes.lock().remove(&scene_path);
|
||||
loading_scenes.safe_lock().remove(&scene_path);
|
||||
match result {
|
||||
Ok(ui) => {
|
||||
sender.send(Message::AddUiScene {
|
||||
@@ -2487,7 +2487,7 @@ impl Editor {
|
||||
let ui = self.engine.user_interfaces.first_mut();
|
||||
|
||||
if let Some(loading_window) = self.scene_loading_window.take() {
|
||||
let set = self.loading_scenes.lock();
|
||||
let set = self.loading_scenes.safe_lock();
|
||||
self.scene_loading_window = loading_window.update(&set, ui);
|
||||
}
|
||||
|
||||
@@ -2498,7 +2498,7 @@ impl Editor {
|
||||
}
|
||||
}
|
||||
|
||||
if !self.loading_scenes.lock().is_empty() {
|
||||
if !self.loading_scenes.safe_lock().is_empty() {
|
||||
self.update_loop_state.request_update_in_next_frame();
|
||||
}
|
||||
|
||||
@@ -2843,7 +2843,7 @@ impl Editor {
|
||||
P: Plugin + 'static,
|
||||
{
|
||||
let inspector = self.plugins.get::<InspectorPlugin>();
|
||||
*inspector.property_editors.context_type_id.lock() = plugin.type_id();
|
||||
*inspector.property_editors.context_type_id.safe_lock() = plugin.type_id();
|
||||
inspector
|
||||
.property_editors
|
||||
.merge(plugin.register_property_editors());
|
||||
@@ -2883,7 +2883,7 @@ impl Editor {
|
||||
{
|
||||
let plugin = self.engine.add_dynamic_plugin_custom(plugin);
|
||||
let inspector = self.plugins.get::<InspectorPlugin>();
|
||||
*inspector.property_editors.context_type_id.lock() = plugin.type_id();
|
||||
*inspector.property_editors.context_type_id.safe_lock() = plugin.type_id();
|
||||
inspector
|
||||
.property_editors
|
||||
.merge(plugin.register_property_editors());
|
||||
@@ -2903,7 +2903,7 @@ impl Editor {
|
||||
// Keep the editor active if user holds any mouse button.
|
||||
|| self.engine.user_interfaces.first().captured_node().is_some()
|
||||
// Keep the editor active until it fully loads all the queued scenes.
|
||||
||!self.loading_scenes.lock().is_empty()
|
||||
||!self.loading_scenes.safe_lock().is_empty()
|
||||
}
|
||||
|
||||
fn on_resumed(&mut self, event_loop: &ActiveEventLoop) {
|
||||
@@ -3231,7 +3231,7 @@ fn update(editor: &mut Editor, event_loop: &ActiveEventLoop) {
|
||||
if need_reload_plugins {
|
||||
let on_plugin_reloaded = |plugin: &dyn Plugin| {
|
||||
let inspector = editor.plugins.get_mut::<InspectorPlugin>();
|
||||
*inspector.property_editors.context_type_id.lock() = plugin.type_id();
|
||||
*inspector.property_editors.context_type_id.safe_lock() = plugin.type_id();
|
||||
inspector
|
||||
.property_editors
|
||||
.merge(plugin.register_property_editors());
|
||||
|
||||
@@ -23,7 +23,7 @@ use crate::{
|
||||
fyrox::{
|
||||
core::{
|
||||
color::Color, pool::ErasedHandle, pool::Handle, reflect::prelude::*,
|
||||
type_traits::prelude::*, visitor::prelude::*,
|
||||
type_traits::prelude::*, visitor::prelude::*, SafeLock,
|
||||
},
|
||||
graph::BaseSceneGraph,
|
||||
gui::{
|
||||
@@ -523,7 +523,7 @@ impl<T: Reflect> PropertyEditorDefinition for NodeHandlePropertyEditorDefinition
|
||||
) -> Result<PropertyEditorInstance, InspectorError> {
|
||||
let value = ctx.property_info.cast_value::<Handle<T>>()?;
|
||||
|
||||
let sender = self.sender.lock().unwrap().clone();
|
||||
let sender = self.sender.safe_lock().unwrap().clone();
|
||||
|
||||
let editor = HandlePropertyEditorBuilder::new(WidgetBuilder::new(), sender.clone())
|
||||
.with_value(*value)
|
||||
|
||||
@@ -28,7 +28,7 @@ use crate::{
|
||||
asset::{core::pool::Handle, manager::ResourceManager, state::ResourceState},
|
||||
core::{
|
||||
color::Color, log::Log, parking_lot::Mutex, reflect::prelude::*,
|
||||
type_traits::prelude::*, uuid_provider, visitor::prelude::*,
|
||||
type_traits::prelude::*, uuid_provider, visitor::prelude::*, SafeLock,
|
||||
},
|
||||
graph::BaseSceneGraph,
|
||||
gui::{
|
||||
@@ -224,7 +224,7 @@ fn make_name(resource_manager: &ResourceManager, material: &MaterialResource) ->
|
||||
if let Some(path) = resource_manager
|
||||
.state()
|
||||
.resource_registry
|
||||
.lock()
|
||||
.safe_lock()
|
||||
.uuid_to_path_buf(resource_uuid)
|
||||
{
|
||||
format!(
|
||||
@@ -394,7 +394,7 @@ impl PropertyEditorDefinition for MaterialPropertyEditorDefinition {
|
||||
Ok(PropertyEditorInstance::Simple {
|
||||
editor: MaterialFieldEditorBuilder::new(WidgetBuilder::new()).build(
|
||||
ctx.build_context,
|
||||
self.sender.lock().clone(),
|
||||
self.sender.safe_lock().clone(),
|
||||
value.clone(),
|
||||
environment.icon_request_sender.clone(),
|
||||
environment.resource_manager.clone(),
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
use commands::{MoveMapTileCommand, SetMapTilesCommand};
|
||||
use fyrox::{
|
||||
asset::untyped::UntypedResource,
|
||||
core::SafeLock,
|
||||
fxhash::FxHashMap,
|
||||
scene::tilemap::{
|
||||
brush::TileMapBrushResource,
|
||||
@@ -193,13 +194,13 @@ impl TileMapInteractionMode {
|
||||
pub fn sync_to_state(&mut self) {
|
||||
let state = self.state.lock();
|
||||
if state.selection_node() != self.tile_map {
|
||||
self.select_effect.lock().positions.clear();
|
||||
self.select_effect.safe_lock().positions.clear();
|
||||
self.selecting.clear();
|
||||
}
|
||||
match state.drawing_mode {
|
||||
DrawingMode::Draw => {
|
||||
let mut overlay = self.overlay_effect.lock();
|
||||
let mut erase_overlay = self.erase_select_effect.lock();
|
||||
let mut overlay = self.overlay_effect.safe_lock();
|
||||
let mut erase_overlay = self.erase_select_effect.safe_lock();
|
||||
overlay.tiles.clear();
|
||||
erase_overlay.positions.clear();
|
||||
let stamp = &state.stamp;
|
||||
@@ -215,8 +216,8 @@ impl TileMapInteractionMode {
|
||||
}
|
||||
}
|
||||
DrawingMode::Erase => {
|
||||
let mut overlay = self.overlay_effect.lock();
|
||||
let mut erase_overlay = self.erase_select_effect.lock();
|
||||
let mut overlay = self.overlay_effect.safe_lock();
|
||||
let mut erase_overlay = self.erase_select_effect.safe_lock();
|
||||
overlay.tiles.clear();
|
||||
erase_overlay.positions.clear();
|
||||
if state.stamp.is_empty() {
|
||||
@@ -227,18 +228,18 @@ impl TileMapInteractionMode {
|
||||
}
|
||||
DrawingMode::Pick => {
|
||||
if self.mouse_mode == MouseMode::None {
|
||||
self.overlay_effect.lock().tiles.clear();
|
||||
self.erase_select_effect.lock().positions.clear();
|
||||
self.overlay_effect.safe_lock().tiles.clear();
|
||||
self.erase_select_effect.safe_lock().positions.clear();
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
self.overlay_effect.lock().tiles.clear();
|
||||
self.erase_select_effect.lock().positions.clear();
|
||||
self.overlay_effect.safe_lock().tiles.clear();
|
||||
self.erase_select_effect.safe_lock().positions.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
fn delete(&mut self) {
|
||||
let sel = &self.select_effect.lock().positions;
|
||||
let sel = &self.select_effect.safe_lock().positions;
|
||||
if sel.is_empty() {
|
||||
return;
|
||||
}
|
||||
@@ -497,8 +498,8 @@ impl InteractionMode for TileMapInteractionMode {
|
||||
let Some(tiles) = tiles_guard.as_loaded_ref() else {
|
||||
return;
|
||||
};
|
||||
let mut overlay = self.overlay_effect.lock();
|
||||
let mut erase_overlay = self.erase_select_effect.lock();
|
||||
let mut overlay = self.overlay_effect.safe_lock();
|
||||
let mut erase_overlay = self.erase_select_effect.safe_lock();
|
||||
if let Some(grid_coord) = grid_coord {
|
||||
overlay.active = true;
|
||||
overlay.offset = grid_coord;
|
||||
@@ -514,10 +515,10 @@ impl InteractionMode for TileMapInteractionMode {
|
||||
DrawingMode::Pick => {
|
||||
if mods.alt {
|
||||
self.mouse_mode = MouseMode::Dragging;
|
||||
let erased_area = &mut self.erase_effect.lock().positions;
|
||||
let erased_area = &mut self.erase_effect.safe_lock().positions;
|
||||
overlay.tiles.clear();
|
||||
erased_area.clear();
|
||||
let selected = &self.select_effect.lock().positions;
|
||||
let selected = &self.select_effect.safe_lock().positions;
|
||||
for pos in selected.iter() {
|
||||
let Some(handle) = tiles.get(*pos) else {
|
||||
continue;
|
||||
@@ -535,7 +536,7 @@ impl InteractionMode for TileMapInteractionMode {
|
||||
state.set_node(self.tile_map);
|
||||
update_select(
|
||||
tile_map,
|
||||
&mut self.select_effect.lock().positions,
|
||||
&mut self.select_effect.safe_lock().positions,
|
||||
&self.selecting,
|
||||
&mut state,
|
||||
grid_coord,
|
||||
@@ -545,7 +546,7 @@ impl InteractionMode for TileMapInteractionMode {
|
||||
}
|
||||
mode => {
|
||||
self.mouse_mode = MouseMode::Drawing;
|
||||
let update = &mut self.update_effect.lock().update;
|
||||
let update = &mut self.update_effect.safe_lock().update;
|
||||
draw(update, tiles, mode, &state, grid_coord, grid_coord);
|
||||
drop(tiles_guard);
|
||||
if state.stamp.brush().is_some() {
|
||||
@@ -594,7 +595,7 @@ impl InteractionMode for TileMapInteractionMode {
|
||||
match self.mouse_mode {
|
||||
MouseMode::None => (),
|
||||
MouseMode::Dragging => {
|
||||
let overlay = &mut self.overlay_effect.lock().tiles;
|
||||
let overlay = &mut self.overlay_effect.safe_lock().tiles;
|
||||
if let (Some(start), Some(end)) = (start, end) {
|
||||
let offset = end - start;
|
||||
if offset != Vector2::new(0, 0) {
|
||||
@@ -603,7 +604,7 @@ impl InteractionMode for TileMapInteractionMode {
|
||||
.copied()
|
||||
.map(|p| p + start)
|
||||
.collect::<Vec<_>>();
|
||||
let selected = &mut self.select_effect.lock().positions;
|
||||
let selected = &mut self.select_effect.safe_lock().positions;
|
||||
selected.clear();
|
||||
selected.extend(tiles.iter().map(|p| p + offset));
|
||||
self.sender.do_command(MoveMapTileCommand::new(
|
||||
@@ -614,17 +615,17 @@ impl InteractionMode for TileMapInteractionMode {
|
||||
}
|
||||
}
|
||||
overlay.clear();
|
||||
self.erase_effect.lock().positions.clear();
|
||||
self.erase_effect.safe_lock().positions.clear();
|
||||
}
|
||||
MouseMode::Drawing => {
|
||||
let state = self.state.lock();
|
||||
if let DrawingMode::Pick = self.current_tool {
|
||||
self.selecting
|
||||
.clone_from(&self.select_effect.lock().positions);
|
||||
.clone_from(&self.select_effect.safe_lock().positions);
|
||||
} else if let Some(tile_set) =
|
||||
state.tile_set.as_ref().or(tile_map.tile_set()).cloned()
|
||||
{
|
||||
let update_source = &mut self.update_effect.lock().update;
|
||||
let update_source = &mut self.update_effect.safe_lock().update;
|
||||
let tile_map_context = TileMapContext {
|
||||
node: tile_map_handle,
|
||||
scene: scene_handle,
|
||||
@@ -681,8 +682,8 @@ impl InteractionMode for TileMapInteractionMode {
|
||||
|
||||
let grid_coord = self.pick_grid(scene, game_scene, mouse_position, frame_size);
|
||||
|
||||
let mut overlay = self.overlay_effect.lock();
|
||||
let mut erase_overlay = self.erase_select_effect.lock();
|
||||
let mut overlay = self.overlay_effect.safe_lock();
|
||||
let mut erase_overlay = self.erase_select_effect.safe_lock();
|
||||
if let Some(grid_coord) = grid_coord {
|
||||
overlay.active = true;
|
||||
overlay.offset = grid_coord;
|
||||
@@ -691,7 +692,7 @@ impl InteractionMode for TileMapInteractionMode {
|
||||
overlay.active = false;
|
||||
erase_overlay.offset = None;
|
||||
}
|
||||
self.cursor_effect.lock().position = grid_coord;
|
||||
self.cursor_effect.safe_lock().position = grid_coord;
|
||||
|
||||
let Some(grid_coord) = grid_coord else {
|
||||
return;
|
||||
@@ -731,14 +732,14 @@ impl InteractionMode for TileMapInteractionMode {
|
||||
drop(tiles_guard);
|
||||
update_select(
|
||||
tile_map,
|
||||
&mut self.select_effect.lock().positions,
|
||||
&mut self.select_effect.safe_lock().positions,
|
||||
&self.selecting,
|
||||
&mut state.into_mut("TileMap select"),
|
||||
start,
|
||||
end,
|
||||
);
|
||||
} else {
|
||||
let update = &mut self.update_effect.lock().update;
|
||||
let update = &mut self.update_effect.safe_lock().update;
|
||||
draw(update, tiles, self.current_tool, &state, start, end);
|
||||
drop(tiles_guard);
|
||||
if let Some(brush) = state.stamp.brush() {
|
||||
@@ -765,9 +766,9 @@ impl InteractionMode for TileMapInteractionMode {
|
||||
_frame_size: Vector2<f32>,
|
||||
_settings: &Settings,
|
||||
) {
|
||||
self.overlay_effect.lock().active = false;
|
||||
self.erase_select_effect.lock().offset = None;
|
||||
self.cursor_effect.lock().position = None;
|
||||
self.overlay_effect.safe_lock().active = false;
|
||||
self.erase_select_effect.safe_lock().offset = None;
|
||||
self.cursor_effect.safe_lock().position = None;
|
||||
}
|
||||
|
||||
fn update(
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
//! is responsible for displaying a grid of tiles where the user may select tiles,
|
||||
//! drag tiles, and use drawing tools upon the tiles.
|
||||
|
||||
use fyrox::core::SafeLock;
|
||||
use fyrox::scene::tilemap::brush::TileMapBrushResource;
|
||||
use fyrox::scene::tilemap::tileset::OptionTileSet;
|
||||
use fyrox::scene::tilemap::{ResourceTilePosition, RotTileHandle};
|
||||
@@ -731,7 +732,7 @@ impl PaletteWidget {
|
||||
self.editable
|
||||
&& self.kind == TilePaletteStage::Tiles
|
||||
&& state.drawing_mode == DrawingMode::Editor
|
||||
&& editor.lock().slice_mode()
|
||||
&& editor.safe_lock().slice_mode()
|
||||
} else {
|
||||
false
|
||||
};
|
||||
@@ -763,7 +764,7 @@ impl PaletteWidget {
|
||||
DrawingMode::Editor => {
|
||||
if let Some(editor) = &state.active_editor {
|
||||
if let &Some(page) = &self.page {
|
||||
editor.lock().highlight(
|
||||
editor.safe_lock().highlight(
|
||||
&mut self.highlight,
|
||||
page,
|
||||
&self.content,
|
||||
@@ -1363,7 +1364,7 @@ impl PaletteWidget {
|
||||
DrawingMode::Editor => {
|
||||
if let Some(editor) = &state.active_editor {
|
||||
if let Some(handle) = TileDefinitionHandle::try_new(page, end) {
|
||||
let editor = editor.lock();
|
||||
let editor = editor.safe_lock();
|
||||
editor.draw_tile(
|
||||
handle,
|
||||
sub_pos,
|
||||
|
||||
@@ -33,7 +33,7 @@ use fyrox::{
|
||||
asset::ResourceDataRef,
|
||||
core::{
|
||||
algebra::Vector2, pool::Handle, reflect::prelude::*, type_traits::prelude::*,
|
||||
visitor::prelude::*,
|
||||
visitor::prelude::*, SafeLock,
|
||||
},
|
||||
gui::{
|
||||
button::{Button, ButtonMessage},
|
||||
@@ -597,7 +597,7 @@ impl PropertyEditors {
|
||||
let mut editors = Vec::default();
|
||||
make_property_editors(state, &mut editors, ctx);
|
||||
let content = StackPanelBuilder::new(
|
||||
WidgetBuilder::new().with_children(editors.iter().map(|v| v.1.lock().handle())),
|
||||
WidgetBuilder::new().with_children(editors.iter().map(|v| v.1.safe_lock().handle())),
|
||||
)
|
||||
.build(ctx);
|
||||
Self {
|
||||
@@ -618,14 +618,14 @@ impl PropertyEditors {
|
||||
// The list has changed somehow, so remove the old editors and construct an all new editor for each layer.
|
||||
for (_, editor) in self.editors.iter() {
|
||||
ui.send_message(WidgetMessage::remove(
|
||||
editor.lock().handle(),
|
||||
editor.safe_lock().handle(),
|
||||
MessageDirection::ToWidget,
|
||||
));
|
||||
}
|
||||
make_property_editors(state, &mut self.editors, &mut ui.build_ctx());
|
||||
for (_, editor) in self.editors.iter() {
|
||||
ui.send_message(WidgetMessage::link(
|
||||
editor.lock().handle(),
|
||||
editor.safe_lock().handle(),
|
||||
MessageDirection::ToWidget,
|
||||
self.content,
|
||||
));
|
||||
@@ -633,7 +633,7 @@ impl PropertyEditors {
|
||||
} else {
|
||||
// The list has not changed, so just sync each editor because one of the layers may have changed.
|
||||
for (_, editor) in self.editors.iter() {
|
||||
editor.lock().sync_to_model(state, ui);
|
||||
editor.safe_lock().sync_to_model(state, ui);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -672,7 +672,7 @@ impl ColliderEditors {
|
||||
let mut editors = Vec::default();
|
||||
make_collider_editors(state, &mut editors, ctx);
|
||||
let content = StackPanelBuilder::new(
|
||||
WidgetBuilder::new().with_children(editors.iter().map(|v| v.1.lock().handle())),
|
||||
WidgetBuilder::new().with_children(editors.iter().map(|v| v.1.safe_lock().handle())),
|
||||
)
|
||||
.build(ctx);
|
||||
Self {
|
||||
@@ -693,14 +693,14 @@ impl ColliderEditors {
|
||||
// The list has changed somehow, so remove the old editors and construct an all new editor for each layer.
|
||||
for (_, editor) in self.editors.iter() {
|
||||
ui.send_message(WidgetMessage::remove(
|
||||
editor.lock().handle(),
|
||||
editor.safe_lock().handle(),
|
||||
MessageDirection::ToWidget,
|
||||
));
|
||||
}
|
||||
make_collider_editors(state, &mut self.editors, &mut ui.build_ctx());
|
||||
for (_, editor) in self.editors.iter() {
|
||||
ui.send_message(WidgetMessage::link(
|
||||
editor.lock().handle(),
|
||||
editor.safe_lock().handle(),
|
||||
MessageDirection::ToWidget,
|
||||
self.content,
|
||||
));
|
||||
@@ -708,7 +708,7 @@ impl ColliderEditors {
|
||||
} else {
|
||||
// The list has not changed, so just sync each editor because one of the layers may have changed.
|
||||
for (_, editor) in self.editors.iter() {
|
||||
editor.lock().sync_to_model(state, ui);
|
||||
editor.safe_lock().sync_to_model(state, ui);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -907,7 +907,7 @@ impl TileInspector {
|
||||
.with_child(tile_size_inspector.handle)
|
||||
.with_child(animation_speed_inspector.handle)
|
||||
.with_child(create_tile)
|
||||
.with_children(tile_editors.iter().map(|e| e.lock().handle()))
|
||||
.with_children(tile_editors.iter().map(|e| e.safe_lock().handle()))
|
||||
.with_child(property_editors.handle)
|
||||
.with_child(collider_editors.handle)
|
||||
.with_child(macro_inspector.handle()),
|
||||
@@ -1109,7 +1109,7 @@ impl TileInspector {
|
||||
.chain(self.property_editors.iter())
|
||||
.chain(self.collider_editors.iter());
|
||||
for editor in iter {
|
||||
editor.lock().handle_ui_message(
|
||||
editor.safe_lock().handle_ui_message(
|
||||
&mut tile_editor_state,
|
||||
message,
|
||||
ui,
|
||||
@@ -1153,7 +1153,7 @@ impl TileInspector {
|
||||
.chain(self.property_editors.iter())
|
||||
.chain(self.collider_editors.iter());
|
||||
for editor_ref in iter {
|
||||
let draw_button = editor_ref.lock().draw_button();
|
||||
let draw_button = editor_ref.safe_lock().draw_button();
|
||||
if message.destination() == draw_button {
|
||||
if tile_editor_state.is_active_editor(editor_ref) {
|
||||
tile_editor_state.set_active_editor(None);
|
||||
|
||||
@@ -22,7 +22,7 @@ use std::hash::Hash;
|
||||
|
||||
use fyrox::{
|
||||
asset::{untyped::UntypedResource, Resource, ResourceData},
|
||||
core::swap_hash_map_entry,
|
||||
core::{swap_hash_map_entry, SafeLock},
|
||||
fxhash::FxHashMap,
|
||||
gui::{
|
||||
button::ButtonMessage,
|
||||
@@ -1154,7 +1154,7 @@ impl CommandTrait for WaveFunctionTaskCommand {
|
||||
}
|
||||
|
||||
fn execute(&mut self, _context: &mut dyn CommandContext) {
|
||||
let mut data_guard = self.task_data.lock();
|
||||
let mut data_guard = self.task_data.safe_lock();
|
||||
if data_guard.state == WfcTaskState::Finished {
|
||||
write_propagator_to_tile_data(
|
||||
&data_guard.constraint,
|
||||
@@ -1180,7 +1180,7 @@ impl CommandTrait for WaveFunctionTaskCommand {
|
||||
}
|
||||
|
||||
fn revert(&mut self, _context: &mut dyn CommandContext) {
|
||||
let mut data_guard = self.task_data.lock();
|
||||
let mut data_guard = self.task_data.safe_lock();
|
||||
if data_guard.state != WfcTaskState::Finished {
|
||||
data_guard.state = WfcTaskState::Cancelled;
|
||||
}
|
||||
@@ -1201,10 +1201,10 @@ fn run_wfc(
|
||||
max_attempts: u32,
|
||||
data: TileMapDataResource,
|
||||
) {
|
||||
let attempts = task_data.lock().attempts;
|
||||
let attempts = task_data.safe_lock().attempts;
|
||||
let mut rng = thread_rng();
|
||||
for i in attempts..max_attempts {
|
||||
let mut guard = task_data.lock();
|
||||
let mut guard = task_data.safe_lock();
|
||||
let task_data = guard.deref_mut();
|
||||
if task_data.state == WfcTaskState::Cancelled {
|
||||
task_data.attempts = i;
|
||||
@@ -1228,5 +1228,5 @@ fn run_wfc(
|
||||
write_propagator_to_tile_data(&task_data.constraint, &task_data.working_propagator, &data);
|
||||
}
|
||||
Log::err(format!("WFC failed after {max_attempts} attempts"));
|
||||
task_data.lock().state = WfcTaskState::Finished;
|
||||
task_data.safe_lock().state = WfcTaskState::Finished;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ use fyrox_resource::untyped::ResourceKind;
|
||||
use fyrox_ui::{
|
||||
border::BorderBuilder,
|
||||
button::{ButtonBuilder, ButtonMessage},
|
||||
core::{parking_lot::Mutex, pool::Handle},
|
||||
core::{parking_lot::Mutex, pool::Handle, SafeLock},
|
||||
grid::{Column, GridBuilder, Row},
|
||||
image::ImageBuilder,
|
||||
message::{MessageDirection, UiMessage},
|
||||
@@ -229,7 +229,7 @@ impl BuildWindow {
|
||||
let pipe: &mut dyn BufRead = &mut BufReader::new(&mut pipe);
|
||||
while reader_active.load(Ordering::SeqCst) {
|
||||
for line in pipe.lines().take(10).flatten() {
|
||||
let mut log_guard = log.lock();
|
||||
let mut log_guard = log.safe_lock();
|
||||
log_guard.push_str(&line);
|
||||
log_guard.push('\n');
|
||||
log_changed.store(true, Ordering::SeqCst);
|
||||
@@ -241,7 +241,7 @@ impl BuildWindow {
|
||||
pub fn reset(&mut self, ui: &UserInterface) {
|
||||
self.active.store(false, Ordering::SeqCst);
|
||||
self.changed.store(false, Ordering::SeqCst);
|
||||
self.log.lock().clear();
|
||||
self.log.safe_lock().clear();
|
||||
ui.send_message(TextMessage::text(
|
||||
self.log_text,
|
||||
MessageDirection::ToWidget,
|
||||
@@ -262,7 +262,7 @@ impl BuildWindow {
|
||||
ui.send_message(TextMessage::text(
|
||||
self.log_text,
|
||||
MessageDirection::ToWidget,
|
||||
self.log.lock().clone(),
|
||||
self.log.safe_lock().clone(),
|
||||
));
|
||||
ui.send_message(ScrollViewerMessage::scroll_to_end(
|
||||
self.scroll_viewer,
|
||||
|
||||
@@ -44,6 +44,7 @@ pub use uuid;
|
||||
use crate::visitor::{Visit, VisitResult, Visitor};
|
||||
use bytemuck::Pod;
|
||||
use fxhash::FxHashMap;
|
||||
pub use safelock::*;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::ffi::OsString;
|
||||
use std::hash::Hasher;
|
||||
@@ -66,6 +67,7 @@ pub mod pool;
|
||||
pub mod quadtree;
|
||||
pub mod rectpack;
|
||||
pub mod reflect;
|
||||
mod safelock;
|
||||
pub mod sparse;
|
||||
pub mod sstorage;
|
||||
pub mod task;
|
||||
|
||||
@@ -25,6 +25,7 @@ use crate::{
|
||||
reflect::{blank_reflect, prelude::*},
|
||||
sstorage::ImmutableString,
|
||||
uuid::Uuid,
|
||||
SafeLock,
|
||||
};
|
||||
use fyrox_core_derive::impl_reflect;
|
||||
use std::{
|
||||
@@ -444,7 +445,7 @@ macro_rules! impl_reflect_inner_mutability {
|
||||
}
|
||||
|
||||
impl<T: Reflect + Clone> Reflect for parking_lot::Mutex<T> {
|
||||
impl_reflect_inner_mutability!(self, { self.lock() }, { self.into_inner() });
|
||||
impl_reflect_inner_mutability!(self, { self.safe_lock() }, { self.into_inner() });
|
||||
}
|
||||
|
||||
impl<T: Reflect + Clone> Reflect for parking_lot::RwLock<T> {
|
||||
@@ -453,7 +454,7 @@ impl<T: Reflect + Clone> Reflect for parking_lot::RwLock<T> {
|
||||
|
||||
#[allow(clippy::mut_mutex_lock)]
|
||||
impl<T: Reflect + Clone> Reflect for std::sync::Mutex<T> {
|
||||
impl_reflect_inner_mutability!(self, { self.lock().unwrap() }, { self.into_inner() });
|
||||
impl_reflect_inner_mutability!(self, { self.safe_lock().unwrap() }, { self.into_inner() });
|
||||
}
|
||||
|
||||
impl<T: Reflect + Clone> Reflect for std::sync::RwLock<T> {
|
||||
@@ -461,7 +462,7 @@ impl<T: Reflect + Clone> Reflect for std::sync::RwLock<T> {
|
||||
}
|
||||
|
||||
impl<T: Reflect + Clone> Reflect for Arc<parking_lot::Mutex<T>> {
|
||||
impl_reflect_inner_mutability!(self, { self.lock() }, {
|
||||
impl_reflect_inner_mutability!(self, { self.safe_lock() }, {
|
||||
Arc::into_inner(*self)
|
||||
.expect("Value cannot be shared!")
|
||||
.into_inner()
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
//! This is an extension for Mutex-like objects that creates a `safe_lock` method
|
||||
//! to replace `lock` and put a time limit on locking, preventing a game from
|
||||
//! permanently freezing due to a deadlock.
|
||||
|
||||
use parking_lot::{Mutex, MutexGuard};
|
||||
#[allow(unused_imports)]
|
||||
use std::sync::TryLockError;
|
||||
use std::time::Duration;
|
||||
|
||||
#[allow(dead_code)]
|
||||
const PANIC_MESSAGE: &str = "lock timeout";
|
||||
|
||||
/// Trait for lockable objects that can panic if they take too long
|
||||
/// to lock. Panicking is preferable over freezing.
|
||||
pub trait SafeLock {
|
||||
const TIMEOUT: Duration = Duration::from_secs(10);
|
||||
type Output<'a>
|
||||
where
|
||||
Self: 'a;
|
||||
/// Attempt to lock the object, with a limit on how long locking may block for,
|
||||
/// panicking if the time limit is exceeded. It panics instead of freezing.
|
||||
fn safe_lock(&self) -> Self::Output<'_>;
|
||||
}
|
||||
|
||||
impl<T: ?Sized> SafeLock for Mutex<T> {
|
||||
type Output<'a>
|
||||
= MutexGuard<'a, T>
|
||||
where
|
||||
T: 'a;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
fn safe_lock(&self) -> Self::Output<'_> {
|
||||
self.lock()
|
||||
}
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn safe_lock(&self) -> Self::Output<'_> {
|
||||
self.try_lock_for(Self::TIMEOUT).expect(PANIC_MESSAGE)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> SafeLock for std::sync::Mutex<T> {
|
||||
type Output<'a>
|
||||
= std::sync::LockResult<std::sync::MutexGuard<'a, T>>
|
||||
where
|
||||
T: 'a;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
fn safe_lock(&self) -> Self::Output<'_> {
|
||||
self.lock()
|
||||
}
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn safe_lock(&self) -> Self::Output<'_> {
|
||||
let start = std::time::Instant::now();
|
||||
loop {
|
||||
match self.try_lock() {
|
||||
Ok(guard) => return Ok(guard),
|
||||
Err(TryLockError::WouldBlock) => (),
|
||||
Err(TryLockError::Poisoned(err)) => return Err(err),
|
||||
}
|
||||
std::thread::yield_now();
|
||||
if start.elapsed() > Self::TIMEOUT {
|
||||
std::panic::panic_any(PANIC_MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use std::{
|
||||
any::Any,
|
||||
panic::{catch_unwind, AssertUnwindSafe},
|
||||
};
|
||||
fn panic_to_string(message: Box<dyn Any>) -> Option<String> {
|
||||
match message.downcast_ref::<&str>() {
|
||||
Some(&str) => Some(str.into()),
|
||||
None => message.downcast::<String>().ok().map(|s| *s),
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn successful_lock_parking_lot() {
|
||||
let mutex = Mutex::new(());
|
||||
drop(mutex.safe_lock());
|
||||
}
|
||||
#[test]
|
||||
fn successful_lock_std() {
|
||||
let mutex = std::sync::Mutex::new(());
|
||||
drop(mutex.safe_lock());
|
||||
}
|
||||
#[test]
|
||||
fn failed_lock_parking_lot() {
|
||||
let mutex = Mutex::new(());
|
||||
let _guard = mutex.safe_lock();
|
||||
let panic_message = catch_unwind(AssertUnwindSafe(|| mutex.safe_lock()))
|
||||
.expect_err("safe_lock did not panic");
|
||||
let Some(message) = panic_to_string(panic_message) else {
|
||||
panic!("safe_lock panicked with wrong type");
|
||||
};
|
||||
assert_eq!(message, PANIC_MESSAGE);
|
||||
}
|
||||
#[test]
|
||||
fn failed_lock_std() {
|
||||
let mutex = std::sync::Mutex::new(());
|
||||
let _guard = mutex.safe_lock();
|
||||
let panic_message =
|
||||
catch_unwind(|| mutex.safe_lock()).expect_err("safe_lock did not panic");
|
||||
let Some(message) = panic_to_string(panic_message) else {
|
||||
panic!("safe_lock panicked with wrong type");
|
||||
};
|
||||
assert_eq!(message, PANIC_MESSAGE);
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ use crate::{
|
||||
parking_lot::Mutex,
|
||||
uuid_provider,
|
||||
visitor::{Visit, VisitResult, Visitor},
|
||||
SafeLock,
|
||||
};
|
||||
use fxhash::{FxHashMap, FxHasher};
|
||||
pub use fyrox_core_derive::TypeUuidProvider;
|
||||
@@ -86,7 +87,7 @@ impl Visit for ImmutableString {
|
||||
|
||||
// Deduplicate on deserialization.
|
||||
if visitor.is_reading() {
|
||||
*self = SSTORAGE.lock().insert(string);
|
||||
*self = SSTORAGE.safe_lock().insert(string);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -159,7 +160,7 @@ impl ImmutableString {
|
||||
/// memory allocator.
|
||||
#[inline]
|
||||
pub fn new<S: AsRef<str>>(string: S) -> ImmutableString {
|
||||
SSTORAGE.lock().insert(string)
|
||||
SSTORAGE.safe_lock().insert(string)
|
||||
}
|
||||
|
||||
/// Returns unique identifier of the string. Keep in mind that uniqueness is guaranteed only
|
||||
@@ -189,13 +190,13 @@ impl From<&str> for ImmutableString {
|
||||
|
||||
impl From<String> for ImmutableString {
|
||||
fn from(value: String) -> Self {
|
||||
SSTORAGE.lock().insert_owned(value)
|
||||
SSTORAGE.safe_lock().insert_owned(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&String> for ImmutableString {
|
||||
fn from(value: &String) -> Self {
|
||||
SSTORAGE.lock().insert(value)
|
||||
SSTORAGE.safe_lock().insert(value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,7 +270,7 @@ impl ImmutableStringStorage {
|
||||
impl ImmutableStringStorage {
|
||||
/// Returns total amount of immutable strings in the storage.
|
||||
pub fn entry_count() -> usize {
|
||||
SSTORAGE.lock().vec.len()
|
||||
SSTORAGE.safe_lock().vec.len()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use crate::futures::executor::ThreadPool;
|
||||
use crate::SafeLock;
|
||||
use parking_lot::Mutex;
|
||||
use std::{
|
||||
any::Any,
|
||||
@@ -152,6 +153,6 @@ impl TaskPool {
|
||||
|
||||
#[inline]
|
||||
pub fn next_task_result(&self) -> Option<TaskResult> {
|
||||
self.receiver.lock().try_recv().ok()
|
||||
self.receiver.safe_lock().try_recv().ok()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ use fyrox_core::pool::Handle;
|
||||
use fyrox_core::{
|
||||
parking_lot::{Mutex, MutexGuard},
|
||||
reflect::prelude::*,
|
||||
TypeUuidProvider, Uuid,
|
||||
SafeLock, TypeUuidProvider, Uuid,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -138,30 +138,33 @@ impl<Node, Ctx> GraphNodeConstructorContainer<Node, Ctx> {
|
||||
{
|
||||
let previous = self
|
||||
.map
|
||||
.lock()
|
||||
.safe_lock()
|
||||
.insert(Inner::type_uuid(), Inner::constructor());
|
||||
assert!(previous.is_none());
|
||||
}
|
||||
|
||||
/// Adds custom type constructor.
|
||||
pub fn add_custom(&self, type_uuid: Uuid, constructor: GraphNodeConstructor<Node, Ctx>) {
|
||||
self.map.lock().insert(type_uuid, constructor);
|
||||
self.map.safe_lock().insert(type_uuid, constructor);
|
||||
}
|
||||
|
||||
/// Unregisters type constructor.
|
||||
pub fn remove(&self, type_uuid: Uuid) {
|
||||
self.map.lock().remove(&type_uuid);
|
||||
self.map.safe_lock().remove(&type_uuid);
|
||||
}
|
||||
|
||||
/// Makes an attempt to create a node using provided type UUID. It may fail if there is no
|
||||
/// node constructor for specified type UUID.
|
||||
pub fn try_create(&self, type_uuid: &Uuid) -> Option<Node> {
|
||||
self.map.lock().get_mut(type_uuid).map(|c| (c.default)())
|
||||
self.map
|
||||
.safe_lock()
|
||||
.get_mut(type_uuid)
|
||||
.map(|c| (c.default)())
|
||||
}
|
||||
|
||||
/// Returns total amount of constructors.
|
||||
pub fn len(&self) -> usize {
|
||||
self.map.lock().len()
|
||||
self.map.safe_lock().len()
|
||||
}
|
||||
|
||||
/// Returns true if the container is empty.
|
||||
@@ -171,6 +174,6 @@ impl<Node, Ctx> GraphNodeConstructorContainer<Node, Ctx> {
|
||||
|
||||
/// Returns the inner map of the node constructors.
|
||||
pub fn map(&self) -> MutexGuard<'_, FxHashMap<Uuid, GraphNodeConstructor<Node, Ctx>>> {
|
||||
self.map.lock()
|
||||
self.map.safe_lock()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ use crate::{
|
||||
utils::navmesh::Navmesh,
|
||||
};
|
||||
use fxhash::FxHashSet;
|
||||
use fyrox_core::SafeLock;
|
||||
use std::{
|
||||
fmt::{Display, Formatter},
|
||||
ops::{Index, IndexMut},
|
||||
@@ -348,7 +349,7 @@ impl SceneLoader {
|
||||
let registry_status = resource_manager
|
||||
.state()
|
||||
.resource_registry
|
||||
.lock()
|
||||
.safe_lock()
|
||||
.status_flag();
|
||||
// Wait until the registry is fully loaded.
|
||||
let registry_status = registry_status.await;
|
||||
@@ -414,9 +415,6 @@ impl SceneLoader {
|
||||
let exclusion_list = used_resources
|
||||
.iter()
|
||||
.filter(|res| {
|
||||
// Calling resource_uuid means locking the header.
|
||||
// To minimize the number of locks we hold at once, get the UUID first,
|
||||
// before we lock the resource manager and registry.
|
||||
let uuid = res.resource_uuid();
|
||||
let state = self.resource_manager.state();
|
||||
let registry = state.resource_registry.lock();
|
||||
|
||||
@@ -641,7 +641,7 @@ mod test {
|
||||
uuid::{uuid, Uuid},
|
||||
variable::InheritableVariable,
|
||||
visitor::{prelude::*, Visitor},
|
||||
TypeUuidProvider,
|
||||
SafeLock, TypeUuidProvider,
|
||||
},
|
||||
engine::{self, SerializationContext},
|
||||
resource::model::{Model, ModelResourceExtension},
|
||||
@@ -746,7 +746,7 @@ mod test {
|
||||
resource_manager
|
||||
.state()
|
||||
.resource_registry
|
||||
.lock()
|
||||
.safe_lock()
|
||||
.set_path("test_output/resources.registry");
|
||||
|
||||
let serialization_context = SerializationContext::new();
|
||||
@@ -794,7 +794,7 @@ mod test {
|
||||
mesh.set_cast_shadows(false);
|
||||
save_scene(&mut derived, derived_asset_path);
|
||||
let registry = resource_manager.state().resource_registry.clone();
|
||||
let mut registry = registry.lock();
|
||||
let mut registry = registry.safe_lock();
|
||||
let mut ctx = registry.modify();
|
||||
ctx.write_metadata(Uuid::new_v4(), derived_asset_path)
|
||||
.unwrap();
|
||||
|
||||
@@ -34,6 +34,7 @@ use crate::{
|
||||
uuid::{uuid, Uuid},
|
||||
variable::InheritableVariable,
|
||||
visitor::prelude::*,
|
||||
SafeLock,
|
||||
},
|
||||
graphics::ElementRange,
|
||||
material::MaterialResourceExtension,
|
||||
@@ -524,7 +525,7 @@ impl Chunk {
|
||||
return;
|
||||
};
|
||||
let count = heightmap.data_ref().modifications_count();
|
||||
let mut quad_tree = self.quad_tree.lock();
|
||||
let mut quad_tree = self.quad_tree.safe_lock();
|
||||
if count != quad_tree.height_mod_count() {
|
||||
*quad_tree = make_quad_tree(&self.heightmap, self.height_map_size, self.block_size);
|
||||
}
|
||||
@@ -818,9 +819,12 @@ impl Chunk {
|
||||
pub fn debug_draw(&self, transform: &Matrix4<f32>, ctx: &mut SceneDrawingContext) {
|
||||
let transform = *transform * Matrix4::new_translation(&self.position());
|
||||
|
||||
self.quad_tree
|
||||
.lock()
|
||||
.debug_draw(&transform, self.height_map_size, self.physical_size, ctx)
|
||||
self.quad_tree.safe_lock().debug_draw(
|
||||
&transform,
|
||||
self.height_map_size,
|
||||
self.physical_size,
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
|
||||
fn set_block_size(&mut self, block_size: Vector2<u32>) {
|
||||
@@ -833,7 +837,7 @@ impl Chunk {
|
||||
if self.heightmap.is_none() {
|
||||
return;
|
||||
}
|
||||
*self.quad_tree.lock() =
|
||||
*self.quad_tree.safe_lock() =
|
||||
make_quad_tree(&self.heightmap, self.height_map_size, self.block_size);
|
||||
}
|
||||
}
|
||||
@@ -2099,7 +2103,7 @@ impl Terrain {
|
||||
drop(texture_modifier);
|
||||
drop(texture_data);
|
||||
|
||||
*chunk.quad_tree.lock() =
|
||||
*chunk.quad_tree.safe_lock() =
|
||||
make_quad_tree(&chunk.heightmap, chunk.height_map_size, chunk.block_size);
|
||||
}
|
||||
|
||||
@@ -2616,7 +2620,7 @@ impl NodeTrait for Terrain {
|
||||
// The first element of the list is the furthest distance, where the lowest LOD is used.
|
||||
// The formula used to produce this list has been chosen arbitrarily based on what seems to produce
|
||||
// the best results in the render.
|
||||
let quad_tree = chunk.quad_tree.lock();
|
||||
let quad_tree = chunk.quad_tree.safe_lock();
|
||||
let levels = (0..=quad_tree.max_level)
|
||||
.map(|n| {
|
||||
ctx.observer_position.z_far
|
||||
|
||||
@@ -63,7 +63,7 @@ use crate::{
|
||||
type_traits::prelude::*,
|
||||
variable::InheritableVariable,
|
||||
visitor::prelude::*,
|
||||
ImmutableString,
|
||||
ImmutableString, SafeLock,
|
||||
},
|
||||
graph::{constructor::ConstructorProvider, BaseSceneGraph},
|
||||
material::{Material, MaterialResource, STANDARD_2D},
|
||||
@@ -1421,7 +1421,7 @@ impl NodeTrait for TileMap {
|
||||
let mut tile_set_lock = TileSetRef::new(tile_set_resource);
|
||||
let tile_set = tile_set_lock.as_loaded();
|
||||
|
||||
let mut hidden_tiles = self.hidden_tiles.lock();
|
||||
let mut hidden_tiles = self.hidden_tiles.safe_lock();
|
||||
hidden_tiles.clear();
|
||||
|
||||
let bounds = ctx
|
||||
@@ -1440,7 +1440,9 @@ impl NodeTrait for TileMap {
|
||||
};
|
||||
|
||||
for effect in self.before_effects.iter() {
|
||||
effect.lock().render_special_tiles(&mut tile_render_context);
|
||||
effect
|
||||
.safe_lock()
|
||||
.render_special_tiles(&mut tile_render_context);
|
||||
}
|
||||
let bounds = tile_render_context.visible_bounds();
|
||||
let Some(tiles) = self.tiles.as_ref().map(|r| r.data_ref()) else {
|
||||
@@ -1465,7 +1467,9 @@ impl NodeTrait for TileMap {
|
||||
}
|
||||
}
|
||||
for effect in self.after_effects.iter() {
|
||||
effect.lock().render_special_tiles(&mut tile_render_context);
|
||||
effect
|
||||
.safe_lock()
|
||||
.render_special_tiles(&mut tile_render_context);
|
||||
}
|
||||
RdcControlFlow::Continue
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ use crate::{
|
||||
core::{
|
||||
parking_lot::{Mutex, MutexGuard},
|
||||
uuid::Uuid,
|
||||
TypeUuidProvider,
|
||||
SafeLock, TypeUuidProvider,
|
||||
},
|
||||
script::{Script, ScriptTrait},
|
||||
};
|
||||
@@ -68,7 +68,7 @@ impl ScriptConstructorContainer {
|
||||
where
|
||||
T: TypeUuidProvider + ScriptTrait + Default,
|
||||
{
|
||||
let old = self.map.lock().insert(
|
||||
let old = self.map.safe_lock().insert(
|
||||
T::type_uuid(),
|
||||
ScriptConstructor {
|
||||
constructor: Box::new(|| Script::new(T::default())),
|
||||
@@ -89,7 +89,7 @@ impl ScriptConstructorContainer {
|
||||
type_uuid: Uuid,
|
||||
constructor: ScriptConstructor,
|
||||
) -> Result<(), String> {
|
||||
let mut map = self.map.lock();
|
||||
let mut map = self.map.safe_lock();
|
||||
if let Some(old) = map.get(&type_uuid) {
|
||||
return Err(format!(
|
||||
"cannot add {} ({}) because its uuid is already used by {} ({})",
|
||||
@@ -102,20 +102,20 @@ impl ScriptConstructorContainer {
|
||||
|
||||
/// Unregisters type constructor.
|
||||
pub fn remove(&self, type_uuid: Uuid) {
|
||||
self.map.lock().remove(&type_uuid);
|
||||
self.map.safe_lock().remove(&type_uuid);
|
||||
}
|
||||
|
||||
/// Makes an attempt to create a script using provided type UUID. It may fail if there is no
|
||||
/// script constructor for specified type UUID.
|
||||
pub fn try_create(&self, type_uuid: &Uuid) -> Option<Script> {
|
||||
self.map
|
||||
.lock()
|
||||
.safe_lock()
|
||||
.get_mut(type_uuid)
|
||||
.map(|c| (c.constructor)())
|
||||
}
|
||||
|
||||
/// Returns inner map of script constructors.
|
||||
pub fn map(&self) -> MutexGuard<BTreeMap<Uuid, ScriptConstructor>> {
|
||||
self.map.lock()
|
||||
self.map.safe_lock()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ use fyrox_core::{
|
||||
sstorage::ImmutableString,
|
||||
uuid::{uuid, Uuid},
|
||||
visitor::{prelude::*, RegionGuard},
|
||||
TypeUuidProvider,
|
||||
SafeLock, TypeUuidProvider,
|
||||
};
|
||||
use fyrox_graphics::gpu_program::SamplerFallback;
|
||||
use fyrox_resource::{
|
||||
@@ -1171,7 +1171,7 @@ pub fn visit_old_material(region: &mut RegionGuard) -> Option<MaterialResource>
|
||||
return Some(MaterialResource::new_ok(
|
||||
Uuid::new_v4(),
|
||||
Default::default(),
|
||||
old_material.lock().clone(),
|
||||
old_material.safe_lock().clone(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
//! on deserialization to create a default instance of corresponding resource.
|
||||
|
||||
use crate::{
|
||||
core::{parking_lot::Mutex, uuid::Uuid, TypeUuidProvider},
|
||||
core::{parking_lot::Mutex, uuid::Uuid, SafeLock, TypeUuidProvider},
|
||||
ResourceData,
|
||||
};
|
||||
use fxhash::FxHashMap;
|
||||
@@ -62,7 +62,7 @@ impl ResourceConstructorContainer {
|
||||
where
|
||||
T: ResourceData + Default + TypeUuidProvider,
|
||||
{
|
||||
let previous = self.map.lock().insert(
|
||||
let previous = self.map.safe_lock().insert(
|
||||
<T as TypeUuidProvider>::type_uuid(),
|
||||
ResourceDataConstructor {
|
||||
callback: Box::new(|| Box::<T>::default()),
|
||||
@@ -75,26 +75,26 @@ impl ResourceConstructorContainer {
|
||||
|
||||
/// Adds custom type constructor.
|
||||
pub fn add_custom(&self, type_uuid: Uuid, constructor: ResourceDataConstructor) {
|
||||
self.map.lock().insert(type_uuid, constructor);
|
||||
self.map.safe_lock().insert(type_uuid, constructor);
|
||||
}
|
||||
|
||||
/// Unregisters type constructor.
|
||||
pub fn remove(&self, type_uuid: Uuid) {
|
||||
self.map.lock().remove(&type_uuid);
|
||||
self.map.safe_lock().remove(&type_uuid);
|
||||
}
|
||||
|
||||
/// Makes an attempt to create a resource data using provided type UUID. It may fail if there is no
|
||||
/// resource data constructor for specified type UUID.
|
||||
pub fn try_create(&self, type_uuid: &Uuid) -> Option<Box<dyn ResourceData>> {
|
||||
self.map
|
||||
.lock()
|
||||
.safe_lock()
|
||||
.get_mut(type_uuid)
|
||||
.map(|c| c.create_instance())
|
||||
}
|
||||
|
||||
/// Returns total amount of constructors.
|
||||
pub fn len(&self) -> usize {
|
||||
self.map.lock().len()
|
||||
self.map.safe_lock().len()
|
||||
}
|
||||
|
||||
/// Returns true if the container is empty.
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
use crate::core::{
|
||||
parking_lot::Mutex,
|
||||
pool::{Handle, Pool},
|
||||
SafeLock,
|
||||
};
|
||||
use crate::UntypedResource;
|
||||
use std::{
|
||||
@@ -72,17 +73,17 @@ impl ResourceEventBroadcaster {
|
||||
/// Adds an event sender to the broadcaster and returns its handle. If the receiver part of the
|
||||
/// channel dies, the sender part is automatically removed from the broadcaster.
|
||||
pub fn add(&self, sender: ResourceEventSender) -> Handle<ResourceEventSender> {
|
||||
self.container.lock().spawn(sender)
|
||||
self.container.safe_lock().spawn(sender)
|
||||
}
|
||||
|
||||
/// Removes an event sender by its handle.
|
||||
pub fn remove(&self, handle: Handle<ResourceEventSender>) -> ResourceEventSender {
|
||||
self.container.lock().free(handle)
|
||||
self.container.safe_lock().free(handle)
|
||||
}
|
||||
|
||||
/// Sends an event to all "subscribers" in the broadcaster.
|
||||
pub fn broadcast(&self, event: ResourceEvent) {
|
||||
let mut container = self.container.lock();
|
||||
let mut container = self.container.safe_lock();
|
||||
container.retain(|sender| sender.send(event.clone()).is_ok());
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
use crate::{collect_used_resources, state::ResourceState, untyped::UntypedResource};
|
||||
use fxhash::FxHashSet;
|
||||
use fyrox_core::SafeLock;
|
||||
|
||||
/// A node of [`ResourceDependencyGraph`].
|
||||
pub struct ResourceGraphNode {
|
||||
@@ -40,7 +41,7 @@ impl ResourceGraphNode {
|
||||
// Look for dependent resources.
|
||||
let mut dependent_resources = FxHashSet::default();
|
||||
|
||||
let header = resource.0.lock();
|
||||
let header = resource.0.safe_lock();
|
||||
if let ResourceState::Ok { ref data, .. } = header.state {
|
||||
(**data).as_reflect(&mut |entity| {
|
||||
collect_used_resources(entity, &mut dependent_resources);
|
||||
|
||||
@@ -38,7 +38,7 @@ use crate::{
|
||||
};
|
||||
use fxhash::FxHashSet;
|
||||
pub use fyrox_core as core;
|
||||
use fyrox_core::{combine_uuids, log::Log};
|
||||
use fyrox_core::{combine_uuids, log::Log, SafeLock};
|
||||
use std::any::Any;
|
||||
use std::path::PathBuf;
|
||||
use std::{
|
||||
@@ -408,7 +408,7 @@ where
|
||||
#[inline]
|
||||
pub fn data_ref(&self) -> ResourceDataRef<'_, T> {
|
||||
ResourceDataRef {
|
||||
guard: self.untyped.0.lock(),
|
||||
guard: self.untyped.0.safe_lock(),
|
||||
phantom: Default::default(),
|
||||
}
|
||||
}
|
||||
@@ -703,7 +703,8 @@ mod tests {
|
||||
};
|
||||
use fyrox_core::{
|
||||
append_extension, futures::executor::block_on, io::FileError, parking_lot::Mutex,
|
||||
reflect::prelude::*, task::TaskPool, uuid, visitor::prelude::*, TypeUuidProvider, Uuid,
|
||||
reflect::prelude::*, task::TaskPool, uuid, visitor::prelude::*, SafeLock, TypeUuidProvider,
|
||||
Uuid,
|
||||
};
|
||||
use ron::ser::PrettyConfig;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -854,7 +855,7 @@ mod tests {
|
||||
resource_manager
|
||||
.state()
|
||||
.resource_registry
|
||||
.lock()
|
||||
.safe_lock()
|
||||
.set_path(Path::new(TEST_FOLDER2).join("resources.registry"));
|
||||
resource_manager.add_loader(MyDataLoader {});
|
||||
resource_manager.update_or_load_registry();
|
||||
@@ -877,7 +878,7 @@ mod tests {
|
||||
resource_manager
|
||||
.state()
|
||||
.resource_registry
|
||||
.lock()
|
||||
.safe_lock()
|
||||
.set_path(Path::new(TEST_FOLDER3).join("resources.registry"));
|
||||
resource_manager.add_loader(MyDataLoader {});
|
||||
resource_manager.update_or_load_registry();
|
||||
|
||||
@@ -32,6 +32,7 @@ use crate::{
|
||||
state::WakersList,
|
||||
};
|
||||
use fxhash::FxHashSet;
|
||||
use fyrox_core::SafeLock;
|
||||
use ron::ser::PrettyConfig;
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
@@ -127,24 +128,33 @@ pub struct ResourceRegistryStatusFlag(Arc<Mutex<RegistryReadyFlagData>>);
|
||||
impl ResourceRegistryStatusFlag {
|
||||
/// Returns current status of the registry.
|
||||
pub fn status(&self) -> ResourceRegistryStatus {
|
||||
self.0.lock().status
|
||||
self.0.safe_lock().status
|
||||
}
|
||||
|
||||
/// Marks the registry as loaded.
|
||||
pub fn mark_as_loaded(&self) {
|
||||
let mut lock = self.0.lock();
|
||||
fn mark_as(&self, status: ResourceRegistryStatus) {
|
||||
let mut lock = self.0.safe_lock();
|
||||
|
||||
lock.status = ResourceRegistryStatus::Loaded;
|
||||
lock.status = status;
|
||||
|
||||
for waker in lock.wakers.drain(..) {
|
||||
waker.wake();
|
||||
}
|
||||
}
|
||||
|
||||
/// Marks the registry as loaded.
|
||||
pub fn mark_as_loaded(&self) {
|
||||
self.mark_as(ResourceRegistryStatus::Loaded);
|
||||
}
|
||||
|
||||
/// Marks the registry as unknown, due to an error.
|
||||
pub fn mark_as_unknown(&self) {
|
||||
self.mark_as(ResourceRegistryStatus::Unknown);
|
||||
}
|
||||
|
||||
/// Marks the registry as loading. This method should be used before trying to load a registry
|
||||
/// from an external source.
|
||||
pub fn mark_as_loading(&self) {
|
||||
self.0.lock().status = ResourceRegistryStatus::Loading;
|
||||
self.0.safe_lock().status = ResourceRegistryStatus::Loading;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,7 +162,7 @@ impl Future for ResourceRegistryStatusFlag {
|
||||
type Output = ResourceRegistryStatus;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let mut lock = self.0.lock();
|
||||
let mut lock = self.0.safe_lock();
|
||||
|
||||
match lock.status {
|
||||
ResourceRegistryStatus::Unknown => Poll::Ready(ResourceRegistryStatus::Unknown),
|
||||
@@ -503,7 +513,7 @@ impl ResourceRegistry {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !loaders.lock().is_supported_resource(&path) {
|
||||
if !loaders.safe_lock().is_supported_resource(&path) {
|
||||
if path
|
||||
.extension()
|
||||
.is_some_and(|ext| ext != "meta" && ext != "registry")
|
||||
|
||||
@@ -326,7 +326,11 @@ impl Visit for UntypedResource {
|
||||
// 1) The registry is not loaded.
|
||||
// 2) You're trying to deserialize the resource handle manually without a proper
|
||||
// environment.
|
||||
assert_eq!(status_flag.status(), ResourceRegistryStatus::Loaded);
|
||||
assert_eq!(
|
||||
status_flag.status(),
|
||||
ResourceRegistryStatus::Loaded,
|
||||
"Resource registry is not loaded"
|
||||
);
|
||||
|
||||
let path = match inner_lock.old_format_path {
|
||||
None => {
|
||||
|
||||
@@ -42,6 +42,7 @@ use fyrox_core::{
|
||||
reflect::prelude::*,
|
||||
uuid_provider,
|
||||
visitor::prelude::*,
|
||||
SafeLock,
|
||||
};
|
||||
use std::{
|
||||
sync::{Arc, Mutex, MutexGuard},
|
||||
@@ -370,7 +371,7 @@ impl SoundContext {
|
||||
/// You'll get a deadlock, so general rule here is to not store result of this method
|
||||
/// anywhere.
|
||||
pub fn state(&self) -> MutexGuard<'_, State> {
|
||||
self.state.as_ref().unwrap().lock().unwrap()
|
||||
self.state.as_ref().unwrap().safe_lock().unwrap()
|
||||
}
|
||||
|
||||
/// Creates deep copy instead of shallow which is done by clone().
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
use crate::context::{SoundContext, SAMPLE_RATE};
|
||||
use fyrox_core::visitor::{Visit, VisitResult, Visitor};
|
||||
use fyrox_core::SafeLock;
|
||||
use std::error::Error;
|
||||
use std::sync::{Arc, Mutex, MutexGuard};
|
||||
|
||||
@@ -103,7 +104,7 @@ impl SoundEngine {
|
||||
|
||||
/// Provides direct access to actual engine data.
|
||||
pub fn state(&self) -> MutexGuard<State> {
|
||||
self.0.lock().unwrap()
|
||||
self.0.safe_lock().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+15
-14
@@ -37,6 +37,7 @@ use crate::{
|
||||
type_traits::prelude::*,
|
||||
uuid_provider,
|
||||
visitor::prelude::*,
|
||||
SafeLock,
|
||||
},
|
||||
curve::key::{CurveKeyView, CurveKeyViewContainer},
|
||||
define_constructor,
|
||||
@@ -121,35 +122,35 @@ pub struct CurveTransformCell(Mutex<CurveTransform>);
|
||||
|
||||
impl Clone for CurveTransformCell {
|
||||
fn clone(&self) -> Self {
|
||||
Self(Mutex::new(self.0.lock().clone()))
|
||||
Self(Mutex::new(self.0.safe_lock().clone()))
|
||||
}
|
||||
}
|
||||
|
||||
impl CurveTransformCell {
|
||||
/// Position of the center of the curve editor in the curve coordinate space.
|
||||
pub fn position(&self) -> Vector2<f32> {
|
||||
self.0.lock().position
|
||||
self.0.safe_lock().position
|
||||
}
|
||||
/// Scape of the curve editor: multiply curve space units by this to get screen space units.
|
||||
pub fn scale(&self) -> Vector2<f32> {
|
||||
self.0.lock().scale
|
||||
self.0.safe_lock().scale
|
||||
}
|
||||
/// Location of the curve editor on the screen, in screen space units.
|
||||
pub fn bounds(&self) -> Rect<f32> {
|
||||
self.0.lock().bounds
|
||||
self.0.safe_lock().bounds
|
||||
}
|
||||
/// Modify the current position. Call this when the center of the curve view should change.
|
||||
pub fn set_position(&self, position: Vector2<f32>) {
|
||||
self.0.lock().position = position
|
||||
self.0.safe_lock().position = position
|
||||
}
|
||||
/// Modify the current zoom of the curve view.
|
||||
pub fn set_scale(&self, scale: Vector2<f32>) {
|
||||
self.0.lock().scale = scale;
|
||||
self.0.safe_lock().scale = scale;
|
||||
}
|
||||
/// Update the bounds of the curve view. Call this to ensure the CurveTransform accurately
|
||||
/// reflects the actual size of the widget being drawn.
|
||||
pub fn set_bounds(&self, bounds: Rect<f32>) {
|
||||
self.0.lock().bounds = bounds;
|
||||
self.0.safe_lock().bounds = bounds;
|
||||
}
|
||||
/// Just like [CurveTransformCell::y_step_iter] but for x-coordinates.
|
||||
/// Iterate through a list of x-coordinates across the width of the bounds.
|
||||
@@ -159,7 +160,7 @@ impl CurveTransformCell {
|
||||
/// This iterator indates where grid lines should be drawn to make a curve easier
|
||||
/// to read for the user.
|
||||
pub fn x_step_iter(&self, grid_size: f32) -> StepIterator {
|
||||
self.0.lock().x_step_iter(grid_size)
|
||||
self.0.safe_lock().x_step_iter(grid_size)
|
||||
}
|
||||
/// Just like [CurveTransformCell::x_step_iter] but for y-coordinates.
|
||||
/// Iterate through a list of y-coordinates across the width of the bounds.
|
||||
@@ -169,31 +170,31 @@ impl CurveTransformCell {
|
||||
/// This iterator indates where grid lines should be drawn to make a curve easier
|
||||
/// to read for the user.
|
||||
pub fn y_step_iter(&self, grid_size: f32) -> StepIterator {
|
||||
self.0.lock().y_step_iter(grid_size)
|
||||
self.0.safe_lock().y_step_iter(grid_size)
|
||||
}
|
||||
/// Construct the transformation matrices to reflect the current position, scale, and bounds.
|
||||
pub fn update_transform(&self) {
|
||||
self.0.lock().update_transform();
|
||||
self.0.safe_lock().update_transform();
|
||||
}
|
||||
/// Transform a point on the curve into a point in the local coordinate space of the widget.
|
||||
pub fn curve_to_local(&self) -> MappedMutexGuard<Matrix3<f32>> {
|
||||
MutexGuard::map(self.0.lock(), |t| &mut t.curve_to_local)
|
||||
MutexGuard::map(self.0.safe_lock(), |t| &mut t.curve_to_local)
|
||||
}
|
||||
/// Transform a point on the curve into a point on the screen.
|
||||
pub fn curve_to_screen(&self) -> MappedMutexGuard<Matrix3<f32>> {
|
||||
MutexGuard::map(self.0.lock(), |t| &mut t.curve_to_screen)
|
||||
MutexGuard::map(self.0.safe_lock(), |t| &mut t.curve_to_screen)
|
||||
}
|
||||
/// Transform a point in the local coordinate space of the widget into a point in the coordinate space of the curve.
|
||||
/// After the transformation, the x-coordinate could be a key location and the y-coordinate could be a key value.
|
||||
/// Y-coordinates are flipped so that positive-y becomes the up direction.
|
||||
pub fn local_to_curve(&self) -> MappedMutexGuard<Matrix3<f32>> {
|
||||
MutexGuard::map(self.0.lock(), |t| &mut t.local_to_curve)
|
||||
MutexGuard::map(self.0.safe_lock(), |t| &mut t.local_to_curve)
|
||||
}
|
||||
/// Transform a point on the screen into a point in the coordinate space of the curve.
|
||||
/// After the transformation, the x-coordinate could be a key location and the y-coordinate could be a key value.
|
||||
/// Y-coordinates are flipped so that positive-y becomes the up direction.
|
||||
pub fn screen_to_curve(&self) -> MappedMutexGuard<Matrix3<f32>> {
|
||||
MutexGuard::map(self.0.lock(), |t| &mut t.screen_to_curve)
|
||||
MutexGuard::map(self.0.safe_lock(), |t| &mut t.screen_to_curve)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ use crate::{
|
||||
sstorage::ImmutableString,
|
||||
uuid::Uuid,
|
||||
visitor::prelude::*,
|
||||
SafeLock,
|
||||
},
|
||||
decorator::Decorator,
|
||||
dropdown_list::DropdownList,
|
||||
@@ -761,7 +762,7 @@ impl PropertyEditorDefinitionContainer {
|
||||
self.definitions.write().insert(
|
||||
definition.value_type_id(),
|
||||
PropertyEditorDefinitionContainerEntry {
|
||||
source_type_id: *self.context_type_id.lock(),
|
||||
source_type_id: *self.context_type_id.safe_lock(),
|
||||
property_editor: definition,
|
||||
},
|
||||
)
|
||||
@@ -786,7 +787,7 @@ impl PropertyEditorDefinitionContainer {
|
||||
self.definitions.write().insert(
|
||||
definition.value_type_id(),
|
||||
PropertyEditorDefinitionContainerEntry {
|
||||
source_type_id: *self.context_type_id.lock(),
|
||||
source_type_id: *self.context_type_id.safe_lock(),
|
||||
property_editor: Box::new(definition),
|
||||
},
|
||||
)
|
||||
|
||||
@@ -36,6 +36,7 @@ use crate::{
|
||||
uuid_provider,
|
||||
variable::InheritableVariable,
|
||||
visitor::prelude::*,
|
||||
SafeLock,
|
||||
},
|
||||
define_constructor,
|
||||
draw::{CommandTexture, Draw, DrawingContext},
|
||||
@@ -503,7 +504,7 @@ impl TextBox {
|
||||
let mut str = str.replace("\r\n", "\n");
|
||||
str.retain(|c| c == '\n' || !c.is_control());
|
||||
if let Some(filter) = self.filter.as_ref() {
|
||||
let filter = &mut *filter.lock();
|
||||
let filter = &mut *filter.safe_lock();
|
||||
str.retain(filter);
|
||||
}
|
||||
str
|
||||
@@ -516,7 +517,7 @@ impl TextBox {
|
||||
.filter(|c| !c.is_control())
|
||||
.collect();
|
||||
if let Some(filter) = self.filter.as_ref() {
|
||||
let filter = &mut *filter.lock();
|
||||
let filter = &mut *filter.safe_lock();
|
||||
str.retain(filter);
|
||||
}
|
||||
str
|
||||
@@ -1106,7 +1107,7 @@ impl Control for TextBox {
|
||||
for symbol in text.chars() {
|
||||
let insert = !symbol.is_control()
|
||||
&& if let Some(filter) = self.filter.as_ref() {
|
||||
let filter = &mut *filter.lock();
|
||||
let filter = &mut *filter.safe_lock();
|
||||
filter(symbol)
|
||||
} else {
|
||||
true
|
||||
|
||||
@@ -33,7 +33,7 @@ use crate::{
|
||||
reflect::prelude::*,
|
||||
uuid::Uuid,
|
||||
visitor::prelude::*,
|
||||
ImmutableString,
|
||||
ImmutableString, SafeLock,
|
||||
},
|
||||
core::{parking_lot::Mutex, variable::InheritableVariable},
|
||||
define_constructor,
|
||||
@@ -1805,7 +1805,7 @@ impl Widget {
|
||||
#[inline]
|
||||
pub fn user_data_cloned<T: Clone + 'static>(&self) -> Option<T> {
|
||||
self.user_data.as_ref().and_then(|v| {
|
||||
let guard = v.lock();
|
||||
let guard = v.safe_lock();
|
||||
guard.downcast_ref::<T>().cloned()
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user