traaains/sim/track/segment/commands/
spawn.rs1use bevy::{
2 asset::{Assets, Handle},
3 ecs::{entity::Entity, observer::ObserverSystemExt, system::Command, world::World},
4 mesh::{Mesh, Mesh2d},
5 sprite_render::{ColorMaterial, MeshMaterial2d},
6 state::condition::in_state,
7 transform::components::Transform,
8};
9
10use crate::{
11 AssetType, AssetsManager,
12 editor::EditorState,
13 shape::{BezierMeshProps, Shapes},
14 sim::{
15 logical_graph::{LogicalBlock, LogicalConnection},
16 track::{
17 node::{Connection, ConnectionLocation, TrackNode},
18 segment::{TrackSegment, on_segment_press_window, signals_manager::SignalsManager},
19 },
20 },
21 utils::Meshable,
22};
23
24pub struct SpawnSegment {
25 segment: TrackSegment,
26 signals: SignalsManager,
27 transform: Transform,
28}
29
30impl SpawnSegment {
31 pub fn new(segment: TrackSegment, signals: SignalsManager, transform: Transform) -> Self {
32 SpawnSegment {
33 segment,
34 signals,
35 transform,
36 }
37 }
38}
39
40fn get_mesh_mat(world: &mut World, shape: &Shapes) -> (Handle<Mesh>, Handle<ColorMaterial>) {
41 let mesh = world
42 .resource_mut::<Assets<Mesh>>()
43 .add(shape.mesh(BezierMeshProps::default()));
44
45 let mat = world
46 .resource::<AssetsManager>()
47 .materials
48 .get(&AssetType::TrackSegmentNormal)
49 .cloned()
50 .unwrap();
51
52 (mesh, mat)
53}
54
55fn handle_logical_blocks_for_node(
56 world: &mut World,
57 node: Entity,
58 block: Entity,
59 new_segment: Entity,
60) {
61 let segments_and_blocks: Vec<_> = world
62 .get::<TrackNode>(node)
63 .unwrap()
64 .connections
65 .iter()
66 .map(|c| {
67 (
68 c.segment,
69 world
70 .get::<TrackSegment>(c.segment)
71 .map(|s| s.block)
72 .unwrap(),
73 )
74 })
75 .filter(|(_, b)| *b != block)
76 .collect();
77
78 for (_, b) in segments_and_blocks.iter() {
80 world
81 .get_mut::<LogicalBlock>(*b)
82 .unwrap()
83 .connections
84 .insert(
85 (node, new_segment).into(),
86 LogicalConnection { block, cover: None },
87 );
88 }
89
90 let mut our_lb = world.get_mut::<LogicalBlock>(block).unwrap();
92 for (s, b) in segments_and_blocks {
93 our_lb.connections.insert(
94 (node, s).into(),
95 LogicalConnection {
96 block: b,
97 cover: None,
98 },
99 );
100 }
101}
102
103impl Command for SpawnSegment {
104 type Out = ();
105
106 fn apply(self, world: &mut World) -> Self::Out {
107 let nodes = [
109 (self.segment.from_node, ConnectionLocation::Start),
110 (self.segment.to_node, ConnectionLocation::End),
111 ];
112
113 for (node, _) in nodes.iter() {
114 if !world
115 .get_mut::<TrackNode>(*node)
116 .unwrap()
117 .connections
118 .has_free()
119 {
120 return;
121 }
122 }
123
124 let (mesh, mat) = get_mesh_mat(world, &self.segment.shape);
126
127 let block = self.segment.block;
128
129 let new_segment = world
131 .spawn((
132 self.transform,
133 Mesh2d(mesh),
134 MeshMaterial2d(mat),
135 self.signals,
136 self.segment,
137 ))
138 .observe(on_segment_press_window.run_if(in_state(EditorState::Viewing)))
139 .id();
140
141 world
142 .get_mut::<LogicalBlock>(block)
143 .unwrap()
144 .number_of_segments += 1;
145
146 for (node, loc) in nodes {
147 handle_logical_blocks_for_node(world, node, block, new_segment);
148
149 world
150 .get_mut::<TrackNode>(node)
151 .unwrap()
152 .connections
153 .add(Connection::new(new_segment, loc))
154 .unwrap();
155 }
156 }
157}