public void MuteTarget(AdKatsRecord record) { this.DebugWrite("Entering muteTarget", 6); try { if (!this.HasAccess(record.target_player, this._CommandKeyDictionary["player_mute"])) { if (!this._RoundMutedPlayers.ContainsKey(record.target_name)) { this._RoundMutedPlayers.Add(record.target_name, 0); this.PlayerSayMessage(record.target_name, this._MutedPlayerMuteMessage); this.SendMessageToSource(record, record.target_name + " has been muted for this round."); } else { this.SendMessageToSource(record, record.target_name + " already muted for this round."); } } else { this.SendMessageToSource(record, "You can't mute an admin, dimwit."); } record.record_action_executed = true; } catch (Exception e) { record.record_exception = new AdKatsException("Error while taking action for Mute record.", e); this.HandleException(record.record_exception); this.FinalizeRecord(record); } this.DebugWrite("Exiting muteTarget", 6); }
//DONE private Boolean FetchIROStatus(AdKatsRecord record) { DebugWrite("FetchIROStatus starting!", 6); //Make sure database connection active if (this.HandlePossibleDisconnect()) { record.record_exception = new AdKatsException("Database not connected."); return false; } try { using (MySqlConnection connection = this.GetDatabaseConnection()) { using (MySqlCommand command = connection.CreateCommand()) { command.CommandText = @" SELECT `record_time` AS `latest_time` FROM `adkats_records_main` INNER JOIN `adkats_commands` ON `adkats_records_main`.`command_type` = `adkats_commands`.`command_id` WHERE `adkats_commands`.`command_key` = 'player_punish' AND `adkats_records_main`.`target_id` = " + record.target_player.player_id + @" AND DATE_ADD(`record_time`, INTERVAL " + this._IROTimeout + @" MINUTE) > UTC_TIMESTAMP() ORDER BY `record_time` DESC LIMIT 1"; using (MySqlDataReader reader = command.ExecuteReader()) { if (reader.Read()) { this.DebugWrite("Punish is Double counted", 6); return true; } return false; } } } } catch (Exception e) { this.HandleException(new AdKatsException("Error while checking if punish will be IRO.", e)); //Assume false if any errors return false; } }
//DONE private IEnumerable<AdKatsRecord> FetchUnreadRecords() { DebugWrite("fetchUnreadRecords starting!", 6); //Create return list List<AdKatsRecord> records = new List<AdKatsRecord>(); //Make sure database connection active if (this.HandlePossibleDisconnect()) { return records; } try { using (MySqlConnection connection = this.GetDatabaseConnection()) { using (MySqlCommand command = connection.CreateCommand()) { String sql = @" SELECT `record_id`, `server_id`, `command_type`, `command_action`, `command_numeric`, `target_name`, `target_id`, `source_name`, `record_message`, `record_time` FROM `" + this._MySqlDatabaseName + @"`.`adkats_records_main` WHERE `adkats_read` = 'N' AND `server_id` = " + this._ServerID; command.CommandText = sql; using (MySqlDataReader reader = command.ExecuteReader()) { //Grab the record while (reader.Read()) { AdKatsRecord record = new AdKatsRecord(); record.record_source = AdKatsRecord.Sources.Database; record.record_id = reader.GetInt64("record_id"); record.server_id = reader.GetInt64("server_id"); Int32 commandTypeInt = reader.GetInt32("command_type"); if (!this._CommandIDDictionary.TryGetValue(commandTypeInt, out record.command_type)) { this.ConsoleError("Unable to parse command type " + commandTypeInt + " when fetching record by ID."); } Int32 commandActionInt = reader.GetInt32("command_action"); if (!this._CommandIDDictionary.TryGetValue(commandActionInt, out record.command_action)) { this.ConsoleError("Unable to parse command action " + commandActionInt + " when fetching record by ID."); } record.command_numeric = reader.GetInt32("command_numeric"); record.target_name = reader.GetString("target_name"); object value = reader.GetValue(6); Int64 targetIDParse = -1; DebugWrite("id fetched!", 6); if (Int64.TryParse(value.ToString(), out targetIDParse)) { DebugWrite("id parsed! " + targetIDParse, 6); //Check if the player needs to be imported, or if they are already in the server AdKatsPlayer importedPlayer = this.FetchPlayer(false, true, targetIDParse, null, null, null); if (importedPlayer == null) { continue; } AdKatsPlayer currentPlayer = null; if (!String.IsNullOrEmpty(importedPlayer.player_name) && this._PlayerDictionary.TryGetValue(importedPlayer.player_name, out currentPlayer)) { this.DebugWrite("External player is currently in the server, using existing data.", 5); record.target_player = currentPlayer; } else { this.DebugWrite("External player is not in the server, fetching from database.", 5); record.target_player = importedPlayer; } record.target_name = record.target_player.player_name; } else { DebugWrite("id parse failed!", 6); } record.source_name = reader.GetString("source_name"); record.record_message = reader.GetString("record_message"); record.record_time = reader.GetDateTime("record_time"); records.Add(record); } } } } } catch (Exception e) { this.HandleException(new AdKatsException("Error while fetching unread records from database.", e)); } DebugWrite("fetchUnreadRecords finished!", 6); return records; }
private void DatabaseCommunicationThreadLoop() { try { this.DebugWrite("DBCOMM: Starting Database Comm Thread", 1); Thread.CurrentThread.Name = "databasecomm"; Boolean firstRun = true; while (true) { try { this.DebugWrite("DBCOMM: Entering Database Comm Thread Loop", 7); if (!this._IsEnabled) { this.DebugWrite("DBCOMM: Detected AdKats not enabled. Exiting thread " + Thread.CurrentThread.Name, 6); break; } //Sleep for 10ms Thread.Sleep(10); //Check if database connection settings have changed if (this._DbSettingsChanged) { this.DebugWrite("DBCOMM: DB Settings have changed, calling test.", 6); if (this.TestDatabaseConnection()) { this.DebugWrite("DBCOMM: Database Connection Good. Continuing Thread.", 6); } else { this._DbSettingsChanged = true; continue; } } //On first run, pull all roles and commands and update database if needed if (firstRun) { this.FetchCommands(); this.FetchRoles(); this.UpdateDatabase37014000(); } //Every 60 seconds feed stat logger settings if (this._LastStatLoggerStatusUpdateTime.AddSeconds(60) < DateTime.UtcNow) { this._LastStatLoggerStatusUpdateTime = DateTime.UtcNow; if (this._StatLoggerVersion == "BF3") { //this.setExternalPluginSetting("CChatGUIDStatsLoggerBF3", "Enable Chatlogging?", "No"); //this.setExternalPluginSetting("CChatGUIDStatsLoggerBF3", "Log ServerSPAM?", "No"); //this.setExternalPluginSetting("CChatGUIDStatsLoggerBF3", "Instant Logging of Chat Messages?", "No"); //this.setExternalPluginSetting("CChatGUIDStatsLoggerBF3", "Enable chatlog filter(Regex)?", "No"); if (this._FeedStatLoggerSettings) { //Due to narwhals, Stat logger time offset is in the opposite direction of Adkats time offset Double slOffset = DateTime.UtcNow.Subtract(DateTime.Now).TotalHours; this.SetExternalPluginSetting("CChatGUIDStatsLoggerBF3", "Servertime Offset", slOffset + ""); } } else if (this._StatLoggerVersion == "UNIVERSAL") { //this.setExternalPluginSetting("CChatGUIDStatsLogger", "Enable Chatlogging?", "No"); //this.setExternalPluginSetting("CChatGUIDStatsLogger", "Log ServerSPAM?", "No"); //this.setExternalPluginSetting("CChatGUIDStatsLogger", "Instant Logging of Chat Messages?", "No"); //this.setExternalPluginSetting("CChatGUIDStatsLogger", "Enable chatlog filter(Regex)?", "No"); if (this._FeedStatLoggerSettings) { //Due to narwhals, Stat logger time offset is in the opposite direction of Adkats time offset Double slOffset = DateTime.UtcNow.Subtract(DateTime.Now).TotalHours; this.SetExternalPluginSetting("CChatGUIDStatsLogger", "Servertime Offset", slOffset + ""); } } else { this.ConsoleError("Stat logger version is unknown, unable to feed stat logger settings."); } //TODO put back in the future //this.confirmStatLoggerSetup(); } //Update server ID if (this._ServerID < 0) { //Checking for database server info if (this.FetchServerID() >= 0) { this.ConsoleSuccess("Database Server Info Fetched. Server ID is " + this._ServerID + "!"); //Push all settings for this instance to the database this.UploadAllSettings(); } else { //Inform the user this.ConsoleError("Database Server info could not be fetched! Make sure XpKiller's Stat Logger is running on this server!"); //Disable the plugin this.Disable(); break; } } else { this.DebugWrite("Skipping server ID fetch. Server ID: " + this._ServerID, 7); } //Check if settings need sync if (this._SettingImportID != this._ServerID || this._LastDbSettingFetch.AddSeconds(DbSettingFetchFrequency) < DateTime.UtcNow) { this.DebugWrite("Preparing to fetch settings from server " + _ServerID, 6); //Fetch new settings from the database this.FetchSettings(this._SettingImportID, this._SettingImportID != this._ServerID); } //Handle Inbound Setting Uploads if (this._SettingUploadQueue.Count > 0) { this.DebugWrite("DBCOMM: Preparing to lock inbound setting queue to get new settings", 7); Queue<CPluginVariable> inboundSettingUpload; lock (this._SettingUploadQueue) { this.DebugWrite("DBCOMM: Inbound settings found. Grabbing.", 6); //Grab all settings in the queue inboundSettingUpload = new Queue<CPluginVariable>(this._SettingUploadQueue.ToArray()); //Clear the queue for next run this._SettingUploadQueue.Clear(); } //Loop through all settings in order that they came in while (inboundSettingUpload.Count > 0) { CPluginVariable setting = inboundSettingUpload.Dequeue(); this.UploadSetting(setting); } } //Handle Inbound Command Uploads if (this._CommandUploadQueue.Count > 0) { this.DebugWrite("DBCOMM: Preparing to lock inbound command queue to get new commands", 7); Queue<AdKatsCommand> inboundCommandUpload; lock (this._CommandUploadQueue) { this.DebugWrite("DBCOMM: Inbound commands found. Grabbing.", 6); //Grab all commands in the queue inboundCommandUpload = new Queue<AdKatsCommand>(this._CommandUploadQueue.ToArray()); //Clear the queue for next run this._CommandUploadQueue.Clear(); } //Loop through all commands in order that they came in while (inboundCommandUpload.Count > 0) { AdKatsCommand command = inboundCommandUpload.Dequeue(); this.UploadCommand(command); this.FetchCommands(); this.FetchRoles(); this.FetchUserList(); this.UpdateSettingPage(); } } //Handle Inbound Role Uploads if (this._RoleUploadQueue.Count > 0) { this.DebugWrite("DBCOMM: Preparing to lock inbound role queue to get new roles", 7); Queue<AdKatsRole> inboundRoleUpload; lock (this._RoleUploadQueue) { this.DebugWrite("DBCOMM: Inbound roles found. Grabbing.", 6); //Grab all roles in the queue inboundRoleUpload = new Queue<AdKatsRole>(this._RoleUploadQueue.ToArray()); //Clear the queue for next run this._RoleUploadQueue.Clear(); } //Loop through all roles in order that they came in while (inboundRoleUpload.Count > 0) { AdKatsRole aRole = inboundRoleUpload.Dequeue(); this.UploadRole(aRole); this.FetchCommands(); this.FetchRoles(); this.FetchUserList(); this.UpdateSettingPage(); } } //Handle Inbound Role Removal if (this._RoleRemovalQueue.Count > 0) { this.DebugWrite("DBCOMM: Preparing to lock removal role queue to get new roles", 7); Queue<AdKatsRole> inboundRoleRemoval; lock (this._RoleRemovalQueue) { this.DebugWrite("DBCOMM: Inbound roles found. Grabbing.", 6); //Grab all roles in the queue inboundRoleRemoval = new Queue<AdKatsRole>(this._RoleRemovalQueue.ToArray()); //Clear the queue for next run this._RoleRemovalQueue.Clear(); } //Loop through all commands in order that they came in while (inboundRoleRemoval.Count > 0) { AdKatsRole aRole = inboundRoleRemoval.Dequeue(); this.RemoveRole(aRole); this.FetchCommands(); this.FetchRoles(); this.FetchUserList(); this.UpdateSettingPage(); } } //Check for new actions from the database at given interval if (this._FetchActionsFromDb && (DateTime.UtcNow > this._LastDbActionFetch.AddSeconds(DbActionFetchFrequency))) { this.RunActionsFromDB(); } else { this.DebugWrite("DBCOMM: Skipping DB action fetch", 7); } //Call banlist at set interval (20 seconds) if (this._UseBanEnforcerPreviousState && (DateTime.UtcNow > this._LastBanListCall.AddSeconds(20))) { this._LastBanListCall = DateTime.UtcNow; this.DebugWrite("banlist.list called at interval.", 6); this.ExecuteCommand("procon.protected.send", "banList.list"); } //Handle access updates if (this._UserUploadQueue.Count > 0 || this._UserRemovalQueue.Count > 0) { this.DebugWrite("DBCOMM: Preparing to lock inbound access queues to retrive access changes", 7); Queue<AdKatsUser> inboundUserRemoval; Queue<AdKatsUser> inboundUserUploads; lock (_UserMutex) { this.DebugWrite("DBCOMM: Inbound access changes found. Grabbing.", 6); //Grab all in the queue inboundUserUploads = new Queue<AdKatsUser>(this._UserUploadQueue.ToArray()); inboundUserRemoval = new Queue<AdKatsUser>(this._UserRemovalQueue.ToArray()); //Clear the queue for next run this._UserUploadQueue.Clear(); this._UserRemovalQueue.Clear(); } //Loop through all records in order that they came in while (inboundUserUploads.Count > 0) { AdKatsUser user = inboundUserUploads.Dequeue(); this.UploadUser(user); } //Loop through all records in order that they came in while (inboundUserRemoval.Count > 0) { AdKatsUser user = inboundUserRemoval.Dequeue(); this.ConsoleWarn("Removing user " + user.user_name); this.RemoveUser(user); } this.FetchUserList(); //Update the setting page with new information this.UpdateSettingPage(); } else if (DateTime.UtcNow > this._LastUserFetch.AddSeconds(DbUserFetchFrequency)) { //Handle user updates directly from the database this.FetchUserList(); //If there are now users in the user list, update the UI if (this._UserCache.Count > 0) { //Update the setting page with new information this.UpdateSettingPage(); } } else if (this._UserCache.Count == 0) { //Handle access updates directly from the database this.FetchUserList(); //If there are now people in the access list, update the UI if (this._UserCache.Count > 0) { //Update the setting page with new information this.UpdateSettingPage(); } } else { this.DebugWrite("DBCOMM: No inbound user changes.", 7); } //Start the other threads if (firstRun) { //Start other threads this._PlayerListingThread.Start(); this._KillProcessingThread.Start(); this._MessageProcessingThread.Start(); this._CommandParsingThread.Start(); this._ActionHandlingThread.Start(); this._TeamSwapThread.Start(); this._BanEnforcerThread.Start(); this._HackerCheckerThread.Start(); firstRun = false; this._ThreadsReady = true; this.UpdateSettingPage(); //Register a command to indicate availibility to other plugins this.RegisterCommand(this._IssueCommandMatchCommand); this.RegisterCommand(this._FetchAuthorizedSoldiersMatchCommand); this.ConsoleWrite("^b^2Running!^n^0 Version: " + this.GetPluginVersion()); } //Ban Enforcer if (this._UseBanEnforcer) { this.FetchNameBanCount(); this.FetchGUIDBanCount(); this.FetchIPBanCount(); if (!this._UseBanEnforcerPreviousState || (DateTime.UtcNow > this._LastDbBanFetch.AddSeconds(DbBanFetchFrequency))) { //Load all bans on startup if (!this._UseBanEnforcerPreviousState) { //Get all bans from procon this.ConsoleWarn("Preparing to queue procon bans for import. Please wait."); this._DbCommunicationWaitHandle.Reset(); this.ExecuteCommand("procon.protected.send", "banList.list"); this._DbCommunicationWaitHandle.WaitOne(TimeSpan.FromMinutes(5)); if (this._CBanProcessingQueue.Count > 0) { this.ConsoleWrite(this._CBanProcessingQueue.Count + " procon bans queued for import. Import might take several minutes if you have many bans!"); } else { this.ConsoleWrite("No procon bans to import into Ban Enforcer."); } } } else { this.DebugWrite("DBCOMM: Skipping DB ban fetch", 7); } //Handle Inbound Ban Comms if (this._BanEnforcerProcessingQueue.Count > 0) { this.DebugWrite("DBCOMM: Preparing to lock inbound ban enforcer queue to retrive new bans", 7); Queue<AdKatsBan> inboundBans; lock (this._BanEnforcerMutex) { this.DebugWrite("DBCOMM: Inbound bans found. Grabbing.", 6); //Grab all messages in the queue inboundBans = new Queue<AdKatsBan>(this._BanEnforcerProcessingQueue.ToArray()); //Clear the queue for next run this._BanEnforcerProcessingQueue.Clear(); } Int32 index = 1; //Loop through all bans in order that they came in while (inboundBans.Count > 0) { if (!this._IsEnabled || !this._UseBanEnforcer) { this.ConsoleWarn("Canceling ban import mid-operation."); break; } //Grab the ban AdKatsBan aBan = inboundBans.Dequeue(); this.DebugWrite("DBCOMM: Processing Frostbite Ban: " + index++, 6); //Upload the ban this.UploadBan(aBan); //Only perform special action when ban is direct //Indirect bans are through the procon banlist, so the player has already been kicked if (aBan.ban_record.source_name != "BanEnforcer") { //Enforce the ban this.EnforceBan(aBan, false); } else { this.RemovePlayerFromDictionary(aBan.ban_record.target_player.player_name); } } } //Handle BF3 Ban Manager imports if (!this._UseBanEnforcerPreviousState) { //Import all bans from BF3 Ban Manager this.ImportBansFromBBM5108(); } //Handle Inbound CBan Uploads if (this._CBanProcessingQueue.Count > 0) { if (!this._UseBanEnforcerPreviousState) { this.ConsoleWarn("Do not disable AdKats or change any settings until upload is complete!"); } this.DebugWrite("DBCOMM: Preparing to lock inbound cBan queue to retrive new cBans", 7); Double totalCBans = 0; Double bansImported = 0; Boolean earlyExit = false; DateTime startTime = DateTime.UtcNow; Queue<CBanInfo> inboundCBans; lock (this._CBanProcessingQueue) { this.DebugWrite("DBCOMM: Inbound cBans found. Grabbing.", 6); //Grab all cBans in the queue inboundCBans = new Queue<CBanInfo>(this._CBanProcessingQueue.ToArray()); totalCBans = inboundCBans.Count; //Clear the queue for next run this._CBanProcessingQueue.Clear(); } //Loop through all cBans in order that they came in Boolean bansFound = false; while (inboundCBans.Count > 0) { //Break from the loop if the plugin is disabled or the setting is reverted. if (!this._IsEnabled || !this._UseBanEnforcer) { this.ConsoleWarn("You exited the ban upload process early, the process was not completed."); earlyExit = true; break; } bansFound = true; CBanInfo cBan = inboundCBans.Dequeue(); //Create the record AdKatsRecord record = new AdKatsRecord(); record.record_source = AdKatsRecord.Sources.InternalAutomated; //Permabans and Temp bans longer than 1 year will be defaulted to permaban if (cBan.BanLength.Seconds > 0 && cBan.BanLength.Seconds < 31536000) { record.command_type = this._CommandKeyDictionary["player_ban_temp"]; record.command_action = this._CommandKeyDictionary["player_ban_temp"]; record.command_numeric = cBan.BanLength.Seconds / 60; } else { record.command_type = this._CommandKeyDictionary["player_ban_perm"]; record.command_action = this._CommandKeyDictionary["player_ban_perm"]; record.command_numeric = 0; } record.source_name = this._CBanAdminName; record.server_id = this._ServerID; record.target_player = this.FetchPlayer(true, true, -1, cBan.SoldierName, cBan.Guid, cBan.IpAddress); if (!String.IsNullOrEmpty(record.target_player.player_name)) { record.target_name = record.target_player.player_name; } record.isIRO = false; record.record_message = cBan.Reason; //Update the ban enforcement depending on available information Boolean nameAvailable = !String.IsNullOrEmpty(record.target_player.player_name); Boolean guidAvailable = !String.IsNullOrEmpty(record.target_player.player_guid); Boolean ipAvailable = !String.IsNullOrEmpty(record.target_player.player_ip); //Create the ban AdKatsBan aBan = new AdKatsBan { ban_record = record, ban_enforceName = nameAvailable && (this._DefaultEnforceName || (!guidAvailable && !ipAvailable) || !String.IsNullOrEmpty(cBan.SoldierName)), ban_enforceGUID = guidAvailable && (this._DefaultEnforceGUID || (!nameAvailable && !ipAvailable) || !String.IsNullOrEmpty(cBan.Guid)), ban_enforceIP = ipAvailable && (this._DefaultEnforceIP || (!nameAvailable && !guidAvailable) || !String.IsNullOrEmpty(cBan.IpAddress)) }; if (!aBan.ban_enforceName && !aBan.ban_enforceGUID && !aBan.ban_enforceIP) { this.ConsoleError("Unable to create ban, no proper player information"); continue; } //Upload the ban this.DebugWrite("Uploading ban from procon.", 5); this.UploadBan(aBan); if (!this._UseBanEnforcerPreviousState && (++bansImported % 25 == 0)) { this.ConsoleWrite(Math.Round(100 * bansImported / totalCBans, 2) + "% of bans uploaded. AVG " + Math.Round(bansImported / ((DateTime.UtcNow - startTime).TotalSeconds), 2) + " uploads/sec."); } } if (bansFound && !earlyExit) { //If all bans have been queued for processing, clear the ban list this.ExecuteCommand("procon.protected.send", "banList.clear"); this.ExecuteCommand("procon.protected.send", "banList.save"); this.ExecuteCommand("procon.protected.send", "banList.list"); if (!this._UseBanEnforcerPreviousState) { this.ConsoleSuccess("All bans uploaded into AdKats database."); } } } this._UseBanEnforcerPreviousState = true; } else { //If the ban enforcer was previously enabled, and the user disabled it, repopulate procon's ban list if (this._UseBanEnforcerPreviousState) { this.RepopulateProconBanList(); this._UseBanEnforcerPreviousState = false; } //If not, completely ignore all ban enforcer code } //Handle Inbound Records if (this._UnprocessedRecordQueue.Count > 0) { this.DebugWrite("DBCOMM: Preparing to lock inbound record queue to retrive new records", 7); Queue<AdKatsRecord> inboundRecords; lock (this._UnprocessedRecordMutex) { this.DebugWrite("DBCOMM: Inbound records found. Grabbing.", 6); //Grab all messages in the queue inboundRecords = new Queue<AdKatsRecord>(this._UnprocessedRecordQueue.ToArray()); //Clear the queue for next run this._UnprocessedRecordQueue.Clear(); } //Loop through all records in order that they came in while (inboundRecords.Count > 0) { //Pull the next record AdKatsRecord record = inboundRecords.Dequeue(); //Upload the record this.HandleRecordUpload(record); //Check for action handling needs if (!record.record_action_executed) { //Action is only called after initial upload, not after update this.DebugWrite("DBCOMM: Upload success. Attempting to add to action queue.", 6); //Only queue the record for action handling if it's not an enforced ban if (record.command_type.command_key != "banenforcer_enforce") { this.QueueRecordForActionHandling(record); } } else { this.DebugWrite("DBCOMM: Update success. Record does not need action handling.", 6); //finalize the record this.FinalizeRecord(record); } } } else { this.DebugWrite("DBCOMM: No unprocessed records. Waiting for input", 7); this._DbCommunicationWaitHandle.Reset(); if (this._FetchActionsFromDb || this._UseBanEnforcer || this._UsingAwa) { //If waiting on DB input, the maximum time we can wait is "db action frequency" this._DbCommunicationWaitHandle.WaitOne(DbActionFetchFrequency * 1000); } else { //Maximum wait time is DB access fetch time this._DbCommunicationWaitHandle.WaitOne(DbUserFetchFrequency * 1000); } } } catch (Exception e) { if (e is ThreadAbortException) { this.HandleException(new AdKatsException("Database Comm thread aborted. Exiting.")); break; } this.HandleException(new AdKatsException("Error occured in Database Comm thread. Skipping current loop.", e)); } } this.DebugWrite("DBCOMM: Ending Database Comm Thread", 1); } catch (Exception e) { this.HandleException(new AdKatsException("Error occured in database comm thread.", e)); } }
public void CancelSourcePendingAction(AdKatsRecord record) { this.DebugWrite("Entering cancelSourcePendingAction", 7); try { this.DebugWrite("attempting to cancel command", 6); lock (_ActionConfirmMutex) { if (!this._ActionConfirmDic.Remove(record.source_name)) { //this.sendMessageToSource(record, "No command to cancel."); } else { this.SendMessageToSource(record, "Previous command Canceled."); } } } catch (Exception e) { record.record_exception = this.HandleException(new AdKatsException("Error while canceling source pending action.", e)); } this.DebugWrite("Exiting cancelSourcePendingAction", 7); }
private void BanEnforcerThreadLoop() { try { this.DebugWrite("BANENF: Starting Ban Enforcer Thread", 1); Thread.CurrentThread.Name = "BanEnforcer"; while (true) { try { this.DebugWrite("BANENF: Entering Ban Enforcer Thread Loop", 7); if (!this._IsEnabled) { this.DebugWrite("BANENF: Detected AdKats not enabled. Exiting thread " + Thread.CurrentThread.Name, 6); break; } //Get all unchecked players Queue<AdKatsPlayer> playerCheckingQueue = new Queue<AdKatsPlayer>(); if (this._BanEnforcerCheckingQueue.Count > 0 && this._UseBanEnforcer) { this.DebugWrite("BANENF: Preparing to lock banEnforcerMutex to retrive new players", 6); lock (_BanEnforcerMutex) { this.DebugWrite("BANENF: Inbound players found. Grabbing.", 5); //Grab all players in the queue playerCheckingQueue = new Queue<AdKatsPlayer>(this._BanEnforcerCheckingQueue.ToArray()); //Clear the queue for next run this._BanEnforcerCheckingQueue.Clear(); } } else { this.DebugWrite("BANENF: No inbound ban checks. Waiting for Input.", 4); //Wait for input this._BanEnforcerWaitHandle.Reset(); this._BanEnforcerWaitHandle.WaitOne(Timeout.Infinite); continue; } //Get all checks in order that they came in while (playerCheckingQueue.Count > 0) { //Grab first/next player AdKatsPlayer aPlayer = playerCheckingQueue.Dequeue(); this.DebugWrite("BANENF: begin reading player", 5); if (this._PlayerDictionary.ContainsKey(aPlayer.player_name)) { AdKatsBan aBan = this.FetchPlayerBan(aPlayer); if (aBan != null) { this.DebugWrite("BANENF: BAN ENFORCED", 3); //Create the new record AdKatsRecord record = new AdKatsRecord { record_source = AdKatsRecord.Sources.InternalAutomated, source_name = "BanEnforcer", isIRO = false, server_id = this._ServerID, target_name = aPlayer.player_name, target_player = aPlayer, command_type = this._CommandKeyDictionary["banenforcer_enforce"], command_numeric = (int) aBan.ban_id, record_message = aBan.ban_record.record_message }; //Queue record for upload this.QueueRecordForProcessing(record); //Enforce the ban this.EnforceBan(aBan, true); } else { this.DebugWrite("BANENF: No ban found for player", 5); //Only call a ban check if the player does not already have a ban if (this._UseHackerChecker) { this.QueuePlayerForHackerCheck(aPlayer); } } } } } catch (Exception e) { if (e is ThreadAbortException) { this.HandleException(new AdKatsException("ban enforcer thread aborted. Exiting.")); break; } this.HandleException(new AdKatsException("Error occured in ban enforcer thread. Skipping current loop.", e)); } } this.DebugWrite("BANENF: Ending Ban Enforcer Thread", 1); } catch (Exception e) { this.HandleException(new AdKatsException("Error occured in ban enforcer thread.", e)); } }
private void CommandParsingThreadLoop() { try { this.DebugWrite("COMMAND: Starting Command Parsing Thread", 1); Thread.CurrentThread.Name = "Command"; while (true) { try { this.DebugWrite("COMMAND: Entering Command Parsing Thread Loop", 7); if (!this._IsEnabled) { this.DebugWrite("COMMAND: Detected AdKats not enabled. Exiting thread " + Thread.CurrentThread.Name, 6); break; } //Sleep for 10ms Thread.Sleep(10); //Get all unparsed inbound messages if (this._UnparsedCommandQueue.Count > 0) { this.DebugWrite("COMMAND: Preparing to lock command queue to retrive new commands", 7); Queue<KeyValuePair<String, String>> unparsedCommands; lock (_UnparsedCommandMutex) { this.DebugWrite("COMMAND: Inbound commands found. Grabbing.", 6); //Grab all messages in the queue unparsedCommands = new Queue<KeyValuePair<String, String>>(this._UnparsedCommandQueue.ToArray()); //Clear the queue for next run this._UnparsedCommandQueue.Clear(); } //Loop through all commands in order that they came in while (unparsedCommands.Count > 0) { this.DebugWrite("COMMAND: begin reading command", 6); //Dequeue the first/next command KeyValuePair<String, String> commandPair = unparsedCommands.Dequeue(); String speaker = commandPair.Key; String command = commandPair.Value; AdKatsRecord record; if (speaker == "Server") { record = new AdKatsRecord { record_source = AdKatsRecord.Sources.ServerCommand, source_name = "ProconAdmin" }; } else { record = new AdKatsRecord { record_source = AdKatsRecord.Sources.InGame, source_name = speaker }; } //Complete the record creation this.CompleteRecordInformation(record, command); } } else { this.DebugWrite("COMMAND: No inbound commands, ready.", 7); //No commands to parse, ready. this._CommandParsingWaitHandle.Reset(); this._CommandParsingWaitHandle.WaitOne(Timeout.Infinite); } } catch (Exception e) { if (e is ThreadAbortException) { this.HandleException(new AdKatsException("Command thread aborted. Exiting.")); break; } this.HandleException(new AdKatsException("Error occured in Command thread. Skipping current loop.", e)); } } this.DebugWrite("COMMAND: Ending Command Thread", 1); } catch (Exception e) { this.HandleException(new AdKatsException("Error occured in command parsing thread.", e)); } }
public void RestartLevel(AdKatsRecord record) { this.DebugWrite("Entering restartLevel", 6); try { this.ExecuteCommand("procon.protected.send", "mapList.restartRound"); this.SendMessageToSource(record, "Round Restarted."); record.record_action_executed = true; } catch (Exception e) { record.record_exception = new AdKatsException("Error while taking action for RestartLevel record.", e); this.HandleException(record.record_exception); this.FinalizeRecord(record); } this.DebugWrite("Exiting restartLevel", 6); }
public void RoundWhitelistTarget(AdKatsRecord record) { this.DebugWrite("Entering roundWhitelistTarget", 6); try { if (!this._TeamswapRoundWhitelist.ContainsKey(record.target_name)) { if (this._TeamswapRoundWhitelist.Count < this._PlayersToAutoWhitelist + 2) { this._TeamswapRoundWhitelist.Add(record.target_name, false); String command = this._CommandKeyDictionary["self_teamswap"].command_text; this.SendMessageToSource(record, record.target_name + " can now use @" + command + " for this round."); } else { this.SendMessageToSource(record, "Cannot whitelist more than two extra people per round."); } } else { this.SendMessageToSource(record, record.target_name + " is already in this round's TeamSwap whitelist."); } record.record_action_executed = true; } catch (Exception e) { record.record_exception = new AdKatsException("Error while taking action for RoundWhitelist record.", e); this.HandleException(record.record_exception); this.FinalizeRecord(record); } this.DebugWrite("Exiting roundWhitelistTarget", 6); }
public void PlayerTell(AdKatsRecord record) { this.DebugWrite("Entering playerTell", 6); try { this.PlayerTellMessage(record.target_name, record.record_message); this.SendMessageToSource(record, record.target_name + " has been told '" + record.record_message + "' by TELL"); record.record_action_executed = true; } catch (Exception e) { record.record_exception = new AdKatsException("Error while taking action for playerTell record.", e); this.HandleException(record.record_exception); this.FinalizeRecord(record); } this.DebugWrite("Exiting playerTell", 6); }
public void PunishTarget(AdKatsRecord record) { this.DebugWrite("Entering punishTarget", 6); try { //If the record has any exceptions, skip everything else and just kill the player if (record.record_exception == null) { //Get number of points the player from server Int32 points = this.FetchPoints(record.target_player); this.DebugWrite(record.target_player.player_name + " has " + points + " points.", 5); //Get the proper action to take for player punishment String action = "noaction"; String skippedAction = null; if (points > (this._PunishmentHierarchy.Length - 1)) { action = this._PunishmentHierarchy[this._PunishmentHierarchy.Length - 1]; } else if (points > 0) { action = this._PunishmentHierarchy[points - 1]; if (record.isIRO) { skippedAction = this._PunishmentHierarchy[points - 2]; } } else { action = this._PunishmentHierarchy[0]; } //Handle the case where and IRO punish skips higher level punishment for a lower one, use the higher one if (skippedAction != null && this._PunishmentSeverityIndex.IndexOf(skippedAction) > this._PunishmentSeverityIndex.IndexOf(action)) { action = skippedAction; } //Set additional message String pointMessage = " [" + ((record.isIRO) ? ("IRO ") : ("")) + points + "pts]"; if (!record.record_message.Contains(pointMessage)) { record.record_message += pointMessage; } const string additionalMessage = ""; Boolean isLowPop = this._OnlyKillOnLowPop && (this._PlayerDictionary.Count < this._LowPopPlayerCount); Boolean iroOverride = record.isIRO && this._IROOverridesLowPop; this.DebugWrite("Server low population: " + isLowPop + " (" + this._PlayerDictionary.Count + " <? " + this._LowPopPlayerCount + ") | Override: " + iroOverride, 5); //Call correct action if ((action == "kill" || (isLowPop && !iroOverride)) && !action.Equals("ban")) { record.command_action = (isLowPop) ? (this._CommandKeyDictionary["player_kill_lowpop"]) : (this._CommandKeyDictionary["player_kill"]); this.KillTarget(record, additionalMessage); } else if (action == "kick") { record.command_action = this._CommandKeyDictionary["player_kick"]; this.KickTarget(record, additionalMessage); } else if (action == "tban60") { record.command_numeric = 60; record.command_action = this._CommandKeyDictionary["player_ban_temp"]; this.TempBanTarget(record, additionalMessage); } else if (action == "tban120") { record.command_numeric = 120; record.command_action = this._CommandKeyDictionary["player_ban_temp"]; this.TempBanTarget(record, additionalMessage); } else if (action == "tbanday") { record.command_numeric = 1440; record.command_action = this._CommandKeyDictionary["player_ban_temp"]; this.TempBanTarget(record, additionalMessage); } else if (action == "tbanweek") { record.command_numeric = 10080; record.command_action = this._CommandKeyDictionary["player_ban_temp"]; this.TempBanTarget(record, additionalMessage); } else if (action == "tban2weeks") { record.command_numeric = 20160; record.command_action = this._CommandKeyDictionary["player_ban_temp"]; this.TempBanTarget(record, additionalMessage); } else if (action == "tbanmonth") { record.command_numeric = 43200; record.command_action = this._CommandKeyDictionary["player_ban_temp"]; this.TempBanTarget(record, additionalMessage); } else if (action == "ban") { record.command_action = this._CommandKeyDictionary["player_ban_perm"]; this.PermaBanTarget(record, additionalMessage); } else { record.command_action = this._CommandKeyDictionary["player_kill"]; this.KillTarget(record, additionalMessage); record.record_exception = new AdKatsException("Punish options are set incorrectly. '" + action + "' not found. Inform plugin setting manager."); this.HandleException(record.record_exception); } } else { //Exception found, just kill the player record.command_action = this._CommandKeyDictionary["player_kill"]; this.KillTarget(record, null); } record.record_action_executed = true; } catch (Exception e) { record.record_exception = new AdKatsException("Error while taking action for Punish record.", e); this.HandleException(record.record_exception); this.FinalizeRecord(record); } this.DebugWrite("Exiting punishTarget", 6); }
public void PlayerListingThreadLoop() { try { this.DebugWrite("PLIST: Starting Player Listing Thread", 1); Thread.CurrentThread.Name = "playerlisting"; while (true) { try { this.DebugWrite("PLIST: Entering Player Listing Thread Loop", 7); if (!this._IsEnabled) { this.DebugWrite("PLIST: Detected AdKats not enabled. Exiting thread " + Thread.CurrentThread.Name, 6); break; } //Get all unparsed inbound lists Queue<List<CPlayerInfo>> inboundPlayerLists; if (this._PlayerListProcessingQueue.Count > 0) { this.DebugWrite("PLIST: Preparing to lock player list queues to retrive new player lists", 7); lock (this._PlayerListProcessingQueue) { this.DebugWrite("PLIST: Inbound player lists found. Grabbing.", 6); //Grab all lists in the queue inboundPlayerLists = new Queue<List<CPlayerInfo>>(this._PlayerListProcessingQueue.ToArray()); //Clear the queue for next run this._PlayerListProcessingQueue.Clear(); } } else { this.DebugWrite("PLIST: No inbound player lists. Waiting for Input.", 4); //Wait for input this._PlayerListProcessingWaitHandle.Reset(); this._PlayerListProcessingWaitHandle.WaitOne(Timeout.Infinite); continue; } //Loop through all messages in order that they came in while (inboundPlayerLists.Count > 0) { this.DebugWrite("PLIST: begin reading player lists", 6); //Dequeue the first/next message List<CPlayerInfo> players = inboundPlayerLists.Dequeue(); this.DebugWrite("Listing Players", 5); //Player list and ban list need to be locked for this operation lock (this._PlayersMutex) { List<String> playerNames = new List<String>(); //Reset the player counts of both sides and recount everything this._UsPlayerCount = 0; this._RuPlayerCount = 0; //Loop over all players in the list foreach (CPlayerInfo player in players) { playerNames.Add(player.SoldierName); AdKatsPlayer aPlayer = null; //Check if the player is already in the player dictionary if (this._PlayerDictionary.TryGetValue(player.SoldierName, out aPlayer)) { //If they are update the internal frostbite player info this._PlayerDictionary[player.SoldierName].frostbitePlayerInfo = player; } else { //If they aren't in the list, fetch their profile from the database aPlayer = this.FetchPlayer(true, false, -1, player.SoldierName, player.GUID, null); //Add the frostbite player info aPlayer.frostbitePlayerInfo = player; //Set their last death/spawn times aPlayer.lastDeath = DateTime.UtcNow; aPlayer.lastSpawn = DateTime.UtcNow; //Add them to the dictionary this._PlayerDictionary.Add(player.SoldierName, aPlayer); //If using ban enforcer, check the player's ban status if (this._UseBanEnforcer) { this.QueuePlayerForBanCheck(aPlayer); } else if (this._UseHackerChecker) { //Queue the player for a hacker check this.QueuePlayerForHackerCheck(aPlayer); } } if (player.TeamID == UsTeamID) { this._UsPlayerCount++; } else if (player.TeamID == RuTeamID) { this._RuPlayerCount++; } } //Make sure the player dictionary is clean of any straglers List<String> dicPlayerNames = this._PlayerDictionary.Keys.ToList(); Int32 straglerCount = 0; Int32 dicCount = this._PlayerDictionary.Count; foreach (String playerName in dicPlayerNames) { if (!playerNames.Contains(playerName)) { straglerCount++; this.DebugWrite("PLIST: Removing " + playerName + " from current player list (VIA CLEANUP).", 4); this._PlayerDictionary.Remove(playerName); } } //Inform the admins of disconnect if (straglerCount > (dicCount / 2)) { //Create the report record AdKatsRecord record = new AdKatsRecord { record_source = AdKatsRecord.Sources.InternalAutomated, isDebug = true, server_id = this._ServerID, command_type = this._CommandKeyDictionary["player_calladmin"], command_numeric = 0, target_name = "Server", target_player = null, source_name = "AdKats", record_message = "Server Crashed / Blaze Disconnected (" + dicCount + " Players Lost)" }; //Process the record this.QueueRecordForProcessing(record); this.ConsoleError(record.record_message); //Set round ended if (!this._RoundEnded) { this._RoundEnded = true; Thread.Sleep(3000); this._RoundEnded = false; } } } //Update last successful player list time this._LastSuccessfulPlayerList = DateTime.UtcNow; //Set the handle for TeamSwap this._PlayerListUpdateWaitHandle.Set(); } } catch (Exception e) { if (e is ThreadAbortException) { this.ConsoleWarn("player listing thread was force aborted. Exiting."); break; } this.HandleException(new AdKatsException("Error occured in player listing thread.", e)); } } this.DebugWrite("PLIST: Ending Player Listing Thread", 1); } catch (Exception e) { this.HandleException(new AdKatsException("Error occured in player listing thread.", e)); } }
public override HttpWebServerResponseData OnHttpRequest(HttpWebServerRequestData data) { String responseString = "AdKats Remote: "; try { foreach (String key in data.Query.AllKeys) { this.DebugWrite("Query Key: " + key + " val: " + data.Query[key], 6); } this.DebugWrite("method: " + data.Method, 6); //this.DebugWrite("doc: " + data.Document, 6); AdKatsRecord record = new AdKatsRecord { record_source = AdKatsRecord.Sources.HTTP }; NameValueCollection dataCollection = null; if (System.String.Compare(data.Method, "GET", System.StringComparison.OrdinalIgnoreCase) == 0) { dataCollection = data.Query; } else if (System.String.Compare(data.Method, "POST", System.StringComparison.OrdinalIgnoreCase) == 0) { return null; //dataCollection = data.POSTData; } if (dataCollection != null) { String commandString = dataCollection["command_type"]; record.command_type = this._CommandKeyDictionary[commandString]; if (dataCollection["access_key"] != null && dataCollection["access_key"] == this._ExternalCommandAccessKey) { //If command not parsable, return without creating if (record.command_type != null) { //Set the command action record.command_action = record.command_type; //Set the source String sourceName = dataCollection["source_name"]; record.source_name = !String.IsNullOrEmpty(sourceName) ? sourceName : "HTTPAdmin"; String duration = dataCollection["record_durationMinutes"]; record.command_numeric = !string.IsNullOrEmpty(duration) ? Int32.Parse(duration) : 0; String message = dataCollection["record_message"]; if (!String.IsNullOrEmpty(message)) { if (message.Length >= this._RequiredReasonLength) { record.record_message = message; //Check the target String targetName = dataCollection["target_name"]; //Check for an exact match if (!String.IsNullOrEmpty(targetName)) { record.target_name = targetName; this.CompleteTargetInformation(record, false); responseString += "Complete."; } else { responseString += "target_name cannot be null"; } } else { responseString += "Reason too short. Needs to be at least " + this._RequiredReasonLength + " chars."; } } else { responseString += "record_message cannot be null."; } } else { responseString += "Command '" + commandString + "' Not Parsable. Check AdKats doc for valid DB commands."; } } else { responseString += "access_key either not given or incorrect."; } } } catch (Exception e) { responseString += e.ToString(); } return new HttpWebServerResponseData(responseString); }
public void NukeTarget(AdKatsRecord record) { this.DebugWrite("Entering nukeTarget", 6); try { foreach (AdKatsPlayer player in this._PlayerDictionary.Values) { if ((record.target_name == "US Team" && player.frostbitePlayerInfo.TeamID == AdKats.UsTeamID) || (record.target_name == "RU Team" && player.frostbitePlayerInfo.TeamID == AdKats.RuTeamID) || (record.target_name == "Server")) { Thread.Sleep(50); ExecuteCommand("procon.protected.send", "admin.killPlayer", player.player_name); this.PlayerSayMessage(record.target_name, "Killed by admin for: " + record.record_message); } } this.SendMessageToSource(record, "You NUKED " + record.target_name + " for " + record.record_message + "."); record.record_action_executed = true; } catch (Exception e) { record.record_exception = new AdKatsException("Error while taking action for NukeServer record.", e); this.HandleException(record.record_exception); this.FinalizeRecord(record); } this.DebugWrite("Exiting nukeTarget", 6); }
public void UnBanTarget(AdKatsRecord record, String additionalMessage) { this.DebugWrite("Entering UnBanTarget", 6); try { record.record_action_executed = true; if (record.target_player == null) { this.ConsoleError("Player was null when attempting to unban."); this.FinalizeRecord(record); return; } AdKatsBan aBan = this.FetchPlayerBan(record.target_player); if (aBan == null) { this.ConsoleError("Ban could not be fetched when attempting to unban"); this.FinalizeRecord(record); return; } aBan.ban_status = "Disabled"; this.UploadBan(aBan); this.SendMessageToSource(record, record.target_player.player_name + " is now unbanned."); } catch (Exception e) { record.record_exception = new AdKatsException("Error while taking action for UnBan record.", e); this.HandleException(record.record_exception); this.FinalizeRecord(record); } this.DebugWrite("Exiting UnBanTarget", 6); }
public Boolean RunAutoReportAction(String reportID) { //Get the reported record AdKatsRecord reportedRecord; if (this._RoundReports.TryGetValue(reportID, out reportedRecord)) { if (this._IsTestingAuthorized && this._ServerName.ToLower().Contains("no explosives") && reportedRecord.source_player != null && reportedRecord.source_player.player_aa && this.FetchOnlineAdminSoldiers().Count == 0) { String messageLower = reportedRecord.record_message.ToLower(); if (reportedRecord.record_message == "Rules: Baserape. In Streets past A Flag" || reportedRecord.record_message == "Rules: Baserape. Past C Flag" || reportedRecord.record_message == "Rules: Team Griefing" || reportedRecord.record_message == "Rules: Destroying Team Assets" || reportedRecord.record_message == "Rules: Frag Rounds" || reportedRecord.record_message == "Rules: Using M320/GP30" || reportedRecord.record_message == "Rules: Frag Rounds" || messageLower.Contains("frag") || messageLower.Contains("past c") || messageLower.Contains("past lockers") || messageLower.Contains("past a") || messageLower.Contains("street") || messageLower.Contains("gp30") || messageLower.Contains("gp-30") || messageLower.Contains("320")) { this.DebugWrite("Handling round report.", 5); //Remove it from the reports for this round this._RoundReports.Remove(reportID); //Update it in the database reportedRecord.command_action = this._CommandKeyDictionary["player_report_confirm"]; this.UpdateRecord(reportedRecord, false); //Get target information AdKatsRecord aRecord = new AdKatsRecord { record_source = AdKatsRecord.Sources.InternalAutomated, isDebug = false, server_id = this._ServerID, command_type = this._CommandKeyDictionary["player_punish"], command_numeric = 0, target_name = reportedRecord.target_name, target_player = reportedRecord.target_player, source_name = "ProconAdmin", record_message = reportedRecord.record_message }; Thread.Sleep(5000); //Inform the reporter that they helped the admins this.SendMessageToSource(reportedRecord, "Your report has been acted on. Thank you."); //Queue for processing right away this.QueueRecordForProcessing(aRecord); return true; } } } else { this.ConsoleError("Unable to process automatic report."); } return false; }
private Boolean AimbotHackCheck(AdKatsPlayer aPlayer, Boolean debugMode) { Boolean acted = false; try { if (aPlayer == null || aPlayer.stats == null || aPlayer.stats.WeaponStats == null) { return false; } List<String> allowedCategories; switch (this._GameVersion) { case GameVersion.BF3: allowedCategories = new List<string>() { "Sub machine guns", "Assault rifles", "Carbines", "Machine guns" }; break; case GameVersion.BF4: allowedCategories = new List<string>() { "PDW", "ASSAULT RIFLE", "CARBINE", "LMG" }; break; default: return false; } List<AdKatsWeaponStats> topWeapons = aPlayer.stats.WeaponStats.Values.ToList(); topWeapons.Sort(delegate(AdKatsWeaponStats a1, AdKatsWeaponStats a2) { if (a1.Kills == a2.Kills) { return 0; } return (a1.Kills < a2.Kills) ? (1) : (-1); }); AdKatsWeaponStats actedWeapon = null; Double actedHskr = -1; Int32 index = 0; foreach (AdKatsWeaponStats weaponStat in topWeapons) { //Break after 15th top weapon if (index++ > 15) { break; } //Only count certain weapon categories if (allowedCategories.Contains(weaponStat.Category)) { //Only take weapons with more than 100 kills if (weaponStat.Kills > 100) { //Check for aimbot hack this.DebugWrite("Checking " + weaponStat.ID + " HSKR (" + weaponStat.HSKR + " >? " + (this._HskTriggerLevel / 100) + ")", 6); if (weaponStat.HSKR > (this._HskTriggerLevel / 100)) { if (weaponStat.HSKR > actedHskr) { actedHskr = weaponStat.HSKR; actedWeapon = weaponStat; } } } } } if (actedWeapon != null) { acted = true; String formattedName = actedWeapon.ID.Replace("-", "").Replace(" ", "").ToUpper(); this.ConsoleWarn(aPlayer.player_name + " auto-banned for aimbot. [" + formattedName + "-" + (int) (actedWeapon.HSKR * 100) + "-" + (int) actedWeapon.Kills + "-" + (int) actedWeapon.Headshots + "]"); if (!debugMode) { //Create the ban record AdKatsRecord record = new AdKatsRecord { record_source = AdKatsRecord.Sources.InternalAutomated, server_id = this._ServerID, command_type = this._CommandKeyDictionary["player_ban_perm"], command_numeric = 0, target_name = aPlayer.player_name, target_player = aPlayer, source_name = "AutoAdmin", record_message = this._HackerCheckerHSKBanMessage + " [" + formattedName + "-" + (int) (actedWeapon.HSKR * 100) + "-" + (int) actedWeapon.Kills + "-" + (int) actedWeapon.Headshots + "]" }; //Process the record this.QueueRecordForProcessing(record); //this.AdminSayMessage(player.player_name + " auto-banned for aimbot. [" + actedWeapon.id + "-" + (int) actedWeapon.hskr + "-" + (int) actedWeapon.kills + "-" + (int) actedWeapon.headshots + "]"); } } } catch (Exception e) { this.HandleException(new AdKatsException("Error running HSK hack check.", e)); } return acted; }
public void SendMessageToSource(AdKatsRecord record, String message) { this.DebugWrite("Entering sendMessageToSource", 7); String returnMessage = null; try { switch (record.record_source) { case AdKatsRecord.Sources.InGame: if (!String.IsNullOrEmpty(message)) { this.PlayerSayMessage(record.source_name, message); } else { this.ConsoleError("message null or empty in sendMessageToSource"); } break; case AdKatsRecord.Sources.ServerCommand: this.ProconChatWrite(message); break; case AdKatsRecord.Sources.Settings: this.ConsoleWrite(message); break; case AdKatsRecord.Sources.Database: //Do nothing, no way to communicate to source when database break; case AdKatsRecord.Sources.InternalAutomated: //Do nothing, no source to communicate with break; case AdKatsRecord.Sources.ExternalPlugin: record.debugMessages.Add(message); break; case AdKatsRecord.Sources.HTTP: record.debugMessages.Add(message); break; default: this.ConsoleWarn("Command source not set, or not recognized."); break; } } catch (Exception e) { record.record_exception = new AdKatsException("Error while sending message to record source.", e); this.HandleException(record.record_exception); } this.DebugWrite("Exiting sendMessageToSource", 7); }
//Done private Boolean CanPunish(AdKatsRecord record) { DebugWrite("canPunish starting!", 6); //Make sure database connection active if (this.HandlePossibleDisconnect()) { record.record_exception = new AdKatsException("Database not connected."); return false; } try { using (MySqlConnection connection = this.GetDatabaseConnection()) { using (MySqlCommand command = connection.CreateCommand()) { command.CommandText = @" SELECT `record_time` AS `latest_time` FROM `adkats_records_main` WHERE `adkats_records_main`.`command_type` = " + this.GetCommandByKey("player_punish").command_id + @" AND `adkats_records_main`.`target_id` = " + record.target_player.player_id + @" AND DATE_ADD(`record_time`, INTERVAL 20 SECOND) > UTC_TIMESTAMP() ORDER BY `record_time` DESC LIMIT 1"; using (MySqlDataReader reader = command.ExecuteReader()) { if (reader.Read()) { this.DebugWrite("can't upload punish", 6); this.SendMessageToSource(record, record.target_name + " already punished in the last 20 seconds."); return false; } return true; } } } } catch (Exception e) { this.HandleException(new AdKatsException("Error while checking if player can be punished.", e)); //Assume false if any errors return false; } }
public void SendServerRules(AdKatsRecord record) { this.DebugWrite("Entering sendServerRules", 6); try { //Send the server rules this.SendServerRules(record.target_name); //Set the executed bool record.record_action_executed = true; } catch (Exception e) { record.record_exception = new AdKatsException("Error while sending server rules (record).", e); this.HandleException(record.record_exception); this.FinalizeRecord(record); } this.DebugWrite("Exiting sendServerRules", 6); }
private Boolean DamageHackCheck(AdKatsPlayer aPlayer, Boolean debugMode) { Boolean acted = false; try { if (aPlayer == null || aPlayer.stats == null || aPlayer.stats.WeaponStats == null) { return false; } List<String> allowedCategories = null; switch (this._GameVersion) { case GameVersion.BF3: allowedCategories = new List<string>() { "Sub machine guns", "Assault rifles", "Carbines", "Machine guns", "Handheld weapons" }; break; case GameVersion.BF4: allowedCategories = new List<string>() { "PDW", "ASSAULT RIFLE", "CARBINE", "LMG", "SIDEARM" }; break; default: return false; } List<AdKatsWeaponStats> topWeapons = aPlayer.stats.WeaponStats.Values.ToList(); topWeapons.Sort(delegate(AdKatsWeaponStats a1, AdKatsWeaponStats a2) { if (a1.Kills == a2.Kills) { return 0; } return (a1.Kills < a2.Kills) ? (1) : (-1); }); AdKatsWeaponStats actedWeapon = null; Double actedPerc = -1; Int32 index = 0; foreach (AdKatsWeaponStats weaponStat in topWeapons) { //Break after 15th top weapon if (index++ > 15) { break; } //Only count certain weapon categories if (allowedCategories.Contains(weaponStat.Category)) { StatLibraryWeapon weapon = null; if (this._StatLibrary.Weapons.TryGetValue(weaponStat.ID, out weapon)) { //Only handle weapons that do < 50 max dps if (weapon.damage_max < 50) { //Only take weapons with more than 50 kills if (weaponStat.Kills > 50) { //Check for damage hack if (weaponStat.DPS > weapon.damage_max) { //Get the percentage over normal Double percDiff = (weaponStat.DPS - weapon.damage_max) / weaponStat.DPS; if (percDiff > (this._DpsTriggerLevel / 100)) { if (percDiff > actedPerc) { actedPerc = percDiff; actedWeapon = weaponStat; } } } } } } else { this.ConsoleWarn("Could not find " + weaponStat.ID + " in " + this._GameVersion + " library of " + this._StatLibrary.Weapons.Count + " weapons."); } } } if (actedWeapon != null) { acted = true; String formattedName = actedWeapon.ID.Replace("-", "").Replace(" ", "").ToUpper(); this.ConsoleWarn(aPlayer.player_name + " auto-banned for damage mod. [" + formattedName + "-" + (int) actedWeapon.DPS + "-" + (int) actedWeapon.Kills + "-" + (int) actedWeapon.Headshots + "]"); if (!debugMode) { //Create the ban record AdKatsRecord record = new AdKatsRecord { record_source = AdKatsRecord.Sources.InternalAutomated, server_id = this._ServerID, command_type = this._CommandKeyDictionary["player_ban_perm"], command_numeric = 0, target_name = aPlayer.player_name, target_player = aPlayer, source_name = "AutoAdmin", record_message = _HackerCheckerDPSBanMessage + " [" + formattedName + "-" + (int) actedWeapon.DPS + "-" + (int) actedWeapon.Kills + "-" + (int) actedWeapon.Headshots + "]" }; //Process the record this.QueueRecordForProcessing(record); //this.AdminSayMessage(player.player_name + " auto-banned for damage mod. [" + actedWeapon.id + "-" + (int) actedWeapon.dps + "-" + (int) actedWeapon.kills + "-" + (int) actedWeapon.headshots + "]"); } } } catch (Exception e) { this.HandleException(new AdKatsException("Error running DPS hack check", e)); } return acted; }
public void SetPluginVariable(String strVariable, String strValue) { if (strValue == null) { return; } try { //this.ConsoleWrite("'" + strVariable + "' -> '" + strValue + "'"); if (strVariable == "UpdateSettings") { //Do nothing. Settings page will be updated after return. } else if (Regex.Match(strVariable, @"Auto-Enable/Keep-Alive").Success) { Boolean autoEnable = Boolean.Parse(strValue); if (autoEnable != this._UseKeepAlive) { if(autoEnable) this.Enable(); this._UseKeepAlive = autoEnable; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Auto-Enable/Keep-Alive", typeof (Boolean), this._UseKeepAlive)); } } else if (Regex.Match(strVariable, @"Send Query").Success) { this.SendQuery(strValue, true); } else if (Regex.Match(strVariable, @"Send Non-Query").Success) { this.SendNonQuery("Experimental Query", strValue, true); } else if (Regex.Match(strVariable, @"Hacker-Check Player").Success) { if (String.IsNullOrEmpty(strValue) || !this._ThreadsReady) { return; } this.ConsoleWarn("Preparing to hacker check " + strValue); if (String.IsNullOrEmpty(strValue) || strValue.Length < 3) { this.ConsoleError("Player name must be at least 3 characters long."); return; } if (!this.SoldierNameValid(strValue)) { this.ConsoleError("Player name contained invalid characters."); return; } AdKatsPlayer aPlayer = new AdKatsPlayer() { player_name = strValue }; this.FetchPlayerStats(aPlayer); if (aPlayer.stats != null) { this.RunStatSiteHackCheck(aPlayer, true); } else { this.ConsoleError("Stats not found for " + strValue); } } else if (Regex.Match(strVariable, @"Setting Import").Success) { Int32 tmp = -1; if (int.TryParse(strValue, out tmp)) { if (tmp != -1) this.QueueSettingImport(tmp); } else { this.ConsoleError("Invalid Input for Setting Import"); } } else if (Regex.Match(strVariable, @"Using AdKats WebAdmin").Success) { Boolean tmp = false; if (Boolean.TryParse(strValue, out tmp)) { this._UsingAwa = tmp; //Update necessary settings for AWA use if (this._UsingAwa) { this._UseBanEnforcer = true; this._FetchActionsFromDb = true; this._DbCommunicationWaitHandle.Set(); } } else { this.ConsoleError("Invalid Input for Using AdKats WebAdmin"); } } #region debugging else if (Regex.Match(strVariable, @"Command Entry").Success) { if (String.IsNullOrEmpty(strValue)) { return; } //Check if the message is a command if (strValue.StartsWith("@") || strValue.StartsWith("!")) { strValue = strValue.Substring(1); } else if (strValue.StartsWith("/@") || strValue.StartsWith("/!")) { strValue = strValue.Substring(2); } else if (strValue.StartsWith("/")) { strValue = strValue.Substring(1); } else { this.ConsoleError("Invalid command format."); return; } AdKatsRecord record = new AdKatsRecord { record_source = AdKatsRecord.Sources.Settings, source_name = "SettingsAdmin" }; this.CompleteRecordInformation(record, strValue); } else if (Regex.Match(strVariable, @"Debug level").Success) { Int32 tmp = 2; if (int.TryParse(strValue, out tmp)) { if (tmp != this._DebugLevel) { this._DebugLevel = tmp; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Debug level", typeof (int), this._DebugLevel)); } } } else if (Regex.Match(strVariable, @"Debug Soldier Name").Success) { if (this.SoldierNameValid(strValue)) { if (strValue != this._DebugSoldierName) { this._DebugSoldierName = strValue; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Debug Soldier Name", typeof (String), this._DebugSoldierName)); } } } else if (Regex.Match(strVariable, @"Server VOIP Address").Success) { if (strValue != this._ServerVoipAddress) { this._ServerVoipAddress = strValue; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Server VOIP Address", typeof (String), this._ServerVoipAddress)); } } else if (Regex.Match(strVariable, @"Rule Print Delay").Success) { Double delay = Double.Parse(strValue); if (this._ServerRulesDelay != delay) { if (delay <= 0) { this.ConsoleError("Delay cannot be negative."); delay = 1.0; } this._ServerRulesDelay = delay; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Rule Print Delay", typeof (Double), this._ServerRulesDelay)); } } else if (Regex.Match(strVariable, @"Rule Print Interval").Success) { Double interval = Double.Parse(strValue); if (this._ServerRulesInterval != interval) { if (interval <= 0) { this.ConsoleError("Interval cannot be negative."); interval = 5.0; } this._ServerRulesInterval = interval; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Rule Print Interval", typeof (Double), this._ServerRulesInterval)); } } else if (Regex.Match(strVariable, @"Server Rule List").Success) { this._ServerRulesList = CPluginVariable.DecodeStringArray(strValue); //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Server Rule List", typeof (String), CPluginVariable.EncodeStringArray(this._ServerRulesList))); } else if (Regex.Match(strVariable, @"Feed MULTIBalancer Whitelist").Success) { Boolean feedMTB = Boolean.Parse(strValue); if (feedMTB != this._FeedMultiBalancerWhitelist) { this._FeedMultiBalancerWhitelist = feedMTB; this.FetchUserList(); //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Feed MULTIBalancer Whitelist", typeof (Boolean), this._FeedMultiBalancerWhitelist)); } } else if (Regex.Match(strVariable, @"Feed Server Reserved Slots").Success) { Boolean feedSRS = Boolean.Parse(strValue); if (feedSRS != this._FeedServerReservedSlots) { this._FeedServerReservedSlots = feedSRS; this.FetchUserList(); //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Feed Server Reserved Slots", typeof(Boolean), this._FeedServerReservedSlots)); } } else if (Regex.Match(strVariable, @"Feed Server Spectator List").Success) { Boolean feedSSL = Boolean.Parse(strValue); if (feedSSL != this._FeedServerSpectatorList) { if (this._GameVersion != GameVersion.BF4) { this.ConsoleError("This feature can only be enabled on BF4 servers."); return; } this._FeedServerSpectatorList = feedSSL; this.FetchUserList(); //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Feed Server Spectator List", typeof(Boolean), this._FeedServerSpectatorList)); } } else if (Regex.Match(strVariable, @"Feed Stat Logger Settings").Success) { Boolean feedSLS = Boolean.Parse(strValue); if (feedSLS != this._FeedStatLoggerSettings) { this._FeedStatLoggerSettings = feedSLS; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Feed Stat Logger Settings", typeof (Boolean), this._FeedStatLoggerSettings)); } } else if (Regex.Match(strVariable, @"Use Experimental Tools").Success) { Boolean useEXP = Boolean.Parse(strValue); if (useEXP != this._UseExperimentalTools) { this._UseExperimentalTools = useEXP; if (this._UseExperimentalTools) { if (this._ThreadsReady) { this.ConsoleWarn("Using experimental tools. Take caution."); } } else { this.ConsoleWarn("Experimental tools disabled."); this._UseWeaponLimiter = false; this._UseGrenadeCookCatcher = false; this._UseHackerChecker = false; this._UseDpsChecker = false; this._UseHskChecker = false; } //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Use Experimental Tools", typeof (Boolean), this._UseExperimentalTools)); this.QueueSettingForUpload(new CPluginVariable(@"Use NO EXPLOSIVES Limiter", typeof (Boolean), this._UseWeaponLimiter)); } } else if (Regex.Match(strVariable, @"Round Timer: Enable").Success) { Boolean useTimer = Boolean.Parse(strValue); if (useTimer != this._UseRoundTimer) { this._UseRoundTimer = useTimer; if (this._UseRoundTimer) { if (this._ThreadsReady) { this.ConsoleWarn("Internal Round Timer activated, will enable on next round."); } } else { this.ConsoleWarn("Internal Round Timer disabled."); } //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Round Timer: Enable", typeof (Boolean), this._UseRoundTimer)); } } else if (Regex.Match(strVariable, @"Round Timer: Round Duration Minutes").Success) { Double duration = Double.Parse(strValue); if (this._RoundTimeMinutes != duration) { if (duration <= 0) { duration = 30.0; } this._RoundTimeMinutes = duration; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Round Timer: Round Duration Minutes", typeof (Double), this._RoundTimeMinutes)); } } else if (Regex.Match(strVariable, @"Use NO EXPLOSIVES Limiter").Success) { Boolean useLimiter = Boolean.Parse(strValue); if (useLimiter != this._UseWeaponLimiter) { this._UseWeaponLimiter = useLimiter; if (this._UseWeaponLimiter) { if (this._ThreadsReady) { this.ConsoleWarn("Internal NO EXPLOSIVES punish limit activated."); } } else { this.ConsoleWarn("Internal NO EXPLOSIVES punish limit disabled."); } //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Use NO EXPLOSIVES Limiter", typeof (Boolean), this._UseWeaponLimiter)); } } else if (Regex.Match(strVariable, @"NO EXPLOSIVES Weapon String").Success) { if (this._WeaponLimiterString != strValue) { if (!String.IsNullOrEmpty(strValue)) { this._WeaponLimiterString = strValue; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"NO EXPLOSIVES Weapon String", typeof (String), this._WeaponLimiterString)); } else { this.ConsoleError("Weapon String cannot be empty."); } } } else if (Regex.Match(strVariable, @"NO EXPLOSIVES Exception String").Success) { if (this._WeaponLimiterExceptionString != strValue) { if (!String.IsNullOrEmpty(strValue)) { this._WeaponLimiterExceptionString = strValue; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"NO EXPLOSIVES Exception String", typeof (String), this._WeaponLimiterExceptionString)); } else { this.ConsoleError("Weapon exception String cannot be empty."); } } } else if (Regex.Match(strVariable, @"Use Grenade Cook Catcher").Success) { Boolean useCookCatcher = Boolean.Parse(strValue); if (useCookCatcher != this._UseGrenadeCookCatcher) { this._UseGrenadeCookCatcher = useCookCatcher; if (this._UseGrenadeCookCatcher) { if (this._ThreadsReady) { this.ConsoleWarn("Internal Grenade Cook Catcher activated."); } } else { this.ConsoleWarn("Internal Grenade Cook Catcher disabled."); } //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Use Grenade Cook Catcher", typeof (Boolean), this._UseGrenadeCookCatcher)); } } else if (Regex.Match(strVariable, @"HackerChecker: Enable").Success) { Boolean useHackChecker = Boolean.Parse(strValue); if (useHackChecker != this._UseHackerChecker) { this._UseHackerChecker = useHackChecker; if (this._UseHackerChecker) { if (this._ThreadsReady) { this.ConsoleWarn("Internal Hacker Checker activated."); } } else { this.ConsoleWarn("Internal Hacker Checker disabled."); } //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"HackerChecker: Enable", typeof (Boolean), this._UseHackerChecker)); } } else if (Regex.Match(strVariable, @"HackerChecker: Whitelist").Success) { this._HackerCheckerWhitelist = CPluginVariable.DecodeStringArray(strValue); //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"HackerChecker: Whitelist", typeof (String), CPluginVariable.EncodeStringArray(this._HackerCheckerWhitelist))); } else if (Regex.Match(strVariable, @"HackerChecker: DPS Checker: Enable").Success) { Boolean useDamageChecker = Boolean.Parse(strValue); if (useDamageChecker != this._UseDpsChecker) { this._UseDpsChecker = useDamageChecker; if (this._UseDpsChecker) { if (this._ThreadsReady) { this.ConsoleWarn("Internal Damage Mod Checker activated."); } } else { this.ConsoleWarn("Internal Damage Mod Checker disabled."); } //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"HackerChecker: DPS Checker: Enable", typeof (Boolean), this._UseDpsChecker)); } } else if (Regex.Match(strVariable, @"HackerChecker: DPS Checker: Trigger Level").Success) { Double triggerLevel = Double.Parse(strValue); if (this._DpsTriggerLevel != triggerLevel) { if (triggerLevel <= 0) { triggerLevel = 100.0; } this._DpsTriggerLevel = triggerLevel; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"HackerChecker: DPS Checker: Trigger Level", typeof (Double), this._DpsTriggerLevel)); } } else if (Regex.Match(strVariable, @"HackerChecker: DPS Checker: Ban Message").Success) { if (this._HackerCheckerDPSBanMessage != strValue) { this._HackerCheckerDPSBanMessage = strValue; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"HackerChecker: DPS Checker: Ban Message", typeof(String), this._HackerCheckerDPSBanMessage)); } } else if (Regex.Match(strVariable, @"HackerChecker: HSK Checker: Enable").Success) { Boolean useAimbotChecker = Boolean.Parse(strValue); if (useAimbotChecker != this._UseHskChecker) { this._UseHskChecker = useAimbotChecker; if (this._UseHskChecker) { if (this._ThreadsReady) { this.ConsoleWarn("Internal Aimbot Checker activated."); } } else { this.ConsoleWarn("Internal Aimbot Checker disabled."); } //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"HackerChecker: HSK Checker: Enable", typeof (Boolean), this._UseHskChecker)); } } else if (Regex.Match(strVariable, @"HackerChecker: HSK Checker: Trigger Level").Success) { Double triggerLevel = Double.Parse(strValue); if (this._HskTriggerLevel != triggerLevel) { if (triggerLevel <= 0) { triggerLevel = 100.0; } this._HskTriggerLevel = triggerLevel; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"HackerChecker: HSK Checker: Trigger Level", typeof (Double), this._HskTriggerLevel)); } } else if (Regex.Match(strVariable, @"HackerChecker: HSK Checker: Ban Message").Success) { if (this._HackerCheckerHSKBanMessage != strValue) { this._HackerCheckerHSKBanMessage = strValue; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"HackerChecker: HSK Checker: Ban Message", typeof(String), this._HackerCheckerHSKBanMessage)); } } #endregion #region HTTP settings else if (Regex.Match(strVariable, @"External Access Key").Success) { if (strValue != this._ExternalCommandAccessKey) { this._ExternalCommandAccessKey = strValue; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"External Access Key", typeof (String), this._ExternalCommandAccessKey)); } } else if (Regex.Match(strVariable, @"Fetch Actions from Database").Success) { Boolean fetch = Boolean.Parse(strValue); if (fetch != this._FetchActionsFromDb) { this._FetchActionsFromDb = fetch; this._DbCommunicationWaitHandle.Set(); //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Fetch Actions from Database", typeof (Boolean), this._FetchActionsFromDb)); } } #endregion #region ban settings else if (Regex.Match(strVariable, @"Use Additional Ban Message").Success) { Boolean use = Boolean.Parse(strValue); if (this._UseBanAppend != use) { this._UseBanAppend = use; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Use Additional Ban Message", typeof (Boolean), this._UseBanAppend)); } } else if (Regex.Match(strVariable, @"Additional Ban Message").Success) { if (strValue.Length > 30) { strValue = strValue.Substring(0, 30); this.ConsoleError("Ban append cannot be more than 30 characters."); } if (this._BanAppend != strValue) { this._BanAppend = strValue; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Additional Ban Message", typeof (String), this._BanAppend)); } } else if (Regex.Match(strVariable, @"Procon Ban Admin Name").Success) { if (strValue.Length > 16) { strValue = strValue.Substring(0, 16); this.ConsoleError("Procon ban admin id cannot be more than 16 characters."); } if (this._CBanAdminName != strValue) { this._CBanAdminName = strValue; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Procon Ban Admin Name", typeof (String), this._CBanAdminName)); } } else if (Regex.Match(strVariable, @"Use Ban Enforcer").Success) { Boolean use = Boolean.Parse(strValue); if (this._UseBanEnforcer != use) { this._UseBanEnforcer = use; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Use Ban Enforcer", typeof (Boolean), this._UseBanEnforcer)); if (this._UseBanEnforcer) { this._FetchActionsFromDb = true; this._DbCommunicationWaitHandle.Set(); } } } else if (Regex.Match(strVariable, @"Enforce New Bans by NAME").Success) { Boolean enforceName = Boolean.Parse(strValue); if (this._DefaultEnforceName != enforceName) { this._DefaultEnforceName = enforceName; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Enforce New Bans by NAME", typeof (Boolean), this._DefaultEnforceName)); } } else if (Regex.Match(strVariable, @"Enforce New Bans by GUID").Success) { Boolean enforceGUID = Boolean.Parse(strValue); if (this._DefaultEnforceGUID != enforceGUID) { this._DefaultEnforceGUID = enforceGUID; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Enforce New Bans by GUID", typeof (Boolean), this._DefaultEnforceGUID)); } } else if (Regex.Match(strVariable, @"Enforce New Bans by IP").Success) { Boolean enforceIP = Boolean.Parse(strValue); if (this._DefaultEnforceIP != enforceIP) { this._DefaultEnforceIP = enforceIP; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Enforce New Bans by IP", typeof(Boolean), this._DefaultEnforceIP)); } } else if (Regex.Match(strVariable, @"Ban Search").Success) { if (String.IsNullOrEmpty(strValue) || strValue.Length < 3) { this.ConsoleError("Search query must be 3 or more characters."); return; } lock (this._BanEnforcerSearchResults) { this._BanEnforcerSearchResults = new List<AdKatsBan>(); List<AdKatsPlayer> matchingPlayers; if (this.FetchMatchingPlayers(strValue, out matchingPlayers, false)) { foreach (AdKatsPlayer aPlayer in matchingPlayers) { AdKatsBan aBan = this.FetchPlayerBan(aPlayer); if (aBan != null) { this._BanEnforcerSearchResults.Add(aBan); } } } if (this._BanEnforcerSearchResults.Count == 0) { this.ConsoleError("No players matching '" + strValue + "' have active bans."); } } } #endregion #region In-Game Command Settings else if (Regex.Match(strVariable, @"Minimum Required Reason Length").Success) { Int32 required = Int32.Parse(strValue); if (this._RequiredReasonLength != required) { this._RequiredReasonLength = required; if (this._RequiredReasonLength < 1) { this._RequiredReasonLength = 1; } //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Minimum Required Reason Length", typeof (Int32), this._RequiredReasonLength)); } } else if (Regex.Match(strVariable, @"Allow Commands from Admin Say").Success) { Boolean allowSayCommands = Boolean.Parse(strValue); if (this._AllowAdminSayCommands != allowSayCommands) { this._AllowAdminSayCommands = allowSayCommands; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Allow Commands from Admin Say", typeof(Boolean), this._AllowAdminSayCommands)); } } else if (strVariable.StartsWith("USR")) { //USR1 | ColColonCleaner | User Email //USR1 | ColColonCleaner | User Phone //USR1 | ColColonCleaner | User Role //USR1 | ColColonCleaner | Delete User? //USR1 | ColColonCleaner | Add Soldier? //USR1 | ColColonCleaner | Soldiers | 293492 | ColColonCleaner | Delete Soldier? String[] commandSplit = CPluginVariable.DecodeStringArray(strVariable); String user_id_str = commandSplit[0].TrimStart("USR".ToCharArray()).Trim(); Int32 user_id = Int32.Parse(user_id_str); String section = commandSplit[2].Trim(); AdKatsUser aUser = null; if (this._UserCache.TryGetValue(user_id, out aUser)) { switch (section) { case "User Email": if (String.IsNullOrEmpty(strValue) || Regex.IsMatch(strValue, @"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$")) { aUser.user_email = strValue; } else { this.ConsoleError(strValue + " is an invalid email address."); return; } //Reupload the user this.QueueUserForUpload(aUser); break; case "User Phone": aUser.user_phone = strValue; //Reupload the user this.QueueUserForUpload(aUser); break; case "User Role": AdKatsRole aRole = null; if (this._RoleNameDictionary.TryGetValue(strValue, out aRole)) { aUser.user_role = aRole; } else { this.ConsoleError("Role " + strValue + " not found."); return; } //Reupload the user this.QueueUserForUpload(aUser); break; case "Delete User?": if (strValue.ToLower() == "delete") { this.QueueUserForRemoval(aUser); } break; case "Add Soldier?": this.TryAddUserSoldier(aUser, strValue); //Reupload the user this.QueueUserForUpload(aUser); break; case "Soldiers": if (strVariable.Contains("Delete Soldier?") && strValue.ToLower() == "delete") { String player_id_str = commandSplit[3].Trim(); Int64 player_id = Int64.Parse(player_id_str); aUser.soldierDictionary.Remove(player_id); //Reupload the user this.QueueUserForUpload(aUser); } break; default: this.ConsoleError("Section " + section + " not found."); break; } } } else if (strVariable.StartsWith("CDE")) { //Trim off all but the command ID and section //5. Command List|CDE1 | Kill Player | Active //5. Command List|CDE1 | Kill Player | Logging //5. Command List|CDE1 | Kill Player | Text String[] commandSplit = CPluginVariable.DecodeStringArray(strVariable); String command_id_str = commandSplit[0].TrimStart("CDE".ToCharArray()).Trim(); Int32 command_id = Int32.Parse(command_id_str); String section = commandSplit[2].Trim(); AdKatsCommand command = null; if (this._CommandIDDictionary.TryGetValue(command_id, out command)) { if (section == "Active") { //Check for valid value if (strValue == "Active") { command.command_active = AdKatsCommand.CommandActive.Active; } else if (strValue == "Disabled") { command.command_active = AdKatsCommand.CommandActive.Disabled; } else if (strValue == "Invisible") { command.command_active = AdKatsCommand.CommandActive.Invisible; } else { this.ConsoleError("Activity setting " + strValue + " was invalid."); return; } } else if (section == "Logging") { //Check for valid value switch (strValue) { case "Log": command.command_logging = AdKatsCommand.CommandLogging.Log; break; case "Mandatory": command.command_logging = AdKatsCommand.CommandLogging.Mandatory; break; case "Ignore": command.command_logging = AdKatsCommand.CommandLogging.Ignore; break; case "Unable": command.command_logging = AdKatsCommand.CommandLogging.Unable; break; default: this.ConsoleError("Logging setting " + strValue + " was invalid."); return; } } else if (section == "Text") { if (String.IsNullOrEmpty(strValue)) { this.ConsoleError("Command text cannot be blank."); return; } //Make sure command text only contains alphanumeric chars, underscores, and dashes Regex rgx = new Regex("[^a-zA-Z0-9_-]"); strValue = rgx.Replace(strValue, ""); //Check to make sure text is not a duplicate foreach (AdKatsCommand testCommand in this._CommandNameDictionary.Values) { if (testCommand.command_text == strValue) { this.ConsoleError("Command text cannot be the same as another command."); return; } } //Assign the command text command.command_text = strValue; } else { this.ConsoleError("Section " + section + " not understood."); return; } //Upload the command changes this.QueueCommandForUpload(command); } else { this.ConsoleError("Command " + command_id + " not found in command dictionary."); } } else if (strVariable.StartsWith("RLE")) { //Trim off all but the command ID and section //RLE1 | Default Guest | CDE3 | Kill Player String[] commandSplit = CPluginVariable.DecodeStringArray(strVariable); String roleIDStr = commandSplit[0].TrimStart("RLE".ToCharArray()).Trim(); Int32 roleID = Int32.Parse(roleIDStr); //If second section is a command prefix, this is the allow/deny clause if (commandSplit[2].Trim().StartsWith("CDE")) { String commandIDStr = commandSplit[2].Trim().TrimStart("CDE".ToCharArray()); Int32 commandID = Int32.Parse(commandIDStr); //Fetch needed role AdKatsRole aRole = null; if (this._RoleIDDictionary.TryGetValue(roleID, out aRole)) { //Fetch needed command AdKatsCommand aCommand = null; if (this._CommandIDDictionary.TryGetValue(commandID, out aCommand)) { switch (strValue.ToLower()) { case "allow": lock (aRole.allowedCommands) { if (!aRole.allowedCommands.ContainsKey(aCommand.command_key)) { aRole.allowedCommands.Add(aCommand.command_key, aCommand); } } this.QueueRoleForUpload(aRole); break; case "deny": lock (aRole.allowedCommands) { aRole.allowedCommands.Remove(aCommand.command_key); } this.QueueRoleForUpload(aRole); break; default: this.ConsoleError("Unknown setting when assigning command allowance."); return; } } else { this.ConsoleError("Command " + commandID + " not found in command dictionary."); } } else { this.ConsoleError("Role " + roleID + " not found in role dictionary."); } } else if (commandSplit[2].Contains("Delete Role?") && strValue.ToLower() == "delete") { //Fetch needed role AdKatsRole aRole = null; if (this._RoleIDDictionary.TryGetValue(roleID, out aRole)) { this.QueueRoleForRemoval(aRole); } else { this.ConsoleError("Unable to fetch role for deletion."); } } } else if (strVariable.StartsWith("BAN")) { //Trim off all but the command ID and section //BAN1 | ColColonCleaner | Some Reason String[] commandSplit = CPluginVariable.DecodeStringArray(strVariable); String banIDStr = commandSplit[0].TrimStart("BAN".ToCharArray()).Trim(); Int32 banID = Int32.Parse(banIDStr); AdKatsBan aBan = null; foreach (AdKatsBan innerBan in this._BanEnforcerSearchResults) { if (innerBan.ban_id == banID) { aBan = innerBan; break; } } if (aBan != null) { switch (strValue) { case "Active": aBan.ban_status = strValue; break; case "Disabled": aBan.ban_status = strValue; break; default: this.ConsoleError("Unknown setting when assigning ban status."); return; } this.UpdateBanStatus(aBan); this.ConsoleSuccess("Ban " + aBan.ban_id + " is now " + strValue); } else { this.ConsoleError("Unable to update ban. This should not happen."); } } #endregion #region punishment settings else if (Regex.Match(strVariable, @"Punishment Hierarchy").Success) { this._PunishmentHierarchy = CPluginVariable.DecodeStringArray(strValue); //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Punishment Hierarchy", typeof (String), CPluginVariable.EncodeStringArray(this._PunishmentHierarchy))); } else if (Regex.Match(strVariable, @"Combine Server Punishments").Success) { Boolean combine = Boolean.Parse(strValue); if (this._CombineServerPunishments != combine) { this._CombineServerPunishments = combine; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Combine Server Punishments", typeof (Boolean), this._CombineServerPunishments)); } } else if (Regex.Match(strVariable, @"Only Kill Players when Server in low population").Success) { Boolean onlyKill = Boolean.Parse(strValue); if (onlyKill != this._OnlyKillOnLowPop) { this._OnlyKillOnLowPop = onlyKill; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Only Kill Players when Server in low population", typeof (Boolean), this._OnlyKillOnLowPop)); } } else if (Regex.Match(strVariable, @"Low Population Value").Success) { Int32 lowPop = Int32.Parse(strValue); if (lowPop != this._LowPopPlayerCount) { this._LowPopPlayerCount = lowPop; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Low Population Value", typeof (Int32), this._LowPopPlayerCount)); } } else if (Regex.Match(strVariable, @"Use IRO Punishment").Success) { Boolean iro = Boolean.Parse(strValue); if (iro != this._IROActive) { this._IROActive = iro; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Use IRO Punishment", typeof (Boolean), this._IROActive)); } } else if (Regex.Match(strVariable, @"IRO Punishment Overrides Low Pop").Success) { Boolean overrideIRO = Boolean.Parse(strValue); if (overrideIRO != this._IROOverridesLowPop) { this._IROOverridesLowPop = overrideIRO; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"IRO Punishment Overrides Low Pop", typeof (Boolean), this._IROOverridesLowPop)); } } else if (Regex.Match(strVariable, @"IRO Timeout Minutes").Success) { Int32 timeout = Int32.Parse(strValue); if (timeout != this._IROTimeout) { this._IROTimeout = timeout; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"IRO Timeout (Minutes)", typeof (Int32), this._IROTimeout)); } } #endregion #region sql settings else if (Regex.Match(strVariable, @"MySQL Hostname").Success) { _MySqlHostname = strValue; this._DbSettingsChanged = true; this._DbCommunicationWaitHandle.Set(); } else if (Regex.Match(strVariable, @"MySQL Port").Success) { Int32 tmp = 3306; int.TryParse(strValue, out tmp); if (tmp > 0 && tmp < 65536) { _MySqlPort = strValue; this._DbSettingsChanged = true; this._DbCommunicationWaitHandle.Set(); } else { this.ConsoleError("Invalid value for MySQL Port: '" + strValue + "'. Must be number between 1 and 65535!"); } } else if (Regex.Match(strVariable, @"MySQL Database").Success) { this._MySqlDatabaseName = strValue; this._DbSettingsChanged = true; this._DbCommunicationWaitHandle.Set(); } else if (Regex.Match(strVariable, @"MySQL Username").Success) { _MySqlUsername = strValue; this._DbSettingsChanged = true; this._DbCommunicationWaitHandle.Set(); } else if (Regex.Match(strVariable, @"MySQL Password").Success) { _MySqlPassword = strValue; this._DbSettingsChanged = true; this._DbCommunicationWaitHandle.Set(); } #endregion #region email settings else if (Regex.Match(strVariable, @"Send Emails").Success) { //Disabled this._UseEmail = Boolean.Parse(strValue); //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable("Send Emails", typeof (Boolean), this._UseEmail)); } else if (Regex.Match(strVariable, @"Use SSL?").Success) { this._EmailHandler.UseSSL = Boolean.Parse(strValue); //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable("Use SSL?", typeof(Boolean), this._EmailHandler.UseSSL)); } else if (Regex.Match(strVariable, @"SMTP-Server address").Success) { if (!String.IsNullOrEmpty(strValue)) { this._EmailHandler.SMTPServer = strValue; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable("SMTP-Server address", typeof (String), this._EmailHandler.SMTPServer)); } } else if (Regex.Match(strVariable, @"SMTP-Server port").Success) { Int32 iPort = Int32.Parse(strValue); if (iPort > 0) { this._EmailHandler.SMTPPort = iPort; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable("SMTP-Server port", typeof(Int32), this._EmailHandler.SMTPPort)); } } else if (Regex.Match(strVariable, @"Sender address").Success) { if (string.IsNullOrEmpty(strValue)) { this._EmailHandler.SenderEmail = "SENDER_CANNOT_BE_EMPTY"; this.ConsoleError("No sender for email was given! Canceling Operation."); } else { this._EmailHandler.SenderEmail = strValue; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable("Sender address", typeof(String), this._EmailHandler.SenderEmail)); } } else if (Regex.Match(strVariable, @"SMTP-Server username").Success) { if (string.IsNullOrEmpty(strValue)) { this._EmailHandler.SMTPUser = "******"; this.ConsoleError("No username for SMTP was given! Canceling Operation."); } else { this._EmailHandler.SMTPUser = strValue; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable("SMTP-Server username", typeof(String), this._EmailHandler.SMTPUser)); } } else if (Regex.Match(strVariable, @"SMTP-Server password").Success) { if (string.IsNullOrEmpty(strValue)) { this._EmailHandler.SMTPPassword = "******"; this.ConsoleError("No password for SMTP was given! Canceling Operation."); } else { this._EmailHandler.SMTPPassword = strValue; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable("SMTP-Server password", typeof(String), this._EmailHandler.SMTPPassword)); } } else if (Regex.Match(strVariable, @"Custom HTML Addition").Success) { this._EmailHandler.CustomHTMLAddition = strValue; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable("Custom HTML Addition", typeof(String), this._EmailHandler.CustomHTMLAddition)); } else if (Regex.Match(strVariable, @"Extra Recipient Email Addresses").Success) { this._EmailHandler.RecipientEmails = CPluginVariable.DecodeStringArray(strValue).ToList(); //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Extra Recipient Email Addresses", typeof (String), strValue)); } #endregion #region mute settings else if (Regex.Match(strVariable, @"On-Player-Muted Message").Success) { if (this._MutedPlayerMuteMessage != strValue) { this._MutedPlayerMuteMessage = strValue; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"On-Player-Muted Message", typeof (String), this._MutedPlayerMuteMessage)); } } else if (Regex.Match(strVariable, @"On-Player-Killed Message").Success) { if (this._MutedPlayerKillMessage != strValue) { this._MutedPlayerKillMessage = strValue; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"On-Player-Killed Message", typeof (String), this._MutedPlayerKillMessage)); } } else if (Regex.Match(strVariable, @"On-Player-Kicked Message").Success) { if (this._MutedPlayerKickMessage != strValue) { this._MutedPlayerKickMessage = strValue; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"On-Player-Kicked Message", typeof (String), this._MutedPlayerKickMessage)); } } if (Regex.Match(strVariable, @"# Chances to give player before kicking").Success) { Int32 tmp = 5; int.TryParse(strValue, out tmp); if (this._MutedPlayerChances != tmp) { this._MutedPlayerChances = tmp; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"# Chances to give player before kicking", typeof (Int32), this._MutedPlayerChances)); } } #endregion #region TeamSwap settings else if (Regex.Match(strVariable, @"Auto-Whitelist Count").Success) { Int32 tmp = 1; int.TryParse(strValue, out tmp); if (tmp != this._PlayersToAutoWhitelist) { if (tmp < 0) tmp = 0; this._PlayersToAutoWhitelist = tmp; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Auto-Whitelist Count", typeof (Int32), this._PlayersToAutoWhitelist)); } } else if (Regex.Match(strVariable, @"Ticket Window High").Success) { Int32 tmp = 2; int.TryParse(strValue, out tmp); if (tmp != this._TeamSwapTicketWindowHigh) { this._TeamSwapTicketWindowHigh = tmp; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Ticket Window High", typeof (Int32), this._TeamSwapTicketWindowHigh)); } } else if (Regex.Match(strVariable, @"Ticket Window Low").Success) { Int32 tmp = 2; int.TryParse(strValue, out tmp); if (tmp != this._TeamSwapTicketWindowLow) { this._TeamSwapTicketWindowLow = tmp; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Ticket Window Low", typeof (Int32), this._TeamSwapTicketWindowLow)); } } #endregion #region Admin Assistants else if (Regex.Match(strVariable, @"Enable Admin Assistant Perk").Success) { Boolean enableAA = Boolean.Parse(strValue); if (this._EnableAdminAssistantPerk != enableAA) { this._EnableAdminAssistantPerk = enableAA; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Enable Admin Assistant Perk", typeof (Boolean), this._EnableAdminAssistantPerk)); } } else if (Regex.Match(strVariable, @"Minimum Confirmed Reports Per Month").Success) { Int32 monthlyReports = Int32.Parse(strValue); if (this._MinimumRequiredMonthlyReports != monthlyReports) { this._MinimumRequiredMonthlyReports = monthlyReports; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Minimum Confirmed Reports Per Month", typeof (Int32), this._MinimumRequiredMonthlyReports)); } } #endregion #region Messaging Settings else if (Regex.Match(strVariable, @"Yell display time seconds").Success) { Int32 yellTime = Int32.Parse(strValue); if (this._YellDuration != yellTime) { this._YellDuration = yellTime; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Yell display time seconds", typeof (Int32), this._YellDuration)); } } else if (Regex.Match(strVariable, @"Pre-Message List").Success) { this._PreMessageList = new List<String>(CPluginVariable.DecodeStringArray(strValue)); //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Pre-Message List", typeof (String), CPluginVariable.EncodeStringArray(this._PreMessageList.ToArray()))); } else if (Regex.Match(strVariable, @"Require Use of Pre-Messages").Success) { Boolean require = Boolean.Parse(strValue); if (require != this._RequirePreMessageUse) { this._RequirePreMessageUse = require; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Require Use of Pre-Messages", typeof (Boolean), this._RequirePreMessageUse)); } } else if (Regex.Match(strVariable, @"Display Admin Name in Kick and Ban Announcement").Success) { Boolean display = Boolean.Parse(strValue); if (display != this._ShowAdminNameInSay) { this._ShowAdminNameInSay = display; //Once setting has been changed, upload the change to database this.QueueSettingForUpload(new CPluginVariable(@"Display Admin Name in Kick and Ban Announcement", typeof (Boolean), this._ShowAdminNameInSay)); } } #endregion #region access settings else if (Regex.Match(strVariable, @"Add User").Success) { if (this.SoldierNameValid(strValue)) { //Create the access objectdd AdKatsUser user = new AdKatsUser { user_name = strValue }; Boolean valid = true; lock (this._UserCache) { foreach (AdKatsUser aUser in this._UserCache.Values) { if (user.user_name == aUser.user_name) { valid = false; } } } if (!valid) { this.ConsoleError("Unable to add " + user.user_name + ", a user with that user id already exists."); return; } //Queue it for processing this.QueueUserForUpload(user); } else { this.ConsoleError("User id had invalid formatting, please try again."); } } else if (Regex.Match(strVariable, @"Add Role").Success) { if (!String.IsNullOrEmpty(strValue)) { String roleName = new Regex("[^a-zA-Z0-9 _-]").Replace(strValue, ""); String roleKey = roleName.Replace(' ', '_'); if (!String.IsNullOrEmpty(roleName) && !String.IsNullOrEmpty(roleKey)) { AdKatsRole aRole = new AdKatsRole { role_key = roleKey, role_name = roleName }; //By default we should include all commands as allowed lock (this._CommandNameDictionary) { foreach (AdKatsCommand aCommand in this._CommandNameDictionary.Values) { aRole.allowedCommands.Add(aCommand.command_key, aCommand); } } //Queue it for upload this.QueueRoleForUpload(aRole); } else { this.ConsoleError("Role id had invalid characters, please try again."); } } } #endregion } catch (Exception e) { this.HandleException(new AdKatsException("Error occured while updating AdKats settings.", e)); } }
public void CallAdminOnTarget(AdKatsRecord record) { this.DebugWrite("Entering callAdminOnTarget", 6); try { Random random = new Random(); Int32 reportID; do { reportID = random.Next(100, 999); } while (_RoundReports.ContainsKey(reportID + "")); this._RoundReports.Add(reportID + "", record); this.SendMessageToSource(record, "ADMIN CALL [" + reportID + "] sent on " + record.target_name + " for " + record.record_message); record.record_action_executed = true; if (!this.RunAutoReportAction(reportID + "")) { String adminAssistantIdentifier = ""; if (record.source_player != null) { adminAssistantIdentifier = record.source_player.player_aa ? ("[AA]") : (""); } //Send to all online players with access to player interaction commands lock (this._PlayersMutex) { foreach (AdKatsPlayer player in this._PlayerDictionary.Values.Where(player => this.RoleIsInteractionAble(player.player_role))) { //If any allowed command is a player interaction command, send the report this.PlayerSayMessage(player.player_name, "ADMIN CALL " + adminAssistantIdentifier + "[" + reportID + "]: " + record.source_name + " called admin on " + record.target_name + " for " + record.record_message); } } if (this._UseEmail) { this._EmailHandler.SendReport(record); } } } catch (Exception e) { record.record_exception = new AdKatsException("Error while taking action for CallAdmin record.", e); this.HandleException(record.record_exception); this.FinalizeRecord(record); } this.DebugWrite("Exiting callAdminOnTarget", 6); }
public void AdminYell(AdKatsRecord record) { this.DebugWrite("Entering adminYell", 6); try { this.AdminYellMessage(record.record_message); this.SendMessageToSource(record, "Server has been told '" + record.record_message + "' by YELL"); record.record_action_executed = true; } catch (Exception e) { record.record_exception = new AdKatsException("Error while taking action for AdminYell record.", e); this.HandleException(record.record_exception); this.FinalizeRecord(record); } this.DebugWrite("Exiting adminYell", 6); }
//Before calling this, the record is initialized, and command_source/source_name are filled public void CompleteRecordInformation(AdKatsRecord record, String message) { try { //Initial split of command by whitespace String[] splitMessage = message.Split(' '); if (splitMessage.Length < 1) { this.DebugWrite("Completely blank command entered", 5); this.SendMessageToSource(record, "You entered a completely blank command."); this.FinalizeRecord(record); return; } String commandString = splitMessage[0].ToLower(); DebugWrite("Raw Command: " + commandString, 6); String remainingMessage = message.TrimStart(splitMessage[0].ToCharArray()).Trim(); //GATE 1: Add general data record.server_id = this._ServerID; record.record_time = DateTime.UtcNow; //GATE 2: Add Command AdKatsCommand commandType = null; if (this._CommandTextDictionary.TryGetValue(commandString, out commandType)) { record.command_type = commandType; record.command_action = commandType; this.DebugWrite("Command parsed. Command is " + commandType.command_key + ".", 5); } else { //If command not parsable, return without creating DebugWrite("Command not parsable", 6); if (record.record_source == AdKatsRecord.Sources.ExternalPlugin) { this.SendMessageToSource(record, "Command not parsable."); this.FinalizeRecord(record); } return; } //GATE 3: Check Access Rights //Check for server command case if (record.record_source == AdKatsRecord.Sources.ServerCommand && !_AllowAdminSayCommands) { this.SendMessageToSource(record, "Access to commands using that method has been disabled in AdKats settings."); this.FinalizeRecord(record); return; } //Check if player has the right to perform what he's asking, only perform for InGame actions if (record.record_source == AdKatsRecord.Sources.InGame) { //Attempt to fetch the source player if (!this._PlayerDictionary.TryGetValue(record.source_name, out record.source_player)) { this.ConsoleError("Source player not found in server for in-game command, unable to complete command."); this.FinalizeRecord(record); return; } if (!this.HasAccess(record.source_player, record.command_type)) { DebugWrite("No rights to call command", 6); //Only tell the user they dont have access if the command is active if (record.command_type.command_active != AdKatsCommand.CommandActive.Disabled) { this.SendMessageToSource(record, "Your user role " + record.source_player.player_role.role_name + " does not have access to " + record.command_type.command_name + "."); } this.FinalizeRecord(record); return; } } //GATE 4: Add specific data based on command type. switch (record.command_type.command_key) { #region MovePlayer case "player_move": { //Remove previous commands awaiting confirmation this.CancelSourcePendingAction(record); if (this._ServerType == "OFFICIAL") { this.SendMessageToSource(record, record.command_type + " cannot be performed on official servers."); this.FinalizeRecord(record); return; } //Parse parameters using max param count String[] parameters = this.ParseParameters(remainingMessage, 1); switch (parameters.Length) { case 0: if (record.record_source != AdKatsRecord.Sources.InGame) { this.SendMessageToSource(record, "You can't use a self-inflicting command from outside the game."); break; } record.record_message = "Self-Inflicted"; record.target_name = record.source_name; this.CompleteTargetInformation(record, true); break; case 1: record.record_message = "MovePlayer"; record.target_name = parameters[0]; //Handle based on report ID if possible if (!this.HandleRoundReport(record)) { this.CompleteTargetInformation(record, false); } break; default: this.SendMessageToSource(record, "Invalid parameters, unable to submit."); return; } } break; #endregion #region ForceMovePlayer case "player_fmove": { //Remove previous commands awaiting confirmation this.CancelSourcePendingAction(record); if (this._ServerType == "OFFICIAL") { this.SendMessageToSource(record, record.command_type + " cannot be performed on official servers."); this.FinalizeRecord(record); return; } //Parse parameters using max param count String[] parameters = this.ParseParameters(remainingMessage, 1); switch (parameters.Length) { case 0: if (record.record_source != AdKatsRecord.Sources.InGame) { this.SendMessageToSource(record, "You can't use a self-inflicting command from outside the game."); this.FinalizeRecord(record); return; } record.record_message = "Self-Inflicted"; record.target_name = record.source_name; this.CompleteTargetInformation(record, true); break; case 1: record.record_message = "ForceMovePlayer"; record.target_name = parameters[0]; //Handle based on report ID if possible if (!this.HandleRoundReport(record)) { this.CompleteTargetInformation(record, false); } break; default: this.SendMessageToSource(record, "Invalid parameters, unable to submit."); return; } } break; #endregion #region Teamswap case "self_teamswap": { //Remove previous commands awaiting confirmation this.CancelSourcePendingAction(record); if (this._ServerType == "OFFICIAL") { this.SendMessageToSource(record, record.command_type + " cannot be performed on official servers."); this.FinalizeRecord(record); return; } //May only call this command from in-game if (record.record_source != AdKatsRecord.Sources.InGame) { this.SendMessageToSource(record, "You can't use a self-inflicting command from outside the game."); this.FinalizeRecord(record); return; } record.record_message = "TeamSwap"; record.target_name = record.source_name; this.CompleteTargetInformation(record, false); } break; #endregion #region KillSelf case "self_kill": { //Remove previous commands awaiting confirmation this.CancelSourcePendingAction(record); if (this._ServerType == "OFFICIAL") { this.SendMessageToSource(record, record.command_type + " cannot be performed on official servers."); this.FinalizeRecord(record); return; } //May only call this command from in-game if (record.record_source != AdKatsRecord.Sources.InGame) { this.SendMessageToSource(record, "You can't use a self-inflicting command from outside the game."); this.FinalizeRecord(record); return; } record.record_message = "Self-Inflicted"; record.target_name = record.source_name; this.CompleteTargetInformation(record, false); } break; #endregion #region KillPlayer case "player_kill": { //Remove previous commands awaiting confirmation this.CancelSourcePendingAction(record); if (this._ServerType == "OFFICIAL") { this.SendMessageToSource(record, record.command_type + " cannot be performed on official servers."); this.FinalizeRecord(record); return; } //Parse parameters using max param count String[] parameters = this.ParseParameters(remainingMessage, 2); switch (parameters.Length) { case 0: if (record.record_source != AdKatsRecord.Sources.InGame) { this.SendMessageToSource(record, "You can't use a self-inflicting command from outside the game."); this.FinalizeRecord(record); return; } record.record_message = "Self-Inflicted"; record.target_name = record.source_name; this.CompleteTargetInformation(record, false); break; case 1: record.target_name = parameters[0]; //Handle based on report ID as only option if (!this.HandleRoundReport(record)) { this.SendMessageToSource(record, "No reason given, unable to submit."); } this.FinalizeRecord(record); return; case 2: record.target_name = parameters[0]; //attempt to handle via pre-message ID record.record_message = this.GetPreMessage(parameters[1], this._RequirePreMessageUse); if (record.record_message == null) { this.SendMessageToSource(record, "Invalid PreMessage ID, valid PreMessage IDs are 1-" + this._PreMessageList.Count); this.FinalizeRecord(record); return; } //Handle based on report ID if possible if (!this.HandleRoundReport(record)) { if (record.record_message.Length >= this._RequiredReasonLength) { this.CompleteTargetInformation(record, false); } else { this.SendMessageToSource(record, "Reason too short, unable to submit."); this.FinalizeRecord(record); return; } } break; default: this.SendMessageToSource(record, "Invalid parameters, unable to submit."); this.FinalizeRecord(record); return; } } break; #endregion #region KickPlayer case "player_kick": { //Remove previous commands awaiting confirmation this.CancelSourcePendingAction(record); if (this._ServerType == "OFFICIAL") { this.SendMessageToSource(record, record.command_type + " cannot be performed on official servers."); this.FinalizeRecord(record); return; } //Parse parameters using max param count String[] parameters = this.ParseParameters(remainingMessage, 2); switch (parameters.Length) { case 0: if (record.record_source != AdKatsRecord.Sources.InGame) { this.SendMessageToSource(record, "You can't use a self-inflicting command from outside the game."); this.FinalizeRecord(record); return; } record.record_message = "Self-Inflicted"; record.target_name = record.source_name; this.CompleteTargetInformation(record, true); break; case 1: record.target_name = parameters[0]; //Handle based on report ID as only option if (!this.HandleRoundReport(record)) { this.SendMessageToSource(record, "No reason given, unable to submit."); this.FinalizeRecord(record); return; } break; case 2: record.target_name = parameters[0]; //attempt to handle via pre-message ID record.record_message = this.GetPreMessage(parameters[1], this._RequirePreMessageUse); if (record.record_message == null) { this.SendMessageToSource(record, "Invalid PreMessage ID, valid PreMessage IDs are 1-" + this._PreMessageList.Count); this.FinalizeRecord(record); return; } //Handle based on report ID if possible if (!this.HandleRoundReport(record)) { if (record.record_message.Length >= this._RequiredReasonLength) { this.CompleteTargetInformation(record, false); } else { this.SendMessageToSource(record, "Reason too short, unable to submit."); this.FinalizeRecord(record); return; } } break; default: this.SendMessageToSource(record, "Invalid parameters, unable to submit."); this.FinalizeRecord(record); return; } } break; #endregion #region TempBanPlayer case "player_ban_temp": { //Remove previous commands awaiting confirmation this.CancelSourcePendingAction(record); if (this._ServerType == "OFFICIAL") { this.SendMessageToSource(record, record.command_type + " cannot be performed on official servers."); this.FinalizeRecord(record); return; } //Parse parameters using max param count String[] parameters = this.ParseParameters(remainingMessage, 3); //Default is minutes Double recordDuration = 0.0; Double durationMultiplier = 1.0; if (parameters.Length > 0) { String stringDuration = parameters[0].ToLower(); DebugWrite("Raw Duration: " + stringDuration, 6); if (stringDuration.EndsWith("s")) { stringDuration = stringDuration.TrimEnd('s'); durationMultiplier = (1.0 / 60.0); } else if (stringDuration.EndsWith("m")) { stringDuration = stringDuration.TrimEnd('m'); durationMultiplier = 1.0; } else if (stringDuration.EndsWith("h")) { stringDuration = stringDuration.TrimEnd('h'); durationMultiplier = 60.0; } else if (stringDuration.EndsWith("d")) { stringDuration = stringDuration.TrimEnd('d'); durationMultiplier = 1440.0; } else if (stringDuration.EndsWith("w")) { stringDuration = stringDuration.TrimEnd('w'); durationMultiplier = 10080.0; } if (!Double.TryParse(stringDuration, out recordDuration)) { this.SendMessageToSource(record, "Invalid time given, unable to submit."); return; } record.command_numeric = (int) (recordDuration * durationMultiplier); } switch (parameters.Length) { case 0: this.SendMessageToSource(record, "No parameters given, unable to submit."); this.FinalizeRecord(record); return; case 1: if (record.record_source != AdKatsRecord.Sources.InGame) { this.SendMessageToSource(record, "You can't use a self-inflicting command from outside the game."); this.FinalizeRecord(record); return; } record.command_numeric = (int) (recordDuration * durationMultiplier); //Target is source record.record_message = "Self-Inflicted"; record.target_name = record.source_name; this.CompleteTargetInformation(record, true); break; case 2: record.command_numeric = (int) (recordDuration * durationMultiplier); record.target_name = parameters[1]; DebugWrite("target: " + record.target_name, 6); //Handle based on report ID as only option if (!this.HandleRoundReport(record)) { this.SendMessageToSource(record, "No reason given, unable to submit."); this.FinalizeRecord(record); return; } break; case 3: record.command_numeric = (int) (recordDuration * durationMultiplier); record.target_name = parameters[1]; DebugWrite("target: " + record.target_name, 6); //attempt to handle via pre-message ID record.record_message = this.GetPreMessage(parameters[2], this._RequirePreMessageUse); if (record.record_message == null) { this.SendMessageToSource(record, "Invalid PreMessage ID, valid PreMessage IDs are 1-" + this._PreMessageList.Count); this.FinalizeRecord(record); return; } DebugWrite("reason: " + record.record_message, 6); //Handle based on report ID if possible if (!this.HandleRoundReport(record)) { if (record.record_message.Length >= this._RequiredReasonLength) { this.CompleteTargetInformation(record, false); } else { this.SendMessageToSource(record, "Reason too short, unable to submit."); this.FinalizeRecord(record); return; } } break; default: this.SendMessageToSource(record, "Invalid parameters, unable to submit."); this.FinalizeRecord(record); return; } } break; #endregion #region PermabanPlayer case "player_ban_perm": { //Remove previous commands awaiting confirmation this.CancelSourcePendingAction(record); if (this._ServerType == "OFFICIAL") { this.SendMessageToSource(record, record.command_type + " cannot be performed on official servers."); this.FinalizeRecord(record); return; } //Parse parameters using max param count String[] parameters = this.ParseParameters(remainingMessage, 2); switch (parameters.Length) { case 0: if (record.record_source != AdKatsRecord.Sources.InGame) { this.SendMessageToSource(record, "You can't use a self-inflicting command from outside the game."); this.FinalizeRecord(record); return; } record.record_message = "Self-Inflicted"; record.target_name = record.source_name; this.CompleteTargetInformation(record, true); break; case 1: record.target_name = parameters[0]; //Handle based on report ID as only option if (!this.HandleRoundReport(record)) { this.SendMessageToSource(record, "No reason given, unable to submit."); this.FinalizeRecord(record); return; } break; case 2: record.target_name = parameters[0]; //attempt to handle via pre-message ID record.record_message = this.GetPreMessage(parameters[1], this._RequirePreMessageUse); if (record.record_message == null) { this.SendMessageToSource(record, "Invalid PreMessage ID, valid PreMessage IDs are 1-" + this._PreMessageList.Count); this.FinalizeRecord(record); return; } //Handle based on report ID if possible if (!this.HandleRoundReport(record)) { if (record.record_message.Length >= this._RequiredReasonLength) { this.CompleteTargetInformation(record, false); } else { this.SendMessageToSource(record, "Reason too short, unable to submit."); this.FinalizeRecord(record); return; } } break; default: this.SendMessageToSource(record, "Invalid parameters, unable to submit."); this.FinalizeRecord(record); return; } } break; #endregion #region PermabanPlayer case "player_unban": { //Remove previous commands awaiting confirmation this.CancelSourcePendingAction(record); if (this._ServerType == "OFFICIAL") { this.SendMessageToSource(record, record.command_type + " cannot be performed on official servers."); this.FinalizeRecord(record); return; } if (!this._UseBanEnforcer || !this._UseBanEnforcerPreviousState) { this.SendMessageToSource(record, "The unban command can only be used when ban enforcer is enabled."); this.FinalizeRecord(record); return; } record.record_message = "Admin Unban"; //Parse parameters using max param count String[] parameters = this.ParseParameters(remainingMessage, 1); switch (parameters.Length) { case 0: //Unban the last player you've banned this.SendMessageToSource(record, "Unbanning the last person you banned is not implemented yet."); this.FinalizeRecord(record); return; case 1: //Unban the target player String partialName = parameters[0]; if (String.IsNullOrEmpty(partialName) || partialName.Length < 3) { this.SendMessageToSource(record, "Name search must be at least 3 characters."); this.FinalizeRecord(record); return; } List<AdKatsBan> matchingBans = new List<AdKatsBan>(); List<AdKatsPlayer> matchingPlayers; if (this.FetchMatchingPlayers(partialName, out matchingPlayers, false)) { foreach (AdKatsPlayer aPlayer in matchingPlayers) { AdKatsBan aBan = this.FetchPlayerBan(aPlayer); if (aBan != null) { matchingBans.Add(aBan); } } } if (matchingBans.Count == 0) { this.SendMessageToSource(record, "No players matching '" + partialName + "' have active bans."); this.FinalizeRecord(record); return; } else if(matchingBans.Count <= 3) { foreach (AdKatsBan innerBan in matchingBans) { this.SendMessageToSource(record, innerBan.ban_record.target_player.player_name + " | " + innerBan.ban_record.record_message); } AdKatsBan aBan = matchingBans[0]; record.target_name = aBan.ban_record.target_player.player_name; record.target_player = aBan.ban_record.target_player; this.ConfirmActionWithSource(record); } else { this.SendMessageToSource(record, "Too many banned players match your search, try again."); this.FinalizeRecord(record); return; } break; default: this.SendMessageToSource(record, "Invalid parameters, unable to submit."); this.FinalizeRecord(record); return; } } break; #endregion #region PunishPlayer case "player_punish": { //Remove previous commands awaiting confirmation this.CancelSourcePendingAction(record); if (this._ServerType == "OFFICIAL") { this.SendMessageToSource(record, record.command_type + " cannot be performed on official servers."); this.FinalizeRecord(record); return; } //Parse parameters using max param count String[] parameters = this.ParseParameters(remainingMessage, 2); switch (parameters.Length) { case 0: if (record.record_source != AdKatsRecord.Sources.InGame) { this.SendMessageToSource(record, "You can't use a self-inflicting command from outside the game."); this.FinalizeRecord(record); return; } record.record_message = "Self-Inflicted"; record.target_name = record.source_name; this.CompleteTargetInformation(record, true); break; case 1: record.target_name = parameters[0]; //Handle based on report ID as only option if (!this.HandleRoundReport(record)) { this.SendMessageToSource(record, "No reason given, unable to submit."); this.FinalizeRecord(record); return; } break; case 2: record.target_name = parameters[0]; //attempt to handle via pre-message ID record.record_message = this.GetPreMessage(parameters[1], this._RequirePreMessageUse); if (record.record_message == null) { this.SendMessageToSource(record, "Invalid PreMessage ID, valid PreMessage IDs are 1-" + this._PreMessageList.Count); this.FinalizeRecord(record); return; } //Handle based on report ID if possible if (!this.HandleRoundReport(record)) { if (record.record_message.Length >= this._RequiredReasonLength) { this.CompleteTargetInformation(record, false); } else { this.SendMessageToSource(record, "Reason too short, unable to submit."); this.FinalizeRecord(record); return; } } break; default: this.SendMessageToSource(record, "Invalid parameters, unable to submit."); this.FinalizeRecord(record); return; } } break; #endregion #region ForgivePlayer case "player_forgive": { //Remove previous commands awaiting confirmation this.CancelSourcePendingAction(record); //Parse parameters using max param count String[] parameters = this.ParseParameters(remainingMessage, 2); switch (parameters.Length) { case 0: if (record.record_source != AdKatsRecord.Sources.InGame) { this.SendMessageToSource(record, "You can't use a self-inflicting command from outside the game."); this.FinalizeRecord(record); return; } record.record_message = "Self-Inflicted"; record.target_name = record.source_name; this.CompleteTargetInformation(record, true); break; case 1: record.target_name = parameters[0]; //Handle based on report ID as only option if (!this.HandleRoundReport(record)) { this.SendMessageToSource(record, "No reason given, unable to submit."); this.FinalizeRecord(record); return; } break; case 2: record.target_name = parameters[0]; //attempt to handle via pre-message ID record.record_message = this.GetPreMessage(parameters[1], this._RequirePreMessageUse); if (record.record_message == null) { this.SendMessageToSource(record, "Invalid PreMessage ID, valid PreMessage IDs are 1-" + this._PreMessageList.Count); this.FinalizeRecord(record); return; } //Handle based on report ID if possible if (!this.HandleRoundReport(record)) { if (record.record_message.Length >= this._RequiredReasonLength) { this.CompleteTargetInformation(record, false); } else { this.SendMessageToSource(record, "Reason too short, unable to submit."); this.FinalizeRecord(record); return; } } break; default: this.SendMessageToSource(record, "Invalid parameters, unable to submit."); this.FinalizeRecord(record); return; } } break; #endregion #region MutePlayer case "player_mute": { //Remove previous commands awaiting confirmation this.CancelSourcePendingAction(record); if (this._ServerType == "OFFICIAL") { this.SendMessageToSource(record, record.command_type + " cannot be performed on official servers."); this.FinalizeRecord(record); return; } //Parse parameters using max param count String[] parameters = this.ParseParameters(remainingMessage, 2); switch (parameters.Length) { case 0: if (record.record_source != AdKatsRecord.Sources.InGame) { this.SendMessageToSource(record, "You can't use a self-inflicting command from outside the game."); this.FinalizeRecord(record); return; } record.record_message = "Self-Inflicted"; record.target_name = record.source_name; this.CompleteTargetInformation(record, true); break; case 1: record.target_name = parameters[0]; //Handle based on report ID as only option if (!this.HandleRoundReport(record)) { this.SendMessageToSource(record, "No reason given, unable to submit."); this.FinalizeRecord(record); return; } break; case 2: record.target_name = parameters[0]; //attempt to handle via pre-message ID record.record_message = this.GetPreMessage(parameters[1], this._RequirePreMessageUse); if (record.record_message == null) { this.SendMessageToSource(record, "Invalid PreMessage ID, valid PreMessage IDs are 1-" + this._PreMessageList.Count); this.FinalizeRecord(record); return; } //Handle based on report ID if possible if (!this.HandleRoundReport(record)) { if (record.record_message.Length >= this._RequiredReasonLength) { this.CompleteTargetInformation(record, false); } else { this.SendMessageToSource(record, "Reason too short, unable to submit."); this.FinalizeRecord(record); return; } } break; default: this.SendMessageToSource(record, "Invalid parameters, unable to submit."); this.FinalizeRecord(record); return; } } break; #endregion #region JoinPlayer case "player_join": { //Remove previous commands awaiting confirmation this.CancelSourcePendingAction(record); if (this._ServerType == "OFFICIAL") { this.SendMessageToSource(record, record.command_type + " cannot be performed on official servers."); this.FinalizeRecord(record); return; } //Parse parameters using max param count String[] parameters = this.ParseParameters(remainingMessage, 1); switch (parameters.Length) { case 0: this.SendMessageToSource(record, "foreveralone.jpg"); this.FinalizeRecord(record); return; case 1: record.target_name = parameters[0]; record.record_message = "Joining Player"; if (!this.HandleRoundReport(record)) { this.CompleteTargetInformation(record, false); } break; default: this.SendMessageToSource(record, "Invalid parameters, unable to submit."); this.FinalizeRecord(record); return; } } break; #endregion #region RoundWhitelistPlayer case "player_roundwhitelist": { //Remove previous commands awaiting confirmation this.CancelSourcePendingAction(record); if (this._ServerType == "OFFICIAL") { this.SendMessageToSource(record, record.command_type + " cannot be performed on official servers."); this.FinalizeRecord(record); return; } //Parse parameters using max param count String[] parameters = this.ParseParameters(remainingMessage, 2); switch (parameters.Length) { case 0: if (record.record_source != AdKatsRecord.Sources.InGame) { this.SendMessageToSource(record, "You can't use a self-inflicting command from outside the game."); this.FinalizeRecord(record); return; } record.record_message = "Self-Inflicted"; record.target_name = record.source_name; this.CompleteTargetInformation(record, true); break; case 1: record.target_name = parameters[0]; //Handle based on report ID as only option if (!this.HandleRoundReport(record)) { this.SendMessageToSource(record, "No reason given, unable to submit."); this.FinalizeRecord(record); return; } break; case 2: record.target_name = parameters[0]; //attempt to handle via pre-message ID record.record_message = this.GetPreMessage(parameters[1], false); //Handle based on report ID if possible if (!this.HandleRoundReport(record)) { if (record.record_message.Length >= this._RequiredReasonLength) { this.CompleteTargetInformation(record, false); } else { this.SendMessageToSource(record, "Reason too short, unable to submit."); this.FinalizeRecord(record); return; } } break; default: this.SendMessageToSource(record, "Invalid parameters, unable to submit."); this.FinalizeRecord(record); return; } } break; #endregion #region ReportPlayer case "player_report": { //Get the command text for report String command = this._CommandKeyDictionary["player_report"].command_text; //Remove previous commands awaiting confirmation this.CancelSourcePendingAction(record); //Parse parameters using max param count String[] parameters = this.ParseParameters(remainingMessage, 2); switch (parameters.Length) { case 0: this.SendMessageToSource(record, "Format must be: @" + command + " playername reason"); this.FinalizeRecord(record); return; case 1: this.SendMessageToSource(record, "Format must be: @" + command + " playername reason"); this.FinalizeRecord(record); return; case 2: record.target_name = parameters[0]; DebugWrite("target: " + record.target_name, 6); //attempt to handle via pre-message ID record.record_message = this.GetPreMessage(parameters[1], false); DebugWrite("reason: " + record.record_message, 6); //Only 1 character reasons are required for reports and admin calls if (record.record_message.Length >= 1) { this.CompleteTargetInformation(record, false); } else { DebugWrite("reason too short", 6); this.SendMessageToSource(record, "Reason too short, unable to submit."); this.FinalizeRecord(record); return; } break; default: this.SendMessageToSource(record, "Invalid parameters, unable to submit."); this.FinalizeRecord(record); return; } } break; #endregion #region CallAdmin case "player_calladmin": { //Get the command text for call admin String command = this._CommandKeyDictionary["player_calladmin"].command_text; //Remove previous commands awaiting confirmation this.CancelSourcePendingAction(record); //Parse parameters using max param count String[] parameters = this.ParseParameters(remainingMessage, 2); switch (parameters.Length) { case 0: this.SendMessageToSource(record, "Format must be: @" + command + " playername reason"); this.FinalizeRecord(record); return; case 1: this.SendMessageToSource(record, "Format must be: @" + command + " playername reason"); this.FinalizeRecord(record); return; case 2: record.target_name = parameters[0]; DebugWrite("target: " + record.target_name, 6); //attempt to handle via pre-message ID record.record_message = this.GetPreMessage(parameters[1], false); DebugWrite("reason: " + record.record_message, 6); //Only 1 character reasons are required for reports and admin calls if (record.record_message.Length >= 1) { this.CompleteTargetInformation(record, false); } else { DebugWrite("reason too short", 6); this.SendMessageToSource(record, "Reason too short, unable to submit."); this.FinalizeRecord(record); return; } break; default: this.SendMessageToSource(record, "Invalid parameters, unable to submit."); this.FinalizeRecord(record); return; } } break; #endregion #region NukeServer case "server_nuke": { //Remove previous commands awaiting confirmation this.CancelSourcePendingAction(record); if (this._ServerType == "OFFICIAL") { this.SendMessageToSource(record, record.command_type + " cannot be performed on official servers."); this.FinalizeRecord(record); return; } //Parse parameters using max param count String[] parameters = this.ParseParameters(remainingMessage, 2); switch (parameters.Length) { case 0: this.SendMessageToSource(record, "No parameters given, unable to submit."); this.FinalizeRecord(record); return; case 1: String targetTeam = parameters[0]; record.record_message = "Nuke Server"; DebugWrite("target: " + targetTeam, 6); if (targetTeam.ToLower().Contains("us")) { record.target_name = "US Team"; record.record_message += " (US Team)"; } else if (targetTeam.ToLower().Contains("ru")) { record.target_name = "RU Team"; record.record_message += " (RU Team)"; } else if (targetTeam.ToLower().Contains("all")) { record.target_name = "Everyone"; record.record_message += " (Everyone)"; } else { this.SendMessageToSource(record, "Use 'US', 'RU', or 'ALL' as targets."); this.FinalizeRecord(record); return; } //Have the admin confirm the action this.ConfirmActionWithSource(record); break; default: this.SendMessageToSource(record, "Invalid parameters, unable to submit."); this.FinalizeRecord(record); return; } } break; #endregion #region KickAll case "server_kickall": this.CancelSourcePendingAction(record); if (this._ServerType == "OFFICIAL") { this.SendMessageToSource(record, record.command_type + " cannot be performed on official servers."); this.FinalizeRecord(record); return; } record.target_name = "Non-Admins"; record.record_message = "Kick All Players"; this.ConfirmActionWithSource(record); break; #endregion #region EndLevel case "round_end": { //Remove previous commands awaiting confirmation this.CancelSourcePendingAction(record); if (this._ServerType == "OFFICIAL") { this.SendMessageToSource(record, record.command_type + " cannot be performed on official servers."); this.FinalizeRecord(record); return; } //Parse parameters using max param count String[] parameters = this.ParseParameters(remainingMessage, 2); switch (parameters.Length) { case 0: this.SendMessageToSource(record, "No parameters given, unable to submit."); this.FinalizeRecord(record); return; case 1: String targetTeam = parameters[0]; DebugWrite("target team: " + targetTeam, 6); record.record_message = "End Round"; if (targetTeam.ToLower().Contains("us")) { record.target_name = "US Team"; record.command_numeric = AdKats.UsTeamID; record.record_message += " (US Win)"; } else if (targetTeam.ToLower().Contains("ru")) { record.target_name = "RU Team"; record.command_numeric = AdKats.RuTeamID; record.record_message += " (RU Win)"; } else { this.SendMessageToSource(record, "Use 'US' or 'RU' as team names to end round"); this.FinalizeRecord(record); return; } break; default: this.SendMessageToSource(record, "Invalid parameters, unable to submit."); this.FinalizeRecord(record); return; } //Have the admin confirm the action this.ConfirmActionWithSource(record); } break; #endregion #region RestartLevel case "round_restart": this.CancelSourcePendingAction(record); if (this._ServerType == "OFFICIAL") { this.SendMessageToSource(record, record.command_type + " cannot be performed on official servers."); this.FinalizeRecord(record); return; } record.target_name = "Server"; record.record_message = "Restart Round"; this.ConfirmActionWithSource(record); break; #endregion #region NextLevel case "round_next": this.CancelSourcePendingAction(record); if (this._ServerType == "OFFICIAL") { this.SendMessageToSource(record, record.command_type + " cannot be performed on official servers."); this.FinalizeRecord(record); return; } record.target_name = "Server"; record.record_message = "Run Next Map"; this.ConfirmActionWithSource(record); break; #endregion #region WhatIs case "self_whatis": { //Remove previous commands awaiting confirmation this.CancelSourcePendingAction(record); //Parse parameters using max param count String[] parameters = this.ParseParameters(remainingMessage, 1); switch (parameters.Length) { case 0: this.SendMessageToSource(record, "No parameters given, unable to submit."); this.FinalizeRecord(record); return; case 1: record.record_message = this.GetPreMessage(parameters[0], true); if (record.record_message == null) { this.SendMessageToSource(record, "Invalid PreMessage ID, valid PreMessage IDs are 1-" + this._PreMessageList.Count); this.FinalizeRecord(record); return; } else { this.SendMessageToSource(record, record.record_message); this.FinalizeRecord(record); return; } break; default: this.SendMessageToSource(record, "Invalid parameters, unable to submit."); this.FinalizeRecord(record); return; } //This type is not processed } break; #endregion #region RequestVoip case "self_voip": { //Remove previous commands awaiting confirmation this.CancelSourcePendingAction(record); //Send them voip information this.SendMessageToSource(record, this._ServerVoipAddress); this.FinalizeRecord(record); return; } break; #endregion #region RequestRules case "self_rules": { //Remove previous commands awaiting confirmation this.CancelSourcePendingAction(record); record.record_message = "Player Requested Rules"; record.target_name = record.source_name; this.CompleteTargetInformation(record, false); } break; #endregion #region AdminSay case "admin_say": { //Remove previous commands awaiting confirmation this.CancelSourcePendingAction(record); //Parse parameters using max param count String[] parameters = this.ParseParameters(remainingMessage, 1); switch (parameters.Length) { case 0: this.SendMessageToSource(record, "No parameters given, unable to submit."); this.FinalizeRecord(record); return; case 1: record.record_message = this.GetPreMessage(parameters[0], false); DebugWrite("message: " + record.record_message, 6); record.target_name = "Server"; this.QueueRecordForProcessing(record); break; default: this.SendMessageToSource(record, "Invalid parameters, unable to submit."); this.FinalizeRecord(record); return; } } break; #endregion #region PlayerSay case "player_say": { //Remove previous commands awaiting confirmation this.CancelSourcePendingAction(record); //Parse parameters using max param count String[] parameters = this.ParseParameters(remainingMessage, 2); switch (parameters.Length) { case 0: this.SendMessageToSource(record, "No parameters given, unable to submit."); this.FinalizeRecord(record); return; case 1: this.SendMessageToSource(record, "No message given, unable to submit."); this.FinalizeRecord(record); return; case 2: record.target_name = parameters[0]; DebugWrite("target: " + record.target_name, 6); record.record_message = this.GetPreMessage(parameters[1], false); DebugWrite("message: " + record.record_message, 6); this.CompleteTargetInformation(record, false); break; default: this.SendMessageToSource(record, "Invalid parameters, unable to submit."); this.FinalizeRecord(record); return; } } break; #endregion #region AdminYell case "admin_yell": { //Remove previous commands awaiting confirmation this.CancelSourcePendingAction(record); //Parse parameters using max param count String[] parameters = this.ParseParameters(remainingMessage, 1); switch (parameters.Length) { case 0: this.SendMessageToSource(record, "No parameters given, unable to submit."); this.FinalizeRecord(record); return; case 1: record.record_message = this.GetPreMessage(parameters[0], false); DebugWrite("message: " + record.record_message, 6); record.target_name = "Server"; this.QueueRecordForProcessing(record); break; default: this.SendMessageToSource(record, "Invalid parameters, unable to submit."); this.FinalizeRecord(record); return; } } break; #endregion #region PlayerYell case "player_yell": { //Remove previous commands awaiting confirmation this.CancelSourcePendingAction(record); //Parse parameters using max param count String[] parameters = this.ParseParameters(remainingMessage, 2); switch (parameters.Length) { case 0: this.SendMessageToSource(record, "No parameters given, unable to submit."); this.FinalizeRecord(record); return; case 1: this.SendMessageToSource(record, "No message given, unable to submit."); this.FinalizeRecord(record); return; case 2: record.target_name = parameters[0]; DebugWrite("target: " + record.target_name, 6); record.record_message = this.GetPreMessage(parameters[1], false); DebugWrite("message: " + record.record_message, 6); this.CompleteTargetInformation(record, false); break; default: this.SendMessageToSource(record, "Invalid parameters, unable to submit."); this.FinalizeRecord(record); return; } } break; #endregion #region AdminTell case "admin_tell": { //Remove previous commands awaiting confirmation this.CancelSourcePendingAction(record); //Parse parameters using max param count String[] parameters = this.ParseParameters(remainingMessage, 1); switch (parameters.Length) { case 0: this.SendMessageToSource(record, "No parameters given, unable to submit."); this.FinalizeRecord(record); return; case 1: record.record_message = this.GetPreMessage(parameters[0], false); DebugWrite("message: " + record.record_message, 6); record.target_name = "Server"; this.QueueRecordForProcessing(record); break; default: this.SendMessageToSource(record, "Invalid parameters, unable to submit."); this.FinalizeRecord(record); return; } } break; #endregion #region PlayerTell case "player_tell": { //Remove previous commands awaiting confirmation this.CancelSourcePendingAction(record); //Parse parameters using max param count String[] parameters = this.ParseParameters(remainingMessage, 2); switch (parameters.Length) { case 0: this.SendMessageToSource(record, "No parameters given, unable to submit."); this.FinalizeRecord(record); return; case 1: this.SendMessageToSource(record, "No message given, unable to submit."); this.FinalizeRecord(record); return; case 2: record.target_name = parameters[0]; DebugWrite("target: " + record.target_name, 6); record.record_message = this.GetPreMessage(parameters[1], false); DebugWrite("message: " + record.record_message, 6); this.CompleteTargetInformation(record, false); break; default: this.SendMessageToSource(record, "Invalid parameters, unable to submit."); this.FinalizeRecord(record); return; } } break; #endregion #region ConfirmCommand case "command_confirm": this.DebugWrite("attempting to confirm command", 6); AdKatsRecord recordAttempt = null; this._ActionConfirmDic.TryGetValue(record.source_name, out recordAttempt); if (recordAttempt != null) { this.DebugWrite("command found, calling processing", 6); this._ActionConfirmDic.Remove(record.source_name); this.QueueRecordForProcessing(recordAttempt); this.FinalizeRecord(record); return; } else { this.DebugWrite("no command to confirm", 6); this.FinalizeRecord(record); return; } //This type is not processed break; #endregion #region CancelCommand case "command_cancel": this.DebugWrite("attempting to cancel command", 6); if (!this._ActionConfirmDic.Remove(record.source_name)) { this.DebugWrite("no command to cancel", 6); } //This type is not processed this.FinalizeRecord(record); return; #endregion default: this.ConsoleError("Unable to complete record for " + record.command_type.command_key + ", handler not found."); this.FinalizeRecord(record); return; } } catch (Exception e) { record.record_exception = this.HandleException(new AdKatsException("Error occured while completing record information.", e)); this.FinalizeRecord(record); return; } }
public void TempBanTarget(AdKatsRecord record, String additionalMessage) { this.DebugWrite("Entering tempBanTarget", 6); try { //Subtract 1 second for visual effect Int32 seconds = (record.command_numeric * 60) - 1; //Perform Actions //Only post to ban enforcer if there are no exceptions if (this._UseBanEnforcer && record.record_exception == null) { //Update the ban enforcement depending on available information Boolean nameAvailable = !String.IsNullOrEmpty(record.target_player.player_name); Boolean guidAvailable = !String.IsNullOrEmpty(record.target_player.player_guid); Boolean ipAvailable = !String.IsNullOrEmpty(record.target_player.player_ip); //Create the ban AdKatsBan aBan = new AdKatsBan { ban_record = record, ban_enforceName = nameAvailable && (this._DefaultEnforceName || (!guidAvailable && !ipAvailable)), ban_enforceGUID = guidAvailable && (this._DefaultEnforceGUID || (!nameAvailable && !ipAvailable)), ban_enforceIP = ipAvailable && (this._DefaultEnforceIP || (!nameAvailable && !guidAvailable)) }; //Queue the ban for upload this.QueueBanForProcessing(aBan); } else { if (record.record_exception != null) { this.HandleException(new AdKatsException("Defaulting to procon banlist usage since exceptions existed in record")); } //Trim the ban message if necessary String banMessage = record.record_message; Int32 cutLength = banMessage.Length - 80; if (cutLength > 0) { banMessage = banMessage.Substring(0, banMessage.Length - cutLength); } this.DebugWrite("Ban Message: '" + banMessage + "'", 3); if (!String.IsNullOrEmpty(record.target_player.player_guid)) { this.ExecuteCommand("procon.protected.send", "banList.add", "guid", record.target_player.player_guid, "seconds", seconds + "", banMessage); this.ExecuteCommand("procon.protected.send", "banList.save"); this.ExecuteCommand("procon.protected.send", "banList.list"); } else if (!String.IsNullOrEmpty(record.target_player.player_ip)) { this.ExecuteCommand("procon.protected.send", "banList.add", "ip", record.target_player.player_ip, "seconds", seconds + "", banMessage); this.ExecuteCommand("procon.protected.send", "banList.save"); this.ExecuteCommand("procon.protected.send", "banList.list"); } else if (!String.IsNullOrEmpty(record.target_player.player_name)) { this.ExecuteCommand("procon.protected.send", "banList.add", "id", record.target_player.player_name, "seconds", seconds + "", banMessage); this.ExecuteCommand("procon.protected.send", "banList.save"); this.ExecuteCommand("procon.protected.send", "banList.list"); } else { this.ConsoleError("Player has no information to ban with."); this.SendMessageToSource(record, "ERROR"); } this.RemovePlayerFromDictionary(record.target_player.player_name); } if (record.target_name != record.source_name) { this.AdminSayMessage("Player " + record.target_name + " was BANNED by " + ((this._ShowAdminNameInSay) ? (record.source_name) : ("admin")) + " for " + record.record_message + " " + additionalMessage); } this.SendMessageToSource(record, "You TEMP BANNED " + record.target_name + " for " + this.FormatTimeString(TimeSpan.FromMinutes(record.command_numeric)) + "." + additionalMessage); record.record_action_executed = true; } catch (Exception e) { record.record_exception = new AdKatsException("Error while taking action for TempBan record.", e); this.HandleException(record.record_exception); this.FinalizeRecord(record); } this.DebugWrite("Exiting tempBanTarget", 6); }
//DONE private AdKatsRecord FetchRecordByID(Int64 recordID, Boolean debug) { DebugWrite("fetchRecordByID starting!", 6); AdKatsRecord record = null; //Make sure database connection active if (this.HandlePossibleDisconnect()) { return null; } try { //Success fetching record Boolean success = false; using (MySqlConnection connection = this.GetDatabaseConnection()) { using (MySqlCommand command = connection.CreateCommand()) { String tablename = (debug) ? ("`adkats_records_debug`") : ("`adkats_records_main`"); String sql = @" SELECT `record_id`, `server_id`, `command_type`, `command_action`, `command_numeric`, `target_name`, `target_id`, `source_name`, `record_message`, `record_time` FROM " + tablename + @" WHERE `record_id` = " + recordID; command.CommandText = sql; using (MySqlDataReader reader = command.ExecuteReader()) { //Grab the record if (reader.Read()) { success = true; record = new AdKatsRecord(); record.record_source = AdKatsRecord.Sources.Database; record.record_id = reader.GetInt64("record_id"); record.server_id = reader.GetInt64("server_id"); Int32 commandTypeInt = reader.GetInt32("command_type"); if (!this._CommandIDDictionary.TryGetValue(commandTypeInt, out record.command_type)) { this.ConsoleError("Unable to parse command type " + commandTypeInt + " when fetching record by ID."); } Int32 commandActionInt = reader.GetInt32("command_action"); if (!this._CommandIDDictionary.TryGetValue(commandActionInt, out record.command_action)) { this.ConsoleError("Unable to parse command action " + commandActionInt + " when fetching record by ID."); } record.command_numeric = reader.GetInt32("command_numeric"); record.target_name = reader.GetString("target_name"); if (!reader.IsDBNull(6)) { record.target_player = new AdKatsPlayer { player_id = reader.GetInt64(6) }; } record.source_name = reader.GetString("source_name"); record.record_message = reader.GetString("record_message"); record.record_time = reader.GetDateTime("record_time"); } if (success) { this.DebugWrite("Record found for ID " + recordID, 5); } else { this.DebugWrite("No record found for ID " + recordID, 5); } } if (success && record.target_player != null) { long oldID = record.target_player.player_id; record.target_player = this.FetchPlayer(false, true, oldID, null, null, null); if (record.target_player == null) { this.ConsoleError("Unable to find player ID: " + oldID); return null; } if (!String.IsNullOrEmpty(record.target_player.player_name)) { record.target_name = record.target_player.player_name; } else { record.target_name = "NoNameTarget"; } } } } } catch (Exception e) { this.HandleException(new AdKatsException("Error while fetching record by ID", e)); } DebugWrite("fetchRecordByID finished!", 6); return record; }
public void AutoWhitelistPlayers() { try { lock (_PlayersMutex) { if (this._PlayersToAutoWhitelist > 0) { Random random = new Random(); List<String> playerListCopy = new List<String>(); foreach (AdKatsPlayer player in this._PlayerDictionary.Values) { this.DebugWrite("Checking for TeamSwap access on " + player.player_name, 6); if (!this.HasAccess(player, this._CommandKeyDictionary["self_teamswap"])) { this.DebugWrite("player doesnt have access, adding them to chance list", 6); if (!playerListCopy.Contains(player.player_name)) { playerListCopy.Add(player.player_name); } } } if (playerListCopy.Count > 0) { Int32 maxIndex = (playerListCopy.Count < this._PlayersToAutoWhitelist) ? (playerListCopy.Count) : (this._PlayersToAutoWhitelist); this.DebugWrite("MaxIndex: " + maxIndex, 6); for (Int32 index = 0; index < maxIndex; index++) { String playerName = null; Int32 iterations = 0; do { playerName = playerListCopy[random.Next(0, playerListCopy.Count - 1)]; } while (this._TeamswapRoundWhitelist.ContainsKey(playerName) && (iterations++ < 100)); if (!this._TeamswapRoundWhitelist.ContainsKey(playerName)) { AdKatsPlayer aPlayer = null; if (this._PlayerDictionary.TryGetValue(playerName, out aPlayer)) { //Create the Exception record AdKatsRecord record = new AdKatsRecord { record_source = AdKatsRecord.Sources.InternalAutomated, server_id = this._ServerID, command_type = this._CommandKeyDictionary["player_roundwhitelist"], command_numeric = 0, target_name = aPlayer.player_name, target_player = aPlayer, source_name = "AdKats", record_message = "Round-Whitelisting Player" }; //Process the record this.QueueRecordForProcessing(record); } else { this.ConsoleError("Player was not in player dictionary when calling auto-whitelist."); } } } } } } } catch (Exception e) { this.HandleException(new AdKatsException("Error while auto-whitelisting players.", e)); } }
private void HandleRecordUpload(AdKatsRecord record) { //Make sure database connection active if (this.HandlePossibleDisconnect()) { record.record_exception = new AdKatsException("Database not connected."); return; } try { this.DebugWrite("DBCOMM: Entering handle record upload", 5); if (record.record_id != -1 || record.record_action_executed) { //Record already has a record ID, or action has already been taken, it can only be updated if (record.command_type.command_logging != AdKatsCommand.CommandLogging.Ignore) { if (record.record_exception == null) { //Only call update if the record contained no errors this.DebugWrite("DBCOMM: UPDATING record for " + record.command_type, 5); //Update Record this.UpdateRecord(record, false); } else { this.DebugWrite("DBCOMM: " + record.command_type + " record contained errors, skipping UPDATE", 4); } } else { this.DebugWrite("DBCOMM: Skipping record UPDATE for " + record.command_type, 5); } } else { this.DebugWrite("DBCOMM: Record needs full upload, checking.", 5); //No record ID. Perform full upload switch (record.command_type.command_key) { case "player_punish": //Upload for punish is required //TODO confirm this stops the action if cant punish if (this.CanPunish(record)) { //Check if the punish will be Double counted Boolean iroStatus = this._IROActive && this.FetchIROStatus(record); if (iroStatus) { record.isIRO = true; //Upload record twice this.DebugWrite("DBCOMM: UPLOADING IRO Punish", 5); //IRO - Immediate Repeat Offence this.UploadRecord(record); this.UploadRecord(record); } else { //Upload record once this.DebugWrite("DBCOMM: UPLOADING Punish", 5); this.UploadRecord(record); } } break; case "player_forgive": //Upload for forgive is required //No restriction on forgives/minute this.DebugWrite("DBCOMM: UPLOADING Forgive", 5); this.UploadRecord(record); break; default: //Case for any other command //Check logging setting for record command type if (record.command_type.command_logging != AdKatsCommand.CommandLogging.Ignore) { this.DebugWrite("UPLOADING record for " + record.command_type, 5); //Upload Record this.UploadRecord(record); } else { this.DebugWrite("Skipping record UPLOAD for " + record.command_type, 6); } break; } } } catch (Exception e) { record.record_exception = this.HandleException(new AdKatsException("Error while handling record upload.", e)); } }
public void MoveTarget(AdKatsRecord record) { this.DebugWrite("Entering moveTarget", 6); try { this.QueuePlayerForMove(record.target_player.frostbitePlayerInfo); this.PlayerSayMessage(record.target_name, "On your next death you will be moved to the opposing team."); this.SendMessageToSource(record, record.target_name + " will be sent to TeamSwap on their next death."); record.record_action_executed = true; } catch (Exception e) { record.record_exception = new AdKatsException("Error while taking action for move record.", e); this.HandleException(record.record_exception); this.FinalizeRecord(record); } this.DebugWrite("Exiting moveTarget", 6); }