bevy_undo2/
extension.rs

1use bevy::app::{App, Update};
2use bevy::prelude::{Event, EventReader, EventWriter, IntoSystemConfigs, ResMut};
3use crate::{CommitReservationsEvent, DecrementCounterEvent, UndoRegisteredArea};
4use crate::request::RequestUndoEvent;
5use crate::reserve::{ReserveCounter, UndoReservedArea, UndoReserveEvent};
6use crate::undo_event::UndoEvent;
7
8
9pub trait AppUndoEx {
10    /// Setup the app to manage undo events of type `T`
11    ///
12    /// In order to use undo-action, you must call [`UndoScheduler::register`](UndoScheduler::register).
13    /// then call [`UndoRequester::undo`](UndoRequester::undo) when you need.
14    fn add_undo_event<T: Event + Clone>(&mut self) -> &mut App;
15}
16
17
18impl AppUndoEx for App {
19    fn add_undo_event<E: Event + Clone>(&mut self) -> &mut App {
20        self.add_event::<E>();
21        self.add_event::<UndoEvent<E>>();
22        self.add_event::<UndoReserveEvent<E>>();
23        self.init_resource::<UndoRegisteredArea<E>>();
24        self.init_resource::<UndoRegisteredArea<UndoReserveEvent<E>>>();
25        self.init_resource::<UndoReservedArea<E>>();
26        self.init_resource::<ReserveCounter>();
27        self.add_systems(Update, (
28            register_all_reserved_events_system::<E>,
29            push_undo_event_system::<E>,
30            pop_undo_event_system::<E>,
31            pop_undo_event_system::<E>,
32            pop_undo_event_system::<UndoReserveEvent<E>>,
33            reserve_event_system::<E>
34        ).chain());
35        self
36    }
37}
38
39
40fn register_all_reserved_events_system<E: Event + Clone>(
41    mut er: EventReader<CommitReservationsEvent>,
42    mut preserve: ResMut<UndoReservedArea<E>>,
43    mut registered_reserve_event_area: ResMut<UndoRegisteredArea<UndoReserveEvent<E>>>,
44) {
45    if let Some(CommitReservationsEvent(counter)) = er.iter().next() {
46        while let Some(event) = preserve.pop() {
47            registered_reserve_event_area.push(UndoEvent {
48                inner: event.clone(),
49                no: **counter + event.reserve_no,
50            });
51        }
52    }
53}
54
55
56fn push_undo_event_system<E: Event + Clone>(
57    mut er: EventReader<UndoEvent<E>>,
58    mut registered_area: ResMut<UndoRegisteredArea<E>>,
59) {
60    for e in er.iter() {
61        registered_area.push(e.clone());
62    }
63}
64
65
66fn pop_undo_event_system<E: Event + Clone>(
67    mut er: EventReader<RequestUndoEvent>,
68    mut ew: EventWriter<E>,
69    mut decrement_writer: EventWriter<DecrementCounterEvent>,
70    mut registered_area: ResMut<UndoRegisteredArea<E>>,
71) {
72    for RequestUndoEvent(counter) in er.iter() {
73        while let Some(undo) = registered_area.pop_if_has_latest(counter) {
74            ew.send(undo);
75            decrement_writer.send(DecrementCounterEvent);
76        }
77    }
78}
79
80
81fn reserve_event_system<E: Event + Clone>(
82    mut er: EventReader<UndoReserveEvent<E>>,
83    mut ew: EventWriter<E>,
84    mut registered_area: ResMut<UndoRegisteredArea<UndoReserveEvent<E>>>,
85    mut decrement_writer: EventWriter<DecrementCounterEvent>,
86) {
87    if er.is_empty() {
88        return;
89    }
90
91    for event in er.iter() {
92        ew.send(event.inner.clone());
93        if event.reserve_no == 1{
94            return;
95        }
96    }
97
98    while let Some(event) = registered_area.pop() {
99        ew.send(event.inner.clone());
100        decrement_writer.send(DecrementCounterEvent);
101        if event.reserve_no == 1{
102            return;
103        }
104    }
105}
106
107