Skip to main content

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}