// Remove player from the list, and notify remaining players public static void UnregisterPlayer( Player player ) { lock( playerListLock ) { if( players.ContainsKey( player.id ) ) { SendToAll( PacketWriter.MakeRemoveEntity( player.id ) ); SendToAll( Color.Sys + player.GetLogName() + " left the server." ); Logger.Log( "{0} left the server.", LogType.UserActivity, player.name ); // better safe than sorry: go through ALL worlds looking for leftover players lock( worldListLock ) { foreach( World world in worlds.Values ) { world.ReleasePlayer( player ); } } players.Remove( player.id ); UpdatePlayerList(); PlayerDB.ProcessLogout( player ); PlayerDB.Save(); } else { Logger.Log( "World.UnregisterPlayer: Trying to unregister a non-existent (unknown id) player.", LogType.Warning ); } } }
internal static void SetSpawn( Player player, Command cmd ) { if( player.Can( Permissions.SetSpawn ) ) { player.world.map.spawn = player.pos; player.world.map.changesSinceSave++; player.Send( PacketWriter.MakeTeleport( 255, player.world.map.spawn ), true ); player.Message( "New spawn point saved." ); Logger.Log( "{0} changed the spawned point.", LogType.UserActivity, player.GetLogName() ); } else { player.NoAccessMessage( Permissions.SetSpawn ); } }
// 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 DoIPBan( Player player, IPAddress address, string reason, string playerName, bool banAll, bool unban ) { Player other; if( unban ) { if( IPBanList.Remove( address ) ) { player.Message( address.ToString() + " has been removed from the IP ban list." ); } else { player.Message( address.ToString() + " is not currently banned." ); } if( banAll ) { foreach( PlayerInfo otherInfo in PlayerDB.FindPlayersByIP( address ) ) { if( otherInfo.ProcessUnBan( player.name, reason + "~UnBanAll" ) ) { player.Message( otherInfo.name + " matched the IP and was also unbanned." ); } } } } else { if( IPBanList.Add( new IPBanInfo( address, playerName, player.name, reason ) ) ) { player.Message( address.ToString() + " has been added to the IP ban list." ); } else { player.Message( address.ToString() + " is already banned." ); } foreach( PlayerInfo otherInfo in PlayerDB.FindPlayersByIP( address ) ) { if( banAll && otherInfo.ProcessBan( player.name, reason + "~BanAll" ) ) { player.Message( otherInfo.name + " matched the IP and was also banned." ); } other = player.world.FindPlayerExact( otherInfo.name ); if( other != null ) { other.session.Kick( "Your IP was just banned by " + player.GetLogName() ); } } } }
// 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 WorldRename( Player player, Command cmd ) { if( !player.Can( Permissions.ManageWorlds ) ) { player.NoAccessMessage( Permissions.ManageWorlds ); return; } string oldName = cmd.Next(); string newName = cmd.Next(); if( oldName == null || newName == null ) { player.Message( "Syntax: " + Color.Help + "/wrename OldName NewName" ); return; } lock( Server.worldListLock ) { World oldWorld = Server.FindWorld( oldName ); World newWorld = Server.FindWorld( newName ); if( oldWorld == null ) { player.Message( "No world found with the specified name: " + oldName ); } else if( newWorld != null ) { player.Message( "A world with the specified name already exists: " + newName ); } else { oldName = oldWorld.name; Server.RenameWorld( oldName, newName ); File.Move( oldName + ".fcm", newName + ".fcm" ); Server.SaveWorldList(); Server.SendToAll( Color.Sys + player.nick + " renamed the world \"" + oldName + "\" to \"" + newName + "\"." ); Logger.Log( player.GetLogName() + " renamed the world \"" + oldName + "\" to \"" + newName + "\".", LogType.UserActivity ); } } }
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 WorldLoad( Player player, Command cmd ) { if( !player.Can( Permissions.ManageWorlds ) ) { player.NoAccessMessage( Permissions.ManageWorlds ); return; } 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 player.Message( "See " + Color.Help + "/help wload" + Color.Sys + " for usage syntax." ); return; } Logger.Log( "Player {0} is attempting to load map \"{1}\"...", LogType.UserActivity, player.GetLogName(), fileName ); player.Message( "Attempting to load " + fileName + "..." ); Map map = Map.Load( player.world, fileName ); if( map == null ) { player.Message( "Could not load specified file." ); return; } if( worldName == null ) { // Loading to current world player.world.ChangeMap( map ); player.world.SendToAll( Color.Sys + player.nick + " loaded a new map for the world \"" + player.world.name + "\".", player ); player.Message( "New map for the world \"" + player.world.name + "\" has been loaded." ); Logger.Log( player.GetLogName() + " loaded new map for " + player.world.name + " from " + fileName, LogType.UserActivity ); } else { // Loading to some other (or new) world if( !Player.IsValidName( worldName ) ) { player.Message( "Invalid world name: \"" + worldName + "\"." ); return; } lock( Server.worldListLock ) { World world = Server.FindWorld( worldName ); if( world != null ) { // Replacing existing world's map world.ChangeMap( map ); world.SendToAll( Color.Sys + player.nick + " loaded a new map for the world \"" + world.name + "\".", player ); player.Message( "New map for the world \"" + world.name + "\" has been loaded." ); Logger.Log( player.GetLogName() + " loaded new map for world \"" + world.name + "\" from " + fileName, LogType.UserActivity ); } else { // Adding a new world if( Server.AddWorld( worldName, map, false ) != null ) { Server.SendToAll( Color.Sys + player.nick + " created a new world named \"" + worldName + "\"." ); Logger.Log( player.GetLogName() + " created a new world named \"" + worldName + "\".", LogType.UserActivity ); Server.SaveWorldList(); } else { player.Message( "Error occured while trying to create a new world." ); } } } } GC.Collect( GC.MaxGeneration, GCCollectionMode.Optimized ); }
internal static void WorldMain( Player player, Command cmd ) { string worldName = cmd.Next(); if( worldName == null ) { player.Message( "Usage: " + Color.Help + "/wmain WorldName" ); return; } World world = Server.FindWorld( worldName ); if( world == null ) { player.Message( "No world \"" + worldName + "\" found." ); } else if( world == Server.mainWorld ) { player.Message( "World \"" + world.name + "\" is already set as main." ); } else if( player.Can( Permissions.ManageWorlds ) ) { if( world.classAccess != ClassList.lowestClass ) { world.classAccess = ClassList.lowestClass; player.Message( "The main world cannot have access restrictions." ); player.Message( "Access restrictions were removed from world \"" + world.name + "\"" ); } world.neverUnload = false; world.LoadMap(); Server.mainWorld.neverUnload = true; Server.mainWorld = world; Server.SaveWorldList(); Server.SendToAll( Color.Sys + player.nick + " set \"" + world.name + "\" to be the main world." ); Logger.Log( player.GetLogName() + " set \"" + world.name + "\" to be the main world.", LogType.UserActivity ); } else { player.NoAccessMessage( Permissions.ManageWorlds ); } }
internal static void WorldBuild( Player player, Command cmd ) { string worldName = cmd.Next(); string className = cmd.Next(); if( worldName == null ) { if( player.world != null ) { if( player.world.classBuild == ClassList.lowestClass ) { player.Message( "This world (" + player.world.name + ") can be modified by anyone." ); } else { player.Message( "This world (" + player.world.name + ") can only be modified by " + player.world.classBuild.color + player.world.classBuild.name + "+" ); } } else { player.Message( "When calling /waccess from console, you must specify the world name." ); } return; } World world = Server.FindWorld( worldName ); if( world == null ) { player.Message( "No world \"" + worldName + "\" found." ); } else if( className == null ) { if( world.classBuild == ClassList.lowestClass ) { player.Message( "World \"" + world.name + "\" can be modified by anyone." ); } else { player.Message( "World \"" + world.name + "\" can be only modified by " + world.classBuild.color + world.classBuild.name + "+" ); } } else if( player.Can( Permissions.ManageWorlds ) ) { PlayerClass playerClass = ClassList.FindClass( className ); if( playerClass == null ) { player.Message( "No class \"" + className + "\" found." ); } else{ world.classBuild = playerClass; Server.SaveWorldList(); if( world.classBuild == ClassList.lowestClass ) { Server.SendToAll( Color.Sys + player.nick + " made the world \"" + world.name + "\" modifiable by anyone." ); } else { Server.SendToAll( Color.Sys + player.nick + " made the world \"" + world.name + "\" modifiable only by " + world.classBuild.color + world.classBuild.name + "+" ); } Logger.Log( player.GetLogName() + " made the world \"" + world.name + "\" modifiable by " + world.classBuild.name + "+", LogType.UserActivity ); } } else { player.NoAccessMessage( Permissions.ManageWorlds ); } }
public void AcceptPlayer( Player player ) { lock( playerListLock ) { lock( mapLock ) { isReadyForUnload = false; if( map == null ) { LoadMap(); } if( Config.GetBool( ConfigKey.BackupOnJoin ) ) { map.SaveBackup( GetMapName(), String.Format( "backups/{0}_{1:yyyy-MM-dd HH-mm}_{2}.fcm", name, DateTime.Now, player.name ) ); } } players.Add( player.id, player ); UpdatePlayerList(); // Reveal newcommer to existing players if( !player.isHidden ) { SendToAll( PacketWriter.MakeAddEntity( player, player.pos ), player ); Server.SendToAll( String.Format( "{0}Player {1} joined \"{2}\".", Color.Sys, player.GetLogName(), name ), player ); } } Logger.Log( "Player {0} joined \"{1}\".", LogType.UserActivity, player.GetLogName(), name ); if( OnPlayerJoined != null ) OnPlayerJoined( player, this ); if( isLocked ) { player.Message( Color.Red, "This map is currently locked." ); } }
internal static void DoReplace(Player player, Position[] marks, object tag) { player.drawingInProgress = true; Block rfromBlock; Block rtoBlock; if (tag == null || player.bl2 == null) { player.Message("ERROR: variable 'tag' or 'bl2' unspecified!"); return; } else { rfromBlock = (Block)tag; rtoBlock = (Block)player.bl2; } // find start/end coordinates int sx = Math.Min(marks[0].x, marks[1].x); int ex = Math.Max(marks[0].x, marks[1].x); int sy = Math.Min(marks[0].y, marks[1].y); int ey = Math.Max(marks[0].y, marks[1].y); int sh = Math.Min(marks[0].h, marks[1].h); int eh = Math.Max(marks[0].h, marks[1].h); int blocks; byte block; int step = 8; blocks = (ex - sx + 1) * (ey - sy + 1) * (eh - sh + 1); if (blocks > 2000000) { player.Message("NOTE: This draw command is too massive to undo."); } if (rfromBlock == Block.Admincrete && !player.Can(Permissions.DeleteAdmincrete)) { player.Message("Error: Cannot delete admincrete!"); return; } if (rtoBlock == Block.Admincrete && !player.Can(Permissions.PlaceAdmincrete)) { player.Message("Error: Cannot place admincrete!"); return; } for (int x = sx; x <= ex; x += step) { for (int y = sy; y <= ey; y += step) { for (int h = sh; h <= eh; h++) { for (int y3 = 0; y3 < step && y + y3 <= ey; y3++) { for (int x3 = 0; x3 < step && x + x3 <= ex; x3++) { block = player.world.map.GetBlock(x + x3, y + y3, h); if (block == (byte)rfromBlock) { player.drawUndoBuffer.Enqueue(new BlockUpdate(Player.Console, x + x3, y + y3, h, block)); player.world.map.QueueUpdate(new BlockUpdate(Player.Console, x + x3, y + y3, h, (byte)rtoBlock)); } } } } } } player.Message("Replacing " + blocks + " blocks... The map is now being updated."); Logger.Log("{0} initiated replacing an area containing {1} blocks from type {2} to type {3}.", LogType.UserActivity, player.GetLogName(), blocks, rfromBlock.ToString(), rtoBlock.ToString()); GC.Collect(GC.MaxGeneration, GCCollectionMode.Optimized); player.drawingInProgress = false; }
internal static void DrawEllipsoid( Player player, Position[] marks, object tag ) { player.drawingInProgress = true; Block drawBlock; if( tag == null ) { drawBlock = player.lastUsedBlockType; } else { drawBlock = (Block)tag; } // find start/end coordinates int sx = Math.Min( marks[0].x, marks[1].x ); int ex = Math.Max( marks[0].x, marks[1].x ); int sy = Math.Min( marks[0].y, marks[1].y ); int ey = Math.Max( marks[0].y, marks[1].y ); int sh = Math.Min( marks[0].h, marks[1].h ); int eh = Math.Max( marks[0].h, marks[1].h ); int blocks; byte block; int step = 8; blocks = (ex - sx + 1) * (ey - sy + 1) * (eh - sh + 1); if( blocks > 2000000 ) { player.Message( "NOTE: This draw command is too massive to undo." ); } // find axis lengths double rx = (ex - sx + 1) / 2 + .25; double ry = (ey - sy + 1) / 2 + .25; double rh = (eh - sh + 1) / 2 + .25; double rx2 = 1 / (rx * rx); double ry2 = 1 / (ry * ry); double rh2 = 1 / (rh * rh); // find center points double cx = (ex + sx) / 2; double cy = (ey + sy) / 2; double ch = (eh + sh) / 2; // prepare to draw player.drawUndoBuffer.Clear(); blocks = (int)(Math.PI * 0.75 * rx * ry * rh); if( blocks > 2000000 ) { player.Message( "NOTE: This draw command is too massive to undo." ); } for ( int x = sx; x <= ex; x += step ) { for ( int y = sy; y <= ey; y += step ) { for ( int h = sh; h <= eh; h++ ) { for ( int y3 = 0; y3 < step && y + y3 <= ey; y3++ ) { for ( int x3 = 0; x3 < step && x + x3 <= ex; x3++ ) { // get relative coordinates double dx = ( x + x3 - cx ); double dy = ( y + y3 - cy ); double dh = ( h - ch ); // test if it's inside ellipse if ( ( dx * dx ) * rx2 + ( dy * dy ) * ry2 + ( dh * dh ) * rh2 <= 1 ) { block = player.world.map.GetBlock( x + x3, y + y3, h ); if ( block == (byte)drawBlock ) continue; if ( block == (byte)Block.Admincrete && !player.Can( Permissions.DeleteAdmincrete ) ) continue; player.drawUndoBuffer.Enqueue( new BlockUpdate( Player.Console, x + x3, y + y3, h, block ) ); player.world.map.QueueUpdate( new BlockUpdate( Player.Console, x + x3, y + y3, h, (byte)drawBlock ) ); } } } } } } player.drawingInProgress = false; player.Message( "Drawing " + blocks + " blocks... The map is now being updated." ); Logger.Log( "{0} initiated drawing a cuboid containing {1} blocks of type {2}.", LogType.UserActivity, player.GetLogName(), blocks, drawBlock.ToString() ); GC.Collect( GC.MaxGeneration, GCCollectionMode.Optimized ); }
internal static void DrawCuboid( Player player, Position[] marks, object tag ) { player.drawingInProgress = true; Block drawBlock; if( tag == null ) { drawBlock = player.lastUsedBlockType; } else { drawBlock = (Block)tag; } // find start/end coordinates int sx = Math.Min( marks[0].x, marks[1].x ); int ex = Math.Max( marks[0].x, marks[1].x ); int sy = Math.Min( marks[0].y, marks[1].y ); int ey = Math.Max( marks[0].y, marks[1].y ); int sh = Math.Min( marks[0].h, marks[1].h ); int eh = Math.Max( marks[0].h, marks[1].h ); int blocks; byte block; int step = 8; blocks = (ex - sx + 1) * (ey - sy + 1) * (eh - sh + 1); if( blocks > 2000000 ) { player.Message( "NOTE: This draw command is too massive to undo." ); } for ( int x = sx; x <= ex; x += step ) { for ( int y = sy; y <= ey; y += step ) { for ( int h = sh; h <= eh; h++ ) { for ( int y3 = 0; y3 < step && y + y3 <= ey; y3++ ) { for ( int x3 = 0; x3 < step && x + x3 <= ex; x3++ ) { block = player.world.map.GetBlock( x + x3, y + y3, h ); if ( block == (byte)drawBlock ) continue; if ( block == (byte)Block.Admincrete && !player.Can( Permissions.DeleteAdmincrete ) ) continue; player.drawUndoBuffer.Enqueue( new BlockUpdate( Player.Console, x + x3, y + y3, h, block ) ); player.world.map.QueueUpdate( new BlockUpdate( Player.Console, x + x3, y + y3, h, (byte)drawBlock ) ); } } } } } player.Message( "Drawing " + blocks + " blocks... The map is now being updated." ); Logger.Log( "{0} initiated drawing a cuboid containing {1} blocks of type {2}.", LogType.UserActivity, player.GetLogName(), blocks, drawBlock.ToString() ); GC.Collect( GC.MaxGeneration, GCCollectionMode.Optimized ); player.drawingInProgress = false; }