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 MeliciousFurnitureFixPlusLethalPerformanceCompat v0.1.1
plugins/MliciosFurnitureFixPlus/MliciosFurnitureFixPlus.dll
Decompiled 14 hours agousing System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Bootstrap; using HarmonyLib; using Unity.Netcode; using UnityEngine; using UnityEngine.SceneManagement; [assembly: AssemblyFileVersion("0.1.1.0")] [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyTitle("MliciosFurnitureFixPlus")] [assembly: AssemblyDescription("Targeted Utility Furniture Pack ship fire exit compatibility fix")] [assembly: AssemblyVersion("0.1.1.0")] namespace MliciosFurnitureFixPlus; internal static class Patches { internal static void Install(Harmony harmony) { Type type = AccessTools.TypeByName("MelanieMeliciousFurniture.Plugin"); Type type2 = ((type == null) ? null : type.Assembly.GetType("FireExitPatch")); Type type3 = AccessTools.TypeByName("LethalLevelLoader.DungeonLoader"); MethodInfo methodInfo = Required(type2, "PreLevelLoad"); MethodInfo methodInfo2 = Required(type2, "PreShipLeft"); MethodInfo methodInfo3 = Required(type3, "GetEntranceTeleports"); MethodInfo methodInfo4 = Required(type3, "PatchFireEscapes"); MethodInfo methodInfo5 = Required(typeof(RoundManager), "SetExitIDs"); MethodInfo methodInfo6 = Required(typeof(EntranceTeleport), "FindExitPoint"); MethodInfo methodInfo7 = Required(typeof(StartOfRound), "ShipHasLeft"); harmony.Patch((MethodBase)methodInfo, Hook("SkipOriginal"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo2, Hook("SkipOriginal"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo4, Hook("Prepare"), Hook("CaptureIds"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, Hook("Register"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); HarmonyMethod val = Hook("FreshExitScan"); harmony.Patch((MethodBase)methodInfo5, (HarmonyMethod)null, Hook("Resolve"), val, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo6, Hook("Find"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)Required(typeof(EntranceTeleport), "Awake"), (HarmonyMethod)null, Hook("Created"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo7, Hook("Reset"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Type type4 = AccessTools.TypeByName("Dawn.DungeonRegistrationHandler"); if (type4 != null) { MethodInfo methodInfo8 = Required(type4, "AdjustFireExits"); HarmonyMethod obj = Hook("PrepareDawn"); HarmonyMethod val2 = Hook("FreshDawnScan"); harmony.Patch((MethodBase)methodInfo8, obj, Hook("CaptureDawnIds"), val2, (HarmonyMethod)null, (HarmonyMethod)null); } harmony.Unpatch((MethodBase)Required(typeof(RoundManager), "LoadNewLevel"), methodInfo); harmony.Unpatch((MethodBase)methodInfo7, methodInfo2); } private static MethodInfo Required(Type type, string name) { MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, name, (Type[])null, (Type[])null)); if (methodInfo == null) { throw new MissingMethodException((type == null) ? "missing dependency type" : type.FullName, name); } return methodInfo; } private static HarmonyMethod Hook(string name) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown HarmonyMethod val = new HarmonyMethod(typeof(Patches), name, (Type[])null); val.priority = 800; return val; } private static bool SkipOriginal() { return false; } private static void Prepare() { Runtime.Prepare(); } private static void PrepareDawn() { Runtime.Prepare(); } private static void CaptureIds() { Runtime.CaptureIds(); } private static void CaptureDawnIds() { if (Runtime.HasRegisteredShip) { Runtime.Log("DawnLib fire-exit generation handled on this peer."); } Runtime.CaptureIds(); } private static void Register(List<EntranceTeleport> __result) { Runtime.Register(__result); } private static void Resolve() { Runtime.Resolve(); } private static void Reset() { Runtime.Reset(); } private static void Created(EntranceTeleport __instance) { Runtime.OnCreated(__instance); } private static bool Find(EntranceTeleport __instance, ref bool __result) { if (!Runtime.TryFind(__instance, out var found)) { return true; } __result = found; return false; } private static EntranceTeleport[] ScanForExitIds() { if (!Runtime.HasRegisteredShip) { return Object.FindObjectsOfType<EntranceTeleport>(); } return Runtime.FreshScan(); } private static EntranceTeleport[] ScanForDawnIds(FindObjectsInactive inactive, FindObjectsSortMode sortMode) { return Runtime.RegisterDawn(); } private static IEnumerable<CodeInstruction> FreshDawnScan(IEnumerable<CodeInstruction> instructions) { int replacements = 0; MethodInfo replacement = AccessTools.Method(typeof(Patches), "ScanForDawnIds", (Type[])null, (Type[])null); foreach (CodeInstruction instruction in instructions) { MethodInfo called = instruction.operand as MethodInfo; if (instruction.opcode == OpCodes.Call && called != null && called.DeclaringType == typeof(Object) && called.Name == "FindObjectsByType" && called.IsGenericMethod && called.GetGenericArguments()[0] == typeof(EntranceTeleport) && called.GetParameters().Length == 2) { instruction.operand = replacement; replacements++; } yield return instruction; } if (replacements != 1) { throw new NotSupportedException("Unexpected DawnLib AdjustFireExits layout: expected one entrance scan, found " + replacements + "."); } } private static IEnumerable<CodeInstruction> FreshExitScan(IEnumerable<CodeInstruction> instructions) { int replacements = 0; MethodInfo replacement = AccessTools.Method(typeof(Patches), "ScanForExitIds", (Type[])null, (Type[])null); foreach (CodeInstruction instruction in instructions) { MethodInfo called = instruction.operand as MethodInfo; if (instruction.opcode == OpCodes.Call && called != null && called.DeclaringType == typeof(Object) && called.Name == "FindObjectsOfType" && called.IsGenericMethod && called.GetGenericArguments()[0] == typeof(EntranceTeleport) && called.GetParameters().Length == 0) { instruction.operand = replacement; replacements++; } yield return instruction; } if (replacements != 1) { throw new NotSupportedException("Unexpected v81 SetExitIDs method: expected exactly one entrance scan, found " + replacements + "."); } } } [BepInDependency("imabatby.lethallevelloader", "1.7.13")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency("MelanieMelicious.furniturePack0", "2.0.5")] [BepInPlugin("TranslationLookasideBufferModding.MliciosFurnitureFixPlus", "MliciosFurniture Fix+", "0.1.1")] public sealed class Plugin : BaseUnityPlugin { public const string Id = "TranslationLookasideBufferModding.MliciosFurnitureFixPlus"; private Harmony harmony; private float nextCheck; private void Awake() { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown if (!((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Repair the Utility Furniture Pack ship fire exit. Install on ALL players. Restart required.").Value) { return; } try { RequireVersion("MelanieMelicious.furniturePack0", "2.0.5"); RequireVersion("imabatby.lethallevelloader", "1.7.13"); Runtime.Log = delegate(string text) { ((BaseUnityPlugin)this).Logger.LogInfo((object)text); }; Runtime.Warn = delegate(string text) { ((BaseUnityPlugin)this).Logger.LogWarning((object)text); }; harmony = new Harmony("TranslationLookasideBufferModding.MliciosFurnitureFixPlus"); Patches.Install(harmony); ((BaseUnityPlugin)this).Logger.LogInfo((object)"MliciosFurnitureFixPlus 0.1.1 active: LLL and DawnLib generation paths, no furniture reparenting, fresh exit-ID scan and explicit ship/interior pairing. LethalPerformance can stay enabled. Same addon required on every player."); } catch (Exception ex) { if (harmony != null) { harmony.UnpatchSelf(); } ((BaseUnityPlugin)this).Logger.LogError((object)("MliciosFurnitureFixPlus could not initialize; original behavior retained: " + ex)); ((Behaviour)this).enabled = false; } } private static void RequireVersion(string guid, string version) { if (!Chainloader.PluginInfos.TryGetValue(guid, out var value) || value.Metadata.Version.ToString() != version) { throw new NotSupportedException("Expected " + guid + " " + version + "."); } } private void Update() { if (!(TimeNow() < nextCheck)) { nextCheck = TimeNow() + 0.5f; Runtime.UpdateInteraction(); } } private static float TimeNow() { return Time.unscaledTime; } } internal sealed class DoorPair { internal EntranceTeleport Ship; internal EntranceTeleport Interior; internal int Id; internal bool Active; internal bool Reported; } internal static class Runtime { internal static Action<string> Log = delegate { }; internal static Action<string> Warn = delegate { }; internal static Func<bool> Landed = delegate { StartOfRound instance = StartOfRound.Instance; return (Object)(object)instance != (Object)null && instance.shipHasLanded && !instance.shipIsLeaving && !instance.inShipPhase; }; internal static Func<EntranceTeleport, bool> Available = IsAvailable; internal static Func<int> Mode = delegate { Type type = AccessTools.TypeByName("MelanieUtilFurnitureConfig"); FieldInfo fieldInfo = ((type == null) ? null : type.GetField("fireExit0Type", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)); object obj = ((fieldInfo == null) ? null : fieldInfo.GetValue(null)); return (obj != null) ? Convert.ToInt32(obj.GetType().GetProperty("Value").GetValue(obj, null)) : 0; }; private static readonly List<DoorPair> pairs = new List<DoorPair>(); private static readonly HashSet<EntranceTeleport> managedInteriors = new HashSet<EntranceTeleport>(); private static readonly FieldInfo gotExit = typeof(EntranceTeleport).GetField("gotExitPoint", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly FieldInfo firstCheck = typeof(EntranceTeleport).GetField("checkedForFirstTime", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly FieldInfo noExit = typeof(EntranceTeleport).GetField("exitPointDoesntExist", BindingFlags.Instance | BindingFlags.NonPublic); private static bool registered; private static bool idsReady; internal static bool HasRegisteredShip => registered; internal static bool IsShip(EntranceTeleport door) { if ((Object)(object)door != (Object)null && door.isEntranceToBuilding) { return ((Object)((Component)door).gameObject).name == "EntranceTeleportShip0"; } return false; } internal static void OnCreated(EntranceTeleport door) { if (IsShip(door)) { SetInteraction(door, active: false); } } private static bool IsAvailable(EntranceTeleport door) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)door == (Object)null) && ((Component)door).gameObject.activeInHierarchy) { Scene scene = ((Component)door).gameObject.scene; if (((Scene)(ref scene)).IsValid()) { Scene scene2 = ((Component)door).gameObject.scene; if (((Scene)(ref scene2)).isLoaded) { AutoParentToShip componentInParent = ((Component)door).GetComponentInParent<AutoParentToShip>(); if ((Object)(object)componentInParent == (Object)null) { return false; } if (componentInParent.disableObject) { return false; } StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance != (Object)null && (Object)(object)instance.unlockablesList != (Object)null && componentInParent.unlockableID >= 0 && componentInParent.unlockableID < instance.unlockablesList.unlockables.Count) { return !instance.unlockablesList.unlockables[componentInParent.unlockableID].inStorage; } return true; } } } return false; } internal static EntranceTeleport[] FreshScan() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) List<EntranceTeleport> list = new List<EntranceTeleport>(); HashSet<int> scenes = new HashSet<int>(); for (int i = 0; i < SceneManager.sceneCount; i++) { AddScene(SceneManager.GetSceneAt(i), list, scenes); } if ((Object)(object)StartOfRound.Instance != (Object)null) { AddScene(((Component)StartOfRound.Instance).gameObject.scene, list, scenes); } return list.OrderBy((EntranceTeleport d) => ((Object)d).GetInstanceID()).ToArray(); } private static void AddScene(Scene scene, List<EntranceTeleport> result, HashSet<int> scenes) { if (((Scene)(ref scene)).IsValid() && ((Scene)(ref scene)).isLoaded && scenes.Add(((Scene)(ref scene)).handle)) { GameObject[] rootGameObjects = ((Scene)(ref scene)).GetRootGameObjects(); foreach (GameObject val in rootGameObjects) { result.AddRange(val.GetComponentsInChildren<EntranceTeleport>(false)); } } } internal static void Prepare() { Reset(); foreach (EntranceTeleport item in FreshScan().Where(IsShip).Where(Available).OrderBy<EntranceTeleport, string>(StableKey, StringComparer.Ordinal)) { item.entranceId = 20; ClearExit(item); pairs.Add(new DoorPair { Ship = item, Id = -1 }); SetInteraction(item, active: false); } } internal static void Register(List<EntranceTeleport> entrances) { if (entrances == null) { return; } if (pairs.Count == 0) { foreach (EntranceTeleport item in FreshScan().Where(IsShip).Where(Available).OrderBy<EntranceTeleport, string>(StableKey, StringComparer.Ordinal)) { pairs.Add(new DoorPair { Ship = item, Id = -1 }); } } List<EntranceTeleport> list = (from p in pairs where (Object)(object)p.Ship != (Object)null && Available(p.Ship) select p.Ship).ToList(); entrances.RemoveAll((EntranceTeleport d) => (Object)(object)d == (Object)null || IsShip(d)); entrances.InsertRange(0, list); registered = list.Count > 0; } internal static EntranceTeleport[] RegisterDawn() { List<EntranceTeleport> list = (from d in FreshScan() where d.isEntranceToBuilding && d.entranceId > 0 && !IsShip(d) select d).ToList(); List<EntranceTeleport> list2 = (from p in pairs where (Object)(object)p.Ship != (Object)null && Available(p.Ship) select p.Ship).ToList(); list.AddRange(list2); registered = list2.Count > 0; return list.ToArray(); } internal static void CaptureIds() { foreach (DoorPair pair in pairs) { if ((Object)(object)pair.Ship != (Object)null) { pair.Id = pair.Ship.entranceId; } } if (registered) { Log("Registered " + pairs.Count + " ship fire exit(s) for this landing: IDs=" + string.Join(",", pairs.Select((DoorPair p) => p.Id.ToString()).ToArray()) + ". Furniture parent preserved."); } } internal static void Resolve() { if (!registered) { return; } idsReady = true; EntranceTeleport[] source = FreshScan(); foreach (DoorPair pair in pairs) { if ((Object)(object)pair.Interior != (Object)null && (Object)(object)pair.Interior.exitScript == (Object)(object)pair.Ship) { ClearExit(pair.Interior); } pair.Interior = null; if ((Object)(object)pair.Ship == (Object)null) { continue; } EntranceTeleport[] array = source.Where((EntranceTeleport d) => !d.isEntranceToBuilding && d.entranceId == pair.Id).ToArray(); bool flag = source.Count((EntranceTeleport d) => d.isEntranceToBuilding && d.entranceId == pair.Id && (!IsShip(d) || Available(d))) == 1; if (pair.Id <= 0 || !flag || array.Length != 1) { ClearExit(pair.Ship); if (!pair.Reported) { Warn("Cannot pair ship fire exit ID=" + pair.Id + ": interior candidates=" + array.Length + ", unique outside=" + flag + ". It remains blocked instead of using a moon's normal fire exit."); } pair.Reported = true; continue; } pair.Interior = array[0]; managedInteriors.Add(pair.Interior); pair.Ship.exitScript = pair.Interior; pair.Interior.exitScript = pair.Ship; if (!pair.Reported) { Log("Paired ID=" + pair.Id + ": " + StableKey(pair.Ship) + " <-> " + StableKey(pair.Interior) + "; spawned=" + ((NetworkBehaviour)pair.Ship).IsSpawned + "/" + ((NetworkBehaviour)pair.Interior).IsSpawned + "."); } pair.Reported = true; } UpdateInteraction(); } internal static bool TryFind(EntranceTeleport source, out bool found) { found = false; DoorPair doorPair = pairs.FirstOrDefault((DoorPair p) => (Object)(object)p.Ship == (Object)(object)source || ((Object)(object)p.Interior != (Object)null && (Object)(object)p.Interior == (Object)(object)source)); if (doorPair == null) { if (IsShip(source) || managedInteriors.Contains(source)) { ClearExit(source); return true; } return false; } EntranceTeleport val = (((Object)(object)source == (Object)(object)doorPair.Ship) ? doorPair.Interior : doorPair.Ship); int num = Mode(); bool flag = (((Object)(object)source == (Object)(object)doorPair.Ship) ? (num != 2) : (num != 1)); found = registered && idsReady && Landed() && flag && Available(doorPair.Ship) && (Object)(object)val != (Object)null && ((Component)val).gameObject.activeInHierarchy && (Object)(object)val.entrancePoint != (Object)null && source.entranceId == doorPair.Id && val.entranceId == doorPair.Id; source.exitScript = (found ? val : null); return true; } internal static void Reset() { foreach (DoorPair pair in pairs) { if ((Object)(object)pair.Ship != (Object)null) { ClearExit(pair.Ship); SetInteraction(pair.Ship, active: false); } if ((Object)(object)pair.Interior != (Object)null && (Object)(object)pair.Interior.exitScript == (Object)(object)pair.Ship) { ClearExit(pair.Interior); } } pairs.Clear(); managedInteriors.Clear(); registered = false; idsReady = false; } internal static void UpdateInteraction() { foreach (DoorPair pair in pairs) { if (!((Object)(object)pair.Ship == (Object)null)) { bool flag = registered && idsReady && Landed() && Available(pair.Ship) && (Object)(object)pair.Interior != (Object)null; if (flag != pair.Active) { SetInteraction(pair.Ship, flag); pair.Active = flag; } } } } private static void ClearExit(EntranceTeleport door) { door.exitScript = null; if (gotExit != null) { gotExit.SetValue(door, false); } if (firstCheck != null) { firstCheck.SetValue(door, false); } if (noExit != null) { noExit.SetValue(door, false); } } private static void SetInteraction(EntranceTeleport door, bool active) { ((Behaviour)door).enabled = active; InteractTrigger component = ((Component)door).GetComponent<InteractTrigger>(); if ((Object)(object)component != (Object)null) { ((Behaviour)component).enabled = active; } BoxCollider component2 = ((Component)door).GetComponent<BoxCollider>(); if ((Object)(object)component2 != (Object)null) { ((Collider)component2).enabled = active; } if ((Object)(object)((Component)door).transform.parent != (Object)null) { Transform val = ((Component)door).transform.parent.Find("EntranceTeleportWarning"); BoxCollider val2 = (((Object)(object)val == (Object)null) ? null : ((Component)val).GetComponent<BoxCollider>()); if ((Object)(object)val2 != (Object)null) { ((Collider)val2).enabled = !active; } } } private static string StableKey(EntranceTeleport door) { //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) string text = ""; Transform val = ((Component)door).transform; while ((Object)(object)val != (Object)null) { text = "/" + ((Object)val).name + "[" + val.GetSiblingIndex() + "]" + text; val = val.parent; } NetworkObject componentInParent = ((Component)door).GetComponentInParent<NetworkObject>(); if (!((Object)(object)componentInParent != (Object)null) || !componentInParent.IsSpawned) { Scene scene = ((Component)door).gameObject.scene; return ((Scene)(ref scene)).name + text; } return "net:" + componentInParent.NetworkObjectId.ToString("D20") + text; } } internal static class VersionInfo { internal const string Version = "0.1.1"; }