Decompiled source of Tally v1.0.0

plugins/Tally/Tally.dll

Decompiled 4 days ago
using 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 System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Managers;
using Microsoft.CodeAnalysis;
using TMPro;
using Tally.Core;
using Tally.Model;
using Tally.Net;
using Tally.UI;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("Tally")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("A Recount-style combat meter for Valheim: damage, DPS, damage taken, healing and personal records, shared between players.")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+a17751e5082e505a18be137d39a6bc8d1c85c329")]
[assembly: AssemblyProduct("Tally")]
[assembly: AssemblyTitle("Tally")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.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 Tally
{
	[BepInPlugin("com.jumpingmushroom.tally", "Tally", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInProcess("valheim.exe")]
	[BepInProcess("valheim.x86_64")]
	public sealed class TallyPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.jumpingmushroom.tally";

		public const string PluginName = "Tally";

		public const string PluginVersion = "1.0.0";

		internal static ManualLogSource Log;

		internal static MeterWindow Window;

		private readonly RecordBanner _banner = new RecordBanner();

		private Harmony _harmony;

		private bool _guiReady;

		private bool _mouseMode;

		private ZNet _lastNet;

		private bool _hadWorld;

		private bool _arrivalPending;

		private float _nextHousekeeping;

		private void Awake()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			PluginConfig.Bind(((BaseUnityPlugin)this).Config);
			Window = new MeterWindow(Recorder.Meter);
			ConsoleCommands.Register();
			_harmony = new Harmony("com.jumpingmushroom.tally");
			_harmony.PatchAll(typeof(TallyPlugin).Assembly);
			GUIManager.OnCustomGUIAvailable += OnGuiAvailable;
			PluginConfig.LayoutChanged += OnLayoutChanged;
			PluginConfig.FontChanged += OnFontChanged;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Tally 1.0.0 loaded.");
		}

		private void OnDestroy()
		{
			GUIManager.OnCustomGUIAvailable -= OnGuiAvailable;
			PluginConfig.LayoutChanged -= OnLayoutChanged;
			PluginConfig.FontChanged -= OnFontChanged;
			ReleaseMouse();
			Window.Destroy();
			_banner.Destroy();
			Fanfare.Banner = null;
			RecordStore.Unload();
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
		}

		private void OnGuiAvailable()
		{
			if (!GUIManager.IsHeadless())
			{
				if ((Object)(object)Player.m_localPlayer == (Object)null)
				{
					Window.SetOpen(open: false);
				}
				Fonts.Refresh();
				PluginConfig.RebindFontChoices(Fonts.Names);
				Window.Create();
				_banner.Create(GUIManager.CustomGUIFront.transform);
				Fanfare.Banner = _banner;
				_guiReady = Window.Created;
				if (PluginConfig.Verbose.Value)
				{
					Log.LogDebug((object)("window created: " + _guiReady));
				}
			}
		}

		private void OnLayoutChanged()
		{
			Window.ApplyLayout();
		}

		private void OnFontChanged()
		{
			if (!((Object)(object)GUIManager.CustomGUIFront == (Object)null))
			{
				Window.Destroy();
				Window.Create();
				_banner.Destroy();
				_banner.Create(GUIManager.CustomGUIFront.transform);
				Fanfare.Banner = _banner;
				_guiReady = Window.Created;
			}
		}

		private void WorldLeft()
		{
			ReleaseMouse();
			Window.SetOpen(open: false);
			Recorder.Clear();
			EventSync.Clear();
			RecordStore.Unload();
			Diagnostics.Reset();
			_arrivalPending = false;
		}

		private void WorldEntered()
		{
			Recorder.Clear();
			EventSync.Clear();
			_arrivalPending = true;
		}

		private void LocalPlayerArrived()
		{
			RecordStore.EnsureLoaded();
			Diagnostics.Reset();
			if (PluginConfig.ShowOnLogin.Value)
			{
				Window.SetOpen(open: true);
			}
		}

		private void Update()
		{
			//IL_00a7: 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_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			ZNet instance = ZNet.instance;
			bool flag = (Object)(object)instance != (Object)null;
			if (!flag && _hadWorld)
			{
				WorldLeft();
			}
			else if (flag && (!_hadWorld || instance != _lastNet))
			{
				WorldEntered();
			}
			_hadWorld = flag;
			_lastNet = instance;
			float time = Time.time;
			EventSync.Update(time);
			if ((Object)(object)Player.m_localPlayer == (Object)null)
			{
				ReleaseMouse();
				return;
			}
			if (_arrivalPending)
			{
				_arrivalPending = false;
				LocalPlayerArrived();
			}
			Recorder.Update(time);
			_banner.Update();
			if (!_guiReady)
			{
				return;
			}
			bool flag2 = Typing();
			if (!flag2)
			{
				if (Keys.Down(PluginConfig.ToggleKey.Value))
				{
					Window.Toggle();
				}
				if (Keys.Down(PluginConfig.ResetKey.Value))
				{
					Window.Reset();
				}
				if (Keys.Down(PluginConfig.CycleModeKey.Value))
				{
					Window.CycleMode();
				}
				if (Keys.Down(PluginConfig.CycleSegmentKey.Value))
				{
					Window.CycleSegment();
				}
			}
			bool flag3 = Window.IsOpen && !flag2 && Keys.Held(PluginConfig.MouseKey.Value);
			if (flag3 != _mouseMode)
			{
				_mouseMode = flag3;
				GUIManager.BlockInput(flag3);
			}
			Window.SetHidden(Hud.IsUserHidden());
			Window.Render();
			Diagnostics.ReportOnce();
			if (time >= _nextHousekeeping)
			{
				_nextHousekeeping = time + 10f;
				RecordStore.EnsureLoaded();
				RecordStore.SaveIfDirty();
			}
		}

		private void ReleaseMouse()
		{
			if (_mouseMode)
			{
				_mouseMode = false;
				GUIManager.BlockInput(false);
			}
		}

		private bool Typing()
		{
			if (Console.IsVisible())
			{
				return true;
			}
			if (Menu.IsVisible())
			{
				return true;
			}
			if (!_mouseMode && TextInput.IsVisible())
			{
				return true;
			}
			if (Minimap.InTextInput())
			{
				return true;
			}
			if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus())
			{
				return true;
			}
			return false;
		}
	}
	public enum ReportTarget
	{
		Chat,
		Console
	}
	public static class PluginConfig
	{
		public static ConfigEntry<KeyboardShortcut> ToggleKey;

		public static ConfigEntry<KeyboardShortcut> ResetKey;

		public static ConfigEntry<KeyboardShortcut> CycleModeKey;

		public static ConfigEntry<KeyboardShortcut> CycleSegmentKey;

		public static ConfigEntry<KeyboardShortcut> MouseKey;

		public static ConfigEntry<bool> ShowOnLogin;

		public static ConfigEntry<Vector2> WindowPosition;

		public static ConfigEntry<float> WindowWidth;

		public static ConfigEntry<float> WindowHeight;

		public static ConfigEntry<float> Opacity;

		public static ConfigEntry<float> BarOpacity;

		public static ConfigEntry<int> FontSize;

		public static ConfigEntry<string> FontName;

		public static ConfigEntry<bool> TextOutline;

		public static ConfigEntry<float> RowHeight;

		public static ConfigEntry<float> FightTimeout;

		public static ConfigEntry<float> ActiveGap;

		public static ConfigEntry<int> HistorySize;

		public static ConfigEntry<bool> IncludeStructures;

		public static ConfigEntry<bool> ShareEnabled;

		public static ConfigEntry<float> ShareRange;

		public static ConfigEntry<float> FlushInterval;

		public static ConfigEntry<bool> RecordsEnabled;

		public static ConfigEntry<bool> RecordBanner;

		public static ConfigEntry<bool> RecordSound;

		public static ConfigEntry<string> RecordSoundPrefab;

		public static ConfigEntry<float> RecordSoundVolume;

		public static ConfigEntry<float> RecordMinDamage;

		public static ConfigEntry<float> BannerSeconds;

		public static ConfigEntry<ReportTarget> ReportTo;

		public static ConfigEntry<int> ReportLines;

		public static ConfigEntry<bool> Verbose;

		public static readonly Vector2 DefaultPosition = Vector2.zero;

		private static ConfigFile _cfg;

		private const string FontDescription = "Font for the window, banner and tooltip, by TextMeshPro asset name. The list holds every font the game has loaded that can draw Latin text, once you are in a world; \"tally fonts\" in the console prints it and \"tally font <name>\" switches. Valheim-AveriaSerifLibre is the game's item-text face, Valheim-AveriaSansLibre its plainer sans, Valheim-Norse the runic display face the title bars use.";

		public static event Action LayoutChanged;

		public static event Action FontChanged;

		private static ConfigurationManagerAttributes Attr(int order, bool advanced = false)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			return new ConfigurationManagerAttributes
			{
				Order = order,
				IsAdvanced = advanced
			};
		}

		public static void Bind(ConfigFile cfg)
		{
			//IL_001b: 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)
			//IL_0041: Expected O, but got Unknown
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Expected O, but got Unknown
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Expected O, but got Unknown
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Expected O, but got Unknown
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Expected O, but got Unknown
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: 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_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Expected O, but got Unknown
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Expected O, but got Unknown
			//IL_0291: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Expected O, but got Unknown
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d6: Expected O, but got Unknown
			//IL_0315: Unknown result type (might be due to invalid IL or missing references)
			//IL_031f: Expected O, but got Unknown
			//IL_0347: Unknown result type (might be due to invalid IL or missing references)
			//IL_0351: Expected O, but got Unknown
			//IL_038b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0395: Expected O, but got Unknown
			//IL_03cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d9: Expected O, but got Unknown
			//IL_0413: Unknown result type (might be due to invalid IL or missing references)
			//IL_041d: Expected O, but got Unknown
			//IL_044c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0456: Expected O, but got Unknown
			//IL_047e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0488: Expected O, but got Unknown
			//IL_04b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ba: Expected O, but got Unknown
			//IL_04f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_04fe: Expected O, but got Unknown
			//IL_0538: Unknown result type (might be due to invalid IL or missing references)
			//IL_0542: Expected O, but got Unknown
			//IL_056a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0574: Expected O, but got Unknown
			//IL_059c: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a6: Expected O, but got Unknown
			//IL_05ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_05d8: Expected O, but got Unknown
			//IL_0604: Unknown result type (might be due to invalid IL or missing references)
			//IL_060e: Expected O, but got Unknown
			//IL_0648: Unknown result type (might be due to invalid IL or missing references)
			//IL_0652: Expected O, but got Unknown
			//IL_068c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0696: Expected O, but got Unknown
			//IL_06d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_06da: Expected O, but got Unknown
			//IL_0702: Unknown result type (might be due to invalid IL or missing references)
			//IL_070c: Expected O, but got Unknown
			//IL_073a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0744: Expected O, but got Unknown
			//IL_076b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0775: Expected O, but got Unknown
			_cfg = cfg;
			ToggleKey = cfg.Bind<KeyboardShortcut>("General", "ToggleKey", new KeyboardShortcut((KeyCode)288, Array.Empty<KeyCode>()), new ConfigDescription("Show or hide the meter window.", (AcceptableValueBase)null, new object[1] { Attr(100) }));
			ResetKey = cfg.Bind<KeyboardShortcut>("General", "ResetKey", KeyboardShortcut.Empty, new ConfigDescription("Clear every segment. Same as the Reset button. Unbound by default.", (AcceptableValueBase)null, new object[1] { Attr(95) }));
			CycleModeKey = cfg.Bind<KeyboardShortcut>("General", "CycleModeKey", KeyboardShortcut.Empty, new ConfigDescription("Step to the next mode (Damage Done, DPS, Damage Taken, Healing, Max Hit, Records). Unbound by default.", (AcceptableValueBase)null, new object[1] { Attr(90) }));
			CycleSegmentKey = cfg.Bind<KeyboardShortcut>("General", "CycleSegmentKey", KeyboardShortcut.Empty, new ConfigDescription("Step to the next segment (Overall, Current, previous fights). Unbound by default.", (AcceptableValueBase)null, new object[1] { Attr(85) }));
			MouseKey = cfg.Bind<KeyboardShortcut>("General", "MouseKey", new KeyboardShortcut((KeyCode)308, Array.Empty<KeyCode>()), new ConfigDescription("Hold this to free the cursor so you can click rows and buttons, drag and resize the window while playing. Attacks and camera are blocked while it is held. Not needed while the map or inventory is open, when the cursor is already free.", (AcceptableValueBase)null, new object[1] { Attr(80) }));
			ShowOnLogin = cfg.Bind<bool>("General", "ShowOnLogin", true, new ConfigDescription("Open the window when you enter a world.", (AcceptableValueBase)null, new object[1] { Attr(75) }));
			WindowPosition = cfg.Bind<Vector2>("Window", "Position", DefaultPosition, new ConfigDescription("Top-left corner in canvas pixels, measured from the top-left of the screen (y is negative going down). Written back when you drag the window. 0,0 means \"not placed yet\": the window goes to the right edge, a third of the way down.", (AcceptableValueBase)null, new object[1] { Attr(70) }));
			WindowWidth = cfg.Bind<float>("Window", "Width", 300f, new ConfigDescription("Window width. Written back when you resize with the corner handle.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(180f, 900f), new object[1] { Attr(65) }));
			WindowHeight = cfg.Bind<float>("Window", "Height", 220f, new ConfigDescription("Window height. Written back when you resize with the corner handle.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(80f, 1200f), new object[1] { Attr(60) }));
			Opacity = cfg.Bind<float>("Window", "Opacity", 0.75f, new ConfigDescription("Opacity of the window background.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), new object[1] { Attr(55) }));
			BarOpacity = cfg.Bind<float>("Window", "BarOpacity", 0.8f, new ConfigDescription("Opacity of the coloured bars.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 1f), new object[1] { Attr(54) }));
			FontSize = cfg.Bind<int>("Window", "FontSize", 14, new ConfigDescription("Text size in the bars.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(9, 24), new object[1] { Attr(50) }));
			FontName = cfg.Bind<string>("Window", "Font", "Valheim-AveriaSerifLibre", new ConfigDescription("Font for the window, banner and tooltip, by TextMeshPro asset name. The list holds every font the game has loaded that can draw Latin text, once you are in a world; \"tally fonts\" in the console prints it and \"tally font <name>\" switches. Valheim-AveriaSerifLibre is the game's item-text face, Valheim-AveriaSansLibre its plainer sans, Valheim-Norse the runic display face the title bars use.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new List<string>(Fonts.Names).ToArray()), new object[1] { Attr(48) }));
			TextOutline = cfg.Bind<bool>("Window", "TextOutline", true, new ConfigDescription("Outline the text, the way the game's own HUD does, so it stays readable where the window is see-through. Uses the font's own outline material; fonts without one draw plain.", (AcceptableValueBase)null, new object[1] { Attr(46) }));
			RowHeight = cfg.Bind<float>("Window", "RowHeight", 19f, new ConfigDescription("Height of each bar.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(12f, 40f), new object[1] { Attr(45) }));
			FightTimeout = cfg.Bind<float>("Tracking", "FightTimeout", 5f, new ConfigDescription("A fight ends after this many seconds without any damage dealt or taken.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 60f), new object[1] { Attr(40) }));
			ActiveGap = cfg.Bind<float>("Tracking", "ActiveGap", 5f, new ConfigDescription("DPS divides damage by the time a player spent actively fighting: the gaps between their hits, each capped at this many seconds. A player who joins late is not penalised for the time before they arrived.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 30f), new object[1] { Attr(38) }));
			HistorySize = cfg.Bind<int>("Tracking", "HistorySize", 5, new ConfigDescription("How many previous fights the Segments button can page back through.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), new object[1] { Attr(36) }));
			IncludeStructures = cfg.Bind<bool>("Tracking", "IncludeStructures", false, new ConfigDescription("Also count damage to trees, logs, rocks, ore and built pieces. Off by default: chopping wood is not combat.", (AcceptableValueBase)null, new object[1] { Attr(34) }));
			ShareEnabled = cfg.Bind<bool>("Sharing", "Enabled", true, new ConfigDescription("Send what this client sees to other players running the mod, and accept what they send. Nothing is installed on the server; players without the mod are unaffected.", (AcceptableValueBase)null, new object[1] { Attr(30) }));
			ShareRange = cfg.Bind<float>("Sharing", "Range", 100f, new ConfigDescription("Ignore events from other players that happened further than this many metres from you.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 1000f), new object[1] { Attr(28) }));
			FlushInterval = cfg.Bind<float>("Sharing", "FlushInterval", 0.5f, new ConfigDescription("Seconds between batched packets to other players.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), new object[1] { Attr(26, advanced: true) }));
			RecordsEnabled = cfg.Bind<bool>("Records", "Enabled", true, new ConfigDescription("Remember your biggest single hit per weapon and overall across sessions, per character and world. Stored in BepInEx/config/Tally/.", (AcceptableValueBase)null, new object[1] { Attr(24) }));
			RecordBanner = cfg.Bind<bool>("Records", "Banner", true, new ConfigDescription("Show a centred banner when a record is beaten.", (AcceptableValueBase)null, new object[1] { Attr(22) }));
			RecordSound = cfg.Bind<bool>("Records", "Sound", true, new ConfigDescription("Play a fanfare when a record is beaten.", (AcceptableValueBase)null, new object[1] { Attr(20) }));
			RecordSoundPrefab = cfg.Bind<string>("Records", "SoundPrefab", "fx_GP_Activation", new ConfigDescription("Name of a vanilla sound prefab to play, resolved through ZNetScene. Candidates that read as celebratory: fx_GP_Activation (guardian power), sfx_secretfound (discovery chime), sfx_lootspawn. The special value @levelup plays the skill level-up sound. \"tally sfx <name>\" in the console previews one; a missing prefab just skips the sound.", (AcceptableValueBase)null, new object[1] { Attr(18) }));
			RecordSoundVolume = cfg.Bind<float>("Records", "SoundVolume", 0.8f, new ConfigDescription("Fanfare volume, on top of the game's effects volume.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), new object[1] { Attr(16) }));
			RecordMinDamage = cfg.Bind<float>("Records", "MinDamage", 50f, new ConfigDescription("No banner or sound for records below this much damage, so a fresh character is not serenaded for every punch.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5000f), new object[1] { Attr(14) }));
			BannerSeconds = cfg.Bind<float>("Records", "BannerSeconds", 4f, new ConfigDescription("How long the banner stays before fading.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 15f), new object[1] { Attr(12) }));
			ReportTo = cfg.Bind<ReportTarget>("Report", "Target", ReportTarget.Chat, new ConfigDescription("Where the Report button sends the current view: in-game chat (everyone nearby sees it) or your own console.", (AcceptableValueBase)null, new object[1] { Attr(10) }));
			ReportLines = cfg.Bind<int>("Report", "Lines", 5, new ConfigDescription("How many rows a report includes.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 15), new object[1] { Attr(8) }));
			Verbose = cfg.Bind<bool>("Logging", "Verbose", false, new ConfigDescription("Log every recorded event and packet to the BepInEx log. Off by default.", (AcceptableValueBase)null, new object[1] { Attr(5, advanced: true) }));
			WindowPosition.SettingChanged += delegate
			{
				Raise(PluginConfig.LayoutChanged);
			};
			WindowWidth.SettingChanged += delegate
			{
				Raise(PluginConfig.LayoutChanged);
			};
			WindowHeight.SettingChanged += delegate
			{
				Raise(PluginConfig.LayoutChanged);
			};
			Opacity.SettingChanged += delegate
			{
				Raise(PluginConfig.LayoutChanged);
			};
			BarOpacity.SettingChanged += delegate
			{
				Raise(PluginConfig.LayoutChanged);
			};
			FontSize.SettingChanged += delegate
			{
				Raise(PluginConfig.LayoutChanged);
			};
			RowHeight.SettingChanged += delegate
			{
				Raise(PluginConfig.LayoutChanged);
			};
			FontName.SettingChanged += delegate
			{
				Raise(PluginConfig.FontChanged);
			};
			TextOutline.SettingChanged += delegate
			{
				Raise(PluginConfig.FontChanged);
			};
		}

		public static void RebindFontChoices(IList<string> names)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Expected O, but got Unknown
			if (_cfg == null || FontName == null || names == null || names.Count == 0)
			{
				return;
			}
			string value = FontName.Value;
			_cfg.Remove(((ConfigEntryBase)FontName).Definition);
			FontName = _cfg.Bind<string>("Window", "Font", "Valheim-AveriaSerifLibre", new ConfigDescription("Font for the window, banner and tooltip, by TextMeshPro asset name. The list holds every font the game has loaded that can draw Latin text, once you are in a world; \"tally fonts\" in the console prints it and \"tally font <name>\" switches. Valheim-AveriaSerifLibre is the game's item-text face, Valheim-AveriaSansLibre its plainer sans, Valheim-Norse the runic display face the title bars use.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new List<string>(names).ToArray()), new object[1] { Attr(48) }));
			FontName.SettingChanged += delegate
			{
				Raise(PluginConfig.FontChanged);
			};
			TextOutline.SettingChanged += delegate
			{
				Raise(PluginConfig.FontChanged);
			};
			foreach (string name in names)
			{
				if (string.Equals(name, value, StringComparison.OrdinalIgnoreCase))
				{
					if (FontName.Value != name)
					{
						FontName.Value = name;
					}
					return;
				}
			}
			if (!string.IsNullOrEmpty(value) && value != FontName.Value)
			{
				TallyPlugin.Log.LogWarning((object)("font \"" + value + "\" is not loaded; using " + FontName.Value));
			}
		}

		private static void Raise(Action a)
		{
			if (a == null)
			{
				return;
			}
			try
			{
				a();
			}
			catch (Exception ex)
			{
				TallyPlugin.Log.LogWarning((object)("config listener threw: " + ex));
			}
		}
	}
}
namespace Tally.UI
{
	public sealed class RowData
	{
		public string Key = "";

		public string Label = "";

		public float Value;

		public string ValueText = "";

		public Color Color;

		public bool Approximate;

		public bool Clickable;

		public Func<string> Tooltip;
	}
	public static class MeterView
	{
		public static readonly MeterMode[] Modes = new MeterMode[6]
		{
			MeterMode.DamageDone,
			MeterMode.Dps,
			MeterMode.DamageTaken,
			MeterMode.Healing,
			MeterMode.MaxHit,
			MeterMode.Records
		};

		public static string ModeName(MeterMode m)
		{
			return m switch
			{
				MeterMode.DamageDone => "Damage Done", 
				MeterMode.Dps => "DPS", 
				MeterMode.DamageTaken => "Damage Taken", 
				MeterMode.Healing => "Healing", 
				MeterMode.MaxHit => "Max Hit", 
				MeterMode.Records => "Records", 
				_ => m.ToString(), 
			};
		}

		public static string SegmentName(Segment s, Meter meter)
		{
			if (s == meter.Overall)
			{
				return "Overall";
			}
			if (s == meter.Current)
			{
				if (!meter.InFight)
				{
					return "Last Fight";
				}
				return "Current Fight";
			}
			return s.Label;
		}

		public static List<RowData> Rows(MeterMode mode, Segment seg, string drill, float now)
		{
			List<RowData> list = new List<RowData>();
			PlayerStats value;
			if (mode == MeterMode.Records)
			{
				if (drill == null)
				{
					RecordRows(list);
				}
				else
				{
					RecordDrill(list, drill);
				}
			}
			else if (drill == null)
			{
				PlayerRows(list, mode, seg);
			}
			else if (seg.Players.TryGetValue(drill, out value))
			{
				DrillRows(list, mode, value, seg);
			}
			list.Sort((RowData a, RowData b) => b.Value.CompareTo(a.Value));
			return list;
		}

		private static void PlayerRows(List<RowData> rows, MeterMode mode, Segment seg)
		{
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			float total = 0f;
			foreach (PlayerStats value in seg.Players.Values)
			{
				total += Value(mode, value);
			}
			foreach (PlayerStats value2 in seg.Players.Values)
			{
				float num = Value(mode, value2);
				if (!(num <= 0f))
				{
					PlayerStats stats = value2;
					Segment segment = seg;
					rows.Add(new RowData
					{
						Key = value2.Name,
						Label = value2.Name,
						Value = num,
						ValueText = ((mode == MeterMode.MaxHit) ? Names.Amount(num) : (Names.Amount(num) + " (" + Names.Percent((total > 0f) ? (num / total) : 0f) + ")")),
						Color = PlayerColors.For(value2.Name),
						Approximate = (value2.Approximate && (mode == MeterMode.DamageDone || mode == MeterMode.Dps || mode == MeterMode.MaxHit)),
						Clickable = true,
						Tooltip = () => PlayerTooltip(mode, stats, segment, total)
					});
				}
			}
		}

		private static float Value(MeterMode mode, PlayerStats p)
		{
			switch (mode)
			{
			case MeterMode.DamageDone:
				return p.Damage;
			case MeterMode.Dps:
				if (!(p.Damage > 0f))
				{
					return 0f;
				}
				return p.Dps;
			case MeterMode.DamageTaken:
				return p.Taken;
			case MeterMode.Healing:
				return p.Healing;
			case MeterMode.MaxHit:
				return p.MaxHit;
			default:
				return 0f;
			}
		}

		private static string PlayerTooltip(MeterMode mode, PlayerStats p, Segment seg, float total)
		{
			StringBuilder stringBuilder = new StringBuilder(256);
			stringBuilder.Append("<b>").Append(p.Name).Append("</b>");
			if (p.Approximate)
			{
				stringBuilder.Append("  <color=#BCAF97>~ includes approximate hits</color>");
			}
			stringBuilder.Append('\n');
			switch (mode)
			{
			case MeterMode.DamageDone:
			case MeterMode.Dps:
				stringBuilder.Append("Damage ").Append(Names.Exact(p.Damage)).Append("  ·  DPS ")
					.Append(Names.Exact(p.Dps))
					.Append("  ·  active ")
					.Append(Names.Duration(p.ActiveTime))
					.Append('\n');
				stringBuilder.Append("Hits ").Append(p.DamageHits).Append("  ·  avg ")
					.Append(Names.Exact((p.DamageHits > 0) ? (p.Damage / (float)p.DamageHits) : 0f))
					.Append("  ·  max ")
					.Append(Names.Exact(p.MaxHit))
					.Append('\n');
				Buckets(stringBuilder, "Weapons", p.Weapons, p.Damage, (mode == MeterMode.Dps) ? p.ActiveTime : 0f);
				break;
			case MeterMode.DamageTaken:
				stringBuilder.Append("Taken ").Append(Names.Exact(p.Taken)).Append("  ·  hits ")
					.Append(p.TakenHits)
					.Append("  ·  avg ")
					.Append(Names.Exact((p.TakenHits > 0) ? (p.Taken / (float)p.TakenHits) : 0f))
					.Append('\n');
				Buckets(stringBuilder, "From", p.TakenFrom, p.Taken, 0f);
				break;
			case MeterMode.Healing:
				stringBuilder.Append("Healed ").Append(Names.Exact(p.Healing)).Append("  ·  overheal ")
					.Append(Names.Exact(p.Overheal))
					.Append("  ·  ticks ")
					.Append(p.Heals)
					.Append('\n');
				Buckets(stringBuilder, "Sources", p.HealFrom, p.Healing, 0f);
				break;
			case MeterMode.MaxHit:
			{
				if (p.TopHits.Count > 0)
				{
					HitRecord hitRecord = p.TopHits[0];
					stringBuilder.Append("Biggest hit ").Append(Names.Exact(hitRecord.Amount)).Append(" with ")
						.Append(hitRecord.Weapon)
						.Append(" on ")
						.Append(hitRecord.Target)
						.Append(hitRecord.Backstab ? " (sneak attack)" : "")
						.Append('\n');
				}
				stringBuilder.Append("<color=#BCAF97>Top hits:</color>\n");
				for (int i = 0; i < p.TopHits.Count && i < 5; i++)
				{
					HitRecord hitRecord2 = p.TopHits[i];
					stringBuilder.Append("  ").Append(Names.Exact(hitRecord2.Amount)).Append("  ")
						.Append(hitRecord2.Weapon)
						.Append(" → ")
						.Append(hitRecord2.Target)
						.Append(hitRecord2.Backstab ? " *" : "")
						.Append('\n');
				}
				break;
			}
			}
			stringBuilder.Append("<color=#BCAF97>Click for the breakdown</color>");
			return stringBuilder.ToString();
		}

		private static void Buckets(StringBuilder sb, string title, Dictionary<string, Bucket> map, float total, float activeTime)
		{
			List<Bucket> list = new List<Bucket>(map.Values);
			list.Sort((Bucket a, Bucket b) => b.Total.CompareTo(a.Total));
			sb.Append("<color=#BCAF97>").Append(title).Append(":</color>\n");
			for (int num = 0; num < list.Count && num < 6; num++)
			{
				Bucket bucket = list[num];
				sb.Append("  ").Append(bucket.Name).Append("  ")
					.Append(Names.Amount(bucket.Total));
				if (activeTime > 0f)
				{
					sb.Append(" (").Append(Names.Exact(bucket.Total / Mathf.Max(1f, activeTime))).Append("/s)");
				}
				else
				{
					sb.Append(" (").Append(Names.Percent((total > 0f) ? (bucket.Total / total) : 0f)).Append(')');
				}
				sb.Append('\n');
			}
			if (list.Count > 6)
			{
				sb.Append("  <color=#BCAF97>and ").Append(list.Count - 6).Append(" more</color>\n");
			}
		}

		private static void DrillRows(List<RowData> rows, MeterMode mode, PlayerStats p, Segment seg)
		{
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			switch (mode)
			{
			case MeterMode.DamageDone:
				BucketRows(rows, p.Weapons, p.Damage, 0f);
				break;
			case MeterMode.Dps:
				BucketRows(rows, p.Weapons, p.Damage, Mathf.Max(1f, p.ActiveTime));
				break;
			case MeterMode.DamageTaken:
				BucketRows(rows, p.TakenFrom, p.Taken, 0f);
				break;
			case MeterMode.Healing:
				BucketRows(rows, p.HealFrom, p.Healing, 0f);
				break;
			case MeterMode.MaxHit:
			{
				for (int i = 0; i < p.TopHits.Count; i++)
				{
					HitRecord h = p.TopHits[i];
					string label = h.Weapon + " → " + h.Target + (h.Backstab ? " *" : "");
					rows.Add(new RowData
					{
						Key = "hit" + i,
						Label = label,
						Value = h.Amount,
						ValueText = Names.Amount(h.Amount),
						Color = PlayerColors.For(h.Weapon),
						Approximate = h.Approximate,
						Clickable = false,
						Tooltip = () => Names.Exact(h.Amount) + " with " + h.Weapon + " on " + h.Target + (h.Backstab ? "\nSneak attack" : "") + (h.Approximate ? "\nApproximate (pre-mitigation)" : "")
					});
				}
				break;
			}
			}
		}

		private static void BucketRows(List<RowData> rows, Dictionary<string, Bucket> map, float total, float activeTime)
		{
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			foreach (Bucket value in map.Values)
			{
				if (!(value.Total <= 0f))
				{
					Bucket bucket = value;
					float num = ((activeTime > 0f) ? (value.Total / activeTime) : value.Total);
					rows.Add(new RowData
					{
						Key = value.Name,
						Label = value.Name,
						Value = num,
						ValueText = Names.Amount(num) + " (" + Names.Percent((total > 0f) ? (value.Total / total) : 0f) + ")",
						Color = PlayerColors.For(value.Name),
						Approximate = value.Approximate,
						Clickable = false,
						Tooltip = () => "<b>" + bucket.Name + "</b>\nTotal " + Names.Exact(bucket.Total) + "  ·  hits " + bucket.Hits + "  ·  avg " + Names.Exact((bucket.Hits > 0) ? (bucket.Total / (float)bucket.Hits) : 0f) + "  ·  max " + Names.Exact(bucket.Max) + (bucket.Approximate ? "\n<color=#BCAF97>~ includes approximate hits</color>" : "")
					});
				}
			}
		}

		private static void RecordRows(List<RowData> rows)
		{
			//IL_0086: 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)
			foreach (KeyValuePair<string, List<RecordStore.Record>> weapon in RecordStore.Weapons)
			{
				if (weapon.Value.Count != 0)
				{
					RecordStore.Record best = weapon.Value[0];
					string key = weapon.Key;
					rows.Add(new RowData
					{
						Key = key,
						Label = key,
						Value = best.Damage,
						ValueText = Names.Amount(best.Damage),
						Color = PlayerColors.For(key),
						Clickable = true,
						Tooltip = () => RecordTooltip(best, header: true)
					});
				}
			}
		}

		private static void RecordDrill(List<RowData> rows, string weapon)
		{
			//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)
			List<RecordStore.Record> list = RecordStore.ForWeapon(weapon);
			if (list == null)
			{
				return;
			}
			for (int i = 0; i < list.Count; i++)
			{
				RecordStore.Record r = list[i];
				rows.Add(new RowData
				{
					Key = "rec" + i,
					Label = r.Target + "  " + r.When() + (r.Backstab ? " *" : ""),
					Value = r.Damage,
					ValueText = Names.Amount(r.Damage),
					Color = PlayerColors.For(weapon),
					Clickable = false,
					Tooltip = () => RecordTooltip(r, header: false)
				});
			}
		}

		private static string RecordTooltip(RecordStore.Record r, bool header)
		{
			StringBuilder stringBuilder = new StringBuilder(160);
			if (header)
			{
				stringBuilder.Append("<b>").Append(r.Weapon).Append("</b>  best ");
			}
			stringBuilder.Append(Names.Exact(r.Damage)).Append(" on ").Append(r.Target)
				.Append('\n');
			if (!string.IsNullOrEmpty(r.DamageType))
			{
				stringBuilder.Append(r.DamageType).Append("  ·  ");
			}
			if (r.Backstab)
			{
				stringBuilder.Append("sneak attack  ·  ");
			}
			if (!string.IsNullOrEmpty(r.Skill))
			{
				stringBuilder.Append(r.Skill).Append(" ").Append((int)r.SkillLevel)
					.Append("  ·  ");
			}
			stringBuilder.Append(r.When());
			if (!string.IsNullOrEmpty(r.World))
			{
				stringBuilder.Append("  ·  ").Append(r.World);
			}
			if (header)
			{
				stringBuilder.Append("\n<color=#BCAF97>Click for the top 10</color>");
			}
			return stringBuilder.ToString();
		}
	}
	public sealed class MeterWindow
	{
		private sealed class Row
		{
			public GameObject Go;

			public RectTransform Rect;

			public Image Bar;

			public TextMeshProUGUI Left;

			public TextMeshProUGUI Right;

			public RowHandler Handler;

			public RowData Data;
		}

		private const float TitleHeight = 22f;

		private const float Padding = 4f;

		private const float RowGap = 2f;

		private const float ButtonFont = 12f;

		private const float PositionSettleDelay = 0.4f;

		private const float DpsRefresh = 0.5f;

		private readonly Meter _meter;

		private readonly Tooltip _tooltip = new Tooltip();

		private readonly List<Row> _rows = new List<Row>();

		private GameObject _root;

		private RectTransform _rect;

		private Image _background;

		private RectTransform _body;

		private TextMeshProUGUI _title;

		private Button _back;

		private GameObject _resizeGrip;

		private float _titleReserved = 150f;

		private Vector2 _lastSeenPosition;

		private Vector2 _lastSeenSize;

		private float _positionSettleAt;

		private bool _suppressLayoutApply;

		private int _builtRevision = -1;

		private bool _dirty = true;

		private float _nextTimedRebuild;

		private Row _hovered;

		private bool _hidden;

		public MeterMode Mode { get; private set; }

		public int SegmentIndex { get; private set; }

		public string Drill { get; private set; }

		public int Scroll { get; private set; }

		public bool IsOpen { get; private set; }

		public bool Created => (Object)(object)_root != (Object)null;

		public MeterWindow(Meter meter)
		{
			_meter = meter;
		}

		public void Create()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: 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)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: 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_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0338: Unknown result type (might be due to invalid IL or missing references)
			//IL_035a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0361: Expected O, but got Unknown
			//IL_03ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0405: Unknown result type (might be due to invalid IL or missing references)
			//IL_041a: Unknown result type (might be due to invalid IL or missing references)
			//IL_042f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0443: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_root != (Object)null) && !((Object)(object)GUIManager.CustomGUIFront == (Object)null))
			{
				Transform transform = GUIManager.CustomGUIFront.transform;
				_root = Widgets.Panel(transform, "TallyWindow", Widgets.Background, raycast: true);
				_rect = Widgets.Rect(_root);
				Widgets.TopLeft(_rect, 0f, 0f, PluginConfig.WindowWidth.Value, PluginConfig.WindowHeight.Value);
				_background = _root.GetComponent<Image>();
				_root.AddComponent<RectMask2D>();
				_root.AddComponent<ScrollRelay>().OnScrolled = OnScrolled;
				Widgets.AddBorder(_root.transform, Widgets.Border);
				GameObject val = Widgets.Panel(_root.transform, "TitleBar", Widgets.TitleBackground, raycast: true);
				RectTransform obj = Widgets.Rect(val);
				obj.anchorMin = new Vector2(0f, 1f);
				obj.anchorMax = new Vector2(1f, 1f);
				obj.pivot = new Vector2(0.5f, 1f);
				obj.anchoredPosition = Vector2.zero;
				obj.sizeDelta = new Vector2(0f, 22f);
				WindowDrag windowDrag = val.AddComponent<WindowDrag>();
				windowDrag.Window = _rect;
				windowDrag.OnMoved = OnMovedByUser;
				_back = Widgets.TextButton(val.transform, "Back", "<", 14f, Back, out var label);
				Widgets.TopLeft(Widgets.Rect(((Component)_back).gameObject), 2f, 1f, 18f, 20f);
				((Graphic)label).color = Widgets.Orange;
				((Component)_back).gameObject.SetActive(false);
				_title = Widgets.Label(val.transform, "Title", 13f, Widgets.Orange, (TextAlignmentOptions)4097);
				RectTransform obj2 = Widgets.Rect(((Component)_title).gameObject);
				obj2.anchorMin = new Vector2(0f, 0f);
				obj2.anchorMax = new Vector2(1f, 1f);
				obj2.offsetMin = new Vector2(6f, 0f);
				obj2.offsetMax = new Vector2(-150f, 0f);
				float x = 2f;
				x = AddTitleButton(x: AddTitleButton(x: AddTitleButton(x: AddTitleButton(x: AddTitleButton(val.transform, "Close", "x", x, delegate
				{
					SetOpen(open: false);
				}), bar: val.transform, name: "Report", text: "Rep", onClick: Report), bar: val.transform, name: "Modes", text: "Mode", onClick: CycleMode), bar: val.transform, name: "Segments", text: "Seg", onClick: CycleSegment), bar: val.transform, name: "Reset", text: "Reset", onClick: Reset);
				_titleReserved = x + 4f;
				obj2.offsetMax = new Vector2(0f - _titleReserved, 0f);
				GameObject val2 = new GameObject("Body", new Type[1] { typeof(RectTransform) });
				val2.transform.SetParent(_root.transform, false);
				_body = Widgets.Rect(val2);
				Widgets.Stretch(_body, 4f, 26f, 4f, 4f);
				_resizeGrip = Widgets.Panel(_root.transform, "Resize", new Color(1f, 1f, 1f, 0.22f), raycast: true);
				RectTransform obj3 = Widgets.Rect(_resizeGrip);
				obj3.anchorMin = new Vector2(1f, 0f);
				obj3.anchorMax = new Vector2(1f, 0f);
				obj3.pivot = new Vector2(1f, 0f);
				obj3.anchoredPosition = new Vector2(-1f, 1f);
				obj3.sizeDelta = new Vector2(12f, 12f);
				ResizeHandle resizeHandle = _resizeGrip.AddComponent<ResizeHandle>();
				resizeHandle.Window = _rect;
				resizeHandle.OnResized = OnResizedByUser;
				_tooltip.Create(transform);
				_rows.Clear();
				_hovered = null;
				_dirty = true;
				_builtRevision = -1;
				_root.SetActive(IsOpen && !_hidden);
				ApplyLayout();
			}
		}

		private float AddTitleButton(Transform bar, string name, string text, float x, Action onClick)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			TextMeshProUGUI label;
			Button obj = Widgets.TextButton(bar, name, text, 12f, onClick, out label);
			float num = Mathf.Ceil(((TMP_Text)label).GetPreferredValues(text).x) + 10f;
			Widgets.TopRight(Widgets.Rect(((Component)obj).gameObject), x, 1f, num, 20f);
			return x + num + 1f;
		}

		public void Destroy()
		{
			_tooltip.Destroy();
			if ((Object)(object)_root != (Object)null)
			{
				Object.Destroy((Object)(object)_root);
			}
			_root = null;
			_rect = null;
			_body = null;
			_title = null;
			_rows.Clear();
			_hovered = null;
		}

		public void ApplyLayout()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: 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_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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_009b: 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_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: 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_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: 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_005d: 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_0066: 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)
			if ((Object)(object)_rect == (Object)null || _suppressLayoutApply)
			{
				return;
			}
			float value = PluginConfig.WindowWidth.Value;
			float value2 = PluginConfig.WindowHeight.Value;
			_rect.sizeDelta = new Vector2(value, value2);
			Vector2 value3 = PluginConfig.WindowPosition.Value;
			if (value3 == PluginConfig.DefaultPosition)
			{
				Vector2 val = Widgets.CanvasSize(_rect);
				((Vector2)(ref value3))..ctor(Mathf.Round(val.x - value - 24f), 0f - Mathf.Round(val.y * 0.33f));
			}
			_rect.anchoredPosition = ClampToCanvas(value3, value);
			_lastSeenPosition = _rect.anchoredPosition;
			_lastSeenSize = _rect.sizeDelta;
			_positionSettleAt = 0f;
			Color background = Widgets.Background;
			background.a = PluginConfig.Opacity.Value;
			((Graphic)_background).color = background;
			foreach (Row row in _rows)
			{
				Object.Destroy((Object)(object)row.Go);
			}
			_rows.Clear();
			_hovered = null;
			_tooltip.Hide();
			_dirty = true;
		}

		private Vector2 ClampToCanvas(Vector2 pos, float width)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: 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_0020: 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_0041: 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)
			Vector2 val = Widgets.CanvasSize(_rect);
			return new Vector2(Mathf.Clamp(pos.x, 60f - width, Mathf.Max(60f - width, val.x - 60f)), Mathf.Clamp(pos.y, 0f - Mathf.Max(0f, val.y - 60f), 0f));
		}

		private void OnMovedByUser()
		{
			_positionSettleAt = Time.unscaledTime + 0.4f;
		}

		private void OnResizedByUser()
		{
			_positionSettleAt = Time.unscaledTime + 0.4f;
			_dirty = true;
		}

		private void PersistWhenSettled()
		{
			//IL_0015: 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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: 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_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: 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_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: 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)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: 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_00cf: 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_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_rect == (Object)null)
			{
				return;
			}
			Vector2 anchoredPosition = _rect.anchoredPosition;
			Vector2 sizeDelta = _rect.sizeDelta;
			if (anchoredPosition != _lastSeenPosition || sizeDelta != _lastSeenSize)
			{
				_lastSeenPosition = anchoredPosition;
				_lastSeenSize = sizeDelta;
				_positionSettleAt = Time.unscaledTime + 0.4f;
				if (sizeDelta != new Vector2(PluginConfig.WindowWidth.Value, PluginConfig.WindowHeight.Value))
				{
					_dirty = true;
				}
			}
			else
			{
				if (_positionSettleAt <= 0f || Time.unscaledTime < _positionSettleAt)
				{
					return;
				}
				_positionSettleAt = 0f;
				_suppressLayoutApply = true;
				try
				{
					if (anchoredPosition != PluginConfig.WindowPosition.Value)
					{
						PluginConfig.WindowPosition.Value = anchoredPosition;
					}
					if (sizeDelta.x != PluginConfig.WindowWidth.Value)
					{
						PluginConfig.WindowWidth.Value = sizeDelta.x;
					}
					if (sizeDelta.y != PluginConfig.WindowHeight.Value)
					{
						PluginConfig.WindowHeight.Value = sizeDelta.y;
					}
				}
				finally
				{
					_suppressLayoutApply = false;
				}
			}
		}

		public void Toggle()
		{
			SetOpen(!IsOpen);
		}

		public void SetHidden(bool hidden)
		{
			if (hidden != _hidden)
			{
				_hidden = hidden;
				if ((Object)(object)_root != (Object)null)
				{
					_root.SetActive(IsOpen && !hidden);
				}
				if (hidden)
				{
					_tooltip.Hide();
				}
			}
		}

		public void SetOpen(bool open)
		{
			IsOpen = open;
			if ((Object)(object)_root != (Object)null)
			{
				_root.SetActive(open && !_hidden);
			}
			if (!open)
			{
				_tooltip.Hide();
				_hovered = null;
			}
			else
			{
				_dirty = true;
			}
		}

		public void SetMode(MeterMode mode)
		{
			Mode = mode;
			Drill = null;
			Scroll = 0;
			_dirty = true;
		}

		public void CycleMode()
		{
			int num = Array.IndexOf(MeterView.Modes, Mode);
			SetMode(MeterView.Modes[(num + 1) % MeterView.Modes.Length]);
		}

		public void CycleSegment()
		{
			int count = _meter.Segments().Count;
			SegmentIndex = (SegmentIndex + 1) % count;
			Drill = null;
			Scroll = 0;
			_dirty = true;
		}

		public void Reset()
		{
			Recorder.Reset();
			SegmentIndex = 0;
			Drill = null;
			Scroll = 0;
			_dirty = true;
		}

		public void Back()
		{
			Drill = null;
			Scroll = 0;
			_dirty = true;
		}

		private void DrillInto(RowData row)
		{
			if (row.Clickable)
			{
				Drill = row.Key;
				Scroll = 0;
				_tooltip.Hide();
				_hovered = null;
				_dirty = true;
			}
		}

		private void OnScrolled(float delta)
		{
			if (delta > 0f && Scroll > 0)
			{
				Scroll--;
			}
			else if (delta < 0f)
			{
				Scroll++;
			}
			_dirty = true;
		}

		public Segment CurrentSegment()
		{
			List<Segment> list = _meter.Segments();
			if (SegmentIndex >= list.Count)
			{
				SegmentIndex = 0;
			}
			return list[SegmentIndex];
		}

		public void Report()
		{
			Segment segment = CurrentSegment();
			List<RowData> list = MeterView.Rows(Mode, segment, Drill, Time.time);
			int num = Mathf.Min(list.Count, PluginConfig.ReportLines.Value);
			List<string> list2 = new List<string>();
			string text = ((Drill != null) ? (Drill + " · " + MeterView.ModeName(Mode)) : MeterView.ModeName(Mode));
			list2.Add("Tally: " + text + " (" + MeterView.SegmentName(segment, _meter) + ")");
			for (int i = 0; i < num; i++)
			{
				RowData rowData = list[i];
				list2.Add(i + 1 + ". " + rowData.Label + " " + (rowData.Approximate ? "~" : "") + rowData.ValueText);
			}
			if (num == 0)
			{
				list2.Add("nothing recorded");
			}
			if (PluginConfig.ReportTo.Value == ReportTarget.Chat && (Object)(object)Chat.instance != (Object)null)
			{
				foreach (string item in list2)
				{
					Chat.instance.SendText((Type)1, item);
				}
				return;
			}
			foreach (string item2 in list2)
			{
				if ((Object)(object)Console.instance != (Object)null)
				{
					((Terminal)Console.instance).AddString(item2);
				}
				TallyPlugin.Log.LogInfo((object)item2);
			}
		}

		public void Render()
		{
			if (!((Object)(object)_root == (Object)null) && IsOpen)
			{
				PersistWhenSettled();
				if (_hovered != null)
				{
					_tooltip.Follow();
				}
				float time = Time.time;
				bool flag = Mode == MeterMode.Dps && _meter.InFight && time >= _nextTimedRebuild;
				if (_dirty || _meter.Revision != _builtRevision || flag)
				{
					_dirty = false;
					_builtRevision = _meter.Revision;
					_nextTimedRebuild = time + 0.5f;
					Rebuild();
				}
			}
		}

		private void Rebuild()
		{
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: 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_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_0262: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0332: Unknown result type (might be due to invalid IL or missing references)
			//IL_0361: Unknown result type (might be due to invalid IL or missing references)
			//IL_038a: Unknown result type (might be due to invalid IL or missing references)
			Segment segment = CurrentSegment();
			List<RowData> list = MeterView.Rows(Mode, segment, Drill, Time.time);
			StringBuilder stringBuilder = new StringBuilder(64);
			if (Drill != null)
			{
				stringBuilder.Append(Drill).Append("  <color=#BCAF97>·</color>  ").Append(MeterView.ModeName(Mode));
			}
			else
			{
				stringBuilder.Append(MeterView.ModeName(Mode)).Append("  <color=#BCAF97>·  ").Append((Mode == MeterMode.Records) ? "all time" : MeterView.SegmentName(segment, _meter))
					.Append("</color>");
			}
			((TMP_Text)_title).text = stringBuilder.ToString();
			((Component)_back).gameObject.SetActive(Drill != null);
			Widgets.Rect(((Component)_title).gameObject).offsetMin = new Vector2((Drill != null) ? 22f : 6f, 0f);
			float value = PluginConfig.RowHeight.Value;
			float num = value + 2f;
			float num2 = _rect.sizeDelta.y - 22f - 8f;
			float width = _rect.sizeDelta.x - 8f;
			int num3 = Mathf.Max(0, Mathf.FloorToInt((num2 + 2f) / num));
			int num4 = Mathf.Max(0, list.Count - num3);
			if (Scroll > num4)
			{
				Scroll = num4;
			}
			float num5 = ((list.Count > 0) ? list[0].Value : 0f);
			float value2 = PluginConfig.BarOpacity.Value;
			float fontSize = PluginConfig.FontSize.Value;
			int num6 = 0;
			int num7 = Scroll;
			while (num7 < list.Count && num6 < num3)
			{
				Row row = ((num6 < _rows.Count) ? _rows[num6] : AddRow());
				RowData rowData = (row.Data = list[num7]);
				row.Go.SetActive(true);
				Widgets.TopLeft(row.Rect, 0f, (float)num6 * num, width, value);
				float num8 = ((num5 > 0f) ? Mathf.Clamp01(rowData.Value / num5) : 0f);
				Color color = rowData.Color;
				color.a = value2;
				((Graphic)row.Bar).color = color;
				RectTransform obj = Widgets.Rect(((Component)row.Bar).gameObject);
				obj.anchorMin = Vector2.zero;
				obj.anchorMax = new Vector2(num8, 1f);
				obj.offsetMin = Vector2.zero;
				obj.offsetMax = Vector2.zero;
				((TMP_Text)row.Left).fontSize = fontSize;
				((TMP_Text)row.Right).fontSize = fontSize;
				((TMP_Text)row.Left).text = num7 + 1 + ". " + rowData.Label;
				((TMP_Text)row.Right).text = (rowData.Approximate ? "~" : "") + rowData.ValueText;
				float num9 = Mathf.Ceil(((TMP_Text)row.Right).GetPreferredValues(((TMP_Text)row.Right).text).x) + 6f;
				Widgets.Rect(((Component)row.Right).gameObject).sizeDelta = new Vector2(num9, 0f);
				Widgets.Rect(((Component)row.Left).gameObject).offsetMax = new Vector2(0f - num9 - 4f, 0f);
				num7++;
				num6++;
			}
			for (int i = num6; i < _rows.Count; i++)
			{
				_rows[i].Go.SetActive(false);
				_rows[i].Data = null;
			}
			if (_hovered != null && (_hovered.Data == null || !_hovered.Go.activeSelf))
			{
				_hovered = null;
				_tooltip.Hide();
			}
			else if (_hovered != null)
			{
				_tooltip.Show(_hovered.Data.Tooltip(), fontSize);
			}
		}

		private Row AddRow()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: 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)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			Row row = new Row();
			row.Go = Widgets.Panel((Transform)(object)_body, "Row", Widgets.BarTrack, raycast: true);
			row.Rect = Widgets.Rect(row.Go);
			row.Handler = row.Go.AddComponent<RowHandler>();
			row.Handler.OnEnter = delegate
			{
				OnRowEnter(row);
			};
			row.Handler.OnExit = delegate
			{
				OnRowExit(row);
			};
			row.Handler.OnClick = delegate
			{
				if (row.Data != null)
				{
					DrillInto(row.Data);
				}
			};
			row.Bar = Widgets.Panel(row.Go.transform, "Bar", Color.white, raycast: false).GetComponent<Image>();
			row.Left = Widgets.Label(row.Go.transform, "Name", PluginConfig.FontSize.Value, Widgets.Text, (TextAlignmentOptions)4097);
			RectTransform obj = Widgets.Rect(((Component)row.Left).gameObject);
			obj.anchorMin = Vector2.zero;
			obj.anchorMax = Vector2.one;
			obj.offsetMin = new Vector2(4f, 0f);
			obj.offsetMax = new Vector2(-4f, 0f);
			row.Right = Widgets.Label(row.Go.transform, "Value", PluginConfig.FontSize.Value, Widgets.Text, (TextAlignmentOptions)4100);
			RectTransform obj2 = Widgets.Rect(((Component)row.Right).gameObject);
			obj2.anchorMin = new Vector2(1f, 0f);
			obj2.anchorMax = new Vector2(1f, 1f);
			obj2.pivot = new Vector2(1f, 0.5f);
			obj2.anchoredPosition = new Vector2(-4f, 0f);
			obj2.sizeDelta = new Vector2(80f, 0f);
			_rows.Add(row);
			return row;
		}

		private void OnRowEnter(Row row)
		{
			if (row.Data != null)
			{
				_hovered = row;
				_tooltip.Show(row.Data.Tooltip(), PluginConfig.FontSize.Value);
			}
		}

		private void OnRowExit(Row row)
		{
			if (_hovered == row)
			{
				_hovered = null;
				_tooltip.Hide();
			}
		}
	}
	public sealed class RecordBanner
	{
		private const float FadeSeconds = 0.8f;

		private GameObject _root;

		private CanvasGroup _group;

		private TextMeshProUGUI _title;

		private TextMeshProUGUI _sub;

		private float _holdUntil;

		private float _fadeUntil;

		public bool Created => (Object)(object)_root != (Object)null;

		public void Create(Transform parent)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			//IL_0067: 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_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: 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_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: 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_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_root != (Object)null))
			{
				_root = new GameObject("TallyBanner", new Type[2]
				{
					typeof(RectTransform),
					typeof(CanvasGroup)
				});
				_root.transform.SetParent(parent, false);
				RectTransform obj = Widgets.Rect(_root);
				obj.anchorMin = new Vector2(0.5f, 0.72f);
				obj.anchorMax = new Vector2(0.5f, 0.72f);
				obj.pivot = new Vector2(0.5f, 0.5f);
				obj.anchoredPosition = Vector2.zero;
				obj.sizeDelta = new Vector2(1200f, 110f);
				_group = _root.GetComponent<CanvasGroup>();
				_group.alpha = 0f;
				_group.blocksRaycasts = false;
				_group.interactable = false;
				_title = Widgets.Label(_root.transform, "Title", 36f, Widgets.Orange, (TextAlignmentOptions)514);
				RectTransform obj2 = Widgets.Rect(((Component)_title).gameObject);
				obj2.anchorMin = new Vector2(0f, 0.45f);
				obj2.anchorMax = new Vector2(1f, 1f);
				obj2.offsetMin = Vector2.zero;
				obj2.offsetMax = Vector2.zero;
				((TMP_Text)_title).fontStyle = (FontStyles)1;
				_sub = Widgets.Label(_root.transform, "Sub", 20f, Widgets.Text, (TextAlignmentOptions)514);
				RectTransform obj3 = Widgets.Rect(((Component)_sub).gameObject);
				obj3.anchorMin = new Vector2(0f, 0f);
				obj3.anchorMax = new Vector2(1f, 0.45f);
				obj3.offsetMin = Vector2.zero;
				obj3.offsetMax = Vector2.zero;
				_root.SetActive(false);
			}
		}

		public void Destroy()
		{
			if ((Object)(object)_root != (Object)null)
			{
				Object.Destroy((Object)(object)_root);
			}
			_root = null;
			_group = null;
		}

		public void Show(string title, string sub, float seconds)
		{
			if (!((Object)(object)_root == (Object)null))
			{
				((TMP_Text)_title).text = title;
				((TMP_Text)_sub).text = sub;
				_group.alpha = 1f;
				_root.SetActive(true);
				_root.transform.SetAsLastSibling();
				_holdUntil = Time.unscaledTime + seconds;
				_fadeUntil = _holdUntil + 0.8f;
			}
		}

		public void Update()
		{
			if ((Object)(object)_root == (Object)null || !_root.activeSelf)
			{
				return;
			}
			float unscaledTime = Time.unscaledTime;
			if (!(unscaledTime < _holdUntil))
			{
				if (unscaledTime >= _fadeUntil)
				{
					_root.SetActive(false);
				}
				else
				{
					_group.alpha = 1f - (unscaledTime - _holdUntil) / 0.8f;
				}
			}
		}
	}
	public sealed class Tooltip
	{
		private const float Padding = 8f;

		private const float MaxWidth = 340f;

		private GameObject _root;

		private RectTransform _rect;

		private TextMeshProUGUI _text;

		private Image _bg;

		public bool Visible
		{
			get
			{
				if ((Object)(object)_root != (Object)null)
				{
					return _root.activeSelf;
				}
				return false;
			}
		}

		public void Create(Transform parent)
		{
			//IL_002a: 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_00a6: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_root != (Object)null))
			{
				_root = Widgets.Panel(parent, "TallyTooltip", new Color(0.03f, 0.025f, 0.02f, 0.92f), raycast: false);
				_rect = Widgets.Rect(_root);
				Widgets.TopLeft(_rect, 0f, 0f, 200f, 50f);
				_bg = _root.GetComponent<Image>();
				Widgets.AddBorder(_root.transform, Widgets.Border);
				_text = Widgets.Label(_root.transform, "Text", 13f, Widgets.Text, (TextAlignmentOptions)257);
				((TMP_Text)_text).textWrappingMode = (TextWrappingModes)1;
				((TMP_Text)_text).overflowMode = (TextOverflowModes)0;
				Widgets.TopLeft(Widgets.Rect(((Component)_text).gameObject), 8f, 8f, 324f, 0f);
				_root.SetActive(false);
			}
		}

		public void Destroy()
		{
			if ((Object)(object)_root != (Object)null)
			{
				Object.Destroy((Object)(object)_root);
			}
			_root = null;
			_rect = null;
			_text = null;
		}

		public void Show(string text, float fontSize)
		{
			//IL_0038: 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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: 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)
			if (!((Object)(object)_root == (Object)null))
			{
				((TMP_Text)_text).fontSize = fontSize;
				((TMP_Text)_text).text = text;
				Vector2 preferredValues = ((TMP_Text)_text).GetPreferredValues(text, 324f, 0f);
				float num = Mathf.Min(340f, preferredValues.x + 16f + 2f);
				float num2 = preferredValues.y + 16f + 2f;
				Widgets.Rect(((Component)_text).gameObject).sizeDelta = new Vector2(num - 16f, num2 - 16f);
				_rect.sizeDelta = new Vector2(num, num2);
				_root.SetActive(true);
				_root.transform.SetAsLastSibling();
				Follow();
			}
		}

		public void Hide()
		{
			if ((Object)(object)_root != (Object)null)
			{
				_root.SetActive(false);
			}
		}

		public void Follow()
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: 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_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: 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_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: 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_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: 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_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			if (Visible)
			{
				Vector2 val = Widgets.MouseInCanvas(_rect);
				Vector2 val2 = Widgets.CanvasSize(_rect);
				Vector2 sizeDelta = _rect.sizeDelta;
				float num = val.x + 16f;
				float num2 = val.y + 20f;
				if (num + sizeDelta.x > val2.x - 4f)
				{
					num = val.x - sizeDelta.x - 8f;
				}
				if (num2 + sizeDelta.y > val2.y - 4f)
				{
					num2 = val.y - sizeDelta.y - 8f;
				}
				num = Mathf.Max(4f, num);
				num2 = Mathf.Max(4f, num2);
				_rect.anchoredPosition = new Vector2(num, 0f - num2);
			}
		}
	}
	public static class Widgets
	{
		public static readonly Color Text = Color32.op_Implicit(new Color32((byte)242, (byte)233, (byte)216, byte.MaxValue));

		public static readonly Color Dim = Color32.op_Implicit(new Color32((byte)188, (byte)175, (byte)151, byte.MaxValue));

		public static readonly Color Border = new Color(0.62f, 0.52f, 0.36f, 0.75f);

		public static readonly Color Background = new Color(0.03f, 0.025f, 0.02f, 1f);

		public static readonly Color TitleBackground = new Color(0.12f, 0.09f, 0.06f, 0.55f);

		public static readonly Color BarTrack = new Color(1f, 1f, 1f, 0.05f);

		public static Color Orange => GUIManager.Instance.ValheimOrange;

		public static TMP_FontAsset Font => Fonts.Current;

		public static RectTransform Rect(GameObject go)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			return (RectTransform)go.transform;
		}

		public static GameObject Panel(Transform parent, string name, Color color, bool raycast)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			GameObject val = new GameObject(name, new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			val.transform.SetParent(parent, false);
			Image component = val.GetComponent<Image>();
			((Graphic)component).color = color;
			((Graphic)component).raycastTarget = raycast;
			return val;
		}

		public static void Stretch(RectTransform r, float left = 0f, float top = 0f, float right = 0f, float bottom = 0f)
		{
			//IL_0001: 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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			r.anchorMin = Vector2.zero;
			r.anchorMax = Vector2.one;
			r.pivot = new Vector2(0.5f, 0.5f);
			r.offsetMin = new Vector2(left, bottom);
			r.offsetMax = new Vector2(0f - right, 0f - top);
		}

		public static void TopLeft(RectTransform r, float x, float y, float width, float height)
		{
			//IL_000b: 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_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: 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)
			r.anchorMin = new Vector2(0f, 1f);
			r.anchorMax = new Vector2(0f, 1f);
			r.pivot = new Vector2(0f, 1f);
			r.anchoredPosition = new Vector2(x, 0f - y);
			r.sizeDelta = new Vector2(width, height);
		}

		public static void TopRight(RectTransform r, float x, float y, float width, float height)
		{
			//IL_000b: 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_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			r.anchorMin = new Vector2(1f, 1f);
			r.anchorMax = new Vector2(1f, 1f);
			r.pivot = new Vector2(1f, 1f);
			r.anchoredPosition = new Vector2(0f - x, 0f - y);
			r.sizeDelta = new Vector2(width, height);
		}

		public static void AddBorder(Transform parent, Color color)
		{
			//IL_0001: 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_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: 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)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: 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_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: 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_00b7: 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_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			Edge(parent, color, new Vector2(0f, 1f), new Vector2(1f, 1f), new Vector2(0f, -1f), Vector2.zero);
			Edge(parent, color, new Vector2(0f, 0f), new Vector2(1f, 0f), Vector2.zero, new Vector2(0f, 1f));
			Edge(parent, color, new Vector2(0f, 0f), new Vector2(0f, 1f), Vector2.zero, new Vector2(1f, 0f));
			Edge(parent, color, new Vector2(1f, 0f), new Vector2(1f, 1f), new Vector2(-1f, 0f), Vector2.zero);
		}

		private static void Edge(Transform parent, Color color, Vector2 anchorMin, Vector2 anchorMax, Vector2 offsetMin, Vector2 offsetMax)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: 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_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			RectTransform obj = Rect(Panel(parent, "Edge", color, raycast: false));
			obj.anchorMin = anchorMin;
			obj.anchorMax = anchorMax;
			obj.offsetMin = offsetMin;
			obj.offsetMax = offsetMax;
		}

		public static TextMeshProUGUI Label(Transform parent, string name, float size, Color color, TextAlignmentOptions align)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[2]
			{
				typeof(RectTransform),
				typeof(TextMeshProUGUI)
			});
			val.transform.SetParent(parent, false);
			TextMeshProUGUI component = val.GetComponent<TextMeshProUGUI>();
			((TMP_Text)component).font = Font;
			if (PluginConfig.TextOutline.Value)
			{
				Fonts.ApplyOutline((TMP_Text)(object)component);
			}
			((TMP_Text)component).fontSize = size;
			((Graphic)component).color = color;
			((TMP_Text)component).alignment = align;
			((Graphic)component).raycastTarget = false;
			((TMP_Text)component).richText = true;
			((TMP_Text)component).textWrappingMode = (TextWrappingModes)0;
			((TMP_Text)component).overflowMode = (TextOverflowModes)3;
			((TMP_Text)component).text = "";
			return component;
		}

		public static Button TextButton(Transform parent, string name, string text, float fontSize, Action onClick, out TextMeshProUGUI label)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: 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_00a6: 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_00e6: 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_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Expected O, but got Unknown
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = Panel(parent, name, new Color(1f, 1f, 1f, 0f), raycast: true);
			Button obj = val.AddComponent<Button>();
			((Selectable)obj).targetGraphic = (Graphic)(object)val.GetComponent<Image>();
			((Selectable)obj).transition = (Transition)1;
			ColorBlock colors = ((Selectable)obj).colors;
			((ColorBlock)(ref colors)).normalColor = new Color(1f, 1f, 1f, 0f);
			((ColorBlock)(ref colors)).highlightedColor = new Color(1f, 1f, 1f, 0.16f);
			((ColorBlock)(ref colors)).pressedColor = new Color(1f, 1f, 1f, 0.32f);
			((ColorBlock)(ref colors)).selectedColor = new Color(1f, 1f, 1f, 0f);
			((ColorBlock)(ref colors)).disabledColor = new Color(1f, 1f, 1f, 0f);
			((ColorBlock)(ref colors)).colorMultiplier = 1f;
			((ColorBlock)(ref colors)).fadeDuration = 0.05f;
			((Selectable)obj).colors = colors;
			Navigation navigation = default(Navigation);
			((Navigation)(ref navigation)).mode = (Mode)0;
			((Selectable)obj).navigation = navigation;
			((UnityEvent)obj.onClick).AddListener((UnityAction)delegate
			{
				onClick();
			});
			label = Label(val.transform, "Text", fontSize, Text, (TextAlignmentOptions)514);
			Stretch(Rect(((Component)label).gameObject));
			((TMP_Text)label).text = text;
			return obj;
		}

		public static float CanvasScale(Component c)
		{
			Canvas componentInParent = c.GetComponentInParent<Canvas>();
			if ((Object)(object)componentInParent == (Object)null)
			{
				return 1f;
			}
			float scaleFactor = componentInParent.rootCanvas.scaleFactor;
			if (!(scaleFactor > 0.01f))
			{
				return 1f;
			}
			return scaleFactor;
		}

		public static Vector2 CanvasSize(RectTransform any)
		{
			//IL_001e: 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_002e: 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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: 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_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)
			Canvas componentInParent = ((Component)any).GetComponentInParent<Canvas>();
			RectTransform val = ((!((Object)(object)componentInParent != (Object)null)) ? ((RectTransform)null) : ((RectTransform)((Component)componentInParent.rootCanvas).transform));
			if ((Object)(object)val != (Object)null)
			{
				Rect rect = val.rect;
				if (((Rect)(ref rect)).width > 1f)
				{
					rect = val.rect;
					if (((Rect)(ref rect)).height > 1f)
					{
						rect = val.rect;
						float width = ((Rect)(ref rect)).width;
						rect = val.rect;
						return new Vector2(width, ((Rect)(ref rect)).height);
					}
				}
			}
			return new Vector2((float)Screen.width, (float)Screen.height);
		}

		public static Vector2 MouseInCanvas(RectTransform any)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: 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_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			float num = CanvasScale((Component)(object)any);
			Vector2 val = CanvasSize(any);
			Vector3 mousePosition = Input.mousePosition;
			return new Vector2(mousePosition.x / num, val.y - mousePosition.y / num);
		}
	}
	public sealed class WindowDrag : MonoBehaviour, IBeginDragHandler, IEventSystemHandler, IDragHandler, IEndDragHandler
	{
		public RectTransform Window;

		public Action OnMoved;

		public void OnBeginDrag(PointerEventData eventData)
		{
		}

		public void OnDrag(PointerEventData eventData)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: 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)
			if (!((Object)(object)Window == (Object)null))
			{
				float num = Widgets.CanvasScale((Component)(object)Window);
				RectTransform window = Window;
				window.anchoredPosition += eventData.delta / num;
			}
		}

		public void OnEndDrag(PointerEventData eventData)
		{
			if (OnMoved != null)
			{
				OnMoved();
			}
		}
	}
	public sealed class ResizeHandle : MonoBehaviour, IBeginDragHandler, IEventSystemHandler, IDragHandler, IEndDragHandler
	{
		public RectTransform Window;

		public Vector2 MinSize = new Vector2(180f, 80f);

		public Action OnResized;

		public void OnBeginDrag(PointerEventData eventData)
		{
		}

		public void OnDrag(PointerEventData eventData)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: 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_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: 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_008c: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)Window == (Object)null))
			{
				float num = Widgets.CanvasScale((Component)(object)Window);
				Vector2 val = Window.sizeDelta + new Vector2(eventData.delta.x / num, (0f - eventData.delta.y) / num);
				val.x = Mathf.Max(MinSize.x, val.x);
				val.y = Mathf.Max(MinSize.y, val.y);
				Window.sizeDelta = val;
			}
		}

		public void OnEndDrag(PointerEventData eventData)
		{
			if (OnResized != null)
			{
				OnResized();
			}
		}
	}
	public sealed class ScrollRelay : MonoBehaviour, IScrollHandler, IEventSystemHandler
	{
		public Action<float> OnScrolled;

		public void OnScroll(PointerEventData eventData)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (OnScrolled != null)
			{
				OnScrolled(eventData.scrollDelta.y);
			}
		}
	}
	public sealed class RowHandler : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler, IPointerClickHandler
	{
		public Action OnEnter;

		public Action OnExit;

		public Action OnClick;

		public void OnPointerEnter(PointerEventData eventData)
		{
			if (OnEnter != null)
			{
				OnEnter();
			}
		}

		public void OnPointerExit(PointerEventData eventData)
		{
			if (OnExit != null)
			{
				OnExit();
			}
		}

		public void OnPointerClick(PointerEventData eventData)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			if ((int)eventData.button == 0 && OnClick != null)
			{
				OnClick();
			}
		}
	}
}
namespace Tally.Patches
{
	internal static class Guard
	{
		private static int _errors;

		public static void Fail(string where, Exception ex)
		{
			if (_errors++ < 5)
			{
				TallyPlugin.Log.LogWarning((object)(where + " threw: " + ex));
			}
		}
	}
	[HarmonyPatch(typeof(Character), "RPC_Damage")]
	internal static class Character_RPC_Damage_Patch
	{
		private static void Prefix(Character __instance, HitData hit)
		{
			try
			{
				ZNetView nview = __instance.m_nview;
				if (hit != null && !((Object)(object)nview == (Object)null) && nview.IsValid() && nview.IsOwner())
				{
					Attribution.OnEffectApplied(__instance, hit);
				}
			}
			catch (Exception ex)
			{
				Guard.Fail("RPC_Damage prefix", ex);
			}
		}
	}
	[HarmonyPatch(typeof(Character), "ApplyDamage")]
	internal static class Character_ApplyDamage_Patch
	{
		private static void Prefix(Character __instance, HitData hit, out bool __state)
		{
			__state = false;
			try
			{
				ZNetView nview = __instance.m_nview;
				if (hit != null && !((Object)(object)nview == (Object)null) && nview.IsValid() && nview.IsOwner() && !__instance.IsDebugFlying() && !__instance.IsDead() && !__instance.IsTeleporting() && !__instance.InCutscene() && !CinematicsManager.IsPlaying())
				{
					__state = true;
				}
			}
			catch (Exception ex)
			{
				Guard.Fail("ApplyDamage prefix", ex);
			}
		}

		private static void Postfix(Character __instance, HitData hit, bool __state)
		{
			if (!__state)
			{
				return;
			}
			try
			{
				float totalDamage = hit.GetTotalDamage();
				if (!(totalDamage <= 0.1f))
				{
					bool backstab = hit.m_backstabBonus > 1f && __instance.m_backstabTime == Time.time;
					Attribution.OnCharacterDamaged(__instance, hit, totalDamage, backstab);
				}
			}
			catch (Exception ex)
			{
				Guard.Fail("ApplyDamage postfix", ex);
			}
		}
	}
	[HarmonyPatch(typeof(Character), "RPC_Heal")]
	internal static class Character_RPC_Heal_Patch
	{
		private static void Prefix(Character __instance, float hp)
		{
			try
			{
				if (hp <= 0f || !__instance.IsPlayer())
				{
					return;
				}
				ZNetView nview = __instance.m_nview;
				if ((Object)(object)nview == (Object)null || !nview.IsValid() || !nview.IsOwner())
				{
					return;
				}
				float health = __instance.GetHealth();
				if (!(health <= 0f) && !__instance.IsDead())
				{
					float maxHealth = __instance.GetMaxHealth();
					float num = Mathf.Min(health + hp, maxHealth) - health;
					if (num < 0f)
					{
						num = 0f;
					}
					float overheal = hp - num;
					Attribution.OnHealed(__instance, num, overheal);
				}
			}
			catch (Exception ex)
			{
				Guard.Fail("RPC_Heal prefix", ex);
			}
		}
	}
	[HarmonyPatch(typeof(Player), "UpdateFood")]
	internal static class Player_UpdateFood_Patch
	{
		private static void Prefix()
		{
			HealContext.Current = "Food";
		}

		private static void Postfix()
		{
			HealContext.Current = null;
		}
	}
	[HarmonyPatch(typeof(SE_Stats), "UpdateStatusEffect")]
	internal static class SE_Stats_UpdateStatusEffect_Patch
	{
		private static readonly Dictionary<int, string> _names = new Dictionary<int, string>();

		internal static void Prefix(SE_Stats __instance)
		{
			try
			{
				int key = ((StatusEffect)__instance).NameHash();
				if (!_names.TryGetValue(key, out var value))
				{
					value = Names.StatusEffect((StatusEffect)(object)__instance);
					_names[key] = value;
				}
				HealContext.Current = value;
			}
			catch (Exception ex)
			{
				Guard.Fail("SE_Stats prefix", ex);
			}
		}

		private static void Postfix()
		{
			HealContext.Current = null;
		}
	}
	[HarmonyPatch(typeof(SE_Stats), "Setup")]
	internal static class SE_Stats_Setup_Patch
	{
		private static void Prefix(SE_Stats __instance)
		{
			SE_Stats_UpdateStatusEffect_Patch.Prefix(__instance);
		}

		private static void Postfix()
		{
			HealContext.Current = null;
		}
	}
	[HarmonyPatch(typeof(Character), "Damage")]
	internal static class Character_Damage_Patch
	{
		private static void Prefix(Character __instance, HitData hit)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null || hit == null)
				{
					return;
				}
				ZNetView nview = __instance.m_nview;
				if (!((Object)(object)nview == (Object)null) && nview.IsValid() && !nview.IsOwner() && !(hit.m_attacker != ((Character)localPlayer).GetZDOID()) && (!__instance.IsPlayer() || hit.m_ignorePVP || (__instance.IsPVPEnabled() && ((Character)localPlayer).IsPVPEnabled())) && !EventSync.PeerHasMod(nview.GetZDO().GetOwner()))
				{
					float totalDamage = hit.GetTotalDamage();
					if (!(totalDamage <= 0f))
					{
						Attribution.OnApproximateHit(__instance, hit, totalDamage);
					}
				}
			}
			catch (Exception ex)
			{
				Guard.Fail("Damage prefix", ex);
			}
		}
	}
	internal static class ObjectHits
	{
		public static bool Alive(ZNetView nview, float health)
		{
			if (PluginConfig.IncludeStructures.Value && (Object)(object)nview != (Object)null && nview.IsValid() && nview.IsOwner())
			{
				return health > 0f;
			}
			return false;
		}

		public static void Report(Component target, ZNetView nview, HitData hit, int minToolTier, bool allowTierZero, string name)
		{
			try
			{
				if (PluginConfig.IncludeStructures.Value && hit != null && !((Object)(object)nview == (Object)null) && nview.IsValid() && nview.IsOwner())
				{
					float totalDamage = hit.GetTotalDamage();
					if (!(totalDamage <= 0f) && hit.CheckToolTier(minToolTier, allowTierZero))
					{
						Attribution.OnObjectDamaged(target, hit, totalDamage, name);
					}
				}
			}
			catch (Exception ex)
			{
				Guard.Fail("object hit", ex);
			}
		}

		public static string PrefabName(Component c)
		{
			return Names.Prettify(Utils.GetPrefabName(c.gameObject));
		}
	}
	[HarmonyPatch(typeof(WearNTear), "RPC_Damage")]
	internal static class WearNTear_RPC_Damage_Patch
	{
		private static void Prefix(WearNTear __instance, out bool __state)
		{
			ZNetView nview = __instance.m_nview;
			__state = ObjectHits.Alive(nview, ((Object)(object)nview != (Object)null && nview.IsValid()) ? nview.GetZDO().GetFloat(ZDOVars.s_health, __instance.m_health) : 0f);
		}

		private static void Postfix(WearNTear __instance, HitData hit, bool __state)
		{
			if (__state)
			{
				string name = (((Object)(object)__instance.m_piece != (Object)null && !string.IsNullOrEmpty(__instance.m_piece.m_name)) ? Names.Localize(__instance.m_piece.m_name) : ObjectHits.PrefabName((Component)(object)__instance));
				ObjectHits.Report((Component)(object)__instance, __instance.m_nview, hit, __instance.m_minToolTier, allowTierZero: true, name);
			}
		}
	}
	[HarmonyPatch(typeof(Destructible), "RPC_Damage")]
	internal static class Destructible_RPC_Damage_Patch
	{
		private static void Prefix(Destructible __instance, out bool __state)
		{
			ZNetView nview = __instance.m_nview;
			__state = !__instance.m_destroyed && ObjectHits.Alive(nview, ((Object)(object)nview != (Object)null && nview.IsValid()) ? nview.GetZDO().GetFloat(ZDOVars.s_health, __instance.m_health) : 0f);
		}

		private static void Postfix(Destructible __instance, HitData hit, bool __state)
		{
			if (__state)
			{
				ObjectHits.Report((Component)(object)__instance, __instance.m_nview, hit, __instance.m_minToolTier, allowTierZero: false, ObjectHits.PrefabName((Component)(object)__instance));
			}
		}
	}
	[HarmonyPatch(typeof(TreeBase), "RPC_Damage")]
	internal static class TreeBase_RPC_Damage_Patch
	{
		private static void Prefix(TreeBase __instance, out bool __state)
		{
			ZNetView nview = __instance.m_nview;
			__state = ObjectHits.Alive(nview, ((Object)(object)nview != (Object)null && nview.IsValid()) ? nview.GetZDO().GetFloat(ZDOVars.s_health, __instance.m_health) : 0f);
		}

		private static void Postfix(TreeBase __instance, HitData hit, bool __state)
		{
			if (__state)
			{
				ObjectHits.Report((Component)(object)__instance, __instance.m_nview, hit, __instance.m_minToolTier, allowTierZero: true, ObjectHits.PrefabName((Component)(object)__instance));
			}
		}
	}
	[HarmonyPatch(typeof(TreeLog), "RPC_Damage")]
	internal static class TreeLog_RPC_Damage_Patch
	{
		private static void Prefix(TreeLog __instance, out bool __state)
		{
			ZNetView nview = __instance.m_nview;
			__state = ObjectHits.Alive(nview, ((Object)(object)nview != (Object)null && nview.IsValid()) ? nview.GetZDO().GetFloat(ZDOVars.s_health, 0f) : 0f);
		}

		private static void Postfix(TreeLog __instance, HitData hit, bool __state)
		{
			if (__state)
			{
				ObjectHits.Report((Component)(object)__instance, __instance.m_nview, hit, __instance.m_minToolTier, allowTierZero: true, ObjectHits.PrefabName((Component)(object)__instance));
			}
		}
	}
	[HarmonyPatch(typeof(MineRock), "RPC_Hit")]
	internal static class MineRock_RPC_Hit_Patch
	{
		private static void Prefix(MineRock __instance, int hitAreaIndex, out bool __state)
		{
			ZNetView nview = __instance.m_nview;
			float health = (((Object)(object)nview != (Object)null && nview.IsValid()) ? nview.GetZDO().GetFloat("Health" + hitAreaIndex, __instance.GetHealth()) : 0f);
			__state = ObjectHits.Alive(nview, health);
		}

		private static void Postfix(MineRock __instance, HitData hit, bool __state)
		{
			if (__state)
			{
				ObjectHits.Report((Component)(object)__instance, __instance.m_nview, hit, __instance.m_minToolTier, allowTierZero: false, ObjectHits.PrefabName((Component)(object)__instance));
			}
		}
	}
	[HarmonyPatch(typeof(MineRock5), "RPC_Damage")]
	internal static class MineRock5_RPC_Damage_Patch
	{
		private static void Prefix(MineRock5 __instance, int hitAreaIndex, out bool __state)
		{
			__state = false;
			try
			{
				ZNetView nview = __instance.m_nview;
				if (!((Object)(object)nview == (Object)null) && nview.IsValid() && nview.IsOwner() && PluginConfig.IncludeStructures.Value)
				{
					__instance.LoadHealth();
					HitArea hitArea = __instance.GetHitArea(hitAreaIndex);
					__state = hitArea != null && hitArea.m_health > 0f;
				}
			}
			catch (Exception ex)
			{
				Guard.Fail("MineRock5 prefix", ex);
			}
		}

		private static void Postfix(MineRock5 __instance, HitData hit, bool __state)
		{
			if (__state)
			{
				ObjectHits.Report((Component)(object)__instance, __instance.m_nview, hit, __instance.m_minToolTier, allowTierZero: false, ObjectHits.PrefabName((Component)(object)__instance));
			}
		}
	}
}
namespace Tally.Net
{
	public static class EventSync
	{
		public sealed class PeerState
		{
			public long Uid;

			public uint Nonce;

			public uint LastSeq;

			public float LastSeen;

			public string Name = "";

			public string Version = "";
		}

		private const byte Protocol = 1;

		private const string EventsRpc = "Tally_Events";

		private const string HelloRpc = "Tally_Hello";

		private const float HelloInterval = 30f;

		private const float PeerTtl = 90f;

		private const int MaxEventsPerPacket = 80;

		private static readonly uint _nonce = (uint)new Random().Next(1, int.MaxValue);

		private static uint _nextSeq = 1u;

		private static ZRoutedRpc _registeredOn;

		private static readonly List<CombatEvent> _outgoing = new List<CombatEvent>();

		private static readonly Dictionary<long, PeerState> _peers = new Dictionary<long, PeerState>();

		private static float _nextFlush;

		private static float _nextHello;

		public static int PacketsSent;

		public static int PacketsReceived;

		public static int EventsSent;

		public static int EventsReceived;

		public static int EventsDropped;

		public static bool Registered => _registeredOn != null;

		public static uint Nonce => _nonce;

		public static void Update(float now)
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance == null)
			{
				_registeredOn = null;
				return;
			}
			if (instance != _registeredOn)
			{
				Register(instance);
			}
			if (!((Object)(object)Player.m_localPlayer == (Object)null))
			{
				if (now >= _nextHello)
				{
					_nextHello = now + 30f;
					SendHello(0L);
				}
				if (now >= _nextFlush)
				{
					_nextFlush = now + Mathf.Max(0.1f, PluginConfig.FlushInterval.Value);
					Flush();
				}
			}
		}

		private static void Register(ZRoutedRpc rpc)
		{
			try
			{
				rpc.Register<ZPackage>("Tally_Events", (Action<long, ZPackage>)OnEvents);
				rpc.Register<ZPackage>("Tally_Hello", (Action<long, ZPackage>)OnHello);
			}
			catch (ArgumentException)
			{
			}
			_registeredOn = rpc;
			_peers.Clear();
			_outgoing.Clear();
			_nextHello = 0f;
			if (PluginConfig.Verbose.Value)
			{
				ManualLogSource log = TallyPlugin.Log;
				uint nonce = _nonce;
				log.LogDebug((object)("routed RPC handlers registered, nonce " + nonce));
			}
		}

		public static void Clear()
		{
			_outgoing.Clear();
			_peers.Clear();
			_nextHello = 0f;
		}

		public static bool PeerHasMod(long uid)
		{
			if (!PluginConfig.ShareEnabled.Value)
			{
				return false;
			}
			if (_peers.TryGetValue(uid, out var value))
			{
				return Time.time - value.LastSeen < 90f;
			}
			return false;
		}

		public static List<PeerState> Peers()
		{
			List<PeerState> list = new List<PeerState>();
			float time = Time.time;
			foreach (PeerState value in _peers.Values)
			{
				if (time - value.LastSeen < 90f)
				{
					list.Add(value);
				}
			}
			return list;
		}

		private static void SendHello(long target)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			if (PluginConfig.ShareEnabled.Value && ZRoutedRpc.instance != null)
			{
				ZPackage val = new ZPackage();
				val.Write((byte)1);
				val.Write(_nonce);
				val.Write("1.0.0");
				val.Write(Recorder.LocalPlayerName ?? "");
				ZRoutedRpc.instance.InvokeRoutedRPC(target, "Tally_Hello", new object[1] { val });
			}
		}

		private s