예제 #1
0
        // login logic
        void LoginSequence()
        {
            byte opcode = reader.ReadByte();

            if (opcode != (byte)InputCodes.Handshake)
            {
                world.log.Log("Session.LoginSequence: Unexpected opcode in the first packet: {0}.", LogType.Error, opcode);
                KickNow("Unexpected handshake message - possible protocol mismatch!");
                return;
            }

            // check protocol version
            int clientProtocolVersion = reader.ReadByte();

            if (clientProtocolVersion != Config.ProtocolVersion)
            {
                world.log.Log("Session.LoginSequence: Wrong protocol version: {0}.", LogType.Error, clientProtocolVersion);
                KickNow("Incompatible protocol version!");
                return;
            }

            // check name for nonstandard characters
            string playerName       = ReadString();
            string verificationCode = ReadString();

            reader.ReadByte(); // unused

            if (!Player.IsValidName(playerName))
            {
                world.log.Log("Session.LoginSequence: Unacceptible player name: {0} ({1})", LogType.SuspiciousActivity, playerName, GetIP().ToString());
                KickNow("Invalid characters in player name!");
                return;
            }

            // check if player is banned
            player = new Player(world, playerName, this, world.map.spawn);
            if (player.info.banned)
            {
                player.info.ProcessFailedLogin(player);
                world.log.Log("Banned player {0} tried to log in.", LogType.SuspiciousActivity, player.name);
                world.SendToAll(PacketWriter.MakeMessage(Color.Sys + "Banned player " + player.name + " tried to log in."), player);
                KickNow("You were banned by " + player.info.bannedBy + " " + DateTime.Now.Subtract(player.info.banDate).Days + " days ago.");
                return;
            }

            // check if player's IP is banned
            IPBanInfo IPBanInfo = world.bans.Get(GetIP());

            if (IPBanInfo != null)
            {
                player.info.ProcessFailedLogin(player);
                IPBanInfo.ProcessAttempt(player);
                world.log.Log("{0} tried to log in from a banned IP.", LogType.SuspiciousActivity, player.name);
                world.SendToAll(PacketWriter.MakeMessage(Color.Sys + player.name + " tried to log in from a banned IP."), null);
                KickNow("Your IP was banned by " + IPBanInfo.bannedBy + " " + DateTime.Now.Subtract(IPBanInfo.banDate).Days + " days ago.");
                return;
            }

            // verify name
            if (!world.server.VerifyName(player.name, verificationCode))
            {
                string standardMessage = String.Format("Session.LoginSequence: Could not verify player name for {0} ({1}).",
                                                       player.name, GetIP());
                if (player.info.timesVisited == 1 || player.info.lastIP.ToString() != GetIP().ToString())
                {
                    switch (world.config.GetString("VerifyNames"))
                    {
                    case "Always":
                    case "Balanced":
                        player.info.ProcessFailedLogin(player);
                        world.log.Log("{0} IP did not match. Player was kicked.", LogType.SuspiciousActivity, standardMessage);
                        KickNow("Could not verify player name!");
                        return;

                    case "Never":
                        world.log.Log("{0} IP did not match. Player was allowed in anyway because VerifyNames is set to Never.",
                                      LogType.SuspiciousActivity,
                                      standardMessage);
                        Send(PacketWriter.MakeMessage(Color.Red + "Your name could not be verified."));
                        world.SendToAll(PacketWriter.MakeMessage(Color.Red + "Name and IP of " + player.name + " could not be verified!"), player);
                        break;
                    }
                }
                else
                {
                    switch (world.config.GetString("VerifyNames"))
                    {
                    case "Always":
                        player.info.ProcessFailedLogin(player);
                        world.log.Log("{0} IP matched previous records for that name. " +
                                      "Player was kicked anyway because VerifyNames is set to Always.", LogType.SuspiciousActivity,
                                      standardMessage);
                        KickNow("Could not verify player name!");
                        return;

                    case "Balanced":
                    case "Never":
                        world.log.Log("{0} IP matched previous records for that name. Player was allowed in.", LogType.SuspiciousActivity,
                                      standardMessage);
                        Send(PacketWriter.MakeMessage(Color.Red + "Your name could not be verified."));
                        if (world.config.GetBool("AnnounceUnverifiedNames"))
                        {
                            world.SendToAll(PacketWriter.MakeMessage(Color.Red + "Name of " + player.name +
                                                                     " could not be verified, but IP matches."), player);
                        }
                        break;
                    }
                }
            }

            // check if another player with the same name is on
            Player potentialClone = world.FindPlayer(player.name);

            if (potentialClone != null)
            {
                player.info.ProcessFailedLogin(player);
                world.log.Log("Session.LoginSequence: Player {0} tried to log in from two computers at once.", LogType.SuspiciousActivity, player.name);
                potentialClone.Message("Warning: someone just attempted to log in using your name.");
                KickNow("Already connected form elsewhere!");
                return;
            }

            potentialClone = world.FindPlayer(GetIP());
            if (potentialClone != null)
            {
                player.info.ProcessFailedLogin(player);
                world.log.Log("Session.LoginSequence: Player {0} tried to log in from same IP ({1}) as {2}.", LogType.SuspiciousActivity,
                              player.name, GetIP().ToString(), potentialClone.name);
                potentialClone.Message("Warning: someone just attempted to log in using your IP.");
                KickNow("Only one connection per IP allowed!");
                return;
            }

            // Register player for future block updates
            if (!world.RegisterPlayer(player))
            {
                KickNow("Sorry, server is full.");
                return;
            }

            player.info.ProcessLogin(player);

            // Player is now authenticated. Send server info.
            writer.Write(PacketWriter.MakeHandshake(world, player));

            // Start sending over the level copy
            writer.WriteLevelBegin();
            byte[] buffer    = new byte[1024];
            int    bytesSent = 0;

            // Fetch compressed map copy
            byte[] blockData;
            using (MemoryStream stream = new MemoryStream()) {
                world.map.GetCompressedCopy(stream, true);
                blockData = stream.ToArray();
            }
            world.log.Log("Session.LoginSequence: Sending compressed level copy ({0} bytes) to {1}.", LogType.Debug,
                          blockData.Length, player.name);

            while (bytesSent < blockData.Length)
            {
                int chunkSize = blockData.Length - bytesSent;
                if (chunkSize > 1024)
                {
                    chunkSize = 1024;
                }
                Array.Copy(blockData, bytesSent, buffer, 0, chunkSize);
                byte progress = (byte)(100 * bytesSent / blockData.Length);

                // write in chunks of 1024 bytes or less
                writer.WriteLevelChunk(buffer, chunkSize, progress);
                bytesSent += chunkSize;
            }

            // Done sending over level copy
            writer.Write(PacketWriter.MakeLevelEnd(world.map));

            // Send playerlist and add player himself
            writer.WriteAddEntity(255, player.name, player.pos);
            world.SendPlayerList(player);

            // Reveal newcommer to existing players
            world.log.Log("{0} ({1}) has joined the server.", LogType.UserActivity, player.name, player.info.playerClass.name);
            world.SendToAll(PacketWriter.MakeAddEntity(player, player.pos), player);
            world.SendToAll(PacketWriter.MakeMessage(Color.Sys + player.name + " (" + player.info.playerClass.color +
                                                     player.info.playerClass.name + Color.Sys + ") has joined the server."),
                            player);

            // Welcome message
            if (player.info.timesVisited > 1)
            {
                player.Message("Welcome back to " + world.config.GetString("ServerName"));
            }
            else
            {
                player.Message("Welcome to " + world.config.GetString("ServerName"));
            }

            player.Message("Your player class is " + player.info.playerClass.color + player.info.playerClass.name + Color.Sys +
                           ". Type /help for details.");

            if (world.config.GetBool("LowLatencyMode"))
            {
                client.NoDelay = true;
            }

            // Done.
            world.log.Log("Session.LoginSequence: {0} is now ready.", LogType.Debug,
                          player.name);
            GC.Collect();
        }