using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using HexBaseEnhancements.Patches; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("HexNowYouRest")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("HexNowYouRest")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("2f19ccf3-f7b4-4290-8797-0a4a4d8f585b")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] namespace HexBaseEnhancements { [BepInPlugin("com.hex.baseenhancements", "HexBaseEnhancements", "1.1.0")] public class Plugin : BaseUnityPlugin { private const string PluginGuid = "com.hex.baseenhancements"; private const string PluginName = "HexBaseEnhancements"; private const string PluginVersion = "1.1.0"; private Harmony _harmonyInstance; private ConfigEntry _isRemoveWetDebuffEnabled; private ConfigEntry _isCustomRestedDelayEnabled; private ConfigEntry _restedDelayInSeconds; private ConfigEntry _isRapidHealthAndStaminaRegenEnabled; private ConfigEntry _isAutoRepairEnabled; private ConfigEntry _isDoorOpenFaster; private ConfigEntry _isDoorsAutoClose; private ConfigEntry _doorAutoCloseInSeconds; private ConfigEntry _isIncreasedComfortRadiusEnabled; private ConfigEntry _isAutoRepairSoundEnabled; private ConfigEntry _comfortRadiusInMeters; internal static ManualLogSource Log; internal static Plugin Instance; internal static bool IsRemoveWetDebuffEnabled => Instance?._isRemoveWetDebuffEnabled?.Value == true; internal static bool IsCustomRestedDelayEnabled => Instance?._isCustomRestedDelayEnabled?.Value == true; internal static int RestedDelayInSeconds => Instance?._restedDelayInSeconds?.Value ?? 2; internal static bool IsRapidHealthAndStaminaRegenEnabled => Instance?._isRapidHealthAndStaminaRegenEnabled?.Value == true; internal static bool IsAutoRepairEnabled => Instance?._isAutoRepairEnabled?.Value == true; internal static bool DoorsOpensFaster => Instance?._isDoorOpenFaster?.Value == true; internal static bool DoorsAutoClose => Instance?._isDoorsAutoClose?.Value == true; internal static int DoorAutoCloseInSeconds => Instance?._doorAutoCloseInSeconds?.Value ?? 1; internal static bool IsIncreasedComfortRadiusEnabled => Instance?._isIncreasedComfortRadiusEnabled?.Value == true; internal static int ComfortRadiusInMeters => Instance?._comfortRadiusInMeters?.Value ?? 10; internal static bool IsAutoRepairSoundEnabled => Instance?._isAutoRepairSoundEnabled?.Value == true; private void Awake() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; BindConfig(); Assembly executingAssembly = Assembly.GetExecutingAssembly(); _harmonyInstance = new Harmony("com.hex.baseenhancements"); _harmonyInstance.PatchAll(executingAssembly); Log.LogInfo((object)"HexBaseEnhancements v1.1.0 loaded."); } private void OnDestroy() { if (_isCustomRestedDelayEnabled != null) { _isCustomRestedDelayEnabled.SettingChanged -= OnCustomRestedDelayEnabledChanged; } if (_restedDelayInSeconds != null) { _restedDelayInSeconds.SettingChanged -= OnRestedDelaySecondsChanged; } Log.LogInfo((object)"HexBaseEnhancements v1.1.0 unloaded."); Harmony harmonyInstance = _harmonyInstance; if (harmonyInstance != null) { harmonyInstance.UnpatchSelf(); } _harmonyInstance = null; Instance = null; Log = null; } private void BindConfig() { //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Expected O, but got Unknown _isRemoveWetDebuffEnabled = ((BaseUnityPlugin)this).Config.Bind("General", "RemoveWetDebuff", true, "Removes the Wet status effect when the player is sheltered and near a fire."); _isCustomRestedDelayEnabled = ((BaseUnityPlugin)this).Config.Bind("General", "CustomRestedDelay", true, "Enables a custom delay before the player receives the Rested status effect."); _restedDelayInSeconds = ((BaseUnityPlugin)this).Config.Bind("General", "RestedDelayInSeconds", 2, "The number of seconds the player must rest before receiving the Rested status effect. Only used when CustomRestedDelay is enabled."); _isRapidHealthAndStaminaRegenEnabled = ((BaseUnityPlugin)this).Config.Bind("General", "EnableRapidHealthAndStaminaRegen", true, "Rapidly restores health and stamina while the player is resting."); _isAutoRepairEnabled = ((BaseUnityPlugin)this).Config.Bind("General", "EnableAutoRepair", true, "Automatically repairs all repairable items in the player's inventory when the player is sheltered and near a fire."); _isDoorOpenFaster = ((BaseUnityPlugin)this).Config.Bind("General", "EnableDoorOpenFaster", true, "Makes doors open really fast."); _isDoorsAutoClose = ((BaseUnityPlugin)this).Config.Bind("General", "EnableDoorsAutoClose", true, "Automatically closes doors after a short delay when opened."); _doorAutoCloseInSeconds = ((BaseUnityPlugin)this).Config.Bind("General", "DoorAutoCloseInSeconds", 1, "The number of seconds after which doors will automatically close when opened. Only used when EnableDoorsAutoClose is enabled."); _isIncreasedComfortRadiusEnabled = ((BaseUnityPlugin)this).Config.Bind("General", "EnableIncreasedComfortRadius", true, "Increases the radius used to detect nearby comfort-providing pieces."); _comfortRadiusInMeters = ((BaseUnityPlugin)this).Config.Bind("General", "ComfortRadiusInMeters", 20, new ConfigDescription("The radius in meters used to detect nearby comfort-providing pieces. Only used when EnableIncreasedComfortRadius is enabled.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 50), Array.Empty())); _isAutoRepairSoundEnabled = ((BaseUnityPlugin)this).Config.Bind("General", "EnableAutoRepairSound", true, "Plays a sound when auto-repairing items. Only used when EnableAutoRepair is enabled."); _isCustomRestedDelayEnabled.SettingChanged += OnCustomRestedDelayEnabledChanged; _restedDelayInSeconds.SettingChanged += OnRestedDelaySecondsChanged; } private void OnCustomRestedDelayEnabledChanged(object sender, EventArgs e) { PatchSECozySetup.ApplyRestedDelay(); } private void OnRestedDelaySecondsChanged(object sender, EventArgs e) { PatchSECozySetup.ApplyRestedDelay(); } } } namespace HexBaseEnhancements.Patches { [HarmonyPatch(typeof(Door), "SetState")] internal static class PatchDoorSetState { private const float VanillaAnimationSpeed = 1f; private const float FastOpenAnimationSpeed = 50f; [HarmonyPrefix] private static void Prefix(int state, Animator ___m_animator) { if (!((Object)(object)___m_animator == (Object)null)) { ___m_animator.speed = ((Plugin.DoorsOpensFaster && state != 0) ? 50f : 1f); } } [HarmonyPostfix] private static void Postfix(Door __instance, int state, ZNetView ___m_nview) { if (Plugin.DoorsAutoClose && !((Object)(object)__instance == (Object)null) && !((Object)(object)___m_nview == (Object)null) && state != 0 && ___m_nview.IsValid() && ___m_nview.IsOwner()) { ((MonoBehaviour)__instance).StartCoroutine(AutoCloseDoor(___m_nview)); } } private static IEnumerator AutoCloseDoor(ZNetView nview) { yield return (object)new WaitForSeconds((float)Plugin.DoorAutoCloseInSeconds); if (!((Object)(object)nview == (Object)null) && nview.IsValid() && nview.IsOwner()) { ZDO zDO = nview.GetZDO(); if (zDO != null && zDO.GetInt(ZDOVars.s_state, 0) != 0) { nview.InvokeRPC("UseDoor", new object[1] { false }); } } } } [HarmonyPatch(typeof(Player), "UpdateCover")] internal static class PatchPlayerUpdateCover { private const float NearFireTimeout = 0.25f; private static readonly FieldInfo NearFireTimerField = AccessTools.Field(typeof(Player), "m_nearFireTimer"); private static readonly MethodInfo GetCoverForPointMethod = AccessTools.Method(typeof(Cover), "GetCoverForPoint", (Type[])null, (Type[])null); private static readonly MethodInfo ApplyShelterEnhancementsMethod = AccessTools.Method(typeof(PatchPlayerUpdateCover), "ApplyShelterEnhancements", (Type[])null, (Type[])null); [HarmonyTranspiler] internal static IEnumerable Transpiler(IEnumerable instructions) { //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Expected O, but got Unknown //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Expected O, but got Unknown List list = instructions.ToList(); List list2 = (from x in list.Select((CodeInstruction instruction, int index2) => new { instruction = instruction, index = index2 }) where CodeInstructionExtensions.Calls(x.instruction, GetCoverForPointMethod) select x.index).ToList(); if (list2.Count != 1) { Plugin.Log.LogError((object)$"Player.UpdateCover transpiler expected 1 call to Cover.GetCoverForPoint, but found {list2.Count}. Patch not applied."); return list; } int index = list2[0] + 1; list.InsertRange(index, (IEnumerable)(object)new CodeInstruction[2] { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)ApplyShelterEnhancementsMethod) }); return list; } private static void ApplyShelterEnhancements(Player player) { if (!((Object)(object)player == (Object)null) && !(NearFireTimerField == null) && player.InShelter() && !((float)NearFireTimerField.GetValue(player) >= 0.25f)) { RemoveWetDebuff(player); RepairInventory(player); } } private static void RemoveWetDebuff(Player player) { if (Plugin.IsRemoveWetDebuffEnabled) { SEMan sEMan = ((Character)player).GetSEMan(); if (sEMan != null && sEMan.HaveStatusEffect(SEMan.s_statusEffectWet)) { sEMan.RemoveStatusEffect(SEMan.s_statusEffectWet, false); } } } private static void RepairInventory(Player player) { //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.IsAutoRepairEnabled) { return; } List allItems = ((Humanoid)player).GetInventory().GetAllItems(); bool flag = false; foreach (ItemData item in allItems) { if (item.m_shared.m_useDurability) { float maxDurability = item.GetMaxDurability(); if (!(item.m_durability >= maxDurability)) { item.m_durability = maxDurability; flag = true; } } } if (!flag) { return; } ((Character)player).Message((MessageType)1, "Inventory items repaired", 0, (Sprite)null); if (Plugin.IsAutoRepairSoundEnabled) { GameObject prefab = ZNetScene.instance.GetPrefab("sfx_gui_repairitem_workbench"); if ((Object)(object)prefab != (Object)null) { Object.Instantiate(prefab, ((Component)player).transform.position, Quaternion.identity); } } } } [HarmonyPatch(typeof(SE_Cozy), "Setup")] internal static class PatchSECozySetup { private const float VanillaRestedDelay = 10f; private static SE_Cozy _currentCozy; [HarmonyPostfix] private static void Postfix(SE_Cozy __instance) { if (!((Object)(object)__instance == (Object)null) && !(__instance.m_statusEffect != "Rested")) { _currentCozy = __instance; ApplyRestedDelay(); RestoreHealthAndStamina(__instance); } } internal static void ApplyRestedDelay() { if (!((Object)(object)_currentCozy == (Object)null)) { _currentCozy.m_delay = (Plugin.IsCustomRestedDelayEnabled ? ((float)Plugin.RestedDelayInSeconds) : 10f); } } private static void RestoreHealthAndStamina(SE_Cozy cozy) { if (Plugin.IsRapidHealthAndStaminaRegenEnabled) { Character character = ((StatusEffect)cozy).m_character; Player val = (Player)(object)((character is Player) ? character : null); if (!((Object)(object)val == (Object)null)) { ((Character)val).Heal(((Character)val).GetMaxHealth(), false); ((Character)val).AddStamina(((Character)val).GetMaxStamina()); } } } } [HarmonyPatch(typeof(SE_Rested), "GetNearbyComfortPieces")] internal static class PatchSERestedGetNearbyComfortPieces { private const float VanillaComfortRadius = 10f; private static readonly FieldInfo TempPiecesField = AccessTools.Field(typeof(SE_Rested), "s_tempPieces"); private static readonly MethodInfo GetAllComfortPiecesInRadiusMethod = AccessTools.Method(typeof(Piece), "GetAllComfortPiecesInRadius", (Type[])null, (Type[])null); private static readonly MethodInfo GetComfortRadiusMethod = AccessTools.Method(typeof(PatchSERestedGetNearbyComfortPieces), "GetComfortRadius", (Type[])null, (Type[])null); [HarmonyTranspiler] internal static IEnumerable Transpiler(IEnumerable instructions) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected O, but got Unknown CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null); val.MatchForward(false, (CodeMatch[])(object)new CodeMatch[3] { new CodeMatch((OpCode?)OpCodes.Ldc_R4, (object)10f, (string)null), new CodeMatch((OpCode?)OpCodes.Ldsfld, (object)TempPiecesField, (string)null), new CodeMatch((Func)((CodeInstruction instruction) => CodeInstructionExtensions.Calls(instruction, GetAllComfortPiecesInRadiusMethod)), (string)null) }); if (!val.IsValid) { Plugin.Log.LogError((object)"SE_Rested.GetNearbyComfortPieces transpiler could not locate the comfort radius call. Patch not applied."); return val.InstructionEnumeration(); } val.Instruction.opcode = OpCodes.Call; val.Instruction.operand = GetComfortRadiusMethod; return val.InstructionEnumeration(); } private static float GetComfortRadius() { if (!Plugin.IsIncreasedComfortRadiusEnabled) { return 10f; } return Plugin.ComfortRadiusInMeters; } } }