// Remove player from the list, and notify remaining players public void UnregisterPlayer(Player player) { if (player == null) { log.Log("World.UnregisterPlayer: Trying to unregister a non-existent (null) player.", LogType.Debug); return; } lock ( playerListLock ) { if (players[player.id] == player) { log.Log("{0} left the server.", LogType.UserActivity, player.name); db.ProcessLogout(player); db.Save(); players[player.id] = null; playerCount--; SendToAll(PacketWriter.MakeRemoveEntity(player.id), null); SendToAll(PacketWriter.MakeMessage(Color.Sys + player.name + " left the server."), null); UpdatePlayerList(); } else { log.Log("World.UnregisterPlayer: Trying to unregister a non-existent (unknown id) player.", LogType.Warning); } } }
void Freeze(Player player, Command cmd) { if (player.Can(Permissions.Freeze)) { string name = cmd.Next(); Player target = world.FindPlayer(name); if (target != null) { if (!target.isFrozen) { world.SendToAll(PacketWriter.MakeMessage(Color.Yellow + target.name + " has been frozen by " + player.name), null); target.isFrozen = true; } else { player.Message(target.name + " is already frozen."); } } else { world.NoPlayerMessage(player, name); } } else { world.NoAccessMessage(player); } }
void Roll(Player player, Command cmd) { Random rand = new Random(); int min = 1, max = 100, num, t1, t2; if (cmd.NextInt(out t1)) { if (cmd.NextInt(out t2)) { if (t2 >= t1) { min = t1; max = t2; } } else if (t1 >= 1) { max = t1; } } num = rand.Next(min, max + 1); string msg = Color.Silver + player.name + " rolled " + num + " (" + min + "..." + max + ")"; world.log.LogConsole(msg); world.SendToAll(PacketWriter.MakeMessage(msg), null); }
void Unfreeze(Player player, Command cmd) { if (player.Can(Permissions.Freeze)) { string name = cmd.Next(); Player target = world.FindPlayer(name); if (target != null) { if (target.isFrozen) { world.SendToAll(PacketWriter.MakeMessage(Color.Yellow + target.name + " is no longer frozen."), null); target.isFrozen = false; } else { player.Message(target.name + " is currently not frozen."); } } else { world.NoPlayerMessage(player, name); } } else { world.NoAccessMessage(player); } }
void Unlock(Player player, Command cmd) { if (!player.Can(Permissions.Lock)) { world.NoAccessMessage(player); return; } world.SendToAll(PacketWriter.MakeMessage(Color.Red + "Lockdown has ended."), null); world.EndLockDown(); }
void Lock(Player player, Command cmd) { if (!player.Can(Permissions.Lock)) { world.NoAccessMessage(player); return; } world.SendToAll(PacketWriter.MakeMessage(Color.Red + "Server is now on lockdown!"), null); world.BeginLockDown(); }
// Queues a system message public void Message(string message) { if (session == null) { world.log.LogConsole(message); } else { Send(PacketWriter.MakeMessage(Color.Sys + message)); } }
// Queues a system message with a custom color public void Message(string color, string message) { if (session == null) { world.log.LogConsole(message); } else { session.Send(PacketWriter.MakeMessage(color + message)); } }
public void ProcessUpdates() { int packetsSent = 0; int maxPacketsPerUpdate = world.server.CalculateMaxPacketsPerUpdate(); BlockUpdate update; while (updates.Count > 0 && packetsSent < maxPacketsPerUpdate) { lock ( queueLock ) { update = updates.Dequeue(); } changesSinceSave++; changesSinceBackup++; SetBlock(update.x, update.y, update.h, update.type); world.SendToAll(PacketWriter.MakeSetBlock(update.x, update.y, update.h, update.type), update.origin, false); if (update.origin != null) { update.origin.info.ProcessBlockBuild(update.type); } packetsSent++; } if (world.loadSendingInProgress) { if (packetsSent < maxPacketsPerUpdate) { GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced); GC.WaitForPendingFinalizers(); world.SendToAll(PacketWriter.MakeMessage(Color.Red + "Map load complete."), null); world.log.Log("Load command finished succesfully.", LogType.SystemActivity); world.loadSendingInProgress = false; world.EndLockDown(); } else { if (!world.loadProgressReported && world.completedBlockUpdates / (float)world.totalBlockUpdates > 0.5f) { world.SendToAll(PacketWriter.MakeMessage(Color.Red + "Map loading: 50%"), null); world.loadProgressReported = true; } world.completedBlockUpdates += packetsSent; } } }
void Say(Player player, Command cmd) { if (player.Can(Permissions.Say)) { string msg = cmd.NextAll(); if (msg != null && msg.Trim().Length > 0) { world.SendToAll(PacketWriter.MakeMessage(Color.Say + msg.Trim()), null); } else { player.Message("Usage: " + Color.Help + "/say message"); } } else { world.NoAccessMessage(player); } }
void Hide(Player player, Command cmd) { if (player.Can(Permissions.Hide)) { if (!player.isHidden) { world.SendToAll(PacketWriter.MakeRemoveEntity(player.id), null); world.SendToAll(PacketWriter.MakeMessage(Color.Sys + player.name + " left the server."), null); player.isHidden = true; player.Message(Color.Gray, "You are now hidden."); } else { player.Message("You are already hidden."); } } else { world.NoAccessMessage(player); } }
// Kick a player. One argument (mandatory) - player name (can be partial). void Kick(Player player, Command cmd) { if (player.Can(Permissions.Kick)) { string name = cmd.Next(); if (name != null) { string msg = cmd.NextAll(); Player offender = world.FindPlayer(name); if (offender != null) { world.SendToAll(PacketWriter.MakeMessage( Color.Red + offender.name + " was kicked by " + player.name), offender); if (msg != null && msg != "") { world.log.Log("{0} was kicked by {1}. Message: {2}", LogType.UserActivity, offender.name, player.name, msg); offender.session.Kick("Kicked by " + player.name + ": " + msg); } else { world.log.Log("{0} was kicked by {1}", LogType.UserActivity, offender.name, player.name); offender.session.Kick("You have been kicked by " + player.name); } } else { world.NoPlayerMessage(player, name); } } else { player.Message("Usage: " + Color.Help + "/kick PlayerName [Message]" + Color.Sys + " or " + Color.Help + "/k PlayerName [Message]"); } } else { world.NoAccessMessage(player); } }
public void SendToAll(string message, string prefix, Player except, bool isHighPriority) { if (message.Length <= 64) { SendToAll(PacketWriter.MakeMessage(message), except, isHighPriority); } else { string[] words = message.Split(' '); int ll = 0, j = 0; bool first = true; for (int i = 0; i < words.Length; i++) { if (ll + words[i].Length > 64) { if (first) { SendToAll(PacketWriter.MakeMessage(String.Join(" ", words, j, i - j - 1)), null, isHighPriority); first = false; } else { SendToAll(PacketWriter.MakeMessage(prefix + String.Join(" ", words, j, i - j - 1)), null, isHighPriority); } j = i; ll = prefix.Length; i--; } else { ll += words[i].Length + 1; } } if (ll != prefix.Length) { } } }
void Unhide(Player player, Command cmd) { if (player.Can(Permissions.Hide)) { if (player.isHidden) { 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); player.isHidden = false; player.Message(Color.Gray, "You are no longer hidden."); } else { player.Message("You are not currently hidden."); } } else { world.NoAccessMessage(player); } }
// Parses message incoming from the player public void ParseMessage(string message, bool fromConsole) { if (DateTime.Now < mutedUntil) { return; } switch (Commands.GetMessageType(message)) { case MessageType.Chat: if (CheckChatSpam()) { return; } info.linesWritten++; string displayedName = nick; if (world.config.GetBool("ClassPrefixesInChat")) { displayedName = info.playerClass.prefix + displayedName; } if (world.config.GetBool("ClassColorsInChat") && info.playerClass.color != "" && info.playerClass.color != Color.White) { displayedName = info.playerClass.color + displayedName + Color.White; } world.SendToAll(PacketWriter.MakeMessage(displayedName + ": " + message), null); world.log.Log("{0}: {1}", LogType.Chat, name, message); break; case MessageType.Command: world.log.Log("{0}: {1}", LogType.UserCommand, name, message); world.cmd.ParseCommand(this, message, fromConsole); break; case MessageType.PrivateChat: if (CheckChatSpam()) { return; } string otherPlayerName = message.Substring(1, message.IndexOf(' ') - 1); Player otherPlayer = world.FindPlayer(otherPlayerName); if (otherPlayer != null) { world.log.Log("{0} to {1}: {2}", LogType.Chat, name, otherPlayer.name, message); otherPlayer.Send(PacketWriter.MakeMessage(Color.Gray + "from " + name + ": " + message.Substring(message.IndexOf(' ') + 1))); Send(PacketWriter.MakeMessage(Color.Gray + "to " + otherPlayer.name + ": " + message.Substring(message.IndexOf(' ') + 1))); } else { world.NoPlayerMessage(this, otherPlayerName); } break; case MessageType.ClassChat: if (CheckChatSpam()) { return; } string className = message.Substring(2, message.IndexOf(' ') - 2); PlayerClass playerClass = world.classes.FindClass(className); if (playerClass != null) { world.log.Log("{0} to {1}: {2}", LogType.ClassChat, name, playerClass.name, message); Packet classMsg = PacketWriter.MakeMessage(Color.Gray + "[" + playerClass.color + playerClass.name + Color.Gray + "]" + name + ": " + message.Substring(message.IndexOf(' ') + 1)); world.SendToClass(classMsg, playerClass); if (info.playerClass != playerClass) { Send(classMsg); } } else { Message("No such class: \"" + className.Substring(1) + "\""); } break; } }
// === Messaging ====================================================== // Broadcast public void SendToAll(string message, Player except) { SendToAll(PacketWriter.MakeMessage(message), except, true); }
// 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(); }
void DoBan(Player player, Command cmd, bool banIP, bool banAll, bool unban) { if (!banAll && !banIP && player.Can(Permissions.Ban) || !banAll && player.Can(Permissions.BanIP) || player.Can(Permissions.BanAll)) { string arg = cmd.Next(); string reason = cmd.NextAll(); IPAddress address; Player offender = world.FindPlayer(arg); PlayerInfo info = world.db.FindPlayerInfoExact(arg); // ban by IP address if (banIP && IPAddress.TryParse(arg, out address)) { if (banIP) { DoIPBan(player, address, reason, null, banAll, unban); } // ban online players } else if (!unban && offender != null) { address = offender.info.lastIP; if (banIP) { DoIPBan(player, address, reason, offender.name, banAll, unban); } if (unban) { if (offender.info.ProcessUnBan(player.name, reason)) { world.log.Log("{0} was unbanned by {1}.", LogType.UserActivity, offender.info.name, player.name); world.SendToAll(PacketWriter.MakeMessage(Color.Red + offender.name + " was unbanned by " + player.name), offender); } else { player.Message(offender.name + " is not currently banned."); } } else { if (offender.info.ProcessBan(player.name, reason)) { world.log.Log("{0} was banned by {1}.", LogType.UserActivity, offender.info.name, player.name); world.SendToAll(PacketWriter.MakeMessage(Color.Red + offender.name + " was banned by " + player.name), offender); offender.session.Kick("You were banned by " + player.name + "!"); } else { player.Message(offender.name + " is already banned."); } } // ban offline players } else if (info != null) { address = info.lastIP; if (banIP) { DoIPBan(player, address, reason, info.name, banAll, unban); } if (unban) { if (info.ProcessUnBan(player.name, reason)) { world.log.Log("{0} (offline) was unbanned by {1}", LogType.UserActivity, info.name, player.name); world.SendToAll(PacketWriter.MakeMessage(Color.Red + info.name + " (offline) was unbanned by " + player.name), null); } else { player.Message(info.name + " (offline) is not currenty banned."); } } else { if (info.ProcessBan(player.name, reason)) { world.log.Log("{0} (offline) was banned by {1}.", LogType.UserActivity, info.name, player.name); world.SendToAll(PacketWriter.MakeMessage(Color.Red + info.name + " (offline) was banned by " + player.name), null); } else { player.Message(info.name + " (offline) is already banned."); } } } else { world.NoPlayerMessage(player, arg); } } else { world.NoAccessMessage(player); } }