Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ConditionalConfigSyncOptionalPatch v1.0.0
patchers/ConditionalConfigSyncOptionalPatch/ConditionalConfigSyncOptionalPatch.dll
Decompiled a month agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using BepInEx; using BepInEx.Logging; using Microsoft.CodeAnalysis; using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Collections.Generic; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("ConditionalConfigSyncOptionalPatch")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("ConditionalConfigSyncOptionalPatch")] [assembly: AssemblyTitle("ConditionalConfigSyncOptionalPatch")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ConditionalConfigSyncOptionalPatch { public static class Patcher { private sealed class PatchSummary { public int ModRequiredAssignments; } private enum PatchStatus { NotApplicable, Patched, AlreadyPatched, SafetyStop } private sealed class PatchResult { public PatchStatus Status { get; } public string Message { get; } private PatchResult(PatchStatus status, string message) { Status = status; Message = message; } public static PatchResult Patched() { return new PatchResult(PatchStatus.Patched, string.Empty); } public static PatchResult AlreadyPatched() { return new PatchResult(PatchStatus.AlreadyPatched, string.Empty); } public static PatchResult NotApplicable(string message) { return new PatchResult(PatchStatus.NotApplicable, message); } public static PatchResult SafetyStop(string message) { return new PatchResult(PatchStatus.SafetyStop, message); } public static PatchResult SafetyStop(Exception exception) { return new PatchResult(PatchStatus.SafetyStop, exception.ToString()); } } private const string TargetAssembly = "assembly_valheim.dll"; private const string PatcherDllName = "ConditionalConfigSyncOptionalPatch.dll"; private const string ConditionalConfigSyncPluginName = "ConditionalConfigSync.Plugin.dll"; private const string ConditionalConfigSyncDllName = "ConditionalConfigSync.dll"; private const string BackupSuffix = ".ccs-original.bak"; private const string MarkerSuffix = ".ccs-patched.sha256"; private static readonly ManualLogSource Log = Logger.CreateLogSource("CCS Optional Patch"); public static IEnumerable<string> TargetDLLs { get { InstallCompatibilityPatches(); yield return "assembly_valheim.dll"; } } public static void Patch(AssemblyDefinition assembly) { } private static void InstallCompatibilityPatches() { string text = Path.Combine(Paths.BepInExRootPath, "plugins"); if (!Directory.Exists(text)) { throw new DirectoryNotFoundException("BepInEx plugin directory was not found: " + text); } Log.LogInfo((object)("Scanning BepInEx plugins for ConditionalConfigSync ModRequired assignments: " + text)); string[] files = Directory.GetFiles(text, "*.dll", SearchOption.AllDirectories); int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; string[] array = files; foreach (string text2 in array) { string fileName = Path.GetFileName(text2); if (string.Equals(fileName, "ConditionalConfigSyncOptionalPatch.dll", StringComparison.OrdinalIgnoreCase)) { Log.LogInfo((object)("Skipping patcher itself: " + text2)); num4++; continue; } if (string.Equals(fileName, "ConditionalConfigSync.dll", StringComparison.OrdinalIgnoreCase)) { Log.LogInfo((object)("Skipping ConditionalConfigSync library: " + text2)); num4++; continue; } if (string.Equals(fileName, "ConditionalConfigSync.Plugin.dll", StringComparison.OrdinalIgnoreCase)) { Log.LogInfo((object)("Skipping ConditionalConfigSync plugin: " + text2)); num4++; continue; } num++; Log.LogInfo((object)("Examining plugin: " + text2)); PatchResult patchResult = PatchPlugin(text2); switch (patchResult.Status) { case PatchStatus.Patched: num2++; break; case PatchStatus.AlreadyPatched: num3++; break; case PatchStatus.SafetyStop: throw new InvalidOperationException(patchResult.Message); } } Log.LogInfo((object)("ConfigSync scan complete. " + $"Examined: {num}, " + $"patched: {num2}, " + $"already patched: {num3}, " + $"skipped: {num4}.")); } private static PatchResult PatchPlugin(string dllPath) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown string fileName = Path.GetFileName(dllPath); string path = dllPath + ".ccs-patched.sha256"; string text = dllPath + ".ccs-original.bak"; string b = ComputeSha256(dllPath); if (File.Exists(path) && string.Equals(File.ReadAllText(path).Trim(), b, StringComparison.OrdinalIgnoreCase)) { Log.LogInfo((object)(fileName + " is already patched.")); return PatchResult.AlreadyPatched(); } ModuleDefinition val; try { val = ModuleDefinition.ReadModule(dllPath, new ReaderParameters { InMemory = true }); } catch (Exception ex) { Log.LogInfo((object)(fileName + ": could not read assembly: " + ex.Message)); return PatchResult.NotApplicable(fileName + ": could not read assembly."); } try { PatchSummary patchSummary = PatchModule(val, fileName); if (patchSummary.ModRequiredAssignments == 0) { Log.LogInfo((object)(fileName + ": no matching ModRequired assignment found.")); return PatchResult.NotApplicable(fileName + ": no matching ModRequired assignment found."); } Log.LogInfo((object)(fileName + ": found " + $"{patchSummary.ModRequiredAssignments} " + "ModRequired=true assignment(s).")); string text2 = dllPath + ".ccs.tmp"; if (File.Exists(text2)) { File.Delete(text2); } try { val.Write(text2); } catch { if (File.Exists(text2)) { File.Delete(text2); } throw; } if (!File.Exists(text)) { File.Copy(dllPath, text, overwrite: false); Log.LogInfo((object)(fileName + ": original backed up to " + Path.GetFileName(text))); } try { File.Copy(text2, dllPath, overwrite: true); } catch { if (File.Exists(text)) { File.Copy(text, dllPath, overwrite: true); } throw; } finally { if (File.Exists(text2)) { File.Delete(text2); } } string text3 = ComputeSha256(dllPath); File.WriteAllText(path, text3 + Environment.NewLine); Log.LogInfo((object)(fileName + ": PATCHED " + $"{patchSummary.ModRequiredAssignments} " + "ModRequired=true assignment(s) to false.")); Log.LogInfo((object)(fileName + ": patched SHA256 = " + text3)); return PatchResult.Patched(); } catch (InvalidOperationException ex2) { return PatchResult.SafetyStop(fileName + ": " + ex2.Message); } catch (Exception arg) { Log.LogError((object)$"{fileName}: patching failed: {arg}"); return PatchResult.NotApplicable(fileName + ": patching failed."); } finally { val.Dispose(); } } private static PatchSummary PatchModule(ModuleDefinition module, string fileName) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) PatchSummary patchSummary = new PatchSummary(); foreach (TypeDefinition item in GetTypeTree((IEnumerable<TypeDefinition>)module.Types)) { Enumerator<MethodDefinition> enumerator2 = item.Methods.GetEnumerator(); try { while (enumerator2.MoveNext()) { MethodDefinition current = enumerator2.Current; if (!current.HasBody) { continue; } IList<Instruction> instructions = (IList<Instruction>)current.Body.Instructions; for (int i = 0; i < instructions.Count; i++) { Instruction val = instructions[i]; if (!IsModRequiredSetterCall(val)) { continue; } Log.LogInfo((object)(fileName + ": FOUND ModRequired setter")); Log.LogInfo((object)(" Method: " + ((MemberReference)current).FullName)); Log.LogInfo((object)$" IL: {val}"); object operand = val.Operand; MethodReference val2 = (MethodReference)((operand is MethodReference) ? operand : null); if (val2 != null) { Log.LogInfo((object)(" Setter: " + ((MemberReference)val2).FullName)); Log.LogInfo((object)(" Declaring type: " + ((MemberReference)((MemberReference)val2).DeclaringType).FullName)); Log.LogInfo((object)(" Declaring type scope: " + $"{((MemberReference)val2).DeclaringType.Scope}")); Log.LogInfo((object)(" Return type: " + ((MemberReference)val2.ReturnType).FullName)); Log.LogInfo((object)(" Parameter count: " + $"{val2.Parameters.Count}")); if (val2.Parameters.Count == 1) { Log.LogInfo((object)(" Parameter type: " + ((MemberReference)((ParameterReference)val2.Parameters[0]).ParameterType).FullName)); } } if (i == 0) { throw new InvalidOperationException("Found ModRequired setter in " + ((MemberReference)current).FullName + ", but it has no preceding instruction."); } Instruction val3 = instructions[i - 1]; Log.LogInfo((object)(" Previous IL: " + $"{val3}")); if (!IsBooleanTrue(val3)) { Log.LogWarning((object)" ModRequired setter found, but the preceding instruction does not load boolean true."); continue; } Log.LogInfo((object)($" Changing {val3} " + "to ldc.i4.0")); val3.OpCode = OpCodes.Ldc_I4_0; val3.Operand = null; patchSummary.ModRequiredAssignments++; Log.LogInfo((object)(" PATCHED " + ((MemberReference)current).FullName + " " + $"at IL offset 0x{val.Offset:X4}")); } } } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } } return patchSummary; } private static bool IsModRequiredSetterCall(Instruction instruction) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) if (instruction.OpCode != OpCodes.Call && instruction.OpCode != OpCodes.Callvirt) { return false; } object operand = instruction.Operand; MethodReference val = (MethodReference)((operand is MethodReference) ? operand : null); if (val == null) { return false; } if (!string.Equals(((MemberReference)val).Name, "set_ModRequired", StringComparison.Ordinal)) { return false; } if (!string.Equals(((MemberReference)val.ReturnType).FullName, "System.Void", StringComparison.Ordinal)) { return false; } if (val.Parameters.Count != 1) { return false; } if (!string.Equals(((MemberReference)((ParameterReference)val.Parameters[0]).ParameterType).FullName, "System.Boolean", StringComparison.Ordinal)) { return false; } return true; } private static bool IsBooleanTrue(Instruction instruction) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (instruction.OpCode == OpCodes.Ldc_I4_1) { return true; } if (instruction.OpCode == OpCodes.Ldc_I4 && instruction.Operand is int num && num == 1) { return true; } return false; } private static IEnumerable<TypeDefinition> GetTypeTree(IEnumerable<TypeDefinition> types) { foreach (TypeDefinition type in types) { yield return type; foreach (TypeDefinition item in GetTypeTree((IEnumerable<TypeDefinition>)type.NestedTypes)) { yield return item; } } } private static string ComputeSha256(string path) { using SHA256 sHA = SHA256.Create(); using FileStream inputStream = File.OpenRead(path); return BitConverter.ToString(sHA.ComputeHash(inputStream)).Replace("-", string.Empty); } } }