Decompiled source of BubbleBar v0.1.0

BubbleBar.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BubbleBar.Logic;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_guiutils")]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("BubbleBar")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0+40f89732a7c28266a7e02ceb9d3318864cc41b52")]
[assembly: AssemblyProduct("BubbleBar")]
[assembly: AssemblyTitle("BubbleBar")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
[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 BubbleBar
{
	internal static class Bars
	{
		private const string BarName = "BubbleBar";

		private const string FillName = "BubbleBarFill";

		private static GameObject _ownBar;

		private static RectTransform _ownRect;

		private static readonly List<GuiBar> _ownFills = new List<GuiBar>();

		private static TMP_Text _ownNumber;

		private const float ShippedThickness = 0.6f;

		private static bool _ownBarFailed;

		private static bool _showing;

		private static string _colorText;

		private static Color _color = Color.cyan;

		internal static void Reset()
		{
			_ownBar = null;
			_ownRect = null;
			_ownNumber = null;
			_ownFills.Clear();
			_ownBarFailed = false;
			_showing = false;
		}

		internal static void Tick()
		{
			if (!ModConfig.Enabled.Value)
			{
				Hide();
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				Hide();
				return;
			}
			RefreshColor();
			TickOwnBar(localPlayer);
			TickAllyBars(localPlayer);
			_showing = true;
		}

		private static void RefreshColor()
		{
			//IL_0050: 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)
			string value = ModConfig.BarColor.Value;
			if (!(value == _colorText))
			{
				_colorText = value;
				Color color = default(Color);
				if (!ColorUtility.TryParseHtmlString(value, ref color))
				{
					BubbleBarPlugin.Log.LogWarning((object)("BarColor is set to \"" + value + "\", which is not a color I can read. Use something like #168DF5. Falling back to the default."));
					ColorUtility.TryParseHtmlString("#168DF5", ref color);
				}
				_color = color;
			}
		}

		internal static void Hide()
		{
			if (!_showing)
			{
				return;
			}
			if ((Object)(object)_ownBar != (Object)null)
			{
				_ownBar.SetActive(false);
			}
			EnemyHud instance = EnemyHud.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			foreach (KeyValuePair<Character, HudData> hud in instance.m_huds)
			{
				if (hud.Value != null && !((Object)(object)hud.Value.m_gui == (Object)null))
				{
					Transform val = hud.Value.m_gui.transform.Find("BubbleBar");
					if ((Object)(object)val != (Object)null)
					{
						((Component)val).gameObject.SetActive(false);
					}
				}
			}
			_showing = false;
		}

		private static void TickOwnBar(Player me)
		{
			//IL_0082: 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_00a0: 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_010f: Unknown result type (might be due to invalid IL or missing references)
			Hud instance = Hud.instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.m_eitrBarRoot == (Object)null || (Object)(object)instance.m_healthBarRoot == (Object)null || ((Object)(object)_ownBar == (Object)null && !BuildOwnBar(instance)))
			{
				return;
			}
			ShieldReading reading = (ModConfig.ShowOwnBar.Value ? Shields.Read((Character)(object)me) : ShieldReading.None);
			_ownBar.SetActive(reading.IsPresent);
			if (reading.IsPresent)
			{
				_ownRect.anchoredPosition = instance.m_eitrBarRoot.anchoredPosition + new Vector2(ModConfig.OwnBarOffsetX.Value, ModConfig.OwnBarOffsetY.Value);
				float value = ModConfig.OwnBarWidth.Value;
				_ownRect.SetSizeWithCurrentAnchors((Axis)0, value);
				float num = 0.6f * ModConfig.OwnBarThickness.Value;
				((Transform)_ownRect).localScale = new Vector3(1f, num, 1f);
				for (int i = 0; i < _ownFills.Count; i++)
				{
					_ownFills[i].SetWidth(value);
					_ownFills[i].SetColor(_color);
					_ownFills[i].SetValue(reading.Fraction);
				}
				ShowNumber(me, reading, num);
			}
		}

		private static void ShowNumber(Player me, ShieldReading reading, float thickness)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_ownNumber == (Object)null))
			{
				bool value = ModConfig.ShowOwnBarNumber.Value;
				((Behaviour)_ownNumber).enabled = value;
				if (value && !(thickness <= 0f))
				{
					((Transform)_ownNumber.rectTransform).localScale = new Vector3(1f, 1f / thickness, 1f);
					SE_Shield shield;
					float num = (Shields.TryGetShield((Character)(object)me, out shield) ? shield.m_totalAbsorbDamage : 0f);
					_ownNumber.text = Mathf.CeilToInt(reading.Fraction * num).ToString();
				}
			}
		}

		private unsafe static bool BuildOwnBar(Hud hud)
		{
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: 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_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			if (_ownBarFailed)
			{
				return false;
			}
			GameObject val = Object.Instantiate<GameObject>(((Component)hud.m_healthBarRoot).gameObject, ((Transform)hud.m_eitrBarRoot).parent, false);
			((Object)val).name = "BubbleBar";
			Transform transform = val.transform;
			_ownRect = (RectTransform)(object)((transform is RectTransform) ? transform : null);
			GuiBar[] componentsInChildren = val.GetComponentsInChildren<GuiBar>(true);
			if ((Object)(object)_ownRect == (Object)null || componentsInChildren.Length == 0)
			{
				Object.Destroy((Object)(object)val);
				_ownRect = null;
				_ownBarFailed = true;
				BubbleBarPlugin.Log.LogWarning((object)"The health bar is not shaped the way I expected, so your own barrier will have no bar for the rest of this session. The ally bars are unaffected.");
				return false;
			}
			_ownRect.anchorMin = hud.m_eitrBarRoot.anchorMin;
			_ownRect.anchorMax = hud.m_eitrBarRoot.anchorMax;
			_ownRect.pivot = hud.m_eitrBarRoot.pivot;
			Vector3 localEulerAngles = ((Transform)_ownRect).localEulerAngles;
			((Transform)_ownRect).localRotation = Quaternion.identity;
			((Transform)_ownRect).localScale = Vector3.one;
			Strip(val);
			AdoptNumber(val, hud);
			_ownFills.Clear();
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				((Component)componentsInChildren[i]).gameObject.SetActive(true);
				componentsInChildren[i].SetMaxValue(1f);
				_ownFills.Add(componentsInChildren[i]);
			}
			_ownBar = val;
			_ownBar.SetActive(false);
			ManualLogSource log = BubbleBarPlugin.Log;
			string[] obj = new string[5]
			{
				"Built the barrier bar from the health bar (",
				_ownFills.Count.ToString(),
				" fills, cleared a rotation of ",
				null,
				null
			};
			Vector3 val2 = localEulerAngles;
			obj[3] = ((object)(*(Vector3*)(&val2))/*cast due to .constrained prefix*/).ToString();
			obj[4] = "). Nudge it with OwnBarOffsetX / OwnBarOffsetY if it sits badly.";
			log.LogInfo((object)string.Concat(obj));
			return true;
		}

		private static void TickAllyBars(Player me)
		{
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			EnemyHud instance = EnemyHud.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			foreach (KeyValuePair<Character, HudData> hud in instance.m_huds)
			{
				Character key = hud.Key;
				HudData value = hud.Value;
				if ((Object)(object)key == (Object)null || value == null || (Object)(object)value.m_gui == (Object)null || (object)key == me || !value.m_gui.activeInHierarchy)
				{
					continue;
				}
				ShieldReading shieldReading = ((ModConfig.ShowAllyBars.Value && Shields.IsAlly(me, key)) ? Shields.Read(key) : ShieldReading.None);
				Transform val = value.m_gui.transform.Find("BubbleBar");
				GameObject val2 = (((Object)(object)val == (Object)null) ? null : ((Component)val).gameObject);
				if ((Object)(object)val2 == (Object)null)
				{
					if (!shieldReading.IsPresent)
					{
						continue;
					}
					val2 = BuildAllyBar(value);
					if ((Object)(object)val2 == (Object)null)
					{
						continue;
					}
				}
				val2.SetActive(shieldReading.IsPresent);
				if (!shieldReading.IsPresent)
				{
					continue;
				}
				Transform obj = value.m_gui.transform.Find("Health");
				RectTransform val3 = (RectTransform)(object)((obj is RectTransform) ? obj : null);
				if (val3 != null)
				{
					Transform transform = val2.transform;
					RectTransform val4 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
					if (val4 != null)
					{
						val4.anchoredPosition = val3.anchoredPosition + new Vector2(0f, ModConfig.AllyBarOffsetY.Value);
					}
				}
				Transform val5 = val2.transform.Find("BubbleBarFill");
				GuiBar val6 = (((Object)(object)val5 == (Object)null) ? null : ((Component)val5).GetComponent<GuiBar>());
				if (!((Object)(object)val6 == (Object)null))
				{
					if ((Object)(object)value.m_healthFast != (Object)null)
					{
						val6.SetWidth(value.m_healthFast.m_width);
					}
					val6.SetColor(_color);
					val6.SetValue(shieldReading.Fraction);
				}
			}
		}

		private static GameObject BuildAllyBar(HudData data)
		{
			Transform val = data.m_gui.transform.Find("Health");
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, data.m_gui.transform, false);
			((Object)val2).name = "BubbleBar";
			GuiBar[] componentsInChildren = val2.GetComponentsInChildren<GuiBar>(true);
			GuiBar val3 = null;
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				if (((Object)componentsInChildren[i]).name.Contains("fast") && !((Object)componentsInChildren[i]).name.Contains("friendly"))
				{
					val3 = componentsInChildren[i];
					break;
				}
			}
			if ((Object)(object)val3 == (Object)null && componentsInChildren.Length != 0)
			{
				val3 = componentsInChildren[0];
			}
			if ((Object)(object)val3 == (Object)null)
			{
				Object.Destroy((Object)(object)val2);
				return null;
			}
			for (int j = 0; j < componentsInChildren.Length; j++)
			{
				if (componentsInChildren[j] != val3)
				{
					((Component)componentsInChildren[j]).gameObject.SetActive(false);
				}
			}
			((Component)val3).gameObject.SetActive(true);
			((Object)val3).name = "BubbleBarFill";
			val3.SetMaxValue(1f);
			Strip(val2);
			return val2;
		}

		private static void AdoptNumber(GameObject clone, Hud hud)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: 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_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: 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_0092: 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_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			_ownNumber = clone.GetComponentInChildren<TMP_Text>(true);
			if ((Object)(object)_ownNumber == (Object)null)
			{
				BubbleBarPlugin.Log.LogInfo((object)"The health bar had no number to borrow, so the barrier bar will not show one. Everything else is unaffected.");
				return;
			}
			((Component)_ownNumber).gameObject.SetActive(true);
			((Behaviour)_ownNumber).enabled = true;
			RectTransform rectTransform = _ownNumber.rectTransform;
			((Transform)rectTransform).localRotation = Quaternion.identity;
			TMP_Text eitrText = hud.m_eitrText;
			if ((Object)(object)eitrText != (Object)null && (object)((Transform)eitrText.rectTransform).parent == hud.m_eitrBarRoot)
			{
				RectTransform rectTransform2 = eitrText.rectTransform;
				rectTransform.anchorMin = rectTransform2.anchorMin;
				rectTransform.anchorMax = rectTransform2.anchorMax;
				rectTransform.pivot = rectTransform2.pivot;
				rectTransform.anchoredPosition = rectTransform2.anchoredPosition;
				rectTransform.sizeDelta = rectTransform2.sizeDelta;
			}
			else
			{
				rectTransform.anchorMin = new Vector2(0.5f, 0.5f);
				rectTransform.anchorMax = new Vector2(0.5f, 0.5f);
				rectTransform.pivot = new Vector2(0.5f, 0.5f);
				rectTransform.anchoredPosition = Vector2.zero;
			}
			if ((Object)(object)eitrText != (Object)null)
			{
				_ownNumber.fontSize = eitrText.fontSize;
				_ownNumber.alignment = eitrText.alignment;
			}
		}

		private static void Strip(GameObject clone)
		{
			Behaviour[] componentsInChildren = clone.GetComponentsInChildren<Behaviour>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				string name = ((object)componentsInChildren[i]).GetType().Name;
				if (name == "Animator" || name.Contains("Text"))
				{
					componentsInChildren[i].enabled = false;
				}
			}
		}
	}
	internal static class DebugCommands
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static ConsoleEvent <0>__Report;
		}

		private const float SearchRadius = 60f;

		internal static void Register()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			object obj = <>O.<0>__Report;
			if (obj == null)
			{
				ConsoleEvent val = Report;
				<>O.<0>__Report = val;
				obj = (object)val;
			}
			new ConsoleCommand("bb_shields", "every character nearby with a magic barrier, and where the reading came from", (ConsoleEvent)obj, false, false, false, true, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		}

		private static void Report(ConsoleEventArgs args)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: 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_0071: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				args.Context.AddString("No player yet.");
				return;
			}
			args.Context.AddString(Describe(localPlayer, (Character)(object)localPlayer, "you"));
			Vector3 position = ((Component)localPlayer).transform.position;
			List<Character> allCharacters = Character.GetAllCharacters();
			int num = 0;
			for (int i = 0; i < allCharacters.Count; i++)
			{
				Character val = allCharacters[i];
				if (!((Object)(object)val == (Object)null) && (object)val != localPlayer)
				{
					float num2 = Vector3.Distance(position, ((Component)val).transform.position);
					if (!(num2 > 60f))
					{
						num++;
						args.Context.AddString(Describe(localPlayer, val, Mathf.RoundToInt(num2) + "m"));
					}
				}
			}
			if (num == 0)
			{
				args.Context.AddString("Nothing else within " + Mathf.RoundToInt(60f) + "m.");
			}
		}

		private static string Describe(Player me, Character c, string where)
		{
			string text = (string.IsNullOrEmpty(c.m_name) ? ((Object)c).name : c.m_name);
			bool flag = Shields.IsAlly(me, c);
			bool flag2 = (Object)(object)c.m_nview != (Object)null && c.m_nview.IsValid();
			bool flag3 = flag2 && c.m_nview.IsOwner();
			string text2 = text + " (" + where + ") - " + (flag ? "ally" : "enemy") + " - " + ((!flag2) ? "no zdo" : (flag3 ? "ours" : "owned elsewhere"));
			if (!flag3)
			{
				ShieldReading shieldReading = (flag2 ? Mirror.Read(c.m_nview.GetZDO()) : ShieldReading.None);
				if (!shieldReading.IsPresent)
				{
					return text2 + " - nothing published" + WhyNotDrawn(flag);
				}
				return text2 + " - mirrored " + Mathf.RoundToInt(shieldReading.Fraction * 100f) + "%" + WhyNotDrawn(flag);
			}
			if (!Shields.TryGetShield(c, out var shield))
			{
				return text2 + " - no barrier";
			}
			ShieldReading shieldReading2 = ShieldReading.For(shield.m_damage, shield.m_totalAbsorbDamage);
			float num = shieldReading2.Fraction * shield.m_totalAbsorbDamage;
			return text2 + " - barrier " + num.ToString("0") + "/" + shield.m_totalAbsorbDamage.ToString("0") + " (" + Mathf.RoundToInt(shieldReading2.Fraction * 100f) + "%), " + ((StatusEffect)shield).GetRemaningTime().ToString("0") + "s left";
		}

		private static string WhyNotDrawn(bool ally)
		{
			if (!ally)
			{
				return " (not drawn, enemies never get a bar)";
			}
			if (!ModConfig.ShowOthersBarriers.Value)
			{
				return " (not drawn, ShowOthersBarriers is off)";
			}
			if (!ModConfig.ShowAllyBars.Value)
			{
				return " (not drawn, ShowAllyBars is off)";
			}
			return string.Empty;
		}
	}
	internal static class Mirror
	{
		private static readonly int FractionHash = StringExtensionMethods.GetStableHashCode("BubbleBar.fraction");

		private static readonly int ExpiryHash = StringExtensionMethods.GetStableHashCode("BubbleBar.expiry");

		private const float SweepSeconds = 0.1f;

		private const float GraceSeconds = 2f;

		private static float _sweepTimer;

		private static bool _publishing;

		internal static void Publish(float dt)
		{
			if (!ModConfig.Enabled.Value)
			{
				if (_publishing)
				{
					Sweep(retractEverything: true);
					_publishing = false;
				}
				return;
			}
			_sweepTimer += dt;
			if (!(_sweepTimer < 0.1f))
			{
				_sweepTimer = 0f;
				_publishing = Sweep(retractEverything: false);
			}
		}

		private static bool Sweep(bool retractEverything)
		{
			ZNet instance = ZNet.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return false;
			}
			long num = Now(instance);
			bool result = false;
			List<IMonoUpdater> instances = Character.Instances;
			for (int i = 0; i < instances.Count; i++)
			{
				IMonoUpdater obj = instances[i];
				Character val = (Character)(object)((obj is Character) ? obj : null);
				if (val == null || (Object)(object)val == (Object)null || (Object)(object)val.m_nview == (Object)null || !val.m_nview.IsValid() || !val.m_nview.IsOwner())
				{
					continue;
				}
				ZDO zDO = val.m_nview.GetZDO();
				if (zDO == null)
				{
					continue;
				}
				SE_Shield shield = null;
				ShieldReading shieldReading = ShieldReading.None;
				if (!retractEverything && Shields.TryGetShield(val, out shield))
				{
					shieldReading = ShieldReading.For(shield.m_damage, shield.m_totalAbsorbDamage);
				}
				if (!shieldReading.IsPresent)
				{
					Clear(zDO);
					continue;
				}
				result = true;
				float remaningTime = ((StatusEffect)shield).GetRemaningTime();
				long num2 = num + (long)(((remaningTime > 0f) ? remaningTime : 2f) * 1000f);
				if (BubbleWire.ShouldWrite(zDO.GetFloat(FractionHash, 0f), shieldReading.Fraction))
				{
					zDO.Set(FractionHash, shieldReading.Fraction);
				}
				if (BubbleWire.ShouldWriteExpiry(zDO.GetLong(ExpiryHash, 0L), num2))
				{
					zDO.Set(ExpiryHash, num2);
				}
			}
			return result;
		}

		internal static ShieldReading Read(ZDO zdo)
		{
			ZNet instance = ZNet.instance;
			if (zdo == null || (Object)(object)instance == (Object)null)
			{
				return ShieldReading.None;
			}
			return BubbleWire.Read(zdo.GetFloat(FractionHash, 0f), zdo.GetLong(ExpiryHash, 0L), Now(instance));
		}

		private static long Now(ZNet net)
		{
			return (long)(net.GetTimeSeconds() * 1000.0);
		}

		private static void Clear(ZDO zdo)
		{
			if (zdo.GetLong(ExpiryHash, 0L) != 0L)
			{
				zdo.Set(ExpiryHash, 0L);
				zdo.Set(FractionHash, 0f);
			}
		}
	}
	internal static class ModConfig
	{
		internal const string DefaultBarColor = "#168DF5";

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<bool> RestoreOnRefresh;

		internal static ConfigEntry<bool> ShowOwnBar;

		internal static ConfigEntry<bool> ShowAllyBars;

		internal static ConfigEntry<string> BarColor;

		internal static ConfigEntry<float> OwnBarOffsetX;

		internal static ConfigEntry<float> OwnBarOffsetY;

		internal static ConfigEntry<float> OwnBarWidth;

		internal static ConfigEntry<float> OwnBarThickness;

		internal static ConfigEntry<bool> ShowOwnBarNumber;

		internal static ConfigEntry<float> AllyBarOffsetY;

		internal static ConfigEntry<bool> ShowOthersBarriers;

		internal static ConfigEntry<bool> LogBarrierEvents;

		internal static void Init(ConfigFile cfg)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Expected O, but got Unknown
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Expected O, but got Unknown
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Expected O, but got Unknown
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Expected O, but got Unknown
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Expected O, but got Unknown
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Expected O, but got Unknown
			Enabled = cfg.Bind<bool>("General", "Enabled", true, "Master switch. Turn this off and the mod does nothing at all - the barrier behaves exactly as it does in vanilla, and nothing new is drawn.");
			RestoreOnRefresh = cfg.Bind<bool>("Barrier", "RestoreOnRefresh", true, new ConfigDescription("With this on, recasting the Staff of Protection while a barrier is already up refills it.\nVanilla only resets the timer: a barrier that has soaked 190 of its 200 damage keeps all 190 and pops on the next hit, however long it now says it will last. With this on, a recast puts it back to a full 200.\nTurn it off to keep vanilla's behavior.", (AcceptableValueBase)null, Array.Empty<object>()));
			ShowOwnBar = cfg.Bind<bool>("Bars", "ShowOwnBar", true, "Show a bar on your own HUD while you have a magic barrier.");
			ShowAllyBars = cfg.Bind<bool>("Bars", "ShowAllyBars", true, new ConfigDescription("Show a bar over allies who have a barrier, under the health bar you already see when you look at them. Never shown on enemies.\nAnother player's barrier is only visible to you if they are running this mod too (their game is what publishes the number). Your own summons and tames work regardless, as long as you're nearby.", (AcceptableValueBase)null, Array.Empty<object>()));
			BarColor = cfg.Bind<string>("Bars", "BarColor", "#168DF5", "The color of the barrier bar, as a hex value. The unfilled part stays dark, similar to eitr/stamina/adrenaline/health.");
			OwnBarWidth = cfg.Bind<float>("Bars", "OwnBarWidth", 128f, new ConfigDescription("How wide your own barrier bar is, in HUD units. 128 matches the eitr bar at 100 maximum eitr.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(32f, 512f), Array.Empty<object>()));
			OwnBarThickness = cfg.Bind<float>("Bars", "OwnBarThickness", 1f, new ConfigDescription("How thick your own barrier bar is, as a multiplier. 1 matches the stamina and eitr bars it sits under. Raise it to be chunkier, lower to be thinner.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.4f, 3f), Array.Empty<object>()));
			ShowOwnBarNumber = cfg.Bind<bool>("Bars", "ShowOwnBarNumber", true, "Print how much damage your barrier can still soak atop your own bar, the way stamina and eitr print theirs. Ally bars never get a number.");
			OwnBarOffsetX = cfg.Bind<float>("Bars", "OwnBarOffsetX", 0f, new ConfigDescription("Sideways nudge for your own barrier bar, relative to the eitr bar.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-400f, 400f), Array.Empty<object>()));
			OwnBarOffsetY = cfg.Bind<float>("Bars", "OwnBarOffsetY", -40f, new ConfigDescription("Vertical nudge for your own barrier bar, relative to the eitr bar. Negative is down.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-400f, 400f), Array.Empty<object>()));
			AllyBarOffsetY = cfg.Bind<float>("Bars", "AllyBarOffsetY", -9f, new ConfigDescription("How far under an ally's health bar their barrier bar sits. Negative is down.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-60f, 60f), Array.Empty<object>()));
			ShowOthersBarriers = cfg.Bind<bool>("Multiplayer", "ShowOthersBarriers", true, new ConfigDescription("Draw bars for barriers on characters another player's game is running - other players, and their summons.\nYour own barrier and your own summons do not go through this; they are read directly and are unaffected. Turn it off if another player's bar ever looks wrong, without losing your own.", (AcceptableValueBase)null, Array.Empty<object>()));
			LogBarrierEvents = cfg.Bind<bool>("Diagnostics", "LogBarrierEvents", false, "Write a line to the BepInEx log every time a barrier is actually refilled, saying how much it had soaked and what it went back to. Meant for working out whether the refill is doing what you think.\nIt says nothing about a barrier going up for the first time, since there is nothing to restore, and nothing at all while RestoreOnRefresh is off.");
		}
	}
	[BepInPlugin("pandincus.bubblebar", "BubbleBar", "0.1.0")]
	[BepInProcess("valheim.exe")]
	public class BubbleBarPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "pandincus.bubblebar";

		public const string PluginName = "BubbleBar";

		public const string PluginVersion = "0.1.0";

		internal static ManualLogSource Log;

		private Harmony _harmony;

		private bool _drawing = true;

		private bool _publishing = true;

		private void Awake()
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			try
			{
				ModConfig.Init(((BaseUnityPlugin)this).Config);
				DebugCommands.Register();
			}
			catch (Exception ex)
			{
				Log.LogError((object)("BubbleBar could not set itself up, so it will do nothing this session. " + ex));
				return;
			}
			_harmony = new Harmony("pandincus.bubblebar");
			Type[] typesFromAssembly = AccessTools.GetTypesFromAssembly(Assembly.GetExecutingAssembly());
			foreach (Type type in typesFromAssembly)
			{
				try
				{
					_harmony.CreateClassProcessor(type).Patch();
				}
				catch (Exception ex2)
				{
					Log.LogError((object)("BubbleBar could not apply " + type.Name + ", so what it carries will not happen. The usual cause is a Valheim update having moved what it hooks. " + ex2));
				}
			}
			Log.LogInfo((object)"BubbleBar v0.1.0 loaded.");
		}

		private void Update()
		{
			if ((Object)(object)Hud.instance == (Object)null)
			{
				Bars.Reset();
				_drawing = true;
			}
			else if (_drawing)
			{
				try
				{
					Bars.Tick();
				}
				catch (Exception ex)
				{
					_drawing = false;
					Log.LogError((object)("BubbleBar could not draw the barrier bars, so they are off until you next load a world. The refill and the multiplayer half are unaffected. " + ex));
					try
					{
						Bars.Hide();
					}
					catch (Exception)
					{
					}
				}
			}
			if (!_publishing)
			{
				return;
			}
			try
			{
				Mirror.Publish(Time.deltaTime);
			}
			catch (Exception ex3)
			{
				_publishing = false;
				Log.LogError((object)("BubbleBar could not publish your barrier, so other players will not see it this session. Your own bars are unaffected. " + ex3));
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	internal static class Shields
	{
		internal static bool TryGetShield(Character character, out SE_Shield shield)
		{
			shield = null;
			if ((Object)(object)character == (Object)null || (Object)(object)character.m_nview == (Object)null || !character.m_nview.IsValid() || !character.m_nview.IsOwner())
			{
				return false;
			}
			SEMan sEMan = character.GetSEMan();
			if (sEMan == null)
			{
				return false;
			}
			List<StatusEffect> statusEffects = sEMan.GetStatusEffects();
			for (int i = 0; i < statusEffects.Count; i++)
			{
				StatusEffect obj = statusEffects[i];
				SE_Shield val = (SE_Shield)(object)((obj is SE_Shield) ? obj : null);
				if (val != null)
				{
					shield = val;
					return true;
				}
			}
			return false;
		}

		internal static ShieldReading Read(Character character)
		{
			if (TryGetShield(character, out var shield))
			{
				return ShieldReading.For(shield.m_damage, shield.m_totalAbsorbDamage);
			}
			if ((Object)(object)character == (Object)null || (Object)(object)character.m_nview == (Object)null || !character.m_nview.IsValid() || character.m_nview.IsOwner())
			{
				return ShieldReading.None;
			}
			if (!ModConfig.ShowOthersBarriers.Value)
			{
				return ShieldReading.None;
			}
			return Mirror.Read(character.m_nview.GetZDO());
		}

		internal static bool IsAlly(Player viewer, Character character)
		{
			if ((Object)(object)character == (Object)null)
			{
				return false;
			}
			if ((Object)(object)viewer == (Object)null)
			{
				return true;
			}
			return !BaseAI.IsEnemy((Character)(object)viewer, character);
		}
	}
}
namespace BubbleBar.Patches
{
	[HarmonyPatch(typeof(SE_Shield), "SetLevel")]
	internal static class ShieldRefresh
	{
		private static void Postfix(SE_Shield __instance)
		{
			if (ModConfig.Enabled.Value && ModConfig.RestoreOnRefresh.Value)
			{
				float damage = __instance.m_damage;
				__instance.m_damage = 0f;
				if (ModConfig.LogBarrierEvents.Value && !(damage <= 0f))
				{
					Character character = ((StatusEffect)__instance).m_character;
					BubbleBarPlugin.Log.LogInfo((object)("Barrier refreshed on " + (((Object)(object)character == (Object)null) ? "(nobody)" : character.m_name) + ": had soaked " + damage.ToString("0") + " of " + __instance.m_totalAbsorbDamage.ToString("0") + ", now back to full."));
				}
			}
		}
	}
}
namespace BubbleBar.Logic
{
	public static class BubbleWire
	{
		public const string FractionKey = "BubbleBar.fraction";

		public const string ExpiryKey = "BubbleBar.expiry";

		public const float WriteEpsilon = 0.00390625f;

		public const long ExpiryDriftMillis = 500L;

		public static ShieldReading Read(float fraction, long expiry, long now)
		{
			if (expiry <= now)
			{
				return ShieldReading.None;
			}
			return ShieldReading.FromFraction(fraction);
		}

		public static bool ShouldWrite(float published, float current)
		{
			if (current <= 0f)
			{
				return published > 0f;
			}
			return ((published > current) ? (published - current) : (current - published)) >= 0.00390625f;
		}

		public static bool ShouldWriteExpiry(long published, long current)
		{
			return ((published > current) ? (published - current) : (current - published)) > 500;
		}
	}
	public readonly struct ShieldReading
	{
		public static readonly ShieldReading None;

		public bool IsPresent { get; }

		public float Fraction { get; }

		private ShieldReading(float fraction)
		{
			IsPresent = true;
			Fraction = fraction;
		}

		public static ShieldReading For(float absorbed, float capacity)
		{
			if (capacity <= 0f)
			{
				return None;
			}
			float num = capacity - absorbed;
			if (num <= 0f)
			{
				return new ShieldReading(0f);
			}
			return new ShieldReading((num >= capacity) ? 1f : (num / capacity));
		}

		internal static ShieldReading FromFraction(float fraction)
		{
			if (float.IsNaN(fraction) || fraction < 0f)
			{
				return None;
			}
			return new ShieldReading((fraction > 1f) ? 1f : fraction);
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}