use crate::{client::Client, Server}; use common::{ comp::{ self, group::{self, Group, GroupManager}, invite::{InviteKind, PendingInvites}, ChatType, GroupManip, }, uid::Uid, }; use common_net::{msg::ServerGeneral, sync::WorldSyncExt}; use common_sys::state::State; use specs::{ world::{Entity, WorldExt}, ReadStorage, WriteStorage, }; pub fn can_invite( state: &State, clients: &ReadStorage<'_, Client>, pending_invites: &mut WriteStorage<'_, PendingInvites>, max_group_size: u32, inviter: Entity, invitee: Entity, ) -> bool { // Disallow inviting entity that is already in your group let groups = state.ecs().read_storage::(); let group_manager = state.ecs().read_resource::(); let already_in_same_group = groups.get(inviter).map_or(false, |group| { group_manager .group_info(*group) .map_or(false, |g| g.leader == inviter) && groups.get(invitee) == Some(group) }); if already_in_same_group { // Inform of failure if let Some(client) = clients.get(inviter) { client.send_fallible(ServerGeneral::server_msg( ChatType::Meta, "Invite failed, can't invite someone already in your group", )); } return false; } // Check if group max size is already reached // Adding the current number of pending invites let group_size_limit_reached = state .ecs() .read_storage() .get(inviter) .copied() .and_then(|group| { // If entity is currently the leader of a full group then they can't invite // anyone else group_manager .group_info(group) .filter(|i| i.leader == inviter) .map(|i| i.num_members) }) .unwrap_or(1) as usize + pending_invites.get(inviter).map_or(0, |p| { p.0.iter() .filter(|(_, k, _)| *k == InviteKind::Group) .count() }) >= max_group_size as usize; if group_size_limit_reached { // Inform inviter that they have reached the group size limit if let Some(client) = clients.get(inviter) { client.send_fallible(ServerGeneral::server_msg( ChatType::Meta, "Invite failed, pending invites plus current group size have reached the group \ size limit" .to_owned(), )); } return false; } true } // TODO: turn chat messages into enums pub fn handle_group(server: &mut Server, entity: specs::Entity, manip: GroupManip) { match manip { GroupManip::Leave => { let state = server.state_mut(); let clients = state.ecs().read_storage::(); let uids = state.ecs().read_storage::(); let mut group_manager = state.ecs().write_resource::(); group_manager.leave_group( entity, &mut state.ecs().write_storage(), &state.ecs().read_storage(), &uids, &state.ecs().entities(), &mut |entity, group_change| { clients .get(entity) .and_then(|c| { group_change .try_map(|e| uids.get(e).copied()) .map(|g| (g, c)) }) .map(|(g, c)| c.send(ServerGeneral::GroupUpdate(g))); }, ); }, GroupManip::Kick(uid) => { let state = server.state_mut(); let clients = state.ecs().read_storage::(); let uids = state.ecs().read_storage::(); let alignments = state.ecs().read_storage::(); let target = match state.ecs().entity_from_uid(uid.into()) { Some(t) => t, None => { // Inform of failure if let Some(client) = clients.get(entity) { client.send_fallible(ServerGeneral::server_msg( ChatType::Meta, "Kick failed, target does not exist.", )); } return; }, }; // Can't kick pet if matches!(alignments.get(target), Some(comp::Alignment::Owned(owner)) if uids.get(target).map_or(true, |u| u != owner)) { if let Some(general_stream) = clients.get(entity) { general_stream.send_fallible(ServerGeneral::server_msg( ChatType::Meta, "Kick failed, you can't kick pets.", )); } return; } // Can't kick yourself if uids.get(entity).map_or(false, |u| *u == uid) { if let Some(client) = clients.get(entity) { client.send_fallible(ServerGeneral::server_msg( ChatType::Meta, "Kick failed, you can't kick yourself.", )); } return; } let mut groups = state.ecs().write_storage::(); let mut group_manager = state.ecs().write_resource::(); // Make sure kicker is the group leader match groups .get(target) .and_then(|group| group_manager.group_info(*group)) { Some(info) if info.leader == entity => { // Remove target from group group_manager.leave_group( target, &mut groups, &state.ecs().read_storage(), &uids, &state.ecs().entities(), &mut |entity, group_change| { clients .get(entity) .and_then(|c| { group_change .try_map(|e| uids.get(e).copied()) .map(|g| (g, c)) }) .map(|(g, c)| c.send(ServerGeneral::GroupUpdate(g))); }, ); // Tell them the have been kicked if let Some(client) = clients.get(target) { client.send_fallible(ServerGeneral::server_msg( ChatType::Meta, "You were removed from the group.", )); } // Tell kicker that they were succesful if let Some(client) = clients.get(entity) { client.send_fallible(ServerGeneral::server_msg( ChatType::Meta, "Player kicked.", )); } }, Some(_) => { // Inform kicker that they are not the leader if let Some(client) = clients.get(entity) { client.send_fallible(ServerGeneral::server_msg( ChatType::Meta, "Kick failed: You are not the leader of the target's group.", )); } }, None => { // Inform kicker that the target is not in a group if let Some(client) = clients.get(entity) { client.send_fallible(ServerGeneral::server_msg( ChatType::Meta, "Kick failed: Your target is not in a group.", )); } }, } }, GroupManip::AssignLeader(uid) => { let state = server.state_mut(); let clients = state.ecs().read_storage::(); let uids = state.ecs().read_storage::(); let target = match state.ecs().entity_from_uid(uid.into()) { Some(t) => t, None => { // Inform of failure if let Some(client) = clients.get(entity) { client.send_fallible(ServerGeneral::server_msg( ChatType::Meta, "Leadership transfer failed, target does not exist", )); } return; }, }; let groups = state.ecs().read_storage::(); let mut group_manager = state.ecs().write_resource::(); // Make sure assigner is the group leader match groups .get(target) .and_then(|group| group_manager.group_info(*group)) { Some(info) if info.leader == entity => { // Assign target as group leader group_manager.assign_leader( target, &groups, &state.ecs().entities(), &state.ecs().read_storage(), &uids, |entity, group_change| { clients .get(entity) .and_then(|c| { group_change .try_map(|e| uids.get(e).copied()) .map(|g| (g, c)) }) .map(|(g, c)| c.send(ServerGeneral::GroupUpdate(g))); }, ); // Tell them they are the leader if let Some(client) = clients.get(target) { client.send_fallible(ServerGeneral::server_msg( ChatType::Meta, "You are the group leader now.", )); } // Tell the old leader that the transfer was succesful if let Some(client) = clients.get(target) { client.send_fallible(ServerGeneral::server_msg( ChatType::Meta, "You are no longer the group leader.", )); } }, Some(_) => { // Inform transferer that they are not the leader if let Some(client) = clients.get(entity) { client.send_fallible(ServerGeneral::server_msg( ChatType::Meta, "Transfer failed: You are not the leader of the target's group.", )); } }, None => { // Inform transferer that the target is not in a group if let Some(client) = clients.get(entity) { client.send_fallible(ServerGeneral::server_msg( ChatType::Meta, "Transfer failed: Your target is not in a group.", )); } }, } }, } }