veloren_server/events/group_manip.rs
1use crate::client::Client;
2use common::{
3 comp::{
4 self, ChatType, Content, GroupManip,
5 group::{ChangeNotification, Group, GroupManager},
6 invite::{InviteKind, PendingInvites},
7 },
8 event::GroupManipEvent,
9 uid::{IdMaps, Uid},
10};
11use common_net::msg::ServerGeneral;
12use specs::{DispatcherBuilder, Entities, Read, ReadStorage, Write, WriteStorage, world::Entity};
13
14use super::{ServerEvent, event_dispatch};
15
16pub(super) fn register_event_systems(builder: &mut DispatcherBuilder) {
17 event_dispatch::<GroupManipEvent>(builder, &[]);
18}
19
20pub fn can_invite(
21 clients: &ReadStorage<'_, Client>,
22 groups: &ReadStorage<'_, Group>,
23 group_manager: &GroupManager,
24 pending_invites: &mut WriteStorage<'_, PendingInvites>,
25 max_group_size: u32,
26 inviter: Entity,
27 invitee: Entity,
28) -> bool {
29 // Disallow inviting entity that is already in your group
30 let already_in_same_group = groups.get(inviter).is_some_and(|group| {
31 group_manager
32 .group_info(*group)
33 .is_some_and(|g| g.leader == inviter)
34 && groups.get(invitee) == Some(group)
35 });
36 if already_in_same_group {
37 // Inform of failure
38 if let Some(client) = clients.get(inviter) {
39 client.send_fallible(ServerGeneral::server_msg(
40 ChatType::Meta,
41 Content::Plain(
42 "Invite failed, can't invite someone already in your group".to_string(),
43 ),
44 ));
45 }
46 return false;
47 }
48
49 // Check if group max size is already reached
50 // Adding the current number of pending invites
51 let group_size_limit_reached = groups
52 .get(inviter)
53 .copied()
54 .and_then(|group| {
55 // If entity is currently the leader of a full group then they can't invite
56 // anyone else
57 group_manager
58 .group_info(group)
59 .filter(|i| i.leader == inviter)
60 .map(|i| i.num_members)
61 })
62 .unwrap_or(1) as usize
63 + pending_invites.get(inviter).map_or(0, |p| {
64 p.0.iter()
65 .filter(|(_, k, _)| *k == InviteKind::Group)
66 .count()
67 })
68 >= max_group_size as usize;
69 if group_size_limit_reached {
70 // Inform inviter that they have reached the group size limit
71 if let Some(client) = clients.get(inviter) {
72 client.send_fallible(ServerGeneral::server_msg(
73 ChatType::Meta,
74 Content::Plain(
75 "Invite failed, pending invites plus current group size have reached the \
76 group size limit"
77 .to_owned(),
78 ),
79 ));
80 }
81 return false;
82 }
83
84 true
85}
86
87pub fn update_map_markers<'a>(
88 map_markers: &ReadStorage<'a, comp::MapMarker>,
89 uids: &ReadStorage<'a, Uid>,
90 client: &Client,
91 change: &ChangeNotification<Entity>,
92) {
93 use comp::group::ChangeNotification::*;
94 let send_update = |entity| {
95 if let (Some(map_marker), Some(uid)) = (map_markers.get(entity), uids.get(entity)) {
96 client.send_fallible(ServerGeneral::MapMarker(
97 comp::MapMarkerUpdate::GroupMember(
98 *uid,
99 comp::MapMarkerChange::Update(map_marker.0),
100 ),
101 ));
102 }
103 };
104 match change {
105 &Added(entity, _) => {
106 send_update(entity);
107 },
108 NewGroup { leader: _, members } => {
109 for (entity, _) in members {
110 send_update(*entity);
111 }
112 },
113 // Removed and NoGroup can be inferred by the client, NewLeader does not affect map markers
114 Removed(_) | NoGroup | NewLeader(_) => {},
115 }
116}
117
118impl ServerEvent for GroupManipEvent {
119 type SystemData<'a> = (
120 Entities<'a>,
121 Write<'a, GroupManager>,
122 Read<'a, IdMaps>,
123 WriteStorage<'a, Group>,
124 ReadStorage<'a, Client>,
125 ReadStorage<'a, Uid>,
126 ReadStorage<'a, comp::Alignment>,
127 ReadStorage<'a, comp::MapMarker>,
128 );
129
130 fn handle(
131 events: impl ExactSizeIterator<Item = Self>,
132 (entities, mut group_manager, id_maps, mut groups, clients, uids, alignments, map_markers): Self::SystemData<'_>,
133 ) {
134 for GroupManipEvent(entity, manip) in events {
135 match manip {
136 GroupManip::Leave => {
137 group_manager.leave_group(
138 entity,
139 &mut groups,
140 &alignments,
141 &uids,
142 &entities,
143 &mut |entity, group_change| {
144 group_change
145 .try_map_ref(|e| uids.get(*e).copied())
146 .zip(clients.get(entity))
147 .map(|(g, c)| {
148 update_map_markers(&map_markers, &uids, c, &group_change);
149 c.send_fallible(ServerGeneral::GroupUpdate(g));
150 });
151 },
152 );
153 },
154 GroupManip::Kick(uid) => {
155 let target = match id_maps.uid_entity(uid) {
156 Some(t) => t,
157 None => {
158 // Inform of failure
159 if let Some(client) = clients.get(entity) {
160 client.send_fallible(ServerGeneral::server_msg(
161 ChatType::Meta,
162 Content::Plain(
163 "Kick failed, target does not exist.".to_string(),
164 ),
165 ));
166 }
167 continue;
168 },
169 };
170
171 // Can't kick pet
172 if matches!(alignments.get(target), Some(comp::Alignment::Owned(owner)) if uids.get(target) != Some(owner))
173 {
174 if let Some(general_stream) = clients.get(entity) {
175 general_stream.send_fallible(ServerGeneral::server_msg(
176 ChatType::Meta,
177 Content::Plain("Kick failed, you can't kick pets.".to_string()),
178 ));
179 }
180 continue;
181 }
182 // Can't kick yourself
183 if uids.get(entity).is_some_and(|u| *u == uid) {
184 if let Some(client) = clients.get(entity) {
185 client.send_fallible(ServerGeneral::server_msg(
186 ChatType::Meta,
187 Content::Plain("Kick failed, you can't kick yourself.".to_string()),
188 ));
189 }
190 continue;
191 }
192
193 // Make sure kicker is the group leader
194 match groups
195 .get(target)
196 .and_then(|group| group_manager.group_info(*group))
197 {
198 Some(info) if info.leader == entity => {
199 // Remove target from group
200 group_manager.leave_group(
201 target,
202 &mut groups,
203 &alignments,
204 &uids,
205 &entities,
206 &mut |entity, group_change| {
207 group_change
208 .try_map_ref(|e| uids.get(*e).copied())
209 .zip(clients.get(entity))
210 .map(|(g, c)| {
211 update_map_markers(
212 &map_markers,
213 &uids,
214 c,
215 &group_change,
216 );
217 c.send_fallible(ServerGeneral::GroupUpdate(g));
218 });
219 },
220 );
221
222 // Tell them the have been kicked
223 if let Some(client) = clients.get(target) {
224 client.send_fallible(ServerGeneral::server_msg(
225 ChatType::Meta,
226 Content::Plain("You were removed from the group.".to_string()),
227 ));
228 }
229 // Tell kicker that they were successful
230 if let Some(client) = clients.get(entity) {
231 client.send_fallible(ServerGeneral::server_msg(
232 ChatType::Meta,
233 Content::Plain("Player kicked.".to_string()),
234 ));
235 }
236 },
237 Some(_) => {
238 // Inform kicker that they are not the leader
239 if let Some(client) = clients.get(entity) {
240 client.send_fallible(ServerGeneral::server_msg(
241 ChatType::Meta,
242 Content::Plain(
243 "Kick failed: You are not the leader of the target's \
244 group."
245 .to_string(),
246 ),
247 ));
248 }
249 },
250 None => {
251 // Inform kicker that the target is not in a group
252 if let Some(client) = clients.get(entity) {
253 client.send_fallible(ServerGeneral::server_msg(
254 ChatType::Meta,
255 Content::Plain(
256 "Kick failed: Your target is not in a group.".to_string(),
257 ),
258 ));
259 }
260 },
261 }
262 },
263 GroupManip::AssignLeader(uid) => {
264 let target = match id_maps.uid_entity(uid) {
265 Some(t) => t,
266 None => {
267 // Inform of failure
268 if let Some(client) = clients.get(entity) {
269 client.send_fallible(ServerGeneral::server_msg(
270 ChatType::Meta,
271 Content::Plain(
272 "Leadership transfer failed, target does not exist"
273 .to_string(),
274 ),
275 ));
276 }
277 continue;
278 },
279 };
280 // Make sure assigner is the group leader
281 match groups
282 .get(target)
283 .and_then(|group| group_manager.group_info(*group))
284 {
285 Some(info) if info.leader == entity => {
286 // Assign target as group leader
287 group_manager.assign_leader(
288 target,
289 &groups,
290 &entities,
291 &alignments,
292 &uids,
293 |entity, group_change| {
294 group_change
295 .try_map_ref(|e| uids.get(*e).copied())
296 .zip(clients.get(entity))
297 .map(|(g, c)| {
298 update_map_markers(
299 &map_markers,
300 &uids,
301 c,
302 &group_change,
303 );
304 c.send_fallible(ServerGeneral::GroupUpdate(g));
305 });
306 },
307 );
308 // Tell them they are the leader
309 if let Some(client) = clients.get(target) {
310 client.send_fallible(ServerGeneral::server_msg(
311 ChatType::Meta,
312 Content::Plain("You are the group leader now.".to_string()),
313 ));
314 }
315 // Tell the old leader that the transfer was succesful
316 if let Some(client) = clients.get(entity) {
317 client.send_fallible(ServerGeneral::server_msg(
318 ChatType::Meta,
319 Content::Plain(
320 "You are no longer the group leader.".to_string(),
321 ),
322 ));
323 }
324 },
325 Some(_) => {
326 // Inform transferer that they are not the leader
327 if let Some(client) = clients.get(entity) {
328 client.send_fallible(ServerGeneral::server_msg(
329 ChatType::Meta,
330 Content::Plain(
331 "Transfer failed: You are not the leader of the target's \
332 group."
333 .to_string(),
334 ),
335 ));
336 }
337 },
338 None => {
339 // Inform transferer that the target is not in a group
340 if let Some(client) = clients.get(entity) {
341 client.send_fallible(ServerGeneral::server_msg(
342 ChatType::Meta,
343 Content::Plain(
344 "Transfer failed: Your target is not in a group."
345 .to_string(),
346 ),
347 ));
348 }
349 },
350 }
351 },
352 }
353 }
354 }
355}