internal static void StaffChat( Player player, Command cmd ) { if( player.Info.IsMuted ) { player.MutedMessage(); return; } if( DateTime.UtcNow < player.Info.MutedUntil ) { player.Message( "You are muted for another {0:0} seconds.", player.Info.MutedUntil.Subtract( DateTime.UtcNow ).TotalSeconds ); return; } Player[] plist = Server.PlayerList; if( plist.Length > 0 ) player.Info.LinesWritten++; string message = cmd.NextAll(); if( message != null && message.Trim().Length > 0 ) { message = message.Trim(); if( player.Can( Permission.UseColorCodes ) && message.Contains( "%" ) ) { message = Color.ReplacePercentCodes( message ); } for( int i = 0; i < plist.Length; i++ ) { if( (plist[i].Can( Permission.ReadStaffChat ) || plist[i] == player) && !plist[i].IsIgnoring( player.Info ) ) { plist[i].Message( "{0}(staff){1}{0}: {2}", Color.PM, player.GetClassyName(), message ); } } } }
internal static void PlayerMessageHandler(Player player, World world, ref string message, ref bool cancel) { if (ConfigKey.IRCBotForwardFromServer.GetBool()) { SendChannelMessage(player.GetClassyName() + Color.IRCReset + ": " + message); } else if (message.StartsWith("#")) { SendChannelMessage(player.GetClassyName() + Color.IRCReset + ": " + message.Substring(1)); } }
public bool Lock(Player player) { if (player == null) { throw new ArgumentNullException("player"); } lock ( lockLock ) { if (IsLocked) { return(false); } else { LockedBy = player.Name; LockedDate = DateTime.UtcNow; IsLocked = true; if (Map != null) { Map.ClearUpdateQueue(); } SendToAll("&WMap was locked by {0}", player.GetClassyName()); Logger.Log("World {0} was locked by {1}", LogType.UserActivity, Name, player.Name); return(true); } } }
public bool Spectate(Player target) { if (target == null) { throw new ArgumentNullException("target"); } if (target == this) { throw new ArgumentException("Cannot spectate self.", "target"); } Message("Now spectating {0}&S. Type &H/unspec&S to stop.", target.GetClassyName()); return(Interlocked.Exchange <Player>(ref Session.SpectatedPlayer, target) == null); }
public bool StopSpectating() { Player wasSpectating = Interlocked.Exchange <Player>(ref Session.SpectatedPlayer, null); if (wasSpectating != null) { Message("Stopped spectating {0}", wasSpectating.GetClassyName()); return(true); } else { return(false); } }
static void PlayerSomethingMessage(Player player, string action, PlayerInfo target, string reason) { string message = String.Format("{0}&W* {1}&W was {2} by {3}&W", Color.IRCBold, target.GetClassyName(), action, player.GetClassyName()); if (!String.IsNullOrEmpty(reason)) { message += " Reason: " + reason; } if (ConfigKey.IRCBotAnnounceServerEvents.GetBool()) { SendAction(message); } }
internal static void StaffChat(Player player, Command cmd) { if (player.Info.IsMuted) { player.MutedMessage(); return; } if (DateTime.UtcNow < player.Info.MutedUntil) { player.Message("You are muted for another {0:0} seconds.", player.Info.MutedUntil.Subtract(DateTime.UtcNow).TotalSeconds); return; } Player[] plist = Server.PlayerList; if (plist.Length > 0) { player.Info.LinesWritten++; } string message = cmd.NextAll(); if (message != null && message.Trim().Length > 0) { message = message.Trim(); if (player.Can(Permission.UseColorCodes) && message.Contains("%")) { message = Color.ReplacePercentCodes(message); } for (int i = 0; i < plist.Length; i++) { if ((plist[i].Can(Permission.ReadStaffChat) || plist[i] == player) && !plist[i].IsIgnoring(player.Info)) { plist[i].Message("{0}(staff){1}{0}: {2}", Color.PM, player.GetClassyName(), message); } } } }
internal static void Where(Player player, Command cmd) { string name = cmd.Next(); Player target = player; if (name != null) { target = Server.FindPlayerOrPrintMatches(player, name, false); if (target == null) { return; } } else if (player.World == null) { player.Message("When called form console, &H/where&S requires a player name."); return; } player.Message("Player {0}&S is on world {1}&S:", target.GetClassyName(), target.World.GetClassyName()); int offset = (int)(target.Position.R / 255f * 64f) + 32; player.Message("{0}({1},{2},{3}) - {4}[{5}{6}{7}{4}{8}]", Color.Silver, target.Position.X / 32, target.Position.Y / 32, target.Position.H / 32, Color.White, Compass.Substring(offset - 12, 11), Color.Red, Compass.Substring(offset - 1, 3), Compass.Substring(offset + 2, 11)); }
public bool Unlock(Player player) { if (player == null) { throw new ArgumentNullException("player"); } lock ( lockLock ) { if (IsLocked) { UnlockedBy = player.Name; UnlockedDate = DateTime.UtcNow; IsLocked = false; SendToAll("&WMap was unlocked by {0}", player.GetClassyName()); Logger.Log("World \"{0}\" was unlocked by {1}", LogType.UserActivity, Name, player.Name); return(true); } else { return(false); } } }
internal static void Roll(Player player, Command cmd) { if (player.Info.IsMuted) { player.MutedMessage(); return; } Random rand = new Random(); int min = 1, max = 100, t1; if (cmd.NextInt(out t1)) { int t2; if (cmd.NextInt(out t2)) { if (t2 < t1) { min = t2; max = t1; } else { min = t1; max = t2; } } else if (t1 >= 1) { max = t1; } } int num = rand.Next(min, max + 1); Server.SendToAll("{0}{1} rolled {2} ({3}...{4})", player.GetClassyName(), Color.Silver, num, min, max); }
public bool Spectate( Player target ) { if( target == null ) throw new ArgumentNullException( "target" ); if( target == this ) throw new ArgumentException( "Cannot spectate self.", "target" ); Message( "Now spectating {0}&S. Type &H/unspec&S to stop.", target.GetClassyName() ); return (Interlocked.Exchange<Player>( ref Session.SpectatedPlayer, target ) == null); }
internal static void WorldLoad( Player player, Command cmd ) { string fileName = cmd.Next(); string worldName = cmd.Next(); if( worldName == null && player.World == null ) { player.Message( "When using /wload from console, you must specify the world name." ); return; } if( fileName == null ) { // No params given at all cdWorldLoad.PrintUsage( player ); return; } // Check if path contains missing drives or invalid characters if( !Paths.IsValidPath( fileName ) ) { player.Message( "Invalid filename or path." ); return; } player.MessageNow( "Looking for \"{0}\"...", fileName ); // Look for the file string sourceFullFileName = Path.Combine( Paths.MapPath, fileName ); if( !File.Exists( sourceFullFileName ) && !Directory.Exists( sourceFullFileName ) ) { if( File.Exists( sourceFullFileName + ".fcm" ) ) { // Try with extension added fileName += ".fcm"; sourceFullFileName += ".fcm"; } else if( MonoCompat.IsCaseSensitive ) { try { // If we're on a case-sensitive OS, try case-insensitive search FileInfo[] candidates = Paths.FindFiles( sourceFullFileName + ".fcm" ); if( candidates.Length == 0 ) { candidates = Paths.FindFiles( sourceFullFileName ); } if( candidates.Length == 0 ) { player.Message( "File/directory not found: {0}", fileName ); } else if( candidates.Length == 1 ) { player.Message( "Filenames are case-sensitive! Did you mean to load \"{0}\"?", candidates[0].Name ); } else { player.Message( "Filenames are case-sensitive! Did you mean to load one of these: {0}", String.Join( ", ", candidates.Select( c => c.Name ).ToArray() ) ); } } catch( DirectoryNotFoundException ex ) { player.Message( ex.Message ); } return; } else { // Nothing found! player.Message( "File/directory not found: {0}", fileName ); return; } } // Make sure that the given file is within the map directory if( !Paths.Contains( Paths.MapPath, sourceFullFileName ) ) { player.UnsafePathMessage(); return; } // Loading map into current world if( worldName == null ) { if( !cmd.IsConfirmed ) { player.AskForConfirmation( cmd, "About to replace THIS MAP with \"{0}\".", fileName ); return; } Map map; try { map = MapUtility.Load( sourceFullFileName ); } catch( Exception ex ) { player.MessageNow( "Could not load specified file: {0}: {1}", ex.GetType().Name, ex.Message ); return; } // Loading to current world player.World.ChangeMap( map ); player.World.SendToAllExcept( "{0}&S loaded a new map for this world.", player, player.GetClassyName() ); player.MessageNow( "New map loaded for the world {0}", player.World.GetClassyName() ); Logger.Log( "{0} loaded new map for world \"{1}\" from {2}", LogType.UserActivity, player.Name, player.World.Name, fileName ); } else { // Loading to some other (or new) world if( !World.IsValidName( worldName ) ) { player.MessageNow( "Invalid world name: \"{0}\".", worldName ); return; } lock( WorldManager.WorldListLock ) { World world = WorldManager.FindWorldExact( worldName ); if( world != null ) { // Replacing existing world's map if( !cmd.IsConfirmed ) { player.AskForConfirmation( cmd, "About to replace map for {0}&S with \"{1}\".", world.GetClassyName(), fileName ); return; } Map map; try { map = MapUtility.Load( sourceFullFileName ); } catch( Exception ex ) { player.MessageNow( "Could not load specified file: {0}: {1}", ex.GetType().Name, ex.Message ); return; } try { world.ChangeMap( map ); } catch( WorldOpException ex ) { Logger.Log( "Could not complete WorldLoad operation: {0}", LogType.Error, ex.Message ); player.Message( "&WWLoad: {0}", ex.Message ); return; } world.SendToAllExcept( "{0}&S loaded a new map for the world {1}", player, player.GetClassyName(), world.GetClassyName() ); player.MessageNow( "New map for the world {0}&S has been loaded.", world.GetClassyName() ); Logger.Log( "{0} loaded new map for world \"{1}\" from {2}", LogType.UserActivity, player.Name, world.Name, sourceFullFileName ); } else { // Adding a new world string targetFullFileName = Path.Combine( Paths.MapPath, worldName + ".fcm" ); if( !cmd.IsConfirmed && File.Exists( targetFullFileName ) && // target file already exists !Paths.Compare( targetFullFileName, sourceFullFileName ) ) { // and is different from sourceFile player.AskForConfirmation( cmd, "A map named \"{0}\" already exists, and will be overwritten with \"{1}\".", Path.GetFileName( targetFullFileName ), Path.GetFileName( sourceFullFileName ) ); return; } Map map; try { map = MapUtility.Load( sourceFullFileName ); } catch( Exception ex ) { player.MessageNow( "Could not load \"{0}\": {1}: {2}", fileName, ex.GetType().Name, ex.Message ); return; } World newWorld; try { newWorld = WorldManager.AddWorld( player, worldName, map, false ); } catch( WorldOpException ex ) { player.Message( "WLoad: {0}", ex.Message ); return; } if( newWorld != null ) { newWorld.BuildSecurity.MinRank = RankManager.ParseRank( ConfigKey.DefaultBuildRank.GetString() ); Server.SendToAll( "{0}&S created a new world named {1}", player.GetClassyName(), newWorld.GetClassyName() ); Logger.Log( "{0} created a new world named \"{1}\" (loaded from \"{2}\")", LogType.UserActivity, player.Name, worldName, fileName ); WorldManager.SaveWorldList(); player.MessageNow( "Reminder: New world's access permission is {0}+&S, and build permission is {1}+", newWorld.AccessSecurity.MinRank.GetClassyName(), newWorld.BuildSecurity.MinRank.GetClassyName() ); } else { player.MessageNow( "Failed to create a new world." ); } } } } Server.RequestGC(); }
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 WorldMain( Player player, Command cmd ) { string worldName = cmd.Next(); if( worldName == null ) { player.Message( "Main world is {0}", WorldManager.MainWorld.GetClassyName() ); return; } World world = WorldManager.FindWorldOrPrintMatches( player, worldName ); if( world == null ) { return; } else if( world == WorldManager.MainWorld ) { player.Message( "World {0}&S is already set as main.", world.GetClassyName() ); } else if( !player.Info.Rank.AllowSecurityCircumvention && !player.CanJoin( world ) ) { // Prevent players from exploiting /wmain to gain access to restricted maps switch( world.AccessSecurity.CheckDetailed( player.Info ) ) { case SecurityCheckResult.RankTooHigh: case SecurityCheckResult.RankTooLow: player.Message( "You are not allowed to set {0}&S as the main world (by rank).", world.GetClassyName() ); return; case SecurityCheckResult.BlackListed: player.Message( "You are not allowed to set {0}&S as the main world (blacklisted).", world.GetClassyName() ); return; } } else { if( world.AccessSecurity.HasRestrictions() ) { world.AccessSecurity.Reset(); player.Message( "The main world cannot have access restrictions. " + "All access restrictions were removed from world {0}", world.GetClassyName() ); } if( !world.SetMainWorld() ) { player.Message( "Main world was not changed." ); return; } WorldManager.SaveWorldList(); Server.SendToAll( "{0}&S set {1}&S to be the main world.", player.GetClassyName(), world.GetClassyName() ); Logger.Log( "{0} set {1} to be the main world.", LogType.UserActivity, player.Name, world.Name ); } }
internal static void WorldUnload( Player player, Command cmd ) { string worldName = cmd.Next(); if( worldName == null ) { cdWorldUnload.PrintUsage( player ); return; } World world = WorldManager.FindWorldOrPrintMatches( player, worldName ); if( world == null ) return; try { WorldManager.RemoveWorld( world ); } catch( WorldOpException ex ) { switch( ex.ErrorCode ) { case WorldOpExceptionCode.CannotDoThatToMainWorld: player.MessageNow( "&WWorld {0}&W is set as the main world. " + "Assign a new main world before deleting this one.", world.GetClassyName() ); return; case WorldOpExceptionCode.WorldNotFound: player.MessageNow( "&WWorld {0}&W is already unloaded.", world.GetClassyName() ); return; default: player.MessageNow( "&WUnexpected error occured while unloading world {0}&W: {1}", world.GetClassyName(), ex.GetType().Name ); Logger.Log( "WorldCommands.WorldUnload: Unexpected error while unloading world {0}: {1}", LogType.Error, world.Name, ex ); return; } } WorldManager.SaveWorldList(); Server.SendToAllExcept( "{0}&S removed {1}&S from the world list.", player, player.GetClassyName(), world.GetClassyName() ); player.Message( "Removed {0}&S from the world list. You can now delete the map file ({1}.fcm) manually.", world.GetClassyName(), world.Name ); Logger.Log( "{0} removed \"{1}\" from the world list.", LogType.UserActivity, player.Name, worldName ); Server.RequestGC(); }
internal static void WorldRename( Player player, Command cmd ) { string oldName = cmd.Next(); string newName = cmd.Next(); if( oldName == null || newName == null ) { cdWorldRename.PrintUsage( player ); return; } World oldWorld = WorldManager.FindWorldOrPrintMatches( player, oldName ); if( oldWorld == null ) return; oldName = oldWorld.Name; if( !cmd.IsConfirmed && File.Exists( Path.Combine( Paths.MapPath, newName + ".fcm" ) ) ) { player.AskForConfirmation( cmd, "Renaming this world will overwrite an existing map file \"{0}.fcm\".", newName ); return; } try { WorldManager.RenameWorld( oldWorld, newName, true ); } catch( WorldOpException ex ) { switch( ex.ErrorCode ) { case WorldOpExceptionCode.NoChangeNeeded: player.MessageNow( "Rename: World is already named \"{0}\"", oldName ); return; case WorldOpExceptionCode.DuplicateWorldName: player.MessageNow( "Rename: Another world named \"{0}\" already exists.", newName ); return; case WorldOpExceptionCode.InvalidWorldName: player.MessageNow( "Rename: Invalid world name: \"{0}\"", newName ); return; case WorldOpExceptionCode.MapMoveError: player.MessageNow( "Rename: World \"{0}\" was renamed to \"{1}\", but the map file could not be moved due to an error: {2}", oldName, newName, ex.InnerException ); return; default: player.MessageNow( "Unexpected error occured while renaming world \"{0}\"", oldName ); Logger.Log( "WorldCommands.Rename: Unexpected error while renaming world {0} to {1}: {2}", LogType.Error, oldWorld.Name, newName, ex ); return; } } WorldManager.SaveWorldList(); Logger.Log( "{0} renamed the world \"{1}\" to \"{2}\".", LogType.UserActivity, player.Name, oldName, newName ); Server.SendToAll( "{0}&S renamed the world \"{1}\" to \"{2}\"", player.GetClassyName(), oldName, newName ); }
// Parses message incoming from the player public void ParseMessage(string rawMessage, bool fromConsole) { if (rawMessage == null) { throw new ArgumentNullException("rawMessage"); } if (partialMessage != null) { rawMessage = partialMessage + rawMessage; partialMessage = null; } switch (CommandManager.GetMessageType(rawMessage)) { case MessageType.Chat: { if (!Can(Permission.Chat)) { return; } if (Info.IsMuted) { MutedMessage(); return; } if (DetectChatSpam()) { return; } if (World != null && !World.FireSentMessageEvent(this, ref rawMessage) || !Server.FireSentMessageEvent(this, ref rawMessage)) { return; } Info.LinesWritten++; Logger.Log("{0}: {1}", LogType.GlobalChat, Name, rawMessage); // Escaped slash removed AFTER logging, to avoid confusion with real commands if (rawMessage.StartsWith("//")) { rawMessage = rawMessage.Substring(1); } if (rawMessage.EndsWith("//")) { rawMessage = rawMessage.Substring(0, rawMessage.Length - 1); } if (Can(Permission.UseColorCodes) && rawMessage.Contains("%")) { rawMessage = Color.ReplacePercentCodes(rawMessage); } Server.SendToAllExceptIgnored(this, "{0}{1}: {2}", Console, GetClassyName(), Color.White, rawMessage); } break; case MessageType.Command: { if (rawMessage.EndsWith("//")) { rawMessage = rawMessage.Substring(0, rawMessage.Length - 1); } Logger.Log("{0}: {1}", LogType.UserCommand, Name, rawMessage); Command cmd = new Command(rawMessage); LastCommand = cmd; CommandManager.ParseCommand(this, cmd, fromConsole); } break; case MessageType.RepeatCommand: { if (LastCommand == null) { Message("No command to repeat."); } else { LastCommand.Rewind(); Logger.Log("{0}: repeat {1}", LogType.UserCommand, Name, LastCommand.Message); Message("Repeat: {0}", LastCommand.Message); CommandManager.ParseCommand(this, LastCommand, fromConsole); } } break; case MessageType.PrivateChat: { if (!Can(Permission.Chat)) { return; } if (Info.IsMuted) { MutedMessage(); return; } if (DetectChatSpam()) { return; } if (rawMessage.EndsWith("//")) { rawMessage = rawMessage.Substring(0, rawMessage.Length - 1); } string otherPlayerName, messageText; if (rawMessage[1] == ' ') { otherPlayerName = rawMessage.Substring(2, rawMessage.IndexOf(' ', 2) - 2); messageText = rawMessage.Substring(rawMessage.IndexOf(' ', 2) + 1); } else { otherPlayerName = rawMessage.Substring(1, rawMessage.IndexOf(' ') - 1); messageText = rawMessage.Substring(rawMessage.IndexOf(' ') + 1); } if (messageText.Contains("%") && Can(Permission.UseColorCodes)) { messageText = Color.ReplacePercentCodes(messageText); } // first, find ALL players (visible and hidden) Player[] allPlayers = Server.FindPlayers(otherPlayerName); // if there is more than 1 target player, exclude hidden players if (allPlayers.Length > 1) { allPlayers = Server.FindPlayers(this, otherPlayerName); } if (allPlayers.Length == 1) { Player target = allPlayers[0]; if (target.IsIgnoring(Info)) { if (CanSee(target)) { MessageNow("&WCannot PM {0}&W: you are ignored.", target.GetClassyName()); } } else { Logger.Log("{0} to {1}: {2}", LogType.PrivateChat, Name, target.Name, messageText); target.Message("{0}from {1}: {2}", Color.PM, Name, messageText); if (CanSee(target)) { Message("{0}to {1}: {2}", Color.PM, target.Name, messageText); } else { NoPlayerMessage(otherPlayerName); } } } else if (allPlayers.Length == 0) { NoPlayerMessage(otherPlayerName); } else { ManyMatchesMessage("player", allPlayers); } } break; case MessageType.RankChat: { if (!Can(Permission.Chat)) { return; } if (Info.IsMuted) { MutedMessage(); return; } if (DetectChatSpam()) { return; } if (rawMessage.EndsWith("//")) { rawMessage = rawMessage.Substring(0, rawMessage.Length - 1); } string rankName = rawMessage.Substring(2, rawMessage.IndexOf(' ') - 2); Rank rank = RankManager.FindRank(rankName); if (rank != null) { Logger.Log("{0} to rank {1}: {2}", LogType.RankChat, Name, rank.Name, rawMessage); string messageText = rawMessage.Substring(rawMessage.IndexOf(' ') + 1); if (messageText.Contains("%") && Can(Permission.UseColorCodes)) { messageText = Color.ReplacePercentCodes(messageText); } string formattedMessage = String.Format("{0}({1}{2}){3}{4}: {5}", rank.Color, (ConfigKey.RankPrefixesInChat.GetBool() ? rank.Prefix : ""), rank.Name, Color.PM, Name, messageText); Server.SendToRank(this, formattedMessage, rank); if (Info.Rank != rank) { Message(formattedMessage); } } else { Message("No rank found matching \"{0}\"", rankName); } } break; case MessageType.Confirmation: { if (CommandToConfirm != null) { if (DateTime.UtcNow.Subtract(CommandToConfirmDate).TotalSeconds < ConfirmationTimeout) { CommandToConfirm.IsConfirmed = true; CommandManager.ParseCommand(this, CommandToConfirm, fromConsole); CommandToConfirm = null; } else { MessageNow("Confirmation timed out. Enter the command again."); } } else { MessageNow("There is no command to confirm."); } } break; case MessageType.PartialMessage: partialMessage = rawMessage.Substring(0, rawMessage.Length - 1); MessageNow("Partial: &F{0}", partialMessage); break; case MessageType.Invalid: { Message("Unknown command."); } break; } }
internal static void Roll( Player player, Command cmd ) { if( player.Info.IsMuted ) { player.MutedMessage(); return; } Random rand = new Random(); int min = 1, max = 100, t1; if( cmd.NextInt( out t1 ) ) { int t2; if( cmd.NextInt( out t2 ) ) { if( t2 < t1 ) { min = t2; max = t1; } else { min = t1; max = t2; } } else if( t1 >= 1 ) { max = t1; } } int num = rand.Next( min, max + 1 ); Server.SendToAll( "{0}{1} rolled {2} ({3}...{4})", player.GetClassyName(), Color.Silver, num, min, max ); }
public bool Lock( Player player ) { if( player == null ) throw new ArgumentNullException( "player" ); lock( lockLock ) { if( IsLocked ) { return false; } else { LockedBy = player.Name; LockedDate = DateTime.UtcNow; IsLocked = true; if( Map != null ) Map.ClearUpdateQueue(); SendToAll( "&WMap was locked by {0}", player.GetClassyName() ); Logger.Log( "World {0} was locked by {1}", LogType.UserActivity, Name, player.Name ); return true; } } }
public Map AcceptPlayer(Player player, bool announce) { if (player == null) { throw new ArgumentNullException("player"); } lock ( WorldLock ) { if (IsFull) { return(null); } if (players.ContainsKey(player.Name.ToLower())) { Logger.Log("This world already contains the player by name ({0}). " + "Some sort of state corruption must have occured.", LogType.Error, player.Name); players.Remove(player.Name.ToLower()); } players.Add(player.Name.ToLower(), player); // load the map, if it's not yet loaded PendingUnload = false; if (Map == null) { LoadMap(); } if (ConfigKey.BackupOnJoin.GetBool()) { string backupFileName = String.Format("{0}_{1:yyyy-MM-dd_HH-mm}_{2}.fcm", Name, DateTime.Now, player.Name); // localized Map.SaveBackup(Path.Combine(Paths.MapPath, GetMapName()), Path.Combine(Paths.BackupPath, backupFileName), true); } AddPlayerForPatrol(player); UpdatePlayerList(); if (announce && ConfigKey.ShowJoinedWorldMessages.GetBool()) { string message = String.Format("&SPlayer {0}&S joined {1}", player.GetClassyName(), GetClassyName()); foreach (Packet packet in PacketWriter.MakeWrappedMessage(">", message, false)) { Server.SendToSeeing(packet, player); } } Logger.Log("Player {0} joined world {1}.", LogType.UserActivity, player.Name, Name); if (OnPlayerJoined != null) { OnPlayerJoined(player, this); } if (IsLocked) { player.Message("&WThis map is currently locked (read-only)."); } if (player.IsHidden) { player.Message("Reminder: You are still hidden."); } return(Map); } }
bool LoginSequence() { byte opcode = reader.ReadByte(); if( opcode != (byte)OpCode.Handshake ) { if( opcode == 2 ) { // This may be someone connecting with an SMP client int strLen = IPAddress.NetworkToHostOrder( reader.ReadInt16() ); if( strLen >= 2 && strLen <= 16 ) { string smpPlayerName = Encoding.UTF8.GetString( reader.ReadBytes( strLen ) ); Logger.Log( "Session.LoginSequence: Player \"{0}\" tried connecting with SMP/Beta client from {1}. " + "fCraft does not support SMP/Beta.", LogType.Warning, smpPlayerName, IP ); // send SMP KICK packet writer.Write( (byte)255 ); byte[] stringData = Encoding.UTF8.GetBytes( NoSmpMessage ); writer.Write( (short)stringData.Length ); writer.Write( stringData ); bytesSent += (1 + stringData.Length); writer.Flush(); } else { // Not SMP client (invalid player name length) Logger.Log( "Session.LoginSequence: Unexpected opcode in the first packet from {0}: {1}.", LogType.Error, IP, opcode ); KickNow( "Unexpected handshake message - possible protocol mismatch!", LeaveReason.ProtocolViolation ); } return false; } else { Logger.Log( "Session.LoginSequence: Unexpected opcode in the first packet from {0}: {1}.", LogType.Error, IP, opcode ); KickNow( "Unexpected handshake message - possible protocol mismatch!", LeaveReason.ProtocolViolation ); return false; } } // Check protocol version int clientProtocolVersion = reader.ReadByte(); if( clientProtocolVersion != Config.ProtocolVersion ) { Logger.Log( "Session.LoginSequence: Wrong protocol version: {0}.", LogType.Error, clientProtocolVersion ); KickNow( "Incompatible protocol version!", LeaveReason.ProtocolViolation ); return false; } string playerName = ReadString(); string verificationCode = ReadString(); reader.ReadByte(); // unused bytesReceived += 131; // Check name for nonstandard characters if( !Player.IsValidName( playerName ) ) { Logger.Log( "Session.LoginSequence: Unacceptible player name: {0} ({1})", LogType.SuspiciousActivity, playerName, IP ); KickNow( "Invalid characters in player name!", LeaveReason.ProtocolViolation ); return false; } // Verify name Player = new Player( null, playerName, this, WorldManager.MainWorld.Map.Spawn ); bool showVerifyNamesWarning = false; if( !Server.VerifyName( Player.Name, verificationCode, Server.Salt ) ) { NameVerificationMode nameVerificationMode = ConfigKey.VerifyNames.GetEnum<NameVerificationMode>(); string standardMessage = String.Format( "Session.LoginSequence: Could not verify player name for {0} ({1}).", Player.Name, IP ); if( IP.Equals( IPAddress.Loopback ) && nameVerificationMode == NameVerificationMode.Always ) { Logger.Log( "{0} Player was identified as connecting from localhost and allowed in.", LogType.SuspiciousActivity, standardMessage ); } else if( IP.IsLAN() && ConfigKey.AllowUnverifiedLAN.GetBool() ) { Logger.Log( "{0} Player was identified as connecting from LAN and allowed in.", LogType.SuspiciousActivity, standardMessage ); } else if( Player.Info.TimesVisited > 1 && Player.Info.LastIP.Equals( IP ) ) { switch( nameVerificationMode ) { case NameVerificationMode.Always: Player.Info.ProcessFailedLogin( this ); Logger.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!", LeaveReason.UnverifiedName ); return false; case NameVerificationMode.Balanced: case NameVerificationMode.Never: Logger.Log( "{0} IP matched previous records for that name. Player was allowed in.", LogType.SuspiciousActivity, standardMessage ); break; } } else { switch( nameVerificationMode ) { case NameVerificationMode.Always: case NameVerificationMode.Balanced: Player.Info.ProcessFailedLogin( this ); Logger.Log( "{0} IP did not match. Player was kicked.", LogType.SuspiciousActivity, standardMessage ); KickNow( "Could not verify player name!", LeaveReason.UnverifiedName ); return false; case NameVerificationMode.Never: Logger.Log( "{0} IP did not match. " + "Player was allowed in anyway because VerifyNames is set to Never.", LogType.SuspiciousActivity, standardMessage ); Player.Message( "&WYour name could not be verified." ); showVerifyNamesWarning = true; break; } } } // Check if player is banned if( Player.Info.Banned ) { Player.Info.ProcessFailedLogin( this ); Logger.Log( "Banned player {0} tried to log in from {1}", LogType.SuspiciousActivity, Player.Name, IP ); if( ConfigKey.ShowBannedConnectionMessages.GetBool() ) { Server.SendToAllWhoCan( "&SBanned player {0}&S tried to log in from {1}", null, Permission.ViewPlayerIPs, Player.GetClassyName(), IP ); Server.SendToAllWhoCant( "&SBanned player {0}&S tried to log in.", null, Permission.ViewPlayerIPs, Player.GetClassyName() ); } string bannedMessage = String.Format( "Banned {0} ago by {1}: {2}", Player.Info.TimeSinceBan.ToMiniString(), Player.Info.BannedBy, Player.Info.BanReason ); KickNow( bannedMessage, LeaveReason.LoginFailed ); return false; } // Check if player's IP is banned IPBanInfo ipBanInfo = IPBanList.Get( IP ); if( ipBanInfo != null ) { Player.Info.ProcessFailedLogin( this ); ipBanInfo.ProcessAttempt( Player ); if( ConfigKey.ShowBannedConnectionMessages.GetBool() ) { Server.SendToAll( "{0}&S tried to log in from a banned IP.", Player.GetClassyName() ); } Logger.Log( "{0} tried to log in from a banned IP.", LogType.SuspiciousActivity, Player.Name ); string bannedMessage = String.Format( "IP-banned {0} ago by {1}: {2}", DateTime.UtcNow.Subtract( ipBanInfo.BanDate ).ToMiniString(), ipBanInfo.BannedBy, ipBanInfo.BanReason ); KickNow( bannedMessage, LeaveReason.LoginFailed ); return false; } // Check if max number of connections is reached for IP if( !Server.RegisterSessionAndCheckConnectionCount( this ) ) { Player.Info.ProcessFailedLogin( this ); Logger.Log( "Session.LoginSequence: Denied player {0}: maximum number of connections was reached for {1}", LogType.SuspiciousActivity, playerName, IP ); KickNow( String.Format( "Max connection count reached for {0}", IP ), LeaveReason.LoginFailed ); return false; } // Check if player is paid (if required) if( ConfigKey.PaidPlayersOnly.GetBool() ) { SendNow( PacketWriter.MakeHandshake( Player, ConfigKey.ServerName.GetString(), "Please wait; Checking paid status..." ) ); writer.Flush(); if( !Player.CheckPaidStatus( Player.Name ) ) { Logger.Log( "Player {0} was kicked because their account is not paid, and PaidOnly setting is enabled.", LogType.SystemActivity, Player.Name ); KickNow( "Paid players allowed only.", LeaveReason.LoginFailed ); return false; } } // Any additional security checks should be done right here if( Server.RaisePlayerConnectingEvent( Player ) ) return false; // ----==== beyond this point, player is considered connecting (allowed to join) ====---- // Register player for future block updates if( !Server.RegisterPlayerAndCheckIfFull( this ) ) { Logger.Log( "Player {0} was kicked because server is full.", LogType.SystemActivity, Player.Name ); string kickMessage = String.Format( "Sorry, server is full ({0}/{1})", Server.PlayerList.Length, ConfigKey.MaxPlayers.GetInt() ); KickNow( kickMessage, LeaveReason.ServerFull ); return false; } Player.Info.ProcessLogin( Player ); // ----==== Beyond this point, player is considered connected (authenticated and registered) ====---- World startingWorld = Server.RaisePlayerConnectedEvent( Player, WorldManager.MainWorld ); // Send server information SendNow( PacketWriter.MakeHandshake( Player, ConfigKey.ServerName.GetString(), ConfigKey.MOTD.GetString() ) ); // AutoRank if( ConfigKey.AutoRankEnabled.GetBool() ) { Rank newRank = AutoRankManager.Check( Player.Info ); if( newRank != null ) { ModerationCommands.DoChangeRank( Player.Console, Player.Info, newRank, "~AutoRank", false, true ); } } bool firstTime = (Player.Info.TimesVisited == 1); if( !JoinWorldNow( startingWorld, true, true ) ) { Logger.Log( "Failed to load main world ({0}) for connecting player {1} (from {2})", LogType.Error, startingWorld.Name, Player.Name, IP ); KickNow( "Unable to join the main world.", LeaveReason.WorldFull ); return false; } // ==== Beyond this point, player is considered ready (has a world) ==== if( showVerifyNamesWarning ) { Server.SendToAllExcept( "&WName and IP of {0}&W are unverified!", Player, Player.GetClassyName() ); } // Check if other banned players logged in from this IP PlayerInfo[] bannedPlayerNames = PlayerDB.FindPlayers( IP, 25 ).Where( playerFromSameIP => playerFromSameIP.Banned ).ToArray(); if( bannedPlayerNames.Length > 0 ) { string logString = String.Format( "&WPlayer {0}&W logged in from an IP previously used by banned players: {1}", Player.GetClassyName(), bannedPlayerNames.JoinToClassyString() ); Server.SendToAll( logString ); Logger.Log( logString, LogType.SuspiciousActivity ); } // Announce join if( ConfigKey.ShowConnectionMessages.GetBool() ) { Server.SendToAllExcept( Server.MakePlayerConnectedMessage( Player, firstTime, Player.World ), Player ); } // check if player is still muted if( Player.Info.MutedUntil > DateTime.UtcNow ) { int secondsLeft = (int)Player.Info.MutedUntil.Subtract( DateTime.UtcNow ).TotalSeconds; Player.Message( "&WYou were previously muted by {0}, {1} seconds left.", Player.Info.MutedBy, secondsLeft ); Server.SendToAllExcept( "&WPlayer {0}&W was previously muted by {1}&W, {2} seconds left.", Player, Player.GetClassyName(), Player.Info.MutedBy, secondsLeft ); } // check if player is still frozen if( Player.Info.IsFrozen ) { if( Player.Info.FrozenOn != DateTime.MinValue ) { Player.Message( "&WYou were previously frozen {0} ago by {1}", Player.Info.TimeSinceFrozen.ToMiniString(), Player.Info.FrozenBy ); Server.SendToAllExcept( "&WPlayer {0}&W was previously frozen {1} ago by {2}.", Player, Player.GetClassyName(), Player.Info.TimeSinceFrozen.ToMiniString(), Player.Info.FrozenBy ); } else { Player.Message( "&WYou were previously frozen by {0}", Player.Info.FrozenBy ); Server.SendToAllExcept( "&WPlayer {0}&W was previously frozen by {1}.", Player, Player.GetClassyName(), Player.Info.FrozenBy ); } } // Welcome message if( File.Exists( Paths.GreetingFileName ) ) { string[] greetingText = File.ReadAllLines( Paths.GreetingFileName ); foreach( string greetingLine in greetingText ) { StringBuilder sb = new StringBuilder( greetingLine ); sb.Replace( "{SERVER_NAME}", ConfigKey.ServerName.GetString() ); sb.Replace( "{RANK}", Player.Info.Rank.GetClassyName() ); sb.Replace( "{PLAYER_NAME}", Player.GetClassyName() ); sb.Replace( "{TIME}", DateTime.Now.ToShortTimeString() ); // localized sb.Replace( "{WORLD}", Player.World.GetClassyName() ); sb.Replace( "{PLAYERS}", Server.CountVisiblePlayers( Player ).ToString() ); sb.Replace( "{WORLDS}", WorldManager.WorldList.Length.ToString() ); sb.Replace( "{MOTD}", ConfigKey.MOTD.GetString() ); Player.Message( sb.ToString() ); } } else { if( firstTime ) { Player.Message( "Welcome to {0}", ConfigKey.ServerName.GetString() ); } else { Player.Message( "Welcome back to {0}", ConfigKey.ServerName.GetString() ); } Player.Message( "Your rank is {0}&S. Type &H/help&S for help.", Player.Info.Rank.GetClassyName() ); } // A reminder for first-time users if( PlayerDB.CountTotalPlayers() == 1 && Player.Info.Rank != RankManager.HighestRank ) { Player.Message( "Type &H/rank {0} {1}&S in console to promote yourself", Player.Name, RankManager.HighestRank.Name ); } Server.RaisePlayerReadyEvent( Player ); IsReady = true; return true; }
public bool Unlock( Player player ) { if( player == null ) throw new ArgumentNullException( "player" ); lock( lockLock ) { if( IsLocked ) { UnlockedBy = player.Name; UnlockedDate = DateTime.UtcNow; IsLocked = false; SendToAll( "&WMap was unlocked by {0}", player.GetClassyName() ); Logger.Log( "World \"{0}\" was unlocked by {1}", LogType.UserActivity, Name, player.Name ); return true; } else { return false; } } }
public Map AcceptPlayer( Player player, bool announce ) { if( player == null ) throw new ArgumentNullException( "player" ); lock( WorldLock ) { if( IsFull ) { return null; } if( players.ContainsKey( player.Name.ToLower() ) ) { Logger.Log( "This world already contains the player by name ({0}). " + "Some sort of state corruption must have occured.", LogType.Error, player.Name ); players.Remove( player.Name.ToLower() ); } players.Add( player.Name.ToLower(), player ); // load the map, if it's not yet loaded PendingUnload = false; if( Map == null ) { LoadMap(); } if( ConfigKey.BackupOnJoin.GetBool() ) { string backupFileName = String.Format( "{0}_{1:yyyy-MM-dd_HH-mm}_{2}.fcm", Name, DateTime.Now, player.Name ); // localized Map.SaveBackup( Path.Combine( Paths.MapPath, GetMapName() ), Path.Combine( Paths.BackupPath, backupFileName ), true ); } AddPlayerForPatrol( player ); UpdatePlayerList(); if( announce && ConfigKey.ShowJoinedWorldMessages.GetBool() ) { string message = String.Format( "&SPlayer {0}&S joined {1}", player.GetClassyName(), GetClassyName() ); foreach( Packet packet in PacketWriter.MakeWrappedMessage( ">", message, false ) ) { Server.SendToSeeing( packet, player ); } } Logger.Log( "Player {0} joined world {1}.", LogType.UserActivity, player.Name, Name ); if( OnPlayerJoined != null ) OnPlayerJoined( player, this ); if( IsLocked ) { player.Message( "&WThis map is currently locked (read-only)." ); } if( player.IsHidden ) { player.Message( "Reminder: You are still hidden." ); } return Map; } }
static void Shutdown( Player player, Command cmd ) { int delay; if( !cmd.NextInt( out delay ) ) { delay = 5; cmd.Rewind(); } string reason = cmd.NextAll(); if( reason.Equals( "abort", StringComparison.OrdinalIgnoreCase ) ) { if( Server.CancelShutdown() ) { Logger.Log( "Shutdown aborted by {0}.", LogType.UserActivity, player.Name ); Server.SendToAll( "&WShutdown aborted by {0}", player.GetClassyName() ); } else { player.MessageNow( "Cannot abort shutdown - too late." ); } return; } Server.SendToAll( "&WServer shutting down in {0} seconds.", delay ); if( String.IsNullOrEmpty( reason ) ) { Logger.Log( "{0} shut down the server ({1} second delay).", LogType.UserActivity, player.Name, delay ); ShutdownParams sp = new ShutdownParams( ShutdownReason.ShuttingDown, delay, true, false ); Server.Shutdown( sp, false ); } else { Server.SendToAll( "&WShutdown reason: {0}", reason ); Logger.Log( "{0} shut down the server ({1} second delay). Reason: {2}", LogType.UserActivity, player.Name, delay, reason ); ShutdownParams sp = new ShutdownParams( ShutdownReason.ShuttingDown, delay, true, false, reason, player ); Server.Shutdown( sp, false ); } }