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 RecentXpBars v0.13.0
plugins/ValheimRecentXpBars.dll
Decompiled a day agousing System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("ValheimRecentXpBars")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("ValheimRecentXpBars")] [assembly: AssemblyTitle("ValheimRecentXpBars")] [assembly: AssemblyVersion("1.0.0.0")] namespace ValheimRecentXpBars; [BepInPlugin("com.foxego.valheim.recentxpbars", "Recent XP Bars", "0.13.0")] public class Plugin : BaseUnityPlugin { public const string ModId = "com.foxego.valheim.recentxpbars"; public const string ModName = "Recent XP Bars"; public const string ModVersion = "0.13.0"; public static ConfigEntry<bool> CfgEnabled; public static ConfigEntry<int> CfgVerticalOffsetPx; public static ConfigEntry<float> CfgBarWidthFraction; public static ConfigEntry<float> CfgUiScale; private Harmony _harmony; private GameObject _hudHost; public static RecentSkillTracker Tracker { get; private set; } private void Awake() { //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Expected O, but got Unknown //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Expected O, but got Unknown Tracker = new RecentSkillTracker(4); CfgEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master toggle for the recent-xp HUD."); CfgVerticalOffsetPx = ((BaseUnityPlugin)this).Config.Bind<int>("Layout", "VerticalOffsetPx", 0, "Pixels above the bottom edge of the screen (1080p-reference units)."); CfgBarWidthFraction = ((BaseUnityPlugin)this).Config.Bind<float>("Layout", "BarWidthFraction", 0.25f, "Each bar's width as a fraction of window width (0.25 = 1/4). Four bars are tiled across the bottom edge."); CfgUiScale = ((BaseUnityPlugin)this).Config.Bind<float>("Layout", "UiScale", 1f, "Extra UI multiplier on top of resolution-based auto-scaling. 1.5 = 50% bigger."); _harmony = new Harmony("com.foxego.valheim.recentxpbars"); _harmony.PatchAll(typeof(SkillXpPatch)); _hudHost = new GameObject("RecentXpBarsHud"); _hudHost.AddComponent<XpBarHud>(); Object.DontDestroyOnLoad((Object)(object)_hudHost); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Recent XP Bars 0.13.0 loaded."); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } if ((Object)(object)_hudHost != (Object)null) { Object.Destroy((Object)(object)_hudHost); } } } public struct SkillEntry { public int SkillId; public int Level; public float Progress; public float LastGain; public float SessionTotal; } public class RecentSkillTracker { private readonly int _capacity; private readonly List<SkillEntry> _entries; public RecentSkillTracker(int capacity = 3) { _capacity = capacity; _entries = new List<SkillEntry>(capacity); } public void Record(int skillId, float gain, int newLevel, float newProgress) { int num = _entries.FindIndex((SkillEntry e) => e.SkillId == skillId); if (num >= 0) { SkillEntry item = _entries[num]; item.Level = newLevel; item.Progress = newProgress; item.LastGain = gain; item.SessionTotal += gain; _entries.RemoveAt(num); _entries.Insert(0, item); return; } SkillEntry skillEntry = default(SkillEntry); skillEntry.SkillId = skillId; skillEntry.Level = newLevel; skillEntry.Progress = newProgress; skillEntry.LastGain = gain; skillEntry.SessionTotal = gain; SkillEntry item2 = skillEntry; if (_entries.Count >= _capacity) { _entries.RemoveAt(_entries.Count - 1); } _entries.Insert(0, item2); } public List<SkillEntry> Snapshot() { return new List<SkillEntry>(_entries); } } [HarmonyPatch(typeof(Skills), "RaiseSkill")] public static class SkillXpPatch { private struct Snapshot { public SkillType Type; public int Level; public float Progress; public bool Valid; } private static Snapshot _pre; private static Skill GetInnerSkill(Skills s, SkillType t) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) return Traverse.Create((object)s).Method("GetSkill", new object[1] { t }).GetValue<Skill>(); } private static void Prefix(Skills __instance, SkillType skillType, float factor) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Invalid comparison between Unknown and I4 //IL_0021: 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_0037: Unknown result type (might be due to invalid IL or missing references) _pre = default(Snapshot); if ((int)skillType != 0 && (int)skillType != 999 && !(factor <= 0f)) { Skill innerSkill = GetInnerSkill(__instance, skillType); if (innerSkill != null) { Snapshot pre = default(Snapshot); pre.Type = skillType; pre.Level = (int)innerSkill.m_level; pre.Progress = innerSkill.GetLevelPercentage(); pre.Valid = true; _pre = pre; } } } private static void Postfix(Skills __instance, SkillType skillType, float factor) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected I4, but got Unknown if (!_pre.Valid || _pre.Type != skillType) { return; } Skill innerSkill = GetInnerSkill(__instance, skillType); if (innerSkill != null) { int num = (int)innerSkill.m_level; float levelPercentage = innerSkill.GetLevelPercentage(); float num2 = (float)(num - _pre.Level) + (levelPercentage - _pre.Progress); if (!(num2 <= 0f)) { Plugin.Tracker?.Record((int)skillType, num2, num, levelPercentage); } } } } public class XpBarHud : MonoBehaviour { private const float ReferenceHeight = 1080f; private const int RowHeightPx = 20; private const int FontSize = 12; private const int FramePx = 2; private const int TextPad = 10; private const int TickCount = 10; private const int GradientHeight = 64; private static readonly int RestedHash = StringExtensionMethods.GetStableHashCode("Rested"); private static Texture2D _frameTex; private static Texture2D _bgTex; private static Texture2D _fillTexRested; private static Texture2D _fillTexNotRested; private static Texture2D _tickTex; private static GUIStyle _leftStyle; private static GUIStyle _outlineStyle; private void OnGUI() { //IL_007e: 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_0094: 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_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) if (Plugin.CfgEnabled == null || !Plugin.CfgEnabled.Value || (Object)(object)Player.m_localPlayer == (Object)null || Hud.IsUserHidden()) { return; } EnsureTextures(); EnsureStyle(); List<SkillEntry> list = Plugin.Tracker?.Snapshot(); if (list != null && list.Count != 0) { float num = Mathf.Max(0.5f, (float)Screen.height / 1080f) * Mathf.Max(0.1f, Plugin.CfgUiScale.Value); Matrix4x4 matrix = GUI.matrix; GUI.matrix = Matrix4x4.TRS(new Vector3(0f, (float)Screen.height, 0f), Quaternion.identity, new Vector3(num, num, 1f)) * Matrix4x4.Translate(new Vector3(0f, (float)(-Screen.height) / num, 0f)); int num2 = Mathf.RoundToInt((float)Screen.width / num); int num3 = Mathf.RoundToInt((float)Screen.height / num); float num4 = Mathf.Clamp(Plugin.CfgBarWidthFraction.Value, 0.05f, 1f); int num5 = Mathf.RoundToInt((float)num2 * num4); int num6 = Mathf.Max(0, Plugin.CfgVerticalOffsetPx.Value); int y = num3 - num6 - 20; SEMan sEMan = ((Character)Player.m_localPlayer).GetSEMan(); Texture2D fillTex = ((sEMan != null && sEMan.HaveStatusEffect(RestedHash)) ? _fillTexRested : _fillTexNotRested); for (int i = 0; i < list.Count; i++) { int x = i * num5; DrawRow(list[i], x, y, num5, fillTex); } GUI.matrix = matrix; } } private void DrawRow(SkillEntry e, int x, int y, int barWidth, Texture2D fillTex) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) GUI.DrawTexture(new Rect((float)x, (float)y, (float)barWidth, 20f), (Texture)(object)_frameTex); int num = x + 2; int num2 = y + 2; int num3 = barWidth - 4; int num4 = 16; GUI.DrawTexture(new Rect((float)num, (float)num2, (float)num3, (float)num4), (Texture)(object)_bgTex); float num5 = Mathf.Clamp01(e.Progress); int num6 = Mathf.RoundToInt((float)num3 * num5); if (num6 > 0) { GUI.DrawTexture(new Rect((float)num, (float)num2, (float)num6, (float)num4), (Texture)(object)fillTex); } for (int i = 1; i < 10; i++) { GUI.DrawTexture(new Rect((float)(num + Mathf.RoundToInt((float)(num3 * i) / 10f)), (float)num2, 1f, (float)num4), (Texture)(object)_tickTex); } string arg = LocalizeSkillName(e.SkillId); string text = $"{arg} {e.Level}"; DrawLabelWithOutline(new Rect((float)(num + 10), (float)num2, (float)(num3 - 20), (float)num4), text); } private static void EnsureTextures() { //IL_0021: 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) //IL_0086: 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_00f0: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_frameTex == (Object)null) { _frameTex = MakeSolidTex(new Color(0.5f, 0.36f, 0.2f, 0.3f)); } if ((Object)(object)_bgTex == (Object)null) { _bgTex = MakeGradientTex(new Color(0.06f, 0.05f, 0.03f, 1f), 0.25f); } if ((Object)(object)_fillTexRested == (Object)null) { _fillTexRested = MakeGradientTex(new Color(0.95f, 0.72f, 0.18f, 1f), 0.3f); } if ((Object)(object)_fillTexNotRested == (Object)null) { _fillTexNotRested = MakeGradientTex(new Color(0.95f, 0.2f, 0.15f, 1f), 0.4f); } if ((Object)(object)_tickTex == (Object)null) { _tickTex = MakeSolidTex(new Color(0f, 0f, 0f, 0.35f)); } } private static Texture2D MakeSolidTex(Color c) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0012: 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_001f: Expected O, but got Unknown Texture2D val = new Texture2D(1, 1) { hideFlags = (HideFlags)61 }; val.SetPixel(0, 0, c); val.Apply(); return val; } private static Texture2D MakeGradientTex(Color baseColor, float targetAlpha) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(1, 64) { hideFlags = (HideFlags)61 }; ((Texture)val).wrapMode = (TextureWrapMode)1; ((Texture)val).filterMode = (FilterMode)1; Color val2 = default(Color); for (int i = 0; i < 64; i++) { float num = Mathf.Abs((float)i / 63f - 0.5f) * 2f; float num2 = Mathf.Lerp(1.25f, 0.55f, num); ((Color)(ref val2))..ctor(Mathf.Clamp01(baseColor.r * num2), Mathf.Clamp01(baseColor.g * num2), Mathf.Clamp01(baseColor.b * num2), targetAlpha); val.SetPixel(0, i, val2); } val.Apply(); return val; } private static void EnsureStyle() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown //IL_0066: 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_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown if (_leftStyle == null) { GUIStyle val = new GUIStyle(GUI.skin.label) { fontSize = 12, fontStyle = (FontStyle)1, alignment = (TextAnchor)3 }; val.normal.textColor = new Color(0.98f, 0.94f, 0.85f, 1f); _leftStyle = val; } if (_outlineStyle == null) { GUIStyle val2 = new GUIStyle(GUI.skin.label) { fontSize = 12, fontStyle = (FontStyle)1, alignment = (TextAnchor)3 }; val2.normal.textColor = new Color(0f, 0f, 0f, 1f); _outlineStyle = val2; } } private static void DrawLabelWithOutline(Rect r, string text) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) int[] array = new int[8] { -1, 0, 1, -1, 1, -1, 0, 1 }; int[] array2 = new int[8] { -1, -1, -1, 0, 0, 1, 1, 1 }; for (int i = 0; i < array.Length; i++) { GUI.Label(new Rect(((Rect)(ref r)).x + (float)array[i], ((Rect)(ref r)).y + (float)array2[i], ((Rect)(ref r)).width, ((Rect)(ref r)).height), text, _outlineStyle); } GUI.Label(r, text, _leftStyle); } private static string LocalizeSkillName(int skillId) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) SkillType val = (SkillType)skillId; string text = ((object)(SkillType)(ref val)).ToString(); string text2 = "$skill_" + text.ToLowerInvariant(); try { if (Localization.instance != null) { string text3 = Localization.instance.Localize(text2); if (!string.IsNullOrEmpty(text3) && text3 != text2) { return text3; } } } catch { } return PrettifyEnumName(text); } private static string PrettifyEnumName(string name) { StringBuilder stringBuilder = new StringBuilder(name.Length + 4); for (int i = 0; i < name.Length; i++) { if (i > 0 && char.IsUpper(name[i]) && !char.IsUpper(name[i - 1])) { stringBuilder.Append(' '); } stringBuilder.Append(name[i]); } return stringBuilder.ToString(); } }