traaains/sim/track/segment/commands/
split.rs1use bevy::{
2 ecs::{entity::Entity, observer::ObserverSystemExt, system::Command},
3 mesh::Mesh2d,
4 sprite_render::MeshMaterial2d,
5 state::condition::in_state,
6 transform::components::Transform,
7};
8use bezier::Bezier;
9use shapes::lerp::Lerp;
10
11use crate::{
12 AssetType, AssetsManager,
13 editor::EditorState,
14 sim::{
15 signal::SignalPos,
16 track::{
17 node::{TrackNode, on_node_press_window},
18 segment::{
19 TrackSegment,
20 commands::{RemoveSegment, SpawnSegment},
21 signals_manager::SignalsManager,
22 },
23 },
24 },
25};
26
27pub struct SplitSegment {
29 target: Entity,
31 idx: f32,
33}
34
35impl SplitSegment {
36 pub fn new(target: Entity, idx: f32) -> Self {
37 SplitSegment { target, idx }
38 }
39}
40
41impl Command for SplitSegment {
42 type Out = Result<(), &'static str>;
43
44 fn apply(self, world: &mut bevy::ecs::world::World) -> Self::Out {
45 let Some((ts_transform, mut ts_signals)) = world
46 .entity_mut(self.target)
47 .take::<(Transform, SignalsManager)>()
48 else {
49 return Err("Failed to get transform from target entity!");
50 };
51
52 let ts = RemoveSegment::new(self.target)
53 .with_despawn_nodes(false)
54 .with_despawn_block(false)
55 .with_despawn_signals(false)
56 .apply(world)?;
57
58 let split_point_world = ts_transform.translation.truncate() + ts.shape.lerp(self.idx);
59
60 let (mesh, mat) = {
62 let assets_manager = world.resource::<AssetsManager>();
63 (
64 assets_manager
65 .meshes
66 .get(&AssetType::TrackNodeNormal)
67 .cloned()
68 .unwrap(),
69 assets_manager
70 .materials
71 .get(&AssetType::TrackNodeNormal)
72 .cloned()
73 .unwrap(),
74 )
75 };
76
77 let split_node = world
78 .spawn((
79 TrackNode::default(),
80 Transform::from_translation(split_point_world.extend(5.0)),
81 Mesh2d(mesh),
82 MeshMaterial2d(mat),
83 ))
84 .observe(on_node_press_window.run_if(in_state(EditorState::Viewing)))
85 .id();
86
87 let (new_from_shape, new_to_shape) = ts.shape.split(self.idx);
89 let new_from_segment =
90 TrackSegment::new(new_from_shape, ts.from_node, split_node, ts.block);
91 let new_to_segment = TrackSegment::new(new_to_shape, split_node, ts.to_node, ts.block);
92
93 let to_signals_map = ts_signals.inner.split_off(&SignalPos(self.idx));
95 let to_signals = SignalsManager {
96 inner: to_signals_map,
97 };
98
99 SpawnSegment::new(new_from_segment, ts_signals, ts_transform).apply(world);
101 SpawnSegment::new(
102 new_to_segment,
103 to_signals,
104 Transform::from_translation(split_point_world.extend(0.0)),
105 )
106 .apply(world);
107
108 Ok(())
109 }
110}