spru_bevy/client/
component.rs1use std::{
2 collections::{HashMap, VecDeque, hash_map},
3 fmt, ops,
4};
5
6use bevy::prelude;
7use derive_where::derive_where;
8use spru::item;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, prelude::Component)]
15#[component(storage = "SparseSet")]
16#[component(immutable)]
17pub struct ClientId(spru::player::Id);
18
19impl ClientId {
20 pub(crate) fn new(id: spru::player::Id) -> Self {
21 Self(id)
22 }
23}
24
25impl ops::Deref for ClientId {
26 type Target = spru::player::Id;
27
28 fn deref(&self) -> &Self::Target {
29 &self.0
30 }
31}
32
33impl fmt::Display for ClientId {
34 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35 fmt::Display::fmt(&self.0, f)
36 }
37}
38
39#[derive(Debug, prelude::Component)]
40#[component(storage = "SparseSet")]
41#[require(FromServer<Client>, ToServer<Client>, FromUser<Client>, EntityMap)]
42pub struct Runner<Client: super::ClientSSS> {
43 pub(crate) client: Client,
44}
45
46impl<Client: super::ClientSSS> Runner<Client> {
47 pub(crate) fn new(client: Client) -> Self {
48 Self { client }
49 }
50}
51
52#[derive_where(Debug; spru::common::signal::ToClient<Client::Common>)]
53#[derive_where(Default)]
54#[derive(prelude::Component)]
55#[component(storage = "SparseSet")]
56pub struct FromServer<Client: super::ClientSSS> {
57 queue: VecDeque<spru::common::signal::ToClient<Client::Common>>,
58}
59
60impl<Client: super::ClientSSS> FromServer<Client> {
61 pub fn len(&self) -> usize {
62 self.queue.len()
63 }
64
65 pub fn is_empty(&self) -> bool {
66 self.queue.is_empty()
67 }
68
69 pub(crate) fn enqueue(&mut self, signal: spru::common::signal::ToClient<Client::Common>) {
70 self.queue.push_back(signal);
71 }
72
73 pub fn dequeue(&mut self) -> Option<spru::common::signal::ToClient<Client::Common>> {
74 self.queue.pop_front()
75 }
76}
77
78#[derive_where(Debug; spru::common::signal::ToServer<Client::Common>)]
79#[derive_where(Default)]
80#[derive(prelude::Component)]
81#[component(storage = "SparseSet")]
82pub struct ToServer<Client: super::ClientSSS> {
83 queue: VecDeque<spru::common::signal::ToServer<Client::Common>>,
84}
85
86impl<Client: super::ClientSSS> ToServer<Client> {
87 pub fn len(&self) -> usize {
88 self.queue.len()
89 }
90
91 pub fn is_empty(&self) -> bool {
92 self.queue.is_empty()
93 }
94
95 pub fn enqueue(&mut self, signal: spru::common::signal::ToServer<Client::Common>) {
96 self.queue.push_back(signal);
97 }
98
99 pub(crate) fn dequeue(&mut self) -> Option<spru::common::signal::ToServer<Client::Common>> {
100 self.queue.pop_front()
101 }
102}
103
104#[derive_where(Debug; UserInput<Client>)]
105#[derive_where(Default)]
106#[derive(prelude::Component)]
107#[component(storage = "SparseSet")]
108pub struct FromUser<Client: super::ClientSSS> {
109 queue: VecDeque<UserInput<Client>>,
110}
111
112impl<Client: super::ClientSSS> FromUser<Client> {
113 pub fn len(&self) -> usize {
114 self.queue.len()
115 }
116
117 pub fn is_empty(&self) -> bool {
118 self.queue.is_empty()
119 }
120
121 pub fn stage_interaction(&mut self, interaction: Client::Interaction) {
122 self.queue
123 .push_back(UserInput::StageInteraction(interaction));
124 }
125
126 pub fn apply_interaction(&mut self, interaction_id: spru::interaction::Pending) {
127 self.queue
128 .push_back(UserInput::ApplyInteraction(Some(interaction_id)));
129 }
130
131 pub fn apply_all_interactions(&mut self) {
132 self.queue.push_back(UserInput::ApplyInteraction(None));
133 }
134
135 pub fn revert_interaction(&mut self, interaction_id: spru::interaction::Pending) {
136 self.queue
137 .push_back(UserInput::RevertInteraction(Some(interaction_id)));
138 }
139
140 pub fn revert_all_interactions(&mut self) {
141 self.queue.push_back(UserInput::RevertInteraction(None));
142 }
143
144 pub(crate) fn dequeue(&mut self) -> Option<UserInput<Client>> {
145 self.queue.pop_front()
146 }
147}
148
149#[allow(
150 clippy::enum_variant_names,
151 reason = "Future variants will not involve interactions"
152)]
153#[derive_where(Debug; Client::Interaction)]
154pub(crate) enum UserInput<Client: super::ClientSSS> {
155 StageInteraction(Client::Interaction),
156 ApplyInteraction(Option<spru::interaction::Pending>),
157 RevertInteraction(Option<spru::interaction::Pending>),
158}
159
160#[derive(Debug, prelude::Component)]
161pub struct Item<T: Send + Sync + 'static>(spru::Item<T>);
162
163impl<T: Send + Sync + 'static> Item<T> {
164 pub(crate) fn new(item: spru::Item<T>) -> Self {
165 Self(item)
166 }
167
168 pub(crate) fn item(&self) -> &spru::Item<T> {
169 &self.0
170 }
171
172 pub(crate) fn item_mut(&mut self) -> &mut spru::Item<T> {
173 &mut self.0
174 }
175
176 pub(crate) fn into_inner(self) -> spru::Item<T> {
177 self.0
178 }
179}
180
181impl<T: Send + Sync + 'static> ops::Deref for Item<T> {
182 type Target = T;
183
184 fn deref(&self) -> &Self::Target {
185 self.item()
186 }
187}
188
189#[derive(Debug, Default, prelude::Component)]
190#[component(storage = "SparseSet")]
191pub struct EntityMap {
192 map: HashMap<item::Id, prelude::Entity>,
193}
194
195impl EntityMap {
196 pub fn get<ID: Into<item::Id>>(&self, id: ID) -> super::BevyResult<prelude::Entity> {
197 let id = id.into();
198 self.map
199 .get(&id)
200 .copied()
201 .ok_or(super::BevyError::IdNotFound(id))
202 }
203
204 pub(crate) fn insert_as(
205 &mut self,
206 id: item::Id,
207 f: impl FnOnce() -> super::BevyResult<prelude::Entity>,
208 ) -> super::BevyResult<prelude::Entity> {
209 match self.map.entry(id) {
210 hash_map::Entry::Occupied(oe) => Err(super::BevyError::IdAlreadyExists(id, *oe.get())),
211 hash_map::Entry::Vacant(ve) => {
212 let entity = f()?;
213 ve.insert(entity);
214 Ok(entity)
215 }
216 }
217 }
218
219 pub(crate) fn remove_as<T>(
220 &mut self,
221 id: item::Id,
222 f: impl FnOnce(prelude::Entity) -> super::BevyResult<T>,
223 ) -> super::BevyResult<T> {
224 match self.map.entry(id) {
225 hash_map::Entry::Occupied(oe) => {
226 let value = f(*oe.get())?;
227 oe.remove();
228 Ok(value)
229 }
230 hash_map::Entry::Vacant(_) => Err(super::BevyError::IdNotFound(id)),
231 }
232 }
233}
234
235impl<ID: Into<item::Id>> ops::Index<ID> for EntityMap {
236 type Output = prelude::Entity;
237
238 fn index(&self, index: ID) -> &Self::Output {
239 &self.map[&index.into()]
240 }
241}