From 77de3c1c0151680f993bdf70ffd96277b7ff3e25 Mon Sep 17 00:00:00 2001 From: data-bomb Date: Wed, 28 Aug 2024 18:40:06 -0700 Subject: [PATCH 1/9] v0.8.74 Game Fixes for Admin Mod --- Si_AdminMod/CheatsLimiter.cs | 10 ++++++++-- Si_AdminMod/Event_Netcode.cs | 2 +- Si_AdminMod/Event_Roles.cs | 38 ++++++++++++++++++++++++++++++------ Si_AdminMod/HelperMethods.cs | 38 +++++++++++++++++++++++------------- Si_AdminMod/ModAttributes.cs | 2 +- 5 files changed, 66 insertions(+), 24 deletions(-) diff --git a/Si_AdminMod/CheatsLimiter.cs b/Si_AdminMod/CheatsLimiter.cs index 21b3268..bc0bbe6 100644 --- a/Si_AdminMod/CheatsLimiter.cs +++ b/Si_AdminMod/CheatsLimiter.cs @@ -118,8 +118,14 @@ public static void SendLimitedCheatsEvent(bool cheatsStatus) bitsSent += byteDataSize * 8U; netBitsSentField.SetValue(null, bitsSent); #endif - - SteamGameServerNetworking.SendP2PPacket(player.PlayerID, byteData, byteDataSize, EP2PSend.k_EP2PSendReliable, player.PlayerChannel); + + #if NET6_0 + NetworkLayer.SendServerPacket(player.PlayerID, gameByteStreamWriter.GetByteData(), byteDataSize, ENetworkPacketSend.Reliable, player.PlayerChannel); + #else + Type networkLayerType = typeof(NetworkLayer); + MethodInfo sendServerPacketMethod = networkLayerType.GetMethod("SendServerPacket", BindingFlags.NonPublic | BindingFlags.Static); + sendServerPacketMethod.Invoke(null, new object[] { player.PlayerID, gameByteStreamWriter.GetByteData(), byteDataSize, ENetworkPacketSend.Reliable, player.PlayerChannel }); + #endif } } } diff --git a/Si_AdminMod/Event_Netcode.cs b/Si_AdminMod/Event_Netcode.cs index 73d7602..3c165a9 100644 --- a/Si_AdminMod/Event_Netcode.cs +++ b/Si_AdminMod/Event_Netcode.cs @@ -77,7 +77,7 @@ static void Prefix(GameByteStreamReader __result, ref byte[] __0, int __1, uint { case (byte)ENetworkPacketType.ChatMessage: { - CSteamID chatterSteamId = (CSteamID)tempReader.ReadUInt64(); + NetworkID chatterSteamId = (NetworkID)tempReader.ReadUInt64(); int chatterChannel = (int)tempReader.ReadByte(); string chatText = tempReader.ReadString(); bool chatTeamOnly = tempReader.ReadBool(); diff --git a/Si_AdminMod/Event_Roles.cs b/Si_AdminMod/Event_Roles.cs index f7189fd..8fd237c 100644 --- a/Si_AdminMod/Event_Roles.cs +++ b/Si_AdminMod/Event_Roles.cs @@ -27,6 +27,7 @@ You should have received a copy of the GNU General Public License using System.Runtime.CompilerServices; using System.Reflection; using System.Data; +using System.Globalization; #if NET6_0 using Il2Cpp; @@ -55,12 +56,25 @@ public static bool Prefix(MP_Strategy __instance, ref GameByteStreamReader __0, } // only look at RPC_RequestRole - if (__1 != (byte)GameModeExt.ERPCs.REQUEST_ROLE) + #if NET6_0 + if (__1 != (byte)MP_Strategy.ERPCs.REQUEST_ROLE) + #else + Type strategyERPCsType = typeof(MP_Strategy).GetNestedType("ERPCs", BindingFlags.NonPublic); + if (strategyERPCsType == null) { + MelonLogger.Error("Cannot find MP_Strategy::ERPCs"); return true; } - Player requestingPlayer = Player.FindPlayer((CSteamID)__0.ReadUInt64(), (int)__0.ReadByte()); + string RPCname = strategyERPCsType.GetEnumName((byte)__1); + + if (string.Compare(RPCname, "REQUEST_ROLE") != 0) + #endif + { + return true; + } + + Player requestingPlayer = Player.FindPlayer((NetworkID)__0.ReadUInt64(), (int)__0.ReadByte()); GameModeExt.ETeamRole eRole = (GameModeExt.ETeamRole)__0.ReadByte(); if (requestingPlayer == null) @@ -109,17 +123,17 @@ public static bool Prefix(MP_Strategy __instance, ref GameByteStreamReader __0, { MelonLogger.Msg("Allowing to join commander"); } - #if NET6_0 +#if NET6_0 __instance.SetCommander(baseTeamSetup.Team, requestingPlayer); __instance.RPC_SynchCommander(baseTeamSetup.Team); - #else +#else Type strategyType = typeof(MP_Strategy); MethodInfo setCommanderMethod = strategyType.GetMethod("SetCommander", BindingFlags.Instance | BindingFlags.NonPublic); setCommanderMethod.Invoke(__instance, parameters: new object?[] { baseTeamSetup.Team, requestingPlayer }); MethodInfo synchCommanderMethod = strategyType.GetMethod("RPC_SynchCommander", BindingFlags.Instance | BindingFlags.NonPublic); synchCommanderMethod.Invoke(__instance, new object[] { baseTeamSetup.Team }); - #endif +#endif FireOnRoleChangedEvent(requestingPlayer, GameModeExt.ETeamRole.COMMANDER); @@ -139,7 +153,19 @@ public static GameByteStreamReader RestoreRPC_RequestRoleReader(Player requestin GameByteStreamWriter gameByteStreamWriter = GameByteStreamWriter.GetGameByteStreamWriter(0U, "Si_AdminMod::RestoreRPC_RequestRoleReader", true); gameByteStreamWriter.WriteByte((byte)ENetworkPacketType.GameModeRPC); gameByteStreamWriter.WriteByte(0); - gameByteStreamWriter.WriteByte((byte)GameModeExt.ERPCs.REQUEST_ROLE); + #if NET6_0 + gameByteStreamWriter.WriteByte((byte)MP_Strategy.ERPCs.REQUEST_ROLE); + #else + Type strategyERPCsType = typeof(MP_Strategy).GetNestedType("ERPCs", BindingFlags.NonPublic); + var rpcValues = strategyERPCsType.GetEnumValues(); + foreach (var rpcValue in rpcValues) + { + if (string.Compare(rpcValue.ToString(), "REQUEST_ROLE") == 0) + { + gameByteStreamWriter.WriteByte((byte)rpcValue); + } + } + #endif gameByteStreamWriter.WriteUInt64((ulong)requestingPlayer.PlayerID); gameByteStreamWriter.WriteByte((byte)requestingPlayer.PlayerChannel); gameByteStreamWriter.WriteByte((byte)role); diff --git a/Si_AdminMod/HelperMethods.cs b/Si_AdminMod/HelperMethods.cs index 7945567..5ead3df 100644 --- a/Si_AdminMod/HelperMethods.cs +++ b/Si_AdminMod/HelperMethods.cs @@ -200,7 +200,8 @@ private static void NetworkSendChat(Player recipient, Player sender, params stri gameByteStreamWriter.WriteUInt64((ulong)sender.PlayerID); gameByteStreamWriter.WriteByte((byte)sender.PlayerChannel); gameByteStreamWriter.WriteString(String.Concat(messages)); - gameByteStreamWriter.WriteBool(false); + gameByteStreamWriter.WriteBool(false); // teamOnly + gameByteStreamWriter.WriteBool(true); // isServerMessage uint byteDataSize = (uint)gameByteStreamWriter.GetByteDataSize(); #if NET6_0 @@ -211,7 +212,14 @@ private static void NetworkSendChat(Player recipient, Player sender, params stri bitsSent += byteDataSize * 8U; netBitsSentField.SetValue(null, bitsSent); #endif - SteamGameServerNetworking.SendP2PPacket(recipient.PlayerID, gameByteStreamWriter.GetByteData(), byteDataSize, EP2PSend.k_EP2PSendReliable, recipient.PlayerChannel); + + #if NET6_0 + NetworkLayer.SendServerPacket(recipient.PlayerID, gameByteStreamWriter.GetByteData(), byteDataSize, ENetworkPacketSend.Reliable, recipient.PlayerChannel); + #else + Type networkLayerType = typeof(NetworkLayer); + MethodInfo sendServerPacketMethod = networkLayerType.GetMethod("SendServerPacket", BindingFlags.NonPublic | BindingFlags.Static); + sendServerPacketMethod.Invoke(null, new object[] { recipient.PlayerID, gameByteStreamWriter.GetByteData(), byteDataSize, ENetworkPacketSend.Reliable, recipient.PlayerChannel }); + #endif } private static void NetworkSendConsole(Player recipient, params string[] messages) @@ -238,7 +246,14 @@ private static void NetworkSendConsole(Player recipient, params string[] message bitsSent += byteDataSize * 8U; netBitsSentField.SetValue(null, bitsSent); #endif - SteamGameServerNetworking.SendP2PPacket(recipient.PlayerID, gameByteStreamWriter.GetByteData(), byteDataSize, EP2PSend.k_EP2PSendReliable, recipient.PlayerChannel); + + #if NET6_0 + NetworkLayer.SendServerPacket(recipient.PlayerID, gameByteStreamWriter.GetByteData(), byteDataSize, ENetworkPacketSend.Reliable, recipient.PlayerChannel); + #else + Type networkLayerType = typeof(NetworkLayer); + MethodInfo sendServerPacketMethod = networkLayerType.GetMethod("SendServerPacket", BindingFlags.NonPublic | BindingFlags.Static); + sendServerPacketMethod.Invoke(null, new object[] { recipient.PlayerID, gameByteStreamWriter.GetByteData(), byteDataSize, ENetworkPacketSend.Reliable, recipient.PlayerChannel }); + #endif } public static Player FindBroadcastPlayer() @@ -300,11 +315,11 @@ public static void PrintError(Exception exception, string? message = null) int iTargetCount = 0; // loop through all players - #if NET6_0 +#if NET6_0 Il2CppSystem.Collections.Generic.List players = Player.Players; - #else +#else List players = Player.Players; - #endif +#endif int iPlayerCount = players.Count; @@ -502,18 +517,13 @@ public static bool KickPlayer(Player playerToKick) return false; } -#if NET6_0 - Il2CppSteamworks.CSteamID serverSteam = NetworkGameServer.GetServerID(); - Il2CppSteamworks.CSteamID playerSteam = playerToKick.PlayerID; -#else - Steamworks.CSteamID serverSteam = NetworkGameServer.GetServerID(); - Steamworks.CSteamID playerSteam = playerToKick.PlayerID; -#endif + NetworkID serverSteam = NetworkGameServer.GetServerID(); + NetworkID playerSteam = playerToKick.PlayerID; int playerChannel = playerToKick.PlayerChannel; NetworkLayer.SendPlayerConnectResponse(ENetworkPlayerConnectType.Kicked, playerSteam, playerChannel, serverSteam); - Player.RemovePlayer(playerSteam, playerChannel); + Player.RemovePlayer(playerSteam); NetworkLayer.SendPlayerConnect(ENetworkPlayerConnectType.Disconnected, playerSteam, playerChannel); return true; diff --git a/Si_AdminMod/ModAttributes.cs b/Si_AdminMod/ModAttributes.cs index b08b00e..b62be9e 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.936", "databomb", "https://github.com/data-bomb/Silica")] +[assembly: MelonInfo(typeof(SiAdminMod), "Admin Mod", "2.0.939", "databomb", "https://github.com/data-bomb/Silica")] [assembly: MelonGame("Bohemia Interactive", "Silica")] // Color.Cyan From 5aa5dbb5ea5eef660ae86ec5cace19fb72544594 Mon Sep 17 00:00:00 2001 From: data-bomb Date: Wed, 28 Aug 2024 18:45:09 -0700 Subject: [PATCH 2/9] Debug Message for Admin-only Cheats - Adds a log message whenever a player is provided cheats access due to their admin powers --- Si_AdminMod/CheatsLimiter.cs | 5 +++++ Si_AdminMod/ModAttributes.cs | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Si_AdminMod/CheatsLimiter.cs b/Si_AdminMod/CheatsLimiter.cs index bc0bbe6..8cce38b 100644 --- a/Si_AdminMod/CheatsLimiter.cs +++ b/Si_AdminMod/CheatsLimiter.cs @@ -110,6 +110,11 @@ public static void SendLimitedCheatsEvent(bool cheatsStatus) Power modPowers = player.GetAdminPowers(); if (player.AdminLevel >= EAdminLevel.STANDARD || AdminMethods.PowerInPowers(Power.Cheat, modPowers)) { + if (SiAdminMod.Pref_Admin_DebugLogMessages.Value) + { + MelonLogger.Msg("Permitting cheats access to admin: " + player.PlayerName + " (server level: " + player.AdminLevel.ToString() + ") (mod powers: " + modPowers.ToString() + ")"); + } + #if NET6_0 NetworkLayer.NetBitsSent += byteDataSize * 8U; #else diff --git a/Si_AdminMod/ModAttributes.cs b/Si_AdminMod/ModAttributes.cs index b62be9e..df7a2e6 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.939", "databomb", "https://github.com/data-bomb/Silica")] +[assembly: MelonInfo(typeof(SiAdminMod), "Admin Mod", "2.0.940", "databomb", "https://github.com/data-bomb/Silica")] [assembly: MelonGame("Bohemia Interactive", "Silica")] // Color.Cyan From 2ceda6033764a4d2ee91a4f182687d3364973765 Mon Sep 17 00:00:00 2001 From: data-bomb Date: Mon, 2 Sep 2024 19:27:04 -0700 Subject: [PATCH 3/9] Efficiency Improvements for Enumerated Values - Switches an O(1) and O(n) string lookup to a O(1) byte lookup in Admin Mod --- Si_AdminMod/Event_Roles.cs | 37 ++++++++++++++++++------------------ Si_AdminMod/ModAttributes.cs | 2 +- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/Si_AdminMod/Event_Roles.cs b/Si_AdminMod/Event_Roles.cs index 8fd237c..089f160 100644 --- a/Si_AdminMod/Event_Roles.cs +++ b/Si_AdminMod/Event_Roles.cs @@ -40,6 +40,7 @@ namespace SilicaAdminMod { public static class Event_Roles { + public static byte ERPC_RequestRole = FindRequestRoleEnumByte(); public static event EventHandler OnRequestCommander = delegate { }; public static event EventHandler OnRoleChanged = delegate { }; @@ -59,16 +60,7 @@ public static bool Prefix(MP_Strategy __instance, ref GameByteStreamReader __0, #if NET6_0 if (__1 != (byte)MP_Strategy.ERPCs.REQUEST_ROLE) #else - Type strategyERPCsType = typeof(MP_Strategy).GetNestedType("ERPCs", BindingFlags.NonPublic); - if (strategyERPCsType == null) - { - MelonLogger.Error("Cannot find MP_Strategy::ERPCs"); - return true; - } - - string RPCname = strategyERPCsType.GetEnumName((byte)__1); - - if (string.Compare(RPCname, "REQUEST_ROLE") != 0) + if (__1 != ERPC_RequestRole) #endif { return true; @@ -156,15 +148,7 @@ public static GameByteStreamReader RestoreRPC_RequestRoleReader(Player requestin #if NET6_0 gameByteStreamWriter.WriteByte((byte)MP_Strategy.ERPCs.REQUEST_ROLE); #else - Type strategyERPCsType = typeof(MP_Strategy).GetNestedType("ERPCs", BindingFlags.NonPublic); - var rpcValues = strategyERPCsType.GetEnumValues(); - foreach (var rpcValue in rpcValues) - { - if (string.Compare(rpcValue.ToString(), "REQUEST_ROLE") == 0) - { - gameByteStreamWriter.WriteByte((byte)rpcValue); - } - } + gameByteStreamWriter.WriteByte(ERPC_RequestRole); #endif gameByteStreamWriter.WriteUInt64((ulong)requestingPlayer.PlayerID); gameByteStreamWriter.WriteByte((byte)requestingPlayer.PlayerChannel); @@ -176,6 +160,21 @@ public static GameByteStreamReader RestoreRPC_RequestRoleReader(Player requestin return gameByteStreamReader; } + private static byte FindRequestRoleEnumByte() + { + Type strategyERPCsType = typeof(MP_Strategy).GetNestedType("ERPCs", BindingFlags.NonPublic); + var rpcValues = strategyERPCsType.GetEnumValues(); + foreach (var rpcValue in rpcValues) + { + if (string.Compare(rpcValue.ToString(), "REQUEST_ROLE") == 0) + { + return (byte)rpcValue; + } + } + + return byte.MaxValue; + } + public static void FireOnRoleChangedEvent(Player player, GameModeExt.ETeamRole role) { if (SiAdminMod.Pref_Admin_DebugLogMessages.Value) diff --git a/Si_AdminMod/ModAttributes.cs b/Si_AdminMod/ModAttributes.cs index df7a2e6..2b4b974 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.940", "databomb", "https://github.com/data-bomb/Silica")] +[assembly: MelonInfo(typeof(SiAdminMod), "Admin Mod", "2.0.941", "databomb", "https://github.com/data-bomb/Silica")] [assembly: MelonGame("Bohemia Interactive", "Silica")] // Color.Cyan From 00ff97ad4b462a68f3e08e1864d9f6ecc84c9dbc Mon Sep 17 00:00:00 2001 From: data-bomb Date: Mon, 2 Sep 2024 19:34:16 -0700 Subject: [PATCH 4/9] Ban List Game Fixes for v0.8.76+ - Switches to NetworkID --- Si_BasicBanlist/Si_BasicBans.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Si_BasicBanlist/Si_BasicBans.cs b/Si_BasicBanlist/Si_BasicBans.cs index d7e4e09..2b4a098 100644 --- a/Si_BasicBanlist/Si_BasicBans.cs +++ b/Si_BasicBanlist/Si_BasicBans.cs @@ -35,7 +35,7 @@ You should have received a copy of the GNU General Public License using System.Collections.Generic; using System.Linq; -[assembly: MelonInfo(typeof(BasicBanlist), "Basic Banlist", "1.5.1", "databomb", "https://github.com/data-bomb/Silica")] +[assembly: MelonInfo(typeof(BasicBanlist), "Basic Banlist", "1.5.2", "databomb", "https://github.com/data-bomb/Silica")] [assembly: MelonGame("Bohemia Interactive", "Silica")] [assembly: MelonOptionalDependencies("Admin Mod")] @@ -332,15 +332,15 @@ public static bool UnbanPlayer(String target, Player? adminPlayer) public static void BanPlayer(Player playerToBan, Player? adminPlayer) { // are we already banned? - if (IsPlayerBanned(playerToBan.PlayerID.m_SteamID)) + if (IsPlayerBanned(playerToBan.PlayerID.SteamID.m_SteamID)) { - MelonLogger.Warning("Player name (" + playerToBan.PlayerName + ") SteamID (" + playerToBan.PlayerID.m_SteamID.ToString() + ") already on banlist."); + MelonLogger.Warning("Player name (" + playerToBan.PlayerName + ") SteamID (" + playerToBan.PlayerID.SteamID.m_SteamID.ToString() + ") already on banlist."); return; } if (MasterBanList == null) { - NetworkServerSettings.PlayerAddBan(playerToBan.PlayerID.m_SteamID, playerToBan.PlayerName, 0, adminPlayer == null ? "banned by SERVER CONSOLE" : "banned by " + adminPlayer.PlayerName); + NetworkServerSettings.PlayerAddBan(playerToBan.PlayerID.SteamID.m_SteamID, playerToBan.PlayerName, 0, adminPlayer == null ? "banned by SERVER CONSOLE" : "banned by " + adminPlayer.PlayerName); } else { @@ -349,7 +349,7 @@ public static void BanPlayer(Player playerToBan, Player? adminPlayer) UpdateBanFile(); } - MelonLogger.Msg("Added player name (" + playerToBan.PlayerName + ") SteamID (" + playerToBan.PlayerID.m_SteamID.ToString() + ") to the banlist."); + MelonLogger.Msg("Added player name (" + playerToBan.PlayerName + ") SteamID (" + playerToBan.PlayerID.SteamID.m_SteamID.ToString() + ") to the banlist."); NetworkGameServer.KickPlayer(playerToBan); HelperMethods.AlertAdminActivity(adminPlayer, playerToBan, "banned"); } From 7dc83e4c5294422085eef649c73ae52fb2d70965 Mon Sep 17 00:00:00 2001 From: data-bomb Date: Mon, 2 Sep 2024 19:41:22 -0700 Subject: [PATCH 5/9] Adds FindByteValueInEnum in HelperMethods - Makes a generic version of the method to find the byte value of a private enum for other mods to leverage --- Si_AdminMod/Event_Roles.cs | 19 +++---------------- Si_AdminMod/HelperMethods.cs | 17 +++++++++++++++++ Si_AdminMod/ModAttributes.cs | 2 +- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/Si_AdminMod/Event_Roles.cs b/Si_AdminMod/Event_Roles.cs index 089f160..66718d9 100644 --- a/Si_AdminMod/Event_Roles.cs +++ b/Si_AdminMod/Event_Roles.cs @@ -40,7 +40,9 @@ namespace SilicaAdminMod { public static class Event_Roles { - public static byte ERPC_RequestRole = FindRequestRoleEnumByte(); + #if !NET6_0 + public static byte ERPC_RequestRole = HelperMethods.FindByteValueInEnum(typeof(MP_Strategy), "ERPCs", "REQUEST_ROLE"); + #endif public static event EventHandler OnRequestCommander = delegate { }; public static event EventHandler OnRoleChanged = delegate { }; @@ -160,21 +162,6 @@ public static GameByteStreamReader RestoreRPC_RequestRoleReader(Player requestin return gameByteStreamReader; } - private static byte FindRequestRoleEnumByte() - { - Type strategyERPCsType = typeof(MP_Strategy).GetNestedType("ERPCs", BindingFlags.NonPublic); - var rpcValues = strategyERPCsType.GetEnumValues(); - foreach (var rpcValue in rpcValues) - { - if (string.Compare(rpcValue.ToString(), "REQUEST_ROLE") == 0) - { - return (byte)rpcValue; - } - } - - return byte.MaxValue; - } - public static void FireOnRoleChangedEvent(Player player, GameModeExt.ETeamRole role) { if (SiAdminMod.Pref_Admin_DebugLogMessages.Value) diff --git a/Si_AdminMod/HelperMethods.cs b/Si_AdminMod/HelperMethods.cs index 5ead3df..893172f 100644 --- a/Si_AdminMod/HelperMethods.cs +++ b/Si_AdminMod/HelperMethods.cs @@ -558,6 +558,23 @@ public static bool KickPlayer(Player playerToKick) return spawnedObject; } + #if !NET6_0 + public static byte FindByteValueInEnum(Type parentType, string enumName, string byteName) + { + Type enumType = parentType.GetNestedType(enumName, BindingFlags.NonPublic); + var enumValues = enumType.GetEnumValues(); + foreach (var enumValue in enumValues) + { + if (string.Compare(enumValue.ToString(), byteName) == 0) + { + return (byte)enumValue; + } + } + + return byte.MaxValue; + } + #endif + public static bool IsTimerActive(float time) { if (time >= 0.0f) diff --git a/Si_AdminMod/ModAttributes.cs b/Si_AdminMod/ModAttributes.cs index 2b4b974..b51b694 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.941", "databomb", "https://github.com/data-bomb/Silica")] +[assembly: MelonInfo(typeof(SiAdminMod), "Admin Mod", "2.0.943", "databomb", "https://github.com/data-bomb/Silica")] [assembly: MelonGame("Bohemia Interactive", "Silica")] // Color.Cyan From 4df35811f184a900e2a4ce5f5c369637161c289e Mon Sep 17 00:00:00 2001 From: data-bomb Date: Mon, 2 Sep 2024 19:52:49 -0700 Subject: [PATCH 6/9] Team Balance Game Fixes v0.8.76+ - Leverage FindByteValueInEnum in HelperMethods - Adjust some variable names to camelCase --- Si_BasicTeamBalance/Si_BasicTeamBalance.cs | 92 ++++++++++++---------- 1 file changed, 52 insertions(+), 40 deletions(-) diff --git a/Si_BasicTeamBalance/Si_BasicTeamBalance.cs b/Si_BasicTeamBalance/Si_BasicTeamBalance.cs index ca415cc..59bf6b9 100644 --- a/Si_BasicTeamBalance/Si_BasicTeamBalance.cs +++ b/Si_BasicTeamBalance/Si_BasicTeamBalance.cs @@ -38,7 +38,7 @@ You should have received a copy of the GNU General Public License using SilicaAdminMod; using System.Linq; -[assembly: MelonInfo(typeof(BasicTeamBalance), "Basic Team Balance", "1.3.9", "databomb", "https://github.com/data-bomb/Silica")] +[assembly: MelonInfo(typeof(BasicTeamBalance), "Basic Team Balance", "1.3.10", "databomb", "https://github.com/data-bomb/Silica")] [assembly: MelonGame("Bohemia Interactive", "Silica")] [assembly: MelonOptionalDependencies("Admin Mod")] @@ -54,6 +54,11 @@ public class BasicTeamBalance : MelonMod static MelonPreferences_Entry _PreventEarlyTeamSwitches = null!; static MelonPreferences_Entry _AllowTeamSwitchAfterTime = null!; + #if !NET6_0 + static byte ERPC_ClearRequest = HelperMethods.FindByteValueInEnum(typeof(MP_Strategy), "ERPCs", "CLEAR_REQUEST"); + static byte ERPC_RequestJoinTeam = HelperMethods.FindByteValueInEnum(typeof(MP_Strategy), "ERPCs", "REQUEST_JOIN_TEAM"); + #endif + static Player? LastPlayerChatMessage; static bool preventTeamSwitches; @@ -109,7 +114,11 @@ public override void OnLateInitializeMelon() public static void SendClearRequest(ulong thisPlayerSteam64, int thisPlayerChannel) { // send RPC_ClearRequest (3) + #if NET6_0 GameByteStreamWriter clearWriteInstance = GameMode.CurrentGameMode.CreateRPCPacket((byte)GameModeExt.ERPCs.CLEAR_REQUEST); + #else + GameByteStreamWriter clearWriteInstance = GameMode.CurrentGameMode.CreateRPCPacket(ERPC_ClearRequest); + #endif if (clearWriteInstance != null) { clearWriteInstance.WriteUInt64(thisPlayerSteam64); @@ -290,7 +299,11 @@ public static bool Prefix(MP_Strategy __instance, GameByteStreamReader __0, byte } // only look at RPC_RequestJoinTeam bytes + #if NET6_0 if (__1 != (byte)GameModeExt.ERPCs.REQUEST_JOIN_TEAM) + #else + if (__1 != ERPC_RequestJoinTeam) + #endif { return true; } @@ -302,25 +315,24 @@ public static bool Prefix(MP_Strategy __instance, GameByteStreamReader __0, byte } // after this point we will modify the read pointers so we have to return false - ulong PlayerSteam64 = __0.ReadUInt64(); - CSteamID PlayerCSteamID = new CSteamID(PlayerSteam64); - PlayerCSteamID.m_SteamID = PlayerSteam64; - int PlayerChannel = __0.ReadByte(); - Player JoiningPlayer = Player.FindPlayer(PlayerCSteamID, PlayerChannel); - Team? TargetTeam = __0.ReadTeam(); - - if (JoiningPlayer == null) + ulong playerSteam64 = __0.ReadUInt64(); + NetworkID playerNetworkID = new NetworkID(playerSteam64); + int playerChannel = __0.ReadByte(); + Player joiningPlayer = Player.FindPlayer(playerNetworkID, playerChannel); + Team? targetTeam = __0.ReadTeam(); + + if (joiningPlayer == null) { - Debug.LogError("MP_Strategy::ProcessNetRPC - Player was NULL for REQUEST_JOIN_TEAM, ID: " + PlayerSteam64.ToString() + ", channel: " + PlayerChannel.ToString()); + Debug.LogError("MP_Strategy::ProcessNetRPC - Player was NULL for REQUEST_JOIN_TEAM, ID: " + playerSteam64.ToString() + ", channel: " + playerChannel.ToString()); return false; } - Team mTeam = JoiningPlayer.Team; + Team mTeam = joiningPlayer.Team; // requests to rejoin the same team - if (UnityEngine.Object.Equals(mTeam, TargetTeam)) + if (UnityEngine.Object.Equals(mTeam, targetTeam)) { - SendClearRequest(PlayerSteam64, PlayerChannel); + SendClearRequest(playerSteam64, playerChannel); return false; } @@ -329,74 +341,74 @@ public static bool Prefix(MP_Strategy __instance, GameByteStreamReader __0, byte if (_PreventEarlyTeamSwitches.Value && GameMode.CurrentGameMode.GameOngoing && preventTeamSwitches && mTeam != null && !JoinCausesImbalance(mTeam, __instance)) { // avoid chat spam - if (LastPlayerChatMessage != JoiningPlayer) + if (LastPlayerChatMessage != joiningPlayer) { - HelperMethods.ReplyToCommand_Player(JoiningPlayer, "'s switch was denied due to early game team lock"); - LastPlayerChatMessage = JoiningPlayer; + HelperMethods.ReplyToCommand_Player(joiningPlayer, "'s switch was denied due to early game team lock"); + LastPlayerChatMessage = joiningPlayer; } - MelonLogger.Msg(JoiningPlayer.PlayerName + "'s team switch was denied due to early game team lock"); + MelonLogger.Msg(joiningPlayer.PlayerName + "'s team switch was denied due to early game team lock"); - SendClearRequest(PlayerSteam64, PlayerChannel); + SendClearRequest(playerSteam64, playerChannel); return false; } // if there is some kind of game bug and the player is on an invalid team then let the change occur - if (JoiningPlayer.Team != null && __instance.GetTeamSetup(JoiningPlayer.Team) == null) + if (joiningPlayer.Team != null && __instance.GetTeamSetup(joiningPlayer.Team) == null) { MelonLogger.Warning("Found player on invalid team. Allowing role change."); - JoiningPlayer.Team = TargetTeam; - NetworkLayer.SendPlayerSelectTeam(JoiningPlayer, TargetTeam); + joiningPlayer.Team = targetTeam; + NetworkLayer.SendPlayerSelectTeam(joiningPlayer, targetTeam); return false; } // the team change should be permitted as it doesn't impact balance - if (!JoinCausesImbalance(TargetTeam, __instance)) + if (!JoinCausesImbalance(targetTeam, __instance)) { - JoiningPlayer.Team = TargetTeam; - NetworkLayer.SendPlayerSelectTeam(JoiningPlayer, TargetTeam); + joiningPlayer.Team = targetTeam; + NetworkLayer.SendPlayerSelectTeam(joiningPlayer, targetTeam); return false; } // if the player hasn't joined a team yet, force them to the team that needs it the most - if (JoiningPlayer.Team == null) + if (joiningPlayer.Team == null) { GameModeExt.ETeamsVersus versusMode = __instance.TeamsVersus; Team? ForcedTeam = FindLowestPopulationTeam(__instance); if (ForcedTeam != null) { // avoid chat spam - if (LastPlayerChatMessage != JoiningPlayer) + if (LastPlayerChatMessage != joiningPlayer) { - HelperMethods.ReplyToCommand_Player(JoiningPlayer, " was forced to " + HelperMethods.GetTeamColor(ForcedTeam) + ForcedTeam.TeamShortName + " to fix imbalance"); - LastPlayerChatMessage = JoiningPlayer; + HelperMethods.ReplyToCommand_Player(joiningPlayer, " was forced to " + HelperMethods.GetTeamColor(ForcedTeam) + ForcedTeam.TeamShortName + " to fix imbalance"); + LastPlayerChatMessage = joiningPlayer; } - MelonLogger.Msg(JoiningPlayer.PlayerName + " was forced to " + ForcedTeam.TeamShortName + " to fix imbalance"); + MelonLogger.Msg(joiningPlayer.PlayerName + " was forced to " + ForcedTeam.TeamShortName + " to fix imbalance"); - JoiningPlayer.Team = ForcedTeam; - NetworkLayer.SendPlayerSelectTeam(JoiningPlayer, ForcedTeam); + joiningPlayer.Team = ForcedTeam; + NetworkLayer.SendPlayerSelectTeam(joiningPlayer, ForcedTeam); return false; } MelonLogger.Warning("Error in FindLowestPopulationTeam(). Could not find a valid team."); - SendClearRequest(PlayerSteam64, PlayerChannel); + SendClearRequest(playerSteam64, playerChannel); return false; } // the player has already joined a team but the change would cause an imbalance // avoid chat spam - if (LastPlayerChatMessage != JoiningPlayer) + if (LastPlayerChatMessage != joiningPlayer) { - HelperMethods.ReplyToCommand_Player(JoiningPlayer, "'s switch was denied due to imbalance"); - LastPlayerChatMessage = JoiningPlayer; + HelperMethods.ReplyToCommand_Player(joiningPlayer, "'s switch was denied due to imbalance"); + LastPlayerChatMessage = joiningPlayer; } - MelonLogger.Msg(JoiningPlayer.PlayerName + "'s team switch was denied due to team imbalance"); + MelonLogger.Msg(joiningPlayer.PlayerName + "'s team switch was denied due to team imbalance"); - SendClearRequest(PlayerSteam64, PlayerChannel); + SendClearRequest(playerSteam64, playerChannel); return false; } catch (Exception error) @@ -430,11 +442,11 @@ public static void Postfix(MusicJukeboxHandler __instance, GameMode __0) } } - #if NET6_0 +#if NET6_0 [HarmonyPatch(typeof(MusicJukeboxHandler), nameof(MusicJukeboxHandler.Update))] - #else +#else [HarmonyPatch(typeof(MusicJukeboxHandler), "Update")] - #endif +#endif private static class ApplyPatch_MusicJukeboxHandlerUpdate { private static void Postfix(MusicJukeboxHandler __instance) From acd08638edbc0f0ea9ff1df32ad086f43fae7f48 Mon Sep 17 00:00:00 2001 From: data-bomb Date: Mon, 2 Sep 2024 20:56:20 -0700 Subject: [PATCH 7/9] Silence Game Fixes for v0.8.76+ - Switch to NetworkIDs for latest Steam API --- Si_ChatSilence/Si_Silence.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Si_ChatSilence/Si_Silence.cs b/Si_ChatSilence/Si_Silence.cs index fd37b6d..96a4ee2 100644 --- a/Si_ChatSilence/Si_Silence.cs +++ b/Si_ChatSilence/Si_Silence.cs @@ -37,7 +37,7 @@ You should have received a copy of the GNU General Public License using System.Linq; -[assembly: MelonInfo(typeof(ChatSilence), "Chat Silence", "2.0.0", "databomb", "https://github.com/data-bomb/Silica")] +[assembly: MelonInfo(typeof(ChatSilence), "Chat Silence", "2.0.1", "databomb", "https://github.com/data-bomb/Silica")] [assembly: MelonGame("Bohemia Interactive", "Silica")] [assembly: MelonOptionalDependencies("Admin Mod")] @@ -45,13 +45,13 @@ namespace Si_ChatSilence { public class ChatSilence : MelonMod { - static List silencedPlayers = null!; - static List mutedPlayers = null!; + static List silencedPlayers = null!; + static List mutedPlayers = null!; public override void OnInitializeMelon() { - silencedPlayers = new List(); - mutedPlayers = new List(); + silencedPlayers = new List(); + mutedPlayers = new List(); } public override void OnLateInitializeMelon() @@ -167,7 +167,7 @@ public static bool IsPlayerSilenced(Player player) return silencedPlayers.Any(s => s == player.PlayerID); } - public static bool IsSteamSilenced(CSteamID steamID) + public static bool IsSteamSilenced(NetworkID steamID) { return silencedPlayers.Any(s => s == steamID); } @@ -332,7 +332,7 @@ public static bool IsPlayerMuted(Player player) return mutedPlayers.Any(s => s == player.PlayerID); } - public static bool IsSteamMuted(CSteamID steamID) + public static bool IsSteamMuted(NetworkID steamID) { return mutedPlayers.Any(s => s == steamID); } From bb02329f9e861d785f6eb0373a24f960a5457521 Mon Sep 17 00:00:00 2001 From: data-bomb Date: Tue, 3 Sep 2024 18:27:23 -0700 Subject: [PATCH 8/9] Logging Game Fixes v0.8.76+ - Align changing prototype for SendPlayerChangeName (NetworkID vs CSteamID) --- Si_Logging/Si_Logging.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Si_Logging/Si_Logging.cs b/Si_Logging/Si_Logging.cs index ccbd58d..b2b07c6 100644 --- a/Si_Logging/Si_Logging.cs +++ b/Si_Logging/Si_Logging.cs @@ -44,7 +44,7 @@ You should have received a copy of the GNU General Public License using System.Text; using System.Runtime.CompilerServices; -[assembly: MelonInfo(typeof(HL_Logging), "Half-Life Logger", "1.4.5", "databomb&zawedcvg", "https://github.com/data-bomb/Silica")] +[assembly: MelonInfo(typeof(HL_Logging), "Half-Life Logger", "1.4.6", "databomb&zawedcvg", "https://github.com/data-bomb/Silica")] [assembly: MelonGame("Bohemia Interactive", "Silica")] [assembly: MelonOptionalDependencies("Admin Mod")] @@ -534,13 +534,13 @@ public void OnRoleChanged(object? sender, OnRoleChangedArgs args) [HarmonyPatch(typeof(NetworkLayer), nameof(NetworkLayer.SendPlayerChangeName))] private static class ApplyPatchSendPlayerChangeName { - public static void Postfix(CSteamID __0, int __1, string __2) + public static void Postfix(NetworkID __0, int __1, string __2) { try { // Player player = GetPlayerFromSteamID(__0); // TODO: grab old name and current team - string LogLine = "\"...<><" + __0.ToString() + "><>\" changed name to \"" + __2 + "\""; + string LogLine = "\"...<><" + __0.SteamID.ToString() + "><>\" changed name to \"" + __2 + "\""; PrintLogLine(LogLine); } catch (Exception error) From d06dec1f54bbaef5db26897cf810e30c09e0e62c Mon Sep 17 00:00:00 2001 From: data-bomb Date: Tue, 3 Sep 2024 18:33:20 -0700 Subject: [PATCH 9/9] Commander Manager Game Fixes v0.8.76+ - Correcting SteamID location within NetworkID --- Si_CommManagement/CommanderBanList.cs | 2 +- Si_CommManagement/Si_CommanderManager.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Si_CommManagement/CommanderBanList.cs b/Si_CommManagement/CommanderBanList.cs index b8135e3..7a1c951 100644 --- a/Si_CommManagement/CommanderBanList.cs +++ b/Si_CommManagement/CommanderBanList.cs @@ -103,7 +103,7 @@ public static bool RemoveBan(Player playerToCmdrUnban) } BanEntry? matchingCmdrBan; - matchingCmdrBan = CommanderBans.BanList.Find(i => i.OffenderSteamId == (long)playerToCmdrUnban.PlayerID.m_SteamID); + matchingCmdrBan = CommanderBans.BanList.Find(i => i.OffenderSteamId == (long)playerToCmdrUnban.PlayerID.SteamID.m_SteamID); if (matchingCmdrBan == null) { diff --git a/Si_CommManagement/Si_CommanderManager.cs b/Si_CommManagement/Si_CommanderManager.cs index 608327c..9a34804 100644 --- a/Si_CommManagement/Si_CommanderManager.cs +++ b/Si_CommManagement/Si_CommanderManager.cs @@ -34,7 +34,7 @@ You should have received a copy of the GNU General Public License using System.Linq; using System.Collections.Generic; -[assembly: MelonInfo(typeof(CommanderManager), "Commander Management", "1.8.1", "databomb", "https://github.com/data-bomb/Silica")] +[assembly: MelonInfo(typeof(CommanderManager), "Commander Management", "1.8.2", "databomb", "https://github.com/data-bomb/Silica")] [assembly: MelonGame("Bohemia Interactive", "Silica")] [assembly: MelonOptionalDependencies("Admin Mod")]