Example #1
0
        public static bool ValidateCommand(S server, Connection conn, Session.Client client, string cmd)
        {
            if (server.GameStarted)
            {
                server.SendChatTo(conn, "Cannot change state when game started. ({0})".F(cmd));
                return false;
            }
            else if (client.State == Session.ClientState.Ready && !(cmd == "ready" || cmd == "startgame"))
            {
                server.SendChatTo(conn, "Cannot change state when marked as ready.");
                return false;
            }

            return true;
        }
Example #2
0
        public static bool ValidateCommand(S server, Connection conn, Session.Client client, string cmd)
        {
            if (server.GameStarted)
            {
                server.SendChatTo(conn, "Cannot change state when game started. ({0})".F(cmd));
                return(false);
            }
            else if (client.State == Session.ClientState.Ready && !(cmd == "ready" || cmd == "startgame"))
            {
                server.SendChatTo(conn, "Cannot change state when marked as ready.");
                return(false);
            }

            return(true);
        }
Example #3
0
        static bool ValidateSlotCommand(S server, Connection conn, Session.Client client, string arg, bool requiresHost)
        {
            if (!server.lobbyInfo.Slots.ContainsKey(arg))
            {
                Log.Write("server", "Invalid slot: {0}", arg);
                return(false);
            }

            if (requiresHost && !client.IsAdmin)
            {
                server.SendChatTo(conn, "Only the host can do that");
                return(false);
            }

            return(true);
        }
Example #4
0
        public bool InterpretCommand( S server, Connection conn, Session.Client client, string cmd)
        {
            if (server.GameStarted)
            {
                server.SendChatTo(conn, "Cannot change state when game started. ({0})".F(cmd));
                return false;
            }
            else if (client.State == Session.ClientState.Ready && !(cmd == "ready" || cmd == "startgame"))
            {
                server.SendChatTo(conn, "Cannot change state when marked as ready.");
                return false;
            }

            var dict = new Dictionary<string, Func<string, bool>>
            {
                { "name",
                    s =>
                    {
                        Log.Write("server", "Player@{0} is now known as {1}", conn.socket.RemoteEndPoint, s);
                        client.Name = s;
                        server.SyncLobbyInfo();
                        return true;
                    }},
                { "race",
                    s =>
                    {
                        client.Country = s;
                        server.SyncLobbyInfo();
                        return true;
                    }},
                { "team",
                    s =>
                    {
                        int team;
                        if (!int.TryParse(s, out team)) { Log.Write("server", "Invalid team: {0}", s ); return false; }

                        client.Team = team;
                        server.SyncLobbyInfo();
                        return true;
                    }},
                { "spawn",
                    s =>
                    {
                        int spawnPoint;
                        if (!int.TryParse(s, out spawnPoint) || spawnPoint < 0 || spawnPoint > server.Map.SpawnPoints.Count())
                        {
                            Log.Write("server", "Invalid spawn point: {0}", s);
                            return false;
                        }

                        if (server.lobbyInfo.Slots[client.Slot].Spectator)
                        {
                            server.SendChatTo( conn, "Can't select a spawnpoint as a spectator" );
                            return false;
                        }

                        if (server.lobbyInfo.Clients.Where( c => c != client ).Any( c => (c.SpawnPoint == spawnPoint) && (c.SpawnPoint != 0) ))
                        {
                            server.SendChatTo( conn, "You can't be at the same spawn point as another player" );
                            return true;
                        }

                        client.SpawnPoint = spawnPoint;
                        server.SyncLobbyInfo();
                        return true;
                    }},
                { "color",
                    s =>
                    {
                        var c = s.Split(',').Select(cc => int.Parse(cc)).ToArray();
                        client.ColorRamp = new ColorRamp((byte)c[0], (byte)c[1], (byte)c[2], (byte)c[3]);
                        server.SyncLobbyInfo();
                        return true;
                    }}
            };

            var cmdName = cmd.Split(' ').First();
            var cmdValue = string.Join(" ", cmd.Split(' ').Skip(1).ToArray());

            Func<string,bool> a;
            if (!dict.TryGetValue(cmdName, out a))
                return false;

            return a(cmdValue);
        }
Example #5
0
        public bool InterpretCommand(S server, Connection conn, Session.Client client, string cmd)
        {
            if (server.GameStarted)
            {
                server.SendChatTo(conn, "Cannot change state when game started. ({0})".F(cmd));
                return false;
            }
            else if (client.State == Session.ClientState.Ready && !(cmd == "ready" || cmd == "startgame"))
            {
                server.SendChatTo(conn, "Cannot change state when marked as ready.");
                return false;
            }

            var dict = new Dictionary<string, Func<string, bool>>
            {
                { "ready",
                    s =>
                    {
                        // if we're downloading, we can't ready up.
                        if (client.State == Session.ClientState.NotReady)
                            client.State = Session.ClientState.Ready;
                        else if (client.State == Session.ClientState.Ready)
                            client.State = Session.ClientState.NotReady;

                        Log.Write("server", "Player @{0} is {1}",
                            conn.socket.RemoteEndPoint, client.State);

                        server.SyncLobbyInfo();

                        if (server.conns.Count > 0 && server.conns.All(c => server.GetClient(c).State == Session.ClientState.Ready))
                            InterpretCommand(server, conn, client, "startgame");

                        return true;
                    }},
                { "startgame",
                    s =>
                    {
                        server.StartGame();
                        return true;
                    }},
                { "lag",
                    s =>
                    {
                        int lag;
                        if (!int.TryParse(s, out lag)) { Log.Write("server", "Invalid order lag: {0}", s); return false; }

                        Log.Write("server", "Order lag is now {0} frames.", lag);

                        server.lobbyInfo.GlobalSettings.OrderLatency = lag;
                        server.SyncLobbyInfo();
                        return true;
                    }},
                { "spectator",
                    s =>
                        {
                            var slotData = server.lobbyInfo.Slots.Where(ax => ax.Spectator && !server.lobbyInfo.Clients.Any(l => l.Slot == ax.Index)).FirstOrDefault();
                            if (slotData == null)
                                return true;

                            client.Slot = slotData.Index;
                            SyncClientToPlayerReference(client, slotData.MapPlayer != null ? server.Map.Players[slotData.MapPlayer] : null);

                        server.SyncLobbyInfo();
                        return true;
                    }},
                { "slot",
                    s =>
                    {
                        int slot;
                        if (!int.TryParse(s, out slot)) { Log.Write("server", "Invalid slot: {0}", s ); return false; }

                        var slotData = server.lobbyInfo.Slots.FirstOrDefault( x => x.Index == slot );
                        if (slotData == null || slotData.Closed || slotData.Bot != null
                            || server.lobbyInfo.Clients.Any( c => c.Slot == slot ))
                            return false;

                        client.Slot = slot;
                        SyncClientToPlayerReference(client, slotData.MapPlayer != null ? server.Map.Players[slotData.MapPlayer] : null);

                        server.SyncLobbyInfo();
                        return true;
                    }},
                { "slot_close",
                    s =>
                    {
                        int slot;
                        if (!int.TryParse(s, out slot)) { Log.Write("server", "Invalid slot: {0}", s ); return false; }

                        var slotData = server.lobbyInfo.Slots.FirstOrDefault( x => x.Index == slot );
                        if (slotData == null)
                            return false;

                        if (conn.PlayerIndex != 0)
                        {
                            server.SendChatTo( conn, "Only the host can alter slots" );
                            return true;
                        }

                        slotData.Closed = true;
                        slotData.Bot = null;

                        /* kick any player that's in the slot */
                        var occupant = server.lobbyInfo.Clients.FirstOrDefault( c => c.Slot == slotData.Index );
                        if (occupant != null)
                        {
                            var occupantConn = server.conns.FirstOrDefault( c => c.PlayerIndex == occupant.Index );
                            if (occupantConn != null)
                                server.DropClient( occupantConn, new Exception() );
                        }

                        server.SyncLobbyInfo();
                        return true;
                    }},
                { "slot_open",
                    s =>
                    {
                        int slot;
                        if (!int.TryParse(s, out slot)) { Log.Write("server", "Invalid slot: {0}", s ); return false; }

                        var slotData = server.lobbyInfo.Slots.FirstOrDefault( x => x.Index == slot );
                        if (slotData == null)
                            return false;

                        if (conn.PlayerIndex != 0)
                        {
                            server.SendChatTo( conn, "Only the host can alter slots" );
                            return true;
                        }

                        slotData.Closed = false;
                        slotData.Bot = null;

                        server.SyncLobbyInfo();
                        return true;
                    }},
                { "slot_bot",
                    s =>
                    {
                        var parts = s.Split(' ');

                        if (parts.Length != 2)
                        {
                            server.SendChatTo( conn, "Malformed slot_bot command" );
                            return true;
                        }

                        int slot;
                        if (!int.TryParse(parts[0], out slot)) { Log.Write("server", "Invalid slot: {0}", s ); return false; }

                        var slotData = server.lobbyInfo.Slots.FirstOrDefault( x => x.Index == slot );
                        if (slotData == null)
                            return false;

                        if (conn.PlayerIndex != 0)
                        {
                            server.SendChatTo( conn, "Only the host can alter slots" );
                            return true;
                        }

                        slotData.Bot = parts[1];

                        server.SyncLobbyInfo();
                        return true;
                    }},
                { "map",
                    s =>
                    {
                        if (conn.PlayerIndex != 0)
                        {
                            server.SendChatTo( conn, "Only the host can change the map" );
                            return true;
                        }
                        server.lobbyInfo.GlobalSettings.Map = s;
                        LoadMap(server);

                        foreach(var c in server.lobbyInfo.Clients)
                        {
                            c.SpawnPoint = 0;
                            var slotData = server.lobbyInfo.Slots.FirstOrDefault( x => x.Index == c.Slot );
                            if (slotData != null && slotData.MapPlayer != null)
                                SyncClientToPlayerReference(c, server.Map.Players[slotData.MapPlayer]);

                            c.State = Session.ClientState.NotReady;
                        }

                        server.SyncLobbyInfo();
                        return true;
                    }},
                { "lockteams",
                    s =>
                    {
                        if (conn.PlayerIndex != 0)
                        {
                            server.SendChatTo( conn, "Only the host can set that option" );
                            return true;
                        }

                        bool.TryParse(s, out server.lobbyInfo.GlobalSettings.LockTeams);
                        server.SyncLobbyInfo();
                        return true;
                    }},
            };

            var cmdName = cmd.Split(' ').First();
            var cmdValue = string.Join(" ", cmd.Split(' ').Skip(1).ToArray());

            Func<string,bool> a;
            if (!dict.TryGetValue(cmdName, out a))
                return false;

            return a(cmdValue);
        }
Example #6
0
        static bool ValidateSlotCommand(S server, Connection conn, Session.Client client, string arg, bool requiresHost)
        {
            if (!server.lobbyInfo.Slots.ContainsKey(arg))
            {
                Log.Write("server", "Invalid slot: {0}", arg );
                return false;
            }

            if (requiresHost && !client.IsAdmin)
            {
                server.SendChatTo( conn, "Only the host can do that" );
                return false;
            }

            return true;
        }
Example #7
0
        public bool InterpretCommand(S server, Connection conn, Session.Client client, string cmd)
        {
            if (!ValidateCommand(server, conn, client, cmd))
                return false;

            var dict = new Dictionary<string, Func<string, bool>>
            {
                { "ready",
                    s =>
                    {
                        // if we're downloading, we can't ready up.
                        if (client.State == Session.ClientState.NotReady)
                            client.State = Session.ClientState.Ready;
                        else if (client.State == Session.ClientState.Ready)
                            client.State = Session.ClientState.NotReady;

                        Log.Write("server", "Player @{0} is {1}",
                            conn.socket.RemoteEndPoint, client.State);

                        server.SyncLobbyInfo();

                        if (server.conns.Count > 0 && server.conns.All(c => server.GetClient(c).State == Session.ClientState.Ready))
                            InterpretCommand(server, conn, client, "startgame");

                        return true;
                    }},
                { "startgame",
                    s =>
                    {
                        server.StartGame();
                        return true;
                    }},
                { "lag",
                    s =>
                    {
                        int lag;
                        if (!int.TryParse(s, out lag)) { Log.Write("server", "Invalid order lag: {0}", s); return false; }

                        Log.Write("server", "Order lag is now {0} frames.", lag);

                        server.lobbyInfo.GlobalSettings.OrderLatency = lag;
                        server.SyncLobbyInfo();
                        return true;
                    }},
                { "slot",
                    s =>
                    {
                        if (!server.lobbyInfo.Slots.ContainsKey(s))
                        {
                            Log.Write("server", "Invalid slot: {0}", s );
                            return false;
                        }
                        var slot = server.lobbyInfo.Slots[s];

                        if (slot.Closed || server.lobbyInfo.ClientInSlot(s) != null)
                            return false;

                        client.Slot = s;
                        S.SyncClientToPlayerReference(client, server.Map.Players[s]);

                        server.SyncLobbyInfo();
                        return true;
                    }},
                { "spectate",
                    s =>
                    {
                        client.Slot = null;
                        client.SpawnPoint = 0;
                        server.SyncLobbyInfo();
                        return true;
                    }},
                { "slot_close",
                    s =>
                    {
                        if (!ValidateSlotCommand( server, conn, client, s, true ))
                            return false;

                        // kick any player that's in the slot
                        var occupant = server.lobbyInfo.ClientInSlot(s);
                        if (occupant != null)
                        {
                            if (occupant.Bot != null)
                                server.lobbyInfo.Clients.Remove(occupant);
                            else
                            {
                                var occupantConn = server.conns.FirstOrDefault( c => c.PlayerIndex == occupant.Index );
                                if (occupantConn != null)
                                {
                                    server.SendOrderTo(occupantConn, "ServerError", "Your slot was closed by the host");
                                    server.DropClient(occupantConn);
                                }
                            }
                        }

                        server.lobbyInfo.Slots[s].Closed = true;
                        server.SyncLobbyInfo();
                        return true;
                    }},
                { "slot_open",
                    s =>
                    {
                        if (!ValidateSlotCommand( server, conn, client, s, true ))
                            return false;

                        var slot = server.lobbyInfo.Slots[s];
                        slot.Closed = false;

                        // Slot may have a bot in it
                        var occupant = server.lobbyInfo.ClientInSlot(s);
                        if (occupant != null && occupant.Bot != null)
                            server.lobbyInfo.Clients.Remove(occupant);

                        server.SyncLobbyInfo();
                        return true;
                    }},
                { "slot_bot",
                    s =>
                    {
                        var parts = s.Split(' ');

                        if (parts.Length < 2)
                        {
                            server.SendChatTo( conn, "Malformed slot_bot command" );
                            return true;
                        }

                        if (!ValidateSlotCommand( server, conn, client, parts[0], true ))
                            return false;

                        var slot = server.lobbyInfo.Slots[parts[0]];
                        var bot = server.lobbyInfo.ClientInSlot(parts[0]);
                        var botType = parts.Skip(1).JoinWith(" ");

                        // Invalid slot
                        if (bot != null && bot.Bot == null)
                        {
                            server.SendChatTo( conn, "Can't add bots to a slot with another client" );
                            return true;
                        }

                        slot.Closed = false;
                        if (bot == null)
                        {
                            // Create a new bot
                            bot = new Session.Client()
                            {
                                Index = server.ChooseFreePlayerIndex(),
                                Name = botType,
                                Bot = botType,
                                Slot = parts[0],
                                Country = "random",
                                SpawnPoint = 0,
                                Team = 0,
                                State = Session.ClientState.NotReady
                            };

                            // pick a random color for the bot
                            var hue = (byte)server.Random.Next(255);
                            var sat = (byte)server.Random.Next(255);
                            var lum = (byte)server.Random.Next(51,255);
                            bot.ColorRamp = new ColorRamp(hue, sat, lum, 10);

                            server.lobbyInfo.Clients.Add(bot);
                        }
                        else
                        {
                            // Change the type of the existing bot
                            bot.Name = botType;
                            bot.Bot = botType;
                        }

                        S.SyncClientToPlayerReference(bot, server.Map.Players[parts[0]]);
                        server.SyncLobbyInfo();
                        return true;
                    }},
                { "map",
                    s =>
                    {
                        if (!client.IsAdmin)
                        {
                            server.SendChatTo( conn, "Only the host can change the map" );
                            return true;
                        }
                        server.lobbyInfo.GlobalSettings.Map = s;
                        var oldSlots = server.lobbyInfo.Slots.Keys.ToArray();
                        LoadMap(server);

                        // Reassign players into new slots based on their old slots:
                        //  - Observers remain as observers
                        //  - Players who now lack a slot are made observers
                        //  - Bots who now lack a slot are dropped
                        var slots = server.lobbyInfo.Slots.Keys.ToArray();
                        int i = 0;
                        foreach (var os in oldSlots)
                        {
                            var c = server.lobbyInfo.ClientInSlot(os);
                            if (c == null)
                                continue;

                            c.SpawnPoint = 0;
                            c.State = Session.ClientState.NotReady;
                            c.Slot = i < slots.Length ? slots[i++] : null;
                            if (c.Slot != null)
                                S.SyncClientToPlayerReference(c, server.Map.Players[c.Slot]);
                            else if (c.Bot != null)
                                server.lobbyInfo.Clients.Remove(c);
                        }

                        server.SyncLobbyInfo();
                        return true;
                    }},
                { "lockteams",
                    s =>
                    {
                        if (!client.IsAdmin)
                        {
                            server.SendChatTo( conn, "Only the host can set that option" );
                            return true;
                        }

                        bool.TryParse(s, out server.lobbyInfo.GlobalSettings.LockTeams);
                        server.SyncLobbyInfo();
                        return true;
                    }},
                { "allowcheats",
                    s =>
                    {
                        if (!client.IsAdmin)
                        {
                            server.SendChatTo( conn, "Only the host can set that option" );
                            return true;
                        }

                        bool.TryParse(s, out server.lobbyInfo.GlobalSettings.AllowCheats);
                        server.SyncLobbyInfo();
                        return true;
                    }},
                { "kick",
                    s =>
                    {

                        if (!client.IsAdmin)
                        {
                            server.SendChatTo( conn, "Only the host can kick players" );
                            return true;
                        }

                        int clientID;
                        int.TryParse( s, out clientID );

                        var connToKick = server.conns.SingleOrDefault( c => server.GetClient(c) != null && server.GetClient(c).Index == clientID);
                        if (connToKick == null)
                        {
                            server.SendChatTo( conn, "Noone in that slot." );
                            return true;
                        }

                        server.SendOrderTo(connToKick, "ServerError", "You have been kicked from the server");
                        server.DropClient(connToKick);
                        server.SyncLobbyInfo();
                        return true;
                    }},
                { "name",
                    s =>
                    {
                        Log.Write("server", "Player@{0} is now known as {1}", conn.socket.RemoteEndPoint, s);
                        client.Name = s;
                        server.SyncLobbyInfo();
                        return true;
                    }},
                { "race",
                    s =>
                    {
                        var parts = s.Split(' ');
                        var targetClient = server.lobbyInfo.ClientWithIndex(int.Parse(parts[0]));

                        // Only the host can change other client's info
                        if (targetClient.Index != client.Index && !client.IsAdmin)
                            return true;

                        // Map has disabled race changes
                        if (server.lobbyInfo.Slots[targetClient.Slot].LockRace)
                            return true;

                        targetClient.Country = parts[1];
                        server.SyncLobbyInfo();
                        return true;
                    }},
                { "team",
                    s =>
                    {
                        var parts = s.Split(' ');
                        var targetClient = server.lobbyInfo.ClientWithIndex(int.Parse(parts[0]));

                        // Only the host can change other client's info
                        if (targetClient.Index != client.Index && !client.IsAdmin)
                            return true;

                        // Map has disabled team changes
                        if (server.lobbyInfo.Slots[targetClient.Slot].LockTeam)
                            return true;

                        int team;
                        if (!int.TryParse(parts[1], out team)) { Log.Write("server", "Invalid team: {0}", s ); return false; }

                        targetClient.Team = team;
                        server.SyncLobbyInfo();
                        return true;
                    }},
                { "spawn",
                    s =>
                    {
                        var parts = s.Split(' ');
                        var targetClient = server.lobbyInfo.ClientWithIndex(int.Parse(parts[0]));

                        // Only the host can change other client's info
                        if (targetClient.Index != client.Index && !client.IsAdmin)
                            return true;

                        // Spectators don't need a spawnpoint
                        if (targetClient.Slot == null)
                            return true;

                        // Map has disabled spawn changes
                        if (server.lobbyInfo.Slots[targetClient.Slot].LockSpawn)
                            return true;

                        int spawnPoint;
                        if (!int.TryParse(parts[1], out spawnPoint) || spawnPoint < 0 || spawnPoint > server.Map.GetSpawnPoints().Length)
                        {
                            Log.Write("server", "Invalid spawn point: {0}", parts[1]);
                            return true;
                        }

                        if (server.lobbyInfo.Clients.Where( cc => cc != client ).Any( cc => (cc.SpawnPoint == spawnPoint) && (cc.SpawnPoint != 0) ))
                        {
                            server.SendChatTo( conn, "You can't be at the same spawn point as another player" );
                            return true;
                        }

                        targetClient.SpawnPoint = spawnPoint;
                        server.SyncLobbyInfo();
                        return true;
                    }},
                { "color",
                    s =>
                    {
                        var parts = s.Split(' ');
                        var targetClient = server.lobbyInfo.ClientWithIndex(int.Parse(parts[0]));

                        // Only the host can change other client's info
                        if (targetClient.Index != client.Index && !client.IsAdmin)
                            return true;

                        // Map has disabled color changes
                        if (targetClient.Slot != null && server.lobbyInfo.Slots[targetClient.Slot].LockColor)
                            return true;

                        var ci = parts[1].Split(',').Select(cc => int.Parse(cc)).ToArray();
                        targetClient.ColorRamp = new ColorRamp((byte)ci[0], (byte)ci[1], (byte)ci[2], (byte)ci[3]);
                        server.SyncLobbyInfo();
                        return true;
                    }}
            };

            var cmdName = cmd.Split(' ').First();
            var cmdValue = cmd.Split(' ').Skip(1).JoinWith(" ");

            Func<string,bool> a;
            if (!dict.TryGetValue(cmdName, out a))
                return false;

            return a(cmdValue);
        }
Example #8
0
        public bool InterpretCommand(S server, Connection conn, Session.Client client, string cmd)
        {
            if (!ValidateCommand(server, conn, client, cmd))
            {
                return(false);
            }

            var dict = new Dictionary <string, Func <string, bool> >
            {
                { "ready",
                  s =>
                  {
                      // if we're downloading, we can't ready up.
                      if (client.State == Session.ClientState.NotReady)
                      {
                          client.State = Session.ClientState.Ready;
                      }
                      else if (client.State == Session.ClientState.Ready)
                      {
                          client.State = Session.ClientState.NotReady;
                      }

                      Log.Write("server", "Player @{0} is {1}",
                                conn.socket.RemoteEndPoint, client.State);

                      server.SyncLobbyInfo();

                      if (server.conns.Count > 0 && server.conns.All(c => server.GetClient(c).State == Session.ClientState.Ready))
                      {
                          InterpretCommand(server, conn, client, "startgame");
                      }

                      return(true);
                  } },
                { "startgame",
                  s =>
                  {
                      server.StartGame();
                      return(true);
                  } },
                { "lag",
                  s =>
                  {
                      int lag;
                      if (!int.TryParse(s, out lag))
                      {
                          Log.Write("server", "Invalid order lag: {0}", s); return(false);
                      }

                      Log.Write("server", "Order lag is now {0} frames.", lag);

                      server.lobbyInfo.GlobalSettings.OrderLatency = lag;
                      server.SyncLobbyInfo();
                      return(true);
                  } },
                { "slot",
                  s =>
                  {
                      if (!server.lobbyInfo.Slots.ContainsKey(s))
                      {
                          Log.Write("server", "Invalid slot: {0}", s);
                          return(false);
                      }
                      var slot = server.lobbyInfo.Slots[s];

                      if (slot.Closed || server.lobbyInfo.ClientInSlot(s) != null)
                      {
                          return(false);
                      }

                      client.Slot = s;
                      S.SyncClientToPlayerReference(client, server.Map.Players[s]);

                      server.SyncLobbyInfo();
                      return(true);
                  } },
                { "spectate",
                  s =>
                  {
                      client.Slot       = null;
                      client.SpawnPoint = 0;
                      server.SyncLobbyInfo();
                      return(true);
                  } },
                { "slot_close",
                  s =>
                  {
                      if (!ValidateSlotCommand(server, conn, client, s, true))
                      {
                          return(false);
                      }

                      // kick any player that's in the slot
                      var occupant = server.lobbyInfo.ClientInSlot(s);
                      if (occupant != null)
                      {
                          if (occupant.Bot != null)
                          {
                              server.lobbyInfo.Clients.Remove(occupant);
                          }
                          else
                          {
                              var occupantConn = server.conns.FirstOrDefault(c => c.PlayerIndex == occupant.Index);
                              if (occupantConn != null)
                              {
                                  server.SendOrderTo(occupantConn, "ServerError", "Your slot was closed by the host");
                                  server.DropClient(occupantConn);
                              }
                          }
                      }

                      server.lobbyInfo.Slots[s].Closed = true;
                      server.SyncLobbyInfo();
                      return(true);
                  } },
                { "slot_open",
                  s =>
                  {
                      if (!ValidateSlotCommand(server, conn, client, s, true))
                      {
                          return(false);
                      }

                      var slot = server.lobbyInfo.Slots[s];
                      slot.Closed = false;

                      // Slot may have a bot in it
                      var occupant = server.lobbyInfo.ClientInSlot(s);
                      if (occupant != null && occupant.Bot != null)
                      {
                          server.lobbyInfo.Clients.Remove(occupant);
                      }

                      server.SyncLobbyInfo();
                      return(true);
                  } },
                { "slot_bot",
                  s =>
                  {
                      var parts = s.Split(' ');

                      if (parts.Length < 2)
                      {
                          server.SendChatTo(conn, "Malformed slot_bot command");
                          return(true);
                      }

                      if (!ValidateSlotCommand(server, conn, client, parts[0], true))
                      {
                          return(false);
                      }

                      var slot    = server.lobbyInfo.Slots[parts[0]];
                      var bot     = server.lobbyInfo.ClientInSlot(parts[0]);
                      var botType = parts.Skip(1).JoinWith(" ");

                      // Invalid slot
                      if (bot != null && bot.Bot == null)
                      {
                          server.SendChatTo(conn, "Can't add bots to a slot with another client");
                          return(true);
                      }

                      slot.Closed = false;
                      if (bot == null)
                      {
                          // Create a new bot
                          bot = new Session.Client()
                          {
                              Index      = server.ChooseFreePlayerIndex(),
                              Name       = botType,
                              Bot        = botType,
                              Slot       = parts[0],
                              Country    = "random",
                              SpawnPoint = 0,
                              Team       = 0,
                              State      = Session.ClientState.NotReady
                          };

                          // pick a random color for the bot
                          var hue = (byte)server.Random.Next(255);
                          var sat = (byte)server.Random.Next(255);
                          var lum = (byte)server.Random.Next(51, 255);
                          bot.ColorRamp = new ColorRamp(hue, sat, lum, 10);

                          server.lobbyInfo.Clients.Add(bot);
                      }
                      else
                      {
                          // Change the type of the existing bot
                          bot.Name = botType;
                          bot.Bot  = botType;
                      }

                      S.SyncClientToPlayerReference(bot, server.Map.Players[parts[0]]);
                      server.SyncLobbyInfo();
                      return(true);
                  } },
                { "map",
                  s =>
                  {
                      if (!client.IsAdmin)
                      {
                          server.SendChatTo(conn, "Only the host can change the map");
                          return(true);
                      }
                      server.lobbyInfo.GlobalSettings.Map = s;
                      var oldSlots = server.lobbyInfo.Slots.Keys.ToArray();
                      LoadMap(server);

                      // Reassign players into new slots based on their old slots:
                      //  - Observers remain as observers
                      //  - Players who now lack a slot are made observers
                      //  - Bots who now lack a slot are dropped
                      var slots = server.lobbyInfo.Slots.Keys.ToArray();
                      int i     = 0;
                      foreach (var os in oldSlots)
                      {
                          var c = server.lobbyInfo.ClientInSlot(os);
                          if (c == null)
                          {
                              continue;
                          }

                          c.SpawnPoint = 0;
                          c.State      = Session.ClientState.NotReady;
                          c.Slot       = i < slots.Length ? slots[i++] : null;
                          if (c.Slot != null)
                          {
                              S.SyncClientToPlayerReference(c, server.Map.Players[c.Slot]);
                          }
                          else if (c.Bot != null)
                          {
                              server.lobbyInfo.Clients.Remove(c);
                          }
                      }

                      server.SyncLobbyInfo();
                      return(true);
                  } },
                { "lockteams",
                  s =>
                  {
                      if (!client.IsAdmin)
                      {
                          server.SendChatTo(conn, "Only the host can set that option");
                          return(true);
                      }

                      bool.TryParse(s, out server.lobbyInfo.GlobalSettings.LockTeams);
                      server.SyncLobbyInfo();
                      return(true);
                  } },
                { "allowcheats",
                  s =>
                  {
                      if (!client.IsAdmin)
                      {
                          server.SendChatTo(conn, "Only the host can set that option");
                          return(true);
                      }

                      bool.TryParse(s, out server.lobbyInfo.GlobalSettings.AllowCheats);
                      server.SyncLobbyInfo();
                      return(true);
                  } },
                { "kick",
                  s =>
                  {
                      if (!client.IsAdmin)
                      {
                          server.SendChatTo(conn, "Only the host can kick players");
                          return(true);
                      }

                      int clientID;
                      int.TryParse(s, out clientID);

                      var connToKick = server.conns.SingleOrDefault(c => server.GetClient(c) != null && server.GetClient(c).Index == clientID);
                      if (connToKick == null)
                      {
                          server.SendChatTo(conn, "Noone in that slot.");
                          return(true);
                      }

                      server.SendOrderTo(connToKick, "ServerError", "You have been kicked from the server");
                      server.DropClient(connToKick);
                      server.SyncLobbyInfo();
                      return(true);
                  } },
                { "name",
                  s =>
                  {
                      Log.Write("server", "Player@{0} is now known as {1}", conn.socket.RemoteEndPoint, s);
                      client.Name = s;
                      server.SyncLobbyInfo();
                      return(true);
                  } },
                { "race",
                  s =>
                  {
                      var parts        = s.Split(' ');
                      var targetClient = server.lobbyInfo.ClientWithIndex(int.Parse(parts[0]));

                      // Only the host can change other client's info
                      if (targetClient.Index != client.Index && !client.IsAdmin)
                      {
                          return(true);
                      }

                      // Map has disabled race changes
                      if (server.lobbyInfo.Slots[targetClient.Slot].LockRace)
                      {
                          return(true);
                      }

                      targetClient.Country = parts[1];
                      server.SyncLobbyInfo();
                      return(true);
                  } },
                { "team",
                  s =>
                  {
                      var parts        = s.Split(' ');
                      var targetClient = server.lobbyInfo.ClientWithIndex(int.Parse(parts[0]));

                      // Only the host can change other client's info
                      if (targetClient.Index != client.Index && !client.IsAdmin)
                      {
                          return(true);
                      }

                      // Map has disabled team changes
                      if (server.lobbyInfo.Slots[targetClient.Slot].LockTeam)
                      {
                          return(true);
                      }

                      int team;
                      if (!int.TryParse(parts[1], out team))
                      {
                          Log.Write("server", "Invalid team: {0}", s); return(false);
                      }

                      targetClient.Team = team;
                      server.SyncLobbyInfo();
                      return(true);
                  } },
                { "spawn",
                  s =>
                  {
                      var parts        = s.Split(' ');
                      var targetClient = server.lobbyInfo.ClientWithIndex(int.Parse(parts[0]));

                      // Only the host can change other client's info
                      if (targetClient.Index != client.Index && !client.IsAdmin)
                      {
                          return(true);
                      }

                      // Spectators don't need a spawnpoint
                      if (targetClient.Slot == null)
                      {
                          return(true);
                      }

                      // Map has disabled spawn changes
                      if (server.lobbyInfo.Slots[targetClient.Slot].LockSpawn)
                      {
                          return(true);
                      }

                      int spawnPoint;
                      if (!int.TryParse(parts[1], out spawnPoint) || spawnPoint <0 || spawnPoint> server.Map.GetSpawnPoints().Length)
                      {
                          Log.Write("server", "Invalid spawn point: {0}", parts[1]);
                          return(true);
                      }

                      if (server.lobbyInfo.Clients.Where(cc => cc != client).Any(cc => (cc.SpawnPoint == spawnPoint) && (cc.SpawnPoint != 0)))
                      {
                          server.SendChatTo(conn, "You can't be at the same spawn point as another player");
                          return(true);
                      }

                      targetClient.SpawnPoint = spawnPoint;
                      server.SyncLobbyInfo();
                      return(true);
                  } },
                { "color",
                  s =>
                  {
                      var parts        = s.Split(' ');
                      var targetClient = server.lobbyInfo.ClientWithIndex(int.Parse(parts[0]));

                      // Only the host can change other client's info
                      if (targetClient.Index != client.Index && !client.IsAdmin)
                      {
                          return(true);
                      }

                      // Map has disabled color changes
                      if (targetClient.Slot != null && server.lobbyInfo.Slots[targetClient.Slot].LockColor)
                      {
                          return(true);
                      }

                      var ci = parts[1].Split(',').Select(cc => int.Parse(cc)).ToArray();
                      targetClient.ColorRamp = new ColorRamp((byte)ci[0], (byte)ci[1], (byte)ci[2], (byte)ci[3]);
                      server.SyncLobbyInfo();
                      return(true);
                  } }
            };

            var cmdName  = cmd.Split(' ').First();
            var cmdValue = cmd.Split(' ').Skip(1).JoinWith(" ");

            Func <string, bool> a;

            if (!dict.TryGetValue(cmdName, out a))
            {
                return(false);
            }

            return(a(cmdValue));
        }