Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of HotbarTint v1.0.5
HotbarTint.dll
Decompiled 12 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Microsoft.CodeAnalysis; using UnityEngine; [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("HotbarTint")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("HotbarTint")] [assembly: AssemblyTitle("HotbarTint")] [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 HotbarTint { [BepInPlugin("lily.hotbartint", "Hotbar Tint", "1.0.5")] public class HotbarTintPlugin : BaseUnityPlugin { private class Slot { public int Column; public Transform Root; public RectTransform Bg; public Behaviour Fill; public GameObject Overlay; public Component Image; public bool Shown; } public const string Version = "1.0.5"; private const float SearchInterval = 2f; private const float ConfigPollInterval = 1f; private const string OverlayName = "lilyTint"; private const int MaxSlotDepth = 3; private ConfigEntry<string> _mode; private ConfigEntry<string> _color; private ConfigEntry<float> _opacity; private ConfigEntry<int> _glowWidth; private ConfigEntry<bool> _debugLog; private ConfigEntry<bool> _fixFill; private FieldInfo _localPlayer; private MethodInfo _getInventory; private MethodInfo _getItemAt; private FieldInfo _equipped; private FieldInfo _shared; private FieldInfo _itemName; private Type _imageType; private PropertyInfo _imgSprite; private PropertyInfo _imgColor; private PropertyInfo _imgRaycast; private bool _broken; private Transform _hotbar; private Transform _slotParent; private int _emptySearches; private int _errorsInARow; private readonly List<Slot> _slots = new List<Slot>(); private float _nextSearch; private float _nextConfigPoll; private DateTime _configStamp; private bool _styleDirty = true; private Sprite _sprite; private TintMode _activeMode; private Color _activeColor; private string _lastEquippedLog; private void Awake() { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Expected O, but got Unknown _mode = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Mode", "Background", new ConfigDescription("How an equipped hotbar slot is marked.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[3] { "Background", "Glow", "Off" }), Array.Empty<object>())); _color = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Color", "#3C8CFF", "Marker color, #RRGGBB or #RRGGBBAA."); _opacity = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Opacity", 0.6f, new ConfigDescription("Marker opacity.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); _glowWidth = ((BaseUnityPlugin)this).Config.Bind<int>("General", "GlowWidth", 3, new ConfigDescription("Rim width in px for Glow mode.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 6), Array.Empty<object>())); _fixFill = ((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility", "FixSeneaLFill", true, "SeneaL UI 1.2.2 leaves a slot's fill off after its item is unequipped, so the slot looks washed out. On = turn the fill back on for occupied, unequipped slots."); _debugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugLog", false, "Log slot -> inventory cell -> item whenever the equipped set changes."); ((BaseUnityPlugin)this).Config.SettingChanged += delegate { _styleDirty = true; }; _configStamp = ConfigStamp(); _broken = !ResolveReflection(); } private bool ResolveReflection() { try { Type type = Type.GetType("Player, assembly_valheim", throwOnError: true); _localPlayer = type.GetField("m_localPlayer", BindingFlags.Static | BindingFlags.Public); _getInventory = type.GetMethod("GetInventory", BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null); _getItemAt = _getInventory.ReturnType.GetMethod("GetItemAt", new Type[2] { typeof(int), typeof(int) }); Type returnType = _getItemAt.ReturnType; _equipped = returnType.GetField("m_equipped"); _shared = returnType.GetField("m_shared"); _itemName = _shared?.FieldType.GetField("m_name"); _imageType = Type.GetType("UnityEngine.UI.Image, UnityEngine.UI", throwOnError: true); _imgSprite = _imageType.GetProperty("sprite"); _imgColor = _imageType.GetProperty("color"); _imgRaycast = _imageType.GetProperty("raycastTarget"); if (_localPlayer == null || _equipped == null || _imgSprite == null || _imgColor == null || _imgRaycast == null) { throw new MissingMemberException("a required game/UI member is missing"); } return true; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("HotbarTint disabled: " + ex.Message)); return false; } } private void Update() { if (_broken) { return; } try { PollConfigFile(); if (FindHotbar()) { if (_styleDirty) { ApplyStyle(); } MarkEquipped(); _errorsInARow = 0; } } catch (Exception ex) { if (TintLogic.OnFrameError(++_errorsInARow) == ErrorAction.Disable) { _broken = true; ((BaseUnityPlugin)this).Logger.LogError((object)$"HotbarTint disabled after {_errorsInARow} errors in a row: {ex}"); } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)$"HotbarTint: error {_errorsInARow}/{3}, resetting the Hotbar cache: {ex}"); ResetCache(); } } } private void ResetCache() { _hotbar = null; _slotParent = null; _slots.Clear(); } private void PollConfigFile() { if (Time.unscaledTime < _nextConfigPoll) { return; } _nextConfigPoll = Time.unscaledTime + 1f; DateTime dateTime = ConfigStamp(); if (!(dateTime == _configStamp)) { _configStamp = dateTime; bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; try { ((BaseUnityPlugin)this).Config.Reload(); } finally { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet; } _styleDirty = true; } } private DateTime ConfigStamp() { if (!File.Exists(((BaseUnityPlugin)this).Config.ConfigFilePath)) { return DateTime.MinValue; } return File.GetLastWriteTimeUtc(((BaseUnityPlugin)this).Config.ConfigFilePath); } private bool FindHotbar() { if ((Object)(object)_hotbar != (Object)null && ((Component)_hotbar).gameObject.activeInHierarchy && _slots.Count > 0) { if (_slots.Exists((Slot s) => (Object)(object)s.Root == (Object)null || (Object)(object)s.Bg == (Object)null)) { ScanSlots(); } return _slots.Count > 0; } if (Time.unscaledTime < _nextSearch) { return false; } _nextSearch = Time.unscaledTime + 2f; ResetCache(); bool flag = false; Transform[] array = Resources.FindObjectsOfTypeAll<Transform>(); foreach (Transform val in array) { if (!(((Object)val).name != "Hotbar") && ((Component)val).gameObject.activeInHierarchy) { flag = true; _hotbar = val; ScanSlots(); if (_slots.Count > 0) { break; } } } if (_slots.Count > 0) { _emptySearches = 0; if (_debugLog.Value) { ManualLogSource logger = ((BaseUnityPlugin)this).Logger; object arg = _slots.Count; Transform slotParent = _slotParent; logger.LogInfo((object)$"HotbarTint: found Hotbar with {arg} slots under {((slotParent != null) ? ((Object)slotParent).name : null)}"); } return true; } _hotbar = null; if (flag && ++_emptySearches == 3) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"HotbarTint: found SeneaL's Hotbar but no slot1..slot8 with a bg under it; the HUD layout may have changed."); } return false; } private static Transform FindSlotParent(Transform root, int depth) { for (int i = 0; i < root.childCount; i++) { Transform child = root.GetChild(i); if (((Object)child).name == "slot1" && (Object)(object)child.Find("bg") != (Object)null) { return root; } } if (depth <= 1) { return null; } for (int j = 0; j < root.childCount; j++) { Transform val = FindSlotParent(root.GetChild(j), depth - 1); if ((Object)(object)val != (Object)null) { return val; } } return null; } private static Behaviour FindFill(Transform slot) { Transform val = slot.Find("opq"); if (!((Object)(object)val != (Object)null)) { return null; } return ((Component)val).GetComponent<Behaviour>(); } private void ScanSlots() { _slots.Clear(); _slotParent = (((Object)(object)_hotbar != (Object)null) ? FindSlotParent(_hotbar, 3) : null); if ((Object)(object)_slotParent == (Object)null) { return; } for (int i = 0; i < _slotParent.childCount; i++) { Transform child = _slotParent.GetChild(i); int num = TintLogic.SlotColumn(((Object)child).name); if (num < 0) { continue; } Transform obj = child.Find("bg"); RectTransform val = (RectTransform)(object)((obj is RectTransform) ? obj : null); if (!((Object)(object)val == (Object)null)) { Transform val2 = child.Find("lilyTint"); if ((Object)(object)val2 != (Object)null) { Object.Destroy((Object)(object)((Component)val2).gameObject); } _slots.Add(new Slot { Column = num, Root = child, Bg = val, Fill = FindFill(child) }); } } _styleDirty = true; } private void ApplyStyle() { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: 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) _styleDirty = false; _activeMode = TintLogic.ParseMode(_mode.Value); Rgba rgba = TintLogic.ParseColor(_color.Value, _opacity.Value); _activeColor = new Color(rgba.R, rgba.G, rgba.B, rgba.A); if ((Object)(object)_sprite != (Object)null) { Object.Destroy((Object)(object)_sprite.texture); Object.Destroy((Object)(object)_sprite); } _sprite = BuildSprite(TintLogic.BuildMask(_activeMode, _glowWidth.Value)); foreach (Slot slot in _slots) { if (!((Object)(object)slot.Overlay == (Object)null)) { _imgSprite.SetValue(slot.Image, _sprite, null); _imgColor.SetValue(slot.Image, _activeColor, null); } } } private static Sprite BuildSprite(float[] mask) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) int num = 68; Texture2D val = new Texture2D(num, num, (TextureFormat)4, false) { name = "HotbarTintMask", filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1 }; Color[] array = (Color[])(object)new Color[num * num]; for (int i = 0; i < num; i++) { for (int j = 0; j < num; j++) { array[(num - 1 - i) * num + j] = new Color(1f, 1f, 1f, mask[i * num + j]); } } val.SetPixels(array); val.Apply(); return Sprite.Create(val, new Rect(0f, 0f, (float)num, (float)num), new Vector2(0.5f, 0.5f), 100f); } private void MarkEquipped() { object value = _localPlayer.GetValue(null); object obj = (((Object)((value is Object) ? value : null) != (Object)null) ? _getInventory.Invoke(value, null) : null); string text = (_debugLog.Value ? "" : null); foreach (Slot slot in _slots) { object obj2 = ((obj != null) ? _getItemAt.Invoke(obj, new object[2] { slot.Column, 0 }) : null); bool equipped = obj2 != null && (bool)_equipped.GetValue(obj2); bool flag = _activeMode != TintMode.Off && TintLogic.ShouldMark(obj2 != null, equipped); if (flag && text != null) { text += $" {((Object)slot.Root).name}=({slot.Column},0):{ItemName(obj2)}"; } SetShown(slot, flag); if ((Object)(object)slot.Fill == (Object)null) { slot.Fill = FindFill(slot.Root); } if ((Object)(object)slot.Fill != (Object)null && TintLogic.ShouldRestoreFill(_fixFill.Value, obj2 != null, equipped, slot.Fill.enabled)) { slot.Fill.enabled = true; } } if (text != null && text != _lastEquippedLog) { _lastEquippedLog = text; ((BaseUnityPlugin)this).Logger.LogInfo((object)("HotbarTint equipped:" + ((text.Length == 0) ? " none" : text))); } } private string ItemName(object item) { object obj = _shared?.GetValue(item); if (obj == null) { return "?"; } return (_itemName?.GetValue(obj) as string) ?? "?"; } private void SetShown(Slot s, bool show) { if ((Object)(object)s.Overlay == (Object)null) { s.Shown = false; if (!show) { return; } CreateOverlay(s); } if (show != s.Shown) { s.Shown = show; s.Overlay.SetActive(show); } } private void CreateOverlay(Slot s) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("lilyTint", new Type[1] { typeof(RectTransform) }); RectTransform val2 = (RectTransform)val.transform; ((Transform)val2).SetParent(s.Root, false); ((Transform)val2).SetSiblingIndex(((Transform)s.Bg).GetSiblingIndex() + 1); val2.anchorMin = s.Bg.anchorMin; val2.anchorMax = s.Bg.anchorMax; val2.pivot = s.Bg.pivot; val2.anchoredPosition = s.Bg.anchoredPosition; val2.sizeDelta = s.Bg.sizeDelta; ((Transform)val2).localScale = ((Transform)s.Bg).localScale; Component val3 = val.AddComponent(_imageType); _imgSprite.SetValue(val3, _sprite, null); _imgColor.SetValue(val3, _activeColor, null); _imgRaycast.SetValue(val3, false, null); val.SetActive(false); s.Overlay = val; s.Image = val3; } private void OnDestroy() { foreach (Slot slot in _slots) { if ((Object)(object)slot.Overlay != (Object)null) { Object.Destroy((Object)(object)slot.Overlay); } } if ((Object)(object)_sprite != (Object)null) { Object.Destroy((Object)(object)_sprite.texture); Object.Destroy((Object)(object)_sprite); } } } public enum TintMode { Background, Glow, Off } public enum ErrorAction { ResetCache, Disable } public struct Rgba { public float R; public float G; public float B; public float A; public Rgba(float r, float g, float b, float a) { R = r; G = g; B = b; A = a; } } public static class TintLogic { public const string DefaultColor = "#3C8CFF"; public const float DefaultOpacity = 0.6f; public const int SlotCount = 8; public const int MaskSize = 68; public const float SlotInset = 6f; public const float CornerRadius = 8f; public const int MaxErrorsInARow = 3; public static int SlotColumn(string name) { if (name == null || !name.StartsWith("slot", StringComparison.Ordinal)) { return -1; } if (!int.TryParse(name.Substring(4), NumberStyles.None, CultureInfo.InvariantCulture, out var result)) { return -1; } if (name.Length != 4 + result.ToString(CultureInfo.InvariantCulture).Length) { return -1; } if (result < 1 || result > 8) { return -1; } return result - 1; } public static bool ShouldMark(bool hasItem, bool equipped) { return hasItem && equipped; } public static bool ShouldRestoreFill(bool fixEnabled, bool hasItem, bool equipped, bool fillEnabled) { if (fixEnabled && hasItem && !equipped) { return !fillEnabled; } return false; } public static ErrorAction OnFrameError(int errorsInARow) { if (errorsInARow < 3) { return ErrorAction.ResetCache; } return ErrorAction.Disable; } public static TintMode ParseMode(string text) { string text2 = (text ?? "").Trim().ToLowerInvariant(); if (!(text2 == "glow")) { if (text2 == "off") { return TintMode.Off; } return TintMode.Background; } return TintMode.Glow; } public static Rgba ParseColor(string text, float opacity) { if (!TryParseHex(text, out var c)) { TryParseHex("#3C8CFF", out c); } c.A *= Math.Max(0f, Math.Min(1f, opacity)); return c; } private static bool TryParseHex(string text, out Rgba c) { c = default(Rgba); string text2 = (text ?? "").Trim(); if (text2.StartsWith("#", StringComparison.Ordinal)) { text2 = text2.Substring(1); } if (text2.Length != 6 && text2.Length != 8) { return false; } if (!uint.TryParse(text2, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out var result)) { return false; } if (text2.Length == 6) { result = (result << 8) | 0xFF; } c = new Rgba((float)((result >> 24) & 0xFF) / 255f, (float)((result >> 16) & 0xFF) / 255f, (float)((result >> 8) & 0xFF) / 255f, (float)(result & 0xFF) / 255f); return true; } public static float RoundedRectCoverage(float px, float py, int size, float inset, float radius) { float num = (float)size / 2f - inset; float val = Math.Abs(px - (float)size / 2f) - (num - radius); float num2 = Math.Abs(py - (float)size / 2f) - (num - radius); float num3 = (float)Math.Sqrt(Math.Max(val, 0f) * Math.Max(val, 0f) + Math.Max(num2, 0f) * Math.Max(num2, 0f)) + Math.Min(Math.Max(val, num2), 0f) - radius; return Math.Max(0f, Math.Min(1f, 0.5f - num3)); } public static float[] BuildMask(TintMode mode, int glowWidth) { int num = 68; int num2 = Math.Max(1, Math.Min(6, glowWidth)); float[] array = new float[num * num]; for (int i = 0; i < num; i++) { for (int j = 0; j < num; j++) { float num3 = RoundedRectCoverage((float)j + 0.5f, (float)i + 0.5f, num, 6f, 8f); float num4 = num3; switch (mode) { case TintMode.Glow: { float num5 = RoundedRectCoverage((float)j + 0.5f, (float)i + 0.5f, num, 6f - (float)num2, 8f + (float)num2); num4 = Math.Max(0f, num5 - num3); break; } case TintMode.Off: num4 = 0f; break; } array[i * num + j] = num4; } } return array; } } }