Skip to content

Commit

Permalink
Adds Siege Compatibility for Commander Management
Browse files Browse the repository at this point in the history
- Adds hooks to support promotion in Siege (Timer, SetCommander)
- Adds generic methods to call from both TowerDefense and Strategy
  • Loading branch information
data-bomb committed Nov 17, 2024
1 parent 5c4bde6 commit 047eab9
Show file tree
Hide file tree
Showing 7 changed files with 296 additions and 171 deletions.
198 changes: 140 additions & 58 deletions Si_CommManagement/CommanderApplications.cs
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,19 @@ public static void Postfix(MusicJukeboxHandler __instance, GameMode __0)
}
}

#if NET6_0
[HarmonyPatch(typeof(MP_TowerDefense), nameof(MP_TowerDefense.RPC_TimerUpdate))]
#else
[HarmonyPatch(typeof(MP_TowerDefense), "RPC_TimerUpdate")]
#endif
private static class CommanderManager_Patch_TowerDefense_TimerUpdate
{
private static void Postfix(MP_TowerDefense __instance)
{
Process_RPC_TimerUpdate(__instance);
}
}

#if NET6_0
[HarmonyPatch(typeof(MP_Strategy), nameof(MP_Strategy.RPC_TimerUpdate))]
#else
Expand All @@ -272,83 +285,152 @@ private static class CommanderManager_Patch_Strategy_TimerUpdate
{
private static void Postfix(MP_Strategy __instance)
{
if (__instance.GameOver)
Process_RPC_TimerUpdate(__instance);
}
}

private static float GameModeTimer
{
get
{
if (GameMode.CurrentGameMode is MP_Strategy strategyInstance)
{
return;
#if NET6_0
return strategyInstance.Timer;
#else
Type strategyType = strategyInstance.GetType();
FieldInfo timerField = strategyType.GetField("Timer", BindingFlags.NonPublic | BindingFlags.Instance);
return (float)timerField.GetValue(strategyInstance);
#endif
}
else if (GameMode.CurrentGameMode is MP_TowerDefense defenseInstance)
{
#if NET6_0
return defenseInstance.Timer;
#else
Type defenseType = defenseInstance.GetType();
FieldInfo timerField = defenseType.GetField("Timer", BindingFlags.NonPublic | BindingFlags.Instance);
return (float)timerField.GetValue(defenseInstance);
#endif
}
throw new ArgumentException("Cannot access gamemode timer");
}
set
{
if (GameMode.CurrentGameMode is MP_Strategy strategyInstance)
{
#if NET6_0
strategyInstance.Timer = value;
#else
Type strategyType = strategyInstance.GetType();
FieldInfo timerField = strategyType.GetField("Timer", BindingFlags.NonPublic | BindingFlags.Instance);
timerField.SetValue(strategyInstance, value);
#endif
}
else if (GameMode.CurrentGameMode is MP_TowerDefense defenseInstance)
{
#if NET6_0
defenseInstance.Timer = value;
#else
Type strategyType = defenseInstance.GetType();
FieldInfo timerField = strategyType.GetField("Timer", BindingFlags.NonPublic | BindingFlags.Instance);
timerField.SetValue(defenseInstance, value);
#endif
}
throw new ArgumentException("Cannot set gamemode timer");
}
}

float timerValue;

private static void RemovePlayerFromRespawnTracker<T>(T gameModeInstance, Player player) where T : GameModeExt
{
if (gameModeInstance is MP_Strategy strategyInstance)
{
#if NET6_0
if (strategyInstance.PlayerRespawnTracker.ContainsKey(player))
{
strategyInstance.PlayerRespawnTracker.Remove(player);
}
#else
FieldInfo playerRespawnTrackerField = typeof(MP_Strategy).GetField("PlayerRespawnTracker", BindingFlags.NonPublic | BindingFlags.Instance);
Dictionary<Player, float> localPlayerRespawnTracker = (Dictionary<Player, float>)playerRespawnTrackerField.GetValue(strategyInstance);
if (localPlayerRespawnTracker.ContainsKey(player))
{
localPlayerRespawnTracker.Remove(player);
playerRespawnTrackerField.SetValue(strategyInstance, localPlayerRespawnTracker);
}
#endif
}
else if (gameModeInstance is MP_TowerDefense defenseInstance)
{
#if NET6_0
timerValue = __instance.Timer;
if (defenseInstance.PlayerRespawnTracker.ContainsKey(player))
{
defenseInstance.PlayerRespawnTracker.Remove(player);
}
#else
Type strategyType = typeof(MP_Strategy);
FieldInfo timerField = strategyType.GetField("Timer", BindingFlags.NonPublic | BindingFlags.Instance);
timerValue = (float)timerField.GetValue(__instance);
FieldInfo playerRespawnTrackerField = typeof(MP_TowerDefense).GetField("PlayerRespawnTracker", BindingFlags.NonPublic | BindingFlags.Instance);
Dictionary<Player, float> localPlayerRespawnTracker = (Dictionary<Player, float>)playerRespawnTrackerField.GetValue(defenseInstance);
if (localPlayerRespawnTracker.ContainsKey(player))
{
localPlayerRespawnTracker.Remove(player);
playerRespawnTrackerField.SetValue(defenseInstance, localPlayerRespawnTracker);
}
#endif
}
}

private static void Process_RPC_TimerUpdate<T>(T gameModeInstance) where T : GameModeExt
{
if (gameModeInstance.GameOver)
{
return;
}

float timerValue = GameModeTimer;

// the last second before the round is about to start
if (timerValue <= 1f && timerValue > 0f)
// the last second before the round is about to start
if (timerValue <= 1f && timerValue > 0f)
{
// switch all applicants to freecam
for (int i = 0; i < SiConstants.MaxPlayableTeams; i++)
{
// switch all applicants to freecam
for (int i = 0; i < SiConstants.MaxPlayableTeams; i++)
if (commanderApplicants[i].Count == 0)
{
if (commanderApplicants[i].Count == 0)
continue;
}

foreach (Player applicantPlayer in commanderApplicants[i])
{
if (applicantPlayer == null)
{
continue;
}

foreach (Player applicantPlayer in commanderApplicants[i])
{
if (applicantPlayer == null)
{
continue;
}

// send to role NONE
CommanderPrimitives.SendToRole(applicantPlayer, GameModeExt.ETeamRole.NONE);
MelonLogger.Msg("Player " + applicantPlayer.PlayerName + " is being sent to role NONE.");
// send to role NONE
CommanderPrimitives.SendToRole(applicantPlayer, GameModeExt.ETeamRole.NONE);
MelonLogger.Msg("Player " + applicantPlayer.PlayerName + " is being sent to role NONE.");

// force switching to role NONE
GameMode.CurrentGameMode.DestroyAllUnitsForPlayer(applicantPlayer);
#if NET6_0
if (__instance.PlayerRespawnTracker.ContainsKey(applicantPlayer))
{
__instance.PlayerRespawnTracker.Remove(applicantPlayer);
}
#else
FieldInfo playerRespawnTrackerField = typeof(MP_Strategy).GetField("PlayerRespawnTracker", BindingFlags.NonPublic | BindingFlags.Instance);
Dictionary<Player, float> localPlayerRespawnTracker = (Dictionary<Player, float>)playerRespawnTrackerField.GetValue(__instance);
if (localPlayerRespawnTracker.ContainsKey(applicantPlayer))
{
localPlayerRespawnTracker.Remove(applicantPlayer);
playerRespawnTrackerField.SetValue(__instance, localPlayerRespawnTracker);
}
#endif
}
// force switching to role NONE
gameModeInstance.DestroyAllUnitsForPlayer(applicantPlayer);
RemovePlayerFromRespawnTracker(gameModeInstance, applicantPlayer);
}
}
}

if (!CommanderManager._BlockRoundStartUntilEnoughApplicants.Value)
{
return;
}

if (AllTeamsHaveCommanderApplicants())
{
return;
}
if (!CommanderManager._BlockRoundStartUntilEnoughApplicants.Value)
{
return;
}

if (timerValue <= 5f && timerValue > 4f)
{
HelperMethods.ReplyToCommand("Round cannot start because all teams don't have a commander. Chat !commander to apply.");
if (AllTeamsHaveCommanderApplicants())
{
return;
}

#if NET6_0
__instance.Timer = 26f;
#else
timerField.SetValue(__instance, 26f);
#endif
}
if (timerValue <= 5f && timerValue > 4f)
{
GameModeTimer = 26f;
HelperMethods.ReplyToCommand("Round cannot start because all teams don't have a commander. Chat !commander to apply.");
}
}
}
Expand Down
17 changes: 3 additions & 14 deletions Si_CommManagement/CommanderBanAdminCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ public static void Command_CommanderDemote(Player? callerPlayer, String args)
}

int targetTeamIndex = -1;
MP_Strategy strategyInstance = GameObject.FindObjectOfType<MP_Strategy>();

// if no team was specified then try and use current team of the admin
if (argumentCount == 0)
Expand All @@ -101,17 +100,7 @@ public static void Command_CommanderDemote(Player? callerPlayer, String args)
{
String targetTeamText = args.Split(' ')[1];

if (String.Equals(targetTeamText, "Human", StringComparison.OrdinalIgnoreCase))
{
// check gamemode - if Humans vs Aliens or the other ones
if (strategyInstance.TeamsVersus == MP_Strategy.ETeamsVersus.HUMANS_VS_ALIENS)
{
// if it's human vs aliens then human translates to the Human (Sol) team index
targetTeamIndex = (int)SiConstants.ETeam.Sol;
}
// otherwise, it's ambigious and we can't make a decision
}
else if (String.Equals(targetTeamText, "Alien", StringComparison.OrdinalIgnoreCase))
if (String.Equals(targetTeamText, "Alien", StringComparison.OrdinalIgnoreCase))
{
targetTeamIndex = (int)SiConstants.ETeam.Alien;
}
Expand Down Expand Up @@ -140,7 +129,7 @@ public static void Command_CommanderDemote(Player? callerPlayer, String args)
}

// check if they have a commander to demote
Player? targetPlayer = strategyInstance.GetCommanderForTeam(targetTeam);
Player? targetPlayer = CommanderPrimitives.GetCommander(targetTeam);

// team has a commander if targetPlayer isn't null
if (targetPlayer == null)
Expand All @@ -155,7 +144,7 @@ public static void Command_CommanderDemote(Player? callerPlayer, String args)
return;
}

CommanderPrimitives.DemoteTeamsCommander(strategyInstance, targetTeam);
CommanderPrimitives.DemoteTeamsCommander(targetTeam);
HelperMethods.AlertAdminActivity(callerPlayer, targetPlayer, "demoted");
}

Expand Down
4 changes: 1 addition & 3 deletions Si_CommManagement/CommanderBanList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,7 @@ public static void AddBan(Player playerToCmdrBan)
if (playerToCmdrBan.IsCommander)
{
Team playerTeam = playerToCmdrBan.Team;
MP_Strategy strategyInstance = GameObject.FindObjectOfType<MP_Strategy>();

CommanderPrimitives.DemoteTeamsCommander(strategyInstance, playerTeam);
CommanderPrimitives.DemoteTeamsCommander(playerTeam);
HelperMethods.ReplyToCommand_Player(playerToCmdrBan, "was demoted");
}

Expand Down
Loading

0 comments on commit 047eab9

Please sign in to comment.