Skip to main content

traaains/sim/track/segment/commands/
spawn.rs

1use 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    // add connections to our block to other blocks at this node
79    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    // add connections to other blocks to our block
91    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        // check node's number of connections
108        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        // get meshes and materials
125        let (mesh, mat) = get_mesh_mat(world, &self.segment.shape);
126
127        let block = self.segment.block;
128
129        // spawn new segment
130        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}