rust/hedgewars-server/src/server/handlers/inroom.rs
changeset 15095 c5a6e8566425
parent 15094 7732013ce64c
child 15096 e935b1ad23f3
--- a/rust/hedgewars-server/src/server/handlers/inroom.rs	Tue May 28 17:49:04 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,615 +0,0 @@
-use mio;
-
-use super::common::rnd_reply;
-use crate::utils::to_engine_msg;
-use crate::{
-    protocol::messages::{
-        add_flags, remove_flags, server_chat, HWProtocolMessage, HWServerMessage::*,
-        ProtocolFlags as Flags,
-    },
-    server::{
-        core::HWServer,
-        coretypes,
-        coretypes::{ClientId, GameCfg, RoomId, VoteType, Voting, MAX_HEDGEHOGS_PER_TEAM},
-        room::{HWRoom, RoomFlags, MAX_TEAMS_IN_ROOM},
-    },
-    utils::is_name_illegal,
-};
-use base64::{decode, encode};
-use log::*;
-use std::{cmp::min, iter::once, mem::swap};
-
-#[derive(Clone)]
-struct ByMsg<'a> {
-    messages: &'a [u8],
-}
-
-impl<'a> Iterator for ByMsg<'a> {
-    type Item = &'a [u8];
-
-    fn next(&mut self) -> Option<<Self as Iterator>::Item> {
-        if let Some(size) = self.messages.get(0) {
-            let (msg, next) = self.messages.split_at(*size as usize + 1);
-            self.messages = next;
-            Some(msg)
-        } else {
-            None
-        }
-    }
-}
-
-fn by_msg(source: &[u8]) -> ByMsg {
-    ByMsg { messages: source }
-}
-
-const VALID_MESSAGES: &[u8] =
-    b"M#+LlRrUuDdZzAaSjJ,NpPwtgfhbc12345\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A";
-const NON_TIMED_MESSAGES: &[u8] = b"M#hb";
-
-#[cfg(canhazslicepatterns)]
-fn is_msg_valid(msg: &[u8], team_indices: &[u8]) -> bool {
-    match msg {
-        [size, typ, body..] => {
-            VALID_MESSAGES.contains(typ)
-                && match body {
-                    [1...MAX_HEDGEHOGS_PER_TEAM, team, ..] if *typ == b'h' => {
-                        team_indices.contains(team)
-                    }
-                    _ => *typ != b'h',
-                }
-        }
-        _ => false,
-    }
-}
-
-fn is_msg_valid(msg: &[u8], _team_indices: &[u8]) -> bool {
-    if let Some(typ) = msg.get(1) {
-        VALID_MESSAGES.contains(typ)
-    } else {
-        false
-    }
-}
-
-fn is_msg_empty(msg: &[u8]) -> bool {
-    msg.get(1).filter(|t| **t == b'+').is_some()
-}
-
-fn is_msg_timed(msg: &[u8]) -> bool {
-    msg.get(1)
-        .filter(|t| !NON_TIMED_MESSAGES.contains(t))
-        .is_some()
-}
-
-fn voting_description(kind: &VoteType) -> String {
-    format!(
-        "New voting started: {}",
-        match kind {
-            VoteType::Kick(nick) => format!("kick {}", nick),
-            VoteType::Map(name) => format!("map {}", name.as_ref().unwrap()),
-            VoteType::Pause => "pause".to_string(),
-            VoteType::NewSeed => "new seed".to_string(),
-            VoteType::HedgehogsPerTeam(number) => format!("hedgehogs per team: {}", number),
-        }
-    )
-}
-
-fn room_message_flag(msg: &HWProtocolMessage) -> RoomFlags {
-    use crate::protocol::messages::HWProtocolMessage::*;
-    match msg {
-        ToggleRestrictJoin => RoomFlags::RESTRICTED_JOIN,
-        ToggleRestrictTeams => RoomFlags::RESTRICTED_TEAM_ADD,
-        ToggleRegisteredOnly => RoomFlags::RESTRICTED_UNREGISTERED_PLAYERS,
-        _ => RoomFlags::empty(),
-    }
-}
-
-pub fn handle(
-    server: &mut HWServer,
-    client_id: ClientId,
-    response: &mut super::Response,
-    room_id: RoomId,
-    message: HWProtocolMessage,
-) {
-    let client = &mut server.clients[client_id];
-    let room = &mut server.rooms[room_id];
-
-    use crate::protocol::messages::HWProtocolMessage::*;
-    match message {
-        Part(msg) => {
-            let msg = match msg {
-                Some(s) => format!("part: {}", s),
-                None => "part".to_string(),
-            };
-            super::common::exit_room(server, client_id, response, &msg);
-        }
-        Chat(msg) => {
-            response.add(
-                ChatMsg {
-                    nick: client.nick.clone(),
-                    msg,
-                }
-                .send_all()
-                .in_room(room_id),
-            );
-        }
-        TeamChat(msg) => {
-            let room = &server.rooms[room_id];
-            if let Some(ref info) = room.game_info {
-                if let Some(clan_color) = room.find_team_color(client_id) {
-                    let client = &server.clients[client_id];
-                    let engine_msg =
-                        to_engine_msg(format!("b{}]{}\x20\x20", client.nick, msg).bytes());
-                    let team = room.clan_team_owners(clan_color).collect();
-                    response.add(ForwardEngineMessage(vec![engine_msg]).send_many(team))
-                }
-            }
-        }
-        Fix => {
-            if client.is_admin() {
-                room.set_is_fixed(true);
-                room.set_join_restriction(false);
-                room.set_team_add_restriction(false);
-                room.set_unregistered_players_restriction(true);
-            }
-        }
-        Unfix => {
-            if client.is_admin() {
-                room.set_is_fixed(false);
-            }
-        }
-        Greeting(text) => {
-            if client.is_admin() || client.is_master() && !room.is_fixed() {
-                room.greeting = text;
-            }
-        }
-        MaxTeams(count) => {
-            if !client.is_master() {
-                response.add(Warning("You're not the room master!".to_string()).send_self());
-            } else if !(2..=MAX_TEAMS_IN_ROOM).contains(&count) {
-                response
-                    .add(Warning("/maxteams: specify number from 2 to 8".to_string()).send_self());
-            } else {
-                server.rooms[room_id].max_teams = count;
-            }
-        }
-        RoomName(new_name) => {
-            if is_name_illegal(&new_name) {
-                response.add(Warning("Illegal room name! A room name must be between 1-40 characters long, must not have a trailing or leading space and must not have any of these characters: $()*+?[]^{|}".to_string()).send_self());
-            } else if server.has_room(&new_name) {
-                response.add(
-                    Warning("A room with the same name already exists.".to_string()).send_self(),
-                );
-            } else {
-                let room = &mut server.rooms[room_id];
-                if room.is_fixed() || room.master_id != Some(client_id) {
-                    response.add(Warning("Access denied.".to_string()).send_self());
-                } else {
-                    let mut old_name = new_name.clone();
-                    let client = &server.clients[client_id];
-                    swap(&mut room.name, &mut old_name);
-                    super::common::get_room_update(Some(old_name), room, Some(&client), response);
-                }
-            }
-        }
-        ToggleReady => {
-            let flags = if client.is_ready() {
-                room.ready_players_number -= 1;
-                remove_flags(&[Flags::Ready])
-            } else {
-                room.ready_players_number += 1;
-                add_flags(&[Flags::Ready])
-            };
-
-            let msg = if client.protocol_number < 38 {
-                LegacyReady(client.is_ready(), vec![client.nick.clone()])
-            } else {
-                ClientFlags(flags, vec![client.nick.clone()])
-            };
-            response.add(msg.send_all().in_room(room.id));
-            client.set_is_ready(!client.is_ready());
-
-            if room.is_fixed() && room.ready_players_number == room.players_number {
-                super::common::start_game(server, room_id, response);
-            }
-        }
-        AddTeam(mut info) => {
-            if room.teams.len() >= room.max_teams as usize {
-                response.add(Warning("Too many teams!".to_string()).send_self());
-            } else if room.addable_hedgehogs() == 0 {
-                response.add(Warning("Too many hedgehogs!".to_string()).send_self());
-            } else if room.find_team(|t| t.name == info.name) != None {
-                response.add(
-                    Warning("There's already a team with same name in the list.".to_string())
-                        .send_self(),
-                );
-            } else if room.game_info.is_some() {
-                response.add(
-                    Warning("Joining not possible: Round is in progress.".to_string()).send_self(),
-                );
-            } else if room.is_team_add_restricted() {
-                response.add(
-                    Warning("This room currently does not allow adding new teams.".to_string())
-                        .send_self(),
-                );
-            } else {
-                info.owner = client.nick.clone();
-                let team = room.add_team(client.id, *info, client.protocol_number < 42);
-                client.teams_in_game += 1;
-                client.clan = Some(team.color);
-                response.add(TeamAccepted(team.name.clone()).send_self());
-                response.add(
-                    TeamAdd(team.to_protocol())
-                        .send_all()
-                        .in_room(room_id)
-                        .but_self(),
-                );
-                response.add(
-                    TeamColor(team.name.clone(), team.color)
-                        .send_all()
-                        .in_room(room_id),
-                );
-                response.add(
-                    HedgehogsNumber(team.name.clone(), team.hedgehogs_number)
-                        .send_all()
-                        .in_room(room_id),
-                );
-
-                let room_master = if let Some(id) = room.master_id {
-                    Some(&server.clients[id])
-                } else {
-                    None
-                };
-                super::common::get_room_update(None, room, room_master, response);
-            }
-        }
-        RemoveTeam(name) => match room.find_team_owner(&name) {
-            None => response.add(
-                Warning("Error: The team you tried to remove does not exist.".to_string())
-                    .send_self(),
-            ),
-            Some((id, _)) if id != client_id => response
-                .add(Warning("You can't remove a team you don't own.".to_string()).send_self()),
-            Some((_, name)) => {
-                client.teams_in_game -= 1;
-                client.clan = room.find_team_color(client.id);
-                super::common::remove_teams(
-                    room,
-                    vec![name.to_string()],
-                    client.is_in_game(),
-                    response,
-                );
-
-                match room.game_info {
-                    Some(ref info) if info.teams_in_game == 0 => {
-                        super::common::end_game(server, room_id, response)
-                    }
-                    _ => (),
-                }
-            }
-        },
-        SetHedgehogsNumber(team_name, number) => {
-            let addable_hedgehogs = room.addable_hedgehogs();
-            if let Some((_, team)) = room.find_team_and_owner_mut(|t| t.name == team_name) {
-                let max_hedgehogs = min(
-                    MAX_HEDGEHOGS_PER_TEAM,
-                    addable_hedgehogs + team.hedgehogs_number,
-                );
-                if !client.is_master() {
-                    response.add(Error("You're not the room master!".to_string()).send_self());
-                } else if !(1..=max_hedgehogs).contains(&number) {
-                    response
-                        .add(HedgehogsNumber(team.name.clone(), team.hedgehogs_number).send_self());
-                } else {
-                    team.hedgehogs_number = number;
-                    response.add(
-                        HedgehogsNumber(team.name.clone(), number)
-                            .send_all()
-                            .in_room(room_id)
-                            .but_self(),
-                    );
-                }
-            } else {
-                response.add(Warning("No such team.".to_string()).send_self());
-            }
-        }
-        SetTeamColor(team_name, color) => {
-            if let Some((owner, team)) = room.find_team_and_owner_mut(|t| t.name == team_name) {
-                if !client.is_master() {
-                    response.add(Error("You're not the room master!".to_string()).send_self());
-                } else {
-                    team.color = color;
-                    response.add(
-                        TeamColor(team.name.clone(), color)
-                            .send_all()
-                            .in_room(room_id)
-                            .but_self(),
-                    );
-                    server.clients[owner].clan = Some(color);
-                }
-            } else {
-                response.add(Warning("No such team.".to_string()).send_self());
-            }
-        }
-        Cfg(cfg) => {
-            if room.is_fixed() {
-                response.add(Warning("Access denied.".to_string()).send_self());
-            } else if !client.is_master() {
-                response.add(Error("You're not the room master!".to_string()).send_self());
-            } else {
-                let cfg = match cfg {
-                    GameCfg::Scheme(name, mut values) => {
-                        if client.protocol_number == 49 && values.len() >= 2 {
-                            let mut s = "X".repeat(50);
-                            s.push_str(&values.pop().unwrap());
-                            values.push(s);
-                        }
-                        GameCfg::Scheme(name, values)
-                    }
-                    cfg => cfg,
-                };
-
-                response.add(cfg.to_server_msg().send_all().in_room(room.id).but_self());
-                room.set_config(cfg);
-            }
-        }
-        Save(name, location) => {
-            response.add(
-                server_chat(format!("Room config saved as {}", name))
-                    .send_all()
-                    .in_room(room_id),
-            );
-            room.save_config(name, location);
-        }
-        #[cfg(feature = "official-server")]
-        SaveRoom(filename) => {
-            if client.is_admin() {
-                match room.get_saves() {
-                    Ok(contents) => response.request_io(super::IoTask::SaveRoom {
-                        room_id,
-                        filename,
-                        contents,
-                    }),
-                    Err(e) => {
-                        warn!("Error while serializing the room configs: {}", e);
-                        response.add(
-                            Warning("Unable to serialize the room configs.".to_string())
-                                .send_self(),
-                        )
-                    }
-                }
-            }
-        }
-        #[cfg(feature = "official-server")]
-        LoadRoom(filename) => {
-            if client.is_admin() {
-                response.request_io(super::IoTask::LoadRoom { room_id, filename });
-            }
-        }
-        Delete(name) => {
-            if !room.delete_config(&name) {
-                response.add(Warning(format!("Save doesn't exist: {}", name)).send_self());
-            } else {
-                response.add(
-                    server_chat(format!("Room config {} has been deleted", name))
-                        .send_all()
-                        .in_room(room_id),
-                );
-            }
-        }
-        CallVote(None) => {
-            response.add(server_chat("Available callvote commands: kick <nickname>, map <name>, pause, newseed, hedgehogs <number>".to_string())
-                .send_self());
-        }
-        CallVote(Some(kind)) => {
-            let is_in_game = room.game_info.is_some();
-            let error = match &kind {
-                VoteType::Kick(nick) => {
-                    if server
-                        .find_client(&nick)
-                        .filter(|c| c.room_id == Some(room_id))
-                        .is_some()
-                    {
-                        None
-                    } else {
-                        Some("/callvote kick: No such user!".to_string())
-                    }
-                }
-                VoteType::Map(None) => {
-                    let names: Vec<_> = server.rooms[room_id].saves.keys().cloned().collect();
-                    if names.is_empty() {
-                        Some("/callvote map: No maps saved in this room!".to_string())
-                    } else {
-                        Some(format!("Available maps: {}", names.join(", ")))
-                    }
-                }
-                VoteType::Map(Some(name)) => {
-                    if room.saves.get(&name[..]).is_some() {
-                        None
-                    } else {
-                        Some("/callvote map: No such map!".to_string())
-                    }
-                }
-                VoteType::Pause => {
-                    if is_in_game {
-                        None
-                    } else {
-                        Some("/callvote pause: No game in progress!".to_string())
-                    }
-                }
-                VoteType::NewSeed => None,
-                VoteType::HedgehogsPerTeam(number) => match number {
-                    1...MAX_HEDGEHOGS_PER_TEAM => None,
-                    _ => Some("/callvote hedgehogs: Specify number from 1 to 8.".to_string()),
-                },
-            };
-
-            match error {
-                None => {
-                    let msg = voting_description(&kind);
-                    let voting = Voting::new(kind, server.room_clients(client_id).collect());
-                    let room = &mut server.rooms[room_id];
-                    room.voting = Some(voting);
-                    response.add(server_chat(msg).send_all().in_room(room_id));
-                    super::common::submit_vote(
-                        server,
-                        coretypes::Vote {
-                            is_pro: true,
-                            is_forced: false,
-                        },
-                        response,
-                    );
-                }
-                Some(msg) => {
-                    response.add(server_chat(msg).send_self());
-                }
-            }
-        }
-        Vote(vote) => {
-            super::common::submit_vote(
-                server,
-                coretypes::Vote {
-                    is_pro: vote,
-                    is_forced: false,
-                },
-                response,
-            );
-        }
-        ForceVote(vote) => {
-            let is_forced = client.is_admin();
-            super::common::submit_vote(
-                server,
-                coretypes::Vote {
-                    is_pro: vote,
-                    is_forced,
-                },
-                response,
-            );
-        }
-        ToggleRestrictJoin | ToggleRestrictTeams | ToggleRegisteredOnly => {
-            if client.is_master() {
-                room.flags.toggle(room_message_flag(&message));
-                super::common::get_room_update(None, room, Some(&client), response);
-            }
-        }
-        StartGame => {
-            super::common::start_game(server, room_id, response);
-        }
-        EngineMessage(em) => {
-            if client.teams_in_game > 0 {
-                let decoding = decode(&em[..]).unwrap();
-                let messages = by_msg(&decoding);
-                let valid = messages.filter(|m| is_msg_valid(m, &client.team_indices));
-                let non_empty = valid.clone().filter(|m| !is_msg_empty(m));
-                let sync_msg = valid.clone().filter(|m| is_msg_timed(m)).last().map(|m| {
-                    if is_msg_empty(m) {
-                        Some(encode(m))
-                    } else {
-                        None
-                    }
-                });
-
-                let em_response = encode(&valid.flat_map(|msg| msg).cloned().collect::<Vec<_>>());
-                if !em_response.is_empty() {
-                    response.add(
-                        ForwardEngineMessage(vec![em_response])
-                            .send_all()
-                            .in_room(room.id)
-                            .but_self(),
-                    );
-                }
-                let em_log = encode(&non_empty.flat_map(|msg| msg).cloned().collect::<Vec<_>>());
-                if let Some(ref mut info) = room.game_info {
-                    if !em_log.is_empty() {
-                        info.msg_log.push(em_log);
-                    }
-                    if let Some(msg) = sync_msg {
-                        info.sync_msg = msg;
-                    }
-                }
-            }
-        }
-        RoundFinished => {
-            let mut game_ended = false;
-            if client.is_in_game() {
-                client.set_is_in_game(false);
-                response.add(
-                    ClientFlags(remove_flags(&[Flags::InGame]), vec![client.nick.clone()])
-                        .send_all()
-                        .in_room(room.id),
-                );
-                let team_names: Vec<_> = room
-                    .client_teams(client_id)
-                    .map(|t| t.name.clone())
-                    .collect();
-
-                if let Some(ref mut info) = room.game_info {
-                    info.teams_in_game -= team_names.len() as u8;
-                    if info.teams_in_game == 0 {
-                        game_ended = true;
-                    }
-
-                    for team_name in team_names {
-                        let msg = once(b'F').chain(team_name.bytes());
-                        response.add(
-                            ForwardEngineMessage(vec![to_engine_msg(msg)])
-                                .send_all()
-                                .in_room(room_id)
-                                .but_self(),
-                        );
-
-                        let remove_msg = to_engine_msg(once(b'F').chain(team_name.bytes()));
-                        if let Some(m) = &info.sync_msg {
-                            info.msg_log.push(m.clone());
-                        }
-                        if info.sync_msg.is_some() {
-                            info.sync_msg = None
-                        }
-                        info.msg_log.push(remove_msg.clone());
-                        response.add(
-                            ForwardEngineMessage(vec![remove_msg])
-                                .send_all()
-                                .in_room(room_id)
-                                .but_self(),
-                        );
-                    }
-                }
-            }
-            if game_ended {
-                super::common::end_game(server, room_id, response)
-            }
-        }
-        Rnd(v) => {
-            let result = rnd_reply(&v);
-            let mut echo = vec!["/rnd".to_string()];
-            echo.extend(v.into_iter());
-            let chat_msg = ChatMsg {
-                nick: server.clients[client_id].nick.clone(),
-                msg: echo.join(" "),
-            };
-            response.add(chat_msg.send_all().in_room(room_id));
-            response.add(result.send_all().in_room(room_id));
-        }
-        Delegate(nick) => {
-            let delegate_id = server.find_client(&nick).map(|c| (c.id, c.room_id));
-            let client = &server.clients[client_id];
-            if !(client.is_admin() || client.is_master()) {
-                response.add(
-                    Warning("You're not the room master or a server admin!".to_string())
-                        .send_self(),
-                )
-            } else {
-                match delegate_id {
-                    None => response.add(Warning("Player is not online.".to_string()).send_self()),
-                    Some((id, _)) if id == client_id => response
-                        .add(Warning("You're already the room master.".to_string()).send_self()),
-                    Some((_, id)) if id != Some(room_id) => response
-                        .add(Warning("The player is not in your room.".to_string()).send_self()),
-                    Some((id, _)) => {
-                        super::common::change_master(server, room_id, id, response);
-                    }
-                }
-            }
-        }
-        _ => warn!("Unimplemented!"),
-    }
-}