private void ScheduleListPlayers(double delay) { DelayedRequest r = new DelayedRequest(delay, fListPlayersTimestamp); DebugWrite("^9Scheduling listPlayers no sooner than " + r.MaxDelay + " seconds from " + r.LastUpdate.ToString("HH:mm:ss"), 7); lock (fListPlayersQ) { fListPlayersQ.Enqueue(r); Monitor.Pulse(fListPlayersQ); } }
private void Reset() { ResetRound(); lock (fPriorityFetchQ) { fPriorityFetchQ.Clear(); Monitor.Pulse(fPriorityFetchQ); } lock (fMoveQ) { fMoveQ.Clear(); Monitor.Pulse(fMoveQ); } lock (fListPlayersQ) { fListPlayersQ.Clear(); Monitor.Pulse(fListPlayersQ); } lock (fAllPlayers) { fAllPlayers.Clear(); } lock (fMoving) { fMoving.Clear(); } lock (fMoveStash) { fMoveStash.Clear(); } lock (fExtrasLock) { fExtraNames.Clear(); fDebugScramblerSuspects.Clear(); } fReassigned.Clear(); fPendingTeamChange.Clear(); fUnassigned.Clear(); /* fKnownPlayers is not cleared right away, since we want to retain stats from previous plugin sessions. It will be garbage collected after MODEL_MINUTES. */ fServerInfo = null; // release Procon reference fListPlayersTimestamp = DateTime.MinValue; fRefreshCommand = false; fServerUptime = 0; fServerCrashed = false; fFinalStatus = null; fMaxTickets = -1; fBalanceIsActive = false; fIsFullRound = false; fLastMsg = null; fRoundsEnabled = 0; fGrandTotalQuits = 0; fGrandRageQuits = 0; fWhileScrambling = false; fUpdateTicketsRequest = null; fTotalRoundEndingRounds = 0; fTotalRoundEndingSeconds = 0; fDebugScramblerBefore[0].Clear(); fDebugScramblerBefore[1].Clear(); fDebugScramblerAfter[0].Clear(); fDebugScramblerAfter[1].Clear(); fDebugScramblerStartRound[0].Clear(); fDebugScramblerStartRound[1].Clear(); }
/* Constructor */ public MULTIbalancer() { /* Private members */ fIsEnabled = false; fFinalizerActive = false; fPluginState = PluginState.Disabled; fGameState = GameState.Unknown; fServerInfo = null; fRefreshCommand = false; fServerUptime = 0; fServerCrashed = false; fDebugScramblerBefore = new List<PlayerModel>[2]{new List<PlayerModel>(), new List<PlayerModel>()}; fDebugScramblerAfter = new List<PlayerModel>[2]{new List<PlayerModel>(), new List<PlayerModel>()}; fDebugScramblerStartRound = new List<PlayerModel>[2]{new List<PlayerModel>(), new List<PlayerModel>()}; fBalancedRound = 0; fUnstackedRound = 0; fUnswitchedRound = 0; fExcludedRound = 0; fExemptRound = 0; fFailedRound = 0; fTotalRound = 0; fBalanceIsActive = false; fRoundsEnabled = 0; fGrandTotalQuits = 0; fGrandRageQuits = 0; fTotalQuits = 0; fRageQuits = 0; fMoveThread = null; fFetchThread = null; fListPlayersThread = null; fScramblerThread = null; fTimerThread = null; fModeToSimple = new Dictionary<String,String>(); fEasyTypeDict = new Dictionary<int, Type>(); fEasyTypeDict.Add(0, typeof(int)); fEasyTypeDict.Add(1, typeof(Int16)); fEasyTypeDict.Add(2, typeof(Int32)); fEasyTypeDict.Add(3, typeof(Int64)); fEasyTypeDict.Add(4, typeof(float)); fEasyTypeDict.Add(5, typeof(long)); fEasyTypeDict.Add(6, typeof(String)); fEasyTypeDict.Add(7, typeof(string)); fEasyTypeDict.Add(8, typeof(double)); fBoolDict = new Dictionary<int, Type>(); fBoolDict.Add(0, typeof(Boolean)); fBoolDict.Add(1, typeof(bool)); fListStrDict = new Dictionary<int, Type>(); fListStrDict.Add(0, typeof(String[])); fPerMode = new Dictionary<String,PerModeSettings>(); fAllPlayers = new List<String>(); fKnownPlayers = new Dictionary<String, PlayerModel>(); fTeam1 = new List<PlayerModel>(); fTeam2 = new List<PlayerModel>(); fTeam3 = new List<PlayerModel>(); fTeam4 = new List<PlayerModel>(); fUnassigned = new List<String>(); fRoundStartTimestamp = DateTime.MinValue; fRoundOverTimestamp = DateTime.MinValue; fListPlayersTimestamp = DateTime.MinValue; fFullUnstackSwapTimestamp = DateTime.MinValue; fLastValidationTimestamp = DateTime.MinValue; fListPlayersQ = new Queue<DelayedRequest>(); fPendingTeamChange = new Dictionary<String,int>(); fMoving = new Dictionary<String, MoveInfo>(); fMoveQ = new Queue<MoveInfo>(); fReassigned = new List<String>(); fReservedSlots = new List<String>(); fTickets = new int[5]{0,0,0,0,0}; fFriendlyMaps = new Dictionary<String,String>(); fFriendlyModes = new Dictionary<String,String>(); fMaxTickets = -1; fRushMaxTickets = -1; fLastBalancedTimestamp = DateTime.MinValue; fEnabledTimestamp = DateTime.MinValue; fFinalStatus = null; fIsFullRound = false; fUnstackState = UnstackState.Off; fLastMsg = null; fRushStage = 0; fRushPrevAttackerTickets = 0; fRushAttackerStageLoss = 0; fRushAttackerStageSamples = 0; fMoveStash = new List<MoveInfo>(); fLastVersionCheckTimestamp = DateTime.MinValue; fTimeOutOfJoint = 0; fUnstackGroupCount = 0; fPriorityFetchQ = new PriorityQueue(this); fIsCacheEnabled = false; fScramblerLock = new DelayedRequest(); fWinner = 0; fUpdateThreadLock = new DelayedRequest(); fLastServerInfoTimestamp = DateTime.Now; fStageInProgress = false; fHost = String.Empty; fPort = String.Empty; fRushMap3Stages = new List<String>(new String[6]{"MP_007", "XP4_Quake", "XP5_002", "MP_012", "XP4_Rubble", "MP_Damage"}); fRushMap5Stages = new List<String>(new String[6]{"MP_013", "XP3_Valley", "MP_017", "XP5_001", "MP_Prison", "MP_Siege"}); fGroupAssignments = new int[5]{0,0,0,0,0}; fDispersalGroups = new List<String>[5]{null, new List<String>(), new List<String>(), new List<String>(), new List<String>()}; fNeedPlayerListUpdate = false; fFriends = new Dictionary<int, List<String>>(); fAllFriends = new List<String>(); fWhileScrambling = false; fExtrasLock = new DelayedRequest(); fExtraNames = new List<String>(); fGotLogin = false; fDebugScramblerSuspects = new Dictionary<String,String>(); fTimerRequestList = new List<DelayedRequest>(); fAverageTicketLoss = new Queue<double>[3]{null, new Queue<double>(), new Queue<double>()}; fTicketLossHistogram = new Histogram(); /* Settings */ /* ===== SECTION 0 - Presets ===== */ SettingsVersion = 1; Preset = PresetItems.Standard; EnableUnstacking = false; EnableSettingsWizard = false; WhichMode = "Conquest Large"; MetroIsInMapRotation = false; MaximumPlayersForMode = 64; LowestMaximumTicketsForMode = 300; HighestMaximumTicketsForMode = 400; PreferredStyleOfBalancing = PresetItems.Standard; ApplySettingsChanges = false; /* ===== SECTION 1 - Settings ===== */ DebugLevel = 2; MaximumServerSize = 64; EnableBattlelogRequests = true; MaximumRequestRate = 10; // in 20 seconds WaitTimeout = 30; // seconds WhichBattlelogStats = BattlelogStats.ClanTagOnly; MaxTeamSwitchesByStrongPlayers = 1; MaxTeamSwitchesByWeakPlayers = 2; UnlimitedTeamSwitchingDuringFirstMinutesOfRound = 5.0; Enable2SlotReserve = false; EnablerecruitCommand = false; EnableWhitelistingOfReservedSlotsList = true; Whitelist = new String[] {DEFAULT_LIST_ITEM}; fSettingWhitelist = new List<String>(Whitelist); DisperseEvenlyList = new String[] {DEFAULT_LIST_ITEM}; fSettingDisperseEvenlyList = new List<String>(DisperseEvenlyList); FriendsList = new String[] {DEFAULT_LIST_ITEM}; fSettingFriendsList = new List<String>(); SecondsUntilAdaptiveSpeedBecomesFast = 3*60; // 3 minutes default EnableInGameCommands = true; /* ===== SECTION 2 - Exclusions ===== */ OnWhitelist = true; OnFriendsList = false; ApplyFriendsListToTeam = false; TopScorers = true; SameClanTagsInSquad = true; SameClanTagsInTeam = false; SameClanTagsForRankDispersal = false; LenientRankDispersal = false; MinutesAfterJoining = 5; MinutesAfterBeingMoved = 90; // 1.5 hours JoinedEarlyPhase = true; JoinedMidPhase = true; JoinedLatePhase = false; /* ===== SECTION 3 - Round Phase & Population Settings ===== */ EarlyPhaseTicketPercentageToUnstack = new double[3] { 0,120,120}; MidPhaseTicketPercentageToUnstack = new double[3] { 0,120,120}; LatePhaseTicketPercentageToUnstack = new double[3] { 0, 0, 0}; EnableTicketLossRateLogging = false; SpellingOfSpeedNamesReminder = Speed.Click_Here_For_Speed_Names; EarlyPhaseBalanceSpeed = new Speed[3] { Speed.Fast, Speed.Adaptive, Speed.Adaptive}; MidPhaseBalanceSpeed = new Speed[3] { Speed.Fast, Speed.Adaptive, Speed.Adaptive}; LatePhaseBalanceSpeed = new Speed[3] { Speed.Stop, Speed.Stop, Speed.Stop}; /* ===== SECTION 4 - Scrambler ===== */ OnlyOnNewMaps = true; // false means scramble every round OnlyOnFinalTicketPercentage = 120; // 0 means scramble regardless of final score ScrambleBy = DefineStrong.RoundScore; KeepSquadsTogether = true; KeepClanTagsInSameTeam = true; KeepFriendsInSameTeam = false; DivideBy = DivideByChoices.None; ClanTagToDivideBy = String.Empty; DelaySeconds = 50; /* ===== SECTION 5 - Messages ===== */ QuietMode = false; // false: chat is global, true: chat is private. Yells are always private YellDurationSeconds = 10; BadBecauseMovedByBalancer = "autobalance moved you to the %toTeam% team"; BadBecauseWinningTeam = "switching to the winning team is not allowed"; BadBecauseBiggestTeam = "switching to the biggest team is not allowed"; BadBecauseRank = "this server splits Colonel 100's between teams"; BadBecauseDispersalList = "you're on the list of players to split between teams"; ChatMovedForBalance = "*** MOVED %name% for balance ..."; YellMovedForBalance = "Moved %name% for balance ..."; ChatMovedToUnstack = "*** MOVED %name% to unstack teams ..."; YellMovedToUnstack = "Moved %name% to unstack teams ..."; ChatDetectedBadTeamSwitch = "%name%, you can't switch to team %fromTeam%: %reason%, sending you back ..."; YellDetectedBadTeamSwitch = "You can't switch to the %fromTeam% team: %reason%, sending you back!"; ChatDetectedGoodTeamSwitch = "%name%, thanks for helping out the %toTeam% team!"; YellDetectedGoodTeamSwitch = "Thanks for helping out the %toTeam% team!"; ChatAfterUnswitching = "%name%, please stay on the %toTeam% team for the rest of this round"; YellAfterUnswitching = "Please stay on the %toTeam% team for the rest of this round"; /* ===== SECTION 6 - Unswitcher ===== */ EnableImmediateUnswitch = true; ForbidSwitchingAfterAutobalance = UnswitchChoice.Always; ForbidSwitchingToWinningTeam = UnswitchChoice.Always; ForbidSwitchingToBiggestTeam = UnswitchChoice.Always; ForbidSwitchingAfterDispersal = UnswitchChoice.Always; /* ===== SECTION 7 - TBD ===== */ /* ===== SECTION 8 - Per-Mode Settings ===== */ /* ===== SECTION 9 - Debug Settings ===== */ ShowInLog = INVALID_NAME_TAG_GUID; ShowCommandInLog = String.Empty; LogChat = true; EnableLoggingOnlyMode = false; EnableExternalLogging = false; ExternalLogSuffix = "_mb.log"; }
private DelayedRequest AddTimedRequest(String name, double maxDelay, Action<DateTime> request) { DelayedRequest r = null; lock (fTimerRequestList) { foreach (DelayedRequest old in fTimerRequestList) { if (!String.IsNullOrEmpty(old.Name) && !String.IsNullOrEmpty(name) && old.Name == name) { ConsoleDebug("ASSERT AddTimedRequest: request with name ^b" + name + "^n already exists, skipping!"); return null; } } r = new DelayedRequest(); r.Name = name; r.MaxDelay = maxDelay; r.LastUpdate = DateTime.MinValue; r.Request = request; ConsoleDebug("Added: " + name); fTimerRequestList.Add(r); } return r; }
private void SetupUpdateTicketsRequest() { if (fUpdateTicketsRequest != null) return; fUpdateTicketsRequest = AddTimedRequest("Update serverInfo every 5 seconds", 5.0, delegate(DateTime now) { try { if (fGameState == GameState.Playing && TotalPlayerCount >= 4) ServerCommand("serverInfo"); } catch (Exception) {} }); }