using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.SceneManagement;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("MuckRested")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Valheim-style Rested buff: rest sheltered near a furnace or cauldron for stamina and health regen.")]
[assembly: AssemblyFileVersion("0.1.2.0")]
[assembly: AssemblyInformationalVersion("0.1.2+879fc7ac66fec639f2f84b4b7a65d5c61c9ed734")]
[assembly: AssemblyProduct("Rested")]
[assembly: AssemblyTitle("MuckRested")]
[assembly: InternalsVisibleTo("MuckRested.Tests")]
[assembly: AssemblyVersion("0.1.2.0")]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
internal sealed class IsReadOnlyAttribute : Attribute
{
}
}
namespace MuckRested
{
public readonly struct StationSample
{
public StationKind Kind { get; }
public float X { get; }
public float Y { get; }
public float Z { get; }
public int OwnerId { get; }
public StationSample(StationKind kind, float x, float y, float z, int ownerId)
{
Kind = kind;
X = x;
Y = y;
Z = z;
OwnerId = ownerId;
}
}
public readonly struct Comfort
{
public bool HasFire { get; }
public int DistinctKinds { get; }
public static Comfort None => new Comfort(hasFire: false, 0);
public Comfort(bool hasFire, int distinctKinds)
{
HasFire = hasFire;
DistinctKinds = distinctKinds;
}
}
public static class ComfortScan
{
public static Comfort Evaluate(IReadOnlyList<StationSample> samples, float px, float py, float pz, float radius, bool ownBuildsOnly, int myId)
{
if (float.IsNaN(radius) || radius < 0f)
{
radius = 0f;
}
float num = radius * radius;
int num2 = 0;
bool hasFire = false;
for (int i = 0; i < samples.Count; i++)
{
StationSample stationSample = samples[i];
if (stationSample.Kind == StationKind.None || (ownBuildsOnly && stationSample.OwnerId != myId))
{
continue;
}
float num3 = stationSample.X - px;
float num4 = stationSample.Y - py;
float num5 = stationSample.Z - pz;
if (!(num3 * num3 + num4 * num4 + num5 * num5 > num))
{
num2 |= StationKinds.Bit(stationSample.Kind);
if (StationKinds.IsFire(stationSample.Kind))
{
hasFire = true;
}
}
}
return new Comfort(hasFire, CountBits(num2));
}
private static int CountBits(int mask)
{
int num = 0;
for (uint num2 = (uint)mask; num2 != 0; num2 >>= 1)
{
num += (int)(num2 & 1);
}
return num;
}
}
public static class HudGate
{
public static bool Hidden(bool notPlaying, bool otherUi, bool inventoryOpen, bool dead)
{
return notPlaying || otherUi || inventoryOpen || dead;
}
}
public readonly struct HudBox
{
public readonly float PlateX;
public readonly float PlateY;
public readonly float PlateWidth;
public readonly float PlateHeight;
public readonly float TextX;
public readonly float TextY;
public readonly float TextWidth;
public readonly float TextHeight;
public readonly float Shadow;
public HudBox(float plateX, float plateY, float plateWidth, float plateHeight, float pad, float textWidth, float textHeight, float shadow)
{
PlateX = plateX;
PlateY = plateY;
PlateWidth = plateWidth;
PlateHeight = plateHeight;
TextX = plateX + pad;
TextY = plateY + pad;
TextWidth = textWidth;
TextHeight = textHeight;
Shadow = shadow;
}
}
public static class HudLayout
{
public const int BaseFontSize = 20;
private const float Margin = 12f;
private const float Pad = 6f;
public static float Scale(int screenHeight)
{
return Math.Max(1f, (float)screenHeight / 1080f);
}
public static int FontSize(int screenHeight)
{
return (int)Math.Round(20f * Scale(screenHeight), MidpointRounding.AwayFromZero);
}
public static HudBox For(int screenWidth, int screenHeight, float textWidth, float textHeight)
{
float num = Scale(screenHeight);
float num2 = (float)Math.Round(6f * num);
float val = (float)Math.Round(12f * num);
float num3 = (float)Math.Ceiling(textWidth) + 2f * num2;
float num4 = (float)Math.Ceiling(textHeight) + 2f * num2;
return new HudBox(Math.Max(0f, Math.Min(val, (float)screenWidth - num3)), Math.Max(0f, Math.Min(val, (float)screenHeight - num4)), shadow: Math.Max(1f, (float)Math.Round(num)), plateWidth: num3, plateHeight: num4, pad: num2, textWidth: (float)Math.Ceiling(textWidth), textHeight: (float)Math.Ceiling(textHeight));
}
}
public static class RegenMath
{
public static float BoostedStamina(float before, float after, float maxStamina, float multiplier)
{
if (float.IsNaN(before) || float.IsNaN(after) || float.IsNaN(multiplier) || !(multiplier > 1f) || !(after > before))
{
return after;
}
float val = after + (after - before) * (multiplier - 1f);
float val2 = Math.Max(after, maxStamina);
return Math.Min(val, val2);
}
public static float RegenHp(float hp, int maxHp, float hunger, float perSecond, float dt)
{
if (!(hp > 0f) || hp >= (float)maxHp || !(hunger > 0f) || !(perSecond > 0f) || !(dt > 0f))
{
return hp;
}
return Math.Min(hp + perSecond * dt, maxHp);
}
}
public static class RestedText
{
public const string Expired = "You are no longer rested.";
public const string RoofHint = "Near a fire: build a roof to rest";
public const int ChatMaxLength = 120;
public static string Clock(float seconds)
{
if (float.IsNaN(seconds) || seconds < 0f)
{
seconds = 0f;
}
int num = (int)Math.Ceiling(seconds);
int num2 = num / 60;
int num3 = num % 60;
return string.Format(CultureInfo.InvariantCulture, "{0}:{1:00}", num2, num3);
}
public static string Hud(RestState state, RestedTuning tuning, bool staminaPatched)
{
if (state.IsRested)
{
string text = "Rested " + Clock(state.RemainingSeconds);
if (!staminaPatched)
{
text += " (no stamina bonus)";
}
return text;
}
if (state.NeedsRoof)
{
return "Near a fire: build a roof to rest";
}
if (!state.CanRest)
{
return "";
}
int num = (int)Math.Floor(state.RestingSeconds);
int num2 = (int)Math.Ceiling(tuning.RestSeconds);
return string.Format(CultureInfo.InvariantCulture, "Resting {0}/{1}", num, num2);
}
public static float HudAlpha(string text)
{
if (!(text == "Near a fire: build a roof to rest"))
{
return 1f;
}
return 0.7f;
}
public static string BecameRested(float seconds, RestedTuning tuning)
{
return string.Format(CultureInfo.InvariantCulture, "You feel rested ({0}). Stamina regen x{1:0.##}, +{2:0.##} HP/s.", Clock(seconds), tuning.StaminaRegenMultiplier, tuning.HealthRegenPerSecond);
}
}
public sealed class RestedTuning
{
public float RestSeconds { get; }
public float BaseDurationSeconds { get; }
public float DurationPerStationSeconds { get; }
public float MaxDurationSeconds { get; }
public float StaminaRegenMultiplier { get; }
public float HealthRegenPerSecond { get; }
public static RestedTuning Defaults { get; } = new RestedTuning(20f, 120f, 60f, 360f, 2f, 0.5f);
public RestedTuning(float restSeconds, float baseDurationSeconds, float durationPerStationSeconds, float maxDurationSeconds, float staminaRegenMultiplier, float healthRegenPerSecond)
{
RestSeconds = Clamp(restSeconds, 0f, 600f, 20f);
BaseDurationSeconds = Clamp(baseDurationSeconds, 0f, 3600f, 120f);
DurationPerStationSeconds = Clamp(durationPerStationSeconds, 0f, 3600f, 60f);
float val = Clamp(maxDurationSeconds, 0f, 7200f, 360f);
MaxDurationSeconds = Math.Max(val, BaseDurationSeconds);
StaminaRegenMultiplier = Clamp(staminaRegenMultiplier, 1f, 10f, 1f);
HealthRegenPerSecond = Clamp(healthRegenPerSecond, 0f, 20f, 0f);
}
public float DurationFor(int stationKinds)
{
int num = Math.Max(0, stationKinds);
return Math.Min(MaxDurationSeconds, BaseDurationSeconds + DurationPerStationSeconds * (float)num);
}
private static float Clamp(float value, float lo, float hi, float nan)
{
if (float.IsNaN(value))
{
return nan;
}
return Math.Min(hi, Math.Max(lo, value));
}
}
public readonly struct RestInput
{
public bool Alive { get; }
public bool Sheltered { get; }
public Comfort Comfort { get; }
public RestInput(bool alive, bool sheltered, Comfort comfort)
{
Alive = alive;
Sheltered = sheltered;
Comfort = comfort;
}
}
public enum RestEvent
{
None,
BecameRested,
Expired
}
public sealed class RestState
{
public float RestingSeconds { get; private set; }
public float RemainingSeconds { get; private set; }
public bool CanRest { get; private set; }
public bool NeedsRoof { get; private set; }
public bool IsRested => RemainingSeconds > 0f;
public RestEvent Tick(float dt, RestInput input, RestedTuning tuning)
{
if (float.IsNaN(dt) || dt < 0f)
{
dt = 0f;
}
if (!input.Alive)
{
bool isRested = IsRested;
Reset();
if (!isRested)
{
return RestEvent.None;
}
return RestEvent.Expired;
}
bool isRested2 = IsRested;
RemainingSeconds = Math.Max(0f, RemainingSeconds - dt);
CanRest = input.Sheltered && input.Comfort.HasFire;
NeedsRoof = !input.Sheltered && input.Comfort.HasFire;
if (CanRest)
{
RestingSeconds += dt;
if (RestingSeconds >= tuning.RestSeconds)
{
RemainingSeconds = Math.Max(RemainingSeconds, tuning.DurationFor(input.Comfort.DistinctKinds));
}
}
else
{
RestingSeconds = 0f;
}
if (!isRested2 && IsRested)
{
return RestEvent.BecameRested;
}
if (isRested2 && !IsRested)
{
return RestEvent.Expired;
}
return RestEvent.None;
}
public void Reset()
{
RestingSeconds = 0f;
RemainingSeconds = 0f;
CanRest = false;
NeedsRoof = false;
}
public void Grant(float seconds)
{
RemainingSeconds = Math.Max(RemainingSeconds, seconds);
}
}
public enum StationKind
{
None,
Workbench,
Anvil,
Cauldron,
Fletch,
Furnace
}
public static class StationKinds
{
public static bool IsFire(StationKind kind)
{
if (kind != StationKind.Furnace)
{
return kind == StationKind.Cauldron;
}
return true;
}
public static int Bit(StationKind kind)
{
if (kind == StationKind.None)
{
return 0;
}
return 1 << (int)kind;
}
}
internal sealed class RestedConfig
{
internal static class Defaults
{
internal const float RestSeconds = 20f;
internal const float BaseDurationSeconds = 120f;
internal const float DurationPerStationSeconds = 60f;
internal const float MaxDurationSeconds = 360f;
internal const float StaminaRegenMultiplier = 2f;
internal const float HealthRegenPerSecond = 0.5f;
internal const float ComfortRadius = 6f;
internal const float RoofCheckHeight = 12f;
internal const float ScanInterval = 0.5f;
}
public readonly ConfigEntry<float> RestSeconds;
public readonly ConfigEntry<float> BaseDurationSeconds;
public readonly ConfigEntry<float> DurationPerStationSeconds;
public readonly ConfigEntry<float> MaxDurationSeconds;
public readonly ConfigEntry<float> StaminaRegenMultiplier;
public readonly ConfigEntry<float> HealthRegenPerSecond;
public readonly ConfigEntry<float> ComfortRadius;
public readonly ConfigEntry<bool> RequireRoof;
public readonly ConfigEntry<float> RoofCheckHeight;
public readonly ConfigEntry<bool> OwnBuildsOnly;
public readonly ConfigEntry<bool> DisableInVersus;
public readonly ConfigEntry<float> ScanInterval;
public readonly ConfigEntry<bool> ShowHud;
public readonly ConfigEntry<bool> ChatMessages;
public readonly ConfigEntry<KeyboardShortcut> GiveRestedKey;
public readonly ConfigEntry<bool> VerboseLogging;
public RestedConfig(ConfigFile cfg)
{
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Expected O, but got Unknown
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_0073: Expected O, but got Unknown
//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
//IL_00ac: Expected O, but got Unknown
//IL_00db: Unknown result type (might be due to invalid IL or missing references)
//IL_00e5: Expected O, but got Unknown
//IL_0114: Unknown result type (might be due to invalid IL or missing references)
//IL_011e: Expected O, but got Unknown
//IL_014d: Unknown result type (might be due to invalid IL or missing references)
//IL_0157: Expected O, but got Unknown
//IL_0186: Unknown result type (might be due to invalid IL or missing references)
//IL_0190: Expected O, but got Unknown
//IL_01db: Unknown result type (might be due to invalid IL or missing references)
//IL_01e5: Expected O, but got Unknown
//IL_024c: Unknown result type (might be due to invalid IL or missing references)
//IL_0256: Expected O, but got Unknown
//IL_029f: Unknown result type (might be due to invalid IL or missing references)
RestSeconds = cfg.Bind<float>("Rested", "RestSeconds", 20f, new ConfigDescription("Seconds you must stay sheltered within ComfortRadius of a furnace or cauldron before the buff starts.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 600f), Array.Empty<object>()));
BaseDurationSeconds = cfg.Bind<float>("Rested", "BaseDurationSeconds", 120f, new ConfigDescription("Base seconds. The fire and each other distinct station kind within ComfortRadius add DurationPerStationSeconds. A lone furnace gives Base + PerStation. Valheim's base is 420. Muck days are shorter, so the default is 120.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3600f), Array.Empty<object>()));
DurationPerStationSeconds = cfg.Bind<float>("Rested", "DurationPerStationSeconds", 60f, new ConfigDescription("Extra seconds added for each distinct station kind within ComfortRadius. Kinds are workbench, anvil, cauldron, fletching table, and furnace.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3600f), Array.Empty<object>()));
MaxDurationSeconds = cfg.Bind<float>("Rested", "MaxDurationSeconds", 360f, new ConfigDescription("Longest Rested buff in seconds. Raised to BaseDurationSeconds when that value is higher.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 7200f), Array.Empty<object>()));
StaminaRegenMultiplier = cfg.Bind<float>("Rested", "StaminaRegenMultiplier", 2f, new ConfigDescription("Multiplier on the stamina vanilla regenerated that frame while Rested. 2 is double regen. 1 disables the bonus.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>()));
HealthRegenPerSecond = cfg.Bind<float>("Rested", "HealthRegenPerSecond", 0.5f, new ConfigDescription("Flat health restored per second while Rested. Skipped at 0 health, at full health, and while hunger is empty.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 20f), Array.Empty<object>()));
ComfortRadius = cfg.Bind<float>("Rested", "ComfortRadius", 6f, new ConfigDescription("Meters around the player in which a furnace, cauldron, or other station counts.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 30f), Array.Empty<object>()));
RequireRoof = cfg.Bind<bool>("Rested", "RequireRoof", true, "When true, a built piece must sit overhead within RoofCheckHeight before resting can start.");
RoofCheckHeight = cfg.Bind<float>("Rested", "RoofCheckHeight", 12f, new ConfigDescription("Meters of the upward roof check, measured from the player camera.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), Array.Empty<object>()));
OwnBuildsOnly = cfg.Bind<bool>("Rested", "OwnBuildsOnly", false, "When true, only pieces you placed count. When false, any player's builds count.");
DisableInVersus = cfg.Bind<bool>("Rested", "DisableInVersus", true, "When true, the rest timer and the health bonus do not run in a Versus match.");
ScanInterval = cfg.Bind<float>("Rested", "ScanInterval", 0.5f, new ConfigDescription("Seconds between station and roof scans. The rest timer still advances every frame.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), Array.Empty<object>()));
ShowHud = cfg.Bind<bool>("Display", "ShowHud", true, "Show the Resting and Rested timer at the top left.");
ChatMessages = cfg.Bind<bool>("Display", "ChatMessages", true, "Write a local chat line when Rested starts and when it ends.");
GiveRestedKey = cfg.Bind<KeyboardShortcut>("Debug", "GiveRestedKey", KeyboardShortcut.Empty, "Local cheat. Press in-game to grant yourself the max Rested duration. Empty disables the key.");
VerboseLogging = cfg.Bind<bool>("Debug", "VerboseLogging", false, "Log each Rested state change and each scan's build count and station kinds.");
}
public RestedTuning Tuning()
{
return new RestedTuning(RestSeconds.Value, BaseDurationSeconds.Value, DurationPerStationSeconds.Value, MaxDurationSeconds.Value, StaminaRegenMultiplier.Value, HealthRegenPerSecond.Value);
}
}
[BepInPlugin("evan.muck.rested", "Rested", "0.1.2")]
public class RestedPlugin : BaseUnityPlugin
{
public const string Guid = "evan.muck.rested";
public const string Name = "Rested";
public const string Version = "0.1.2";
internal static ManualLogSource Log;
internal static RestedConfig Cfg;
internal static bool StaminaPatched;
private void Awake()
{
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
Cfg = new RestedConfig(((BaseUnityPlugin)this).Config);
StaminaPatched = TryPatch(new Harmony("evan.muck.rested"), typeof(StaminaPatch));
if (!StaminaPatched)
{
Log.LogError((object)"Rested: stamina patch failed, stamina bonus disabled. HP regen still works.");
}
RestedRunner.Ensure();
RestedTuning restedTuning = (RestedSession.Tuning = Cfg.Tuning());
Log.LogInfo((object)("Rested 0.1.2 loaded. Local-only: other players do not need this mod. " + $"Rest {restedTuning.RestSeconds}s, duration {restedTuning.BaseDurationSeconds}s + {restedTuning.DurationPerStationSeconds}s per station, " + $"max {restedTuning.MaxDurationSeconds}s, stamina x{restedTuning.StaminaRegenMultiplier}, +{restedTuning.HealthRegenPerSecond} HP/s."));
}
private static bool TryPatch(Harmony harmony, Type patchClass)
{
try
{
harmony.CreateClassProcessor(patchClass).Patch();
return true;
}
catch (Exception arg)
{
Log.LogError((object)string.Format("{0} failed to patch {1}: {2}", "Rested", patchClass.Name, arg));
return false;
}
}
}
internal sealed class RestedRunner : MonoBehaviour
{
private static RestedRunner _instance;
private float _scanTimer;
private bool _sheltered;
private Comfort _comfort;
private bool _errored;
private GUIStyle _label;
private string _measured;
private Vector2 _textSize;
private bool _loggedGate;
public static void Ensure()
{
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Expected O, but got Unknown
if (!((Object)(object)_instance != (Object)null))
{
GameObject val = new GameObject("MuckRested")
{
hideFlags = (HideFlags)61
};
Object.DontDestroyOnLoad((Object)val);
_instance = val.AddComponent<RestedRunner>();
}
}
private void OnEnable()
{
SceneManager.activeSceneChanged += OnSceneChanged;
}
private void OnDisable()
{
SceneManager.activeSceneChanged -= OnSceneChanged;
}
private void OnSceneChanged(Scene previous, Scene next)
{
RestedSession.State.Reset();
StationProbe.Clear();
_comfort = Comfort.None;
_sheltered = false;
}
private void Update()
{
if (_errored)
{
return;
}
try
{
RunFrame();
}
catch (Exception arg)
{
_errored = true;
RestedPlugin.Log.LogError((object)$"Rested update failed: {arg}");
}
}
private void RunFrame()
{
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
//IL_0101: Unknown result type (might be due to invalid IL or missing references)
//IL_0152: Unknown result type (might be due to invalid IL or missing references)
if (RestedPlugin.Cfg.DisableInVersus.Value && IsVersus())
{
RestedSession.State.Reset();
return;
}
KeyboardShortcut value = RestedPlugin.Cfg.GiveRestedKey.Value;
if (((KeyboardShortcut)(ref value)).IsDown())
{
RestedSession.State.Grant(RestedSession.Tuning.MaxDurationSeconds);
}
PlayerStatus instance = PlayerStatus.Instance;
PlayerMovement instance2 = PlayerMovement.Instance;
if ((Object)(object)instance == (Object)null || (Object)(object)instance2 == (Object)null || (Object)(object)ResourceManager.Instance == (Object)null || (Object)(object)LocalClient.instance == (Object)null)
{
RestedSession.State.Reset();
return;
}
float deltaTime = Time.deltaTime;
_scanTimer -= deltaTime;
if (_scanTimer <= 0f)
{
_scanTimer = RestedPlugin.Cfg.ScanInterval.Value;
RestedSession.Tuning = RestedPlugin.Cfg.Tuning();
Vector3 position = ((Component)instance2).transform.position;
List<StationSample> samples = StationProbe.Collect();
_comfort = ComfortScan.Evaluate(samples, position.x, position.y, position.z, RestedPlugin.Cfg.ComfortRadius.Value, RestedPlugin.Cfg.OwnBuildsOnly.Value, LocalClient.instance.myId);
_sheltered = !RestedPlugin.Cfg.RequireRoof.Value || ShelterProbe.IsSheltered(instance2.playerCam.position, RestedPlugin.Cfg.RoofCheckHeight.Value);
if (RestedPlugin.Cfg.VerboseLogging.Value)
{
int num = 0;
if (ResourceManager.Instance.builds != null)
{
num = ResourceManager.Instance.builds.Count;
}
RestedPlugin.Log.LogInfo((object)$"Rested scan: {num} builds, kinds {Describe(samples)}, sheltered {_sheltered}.");
}
}
bool alive = !instance.IsPlayerDead() && instance.hp > 0f;
RestEvent restEvent = RestedSession.State.Tick(deltaTime, new RestInput(alive, _sheltered, _comfort), RestedSession.Tuning);
if (RestedSession.State.IsRested)
{
instance.hp = RegenMath.RegenHp(instance.hp, instance.maxHp, instance.hunger, RestedSession.Tuning.HealthRegenPerSecond, deltaTime);
}
if (RestedPlugin.Cfg.ChatMessages.Value && (Object)(object)ChatBox.Instance != (Object)null)
{
switch (restEvent)
{
case RestEvent.BecameRested:
ChatBox.Instance.AppendMessage(-1, RestedText.BecameRested(RestedSession.State.RemainingSeconds, RestedSession.Tuning), "");
break;
case RestEvent.Expired:
ChatBox.Instance.AppendMessage(-1, "You are no longer rested.", "");
break;
}
}
if (RestedPlugin.Cfg.VerboseLogging.Value && restEvent != RestEvent.None)
{
RestedPlugin.Log.LogInfo((object)$"Rested event {restEvent}, remaining {RestedSession.State.RemainingSeconds}.");
}
}
private static bool IsVersus()
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Invalid comparison between Unknown and I4
GameSettings gameSettings = GameManager.gameSettings;
if (gameSettings == null)
{
return false;
}
return (int)gameSettings.gameMode == 1;
}
private void OnGUI()
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Invalid comparison between Unknown and I4
//IL_0071: Unknown result type (might be due to invalid IL or missing references)
//IL_0076: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_00a8: Expected O, but got Unknown
//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
//IL_00b7: Expected O, but got Unknown
//IL_00bc: Expected O, but got Unknown
//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
//IL_00ff: Expected O, but got Unknown
//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
if ((int)Event.current.type != 7 || !RestedPlugin.Cfg.ShowHud.Value)
{
return;
}
string text = RestedText.Hud(RestedSession.State, RestedSession.Tuning, RestedPlugin.StaminaPatched);
if (text.Length != 0 && !Covered())
{
int num = HudLayout.FontSize(Screen.height);
if (_label == null || _label.fontSize != num)
{
_label = new GUIStyle(GUI.skin.label)
{
fontSize = num,
fontStyle = (FontStyle)1,
alignment = (TextAnchor)3,
wordWrap = false,
clipping = (TextClipping)0,
padding = new RectOffset(0, 0, 0, 0),
margin = new RectOffset(0, 0, 0, 0)
};
_label.normal.textColor = Color.white;
_measured = null;
}
if (_measured != text)
{
_measured = text;
_textSize = _label.CalcSize(new GUIContent(text));
}
DrawHud(HudLayout.For(Screen.width, Screen.height, _textSize.x, _textSize.y), text, _label, RestedText.HudAlpha(text));
}
}
private bool Covered()
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Invalid comparison between Unknown and I4
try
{
OtherInput instance = OtherInput.Instance;
PlayerStatus instance2 = PlayerStatus.Instance;
bool flag = (int)GameManager.state != 1;
return HudGate.Hidden(flag, !flag && (Object)(object)instance != (Object)null && instance.OtherUiActive(), !flag && (Object)(object)instance != (Object)null && instance.IsAnyMenuOpen(), (Object)(object)instance2 != (Object)null && instance2.IsPlayerDead());
}
catch (Exception arg)
{
if (!_loggedGate)
{
_loggedGate = true;
RestedPlugin.Log.LogError((object)$"Rested: reading Muck's menu state for the label failed. The label stays visible. {arg}");
}
return false;
}
}
private static void DrawHud(HudBox box, string text, GUIStyle style, float alpha)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
Color color = GUI.color;
GUI.color = new Color(0f, 0f, 0f, 0.45f * alpha);
GUI.DrawTexture(new Rect(box.PlateX, box.PlateY, box.PlateWidth, box.PlateHeight), (Texture)(object)Texture2D.whiteTexture);
GUI.color = new Color(0f, 0f, 0f, 0.9f * alpha);
GUI.Label(new Rect(box.TextX + box.Shadow, box.TextY + box.Shadow, box.TextWidth, box.TextHeight), text, style);
GUI.color = new Color(1f, 1f, 1f, alpha);
GUI.Label(new Rect(box.TextX, box.TextY, box.TextWidth, box.TextHeight), text, style);
GUI.color = color;
}
private static string Describe(List<StationSample> samples)
{
int num = 0;
string text = "";
for (int i = 0; i < samples.Count; i++)
{
int num2 = StationKinds.Bit(samples[i].Kind);
if (num2 != 0 && (num & num2) == 0)
{
num |= num2;
if (text.Length > 0)
{
text += ", ";
}
text += samples[i].Kind;
}
}
if (text.Length != 0)
{
return text;
}
return "none";
}
}
internal static class RestedSession
{
public static readonly RestState State = new RestState();
public static RestedTuning Tuning = RestedTuning.Defaults;
}
internal static class ShelterProbe
{
private static readonly RaycastHit[] Hits = (RaycastHit[])(object)new RaycastHit[16];
internal static bool IsSheltered(Vector3 head, float height)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
int num = Physics.RaycastNonAlloc(head, Vector3.up, Hits, height, -1, (QueryTriggerInteraction)1);
for (int i = 0; i < num; i++)
{
if ((Object)(object)((Component)((RaycastHit)(ref Hits[i])).collider).GetComponentInParent<BuildInfo>() != (Object)null)
{
return true;
}
}
return false;
}
}
[HarmonyPatch(typeof(PlayerStatus), "Stamina")]
internal static class StaminaPatch
{
private static bool _logged;
[HarmonyPriority(800)]
private static void Prefix(PlayerStatus __instance, out float __state)
{
try
{
__state = __instance.stamina;
}
catch
{
__state = float.NaN;
}
}
[HarmonyPriority(0)]
private static void Postfix(PlayerStatus __instance, float __state)
{
try
{
if (RestedSession.State.IsRested && !((Object)(object)__instance != (Object)(object)PlayerStatus.Instance) && !float.IsNaN(__state))
{
__instance.stamina = RegenMath.BoostedStamina(__state, __instance.stamina, __instance.maxStamina, RestedSession.Tuning.StaminaRegenMultiplier);
}
}
catch (Exception arg)
{
if (!_logged)
{
_logged = true;
RestedPlugin.Log.LogError((object)$"Rested stamina bonus failed: {arg}");
}
}
}
}
internal static class StationProbe
{
private static readonly Dictionary<int, StationKind> KindByKey = new Dictionary<int, StationKind>();
private static readonly List<StationSample> Samples = new List<StationSample>();
internal static void Clear()
{
KindByKey.Clear();
}
internal static List<StationSample> Collect()
{
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
Samples.Clear();
Dictionary<int, GameObject> builds = ResourceManager.Instance.builds;
if (builds == null)
{
return Samples;
}
foreach (KeyValuePair<int, GameObject> item in builds)
{
GameObject value = item.Value;
if ((Object)(object)value == (Object)null)
{
continue;
}
if (!KindByKey.TryGetValue(item.Key, out var value2))
{
value2 = Classify(value);
KindByKey[item.Key] = value2;
}
if (value2 != StationKind.None)
{
Vector3 position = value.transform.position;
BuildInfo component = value.GetComponent<BuildInfo>();
int ownerId = -1;
if ((Object)(object)component != (Object)null)
{
ownerId = component.ownerId;
}
Samples.Add(new StationSample(value2, position.x, position.y, position.z, ownerId));
}
}
return Samples;
}
private static StationKind Classify(GameObject go)
{
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)go.GetComponentInChildren<FurnaceSync>(true) != (Object)null)
{
return StationKind.Furnace;
}
if ((Object)(object)go.GetComponentInChildren<CauldronSync>(true) != (Object)null)
{
return StationKind.Cauldron;
}
CraftingInteract componentInChildren = go.GetComponentInChildren<CraftingInteract>(true);
if ((Object)(object)componentInChildren != (Object)null)
{
return Map(componentInChildren.state);
}
ChestInteract componentInChildren2 = go.GetComponentInChildren<ChestInteract>(true);
if ((Object)(object)componentInChildren2 != (Object)null)
{
return Map(componentInChildren2.state);
}
return StationKind.None;
}
internal static StationKind Map(CraftingState state)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Expected I4, but got Unknown
return (state - 1) switch
{
0 => StationKind.Workbench,
1 => StationKind.Anvil,
2 => StationKind.Cauldron,
3 => StationKind.Fletch,
4 => StationKind.Furnace,
_ => StationKind.None,
};
}
}
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "MuckRested";
public const string PLUGIN_NAME = "Rested";
public const string PLUGIN_VERSION = "0.1.2";
}
}