internal static void Unignore(Player player, Command cmd) { string name = cmd.Next(); if (name != null) { PlayerInfo targetInfo; if (!PlayerDB.FindPlayerInfo(name, out targetInfo)) { PlayerInfo[] infos = PlayerDB.FindPlayers(name); if (infos.Length == 1) { targetInfo = infos[0]; } else if (infos.Length > 1) { player.ManyMatchesMessage("player", infos); return; } else { player.NoPlayerMessage(name); return; } } else if (targetInfo == null) { player.NoPlayerMessage(name); return; } if (player.Unignore(targetInfo)) { player.MessageNow("You are no longer ignoring {0}", targetInfo.GetClassyName()); } else { player.MessageNow("You are not currently ignoring {0}", targetInfo.GetClassyName()); } } else { PlayerInfo[] ignoreList = player.GetIgnoreList(); if (ignoreList.Length > 0) { player.MessageNow("Ignored players: {0}", ignoreList.JoinToClassyString()); } else { player.MessageNow("You are not currently ignoring anyone."); } return; } }
internal static void Bring( Player player, Command cmd ) { if( player.Can( Permissions.Bring ) ) { string name = cmd.Next(); Player target = player.world.FindPlayer( name ); if( target != null ) { Position pos = player.pos; pos.x += 1; pos.y += 1; pos.h += 1; target.Send( PacketWriter.MakeTeleport( 255, pos ) ); } else { player.NoPlayerMessage( name ); } } else { player.NoAccessMessage( Permissions.Bring ); } }
internal static void ZoneEdit(Player player, Command cmd) { bool changesWereMade = false; string zoneName = cmd.Next(); if (zoneName == null) { player.Message("No zone name specified. See &H/help zedit"); return; } Zone zone = player.World.Map.FindZone(zoneName); if (zone == null) { player.Message("No zone found with the name \"{0}\". See &H/zones", zoneName); return; } string name; while ((name = cmd.Next()) != null) { if (name.Length < 2) { continue; } if (name.StartsWith("+")) { PlayerInfo info; if (!PlayerDB.FindPlayerInfo(name.Substring(1), out info)) { player.Message("More than one player found matching \"{0}\"", name.Substring(1)); return; } if (info == null) { player.NoPlayerMessage(name.Substring(1)); return; } // prevent players from whitelisting themselves to bypass protection if (!player.Info.Rank.AllowSecurityCircumvention && player.Info == info) { if (!zone.Controller.Check(info)) { player.Message("You must be {0}+&S to add yourself to this zone's whitelist.", zone.Controller.MinRank.GetClassyName()); continue; } } switch (zone.Controller.Include(info)) { case PermissionOverride.Deny: player.Message("{0}&S is no longer excluded from zone {1}", info.GetClassyName(), zone.GetClassyName()); changesWereMade = true; break; case PermissionOverride.None: player.Message("{0}&S is now included in zone {1}", info.GetClassyName(), zone.GetClassyName()); changesWereMade = true; break; case PermissionOverride.Allow: player.Message("{0}&S is already included in zone {1}", info.GetClassyName(), zone.GetClassyName()); break; } } else if (name.StartsWith("-")) { PlayerInfo info; if (!PlayerDB.FindPlayerInfo(name.Substring(1), out info)) { player.Message("More than one player found matching \"{0}\"", name.Substring(1)); return; } if (info == null) { player.NoPlayerMessage(name.Substring(1)); return; } switch (zone.Controller.Exclude(info)) { case PermissionOverride.Deny: player.Message("{0}&S is already excluded from zone {1}", info.GetClassyName(), zone.GetClassyName()); break; case PermissionOverride.None: player.Message("{0}&S is now excluded from zone {1}", info.GetClassyName(), zone.GetClassyName()); changesWereMade = true; break; case PermissionOverride.Allow: player.Message("{0}&S is no longer included in zone {1}", info.GetClassyName(), zone.GetClassyName()); changesWereMade = true; break; } } else { Rank minRank = RankManager.ParseRank(name); if (minRank != null) { // prevent players from lowering rank so bypass protection if (!player.Info.Rank.AllowSecurityCircumvention && zone.Controller.MinRank > player.Info.Rank && minRank <= player.Info.Rank) { player.Message("You are not allowed to lower the zone's rank."); continue; } if (zone.Controller.MinRank != minRank) { zone.Controller.MinRank = minRank; player.Message("Permission for zone \"{0}\" changed to {1}+", zone.Name, minRank.GetClassyName()); changesWereMade = true; } } else { player.NoRankMessage(name); } } if (changesWereMade) { zone.Edit(player.Info); player.World.Map.ChangedSinceSave = true; } else { player.Message("No changes were made to the zone."); } } }
internal static void ZoneAdd(Player player, Command cmd) { string zoneName = cmd.Next(); if (zoneName == null) { cdZoneAdd.PrintUsage(player); return; } Zone zone = new Zone(); if (zoneName.StartsWith("+")) { PlayerInfo info; if (!PlayerDB.FindPlayerInfo(zoneName.Substring(1), out info)) { player.Message("More than one player found matching \"{0}\"", zoneName.Substring(1)); return; } if (info == null) { player.NoPlayerMessage(zoneName.Substring(1)); return; } zone.Name = info.Name; zone.Controller.MinRank = info.Rank.NextRankUp ?? info.Rank; zone.Controller.Include(info); player.Message("Zone: Creating a {0}+&S zone for player {1}&S. Place a block or type /mark to use your location.", zone.Controller.MinRank.GetClassyName(), info.GetClassyName()); player.SetCallback(2, ZoneAddCallback, zone, cdZoneAdd.Permissions); } else { if (!World.IsValidName(zoneName)) { player.Message("\"{0}\" is not a valid zone name", zoneName); return; } if (player.World.Map.FindZone(zoneName) != null) { player.Message("A zone with this name already exists. Use &H/zedit&S to edit."); return; } zone.Name = zoneName; string rankName = cmd.Next(); if (rankName == null) { player.Message("No rank was specified. See &H/help zone"); return; } Rank minRank = RankManager.ParseRank(rankName); if (minRank != null) { string name; while ((name = cmd.Next()) != null) { if (name.Length == 0) { continue; } PlayerInfo info; if (!PlayerDB.FindPlayerInfo(name.Substring(1), out info)) { player.Message("More than one player found matching \"{0}\"", name.Substring(1)); return; } if (info == null) { player.NoPlayerMessage(name.Substring(1)); return; } if (name.StartsWith("+")) { zone.Controller.Include(info); } else if (name.StartsWith("-")) { zone.Controller.Exclude(info); } } zone.Controller.MinRank = minRank; player.SetCallback(2, ZoneAddCallback, zone, cdZoneAdd.Permissions); player.Message("Zone: Place a block or type /mark to use your location."); } else { player.NoRankMessage(rankName); } } }
internal static void ZoneEdit( Player player, Command cmd ) { bool changesWereMade = false; string zoneName = cmd.Next(); if( zoneName == null ) { player.Message( "No zone name specified. See &H/help zedit" ); return; } Zone zone = player.World.Map.FindZone( zoneName ); if( zone == null ) { player.Message( "No zone found with the name \"{0}\". See &H/zones", zoneName ); return; } string name; while( (name = cmd.Next()) != null ) { if( name.Length < 2 ) continue; if( name.StartsWith( "+" ) ) { PlayerInfo info; if( !PlayerDB.FindPlayerInfo( name.Substring( 1 ), out info ) ) { player.Message( "More than one player found matching \"{0}\"", name.Substring( 1 ) ); return; } if( info == null ) { player.NoPlayerMessage( name.Substring( 1 ) ); return; } // prevent players from whitelisting themselves to bypass protection if( !player.Info.Rank.AllowSecurityCircumvention && player.Info == info ) { if( !zone.Controller.Check( info ) ) { player.Message( "You must be {0}+&S to add yourself to this zone's whitelist.", zone.Controller.MinRank.GetClassyName() ); continue; } } switch( zone.Controller.Include( info ) ) { case PermissionOverride.Deny: player.Message( "{0}&S is no longer excluded from zone {1}", info.GetClassyName(), zone.GetClassyName() ); changesWereMade = true; break; case PermissionOverride.None: player.Message( "{0}&S is now included in zone {1}", info.GetClassyName(), zone.GetClassyName() ); changesWereMade = true; break; case PermissionOverride.Allow: player.Message( "{0}&S is already included in zone {1}", info.GetClassyName(), zone.GetClassyName() ); break; } } else if( name.StartsWith( "-" ) ) { PlayerInfo info; if( !PlayerDB.FindPlayerInfo( name.Substring( 1 ), out info ) ) { player.Message( "More than one player found matching \"{0}\"", name.Substring( 1 ) ); return; } if( info == null ) { player.NoPlayerMessage( name.Substring( 1 ) ); return; } switch( zone.Controller.Exclude( info ) ) { case PermissionOverride.Deny: player.Message( "{0}&S is already excluded from zone {1}", info.GetClassyName(), zone.GetClassyName() ); break; case PermissionOverride.None: player.Message( "{0}&S is now excluded from zone {1}", info.GetClassyName(), zone.GetClassyName() ); changesWereMade = true; break; case PermissionOverride.Allow: player.Message( "{0}&S is no longer included in zone {1}", info.GetClassyName(), zone.GetClassyName() ); changesWereMade = true; break; } } else { Rank minRank = RankManager.ParseRank( name ); if( minRank != null ) { // prevent players from lowering rank so bypass protection if( !player.Info.Rank.AllowSecurityCircumvention && zone.Controller.MinRank > player.Info.Rank && minRank <= player.Info.Rank ) { player.Message( "You are not allowed to lower the zone's rank." ); continue; } if( zone.Controller.MinRank != minRank ) { zone.Controller.MinRank = minRank; player.Message( "Permission for zone \"{0}\" changed to {1}+", zone.Name, minRank.GetClassyName() ); changesWereMade = true; } } else { player.NoRankMessage( name ); } } if( changesWereMade ) { zone.Edit( player.Info ); player.World.Map.ChangedSinceSave = true; } else { player.Message( "No changes were made to the zone." ); } } }
internal static void BanInfo(Player player, Command cmd) { string name = cmd.Next(); IPAddress address; if (name == null) { name = player.Name; } else if (!player.Can(Permission.ViewOthersInfo)) { player.NoAccessMessage(Permission.ViewOthersInfo); return; } if (Server.IsIP(name) && IPAddress.TryParse(name, out address)) { IPBanInfo info = IPBanList.Get(address); if (info != null) { player.Message("{0} was banned by {1} on {2:dd MMM yyyy}.", info.Address, info.BannedBy, info.BanDate); if (!String.IsNullOrEmpty(info.PlayerName)) { player.Message(" IP ban was banned by association with {0}", info.PlayerName); } if (info.Attempts > 0) { player.Message(" There have been {0} attempts to log in, most recently", info.Attempts); player.Message(" on {0:dd MMM yyyy} by {1}.", info.LastAttemptDate, info.LastAttemptName); } if (info.BanReason.Length > 0) { player.Message(" Ban reason: {0}", info.BanReason); } } else { player.Message("{0} is currently NOT banned.", address); } } else { PlayerInfo info; if (!PlayerDB.FindPlayerInfo(name, out info)) { player.Message("More than one player found matching \"{0}\"", name); } else if (info != null) { if (info.Banned) { player.Message("Player {0}&S is &WBANNED", info.GetClassyName()); } else { player.Message("Player {0}&S is NOT banned.", info.GetClassyName()); } if (!String.IsNullOrEmpty(info.BannedBy)) { player.Message(" Last ban by {0} on {1:dd MMM yyyy} ({2} ago).", info.BannedBy, info.BanDate, info.TimeSinceBan.ToMiniString()); if (info.BanReason.Length > 0) { player.Message(" Last ban reason: {0}", info.BanReason); } } if (!String.IsNullOrEmpty(info.UnbannedBy)) { player.Message(" Unbanned by {0} on {1:dd MMM yyyy} ({2} ago).", info.UnbannedBy, info.UnbanDate, info.TimeSinceUnban.ToMiniString()); if (info.UnbanReason.Length > 0) { player.Message(" Last unban reason: {0}", info.UnbanReason); } } if (info.BanDate != DateTime.MinValue) { TimeSpan banDuration; if (info.Banned) { banDuration = info.TimeSinceBan; } else { banDuration = info.UnbanDate.Subtract(info.BanDate); } player.Message(" Last ban duration: {0} days and {1:F1} hours.", (int)banDuration.TotalDays, banDuration.TotalHours); } } else { player.NoPlayerMessage(name); } } }
internal static void Unfreeze( Player player, Command cmd ) { if( player.Can( Permissions.Freeze ) ) { string name = cmd.Next(); Player target = Server.FindPlayer( name ); if( target != null ) { if( target.isFrozen ) { Server.SendToAll( Color.Sys + target.nick + " is no longer frozen." ); target.isFrozen = false; } else { player.Message( target.GetLogName() + " is currently not frozen." ); } } else { player.NoPlayerMessage( name ); } } else { player.NoAccessMessage( Permissions.Freeze ); } }
internal static void TP( Player player, Command cmd ) { if( player.Can( Permissions.Teleport ) ) { string name = cmd.Next(); if( name == null ) { player.Send( PacketWriter.MakeTeleport( 255, player.world.map.spawn ) ); } else { Player target = player.world.FindPlayer( name ); if( target != null ) { Position pos = target.pos; pos.x += 1; pos.y += 1; pos.h += 1; player.Send( PacketWriter.MakeTeleport( 255, pos ) ); } else if( cmd.Next() == null ) { player.NoPlayerMessage( name ); } else { cmd.Rewind(); int x, y, h; if( cmd.NextInt( out x ) && cmd.NextInt( out y ) && cmd.NextInt( out h ) ) { if( x < 0 || x > player.world.map.widthX || y < 0 || y > player.world.map.widthY || y < 0 || y > player.world.map.height ) { player.Message( "Specified coordinates are outside the map!" ); } else { player.pos.Set( x * 32 + 16, y * 32 + 16, h * 32 + 16, player.pos.r, player.pos.l ); player.Send( PacketWriter.MakeTeleport( 255, player.pos ) ); } } else { player.Message( "See " + Color.Help + "/help tp" + Color.Sys + " for information on using /tp" ); } } } } else { player.NoAccessMessage( Permissions.Teleport ); } }
internal static void Where( Player player, Command cmd ) { int offset; string name = cmd.Next(); Player target = player; if( name != null ) { target = Server.FindPlayer( name ); if( target != null ) { player.Message( "Coordinates of player \"" + target.nick + "\" (on \"" + target.world.name + "\"):" ); } else { player.NoPlayerMessage( name ); return; } } offset = (int)(target.pos.r / 255f * 64f) + 32; player.Message( Color.Silver, String.Format( "({0},{1},{2}) - {3}[{4}{5}{6}{3}{7}]", target.pos.x / 32, target.pos.y / 32, target.pos.h / 32, Color.White, compass.Substring( offset - 12, 11 ), Color.Red, compass.Substring( offset - 1, 3 ), compass.Substring( offset + 2, 11 ) ) ); }
// Player information display. // When used without arguments, shows players's own stats. // An optional argument allows to look at other people's stats. internal static void Info( Player player, Command cmd ) { string name = cmd.Next(); if( name == null ) { name = player.name; } else if( !player.Can( Permissions.ViewOthersInfo ) ) { player.NoAccessMessage( Permissions.ViewOthersInfo ); return; } Player target = Server.FindPlayerByNick( name ); if( target != null && target.nick != target.name ) { player.Message( Color.Red, "Warning: Player named " + target.name + " is using a nickname \"" + target.nick + "\"" ); player.Message( Color.Red, "The information below is for the REAL " + name ); } PlayerInfo info; if( !PlayerDB.FindPlayerInfo( name, out info ) ) { player.ManyPlayersMessage( name ); } else if( info != null ) { if( DateTime.Now.Subtract( info.lastLoginDate ).TotalDays < 1 ) { player.Message( String.Format( "About {0}: Last login {1:F1} hours ago from {2}", info.name, DateTime.Now.Subtract( info.lastLoginDate ).TotalHours, info.lastIP ) ); } else { player.Message( String.Format( "About {0}: Last login {1:F1} days ago from {2}", info.name, DateTime.Now.Subtract( info.lastLoginDate ).TotalDays, info.lastIP ) ); } player.Message( String.Format( " Logged in {0} time(s) since {1:dd MMM yyyy}.", info.timesVisited, info.firstLoginDate ) ); player.Message( String.Format( " Built {0} and deleted {1} blocks, and wrote {2} messages.", info.blocksBuilt, info.blocksDeleted, info.linesWritten ) ); if( player.info.classChangedBy != "-" ) { player.Message( String.Format( " Promoted to {0} by {1} on {2:dd MMM yyyy}.", info.playerClass.name, info.classChangedBy, info.classChangeDate ) ); } else { player.Message( String.Format( " Class is {0} (default).", info.playerClass.name ) ); } TimeSpan totalTime = info.totalTimeOnServer; if( Server.FindPlayerExact( player.name ) != null ) { totalTime = totalTime.Add( DateTime.Now.Subtract( info.lastLoginDate ) ); } player.Message( String.Format( " Spent a total of {0:F1} hours ({1:F1} minutes) here.", totalTime.TotalHours, totalTime.TotalMinutes ) ); } else { player.NoPlayerMessage( name ); } }
// Shows ban information. // When used without arguments, shows players's own ban stats. // An optional argument allows to look at other people's ban stats. internal static void BanInfo( Player player, Command cmd ) { string name = cmd.Next(); IPAddress address; if( name == null ) { name = player.name; } else if( !player.Can( Permissions.ViewOthersInfo ) ) { player.NoAccessMessage( Permissions.ViewOthersInfo ); } else if( IPAddress.TryParse( name, out address ) ) { IPBanInfo info = IPBanList.Get( address ); if( info != null ) { player.Message( String.Format( "{0} was banned by {1} on {2:dd MMM yyyy}.", info.address, info.bannedBy, info.banDate ) ); if( info.playerName != null ) { player.Message( " IP ban was banned by association with " + info.playerName ); } if( info.attempts > 0 ) { player.Message( " There have been " + info.attempts + " attempts to log in, most recently" ); player.Message( String.Format( " on {0:dd MMM yyyy} by {1}.", info.lastAttemptDate, info.lastAttemptName ) ); } if( info.banReason != "" ) { player.Message( " Memo: " + info.banReason ); } } else { player.Message( address.ToString() + " is currently NOT banned." ); } } else { PlayerInfo info; if( !PlayerDB.FindPlayerInfo( name, out info ) ) { player.ManyPlayersMessage( name ); } else if( info != null ) { if( info.banned ) { player.Message( "Player " + info.name + " is currently " + Color.Red + "banned." ); } else { player.Message( "Player " + info.name + " is currently NOT banned." ); } if( info.bannedBy != "-" ) { player.Message( String.Format( " Last banned by {0} on {1:dd MMM yyyy}.", info.bannedBy, info.banDate ) ); if( info.banReason != "" ) { player.Message( " Ban memo: " + info.banReason ); } } if( info.unbannedBy != "-" ) { player.Message( String.Format( " Unbanned by {0} on {1:dd MMM yyyy}.", info.unbannedBy, info.unbanDate ) ); if( info.unbanReason != "" ) { player.Message( " Unban memo: " + info.unbanReason ); } } if( info.banDate != DateTime.MinValue ) { TimeSpan banDuration; if( info.banned ) { banDuration = DateTime.Now.Subtract( info.banDate ); } else { banDuration = info.unbanDate.Subtract( info.banDate ); } player.Message( String.Format( " Last ban duration: {0} days and {1:F1} hours.", (int)banDuration.TotalDays, banDuration.TotalHours ) ); } } else { player.NoPlayerMessage( name ); } } }
/// <summary>Find player by name using autocompletion (returns only whose whom player can see) /// Returns null and prints message if none or multiple players matched.</summary> /// <param name="player">Player who initiated the search. This is where messages are sent.</param> /// <param name="name">Full or partial name of the search target.</param> /// <param name="includeHidden">Whether to include hidden players in the search.</param> /// <returns>Player object, or null if no player was found.</returns> public static Player FindPlayerOrPrintMatches( Player player, string name, bool includeHidden ) { if( player == null ) throw new ArgumentNullException( "player" ); if( name == null ) throw new ArgumentNullException( "name" ); Player[] matches; if( includeHidden ) { matches = FindPlayers( name ); } else { matches = FindPlayers( player, name ); } if( matches.Length == 0 ) { player.NoPlayerMessage( name ); return null; } else if( matches.Length > 1 ) { player.ManyMatchesMessage( "player", matches ); return null; } else { return matches[0]; } }
internal static void Info( Player player, Command cmd ) { string name = cmd.Next(); if( name == null ) { name = player.Name; } else if( !player.Can( Permission.ViewOthersInfo ) ) { player.NoAccessMessage( Permission.ViewOthersInfo ); return; } IPAddress ip; PlayerInfo[] infos; if( Server.IsIP( name ) && IPAddress.TryParse( name, out ip ) ) { // find players by IP infos = PlayerDB.FindPlayers( ip, PlayerDB.NumberOfMatchesToPrint ); } else if( name.Contains( "*" ) || name.Contains( "." ) ) { // find players by regex/wildcard string regexString = "^" + RegexNonNameChars.Replace( name, "" ).Replace( "*", ".*" ) + "$"; Regex regex = new Regex( regexString, RegexOptions.IgnoreCase | RegexOptions.Compiled ); infos = PlayerDB.FindPlayers( regex, PlayerDB.NumberOfMatchesToPrint ); } else { // find players by partial matching PlayerInfo tempInfo; if( !PlayerDB.FindPlayerInfo( name, out tempInfo ) ) { infos = PlayerDB.FindPlayers( name, PlayerDB.NumberOfMatchesToPrint ); } else if( tempInfo == null ) { player.NoPlayerMessage( name ); return; } else { infos = new[] { tempInfo }; } } if( infos.Length == 1 ) { PrintPlayerInfo( player, infos[0] ); } else if( infos.Length > 1 ) { player.ManyMatchesMessage( "player", infos ); if( infos.Length == PlayerDB.NumberOfMatchesToPrint ) { player.Message( "NOTE: Only first {0} matches are shown.", PlayerDB.NumberOfMatchesToPrint ); } } else { player.NoPlayerMessage( name ); } }
internal static void BanInfo( Player player, Command cmd ) { string name = cmd.Next(); IPAddress address; if( name == null ) { name = player.Name; } else if( !player.Can( Permission.ViewOthersInfo ) ) { player.NoAccessMessage( Permission.ViewOthersInfo ); return; } if( Server.IsIP( name ) && IPAddress.TryParse( name, out address ) ) { IPBanInfo info = IPBanList.Get( address ); if( info != null ) { player.Message( "{0} was banned by {1} on {2:dd MMM yyyy}.", info.Address, info.BannedBy, info.BanDate ); if( !String.IsNullOrEmpty( info.PlayerName ) ) { player.Message( " IP ban was banned by association with {0}", info.PlayerName ); } if( info.Attempts > 0 ) { player.Message( " There have been {0} attempts to log in, most recently", info.Attempts ); player.Message( " on {0:dd MMM yyyy} by {1}.", info.LastAttemptDate, info.LastAttemptName ); } if( info.BanReason.Length > 0 ) { player.Message( " Ban reason: {0}", info.BanReason ); } } else { player.Message( "{0} is currently NOT banned.", address ); } } else { PlayerInfo info; if( !PlayerDB.FindPlayerInfo( name, out info ) ) { player.Message( "More than one player found matching \"{0}\"", name ); } else if( info != null ) { if( info.Banned ) { player.Message( "Player {0}&S is &WBANNED", info.GetClassyName() ); } else { player.Message( "Player {0}&S is NOT banned.", info.GetClassyName() ); } if( !String.IsNullOrEmpty( info.BannedBy ) ) { player.Message( " Last ban by {0} on {1:dd MMM yyyy} ({2} ago).", info.BannedBy, info.BanDate, info.TimeSinceBan.ToMiniString() ); if( info.BanReason.Length > 0 ) { player.Message( " Last ban reason: {0}", info.BanReason ); } } if( !String.IsNullOrEmpty( info.UnbannedBy ) ) { player.Message( " Unbanned by {0} on {1:dd MMM yyyy} ({2} ago).", info.UnbannedBy, info.UnbanDate, info.TimeSinceUnban.ToMiniString() ); if( info.UnbanReason.Length > 0 ) { player.Message( " Last unban reason: {0}", info.UnbanReason ); } } if( info.BanDate != DateTime.MinValue ) { TimeSpan banDuration; if( info.Banned ) { banDuration = info.TimeSinceBan; } else { banDuration = info.UnbanDate.Subtract( info.BanDate ); } player.Message( " Last ban duration: {0} days and {1:F1} hours.", (int)banDuration.TotalDays, banDuration.TotalHours ); } } else { player.NoPlayerMessage( name ); } } }
internal static void Info(Player player, Command cmd) { string name = cmd.Next(); if (name == null) { name = player.Name; } else if (!player.Can(Permission.ViewOthersInfo)) { player.NoAccessMessage(Permission.ViewOthersInfo); return; } IPAddress ip; PlayerInfo[] infos; if (Server.IsIP(name) && IPAddress.TryParse(name, out ip)) { // find players by IP infos = PlayerDB.FindPlayers(ip, PlayerDB.NumberOfMatchesToPrint); } else if (name.Contains("*") || name.Contains(".")) { // find players by regex/wildcard string regexString = "^" + RegexNonNameChars.Replace(name, "").Replace("*", ".*") + "$"; Regex regex = new Regex(regexString, RegexOptions.IgnoreCase | RegexOptions.Compiled); infos = PlayerDB.FindPlayers(regex, PlayerDB.NumberOfMatchesToPrint); } else { // find players by partial matching PlayerInfo tempInfo; if (!PlayerDB.FindPlayerInfo(name, out tempInfo)) { infos = PlayerDB.FindPlayers(name, PlayerDB.NumberOfMatchesToPrint); } else if (tempInfo == null) { player.NoPlayerMessage(name); return; } else { infos = new[] { tempInfo }; } } if (infos.Length == 1) { PrintPlayerInfo(player, infos[0]); } else if (infos.Length > 1) { player.ManyMatchesMessage("player", infos); if (infos.Length == PlayerDB.NumberOfMatchesToPrint) { player.Message("NOTE: Only first {0} matches are shown.", PlayerDB.NumberOfMatchesToPrint); } } else { player.NoPlayerMessage(name); } }
internal static void DoBan( Player player, Command cmd, bool banIP, bool banAll, bool unban ) { if( !player.Can( Permissions.Ban ) ) { player.NoAccessMessage( Permissions.Ban ); return; } else if( banIP && !player.Can( Permissions.BanIP ) ) { player.NoAccessMessage( Permissions.BanIP ); return; } else if( banAll && !player.Can( Permissions.BanAll ) ) { player.NoAccessMessage( Permissions.BanAll ); return; } string arg = cmd.Next(); string reason = cmd.NextAll(); IPAddress address; Player offender = Server.FindPlayer( arg ); PlayerInfo info = PlayerDB.FindPlayerInfoExact( arg ); // ban by IP address if( banIP && IPAddress.TryParse( arg, out address ) ) { DoIPBan( player, address, reason, null, banAll, unban ); // ban online players } else if( !unban && offender != null ) { // check permissions if( !player.info.playerClass.CanBan( offender.info.playerClass ) ) { player.Message( "You can only ban players ranked " + player.info.playerClass.maxBan.color + player.info.playerClass.maxBan.name + Color.Sys + " or lower." ); player.Message( offender.GetLogName() + " is ranked " + offender.info.playerClass.name + "." ); } else { address = offender.info.lastIP; if( banIP ) DoIPBan( player, address, reason, offender.name, banAll, unban ); if( offender.info.ProcessBan( player.name, reason ) ) { Logger.Log( "{0} was banned by {1}.", LogType.UserActivity, offender.info.name, player.GetLogName() ); Server.SendToAll( Color.Red + offender.name + " was banned by " + player.nick, offender ); offender.session.Kick( "You were just banned by " + player.GetLogName() ); } else { player.Message( offender.name + " is already banned." ); } } // ban offline players } else if( info != null ) { if( !player.info.playerClass.CanBan( info.playerClass ) ) { PlayerClass maxRank = player.info.playerClass.maxBan; if( maxRank == null ) { player.Message( "You can only ban players ranked " + player.info.playerClass.color + player.info.playerClass.name + Color.Sys + " or lower." ); } else { player.Message( "You can only ban players ranked " + maxRank.color + maxRank.name + Color.Sys + " or lower." ); } player.Message( info.name + " is ranked " + info.playerClass.name + "." ); } else { address = info.lastIP; if( banIP ) DoIPBan( player, address, reason, info.name, banAll, unban ); if( unban ) { if( info.ProcessUnBan( player.name, reason ) ) { Logger.Log( "{0} (offline) was unbanned by {1}", LogType.UserActivity, info.name, player.GetLogName() ); Server.SendToAll( Color.Red + info.name + " (offline) was unbanned by " + player.nick ); } else { player.Message( info.name + " (offline) is not currenty banned." ); } } else { if( info.ProcessBan( player.name, reason ) ) { Logger.Log( "{0} (offline) was banned by {1}.", LogType.UserActivity, info.name, player.GetLogName() ); Server.SendToAll( Color.Red + info.name + " (offline) was banned by " + player.nick ); } else { player.Message( info.name + " (offline) is already banned." ); } } } } else { player.NoPlayerMessage( arg ); player.Message( "Use the FULL player name for ban/unban commands." ); } }
internal static void Freeze( Player player, Command cmd ) { if( player.Can( Permissions.Freeze ) ) { string name = cmd.Next(); Player target = Server.FindPlayer( name ); if( target != null ) { if( !target.isFrozen ) { Server.SendToAll( Color.Sys + target.nick + " has been frozen by " + player.nick ); target.isFrozen = true; } else { player.Message( target.GetLogName() + " is already frozen." ); } } else { player.NoPlayerMessage( name ); } } else { player.NoAccessMessage( Permissions.Freeze ); } }
internal static void Whois( Player player, Command cmd ) { string name = cmd.Next(); if( name == null ) { player.Message( "Usage: " + Color.Help + "/whois PlayerNickname" ); return; } Player target = Server.FindPlayerByNick( name ); if( target != null ) { if( target.nick != target.name ) { player.Message( "Player named " + target.name + " is using a nickname \"" + target.nick + "\"" ); } else { player.Message( "Player named " + target.name + " is not using any nickname." ); } } else { player.NoPlayerMessage( name ); } }
// Kick a player. One argument (mandatory) - player name (can be partial). internal static void Kick( Player player, Command cmd ) { if( !player.Can( Permissions.Kick ) ) { player.NoAccessMessage( Permissions.Kick ); return; } string name = cmd.Next(); if( name != null ) { string msg = cmd.NextAll(); Player offender = Server.FindPlayer( name ); if( offender != null ) { if( !player.info.playerClass.CanKick( offender.info.playerClass ) ) { player.Message( "You can only kick players ranked " + player.info.playerClass.maxKick.color + player.info.playerClass.maxKick.name + Color.Sys + " or lower." ); player.Message( offender.GetLogName() + " is ranked " + offender.info.playerClass.name + "." ); } else { Server.SendToAll( Color.Red + offender.nick + " was kicked by " + player.nick ); if( msg != null && msg != "" ) { Logger.Log( "{0} was kicked by {1}. Memo: {2}", LogType.UserActivity, offender.GetLogName(), player.GetLogName(), msg ); offender.session.Kick( "Kicked by " + player.GetLogName() + ": " + msg ); } else { Logger.Log( "{0} was kicked by {1}", LogType.UserActivity, offender.GetLogName(), player.GetLogName() ); offender.session.Kick( "You have been kicked by " + player.GetLogName() ); } } } else { player.NoPlayerMessage( name ); } } else { player.Message( "Usage: " + Color.Help + "/kick PlayerName [Message]" + Color.Sys + " or " + Color.Help + "/k PlayerName [Message]" ); } }
internal static void Unignore( Player player, Command cmd ) { string name = cmd.Next(); if( name != null ) { PlayerInfo targetInfo; if( !PlayerDB.FindPlayerInfo( name, out targetInfo ) ) { PlayerInfo[] infos = PlayerDB.FindPlayers( name ); if( infos.Length == 1 ) { targetInfo = infos[0]; } else if( infos.Length > 1 ) { player.ManyMatchesMessage( "player", infos ); return; } else { player.NoPlayerMessage( name ); return; } } else if( targetInfo == null ) { player.NoPlayerMessage( name ); return; } if( player.Unignore( targetInfo ) ) { player.MessageNow( "You are no longer ignoring {0}", targetInfo.GetClassyName() ); } else { player.MessageNow( "You are not currently ignoring {0}", targetInfo.GetClassyName() ); } } else { PlayerInfo[] ignoreList = player.GetIgnoreList(); if( ignoreList.Length > 0 ) { player.MessageNow( "Ignored players: {0}", ignoreList.JoinToClassyString() ); } else { player.MessageNow( "You are not currently ignoring anyone." ); } return; } }
// Change player class internal static void ChangeClass( Player player, Command cmd ) { string name = cmd.Next(); string newClassName = cmd.Next(); if( name == null || newClassName == null ) { player.Message( "Usage: " + Color.Help + "/user PlayerName ClassName" ); player.Message( "To see a list of classes and permissions, use " + Color.Help + "/class" ); return; } Player target = Server.FindPlayer( name ); if( target == null ) { player.NoPlayerMessage( name ); return; } PlayerClass newClass = ClassList.FindClass( newClassName ); if( newClass == null ) { player.Message( "Unrecognized player class: " + newClassName ); return; } if( target.info.playerClass == newClass ) { player.Message( target.GetLogName() + " is already " + newClass.color + newClass.name ); return; } bool promote = target.info.playerClass.rank < newClass.rank; if( (promote && !player.Can( Permissions.Promote )) ) { player.NoAccessMessage( Permissions.Promote ); return; } else if( !promote && !player.Can( Permissions.Demote ) ) { player.NoAccessMessage( Permissions.Demote ); return; } if( promote && !player.info.playerClass.CanPromote( newClass ) ) { player.Message( "You can only promote players up to " + player.info.playerClass.maxPromote.color + player.info.playerClass.maxPromote.name ); player.Message( target.GetLogName() + " is ranked " + target.info.playerClass.name + "." ); return; } else if( !promote && !player.info.playerClass.CanDemote( target.info.playerClass ) ) { player.Message( "You can only demote players that are " + player.info.playerClass.maxDemote.color + player.info.playerClass.maxDemote.name + Color.Sys + " or lower." ); player.Message( target.GetLogName() + " is ranked " + target.info.playerClass.name + "." ); return; } if( promote && target.info.playerClass.rank < newClass.rank || target.info.playerClass.rank > newClass.rank ) { PlayerClass oldClass = target.info.playerClass; if( !Server.FirePlayerClassChange( target, player, oldClass, newClass ) ) return; Logger.Log( "{0} changed the class of {1} from {2} to {3}.", LogType.UserActivity, player.GetLogName(), target.GetLogName(), target.info.playerClass.name, newClass.name ); target.info.playerClass = newClass; target.info.classChangeDate = DateTime.Now; target.info.classChangedBy = player.name; Server.FirePlayerListChangedEvent(); target.Send( PacketWriter.MakeSetPermission( target ) ); target.mode = BlockPlacementMode.Normal; if( promote ) { player.Message( "You promoted " + target.name + " to " + newClass.color + newClass.name ); target.Message( "You have been promoted to " + newClass.color + newClass.name + Color.Sys + " by " + player.nick ); } else { player.Message( "You demoted " + target.name + " to " + newClass.color + newClass.name ); target.Message( "You have been demoted to " + newClass.color + newClass.name + Color.Sys + " by " + player.nick ); } if( Config.GetBool( ConfigKey.ClassPrefixesInList ) || Config.GetBool( ConfigKey.ClassColorsInChat ) ) { target.world.UpdatePlayer( target ); } } else { if( promote ) { player.Message( target.GetLogName() + " is already same or lower rank than " + newClass.name ); } else { player.Message( target.GetLogName() + " is already same or higher rank than " + newClass.name ); } } }
internal static void WorldBuild( Player player, Command cmd ) { string worldName = cmd.Next(); // Print information about the current world if( worldName == null ) { if( player == Player.Console ) { player.Message( "When calling /wbuild from console, you must specify a world name." ); } else { player.World.BuildSecurity.PrintDescription( player, player.World, "world", "modified" ); } return; } // Find a world by name World world = WorldManager.FindWorldOrPrintMatches( player, worldName ); if( world == null ) return; string name = cmd.Next(); if( name == null ) { world.BuildSecurity.PrintDescription( player, world, "world", "modified" ); return; } bool changesWereMade = false; do { if( name.Length < 2 ) continue; // Whitelisting individuals if( name.StartsWith( "+" ) ) { PlayerInfo info; if( !PlayerDB.FindPlayerInfo( name.Substring( 1 ), out info ) ) { player.Message( "More than one player found matching \"{0}\"", name.Substring( 1 ) ); continue; } else if( info == null ) { player.NoPlayerMessage( name.Substring( 1 ) ); continue; } // prevent players from whitelisting themselves to bypass protection if( player.Info == info && !player.Info.Rank.AllowSecurityCircumvention ) { switch( world.BuildSecurity.CheckDetailed( player.Info ) ) { case SecurityCheckResult.RankTooLow: player.Message( "&WYou must be {0}&W+ to add yourself to the build whitelist of {0}", world.BuildSecurity.MinRank.GetClassyName(), world.GetClassyName() ); continue; // TODO: RankTooHigh case SecurityCheckResult.BlackListed: player.Message( "&WYou cannot remove yourself from the build blacklist of {0}", world.GetClassyName() ); continue; } } if( world.BuildSecurity.CheckDetailed( info ) == SecurityCheckResult.Allowed ) { player.Message( "{0}&S is already allowed to build in {1}&S (by rank)", info.GetClassyName(), world.GetClassyName() ); continue; } Player target = Server.FindPlayerExact( info ); if( target == player ) target = null; // to avoid duplicate messages switch( world.BuildSecurity.Include( info ) ) { case PermissionOverride.Deny: if( world.BuildSecurity.Check( info ) ) { player.Message( "{0}&S is no longer barred from building in {1}", info.GetClassyName(), world.GetClassyName() ); if( target != null ) { target.Message( "You can now build in world {0}&S (removed from blacklist by {1}&S).", world.GetClassyName(), player.GetClassyName() ); } } else { player.Message( "{0}&S was removed from the build blacklist of {1}&S. " + "Player is still NOT allowed to build (by rank).", info.GetClassyName(), world.GetClassyName() ); if( target != null ) { target.Message( "You were removed from the build blacklist of world {0}&S by {1}&S. " + "You are still NOT allowed to build (by rank).", player.GetClassyName(), world.GetClassyName() ); } } Logger.Log( "{0} removed {1} from the build blacklist of {2}", LogType.UserActivity, player.Name, info.Name, world.Name ); changesWereMade = true; break; case PermissionOverride.None: player.Message( "{0}&S is now allowed to build in {1}", info.GetClassyName(), world.GetClassyName() ); if( target != null ) { target.Message( "You can now build in world {0}&S (whitelisted by {1}&S).", world.GetClassyName(), player.GetClassyName() ); } Logger.Log( "{0} added {1} to the build whitelist on world {2}", LogType.UserActivity, player.Name, info.Name, world.Name ); changesWereMade = true; break; case PermissionOverride.Allow: player.Message( "{0}&S is already on the build whitelist of {1}", info.GetClassyName(), world.GetClassyName() ); break; } // Blacklisting individuals } else if( name.StartsWith( "-" ) ) { PlayerInfo info; if( !PlayerDB.FindPlayerInfo( name.Substring( 1 ), out info ) ) { player.Message( "More than one player found matching \"{0}\"", name.Substring( 1 ) ); continue; } else if( info == null ) { player.NoPlayerMessage( name.Substring( 1 ) ); continue; } if( world.BuildSecurity.CheckDetailed( info ) == SecurityCheckResult.RankTooHigh || world.BuildSecurity.CheckDetailed( info ) == SecurityCheckResult.RankTooLow ) { player.Message( "{0}&S is already barred from building in {1}&S (by rank)", info.GetClassyName(), world.GetClassyName() ); continue; } Player target = Server.FindPlayerExact( info ); if( target == player ) target = null; // to avoid duplicate messages switch( world.BuildSecurity.Exclude( info ) ) { case PermissionOverride.Deny: player.Message( "{0}&S is already on build blacklist of {1}", info.GetClassyName(), world.GetClassyName() ); break; case PermissionOverride.None: player.Message( "{0}&S is now barred from building in {1}", info.GetClassyName(), world.GetClassyName() ); if( target != null ) { target.Message( "&WYou were barred by {0}&W from building in world {1}", player.GetClassyName(), world.GetClassyName() ); } Logger.Log( "{0} added {1} to the build blacklist on world {2}", LogType.UserActivity, player.Name, info.Name, world.Name ); changesWereMade = true; break; case PermissionOverride.Allow: if( world.BuildSecurity.Check( info ) ) { player.Message( "{0}&S is no longer on the build whitelist of {1}&S. " + "Player is still allowed to build (by rank).", info.GetClassyName(), world.GetClassyName() ); if( target != null ) { target.Message( "You were removed from the build whitelist of world {0}&S by {1}&S. " + "You are still allowed to build (by rank).", player.GetClassyName(), world.GetClassyName() ); } } else { player.Message( "{0}&S is no longer allowed to build in {1}", info.GetClassyName(), world.GetClassyName() ); if( target != null ) { target.Message( "&WYou can no longer build in world {0}&W (removed from whitelist by {1}&W).", world.GetClassyName(), player.GetClassyName() ); } } Logger.Log( "{0} removed {1} from the build whitelist on world {2}", LogType.UserActivity, player.Name, info.Name, world.Name ); changesWereMade = true; break; } // Setting minimum rank } else { Rank rank = RankManager.FindRank( name ); if( rank == null ) { player.NoRankMessage( name ); } else if( !player.Info.Rank.AllowSecurityCircumvention && world.BuildSecurity.MinRank > rank && world.BuildSecurity.MinRank > player.Info.Rank ) { player.Message( "&WYou must be ranked {0}&W+ to lower build restrictions for world {1}", world.BuildSecurity.MinRank.GetClassyName(), world.GetClassyName() ); } else { // list players who are redundantly blacklisted SecurityController.PlayerListCollection lists = world.BuildSecurity.ExceptionList; PlayerInfo[] noLongerExcluded = lists.Excluded.Where( excludedPlayer => excludedPlayer.Rank < rank ).ToArray(); if( noLongerExcluded.Length > 0 ) { player.Message( "Following players no longer need to be blacklisted on world {0}&S: {1}", world.GetClassyName(), noLongerExcluded.JoinToClassyString() ); } // list players who are redundantly whitelisted PlayerInfo[] noLongerIncluded = lists.Included.Where( includedPlayer => includedPlayer.Rank >= rank ).ToArray(); if( noLongerIncluded.Length > 0 ) { player.Message( "Following players no longer need to be whitelisted on world {0}&S: {1}", world.GetClassyName(), noLongerIncluded.JoinToClassyString() ); } // apply changes world.BuildSecurity.MinRank = rank; changesWereMade = true; if( world.BuildSecurity.MinRank == RankManager.LowestRank ) { Server.SendToAll( "{0}&S allowed anyone to build on world {1}", player.GetClassyName(), world.GetClassyName() ); } else { Server.SendToAll( "{0}&S allowed only {1}+&S to build in world {2}", player.GetClassyName(), world.BuildSecurity.MinRank.GetClassyName(), world.GetClassyName() ); } Logger.Log( "{0} set build rank for world {1} to {2}+", LogType.UserActivity, player.Name, world.Name, world.BuildSecurity.MinRank.Name ); } } } while( (name = cmd.Next()) != null ); if( changesWereMade ) { WorldManager.SaveWorldList(); } }
internal static void ZoneAdd( Player player, Command cmd ) { string zoneName = cmd.Next(); if( zoneName == null ) { cdZoneAdd.PrintUsage( player ); return; } Zone zone = new Zone(); if( zoneName.StartsWith( "+" ) ) { PlayerInfo info; if( !PlayerDB.FindPlayerInfo( zoneName.Substring( 1 ), out info ) ) { player.Message( "More than one player found matching \"{0}\"", zoneName.Substring( 1 ) ); return; } if( info == null ) { player.NoPlayerMessage( zoneName.Substring( 1 ) ); return; } zone.Name = info.Name; zone.Controller.MinRank = info.Rank.NextRankUp ?? info.Rank; zone.Controller.Include( info ); player.Message( "Zone: Creating a {0}+&S zone for player {1}&S. Place a block or type /mark to use your location.", zone.Controller.MinRank.GetClassyName(), info.GetClassyName() ); player.SetCallback( 2, ZoneAddCallback, zone, cdZoneAdd.Permissions ); } else { if( !World.IsValidName( zoneName ) ) { player.Message( "\"{0}\" is not a valid zone name", zoneName ); return; } if( player.World.Map.FindZone( zoneName ) != null ) { player.Message( "A zone with this name already exists. Use &H/zedit&S to edit." ); return; } zone.Name = zoneName; string rankName = cmd.Next(); if( rankName == null ) { player.Message( "No rank was specified. See &H/help zone" ); return; } Rank minRank = RankManager.ParseRank( rankName ); if( minRank != null ) { string name; while( (name = cmd.Next()) != null ) { if( name.Length == 0 ) continue; PlayerInfo info; if( !PlayerDB.FindPlayerInfo( name.Substring( 1 ), out info ) ) { player.Message( "More than one player found matching \"{0}\"", name.Substring( 1 ) ); return; } if( info == null ) { player.NoPlayerMessage( name.Substring( 1 ) ); return; } if( name.StartsWith( "+" ) ) { zone.Controller.Include( info ); } else if( name.StartsWith( "-" ) ) { zone.Controller.Exclude( info ); } } zone.Controller.MinRank = minRank; player.SetCallback( 2, ZoneAddCallback, zone, cdZoneAdd.Permissions ); player.Message( "Zone: Place a block or type /mark to use your location." ); } else { player.NoRankMessage( rankName ); } } }
internal static void SetInfo( Player player, Command cmd ) { string targetName = cmd.Next(); string propertyName = cmd.Next(); string valName = cmd.NextAll(); if( targetName == null || propertyName == null ) { cdSetInfo.PrintUsage( player ); return; } PlayerInfo info; if( !PlayerDB.FindPlayerInfo( targetName, out info ) ) { player.Message( "More than one player found matching \"{0}\"", targetName ); } else if( info == null ) { player.NoPlayerMessage( targetName ); } else { switch( propertyName.ToLower() ) { case "timeskicked": int oldTimesKicked = info.TimesKicked; if( ValidateInt( valName, 0, 1000 ) ) { info.TimesKicked = Int32.Parse( valName ); player.Message( "TimesKicked for {0}&S changed from {1} to {2}", info.GetClassyName(), oldTimesKicked, info.TimesKicked ); } else { player.Message( "Value not in valid range (0...1000)" ); } return; case "previousrank": Rank newPreviousRank = RankManager.ParseRank( valName ); Rank oldPreviousRank = info.PreviousRank; if( newPreviousRank != null ) { info.PreviousRank = newPreviousRank; player.Message( "PreviousRank for {0}&S changed from {1}&S to {2}", info.GetClassyName(), oldPreviousRank.GetClassyName(), info.PreviousRank.GetClassyName() ); } else { player.NoRankMessage( valName ); } return; case "totaltime": TimeSpan newTotalTime; TimeSpan oldTotalTime = info.TotalTime; if( TimeSpan.TryParse( valName, out newTotalTime ) ) { info.TotalTime = newTotalTime; player.Message( "TotalTime for {0}&S changed from {1} to {2}", info.GetClassyName(), oldTotalTime.ToCompactString(), info.TotalTime.ToCompactString() ); } else { player.Message( "Could not parse time. Expected format: Days.HH:MM:SS" ); } return; case "rankchangetype": RankChangeType oldType = info.RankChangeType; foreach( string val in Enum.GetNames( typeof( RankChangeType ) ) ) { if( val.Equals( valName, StringComparison.OrdinalIgnoreCase ) ) { info.RankChangeType = (RankChangeType)Enum.Parse( typeof( RankChangeType ), valName, true ); player.Message( "RankChangeType for {0}&S changed from {1} to {2}", info.GetClassyName(), oldType, info.RankChangeType ); return; } } player.Message( "Could not parse RankChangeType. Allowed values: {0}", String.Join( ", ", Enum.GetNames( typeof( RankChangeType ) ) ) ); return; case "banreason": string oldBanReason = info.BanReason; info.BanReason = valName; player.Message( "BanReason for {0}&S changed from \"{1}\" to \"{2}\"", info.GetClassyName(), oldBanReason, info.BanReason ); return; case "unbanreason": string oldUnbanReason = info.UnbanReason; info.UnbanReason = valName; player.Message( "UnbanReason for {0}&S changed from \"{1}\" to \"{2}\"", info.GetClassyName(), oldUnbanReason, info.UnbanReason ); return; case "rankchangereason": string oldRankChangeReason = info.RankChangeReason; info.RankChangeReason = valName; player.Message( "RankChangeReason for {0}&S changed from \"{1}\" to \"{2}\"", info.GetClassyName(), oldRankChangeReason, info.RankChangeReason ); return; case "lastkickreason": string oldLastKickReason = info.LastKickReason; info.LastKickReason = valName; player.Message( "LastKickReason for {0}&S changed from \"{1}\" to \"{2}\"", info.GetClassyName(), oldLastKickReason, info.LastKickReason ); return; default: player.Message( "Only the following properties are editable: " + "TimesKicked, PreviousRank, TotalTime, RankChangeType, " + "BanReason, UnbanReason, RankChangeReason, LastKickReason" ); return; } } }