From b6089617c639a1eb88bcd9fc0135f132e0138694 Mon Sep 17 00:00:00 2001 From: Dmitry Stepanov Date: Tue, 22 Sep 2026 22:50:29 +0300 Subject: [PATCH] fixed crash when adding/removing audio bus + fixed crashes in undo/redo - #930 --- editor/src/audio/mod.rs | 15 ++-- editor/src/scene/commands/effect.rs | 118 +++++++++++----------------- 2 files changed, 56 insertions(+), 77 deletions(-) diff --git a/editor/src/audio/mod.rs b/editor/src/audio/mod.rs index 124f2a33a..3db343ef9 100644 --- a/editor/src/audio/mod.rs +++ b/editor/src/audio/mod.rs @@ -51,7 +51,7 @@ use crate::{ plugins::inspector::editors::resource::{ResourceFieldBuilder, ResourceFieldMessage}, scene::{ commands::{ - effect::{AddAudioBusCommand, LinkAudioBuses, RemoveAudioBusCommand}, + effect::{AddOrRemoveAudioBusCommand, LinkAudioBuses}, sound_context::{ SetDistanceModelCommand, SetHrtfRendererHrirSphereResource, SetRendererCommand, }, @@ -189,10 +189,11 @@ fn fetch_possible_parent_buses( let mut stack = vec![graph.primary_bus_handle()]; let mut result = Vec::new(); while let Some(other_bus) = stack.pop() { - let other_bus_ref = graph.try_get_bus_ref(other_bus).expect("Malformed graph!"); - if other_bus != bus { - result.push((other_bus, other_bus_ref.name().to_owned())); - stack.extend_from_slice(other_bus_ref.children()); + if let Ok(other_bus_ref) = graph.try_get_bus_ref(other_bus) { + if other_bus != bus { + result.push((other_bus, other_bus_ref.name().to_owned())); + stack.extend_from_slice(other_bus_ref.children()); + } } } result @@ -375,7 +376,7 @@ impl AudioPanel { ) { if let Some(ButtonMessage::Click) = message.data() { if message.destination() == self.add_bus { - sender.do_command(AddAudioBusCommand::new(AudioBus::new( + sender.do_command(AddOrRemoveAudioBusCommand::new_add(AudioBus::new( "AudioBus".to_string(), ))) } else if message.destination() == self.remove_bus { @@ -385,7 +386,7 @@ impl AudioPanel { ))]; for &bus in &selection.buses { - commands.push(Command::new(RemoveAudioBusCommand::new(bus))); + commands.push(Command::new(AddOrRemoveAudioBusCommand::new_remove(bus))); } sender.do_command(CommandGroup::from(commands)); diff --git a/editor/src/scene/commands/effect.rs b/editor/src/scene/commands/effect.rs index 599302c8b..9d868e8f1 100644 --- a/editor/src/scene/commands/effect.rs +++ b/editor/src/scene/commands/effect.rs @@ -25,107 +25,85 @@ use crate::fyrox::{ use crate::{command::CommandContext, CommandTrait, GameSceneContext}; #[derive(Debug)] -pub struct AddAudioBusCommand { +pub struct AddOrRemoveAudioBusCommand { bus: Option, handle: Handle, ticket: Option>, + add: bool, } -impl AddAudioBusCommand { - pub fn new(bus: AudioBus) -> Self { +impl AddOrRemoveAudioBusCommand { + pub fn new_add(bus: AudioBus) -> Self { Self { bus: Some(bus), handle: Default::default(), ticket: None, + add: true, } } -} -impl CommandTrait for AddAudioBusCommand { - fn name(&mut self, _: &dyn CommandContext) -> String { - "Add Effect".to_owned() - } - - fn execute(&mut self, context: &mut dyn CommandContext) { - let context = context.get_mut::(); - let mut state = context.scene.graph.sound_context.state(); - let parent = state.bus_graph_ref().primary_bus_handle(); - self.handle = state - .bus_graph_mut() - .add_bus(self.bus.take().unwrap(), parent); - } - - fn revert(&mut self, context: &mut dyn CommandContext) { - let context = context.get_mut::(); - let (ticket, effect) = context - .scene - .graph - .sound_context - .state() - .bus_graph_mut() - .try_take_reserve_bus(self.handle) - .unwrap(); - self.bus = Some(effect); - self.ticket = Some(ticket); - } - - fn finalize(&mut self, context: &mut dyn CommandContext) { - let context = context.get_mut::(); - if let Some(ticket) = self.ticket.take() { - context - .scene - .graph - .sound_context - .state() - .bus_graph_mut() - .forget_bus_ticket(ticket); - } - } -} - -#[derive(Debug)] -pub struct RemoveAudioBusCommand { - bus: Option, - handle: Handle, - ticket: Option>, -} - -impl RemoveAudioBusCommand { - pub fn new(handle: Handle) -> Self { + pub fn new_remove(handle: Handle) -> Self { Self { bus: None, handle, ticket: None, + add: false, } } -} -impl CommandTrait for RemoveAudioBusCommand { - fn name(&mut self, _: &dyn CommandContext) -> String { - "Remove Effect".to_owned() + fn add(&mut self, context: &mut dyn CommandContext) { + let context = context.get_mut::(); + let mut state = context.scene.graph.sound_context.state(); + let parent = state.bus_graph_ref().primary_bus_handle(); + if let Some(bus) = self.bus.take() { + let bus_graph = state.bus_graph_mut(); + if let Some(ticket) = self.ticket.take() { + self.handle = bus_graph.put_bus_back(ticket, bus); + } else { + self.handle = bus_graph.add_bus(bus, parent); + } + } } - fn execute(&mut self, context: &mut dyn CommandContext) { + fn remove(&mut self, context: &mut dyn CommandContext) { let context = context.get_mut::(); - let (ticket, effect) = context + if let Ok((ticket, effect)) = context .scene .graph .sound_context .state() .bus_graph_mut() .try_take_reserve_bus(self.handle) - .unwrap(); - self.bus = Some(effect); - self.ticket = Some(ticket); + { + self.bus = Some(effect); + self.ticket = Some(ticket); + } + } +} + +impl CommandTrait for AddOrRemoveAudioBusCommand { + fn name(&mut self, _: &dyn CommandContext) -> String { + if self.add { + "Add Audio Bus".to_owned() + } else { + "Remove Audio Bus".to_owned() + } + } + + fn execute(&mut self, context: &mut dyn CommandContext) { + if self.add { + self.add(context) + } else { + self.remove(context) + } } fn revert(&mut self, context: &mut dyn CommandContext) { - let context = context.get_mut::(); - let mut state = context.scene.graph.sound_context.state(); - let parent = state.bus_graph_ref().primary_bus_handle(); - self.handle = state - .bus_graph_mut() - .add_bus(self.bus.take().unwrap(), parent); + if self.add { + self.remove(context); + } else { + self.add(context); + } } fn finalize(&mut self, context: &mut dyn CommandContext) {