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 clients
145 .get(entity)
146 .and_then(|c| {
147 group_change
148 .try_map_ref(|e| uids.get(*e).copied())
149 .map(|g| (g, c))
150 })
151 .map(|(g, c)| {
152 update_map_markers(&map_markers, &uids, c, &group_change);
153 c.send_fallible(ServerGeneral::GroupUpdate(g));
154 });
155 },
156 );
157 },
158 GroupManip::Kick(uid) => {
159 let target = match id_maps.uid_entity(uid) {
160 Some(t) => t,
161 None => {
162 // Inform of failure
163 if let Some(client) = clients.get(entity) {
164 client.send_fallible(ServerGeneral::server_msg(
165 ChatType::Meta,
166 Content::Plain(
167 "Kick failed, target does not exist.".to_string(),
168 ),
169 ));
170 }
171 continue;
172 },
173 };
174
175 // Can't kick pet
176 if matches!(alignments.get(target), Some(comp::Alignment::Owned(owner)) if uids.get(target) != Some(owner))
177 {
178 if let Some(general_stream) = clients.get(entity) {
179 general_stream.send_fallible(ServerGeneral::server_msg(
180 ChatType::Meta,
181 Content::Plain("Kick failed, you can't kick pets.".to_string()),
182 ));
183 }
184 continue;
185 }
186 // Can't kick yourself
187 if uids.get(entity).is_some_and(|u| *u == uid) {
188 if let Some(client) = clients.get(entity) {
189 client.send_fallible(ServerGeneral::server_msg(
190 ChatType::Meta,
191 Content::Plain("Kick failed, you can't kick yourself.".to_string()),
192 ));
193 }
194 continue;
195 }
196
197 // Make sure kicker is the group leader
198 match groups
199 .get(target)
200 .and_then(|group| group_manager.group_info(*group))
201 {
202 Some(info) if info.leader == entity => {
203 // Remove target from group
204 group_manager.leave_group(
205 target,
206 &mut groups,
207 &alignments,
208 &uids,
209 &entities,
210 &mut |entity, group_change| {
211 clients
212 .get(entity)
213 .and_then(|c| {
214 group_change
215 .try_map_ref(|e| uids.get(*e).copied())
216 .map(|g| (g, c))
217 })
218 .map(|(g, c)| {
219 update_map_markers(
220 &map_markers,
221 &uids,
222 c,
223 &group_change,
224 );
225 c.send_fallible(ServerGeneral::GroupUpdate(g));
226 });
227 },
228 );
229
230 // Tell them the have been kicked
231 if let Some(client) = clients.get(target) {
232 client.send_fallible(ServerGeneral::server_msg(
233 ChatType::Meta,
234 Content::Plain("You were removed from the group.".to_string()),
235 ));
236 }
237 // Tell kicker that they were successful
238 if let Some(client) = clients.get(entity) {
239 client.send_fallible(ServerGeneral::server_msg(
240 ChatType::Meta,
241 Content::Plain("Player kicked.".to_string()),
242 ));
243 }
244 },
245 Some(_) => {
246 // Inform kicker that they are not the leader
247 if let Some(client) = clients.get(entity) {
248 client.send_fallible(ServerGeneral::server_msg(
249 ChatType::Meta,
250 Content::Plain(
251 "Kick failed: You are not the leader of the target's \
252 group."
253 .to_string(),
254 ),
255 ));
256 }
257 },
258 None => {
259 // Inform kicker that the target is not in a group
260 if let Some(client) = clients.get(entity) {
261 client.send_fallible(ServerGeneral::server_msg(
262 ChatType::Meta,
263 Content::Plain(
264 "Kick failed: Your target is not in a group.".to_string(),
265 ),
266 ));
267 }
268 },
269 }
270 },
271 GroupManip::AssignLeader(uid) => {
272 let target = match id_maps.uid_entity(uid) {
273 Some(t) => t,
274 None => {
275 // Inform of failure
276 if let Some(client) = clients.get(entity) {
277 client.send_fallible(ServerGeneral::server_msg(
278 ChatType::Meta,
279 Content::Plain(
280 "Leadership transfer failed, target does not exist"
281 .to_string(),
282 ),
283 ));
284 }
285 continue;
286 },
287 };
288 // Make sure assigner is the group leader
289 match groups
290 .get(target)
291 .and_then(|group| group_manager.group_info(*group))
292 {
293 Some(info) if info.leader == entity => {
294 // Assign target as group leader
295 group_manager.assign_leader(
296 target,
297 &groups,
298 &entities,
299 &alignments,
300 &uids,
301 |entity, group_change| {
302 clients
303 .get(entity)
304 .and_then(|c| {
305 group_change
306 .try_map_ref(|e| uids.get(*e).copied())
307 .map(|g| (g, c))
308 })
309 .map(|(g, c)| {
310 update_map_markers(
311 &map_markers,
312 &uids,
313 c,
314 &group_change,
315 );
316 c.send_fallible(ServerGeneral::GroupUpdate(g));
317 });
318 },
319 );
320 // Tell them they are the leader
321 if let Some(client) = clients.get(target) {
322 client.send_fallible(ServerGeneral::server_msg(
323 ChatType::Meta,
324 Content::Plain("You are the group leader now.".to_string()),
325 ));
326 }
327 // Tell the old leader that the transfer was succesful
328 if let Some(client) = clients.get(entity) {
329 client.send_fallible(ServerGeneral::server_msg(
330 ChatType::Meta,
331 Content::Plain(
332 "You are no longer the group leader.".to_string(),
333 ),
334 ));
335 }
336 },
337 Some(_) => {
338 // Inform transferer that they are not the leader
339 if let Some(client) = clients.get(entity) {
340 client.send_fallible(ServerGeneral::server_msg(
341 ChatType::Meta,
342 Content::Plain(
343 "Transfer failed: You are not the leader of the target's \
344 group."
345 .to_string(),
346 ),
347 ));
348 }
349 },
350 None => {
351 // Inform transferer that the target is not in a group
352 if let Some(client) = clients.get(entity) {
353 client.send_fallible(ServerGeneral::server_msg(
354 ChatType::Meta,
355 Content::Plain(
356 "Transfer failed: Your target is not in a group."
357 .to_string(),
358 ),
359 ));
360 }
361 },
362 }
363 },
364 }
365 }
366 }
367}