// 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(); }