From 77aab4fc361fe2fb1d0438d356ac748ec5481acd Mon Sep 17 00:00:00 2001 From: data-bomb Date: Sat, 16 Nov 2024 10:28:06 -0800 Subject: [PATCH] Handle Roles with Tower Defense Mode - Creates generic methods that work with both MP_Strategy and MP_TowerDefense modes for capturing player role changes and whether to permit commander applicants --- Si_AdminMod/Event_Roles.cs | 198 ++++++++++++++++++++++++----------- Si_AdminMod/ModAttributes.cs | 2 +- 2 files changed, 139 insertions(+), 61 deletions(-) diff --git a/Si_AdminMod/Event_Roles.cs b/Si_AdminMod/Event_Roles.cs index 66718d9..c5acf87 100644 --- a/Si_AdminMod/Event_Roles.cs +++ b/Si_AdminMod/Event_Roles.cs @@ -28,6 +28,8 @@ You should have received a copy of the GNU General Public License using System.Reflection; using System.Data; using System.Globalization; +using static MelonLoader.MelonLogger; + #if NET6_0 using Il2Cpp; @@ -41,7 +43,8 @@ namespace SilicaAdminMod public static class Event_Roles { #if !NET6_0 - public static byte ERPC_RequestRole = HelperMethods.FindByteValueInEnum(typeof(MP_Strategy), "ERPCs", "REQUEST_ROLE"); + public static byte ERPC_Strategy_RequestRole = HelperMethods.FindByteValueInEnum(typeof(MP_Strategy), "ERPCs", "REQUEST_ROLE"); + public static byte ERPC_TowerDefense_RequestRole = HelperMethods.FindByteValueInEnum(typeof(MP_TowerDefense), "ERPCs", "REQUEST_ROLE"); #endif public static event EventHandler OnRequestCommander = delegate { }; public static event EventHandler OnRoleChanged = delegate { }; @@ -62,96 +65,171 @@ public static bool Prefix(MP_Strategy __instance, ref GameByteStreamReader __0, #if NET6_0 if (__1 != (byte)MP_Strategy.ERPCs.REQUEST_ROLE) #else - if (__1 != ERPC_RequestRole) + if (__1 != ERPC_Strategy_RequestRole) #endif { return true; } - Player requestingPlayer = Player.FindPlayer((NetworkID)__0.ReadUInt64(), (int)__0.ReadByte()); - GameModeExt.ETeamRole eRole = (GameModeExt.ETeamRole)__0.ReadByte(); + return ProcessRequestRole(__instance, ref __0, __1); + } + catch (Exception error) + { + HelperMethods.PrintError(error, "Failed to run MP_Strategy::ProcessNetRPC"); + } - if (requestingPlayer == null) - { - MelonLogger.Warning("Cannot find player in role request."); - return false; - } + return true; + } + } - // would the game code treat it as an infantry/no role request? - if (eRole != GameModeExt.ETeamRole.COMMANDER || __instance.GetCommanderForTeam(requestingPlayer.Team)) + [HarmonyPatch(typeof(MP_TowerDefense), nameof(MP_TowerDefense.ProcessNetRPC))] + static class ApplyPatch_MPTowerDefense_RequestRole + { + public static bool Prefix(MP_TowerDefense __instance, ref GameByteStreamReader __0, byte __1) + { + try + { + if (__instance == null || __0 == null) { - __0 = RestoreRPC_RequestRoleReader(requestingPlayer, eRole); - FireOnRoleChangedEvent(requestingPlayer, eRole); return true; } - BaseTeamSetup baseTeamSetup = __instance.GetTeamSetup(requestingPlayer.Team); - if (baseTeamSetup == null) + // only look at RPC_RequestRole + #if NET6_0 + if (__1 != (byte)MP_TowerDefense.ERPCs.REQUEST_ROLE) + #else + if (__1 != ERPC_TowerDefense_RequestRole) + #endif { - return false; + return true; } - OnRequestCommanderArgs onRequestCommanderArgs = FireOnRequestCommanderEvent(requestingPlayer); + return ProcessRequestRole(__instance, ref __0, __1); + } + catch (Exception error) + { + HelperMethods.PrintError(error, "Failed to run MP_TowerDefense::ProcessNetRPC"); + } - if (onRequestCommanderArgs.Block) - { - if (SiAdminMod.Pref_Admin_DebugLogMessages.Value) - { - MelonLogger.Msg("Blocking commander role request for " + onRequestCommanderArgs.Requester.PlayerName); - } - - if (!onRequestCommanderArgs.PreventSpawnWhenBlocked) - { - if (SiAdminMod.Pref_Admin_DebugLogMessages.Value) - { - MelonLogger.Msg("Preventing Spawn"); - } - __instance.SpawnUnitForPlayer(requestingPlayer, requestingPlayer.Team); - FireOnRoleChangedEvent(requestingPlayer, GameModeExt.ETeamRole.INFANTRY); - } - - return false; - } + return true; + } + } + + public static bool ProcessRequestRole(T gameModeInstance, ref GameByteStreamReader reader, byte rpcIndex) where T : GameModeExt + { + Player requestingPlayer = Player.FindPlayer((NetworkID)reader.ReadUInt64(), (int)reader.ReadByte()); + GameModeExt.ETeamRole eRole = (GameModeExt.ETeamRole)reader.ReadByte(); + + if (requestingPlayer == null) + { + MelonLogger.Warning("Cannot find player in role request."); + return false; + } + + // would the game code treat it as an infantry/no role request? + if (eRole != GameModeExt.ETeamRole.COMMANDER || gameModeInstance.GetCommanderForTeam(requestingPlayer.Team)) + { + reader = RestoreRPC_RequestRoleReader(gameModeInstance, requestingPlayer, eRole); + FireOnRoleChangedEvent(requestingPlayer, eRole); + return true; + } + + BaseTeamSetup? baseTeamSetup = GetTeamSetup(gameModeInstance, requestingPlayer.Team); + if (baseTeamSetup == null) + { + return false; + } + + OnRequestCommanderArgs onRequestCommanderArgs = FireOnRequestCommanderEvent(requestingPlayer); + + if (onRequestCommanderArgs.Block) + { + if (SiAdminMod.Pref_Admin_DebugLogMessages.Value) + { + MelonLogger.Msg("Blocking commander role request for " + onRequestCommanderArgs.Requester.PlayerName); + } + if (!onRequestCommanderArgs.PreventSpawnWhenBlocked) + { if (SiAdminMod.Pref_Admin_DebugLogMessages.Value) { - MelonLogger.Msg("Allowing to join commander"); + MelonLogger.Msg("Preventing Spawn"); } -#if NET6_0 - __instance.SetCommander(baseTeamSetup.Team, requestingPlayer); - __instance.RPC_SynchCommander(baseTeamSetup.Team); -#else - Type strategyType = typeof(MP_Strategy); - MethodInfo setCommanderMethod = strategyType.GetMethod("SetCommander", BindingFlags.Instance | BindingFlags.NonPublic); - setCommanderMethod.Invoke(__instance, parameters: new object?[] { baseTeamSetup.Team, requestingPlayer }); + gameModeInstance.SpawnUnitForPlayer(requestingPlayer, requestingPlayer.Team); + FireOnRoleChangedEvent(requestingPlayer, GameModeExt.ETeamRole.INFANTRY); + } - MethodInfo synchCommanderMethod = strategyType.GetMethod("RPC_SynchCommander", BindingFlags.Instance | BindingFlags.NonPublic); - synchCommanderMethod.Invoke(__instance, new object[] { baseTeamSetup.Team }); -#endif + return false; + } - FireOnRoleChangedEvent(requestingPlayer, GameModeExt.ETeamRole.COMMANDER); + if (SiAdminMod.Pref_Admin_DebugLogMessages.Value) + { + MelonLogger.Msg("Allowing to join commander"); + } - return false; - } - catch (Exception error) + #if NET6_0 + if (gameModeInstance is MP_Strategy strategyInstance) + { + strategyInstance.SetCommander(baseTeamSetup.Team, requestingPlayer); + strategyInstance.RPC_SynchCommander(baseTeamSetup.Team); + } + else if (gameModeInstance is MP_TowerDefense defenseInstance) + { + defenseInstance.SetCommander(baseTeamSetup.Team, requestingPlayer); + defenseInstance.RPC_SynchCommander(baseTeamSetup.Team); + } + #else + Type gameModeType = gameModeInstance.GetType(); + MethodInfo setCommanderMethod = gameModeType.GetMethod("SetCommander", BindingFlags.Instance | BindingFlags.NonPublic); + setCommanderMethod.Invoke(gameModeInstance, parameters: new object?[] { baseTeamSetup.Team, requestingPlayer }); + + MethodInfo synchCommanderMethod = gameModeType.GetMethod("RPC_SynchCommander", BindingFlags.Instance | BindingFlags.NonPublic); + synchCommanderMethod.Invoke(gameModeInstance, new object[] { baseTeamSetup.Team }); + #endif + + FireOnRoleChangedEvent(requestingPlayer, GameModeExt.ETeamRole.COMMANDER); + + return false; + } + + public static BaseTeamSetup? GetTeamSetup(T gameModeInstance, Team team) where T : GameModeExt + { + foreach (BaseTeamSetup baseTeamSetup in gameModeInstance.BaseTeamSetups) + { + if (gameModeInstance.GetTeamSetupActive(baseTeamSetup) && baseTeamSetup.Team == team) { - HelperMethods.PrintError(error, "Failed to run MP_Strategy::ProcessNetRPC"); + return baseTeamSetup; } - - return true; } + + return null; } - public static GameByteStreamReader RestoreRPC_RequestRoleReader(Player requestingPlayer, GameModeExt.ETeamRole role) + public static GameByteStreamReader RestoreRPC_RequestRoleReader(T gameModeInstance, Player requestingPlayer, GameModeExt.ETeamRole role) where T : GameModeExt { GameByteStreamWriter gameByteStreamWriter = GameByteStreamWriter.GetGameByteStreamWriter(0U, "Si_AdminMod::RestoreRPC_RequestRoleReader", true); gameByteStreamWriter.WriteByte((byte)ENetworkPacketType.GameModeRPC); gameByteStreamWriter.WriteByte(0); - #if NET6_0 - gameByteStreamWriter.WriteByte((byte)MP_Strategy.ERPCs.REQUEST_ROLE); - #else - gameByteStreamWriter.WriteByte(ERPC_RequestRole); - #endif + //#if NET6_0 + if (gameModeInstance is MP_Strategy) + { + #if NET6_0 + gameByteStreamWriter.WriteByte((byte)MP_Strategy.ERPCs.REQUEST_ROLE); + #else + gameByteStreamWriter.WriteByte((byte)ERPC_Strategy_RequestRole); + #endif + } + else if (gameModeInstance is MP_TowerDefense) + { + #if NET6_0 + gameByteStreamWriter.WriteByte((byte)MP_TowerDefense.ERPCs.REQUEST_ROLE); + #else + gameByteStreamWriter.WriteByte((byte)ERPC_TowerDefense_RequestRole); + #endif + } + //#else + //gameByteStreamWriter.WriteByte(ERPC_Strategy_RequestRole); + //#endif gameByteStreamWriter.WriteUInt64((ulong)requestingPlayer.PlayerID); gameByteStreamWriter.WriteByte((byte)requestingPlayer.PlayerChannel); gameByteStreamWriter.WriteByte((byte)role); diff --git a/Si_AdminMod/ModAttributes.cs b/Si_AdminMod/ModAttributes.cs index a47a64d..ae8b3d5 100644 --- a/Si_AdminMod/ModAttributes.cs +++ b/Si_AdminMod/ModAttributes.cs @@ -21,7 +21,7 @@ You should have received a copy of the GNU General Public License using SilicaAdminMod; using System.Drawing; -[assembly: MelonInfo(typeof(SiAdminMod), "Admin Mod", "2.0.965", "databomb", "https://github.com/data-bomb/Silica")] +[assembly: MelonInfo(typeof(SiAdminMod), "Admin Mod", "2.0.995", "databomb", "https://github.com/data-bomb/Silica")] [assembly: MelonGame("Bohemia Interactive", "Silica")] // Color.Cyan