using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Peak.Network; using Photon.Pun; using UnityEngine; using Zorro.Core; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("com.github.LengSword.HazardControl")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.1.0")] [assembly: AssemblyInformationalVersion("0.1.1+8962e8fa276dec487d6ed92b22b5231e17266350")] [assembly: AssemblyProduct("com.github.LengSword.HazardControl")] [assembly: AssemblyTitle("HazardControl")] [assembly: AssemblyMetadata("RepositoryUrl", "https://codeberg.org/yls-peak-mods/HazardControl")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.1.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] 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 BepInEx { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] [Embedded] internal sealed class BepInAutoPluginAttribute : Attribute { public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace BepInEx.Preloader.Core.Patching { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] [Embedded] internal sealed class PatcherAutoPluginAttribute : Attribute { public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace Microsoft.CodeAnalysis { [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace HazardControl { [BepInPlugin("com.github.LengSword.HazardControl", "HazardControl", "0.1.1")] public class Plugin : BaseUnityPlugin { public const string Id = "com.github.LengSword.HazardControl"; internal static ManualLogSource Logger { get; private set; } public static string Name => "HazardControl"; public static string Version => "0.1.1"; private void Awake() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown Logger = ((BaseUnityPlugin)this).Logger; Logger.LogInfo((object)("Plugin " + Name + " is loaded!")); PluginConfig.Initialize(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger); Harmony val = new Harmony("com.github.LengSword.HazardControl"); val.PatchAll(); } } public static class PluginConfig { private static readonly Dictionary> FogWaitTimes = new Dictionary>(); internal static ConfigEntry EnableFogControl { get; private set; } = null; internal static ConfigEntry FogSpeedMultiplier { get; private set; } = null; internal static ConfigEntry FogSyncRate { get; private set; } = null; internal static ConfigEntry EnableCalderaLavaControl { get; private set; } = null; internal static ConfigEntry CalderaLavaCycleSpeedMultiplier { get; private set; } = null; internal static ConfigEntry CalderaLavaSyncRate { get; private set; } = null; internal static ConfigEntry CalderaLavaNeverLowers { get; private set; } = null; internal static ConfigEntry CalderaLavaNeverLowersPosition { get; private set; } = null; internal static ConfigEntry CalderaLavaDynamicHeight { get; private set; } = null; internal static ConfigEntry CalderaLavaDynamicMinHeight { get; private set; } = null; internal static ConfigEntry CalderaLavaDynamicMaxHeight { get; private set; } = null; internal static ConfigEntry CalderaLavaDynamicCycleSeconds { get; private set; } = null; internal static ConfigEntry CalderaLavaDynamicPauseSeconds { get; private set; } = null; internal static ConfigEntry EnableKilnLavaControl { get; private set; } = null; internal static ConfigEntry KilnLavaWaitTime { get; private set; } = null; internal static ConfigEntry KilnLavaSpeedMultiplier { get; private set; } = null; internal static ConfigEntry KilnLavaSyncRate { get; private set; } = null; internal static ConfigEntry EnableGloomControl { get; private set; } = null; internal static ConfigEntry GloomWaitTime { get; private set; } = null; internal static ConfigEntry GloomSpeedMultiplier { get; private set; } = null; internal static ConfigEntry GloomSyncRate { get; private set; } = null; internal static ConfigEntry EnableVoidGhostsControl { get; private set; } = null; internal static ConfigEntry VoidGhostsWaitTime { get; private set; } = null; internal static ConfigEntry VoidGhostsSpeedMultiplier { get; private set; } = null; internal static ConfigEntry VoidGhostsSyncRate { get; private set; } = null; public static void Initialize(ConfigFile config, ManualLogSource logger) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Expected O, but got Unknown //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Expected O, but got Unknown //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Expected O, but got Unknown //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Expected O, but got Unknown //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Expected O, but got Unknown //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Expected O, but got Unknown //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Expected O, but got Unknown //IL_0282: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Expected O, but got Unknown //IL_02d5: Unknown result type (might be due to invalid IL or missing references) //IL_02df: Expected O, but got Unknown //IL_030d: Unknown result type (might be due to invalid IL or missing references) //IL_0317: Expected O, but got Unknown //IL_0345: Unknown result type (might be due to invalid IL or missing references) //IL_034f: Expected O, but got Unknown //IL_0398: Unknown result type (might be due to invalid IL or missing references) //IL_03a2: Expected O, but got Unknown //IL_03d0: Unknown result type (might be due to invalid IL or missing references) //IL_03da: Expected O, but got Unknown //IL_0408: Unknown result type (might be due to invalid IL or missing references) //IL_0412: Expected O, but got Unknown //IL_045b: Unknown result type (might be due to invalid IL or missing references) //IL_0465: Expected O, but got Unknown //IL_0493: Unknown result type (might be due to invalid IL or missing references) //IL_049d: Expected O, but got Unknown //IL_04cb: Unknown result type (might be due to invalid IL or missing references) //IL_04d5: Expected O, but got Unknown EnableFogControl = config.Bind("Fog", "Enable Fog control", true, "Enable the fog control features."); FogWaitTimes.Clear(); BindFogWaitTime(config, (BiomeType)0); BindFogWaitTime(config, (BiomeType)1); BindFogWaitTime(config, (BiomeType)2); BindFogWaitTime(config, (BiomeType)6); BindFogWaitTime(config, (BiomeType)7); FogSpeedMultiplier = config.Bind("Fog", "FogSpeedMultiplier", 1f, new ConfigDescription("Multiplies the speed of the Fog. 1.0 is normal speed.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 50f), Array.Empty())); FogSyncRate = config.Bind("Fog", "FogSyncRate", 1f, new ConfigDescription("Seconds between updating fog speed to clients. 5 seconds is the vanilla rate. Lower values might cause more lag.", (AcceptableValueBase)(object)new AcceptableValueRange(0.01f, 5f), Array.Empty())); EnableCalderaLavaControl = config.Bind("CalderaLava", "Enable Caldera lava control", true, "Enable Caldera lava control features."); CalderaLavaCycleSpeedMultiplier = config.Bind("CalderaLava", "Lava cycle speed multiplier", 1f, new ConfigDescription("Lava Cycle speed multiplier.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 50f), Array.Empty())); CalderaLavaSyncRate = config.Bind("CalderaLava", "Lava sync rate", 1f, new ConfigDescription("Seconds between updating caldera lava speed to clients. 5 seconds is the vanilla rate. Lower values might cause more lag.", (AcceptableValueBase)(object)new AcceptableValueRange(0.01f, 5f), Array.Empty())); CalderaLavaNeverLowers = config.Bind("CalderaLava", "Fixed lava (overrides speed mult)", false, "Prevents the lava from moving."); CalderaLavaNeverLowersPosition = config.Bind("CalderaLava", "Fixed lava position", 1f, new ConfigDescription("How high the lava should be when fixed lava is enabled. 0 is lowest, 1 is highest.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); CalderaLavaDynamicHeight = config.Bind("CalderaLava", "Dynamic lava height", false, "Enables dynamic lava height."); CalderaLavaDynamicMinHeight = config.Bind("CalderaLava", "Dynamic minimum lava height", 0f, new ConfigDescription("Minimum height of the lava when dynamic lava height is enabled. 0 is lowest (original min height), 1 is highest (original max height).", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 5f), Array.Empty())); CalderaLavaDynamicMaxHeight = config.Bind("CalderaLava", "Dynamic maximum lava height", 1f, new ConfigDescription("Maximum height of the lava when dynamic lava height is enabled. 1 is original max height", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 5f), Array.Empty())); CalderaLavaDynamicCycleSeconds = config.Bind("CalderaLava", "Dynamic lava cycle seconds", 80f, new ConfigDescription("Seconds for a full cycle of lava height change when dynamic lava height is enabled. A full cycle is from min height to max height and back to min height.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 300f), Array.Empty())); CalderaLavaDynamicPauseSeconds = config.Bind("CalderaLava", "Dynamic lava pause seconds", 10f, new ConfigDescription("Seconds to pause at minimum and maximum lava height when dynamic lava height is enabled. The lava will pause at minimum height for this duration, then move to maximum height, pause again for this duration, then move back to minimum height.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 100f), Array.Empty())); EnableKilnLavaControl = config.Bind("KilnLava", "Enable Kiln lava control", true, "Enable the Kiln lava control features."); KilnLavaWaitTime = config.Bind("KilnLava", "Lava wait time", -1f, new ConfigDescription("Seconds before the Kiln lava starts rising. -1 preserves the wait time defined by the game scene (currently 180 seconds).", (AcceptableValueBase)(object)new AcceptableValueRange(-1f, 3600f), Array.Empty())); KilnLavaSpeedMultiplier = config.Bind("KilnLava", "Lava speed multiplier", 1f, new ConfigDescription("Multiplies the speed of the Kiln lava. 1.0 is normal speed.", (AcceptableValueBase)(object)new AcceptableValueRange(-20f, 20f), Array.Empty())); KilnLavaSyncRate = config.Bind("KilnLava", "Lava sync rate", 5f, new ConfigDescription("Seconds between updating kiln lava speed to clients. 15 seconds is the vanilla rate. Lower values might cause more lag.", (AcceptableValueBase)(object)new AcceptableValueRange(0.01f, 15f), Array.Empty())); EnableGloomControl = config.Bind("Gloom", "Enable Gloom control", true, "Enable the Gloom control features."); GloomWaitTime = config.Bind("Gloom", "Gloom wait time", -1f, new ConfigDescription("Seconds before the Gloom starts rising. -1 preserves the wait time defined by the game scene (currently 150 seconds).", (AcceptableValueBase)(object)new AcceptableValueRange(-1f, 3600f), Array.Empty())); GloomSpeedMultiplier = config.Bind("Gloom", "Gloom speed multiplier", 1f, new ConfigDescription("Multiplies the Gloom's rising speed. 1.0 is the scene-defined speed.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 20f), Array.Empty())); GloomSyncRate = config.Bind("Gloom", "Gloom sync rate", 5f, new ConfigDescription("Seconds between updating Gloom state to clients. 15 seconds is the vanilla rate. Lower values might cause more lag.", (AcceptableValueBase)(object)new AcceptableValueRange(0.01f, 15f), Array.Empty())); EnableVoidGhostsControl = config.Bind("VoidGhosts", "Enable Void Ghosts control", true, "Enable the Void Ghosts control features."); VoidGhostsWaitTime = config.Bind("VoidGhosts", "Void Ghosts wait time", -1f, new ConfigDescription("Seconds after the triggering soul event before the Void Ghosts start rising. -1 preserves the wait time defined by the game scene (currently 0 seconds).", (AcceptableValueBase)(object)new AcceptableValueRange(-1f, 3600f), Array.Empty())); VoidGhostsSpeedMultiplier = config.Bind("VoidGhosts", "Void Ghosts speed multiplier", 1f, new ConfigDescription("Multiplies the Void Ghosts' rising speed. 1.0 is the scene-defined speed.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 20f), Array.Empty())); VoidGhostsSyncRate = config.Bind("VoidGhosts", "Void Ghosts sync rate", 5f, new ConfigDescription("Seconds between updating Void Ghosts state to clients. 15 seconds is the vanilla rate. Lower values might cause more lag.", (AcceptableValueBase)(object)new AcceptableValueRange(0.01f, 15f), Array.Empty())); logger.LogInfo((object)"Plugin Config Loaded."); } internal static bool TryGetFogWaitTime(BiomeType biome, out float waitTime) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) if (FogWaitTimes.TryGetValue(biome, out ConfigEntry value) && value.Value >= 0f) { waitTime = value.Value; return true; } waitTime = -1f; return false; } private unsafe static void BindFogWaitTime(ConfigFile config, BiomeType biome) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown FogWaitTimes[biome] = config.Bind("FogWaitTimes", ((object)(*(BiomeType*)(&biome))/*cast due to .constrained prefix*/).ToString(), -1f, new ConfigDescription($"Seconds of non-resting game time before the Fog starts moving in {biome}. A non-negative value uses an exact timer and prevents position thresholds from starting the Fog early. -1 preserves the original behavior. The current scene maxWaitTime is 1000 seconds; it does not start the Fog on Shore.", (AcceptableValueBase)(object)new AcceptableValueRange(-1f, 3600f), Array.Empty())); } } } namespace HazardControl.Patches { [HarmonyPatch(typeof(Lava), "FixedUpdate")] internal sealed class CalderaLavaPatch { internal static SyncedAnimation? lavaAnim; private const float GameMinLavaY = 780f; private const float GameMaxLavaY = 785f; private static float dynamicTimer; private static float DynamicTravelSeconds => (PluginConfig.CalderaLavaDynamicCycleSeconds.Value - PluginConfig.CalderaLavaDynamicPauseSeconds.Value * 2f) / 2f; public static bool Prefix(Lava __instance) { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) if (!PhotonNetwork.IsMasterClient || !PluginConfig.EnableCalderaLavaControl.Value) { return true; } if ((Object)(object)lavaAnim == (Object)null) { lavaAnim = ((Component)__instance).GetComponent(); } if (__instance.isKiln) { return true; } if (PluginConfig.CalderaLavaDynamicHeight.Value) { UpdateDynamicHeight(__instance); return true; } if (!((Behaviour)lavaAnim.anim).enabled) { ((Behaviour)lavaAnim.anim).enabled = true; } lavaAnim.anim.speed = PluginConfig.CalderaLavaCycleSpeedMultiplier.Value; if (PluginConfig.CalderaLavaNeverLowers.Value) { lavaAnim.anim.speed = 0f; AnimatorStateInfo currentAnimatorStateInfo = lavaAnim.anim.GetCurrentAnimatorStateInfo(0); lavaAnim.anim.Play(((AnimatorStateInfo)(ref currentAnimatorStateInfo)).shortNameHash, 0, 0.7f * PluginConfig.CalderaLavaNeverLowersPosition.Value); } return true; } private static void UpdateDynamicHeight(Lava lava) { //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)lavaAnim?.anim == (Object)null)) { ((Behaviour)lavaAnim.anim).enabled = false; float num = Mathf.Max(0f, Mathf.Min(PluginConfig.CalderaLavaDynamicMinHeight.Value, PluginConfig.CalderaLavaDynamicMaxHeight.Value)); float num2 = Mathf.Max(0f, Mathf.Max(PluginConfig.CalderaLavaDynamicMinHeight.Value, PluginConfig.CalderaLavaDynamicMaxHeight.Value)); float num3 = Mathf.Max(0f, PluginConfig.CalderaLavaCycleSpeedMultiplier.Value); dynamicTimer += Time.fixedDeltaTime * num3; float num4 = Mathf.Repeat(dynamicTimer, PluginConfig.CalderaLavaDynamicCycleSeconds.Value); float num5; if (num4 < PluginConfig.CalderaLavaDynamicPauseSeconds.Value) { num5 = 0f; } else if (num4 < PluginConfig.CalderaLavaDynamicPauseSeconds.Value + DynamicTravelSeconds) { float num6 = (num4 - PluginConfig.CalderaLavaDynamicPauseSeconds.Value) / DynamicTravelSeconds; num5 = Mathf.SmoothStep(0f, 1f, num6); } else if (num4 < PluginConfig.CalderaLavaDynamicPauseSeconds.Value + DynamicTravelSeconds + PluginConfig.CalderaLavaDynamicPauseSeconds.Value) { num5 = 1f; } else { float num7 = (num4 - (PluginConfig.CalderaLavaDynamicPauseSeconds.Value + DynamicTravelSeconds + PluginConfig.CalderaLavaDynamicPauseSeconds.Value)) / DynamicTravelSeconds; num5 = 1f - Mathf.SmoothStep(0f, 1f, num7); } float num8 = 5f; float num9 = 780f + num8 * num; float num10 = 780f + num8 * num2; float num11 = Mathf.Lerp(num9, num10, num5); Vector3 position = ((Component)lava).transform.position; ((Component)lava).transform.position = new Vector3(position.x, num11, position.z); } } } [HarmonyPatch(typeof(SyncedAnimation), "Update")] internal sealed class SyncedAnimationPatch { internal static void Postfix(SyncedAnimation __instance) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) if (PhotonNetwork.IsMasterClient && PluginConfig.EnableCalderaLavaControl.Value && __instance.syncCounter > PluginConfig.CalderaLavaSyncRate.Value) { __instance.syncCounter = 0f; PhotonView view = __instance.view; object[] array = new object[1]; AnimatorStateInfo currentAnimatorStateInfo = __instance.anim.GetCurrentAnimatorStateInfo(0); array[0] = ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime % 1f; view.RPC("RPCA_SyncAnim", (RpcTarget)0, array); } } } [HarmonyPatch(typeof(OrbFogHandler))] internal static class OrbFogHandlerUpdatePatch { private const float VanillaFogSpeed = 0.4f; [HarmonyPrefix] [HarmonyPatch("Update")] private static void ForceConfigValues(OrbFogHandler __instance) { if (PhotonNetwork.IsMasterClient && PluginConfig.EnableFogControl.Value) { __instance.speed = 0.4f * (PluginConfig.FogSpeedMultiplier?.Value ?? 1f); if (__instance.syncCounter > (PluginConfig.FogSyncRate?.Value ?? 5f)) { __instance.syncCounter = 0f; __instance.photonView.RPC("RPCA_SyncFog", (RpcTarget)1, new object[2] { __instance.currentSize, __instance.isMoving }); } } } [HarmonyPrefix] [HarmonyPatch("PlayersHaveMovedOn")] private static bool SuppressPositionTriggerForExactTimer(OrbFogHandler __instance, ref bool __result) { if (!TryGetConfiguredWaitTime(__instance, out var _)) { return true; } __result = false; return false; } [HarmonyPostfix] [HarmonyPatch("TimeToMove")] private static void ApplyExactWaitTime(OrbFogHandler __instance, ref bool __result) { if (TryGetConfiguredWaitTime(__instance, out var waitTime)) { __result = Ascents.currentAscent >= 0 && __instance.currentWaitTime >= waitTime; } } private static bool TryGetConfiguredWaitTime(OrbFogHandler instance, out float waitTime) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) waitTime = -1f; if (!NetCode.Session.IsHost || !PluginConfig.EnableFogControl.Value) { return false; } MapHandler instance2 = Singleton.Instance; int currentID = instance.currentID; if ((Object)(object)instance2 == (Object)null || instance2.segments == null || currentID < 0 || currentID >= instance2.segments.Length || instance2.segments[currentID] == null) { return false; } BiomeType biomeForSegment = MapHandler.GetBiomeForSegment(currentID); return PluginConfig.TryGetFogWaitTime(biomeForSegment, out waitTime); } } [HarmonyPatch(typeof(LavaRising), "Update")] internal static class RisingFieldUpdatePatch { [HarmonyPrefix] private static void PrepareControlledState(LavaRising __instance) { if (RisingFieldControl.ShouldResumeKilnLava(__instance)) { __instance.ended = false; } } [HarmonyTranspiler] private static IEnumerable ApplyRisingFieldControls(IEnumerable instructions) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Expected O, but got Unknown //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Expected O, but got Unknown //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Expected O, but got Unknown //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Expected O, but got Unknown //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Expected O, but got Unknown List list = new List(instructions); List matches = FindMatches(list, IsWaitTimeRead); List matches2 = FindMatches(list, IsTravelDelta); List matches3 = FindMatches(list, IsSyncInterval); List<(int, CodeInstruction[])> list2 = new List<(int, CodeInstruction[])>(); AddInsertion(list2, matches, "wait-time comparison", new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)SymbolExtensions.GetMethodInfo((Expression)(() => RisingFieldControl.GetWaitTime(0f, null))))); AddInsertion(list2, matches2, "travel delta", new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)SymbolExtensions.GetMethodInfo((Expression)(() => RisingFieldControl.GetTravelDelta(0f, null))))); AddInsertion(list2, matches3, "sync interval", new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)SymbolExtensions.GetMethodInfo((Expression)(() => RisingFieldControl.GetSyncInterval(0f, null))))); list2.Sort(((int Index, CodeInstruction[] Instructions) left, (int Index, CodeInstruction[] Instructions) right) => right.Index.CompareTo(left.Index)); foreach (var (num, collection) in list2) { list.InsertRange(num + 1, collection); } return list; } private static void AddInsertion(ICollection<(int Index, CodeInstruction[] Instructions)> insertions, IReadOnlyList matches, string controlPoint, params CodeInstruction[] instructions) { if (matches.Count == 1) { insertions.Add((matches[0], instructions)); } else { Plugin.Logger.LogError((object)$"Could not apply the rising-field {controlPoint} control; expected one IL match but found {matches.Count}. This control will use vanilla behavior."); } } private static List FindMatches(IReadOnlyList code, Func, int, bool> predicate) { List list = new List(); for (int i = 0; i < code.Count; i++) { if (predicate(code, i)) { list.Add(i); } } return list; } private static bool IsWaitTimeRead(IReadOnlyList code, int index) { if (index >= 2 && index + 1 < code.Count && Calls(code[index - 2], typeof(LavaRising), "get_secondsWaitedToStart") && code[index - 1].opcode == OpCodes.Ldarg_0 && LoadsField(code[index], typeof(LavaRising), "initialWaitTime")) { return IsLessOrEqualBranch(code[index + 1].opcode); } return false; } private static bool IsTravelDelta(IReadOnlyList code, int index) { if (index + 2 < code.Count && Calls(code[index], typeof(Time), "get_deltaTime") && code[index + 1].opcode == OpCodes.Add) { return Calls(code[index + 2], typeof(LavaRising), "set_timeTraveled"); } return false; } private static bool IsSyncInterval(IReadOnlyList code, int index) { if (index >= 2 && index + 1 < code.Count && code[index - 2].opcode == OpCodes.Ldarg_0 && LoadsField(code[index - 1], typeof(LavaRising), "syncTime") && code[index].opcode == OpCodes.Ldc_R4 && code[index].operand is float num && num == 15f) { return IsLessOrEqualBranch(code[index + 1].opcode); } return false; } private static bool LoadsField(CodeInstruction instruction, Type declaringType, string fieldName) { if (instruction.operand is FieldInfo fieldInfo && fieldInfo.DeclaringType == declaringType) { return fieldInfo.Name == fieldName; } return false; } private static bool Calls(CodeInstruction instruction, Type declaringType, string methodName) { if (instruction.operand is MethodBase methodBase && methodBase.DeclaringType == declaringType) { return methodBase.Name == methodName; } return false; } private static bool IsLessOrEqualBranch(OpCode opcode) { if (!(opcode == OpCodes.Ble) && !(opcode == OpCodes.Ble_S) && !(opcode == OpCodes.Ble_Un)) { return opcode == OpCodes.Ble_Un_S; } return true; } } [HarmonyPatch(typeof(LavaRising), "EndRising")] internal static class RisingFieldEndPatch { [HarmonyPrefix] private static bool AllowEndRising(LavaRising __instance) { return !RisingFieldControl.ShouldResumeKilnLava(__instance); } } internal static class RisingFieldControl { private enum ControlKind { None, KilnLava, Gloom, VoidGhosts } internal static float GetWaitTime(float vanillaWaitTime, LavaRising field) { return GetEnabledKind(field) switch { ControlKind.KilnLava => GetOptionalOverride(PluginConfig.KilnLavaWaitTime.Value, vanillaWaitTime), ControlKind.Gloom => GetOptionalOverride(PluginConfig.GloomWaitTime.Value, vanillaWaitTime), ControlKind.VoidGhosts => GetOptionalOverride(PluginConfig.VoidGhostsWaitTime.Value, vanillaWaitTime), _ => vanillaWaitTime, }; } internal static float GetTravelDelta(float vanillaDelta, LavaRising field) { float num; switch (GetEnabledKind(field)) { case ControlKind.None: return vanillaDelta; case ControlKind.KilnLava: num = PluginConfig.KilnLavaSpeedMultiplier.Value; break; case ControlKind.Gloom: num = PluginConfig.GloomSpeedMultiplier.Value; break; case ControlKind.VoidGhosts: num = PluginConfig.VoidGhostsSpeedMultiplier.Value; break; default: num = 1f; break; } float num2 = num; float num3 = Mathf.Max(0f, field.timeTraveled + vanillaDelta * num2); return num3 - field.timeTraveled; } internal static float GetSyncInterval(float vanillaInterval, LavaRising field) { return GetEnabledKind(field) switch { ControlKind.KilnLava => PluginConfig.KilnLavaSyncRate.Value, ControlKind.Gloom => PluginConfig.GloomSyncRate.Value, ControlKind.VoidGhosts => PluginConfig.VoidGhostsSyncRate.Value, _ => vanillaInterval, }; } internal static bool ShouldResumeKilnLava(LavaRising field) { if (GetEnabledKind(field) == ControlKind.KilnLava && PluginConfig.KilnLavaSpeedMultiplier.Value < 0f) { return field.started; } return false; } private static ControlKind GetEnabledKind(LavaRising field) { if (!PhotonNetwork.IsMasterClient) { return ControlKind.None; } ControlKind kind = GetKind(field); switch (kind) { case ControlKind.KilnLava: if (PluginConfig.EnableKilnLavaControl.Value) { return kind; } break; case ControlKind.Gloom: if (PluginConfig.EnableGloomControl.Value) { return kind; } break; case ControlKind.VoidGhosts: if (PluginConfig.EnableVoidGhostsControl.Value) { return kind; } break; } return ControlKind.None; } private static ControlKind GetKind(LavaRising field) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: 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) //IL_001c: Invalid comparison between Unknown and I4 //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Invalid comparison between Unknown and I4 //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Invalid comparison between Unknown and I4 if ((int)field.risingFieldType == 0 && (int)field.requiredSegment == 4) { return ControlKind.KilnLava; } RisingFieldType risingFieldType = field.risingFieldType; if ((int)risingFieldType != 1) { if ((int)risingFieldType == 2) { return ControlKind.VoidGhosts; } return ControlKind.None; } return ControlKind.Gloom; } private static float GetOptionalOverride(float configuredValue, float vanillaValue) { if (!(configuredValue < 0f)) { return configuredValue; } return vanillaValue; } } } namespace System.Diagnostics.CodeAnalysis { [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class ConstantExpectedAttribute : Attribute { public object? Min { get; set; } public object? Max { get; set; } } [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class ExperimentalAttribute : Attribute { public string DiagnosticId { get; } public string? UrlFormat { get; set; } public ExperimentalAttribute(string diagnosticId) { DiagnosticId = diagnosticId; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] [ExcludeFromCodeCoverage] internal sealed class MemberNotNullAttribute : Attribute { public string[] Members { get; } public MemberNotNullAttribute(string member) { Members = new string[1] { member }; } public MemberNotNullAttribute(params string[] members) { Members = members; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] [ExcludeFromCodeCoverage] internal sealed class MemberNotNullWhenAttribute : Attribute { public bool ReturnValue { get; } public string[] Members { get; } public MemberNotNullWhenAttribute(bool returnValue, string member) { ReturnValue = returnValue; Members = new string[1] { member }; } public MemberNotNullWhenAttribute(bool returnValue, params string[] members) { ReturnValue = returnValue; Members = members; } } [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class SetsRequiredMembersAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class StringSyntaxAttribute : Attribute { public const string CompositeFormat = "CompositeFormat"; public const string DateOnlyFormat = "DateOnlyFormat"; public const string DateTimeFormat = "DateTimeFormat"; public const string EnumFormat = "EnumFormat"; public const string GuidFormat = "GuidFormat"; public const string Json = "Json"; public const string NumericFormat = "NumericFormat"; public const string Regex = "Regex"; public const string TimeOnlyFormat = "TimeOnlyFormat"; public const string TimeSpanFormat = "TimeSpanFormat"; public const string Uri = "Uri"; public const string Xml = "Xml"; public string Syntax { get; } public object?[] Arguments { get; } public StringSyntaxAttribute(string syntax) { Syntax = syntax; Arguments = new object[0]; } public StringSyntaxAttribute(string syntax, params object?[] arguments) { Syntax = syntax; Arguments = arguments; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class UnscopedRefAttribute : Attribute { } } namespace System.Runtime.Versioning { [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class RequiresPreviewFeaturesAttribute : Attribute { public string? Message { get; } public string? Url { get; set; } public RequiresPreviewFeaturesAttribute() { } public RequiresPreviewFeaturesAttribute(string? message) { Message = message; } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CallerArgumentExpressionAttribute : Attribute { public string ParameterName { get; } public CallerArgumentExpressionAttribute(string parameterName) { ParameterName = parameterName; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CollectionBuilderAttribute : Attribute { public Type BuilderType { get; } public string MethodName { get; } public CollectionBuilderAttribute(Type builderType, string methodName) { BuilderType = builderType; MethodName = methodName; } } [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CompilerFeatureRequiredAttribute : Attribute { public const string RefStructs = "RefStructs"; public const string RequiredMembers = "RequiredMembers"; public string FeatureName { get; } public bool IsOptional { get; set; } public CompilerFeatureRequiredAttribute(string featureName) { FeatureName = featureName; } } [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class InterpolatedStringHandlerArgumentAttribute : Attribute { public string[] Arguments { get; } public InterpolatedStringHandlerArgumentAttribute(string argument) { Arguments = new string[1] { argument }; } public InterpolatedStringHandlerArgumentAttribute(params string[] arguments) { Arguments = arguments; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class InterpolatedStringHandlerAttribute : Attribute { } [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] internal static class IsExternalInit { } [AttributeUsage(AttributeTargets.Method, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class ModuleInitializerAttribute : Attribute { } [AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class OverloadResolutionPriorityAttribute : Attribute { public int Priority { get; } public OverloadResolutionPriorityAttribute(int priority) { Priority = priority; } } [AttributeUsage(AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)] [ExcludeFromCodeCoverage] internal sealed class ParamCollectionAttribute : Attribute { } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class RequiredMemberAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] internal sealed class RequiresLocationAttribute : Attribute { } [AttributeUsage(AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event | AttributeTargets.Interface, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class SkipLocalsInitAttribute : Attribute { } }