Decompiled source of Stund v1.0.0

plugins/Stund/Stund.dll

Decompiled a day ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Ezomic.Core;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyCompany("Thijssen Software")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright (c) 2026 Robbin Thijssen")]
[assembly: AssemblyDescription("The time of day and the day number, on screen.")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+28cb10935aaadcaed6f8a998f03e9cae28f999a1")]
[assembly: AssemblyProduct("Stund")]
[assembly: AssemblyTitle("Stund")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Stund
{
	internal static class Clock
	{
		private static TMP_Text _label;

		private static Corner _placedWhere;

		private static float _placedX;

		private static float _placedY;

		private static int _placedSize;

		private static string _last;

		internal unsafe static void Build(Hud hud)
		{
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			_label = null;
			_last = null;
			if ((Object)(object)hud == (Object)null)
			{
				return;
			}
			TMP_Text healthText = hud.m_healthText;
			if ((Object)(object)healthText == (Object)null)
			{
				StundPlugin.Log.LogWarning((object)"No health readout to copy the font from - no clock this session. Nothing else about the HUD is affected.");
				return;
			}
			Transform val = (((Object)(object)hud.m_rootObject != (Object)null) ? hud.m_rootObject.transform : ((Component)hud).transform);
			GameObject val2 = Object.Instantiate<GameObject>(((Component)healthText).gameObject, val);
			((Object)val2).name = "Stund_Clock";
			_label = val2.GetComponent<TMP_Text>();
			if ((Object)(object)_label == (Object)null)
			{
				Object.Destroy((Object)(object)val2);
				StundPlugin.Log.LogWarning((object)"The copied health readout carried no text component.");
				return;
			}
			Strip(val2);
			Vector3 localEulerAngles = healthText.transform.localEulerAngles;
			if (((Vector3)(ref localEulerAngles)).sqrMagnitude > 0.01f)
			{
				ManualLogSource log = StundPlugin.Log;
				Vector3 val3 = localEulerAngles;
				log.LogInfo((object)("The health readout is not upright - local rotation " + ((object)(*(Vector3*)(&val3))/*cast due to .constrained prefix*/).ToString() + ". The clock resets its own, so this costs nothing here."));
			}
			val2.SetActive(true);
			_label.text = "";
			((Graphic)_label).raycastTarget = false;
			_placedSize = 0;
			if (StundConfig.Verbose.Value)
			{
				StundPlugin.Log.LogInfo((object)("Clock built under " + ((Object)val).name + "."));
			}
		}

		private static void Strip(GameObject go)
		{
			Component[] components = go.GetComponents<Component>();
			foreach (Component val in components)
			{
				if (!(val is RectTransform) && !(val is CanvasRenderer) && !(val is TMP_Text))
				{
					Object.DestroyImmediate((Object)(object)val);
				}
			}
			for (int num = go.transform.childCount - 1; num >= 0; num--)
			{
				Object.DestroyImmediate((Object)(object)((Component)go.transform.GetChild(num)).gameObject);
			}
		}

		internal static void Tick()
		{
			if ((Object)(object)_label == (Object)null)
			{
				return;
			}
			bool value = StundConfig.Enabled.Value;
			if (((Component)_label).gameObject.activeSelf != value)
			{
				((Component)_label).gameObject.SetActive(value);
			}
			if (!value)
			{
				return;
			}
			Place();
			if (!TryRead(out var hour, out var minute, out var day))
			{
				if (_last != "")
				{
					_last = "";
					_label.text = "";
				}
				return;
			}
			string text = Render(hour, minute, day);
			if (!(text == _last))
			{
				_last = text;
				_label.text = text;
			}
		}

		internal static bool TryRead(out int hour, out int minute, out int day)
		{
			hour = 0;
			minute = 0;
			day = 0;
			EnvMan instance = EnvMan.instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)ZNet.instance == (Object)null)
			{
				return false;
			}
			long dayLengthSec = instance.m_dayLengthSec;
			if (dayLengthSec <= 0)
			{
				return false;
			}
			double num = ZNet.instance.GetTimeSeconds() % (double)dayLengthSec / (double)dayLengthSec * 24.0;
			hour = (int)num;
			minute = (int)((num - (double)hour) * 60.0);
			day = instance.GetDay();
			return true;
		}

		private static string Render(int hour, int minute, int day)
		{
			string text;
			if (StundConfig.TwentyFourHour.Value)
			{
				text = hour.ToString("00") + ":" + minute.ToString("00");
			}
			else
			{
				int num = hour % 12;
				if (num == 0)
				{
					num = 12;
				}
				text = num + ":" + minute.ToString("00") + ((hour < 12) ? " AM" : " PM");
			}
			if (!StundConfig.ShowDay.Value)
			{
				return text;
			}
			return "Day " + day + "   " + text;
		}

		private static void Place()
		{
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			Corner value = StundConfig.Where.Value;
			float value2 = StundConfig.OffsetX.Value;
			float value3 = StundConfig.OffsetY.Value;
			int value4 = StundConfig.FontSize.Value;
			if (value != _placedWhere || value2 != _placedX || value3 != _placedY || value4 != _placedSize)
			{
				_placedWhere = value;
				_placedX = value2;
				_placedY = value3;
				_placedSize = value4;
				Vector2 val = default(Vector2);
				TextAlignmentOptions alignment;
				switch (value)
				{
				case Corner.TopLeft:
					((Vector2)(ref val))..ctor(0f, 1f);
					alignment = (TextAlignmentOptions)257;
					break;
				case Corner.TopRight:
					((Vector2)(ref val))..ctor(1f, 1f);
					alignment = (TextAlignmentOptions)260;
					break;
				case Corner.BottomLeft:
					((Vector2)(ref val))..ctor(0f, 0f);
					alignment = (TextAlignmentOptions)1025;
					break;
				case Corner.BottomCentre:
					((Vector2)(ref val))..ctor(0.5f, 0f);
					alignment = (TextAlignmentOptions)1026;
					break;
				case Corner.BottomRight:
					((Vector2)(ref val))..ctor(1f, 0f);
					alignment = (TextAlignmentOptions)1028;
					break;
				default:
					((Vector2)(ref val))..ctor(0.5f, 1f);
					alignment = (TextAlignmentOptions)258;
					break;
				}
				RectTransform val2 = (RectTransform)_label.transform;
				val2.anchorMin = val;
				val2.anchorMax = val;
				val2.pivot = val;
				val2.sizeDelta = new Vector2(320f, (float)value4 * 2f);
				val2.anchoredPosition = new Vector2(value2, value3);
				((Transform)val2).localRotation = Quaternion.identity;
				((Transform)val2).localScale = Vector3.one;
				_label.alignment = alignment;
				_label.fontSize = value4;
				_label.enableAutoSizing = false;
			}
		}
	}
	internal enum Corner
	{
		TopLeft,
		TopCentre,
		TopRight,
		BottomLeft,
		BottomCentre,
		BottomRight
	}
	internal static class StundConfig
	{
		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<Corner> Where;

		internal static ConfigEntry<float> OffsetX;

		internal static ConfigEntry<float> OffsetY;

		internal static ConfigEntry<int> FontSize;

		internal static ConfigEntry<bool> ShowDay;

		internal static ConfigEntry<bool> TwentyFourHour;

		internal static ConfigEntry<bool> Verbose;

		internal static void Bind(ConfigFile cfg)
		{
			Enabled = cfg.Bind<bool>("Stund", "Enabled", true, "Off leaves the plugin loaded and takes the clock off the screen.");
			Where = cfg.Bind<Corner>("Stund", "Where", Corner.TopCentre, "Which corner of the screen the clock hangs off. The top left is the bars and the top right is the map, so the top centre is the one that is usually empty - a boss health bar is the thing that will overlap it.");
			OffsetX = cfg.Bind<float>("Stund", "OffsetX", 0f, "Pixels from that corner, left to right. Positive is rightwards from any corner; from a right-hand corner that is off the screen.");
			OffsetY = cfg.Bind<float>("Stund", "OffsetY", -28f, "Pixels from that corner, bottom to top. Negative moves down, so a top corner wants a negative number here and a bottom corner a positive one.");
			FontSize = cfg.Bind<int>("Stund", "FontSize", 20, "Point size of the clock. Below about 12 it stops being readable at a glance, which defeats the point of it being on screen at all.");
			ShowDay = cfg.Bind<bool>("Stund", "ShowDay", true, "Show the day number beside the time. It is the same number the game announces at dawn, so it agrees with the message rather than counting its own days.");
			TwentyFourHour = cfg.Bind<bool>("Stund", "TwentyFourHour", true, "Off gives 5:45 PM instead of 17:45. Sunrise is about 06:15 and sunset about 17:45 either way.");
			Verbose = cfg.Bind<bool>("Stund", "Verbose", false, "Write what the clock found to build itself with to BepInEx/LogOutput.log. Off unless the clock is missing; it is a handful of lines at each world load.");
		}
	}
	internal static class StundPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(Hud), "Awake")]
		private static void HudAwake(Hud __instance)
		{
			Clock.Build(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Hud), "Update")]
		private static void HudUpdate()
		{
			Clock.Tick();
		}
	}
	[BepInPlugin("ezomic.valheim.stund", "Stund", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class StundPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "ezomic.valheim.stund";

		public const string PluginName = "Stund";

		public const string PluginVersion = "1.0.0";

		public const string PluginAuthor = "Robbin Thijssen";

		private const string CoreGuid = "ezomic.valheim.core";

		internal static ManualLogSource Log;

		internal static bool CorePresent;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			StundConfig.Bind(((BaseUnityPlugin)this).Config);
			TryRegisterWithCore();
			_harmony = new Harmony("ezomic.valheim.stund");
			_harmony.PatchAll(typeof(StundPatches));
			Log.LogInfo((object)"Stund 1.0.0 by Robbin Thijssen - ready.");
		}

		private void TryRegisterWithCore()
		{
			CorePresent = Chainloader.PluginInfos.ContainsKey("ezomic.valheim.core");
			if (!CorePresent)
			{
				Log.LogInfo((object)"Core not installed - running standalone, without the version gate.");
			}
			else
			{
				RegisterWithCore();
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private void RegisterWithCore()
		{
			Suite.Register("ezomic.valheim.stund", "Stund", "1.0.0", ((BaseUnityPlugin)this).Config, (Requirement)1, (Assembly)null);
			Suite.Local((ConfigEntryBase[])(object)new ConfigEntryBase[8]
			{
				(ConfigEntryBase)StundConfig.Enabled,
				(ConfigEntryBase)StundConfig.Where,
				(ConfigEntryBase)StundConfig.OffsetX,
				(ConfigEntryBase)StundConfig.OffsetY,
				(ConfigEntryBase)StundConfig.FontSize,
				(ConfigEntryBase)StundConfig.ShowDay,
				(ConfigEntryBase)StundConfig.TwentyFourHour,
				(ConfigEntryBase)StundConfig.Verbose
			});
		}

		private void OnDestroy()
		{
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
		}
	}
}