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 Connected Doors v1.0.1
ConnectedDoors.dll
Decompiled 11 hours agousing System; using System.Collections.Generic; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using Dawn; using HarmonyLib; using Unity.Netcode; using UnityEngine; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace ConnectedDoors; internal static class ModInfo { public const string GUID = "ConnectedDoors.PocketRoomAddon"; public const string NAME = "Connected Doors"; public const string VERSION = "1.0.1"; public const string PocketRoomsGuid = "MelanieMelicious.pocketRoom"; public const string PocketRoomLibGuid = "MelanieMelicious.pocketRoomLib"; public const string DawnLibGuid = "com.github.teamxiaolan.dawnlib"; public const string DawnNamespace = "ConnectedDoors"; } internal class DoorEntry { public int Index; public string Name; public GameObject Prefab; public UnlockableItem Item; } [BepInPlugin("ConnectedDoors.PocketRoomAddon", "Connected Doors", "1.0.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { internal static ManualLogSource Log; internal static readonly List<DoorEntry> Doors = new List<DoorEntry>(); private static UnlockableItem template; private static GameObject holder; private ConfigEntry<int> price; internal static void Info(string text) { if (Log != null) { Log.LogInfo((object)text); } } internal static void Warn(string text) { if (Log != null) { Log.LogWarning((object)text); } } internal static void Error(string text) { if (Log != null) { Log.LogError((object)text); } } private void Awake() { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; price = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Price", 0, "Price of each connected door in the terminal store. 0 = free."); try { BuildDoors(Math.Max(0, price.Value)); Harmony harmony = new Harmony("ConnectedDoors.PocketRoomAddon"); TryPatch(harmony, typeof(StartOfRoundAwakePatch)); TryPatch(harmony, typeof(TerminalAwakePatch)); TryPatch(harmony, typeof(LoadUnlockablesPatch)); Info("Connected Doors 1.0.1 loaded: " + Doors.Count + " doors registered."); } catch (Exception ex) { Error("Connected Doors could not start, no doors were added: " + ex); } } private static void TryPatch(Harmony harmony, Type patchClass) { try { harmony.PatchAll(patchClass); } catch (Exception ex) { Warn("Could not apply " + patchClass.Name + " (the doors are still registered): " + ex.Message); } } private static void BuildDoors(int cost) { template = FindTemplate(); Info("Using the door of '" + template.unlockableName + "' (" + ((Object)template.prefabObject).name + ") as the model."); for (int i = 0; i < 2; i++) { DoorEntry doorEntry = CreateDoor(i, template); Doors.Add(doorEntry); DawnBridge.Register(doorEntry.Prefab, doorEntry.Item, doorEntry.Name, cost); Info("Registered '" + doorEntry.Name + "' (price " + cost + ")."); } } private static UnlockableItem FindTemplate() { if (!Chainloader.PluginInfos.TryGetValue("MelanieMelicious.pocketRoom", out var value) || (Object)(object)value.Instance == (Object)null) { throw new InvalidOperationException("The Pocket Rooms plugin is not loaded."); } object instance = value.Instance; FieldInfo field = instance.GetType().GetField("unlockList", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); UnlockableItem[] array = ((!(field == null)) ? (field.GetValue(instance) as UnlockableItem[]) : null); if (array == null || array.Length == 0) { throw new InvalidOperationException("Pocket Rooms did not provide its furniture list (unsupported Pocket Rooms version?)."); } UnlockableItem[] array2 = array; foreach (UnlockableItem val in array2) { if (val != null && !((Object)(object)val.prefabObject == (Object)null)) { GameObject prefabObject = val.prefabObject; if (!((Object)(object)prefabObject.GetComponent<NetworkObject>() == (Object)null) && (Object)(object)FindDoorTeleport(prefabObject) != (Object)null) { return val; } } } throw new InvalidOperationException("No usable door was found in the Pocket Rooms furniture."); } private static RoomTeleport FindDoorTeleport(GameObject root) { RoomTeleport[] componentsInChildren = root.GetComponentsInChildren<RoomTeleport>(true); for (int i = 0; i < componentsInChildren.Length; i++) { if (!componentsInChildren[i].isExit) { return componentsInChildren[i]; } } return null; } private static void EnsureHolder() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown if (!((Object)(object)holder != (Object)null)) { holder = new GameObject("ConnectedDoors_PrefabHolder"); ((Object)holder).hideFlags = (HideFlags)61; holder.SetActive(false); } } private static string DoorName(int index) { return "connecteddoor" + index; } private static GameObject BuildPrefab(int index, UnlockableItem source) { EnsureHolder(); GameObject val = Object.Instantiate<GameObject>(source.prefabObject, holder.transform); ((Object)val).hideFlags = (HideFlags)61; ((Object)val).name = "ConnectedDoor" + index; RoomTeleport val2 = FindDoorTeleport(val); if ((Object)(object)val2 == (Object)null) { throw new InvalidOperationException("The door teleport went missing while cloning."); } Transform val3 = ((Component)val2).transform; while ((Object)(object)val3 != (Object)null && (Object)(object)val3.parent != (Object)(object)val.transform) { val3 = val3.parent; } if ((Object)(object)val3 == (Object)null) { throw new InvalidOperationException("The door teleport is not inside a door object."); } PocketRoom component = val.GetComponent<PocketRoom>(); if ((Object)(object)component != (Object)null) { Object.DestroyImmediate((Object)(object)component); } Transform transform = val.transform; for (int num = transform.childCount - 1; num >= 0; num--) { Transform child = transform.GetChild(num); if ((Object)(object)child != (Object)(object)val3) { Object.DestroyImmediate((Object)(object)((Component)child).gameObject); } } InteractTrigger componentInChildren = ((Component)val3).GetComponentInChildren<InteractTrigger>(true); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.hoverTip = "Go through : [LMB]"; componentInChildren.disabledHoverTip = "Nothing on the other side"; } NetworkObject component2 = val.GetComponent<NetworkObject>(); if ((Object)(object)component2 == (Object)null) { throw new InvalidOperationException("The door prefab has no NetworkObject."); } SetNetworkObjectHash(component2, StableHash("ConnectedDoors/" + DoorName(index))); ConnectedDoorLink connectedDoorLink = val.AddComponent<ConnectedDoorLink>(); connectedDoorLink.index = index; connectedDoorLink.teleport = val2; connectedDoorLink.walkTrigger = ((Component)val2).GetComponent<Collider>(); connectedDoorLink.interact = componentInChildren; connectedDoorLink.ship = val.GetComponent<AutoParentToShip>(); int num2 = val.GetComponentsInChildren<NetworkBehaviour>(true).Length; Info(((Object)val).name + ": " + num2 + " network behaviours, " + transform.childCount + " child object(s) kept."); return val; } private static DoorEntry CreateDoor(int index, UnlockableItem source) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown string text = DoorName(index); GameObject val = BuildPrefab(index, source); UnlockableItem val2 = new UnlockableItem(); FieldInfo[] fields = typeof(UnlockableItem).GetFields(BindingFlags.Instance | BindingFlags.Public); foreach (FieldInfo fieldInfo in fields) { fieldInfo.SetValue(val2, fieldInfo.GetValue(source)); } val2.unlockableName = text; val2.prefabObject = val; SetFieldIfPresent(val2, "shopSelectionNode", null); SetFieldIfPresent(val2, "alreadyUnlocked", false); SetFieldIfPresent(val2, "hasBeenUnlockedByPlayer", false); SetFieldIfPresent(val2, "inStorage", false); SetFieldIfPresent(val2, "hasBeenMoved", false); DoorEntry doorEntry = new DoorEntry(); doorEntry.Index = index; doorEntry.Name = text; doorEntry.Prefab = val; doorEntry.Item = val2; return doorEntry; } private static void SetFieldIfPresent(object target, string fieldName, object value) { FieldInfo field = target.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { field.SetValue(target, value); } } private static void SetNetworkObjectHash(NetworkObject netObj, uint hash) { FieldInfo field = typeof(NetworkObject).GetField("GlobalObjectIdHash", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { throw new MissingFieldException("NetworkObject.GlobalObjectIdHash was not found (unsupported Netcode version?)."); } field.SetValue(netObj, hash); } internal static uint StableHash(string text) { uint num = 2166136261u; for (int i = 0; i < text.Length; i++) { num ^= text[i]; num *= 16777619; } return (num == 0) ? 1u : num; } internal static void EnsureDoorsAlive(string when) { foreach (DoorEntry door in Doors) { if ((Object)(object)door.Prefab != (Object)null) { continue; } Error("'" + door.Name + "' lost its prefab before " + when + " (something destroyed it). Rebuilding it so the game can still start."); try { GameObject val = (door.Prefab = BuildPrefab(door.Index, template)); door.Item.prefabObject = val; try { if ((Object)(object)NetworkManager.Singleton != (Object)null) { NetworkManager.Singleton.AddNetworkPrefab(val); } } catch (Exception ex) { Warn("Could not register the rebuilt '" + door.Name + "' with Netcode: " + ex.Message); } } catch (Exception ex2) { Error("Could not rebuild '" + door.Name + "': " + ex2); } } } internal static void AssignUnlockableIds(string when) { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.unlockablesList == (Object)null) { return; } List<UnlockableItem> unlockables = instance.unlockablesList.unlockables; foreach (DoorEntry door in Doors) { if ((Object)(object)door.Prefab == (Object)null) { continue; } int num = unlockables.IndexOf(door.Item); if (num < 0) { Warn("'" + door.Name + "' is not in the unlockables list (" + when + "); was it registered by DawnLib?"); continue; } PlaceableShipObject[] componentsInChildren = door.Prefab.GetComponentsInChildren<PlaceableShipObject>(true); foreach (PlaceableShipObject val in componentsInChildren) { val.unlockableID = num; } AutoParentToShip[] componentsInChildren2 = door.Prefab.GetComponentsInChildren<AutoParentToShip>(true); foreach (AutoParentToShip val2 in componentsInChildren2) { val2.unlockableID = num; } Info("'" + door.Name + "' has unlockable id " + num + " (" + when + ")."); } } } [HarmonyPatch(typeof(StartOfRound), "Awake")] internal static class StartOfRoundAwakePatch { [HarmonyPriority(800)] [HarmonyPrefix] private static void CheckPrefabs() { try { Plugin.EnsureDoorsAlive("StartOfRound.Awake"); } catch (Exception ex) { Plugin.Error("Connected Doors prefab check failed: " + ex); } } } [HarmonyPatch(typeof(Terminal), "Awake")] internal static class TerminalAwakePatch { [HarmonyPostfix] private static void AssignIds() { try { Plugin.AssignUnlockableIds("after Terminal.Awake"); } catch (Exception ex) { Plugin.Error("Connected Doors could not assign unlockable ids: " + ex); } } } [HarmonyPatch(typeof(StartOfRound), "LoadUnlockables")] internal static class LoadUnlockablesPatch { [HarmonyPriority(800)] [HarmonyPrefix] private static void AssignIds() { try { Plugin.EnsureDoorsAlive("StartOfRound.LoadUnlockables"); Plugin.AssignUnlockableIds("before LoadUnlockables"); } catch (Exception ex) { Plugin.Error("Connected Doors could not assign unlockable ids: " + ex); } } } internal static class DawnBridge { internal static void Register(GameObject prefab, UnlockableItem item, string key, int cost) { DawnLib.RegisterNetworkPrefab(prefab); DawnLib.DefineUnlockable(NamespacedKey<DawnUnlockableItemInfo>.From("ConnectedDoors", key), item, (Action<UnlockableInfoBuilder>)delegate(UnlockableInfoBuilder builder) { builder.SetCost(cost); }); } } public class ConnectedDoorLink : MonoBehaviour { public int index; public RoomTeleport teleport; public Collider walkTrigger; public InteractTrigger interact; public AutoParentToShip ship; private static readonly List<ConnectedDoorLink> Live = new List<ConnectedDoorLink>(); private int frame; private bool? lastConnected; private void OnEnable() { if (!Live.Contains(this)) { Live.Add(this); } Plugin.Info("Door " + index + " appeared."); RefreshAll(); } private void OnDisable() { Live.Remove(this); RefreshAll(); } private void OnDestroy() { Live.Remove(this); } private void Update() { frame++; if (frame % 15 == 0) { RefreshAll(); } } private bool IsStored() { return (Object)(object)ship != (Object)null && ship.disableObject; } private static void RefreshAll() { for (int i = 0; i < Live.Count; i++) { ConnectedDoorLink connectedDoorLink = Live[i]; ConnectedDoorLink partner = null; for (int j = 0; j < Live.Count; j++) { ConnectedDoorLink connectedDoorLink2 = Live[j]; if ((Object)(object)connectedDoorLink2 != (Object)(object)connectedDoorLink && connectedDoorLink2.index != connectedDoorLink.index && !connectedDoorLink2.IsStored()) { partner = connectedDoorLink2; break; } } connectedDoorLink.Link(partner); } } private void Link(ConnectedDoorLink partner) { if (!((Object)(object)teleport == (Object)null)) { bool flag = (Object)(object)partner != (Object)null && (Object)(object)partner.teleport != (Object)null && (Object)(object)partner.teleport.entrancePoint != (Object)null && (Object)(object)teleport.entrancePoint != (Object)null && !IsStored(); teleport.exitPoint = ((!flag) ? teleport.entrancePoint : partner.teleport.entrancePoint); if ((Object)(object)walkTrigger != (Object)null) { walkTrigger.enabled = flag; } if ((Object)(object)interact != (Object)null) { interact.interactable = flag; } bool? flag2 = lastConnected; if (!flag2.HasValue || lastConnected.Value != flag) { lastConnected = flag; Plugin.Info((!flag) ? ("Door " + index + " has no door to connect to (the other door is not placed or is in storage).") : ("Door " + index + " is now connected to door " + partner.index + ".")); } } } }