diff --git a/Nuclei/Events/ServerEvents.cs b/Nuclei/Events/ServerEvents.cs index 7ff1cd1..bc7d6fb 100644 --- a/Nuclei/Events/ServerEvents.cs +++ b/Nuclei/Events/ServerEvents.cs @@ -1,4 +1,5 @@ using System; +using Nuclei.Features; namespace Nuclei.Events; @@ -15,6 +16,7 @@ public static class ServerEvents internal static void OnServerStarted() { ServerStarted?.Invoke(); + TimeService.Initialize(); } /// @@ -26,4 +28,4 @@ internal static void OnServerStopped() { ServerStopped?.Invoke(); } -} \ No newline at end of file +} diff --git a/Nuclei/Events/TimeEvents.cs b/Nuclei/Events/TimeEvents.cs index 17b4e69..9db5e98 100644 --- a/Nuclei/Events/TimeEvents.cs +++ b/Nuclei/Events/TimeEvents.cs @@ -1,4 +1,5 @@ using System; +using Nuclei.Features; namespace Nuclei.Events; @@ -57,6 +58,7 @@ internal static void OnEveryMinute() internal static void OnEvery10Minutes() { Every10Minutes?.Invoke(); + AutoBalanceService.BalanceTeams(); } internal static void OnEvery30Minutes() diff --git a/Nuclei/Features/AutoBalanceService.cs b/Nuclei/Features/AutoBalanceService.cs new file mode 100644 index 0000000..649c50f --- /dev/null +++ b/Nuclei/Features/AutoBalanceService.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using NuclearOption.Networking; + +namespace Nuclei.Features; + +// Used with a timer service, it will check and balance team player count +public static class AutoBalanceService +{ + public static bool BalanceTeams() + { + var HQs = FactionRegistry.GetAllHQs().ToList(); + + // new List<> required due to bug in GetPlayers() code if called multiple times + var faction1Players = new List(HQs[0].GetPlayers(false)); + var faction2Players = new List(HQs[1].GetPlayers(false)); + + double faction1PlayersCount = faction1Players.Count; + double faction2PlayersCount = faction2Players.Count; + + double totalPlayers = faction1PlayersCount + faction2PlayersCount; + + if (HQs[0].preventJoin || HQs[1].preventJoin) return false; // If co-op, don't balance + + //get % of players of total for each faction + double faction1Ratio = faction1PlayersCount / totalPlayers; + double faction2Ratio = faction2PlayersCount / totalPlayers; + + // if the difference btwn the %'s is greater than the ratioMinimum, commence auto-balance + // TODO: Make this configurable via Nuclei.Config + double ratioMinimum = .10; + double factionRatioDifference = Math.Abs(faction1Ratio - faction2Ratio); + + if (factionRatioDifference > ratioMinimum) + { + // dont balance if ratio reaches threshold but team is only diff by 1 players + if (faction1PlayersCount - faction2PlayersCount == 1) return false; + + + // Formula meaning: Get the % of players, where % is the ratio difference. This number + // is max players needed to move, except you need to div by 2 because each player moved + // moves the ratio diff 2x. + var numPlayersToMove = (int)(factionRatioDifference * totalPlayers / 2); + + // Autobalance players from faction 1 to faction 2 + if (faction1PlayersCount > faction2PlayersCount) + { + MovePlayers(numPlayersToMove, faction1Players, HQs[1]); + return true; + } + // Autobalance players from faction 2 to faction 1 + else + { + + MovePlayers(numPlayersToMove, faction2Players, HQs[0]); + return true; + } + } + else return false; + } + + private static void MovePlayers(int numPlayersToMove, List factionPlayers, FactionHQ factionToSet) + { + int factionPlayerCount = factionPlayers.Count; + ChatService.SendChatMessage($"movePlayers factionPlayerCount: {factionPlayerCount}"); + HashSet indices = []; + Random rnd = new(); + for (int i = 0; i < numPlayersToMove; i++) + { + if (!indices.Add(rnd.Next(0, factionPlayerCount))) + i--; // redo if random num generated is already in hashset + } + + foreach (var x in indices) + { + + // TODO: FIND WAY TO CHANGE FACTION MID GAME. functions below do not work + //factionPlayers[x].SetFaction(factionToSet); + //factionToSet.AddPlayer(factionPlayers[x]); + } + } +} diff --git a/Nuclei/Features/MissionService.cs b/Nuclei/Features/MissionService.cs index 49ea733..336d2e6 100644 --- a/Nuclei/Features/MissionService.cs +++ b/Nuclei/Features/MissionService.cs @@ -47,7 +47,7 @@ public static class MissionService /// /// The current mission time. /// - public static float CurrentMissionTime => Globals.MissionManagerInstance.missionTime; + public static float CurrentMissionTime => Globals.MissionManagerInstance.MissionTime; /// /// Gets all Mission Keys as an IEnumerable. diff --git a/Nuclei/Features/TimeService.cs b/Nuclei/Features/TimeService.cs index 885c8f3..d0e3c42 100644 --- a/Nuclei/Features/TimeService.cs +++ b/Nuclei/Features/TimeService.cs @@ -54,6 +54,15 @@ private void FixedUpdate() _lastTime = currentTime; TimeEvents.OnEverySecond(); + + + // MoTD + var motdFreq = NucleiConfig.MotDFrequency!.Value; + if (currentTime % motdFreq == 0) + { + ChatService.SendMotD(); + } + if (currentTime % 3600 == 0) { TimeEvents.OnEveryHour(); @@ -85,4 +94,4 @@ private void FixedUpdate() TimeEvents.OnEvery30Seconds(); } } -} \ No newline at end of file +}