using System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using Unity.Netcode; 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("FacilityScan")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("FacilityScan")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("7ec22a90-f30d-4c0e-95d4-d97a377caff8")] [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 FacilityScan; public enum BroadcastMode { SelfOnly, HostOnly, Always } [BepInPlugin("azumi.FacilityScan", "FacilityScan", "1.0.0")] [BepInProcess("Lethal Company.exe")] public class Plugin : BaseUnityPlugin { public const string PLUGIN_GUID = "azumi.FacilityScan"; public const string PLUGIN_NAME = "FacilityScan"; public const string PLUGIN_VERSION = "1.0.0"; internal static Plugin Instance; internal static ManualLogSource Log; internal static ConfigEntry Enabled; internal static ConfigEntry Broadcast; private readonly Harmony harmony = new Harmony("azumi.FacilityScan"); private void Awake() { Instance = this; Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind("General", "Enabled", true, "Enable FacilityScan."); Broadcast = ((BaseUnityPlugin)this).Config.Bind("General", "BroadcastMode", BroadcastMode.HostOnly, "SelfOnly / HostOnly / Always"); harmony.PatchAll(); Log.LogInfo((object)"FacilityScan loaded."); } } internal static class ChatUtils { public static bool SendChatToSelf(string message) { HUDManager instance = HUDManager.Instance; if ((Object)(object)instance == (Object)null) { return false; } instance.AddTextToChatOnServer(message, -1); return true; } public static bool SendChatToEveryone(string message) { HUDManager instance = HUDManager.Instance; if ((Object)(object)instance == (Object)null) { return false; } PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val == (Object)null) { return false; } instance.AddTextToChatOnServer(message, (int)val.playerClientId); return true; } } internal static class NetworkUtils { public static bool IsHost() { return (Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsHost; } public static bool IsClient() { return (Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsClient; } } [HarmonyPatch(typeof(RoundManager))] internal class RoundManagerPatch { private static int lastSeed = -1; [HarmonyPatch("FinishGeneratingNewLevelClientRpc")] [HarmonyPostfix] private static void FinishGeneratingNewLevelClientRpcPostfix() { if (!NetworkUtils.IsClient() || !Plugin.Enabled.Value) { return; } RoundManager instance = RoundManager.Instance; if ((Object)(object)instance == (Object)null) { return; } int randomMapSeed = StartOfRound.Instance.randomMapSeed; if (randomMapSeed == lastSeed) { return; } lastSeed = randomMapSeed; SelectableLevel currentLevel = StartOfRound.Instance.currentLevel; if (!((Object)(object)currentLevel == (Object)null) && !currentLevel.PlanetName.Contains("Gordion")) { string facilityName = GetFacilityName(); string text = "Facility: " + facilityName; bool flag = false; if (Plugin.Broadcast.Value switch { BroadcastMode.SelfOnly => ChatUtils.SendChatToSelf(text), BroadcastMode.HostOnly => (!NetworkUtils.IsHost()) ? ChatUtils.SendChatToSelf(text) : ChatUtils.SendChatToEveryone(text), _ => ChatUtils.SendChatToEveryone(text), }) { Plugin.Log.LogInfo((object)("Sent: " + text)); } else { Plugin.Log.LogError((object)"Failed to send message."); } } } private static string GetFacilityName() { try { RoundManager instance = RoundManager.Instance; if ((Object)(object)instance == (Object)null) { return "Unknown"; } if ((Object)(object)instance.dungeonGenerator == (Object)null) { return "Unknown"; } if (instance.dungeonGenerator.Generator != null && (Object)(object)instance.dungeonGenerator.Generator.DungeonFlow != (Object)null) { string name = ((Object)instance.dungeonGenerator.Generator.DungeonFlow).name; string text = name.ToLowerInvariant(); Plugin.Log.LogInfo((object)("DungeonFlow raw name: " + name)); if (text.Contains("level1") || text.Contains("factory") || text.Contains("facility")) { return "Factory"; } if (text.Contains("mansion") || text.Contains("level2") || text.Contains("manor")) { return "Mansion"; } if (text.Contains("level3") || text.Contains("mine") || text.Contains("shaft") || text.Contains("cave") || text.Contains("mineshaft")) { return "Mineshaft"; } } if ((Object)(object)((Component)instance.dungeonGenerator).gameObject != (Object)null) { string name2 = ((Object)((Component)instance.dungeonGenerator).gameObject).name; string text2 = name2.ToLowerInvariant(); Plugin.Log.LogInfo((object)("DungeonGenerator object name: " + name2)); if (text2.Contains("mine") || text2.Contains("shaft") || text2.Contains("cave")) { return "Mineshaft"; } if (text2.Contains("mansion")) { return "Mansion"; } if (text2.Contains("factory") || text2.Contains("facility") || text2.Contains("level1")) { return "Factory"; } } return "Unknown"; } catch (Exception ex) { Plugin.Log.LogError((object)ex); return "Unknown"; } } }