From 63f580d149aee243023be6a262a85f0a1da7e703 Mon Sep 17 00:00:00 2001 From: Death Date: Mon, 17 Aug 2020 12:06:52 +0200 Subject: [PATCH 01/12] Make Internal equivalents methods for NetworkingAPI so that SetHooks can register properly the types without throwing --- R2API/Networking/NetworkingAPI.cs | 37 +++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/R2API/Networking/NetworkingAPI.cs b/R2API/Networking/NetworkingAPI.cs index 66813070..3d175a16 100644 --- a/R2API/Networking/NetworkingAPI.cs +++ b/R2API/Networking/NetworkingAPI.cs @@ -29,13 +29,19 @@ public static bool Loaded { private static readonly Dictionary NetRequests = new Dictionary(); public static bool RegisterMessageType() where TMessage : INetMessage, new() { - if(!Loaded) { + if (!Loaded) { throw new InvalidOperationException($"{nameof(NetworkingAPI)} is not loaded. Please use [{nameof(R2APISubmoduleDependency)}(nameof({nameof(NetworkingAPI)})]"); } + + return RegisterMessageTypeInternal(); + } + + internal static bool RegisterMessageTypeInternal() where TMessage : INetMessage, new () { var inst = new TMessage(); - var type = inst.GetType(); + var type = inst.GetType(); int hash = GetNetworkHash(type); + if (NetMessages.ContainsKey(hash)) { R2API.Logger.LogError("Tried to register a message type with a duplicate hash"); return false; @@ -47,10 +53,16 @@ public static bool Loaded { } public static bool RegisterCommandType() where TCommand : INetCommand, new() { - if(!Loaded) { + if (!Loaded) { throw new InvalidOperationException($"{nameof(NetworkingAPI)} is not loaded. Please use [{nameof(R2APISubmoduleDependency)}(nameof({nameof(NetworkingAPI)})]"); } + + return RegisterCommandTypeInternal(); + } + + public static bool RegisterCommandTypeInternal() where TCommand : INetCommand, new() { var inst = new TCommand(); + var type = inst.GetType(); int hash = GetNetworkHash(type); @@ -67,9 +79,16 @@ public static bool Loaded { public static bool RegisterRequestTypes() where TRequest : INetRequest, new() where TReply : INetRequestReply, new() { - if(!Loaded) { + if (!Loaded) { throw new InvalidOperationException($"{nameof(NetworkingAPI)} is not loaded. Please use [{nameof(R2APISubmoduleDependency)}(nameof({nameof(NetworkingAPI)})]"); } + + return RegisterRequestTypesInternal(); + } + + internal static bool RegisterRequestTypesInternal() + where TRequest : INetRequest, new() + where TReply : INetRequestReply, new() { var request = new TRequest(); var reply = new TReply(); @@ -86,12 +105,12 @@ public static bool RegisterRequestTypes() [R2APISubmoduleInit(Stage = InitStage.SetHooks)] internal static void SetHooks() { - RegisterMessageType(); - RegisterMessageType(); - RegisterMessageType(); + RegisterMessageTypeInternal(); + RegisterMessageTypeInternal(); + RegisterMessageTypeInternal(); - RegisterMessageType(); - RegisterRequestTypes(); + RegisterMessageTypeInternal(); + RegisterRequestTypesInternal(); GameNetworkManager.onStartServerGlobal += RegisterServerHandlers; GameNetworkManager.onStartClientGlobal += RegisterClientHandlers; From fdcd72fa29ebe8e25a82edb3c1f2c5181221df25 Mon Sep 17 00:00:00 2001 From: KingEnderBrine <31794213+KingEnderBrine@users.noreply.github.com> Date: Mon, 17 Aug 2020 18:57:14 +0700 Subject: [PATCH 02/12] [LanguageAPI] load from file fix --- R2API/LanguageAPI.cs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/R2API/LanguageAPI.cs b/R2API/LanguageAPI.cs index 25791ba5..7aee34fe 100644 --- a/R2API/LanguageAPI.cs +++ b/R2API/LanguageAPI.cs @@ -64,14 +64,23 @@ private static void LoadCustomTokensFromFile(string file) { return; } - var languageTokens = jsonNode.Keys; - foreach (var language in languageTokens) { - JSONNode generic = jsonNode[language]; - if (generic == null) { + var genericsAdded = false; + var languages = jsonNode.Keys; + foreach (var language in languages) { + JSONNode languageTokens = jsonNode[language]; + if (languageTokens == null) { return; } - foreach (string text in generic.Keys) { - Add(text, generic[text].Value); + + if (!genericsAdded) { + foreach (string text in languageTokens.Keys) { + Add(text, languageTokens[text].Value); + } + genericsAdded = true; + } + + foreach (string text in languageTokens.Keys) { + Add(text, languageTokens[text].Value, language); } } } From dd2b196add37adb40113326603973e4f2c64f418 Mon Sep 17 00:00:00 2001 From: Death Date: Thu, 20 Aug 2020 03:23:28 +0200 Subject: [PATCH 03/12] Apparently Cecil can send back an empty CustomAttributeArgument list --- R2API/Utils/NetworkCompatibility.cs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/R2API/Utils/NetworkCompatibility.cs b/R2API/Utils/NetworkCompatibility.cs index 9da10c56..09d67b81 100644 --- a/R2API/Utils/NetworkCompatibility.cs +++ b/R2API/Utils/NetworkCompatibility.cs @@ -146,13 +146,16 @@ void CallWhenAssembliesAreScanned() { private static void TryGetNetworkCompatibilityArguments(IList attributeArguments, out CompatibilityLevel compatibilityLevel, out VersionStrictness versionStrictness) { - if (attributeArguments[0].Value is int && attributeArguments[1].Value is int) { - compatibilityLevel = (CompatibilityLevel)attributeArguments[0].Value; - versionStrictness = (VersionStrictness)attributeArguments[1].Value; - } - else { - compatibilityLevel = CompatibilityLevel.EveryoneMustHaveMod; - versionStrictness = VersionStrictness.EveryoneNeedSameModVersion; + compatibilityLevel = CompatibilityLevel.EveryoneMustHaveMod; + versionStrictness = VersionStrictness.EveryoneNeedSameModVersion; + + if (attributeArguments != null && attributeArguments.Count > 0) { + if (attributeArguments[0].Value is int) { + compatibilityLevel = (CompatibilityLevel)attributeArguments[0].Value; + } + if (attributeArguments[1].Value is int) { + versionStrictness = (VersionStrictness)attributeArguments[1].Value; + } } } } From 935870c85e8af971998b67bd60201e58c9c81f91 Mon Sep 17 00:00:00 2001 From: Death Date: Thu, 20 Aug 2020 14:57:54 +0200 Subject: [PATCH 04/12] - DetectAndRemoveDuplicateAssemblies now work with assemblies that have multiple BepinPlugin types in it - Add Debug Log when the plugin scanner fails to scan an assembly --- R2API/Utils/PluginScanner.cs | 85 ++++++++++++++++++++++++++++-------- 1 file changed, 67 insertions(+), 18 deletions(-) diff --git a/R2API/Utils/PluginScanner.cs b/R2API/Utils/PluginScanner.cs index 60e38a47..e37f4b0a 100644 --- a/R2API/Utils/PluginScanner.cs +++ b/R2API/Utils/PluginScanner.cs @@ -15,9 +15,13 @@ private List PluginsAssemblyDefinitions { var assemblies = new List(); var resolver = new DefaultAssemblyResolver(); var gameDirectory = new DirectoryInfo(Paths.GameRootPath); + + // todo: make resolver able to resolve embedded assemblies foreach (var directory in gameDirectory.EnumerateDirectories("*", SearchOption.AllDirectories)) { resolver.AddSearchDirectory(directory.FullName); } + + R2API.Logger.LogDebug("Adding to the list of assemblies to scan:"); foreach (string dll in Directory.GetFiles(Paths.PluginPath, "*.dll", SearchOption.AllDirectories)) { var fileName = Path.GetFileName(dll); @@ -28,9 +32,10 @@ private List PluginsAssemblyDefinitions { try { assemblies.Add(AssemblyDefinition.ReadAssembly(dll, new ReaderParameters { AssemblyResolver = resolver })); + R2API.Logger.LogDebug($"{fileName}"); } catch (Exception) { - // ignored + R2API.Logger.LogDebug($"Cecil ReadAssembly couldn't read {dll}"); } } @@ -43,23 +48,53 @@ private List PluginsAssemblyDefinitions { } private static void DetectAndRemoveDuplicateAssemblies(ref List assemblies) { - var bepinPluginAttributes = assemblies.SelectMany(assemblyDef => - assemblyDef.MainModule.Types.SelectMany(typeDef => typeDef.CustomAttributes)) - .Where(attribute => attribute.AttributeType.FullName == typeof(BepInPlugin).FullName); - var duplicateOldAssemblies = new HashSet(); - foreach (var bepinPlugin in bepinPluginAttributes) { - var (modGuid, modVer) = GetBepinPluginInfo(bepinPlugin.ConstructorArguments); - foreach (var bepinPlugin2 in bepinPluginAttributes) { - if (bepinPlugin == bepinPlugin2) + + foreach (var assemblyDef in assemblies) { + var bepinPluginAttributes = assemblyDef.MainModule.Types.SelectMany(typeDef => typeDef.CustomAttributes) + .Where(attribute => attribute.AttributeType.FullName == typeof(BepInPlugin).FullName).ToList(); + foreach (var otherAssemblyDef in assemblies) { + if (assemblyDef == otherAssemblyDef) continue; - var (modGuid2, modVer2) = GetBepinPluginInfo(bepinPlugin2.ConstructorArguments); + var otherBepinPluginAttributes = otherAssemblyDef.MainModule.Types.SelectMany(typeDef => typeDef.CustomAttributes) + .Where(attribute => attribute.AttributeType.FullName == typeof(BepInPlugin).FullName).ToList(); + + AssemblyDefinition goodAssembly = null; + string goodAssemblyVer = null; + AssemblyDefinition oldDuplicateAssembly = null; + string oldDuplicateModVer = null; + + var count = bepinPluginAttributes.Count; + if (count > 0) { + if (count == otherBepinPluginAttributes.Count) { + for (int i = 0; i < count; i++) { + var (modGuid, modVer) = GetBepinPluginInfo(bepinPluginAttributes[i].ConstructorArguments); + var (otherModGuid, otherModVer) = GetBepinPluginInfo(otherBepinPluginAttributes[i].ConstructorArguments); + + if (modGuid == null) + break; + + if (modGuid == otherModGuid) { + var comparedTo = string.Compare(modVer, otherModVer, StringComparison.Ordinal); + if (comparedTo >= 0) { + goodAssembly = bepinPluginAttributes[i].AttributeType.Module.Assembly; + goodAssemblyVer = modVer; + oldDuplicateAssembly = otherBepinPluginAttributes[i].AttributeType.Module.Assembly; + oldDuplicateModVer = otherModVer; + } + } + else { + oldDuplicateAssembly = null; + break; + } + } - if (modGuid == modGuid2) { - var comparedTo = string.Compare(modVer, modVer2, StringComparison.Ordinal); - if (comparedTo >= 0) { - duplicateOldAssemblies.Add(bepinPlugin2.AttributeType.Module.Assembly); + if (oldDuplicateAssembly != null) { + R2API.Logger.LogDebug($"Removing {oldDuplicateAssembly.MainModule.FileName} (ModVer : {oldDuplicateModVer}) from the list " + + $"because it's a duplicate of {goodAssembly.MainModule.FileName} (ModVer : {goodAssemblyVer})."); + duplicateOldAssemblies.Add(oldDuplicateAssembly); + } } } } @@ -135,8 +170,15 @@ private void ScanAssemblyTypes(IEnumerable types) { } } } - catch (Exception) { - // ignored + catch (Exception ex) { + // AssemblyResolutionException will happen on types that are resolved from + // dynamicaly loaded / soft dependency assemblies + if (!(ex is AssemblyResolutionException)) { + R2API.Logger.LogDebug( + $"Catched ex when handling attribute scan request : {ex}\n" + + $"We were looking for {attributeScanRequest.SearchedTypeFullName} " + + $"in the assembly called {typeDef.Module.FileName}"); + } } } } @@ -153,8 +195,15 @@ private void ScanAssemblyTypes(IEnumerable types) { } } } - catch (Exception) { - // ignored + catch (Exception ex) { + // AssemblyResolutionException will happen on types that are resolved from + // dynamicaly loaded / soft dependency assemblies + if (!(ex is AssemblyResolutionException)) { + R2API.Logger.LogDebug( + $"Catched ex when handling class scan request : {ex}\n" + + $"We were looking for {classScanRequest.SearchedTypeFullName} " + + $"in the assembly called {typeDef.Module.FileName}"); + } } } } From cb3a0de0d1373b41ca7cb06456a09147fc4ef5ac Mon Sep 17 00:00:00 2001 From: Death Date: Thu, 20 Aug 2020 22:08:14 +0200 Subject: [PATCH 05/12] - Add message so that end user know what mods they are missing when a mod mismatch happen - Add a more detailed error message when the monomod patch of r2api is not loaded --- R2API/R2API.cs | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/R2API/R2API.cs b/R2API/R2API.cs index 4580dd86..ca080f0f 100644 --- a/R2API/R2API.cs +++ b/R2API/R2API.cs @@ -89,7 +89,7 @@ static GameNetworkManager.SimpleLocalizedKickReason SwapToStandardMessage(GameNe { reason.GetDisplayTokenAndFormatParams(out var token, out _); return new GameNetworkManager.SimpleLocalizedKickReason(token, - "This information is not yet available, see below the list of all mods the server needs you to have : ", + "", string.Join("\n", NetworkModCompatibilityHelper.networkModList)); } c.Index++; @@ -97,6 +97,28 @@ static GameNetworkManager.SimpleLocalizedKickReason SwapToStandardMessage(GameNe } }; + // Temporary fix for displaying correctly the mods that the user is missing when trying to connect + On.RoR2.Networking.GameNetworkManager.SimpleLocalizedKickReason.GetDisplayTokenAndFormatParams += + (On.RoR2.Networking.GameNetworkManager.SimpleLocalizedKickReason.orig_GetDisplayTokenAndFormatParams orig, + GameNetworkManager.SimpleLocalizedKickReason self, out string token, out object[] formatArgs) => { + var baseToken = self.baseToken; + var args = self.formatArgs; + token = baseToken; + if (baseToken != "KICK_REASON_MOD_MISMATCH") + { + token = baseToken; + formatArgs = args; + return; + } + var mods = args[1].Split('\n'); + var myMods = NetworkModCompatibilityHelper.networkModList; + + var extraMods = string.Join("\n", myMods.Except(mods)); + var missingMods = string.Join("\n", mods.Except(myMods)); + + formatArgs = new object[] { extraMods, missingMods }; + }; + // Temporary fix until the KVP Foreach properly check for null Value before calling Equals on them IL.RoR2.SteamworksLobbyDataGenerator.RebuildLobbyData += il => { var c = new ILCursor(il); @@ -221,12 +243,17 @@ private static void CheckForIncompatibleAssemblies() { private static void CheckR2APIMonomodPatch() { var isHere = AppDomain.CurrentDomain.GetAssemblies().Any(assembly => assembly.FullName.ToLower().Contains("r2api.mm.monomodrules")); - if (!isHere) { + if (isHere) { var message = new List { "The Monomod patch of R2API seems to be missing", "Please make sure that a file called:", "Assembly-CSharp.R2API.mm.dll", "is present in the Risk of Rain 2\\BepInEx\\monomod\\ folder", + "or", + "You are missing the monomod loader that is normally located in,", + "the Risk of Rain 2\\BepInEx\\patchers\\BepInEx.MonoMod.Loader folder.", + "If you don't have this folder, please download BepInEx again from the", + "thunderstore and make sure to follow the installation instructions." }; Logger.LogBlockError(message); } From db84354f0d7e8645235057c15f2c98f3a739e044 Mon Sep 17 00:00:00 2001 From: Death Date: Thu, 20 Aug 2020 23:17:36 +0200 Subject: [PATCH 06/12] Elite Tier array Index was incorrectly set at 1 instead of the current elite tier. --- R2API/EliteAPI.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/R2API/EliteAPI.cs b/R2API/EliteAPI.cs index fc95285c..556422ef 100644 --- a/R2API/EliteAPI.cs +++ b/R2API/EliteAPI.cs @@ -57,7 +57,6 @@ private static void GetOriginalEliteCountHook(ILContext il) { private static void AddEliteAction(List eliteDefinitions) { foreach (var customElite in EliteDefinitions) { eliteDefinitions.Add(customElite.EliteDef); - var currentEliteTiers = GetCombatDirectorEliteTiers(); if (customElite.EliteTier == 1) { var index = currentEliteTiers[1].eliteTypes.Length; @@ -69,7 +68,7 @@ private static void AddEliteAction(List eliteDefinitions) { var eliteTierIndex = customElite.EliteTier + 1; var eliteTypeIndex = currentEliteTiers[eliteTierIndex].eliteTypes.Length; Array.Resize(ref currentEliteTiers[eliteTierIndex].eliteTypes, eliteTypeIndex + 1); - currentEliteTiers[1].eliteTypes[eliteTypeIndex] = customElite.EliteDef.eliteIndex; + currentEliteTiers[eliteTierIndex].eliteTypes[eliteTypeIndex] = customElite.EliteDef.eliteIndex; } OverrideCombatDirectorEliteTiers(currentEliteTiers); From cabf233c0c77a9d78dcccef1ee5b596f8c4ae52f Mon Sep 17 00:00:00 2001 From: Death Date: Thu, 20 Aug 2020 23:31:10 +0200 Subject: [PATCH 07/12] revert back test --- R2API/R2API.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R2API/R2API.cs b/R2API/R2API.cs index ca080f0f..28c57de9 100644 --- a/R2API/R2API.cs +++ b/R2API/R2API.cs @@ -243,7 +243,7 @@ private static void CheckForIncompatibleAssemblies() { private static void CheckR2APIMonomodPatch() { var isHere = AppDomain.CurrentDomain.GetAssemblies().Any(assembly => assembly.FullName.ToLower().Contains("r2api.mm.monomodrules")); - if (isHere) { + if (!isHere) { var message = new List { "The Monomod patch of R2API seems to be missing", "Please make sure that a file called:", From 8c66f4e3b5c7ac8d46aef7f2141e1a5c24334ff8 Mon Sep 17 00:00:00 2001 From: Death Date: Thu, 20 Aug 2020 23:51:31 +0200 Subject: [PATCH 08/12] More logging for NetworkCompatibility --- R2API/Utils/NetworkCompatibility.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/R2API/Utils/NetworkCompatibility.cs b/R2API/Utils/NetworkCompatibility.cs index 09d67b81..33285ed2 100644 --- a/R2API/Utils/NetworkCompatibility.cs +++ b/R2API/Utils/NetworkCompatibility.cs @@ -12,7 +12,8 @@ namespace R2API.Utils { /// public enum CompatibilityLevel { NoNeedForSync, - EveryoneMustHaveMod + EveryoneMustHaveMod, + BreaksMultiplayer } /// @@ -83,8 +84,13 @@ internal void BuildModList(PluginScanner pluginScanner) { // By default, any plugins that don't have the NetworkCompatibility attribute and // don't have the ManualNetworkRegistration attribute are added to the networked mod list if (!haveNetworkCompatAttribute) { - if (bepinPluginAttribute != null && !haveManualRegistrationAttribute) { - modList.Add(modGuid + ModGuidAndModVersionSeparator + modVersion); + if (bepinPluginAttribute != null){ + if (!haveManualRegistrationAttribute) { + modList.Add(modGuid + ModGuidAndModVersionSeparator + modVersion); + } + else { + R2API.Logger.LogDebug($"Found {nameof(ManualNetworkRegistrationAttribute)} type. Ignoring."); + } } else { R2API.Logger.LogDebug($"Found {nameof(BaseUnityPlugin)} type but no {nameof(BepInPlugin)} attribute"); From 832f6efabd0fff2056e8fe899d09fe8017709f6f Mon Sep 17 00:00:00 2001 From: Death Date: Fri, 21 Aug 2020 01:11:15 +0200 Subject: [PATCH 09/12] LoadedModules goes static so that NetworkCompatibility can access it (R2API.IsLoaded isnt available yet) --- R2API/Utils/APISubmodule.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R2API/Utils/APISubmodule.cs b/R2API/Utils/APISubmodule.cs index 26dfd7c7..425acb10 100644 --- a/R2API/Utils/APISubmodule.cs +++ b/R2API/Utils/APISubmodule.cs @@ -53,7 +53,7 @@ public class APISubmoduleHandler { private readonly int _build; private readonly ManualLogSource _logger; private HashSet _moduleSet; - private HashSet LoadedModules; + private static HashSet LoadedModules; internal APISubmoduleHandler(int build, ManualLogSource logger = null) { _build = build; @@ -64,7 +64,7 @@ internal APISubmoduleHandler(int build, ManualLogSource logger = null) { /// Return true if the specified submodule is loaded. /// /// nameof the submodule - public bool IsLoaded(string submodule) => LoadedModules.Contains(submodule); + public static bool IsLoaded(string submodule) => LoadedModules.Contains(submodule); internal HashSet LoadRequested(PluginScanner pluginScanner) { _moduleSet = new HashSet(); From 3400e88baaaabf67485c7a892dfaeb88ef10eb4c Mon Sep 17 00:00:00 2001 From: Death Date: Fri, 21 Aug 2020 01:11:54 +0200 Subject: [PATCH 10/12] Add R2API to the network mod list if networking api is enabled : It can affect networking and ready to use messages could be different from a r2api version to another --- R2API/Utils/NetworkCompatibility.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/R2API/Utils/NetworkCompatibility.cs b/R2API/Utils/NetworkCompatibility.cs index 33285ed2..5ad3111a 100644 --- a/R2API/Utils/NetworkCompatibility.cs +++ b/R2API/Utils/NetworkCompatibility.cs @@ -4,11 +4,13 @@ using System.Linq; using BepInEx; using Mono.Cecil; +using R2API.Networking; using RoR2; namespace R2API.Utils { /// /// Enum used for telling whether or not the mod should be needed by everyone in multiplayer games. + /// Also can specify if the mod does not work in multiplayer. /// public enum CompatibilityLevel { NoNeedForSync, @@ -139,6 +141,9 @@ internal void BuildModList(PluginScanner pluginScanner) { void CallWhenAssembliesAreScanned() { if (modList.Count != 0) { + if (IsR2APIAffectingNetwork()) { + modList.Add(R2API.PluginGUID + ModGuidAndModVersionSeparator + R2API.PluginVersion); + } var sortedModList = modList.ToList(); sortedModList.Sort(); R2API.Logger.LogInfo("[NetworkCompatibility] Adding to the networkModList : "); @@ -150,6 +155,10 @@ void CallWhenAssembliesAreScanned() { } } + internal static bool IsR2APIAffectingNetwork() { + return APISubmoduleHandler.IsLoaded(nameof(NetworkingAPI)); + } + private static void TryGetNetworkCompatibilityArguments(IList attributeArguments, out CompatibilityLevel compatibilityLevel, out VersionStrictness versionStrictness) { compatibilityLevel = CompatibilityLevel.EveryoneMustHaveMod; From 48b3ad2dea6993030ad784a981b93db4e8fcd22b Mon Sep 17 00:00:00 2001 From: Death Date: Fri, 21 Aug 2020 02:17:53 +0200 Subject: [PATCH 11/12] Better detection of duplicate assemblies that could be sitting in the plugins folder --- R2API/Utils/PluginScanner.cs | 56 +++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/R2API/Utils/PluginScanner.cs b/R2API/Utils/PluginScanner.cs index e37f4b0a..be1fd2b9 100644 --- a/R2API/Utils/PluginScanner.cs +++ b/R2API/Utils/PluginScanner.cs @@ -51,9 +51,13 @@ private static void DetectAndRemoveDuplicateAssemblies(ref List(); foreach (var assemblyDef in assemblies) { + if (duplicateOldAssemblies.Contains(assemblyDef)) + continue; var bepinPluginAttributes = assemblyDef.MainModule.Types.SelectMany(typeDef => typeDef.CustomAttributes) .Where(attribute => attribute.AttributeType.FullName == typeof(BepInPlugin).FullName).ToList(); foreach (var otherAssemblyDef in assemblies) { + if (duplicateOldAssemblies.Contains(otherAssemblyDef)) + continue; if (assemblyDef == otherAssemblyDef) continue; @@ -65,38 +69,36 @@ private static void DetectAndRemoveDuplicateAssemblies(ref List 0) { - if (count == otherBepinPluginAttributes.Count) { - for (int i = 0; i < count; i++) { - var (modGuid, modVer) = GetBepinPluginInfo(bepinPluginAttributes[i].ConstructorArguments); - var (otherModGuid, otherModVer) = GetBepinPluginInfo(otherBepinPluginAttributes[i].ConstructorArguments); - - if (modGuid == null) - break; - - if (modGuid == otherModGuid) { - var comparedTo = string.Compare(modVer, otherModVer, StringComparison.Ordinal); - if (comparedTo >= 0) { - goodAssembly = bepinPluginAttributes[i].AttributeType.Module.Assembly; - goodAssemblyVer = modVer; - oldDuplicateAssembly = otherBepinPluginAttributes[i].AttributeType.Module.Assembly; - oldDuplicateModVer = otherModVer; - } - } - else { - oldDuplicateAssembly = null; - break; + foreach (var bepinPluginAttribute in bepinPluginAttributes) { + var (modGuid, modVer) = GetBepinPluginInfo(bepinPluginAttribute.ConstructorArguments); + + if (modGuid == null) + break; + + foreach (var otherBepinPluginAttribute in otherBepinPluginAttributes) { + var (otherModGuid, otherModVer) = GetBepinPluginInfo(otherBepinPluginAttribute.ConstructorArguments); + if (modGuid == otherModGuid) { + var comparedTo = string.Compare(modVer, otherModVer, StringComparison.Ordinal); + var isModVerMoreRecentThanOtherModVer = comparedTo >= 0; + if (isModVerMoreRecentThanOtherModVer) { + goodAssembly = bepinPluginAttribute.AttributeType.Module.Assembly; + goodAssemblyVer = modVer; + oldDuplicateAssembly = otherBepinPluginAttribute.AttributeType.Module.Assembly; + oldDuplicateModVer = otherModVer; } } - - if (oldDuplicateAssembly != null) { - R2API.Logger.LogDebug($"Removing {oldDuplicateAssembly.MainModule.FileName} (ModVer : {oldDuplicateModVer}) from the list " + - $"because it's a duplicate of {goodAssembly.MainModule.FileName} (ModVer : {goodAssemblyVer})."); - duplicateOldAssemblies.Add(oldDuplicateAssembly); + else { + oldDuplicateAssembly = null; + break; } } } + + if (oldDuplicateAssembly != null) { + R2API.Logger.LogDebug($"Removing {oldDuplicateAssembly.MainModule.FileName} (ModVer : {oldDuplicateModVer}) from the list " + + $"because it's a duplicate of {goodAssembly.MainModule.FileName} (ModVer : {goodAssemblyVer})."); + duplicateOldAssemblies.Add(oldDuplicateAssembly); + } } } From ddc1dad1bcdd973ca58dc23021f4aef108acb4bf Mon Sep 17 00:00:00 2001 From: Death Date: Fri, 21 Aug 2020 02:22:25 +0200 Subject: [PATCH 12/12] todo for BreaksMultiplayer mod --- R2API/Utils/NetworkCompatibility.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R2API/Utils/NetworkCompatibility.cs b/R2API/Utils/NetworkCompatibility.cs index 5ad3111a..bbb26c68 100644 --- a/R2API/Utils/NetworkCompatibility.cs +++ b/R2API/Utils/NetworkCompatibility.cs @@ -15,7 +15,7 @@ namespace R2API.Utils { public enum CompatibilityLevel { NoNeedForSync, EveryoneMustHaveMod, - BreaksMultiplayer + //BreaksMultiplayer //todo } /// @@ -32,7 +32,7 @@ public enum VersionStrictness { /// you want to specify if the mod should be installed by everyone in multiplayer games or not. /// If the mod is required to be installed by everyone, you'll need to also specify if the same mod version should be used by everyone or not. /// By default, it's supposed that everyone needs the mod and the same version. - /// e.g: [NetworkCompatibility(CompatibilityLevel.NoNeedForSync, VersionStrictness.DifferentModVersionsAreOk)] + /// e.g: [NetworkCompatibility(CompatibilityLevel.NoNeedForSync)] /// [AttributeUsage(AttributeTargets.Class | AttributeTargets.Assembly)] public class NetworkCompatibility : Attribute {