From b44b9a0dcb6247597399267a2e01bef34c95516d Mon Sep 17 00:00:00 2001 From: James Armstrong Date: Mon, 29 Dec 2025 12:13:00 -0800 Subject: [PATCH 1/8] Add rank catchup system --- Nuclei/Events/PlayerEvents.cs | 2 ++ Nuclei/Features/RankCatchUpService.cs | 41 +++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 Nuclei/Features/RankCatchUpService.cs diff --git a/Nuclei/Events/PlayerEvents.cs b/Nuclei/Events/PlayerEvents.cs index dae0291..abae35d 100644 --- a/Nuclei/Events/PlayerEvents.cs +++ b/Nuclei/Events/PlayerEvents.cs @@ -1,5 +1,6 @@ using System; using NuclearOption.Networking; +using Nuclei.Features; namespace Nuclei.Events; @@ -16,6 +17,7 @@ public static class PlayerEvents internal static void OnPlayerJoined(Player e) { PlayerJoined?.Invoke(e); + RankCatchUpService.CatchUpPlayer(e); } /// diff --git a/Nuclei/Features/RankCatchUpService.cs b/Nuclei/Features/RankCatchUpService.cs new file mode 100644 index 0000000..7539cfe --- /dev/null +++ b/Nuclei/Features/RankCatchUpService.cs @@ -0,0 +1,41 @@ +using NuclearOption.Networking; +using Nuclei.Helpers; +using UnityEngine; +namespace Nuclei.Features; + +public class RankCatchUpService +{ + public static void CatchUpPlayer(Player player) + { + var currentMissionTime = Time.timeSinceLevelLoad; + var maxMissionTime = Globals.DedicatedServerManagerInstance.CurrentMissionOption.MaxTime; + var percentComplete = currentMissionTime / maxMissionTime; + + if (percentComplete < .20) return; + else if (percentComplete >= .80) + { + player.SetRank(5, false); + player.SetAllocation(player.Allocation + 300f); + } + else if (percentComplete >= .60) + { + player.SetRank(4, false); + player.SetAllocation(player.Allocation + 250f); + } + else if (percentComplete >= .40) + { + player.SetRank(3, false); + player.SetAllocation(player.Allocation + 200f); + } + else if (percentComplete >= .40) + { + player.SetRank(2, false); + player.SetAllocation(player.Allocation + 150f); + } + else if (percentComplete >= .20) + { + player.SetRank(1, false); + player.SetAllocation(player.Allocation + 100); + } + } +} \ No newline at end of file From 42db5dcdbe96b1ac490466f13dd353feaf00db5d Mon Sep 17 00:00:00 2001 From: James Armstrong Date: Tue, 30 Dec 2025 15:10:43 -0800 Subject: [PATCH 2/8] Add check in case they rejoin --- Nuclei/Features/RankCatchUpService.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Nuclei/Features/RankCatchUpService.cs b/Nuclei/Features/RankCatchUpService.cs index 7539cfe..e620ed9 100644 --- a/Nuclei/Features/RankCatchUpService.cs +++ b/Nuclei/Features/RankCatchUpService.cs @@ -7,10 +7,16 @@ public class RankCatchUpService { public static void CatchUpPlayer(Player player) { + if (player.PlayerRank != 0) + { + Nuclei.Logger?.LogDebug($"Player {player.PlayerName} already has rank {player.PlayerRank}, skipping catch-up."); + return; + } var currentMissionTime = Time.timeSinceLevelLoad; var maxMissionTime = Globals.DedicatedServerManagerInstance.CurrentMissionOption.MaxTime; var percentComplete = currentMissionTime / maxMissionTime; + if (percentComplete < .20) return; else if (percentComplete >= .80) { From bdc24adae29aa52aa89ca66c4217cf33497c6936 Mon Sep 17 00:00:00 2001 From: James Armstrong Date: Tue, 30 Dec 2025 16:11:47 -0800 Subject: [PATCH 3/8] Improve help command listing --- Nuclei/Features/Commands/DefaultCommands/HelpCommand.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Nuclei/Features/Commands/DefaultCommands/HelpCommand.cs b/Nuclei/Features/Commands/DefaultCommands/HelpCommand.cs index 5466059..b94b362 100644 --- a/Nuclei/Features/Commands/DefaultCommands/HelpCommand.cs +++ b/Nuclei/Features/Commands/DefaultCommands/HelpCommand.cs @@ -26,7 +26,12 @@ public override bool Execute(Player player, string[] args) { var accessibleCommands = CommandService.GetCommands().Where(c => c.PermissionLevel <= CommandService.GetPlayerPermissionLevel(player)).ToList(); var commandNames = accessibleCommands.Select(c => c.Name).ToList(); - ChatService.SendPrivateChatMessage($"You have access to the following commands: {string.Join(", ", commandNames)}", player); + ChatService.SendPrivateChatMessage($"You have access to the following commands:", player); + ChatService.SendPrivateChatMessage($"(For more help, type {NucleiConfig.CommandPrefixChar}{Usage})", player); + foreach (var cmd in commandNames) + { + ChatService.SendPrivateChatMessage($"{cmd}", player); + } return true; } From aeca9c05f3931e23f28db433df41f606bfed3976 Mon Sep 17 00:00:00 2001 From: James Armstrong Date: Wed, 31 Dec 2025 00:09:38 -0800 Subject: [PATCH 4/8] Provide cmd descriptions when calling /help --- Nuclei/Features/Commands/DefaultCommands/HelpCommand.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Nuclei/Features/Commands/DefaultCommands/HelpCommand.cs b/Nuclei/Features/Commands/DefaultCommands/HelpCommand.cs index b94b362..07fa4fb 100644 --- a/Nuclei/Features/Commands/DefaultCommands/HelpCommand.cs +++ b/Nuclei/Features/Commands/DefaultCommands/HelpCommand.cs @@ -25,12 +25,12 @@ public override bool Execute(Player player, string[] args) if (args.Length == 0) { var accessibleCommands = CommandService.GetCommands().Where(c => c.PermissionLevel <= CommandService.GetPlayerPermissionLevel(player)).ToList(); - var commandNames = accessibleCommands.Select(c => c.Name).ToList(); + var commands = accessibleCommands.ToList(); ChatService.SendPrivateChatMessage($"You have access to the following commands:", player); ChatService.SendPrivateChatMessage($"(For more help, type {NucleiConfig.CommandPrefixChar}{Usage})", player); - foreach (var cmd in commandNames) + foreach (var cmd in commands) { - ChatService.SendPrivateChatMessage($"{cmd}", player); + ChatService.SendPrivateChatMessage($"{cmd.Name} - {cmd.Description}", player); } return true; } From 54d1edb02a4537aa1991b4d9c462f891bf44602c Mon Sep 17 00:00:00 2001 From: James Armstrong Date: Wed, 31 Dec 2025 00:41:08 -0800 Subject: [PATCH 5/8] Fix verification --- Nuclei/Features/RankCatchUpService.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Nuclei/Features/RankCatchUpService.cs b/Nuclei/Features/RankCatchUpService.cs index e620ed9..03a1221 100644 --- a/Nuclei/Features/RankCatchUpService.cs +++ b/Nuclei/Features/RankCatchUpService.cs @@ -7,10 +7,9 @@ public class RankCatchUpService { public static void CatchUpPlayer(Player player) { - if (player.PlayerRank != 0) + if (player.GetAuthData().SaveData.Faction != null) { - Nuclei.Logger?.LogDebug($"Player {player.PlayerName} already has rank {player.PlayerRank}, skipping catch-up."); - return; + return; // Means that they already joined the server. No double-dipping! } var currentMissionTime = Time.timeSinceLevelLoad; var maxMissionTime = Globals.DedicatedServerManagerInstance.CurrentMissionOption.MaxTime; @@ -41,7 +40,7 @@ public static void CatchUpPlayer(Player player) else if (percentComplete >= .20) { player.SetRank(1, false); - player.SetAllocation(player.Allocation + 100); + player.SetAllocation(player.Allocation + 100f); } } } \ No newline at end of file From 8b7469974f6cd6f510b0bbcb1e8c58788d5fae29 Mon Sep 17 00:00:00 2001 From: James Armstrong Date: Thu, 1 Jan 2026 21:17:53 -0800 Subject: [PATCH 6/8] Make catchup toggleable via config --- Nuclei/Events/PlayerEvents.cs | 2 +- Nuclei/Features/NucleiConfig.cs | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Nuclei/Events/PlayerEvents.cs b/Nuclei/Events/PlayerEvents.cs index abae35d..b86cbf0 100644 --- a/Nuclei/Events/PlayerEvents.cs +++ b/Nuclei/Events/PlayerEvents.cs @@ -17,7 +17,7 @@ public static class PlayerEvents internal static void OnPlayerJoined(Player e) { PlayerJoined?.Invoke(e); - RankCatchUpService.CatchUpPlayer(e); + if (NucleiConfig.RankCatchUp!.Value) RankCatchUpService.CatchUpPlayer(e); } /// diff --git a/Nuclei/Features/NucleiConfig.cs b/Nuclei/Features/NucleiConfig.cs index 6acfb49..45aa26e 100644 --- a/Nuclei/Features/NucleiConfig.cs +++ b/Nuclei/Features/NucleiConfig.cs @@ -83,6 +83,8 @@ public static class NucleiConfig internal static ConfigEntry? CommandPrefix; internal const string DefaultCommandPrefix = "/"; + internal static ConfigEntry? RankCatchUp; + internal const bool DefaultRankCatchUp = true; internal static List ModeratorsList => Moderators!.Value.Split(';').Where(m => !string.IsNullOrWhiteSpace(m)).ToList(); @@ -164,6 +166,9 @@ internal static void InitSettings(ConfigFile config) CommandPrefix = config.Bind(GeneralSection, "CommandPrefix", DefaultCommandPrefix, "What to use as the command prefix (the character at the start of a command)."); Nuclei.Logger?.LogDebug($"CommandPrefix: {CommandPrefix.Value}"); + + RankCatchUp = config.Bind(GeneralSection, "RankCatchUp", DefaultRankCatchUp, "Whether to enable the rank catch-up system, which gives players a rank and allocation boost based on how far into the mission they join."); + Nuclei.Logger?.LogDebug($"RankCatchUp: {RankCatchUp.Value}"); Nuclei.Logger?.LogDebug("Loaded settings!"); } From 1f23df9a7091d00937b11ead3c79e07cddfcca66 Mon Sep 17 00:00:00 2001 From: jmarmstrong1207 Date: Tue, 6 Jan 2026 14:40:55 -0800 Subject: [PATCH 7/8] Send usage string when doing /help --- Nuclei/Features/Commands/DefaultCommands/HelpCommand.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Nuclei/Features/Commands/DefaultCommands/HelpCommand.cs b/Nuclei/Features/Commands/DefaultCommands/HelpCommand.cs index 07fa4fb..4679f2f 100644 --- a/Nuclei/Features/Commands/DefaultCommands/HelpCommand.cs +++ b/Nuclei/Features/Commands/DefaultCommands/HelpCommand.cs @@ -43,6 +43,7 @@ public override bool Execute(Player player, string[] args) } ChatService.SendPrivateChatMessage($"Command '{command.Name}': {command.Description}", player); + ChatService.SendPrivateChatMessage($"Usage: {command.Usage}", player); return true; } From 64f92e5c4de6e755d68f794d4bd29500f4649adf Mon Sep 17 00:00:00 2001 From: James Armstrong Date: Mon, 19 Jan 2026 18:06:11 -0800 Subject: [PATCH 8/8] Optimize Code --- Nuclei/Features/RankCatchUpService.cs | 29 ++++++++++++++++----------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/Nuclei/Features/RankCatchUpService.cs b/Nuclei/Features/RankCatchUpService.cs index 03a1221..b908387 100644 --- a/Nuclei/Features/RankCatchUpService.cs +++ b/Nuclei/Features/RankCatchUpService.cs @@ -13,34 +13,39 @@ public static void CatchUpPlayer(Player player) } var currentMissionTime = Time.timeSinceLevelLoad; var maxMissionTime = Globals.DedicatedServerManagerInstance.CurrentMissionOption.MaxTime; - var percentComplete = currentMissionTime / maxMissionTime; + var percentComplete = (currentMissionTime / maxMissionTime) * 2; + var rank = 0; + var allocation = 0f; if (percentComplete < .20) return; - else if (percentComplete >= .80) + else if (percentComplete >= .80) { - player.SetRank(5, false); - player.SetAllocation(player.Allocation + 300f); + rank = 5; + allocation = 400f; } else if (percentComplete >= .60) { - player.SetRank(4, false); - player.SetAllocation(player.Allocation + 250f); + rank = 4; + allocation = 350f; } else if (percentComplete >= .40) { - player.SetRank(3, false); - player.SetAllocation(player.Allocation + 200f); + rank = 3; + allocation = 300f; } else if (percentComplete >= .40) { - player.SetRank(2, false); - player.SetAllocation(player.Allocation + 150f); + rank = 2; + allocation = 250f; } else if (percentComplete >= .20) { - player.SetRank(1, false); - player.SetAllocation(player.Allocation + 100f); + rank = 1; + allocation = 200f; } + player.SetRank(rank, false); + player.SetAllocation(player.Allocation + allocation); + ChatService.SendPrivateChatMessage($"Late join - You have been promoted to Rank {rank} with +${allocation}m", player); } } \ No newline at end of file