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 ReviveDesyncPatch v1.0.0
ReviveDesyncPatch.dll
Decompiled 6 months agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("ReviveDesyncPatch")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ReviveDesyncPatch")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("9f24b82b-ae21-4493-9097-c1f358f90742")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace ReviveDesyncPatch { [BepInPlugin("DaanSmoki.ReviveDesyncPatch", "ReviveDesyncPatch", "1.0.0")] public sealed class BaseClass : BaseUnityPlugin { public const string ModGUID = "DaanSmoki.ReviveDesyncPatch"; public const string ModName = "ReviveDesyncPatch"; public const string ModVersion = "1.0.0"; private ConfigEntry<float> _endOfGameWaitUntilTimeoutSeconds; internal static BaseClass Instance { get; private set; } internal static Harmony Harmony { get; private set; } internal static ManualLogSource Log { get; private set; } internal static float TimeoutSeconds { get { float valueOrDefault = (Instance?._endOfGameWaitUntilTimeoutSeconds?.Value).GetValueOrDefault(10f); return Mathf.Max(1f, valueOrDefault); } } private void Awake() { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; _endOfGameWaitUntilTimeoutSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("General", "EndOfGameWaitUntilTimeoutSeconds", 10f, "Max seconds to wait for playersRevived >= connectedPlayers in EndOfGame before forcing continuation (set 5–10s)."); Log.LogInfo((object)string.Format("{0} {1} initializing… (Timeout={2:0.##}s)", "ReviveDesyncPatch", "1.0.0", TimeoutSeconds)); Harmony = new Harmony("DaanSmoki.ReviveDesyncPatch"); Harmony.PatchAll(Assembly.GetExecutingAssembly()); Log.LogInfo((object)"ReviveDesyncPatch initialized and patches applied."); } } internal sealed class WaitUntilOrTimeout : CustomYieldInstruction { private readonly Func<bool> _predicate; private readonly float _deadline; public override bool keepWaiting { get { bool flag = !_predicate(); bool flag2 = Time.realtimeSinceStartup < _deadline; return flag && flag2; } } public WaitUntilOrTimeout(Func<bool> predicate, float timeoutSeconds) { _predicate = predicate ?? ((Func<bool>)(() => true)); _deadline = Time.realtimeSinceStartup + Mathf.Max(1f, timeoutSeconds); } } internal static class WaitHelpers { public static CustomYieldInstruction MakeWaitUntilWithTimeout(Func<bool> predicate) { return (CustomYieldInstruction)(object)new WaitUntilOrTimeout(predicate, BaseClass.TimeoutSeconds); } } } namespace ReviveDesyncPatch.Patches { [HarmonyPatch] public static class EndOfGame_Transpiler { [HarmonyTargetMethod] private static MethodBase TargetMethod() { Type typeFromHandle = typeof(StartOfRound); Type[] nestedTypes = typeFromHandle.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic); Type type = nestedTypes.FirstOrDefault((Type t) => t.Name.StartsWith("<EndOfGame>", StringComparison.Ordinal) && typeof(IEnumerator).IsAssignableFrom(t)); if (type == null) { ManualLogSource log = BaseClass.Log; if (log != null) { log.LogWarning((object)"[LDF] Could not find EndOfGame state machine type. Game update?"); } return null; } MethodInfo methodInfo = AccessTools.Method(type, "MoveNext", (Type[])null, (Type[])null); if (methodInfo == null) { ManualLogSource log2 = BaseClass.Log; if (log2 != null) { log2.LogWarning((object)"[LDF] Could not find MoveNext on EndOfGame state machine."); } } else { ManualLogSource log3 = BaseClass.Log; if (log3 != null) { log3.LogInfo((object)("[LDF] Targeting iterator method: " + type.FullName + ".MoveNext")); } } return methodInfo; } [HarmonyTranspiler] public static IEnumerable<CodeInstruction> Transpile(IEnumerable<CodeInstruction> instructions) { //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(instructions); ConstructorInfo constructor = typeof(WaitUntil).GetConstructor(new Type[1] { typeof(Func<bool>) }); MethodInfo methodInfo = AccessTools.Method(typeof(WaitHelpers), "MakeWaitUntilWithTimeout", (Type[])null, (Type[])null); int num = 0; for (int i = 0; i < list.Count; i++) { CodeInstruction val = list[i]; if (val.opcode == OpCodes.Newobj && val.operand is ConstructorInfo constructorInfo && constructorInfo == constructor) { list[i] = new CodeInstruction(OpCodes.Call, (object)methodInfo); num++; } } if (num > 0) { ManualLogSource log = BaseClass.Log; if (log != null) { log.LogInfo((object)$"[LDF] Patched {num} WaitUntil -> timed WaitUntilOrTimeout in EndOfGame iterator."); } } else { ManualLogSource log2 = BaseClass.Log; if (log2 != null) { log2.LogWarning((object)"[LDF] No WaitUntil ctor found to patch in EndOfGame iterator. Game update or different code path?"); } } return list; } } }