using BepInEx; using BepInEx.Logging; using HarmonyLib; using System; using System.Linq; namespace DevourUnlocker.BepInEx { [BepInPlugin("com.mithral.devourunlocker", "DevourUnlocker", "2.0.0")] public class Plugin : BaseUnityPlugin { internal static ManualLogSource Log; private Harmony _harmony; void Awake() { Log = Logger; Log.LogInfo("DevourUnlocker BepInEx v2 loaded — selective unlock"); _harmony = new Harmony("com.mithral.devourunlocker"); try { _harmony.PatchAll(); Log.LogInfo("Harmony patches applied"); } catch (Exception e) { Log.LogError(e); } } void OnGUI() { if (!DevourGUI.visible) return; DevourGUI.Draw(); } void Update() { if (UnityEngine.Input.GetKeyDown(UnityEngine.KeyCode.F6)) DevourGUI.visible = !DevourGUI.visible; } void OnDestroy() { _harmony?.UnpatchSelf(); } } // Generic unlock patches — try multiple owner classes // Always-on: every IsRobe/IsCharacter/Has* check returns true, every UpdateLocked* is skipped static class Patches { static System.Reflection.MethodBase Find(string typeName, string method) { var t = AccessTools.TypeByName(typeName); if (t==null) return null; var m = AccessTools.Method(t, method); if (m!=null) Plugin.Log?.LogInfo($"Found {typeName}.{method}"); return m; } static System.Reflection.MethodBase FindAny(string method, params string[] types){ foreach(var tn in types){ var m=Find(tn,method); if(m!=null) return m; } Plugin.Log?.LogWarning($"{method} not found in {string.Join(",",types)}"); return null; } [HarmonyPatch] class IsRobeUnlockedPatch { static System.Reflection.MethodBase TargetMethod()=> FindAny("IsRobeUnlocked","NolanRankController","SurvivalLobbyController","LobbyController"); static bool Prefix(ref bool __result){ __result=true; return false; } } [HarmonyPatch] class IsCharacterUnlockedPatch { static System.Reflection.MethodBase TargetMethod()=> FindAny("IsCharacterUnlocked","NolanRankController","SurvivalLobbyController"); static bool Prefix(ref bool __result){ __result=true; return false; } } [HarmonyPatch] class HasPerkPatch { static System.Reflection.MethodBase TargetMethod()=> FindAny("HasPerk","NolanRankController"); static bool Prefix(ref bool __result){ __result=true; return false; } } [HarmonyPatch] class HasOutfitPatch { static System.Reflection.MethodBase TargetMethod()=> FindAny("HasOutfit","NolanRankController"); static bool Prefix(ref bool __result){ __result=true; return false; } } [HarmonyPatch] class HasCollectedAllPatch { static System.Reflection.MethodBase TargetMethod()=> FindAny("HasCollectedAllBarbedWires","NolanRankController"); static bool Prefix(ref bool __result){ __result=true; return false; } } // UpdateLocked* — skip (return false to prevent original from marking locked) [HarmonyPatch] class UpdateLockedPetsPatch { static System.Reflection.MethodBase TargetMethod()=> FindAny("UpdateLockedPets","SurvivalLobbyController","LobbyController"); static bool Prefix()=> false; } [HarmonyPatch] class UpdateLockedPerksPatch { static System.Reflection.MethodBase TargetMethod()=> FindAny("UpdateLockedPerks","SurvivalLobbyController"); static bool Prefix()=> false; } [HarmonyPatch] class UpdateLockedFlashlightsPatch { static System.Reflection.MethodBase TargetMethod()=> FindAny("UpdateLockedFlashlights","SurvivalLobbyController"); static bool Prefix()=> false; } [HarmonyPatch] class UpdateLockedEmotesPatch { static System.Reflection.MethodBase TargetMethod()=> FindAny("UpdateLockedEmotes","SurvivalLobbyController"); static bool Prefix()=> false; } [HarmonyPatch] class UpdateLockedOutfitsPatch { static System.Reflection.MethodBase TargetMethod()=> FindAny("UpdateLockedOutfits","SurvivalLobbyController"); static bool Prefix()=> false; } [HarmonyPatch] class UpdateLockedRobesPatch { static System.Reflection.MethodBase TargetMethod()=> FindAny("UpdateLockedRobes","SurvivalLobbyController"); static bool Prefix()=> false; } [HarmonyPatch] class WaitForPurchasedPetValidationPatch { static System.Reflection.MethodBase TargetMethod()=> FindAny("WaitForPurchasedPetValidation","SurvivalLobbyController"); static bool Prefix()=> false; } } static class DevourGUI { public static bool visible = false; // always-on, GUI hidden by default (F6 to show debug) public static void Draw() { var rect = new UnityEngine.Rect(20, 20, 400, 100); UnityEngine.GUI.Box(rect, ""); GUILayout.BeginArea(rect); GUILayout.Label("DevourUnlocker — Always On (all robes/chars/perks/pets unlocked)"); GUILayout.Label("F6 to toggle this debug window"); GUILayout.EndArea(); } } }