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