public void ActOnInMessage(IConMessage comMsg) { HubMessage message = (HubMessage)comMsg; if (message is MainChat) { MainChat main = (MainChat)message; MainMessage msg = new MainMessage(main.From, main.Content); Update(hub, new FmdcEventArgs(Actions.MainMessage, msg)); } else if (message is To) { To to = (To)message; PrivateMessage pm = new PrivateMessage(to.To, to.From, to.Content); Update(hub, new FmdcEventArgs(Actions.PrivateMessage, pm)); } else if (message is SR) { SR searchResult = (SR)message; SearchResultInfo srinfo = new SearchResultInfo(searchResult.Info, searchResult.From); Update(hub, new FmdcEventArgs(Actions.SearchResult, srinfo)); } else if (message is Search) { Search search = (Search)message; if (hub.Share == null) { return; } int maxReturns = 5; bool active = false; if (search.Address != null) { maxReturns = 10; active = true; } System.Collections.Generic.List <ContentInfo> ret = new System.Collections.Generic.List <ContentInfo>(maxReturns); // TODO : This lookup can be done nicer lock (hub.Share) { foreach (System.Collections.Generic.KeyValuePair <string, Containers.ContentInfo> var in hub.Share) { if (var.Value == null) { continue; } bool foundEnough = false; string ext = search.Info.Get(SearchInfo.EXTENTION); string sch = search.Info.Get(SearchInfo.SEARCH); if (ext != null && sch != null) { ContentInfo contentInfo = new ContentInfo(); if (search.Info.ContainsKey(SearchInfo.TYPE)) { switch (search.Info.Get(SearchInfo.TYPE)) { case "2": contentInfo.Set(ContentInfo.TTH, search.Info.Get(SearchInfo.SEARCH)); if (hub.Share.ContainsContent(ref contentInfo)) { ret.Add(contentInfo); } // We are looking through whole share here. // If no TTH matching. Ignore. foundEnough = true; break; case "1": default: if (var.Value.ContainsKey(ContentInfo.VIRTUAL) && (System.IO.Path.GetDirectoryName(var.Value.Get(ContentInfo.VIRTUAL)).IndexOf(sch, System.StringComparison.OrdinalIgnoreCase) != -1)) { ret.Add(var.Value); } break; } } if (!foundEnough) { string infoExt = System.IO.Path.GetExtension(var.Value.Get(ContentInfo.VIRTUAL)).TrimStart('.'); if ( var.Value.ContainsKey(ContentInfo.VIRTUAL) && (var.Value.Get(ContentInfo.VIRTUAL).IndexOf(sch, System.StringComparison.OrdinalIgnoreCase) != -1) && (ext.Length == 0 || ext.Contains(infoExt)) ) { ret.Add(var.Value); } } } if (foundEnough || ret.Count >= maxReturns) { break; } } } // Test against size restrictions for (int i = 0; i < ret.Count; i++) { bool send = true; long size = -1; try { size = int.Parse(search.Info.Get(SearchInfo.SIZE)); } catch { } if (search.Info.ContainsKey(SearchInfo.SIZETYPE) && size != -1) { switch (search.Info.Get(SearchInfo.SIZETYPE)) { case "1": // Min Size send = (size <= ret[i].Size); break; case "2": // Max Size send = (size >= ret[i].Size); break; case "3": // Equal Size send = (size == ret[i].Size); break; } } // Should this be sent? if (send) { SR sr = new SR(hub, ret[i], (search.Info.ContainsKey(SearchInfo.EXTENTION) ? search.Info.Get(SearchInfo.EXTENTION).Equals("$0") : false), search.From); if (active) { // Send with UDP UdpConnection.Send(sr, search.Address); } else { // Send through hub hub.Send(sr); } } } } else if (message is Lock) { hub.Send(new Supports(hub)); hub.Send(new Key(hub, ((Lock)message).Key)); hub.Send(new ValidateNick(hub)); } else if (message is HubNmdc.HubName) { HubNmdc.HubName hubname = (HubNmdc.HubName)message; Containers.HubName name = null; if (hubname.Topic != null) { name = new Containers.HubName(hubname.Name, hubname.Topic); } else { name = new Containers.HubName(hubname.Content); } Update(hub, new FmdcEventArgs(Actions.Name, name)); } else if (message is NickList) { NickList nicks = (NickList)message; foreach (string userid in nicks.List) { UserInfo userInfo = new UserInfo(); userInfo.DisplayName = userid; userInfo.Set(UserInfo.STOREID, hub.HubSetting.Address + hub.HubSetting.Port.ToString() + userid); if (hub.GetUserById(userid) == null) { Update(hub, new FmdcEventArgs(Actions.UserOnline, userInfo)); } } } else if (message is OpList) { OpList ops = (OpList)message; foreach (string userid in ops.List) { UserInfo userInfo = new UserInfo(); userInfo.DisplayName = userid; userInfo.Set(UserInfo.STOREID, hub.HubSetting.Address + hub.HubSetting.Port.ToString() + userid); userInfo.IsOperator = true; User usr = null; if ((usr = hub.GetUserById(userid)) == null) { Update(hub, new FmdcEventArgs(Actions.UserOnline, userInfo)); } else { usr.UserInfo = userInfo; Update(hub, new FmdcEventArgs(Actions.UserInfoChange, usr.UserInfo)); } } } else if (message is Quit) { Quit quit = (Quit)message; User usr = null; if ((usr = hub.GetUserById(quit.From)) != null) { Update(hub, new FmdcEventArgs(Actions.UserOffline, usr.UserInfo)); } } else if (message is LogedIn) { hub.RegMode = 2; } else if (message is ValidateDenide) { Update(hub, new FmdcEventArgs(Actions.StatusChange, new HubStatus(HubStatus.Codes.Disconnected))); } else if (message is GetPass) { hub.RegMode = 1; if (hub.HubSetting.Password.Length == 0) { Update(hub, new FmdcEventArgs(Actions.Password, null)); } else { hub.Send(new MyPass(hub)); } } else if (message is MyINFO) { MyINFO myinfo = (MyINFO)message; User usr = null; if ((usr = hub.GetUserById(message.From)) == null) { Update(hub, new FmdcEventArgs(Actions.UserOnline, myinfo.UserInfo)); } else { bool op = usr.IsOperator; usr.UserInfo = myinfo.UserInfo; usr.UserInfo.IsOperator = op; Update(hub, new FmdcEventArgs(Actions.UserInfoChange, usr.UserInfo)); } } else if (message is Hello) { if (hub.HubSetting.DisplayName.Equals(message.From)) { hub.Send(new Version(hub)); hub.Send(new GetNickList(hub)); if (hub.RegMode < 0) { hub.RegMode = 0; } UpdateMyInfo(); } } else if (message is ConnectToMe) { ConnectToMe conToMe = (ConnectToMe)message; Transfer trans = new Transfer(conToMe.Address, conToMe.Port); trans.Share = this.hub.Share; trans.Me = hub.Me; trans.Source = new Source(hub.RemoteAddress.ToString(), null); // Protocol has to be set last. trans.Protocol = new TransferNmdcProtocol(trans); #if !COMPACT_FRAMEWORK if (conToMe.TLS && hub.Me.ContainsKey(UserInfo.SECURE)) { trans.SecureProtocol = SecureProtocols.TLS; } #endif Update(hub, new FmdcEventArgs(Actions.TransferStarted, trans)); } else if (message is RevConnectToMe) { RevConnectToMe revConToMe = (RevConnectToMe)message; User usr = null; usr = hub.GetUserById(revConToMe.From); if (hub.Me.Mode == FlowLib.Enums.ConnectionTypes.Passive) { if (usr != null) { // If user are not set as passive. Set it as it and respond with a revconnect. if (usr.UserInfo.Mode != FlowLib.Enums.ConnectionTypes.Passive) { usr.UserInfo.Mode = FlowLib.Enums.ConnectionTypes.Passive; hub.Send(new RevConnectToMe(revConToMe.From, hub)); } } } else { if (usr != null) { Update(hub, new FmdcEventArgs(Actions.TransferRequest, new TransferRequest(usr.ID, hub, usr.UserInfo))); #if !COMPACT_FRAMEWORK // Security, Windows Mobile doesnt support SSLStream so we disable this feature for it. if ( usr.UserInfo.ContainsKey(UserInfo.SECURE) && hub.Me.ContainsKey(UserInfo.SECURE) && !string.IsNullOrEmpty(hub.Me.Get(UserInfo.SECURE)) ) { hub.Send(new ConnectToMe(usr.ID, hub.Share.Port, hub, SecureProtocols.TLS)); } else #endif hub.Send(new ConnectToMe(usr.ID, hub.Share.Port, hub)); } } } else if (message is ForceMove) { ForceMove forceMove = (ForceMove)message; hub.Disconnect(); Update(hub, new FmdcEventArgs(Actions.Redirect, new RedirectInfo(forceMove.Address))); } }
/* Constructor */ public MULTIbalancer() { /* Private members */ fIsEnabled = false; fFinalizerActive = false; fAborted = 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; fPlayerCount = 0; fBF4CommanderCount = 0; fBF4SpectatorCount = 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[11]{"MP_007", "XP4_Quake", "XP5_002", "MP_012", "XP4_Rubble", "MP_Damage", "XP0_Caspian", "XP0_Firestorm", "XP1_001" /* BF4 */, "XP1_003" /* BF4 */, "XP2_003"}); 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(); fFactionByTeam = new int[5]{-1,-1,-1,-1,-1}; fRevealSettings = false; fShowRiskySettings = false; fLastFastMoveTimestamp = DateTime.MinValue; fRoundTimeLimit = 1.0; fScrambleByCommand = false; fDisableUnswitcherByRemote = false; fLastAutoChatTimestamp = DateTime.MinValue; /* Settings */ /* ===== SECTION 0 - Presets ===== */ SettingsVersion = 1; Preset = PresetItems.Standard; EnableUnstacking = false; EnableAdminKillForFastBalance = false; SelectFastBalanceBy = ForceMove.Newest; 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; ReassignNewPlayers = true; EnableTicketLossRateLogging = false; /* ===== 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}; 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 ===== */ OnlyByCommand = false; 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 high rank players between teams"; BadBecauseDispersalList = "you're on the list of players to split between teams"; BadBecauseClan = "players with same clan tags are split up"; // DCE 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"; TeamsWillBeScrambled = "*** Teams will be SCRAMBLED next round!"; ChatAutobalancing = "Preparing to autobalance ... (%technicalDetails%)"; YellAutobalancing = String.Empty; // no yell by default /* ===== 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"; EnableRiskyFeatures = false; }
protected HubMessage ParseMessage(string raw) { raw = raw.Replace(this.Seperator, ""); HubMessage msg = new HubMessage(hub, raw); if (!string.IsNullOrEmpty(raw)) { switch (raw[0]) { case '$': int pos; string cmd = null; if ((pos = raw.IndexOf(' ')) != -1) { cmd = raw.Substring(0, pos).ToLower(); } else { if (raw.Length >= 10) { break; } cmd = raw.ToLower(); } if (cmd == null || cmd.Equals(string.Empty)) { break; } switch (cmd) { case "$lock": msg = new Lock(hub, raw); break; case "$supports": msg = new Supports(hub, raw); break; case "$hubname": msg = new HubNmdc.HubName(hub, raw); break; case "$hello": msg = new Hello(hub, raw); break; case "$myinfo": msg = new MyINFO(hub, raw); break; case "$nicklist": msg = new NickList(hub, raw); break; case "$oplist": msg = new OpList(hub, raw); break; case "$to:": msg = new To(hub, raw); break; case "$quit": msg = new Quit(hub, raw); break; case "$getpass": msg = new GetPass(hub, raw); break; case "$logedin": msg = new LogedIn(hub, raw); break; case "$validatedenide": msg = new ValidateDenide(hub, raw); break; case "$forcemove": msg = new ForceMove(hub, raw); break; case "$connecttome": msg = new ConnectToMe(hub, raw); break; case "$revconnecttome": msg = new RevConnectToMe(hub, raw); break; case "$search": msg = new Search(hub, raw); break; case "$sr": msg = new SR(hub, raw); break; } break; default: // No command. Assume MainChat. msg = new MainChat(hub, raw); break; } } return(msg); }
private void ResetSettings() { MULTIbalancer rhs = new MULTIbalancer(); /* ===== SECTION 0 - Presets ===== */ Preset = rhs.Preset; // EnableUnstacking = rhs.EnableUnstacking; // don't reset EnableUnstacking EnableAdminKillForFastBalance = rhs.EnableAdminKillForFastBalance; SelectFastBalanceBy = rhs.SelectFastBalanceBy; /* ===== SECTION 1 - Settings ===== */ DebugLevel = rhs.DebugLevel; MaximumServerSize = rhs.MaximumServerSize; EnableBattlelogRequests = rhs.EnableBattlelogRequests; MaximumRequestRate = rhs.MaximumRequestRate; WaitTimeout = rhs.WaitTimeout; WhichBattlelogStats = rhs.WhichBattlelogStats; MaxTeamSwitchesByStrongPlayers = rhs.MaxTeamSwitchesByStrongPlayers; MaxTeamSwitchesByWeakPlayers = rhs.MaxTeamSwitchesByWeakPlayers; UnlimitedTeamSwitchingDuringFirstMinutesOfRound = rhs.UnlimitedTeamSwitchingDuringFirstMinutesOfRound; Enable2SlotReserve = rhs.Enable2SlotReserve; EnablerecruitCommand = rhs.EnablerecruitCommand; EnableWhitelistingOfReservedSlotsList = rhs.EnableWhitelistingOfReservedSlotsList; SecondsUntilAdaptiveSpeedBecomesFast = rhs.SecondsUntilAdaptiveSpeedBecomesFast; EnableInGameCommands = rhs.EnableInGameCommands; ReassignNewPlayers = rhs.ReassignNewPlayers; // Whitelist = rhs.Whitelist; // don't reset the whitelist // DisperseEvenlyList = rhs.DisperseEvenlyList; // don't reset the dispersal list EnableTicketLossRateLogging = rhs.EnableTicketLossRateLogging; /* ===== SECTION 2 - Exclusions ===== */ OnWhitelist = rhs.OnWhitelist; OnFriendsList = rhs.OnFriendsList; ApplyFriendsListToTeam = rhs.ApplyFriendsListToTeam; TopScorers = rhs.TopScorers; SameClanTagsInSquad = rhs.SameClanTagsInSquad; SameClanTagsInTeam = rhs.SameClanTagsInTeam; SameClanTagsForRankDispersal = rhs.SameClanTagsForRankDispersal; LenientRankDispersal = rhs.LenientRankDispersal; MinutesAfterJoining = rhs.MinutesAfterJoining; MinutesAfterBeingMoved = rhs.MinutesAfterBeingMoved; JoinedEarlyPhase = rhs.JoinedEarlyPhase; JoinedMidPhase = rhs.JoinedMidPhase; JoinedLatePhase = rhs.JoinedLatePhase; /* ===== SECTION 3 - Round Phase & Population Settings ===== */ EarlyPhaseTicketPercentageToUnstack = rhs.EarlyPhaseTicketPercentageToUnstack; MidPhaseTicketPercentageToUnstack = rhs.MidPhaseTicketPercentageToUnstack; LatePhaseTicketPercentageToUnstack = rhs.LatePhaseTicketPercentageToUnstack; SpellingOfSpeedNamesReminder = rhs.SpellingOfSpeedNamesReminder; EarlyPhaseBalanceSpeed = rhs.EarlyPhaseBalanceSpeed; MidPhaseBalanceSpeed = rhs.MidPhaseBalanceSpeed; LatePhaseBalanceSpeed = rhs.LatePhaseBalanceSpeed; /* ===== SECTION 4 - Scrambler ===== */ OnlyByCommand = rhs.OnlyByCommand; OnlyOnNewMaps = rhs.OnlyOnNewMaps; OnlyOnFinalTicketPercentage = rhs.OnlyOnFinalTicketPercentage; ScrambleBy = rhs.ScrambleBy; KeepClanTagsInSameTeam = rhs.KeepClanTagsInSameTeam; KeepFriendsInSameTeam = rhs.KeepFriendsInSameTeam; DivideBy = rhs.DivideBy; ClanTagToDivideBy = rhs.ClanTagToDivideBy; DelaySeconds = rhs.DelaySeconds; /* ===== SECTION 5 - Messages ===== */ QuietMode = rhs.QuietMode; YellDurationSeconds = rhs.YellDurationSeconds; BadBecauseMovedByBalancer = rhs.BadBecauseMovedByBalancer; BadBecauseWinningTeam = rhs.BadBecauseWinningTeam; BadBecauseBiggestTeam = rhs.BadBecauseBiggestTeam; BadBecauseRank = rhs.BadBecauseRank; BadBecauseDispersalList = rhs.BadBecauseDispersalList; BadBecauseClan = rhs.BadBecauseClan; // DCE ChatMovedForBalance = rhs.ChatMovedForBalance; YellMovedForBalance = rhs.YellMovedForBalance; ChatMovedToUnstack = rhs.ChatMovedToUnstack; YellMovedToUnstack = rhs.YellMovedToUnstack; ChatDetectedBadTeamSwitch = rhs.ChatDetectedBadTeamSwitch; YellDetectedBadTeamSwitch = rhs.YellDetectedBadTeamSwitch; ChatDetectedGoodTeamSwitch = rhs.ChatDetectedGoodTeamSwitch; YellDetectedGoodTeamSwitch = rhs.YellDetectedGoodTeamSwitch; ChatAfterUnswitching = rhs.ChatAfterUnswitching; YellAfterUnswitching = rhs.YellAfterUnswitching; TeamsWillBeScrambled = rhs.TeamsWillBeScrambled; ChatAutobalancing = rhs.ChatAutobalancing; YellAutobalancing = rhs.YellAutobalancing; /* ===== SECTION 6 - Unswitcher ===== */ ForbidSwitchingAfterAutobalance = rhs.ForbidSwitchingAfterAutobalance; ForbidSwitchingToWinningTeam = rhs.ForbidSwitchingToWinningTeam; ForbidSwitchingToBiggestTeam = rhs.ForbidSwitchingToBiggestTeam; ForbidSwitchingAfterDispersal = rhs.ForbidSwitchingAfterDispersal; EnableImmediateUnswitch = rhs.EnableImmediateUnswitch; /* ===== SECTION 7 - TBD ===== */ /* ===== SECTION 8 - Per-Mode Settings ===== */ List<String> simpleModes = GetSimplifiedModes(); fPerMode.Clear(); foreach (String sm in simpleModes) { PerModeSettings oneSet = null; if (!fPerMode.ContainsKey(sm)) { oneSet = new PerModeSettings(sm, fGameVersion); fPerMode[sm] = oneSet; } } /* ===== SECTION 9 - Debug Settings ===== */ ShowCommandInLog = rhs.ShowCommandInLog; LogChat = rhs.LogChat; EnableLoggingOnlyMode = rhs.EnableLoggingOnlyMode; EnableRiskyFeatures = rhs.EnableRiskyFeatures; }