Decompiled source of Bizare Score HUD v1.0.1

BepInEx/plugins/BizareScoreHUD/BizareScoreHUD.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using BizareScoreHUD.Compatibility;
using BizareScoreHUD.Domain;
using BizareScoreHUD.Networking;
using BizareScoreHUD.Patches;
using BizareScoreHUD.Persistence;
using BizareScoreHUD.Tracking;
using BizareScoreHUD.UI;
using HarmonyLib;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;
using Valheim.SettingsGui;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("BizareScoreHUD")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Score HUD for the Bizare Valheim modpack.")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1+239dbd73cb87f90f4fab1f6ff6b95a7a8ea3bcf5")]
[assembly: AssemblyProduct("BizareScoreHUD")]
[assembly: AssemblyTitle("BizareScoreHUD")]
[assembly: AssemblyVersion("1.0.1.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace BizareScoreHUD
{
	[BepInPlugin("com.igentuman.bizarehud", "Score HUD for Bizare", "1.0.1")]
	[BepInDependency("com.jotunn.jotunn", "2.30.2")]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.igentuman.bizarehud";

		public const string PluginName = "Score HUD for Bizare";

		public const string PluginVersion = "1.0.1";

		private StatsRuntime? _runtime;

		private long _lastSecond = -1L;

		private Snapshot? _lastSnapshot;

		private ConfigEntry<float> _hudScale;

		private ConfigEntry<Vector2> _hudPosition;

		private Harmony? _patches;

		private float? _scalePreview;

		private StatsHud? _hud;

		private Hud? _gameHud;

		private bool _headless;

		internal static Plugin? Instance { get; private set; }

		internal ConfigEntry<float> HudScale => _hudScale;

		private void Awake()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Expected O, but got Unknown
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			_runtime = new StatsRuntime(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger);
			_patches = new Harmony("com.igentuman.bizarehud");
			_patches.PatchAll(typeof(Plugin).Assembly);
			_headless = GUIManager.IsHeadless();
			if (!_headless)
			{
				HudLocalization.Register();
				_hudScale = ((BaseUnityPlugin)this).Config.Bind<float>("HUD", "Scale", 0.65f, new ConfigDescription("Scale the entire HUD relative to the game's UI scale.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 2f), Array.Empty<object>()));
				_hudPosition = ((BaseUnityPlugin)this).Config.Bind<Vector2>("HUD", "Position", new Vector2(-1f, -1f), "Normalized panel position from the top left (0–1). Negative values use the default position. Drag the header with inventory open to move it.");
				_hudScale.SettingChanged += OnPresentationChanged;
			}
		}

		private void Start()
		{
			try
			{
				ArenaAdapter.Install(_patches);
				ArenaAdapter.InstallTraders(_patches);
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Compatibility adapter could not be installed: " + ex));
			}
		}

		private void Update()
		{
			_runtime?.Tick();
		}

		private void LateUpdate()
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			if (_headless)
			{
				return;
			}
			Hud instance = Hud.instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.m_rootObject == (Object)null)
			{
				RemoveHud();
				return;
			}
			if ((Object)(object)_gameHud != (Object)(object)instance || (Object)(object)_hud == (Object)null)
			{
				RemoveHud();
				_gameHud = instance;
				_hud = StatsHud.Create(instance.m_rootObject.transform);
				_hud.InitializePosition(_hudPosition.Value, delegate(Vector2 position)
				{
					//IL_0006: Unknown result type (might be due to invalid IL or missing references)
					_hudPosition.Value = position;
				});
				ApplyPresentation();
			}
			_hud.SetVisible((Object)(object)Player.m_localPlayer != (Object)null && instance.IsVisible() && !((Component)instance.m_loadingScreen).gameObject.activeInHierarchy);
			long num = (long)(_runtime?.Elapsed.TotalSeconds ?? 0.0);
			if (_lastSnapshot != _runtime?.Current || _lastSecond != num)
			{
				_lastSnapshot = _runtime?.Current;
				_lastSecond = num;
				ApplyPresentation();
			}
			_hud.UpdateLayout();
		}

		private void OnPresentationChanged(object sender, EventArgs args)
		{
			ApplyPresentation();
		}

		private void ApplyPresentation()
		{
			if (!((Object)(object)_hud == (Object)null))
			{
				Snapshot snapshot = _runtime?.Current;
				_hud.SetValues((snapshot == null) ? HudDisplayValues.Empty : new HudDisplayValues(_runtime.Elapsed, snapshot.Personal.Kills, snapshot.Personal.Gold, snapshot.Personal.Score, snapshot.BestUnits / 1000000, snapshot.ConnectedPlayers >= 2, snapshot.Team.Kills, snapshot.Team.Gold, snapshot.Team.Score));
				_hud.SetScale(_scalePreview ?? _hudScale.Value);
			}
		}

		internal void PreviewScale(float? scale)
		{
			_scalePreview = scale;
			ApplyPresentation();
		}

		private void RemoveHud()
		{
			if ((Object)(object)_hud != (Object)null)
			{
				_hud.FinishDrag();
				Object.Destroy((Object)(object)((Component)_hud).gameObject);
			}
			_hud = null;
			_gameHud = null;
		}

		private void OnDestroy()
		{
			_runtime?.Dispose();
			ArenaAdapter.Clear();
			VanillaSettingsIntegration.Shutdown();
			Harmony? patches = _patches;
			if (patches != null)
			{
				patches.UnpatchSelf();
			}
			Instance = null;
			if (!_headless && _hudScale != null)
			{
				_hudScale.SettingChanged -= OnPresentationChanged;
			}
			RemoveHud();
		}
	}
}
namespace BizareScoreHUD.UI
{
	public readonly struct HudDisplayValues
	{
		public static HudDisplayValues Empty => default(HudDisplayValues);

		public TimeSpan Time { get; }

		public long Kills { get; }

		public long GoldEarned { get; }

		public long Score { get; }

		public long BestScore { get; }

		public bool ShowTeam { get; }

		public long TeamKills { get; }

		public long TeamGold { get; }

		public long TeamScore { get; }

		public HudDisplayValues(TimeSpan time, long kills, long goldEarned, long score, long bestScore, bool showTeam = false, long teamKills = 0L, long teamGold = 0L, long teamScore = 0L)
		{
			Time = time;
			Kills = kills;
			GoldEarned = goldEarned;
			Score = score;
			BestScore = bestScore;
			ShowTeam = showTeam;
			TeamKills = teamKills;
			TeamGold = teamGold;
			TeamScore = teamScore;
		}
	}
	public sealed class HudDragHandle : MonoBehaviour, IPointerDownHandler, IEventSystemHandler, IBeginDragHandler, IDragHandler, IEndDragHandler
	{
		private static readonly FieldRef<InventoryGui, ItemData> DragItem = AccessTools.FieldRefAccess<InventoryGui, ItemData>("m_dragItem");

		private StatsHud _hud;

		private Vector2 _offset;

		private bool _dragging;

		internal static bool CanDrag
		{
			get
			{
				if (InventoryGui.IsVisible() && (Object)(object)InventoryGui.instance != (Object)null && DragItem.Invoke(InventoryGui.instance) == null && !InventoryGui.instance.m_splitDialog.IsActive && (Object)(object)Settings.instance == (Object)null && !Menu.IsVisible() && !Console.IsVisible() && !Minimap.IsOpen())
				{
					if (!((Object)(object)TextViewer.instance == (Object)null))
					{
						return !TextViewer.instance.IsVisible();
					}
					return true;
				}
				return false;
			}
		}

		internal void Initialize(StatsHud hud)
		{
			_hud = hud;
		}

		public void OnPointerDown(PointerEventData data)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			if ((int)data.button == 0)
			{
				Begin(data.position);
			}
		}

		public void OnBeginDrag(PointerEventData data)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			if ((int)data.button == 0)
			{
				Begin(data.position);
			}
		}

		private void Begin(Vector2 screenPosition)
		{
			//IL_0016: 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_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: 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)
			if (!_dragging && CanDrag && _hud.PointerToParent(screenPosition, _hud.EventCamera, out var point))
			{
				_offset = _hud.PanelPosition - point;
				_dragging = true;
			}
		}

		public void OnDrag(PointerEventData data)
		{
			//IL_001e: 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_003f: 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)
			if (_dragging)
			{
				Vector2 point;
				if (!CanDrag)
				{
					Finish();
				}
				else if (_hud.PointerToParent(data.position, _hud.EventCamera, out point))
				{
					_hud.MoveTo(point + _offset);
				}
			}
		}

		internal void UpdatePointer()
		{
			//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_001f: 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_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			if (!CanDrag || !Application.isFocused)
			{
				Finish();
				return;
			}
			Vector2 val = Vector2.op_Implicit(ZInput.pointerPosition);
			if (!_dragging && ZInput.GetMouseButtonDown(0) && _hud.ContainsDragPoint(val))
			{
				Begin(val);
			}
			if (_dragging)
			{
				if (_hud.PointerToParent(val, _hud.EventCamera, out var point))
				{
					_hud.MoveTo(point + _offset);
				}
				if (ZInput.GetMouseButtonUp(0) || !ZInput.GetMouseButton(0))
				{
					Finish();
				}
			}
		}

		public void OnEndDrag(PointerEventData data)
		{
			Finish();
		}

		internal void Finish()
		{
			if (_dragging)
			{
				_dragging = false;
				_hud.SavePosition();
			}
		}

		private void OnDisable()
		{
			Finish();
		}
	}
	internal static class HudLocalization
	{
		internal static void Register()
		{
			CustomLocalization localization = LocalizationManager.Instance.GetLocalization();
			string text = "English";
			localization.AddTranslation(ref text, new Dictionary<string, string>
			{
				{ "bizarehud_time", "Time" },
				{ "bizarehud_kills", "Kills" },
				{ "bizarehud_gold", "Gold Earned" },
				{ "bizarehud_score", "Score" },
				{ "bizarehud_best", "Best score" },
				{ "bizarehud_personal", "Personal" },
				{ "bizarehud_team", "Team" },
				{ "bizarehud_drag", "Drag panel to move" },
				{ "bizarehud_scale", "Bizare HUD Scale" }
			});
			text = "Russian";
			localization.AddTranslation(ref text, new Dictionary<string, string>
			{
				{ "bizarehud_time", "Время" },
				{ "bizarehud_kills", "Убийства" },
				{ "bizarehud_gold", "Заработано золота" },
				{ "bizarehud_score", "Очки" },
				{ "bizarehud_best", "Рекорд" },
				{ "bizarehud_personal", "Личная статистика" },
				{ "bizarehud_team", "Команда" },
				{ "bizarehud_drag", "Перетащите панель для перемещения" },
				{ "bizarehud_scale", "Масштаб HUD Bizare" }
			});
		}

		internal static string Text(string key)
		{
			return Localization.instance.Localize("$bizarehud_" + key);
		}
	}
	public sealed class StatsHud : MonoBehaviour
	{
		private HudDisplayValues _values;

		private Text _dragLabel;

		private Text _time;

		private Text _kills;

		private Text _goldEarned;

		private Text _score;

		private Text _bestScore;

		private Text _personal;

		private Text _teamTitle;

		private Text _teamKills;

		private Text _teamGold;

		private Text _teamScore;

		private RectTransform _rect;

		private HudDragHandle _handle;

		private RectTransform _dragHeader;

		private Canvas _canvas;

		private Image _background;

		private bool _editable;

		private Vector2 _position = new Vector2(-1f, -1f);

		private Action<Vector2>? _savePosition;

		private const float HandleHeight = 24f;

		private const float HorizontalPadding = 12f;

		private const float VerticalPadding = 8f;

		private RectTransform ParentRect => (RectTransform)((Transform)_rect).parent;

		internal Vector2 PanelPosition => _rect.anchoredPosition;

		internal Camera EventCamera
		{
			get
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				Canvas rootCanvas = _canvas.rootCanvas;
				if ((int)rootCanvas.renderMode != 0)
				{
					return rootCanvas.worldCamera;
				}
				return null;
			}
		}

		public static StatsHud Create(Transform parent)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Expected O, but got Unknown
			//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)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: 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_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: 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)
			//IL_0262: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02af: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0307: Unknown result type (might be due to invalid IL or missing references)
			//IL_030c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0340: Unknown result type (might be due to invalid IL or missing references)
			//IL_0345: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("BizareScoreHUD", new Type[6]
			{
				typeof(RectTransform),
				typeof(CanvasGroup),
				typeof(Canvas),
				typeof(GraphicRaycaster),
				typeof(CanvasRenderer),
				typeof(Image)
			});
			val.transform.SetParent(parent, false);
			val.layer = 5;
			Image component = val.GetComponent<Image>();
			((Graphic)component).color = Color32.op_Implicit(new Color32((byte)36, (byte)36, (byte)36, (byte)180));
			((Graphic)component).raycastTarget = false;
			CanvasGroup component2 = val.GetComponent<CanvasGroup>();
			component2.interactable = true;
			component2.blocksRaycasts = true;
			component2.ignoreParentGroups = true;
			Canvas component3 = val.GetComponent<Canvas>();
			component3.overrideSorting = false;
			component3.sortingOrder = 2001;
			StatsHud statsHud = val.AddComponent<StatsHud>();
			statsHud._rect = val.GetComponent<RectTransform>();
			statsHud._canvas = component3;
			statsHud._background = component;
			RectTransform rect = statsHud._rect;
			RectTransform rect2 = statsHud._rect;
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(0f, 1f);
			rect2.anchorMax = val2;
			rect.anchorMin = val2;
			statsHud._rect.pivot = new Vector2(0f, 1f);
			statsHud._rect.anchoredPosition = new Vector2(16f, -200f);
			statsHud._rect.sizeDelta = new Vector2(640f, 204f);
			statsHud._handle = val.AddComponent<HudDragHandle>();
			statsHud._handle.Initialize(statsHud);
			Font builtinResource = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
			statsHud._time = statsHud.CreateRow("Time", builtinResource, 24, Color.white, 0f, 34f);
			statsHud._kills = statsHud.CreateRow("Kills", builtinResource, 36, Color.red, 34f, 40f);
			statsHud._goldEarned = statsHud.CreateRow("GoldEarned", builtinResource, 36, Color32.op_Implicit(new Color32(byte.MaxValue, (byte)215, (byte)0, byte.MaxValue)), 74f, 42f);
			statsHud._score = statsHud.CreateRow("Score", builtinResource, 36, Color32.op_Implicit(new Color32(byte.MaxValue, (byte)165, (byte)0, byte.MaxValue)), 116f, 40f);
			statsHud._bestScore = statsHud.CreateRow("BestScore", builtinResource, 24, Color32.op_Implicit(new Color32(byte.MaxValue, (byte)165, (byte)0, byte.MaxValue)), 156f, 32f);
			statsHud._personal = statsHud.CreateRow("Personal", builtinResource, 24, Color.white, 0f, 34f);
			statsHud._teamTitle = statsHud.CreateRow("TeamTitle", builtinResource, 24, Color.white, 222f, 34f);
			statsHud._teamKills = statsHud.CreateRow("TeamKills", builtinResource, 36, Color.red, 256f, 40f);
			statsHud._teamGold = statsHud.CreateRow("TeamGold", builtinResource, 36, Color32.op_Implicit(new Color32(byte.MaxValue, (byte)215, (byte)0, byte.MaxValue)), 296f, 42f);
			statsHud._teamScore = statsHud.CreateRow("TeamScore", builtinResource, 36, Color32.op_Implicit(new Color32(byte.MaxValue, (byte)165, (byte)0, byte.MaxValue)), 338f, 40f);
			statsHud.CreateHandle(builtinResource);
			Localization.OnLanguageChange = (Action)Delegate.Combine(Localization.OnLanguageChange, new Action(statsHud.RefreshLocalization));
			return statsHud;
		}

		public void SetValues(HudDisplayValues values)
		{
			//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
			_values = values;
			SetText(_personal, HudLocalization.Text("personal"));
			SetText(_teamTitle, HudLocalization.Text("team"));
			SetText(_dragLabel, HudLocalization.Text("drag"));
			long num = values.Time.Ticks / 36000000000L;
			SetText(_time, string.Format(CultureInfo.InvariantCulture, HudLocalization.Text("time") + ": {0:00}:{1:00}:{2:00}", num, values.Time.Minutes, values.Time.Seconds));
			SetText(_kills, HudLocalization.Text("kills") + ": " + values.Kills.ToString(CultureInfo.InvariantCulture));
			SetText(_goldEarned, HudLocalization.Text("gold") + ": " + values.GoldEarned.ToString(CultureInfo.InvariantCulture));
			SetText(_score, HudLocalization.Text("score") + ": " + values.Score.ToString(CultureInfo.InvariantCulture));
			SetText(_bestScore, HudLocalization.Text("best") + ": " + values.BestScore.ToString(CultureInfo.InvariantCulture));
			SetText(_teamKills, HudLocalization.Text("kills") + ": " + values.TeamKills.ToString(CultureInfo.InvariantCulture));
			SetText(_teamGold, HudLocalization.Text("gold") + ": " + values.TeamGold.ToString(CultureInfo.InvariantCulture));
			SetText(_teamScore, HudLocalization.Text("score") + ": " + values.TeamScore.ToString(CultureInfo.InvariantCulture));
			Text[] array = (Text[])(object)new Text[5] { _personal, _teamTitle, _teamKills, _teamGold, _teamScore };
			for (int i = 0; i < array.Length; i++)
			{
				((Component)array[i]).gameObject.SetActive(values.ShowTeam);
			}
			Text[] array2 = (Text[])(object)new Text[5] { _time, _kills, _goldEarned, _score, _bestScore };
			float[] array3 = new float[5] { 0f, 34f, 74f, 116f, 156f };
			for (int j = 0; j < array2.Length; j++)
			{
				((Graphic)array2[j]).rectTransform.anchoredPosition = new Vector2(12f, -8f - array3[j] - (values.ShowTeam ? 34f : 0f));
			}
			_rect.SetSizeWithCurrentAnchors((Axis)1, (values.ShowTeam ? 378f : 188f) + 16f);
			float num2 = Mathf.Max(new float[5] { _time.preferredWidth, _kills.preferredWidth, _goldEarned.preferredWidth, _score.preferredWidth, _bestScore.preferredWidth });
			if (values.ShowTeam)
			{
				num2 = Mathf.Max(new float[6] { num2, _personal.preferredWidth, _teamTitle.preferredWidth, _teamKills.preferredWidth, _teamGold.preferredWidth, _teamScore.preferredWidth });
			}
			num2 = Mathf.Max(num2, _dragLabel.preferredWidth);
			_rect.SetSizeWithCurrentAnchors((Axis)0, Mathf.Max(280f, num2) + 24f);
		}

		private void RefreshLocalization()
		{
			SetValues(_values);
		}

		private void OnDestroy()
		{
			Localization.OnLanguageChange = (Action)Delegate.Remove(Localization.OnLanguageChange, new Action(RefreshLocalization));
		}

		public void SetScale(float scale)
		{
			//IL_0006: 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)
			((Transform)_rect).localScale = Vector3.one * Mathf.Clamp(scale, 0.5f, 2f);
		}

		public void InitializePosition(Vector2 position, Action<Vector2> savePosition)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			_position = position;
			_savePosition = savePosition;
		}

		internal bool ContainsDragPoint(Vector2 point)
		{
			//IL_0006: 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)
			if (!RectTransformUtility.RectangleContainsScreenPoint(_rect, point, EventCamera))
			{
				return RectTransformUtility.RectangleContainsScreenPoint(_dragHeader, point, EventCamera);
			}
			return true;
		}

		internal bool PointerToParent(Vector2 screen, Camera camera, out Vector2 point)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: 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_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_003b: 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)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			bool result = RectTransformUtility.ScreenPointToLocalPointInRectangle(ParentRect, screen, camera, ref point);
			Vector2 val = point;
			Rect rect = ParentRect.rect;
			float xMin = ((Rect)(ref rect)).xMin;
			rect = ParentRect.rect;
			point = val - new Vector2(xMin, ((Rect)(ref rect)).yMax);
			return result;
		}

		private void GetPositionBounds(out Vector2 minimum, out Vector2 maximum)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: 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_0043: 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_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: 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_00a1: Unknown result type (might be due to invalid IL or missing references)
			Camera eventCamera = EventCamera;
			PointerToParent(Vector2.zero, eventCamera, out var point);
			PointerToParent(new Vector2((float)Screen.width, (float)Screen.height), eventCamera, out var point2);
			float x = ((Transform)_rect).localScale.x;
			float x2 = point.x;
			float y = point.y;
			Rect rect = _rect.rect;
			minimum = new Vector2(x2, y + ((Rect)(ref rect)).height * x);
			float x3 = point2.x;
			rect = _rect.rect;
			maximum = new Vector2(x3 - ((Rect)(ref rect)).width * x, point2.y - 24f * x);
			maximum.x = Mathf.Max(minimum.x, maximum.x);
			minimum.y = Mathf.Min(minimum.y, maximum.y);
		}

		public void UpdateLayout()
		{
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: 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)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: 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_00d2: 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)
			if (!((Object)(object)_handle == (Object)null))
			{
				bool flag = ((Component)this).gameObject.activeInHierarchy && HudDragHandle.CanDrag;
				if (flag != _editable)
				{
					_editable = flag;
					_canvas.overrideSorting = flag;
					((Graphic)_background).raycastTarget = flag;
					((Component)_dragHeader).gameObject.SetActive(flag);
				}
				if (!flag)
				{
					_handle.Finish();
				}
				GetPositionBounds(out var minimum, out var maximum);
				Vector2 val = ((_position.x < 0f || _position.y < 0f) ? new Vector2(16f, -200f) : new Vector2(Mathf.Lerp(minimum.x, maximum.x, _position.x), Mathf.Lerp(maximum.y, minimum.y, _position.y)));
				Vector2 val2 = default(Vector2);
				((Vector2)(ref val2))..ctor(Mathf.Clamp(val.x, minimum.x, maximum.x), Mathf.Clamp(val.y, minimum.y, maximum.y));
				if (_rect.anchoredPosition != val2)
				{
					_rect.anchoredPosition = val2;
				}
				if (flag)
				{
					_handle.UpdatePointer();
				}
			}
		}

		internal void MoveTo(Vector2 position)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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_002d: 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_003e: 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_004f: 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_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: 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_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			GetPositionBounds(out var minimum, out var maximum);
			_rect.anchoredPosition = new Vector2(Mathf.Clamp(position.x, minimum.x, maximum.x), Mathf.Clamp(position.y, minimum.y, maximum.y));
			_position = new Vector2(Mathf.InverseLerp(minimum.x, maximum.x, _rect.anchoredPosition.x), Mathf.InverseLerp(maximum.y, minimum.y, _rect.anchoredPosition.y));
		}

		internal void SavePosition()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			_savePosition?.Invoke(_position);
		}

		public void FinishDrag()
		{
			_handle.Finish();
		}

		private void CreateHandle(Font font)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: 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_0119: 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_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("DragHeader", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image)
			});
			val.transform.SetParent(((Component)this).transform, false);
			val.layer = 5;
			RectTransform val2 = (_dragHeader = val.GetComponent<RectTransform>());
			val2.anchorMin = new Vector2(0f, 1f);
			val2.anchorMax = Vector2.one;
			val2.pivot = new Vector2(0f, 0f);
			val2.sizeDelta = new Vector2(0f, 24f);
			((Graphic)val.GetComponent<Image>()).color = Color32.op_Implicit(new Color32((byte)36, (byte)36, (byte)36, (byte)220));
			GameObject val3 = new GameObject("Label", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Text)
			});
			val3.transform.SetParent(val.transform, false);
			val3.layer = 5;
			RectTransform component = val3.GetComponent<RectTransform>();
			component.anchorMax = Vector2.one;
			component.sizeDelta = Vector2.zero;
			Text component2 = val3.GetComponent<Text>();
			component2.font = font;
			component2.fontSize = 16;
			component2.alignment = (TextAnchor)4;
			((Graphic)component2).color = Color.white;
			_dragLabel = component2;
			component2.text = HudLocalization.Text("drag");
			((Graphic)component2).raycastTarget = false;
			val.SetActive(false);
		}

		public void SetVisible(bool visible)
		{
			if (((Component)this).gameObject.activeSelf != visible)
			{
				((Component)this).gameObject.SetActive(visible);
			}
		}

		private Text CreateRow(string name, Font font, int size, Color color, float top, float height)
		{
			//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_0045: 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_005d: 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_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Text)
			});
			val.transform.SetParent(((Component)this).transform, false);
			val.layer = 5;
			RectTransform component = val.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0f, 1f);
			component.anchorMax = Vector2.one;
			component.pivot = new Vector2(0f, 1f);
			component.anchoredPosition = new Vector2(12f, 0f - top - 8f);
			component.sizeDelta = new Vector2(-24f, height);
			Text component2 = val.GetComponent<Text>();
			component2.font = font;
			component2.fontSize = size;
			component2.fontStyle = (FontStyle)0;
			((Graphic)component2).color = color;
			component2.alignment = (TextAnchor)0;
			component2.supportRichText = false;
			component2.resizeTextForBestFit = false;
			component2.horizontalOverflow = (HorizontalWrapMode)1;
			component2.verticalOverflow = (VerticalWrapMode)1;
			((Graphic)component2).raycastTarget = false;
			return component2;
		}

		private static void SetText(Text label, string value)
		{
			if (label.text != value)
			{
				label.text = value;
			}
		}
	}
	public sealed class VanillaSettingsIntegration : MonoBehaviour
	{
		[HarmonyPatch(typeof(GraphicsSettings), "Initialize")]
		private static class InitializePatch
		{
			private static void Postfix(GraphicsSettings __instance)
			{
				Install(__instance);
			}
		}

		[HarmonyPatch(typeof(Settings), "ApplyAndClose")]
		private static class SavePatch
		{
			private static void Prefix()
			{
				Commit();
			}
		}

		[HarmonyPatch(typeof(Settings), "OnBack")]
		private static class BackPatch
		{
			private static void Prefix()
			{
				ClosePreview();
			}
		}

		private static VanillaSettingsIntegration? _active;

		private Slider _slider;

		private TMP_Text _value;

		private TMP_Text _label;

		private List<Slider> _navigation;

		private Plugin _plugin;

		private bool _finished;

		private bool _disposed;

		internal static void Install(GraphicsSettings graphics)
		{
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Expected O, but got Unknown
			//IL_022c: 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_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			Settings componentInParent = ((Component)graphics).GetComponentInParent<Settings>();
			if (!((Object)(object)Plugin.Instance == (Object)null) && !((Object)(object)componentInParent == (Object)null) && !((Object)(object)((Component)componentInParent).GetComponent<VanillaSettingsIntegration>() != (Object)null))
			{
				GameObject value = Traverse.Create((object)graphics).Field<GameObject>("m_qualitySliderPrefab").Value;
				GameObject val = Object.Instantiate<GameObject>(value, value.transform.parent);
				((Object)val).name = "BizareHudScale";
				VanillaSettingsIntegration vanillaSettingsIntegration = (_active = ((Component)componentInParent).gameObject.AddComponent<VanillaSettingsIntegration>());
				vanillaSettingsIntegration._plugin = Plugin.Instance;
				vanillaSettingsIntegration._slider = val.GetComponent<Slider>();
				vanillaSettingsIntegration._slider.onValueChanged = new SliderEvent();
				vanillaSettingsIntegration._slider.minValue = 50f;
				vanillaSettingsIntegration._slider.maxValue = 200f;
				vanillaSettingsIntegration._slider.wholeNumbers = true;
				vanillaSettingsIntegration._label = ((Component)val.transform.Find("Label")).GetComponent<TMP_Text>();
				vanillaSettingsIntegration.RefreshLocalization();
				Localization.OnLanguageChange = (Action)Delegate.Combine(Localization.OnLanguageChange, new Action(vanillaSettingsIntegration.RefreshLocalization));
				vanillaSettingsIntegration._value = ((Component)val.transform.Find("Info/Value")).GetComponent<TMP_Text>();
				((Component)val.transform.Find("Info/Warning")).gameObject.SetActive(false);
				vanillaSettingsIntegration._navigation = Traverse.Create((object)graphics).Field<List<Slider>>("m_dynamicQualitySliders").Value;
				int count = vanillaSettingsIntegration._navigation.Count;
				val.transform.SetSiblingIndex((count > 0) ? (((Component)vanillaSettingsIntegration._navigation[count - 1]).transform.GetSiblingIndex() + 1) : (value.transform.GetSiblingIndex() + 1));
				vanillaSettingsIntegration._navigation.Add(vanillaSettingsIntegration._slider);
				vanillaSettingsIntegration.SyncConfig(null, EventArgs.Empty);
				((UnityEvent<float>)(object)vanillaSettingsIntegration._slider.onValueChanged).AddListener((UnityAction<float>)vanillaSettingsIntegration.OnScaleChanged);
				vanillaSettingsIntegration._plugin.HudScale.SettingChanged += vanillaSettingsIntegration.SyncConfig;
				val.SetActive(true);
				RectTransform value2 = Traverse.Create((object)graphics).Field<RectTransform>("m_listRoot").Value;
				VerticalLayoutGroup value3 = Traverse.Create((object)graphics).Field<VerticalLayoutGroup>("m_verticalLayoutGroup").Value;
				Rect rect = value2.rect;
				float height = ((Rect)(ref rect)).height;
				rect = ((RectTransform)val.transform).rect;
				value2.SetSizeWithCurrentAnchors((Axis)1, height + ((Rect)(ref rect)).height + ((HorizontalOrVerticalLayoutGroup)value3).spacing);
				LayoutRebuilder.MarkLayoutForRebuild(value2);
			}
		}

		private void RefreshLocalization()
		{
			_label.text = HudLocalization.Text("scale");
		}

		private void SyncConfig(object sender, EventArgs args)
		{
			_slider.SetValueWithoutNotify(_plugin.HudScale.Value * 100f);
			_value.text = Mathf.RoundToInt(_slider.value) + "%";
			_plugin.PreviewScale(null);
		}

		private void OnScaleChanged(float percent)
		{
			_value.text = Mathf.RoundToInt(percent) + "%";
			_plugin.PreviewScale(percent / 100f);
		}

		internal static void Commit()
		{
			if (!((Object)(object)_active == (Object)null) && !_active._finished)
			{
				VanillaSettingsIntegration active = _active;
				active._finished = true;
				active._plugin.HudScale.Value = active._slider.value / 100f;
				active._plugin.PreviewScale(null);
			}
		}

		internal static void ClosePreview()
		{
			if (!((Object)(object)_active == (Object)null))
			{
				_active._plugin.PreviewScale(null);
			}
		}

		internal static void Shutdown()
		{
			if (!((Object)(object)_active == (Object)null))
			{
				VanillaSettingsIntegration? active = _active;
				active.Cleanup();
				Object.Destroy((Object)(object)active);
			}
		}

		private void OnDestroy()
		{
			Cleanup();
		}

		private void Cleanup()
		{
			if (!_disposed)
			{
				_disposed = true;
				Localization.OnLanguageChange = (Action)Delegate.Remove(Localization.OnLanguageChange, new Action(RefreshLocalization));
				if ((Object)(object)_slider != (Object)null)
				{
					((UnityEvent<float>)(object)_slider.onValueChanged).RemoveListener((UnityAction<float>)OnScaleChanged);
					_navigation?.Remove(_slider);
				}
				if ((Object)(object)_plugin != (Object)null)
				{
					_plugin.HudScale.SettingChanged -= SyncConfig;
					_plugin.PreviewScale(null);
				}
				if ((Object)(object)_active == (Object)(object)this)
				{
					_active = null;
				}
				if ((Object)(object)_slider != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)_slider).gameObject);
				}
			}
		}
	}
}
namespace BizareScoreHUD.Tracking
{
	public static class InventoryTracking
	{
		private sealed class Before
		{
			public int Count;

			public List<LotRange> Ranges = new List<LotRange>();
		}

		private sealed class Operation
		{
			private readonly Dictionary<ItemData, Before> _before = new Dictionary<ItemData, Before>();

			private readonly HashSet<Inventory> _inventories = new HashSet<Inventory>();

			private readonly Dictionary<ItemData, ItemDrop?> _loose = new Dictionary<ItemData, ItemDrop>();

			public readonly List<ItemDrop> Outputs = new List<ItemDrop>();

			private readonly bool _reward = RewardDepth > 0;

			public void Add(Inventory inventory)
			{
				if (!_inventories.Add(inventory))
				{
					return;
				}
				bool fresh = inventory != Local;
				foreach (ItemData item in inventory.GetAllItems().Where(Currency))
				{
					Capture(item, fresh);
				}
				if (inventory == Local)
				{
					Audited.Add(inventory);
				}
			}

			public unsafe void AddLoose(ItemData item, ItemDrop? drop)
			{
				//IL_009c: 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)
				if (!_inventories.Any((Inventory i) => i.ContainsItem(item)))
				{
					if (!_loose.ContainsKey(item) || (Object)(object)drop != (Object)null)
					{
						_loose[item] = drop;
					}
					string stable = null;
					ZNetView val = (((Object)(object)drop == (Object)null) ? null : ((Component)drop).GetComponent<ZNetView>());
					if ((Object)(object)val != (Object)null && val.IsValid())
					{
						string obj = StatsRuntime.Instance?.WorldId;
						ZDOID uid = val.GetZDO().m_uid;
						stable = "drop:" + obj + ":" + ((object)(*(ZDOID*)(&uid))/*cast due to .constrained prefix*/).ToString();
					}
					Capture(item, (Object)(object)drop != (Object)null || _reward, stable);
				}
			}

			private void Capture(ItemData item, bool fresh, string? stable = null)
			{
				if (!_before.ContainsKey(item))
				{
					_before.Add(item, new Before
					{
						Count = item.m_stack,
						Ranges = Provenance.Copy(Read(item, fresh, stable))
					});
				}
			}

			public void Finish()
			{
				HashSet<ItemData> hashSet = new HashSet<ItemData>();
				foreach (Inventory inventory in _inventories)
				{
					foreach (ItemData item in inventory.GetAllItems().Where(Currency))
					{
						hashSet.Add(item);
					}
				}
				foreach (KeyValuePair<ItemData, ItemDrop> item2 in _loose)
				{
					if (item2.Value != null && (Object)(object)item2.Value != (Object)null && (Object)(object)((Component)item2.Value).GetComponent<ZNetView>() != (Object)null && ((Component)item2.Value).GetComponent<ZNetView>().IsValid())
					{
						hashSet.Add(item2.Key);
					}
				}
				foreach (ItemDrop output in Outputs)
				{
					if ((Object)(object)output != (Object)null)
					{
						hashSet.Add(output.m_itemData);
					}
				}
				Dictionary<ItemData, List<LotRange>> dictionary = new Dictionary<ItemData, List<LotRange>>();
				List<LotRange> list = new List<LotRange>();
				foreach (KeyValuePair<ItemData, Before> item3 in _before)
				{
					List<LotRange> list2 = Provenance.Copy(item3.Value.Ranges);
					long quantity = (hashSet.Contains(item3.Key) ? Math.Min(item3.Value.Count, item3.Key.m_stack) : 0);
					dictionary[item3.Key] = Provenance.Take(list2, quantity);
					list.AddRange(list2);
				}
				foreach (ItemData item4 in hashSet)
				{
					if (!dictionary.TryGetValue(item4, out var value))
					{
						value = (dictionary[item4] = new List<LotRange>());
					}
					long num = item4.m_stack - value.Sum((LotRange r) => r.Count);
					long val = list.Sum((LotRange r) => r.Count);
					long num2 = Math.Min(num, val);
					value.AddRange(Provenance.Take(list, num2));
					num -= num2;
					if (num > 0)
					{
						if (!_reward)
						{
							StatsRuntime.Instance?.Warn("Unclassified positive currency mutation held neutral: " + num);
						}
						LotRange lotRange = Provenance.Create(num, _reward, StatsRuntime.Instance?.RunId ?? "");
						lotRange.World = StatsRuntime.Instance?.WorldId ?? "";
						value.Add(lotRange);
					}
					Write(item4, value);
				}
				if (Local != null && _inventories.Contains(Local))
				{
					Credit(Local);
				}
				foreach (ItemDrop item5 in _loose.Values.Concat<ItemDrop>(Outputs))
				{
					if ((Object)(object)item5 != (Object)null)
					{
						SaveDrop?.Invoke(item5, null);
					}
				}
			}
		}

		private const string Key = "com.igentuman.bizarehud.lots.v1";

		private static Operation? _operation;

		private static int _depth;

		public static int Loading;

		public static int RewardDepth;

		private static readonly HashSet<Inventory> Audited = new HashSet<Inventory>();

		private static readonly MethodInfo? SaveDrop = AccessTools.Method(typeof(ItemDrop), "Save", (Type[])null, (Type[])null);

		private static readonly FieldInfo? DropInstances = AccessTools.Field(typeof(ItemDrop), "s_instances");

		private static Inventory? Local
		{
			get
			{
				if (!((Object)(object)Player.m_localPlayer == (Object)null))
				{
					return ((Humanoid)Player.m_localPlayer).GetInventory();
				}
				return null;
			}
		}

		public static bool Currency(ItemData item)
		{
			if ((Object)(object)item.m_dropPrefab != (Object)null)
			{
				return ((Object)item.m_dropPrefab).name == "Coins";
			}
			return false;
		}

		public static void Clear()
		{
			_operation = null;
			_depth = (Loading = (RewardDepth = 0));
			Audited.Clear();
		}

		public static void Audit(Inventory inventory)
		{
			if (_operation != null || Loading > 0)
			{
				return;
			}
			foreach (ItemData item in inventory.GetAllItems().Where(Currency))
			{
				Read(item, fresh: false);
			}
			Audited.Add(inventory);
			if (StatsRuntime.Instance == null || StatsRuntime.Instance.RunId.Length <= 0)
			{
				return;
			}
			try
			{
				Credit(inventory);
			}
			catch (Exception ex)
			{
				StatsRuntime.Instance.Warn("Pending carrier acquisition deferred: " + ex.Message);
			}
		}

		private static List<LotRange> Read(ItemData item, bool fresh, string? stableLot = null)
		{
			if (item.m_customData.TryGetValue("com.igentuman.bizarehud.lots.v1", out var value))
			{
				try
				{
					List<LotRange> list = Json.Read<List<LotRange>>(value);
					if (list.Count <= 256 && list.All((LotRange r) => r.Count > 0 && r.Start >= 0 && r.Start <= long.MaxValue - r.Count) && list.Sum((LotRange r) => r.Count) == item.m_stack)
					{
						string world = StatsRuntime.Instance?.WorldId ?? "";
						if (world.Length > 0 && list.Any((LotRange r) => r.World.Length > 0 && r.World != world))
						{
							foreach (LotRange item2 in list)
							{
								item2.Fresh = false;
							}
							Write(item, list);
						}
						return list;
					}
				}
				catch (Exception ex) when (ex is JsonException || ex is OverflowException || ex is InvalidOperationException)
				{
				}
				StatsRuntime.Instance?.Warn("Invalid currency provenance quarantined as neutral");
				fresh = false;
			}
			List<LotRange> list2 = new List<LotRange>();
			if (item.m_stack > 0)
			{
				LotRange lotRange = Provenance.Create(item.m_stack, fresh, StatsRuntime.Instance?.RunId ?? "");
				lotRange.World = StatsRuntime.Instance?.WorldId ?? "";
				if (stableLot != null)
				{
					lotRange.Lot = stableLot;
				}
				list2.Add(lotRange);
			}
			Write(item, list2);
			return list2;
		}

		private static void Write(ItemData item, List<LotRange> ranges)
		{
			string text = Json.Write(ranges);
			if (!item.m_customData.TryGetValue("com.igentuman.bizarehud.lots.v1", out var value) || value != text)
			{
				item.m_customData["com.igentuman.bizarehud.lots.v1"] = text;
			}
		}

		public static void Begin(Inventory? inventory, object[] args)
		{
			if (Loading > 0 || StatsRuntime.Instance == null || StatsRuntime.Instance.RunId.Length == 0)
			{
				return;
			}
			if (_operation == null)
			{
				_operation = new Operation();
			}
			_depth++;
			if (inventory != null)
			{
				_operation.Add(inventory);
			}
			foreach (object obj in args)
			{
				Inventory val = (Inventory)((obj is Inventory) ? obj : null);
				if (val != null)
				{
					_operation.Add(val);
				}
				ItemData val2 = (ItemData)((obj is ItemData) ? obj : null);
				if (val2 != null && Currency(val2))
				{
					_operation.AddLoose(val2, null);
				}
			}
		}

		public static void Pickup(Humanoid humanoid, GameObject go)
		{
			ItemDrop val = (((Object)(object)go == (Object)null) ? null : go.GetComponent<ItemDrop>());
			if ((Object)(object)val != (Object)null)
			{
				val.Load();
			}
			Begin(humanoid.GetInventory(), Array.Empty<object>());
			if (_operation != null && (Object)(object)val != (Object)null && Currency(val.m_itemData))
			{
				_operation.AddLoose(val.m_itemData, val);
			}
		}

		public static void GroundStack(ItemDrop receiver)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			Begin(null, Array.Empty<object>());
			if (_operation == null || !Currency(receiver.m_itemData))
			{
				return;
			}
			ItemDrop[] array = ((DropInstances?.GetValue(null) as IEnumerable<ItemDrop>) ?? Array.Empty<ItemDrop>()).ToArray();
			foreach (ItemDrop val in array)
			{
				if (!((Object)(object)val == (Object)null) && Currency(val.m_itemData) && !(Vector3.Distance(((Component)receiver).transform.position, ((Component)val).transform.position) > 4f))
				{
					ZNetView component = ((Component)val).GetComponent<ZNetView>();
					if (!((Object)(object)component == (Object)null) && component.IsValid() && component.IsOwner())
					{
						val.Load();
						_operation.AddLoose(val.m_itemData, val);
					}
				}
			}
		}

		public static void Output(ItemDrop drop)
		{
			if (_operation != null && (Object)(object)drop != (Object)null && Currency(drop.m_itemData))
			{
				_operation.Outputs.Add(drop);
			}
		}

		public static void End()
		{
			if (_operation == null || _depth == 0 || --_depth != 0)
			{
				return;
			}
			Operation operation = _operation;
			_operation = null;
			try
			{
				operation.Finish();
			}
			catch (Exception ex)
			{
				StatsRuntime.Instance?.Warn("Currency reconciliation deferred: " + ex);
			}
		}

		private static void Credit(Inventory inventory)
		{
			foreach (ItemData item in inventory.GetAllItems().Where(Currency))
			{
				List<LotRange> list = Read(item, fresh: false);
				foreach (IGrouping<string, LotRange> item2 in from r in list
					where r.Fresh && r.Run.Length > 0
					group r by r.Run)
				{
					if (!StatsRuntime.Instance.Submit(new Report
					{
						Kind = "gold",
						Run = item2.Key,
						Ranges = Provenance.Copy(item2)
					}))
					{
						throw new InvalidOperationException("Acquisition remains unacknowledged in its carrier");
					}
				}
				foreach (LotRange item3 in list)
				{
					item3.Fresh = false;
				}
				Write(item, list);
			}
		}
	}
	public sealed class RewardScope : IDisposable
	{
		private bool _disposed;

		public RewardScope(Inventory inventory)
		{
			InventoryTracking.RewardDepth++;
			InventoryTracking.Begin(inventory, Array.Empty<object>());
		}

		public void Dispose()
		{
			if (_disposed)
			{
				return;
			}
			_disposed = true;
			try
			{
				InventoryTracking.End();
			}
			finally
			{
				InventoryTracking.RewardDepth--;
			}
		}
	}
}
namespace BizareScoreHUD.Persistence
{
	public static class Json
	{
		public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
		{
			ContractResolver = (IContractResolver)new DefaultContractResolver
			{
				NamingStrategy = (NamingStrategy)new CamelCaseNamingStrategy
				{
					ProcessDictionaryKeys = false,
					OverrideSpecifiedNames = true
				}
			},
			MaxDepth = 64,
			TypeNameHandling = (TypeNameHandling)0
		};

		public static string Write(object value)
		{
			return JsonConvert.SerializeObject(value, Settings);
		}

		public static T Read<T>(string value)
		{
			T val = JsonConvert.DeserializeObject<T>(value, Settings);
			if (val == null)
			{
				throw new InvalidDataException("Empty JSON");
			}
			return val;
		}

		public static T Clone<T>(T value)
		{
			return Read<T>(Write(value));
		}
	}
	public sealed class DeathsConverter : JsonConverter<Dictionary<string, string>>
	{
		public override Dictionary<string, string> ReadJson(JsonReader reader, Type objectType, Dictionary<string, string>? existingValue, bool hasExistingValue, JsonSerializer serializer)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Invalid comparison between Unknown and I4
			Dictionary<string, string> dictionary = existingValue ?? new Dictionary<string, string>();
			if ((int)reader.TokenType == 11)
			{
				return dictionary;
			}
			if ((int)reader.TokenType == 2)
			{
				foreach (JToken item in JArray.Load(reader))
				{
					dictionary[((string)item) ?? throw new InvalidDataException("Invalid death record")] = "";
				}
				return dictionary;
			}
			foreach (JProperty item2 in JObject.Load(reader).Properties())
			{
				dictionary[item2.Name] = ((string)item2.Value) ?? "";
			}
			return dictionary;
		}

		public override void WriteJson(JsonWriter writer, Dictionary<string, string>? value, JsonSerializer serializer)
		{
			writer.WriteStartObject();
			if (value != null)
			{
				foreach (KeyValuePair<string, string> item in value)
				{
					writer.WritePropertyName(item.Key);
					writer.WriteValue(item.Value);
				}
			}
			writer.WriteEndObject();
		}
	}
	public sealed class JournalRecord
	{
		public long Revision;

		public bool Delta;

		public string State = "";

		public string Hash = "";
	}
	public sealed class JournalChange
	{
		public string[] Path = Array.Empty<string>();

		public bool Remove;

		public JToken? Value;
	}
	public sealed class BestFile
	{
		public int SchemaVersion = 1;

		public Dictionary<string, long> Checkpoints = new Dictionary<string, long>();

		public List<BestRecord> Players = new List<BestRecord>();
	}
	public sealed class StateRepository
	{
		public static bool SyncWrites;

		private readonly string _root;

		private readonly string _directory;

		private readonly string _journal;

		private JObject? _lastPersisted;

		public StateRepository(string root, string world)
		{
			_root = root;
			_directory = Path.Combine(root, world);
			Directory.CreateDirectory(_directory);
			_journal = Path.Combine(_directory, "journal.jsonl");
		}

		private static string Hash(string value)
		{
			using SHA256 sHA = SHA256.Create();
			return Convert.ToBase64String(sHA.ComputeHash(Encoding.UTF8.GetBytes(value)));
		}

		private static T? LoadWithBackup<T>(string path) where T : class
		{
			if (!File.Exists(path) && !File.Exists(path + ".bak"))
			{
				return null;
			}
			string[] array = new string[2]
			{
				path,
				path + ".bak"
			};
			foreach (string path2 in array)
			{
				if (!File.Exists(path2))
				{
					continue;
				}
				try
				{
					string text = File.ReadAllText(path2);
					if (typeof(T) == typeof(BestFile))
					{
						ValidateBests(text);
					}
					return Json.Read<T>(text);
				}
				catch (JsonException)
				{
				}
				catch (InvalidDataException)
				{
				}
			}
			throw new InvalidDataException("Cannot recover " + path);
		}

		private static void ValidateBests(string json)
		{
			JObject obj = JObject.Parse(json);
			if ((int?)obj["schemaVersion"] > 1)
			{
				throw new NotSupportedException("Unsupported newer best-score schema");
			}
			if ((int?)obj["schemaVersion"] != 1)
			{
				throw new InvalidDataException("Invalid best-score schema");
			}
			JToken obj2 = obj["players"];
			JToken obj3 = ((obj2 is JArray) ? obj2 : null) ?? throw new InvalidDataException("Missing best-score records");
			HashSet<string> hashSet = new HashSet<string>();
			foreach (JToken item in (JArray)obj3)
			{
				string text = (string)item[(object)"participantId"];
				long? num = (long?)item[(object)"scoreUnits"];
				long? num2 = (long?)item[(object)"score"];
				if (string.IsNullOrEmpty(text) || !hashSet.Add(text) || !num.HasValue || num < 0 || num2 != num / 1000000)
				{
					throw new InvalidDataException("Inconsistent best-score record");
				}
			}
		}

		private WorldState? Replay(string journal)
		{
			JObject document;
			return Replay(journal, out document);
		}

		private WorldState? Replay(string journal, out JObject? document)
		{
			document = null;
			if (!File.Exists(journal))
			{
				return null;
			}
			string text = File.ReadAllText(journal);
			int num = text.LastIndexOf('\n');
			if (num < text.Length - 1)
			{
				using FileStream fileStream = new FileStream(journal, FileMode.Open, FileAccess.Write, FileShare.Read);
				fileStream.SetLength(Encoding.UTF8.GetByteCount(text.Substring(0, num + 1)));
				fileStream.Flush(SyncWrites);
				text = text.Substring(0, num + 1);
			}
			JObject val = null;
			long num2 = 0L;
			string[] array = text.Split('\n');
			foreach (string text2 in array)
			{
				if (text2.Length == 0)
				{
					continue;
				}
				JournalRecord journalRecord = Json.Read<JournalRecord>(text2);
				if (journalRecord.Hash != Hash(journalRecord.State))
				{
					throw new InvalidDataException("Journal checksum mismatch");
				}
				if (val != null && journalRecord.Revision <= num2)
				{
					throw new InvalidDataException("Unordered journal");
				}
				if (journalRecord.Delta)
				{
					if (val == null)
					{
						throw new InvalidDataException("Journal delta without initial state");
					}
					foreach (JournalChange item in Json.Read<List<JournalChange>>(journalRecord.State))
					{
						Apply(val, item);
					}
				}
				else
				{
					val = JObject.Parse(journalRecord.State);
				}
				if ((int?)val["schemaVersion"] != 1 || (long?)val["revision"] != journalRecord.Revision)
				{
					throw new InvalidDataException("Unsupported journal schema/revision");
				}
				num2 = journalRecord.Revision;
			}
			document = val;
			if (val != null)
			{
				return Json.Read<WorldState>(((JToken)val).ToString((Formatting)0, Array.Empty<JsonConverter>()));
			}
			return null;
		}

		private static void Apply(JObject root, JournalChange change)
		{
			if (change.Path.Length == 0)
			{
				throw new InvalidDataException("Invalid journal path");
			}
			JObject val = root;
			foreach (string item in change.Path.Take(change.Path.Length - 1))
			{
				JToken obj = val[item];
				val = (JObject)(object)(((obj is JObject) ? obj : null) ?? throw new InvalidDataException("Invalid journal parent"));
			}
			string text = change.Path[change.Path.Length - 1];
			if (change.Remove)
			{
				val.Remove(text);
				return;
			}
			JObject obj2 = val;
			JToken? value = change.Value;
			obj2[text] = (JToken)(((object)((value != null) ? value.DeepClone() : null)) ?? ((object)JValue.CreateNull()));
		}

		private static void Diff(JObject before, JObject after, List<string> path, List<JournalChange> changes)
		{
			foreach (JProperty item in before.Properties())
			{
				if (after.Property(item.Name) == null)
				{
					changes.Add(new JournalChange
					{
						Path = path.Concat(new string[1] { item.Name }).ToArray(),
						Remove = true
					});
				}
			}
			foreach (JProperty item2 in after.Properties())
			{
				List<string> list = path.Concat(new string[1] { item2.Name }).ToList();
				JProperty val = before.Property(item2.Name);
				if (val != null && JToken.DeepEquals(val.Value, item2.Value))
				{
					continue;
				}
				JToken obj = ((val != null) ? val.Value : null);
				JObject val2 = (JObject)(object)((obj is JObject) ? obj : null);
				if (val2 != null)
				{
					JToken value = item2.Value;
					JObject val3 = (JObject)(object)((value is JObject) ? value : null);
					if (val3 != null)
					{
						Diff(val2, val3, list, changes);
						continue;
					}
				}
				changes.Add(new JournalChange
				{
					Path = list.ToArray(),
					Value = item2.Value.DeepClone()
				});
			}
		}

		public WorldState Load(string world, ArenaDifficulty difficulty)
		{
			JObject document;
			WorldState worldState = Replay(_journal, out document) ?? LoadWithBackup<WorldState>(Path.Combine(_directory, "state.json"));
			_lastPersisted = document;
			if (worldState == null)
			{
				worldState = new WorldState
				{
					World = world
				};
				worldState.Start(difficulty);
			}
			if (worldState.SchemaVersion != 1 || worldState.World != world || !worldState.Runs.ContainsKey(worldState.CurrentRun))
			{
				throw new InvalidDataException("Invalid world state");
			}
			RestoreParticipantKeys(worldState);
			BestFile bestFile;
			string[] files;
			try
			{
				bestFile = LoadWithBackup<BestFile>(Path.Combine(_root, "best_scores.json")) ?? new BestFile();
			}
			catch (InvalidDataException)
			{
				bestFile = new BestFile();
				files = Directory.GetFiles(_root, "journal.jsonl", SearchOption.AllDirectories);
				foreach (string journal in files)
				{
					WorldState worldState2 = Replay(journal);
					if (worldState2 != null)
					{
						Merge(bestFile, worldState2);
					}
				}
				if (bestFile.Checkpoints.Count == 0)
				{
					throw;
				}
			}
			if (bestFile.SchemaVersion != 1)
			{
				throw new InvalidDataException("Unsupported best-score schema");
			}
			files = Directory.GetFiles(_root, "journal.jsonl", SearchOption.AllDirectories);
			foreach (string journal2 in files)
			{
				WorldState worldState3 = Replay(journal2);
				if (worldState3 != null)
				{
					Merge(bestFile, worldState3);
				}
			}
			foreach (BestRecord player in bestFile.Players)
			{
				if (!worldState.Bests.TryGetValue(player.ParticipantId, out BestRecord value) || player.ScoreUnits > value.ScoreUnits)
				{
					worldState.Bests[player.ParticipantId] = player;
				}
			}
			AtomicWrite(Path.Combine(_root, "best_scores.json"), JsonConvert.SerializeObject((object)bestFile, (Formatting)1, Json.Settings));
			return worldState;
		}

		private static void Merge(BestFile file, WorldState state)
		{
			RestoreParticipantKeys(state);
			foreach (BestRecord best in state.Bests.Values)
			{
				BestRecord bestRecord = file.Players.Find((BestRecord p) => p.ParticipantId == best.ParticipantId);
				Participant value;
				if (bestRecord == null)
				{
					file.Players.Add(best);
				}
				else if (best.ScoreUnits > bestRecord.ScoreUnits)
				{
					file.Players.Remove(bestRecord);
					file.Players.Add(best);
				}
				else if (state.Participants.TryGetValue(best.ParticipantId, out value))
				{
					bestRecord.Nickname = value.Nickname;
				}
			}
			file.Checkpoints[state.World] = state.Revision;
		}

		private static void RestoreParticipantKeys(WorldState state)
		{
			KeyValuePair<string, Participant>[] array = state.Participants.ToArray();
			for (int i = 0; i < array.Length; i++)
			{
				KeyValuePair<string, Participant> keyValuePair = array[i];
				string id = keyValuePair.Value.Id;
				if (keyValuePair.Key == id)
				{
					continue;
				}
				if (id.Length == 0 || state.Participants.ContainsKey(id))
				{
					throw new InvalidDataException("Conflicting participant identity in saved state");
				}
				state.Participants.Remove(keyValuePair.Key);
				state.Participants.Add(id, keyValuePair.Value);
				foreach (Run value2 in state.Runs.Values)
				{
					if (value2.Players.TryGetValue(keyValuePair.Key, out Counters value))
					{
						if (value2.Players.ContainsKey(id))
						{
							throw new InvalidDataException("Conflicting participant counters in saved state");
						}
						value2.Players.Remove(keyValuePair.Key);
						value2.Players.Add(id, value);
					}
				}
			}
			KeyValuePair<string, BestRecord>[] array2 = state.Bests.ToArray();
			for (int i = 0; i < array2.Length; i++)
			{
				KeyValuePair<string, BestRecord> keyValuePair2 = array2[i];
				string participantId = keyValuePair2.Value.ParticipantId;
				if (!(keyValuePair2.Key == participantId))
				{
					if (participantId.Length == 0 || state.Bests.ContainsKey(participantId))
					{
						throw new InvalidDataException("Conflicting best-score identity in saved state");
					}
					state.Bests.Remove(keyValuePair2.Key);
					state.Bests.Add(participantId, keyValuePair2.Value);
				}
			}
		}

		public void Append(WorldState state)
		{
			JObject val = JObject.Parse(Json.Write(state));
			bool flag = _lastPersisted != null;
			string text;
			if (flag)
			{
				List<JournalChange> list = new List<JournalChange>();
				Diff(_lastPersisted, val, new List<string>(), list);
				text = Json.Write(list);
			}
			else
			{
				text = ((JToken)val).ToString((Formatting)0, Array.Empty<JsonConverter>());
			}
			byte[] bytes = Encoding.UTF8.GetBytes(Json.Write(new JournalRecord
			{
				Revision = state.Revision,
				Delta = flag,
				State = text,
				Hash = Hash(text)
			}) + "\n");
			using FileStream fileStream = new FileStream(_journal, FileMode.Append, FileAccess.Write, FileShare.Read);
			fileStream.Write(bytes, 0, bytes.Length);
			fileStream.Flush(SyncWrites);
			_lastPersisted = val;
		}

		public void Checkpoint(WorldState state)
		{
			AtomicWrite(Path.Combine(_directory, "state.json"), Json.Write(state));
			BestFile bestFile = LoadWithBackup<BestFile>(Path.Combine(_root, "best_scores.json")) ?? new BestFile();
			Merge(bestFile, state);
			AtomicWrite(Path.Combine(_root, "best_scores.json"), JsonConvert.SerializeObject((object)bestFile, (Formatting)1, Json.Settings));
		}

		public static void AtomicWrite(string path, string data)
		{
			Directory.CreateDirectory(Path.GetDirectoryName(path));
			string text = path + ".tmp";
			using (FileStream fileStream = new FileStream(text, FileMode.Create, FileAccess.Write, FileShare.None))
			{
				byte[] bytes = Encoding.UTF8.GetBytes(data);
				fileStream.Write(bytes, 0, bytes.Length);
				fileStream.Flush(SyncWrites);
			}
			if (File.Exists(path))
			{
				File.Replace(text, path, path + ".bak");
			}
			else
			{
				File.Move(text, path);
			}
		}
	}
}
namespace BizareScoreHUD.Patches
{
	[HarmonyPatch]
	internal static class InventoryMutationPatch
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			return from m in typeof(Inventory).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
				where new string[7] { "AddItem", "RemoveItem", "RemoveOneItem", "MoveAll", "MoveItemToThis", "StackAll", "MoveInventoryToGrave" }.Contains(m.Name)
				select m;
		}

		private static void Prefix(Inventory __instance, object[] __args, out bool __state)
		{
			__state = InventoryTracking.Loading == 0;
			if (__state)
			{
				InventoryTracking.Begin(__instance, __args);
			}
		}

		private static Exception? Finalizer(Exception? __exception, bool __state)
		{
			if (__state)
			{
				InventoryTracking.End();
			}
			return __exception;
		}
	}
	[HarmonyPatch]
	internal static class InventoryLoadPatch
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			return from m in typeof(Inventory).GetMethods()
				where m.Name == "Load"
				select m;
		}

		private static void Prefix()
		{
			InventoryTracking.Loading++;
		}

		private static Exception? Finalizer(Exception? __exception)
		{
			InventoryTracking.Loading--;
			return __exception;
		}
	}
	[HarmonyPatch(typeof(Humanoid), "Pickup")]
	internal static class PickupPatch
	{
		private static void Prefix(Humanoid __instance, GameObject go)
		{
			InventoryTracking.Pickup(__instance, go);
		}

		private static Exception? Finalizer(Exception? __exception)
		{
			InventoryTracking.End();
			return __exception;
		}
	}
	[HarmonyPatch(typeof(Humanoid), "DropItem")]
	internal static class DropPatch
	{
		private static void Prefix(Humanoid __instance, Inventory inventory, ItemData item)
		{
			InventoryTracking.Begin(inventory ?? __instance.GetInventory(), new object[1] { item });
		}

		private static Exception? Finalizer(Exception? __exception)
		{
			InventoryTracking.End();
			return __exception;
		}
	}
	[HarmonyPatch(typeof(ItemDrop), "DropItem")]
	internal static class DropOutputPatch
	{
		private static void Postfix(ItemDrop __result)
		{
			InventoryTracking.Output(__result);
		}
	}
	[HarmonyPatch(typeof(ItemDrop), "AutoStackItems")]
	internal static class GroundStackPatch
	{
		private static void Prefix(ItemDrop __instance)
		{
			InventoryTracking.GroundStack(__instance);
		}

		private static Exception? Finalizer(Exception? __exception)
		{
			InventoryTracking.End();
			return __exception;
		}
	}
	[HarmonyPatch(typeof(StoreGui), "SellItem")]
	internal static class SalePatch
	{
		internal static void Prefix()
		{
			InventoryTracking.RewardDepth++;
			InventoryTracking.Begin(((Object)(object)Player.m_localPlayer == (Object)null) ? null : ((Humanoid)Player.m_localPlayer).GetInventory(), Array.Empty<object>());
		}

		internal static Exception? Finalizer(Exception? __exception)
		{
			try
			{
				InventoryTracking.End();
				return __exception;
			}
			finally
			{
				InventoryTracking.RewardDepth--;
			}
		}
	}
	[HarmonyPatch(typeof(Character), "ApplyDamage")]
	internal static class DamagePatch
	{
		private static void Prefix(Character __instance, HitData hit)
		{
			if (__instance.IsPlayer() || __instance.IsTamed() || __instance.IsDead() || hit.GetTotalDamage() <= 0.1f)
			{
				return;
			}
			Character attacker = hit.GetAttacker();
			Player val = (Player)(object)((attacker is Player) ? attacker : null);
			if (val == null || !BaseAI.IsEnemy(__instance, (Character)(object)val))
			{
				return;
			}
			ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
			if (!((Object)(object)component == (Object)null) && component.IsValid() && component.IsOwner())
			{
				ZDO zDO = component.GetZDO();
				long playerID = val.GetPlayerID();
				long ticks = ZNet.instance.GetTime().Ticks;
				if (zDO.GetLong(ZdoKeys.Attacker, 0L) != playerID || ticks - zDO.GetLong(ZdoKeys.HitTime, 0L) >= 10000000)
				{
					zDO.Set(ZdoKeys.Attacker, playerID);
					zDO.Set(ZdoKeys.HitTime, ticks);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Character), "OnDeath")]
	internal static class DeathPatch
	{
		private static void Prefix(Character __instance)
		{
			if (__instance.IsPlayer() || __instance.IsTamed())
			{
				return;
			}
			ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
			StatsRuntime instance = StatsRuntime.Instance;
			if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner() || instance == null)
			{
				return;
			}
			ZDO zDO = component.GetZDO();
			string text = zDO.GetString(ZdoKeys.Wave, "");
			long num = zDO.GetLong(ZdoKeys.Attacker, 0L);
			long num2 = zDO.GetLong(ZdoKeys.HitTime, 0L);
			if (num != 0L && ZNet.instance.GetTime().Ticks - num2 <= 300000000)
			{
				string text2 = zDO.GetString(ZdoKeys.Run, "");
				if (text.Length == 0 || text2.Length == 0)
				{
					instance.Warn("Unresolved arena kill: " + ((Object)__instance).name);
					return;
				}
				instance.Submit(new Report
				{
					Kind = "kill",
					Run = text2,
					Victim = ((object)Unsafe.As<ZDOID, ZDOID>(ref zDO.m_uid)/*cast due to .constrained prefix*/).ToString(),
					Wave = text,
					Killer = num,
					Level = __instance.GetLevel(),
					Boss = __instance.IsBoss()
				});
			}
		}
	}
	[HarmonyPatch(typeof(ZDOMan), "HandleDestroyedZDO")]
	internal static class PreserveVictimPatch
	{
		private static void Prefix(ZDOMan __instance, ZDOID uid)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			ZDO zDO = __instance.GetZDO(uid);
			if (zDO != null)
			{
				StatsRuntime.Instance?.PreserveVictim(zDO);
			}
		}
	}
}
namespace BizareScoreHUD.Networking
{
	public sealed class Report
	{
		public int Protocol = 1;

		public string Id = "";

		public string World = "";

		public string Kind = "";

		public string Run = "";

		public string Victim = "";

		public string Wave = "";

		public long Killer;

		public int Level;

		public bool Boss;

		public List<LotRange> Ranges = new List<LotRange>();
	}
	public sealed class Snapshot
	{
		public int Protocol = 1;

		public long Revision;

		public string World = "";

		public string Run = "";

		public long StartedUtcTicks;

		public long ServerUtcTicks;

		public string Ack = "";

		public string Error = "";

		public Counters Personal = new Counters();

		public Counters Team = new Counters();

		public long BestUnits;

		public int ConnectedPlayers;

		public List<ArenaEvent> Events = new List<ArenaEvent>();

		public List<Wave> EventWaves = new List<Wave>();
	}
	public sealed class StatsRuntime : IDisposable
	{
		private const string ReportRpc = "BizareHUD.Report.v1";

		private const string SnapshotRpc = "BizareHUD.Snapshot.v1";

		private readonly ManualLogSource _log;

		private readonly ConfigEntry<ArenaDifficulty> _difficulty;

		private readonly string _root;

		private ZRoutedRpc? _rpc;

		private ZNet? _net;

		private StateRepository? _repository;

		private WorldState? _state;

		private bool _failed;

		private float _nextPoll;

		private float _nextCheckpoint;

		private readonly Dictionary<long, string> _bindings = new Dictionary<long, string>();

		private readonly Dictionary<long, float> _lastRequest = new Dictionary<long, float>();

		private readonly List<Report> _pending = new List<Report>();

		private readonly Dictionary<string, int> _attempts = new Dictionary<string, int>();

		private readonly Dictionary<string, float> _retryAt = new Dictionary<string, float>();

		private string? _pendingPath;

		private long _pendingCharacter;

		private float _receivedAt;

		private bool _journalDirty;

		private bool _pendingDirty;

		private bool _publishDirty;

		private long _checkpointed = -1L;

		public static StatsRuntime? Instance { get; private set; }

		public Snapshot? Current { get; private set; }

		public WorldState? State => _state;

		public bool IsServer
		{
			get
			{
				if ((Object)(object)ZNet.instance != (Object)null)
				{
					return ZNet.instance.IsServer();
				}
				return false;
			}
		}

		public string RunId
		{
			get
			{
				object obj;
				if (!_failed)
				{
					if (!IsServer)
					{
						obj = Current?.Run;
						if (obj == null)
						{
							return "";
						}
					}
					else
					{
						obj = _state?.CurrentRun;
						if (obj == null)
						{
							return "";
						}
					}
				}
				else
				{
					obj = "";
				}
				return (string)obj;
			}
		}

		public string WorldId
		{
			get
			{
				object obj;
				if (IsServer)
				{
					obj = _state?.World ?? "";
				}
				else
				{
					obj = Current?.World;
					if (obj == null)
					{
						return "";
					}
				}
				return (string)obj;
			}
		}

		private int Connected => _net.GetPeers().Count((ZNetPeer p) => p.IsReady() && p.m_playerID != 0) + (((Object)(object)Player.m_localPlayer != (Object)null) ? 1 : 0);

		public TimeSpan Elapsed
		{
			get
			{
				if (Current != null)
				{
					return TimeSpan.FromSeconds(Math.Max(0.0, (double)(Current.ServerUtcTicks - Current.StartedUtcTicks) / 10000000.0 + (double)Time.unscaledTime - (double)_receivedAt));
				}
				return TimeSpan.Zero;
			}
		}

		public StatsRuntime(ConfigFile config, ManualLogSource log)
		{
			Instance = this;
			_log = log;
			_difficulty = config.Bind<ArenaDifficulty>("Server", "Difficulty", ArenaDifficulty.Normal, "Server-owned scoring difficulty. Changes apply at the next accepted arena reset.");
			_root = config.Bind<string>("Server", "DataDirectory", Path.Combine(Paths.ConfigPath, "BizareScoreHUD", "data"), "Server statistics and shared best scores directory.").Value;
			StateRepository.SyncWrites = config.Bind<bool>("Server", "SyncWrites", false, "Force every statistics write to disk (fsync). Protects against power loss, but each kill or sale then stalls on slow drives.").Value;
		}

		public void Warn(string message)
		{
			_log.LogWarning((object)message);
		}

		private void EndSession()
		{
			Flush();
			if (_state != null && !_failed)
			{
				TryCheckpoint();
			}
			_state = null;
			_repository = null;
			_bindings.Clear();
			_lastRequest.Clear();
			Current = null;
			_pending.Clear();
			_attempts.Clear();
			_retryAt.Clear();
			_pendingPath = null;
			_pendingCharacter = 0L;
			_failed = false;
			_journalDirty = (_pendingDirty = (_publishDirty = false));
			_checkpointed = -1L;
			InventoryTracking.Clear();
			ArenaAdapter.Clear();
		}

		public void Tick()
		{
			if ((Object)(object)_net != (Object)(object)ZNet.instance || _rpc != ZRoutedRpc.instance)
			{
				EndSession();
				_net = ZNet.instance;
				_rpc = ZRoutedRpc.instance;
				if ((Object)(object)_net == (Object)null || _rpc == null)
				{
					return;
				}
				_rpc.Register<string>("BizareHUD.Report.v1", (Action<long, string>)OnReport);
				_rpc.Register<string>("BizareHUD.Snapshot.v1", (Action<long, string>)OnSnapshot);
				if (IsServer)
				{
					try
					{
						string text = _net.GetWorldUID().ToString(CultureInfo.InvariantCulture);
						_repository = new StateRepository(_root, text);
						_state = _repository.Load(text, _difficulty.Value);
						if (GUIManagerHeadless())
						{
							_pendingPath = Path.Combine(_root, text, "server_pending.json");
							_pendingCharacter = -1L;
							if (File.Exists(_pendingPath))
							{
								_pending.AddRange(Json.Read<List<Report>>(File.ReadAllText(_pendingPath)));
							}
						}
					}
					catch (Exception ex)
					{
						_failed = true;
						_log.LogError((object)("Statistics storage could not be loaded; accounting stopped: " + ex));
					}
				}
			}
			if ((Object)(object)_net == (Object)null || _rpc == null || _failed)
			{
				return;
			}
			if (Time.unscaledTime >= _nextPoll)
			{
				_nextPoll = Time.unscaledTime + 2f;
				if ((Object)(object)Player.m_localPlayer != (Object)null)
				{
					LoadPending();
					Submit(new Report
					{
						Kind = "hello",
						World = WorldId
					});
					InventoryTracking.Audit(((Humanoid)Player.m_localPlayer).GetInventory());
				}
				int num = 0;
				Report[] array = _pending.ToArray();
				foreach (Report report in array)
				{
					if (num == 32)
					{
						break;
					}
					if (!(report.World != WorldId) && (!_retryAt.TryGetValue(report.Id, out var value) || !(Time.unscaledTime < value)))
					{
						int value2;
						int num2 = (_attempts.TryGetValue(report.Id, out value2) ? value2 : 0);
						_attempts[report.Id] = num2 + 1;
						_retryAt[report.Id] = Time.unscaledTime + Math.Min(60f, 2f * (float)(1 << Math.Min(num2, 5)));
						Send(report);
						num++;
					}
				}
				if (IsServer)
				{
					_publishDirty = true;
				}
			}
			if (_publishDirty)
			{
				_publishDirty = false;
				Publish();
			}
			if (_state != null && Time.unscaledTime >= _nextCheckpoint)
			{
				_nextCheckpoint = Time.unscaledTime + 15f;
				TryCheckpoint();
			}
			Flush();
		}

		private void Flush()
		{
			if (_failed)
			{
				return;
			}
			if (_journalDirty && _state != null && _repository != null)
			{
				_journalDirty = false;
				try
				{
					_repository.Append(_state);
				}
				catch (Exception ex)
				{
					_failed = true;
					_log.LogError((object)("Durable statistics commit failed; accounting stopped: " + ex));
					return;
				}
			}
			if (!_pendingDirty || _pendingPath == null)
			{
				return;
			}
			_pendingDirty = false;
			try
			{
				StateRepository.AtomicWrite(_pendingPath, Json.Write(_pending));
			}
			catch (Exception ex2)
			{
				_failed = true;
				_log.LogError((object)("Pending observations could not be saved; accounting stopped: " + ex2));
			}
		}

		private void LoadPending()
		{
			long playerID = Player.m_localPlayer.GetPlayerID();
			if (playerID == _pendingCharacter)
			{
				return;
			}
			Flush();
			_pending.Clear();
			_attempts.Clear();
			_retryAt.Clear();
			_pendingCharacter = playerID;
			_pendingPath = Path.Combine(Paths.ConfigPath, "BizareScoreHUD", "pending", playerID.ToString(CultureInfo.InvariantCulture) + ".json");
			if (!File.Exists(_pendingPath))
			{
				return;
			}
			try
			{
				_pending.AddRange(Json.Read<List<Report>>(File.ReadAllText(_pendingPath)));
			}
			catch (Exception ex)
			{
				_failed = true;
				_log.LogError((object)("Cannot recover pending observations: " + ex));
			}
		}

		private void SavePending()
		{
			if (_pendingPath != null)
			{
				_pendingDirty = true;
			}
		}

		private static bool GUIManagerHeadless()
		{
			return GUIManager.IsHeadless();
		}

		public bool Submit(Report report)
		{
			if (_failed || _rpc == null)
			{
				return false;
			}
			if (report.Kind != "hello")
			{
				if (string.IsNullOrEmpty(report.Run) || string.IsNullOrEmpty(WorldId))
				{
					Warn("Unresolved observation before server run binding: " + report.Kind);
					return false;
				}
				report.Id = ((report.Id.Length == 0) ? Guid.NewGuid().ToString("N") : report.Id);
				report.World = WorldId;
				if ((Object)(object)Player.m_localPlayer != (Object)null)
				{
					LoadPending();
				}
				if (_failed)
				{
					return false;
				}
				if (_pending.Count >= 4096)
				{
					Warn("Pending report capacity reached; observation deferred");
					return false;
				}
				_pending.Add(report);
				SavePending();
			}
			try
			{
				Send(report);
			}
			catch (Exception ex)
			{
				Warn("Observation remains queued: " + ex.Message);
			}
			return true;
		}

		private void Send(Report report)
		{
			if (IsServer)
			{
				OnReport(ZNet.GetUID(), Json.Write(report));
				return;
			}
			ZNet? net = _net;
			if (((net != null) ? net.GetServerPeer() : null) != null)
			{
				_rpc.InvokeRoutedRPC(_net.GetServerPeer().m_uid, "BizareHUD.Report.v1", new object[1] { Json.Write(report) });
			}
		}

		private unsafe string? Bind(long sender)
		{
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			long playerID;
			string nickname;
			string text;
			if (sender == ZNet.GetUID())
			{
				if ((Object)(object)Player.m_localPlayer == (Object)null)
				{
					return null;
				}
				playerID = Player.m_localPlayer.GetPlayerID();
				nickname = Player.m_localPlayer.GetPlayerName();
				text = ((object)Unsafe.As<PlatformUserID, PlatformUserID>(ref UserInfo.GetLocalUser().UserId)/*cast due to .constrained prefix*/).ToString();
			}
			else
			{
				ZNetPeer peer = _net.GetPeer(sender);
				if (peer == null || !peer.IsReady() || peer.m_playerID == 0L)
				{
					return null;
				}
				playerID = peer.m_playerID;
				nickname = peer.m_playerName;
				text = peer.m_socket.GetHostName();
				if (((object)peer.m_socket).GetType().Name == "ZSteamSocket")
				{
					text = ((object)new PlatformUserID("Steam", text)/*cast due to .constrained prefix*/).ToString();
				}
				else
				{
					PlatformUserID val = default(PlatformUserID);
					if (!PlatformUserID.TryParse(text, ref val))
					{
						throw new InvalidOperationException("Authenticated platform account unavailable");
					}
					text = ((object)(*(PlatformUserID*)(&val))/*cast due to .constrained prefix*/).ToString();
				}
			}
			if (text.Length == 0 || playerID == 0L)
			{
				return null;
			}
			string id = text + ":" + playerID.ToString(CultureInfo.InvariantCulture);
			_bindings[sender] = id;
			if (!_state.Participants.TryGetValue(id, out Participant value) || value.Nickname != nickname)
			{
				Commit(delegate(WorldState s)
				{
					s.Join(id, nickname);
				});
			}
			return id;
		}

		private void OnReport(long sender, string payload)
		{
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			if (!IsServer || _state == null || _failed || payload.Length > 65536)
			{
				return;
			}
			Report report = null;
			try
			{
				report = Json.Read<Report>(payload);
				if (report.Protocol != 1)
				{
					throw new InvalidOperationException("Unsupported statistics protocol");
				}
				string player = Bind(sender);
				if (player == null && sender == ZNet.GetUID() && report.Kind == "kill")
				{
					player = FindParticipant(report.Killer);
				}
				if (player == null)
				{
					return;
				}
				if (report.Kind == "hello")
				{
					if (!_lastRequest.TryGetValue(sender, out var value) || Time.unscaledTime - value >= 1f)
					{
						_lastRequest[sender] = Time.unscaledTime;
						Reply(sender, player, "", "");
					}
					return;
				}
				if (report.World != _state.World || report.Id.Length != 32 || !_state.Runs.ContainsKey(report.Run))
				{
					throw new InvalidOperationException("Wrong world/run or invalid event");
				}
				string kind = report.Kind;
				if (!(kind == "gold"))
				{
					if (!(kind == "kill"))
					{
						throw new InvalidOperationException("Unknown observation kind");
					}
					if (!_state.Deaths.ContainsKey(report.Victim))
					{
						if (!TryId(report.Victim, out var id))
						{
							throw new InvalidOperationException("Invalid victim");
						}
						ZDO zDO = ZDOMan.instance.GetZDO(id);
						MobRecord value2;
						MobRecord evidence = ((zDO != null) ? Observe(zDO) : (_state.Mobs.TryGetValue(report.Victim, out value2) ? value2 : null));
						if (evidence == null || evidence.Owner != sender)
						{
							throw new InvalidOperationException("Victim not owned by reporting peer");
						}
						string wave = evidence.Wave;
						if (wave != report.Wave || !_state.Waves.TryGetValue(wave, out Wave value3) || value3.Run != report.Run)
						{
							throw new InvalidOperationException("Missing server wave association");
						}
						if (evidence.Boss != report.Boss)
						{
							throw new InvalidOperationException("Unclassified custom boss override");
						}
						if (evidence.Tamed)
						{
							throw new InvalidOperationException("Ineligible victim");
						}
						string killer = FindParticipant(report.Killer);
						if (killer == null)
						{
							throw new InvalidOperationException("Unresolved killer identity");
						}
						int level = evidence.Level;
						Commit(delegate(WorldState s)
						{
							s.Kill(report.Victim, wave, killer, level, evidence.Boss);
						});
					}
				}
				else
				{
					if (report.Ranges.Count > 256)
					{
						throw new InvalidOperationException("Too many currency ranges");
					}
					Commit(delegate(WorldState s)
					{
						s.Acquire(player, report.Run, report.Ranges);
					});
				}
				Reply(sender, player, report.Id, "");
				_publishDirty = true;
			}
			catch (Exception ex)
			{
				Warn("Rejected statistics observation: " + ex.Message);
				if (report != null && _bindings.TryGetValue(sender, out string value4))
				{
					Reply(sender, value4, "", ex.Message);
				}
			}
		}

		private string? FindParticipant(long character)
		{
			foreach (ZNetPeer peer in _net.GetPeers())
			{
				if (peer.m_playerID == character)
				{
					return Bind(peer.m_uid);
				}
			}
			if ((Object)(object)Player.m_localPlayer != (Object)null && Player.m_localPlayer.GetPlayerID() == character)
			{
				return Bind(ZNet.GetUID());
			}
			return _state.Participants.Keys.SingleOrDefault((string id) => id.EndsWith(":" + character.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal));
		}

		public static bool TryId(string text, out ZDOID id)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//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)
			id = ZDOID.None;
			string[] array = text.Split(':');
			if (array.Length != 2 || !long.TryParse(array[0], out var result) || !uint.TryParse(array[1], out var result2))
			{
				return false;
			}
			id = new ZDOID(result, result2);
			return true;
		}

		public void Commit(Action<WorldState> reduce)
		{
			if (_state != null && _repository != null && !_failed)
			{
				reduce(_state);
				_state.Revision = checked(_state.Revision + 1);
				_journalDirty = true;
			}
		}

		public Wave? AcceptWave(ZDO arena, int tier, int stage)
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			if (_state == null)
			{
				return null;
			}
			Wave wave = new Wave
			{
				Id = Guid.NewGuid().ToString("N"),
				Run = _state.CurrentRun,
				Arena = ((object)Unsafe.As<ZDOID, ZDOID>(ref arena.m_uid)/*cast due to .constrained prefix*/).ToString(),
				Sequence = _state.Revision + 1,
				Tier = tier,
				Stage = stage,
				GlobalNumber = ScorePolicy.GlobalWave(tier, stage),
				X = arena.GetPosition().x,
				Z = arena.GetPosition().z
			};
			Commit(delegate(WorldState s)
			{
				s.Waves.Add(wave.Id, wave);
			});
			return wave;
		}

		public void Reset(string activation)
		{
			Commit(delegate(WorldState s)
			{
				s.Reset(activation, _difficulty.Value);
			});
			Publish();
		}

		public void Associate(ZDO zdo, Wave wave)
		{
			if (zdo.GetString(ZdoKeys.Wave, "").Length == 0 && (IsServer || zdo.IsOwner()))
			{
				zdo.Set(ZdoKeys.Wave, wave.Id);
				zdo.Set(ZdoKeys.Run, wave.Run);
			}
		}

		public void EventStarted(RandomEvent? ev, Vector3 position, Wave? context)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (!IsServer || _state == null)
			{
				return;
			}
			Commit(delegate(WorldState s)
			{
				s.Events.RemoveAll(delegate(ArenaEvent e)
				{
					//IL_002c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0031: Unknown result type (might be due to invalid IL or missing references)
					if (ev != null)
					{
						Vector2 val = new Vector2(e.X - position.x, e.Z - position.z);
						return ((Vector2)(ref val)).sqrMagnitude < 1f;
					}
					return true;
				});
				if (ev != null && context != null)
				{
					s.Events.Add(new ArenaEvent
					{
						Name = ev.m_name,
						Wave = context.Id,
						X = position.x,
						Z = position.z
					});
				}
			});
			Publish();
		}

		public Wave? EventWave(RandomEvent ev)
		{
			ArenaEvent entry = ((!IsServer) ? Current?.Events : _state?.Events)?.LastOrDefault(delegate(ArenaEvent e)
			{
				//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)
				if (e.Name == ev.m_name)
				{
					Vector2 val = new Vector2(e.X - ev.m_pos.x, e.Z - ev.m_pos.z);
					return ((Vector2)(ref val)).sqrMagnitude < 1f;
				}
				return false;
			});
			if (entry == null)
			{
				return null;
			}
			if (!IsServer)
			{
				return Current?.EventWaves.Find((Wave w) => w.Id == entry.Wave);
			}
			if (!_state.Waves.TryGetValue(entry.Wave, out Wave value))
			{
				return null;
			}
			return value;
		}

		public MobRecord? Observe(ZDO zdo)
		{
			if (_state == null || (Object)(object)ZNetScene.instance == (Object)null)
			{
				return null;
			}
			string text = zdo.GetString(ZdoKeys.Wave, "");
			if (text.Length == 0 || !_state.Waves.ContainsKey(text))
			{
				return null;
			}
			GameObject prefab = ZNetScene.instance.GetPrefab(zdo.GetPrefab());
			Character val = (((Object)(object)prefab == (Object)null) ? null : prefab.GetComponent<Character>());
			if ((Object)(object)val == (Object)null || val.IsPlayer())
			{
				return null;
			}
			return new MobRecord
			{
				Wave = text,
				Owner = zdo.GetOwner(),
				Level = zdo.GetInt(ZDOVars.s_level, 1),
				Boss = val.IsBoss(),
				Tamed = zdo.GetBool(ZDOVars.s_tamed, false),
				LastAttacker = zdo.GetLong(ZdoKeys.Attacker, 0L),
				HitTicks = zdo.GetLong(ZdoKeys.HitTime, 0L)
			};
		}

		public void PreserveVictim(ZDO zdo)
		{
			if (!IsServer || _state == null)
			{
				return;
			}
			MobRecord evidence = Observe(zdo);
			if (evidence == null)
			{
				return;
			}
			string id = ((object)Unsafe.As<ZDOID, ZDOID>(ref zdo.m_uid)/*cast due to .constrained prefix*/).ToString();
			if (!_state.Deaths.ContainsKey(id) && (evidence.Owner != ZNet.GetUID() || !((Object)(object)Player.m_localPlayer == (Object)null)))
			{
				Commit(delegate(WorldState s)
				{
					s.Mobs[id] = evidence;
				});
			}
		}

		private void Reply(long sender, string player, string ack, string error)
		{
			WorldState s = _state;
			BestRecord value;
			string text = Json.Write(new Snapshot
			{
				Revision = s.Revision,
				World = s.World,
				Run = s.CurrentRun,
				StartedUtcTicks = s.Active.StartedUtcTicks,
				ServerUtcTicks = DateTime.UtcNow.Ticks,
				Events = s.Events,
				EventWaves = s.Events.Select((ArenaEvent e) => s.Waves[e.Wave]).Distinct().ToList(),
				Ack = ack,
				Error = error,
				Personal = s.Get(s.CurrentRun, player),
				Team = s.Team(),
				BestUnits = (s.Bests.TryGetValue(player, out value) ? value.ScoreUnits : 0),
				ConnectedPlayers = Connected
			});
			if (sender == ZNet.GetUID())
			{
				OnSnapshot(sender, text);
				return;
			}
			_rpc.InvokeRoutedRPC(sender, "BizareHUD.Snapshot.v1", new object[1] { text });
		}

		public void Publish()
		{
			if (_state == null || _failed)
			{
				return;
			}
			ZNetPeer[] array = (from p in _net.GetPeers()
				where p.IsReady() && p.m_playerID != 0
				select p).ToArray();
			foreach (ZNetPeer val in array)
			{
				string text = Bind(val.m_uid);
				if (text != null)
				{
					Reply(val.m_uid, text, "", "");
				}
			}
			if ((Object)(object)Player.m_localPlayer != (Object)null)
			{
				string text2 = Bind(ZNet.GetUID());
				if (text2 != null)
				{
					Reply(ZNet.GetUID(), text2, "", "");
				}
			}
		}

		private void OnSnapshot(long sender, string payload)
		{
			long num;
			if (!IsServer)
			{
				ZNet? net = _net;
				num = ((net == null) ? ((long?)null) : net.GetServerPeer()?.m_uid).GetValueOrDefault();
			}
			else
			{
				num = ZNet.GetUID();
			}
			long num2 = num;
			if (sender != num2 || payload.Length > 65536)
			{
				return;
			}
			try
			{
				Snapshot snapshot = Json.Read<Snapshot>(payload);
				if (snapshot.Protocol == 1)
				{
					if (snapshot.Ack.Length > 0 && _pending.RemoveAll((Report r) => r.Id == snapshot.Ack && r.World == snapshot.World) > 0)
					{
						_attempts.Remove(snapshot.Ack);
						_retryAt.Remove(snapshot.Ack);
						SavePending();
					}
					if (Current == null || !(Current.World == snapshot.World) || snapshot.Revision >= Current.Revision)
					{
						Current = snapshot;
						_receivedAt = Time.unscaledTime;
					}
				}
			}
			catch (Exception ex)
			{
				Warn("Invalid statistics snapshot: " + ex.Message);
			}
		}

		private void TryCheckpoint()
		{
			if (_state == null || _repository == null || _failed)
			{
				return;
			}
			Flush();
			if (_failed || _state.Revision == _checkpointed)
			{
				return;
			}
			try
			{
				_repository.Checkpoint(_state);
				_checkpointed = _state.Revision;
			}
			catch (Exception ex)
			{
				_log.LogError((object)("Statistics checkpoint failed; journal retained: " + ex));
			}
		}

		public void Dispose()
		{
			EndSession();
			Instance = null;
		}
	}
	internal static class ZdoKeys
	{
		public static readonly int Wave = StringExtensionMethods.GetStableHashCode("bizarehud.wave");

		public static readonly int Run = StringExtensionMethods.GetStableHashCode("bizarehud.run");

		public static readonly int Attacker = StringExtensionMethods.GetStableHashCode("bizarehud.attacker");

		public static readonly int HitTime = StringExtensionMethods.GetStableHashCode("bizarehud.hitTime");
	}
}
namespace BizareScoreHUD.Domain
{
	public static class Provenance
	{
		public static List<LotRange> Take(List<LotRange> source, long quantity)
		{
			if (quantity < 0 || source.Sum((LotRange r) => r.Count) < quantity)
			{
				throw new InvalidOperationException("Currency conservation failure");
			}
			List<LotRange> list = new List<LotRange>();
			while (quantity > 0)
			{
				LotRange lotRange = source[0];
				long num = Math.Min(quantity, lotRange.Count);
				list.Add(lotRange.Slice(0L, num));
				quantity -= num;
				if (num == lotRange.Count)
				{
					source.RemoveAt(0);
					continue;
				}
				checked
				{
					lotRange.Start += num;
				}
				lotRange.Count -= num;
			}
			return list;
		}

		public static List<LotRange> Copy(IEnumerable<LotRange> source)
		{
			return source.Select((LotRange r) => r.Slice(0L, r.Count)).ToList();
		}

		public static LotRange Create(long count, bool fresh, string run)
		{
			return new LotRange
			{
				Lot = Guid.NewGuid().ToString("N"),
				Count = count,
				Fresh = fresh,
				Run = run
			};
		}
	}
	public enum ArenaDifficulty
	{
		Easy,
		Normal,
		Hard,
		UltraHard
	}
	public static class ScorePolicy
	{
		public const long UnitsPerPoint = 1000000L;

		public static readonly string[] StageKeys = new string[8] { "meadowstage", "blackforeststage", "swampstage", "mountstage", "plainsstage", "mistlandsstage", "ashlandsstage", "deepnorthstage" };

		public static readonly int[] StageCounts = new int[8] { 4, 8, 8, 6, 6, 6, 8, 7 };

		public static long KillUnits(int tier, int wave, int level, bool boss, ArenaDifficulty difficulty)
		{
			if (tier < 1 || tier > 100 || wave < 1 || wave > 100000)
			{
				throw new ArgumentOutOfRangeException("wave");
			}
			if (!boss && (level < 1 || level > 3))
			{
				throw new ArgumentOutOfRangeException("level", "Unsupported mob level");
			}
			int num = difficulty switch
			{
				ArenaDifficulty.Easy => 75, 
				ArenaDifficulty.Normal => 100, 
				ArenaDifficulty.Hard => 125, 
				ArenaDifficulty.UltraHard => 150, 
				_ => throw new ArgumentOutOfRangeException("difficulty"), 
			};
			long num2;
			checked
			{
				num2 = unchecked((long)(boss ? 100 : 10)) * unchecked((long)(boss ? 100 : checked(100 + (level - 1) * 25))) * (9 + tier) * (99 + wave) * num;
			}
			if (num2 % 10 != 0L)
			{
				throw new InvalidOperationException("Inexact scoring rule");
			}
			return num2 / 10;
		}

		public static int GlobalWave(int tier, int stage)
		{
			if (tier < 1 || tier > StageCounts.Length || stage < 1 || stage > StageCounts[tier - 1])
			{
				throw new ArgumentOutOfRangeException("stage");
			}
			int num = stage;
			for (int i = 0; i < tier - 1; i++)
			{
				num += StageCounts[i];
			}
			return num;
		}
	}
	public sealed class Counters
	{
		public long ScoreUnits;

		public long Kills;

		public long Gold;

		public long Score => ScoreUnits / 1000000;
	}
	public sealed class Participant
	{
		public string Id = "";

		public string Nickname = "";
	}
	public sealed class BestRecord
	{
		public string ParticipantId = "";

		public string Nickname = "";

		public long ScoreUnits;

		public string World = "";

		public string Run = "";

		public ArenaDifficulty Difficulty;

		public int RuleVersion = 1;

		public long Score => ScoreUnits / 1000000;
	}
	public sealed class Wave
	{
		public string Id = "";

		public string Run = "";

		public string Arena = "";

		public long Sequence;

		public int Tier;

		public int Stage;

		public int GlobalNumber;

		public float X;

		public float Z;
	}
	public sealed class Run
	{
		public string Id = Guid.NewGuid().ToString("N");

		public long StartedUtcTicks = DateTime.UtcNow.Ticks;

		public ArenaDiffic